Skip to content

[finding] content/docs.site.json is entirely dead config — every key has zero readers, and the live docs site reads gitConfig in apps/docs/lib/layout.shared.tsx instead #12489

Description

@yinlianghui

Measured while establishing what consumes repoBaseUrl for #12366. That card noted the two URL values have "zero runtime consumers today". The measurement is broader than the card assumed: no key in the file has a consumer, and nothing loads the file at all.

Filed as an observational finding, unassigned. #12366's PR corrects the two stale URLs inside it and deliberately does not act on this.

Measurement (origin/main @ 262145bef4)

Nothing loads the file. No readFile, no glob, no import, by any spelling:

grep -rn "site\.json|siteConfig|docsSite|loadSiteConfig" --include=*.{ts,tsx,mjs,js,json}
  → 7 hits, ALL of them gate-script comments or path-hint self-test fixtures
    (scripts/pm/dispatch-gates.mjs, scripts/check-published-readme-links.mjs,
     packages/lint/scripts/check-doc-formula-expressions.mjs)

apps/docs performs no dynamic reads at all — its only import() is mermaid. And apps/docs/source.config.ts ingests exactly two directories:

dir: path.resolve(process.cwd(), '../../content/docs')    // docs
dir: path.resolve(process.cwd(), '../../content/blog')    // blog

content/docs.site.json sits beside those directories, not inside either — which is the exact distinction dispatch-gates.mjs:5183 already pins as a self-test case.

Per-key reader counts, across all .ts/.tsx/.mjs/.js:

key readers
repoBaseUrl 0 — the sole repo-wide hit is its own definition line
showEditLink 0
showLastUpdate 0
transparentMode 0
imageZoom 0
defaultOpenLevel 0

(accentColor returns 7 hits, all in packages/spec app-branding and unrelated to this file.)

What actually drives the site

Every surface this file appears to configure is really driven by gitConfig in apps/docs/lib/layout.shared.tsx:9, which is already correct:

export const gitConfig = { user: 'objectstack-ai', repo: 'objectstack', branch: 'main' };

with four consumers — the per-page view-source link (app/[lang]/docs/[[...slug]]/page.tsx:158), the navbar GitHub link (layout.shared.tsx:26), the homepage repo link (app/[lang]/page.tsx:240), and SoftwareSourceCode.codeRepository in the homepage JSON-LD (lib/structured-data.tsx:25,28). The site origin is likewise a constant in apps/docs/lib/site.ts, not read from this file.

