chore: drop asuracomic.net from the userscript, CORS allowlist and docs (#97)
Closes #96. ## What Removes every reference that still invites a Reader onto `asuracomic.net`. The domain's deep links 301 to the `asurascans.com` **root**, discarding the path (re-checked 2026-07-25), so a page on it never yields a series document client-side and a stored address on it never yields a series page server-side. #95 already pinned each Site to one hostname, so the backend rejects such an address cleanly; this is the cleanup around that. | File | Change | |---|---| | `userscript/manga-bookmark.user.js` | drops the `@match`, narrows the asura adapter to `/(^\|\.)asurascans\.com$/` | | `userscript/test/logic.test.js` | new test pinning the narrowed host match | | `.env.example`, `docker-compose.yml` | origin dropped from the `ALLOWED_ORIGINS` default | | `DEPLOY.md` | same, and the sample list gains the two novel origins it was missing | | `backend/api_test.go` | CORS fixtures and round-trip seed move to `asurascans.com` | | `README.md`, `AGENTS.md` | notes say the host is dropped, not "stays matched" | ## Behaviour - A Reader landing on `asuracomic.net` gets no userscript UI. Previously the script loaded and could do nothing useful — the redirect had already discarded the path. - A request whose `Origin` is `https://asuracomic.net` is no longer reflected by a deployment using the shipped defaults. - No backend logic changed: the CORS rule, the address gate and the poller are untouched. `AllowedOrigins` is data, not code. ## Security invariant preserved CORS still reflects `Origin` only when it appears in `ALLOWED_ORIGINS`, with `GET,PUT,DELETE,OPTIONS` and a `204` preflight — `TestCORSPreflight` and `TestCORSDisallowedOrigin` still pin both halves, now against a live origin. This change only removes a value from the allowlist, which is a narrowing. ## Verification - `go test ./...` — full backend suite green (real Postgres per package). - `node --test test/*.test.js` — 66/66 green, up one from the new match test. ## Deploy note (does not happen on merge) The live allowlist comes from the VPS `.env`, not from these defaults, so the origin must be dropped there in the same deploy. The one-off row repair for any stored `asuracomic.net` address is in #96. Reviewed-on: #97 Co-authored-by: Sulthan Zaki <sultankiki05@gmail.com> Co-committed-by: Sulthan Zaki <sultankiki05@gmail.com>
This commit was merged in pull request #97.
This commit is contained in:
+1
-1
@@ -15,7 +15,7 @@ OWNER_DISCORD_ID=changeme-your-discord-user-id
|
|||||||
# Comma-separated origins allowed to call the API (CORS). Both Asura domains
|
# Comma-separated origins allowed to call the API (CORS). Both Asura domains
|
||||||
# plus Demonic, Comix, Kagane, and the two novel sites. Add/remove as the
|
# plus Demonic, Comix, Kagane, and the two novel sites. Add/remove as the
|
||||||
# sites' hostnames change.
|
# sites' hostnames change.
|
||||||
ALLOWED_ORIGINS=https://asuracomic.net,https://asurascans.com,https://demonicscans.org,https://comix.to,https://kagane.to,https://novelfull.com,https://lightnovelworld.net
|
ALLOWED_ORIGINS=https://asurascans.com,https://demonicscans.org,https://comix.to,https://kagane.to,https://novelfull.com,https://lightnovelworld.net
|
||||||
|
|
||||||
# Password for the bundled Postgres container, and therefore half of the
|
# Password for the bundled Postgres container, and therefore half of the
|
||||||
# DATABASE_URL compose builds for the backend. Generate one:
|
# DATABASE_URL compose builds for the backend. Generate one:
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ Guidance for OpenCode (and Claude Code) working in this repo.
|
|||||||
|
|
||||||
Read-progress tracker for two libraries — manga and novels — behind one self-hosted Go backend. Two separate Violentmonkey userscripts inject on-page UI (floating button + slide-in panel) and sync progress, so bookmarks unify across sites and devices:
|
Read-progress tracker for two libraries — manga and novels — behind one self-hosted Go backend. Two separate Violentmonkey userscripts inject on-page UI (floating button + slide-in panel) and sync progress, so bookmarks unify across sites and devices:
|
||||||
|
|
||||||
- `manga-bookmark.user.js` — **asurascans.com** (current domain; asuracomic.net 301s here), **demonicscans.org**, **comix.to**, **kagane.to**.
|
- `manga-bookmark.user.js` — **asurascans.com** (asuracomic.net is dropped: its deep links 301 to the asurascans.com root, discarding the path), **demonicscans.org**, **comix.to**, **kagane.to**.
|
||||||
- `novel-bookmark.user.js` — **novelfull.com**, **lightnovelworld.net**.
|
- `novel-bookmark.user.js` — **novelfull.com**, **lightnovelworld.net**.
|
||||||
|
|
||||||
One backend, one `bookmarks` table: a `kind` column (`manga`|`novel`) splits the libraries and the web UI switches between them. Rows are keyed `<site>:<series_id>`.
|
One backend, one `bookmarks` table: a `kind` column (`manga`|`novel`) splits the libraries and the web UI switches between them. Rows are keyed `<site>:<series_id>`.
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ TOKEN_KEY=<paste output of: openssl rand -hex 32>
|
|||||||
OWNER_DISCORD_ID=<discord user id>
|
OWNER_DISCORD_ID=<discord user id>
|
||||||
|
|
||||||
# CORS allowlist — leave as-is unless a site changes hostname.
|
# CORS allowlist — leave as-is unless a site changes hostname.
|
||||||
ALLOWED_ORIGINS=https://asuracomic.net,https://asurascans.com,https://demonicscans.org,https://comix.to,https://kagane.to
|
ALLOWED_ORIGINS=https://asurascans.com,https://demonicscans.org,https://comix.to,https://kagane.to,https://novelfull.com,https://lightnovelworld.net
|
||||||
|
|
||||||
# Required — password for the bundled Postgres container. Compose builds the
|
# Required — password for the bundled Postgres container. Compose builds the
|
||||||
# backend's DATABASE_URL out of it and has no fallback for either.
|
# backend's DATABASE_URL out of it and has no fallback for either.
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Manga Bookmark
|
# Manga Bookmark
|
||||||
|
|
||||||
Track manga read-progress on **asurascans.com** (a.k.a. asuracomic.net),
|
Track manga read-progress on **asurascans.com**,
|
||||||
**demonicscans.org**, **comix.to**, and **kagane.to** from a phone (Bromite /
|
**demonicscans.org**, **comix.to**, and **kagane.to** from a phone (Bromite /
|
||||||
mobile Chromium), synced to a self-hosted Go backend so bookmarks unify across
|
mobile Chromium), synced to a self-hosted Go backend so bookmarks unify across
|
||||||
all four sites and all devices.
|
all four sites and all devices.
|
||||||
@@ -274,11 +274,12 @@ the backend acquires, stores and serves every Cover from its own origin
|
|||||||
| **Kagane** (`kagane.to`) | `/series/<uuid>` | `/series/<uuid>/reader/<bookUuid>` | `<uuid>` |
|
| **Kagane** (`kagane.to`) | `/series/<uuid>` | `/series/<uuid>/reader/<bookUuid>` | `<uuid>` |
|
||||||
|
|
||||||
Notes:
|
Notes:
|
||||||
- **`asuracomic.net` deep links are dead (re-checked 2026-07-25).** They 301 to
|
- **`asuracomic.net` is no longer matched (deep links dead, re-checked
|
||||||
the `asurascans.com` **root**, discarding the path, at the edge — before the
|
2026-07-25).** They 301 to the `asurascans.com` **root**, discarding the path,
|
||||||
userscript gets a document — so nothing client-side can rescue them. Reach
|
at the edge — before the userscript gets a document — so nothing client-side
|
||||||
series through `asurascans.com`. The host stays matched in case the redirect
|
can rescue them. The backend rejects stored addresses on that host too, since
|
||||||
starts preserving paths again.
|
the poller pins each Site to one hostname. Reach series through
|
||||||
|
`asurascans.com`.
|
||||||
- Asura `og:title` carries a `Chapter N - Read Online \| Asura Scans` suffix that
|
- Asura `og:title` carries a `Chapter N - Read Online \| Asura Scans` suffix that
|
||||||
the adapter strips; Demonic chapter `og:title` is `<Title> Chapter N`.
|
the adapter strips; Demonic chapter `og:title` is `<Title> Chapter N`.
|
||||||
- Demonic's `<slug>` is identical on `/manga/…` and the canonical `/title/…`
|
- Demonic's `<slug>` is identical on `/manga/…` and the canonical `/title/…`
|
||||||
|
|||||||
+6
-6
@@ -33,7 +33,7 @@ const testCoverBaseURL = "https://bookmarks.test"
|
|||||||
func testConfig() Config {
|
func testConfig() Config {
|
||||||
return Config{
|
return Config{
|
||||||
TokenKey: testTokenKey,
|
TokenKey: testTokenKey,
|
||||||
AllowedOrigins: []string{"https://asuracomic.net", "https://demonicscans.org"},
|
AllowedOrigins: []string{"https://asurascans.com", "https://demonicscans.org"},
|
||||||
Port: "8080",
|
Port: "8080",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -169,7 +169,7 @@ func TestAuthAccepted(t *testing.T) {
|
|||||||
func TestCORSPreflight(t *testing.T) {
|
func TestCORSPreflight(t *testing.T) {
|
||||||
srv := newTestServer(t)
|
srv := newTestServer(t)
|
||||||
req := httptest.NewRequest(http.MethodOptions, "/bookmarks/asura:foo-1", nil)
|
req := httptest.NewRequest(http.MethodOptions, "/bookmarks/asura:foo-1", nil)
|
||||||
req.Header.Set("Origin", "https://asuracomic.net")
|
req.Header.Set("Origin", "https://asurascans.com")
|
||||||
req.Header.Set("Access-Control-Request-Method", "PUT")
|
req.Header.Set("Access-Control-Request-Method", "PUT")
|
||||||
rr := httptest.NewRecorder()
|
rr := httptest.NewRecorder()
|
||||||
srv.ServeHTTP(rr, req)
|
srv.ServeHTTP(rr, req)
|
||||||
@@ -177,7 +177,7 @@ func TestCORSPreflight(t *testing.T) {
|
|||||||
if rr.Code != http.StatusNoContent {
|
if rr.Code != http.StatusNoContent {
|
||||||
t.Fatalf("preflight status = %d, want 204", rr.Code)
|
t.Fatalf("preflight status = %d, want 204", rr.Code)
|
||||||
}
|
}
|
||||||
if got := rr.Header().Get("Access-Control-Allow-Origin"); got != "https://asuracomic.net" {
|
if got := rr.Header().Get("Access-Control-Allow-Origin"); got != "https://asurascans.com" {
|
||||||
t.Fatalf("Allow-Origin = %q, want reflected origin", got)
|
t.Fatalf("Allow-Origin = %q, want reflected origin", got)
|
||||||
}
|
}
|
||||||
if got := rr.Header().Get("Access-Control-Allow-Methods"); got == "" {
|
if got := rr.Header().Get("Access-Control-Allow-Methods"); got == "" {
|
||||||
@@ -204,11 +204,11 @@ func TestBookmarkRoundTrip(t *testing.T) {
|
|||||||
key := "asura:solo-leveling-123"
|
key := "asura:solo-leveling-123"
|
||||||
in := store.Bookmark{
|
in := store.Bookmark{
|
||||||
Title: "Solo Leveling",
|
Title: "Solo Leveling",
|
||||||
SeriesURL: "https://asuracomic.net/series/solo-leveling-123",
|
SeriesURL: "https://asurascans.com/series/solo-leveling-123",
|
||||||
Cover: "https://asuracomic.net/cover.jpg",
|
Cover: "https://asurascans.com/cover.jpg",
|
||||||
LastChapter: "Chapter 10",
|
LastChapter: "Chapter 10",
|
||||||
LastChapterNum: 10,
|
LastChapterNum: 10,
|
||||||
LastChapterURL: "https://asuracomic.net/series/solo-leveling-123/chapter/10",
|
LastChapterURL: "https://asurascans.com/series/solo-leveling-123/chapter/10",
|
||||||
}
|
}
|
||||||
body, _ := json.Marshal(in)
|
body, _ := json.Marshal(in)
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -25,7 +25,7 @@ services:
|
|||||||
# Owner's Discord user ID — required. Seeds the owner Reader (the
|
# Owner's Discord user ID — required. Seeds the owner Reader (the
|
||||||
# administrator); every other Reader registers on their first login.
|
# administrator); every other Reader registers on their first login.
|
||||||
OWNER_DISCORD_ID: ${OWNER_DISCORD_ID:?set OWNER_DISCORD_ID in .env}
|
OWNER_DISCORD_ID: ${OWNER_DISCORD_ID:?set OWNER_DISCORD_ID in .env}
|
||||||
ALLOWED_ORIGINS: ${ALLOWED_ORIGINS:-https://asuracomic.net,https://asurascans.com,https://demonicscans.org,https://comix.to,https://kagane.to,https://novelfull.com,https://lightnovelworld.net}
|
ALLOWED_ORIGINS: ${ALLOWED_ORIGINS:-https://asurascans.com,https://demonicscans.org,https://comix.to,https://kagane.to,https://novelfull.com,https://lightnovelworld.net}
|
||||||
# The bookmarks database. Host is the compose service name; the password
|
# The bookmarks database. Host is the compose service name; the password
|
||||||
# comes from .env so it is never committed.
|
# comes from .env so it is never committed.
|
||||||
DATABASE_URL: ${DATABASE_URL:-postgres://bookmarks:${POSTGRES_PASSWORD:?set POSTGRES_PASSWORD in .env}@postgres:5432/bookmarks?sslmode=disable}
|
DATABASE_URL: ${DATABASE_URL:-postgres://bookmarks:${POSTGRES_PASSWORD:?set POSTGRES_PASSWORD in .env}@postgres:5432/bookmarks?sslmode=disable}
|
||||||
|
|||||||
@@ -15,10 +15,8 @@
|
|||||||
"13": "Web UI Handlers",
|
"13": "Web UI Handlers",
|
||||||
"14": "Go Error Handling",
|
"14": "Go Error Handling",
|
||||||
"15": "CDP Browser Client",
|
"15": "CDP Browser Client",
|
||||||
"16": "Store",
|
|
||||||
"17": "Go Code Style Guide",
|
"17": "Go Code Style Guide",
|
||||||
"18": "Agent Skills",
|
"18": "Agent Skills",
|
||||||
"19": "Open",
|
|
||||||
"20": "I/O Performance Patterns",
|
"20": "I/O Performance Patterns",
|
||||||
"21": "CPU Optimization",
|
"21": "CPU Optimization",
|
||||||
"22": "Caching Patterns",
|
"22": "Caching Patterns",
|
||||||
@@ -29,7 +27,6 @@
|
|||||||
"27": "Find Skills Guide",
|
"27": "Find Skills Guide",
|
||||||
"28": "Allocation Patterns",
|
"28": "Allocation Patterns",
|
||||||
"29": "Observability & Alerting",
|
"29": "Observability & Alerting",
|
||||||
"30": "PG Test Infrastructure",
|
|
||||||
"31": "Memory Layout",
|
"31": "Memory Layout",
|
||||||
"32": "Repo Hard Constraints",
|
"32": "Repo Hard Constraints",
|
||||||
"33": "Go Testing Guide",
|
"33": "Go Testing Guide",
|
||||||
@@ -40,8 +37,6 @@
|
|||||||
"38": "novel-logic.test.js",
|
"38": "novel-logic.test.js",
|
||||||
"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": "DB Cutover Runbook",
|
|
||||||
"42": "Memory Layout Patterns",
|
|
||||||
"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 +119,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": "Duration",
|
|
||||||
"126": "Bookmark Manager",
|
"126": "Bookmark Manager",
|
||||||
"127": "triage-labels.md",
|
"127": "triage-labels.md",
|
||||||
"128": "Cross-Ticket Contract",
|
"128": "Cross-Ticket Contract",
|
||||||
@@ -152,14 +146,6 @@
|
|||||||
"150": "Reviewer Subagent (opencode)",
|
"150": "Reviewer Subagent (opencode)",
|
||||||
"151": "Finding Severity Rubric",
|
"151": "Finding Severity Rubric",
|
||||||
"152": "Spec Compliance Review",
|
"152": "Spec Compliance Review",
|
||||||
"153": "CDP Browser Unit (chrome/)",
|
|
||||||
"154": "Cinder Design System",
|
|
||||||
"155": "Cloudflare Challenge Behaviour",
|
|
||||||
"156": "Ember Means New Chapter Only",
|
|
||||||
"157": "Gitea + tea CLI",
|
|
||||||
"158": "Graphify Knowledge Graph",
|
|
||||||
"159": "novel-bookmark.user.js",
|
|
||||||
"160": "Security Invariants",
|
|
||||||
"161": "Why Use samber/oops",
|
"161": "Why Use samber/oops",
|
||||||
"162": "singleflight Cache Stampede Prevention",
|
"162": "singleflight Cache Stampede Prevention",
|
||||||
"163": "Struct Field Alignment",
|
"163": "Struct Field Alignment",
|
||||||
@@ -184,15 +170,6 @@
|
|||||||
"194": "SQLite-to-Postgres Cutover Runbook",
|
"194": "SQLite-to-Postgres Cutover Runbook",
|
||||||
"195": "Import SQL Generation Rules",
|
"195": "Import SQL Generation Rules",
|
||||||
"196": "Throwaway Import Generator",
|
"196": "Throwaway Import Generator",
|
||||||
"197": "ADR-0002 (Discord OAuth Sign-In)",
|
|
||||||
"198": "ADR-0006 (Browser Out of API Stack)",
|
|
||||||
"199": "ADR-0007 (Absolute Cover URLs)",
|
|
||||||
"200": "bookmark-api Service",
|
|
||||||
"201": "Deployment Runbook",
|
|
||||||
"202": "Issue #24 (Derived Credentials)",
|
|
||||||
"203": "Tailscale ACL Tagging",
|
|
||||||
"204": "TOKEN_KEY Credential Derivation",
|
|
||||||
"205": "Traefik Reverse Proxy",
|
|
||||||
"206": "Real scaling limit is the poller outbound fetch budget",
|
"206": "Real scaling limit is the poller outbound fetch budget",
|
||||||
"207": "PostgreSQL (jackc/pgx/v5)",
|
"207": "PostgreSQL (jackc/pgx/v5)",
|
||||||
"208": "SQLite (modernc.org/sqlite)",
|
"208": "SQLite (modernc.org/sqlite)",
|
||||||
@@ -249,12 +226,6 @@
|
|||||||
"259": "Dark-First Design Constraint",
|
"259": "Dark-First Design Constraint",
|
||||||
"260": "Discord Guild Membership",
|
"260": "Discord Guild Membership",
|
||||||
"261": "Reader Isolation Invariant",
|
"261": "Reader Isolation Invariant",
|
||||||
"262": "Site Adapters",
|
|
||||||
"263": "Go Backend (backend/)",
|
|
||||||
"264": "localStorage Cache and Retry Queue",
|
|
||||||
"265": "Latest Chapter Poller",
|
|
||||||
"266": "Postgres Store (postgres:17-alpine)",
|
|
||||||
"267": "README Config and Endpoint Reference",
|
|
||||||
"268": "Browser Unit Redeploy",
|
"268": "Browser Unit Redeploy",
|
||||||
"269": "pg_dump Hot Backup",
|
"269": "pg_dump Hot Backup",
|
||||||
"270": "Redeploy Runbook",
|
"270": "Redeploy Runbook",
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
# Graph Report - mangaBookmark (2026-08-12)
|
# Graph Report - mangaBookmark (2026-08-12)
|
||||||
|
|
||||||
## Corpus Check
|
## Corpus Check
|
||||||
- 110 files · ~267,753 words
|
- 110 files · ~267,791 words
|
||||||
- Verdict: corpus is large enough that graph structure adds value.
|
- Verdict: corpus is large enough that graph structure adds value.
|
||||||
|
|
||||||
## Summary
|
## Summary
|
||||||
- 1651 nodes · 3253 edges · 262 communities (67 shown, 195 thin omitted)
|
- 1621 nodes · 3242 edges · 233 communities (63 shown, 170 thin omitted)
|
||||||
- Extraction: 90% EXTRACTED · 10% INFERRED · 0% AMBIGUOUS · INFERRED: 314 edges (avg confidence: 0.77)
|
- Extraction: 90% EXTRACTED · 10% INFERRED · 0% AMBIGUOUS · INFERRED: 312 edges (avg confidence: 0.77)
|
||||||
- Token cost: 0 input · 0 output
|
- Token cost: 0 input · 0 output
|
||||||
|
|
||||||
## Graph Freshness
|
## Graph Freshness
|
||||||
- Built from commit: `700de202`
|
- Built from commit: `8ae98816`
|
||||||
- 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).
|
||||||
|
|
||||||
@@ -31,10 +31,8 @@
|
|||||||
- [[_COMMUNITY_Web UI Handlers|Web UI Handlers]]
|
- [[_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_CDP Browser Client|CDP Browser Client]]
|
||||||
- [[_COMMUNITY_Store|Store]]
|
|
||||||
- [[_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]]
|
||||||
- [[_COMMUNITY_Open|Open]]
|
|
||||||
- [[_COMMUNITY_IO Performance Patterns|I/O Performance Patterns]]
|
- [[_COMMUNITY_IO Performance Patterns|I/O Performance Patterns]]
|
||||||
- [[_COMMUNITY_CPU Optimization|CPU Optimization]]
|
- [[_COMMUNITY_CPU Optimization|CPU Optimization]]
|
||||||
- [[_COMMUNITY_Caching Patterns|Caching Patterns]]
|
- [[_COMMUNITY_Caching Patterns|Caching Patterns]]
|
||||||
@@ -45,7 +43,6 @@
|
|||||||
- [[_COMMUNITY_Find Skills Guide|Find Skills Guide]]
|
- [[_COMMUNITY_Find Skills Guide|Find Skills Guide]]
|
||||||
- [[_COMMUNITY_Allocation Patterns|Allocation Patterns]]
|
- [[_COMMUNITY_Allocation Patterns|Allocation Patterns]]
|
||||||
- [[_COMMUNITY_Observability & Alerting|Observability & Alerting]]
|
- [[_COMMUNITY_Observability & Alerting|Observability & Alerting]]
|
||||||
- [[_COMMUNITY_PG Test Infrastructure|PG Test Infrastructure]]
|
|
||||||
- [[_COMMUNITY_Memory Layout|Memory Layout]]
|
- [[_COMMUNITY_Memory Layout|Memory Layout]]
|
||||||
- [[_COMMUNITY_Repo Hard Constraints|Repo Hard Constraints]]
|
- [[_COMMUNITY_Repo Hard Constraints|Repo Hard Constraints]]
|
||||||
- [[_COMMUNITY_Go Testing Guide|Go Testing Guide]]
|
- [[_COMMUNITY_Go Testing Guide|Go Testing Guide]]
|
||||||
@@ -56,8 +53,6 @@
|
|||||||
- [[_COMMUNITY_novel-logic.test.js|novel-logic.test.js]]
|
- [[_COMMUNITY_novel-logic.test.js|novel-logic.test.js]]
|
||||||
- [[_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_DB Cutover Runbook|DB Cutover Runbook]]
|
|
||||||
- [[_COMMUNITY_Memory Layout Patterns|Memory Layout Patterns]]
|
|
||||||
- [[_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]]
|
||||||
@@ -140,7 +135,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_Duration|Duration]]
|
|
||||||
- [[_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]]
|
||||||
@@ -168,14 +162,6 @@
|
|||||||
- [[_COMMUNITY_Reviewer Subagent (opencode)|Reviewer Subagent (opencode)]]
|
- [[_COMMUNITY_Reviewer Subagent (opencode)|Reviewer Subagent (opencode)]]
|
||||||
- [[_COMMUNITY_Finding Severity Rubric|Finding Severity Rubric]]
|
- [[_COMMUNITY_Finding Severity Rubric|Finding Severity Rubric]]
|
||||||
- [[_COMMUNITY_Spec Compliance Review|Spec Compliance Review]]
|
- [[_COMMUNITY_Spec Compliance Review|Spec Compliance Review]]
|
||||||
- [[_COMMUNITY_CDP Browser Unit (chrome)|CDP Browser Unit (chrome/)]]
|
|
||||||
- [[_COMMUNITY_Cinder Design System|Cinder Design System]]
|
|
||||||
- [[_COMMUNITY_Cloudflare Challenge Behaviour|Cloudflare Challenge Behaviour]]
|
|
||||||
- [[_COMMUNITY_Ember Means New Chapter Only|Ember Means New Chapter Only]]
|
|
||||||
- [[_COMMUNITY_Gitea + tea CLI|Gitea + tea CLI]]
|
|
||||||
- [[_COMMUNITY_Graphify Knowledge Graph|Graphify Knowledge Graph]]
|
|
||||||
- [[_COMMUNITY_novel-bookmark.user.js|novel-bookmark.user.js]]
|
|
||||||
- [[_COMMUNITY_Security Invariants|Security Invariants]]
|
|
||||||
- [[_COMMUNITY_Why Use samberoops|Why Use samber/oops]]
|
- [[_COMMUNITY_Why Use samberoops|Why Use samber/oops]]
|
||||||
- [[_COMMUNITY_singleflight Cache Stampede Prevention|singleflight Cache Stampede Prevention]]
|
- [[_COMMUNITY_singleflight Cache Stampede Prevention|singleflight Cache Stampede Prevention]]
|
||||||
- [[_COMMUNITY_Struct Field Alignment|Struct Field Alignment]]
|
- [[_COMMUNITY_Struct Field Alignment|Struct Field Alignment]]
|
||||||
@@ -199,15 +185,6 @@
|
|||||||
- [[_COMMUNITY_SQLite-to-Postgres Cutover Runbook|SQLite-to-Postgres Cutover Runbook]]
|
- [[_COMMUNITY_SQLite-to-Postgres Cutover Runbook|SQLite-to-Postgres Cutover Runbook]]
|
||||||
- [[_COMMUNITY_Import SQL Generation Rules|Import SQL Generation Rules]]
|
- [[_COMMUNITY_Import SQL Generation Rules|Import SQL Generation Rules]]
|
||||||
- [[_COMMUNITY_Throwaway Import Generator|Throwaway Import Generator]]
|
- [[_COMMUNITY_Throwaway Import Generator|Throwaway Import Generator]]
|
||||||
- [[_COMMUNITY_ADR-0002 (Discord OAuth Sign-In)|ADR-0002 (Discord OAuth Sign-In)]]
|
|
||||||
- [[_COMMUNITY_ADR-0006 (Browser Out of API Stack)|ADR-0006 (Browser Out of API Stack)]]
|
|
||||||
- [[_COMMUNITY_ADR-0007 (Absolute Cover URLs)|ADR-0007 (Absolute Cover URLs)]]
|
|
||||||
- [[_COMMUNITY_bookmark-api Service|bookmark-api Service]]
|
|
||||||
- [[_COMMUNITY_Deployment Runbook|Deployment Runbook]]
|
|
||||||
- [[_COMMUNITY_Issue 24 (Derived Credentials)|Issue #24 (Derived Credentials)]]
|
|
||||||
- [[_COMMUNITY_Tailscale ACL Tagging|Tailscale ACL Tagging]]
|
|
||||||
- [[_COMMUNITY_TOKEN_KEY Credential Derivation|TOKEN_KEY Credential Derivation]]
|
|
||||||
- [[_COMMUNITY_Traefik Reverse Proxy|Traefik Reverse Proxy]]
|
|
||||||
- [[_COMMUNITY_Real scaling limit is the poller outbound fetch budget|Real scaling limit is the poller outbound fetch budget]]
|
- [[_COMMUNITY_Real scaling limit is the poller outbound fetch budget|Real scaling limit is the poller outbound fetch budget]]
|
||||||
- [[_COMMUNITY_PostgreSQL (jackcpgxv5)|PostgreSQL (jackc/pgx/v5)]]
|
- [[_COMMUNITY_PostgreSQL (jackcpgxv5)|PostgreSQL (jackc/pgx/v5)]]
|
||||||
- [[_COMMUNITY_SQLite (modernc.orgsqlite)|SQLite (modernc.org/sqlite)]]
|
- [[_COMMUNITY_SQLite (modernc.orgsqlite)|SQLite (modernc.org/sqlite)]]
|
||||||
@@ -264,12 +241,6 @@
|
|||||||
- [[_COMMUNITY_Dark-First Design Constraint|Dark-First Design Constraint]]
|
- [[_COMMUNITY_Dark-First Design Constraint|Dark-First Design Constraint]]
|
||||||
- [[_COMMUNITY_Discord Guild Membership|Discord Guild Membership]]
|
- [[_COMMUNITY_Discord Guild Membership|Discord Guild Membership]]
|
||||||
- [[_COMMUNITY_Reader Isolation Invariant|Reader Isolation Invariant]]
|
- [[_COMMUNITY_Reader Isolation Invariant|Reader Isolation Invariant]]
|
||||||
- [[_COMMUNITY_Site Adapters|Site Adapters]]
|
|
||||||
- [[_COMMUNITY_Go Backend (backend)|Go Backend (backend/)]]
|
|
||||||
- [[_COMMUNITY_localStorage Cache and Retry Queue|localStorage Cache and Retry Queue]]
|
|
||||||
- [[_COMMUNITY_Latest Chapter Poller|Latest Chapter Poller]]
|
|
||||||
- [[_COMMUNITY_Postgres Store (postgres17-alpine)|Postgres Store (postgres:17-alpine)]]
|
|
||||||
- [[_COMMUNITY_README Config and Endpoint Reference|README Config and Endpoint Reference]]
|
|
||||||
- [[_COMMUNITY_Browser Unit Redeploy|Browser Unit Redeploy]]
|
- [[_COMMUNITY_Browser Unit Redeploy|Browser Unit Redeploy]]
|
||||||
- [[_COMMUNITY_pg_dump Hot Backup|pg_dump Hot Backup]]
|
- [[_COMMUNITY_pg_dump Hot Backup|pg_dump Hot Backup]]
|
||||||
- [[_COMMUNITY_Redeploy Runbook|Redeploy Runbook]]
|
- [[_COMMUNITY_Redeploy Runbook|Redeploy Runbook]]
|
||||||
@@ -307,15 +278,13 @@
|
|||||||
## Hyperedges (group relationships)
|
## 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]
|
- **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]
|
- **Subagent-Driven Development Pipeline** — _opencode_agent_implementer_implementer, _opencode_agent_reviewer_reviewer, _opencode_agent_implementer_subagent_driven_development [INFERRED 0.85]
|
||||||
- **Deployment Runbook Family** — cutover_cutover, deploy_deploy, redeploy_redeploy [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]
|
- **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]
|
- **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]
|
||||||
- **Deployment Topology** — docker_compose_bookmark_api, docker_compose_postgres, docker_compose_prod_traefik, chrome_docker_compose_browser, docker_compose_db_network [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]
|
- **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]
|
- **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 (262 total, 195 thin omitted)
|
## Communities (233 total, 170 thin omitted)
|
||||||
|
|
||||||
### Community 0 - "HTMX Library Internals"
|
### Community 0 - "HTMX Library Internals"
|
||||||
Cohesion: 0.08
|
Cohesion: 0.08
|
||||||
@@ -327,47 +296,47 @@ Nodes (84): floatPtr(), testConfig(), getCover(), Cookie, Handler, ResponseRecor
|
|||||||
|
|
||||||
### Community 2 - "Manga Userscript Adapters"
|
### Community 2 - "Manga Userscript Adapters"
|
||||||
Cohesion: 0.06
|
Cohesion: 0.06
|
||||||
Nodes (77): adapterFor(), anchorsFromDocument(), anchorsFromHTML(), apiDelete(), apiGet(), apiPut(), applyFabPos(), applyLatestChapterIfChanged() (+69 more)
|
Nodes (76): adapterFor(), anchorsFromDocument(), anchorsFromHTML(), apiDelete(), apiGet(), apiPut(), applyFabPos(), applyLatestChapterIfChanged() (+68 more)
|
||||||
|
|
||||||
### Community 3 - "Novel Userscript Adapters"
|
### Community 3 - "Novel Userscript Adapters"
|
||||||
Cohesion: 0.06
|
Cohesion: 0.06
|
||||||
Nodes (78): adapterFor(), anchorsFromDocument(), anchorsFromHTML(), apiDelete(), apiGet(), apiPut(), applyFabPos(), applyLatestChapterIfChanged() (+70 more)
|
Nodes (79): adapterFor(), anchorsFromDocument(), anchorsFromHTML(), apiDelete(), apiGet(), apiPut(), applyFabPos(), applyLatestChapterIfChanged() (+71 more)
|
||||||
|
|
||||||
### Community 4 - "Series Acquisition Tests"
|
### Community 4 - "Series Acquisition Tests"
|
||||||
Cohesion: 0.09
|
Cohesion: 0.10
|
||||||
Nodes (68): bookmarkNewKaganeSeries(), bookmarkNewNovelfullSeries(), bookmarkNewSeries(), Context, Store, T, newAcquirer(), readBookmark() (+60 more)
|
Nodes (67): bookmarkNewKaganeSeries(), bookmarkNewNovelfullSeries(), bookmarkNewSeries(), Context, Store, T, newAcquirer(), readBookmark() (+59 more)
|
||||||
|
|
||||||
### Community 5 - "Bookmarks API Tests"
|
### Community 5 - "Bookmarks API Tests"
|
||||||
Cohesion: 0.08
|
Cohesion: 0.08
|
||||||
Nodes (67): auth(), getBookmarks(), Handler, Request, Store, T, newTestServer(), newTestStore() (+59 more)
|
Nodes (67): auth(), getBookmarks(), Handler, Request, Store, T, newTestServer(), newTestStore() (+59 more)
|
||||||
|
|
||||||
### Community 7 - "Cover & Acquire Internals"
|
### Community 7 - "Cover & Acquire Internals"
|
||||||
Cohesion: 0.10
|
Cohesion: 0.09
|
||||||
Nodes (30): Addr, Context, Store, defaultCoverResolver(), fetchCoverBytes(), Client, Context, NewCoverFetcher() (+22 more)
|
Nodes (31): Addr, Context, Store, defaultCoverResolver(), fetchCoverBytes(), Client, Context, NewCoverFetcher() (+23 more)
|
||||||
|
|
||||||
### Community 8 - "System Architecture Concepts"
|
### Community 8 - "System Architecture Concepts"
|
||||||
Cohesion: 0.10
|
Cohesion: 0.10
|
||||||
Nodes (26): Confirm-Gated Destructive Actions, Discord OAuth & Guild-Membership Gate, Lifecycle Buckets (reading/archived/finished), Reader-Owned Store, HMAC-Derived Reader Credentials, Web Package (Browser UI + Templates), app.html — App Shell Template, Manga/Novel Library Switch (+18 more)
|
Nodes (26): Confirm-Gated Destructive Actions, Discord OAuth & Guild-Membership Gate, Lifecycle Buckets (reading/archived/finished), Reader-Owned Store, HMAC-Derived Reader Credentials, Web Package (Browser UI + Templates), app.html — App Shell Template, Manga/Novel Library Switch (+18 more)
|
||||||
|
|
||||||
### Community 9 - "Session Middleware"
|
### Community 9 - "Session Middleware"
|
||||||
Cohesion: 0.16
|
Cohesion: 0.07
|
||||||
Nodes (20): ClearCookie(), ClientIP(), Duration, Mutex, Request, ResponseWriter, Time, isHTTPS() (+12 more)
|
Nodes (35): ClearCookie(), ClientIP(), Duration, Mutex, Request, ResponseWriter, Time, isHTTPS() (+27 more)
|
||||||
|
|
||||||
### Community 10 - "Go Test Helpers"
|
### Community 10 - "Go Test Helpers"
|
||||||
Cohesion: 0.05
|
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.15
|
Cohesion: 0.07
|
||||||
Nodes (43): Store, T, newTestStore(), readLatestCheckedAt(), readSeries(), secondReader(), seedForCheck(), seedSecondReader() (+35 more)
|
Nodes (79): M, TestMain(), M, TestMain(), M, Main(), start(), URL() (+71 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 (33): Handler, Request, ResponseWriter, Store, Healthz(), writeJSON(), Auth(), compressible() (+25 more)
|
||||||
|
|
||||||
### Community 13 - "Web UI Handlers"
|
### Community 13 - "Web UI Handlers"
|
||||||
Cohesion: 0.07
|
Cohesion: 0.06
|
||||||
Nodes (33): Context, Mutex, Request, ResponseWriter, Time, Handler, newOAuthStates(), T (+25 more)
|
Nodes (24): coverRelativePath(), coverSourceAddress(), displayChapter(), Store, currentLib(), currentTab(), filterBookmarks(), Client (+16 more)
|
||||||
|
|
||||||
### Community 14 - "Go Error Handling"
|
### Community 14 - "Go Error Handling"
|
||||||
Cohesion: 0.06
|
Cohesion: 0.06
|
||||||
@@ -377,18 +346,10 @@ Nodes (33): Creating Errors, Custom Error Types, Custom types that wrap other er
|
|||||||
Cohesion: 0.08
|
Cohesion: 0.08
|
||||||
Nodes (31): awaitPromise(), browserConnectionLost(), classifyBrowserError(), Action, Context, Mutex, jsString(), kaganeAPIURL() (+23 more)
|
Nodes (31): awaitPromise(), browserConnectionLost(), classifyBrowserError(), Action, Context, Mutex, jsString(), kaganeAPIURL() (+23 more)
|
||||||
|
|
||||||
### Community 16 - "Store"
|
|
||||||
Cohesion: 0.12
|
|
||||||
Nodes (4): CoverContentType(), coverRelativePath(), coverSourceAddress(), Store
|
|
||||||
|
|
||||||
### Community 17 - "Go Code Style Guide"
|
### Community 17 - "Go Code Style Guide"
|
||||||
Cohesion: 0.08
|
Cohesion: 0.08
|
||||||
Nodes (23): Code Style Details, Extract Complex Conditions, Value vs Pointer Arguments, Code Organization Within Files, Complex Conditions & Init Scope, Composite Literals, Control Flow, Cross-References (+15 more)
|
Nodes (23): Code Style Details, Extract Complex Conditions, Value vs Pointer Arguments, Code Organization Within Files, Complex Conditions & Init Scope, Composite Literals, Control Flow, Cross-References (+15 more)
|
||||||
|
|
||||||
### Community 19 - "Open"
|
|
||||||
Cohesion: 0.17
|
|
||||||
Nodes (19): applyMigration(), migrate(), Open(), refreshOwnerToken(), scanSeries(), seedOwner(), TestCoverIsContentAddressedOnFilesystem(), TestCoverPersistsAcrossReopen() (+11 more)
|
|
||||||
|
|
||||||
### Community 20 - "I/O Performance Patterns"
|
### Community 20 - "I/O Performance Patterns"
|
||||||
Cohesion: 0.11
|
Cohesion: 0.11
|
||||||
Nodes (18): Avoid io.ReadAll for large payloads, Batch Operations, Buffered I/O, Cgo Overhead, Channel: batch processing from a stream, Concurrent Multi-Stage Pipelines, Connection pooling, Database: batch inserts over row-by-row (+10 more)
|
Nodes (18): Avoid io.ReadAll for large payloads, Batch Operations, Buffered I/O, Cgo Overhead, Channel: batch processing from a stream, Concurrent Multi-Stage Pipelines, Connection pooling, Database: batch inserts over row-by-row (+10 more)
|
||||||
@@ -429,10 +390,6 @@ Nodes (14): Allocation Patterns, Backing Array Leaks, Direct indexing vs append,
|
|||||||
Cohesion: 0.22
|
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)
|
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 30 - "PG Test Infrastructure"
|
|
||||||
Cohesion: 0.18
|
|
||||||
Nodes (12): M, TestMain(), M, TestMain(), M, Main(), start(), URL() (+4 more)
|
|
||||||
|
|
||||||
### Community 31 - "Memory Layout"
|
### Community 31 - "Memory Layout"
|
||||||
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
|
||||||
@@ -465,10 +422,6 @@ Nodes (6): Design Health Score, Design Specificity Verdict, Minor Observations,
|
|||||||
Cohesion: 0.29
|
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 42 - "Memory Layout Patterns"
|
|
||||||
Cohesion: 0.48
|
|
||||||
Nodes (6): T, TestCreateAndGetSession(), TestDeleteSessionIsPerReader(), TestDeleteSessionRevokes(), TestExpiredSessionIsGone(), TestGetSessionUnknownID()
|
|
||||||
|
|
||||||
### Community 45 - "Go Perf Alert Rules"
|
### Community 45 - "Go Perf Alert Rules"
|
||||||
Cohesion: 0.50
|
Cohesion: 0.50
|
||||||
Nodes (4): Prometheus Alerting Rules (Go Performance), GoroutineLeak Alert, HighGCPauseTime Alert, MemoryNearLimit Alert
|
Nodes (4): Prometheus Alerting Rules (Go Performance), GoroutineLeak Alert, HighGCPauseTime Alert, MemoryNearLimit Alert
|
||||||
@@ -490,12 +443,12 @@ Cohesion: 1.00
|
|||||||
Nodes (3): Mirrored Double Bookmark Mark, Ember Flame Accent, BookmarkManager Logo
|
Nodes (3): Mirrored Double Bookmark Mark, Ember Flame Accent, BookmarkManager Logo
|
||||||
|
|
||||||
### Community 103 - "bookmark-api Service"
|
### Community 103 - "bookmark-api Service"
|
||||||
Cohesion: 0.18
|
Cohesion: 0.24
|
||||||
Nodes (16): Backend Go Service (stdlib net/http), Browser Sidecar (BROWSER_WS_URL), Store Package (Postgres Persistence), Browser Sidecar Service, CDP Endpoint (Tailnet-Bound :9222), Persistent Chrome Profile Volume, chrome/docker-compose.yml — Browser Deployable Unit, bookmark-api Service (+8 more)
|
Nodes (10): Backend Go Service (stdlib net/http), Browser Sidecar (BROWSER_WS_URL), Browser Sidecar Service, CDP Endpoint (Tailnet-Bound :9222), Persistent Chrome Profile Volume, chrome/docker-compose.yml — Browser Deployable Unit, bookmark-api Prod Override, CDP Never on Shared Proxy Network (+2 more)
|
||||||
|
|
||||||
### Community 104 - "AGENTS.md"
|
### Community 104 - "AGENTS.md"
|
||||||
Cohesion: 0.12
|
Cohesion: 0.12
|
||||||
Nodes (15): Agent skills, AGENTS.md, Architecture, Commands, Comments, Design system, Domain docs, Forge: Gitea, not GitHub (+7 more)
|
Nodes (14): Agent skills, Architecture, Commands, Comments, Design system, Domain docs, Forge: Gitea, not GitHub, graphify (+6 more)
|
||||||
|
|
||||||
### Community 105 - "reviewer.md"
|
### Community 105 - "reviewer.md"
|
||||||
Cohesion: 0.12
|
Cohesion: 0.12
|
||||||
@@ -582,19 +535,19 @@ 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`)
|
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
|
## Knowledge Gaps
|
||||||
- **530 isolated node(s):** `bookmarkmanager/backend`, `ctxKey`, `loginView`, `ctxKey`, `test` (+525 more)
|
- **508 isolated node(s):** `bookmarkmanager/backend`, `ctxKey`, `loginView`, `ctxKey`, `test` (+503 more)
|
||||||
These have ≤1 connection - possible missing edges or undocumented components.
|
These have ≤1 connection - possible missing edges or undocumented components.
|
||||||
- **195 thin communities (<3 nodes) omitted from report** — run `graphify query` to explore isolated nodes.
|
- **170 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 `New()` connect `Series Acquisition Tests` to `Bookmarks API Tests`, `Cover & Acquire Internals`, `Session Middleware`, `Web UI Handlers`, `Open`?**
|
- **Why does `New()` connect `Series Acquisition Tests` to `Bookmarks API Tests`, `Cover & Acquire Internals`, `Session Middleware`, `Store Tests`, `Web UI Handlers`?**
|
||||||
_High betweenness centrality (0.047) - this node is a cross-community bridge._
|
_High betweenness centrality (0.052) - this node is a cross-community bridge._
|
||||||
- **Why does `Open()` connect `Open` to `Cover Fetch Test Helpers`, `Series Acquisition Tests`, `Bookmarks API Tests`, `Store Tests`, `Store`, `PG Test Infrastructure`?**
|
- **Why does `Open()` connect `Store Tests` to `Cover Fetch Test Helpers`, `Web UI Handlers`, `Series Acquisition Tests`, `Bookmarks API Tests`?**
|
||||||
_High betweenness centrality (0.032) - this node is a cross-community bridge._
|
_High betweenness centrality (0.034) - 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`?**
|
- **Why does `newRouter()` connect `Bookmarks API Tests` to `Cover Fetch Test Helpers`, `Bookmarks API Handler`, `Series Acquisition Tests`?**
|
||||||
_High betweenness centrality (0.025) - this node is a cross-community bridge._
|
_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?**
|
- **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._
|
_`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?**
|
- **Are the 8 inferred relationships involving `newWebTestServer()` (e.g. with `TestListRendersAcquiredCover()` and `TestPublicCoverRejectsUnknownAddress()`) actually correct?**
|
||||||
@@ -602,4 +555,4 @@ _Questions this graph is uniquely positioned to answer:_
|
|||||||
- **Are the 6 inferred relationships involving `newTestStore()` (e.g. with `TestCreateAndGetSession()` and `TestDeleteSessionIsPerReader()`) actually correct?**
|
- **Are the 6 inferred relationships involving `newTestStore()` (e.g. with `TestCreateAndGetSession()` and `TestDeleteSessionIsPerReader()`) actually correct?**
|
||||||
_`newTestStore()` has 6 INFERRED edges - model-reasoned connections that need verification._
|
_`newTestStore()` has 6 INFERRED edges - model-reasoned connections that need verification._
|
||||||
- **What connects `bookmarkmanager/backend`, `ctxKey`, `loginView` to the rest of the system?**
|
- **What connects `bookmarkmanager/backend`, `ctxKey`, `loginView` to the rest of the system?**
|
||||||
_572 weakly-connected nodes found - possible documentation gaps or missing edges._
|
_548 weakly-connected nodes found - possible documentation gaps or missing edges._
|
||||||
File diff suppressed because one or more lines are too long
+1266
-1837
File diff suppressed because it is too large
Load Diff
+22
-22
@@ -35,9 +35,9 @@
|
|||||||
"semantic_hash": "4a94ac85bad6bce330d085bcc0ae3ffd"
|
"semantic_hash": "4a94ac85bad6bce330d085bcc0ae3ffd"
|
||||||
},
|
},
|
||||||
"userscript/manga-bookmark.user.js": {
|
"userscript/manga-bookmark.user.js": {
|
||||||
"mtime": 1786363889.5678573,
|
"mtime": 1786488438.9080842,
|
||||||
"ast_hash": "de4abcf9e0f099fb82b630d443db739f",
|
"ast_hash": "1f8bcddd3632d709f058a8401af8f127",
|
||||||
"semantic_hash": "de4abcf9e0f099fb82b630d443db739f"
|
"semantic_hash": ""
|
||||||
},
|
},
|
||||||
".agents/skills/find-skills/SKILL.md": {
|
".agents/skills/find-skills/SKILL.md": {
|
||||||
"mtime": 1784884338.760326,
|
"mtime": 1784884338.760326,
|
||||||
@@ -140,19 +140,19 @@
|
|||||||
"semantic_hash": "3a08979e4603aae5c32a58d5b6c39765"
|
"semantic_hash": "3a08979e4603aae5c32a58d5b6c39765"
|
||||||
},
|
},
|
||||||
"CLAUDE.md": {
|
"CLAUDE.md": {
|
||||||
"mtime": 1786446007.0443642,
|
"mtime": 1786488493.5922732,
|
||||||
"ast_hash": "8f79ab45cb9c6466da7c4b65f0bceadf",
|
"ast_hash": "7362a25f37333a2a6a55a5aeccf9b0cb",
|
||||||
"semantic_hash": ""
|
"semantic_hash": ""
|
||||||
},
|
},
|
||||||
"DEPLOY.md": {
|
"DEPLOY.md": {
|
||||||
"mtime": 1786363889.552731,
|
"mtime": 1786488464.5532806,
|
||||||
"ast_hash": "7fa7bb75239f8ad3798e44c12dce374c",
|
"ast_hash": "2b7b537aa1c0954400c19acc4b634029",
|
||||||
"semantic_hash": "7fa7bb75239f8ad3798e44c12dce374c"
|
"semantic_hash": ""
|
||||||
},
|
},
|
||||||
"README.md": {
|
"README.md": {
|
||||||
"mtime": 1786363889.552731,
|
"mtime": 1786488487.8305292,
|
||||||
"ast_hash": "bb33ecb93e23c8f039049aec75217263",
|
"ast_hash": "9d6be8aa8a2946c23ad48d8f2864b5ca",
|
||||||
"semantic_hash": "bb33ecb93e23c8f039049aec75217263"
|
"semantic_hash": ""
|
||||||
},
|
},
|
||||||
"docker-compose.prod.yml": {
|
"docker-compose.prod.yml": {
|
||||||
"mtime": 1786292465.8305523,
|
"mtime": 1786292465.8305523,
|
||||||
@@ -160,9 +160,9 @@
|
|||||||
"semantic_hash": "0751998a532297b8ac507a01ec48dc31"
|
"semantic_hash": "0751998a532297b8ac507a01ec48dc31"
|
||||||
},
|
},
|
||||||
"docker-compose.yml": {
|
"docker-compose.yml": {
|
||||||
"mtime": 1786363889.5678573,
|
"mtime": 1786488450.3508112,
|
||||||
"ast_hash": "d9a58147a573517afa4603b41cf55ca8",
|
"ast_hash": "124fd581bf0a662ff15012abfdb40a92",
|
||||||
"semantic_hash": "d9a58147a573517afa4603b41cf55ca8"
|
"semantic_hash": ""
|
||||||
},
|
},
|
||||||
".claude/settings.json": {
|
".claude/settings.json": {
|
||||||
"mtime": 1784951973.1869545,
|
"mtime": 1784951973.1869545,
|
||||||
@@ -200,14 +200,14 @@
|
|||||||
"semantic_hash": "e69a8340a371579ca3ea689660f7d7bd"
|
"semantic_hash": "e69a8340a371579ca3ea689660f7d7bd"
|
||||||
},
|
},
|
||||||
"AGENTS.md": {
|
"AGENTS.md": {
|
||||||
"mtime": 1786446007.0443642,
|
"mtime": 1786488493.5922732,
|
||||||
"ast_hash": "8f79ab45cb9c6466da7c4b65f0bceadf",
|
"ast_hash": "7362a25f37333a2a6a55a5aeccf9b0cb",
|
||||||
"semantic_hash": ""
|
"semantic_hash": ""
|
||||||
},
|
},
|
||||||
"userscript/test/logic.test.js": {
|
"userscript/test/logic.test.js": {
|
||||||
"mtime": 1786363889.5716388,
|
"mtime": 1786488563.581765,
|
||||||
"ast_hash": "03b5c6c93786c55ac771fd79fd4a75bb",
|
"ast_hash": "80d512bfe6fa8b847f3ba6169c321a74",
|
||||||
"semantic_hash": "03b5c6c93786c55ac771fd79fd4a75bb"
|
"semantic_hash": ""
|
||||||
},
|
},
|
||||||
".claude/skills/testing-the-userscript/SKILL.md": {
|
".claude/skills/testing-the-userscript/SKILL.md": {
|
||||||
"mtime": 1786363889.5489495,
|
"mtime": 1786363889.5489495,
|
||||||
@@ -225,9 +225,9 @@
|
|||||||
"semantic_hash": "421cd7e57f02d4b467f120ca6ddd7b6a"
|
"semantic_hash": "421cd7e57f02d4b467f120ca6ddd7b6a"
|
||||||
},
|
},
|
||||||
"backend/api_test.go": {
|
"backend/api_test.go": {
|
||||||
"mtime": 1786363889.552731,
|
"mtime": 1786488480.637822,
|
||||||
"ast_hash": "3fbe8423060efbc34517901dce44e9b5",
|
"ast_hash": "8e4b9293bc2e45ee3f42027315594fd5",
|
||||||
"semantic_hash": "3fbe8423060efbc34517901dce44e9b5"
|
"semantic_hash": ""
|
||||||
},
|
},
|
||||||
"backend/cover_test.go": {
|
"backend/cover_test.go": {
|
||||||
"mtime": 1786363889.552731,
|
"mtime": 1786363889.552731,
|
||||||
|
|||||||
@@ -6,7 +6,6 @@
|
|||||||
// @author you
|
// @author you
|
||||||
// @downloadURL https://bookmark-api.violetcrown.my.id/u/__API_TOKEN__/manga-bookmark.user.js
|
// @downloadURL https://bookmark-api.violetcrown.my.id/u/__API_TOKEN__/manga-bookmark.user.js
|
||||||
// @updateURL https://bookmark-api.violetcrown.my.id/u/__API_TOKEN__/manga-bookmark.user.js
|
// @updateURL https://bookmark-api.violetcrown.my.id/u/__API_TOKEN__/manga-bookmark.user.js
|
||||||
// @match https://asuracomic.net/*
|
|
||||||
// @match https://asurascans.com/*
|
// @match https://asurascans.com/*
|
||||||
// @match https://demonicscans.org/*
|
// @match https://demonicscans.org/*
|
||||||
// @match https://comix.to/*
|
// @match https://comix.to/*
|
||||||
@@ -112,12 +111,10 @@
|
|||||||
|
|
||||||
const asura = {
|
const asura = {
|
||||||
site: "asura",
|
site: "asura",
|
||||||
// asuracomic.net deep links 301 to the asurascans.com *root*, dropping the
|
// asuracomic.net is not matched: its deep links 301 to the asurascans.com
|
||||||
// path, and that happens at the edge before this script gets a document —
|
// *root* at the edge, discarding the path, so this script never sees a
|
||||||
// so those URLs cannot be handled here at all (checked 2026-07-25). It stays
|
// series document there (re-checked 2026-07-25).
|
||||||
// matched in case the redirect starts preserving paths again; until then,
|
matches: (loc) => /(^|\.)asurascans\.com$/.test(loc.hostname),
|
||||||
// reach series through asurascans.com.
|
|
||||||
matches: (loc) => /(^|\.)asurascans\.com$|(^|\.)asuracomic\.net$/.test(loc.hostname),
|
|
||||||
detect(loc) {
|
detect(loc) {
|
||||||
const path = loc.pathname;
|
const path = loc.pathname;
|
||||||
// /comics/<slug-hash>/chapter/<n>
|
// /comics/<slug-hash>/chapter/<n>
|
||||||
|
|||||||
@@ -120,6 +120,14 @@ test("asura.detect returns other for non-series paths", () => {
|
|||||||
assert.equal(asura.detect(loc("https://asurascans.com/bookmarks")).type, "other");
|
assert.equal(asura.detect(loc("https://asurascans.com/bookmarks")).type, "other");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("asura.matches accepts only asurascans.com", () => {
|
||||||
|
assert.equal(asura.matches({ hostname: "asurascans.com" }), true);
|
||||||
|
assert.equal(asura.matches({ hostname: "www.asurascans.com" }), true);
|
||||||
|
// Dead domain: deep links 301 to the asurascans.com root, discarding the path.
|
||||||
|
assert.equal(asura.matches({ hostname: "asuracomic.net" }), false);
|
||||||
|
assert.equal(asura.matches({ hostname: "asurascans.com.evil.example" }), false);
|
||||||
|
});
|
||||||
|
|
||||||
test("asura.latestChapterFromAnchors takes the highest and skips the First Chapter shortcut", () => {
|
test("asura.latestChapterFromAnchors takes the highest and skips the First Chapter shortcut", () => {
|
||||||
const best = asura.latestChapterFromAnchors([
|
const best = asura.latestChapterFromAnchors([
|
||||||
{ href: "/comics/solo-leveling-059befe1/chapter/1", text: "Chapter 1" },
|
{ href: "/comics/solo-leveling-059befe1/chapter/1", text: "Chapter 1" },
|
||||||
|
|||||||
Reference in New Issue
Block a user