From 59c53de21f226dd5e373c9e3357d3a5c1fb3669d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nikola=20Perovi=C4=87?= <46610174+Fooftilly@users.noreply.github.com> Date: Tue, 29 Sep 2026 21:52:09 +0200 Subject: [PATCH 1/6] docs: point frontend coherence comments at leaf rules --- frontend/js/api.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/frontend/js/api.js b/frontend/js/api.js index 4471caa8..d9e4dc40 100644 --- a/frontend/js/api.js +++ b/frontend/js/api.js @@ -1086,7 +1086,7 @@ function prksMarkConceptsDomainChanged() { * successful call to one of those helpers invalidates the whole Positions * domain rather than working out which Positions were actually affected. * Independent of the Concepts domain by construction -- see - * docs/agent-rules/offline-pwa.md "Offline coherence domains". + * docs/agent-rules/offline-entity-coherence.md. */ function prksMarkPositionsDomainChanged() { if (typeof prksOfflineMarkPositionsChanged !== 'function') return null; @@ -1146,7 +1146,7 @@ function prksMarkPlaylistsDomainChanged() { * the sync coordinator needs ONE place to change "discard the projection" into * "apply the pending operation to it optimistically". A scattered * deleteList('works-browse:index') would have to be rewritten everywhere. - * See docs/agent-rules/offline-pwa.md, "Offline browse catalogs". + * See docs/agent-rules/offline-browse-protocol.md. * ------------------------------------------------------------------------ */ /** The stable Work catalog behind #/progress, #/types and #/types/:type. */ @@ -1186,7 +1186,7 @@ function prksMarkWorkBrowseDisplayChanged() { * Folder: moving a Work changes two Folder details AND both `work_count`s in * `folders:index`, and reparenting changes the hierarchy for every ancestor. * A cached Folder detail also embeds whole Work cards, so Work display changes - * stale it too -- see docs/agent-rules/offline-pwa.md, "Offline coherence domains". + * stale it too -- see docs/agent-rules/offline-folder-tag-coherence.md. */ function prksMarkFoldersDomainChanged() { if (typeof prksOfflineMarkFoldersChanged !== 'function') return null; From 011d6cf9c0af9d394c1cc679407fd46225b2c595 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nikola=20Perovi=C4=87?= <46610174+Fooftilly@users.noreply.github.com> Date: Tue, 29 Sep 2026 21:52:14 +0200 Subject: [PATCH 2/6] docs: update cache-validator guidance references --- frontend/js/app.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/frontend/js/app.js b/frontend/js/app.js index a654c36a..6ff29f85 100644 --- a/frontend/js/app.js +++ b/frontend/js/app.js @@ -2441,7 +2441,7 @@ const PRKS_FOLDERS_DOMAIN = 'folders'; * Work cards through prksWorkCardHtml() and the right-panel tag list. Backend * hierarchy rules (cycles, unique titles, count correctness) stay canonical -- * this only stops a malformed payload from being cached or rendered. See - * docs/agent-rules/offline-pwa.md, "Offline coherence domains". */ + * docs/agent-rules/offline-folder-tag-coherence.md. */ function prksIsFolderCount(value) { return typeof value === 'number' && Number.isFinite(value) && Number.isInteger(value) && value >= 0; } @@ -2529,8 +2529,7 @@ const PRKS_PLAYLISTS_DOMAIN = 'playlists'; * endpoint happens to join in. `renderPlaylistsIndex()` uses id/title/ * item_count; `renderPlaylistDetail()` and the right-panel editor use * id/title/description/original_url plus each item's id (-> #/works/:id), - * title, author_text and published_date. See docs/agent-rules/offline-pwa.md, - * "Offline coherence domains". */ + * title, author_text and published_date. See docs/agent-rules/offline-entity-coherence.md. */ function prksIsPlaylistItemCount(value) { return typeof value === 'number' && Number.isFinite(value) && value >= 0; } From 24baf9ed6cf83381942d79079e22eefd1791c9b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nikola=20Perovi=C4=87?= <46610174+Fooftilly@users.noreply.github.com> Date: Tue, 29 Sep 2026 21:52:18 +0200 Subject: [PATCH 3/6] docs: point browse projection comment at leaf rule --- backend/db_manager.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/backend/db_manager.py b/backend/db_manager.py index 4a7f53a9..06dad889 100644 --- a/backend/db_manager.py +++ b/backend/db_manager.py @@ -261,8 +261,7 @@ def _prks_merge_bibtex_export_fields_patch( # whole abstract, the bibliographic block (journal/volume/issue/pages/isbn/doi), # or the timestamps a card never shows. Carrying the full abstract measured at # ~59.5% of the /api/works payload while only #/progress reads it -- and only -# its first 100 characters. See docs/agent-rules/offline-pwa.md, -# "Offline browse catalogs". +# its first 100 characters. See docs/agent-rules/offline-browse-protocol.md. _PRKS_WORK_BROWSE_COLUMNS: Tuple[str, ...] = ( "id", "title", From c2476354907cc791b88721de4502352cb2b1d58b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nikola=20Perovi=C4=87?= <46610174+Fooftilly@users.noreply.github.com> Date: Tue, 29 Sep 2026 21:52:22 +0200 Subject: [PATCH 4/6] test: reject stale monolith guidance references --- tests/test_agent_guidance_current.py | 31 ++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/tests/test_agent_guidance_current.py b/tests/test_agent_guidance_current.py index 84a12bbb..be57d034 100644 --- a/tests/test_agent_guidance_current.py +++ b/tests/test_agent_guidance_current.py @@ -184,6 +184,37 @@ def test_relationship_removal_never_prunes_tag_identity(self): normalized_contract, ) + def test_source_comments_do_not_reference_removed_monolith_sections(self): + source_paths = ( + ROOT / "frontend" / "js" / "api.js", + ROOT / "frontend" / "js" / "app.js", + ROOT / "backend" / "db_manager.py", + ) + stale_references = ( + 'offline-pwa.md "Offline coherence domains"', + 'offline-pwa.md, "Offline coherence domains"', + 'offline-pwa.md,\n * "Offline coherence domains"', + 'offline-pwa.md,\n# "Offline browse catalogs"', + 'offline-pwa.md, "Offline browse catalogs"', + ) + for path in source_paths: + text = path.read_text(encoding="utf-8") + for phrase in stale_references: + with self.subTest(path=str(path.relative_to(ROOT)), phrase=phrase): + self.assertNotIn(phrase, text) + self.assertIn( + "docs/agent-rules/offline-entity-coherence.md", + (ROOT / "frontend" / "js" / "api.js").read_text(encoding="utf-8"), + ) + self.assertIn( + "docs/agent-rules/offline-folder-tag-coherence.md", + (ROOT / "frontend" / "js" / "app.js").read_text(encoding="utf-8"), + ) + self.assertIn( + "docs/agent-rules/offline-browse-protocol.md", + (ROOT / "backend" / "db_manager.py").read_text(encoding="utf-8"), + ) + def test_router_covers_remaining_durable_family_routes(self): sync_map = (ROOT / "docs" / "agent-context" / "sync-map.md").read_text(encoding="utf-8") router = self.offline_pwa From 14f2ed3cffc1f492cbd5e5d931d3f9470098cca4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nikola=20Perovi=C4=87?= <46610174+Fooftilly@users.noreply.github.com> Date: Tue, 29 Sep 2026 21:53:21 +0200 Subject: [PATCH 5/6] test: require source comments to use leaf guidance --- tests/test_agent_guidance_current.py | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/tests/test_agent_guidance_current.py b/tests/test_agent_guidance_current.py index be57d034..e50072b6 100644 --- a/tests/test_agent_guidance_current.py +++ b/tests/test_agent_guidance_current.py @@ -184,24 +184,21 @@ def test_relationship_removal_never_prunes_tag_identity(self): normalized_contract, ) - def test_source_comments_do_not_reference_removed_monolith_sections(self): + def test_source_comments_point_to_offline_leaf_rules_not_router(self): source_paths = ( ROOT / "frontend" / "js" / "api.js", ROOT / "frontend" / "js" / "app.js", ROOT / "backend" / "db_manager.py", ) - stale_references = ( - 'offline-pwa.md "Offline coherence domains"', - 'offline-pwa.md, "Offline coherence domains"', - 'offline-pwa.md,\n * "Offline coherence domains"', - 'offline-pwa.md,\n# "Offline browse catalogs"', - 'offline-pwa.md, "Offline browse catalogs"', - ) for path in source_paths: text = path.read_text(encoding="utf-8") - for phrase in stale_references: - with self.subTest(path=str(path.relative_to(ROOT)), phrase=phrase): - self.assertNotIn(phrase, text) + with self.subTest(path=str(path.relative_to(ROOT))): + self.assertNotIn( + "docs/agent-rules/offline-pwa.md", + text, + "domain-specific source comments should point to the owning " + "offline leaf, not the rule router", + ) self.assertIn( "docs/agent-rules/offline-entity-coherence.md", (ROOT / "frontend" / "js" / "api.js").read_text(encoding="utf-8"), From 2066b96bf2d3f76bf4aab0c23d2fb54d2587c053 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nikola=20Perovi=C4=87?= <46610174+Fooftilly@users.noreply.github.com> Date: Tue, 29 Sep 2026 22:06:57 +0200 Subject: [PATCH 6/6] test: bind each source comment to its guidance leaf --- tests/test_agent_guidance_current.py | 70 ++++++++++++++++++++-------- 1 file changed, 51 insertions(+), 19 deletions(-) diff --git a/tests/test_agent_guidance_current.py b/tests/test_agent_guidance_current.py index e50072b6..3a9cbb94 100644 --- a/tests/test_agent_guidance_current.py +++ b/tests/test_agent_guidance_current.py @@ -185,32 +185,64 @@ def test_relationship_removal_never_prunes_tag_identity(self): ) def test_source_comments_point_to_offline_leaf_rules_not_router(self): - source_paths = ( - ROOT / "frontend" / "js" / "api.js", - ROOT / "frontend" / "js" / "app.js", - ROOT / "backend" / "db_manager.py", - ) - for path in source_paths: - text = path.read_text(encoding="utf-8") - with self.subTest(path=str(path.relative_to(ROOT))): + api = (ROOT / "frontend" / "js" / "api.js").read_text(encoding="utf-8") + app = (ROOT / "frontend" / "js" / "app.js").read_text(encoding="utf-8") + db_manager = (ROOT / "backend" / "db_manager.py").read_text(encoding="utf-8") + + for path, text in ( + ("frontend/js/api.js", api), + ("frontend/js/app.js", app), + ("backend/db_manager.py", db_manager), + ): + with self.subTest(path=path): self.assertNotIn( "docs/agent-rules/offline-pwa.md", text, "domain-specific source comments should point to the owning " "offline leaf, not the rule router", ) - self.assertIn( - "docs/agent-rules/offline-entity-coherence.md", - (ROOT / "frontend" / "js" / "api.js").read_text(encoding="utf-8"), - ) - self.assertIn( - "docs/agent-rules/offline-folder-tag-coherence.md", - (ROOT / "frontend" / "js" / "app.js").read_text(encoding="utf-8"), - ) - self.assertIn( - "docs/agent-rules/offline-browse-protocol.md", - (ROOT / "backend" / "db_manager.py").read_text(encoding="utf-8"), + + expected_comment_mappings = ( + ( + "api Positions coherence", + api, + "Independent of the Concepts domain by construction -- see\n" + " * docs/agent-rules/offline-entity-coherence.md.", + ), + ( + "api browse projection coherence", + api, + "deleteList('works-browse:index') would have to be rewritten everywhere.\n" + " * See docs/agent-rules/offline-browse-protocol.md.", + ), + ( + "api Folder coherence", + api, + "A cached Folder detail also embeds whole Work cards, so Work display changes\n" + " * stale it too -- see docs/agent-rules/offline-folder-tag-coherence.md.", + ), + ( + "app Folder validator", + app, + "this only stops a malformed payload from being cached or rendered. See\n" + " * docs/agent-rules/offline-folder-tag-coherence.md.", + ), + ( + "app Playlist validator", + app, + "title, author_text and published_date. See " + "docs/agent-rules/offline-entity-coherence.md.", + ), + ( + "backend browse projection", + db_manager, + "its first 100 characters. See " + "docs/agent-rules/offline-browse-protocol.md.", + ), ) + for label, text, expected in expected_comment_mappings: + with self.subTest(comment=label): + self.assertIn(expected, text) def test_router_covers_remaining_durable_family_routes(self): sync_map = (ROOT / "docs" / "agent-context" / "sync-map.md").read_text(encoding="utf-8")