diff --git a/Changelog.md b/Changelog.md
index 8f4afe18557ca5dd7698aa19760736586abb1196..98f8d93e44b2ee79b2ad0bc4e3fabb2c75fbeaed 100644
--- a/Changelog.md
+++ b/Changelog.md
@@ -2,6 +2,9 @@
 
 All notable changes to this project will be documented in this file.
 
+## [0.55] - 2020-12-08
+- LGR-73: updated business logic for classifying LG routers public/internal
+
 ## [0.54] - 2020-10-07
 - DBOARD3-334: peer-info classifier performance improvement
 
diff --git a/inventory_provider/db/opsdb.py b/inventory_provider/db/opsdb.py
index 07a24e275ca2aa107ddcfc1199fee64292ac4745..cdf49bdc947cb282b5e86093dee0f5448d5708f7 100644
--- a/inventory_provider/db/opsdb.py
+++ b/inventory_provider/db/opsdb.py
@@ -400,27 +400,40 @@ SELECT
     g.longitude AS pop_longitude,
     p.country_code AS pop_country_code,
     g.country AS pop_country,
-    g.city AS pop_city
+    e.model AS equipment_model
 FROM
     opsdb.equipment e
     LEFT JOIN opsdb.pop p ON p.absid = e.PTR_pop
     LEFT JOIN opsdb.geocoding g ON g.absid = p.PTR_geocoding
     LEFT JOIN opsdb.organisation o ON o.absid = e.PTR_owner
 WHERE
-    e.model LIKE 'mx%'
+    e.manufacturer = 'Juniper'
     AND e.status = 'Operational'
     AND o.name = 'DANTE / GEANT'
-    AND NOT (e.name REGEXP 'vpn-proxy|vrr|taas')
+    AND NOT (e.name REGEXP 'vpn-proxy|vrr|taas|junosspace')
 """
 
+    def _public(row):
+        # cf. LGR-73
+
+        if row['pop_name'] in INTERNAL_POP_NAMES:
+            return False
+
+        router_name_lower = row['router_name'].lower()
+        if any(router_name_lower.startswith(prefix)
+                for prefix in ['srx', 'gts', 'sw', 'qfx']):
+            return False
+
+        if row['pop_city'].lower() == 'slough' \
+                and not row['equipment_model'].upper().startswith('MX'):
+            return False
+
+        return True
+
     def _row2rsp(row):
-        print(row)
         return {
             'equipment name': row['router_name'],
-            'type':
-                'INTERNAL'
-                if row['pop_name'] in INTERNAL_POP_NAMES
-                else 'CORE',
+            'type': 'CORE' if _public(row) else 'INTERNAL',
             'pop': {
                 'name': row['pop_name'],
                 'city': row['pop_city'],
diff --git a/inventory_provider/routes/lg.py b/inventory_provider/routes/lg.py
index e8b72f6a0f312b4fb445a34f438a7d9bb168fab0..bcb528ccc8252f806c3ce5b8b6366dea7e8da0f8 100644
--- a/inventory_provider/routes/lg.py
+++ b/inventory_provider/routes/lg.py
@@ -1,6 +1,6 @@
 import json
 
-from flask import Blueprint, jsonify, Response
+from flask import Blueprint, jsonify, Response, current_app
 
 from inventory_provider.routes import common
 
@@ -25,29 +25,25 @@ def routers(access):
             status=404,
             mimetype='text/html')
 
-    redis = common.get_current_redis()
-
     def _visible(router):
         if access == ACCESS_INTERNAL:
             return True
         return router['type'] == 'CORE'
 
     def _routers():
-        i = 0
-        for k in redis.scan_iter('opsdb:lg:*'):
-            rtr = redis.get(k.decode('utf-8')).decode('utf-8')
-            rtr = json.loads(rtr)
-            i += 1
-            if _visible(rtr):
-                yield rtr
+        for doc in common.load_json_docs(
+                config_params=current_app.config['INVENTORY_PROVIDER_CONFIG'],
+                key_pattern='opsdb:lg:*'):
+            yield doc['value']
 
+    redis = common.get_current_redis()
     cache_key = f'classifier-cache:lg:{access}'
     result = redis.get(cache_key)
 
     if result:
         result = json.loads(result.decode('utf-8'))
     else:
-        result = list(_routers())
+        result = list(filter(_visible, _routers()))
         # cache this data for the next call
         redis.set(cache_key, json.dumps(result).encode('utf-8'))
 
diff --git a/setup.py b/setup.py
index e955ca263415521e8ff1272197bc0ccf51bfd351..cede0c37d6d0f10ac079969dc6f42a5e276fc2a7 100644
--- a/setup.py
+++ b/setup.py
@@ -2,7 +2,7 @@ from setuptools import setup, find_packages
 
 setup(
     name='inventory-provider',
-    version="0.54",
+    version="0.55",
     author='GEANT',
     author_email='swd@geant.org',
     description='Dashboard inventory provider',
diff --git a/test/test_opsdb_queries.py b/test/test_opsdb_queries.py
index e3d0bc56176fa30551bab6011459ad9b19cf497e..da219e271fd717a46655b5b6721ffa027d3fbe01 100644
--- a/test/test_opsdb_queries.py
+++ b/test/test_opsdb_queries.py
@@ -281,6 +281,26 @@ def test_lookup_lg_routers(connection, cached_test_data):
     jsonschema.validate(routers, LG_ROUTERS_SCHEMA)
     assert routers  # shouldn't be empty
 
+    # LGR-73
+    assert any(
+        r['equipment name'].startswith('sw2.am.office') for r in routers)
+    assert any(
+        r['equipment name'].startswith('sw3.am.office') for r in routers)
+
+    switches = filter(
+        lambda r: r['equipment name'].startswith('sw'), routers)
+    assert all(s['type'] == 'INTERNAL' for s in switches)
+
+    assert not any(
+        r['equipment name'].lower().startswith('junosspace') for r in routers)
+
+    internal_prefix_patterns = ['srx', 'gts', 'qfx']
+    for prefix in internal_prefix_patterns:
+        filtered = filter(
+            lambda r: r['equipment name'].lower().startswith(prefix), routers)
+        assert all(r['type'] == 'INTERNAL' for r in filtered), \
+            f'not all {prefix}* routers are INTERNAL'
+
 
 CIRCUIT_INFO_SCHEMA = {
     "$schema": "http://json-schema.org/draft-07/schema#",
diff --git a/tox.ini b/tox.ini
index a4cd729f02609783ef037fa1c93cbcc492104d50..f08e8f1c3512dd36edca87ebb6b20de3a3212053 100644
--- a/tox.ini
+++ b/tox.ini
@@ -11,7 +11,7 @@ deps =
 
 commands =
     coverage erase
-    coverage run --source inventory_provider -m py.test {posargs}
+    coverage run --source inventory_provider --omit='inventory_provider/routes/ims*,inventory_provider/db/ims*,inventory_provider/tasks/ims*' -m py.test {posargs}
     coverage xml
     coverage html
     coverage report --fail-under 75