Compare commits

..

1 Commits

Author SHA1 Message Date
sulthan 81631ef08f fix: don't read Cloudflare's injected jsd script as a refusal
demonicscans.org turned JS detections on, so Cloudflare began injecting
/cdn-cgi/challenge-platform/scripts/jsd/main.js into ordinary 200 pages.
isInterstitial matched the bare /cdn-cgi/challenge-platform/ prefix, so
every real demonic series page became errChallengeHeld: two per pass
parked the Lane in the 15m refusal backoff while plain TLS was in fact
returning the full page (200, 133KB, 22 chapter anchors, verified live
2026-08-16).

Match the challenge orchestration path /cdn-cgi/challenge-platform/h/
instead — served only by the interstitial itself, stable across its
wording and locale.
2026-08-16 21:17:10 +07:00
12 changed files with 615 additions and 834 deletions
-6
View File
@@ -266,9 +266,3 @@ 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.
+1 -1
View File
@@ -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, st.Asleep = defaultGap, true st.Gap = defaultGap
return defaultGap return defaultGap
} }
if s.Browser != nil { if s.Browser != nil {
-21
View File
@@ -1388,11 +1388,6 @@ 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)
@@ -1401,9 +1396,6 @@ 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())
@@ -1412,19 +1404,6 @@ 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).
-5
View File
@@ -19,11 +19,6 @@ 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).
+3 -8
View File
@@ -61,11 +61,8 @@ 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). A // — the difference between a stopped Lane and a quiet one (story 13).
// 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
@@ -155,9 +152,8 @@ 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 — or one // working, as distinct from one that is quiet for want of work.
// deliberately leaving Chrome asleep until its group gathers. stalled := l.Due > 0 && l.Checked == 0
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()
@@ -172,7 +168,6 @@ 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,7 +23,6 @@
{{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>
-31
View File
@@ -776,37 +776,6 @@ 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.
+5 -1
View File
@@ -12,8 +12,9 @@
"10": "Go Test Helpers", "10": "Go Test Helpers",
"11": "Store Tests", "11": "Store Tests",
"12": "Bookmarks API Handler", "12": "Bookmarks API Handler",
"13": "displayChapter", "13": "Web UI Handlers",
"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",
@@ -29,6 +30,7 @@
"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",
@@ -39,6 +41,7 @@
"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",
@@ -121,6 +124,7 @@
"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",
+44 -28
View File
@@ -1,16 +1,16 @@
# Graph Report - mangaBookmark (2026-08-16) # Graph Report - mangaBookmark (2026-08-16)
## Corpus Check ## Corpus Check
- 119 files · ~291,777 words - 119 files · ~290,953 words
- Verdict: corpus is large enough that graph structure adds value. - Verdict: corpus is large enough that graph structure adds value.
## Summary ## Summary
- 1739 nodes · 3610 edges · 217 communities (67 shown, 150 thin omitted) - 1736 nodes · 3597 edges · 221 communities (70 shown, 151 thin omitted)
- Extraction: 90% EXTRACTED · 10% INFERRED · 0% AMBIGUOUS · INFERRED: 363 edges (avg confidence: 0.78) - Extraction: 90% EXTRACTED · 10% INFERRED · 0% AMBIGUOUS · INFERRED: 361 edges (avg confidence: 0.78)
- Token cost: 0 input · 0 output - Token cost: 0 input · 0 output
## Graph Freshness ## Graph Freshness
- Built from commit: `20fff588` - Built from commit: `56afb9f2`
- 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,8 +28,9 @@
- [[_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_displayChapter|displayChapter]] - [[_COMMUNITY_Web UI Handlers|Web UI Handlers]]
- [[_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]]
@@ -45,6 +46,7 @@
- [[_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]]
@@ -54,6 +56,7 @@
- [[_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]]
@@ -136,6 +139,7 @@
- [[_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]]
@@ -266,7 +270,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 (217 total, 150 thin omitted) ## Communities (221 total, 151 thin omitted)
### Community 0 - "HTMX Library Internals" ### Community 0 - "HTMX Library Internals"
Cohesion: 0.08 Cohesion: 0.08
@@ -274,7 +278,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 (88): floatPtr(), testConfig(), getCover(), Cookie, Handler, ResponseRecorder, T, TestListRendersAcquiredCover() (+80 more) Nodes (89): floatPtr(), testConfig(), getCover(), Cookie, Handler, ResponseRecorder, T, TestListRendersAcquiredCover() (+81 more)
### Community 2 - "Manga Userscript Adapters" ### Community 2 - "Manga Userscript Adapters"
Cohesion: 0.06 Cohesion: 0.06
@@ -289,12 +293,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.11 Cohesion: 0.07
Nodes (54): auth(), getBookmarks(), Handler, Request, Store, T, newTestServer(), newTestStore() (+46 more) Nodes (71): auth(), getBookmarks(), Handler, Request, Store, T, newTestServer(), newTestStore() (+63 more)
### Community 7 - "Cover & Acquire Internals" ### Community 7 - "Cover & Acquire Internals"
Cohesion: 0.08 Cohesion: 0.06
Nodes (31): fakeLanes, Context, Store, WaitGroup, isInterstitial(), fetchCoverBytes(), browserWakeDue(), fetcherFor() (+23 more) Nodes (43): Addr, fakeLanes, Context, Store, WaitGroup, isInterstitial(), defaultCoverResolver(), fetchCoverBytes() (+35 more)
### Community 8 - "System Architecture Concepts" ### Community 8 - "System Architecture Concepts"
Cohesion: 0.15 Cohesion: 0.15
@@ -309,21 +313,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.07 Cohesion: 0.14
Nodes (81): M, TestMain(), M, TestMain(), M, Main(), start(), URL() (+73 more) Nodes (45): Store, T, newTestStore(), readLatestCheckedAt(), readSeries(), secondReader(), seedForCheck(), seedSecondReader() (+37 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)
@@ -361,8 +365,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.06 Cohesion: 0.05
Nodes (57): awaitPromise(), browserConnectionLost(), classifyBrowserError(), comixRead(), comixSeriesPageURL(), Action, Context, Mutex (+49 more) Nodes (61): awaitPromise(), browserConnectionLost(), classifyBrowserError(), comixRead(), comixSeriesPageURL(), Action, Context, Mutex (+53 more)
### Community 27 - "Find Skills Guide" ### Community 27 - "Find Skills Guide"
Cohesion: 0.14 Cohesion: 0.14
@@ -380,6 +384,10 @@ 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)
@@ -409,8 +417,12 @@ 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.05 Cohesion: 0.14
Nodes (25): coverRelativePath(), coverSourceAddress(), displayChapter(), Store, scanSeries(), currentLib(), currentTab(), filterBookmarks() (+17 more) Nodes (18): currentLib(), currentTab(), filterBookmarks(), Client, HandlerFunc, Request, ResponseWriter, Store (+10 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
@@ -520,6 +532,10 @@ 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
@@ -535,17 +551,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.
- **150 thin communities (<3 nodes) omitted from report** — run `graphify query` to explore isolated nodes. - **151 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 `Store Tests` to `Cover Fetch Test Helpers`, `Series Acquisition Tests`, `Bookmarks API Tests`, `Handler`, `displayChapter`?** - **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.057) - this node is a cross-community bridge._ _High betweenness centrality (0.060) - this node is a cross-community bridge._
- **Why does `New()` connect `Series Acquisition Tests` to `Bookmarks API Tests`, `Cover & Acquire Internals`, `Handler`, `Session Middleware`, `Store Tests`, `displayChapter`, `ResponseWriter`?** - **Why does `New()` connect `Series Acquisition Tests` to `Bookmarks API Tests`, `Cover & Acquire Internals`, `Handler`, `Session Middleware`, `CDP Browser Client`, `ResponseWriter`?**
_High betweenness centrality (0.051) - this node is a cross-community bridge._ _High betweenness centrality (0.050) - this node is a cross-community bridge._
- **Why does `newRouter()` connect `Bookmarks API Tests` to `Cover Fetch Test Helpers`, `Series Acquisition Tests`, `Bookmarks API Handler`, `displayChapter`, `ResponseWriter`?** - **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._ _High betweenness centrality (0.030) - 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
+519 -689
View File
File diff suppressed because it is too large Load Diff
+39 -39
View File
@@ -25,7 +25,7 @@
"semantic_hash": "dac242903b0e98c3e4395159d609e08e" "semantic_hash": "dac242903b0e98c3e4395159d609e08e"
}, },
"backend/main.go": { "backend/main.go": {
"mtime": 1786886056.023822, "mtime": 1786863963.3450089,
"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": 1786886056.0389624, "mtime": 1786872888.3482232,
"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": 1786891437.925184, "mtime": 1786865248.7717106,
"ast_hash": "74aed7f5a5b196d2b860cd6a34266ec6", "ast_hash": "7c298e39c63e4502cf6272d1e206e9ef",
"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": 1786886056.0313923, "mtime": 1786865139.9022946,
"ast_hash": "3bd39932997c8e245508874194db4e49", "ast_hash": "3bd39932997c8e245508874194db4e49",
"semantic_hash": "" "semantic_hash": ""
}, },
"backend/api_test.go": { "backend/api_test.go": {
"mtime": 1786886056.016252, "mtime": 1786868080.2317674,
"ast_hash": "b64372df5429fb14e48b37b3bab10402", "ast_hash": "b64372df5429fb14e48b37b3bab10402",
"semantic_hash": "" "semantic_hash": ""
}, },
"backend/cover_test.go": { "backend/cover_test.go": {
"mtime": 1786886056.016252, "mtime": 1786863966.7084978,
"ast_hash": "fd6b3f6ef46bd17b0241d104b6e5bdf6", "ast_hash": "fd6b3f6ef46bd17b0241d104b6e5bdf6",
"semantic_hash": "" "semantic_hash": ""
}, },
"backend/internal/api/handlers.go": { "backend/internal/api/handlers.go": {
"mtime": 1786886056.016252, "mtime": 1786867745.788687,
"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": 1786889854.5578685, "mtime": 1786861012.026504,
"ast_hash": "b65f3693db77c69ef0a6247fd75118bc", "ast_hash": "75f34a974568d122681939dd297944a2",
"semantic_hash": "" "semantic_hash": ""
}, },
"backend/internal/latest/browser_test.go": { "backend/internal/latest/browser_test.go": {
"mtime": 1786889854.5578685, "mtime": 1786857336.6414917,
"ast_hash": "118aba3d794b9faf893c45e58298e11a", "ast_hash": "800fa6aa471ada054a3c48943ad17ab7",
"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": 1786891405.415882, "mtime": 1786872774.641225,
"ast_hash": "54f6eec9d2090c7713f502c8553063a2", "ast_hash": "5e55e2ac5cb7d347807754f92425d29b",
"semantic_hash": "" "semantic_hash": ""
}, },
"backend/internal/latest/poller_test.go": { "backend/internal/latest/poller_test.go": {
"mtime": 1786891462.5665002, "mtime": 1786865291.3758123,
"ast_hash": "512806a9c6e15036a75f01bf5577c20b", "ast_hash": "1da669ac748a8d1a0289e557392fa3fd",
"semantic_hash": "" "semantic_hash": ""
}, },
"backend/internal/latest/sites.go": { "backend/internal/latest/sites.go": {
"mtime": 1786886056.0200372, "mtime": 1786868771.0663204,
"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": 1786886056.0200372, "mtime": 1786868763.646761,
"ast_hash": "34f55617b7409f03f02e925bec92fac0", "ast_hash": "34f55617b7409f03f02e925bec92fac0",
"semantic_hash": "" "semantic_hash": ""
}, },
"backend/internal/store/store_test.go": { "backend/internal/store/store_test.go": {
"mtime": 1786886056.0200372, "mtime": 1786867781.301985,
"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": 1786886056.023822, "mtime": 1786863744.1453943,
"ast_hash": "b051f2de214c4b253ee09fbbdb8ebb60", "ast_hash": "b051f2de214c4b253ee09fbbdb8ebb60",
"semantic_hash": "" "semantic_hash": ""
}, },
"backend/reader_credential_test.go": { "backend/reader_credential_test.go": {
"mtime": 1786886056.023822, "mtime": 1786863966.7092986,
"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": 1786886056.0389624, "mtime": 1786872902.809149,
"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": 1786891513.6486945, "mtime": 1786872951.3127444,
"ast_hash": "b4233ebc5ff905b701ded9427277ad8c", "ast_hash": "68bc86af9593adad1e37fa05188fe63e",
"semantic_hash": "" "semantic_hash": ""
}, },
"backend/CLAUDE.md": { "backend/CLAUDE.md": {
"mtime": 1786891513.6486945, "mtime": 1786872951.3127444,
"ast_hash": "b4233ebc5ff905b701ded9427277ad8c", "ast_hash": "68bc86af9593adad1e37fa05188fe63e",
"semantic_hash": "" "semantic_hash": ""
}, },
"backend/internal/web/templates/app.html": { "backend/internal/web/templates/app.html": {
"mtime": 1786886056.023822, "mtime": 1786864445.1584811,
"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": 1786886056.023822, "mtime": 1786864296.770521,
"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": 1786891396.3216066, "mtime": 1786865033.5648637,
"ast_hash": "5893c77b117a5bcec3a4583aa51e7f42", "ast_hash": "8141514efa5a7a66e77b9a62d4982d52",
"semantic_hash": "" "semantic_hash": ""
}, },
"backend/internal/store/migrations/0010_reader_sightings.sql": { "backend/internal/store/migrations/0010_reader_sightings.sql": {
"mtime": 1786886056.0200372, "mtime": 1786863695.6957178,
"ast_hash": "a72c08c63fad530df3c793d16edfa385", "ast_hash": "a72c08c63fad530df3c793d16edfa385",
"semantic_hash": "" "semantic_hash": ""
}, },
"backend/internal/web/admin.go": { "backend/internal/web/admin.go": {
"mtime": 1786891411.0618205, "mtime": 1786865087.473256,
"ast_hash": "e02249496b57096cf1929f9cd0e35c3e", "ast_hash": "b1c0f23a102a9bc7f84adf306d743f56",
"semantic_hash": "" "semantic_hash": ""
}, },
"backend/internal/web/templates/admin.html": { "backend/internal/web/templates/admin.html": {
"mtime": 1786886056.023822, "mtime": 1786865108.4095602,
"ast_hash": "f04ea1cb01369d53053eac489e796faa", "ast_hash": "f04ea1cb01369d53053eac489e796faa",
"semantic_hash": "" "semantic_hash": ""
}, },
"backend/internal/web/templates/lanes.html": { "backend/internal/web/templates/lanes.html": {
"mtime": 1786891416.6118941, "mtime": 1786865113.5362902,
"ast_hash": "0e96f66560bac29713a71ec31139d25e", "ast_hash": "8b9f9c7a56e0ec3bf950aa70acd95e92",
"semantic_hash": "" "semantic_hash": ""
}, },
"backend/internal/latest/sighting_test.go": { "backend/internal/latest/sighting_test.go": {
"mtime": 1786886056.0200372, "mtime": 1786868815.9760568,
"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": 1786886056.0200372, "mtime": 1786867605.3728056,
"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": 1786886056.0313923, "mtime": 1786872970.473592,
"ast_hash": "0b6ca704f62185c9d629320f2d8475b5", "ast_hash": "0b6ca704f62185c9d629320f2d8475b5",
"semantic_hash": "" "semantic_hash": ""
} }