Owner-only admin page: Reader roster plus Poll Lane status (#102) (#107)

Closes #102.

The only operational surface was /healthz and a fold-out roster inside the owner's own reading page. This adds /admin: an owner-only page carrying the Reader roster and one row per Poll Lane.

- **Poller seam.** `latest.Poller` records each Lane's last pass (`Site`, `Due`, `Checked`, `LastRun`, `Gap`, `Clamped`, `Browser`) and answers `LaneStatus()`; the page reads that snapshot, never a table. A pass that returns before computing its figures (refusal backoff, sidecar down) carries the previous pass's figures forward rather than recording zeroes, and a Lane that has never reached a pace renders no gap at all. Refusal and sidecar reachability are derived at snapshot time.
- **Owner gate at registration.** Every route reaching past the acting Reader lives in `adminRoutes()` and is wrapped in `requireOwner` when it is registered, so a missing gate is visible in the route list rather than hidden in a handler. `web.AdminPatterns()` is what the gate test walks, so a new route cannot be added without being tested. A non-owner gets 404, never 403.
- **Nil poller is a first-class state.** `main.newRouter` takes the reporter as an interface and converts a nil `*Poller` to a nil interface; no poller and no completed pass both render "No data yet" with the reason spelled out, rather than confident zeroes.
- **Roster moved** off the reading page onto /admin, with the Sighting counters and a confirm-gated `Clear marks` control. #103 fills those counters, so on delivery they read zero for everyone - deliberate ordering.
- **One accent, `--patina`** (verdigris, both colour branches): the far side of the wheel from ember's crimson and clear of the archive blue. Ember still means new chapter only; revocation still wears --danger.

Verification: `go vet ./...` and `go test ./...` green (Docker-backed); admin page screenshotted at 1100px and 390px in both colour schemes. Reviewed on both axes (spec, standards); findings on the accent hue, zero-figure honesty and three tests that could not fail are fixed in 58014eb.
Reviewed-on: #107
Co-authored-by: Sulthan Zaki <sultankiki05@gmail.com>
Co-committed-by: Sulthan Zaki <sultankiki05@gmail.com>
This commit was merged in pull request #107.
This commit is contained in:
2026-08-16 15:02:13 +07:00
committed by sulthan
parent 3303a55b20
commit 1e6f1e985d
25 changed files with 3822 additions and 1733 deletions
+1 -4
View File
@@ -151,6 +151,7 @@
"150": "Reviewer Subagent (opencode)",
"151": "Finding Severity Rubric",
"152": "Spec Compliance Review",
"156": "ResponseWriter",
"161": "Why Use samber/oops",
"162": "singleflight Cache Stampede Prevention",
"163": "Struct Field Alignment",
@@ -205,10 +206,6 @@
"245": "wayfinder map/ticket mechanism",
"246": "Triage labels: canonical roles to tracker labels",
"247": "Canonical triage role labels (needs-triage ... wontfix)",
"248": "Cinder (BookmarkManager Web UI design system)",
"249": "Heat is typographic: ember reserved for unread chapters",
"250": "Design tokens (dark + light branches, no hardcoded hex)",
"251": "Three type roles: display serif / mono small-caps / sans",
"252": "a[aria-label='All Chapter'] priority pointer",
"253": "Research: lightnovelworld chapter slug vs series slug",
"254": "Gitea issue #77 (chapter vs series slug)",
+51 -52
View File
@@ -1,16 +1,16 @@
# Graph Report - mangaBookmark (2026-08-16)
## Corpus Check
- 113 files · ~279,161 words
- 116 files · ~284,419 words
- Verdict: corpus is large enough that graph structure adds value.
## Summary
- 1668 nodes · 3379 edges · 222 communities (68 shown, 154 thin omitted)
- Extraction: 91% EXTRACTED · 9% INFERRED · 0% AMBIGUOUS · INFERRED: 320 edges (avg confidence: 0.77)
- 1701 nodes · 3463 edges · 219 communities (69 shown, 150 thin omitted)
- Extraction: 91% EXTRACTED · 9% INFERRED · 0% AMBIGUOUS · INFERRED: 326 edges (avg confidence: 0.77)
- Token cost: 0 input · 0 output
## Graph Freshness
- Built from commit: `4f1cbcfd`
- Built from commit: `58014eb8`
- Run `git rev-parse HEAD` and compare to check if the graph is stale.
- Run `graphify update .` after code changes (no API cost).
@@ -45,8 +45,8 @@
- [[_COMMUNITY_Find Skills Guide|Find Skills Guide]]
- [[_COMMUNITY_Allocation Patterns|Allocation Patterns]]
- [[_COMMUNITY_Observability & Alerting|Observability & Alerting]]
- [[_COMMUNITY_AGENTS|AGENTS.md]]
- [[_COMMUNITY_Store|Store]]
- [[_COMMUNITY_Open|Open]]
- [[_COMMUNITY_Go Testing Guide|Go Testing Guide]]
- [[_COMMUNITY_Session Store|Session Store]]
- [[_COMMUNITY_Web UI Filter Logic|Web UI Filter Logic]]
@@ -166,6 +166,7 @@
- [[_COMMUNITY_Reviewer Subagent (opencode)|Reviewer Subagent (opencode)]]
- [[_COMMUNITY_Finding Severity Rubric|Finding Severity Rubric]]
- [[_COMMUNITY_Spec Compliance Review|Spec Compliance Review]]
- [[_COMMUNITY_ResponseWriter|ResponseWriter]]
- [[_COMMUNITY_Why Use samberoops|Why Use samber/oops]]
- [[_COMMUNITY_singleflight Cache Stampede Prevention|singleflight Cache Stampede Prevention]]
- [[_COMMUNITY_Struct Field Alignment|Struct Field Alignment]]
@@ -220,10 +221,6 @@
- [[_COMMUNITY_wayfinder mapticket mechanism|wayfinder map/ticket mechanism]]
- [[_COMMUNITY_Triage labels canonical roles to tracker labels|Triage labels: canonical roles to tracker labels]]
- [[_COMMUNITY_Canonical triage role labels (needs-triage ... wontfix)|Canonical triage role labels (needs-triage ... wontfix)]]
- [[_COMMUNITY_Cinder (BookmarkManager Web UI design system)|Cinder (BookmarkManager Web UI design system)]]
- [[_COMMUNITY_Heat is typographic ember reserved for unread chapters|Heat is typographic: ember reserved for unread chapters]]
- [[_COMMUNITY_Design tokens (dark + light branches, no hardcoded hex)|Design tokens (dark + light branches, no hardcoded hex)]]
- [[_COMMUNITY_Three type roles display serif mono small-caps sans|Three type roles: display serif / mono small-caps / sans]]
- [[_COMMUNITY_aaria-label='All Chapter' priority pointer|a[aria-label='All Chapter'] priority pointer]]
- [[_COMMUNITY_Research lightnovelworld chapter slug vs series slug|Research: lightnovelworld chapter slug vs series slug]]
- [[_COMMUNITY_Gitea issue 77 (chapter vs series slug)|Gitea issue #77 (chapter vs series slug)]]
@@ -238,16 +235,16 @@
- [[_COMMUNITY_Userscript CLAUDE guidance|Userscript CLAUDE guidance]]
## God Nodes (most connected - your core abstractions)
1. `testConfig()` - 53 edges
2. `newWebTestServer()` - 49 edges
3. `newTestStore()` - 48 edges
4. `newTestStore()` - 43 edges
1. `testConfig()` - 54 edges
2. `newTestStore()` - 49 edges
3. `newWebTestServer()` - 49 edges
4. `newTestStore()` - 44 edges
5. `e()` - 33 edges
6. `Open()` - 29 edges
6. `Open()` - 30 edges
7. `Handler` - 29 edges
8. `ne()` - 28 edges
9. `De()` - 28 edges
10. `Store` - 27 edges
8. `Store` - 28 edges
9. `ne()` - 28 edges
10. `De()` - 28 edges
## Surprising Connections (you probably didn't know these)
- `el()` --indirect_call--> `c()` [INFERRED]
@@ -267,21 +264,19 @@
## Hyperedges (group relationships)
- **Batch Ticket Implementation Pipeline** — _claude_skills_implement_tickets_skill_implement_tickets, _omp_agents_ticket_implementer_ticket_implementer, _omp_agents_ticket_implementer_cr_spec, _omp_agents_ticket_implementer_cr_standards [INFERRED 0.85]
- **Subagent-Driven Development Pipeline** — _opencode_agent_implementer_implementer, _opencode_agent_reviewer_reviewer, _opencode_agent_implementer_subagent_driven_development [INFERRED 0.85]
- **Go HTML Template Family** — backend_internal_web_templates_app_doc, backend_internal_web_templates_card_doc, backend_internal_web_templates_list_doc, backend_internal_web_templates_chrome_doc, backend_internal_web_templates_login_doc, backend_internal_web_templates_setup_doc, backend_internal_web_templates_readers_doc, backend_internal_web_templates_icons_doc [INFERRED 0.95]
- **htmx Fragment Swap Flow** — backend_internal_web_templates_app_doc, backend_internal_web_templates_card_doc, backend_internal_web_templates_chrome_doc, backend_internal_web_templates_setup_doc, backend_internal_web_templates_readers_doc [INFERRED 0.95]
- **Backend owns the truth (single-writer ownership of shared facts)** — docs_adr_0003_series_shared_and_poll_owned_poll_owned_writes, docs_adr_0004_wire_format_does_not_mirror_the_schema_flat_wire_contract, docs_adr_0007_backend_hosts_cover_bytes_server_side_covers [INFERRED 0.85]
- **Headless browser infrastructure (sidecar, on-demand, home deployment)** — docs_adr_0005_on_demand_browser_headless_shell, docs_adr_0005_on_demand_browser_cdp, docs_adr_0005_on_demand_browser_on_demand_start, docs_adr_0006_browser_on_the_home_machine_home_machine_rationale [INFERRED 0.85]
- **lightnovelworld series-identity investigation and fix** — docs_research_lightnovelworld_chapter_vs_series_slug_issue_77, docs_research_lightnovelworld_chapter_vs_series_slug_unscoped_regex, docs_adr_0008_series_identity_is_discovered_not_derived_discovered_identity [INFERRED 0.85]
## Communities (222 total, 154 thin omitted)
## Communities (219 total, 150 thin omitted)
### Community 0 - "HTMX Library Internals"
Cohesion: 0.08
Nodes (101): A(), ae(), an(), at(), B(), be(), bn(), bt() (+93 more)
### Community 1 - "Cover Fetch Test Helpers"
Cohesion: 0.10
Nodes (84): floatPtr(), testConfig(), getCover(), Cookie, Handler, ResponseRecorder, T, TestListRendersAcquiredCover() (+76 more)
Cohesion: 0.09
Nodes (89): floatPtr(), testConfig(), getCover(), Cookie, Handler, ResponseRecorder, T, TestListRendersAcquiredCover() (+81 more)
### Community 2 - "Manga Userscript Adapters"
Cohesion: 0.06
@@ -296,16 +291,16 @@ Cohesion: 0.08
Nodes (78): bookmarkNewKaganeSeries(), bookmarkNewNovelfullSeries(), bookmarkNewSeries(), Context, Store, T, newAcquirer(), readBookmark() (+70 more)
### Community 5 - "Bookmarks API Tests"
Cohesion: 0.06
Nodes (74): auth(), getBookmarks(), Handler, Request, Store, T, newTestServer(), newTestStore() (+66 more)
Cohesion: 0.07
Nodes (70): auth(), getBookmarks(), Handler, Request, Store, T, newTestServer(), newTestStore() (+62 more)
### Community 7 - "Cover & Acquire Internals"
Cohesion: 0.08
Nodes (37): Addr, Context, Store, WaitGroup, isInterstitial(), defaultCoverResolver(), fetchCoverBytes(), Client (+29 more)
Cohesion: 0.07
Nodes (43): Addr, fakeLanes, Context, Store, WaitGroup, defaultCoverResolver(), fetchCoverBytes(), Client (+35 more)
### Community 8 - "System Architecture Concepts"
Cohesion: 0.13
Nodes (20): app.html — App Shell Template, Manga/Novel Library Switch, Bookmark Bucket Tabs, Confirm Row (Archive/Finish/Remove), card.html — Series Card Template, htmx /ui/* Mutation Endpoints, chrome.html — Out-of-Band Regions, Action Key (+12 more)
Cohesion: 0.15
Nodes (15): Confirm Row (Archive/Finish/Remove), card.html — Series Card Template, htmx /ui/* Mutation Endpoints, chrome.html — Out-of-Band Regions, Action Key, Brand Mark SVG, Continue Reading Strip, icons.html — Icon Sprite Template (+7 more)
### Community 9 - "Session Middleware"
Cohesion: 0.08
@@ -317,7 +312,7 @@ Nodes (39): Test Helpers, Test Timeout, Basic Handler Test, HTTP Handler Testing
### Community 11 - "Store Tests"
Cohesion: 0.14
Nodes (45): scanSeries(), Store, T, newTestStore(), readLatestCheckedAt(), readSeries(), secondReader(), seedForCheck() (+37 more)
Nodes (45): Store, T, newTestStore(), readLatestCheckedAt(), readSeries(), secondReader(), seedForCheck(), seedSecondReader() (+37 more)
### Community 12 - "Bookmarks API Handler"
Cohesion: 0.08
@@ -332,8 +327,8 @@ Cohesion: 0.06
Nodes (33): Creating Errors, Custom Error Types, Custom types that wrap other errors, Decision table: which error strategy to use, Error Creation, Error String Conventions, Errors as Values, `errors.New` — static error messages (+25 more)
### Community 15 - "CDP Browser Client"
Cohesion: 0.06
Nodes (56): awaitPromise(), browserConnectionLost(), classifyBrowserError(), comixRead(), comixSeriesPageURL(), Action, Context, Mutex (+48 more)
Cohesion: 0.20
Nodes (17): applyMigration(), migrate(), Open(), refreshOwnerToken(), seedOwner(), TestCoverIsContentAddressedOnFilesystem(), TestCoverPersistsAcrossReopen(), TestMigration0002BackfillsExistingBookmarks() (+9 more)
### Community 16 - "Cloudflare bot scoring and poll cadence — what is actually documented"
Cohesion: 0.06
@@ -372,8 +367,8 @@ Cohesion: 0.33
Nodes (12): coverResponse(), Request, T, TestCoverFetcherCanonicalisesJpgAlias(), TestCoverFetcherFetchesPublicHTTPSImage(), TestCoverFetcherRefusesUnsafeDestinationsBeforeRequest(), TestCoverFetcherRejectsNonImage(), TestCoverFetcherRejectsOversizedBody() (+4 more)
### Community 26 - "Open"
Cohesion: 0.40
Nodes (5): Map of pointers for large, frequently updated structs, Memory Layout, Pointer receivers for large structs, Struct field alignment, Zero-size field at end of struct
Cohesion: 0.05
Nodes (62): awaitPromise(), browserConnectionLost(), classifyBrowserError(), comixRead(), comixSeriesPageURL(), Action, Context, Mutex (+54 more)
### Community 27 - "Find Skills Guide"
Cohesion: 0.14
@@ -387,13 +382,13 @@ Nodes (14): Allocation Patterns, Backing Array Leaks, Direct indexing vs append,
Cohesion: 0.22
Nodes (9): Alerting rules (examples), CPU saturation, GC pressure, Goroutine leaks, Grafana Dashboards, Memory leaks, Prometheus Metrics for Go, PromQL Queries for Performance Diagnosis (+1 more)
### Community 31 - "Store"
Cohesion: 0.12
Nodes (3): coverRelativePath(), coverSourceAddress(), Store
### Community 30 - "AGENTS.md"
Cohesion: 0.40
Nodes (5): Map of pointers for large, frequently updated structs, Memory Layout, Pointer receivers for large structs, Struct field alignment, Zero-size field at end of struct
### Community 32 - "Open"
Cohesion: 0.14
Nodes (20): applyMigration(), displayChapter(), migrate(), Open(), refreshOwnerToken(), seedOwner(), TestCoverIsContentAddressedOnFilesystem(), TestCoverPersistsAcrossReopen() (+12 more)
### Community 31 - "Store"
Cohesion: 0.08
Nodes (8): coverRelativePath(), coverSourceAddress(), displayChapter(), Store, scanSeries(), TestDisplayChapter(), Bookmark, ReaderSummary
### Community 33 - "Go Testing Guide"
Cohesion: 0.20
@@ -539,29 +534,33 @@ Nodes (3): ADR-0005: On-demand browser sidecar, Constraints, Decision
Cohesion: 0.48
Nodes (6): T, TestCreateAndGetSession(), TestDeleteSessionIsPerReader(), TestDeleteSessionRevokes(), TestExpiredSessionIsGone(), TestGetSessionUnknownID()
### Community 156 - "ResponseWriter"
Cohesion: 0.18
Nodes (13): AdminPatterns(), HandlerFunc, Request, ResponseWriter, Time, Handler, readerPathID(), since() (+5 more)
### Community 273 - "AGENTS.md"
Cohesion: 0.50
Nodes (3): Live URL shapes (verified 2026-07-26, may drift — re-check against live pages before trust), Second script: `novel-bookmark.user.js`, Userscript structure (single IIFE, `manga-bookmark.user.js`)
## Knowledge Gaps
- **524 isolated node(s):** `bookmarkmanager/backend`, `ctxKey`, `loginView`, `ctxKey`, `test` (+519 more)
- **520 isolated node(s):** `bookmarkmanager/backend`, `ctxKey`, `loginView`, `ctxKey`, `test` (+515 more)
These have ≤1 connection - possible missing edges or undocumented components.
- **154 thin communities (<3 nodes) omitted from report** — run `graphify query` to explore isolated nodes.
- **150 thin communities (<3 nodes) omitted from report** — run `graphify query` to explore isolated nodes.
## Suggested Questions
_Questions this graph is uniquely positioned to answer:_
- **Why does `New()` connect `Series Acquisition Tests` to `Open`, `Bookmarks API Tests`, `Cover & Acquire Internals`, `Session Middleware`, `Web UI Handlers`?**
_High betweenness centrality (0.045) - this node is a cross-community bridge._
- **Why does `Open()` connect `Open` to `Cover Fetch Test Helpers`, `Series Acquisition Tests`, `Bookmarks API Tests`, `pgtest.go`, `Store Tests`, `Store`?**
_High betweenness centrality (0.033) - this node is a cross-community bridge._
- **Why does `newRouter()` connect `Bookmarks API Tests` to `Cover Fetch Test Helpers`, `Bookmarks API Handler`, `Series Acquisition Tests`?**
_High betweenness centrality (0.027) - this node is a cross-community bridge._
- **Are the 47 inferred relationships involving `testConfig()` (e.g. with `TestListRendersAcquiredCover()` and `TestPublicCoverNeverEchoesNonImage()`) actually correct?**
_`testConfig()` has 47 INFERRED edges - model-reasoned connections that need verification._
- **Are the 8 inferred relationships involving `newWebTestServer()` (e.g. with `TestListRendersAcquiredCover()` and `TestPublicCoverRejectsUnknownAddress()`) actually correct?**
_`newWebTestServer()` has 8 INFERRED edges - model-reasoned connections that need verification._
- **Why does `Open()` connect `CDP Browser Client` to `Cover Fetch Test Helpers`, `Series Acquisition Tests`, `Bookmarks API Tests`, `pgtest.go`, `Store Tests`, `Store`?**
_High betweenness centrality (0.050) - this node is a cross-community bridge._
- **Why does `New()` connect `Series Acquisition Tests` to `Bookmarks API Tests`, `Cover & Acquire Internals`, `Session Middleware`, `Web UI Handlers`, `CDP Browser Client`, `ResponseWriter`?**
_High betweenness centrality (0.048) - this node is a cross-community bridge._
- **Why does `newRouter()` connect `Bookmarks API Tests` to `Cover Fetch Test Helpers`, `Bookmarks API Handler`, `Series Acquisition Tests`, `ResponseWriter`?**
_High betweenness centrality (0.031) - this node is a cross-community bridge._
- **Are the 48 inferred relationships involving `testConfig()` (e.g. with `TestListRendersAcquiredCover()` and `TestPublicCoverNeverEchoesNonImage()`) actually correct?**
_`testConfig()` has 48 INFERRED edges - model-reasoned connections that need verification._
- **Are the 12 inferred relationships involving `newTestStore()` (e.g. with `TestAcquireDoesNotBlockTheWrite()` and `TestAcquireFailureLeavesTheBookmarkIntact()`) actually correct?**
_`newTestStore()` has 12 INFERRED edges - model-reasoned connections that need verification._
- **Are the 8 inferred relationships involving `newWebTestServer()` (e.g. with `TestListRendersAcquiredCover()` and `TestPublicCoverRejectsUnknownAddress()`) actually correct?**
_`newWebTestServer()` has 8 INFERRED edges - model-reasoned connections that need verification._
- **What connects `bookmarkmanager/backend`, `ctxKey`, `loginView` to the rest of the system?**
_557 weakly-connected nodes found - possible documentation gaps or missing edges._
_552 weakly-connected nodes found - possible documentation gaps or missing edges._
File diff suppressed because one or more lines are too long
+2637 -1496
View File
File diff suppressed because it is too large Load Diff
+72 -47
View File
@@ -25,8 +25,8 @@
"semantic_hash": "dac242903b0e98c3e4395159d609e08e"
},
"backend/main.go": {
"mtime": 1786859325.126449,
"ast_hash": "4ad77c286522f97d14b6009ff37118e5",
"mtime": 1786863963.3450089,
"ast_hash": "d5a50b03438d7c120079d40cc578462b",
"semantic_hash": ""
},
"skills-lock.json": {
@@ -145,12 +145,12 @@
"semantic_hash": ""
},
"DEPLOY.md": {
"mtime": 1786859620.9977603,
"mtime": 1786861012.026504,
"ast_hash": "b7c2f813aded562ee9291c9baed795ad",
"semantic_hash": ""
},
"README.md": {
"mtime": 1786859273.3238454,
"mtime": 1786861012.026504,
"ast_hash": "81af12a0a2d43e791efd030b5f4d6cbc",
"semantic_hash": ""
},
@@ -160,7 +160,7 @@
"semantic_hash": "0751998a532297b8ac507a01ec48dc31"
},
"docker-compose.yml": {
"mtime": 1786859258.6255276,
"mtime": 1786861012.026504,
"ast_hash": "d3b53a8f42a8e0acb4fc4306ea42c093",
"semantic_hash": ""
},
@@ -170,12 +170,12 @@
"semantic_hash": "e51077b6a7f1f67afc748f1a32a1557d"
},
"backend/web_test.go": {
"mtime": 1786216141.700644,
"ast_hash": "8f1b093b59eb1ed81bc7fc0c22495c50",
"semantic_hash": "8f1b093b59eb1ed81bc7fc0c22495c50"
"mtime": 1786865248.7717106,
"ast_hash": "7c298e39c63e4502cf6272d1e206e9ef",
"semantic_hash": ""
},
"backend/main_test.go": {
"mtime": 1786859172.6449091,
"mtime": 1786863966.7091317,
"ast_hash": "0a5d4dbdc770b40c329ccccc899b59f4",
"semantic_hash": ""
},
@@ -220,19 +220,19 @@
"semantic_hash": ""
},
"docs/design-system.md": {
"mtime": 1786022513.9623306,
"ast_hash": "421cd7e57f02d4b467f120ca6ddd7b6a",
"semantic_hash": "421cd7e57f02d4b467f120ca6ddd7b6a"
"mtime": 1786865139.9022946,
"ast_hash": "3bd39932997c8e245508874194db4e49",
"semantic_hash": ""
},
"backend/api_test.go": {
"mtime": 1786499529.7651505,
"ast_hash": "8e4b9293bc2e45ee3f42027315594fd5",
"mtime": 1786863966.7056258,
"ast_hash": "0d443b4fe3c04ab057505d73b8a88d07",
"semantic_hash": ""
},
"backend/cover_test.go": {
"mtime": 1786363889.552731,
"ast_hash": "c7e313d6c92eb28e6d370e5e89035984",
"semantic_hash": "c7e313d6c92eb28e6d370e5e89035984"
"mtime": 1786863966.7084978,
"ast_hash": "fd6b3f6ef46bd17b0241d104b6e5bdf6",
"semantic_hash": ""
},
"backend/internal/api/handlers.go": {
"mtime": 1786363889.552731,
@@ -245,7 +245,7 @@
"semantic_hash": "385b36f58488b7e6d93eb6d6034e9ee3"
},
"backend/internal/latest/browser.go": {
"mtime": 1786859355.8677974,
"mtime": 1786861012.026504,
"ast_hash": "75f34a974568d122681939dd297944a2",
"semantic_hash": ""
},
@@ -260,17 +260,17 @@
"semantic_hash": ""
},
"backend/internal/latest/poller.go": {
"mtime": 1786860083.6713927,
"ast_hash": "be728405cde3df49baf72bd7837f2971",
"mtime": 1786865046.096795,
"ast_hash": "2bfb51177e3df474b80ea1b05523377e",
"semantic_hash": ""
},
"backend/internal/latest/poller_test.go": {
"mtime": 1786860168.103984,
"ast_hash": "5dba515d28c0523500c1ceb581a54e58",
"mtime": 1786865291.3758123,
"ast_hash": "1da669ac748a8d1a0289e557392fa3fd",
"semantic_hash": ""
},
"backend/internal/latest/sites.go": {
"mtime": 1786860007.8224697,
"mtime": 1786861012.026504,
"ast_hash": "9b90f9b710ccbd0d0a0a6a0dd721ff3c",
"semantic_hash": ""
},
@@ -340,13 +340,13 @@
"semantic_hash": "0b6764a0ee20f5cb7748eecd31a1d220"
},
"backend/internal/store/store.go": {
"mtime": 1786860012.3431706,
"ast_hash": "c62e73142386c58ab833d404d0c24dc4",
"mtime": 1786863704.5112119,
"ast_hash": "989629af18232e35b12f1eef2a8cb422",
"semantic_hash": ""
},
"backend/internal/store/store_test.go": {
"mtime": 1786858248.9426548,
"ast_hash": "039729554517960d1ae98f8409baf4ba",
"mtime": 1786863712.075631,
"ast_hash": "e48f21e34238ba46874cc88cf96e022f",
"semantic_hash": ""
},
"backend/internal/userscript/userscript.go": {
@@ -380,14 +380,14 @@
"semantic_hash": "19a573773be4ca22570ca2f8543120c5"
},
"backend/internal/web/web.go": {
"mtime": 1786363889.5678573,
"ast_hash": "8308949c658d3a08ce1c3cdbea6a907c",
"semantic_hash": "8308949c658d3a08ce1c3cdbea6a907c"
"mtime": 1786863744.1453943,
"ast_hash": "b051f2de214c4b253ee09fbbdb8ebb60",
"semantic_hash": ""
},
"backend/reader_credential_test.go": {
"mtime": 1786216141.700644,
"ast_hash": "2a751ea6d9c06635aa3179db0aef1b2b",
"semantic_hash": "2a751ea6d9c06635aa3179db0aef1b2b"
"mtime": 1786863966.7092986,
"ast_hash": "0c93de387af595901c43b6bdb3bed8cc",
"semantic_hash": ""
},
"chrome/entrypoint.sh": {
"mtime": 1786363889.5678573,
@@ -415,7 +415,7 @@
"semantic_hash": "e44a2f6f624db044e19508bc5ab05592"
},
"CONTEXT.md": {
"mtime": 1786859395.4497814,
"mtime": 1786861012.022683,
"ast_hash": "4aafbce0b046e6e34734fb414df818ce",
"semantic_hash": ""
},
@@ -425,19 +425,19 @@
"semantic_hash": "6c6f3e4c4c2f57867894280bce728c50"
},
"backend/AGENTS.md": {
"mtime": 1786860230.7890837,
"ast_hash": "7ceec7c4576f6e91eaf02c200a0dd1b3",
"mtime": 1786865319.314815,
"ast_hash": "5bbabcd7dd425302cb0d989d8897baf6",
"semantic_hash": ""
},
"backend/CLAUDE.md": {
"mtime": 1786860230.7890837,
"ast_hash": "7ceec7c4576f6e91eaf02c200a0dd1b3",
"mtime": 1786865319.314815,
"ast_hash": "5bbabcd7dd425302cb0d989d8897baf6",
"semantic_hash": ""
},
"backend/internal/web/templates/app.html": {
"mtime": 1786216141.692644,
"ast_hash": "3965e20e204afb71ba2a3aa86cb7c61c",
"semantic_hash": "3965e20e204afb71ba2a3aa86cb7c61c"
"mtime": 1786864445.1584811,
"ast_hash": "99d3e1139042d0eb61627155dddb3843",
"semantic_hash": ""
},
"backend/internal/web/templates/card.html": {
"mtime": 1786363889.5678573,
@@ -465,9 +465,9 @@
"semantic_hash": "bcc3101498a66cf8b79f9d97c6c9cd6b"
},
"backend/internal/web/templates/readers.html": {
"mtime": 1786216141.696644,
"ast_hash": "c5034e76bd20a705d2799cb5ecb328f0",
"semantic_hash": "c5034e76bd20a705d2799cb5ecb328f0"
"mtime": 1786864296.770521,
"ast_hash": "2b1cbb24d6185e48561966db1af04ba4",
"semantic_hash": ""
},
"backend/internal/web/templates/setup.html": {
"mtime": 1786216141.696644,
@@ -570,7 +570,7 @@
"semantic_hash": "60d9eb7c59a3751baf4f31c7655217e7"
},
"backend/internal/latest/acquire.go": {
"mtime": 1786859346.3297389,
"mtime": 1786861012.026504,
"ast_hash": "d605e3c94a62fc7787efbc139696b9d2",
"semantic_hash": ""
},
@@ -615,7 +615,7 @@
"semantic_hash": ""
},
"backend/internal/latest/read.go": {
"mtime": 1786859355.8679621,
"mtime": 1786861012.026504,
"ast_hash": "9f039cc3ad74f803d7621f7ef4157bf2",
"semantic_hash": ""
},
@@ -630,8 +630,33 @@
"semantic_hash": ""
},
"docs/adr/0010-poll-lanes-per-site-pace.md": {
"mtime": 1786860214.4637265,
"mtime": 1786861012.026504,
"ast_hash": "dc19d75f034ca920d93b9c71e6ca28e6",
"semantic_hash": ""
},
"backend/internal/latest/status.go": {
"mtime": 1786865033.5648637,
"ast_hash": "8141514efa5a7a66e77b9a62d4982d52",
"semantic_hash": ""
},
"backend/internal/store/migrations/0010_reader_sightings.sql": {
"mtime": 1786863695.6957178,
"ast_hash": "a72c08c63fad530df3c793d16edfa385",
"semantic_hash": ""
},
"backend/internal/web/admin.go": {
"mtime": 1786865087.473256,
"ast_hash": "b1c0f23a102a9bc7f84adf306d743f56",
"semantic_hash": ""
},
"backend/internal/web/templates/admin.html": {
"mtime": 1786865108.4095602,
"ast_hash": "f04ea1cb01369d53053eac489e796faa",
"semantic_hash": ""
},
"backend/internal/web/templates/lanes.html": {
"mtime": 1786865113.5362902,
"ast_hash": "8b9f9c7a56e0ec3bf950aa70acd95e92",
"semantic_hash": ""
}
}