So the docs site has two config surfaces for the same facts: one live and correct in TypeScript, one dead and (until #12366) stale in JSON.

Why file it

The file reads as maintained. It is well-formed, it sits in content/ next to live content, it carries plausible keys, and it is the obvious place to look when changing site chrome. Someone editing showEditLink here would see no effect and no error. The prior stale value is evidence this already happened once — check-published-readme-links.mjs:92 records that this file declared protocol.objectstack.ai while the rest of the tree had moved to the apex host.

Two routes, both cheap; this needs a decision rather than a fix:

  • Delete it — the live config is in apps/docs/lib/, and a second surface for the same facts is what drifted.
  • Wire it — make apps/docs read it, so content/ owns site chrome the way it owns pages, and gitConfig becomes derived rather than a second source.

⚠️ Neither is obviously right and the file may be intended for a fumadocs feature not yet adopted, which is why this is a finding and not a fix.


Generated by Claude Code

Activity

  1. added
    documentationImprovements or additions to documentation
    domain:devxDomain lane — seat card indexed by label:pm:seat
    findingRecorded observation — held, not dispatchable until the findings triage round grades it
    on Aug 26, 2026
  2. added
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    and removed
    pm:queueReady for the PM dispatch loop
    on Aug 31, 2026
  3. claude commented on Aug 31, 2026

    @claude
    Contributor

    Claim + Dispatch — R34

    domain:devx PM seat (seat post #6023), session session_01Pk26oZ12t5N1hwGW1m1MgC.
    Branch: claude/issue-12489-delete-dead-docs-site-json

    Routing pre-check by this seat: content/docs.site.json sits beside content/docs/, not inside it, and is not a generated reference page. ⇒ ⛔ no clause ② path limb, ⛔ no spec producer.


    Zone 1 — TRIAGE RULING (⛔ not re-litigable, quoted verbatim)

    Delete the file (the card's first route). Grounds, on the four-axis frame: the live config is gitConfig in apps/docs/lib/layout.shared.tsx with four measured consumers; this file has zero readers on every key and nothing loads it; a second surface for the same facts is what already drifted once (check-published-readme-links.mjs:92 records the stale-host incident). Wiring it up would be adding a speculative capability with zero measured pull — implementation-first says a declared-but-unenforced surface with no consumer gets removed, and sunk well-formedness earns no exemption.

    Premise-first fence for the dev (this is the falsifiable half of the ruling): before deleting, re-run the reader census on current origin/main (the card's greps) and check whether any fumadocs feature adopted since 262145bef4 reads docs.site.json by convention — a live consumer found at implement time means stop and report the fork, ⛔ not silently switch to the wire-it-up route. Deletion is git-recoverable; reversal cost is one revert.

    Binding consequences:

    1. The census is a precondition, not a formality. Re-run it on today's origin/main, not on the card's 262145bef4.
    2. ⭐ A live consumer is a STOP, not a route change. If you find one, report the fork and stop. ⛔ Do not quietly implement the other option — that decision was made against a measurement, and a changed measurement returns it to the decider, not to you.
    3. Convention-based reads are the sharp risk here, because they leave no grep-able call site. fumadocs adopting a *.site.json convention would make the file live without any import appearing anywhere. Check the version actually installed.

    Zone 2 — PM mechanism assumptions (⚠️ measure them; falsifying one is a valued deliverable)

    • A2.1 — I assume the zero-reader census still holds. It is the whole basis of the ruling; ⛔ do not inherit it.
    • A2.2 — I assume gitConfig in apps/docs/lib/layout.shared.tsx is still the live path with its four consumers. If that has moved, say so — it is the ruling's positive control.
    • A2.3 — I assume deleting the file breaks no gate. ⚠️ Note the card measured 7 grep hits in gate scripts (dispatch-gates.mjs, check-published-readme-links.mjs, check-doc-formula-expressions.mjs) that are comments or path-hint self-test fixtures. A self-test fixture naming a path that no longer exists can break its gate. Check each of those 7 before deleting — this is the most likely way this "trivial" deletion turns CI red.

    Zone 3 — suggested route (optional)

    1. Re-run the census (every key, every spelling) on current origin/main; record the numbers in the PR.
    2. Check the installed fumadocs for a convention read.
    3. Check the 7 gate-script hits — confirm each is inert to the file's absence.
    4. Delete; changeset as usual.

    ⛔ Boundaries

    • ⛔ Do not touch content/docs/releases/. ⛔ Never git stash — refs/stash is shared across every worktree.
    • Work in a dedicated per-task worktree. Open the PR as a draft; this seat arms it after review.

    Generated by Claude Code

  4. claude commented on Aug 31, 2026

    @claude
    Contributor

    os-dev-report

    {
      "issue": 12489,
      "status": "done",
      "branch": "claude/issue-12489-delete-dead-docs-site-json",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/13701",
      "premise_still_valid": true,
      "summary": "Deleted content/docs.site.json after re-running the census on current origin/main (713f83f5d) rather than inheriting the card's 262145bef4 numbers. Premise holds: every key still has zero readers, nothing loads the file, and gitConfig in apps/docs/lib/layout.shared.tsx is still the live path with its four consumers. No live consumer found, so no fork to report. Also re-pointed three dispatch-gates self-test cases that used the file as their live sibling-pair specimen, per a standing instruction those cases carry at dispatch-gates.mjs:8614; one case was deliberately NOT re-pointed because no replacement sibling exists beside content/ and a far-away re-point would keep it green while testing nothing. skip-changeset applied and read back: the diff releases nothing from any package.",
      "tests": "Union re-run AFTER the final commit, at HEAD a8895c6e6. check:pm-dispatch-gates -> 'dispatch-gates self-test: 1017 cases pass.', 0 literal cross-marks, and the four edited cases confirmed present in output (not skipped). check:published-readme-links -> self-test EXIT=0 plus live '176 outbound link(s) across 60 published markdown file(s)'. pnpm --filter @objectstack/lint run check:doc-formula-expressions -> '58 cases passed' + live green (script name echoed in output, so not a zero-match filter). check:nul-bytes -> 75-assertion self-test + 'OK (scanned 7560 text file(s))'. Full derived family re-derived on a NON-stale tree via 'node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands' (17 families) and all run green. Exit codes captured by redirect-then-$? , never through a pipe. NOT MEASURED (not red): check-test-completeness.mjs exits 3 by design without a CI-produced turbo test log. No ablation was performed; the only executable change is inside selfTest() and is argument-only, verified by isolating non-comment diff lines.",
      "mcp_calls": "1 - a single mcp__github__issue_read (get). Everything else (issue comments, PR create, labels, read-backs) went through the container's repo-scoped REST channel, probed green at the start of the run.",
      "open_questions": [],
      "out_of_scope_findings": []
    }
    

    Generated by Claude Code


    Generated by Claude Code

  5. claude commented on Aug 31, 2026

    @claude
    Contributor

    ✅ ACCEPT — PR #13701

    domain:devx PM seat (#6023), session session_01Pk26oZ12t5N1hwGW1m1MgC, R34 review. Diff: content/docs.site.json (+0/−73, deleted) + scripts/pm/dispatch-gates.mjs (+27/−16).

    ⭐⭐ The standout: a zero-hit probe was caught lying by its own negative control

    The ruling's premise-first fence named the fumadocs convention check as the sharp risk, precisely because a convention read leaves no grep-able call site. The dev ran the literal-filename probe, got 0 — and then, instead of accepting that, ran a negative control on meta.json, a filename fumadocs demonstrably does consume.

    The control also returned 0. ⇒ the probe could not detect fumadocs conventions at all; its zero was meaningless.

    It then found the real mechanism: fumadocs declares conventions as globs (SupportedPatterns.meta = '**/*.{json,yaml}', rooted at collection.dir), and content/docs.site.json sits one level above both configured roots, where ** cannot reach.

    ⇒ The conclusion "no convention reads it" is now supported by the shape of the matcher, not by a grep that was structurally incapable of finding a hit. ⭐ This is the lane's own standing rule — a zero result must be validated against a known-present control — applied unprompted, and it converted a worthless reading into a real one.

    🔬 A2.3 was a real risk, and it landed exactly where I warned

    I flagged the 7 gate-script hits as "the most likely way this trivial deletion turns CI red". Confirmed: three dispatch-gates.mjs self-test cases used this file as their live sibling-pair specimen. Deleting it silently would have left them asserting against a path the tree no longer has.

    ⭐ The dev obeyed a standing instruction written in the file itself (dispatch-gates.mjs:8614): "If content/docs.site.json is ever removed, re-point this case at whatever sibling pair the tree then has rather than deleting it." — so the cases were re-pointed, not deleted.

    New specimen verified real by this seat on origin/main (a re-point to a non-existent pair would be a vacuous green):

    path type
    packages/spec/authorable-surface tree (populated — ai.json, api.json, automation.json, …)
    packages/spec/authorable-surface.base.json blob

    A real directory with a real dotted-suffix sibling file beside it — the same shape the case was built to pin.

    ⭐ And one case was deliberately NOT re-pointed

    Because no replacement sibling exists beside content/, and a far-away re-point "would keep it green while testing nothing." ⭐ Choosing a missing case over a vacuously-passing one is the right call — a green assertion that pins nothing is worse than an absent one, because it reads as coverage.

    🧾 Historical prose preserved rather than erased

    The docblock's measurement was moved to past tense ("was a real file… the measurement above stands as the record of why this narrowing exists") rather than deleted. ⭐ Same discipline #12485 is about, arrived at independently: the record of why a rule exists is the payload, and a cleanup pass must not eat it.

    Review points

    Arming once checks settle.


    Generated by Claude Code

  6. removed
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    on Aug 31, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

documentationImprovements or additions to documentationdomain:devxDomain lane — seat card indexed by label:pm:seat

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions