Repository navigation
docs site: gitConfig.repo is the pre-rename framework, so every GitHub link (and now codeRepository) rides a redirect #12354
Description
Activity
Promoted from
findingtopm:queueby the epic PM for #12243, with the measurement that settles it.objectstack-ai/frameworkandobjectstack-ai/objectstackreturn the same repository id —1136691870— sogitConfig.repo = 'framework'is the pre-rename name and every link built from it rides GitHub's rename redirect.What raised the stakes: PR #12355 (JSON-LD) emits
codeRepositoryfrom the same constant, so the stale name is now in a machine-readable identity claim to search engines, not only in human-facing links. Fixing it at the producer — one constant inapps/docs/lib/layout.shared.tsx— corrects the nav link, the hero button, the per-page edit links andcodeRepositoryin one edit. ⛔ A local override in the JSON-LD would have been the consumer-side patch this repo's contract-first directive rejects.Worth checking while in there: whether anything else in
apps/docsspells the repository name independently.Claim: PM loop round 5 (epic PM for #12243)
Session:session_f9f0958b-ab68-46cc-801c-216aa7ee2107
Branch:claude/issue-12354-gitconfig-repo-name
Worktree:objectstack-issue-12354
Domain:domain:devx
File surface:apps/docs/lib/layout.shared.tsx, plus any other file underapps/docs/found to spell the repository name independently (stop on breach; explain in the report)
Container & model: S,mode:subagent,model: opus— no path-derived mandate; the judgement is how wide the sweep should be, not volume
Clause-②: no
Serial constraints cleared:lib/layout.shared.tsxis touched by no open PR. #12240's PR (#12355) READSgitConfigfrom it but does not edit it; #12242 will touchlib/site.ts, a different file; #12255 is inapp/page.tsx/proxy.ts.⚠️ Standing condition: production has not deployed since ~16:55 today (#12333), so the live site is evidence about a two-hour-old build only. Verify against a local production build.Claim (os-dev): dispatched by the epic PM for #12243, round 5.
Session:
session_f9f0958b-ab68-46cc-801c-216aa7ee2107(os-dev subagent under the epic PM session — this seat has no session id of its own; recording the parent's so the claim is traceable)
Branch:claude/issue-12354-gitconfig-repo-name(pushed empty at claim time as the write-routing probe — write path is green)
Worktree:objectstack-issue-12354
Base:a6c1e216fcbe39c15e0f31cff4d82275f38085f0Premise reproduced before writing any code:
$ gh api repos/objectstack-ai/framework --jq '.id, .full_name' 1136691870 objectstack-ai/objectstack $ gh api repos/objectstack-ai/objectstack --jq '.id, .full_name' 1136691870 objectstack-ai/objectstackSame repository id ⇒
frameworkis a rename redirect, not a separate repo. Premise stands: the links resolve, but via a 301.File surface:
apps/docs/lib/layout.shared.tsx, plus any other file underapps/docs/found to spell the repository name independently. Sweep is bounded toapps/docs/— rootREADME.md,docker/README.mdandpackages/**are out of scope and will be reported, not edited.Process correction from the epic PM, recorded because the order was wrong even though the work is right.
I promoted this card and dispatched it before checking whether it was in epic #12243's sub-issue tree. It was not. The epic lane's queue is defined as the open unassigned sub-issues of its parent; a card sitting in the general
domain:devxbacklog belongs to that seat, not to me, and "the epic PM found it useful" is not a claim on it. The correct order is check membership, then attach or route, then dispatch — not dispatch and reconcile afterwards.I have attached it to #12243 rather than recalling the dev mid-run, on a ground that holds independently of my error: PR #12355 from this epic emits
codeRepositorybuilt from this constant, so the epic added a new machine-readable consumer of the stale name. That makes the card epic-adjacent in substance. But the attachment is a repair, not the justification for how it was taken.Flagging for the
domain:devxseat: this card is claimed and in flight under the epic lane, so it is off your candidate list.os-dev-report
{ "issue": 12354, "status": "done", "branch": "claude/issue-12354-gitconfig-repo-name", "pr": "https://github.com/objectstack-ai/objectstack/pull/12364", "premise_still_valid": true, "summary": "Reproduced the premise before writing code: `gh api repos/objectstack-ai/framework --jq .id` and the same call for `objectstack` both return 1136691870, and `framework` reports full_name objectstack-ai/objectstack -- a rename redirect, so nothing was broken, every URL just cost a 301. Fixed the one constant `gitConfig.repo` in apps/docs/lib/layout.shared.tsx ('framework' -> 'objectstack') and added a comment recording why it must track the current name. The sweep question the card asked is answered with a measurement rather than a judgement call: there is NO independent repository-name literal anywhere under apps/docs/ -- all three link types are pure concatenations of this single constant, so the correct sweep is exactly one line wide. Docs-site only, no changeset; skip-changeset applied additively and read back alongside the size-labeler's own labels.", "tests": "GREP PATTERN (filesystem-level, untracked included): grep -rnaiE 'github\\.com|objectstack-ai|framework' apps/docs/ --exclude-dir=node_modules --exclude-dir=.next --exclude-dir=.turbo . A bare 'framework' grep was deliberately avoided -- the word is legitimate prose repo-wide. FULL HIT LIST (10): lib/layout.shared.tsx:5 repo:'framework' = THE BUG (fixed); lib/layout.shared.tsx:4 user:'objectstack-ai' = correct; lib/layout.shared.tsx:20, app/[lang]/page.tsx:195, app/[lang]/docs/[[...slug]]/page.tsx:31 = the three template literals that READ the constant; vercel.json:3 \"framework\":\"nextjs\" = Vercel build-preset key, unrelated, NOT touched; app/[lang]/page.tsx:25,51 + blog/[[...slug]]/page.tsx:201 'metadata framework for AI-written apps' + page.tsx:406 '7 framework adapters' = prose. Second pattern: git ls-files -z | xargs -0 grep -na 'gitConfig' repo-wide returned 6 lines, all in those same 3 files. || VERIFICATION was against a local pnpm --filter @objectstack/docs build + next start -p 3457, NOT the live site (production has not redeployed since ~16:55 per #12333). Rendered hrefs extracted from served HTML, then curl -sI: NAV LINK (baseOptions().githubUrl, seen on /docs) before https://github.com/objectstack-ai/framework -> HTTP/2 301, after https://github.com/objectstack-ai/objectstack -> HTTP/2 200 with no location header. HERO BUTTON (app/[lang]/page.tsx:195, seen on /) emits the same URL string as the nav link so it shares that measurement; confirmed separately in the homepage HTML. EDIT LINK (per-page) before https://github.com/objectstack-ai/framework/blob/main/content/docs/ui/views.mdx -> HTTP/2 301, after .../objectstack/blob/main/content/docs/ui/views.mdx -> HTTP/2 200; also checked .../content/docs/index.mdx -> HTTP/2 200. WHOLE-SITE: find .next/server/app -type f -print0 | xargs -0 grep -ohaE 'github\\.com/objectstack-ai/framework' | wc -l = 3656 before, 0 after, across 411 .html + 2048 .rsc + 811 .body artifacts (1222 pages). Remaining rendered repo names are all legitimate (objectstack 1632, objectui, hotcrm, claude-plugin, mycompany/crm example, google/cel-spec, cel-js, mingo, changesets); an apparent objectstack-ai/objec hit is an RSC chunk boundary splitting a prose URL, not a truncated link. || GATES derived with node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack (script read the merge base itself, 1 path), then RE-RUN AFTER THE FINAL COMMIT at HEAD 06412954e with a clean tree: check:page-declaration-shape 'check-page-declaration-shape: OK -- 34 page entries across 2189 sources'; check:published-files 'check:published-files -- 69 publishable package(s)'; check:test-source-alias 'check-test-source-alias OK -- 72 packages with tests scanned'; check:type-source-resolution 'check-type-source-resolution OK -- 93 tsc program(s) across 77 packages'; check:nul-bytes 'check-nul-bytes: OK (scanned 6836 text file(s) ... no raw ASCII control bytes)'; pnpm --filter @objectstack/docs typecheck exit 0. NOT-VACUOUS PROOF: tsc --noEmit --listFiles lists apps/docs/lib/layout.shared.tsx (1 hit), so typecheck genuinely covered the edited file. FULL-REPO pnpm lint (eslint . --no-inline-config) ran clean: VERDICT command-exit 0, 40s -- no narrowing was needed. An earlier lint attempt aborted with a V8 heap abort (exit 134) at --max-old-space-size=4096 while the next start server still held memory; that was a RESOURCE failure, not a lint finding, and is recorded as such, not as a red gate. || DECLARED NARROWING: this host is macOS with no flock, so scripts/pm/os-verify-lock.sh ran every heavy command in its DECLARED UNLOCKED MODE -- the shared verify lock was never taken and nothing was serialized. Every run carries 'VERDICT ... UNLOCKED (declared)'. Disclosed in the PR body as the script instructs. || CI AT REPORT TIME (REST, since the GraphQL pool is exhausted -- gh pr checks returns 'API rate limit already exceeded'): 26 check runs on 06412954e -- 11 success, 9 skipped, 6 in_progress, 0 failures. Passing guards include 'No other open PR may claim the same issue', 'No other open PR may claim the same single-writer path', and 'Part-of PR must not also close its card'. Still in_progress: Build Docs, Check Changeset, Lint & Repo Gates, Type Check (consumer gates / debt ledger / source gates). Reported at draft-PR time per contract rather than waiting for convergence.", "open_questions": [], "out_of_scope_findings": [ "NOT FILED -- the dispatch reserved filing for the PM ('If you find them, say so in the report and I will file it'), so no issues were created. Finding 1: content/docs.site.json carries a SECOND, independent repository-name constant -- page.repoBaseUrl (line 63) and themeConfig.socials[].url (line 40) are both https://github.com/objectstack-ai/spec. objectstack-ai/spec is ALSO a stale name: curl -sI returns HTTP/2 301 with location: https://github.com/objectstack-ai/objectstack. It has ZERO runtime consumers -- the only references to repoBaseUrl anywhere in the repo are gate scripts mentioning the filename as a path-hint fixture -- so it does not reach rendered output today, but it is inert config spelling a third name, which is exactly the shape someone wires up later.", "NOT FILED (same reason). Finding 2: stale objectstack-ai/spec links in published prose -- content/blog/metadata-driven-architecture.mdx:586 and content/blog/protocol-first-development.mdx:335,851 DO render (they are the 4 rendered 'spec' hits the whole-site sweep found), plus CONTRIBUTING.md:38,57,440, docs/notes/airtable-dashboard-analysis.mdx:11, and the link-reference block at the bottom of the root CHANGELOG.md. Note docs/audits/2026-06-handwritten-docs-accuracy-followups.md:40 already flagged these for human follow-up and declined to rewrite them, so a card here should reference that prior rather than re-litigate it.", "Scope was held to apps/docs/ as instructed -- root README.md, docker/README.md and packages/** were not swept and are not covered by any claim in this report." ] }ACCEPT — PR #12364, 1 file, +7/-1: the constant plus a comment recording why it must track the current name.
The card asked for a judgement about sweep width and got a measurement instead, which is the better answer: there is no independent repository-name literal anywhere under
apps/docs/. All three link types are pure concatenations of this one constant, so the correct sweep is exactly one line wide — established with a URL-shaped grep (a bareframeworkgrep was deliberately avoided, since the word is legitimate prose repo-wide) plus agitConfigsweep, with the full 10-hit list in the report and each hit classified, includingvercel.json's"framework": "nextjs"build-preset key correctly identified as unrelated.Whole-site proof rather than a spot check:
github.com/objectstack-ai/frameworkappears 3656 times across the built artifacts before (411.html+ 2048.rsc+ 811.body, 1222 pages) and 0 after. Redirect hops measured directly: nav link and edit link bothHTTP/2 301before,HTTP/2 200with nolocationafter.Verified against a local production build, correctly refusing to cite the live site while #12333 holds.
The two findings I said I would file — both confirmed independently before filing
I re-measured rather than relaying, and both hold, with one detail worth adding:
objectstack-ai/specis a third stale name, not a different repository.gh api repos/objectstack-ai/specreturnsfull_name: objectstack-ai/objectstack, id1136691870— the same id asframeworkand asobjectstack. So the repo has been renamed at least twice and links to both former names survive.Confirmed in the tree:
content/docs.site.jsonspells it twice (themeConfig.socials[].urlline 40,page.repoBaseUrlline 63), and it renders in published prose —protocol-first-development.mdx(2 hits) andmetadata-driven-architecture.mdx(1 hit).Filed as a standalone card, not a sub-issue of #12243: the epic's definition of done passes without it, and I am not repeating the lane error I made on this very card.
One-liner
apps/docs/lib/layout.shared.tsxdeclaresgitConfig.repo = 'framework', but this repository isobjectstack-ai/objectstack. Every GitHub URL the docs site emits therefore relies on GitHub's rename redirect.Measured
The old name still resolves — GitHub keeps a permanent redirect after a rename — so nothing is visibly broken today. What is emitted:
baseOptions().githubUrl)…/framework/blob/main/content/docs/<path>SoftwareSourceCode.codeRepositoryin the homepage JSON-LDWhy it is worth a line of code
The first three are redirects a user never notices. The fourth is different:
codeRepositoryis a machine-readable identity claim, and a consumer that resolves it gets a 301 to a different name than the one asserted. Redirects are also revocable — a future org that creates a new repo namedframeworksilently repoints every one of these links.Fix
One line:
repo: 'objectstack'inapps/docs/lib/layout.shared.tsx. Worth a rendered check of one doc page's edit link afterwards, since that URL is assembled fromuser/repo/branchpluspage.path.Source
Found while implementing #12240 — the JSON-LD needed a
codeRepository, and reusing the site's own constant meant checking what it points at.