fix: an asleep browser Lane is not a stalled one on the admin page (#110)
Co-authored-by: Sulthan Zaki <sultankiki05@gmail.com> Co-committed-by: Sulthan Zaki <sultankiki05@gmail.com>
This commit was merged in pull request #110.
This commit is contained in:
@@ -266,3 +266,9 @@ Guidance for OpenCode (and Claude Code) working under `backend/`. See root `AGEN
|
|||||||
than recording zeroes; a Lane that has never reached a pace renders no gap at
|
than recording zeroes; a Lane that has never reached a pace renders no gap at
|
||||||
all. `Checked` next to `Due` is what separates a stopped Lane from a quiet
|
all. `Checked` next to `Due` is what separates a stopped Lane from a quiet
|
||||||
one, so neither figure may be dropped from the row.
|
one, so neither figure may be dropped from the row.
|
||||||
|
Due-without-Checked is *not* by itself a stall: a browser Lane under both
|
||||||
|
wake thresholds sets `LaneState.Asleep` at the on-demand gate and renders
|
||||||
|
"browser asleep" instead of "not checking", and never counts toward
|
||||||
|
`Attention`. That is the commonest healthy state for kagane, comix and
|
||||||
|
novelfull — one due Series, nothing checked — so spending the stall mark on
|
||||||
|
it would train the owner to ignore the mark that matters.
|
||||||
|
|||||||
@@ -263,7 +263,7 @@ func (p *Poller) runLanePass(ctx context.Context, name string, paced bool) time.
|
|||||||
// browser): waking it for a single Poll would cost a challenge solve
|
// browser): waking it for a single Poll would cost a challenge solve
|
||||||
// per request. The Lane still paces at the default gap, which is what
|
// per request. The Lane still paces at the default gap, which is what
|
||||||
// the owner's page must show rather than a zero.
|
// the owner's page must show rather than a zero.
|
||||||
st.Gap = defaultGap
|
st.Gap, st.Asleep = defaultGap, true
|
||||||
return defaultGap
|
return defaultGap
|
||||||
}
|
}
|
||||||
if s.Browser != nil {
|
if s.Browser != nil {
|
||||||
|
|||||||
@@ -1388,6 +1388,11 @@ func TestBrowserLaneWakeThresholds(t *testing.T) {
|
|||||||
if got := browser.callCount(); got != 0 {
|
if got := browser.callCount(); got != 0 {
|
||||||
t.Fatalf("browser fetches with 3 freshly-due series = %d, want 0 (Chrome stays asleep)", got)
|
t.Fatalf("browser fetches with 3 freshly-due series = %d, want 0 (Chrome stays asleep)", got)
|
||||||
}
|
}
|
||||||
|
// The owner's page reads this state off the snapshot, and Due-without-
|
||||||
|
// Checked has to be distinguishable there from a Lane that has stopped.
|
||||||
|
if lane := laneByName(t, p, "kagane"); !lane.Asleep || lane.Due != 3 || lane.Checked != 0 {
|
||||||
|
t.Fatalf("asleep kagane lane = %+v, want Asleep with 3 due and 0 checked", lane)
|
||||||
|
}
|
||||||
// 5 due crosses the count threshold.
|
// 5 due crosses the count threshold.
|
||||||
for i := 3; i < 5; i++ {
|
for i := 3; i < 5; i++ {
|
||||||
seed(i)
|
seed(i)
|
||||||
@@ -1396,6 +1401,9 @@ func TestBrowserLaneWakeThresholds(t *testing.T) {
|
|||||||
if got := browser.callCount(); got != 5 {
|
if got := browser.callCount(); got != 5 {
|
||||||
t.Fatalf("browser fetches with 5 due series = %d, want 5", got)
|
t.Fatalf("browser fetches with 5 due series = %d, want 5", got)
|
||||||
}
|
}
|
||||||
|
if lane := laneByName(t, p, "kagane"); lane.Asleep {
|
||||||
|
t.Fatalf("woken kagane lane still reports Asleep: %+v", lane)
|
||||||
|
}
|
||||||
// A single long-neglected series wakes the browser by age alone.
|
// A single long-neglected series wakes the browser by age alone.
|
||||||
seedForCheck(t, s, "kagane:ancient", "https://kagane.to/series/ancient", 0)
|
seedForCheck(t, s, "kagane:ancient", "https://kagane.to/series/ancient", 0)
|
||||||
p.runOnce(context.Background())
|
p.runOnce(context.Background())
|
||||||
@@ -1404,6 +1412,19 @@ func TestBrowserLaneWakeThresholds(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// laneByName pulls one Lane out of the poller's snapshot, failing rather than
|
||||||
|
// returning a zero LaneState a caller would assert against by accident.
|
||||||
|
func laneByName(t *testing.T, p *Poller, site string) LaneState {
|
||||||
|
t.Helper()
|
||||||
|
for _, lane := range p.LaneStatus().Lanes {
|
||||||
|
if lane.Site == site {
|
||||||
|
return lane
|
||||||
|
}
|
||||||
|
}
|
||||||
|
t.Fatalf("no %q lane in the snapshot", site)
|
||||||
|
return LaneState{}
|
||||||
|
}
|
||||||
|
|
||||||
// When one browser Lane loses the sidecar, the round's remaining browser
|
// When one browser Lane loses the sidecar, the round's remaining browser
|
||||||
// Lanes are skipped: every fetch would fail anyway, and their Series must not
|
// Lanes are skipped: every fetch would fail anyway, and their Series must not
|
||||||
// burn their stamps on a dead Chrome (issue #100).
|
// burn their stamps on a dead Chrome (issue #100).
|
||||||
|
|||||||
@@ -19,6 +19,11 @@ type LaneState struct {
|
|||||||
Clamped bool
|
Clamped bool
|
||||||
Refusing bool
|
Refusing bool
|
||||||
Browser bool
|
Browser bool
|
||||||
|
// Asleep marks a browser Lane whose last pass declined to wake Chrome
|
||||||
|
// because it was under both wake thresholds (ADR-0005). Due without
|
||||||
|
// Checked then means "waiting for the group to gather", not "stopped", and
|
||||||
|
// the page must not draw it as a stall.
|
||||||
|
Asleep bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Status is the owner's page snapshot of the whole poller (issue #102).
|
// Status is the owner's page snapshot of the whole poller (issue #102).
|
||||||
|
|||||||
@@ -61,8 +61,11 @@ type laneRow struct {
|
|||||||
// is configured, which stops those Series just as completely.
|
// is configured, which stops those Series just as completely.
|
||||||
BrowserLost bool
|
BrowserLost bool
|
||||||
// Stalled marks a Lane with Series waiting that its last pass did not read
|
// Stalled marks a Lane with Series waiting that its last pass did not read
|
||||||
// — the difference between a stopped Lane and a quiet one (story 13).
|
// — the difference between a stopped Lane and a quiet one (story 13). A
|
||||||
|
// browser Lane holding Chrome asleep under the wake thresholds is neither,
|
||||||
|
// so it carries Asleep instead and never Stalled.
|
||||||
Stalled bool
|
Stalled bool
|
||||||
|
Asleep bool
|
||||||
// Attention is the one flag the template colours on, so an unhealthy Lane
|
// Attention is the one flag the template colours on, so an unhealthy Lane
|
||||||
// is found at a glance rather than read for.
|
// is found at a glance rather than read for.
|
||||||
Attention bool
|
Attention bool
|
||||||
@@ -152,8 +155,9 @@ func (h *Handler) lanesView() lanesView {
|
|||||||
for _, l := range snap.Lanes {
|
for _, l := range snap.Lanes {
|
||||||
lost := l.Browser && !snap.BrowserReachable
|
lost := l.Browser && !snap.BrowserReachable
|
||||||
// Series waiting and none read is the shape of a Lane that has stopped
|
// Series waiting and none read is the shape of a Lane that has stopped
|
||||||
// working, as distinct from one that is quiet for want of work.
|
// working, as distinct from one that is quiet for want of work — or one
|
||||||
stalled := l.Due > 0 && l.Checked == 0
|
// deliberately leaving Chrome asleep until its group gathers.
|
||||||
|
stalled := l.Due > 0 && l.Checked == 0 && !l.Asleep
|
||||||
gap := ""
|
gap := ""
|
||||||
if l.Gap > 0 {
|
if l.Gap > 0 {
|
||||||
gap = l.Gap.Truncate(time.Second).String()
|
gap = l.Gap.Truncate(time.Second).String()
|
||||||
@@ -168,6 +172,7 @@ func (h *Handler) lanesView() lanesView {
|
|||||||
Refusing: l.Refusing,
|
Refusing: l.Refusing,
|
||||||
BrowserLost: lost,
|
BrowserLost: lost,
|
||||||
Stalled: stalled,
|
Stalled: stalled,
|
||||||
|
Asleep: l.Asleep,
|
||||||
Attention: l.Clamped || l.Refusing || lost || stalled,
|
Attention: l.Clamped || l.Refusing || lost || stalled,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
{{if .Refusing}}<span class="lane-mark">refusing</span>{{end}}
|
{{if .Refusing}}<span class="lane-mark">refusing</span>{{end}}
|
||||||
{{if .BrowserLost}}<span class="lane-mark">no browser</span>{{end}}
|
{{if .BrowserLost}}<span class="lane-mark">no browser</span>{{end}}
|
||||||
{{if .Stalled}}<span class="lane-mark">not checking</span>{{end}}
|
{{if .Stalled}}<span class="lane-mark">not checking</span>{{end}}
|
||||||
|
{{if .Asleep}}<span class="lane-mark">browser asleep</span>{{end}}
|
||||||
</li>
|
</li>
|
||||||
{{end}}
|
{{end}}
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
@@ -776,6 +776,37 @@ func TestAdminPageShowsLaneStatus(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A browser Lane under both wake thresholds holds Chrome asleep (ADR-0005), so
|
||||||
|
// Series due with none checked is the design working, not a stopped Lane. The
|
||||||
|
// two must not render the same mark: "not checking" is the owner's cue to go
|
||||||
|
// looking, and spending it on the commonest healthy browser-Lane state trains
|
||||||
|
// them to ignore it.
|
||||||
|
func TestAsleepBrowserLaneIsNotMarkedStalled(t *testing.T) {
|
||||||
|
lanes := fakeLanes{latest.Status{
|
||||||
|
Lanes: []latest.LaneState{
|
||||||
|
{Site: "kagane", Due: 1, LastRun: time.Now(), Gap: 10 * time.Second, Browser: true, Asleep: true},
|
||||||
|
},
|
||||||
|
BrowserConfigured: true,
|
||||||
|
BrowserReachable: true,
|
||||||
|
}}
|
||||||
|
router, st, _ := oauthWebTestServer(t, lanes)
|
||||||
|
|
||||||
|
req := httptest.NewRequest(http.MethodGet, "/ui/admin/lanes", nil)
|
||||||
|
req.AddCookie(sessionCookie(t, st))
|
||||||
|
rr := httptest.NewRecorder()
|
||||||
|
router.ServeHTTP(rr, req)
|
||||||
|
body := rr.Body.String()
|
||||||
|
if strings.Contains(body, "not checking") {
|
||||||
|
t.Errorf("an asleep browser Lane is marked as stalled:\n%s", body)
|
||||||
|
}
|
||||||
|
if !strings.Contains(body, "browser asleep") {
|
||||||
|
t.Errorf("an asleep browser Lane says nothing about why it read nothing:\n%s", body)
|
||||||
|
}
|
||||||
|
if strings.Contains(body, `class="attention"`) {
|
||||||
|
t.Errorf("an asleep browser Lane is coloured as unhealthy:\n%s", body)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// A Lane whose pass never reached a figure must not have that figure drawn as
|
// A Lane whose pass never reached a figure must not have that figure drawn as
|
||||||
// a zero: a refusing Lane still reports the due count and gap its last real
|
// a zero: a refusing Lane still reports the due count and gap its last real
|
||||||
// pass saw, and a Lane that has never reached one omits it entirely.
|
// pass saw, and a Lane that has never reached one omits it entirely.
|
||||||
|
|||||||
@@ -12,9 +12,8 @@
|
|||||||
"10": "Go Test Helpers",
|
"10": "Go Test Helpers",
|
||||||
"11": "Store Tests",
|
"11": "Store Tests",
|
||||||
"12": "Bookmarks API Handler",
|
"12": "Bookmarks API Handler",
|
||||||
"13": "Web UI Handlers",
|
"13": "displayChapter",
|
||||||
"14": "Go Error Handling",
|
"14": "Go Error Handling",
|
||||||
"15": "CDP Browser Client",
|
|
||||||
"16": "Cloudflare bot scoring and poll cadence — what is actually documented",
|
"16": "Cloudflare bot scoring and poll cadence — what is actually documented",
|
||||||
"17": "Go Code Style Guide",
|
"17": "Go Code Style Guide",
|
||||||
"18": "Agent Skills",
|
"18": "Agent Skills",
|
||||||
@@ -30,7 +29,6 @@
|
|||||||
"28": "Allocation Patterns",
|
"28": "Allocation Patterns",
|
||||||
"29": "Observability & Alerting",
|
"29": "Observability & Alerting",
|
||||||
"30": "AGENTS.md",
|
"30": "AGENTS.md",
|
||||||
"31": "Store",
|
|
||||||
"32": "Open",
|
"32": "Open",
|
||||||
"33": "Go Testing Guide",
|
"33": "Go Testing Guide",
|
||||||
"34": "Session Store",
|
"34": "Session Store",
|
||||||
@@ -41,7 +39,6 @@
|
|||||||
"39": "UI Critique 2026-07-26A",
|
"39": "UI Critique 2026-07-26A",
|
||||||
"40": "UI Critique 2026-07-26B",
|
"40": "UI Critique 2026-07-26B",
|
||||||
"41": "Handler",
|
"41": "Handler",
|
||||||
"42": "pgtest.go",
|
|
||||||
"43": "Issue Tracker & Triage",
|
"43": "Issue Tracker & Triage",
|
||||||
"44": "Ticket Workflow",
|
"44": "Ticket Workflow",
|
||||||
"45": "Go Perf Alert Rules",
|
"45": "Go Perf Alert Rules",
|
||||||
@@ -124,7 +121,6 @@
|
|||||||
"122": "Identity comes from Discord OAuth; we store no passwords and send no email",
|
"122": "Identity comes from Discord OAuth; we store no passwords and send no email",
|
||||||
"123": "The wire format stays flat and deliberately does not mirror the schema",
|
"123": "The wire format stays flat and deliberately does not mirror the schema",
|
||||||
"124": "ADR-0005: On-demand browser sidecar",
|
"124": "ADR-0005: On-demand browser sidecar",
|
||||||
"125": "sessions_test.go",
|
|
||||||
"126": "Bookmark Manager",
|
"126": "Bookmark Manager",
|
||||||
"127": "triage-labels.md",
|
"127": "triage-labels.md",
|
||||||
"128": "Cross-Ticket Contract",
|
"128": "Cross-Ticket Contract",
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
# Graph Report - mangaBookmark (2026-08-16)
|
# Graph Report - mangaBookmark (2026-08-16)
|
||||||
|
|
||||||
## Corpus Check
|
## Corpus Check
|
||||||
- 119 files · ~290,953 words
|
- 119 files · ~291,777 words
|
||||||
- Verdict: corpus is large enough that graph structure adds value.
|
- Verdict: corpus is large enough that graph structure adds value.
|
||||||
|
|
||||||
## Summary
|
## Summary
|
||||||
- 1736 nodes · 3597 edges · 221 communities (70 shown, 151 thin omitted)
|
- 1739 nodes · 3610 edges · 217 communities (67 shown, 150 thin omitted)
|
||||||
- Extraction: 90% EXTRACTED · 10% INFERRED · 0% AMBIGUOUS · INFERRED: 361 edges (avg confidence: 0.78)
|
- Extraction: 90% EXTRACTED · 10% INFERRED · 0% AMBIGUOUS · INFERRED: 363 edges (avg confidence: 0.78)
|
||||||
- Token cost: 0 input · 0 output
|
- Token cost: 0 input · 0 output
|
||||||
|
|
||||||
## Graph Freshness
|
## Graph Freshness
|
||||||
- Built from commit: `56afb9f2`
|
- Built from commit: `20fff588`
|
||||||
- Run `git rev-parse HEAD` and compare to check if the graph is stale.
|
- Run `git rev-parse HEAD` and compare to check if the graph is stale.
|
||||||
- Run `graphify update .` after code changes (no API cost).
|
- Run `graphify update .` after code changes (no API cost).
|
||||||
|
|
||||||
@@ -28,9 +28,8 @@
|
|||||||
- [[_COMMUNITY_Go Test Helpers|Go Test Helpers]]
|
- [[_COMMUNITY_Go Test Helpers|Go Test Helpers]]
|
||||||
- [[_COMMUNITY_Store Tests|Store Tests]]
|
- [[_COMMUNITY_Store Tests|Store Tests]]
|
||||||
- [[_COMMUNITY_Bookmarks API Handler|Bookmarks API Handler]]
|
- [[_COMMUNITY_Bookmarks API Handler|Bookmarks API Handler]]
|
||||||
- [[_COMMUNITY_Web UI Handlers|Web UI Handlers]]
|
- [[_COMMUNITY_displayChapter|displayChapter]]
|
||||||
- [[_COMMUNITY_Go Error Handling|Go Error Handling]]
|
- [[_COMMUNITY_Go Error Handling|Go Error Handling]]
|
||||||
- [[_COMMUNITY_CDP Browser Client|CDP Browser Client]]
|
|
||||||
- [[_COMMUNITY_Cloudflare bot scoring and poll cadence — what is actually documented|Cloudflare bot scoring and poll cadence — what is actually documented]]
|
- [[_COMMUNITY_Cloudflare bot scoring and poll cadence — what is actually documented|Cloudflare bot scoring and poll cadence — what is actually documented]]
|
||||||
- [[_COMMUNITY_Go Code Style Guide|Go Code Style Guide]]
|
- [[_COMMUNITY_Go Code Style Guide|Go Code Style Guide]]
|
||||||
- [[_COMMUNITY_Agent Skills|Agent Skills]]
|
- [[_COMMUNITY_Agent Skills|Agent Skills]]
|
||||||
@@ -46,7 +45,6 @@
|
|||||||
- [[_COMMUNITY_Allocation Patterns|Allocation Patterns]]
|
- [[_COMMUNITY_Allocation Patterns|Allocation Patterns]]
|
||||||
- [[_COMMUNITY_Observability & Alerting|Observability & Alerting]]
|
- [[_COMMUNITY_Observability & Alerting|Observability & Alerting]]
|
||||||
- [[_COMMUNITY_AGENTS|AGENTS.md]]
|
- [[_COMMUNITY_AGENTS|AGENTS.md]]
|
||||||
- [[_COMMUNITY_Store|Store]]
|
|
||||||
- [[_COMMUNITY_Go Testing Guide|Go Testing Guide]]
|
- [[_COMMUNITY_Go Testing Guide|Go Testing Guide]]
|
||||||
- [[_COMMUNITY_Session Store|Session Store]]
|
- [[_COMMUNITY_Session Store|Session Store]]
|
||||||
- [[_COMMUNITY_Web UI Filter Logic|Web UI Filter Logic]]
|
- [[_COMMUNITY_Web UI Filter Logic|Web UI Filter Logic]]
|
||||||
@@ -56,7 +54,6 @@
|
|||||||
- [[_COMMUNITY_UI Critique 2026-07-26A|UI Critique 2026-07-26A]]
|
- [[_COMMUNITY_UI Critique 2026-07-26A|UI Critique 2026-07-26A]]
|
||||||
- [[_COMMUNITY_UI Critique 2026-07-26B|UI Critique 2026-07-26B]]
|
- [[_COMMUNITY_UI Critique 2026-07-26B|UI Critique 2026-07-26B]]
|
||||||
- [[_COMMUNITY_Handler|Handler]]
|
- [[_COMMUNITY_Handler|Handler]]
|
||||||
- [[_COMMUNITY_pgtest.go|pgtest.go]]
|
|
||||||
- [[_COMMUNITY_Issue Tracker & Triage|Issue Tracker & Triage]]
|
- [[_COMMUNITY_Issue Tracker & Triage|Issue Tracker & Triage]]
|
||||||
- [[_COMMUNITY_Ticket Workflow|Ticket Workflow]]
|
- [[_COMMUNITY_Ticket Workflow|Ticket Workflow]]
|
||||||
- [[_COMMUNITY_Go Perf Alert Rules|Go Perf Alert Rules]]
|
- [[_COMMUNITY_Go Perf Alert Rules|Go Perf Alert Rules]]
|
||||||
@@ -139,7 +136,6 @@
|
|||||||
- [[_COMMUNITY_Identity comes from Discord OAuth; we store no passwords and send no email|Identity comes from Discord OAuth; we store no passwords and send no email]]
|
- [[_COMMUNITY_Identity comes from Discord OAuth; we store no passwords and send no email|Identity comes from Discord OAuth; we store no passwords and send no email]]
|
||||||
- [[_COMMUNITY_The wire format stays flat and deliberately does not mirror the schema|The wire format stays flat and deliberately does not mirror the schema]]
|
- [[_COMMUNITY_The wire format stays flat and deliberately does not mirror the schema|The wire format stays flat and deliberately does not mirror the schema]]
|
||||||
- [[_COMMUNITY_ADR-0005 On-demand browser sidecar|ADR-0005: On-demand browser sidecar]]
|
- [[_COMMUNITY_ADR-0005 On-demand browser sidecar|ADR-0005: On-demand browser sidecar]]
|
||||||
- [[_COMMUNITY_sessions_test.go|sessions_test.go]]
|
|
||||||
- [[_COMMUNITY_Bookmark Manager|Bookmark Manager]]
|
- [[_COMMUNITY_Bookmark Manager|Bookmark Manager]]
|
||||||
- [[_COMMUNITY_triage-labels|triage-labels.md]]
|
- [[_COMMUNITY_triage-labels|triage-labels.md]]
|
||||||
- [[_COMMUNITY_Cross-Ticket Contract|Cross-Ticket Contract]]
|
- [[_COMMUNITY_Cross-Ticket Contract|Cross-Ticket Contract]]
|
||||||
@@ -270,7 +266,7 @@
|
|||||||
- **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]
|
- **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]
|
- **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 (221 total, 151 thin omitted)
|
## Communities (217 total, 150 thin omitted)
|
||||||
|
|
||||||
### Community 0 - "HTMX Library Internals"
|
### Community 0 - "HTMX Library Internals"
|
||||||
Cohesion: 0.08
|
Cohesion: 0.08
|
||||||
@@ -278,7 +274,7 @@ Nodes (101): A(), ae(), an(), at(), B(), be(), bn(), bt() (+93 more)
|
|||||||
|
|
||||||
### Community 1 - "Cover Fetch Test Helpers"
|
### Community 1 - "Cover Fetch Test Helpers"
|
||||||
Cohesion: 0.09
|
Cohesion: 0.09
|
||||||
Nodes (89): floatPtr(), testConfig(), getCover(), Cookie, Handler, ResponseRecorder, T, TestListRendersAcquiredCover() (+81 more)
|
Nodes (88): floatPtr(), testConfig(), getCover(), Cookie, Handler, ResponseRecorder, T, TestListRendersAcquiredCover() (+80 more)
|
||||||
|
|
||||||
### Community 2 - "Manga Userscript Adapters"
|
### Community 2 - "Manga Userscript Adapters"
|
||||||
Cohesion: 0.06
|
Cohesion: 0.06
|
||||||
@@ -293,12 +289,12 @@ Cohesion: 0.07
|
|||||||
Nodes (103): bookmarkNewKaganeSeries(), bookmarkNewNovelfullSeries(), bookmarkNewSeries(), Context, Store, T, newAcquirer(), readBookmark() (+95 more)
|
Nodes (103): bookmarkNewKaganeSeries(), bookmarkNewNovelfullSeries(), bookmarkNewSeries(), Context, Store, T, newAcquirer(), readBookmark() (+95 more)
|
||||||
|
|
||||||
### Community 5 - "Bookmarks API Tests"
|
### Community 5 - "Bookmarks API Tests"
|
||||||
Cohesion: 0.07
|
Cohesion: 0.11
|
||||||
Nodes (71): auth(), getBookmarks(), Handler, Request, Store, T, newTestServer(), newTestStore() (+63 more)
|
Nodes (54): auth(), getBookmarks(), Handler, Request, Store, T, newTestServer(), newTestStore() (+46 more)
|
||||||
|
|
||||||
### Community 7 - "Cover & Acquire Internals"
|
### Community 7 - "Cover & Acquire Internals"
|
||||||
Cohesion: 0.06
|
Cohesion: 0.08
|
||||||
Nodes (43): Addr, fakeLanes, Context, Store, WaitGroup, isInterstitial(), defaultCoverResolver(), fetchCoverBytes() (+35 more)
|
Nodes (31): fakeLanes, Context, Store, WaitGroup, isInterstitial(), fetchCoverBytes(), browserWakeDue(), fetcherFor() (+23 more)
|
||||||
|
|
||||||
### Community 8 - "System Architecture Concepts"
|
### Community 8 - "System Architecture Concepts"
|
||||||
Cohesion: 0.15
|
Cohesion: 0.15
|
||||||
@@ -313,21 +309,21 @@ Cohesion: 0.05
|
|||||||
Nodes (39): Test Helpers, Test Timeout, Basic Handler Test, HTTP Handler Testing, Query Parameters and Headers, Docker Compose Fixture, Integration Testing, SQL Schema Fixture (+31 more)
|
Nodes (39): Test Helpers, Test Timeout, Basic Handler Test, HTTP Handler Testing, Query Parameters and Headers, Docker Compose Fixture, Integration Testing, SQL Schema Fixture (+31 more)
|
||||||
|
|
||||||
### Community 11 - "Store Tests"
|
### Community 11 - "Store Tests"
|
||||||
Cohesion: 0.14
|
Cohesion: 0.07
|
||||||
Nodes (45): Store, T, newTestStore(), readLatestCheckedAt(), readSeries(), secondReader(), seedForCheck(), seedSecondReader() (+37 more)
|
Nodes (81): M, TestMain(), M, TestMain(), M, Main(), start(), URL() (+73 more)
|
||||||
|
|
||||||
### Community 12 - "Bookmarks API Handler"
|
### Community 12 - "Bookmarks API Handler"
|
||||||
Cohesion: 0.08
|
Cohesion: 0.08
|
||||||
Nodes (32): Handler, Request, ResponseWriter, Store, Healthz(), writeJSON(), Auth(), compressible() (+24 more)
|
Nodes (32): Handler, Request, ResponseWriter, Store, Healthz(), writeJSON(), Auth(), compressible() (+24 more)
|
||||||
|
|
||||||
|
### Community 13 - "displayChapter"
|
||||||
|
Cohesion: 0.09
|
||||||
|
Nodes (36): Addr, Config, NewBrowserFetcher(), defaultCoverResolver(), Client, Context, NewCoverFetcher(), NewCoverFetcherWithResolver() (+28 more)
|
||||||
|
|
||||||
### Community 14 - "Go Error Handling"
|
### Community 14 - "Go Error Handling"
|
||||||
Cohesion: 0.06
|
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)
|
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.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"
|
### Community 16 - "Cloudflare bot scoring and poll cadence — what is actually documented"
|
||||||
Cohesion: 0.06
|
Cohesion: 0.06
|
||||||
Nodes (33): 1.1 The score itself, 1.2 The detection engines (Enterprise Bot Management), 1.3 Rate limiting is a separate product, 1. What a bot score is and what feeds it, 2.1 What each plan gets, 2.2 Bot Fight Mode specifics (the Free-plan product), 2.3 Does the free tier "score" continuously?, 2. The free-plan reality (+25 more)
|
Nodes (33): 1.1 The score itself, 1.2 The detection engines (Enterprise Bot Management), 1.3 Rate limiting is a separate product, 1. What a bot score is and what feeds it, 2.1 What each plan gets, 2.2 Bot Fight Mode specifics (the Free-plan product), 2.3 Does the free tier "score" continuously?, 2. The free-plan reality (+25 more)
|
||||||
@@ -365,8 +361,8 @@ Cohesion: 0.33
|
|||||||
Nodes (12): coverResponse(), Request, T, TestCoverFetcherCanonicalisesJpgAlias(), TestCoverFetcherFetchesPublicHTTPSImage(), TestCoverFetcherRefusesUnsafeDestinationsBeforeRequest(), TestCoverFetcherRejectsNonImage(), TestCoverFetcherRejectsOversizedBody() (+4 more)
|
Nodes (12): coverResponse(), Request, T, TestCoverFetcherCanonicalisesJpgAlias(), TestCoverFetcherFetchesPublicHTTPSImage(), TestCoverFetcherRefusesUnsafeDestinationsBeforeRequest(), TestCoverFetcherRejectsNonImage(), TestCoverFetcherRejectsOversizedBody() (+4 more)
|
||||||
|
|
||||||
### Community 26 - "Open"
|
### Community 26 - "Open"
|
||||||
Cohesion: 0.05
|
Cohesion: 0.06
|
||||||
Nodes (61): awaitPromise(), browserConnectionLost(), classifyBrowserError(), comixRead(), comixSeriesPageURL(), Action, Context, Mutex (+53 more)
|
Nodes (57): awaitPromise(), browserConnectionLost(), classifyBrowserError(), comixRead(), comixSeriesPageURL(), Action, Context, Mutex (+49 more)
|
||||||
|
|
||||||
### Community 27 - "Find Skills Guide"
|
### Community 27 - "Find Skills Guide"
|
||||||
Cohesion: 0.14
|
Cohesion: 0.14
|
||||||
@@ -384,10 +380,6 @@ Nodes (9): Alerting rules (examples), CPU saturation, GC pressure, Goroutine lea
|
|||||||
Cohesion: 0.40
|
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
|
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 31 - "Store"
|
|
||||||
Cohesion: 0.09
|
|
||||||
Nodes (5): coverRelativePath(), coverSourceAddress(), Store, scanSeries(), ReaderSummary
|
|
||||||
|
|
||||||
### Community 33 - "Go Testing Guide"
|
### Community 33 - "Go Testing Guide"
|
||||||
Cohesion: 0.20
|
Cohesion: 0.20
|
||||||
Nodes (10): CI Regression Detection, Common Mistakes, Core Philosophy, Cross-References, Decision Tree: Where Is Time Spent?, Deep Dives, Go Performance Optimization, Iterative Optimization Methodology (+2 more)
|
Nodes (10): CI Regression Detection, Common Mistakes, Core Philosophy, Cross-References, Decision Tree: Where Is Time Spent?, Deep Dives, Go Performance Optimization, Iterative Optimization Methodology (+2 more)
|
||||||
@@ -417,12 +409,8 @@ Cohesion: 0.29
|
|||||||
Nodes (6): Design Health Score, Design Specificity Verdict, Minor Observations, Persona Red Flags, Priority Issues, Questions to Consider
|
Nodes (6): Design Health Score, Design Specificity Verdict, Minor Observations, Persona Red Flags, Priority Issues, Questions to Consider
|
||||||
|
|
||||||
### Community 41 - "Handler"
|
### Community 41 - "Handler"
|
||||||
Cohesion: 0.14
|
Cohesion: 0.05
|
||||||
Nodes (18): currentLib(), currentTab(), filterBookmarks(), Client, HandlerFunc, Request, ResponseWriter, Store (+10 more)
|
Nodes (25): coverRelativePath(), coverSourceAddress(), displayChapter(), Store, scanSeries(), currentLib(), currentTab(), filterBookmarks() (+17 more)
|
||||||
|
|
||||||
### Community 42 - "pgtest.go"
|
|
||||||
Cohesion: 0.18
|
|
||||||
Nodes (12): M, TestMain(), M, TestMain(), M, Main(), start(), URL() (+4 more)
|
|
||||||
|
|
||||||
### Community 45 - "Go Perf Alert Rules"
|
### Community 45 - "Go Perf Alert Rules"
|
||||||
Cohesion: 0.50
|
Cohesion: 0.50
|
||||||
@@ -532,10 +520,6 @@ Nodes (3): Consequence, The wire format stays flat and deliberately does not mir
|
|||||||
Cohesion: 0.50
|
Cohesion: 0.50
|
||||||
Nodes (3): ADR-0005: On-demand browser sidecar, Constraints, Decision
|
Nodes (3): ADR-0005: On-demand browser sidecar, Constraints, Decision
|
||||||
|
|
||||||
### Community 125 - "sessions_test.go"
|
|
||||||
Cohesion: 0.48
|
|
||||||
Nodes (6): T, TestCreateAndGetSession(), TestDeleteSessionIsPerReader(), TestDeleteSessionRevokes(), TestExpiredSessionIsGone(), TestGetSessionUnknownID()
|
|
||||||
|
|
||||||
### Community 154 - "ADR-0011: Sightings — a Reader report defers a Poll where being wrong hurts only them"
|
### Community 154 - "ADR-0011: Sightings — a Reader report defers a Poll where being wrong hurts only them"
|
||||||
Cohesion: 0.33
|
Cohesion: 0.33
|
||||||
Nodes (5): ADR-0011: Sightings — a Reader report defers a Poll where being wrong hurts only them, Constraints preserved, Decision, Tradeoffs and rejections, Why
|
Nodes (5): ADR-0011: Sightings — a Reader report defers a Poll where being wrong hurts only them, Constraints preserved, Decision, Tradeoffs and rejections, Why
|
||||||
@@ -551,17 +535,17 @@ Nodes (3): Live URL shapes (verified 2026-07-26, may drift — re-check against
|
|||||||
## Knowledge Gaps
|
## Knowledge Gaps
|
||||||
- **524 isolated node(s):** `bookmarkmanager/backend`, `ctxKey`, `loginView`, `ctxKey`, `test` (+519 more)
|
- **524 isolated node(s):** `bookmarkmanager/backend`, `ctxKey`, `loginView`, `ctxKey`, `test` (+519 more)
|
||||||
These have ≤1 connection - possible missing edges or undocumented components.
|
These have ≤1 connection - possible missing edges or undocumented components.
|
||||||
- **151 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
|
## Suggested Questions
|
||||||
_Questions this graph is uniquely positioned to answer:_
|
_Questions this graph is uniquely positioned to answer:_
|
||||||
|
|
||||||
- **Why does `Open()` connect `CDP Browser Client` to `Cover Fetch Test Helpers`, `Series Acquisition Tests`, `Bookmarks API Tests`, `pgtest.go`, `Store Tests`, `Store`?**
|
- **Why does `Open()` connect `Store Tests` to `Cover Fetch Test Helpers`, `Series Acquisition Tests`, `Bookmarks API Tests`, `Handler`, `displayChapter`?**
|
||||||
_High betweenness centrality (0.060) - this node is a cross-community bridge._
|
_High betweenness centrality (0.057) - this node is a cross-community bridge._
|
||||||
- **Why does `New()` connect `Series Acquisition Tests` to `Bookmarks API Tests`, `Cover & Acquire Internals`, `Handler`, `Session Middleware`, `CDP Browser Client`, `ResponseWriter`?**
|
- **Why does `New()` connect `Series Acquisition Tests` to `Bookmarks API Tests`, `Cover & Acquire Internals`, `Handler`, `Session Middleware`, `Store Tests`, `displayChapter`, `ResponseWriter`?**
|
||||||
_High betweenness centrality (0.050) - this node is a cross-community bridge._
|
_High betweenness centrality (0.051) - 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`?**
|
- **Why does `newRouter()` connect `Bookmarks API Tests` to `Cover Fetch Test Helpers`, `Series Acquisition Tests`, `Bookmarks API Handler`, `displayChapter`, `ResponseWriter`?**
|
||||||
_High betweenness centrality (0.030) - this node is a cross-community bridge._
|
_High betweenness centrality (0.031) - this node is a cross-community bridge._
|
||||||
- **Are the 25 inferred relationships involving `newTestStore()` (e.g. with `TestAcquireDoesNotBlockTheWrite()` and `TestAcquireFailureLeavesTheBookmarkIntact()`) actually correct?**
|
- **Are the 25 inferred relationships involving `newTestStore()` (e.g. with `TestAcquireDoesNotBlockTheWrite()` and `TestAcquireFailureLeavesTheBookmarkIntact()`) actually correct?**
|
||||||
_`newTestStore()` has 25 INFERRED edges - model-reasoned connections that need verification._
|
_`newTestStore()` has 25 INFERRED edges - model-reasoned connections that need verification._
|
||||||
- **Are the 48 inferred relationships involving `testConfig()` (e.g. with `TestListRendersAcquiredCover()` and `TestPublicCoverNeverEchoesNonImage()`) actually correct?**
|
- **Are the 48 inferred relationships involving `testConfig()` (e.g. with `TestListRendersAcquiredCover()` and `TestPublicCoverNeverEchoesNonImage()`) actually correct?**
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
+689
-519
File diff suppressed because it is too large
Load Diff
+39
-39
@@ -25,7 +25,7 @@
|
|||||||
"semantic_hash": "dac242903b0e98c3e4395159d609e08e"
|
"semantic_hash": "dac242903b0e98c3e4395159d609e08e"
|
||||||
},
|
},
|
||||||
"backend/main.go": {
|
"backend/main.go": {
|
||||||
"mtime": 1786863963.3450089,
|
"mtime": 1786886056.023822,
|
||||||
"ast_hash": "d5a50b03438d7c120079d40cc578462b",
|
"ast_hash": "d5a50b03438d7c120079d40cc578462b",
|
||||||
"semantic_hash": ""
|
"semantic_hash": ""
|
||||||
},
|
},
|
||||||
@@ -35,7 +35,7 @@
|
|||||||
"semantic_hash": "4a94ac85bad6bce330d085bcc0ae3ffd"
|
"semantic_hash": "4a94ac85bad6bce330d085bcc0ae3ffd"
|
||||||
},
|
},
|
||||||
"userscript/manga-bookmark.user.js": {
|
"userscript/manga-bookmark.user.js": {
|
||||||
"mtime": 1786872888.3482232,
|
"mtime": 1786886056.0389624,
|
||||||
"ast_hash": "4e79684942234b26f4a1fb03fccd6d35",
|
"ast_hash": "4e79684942234b26f4a1fb03fccd6d35",
|
||||||
"semantic_hash": ""
|
"semantic_hash": ""
|
||||||
},
|
},
|
||||||
@@ -170,8 +170,8 @@
|
|||||||
"semantic_hash": "e51077b6a7f1f67afc748f1a32a1557d"
|
"semantic_hash": "e51077b6a7f1f67afc748f1a32a1557d"
|
||||||
},
|
},
|
||||||
"backend/web_test.go": {
|
"backend/web_test.go": {
|
||||||
"mtime": 1786865248.7717106,
|
"mtime": 1786891437.925184,
|
||||||
"ast_hash": "7c298e39c63e4502cf6272d1e206e9ef",
|
"ast_hash": "74aed7f5a5b196d2b860cd6a34266ec6",
|
||||||
"semantic_hash": ""
|
"semantic_hash": ""
|
||||||
},
|
},
|
||||||
"backend/main_test.go": {
|
"backend/main_test.go": {
|
||||||
@@ -220,22 +220,22 @@
|
|||||||
"semantic_hash": ""
|
"semantic_hash": ""
|
||||||
},
|
},
|
||||||
"docs/design-system.md": {
|
"docs/design-system.md": {
|
||||||
"mtime": 1786865139.9022946,
|
"mtime": 1786886056.0313923,
|
||||||
"ast_hash": "3bd39932997c8e245508874194db4e49",
|
"ast_hash": "3bd39932997c8e245508874194db4e49",
|
||||||
"semantic_hash": ""
|
"semantic_hash": ""
|
||||||
},
|
},
|
||||||
"backend/api_test.go": {
|
"backend/api_test.go": {
|
||||||
"mtime": 1786868080.2317674,
|
"mtime": 1786886056.016252,
|
||||||
"ast_hash": "b64372df5429fb14e48b37b3bab10402",
|
"ast_hash": "b64372df5429fb14e48b37b3bab10402",
|
||||||
"semantic_hash": ""
|
"semantic_hash": ""
|
||||||
},
|
},
|
||||||
"backend/cover_test.go": {
|
"backend/cover_test.go": {
|
||||||
"mtime": 1786863966.7084978,
|
"mtime": 1786886056.016252,
|
||||||
"ast_hash": "fd6b3f6ef46bd17b0241d104b6e5bdf6",
|
"ast_hash": "fd6b3f6ef46bd17b0241d104b6e5bdf6",
|
||||||
"semantic_hash": ""
|
"semantic_hash": ""
|
||||||
},
|
},
|
||||||
"backend/internal/api/handlers.go": {
|
"backend/internal/api/handlers.go": {
|
||||||
"mtime": 1786867745.788687,
|
"mtime": 1786886056.016252,
|
||||||
"ast_hash": "ae4f3b961450f06a06e0632eb273a5b2",
|
"ast_hash": "ae4f3b961450f06a06e0632eb273a5b2",
|
||||||
"semantic_hash": ""
|
"semantic_hash": ""
|
||||||
},
|
},
|
||||||
@@ -245,13 +245,13 @@
|
|||||||
"semantic_hash": "385b36f58488b7e6d93eb6d6034e9ee3"
|
"semantic_hash": "385b36f58488b7e6d93eb6d6034e9ee3"
|
||||||
},
|
},
|
||||||
"backend/internal/latest/browser.go": {
|
"backend/internal/latest/browser.go": {
|
||||||
"mtime": 1786861012.026504,
|
"mtime": 1786889854.5578685,
|
||||||
"ast_hash": "75f34a974568d122681939dd297944a2",
|
"ast_hash": "b65f3693db77c69ef0a6247fd75118bc",
|
||||||
"semantic_hash": ""
|
"semantic_hash": ""
|
||||||
},
|
},
|
||||||
"backend/internal/latest/browser_test.go": {
|
"backend/internal/latest/browser_test.go": {
|
||||||
"mtime": 1786857336.6414917,
|
"mtime": 1786889854.5578685,
|
||||||
"ast_hash": "800fa6aa471ada054a3c48943ad17ab7",
|
"ast_hash": "118aba3d794b9faf893c45e58298e11a",
|
||||||
"semantic_hash": ""
|
"semantic_hash": ""
|
||||||
},
|
},
|
||||||
"backend/internal/latest/fetch.go": {
|
"backend/internal/latest/fetch.go": {
|
||||||
@@ -260,17 +260,17 @@
|
|||||||
"semantic_hash": ""
|
"semantic_hash": ""
|
||||||
},
|
},
|
||||||
"backend/internal/latest/poller.go": {
|
"backend/internal/latest/poller.go": {
|
||||||
"mtime": 1786872774.641225,
|
"mtime": 1786891405.415882,
|
||||||
"ast_hash": "5e55e2ac5cb7d347807754f92425d29b",
|
"ast_hash": "54f6eec9d2090c7713f502c8553063a2",
|
||||||
"semantic_hash": ""
|
"semantic_hash": ""
|
||||||
},
|
},
|
||||||
"backend/internal/latest/poller_test.go": {
|
"backend/internal/latest/poller_test.go": {
|
||||||
"mtime": 1786865291.3758123,
|
"mtime": 1786891462.5665002,
|
||||||
"ast_hash": "1da669ac748a8d1a0289e557392fa3fd",
|
"ast_hash": "512806a9c6e15036a75f01bf5577c20b",
|
||||||
"semantic_hash": ""
|
"semantic_hash": ""
|
||||||
},
|
},
|
||||||
"backend/internal/latest/sites.go": {
|
"backend/internal/latest/sites.go": {
|
||||||
"mtime": 1786868771.0663204,
|
"mtime": 1786886056.0200372,
|
||||||
"ast_hash": "5786000dd0dfd5b4b3bd2b87b1fc100b",
|
"ast_hash": "5786000dd0dfd5b4b3bd2b87b1fc100b",
|
||||||
"semantic_hash": ""
|
"semantic_hash": ""
|
||||||
},
|
},
|
||||||
@@ -340,12 +340,12 @@
|
|||||||
"semantic_hash": "0b6764a0ee20f5cb7748eecd31a1d220"
|
"semantic_hash": "0b6764a0ee20f5cb7748eecd31a1d220"
|
||||||
},
|
},
|
||||||
"backend/internal/store/store.go": {
|
"backend/internal/store/store.go": {
|
||||||
"mtime": 1786868763.646761,
|
"mtime": 1786886056.0200372,
|
||||||
"ast_hash": "34f55617b7409f03f02e925bec92fac0",
|
"ast_hash": "34f55617b7409f03f02e925bec92fac0",
|
||||||
"semantic_hash": ""
|
"semantic_hash": ""
|
||||||
},
|
},
|
||||||
"backend/internal/store/store_test.go": {
|
"backend/internal/store/store_test.go": {
|
||||||
"mtime": 1786867781.301985,
|
"mtime": 1786886056.0200372,
|
||||||
"ast_hash": "16f69d97eb63bcec7409294466642411",
|
"ast_hash": "16f69d97eb63bcec7409294466642411",
|
||||||
"semantic_hash": ""
|
"semantic_hash": ""
|
||||||
},
|
},
|
||||||
@@ -380,12 +380,12 @@
|
|||||||
"semantic_hash": "19a573773be4ca22570ca2f8543120c5"
|
"semantic_hash": "19a573773be4ca22570ca2f8543120c5"
|
||||||
},
|
},
|
||||||
"backend/internal/web/web.go": {
|
"backend/internal/web/web.go": {
|
||||||
"mtime": 1786863744.1453943,
|
"mtime": 1786886056.023822,
|
||||||
"ast_hash": "b051f2de214c4b253ee09fbbdb8ebb60",
|
"ast_hash": "b051f2de214c4b253ee09fbbdb8ebb60",
|
||||||
"semantic_hash": ""
|
"semantic_hash": ""
|
||||||
},
|
},
|
||||||
"backend/reader_credential_test.go": {
|
"backend/reader_credential_test.go": {
|
||||||
"mtime": 1786863966.7092986,
|
"mtime": 1786886056.023822,
|
||||||
"ast_hash": "0c93de387af595901c43b6bdb3bed8cc",
|
"ast_hash": "0c93de387af595901c43b6bdb3bed8cc",
|
||||||
"semantic_hash": ""
|
"semantic_hash": ""
|
||||||
},
|
},
|
||||||
@@ -395,7 +395,7 @@
|
|||||||
"semantic_hash": "8008a187690764436540fab47ba0cfcc"
|
"semantic_hash": "8008a187690764436540fab47ba0cfcc"
|
||||||
},
|
},
|
||||||
"userscript/novel-bookmark.user.js": {
|
"userscript/novel-bookmark.user.js": {
|
||||||
"mtime": 1786872902.809149,
|
"mtime": 1786886056.0389624,
|
||||||
"ast_hash": "36c81462919719f0e053ca5d633a243a",
|
"ast_hash": "36c81462919719f0e053ca5d633a243a",
|
||||||
"semantic_hash": ""
|
"semantic_hash": ""
|
||||||
},
|
},
|
||||||
@@ -425,17 +425,17 @@
|
|||||||
"semantic_hash": "6c6f3e4c4c2f57867894280bce728c50"
|
"semantic_hash": "6c6f3e4c4c2f57867894280bce728c50"
|
||||||
},
|
},
|
||||||
"backend/AGENTS.md": {
|
"backend/AGENTS.md": {
|
||||||
"mtime": 1786872951.3127444,
|
"mtime": 1786891513.6486945,
|
||||||
"ast_hash": "68bc86af9593adad1e37fa05188fe63e",
|
"ast_hash": "b4233ebc5ff905b701ded9427277ad8c",
|
||||||
"semantic_hash": ""
|
"semantic_hash": ""
|
||||||
},
|
},
|
||||||
"backend/CLAUDE.md": {
|
"backend/CLAUDE.md": {
|
||||||
"mtime": 1786872951.3127444,
|
"mtime": 1786891513.6486945,
|
||||||
"ast_hash": "68bc86af9593adad1e37fa05188fe63e",
|
"ast_hash": "b4233ebc5ff905b701ded9427277ad8c",
|
||||||
"semantic_hash": ""
|
"semantic_hash": ""
|
||||||
},
|
},
|
||||||
"backend/internal/web/templates/app.html": {
|
"backend/internal/web/templates/app.html": {
|
||||||
"mtime": 1786864445.1584811,
|
"mtime": 1786886056.023822,
|
||||||
"ast_hash": "99d3e1139042d0eb61627155dddb3843",
|
"ast_hash": "99d3e1139042d0eb61627155dddb3843",
|
||||||
"semantic_hash": ""
|
"semantic_hash": ""
|
||||||
},
|
},
|
||||||
@@ -465,7 +465,7 @@
|
|||||||
"semantic_hash": "bcc3101498a66cf8b79f9d97c6c9cd6b"
|
"semantic_hash": "bcc3101498a66cf8b79f9d97c6c9cd6b"
|
||||||
},
|
},
|
||||||
"backend/internal/web/templates/readers.html": {
|
"backend/internal/web/templates/readers.html": {
|
||||||
"mtime": 1786864296.770521,
|
"mtime": 1786886056.023822,
|
||||||
"ast_hash": "2b1cbb24d6185e48561966db1af04ba4",
|
"ast_hash": "2b1cbb24d6185e48561966db1af04ba4",
|
||||||
"semantic_hash": ""
|
"semantic_hash": ""
|
||||||
},
|
},
|
||||||
@@ -635,42 +635,42 @@
|
|||||||
"semantic_hash": ""
|
"semantic_hash": ""
|
||||||
},
|
},
|
||||||
"backend/internal/latest/status.go": {
|
"backend/internal/latest/status.go": {
|
||||||
"mtime": 1786865033.5648637,
|
"mtime": 1786891396.3216066,
|
||||||
"ast_hash": "8141514efa5a7a66e77b9a62d4982d52",
|
"ast_hash": "5893c77b117a5bcec3a4583aa51e7f42",
|
||||||
"semantic_hash": ""
|
"semantic_hash": ""
|
||||||
},
|
},
|
||||||
"backend/internal/store/migrations/0010_reader_sightings.sql": {
|
"backend/internal/store/migrations/0010_reader_sightings.sql": {
|
||||||
"mtime": 1786863695.6957178,
|
"mtime": 1786886056.0200372,
|
||||||
"ast_hash": "a72c08c63fad530df3c793d16edfa385",
|
"ast_hash": "a72c08c63fad530df3c793d16edfa385",
|
||||||
"semantic_hash": ""
|
"semantic_hash": ""
|
||||||
},
|
},
|
||||||
"backend/internal/web/admin.go": {
|
"backend/internal/web/admin.go": {
|
||||||
"mtime": 1786865087.473256,
|
"mtime": 1786891411.0618205,
|
||||||
"ast_hash": "b1c0f23a102a9bc7f84adf306d743f56",
|
"ast_hash": "e02249496b57096cf1929f9cd0e35c3e",
|
||||||
"semantic_hash": ""
|
"semantic_hash": ""
|
||||||
},
|
},
|
||||||
"backend/internal/web/templates/admin.html": {
|
"backend/internal/web/templates/admin.html": {
|
||||||
"mtime": 1786865108.4095602,
|
"mtime": 1786886056.023822,
|
||||||
"ast_hash": "f04ea1cb01369d53053eac489e796faa",
|
"ast_hash": "f04ea1cb01369d53053eac489e796faa",
|
||||||
"semantic_hash": ""
|
"semantic_hash": ""
|
||||||
},
|
},
|
||||||
"backend/internal/web/templates/lanes.html": {
|
"backend/internal/web/templates/lanes.html": {
|
||||||
"mtime": 1786865113.5362902,
|
"mtime": 1786891416.6118941,
|
||||||
"ast_hash": "8b9f9c7a56e0ec3bf950aa70acd95e92",
|
"ast_hash": "0e96f66560bac29713a71ec31139d25e",
|
||||||
"semantic_hash": ""
|
"semantic_hash": ""
|
||||||
},
|
},
|
||||||
"backend/internal/latest/sighting_test.go": {
|
"backend/internal/latest/sighting_test.go": {
|
||||||
"mtime": 1786868815.9760568,
|
"mtime": 1786886056.0200372,
|
||||||
"ast_hash": "3b1372bbeeb538b73f86f57da210b4cc",
|
"ast_hash": "3b1372bbeeb538b73f86f57da210b4cc",
|
||||||
"semantic_hash": ""
|
"semantic_hash": ""
|
||||||
},
|
},
|
||||||
"backend/internal/store/migrations/0011_series_sightings.sql": {
|
"backend/internal/store/migrations/0011_series_sightings.sql": {
|
||||||
"mtime": 1786867605.3728056,
|
"mtime": 1786886056.0200372,
|
||||||
"ast_hash": "d0ade928a6e951eb179e4d0255cca526",
|
"ast_hash": "d0ade928a6e951eb179e4d0255cca526",
|
||||||
"semantic_hash": ""
|
"semantic_hash": ""
|
||||||
},
|
},
|
||||||
"docs/adr/0011-sighting-deferral-trust-model.md": {
|
"docs/adr/0011-sighting-deferral-trust-model.md": {
|
||||||
"mtime": 1786872970.473592,
|
"mtime": 1786886056.0313923,
|
||||||
"ast_hash": "0b6ca704f62185c9d629320f2d8475b5",
|
"ast_hash": "0b6ca704f62185c9d629320f2d8475b5",
|
||||||
"semantic_hash": ""
|
"semantic_hash": ""
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user