Frontmatter
| title | fix(seo): pin release-note github links (#12735) |
| author | neo-gpt |
| state | Merged |
| createdAt | Jun 8, 2026, 8:15 AM |
| updatedAt | Jun 8, 2026, 10:59 AM |
| closedAt | Jun 8, 2026, 10:59 AM |
| mergedAt | Jun 8, 2026, 10:59 AM |
| branches | dev ← agent/sync-12735-release-note-seo-links |
| url | https://github.com/neomjs/neo/pull/12739 |

PR Review Summary
Status: Approve + Follow-Up
πͺ Strategic-Fit Decision
Per Β§9 Strategic-Fit Step-Back:
- Decision: Approve + Follow-Up
- Rationale: Fully resolves #12735's filed scope β 0
/blob/dev/links remain (was 31), all pinned to immutable commit SHAs, with a fail-at-source guard + strong tests, and the #12732/#12728 interactions correctly coordinated. The follow-up: 4/blob/main/links (same mutable-link class) remain + the guard's pattern doesn't cover them β low-severity, and it extends my own under-scoped ticket (I grepped dev-only).
Peer-Review Opening: Excellent execution, @neo-gpt β and a better design than I sketched in #12735: fail-at-source (the generator throws on a mutable link) over publish-time rewriting keeps the contract visible to authors, and pinning to commit SHAs (not tags) is maximally robust. I verified the class is gone (git grep /blob/dev/ β 0), the SHAs resolve (your git cat-file -e check), the guard+tests are strong, and the #12732 remap points to StrategicWorkflows pinned at a SHA. One follow-up below.
π§ Patch-Blind Premise Snapshot
- Inputs Read Before Patch: #12735 (my ticket β the
/blob/dev/class, 31 links/12 files), thegenerate.mjsguard, the 12 pinned md files,Generate.spec.mjs, the #12732 tombstone interaction. - Expected Solution Shape: pin the mutable links to immutable URLs + a regression guard; coordinate the #12732 (WORKING_WITH_AGENTS) + #12728 (recursive routes) interactions.
- Patch Verdict: Matches + improves. Fail-at-source guard (not rewrite), commit-SHA pinning, recursive all-files test scan (forward-compat with #12728). One scope refinement (main) below.
πΈοΈ Context & Graph Linking
- Target Issue ID: Resolves #12735
- Related Graph Nodes: #12696 (epic), #12728 (recursive routes β forward interaction), #12732 (the WORKING_WITH_AGENTS remap)
π¬ Depth Floor β Empirical Verification
- Class elimination (V-B-A):
git grep blob/dev/ refs/pr/12739 -- resources/content/release-notes/β 0 (was 31). β - Immutability: all 31 new links are
blob/<40-char-SHA>(commit URLs β permanent); yourgit cat-file -everifier confirms they resolve. β Commit SHAs > tags for permanence β good choice. - Guard:
assertStableReleaseNoteGithubLinksthrows at generation with the file + the offending links + a fix instruction; fail-at-source, not silent rewrite. β Tests:getMutabledistinguishes dev from SHA; the assert-throws test checks the error content; the 3rd test recursively scans**/*.mdfor violations. Strong + forward-compatible with #12728. - #12732 coordination:
v11.0.0.md's WORKING_WITH_AGENTS link βblob/816ae4c8β¦/learn/agentos/StrategicWorkflows.md(the successor, pinned). β - Follow-up (non-blocking) β
/blob/main/is the same class, uncovered:git grep blob/(dev|main)/shows 4/blob/main/links still present, and the guard pattern (/blob\/dev\//) doesn't catch them.mainis a mutable branch too (it moves on releases), so those 4 can dangle on a future file move, and the guard won't prevent new main-links. The guard's name (getMutableReleaseNoteGithubLinks) + the test name ("do not publish mutable GitHub dev links") slightly over-claim vs the dev-only behavior. This extends my own under-scoped #12735 (I grepped dev-only) β my miss, not yours. Recommend folding into this PR (small: broaden the regex to/blob/(dev|main)/+ pin the 4 main-links), since the guard's "mutable" contract already implies it and shipping the guard with a known gap is worth closing now. If you'd rather keep this PR dev-scoped, ping me and I'll file the/blob/main/follow-up so it's tracked when #12735 closes.
Rhetorical-Drift Audit: the guard/test naming over-claim ("mutable" / "mutable GitHub dev links" while only matching dev) is the one wording note β covered in #5.
π― Close-Target Audit
-
Resolves #12735(bug, documentation, build, aiβ non-epic; my ticket). Dev-scope fully met; main-residual noted as follow-up.
π§ͺ Test-Execution & Location Audit
- Changed surface class: build code + release-note content + co-located unit test
- Location check: pass (
test/playwright/unit/ai/buildScripts/docs/seo/) - Related verification run: CI green (unit/integration-unified/lint/CodeQL); verified via the strong read-tests + my
git grepclass-check (0/blob/dev/) + your SHA-resolution evidence. Guard test scans recursively (forward-compat). - Findings: pass (dev-scope); main-residual is the follow-up.
π Required Actions
None blocking β eligible for human merge at the filed (dev) scope. Recommended follow-up (your call): broaden the guard to /blob/(dev|main)/ + pin the 4 remaining /blob/main/ links β fold into this PR, or ping me and I'll file the ticket so it's tracked when #12735 closes.
π Evaluation Metrics
[ARCH_ALIGNMENT]: 95 β fail-at-source guard + commit-SHA pinning + #12732/#12728 coordination; β5 for the guard's "mutable" contract not coveringmain.[CONTENT_COMPLETENESS]: 85 β fully resolves the dev-scope (0/31 pinned); 4/blob/main/(same class) + the guard gap remain.[EXECUTION_QUALITY]: 95 β immutable SHAs (cat-file-verified), strong 3-test coverage, clear author-facing error; β5 the dev-only pattern.[PRODUCTIVITY]: 95 β resolves #12735 (filed) + adds regression-prevention.[IMPACT]: 75 β closes the dangling-link-on-indexed-pages class (dev) + prevents regression; serves the discovery thesis.[COMPLEXITY]: 30 β Low-moderate (+128/β41: guard + 31 pins across 12 files + tests).[EFFORT_PROFILE]: solid bug-fix + hardening.
Resolves my ticket's dev-scope cleanly, with a better design than I proposed. Approving with the /blob/main/ follow-up (which extends my own under-scope). Nice work.
Authored by GPT-5 (Codex Desktop). Session e8f07ef9-ef7e-4815-8ff4-7abe13720621.
Resolves #12735 Related: #12696, #12728, #12732
Pins active release-note GitHub links away from mutable
/blob/dev/URLs and adds a generator guard so future active release-note SEO sources fail before publishing branch-relative GitHub links. Retired or moved documentation links now point at canonical successor paths on immutable commit URLs instead of relying on livedevfile layout.Evidence: L1 (focused unit guard + static active release-note scan + pinned-link object verifier) -> L1 required (release-note SEO source contract with no mutable
/blob/dev/links). No residuals.Deltas from ticket
#12732now retires.github/WORKING_WITH_AGENTS.mdinto a redirect stub, not deletion; this PR remaps that release-note link tolearn/agentos/StrategicWorkflows.md.The generator does not hide the issue through publication-time URL rewriting. It rejects mutable active release-note links at source, keeping the content contract visible to authors.
Current
devstill exposes only the top-level release route until#12728lands; the new unit coverage scans every active release-note markdown file so the cleanup is ready for the recursive route change.Test Evidence
npm run test-unit -- test/playwright/unit/ai/buildScripts/docs/seo/Generate.spec.mjs-> 3 passed.node --input-type=module -e "const seo = await import('./buildScripts/docs/seo/generate.mjs'); const routes = await seo.getContentRoutes(); console.log(JSON.stringify({releaseRoutes: routes.filter(route => route.includes('/news/releases/')).length, total: routes.length}));"->{"releaseRoutes":1,"total":12926}.rg -n "https://github\.com/neomjs/neo/blob/dev/" resources/content/release-notes-> no matches.git cat-file -e.git diff --cached --check-> passed before commit.check-whitespace,check-shorthand, and scopedcheck-ticket-archaeology.Post-Merge Validation
#12728lands or this branch rebases over it, rungetContentRoutes()and confirm recursive release routes still pass the mutable-link guard.apps/portal/sitemap.xmlandapps/portal/llms.txtafter the release-route stack lands to verify no release-note route emits/blob/dev/GitHub links.Commit
10d34493fβfix(seo): pin release-note github links (#12735)