fix(review): make repo-doc refresh diff-aware and preserve manual edits - #3056
Conversation
Wraps generated AGENTS.md content in a start/end marker pair (src/review/generated-doc-refresh.ts) and teaches openRepoDocPullRequest to recompute only that span against the current file on the default branch: unchanged content skips the PR entirely, a changed section is replaced while everything outside the markers is preserved byte-for-byte, and a missing or malformed marker block fails closed with a reason instead of guessing. Also drops the rendered content's embedded timestamp, since it would otherwise make the no-change comparison never match across refreshes of an unchanged profile. Closes #3004. Part of #2993.
|
Superagent didn't find any vulnerabilities or security issues in this PR. |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #3056 +/- ##
=======================================
Coverage 96.11% 96.11%
=======================================
Files 263 264 +1
Lines 28960 29001 +41
Branches 10537 10549 +12
=======================================
+ Hits 27834 27875 +41
Misses 492 492
Partials 634 634
🚀 New features to boost your workflow:
|
|
Tip 🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩 ✅ Gittensory review result - approve/merge recommendedReview updated: 2026-07-04 11:57:27 UTC
✅ Suggested Action - Approve/Merge
Review summary Nits — 5 non-blocking
Review context
Contributor next steps
Signal definitions
🟩 Safe / merged · 🟦 Advisory · 🟨 Held for review · 🟥 Blocked / closed 💰 Earn for open-source contributions like this. Gittensor lets GitHub contributors earn for the work they already do — register to start earning →. Checked by Gittensory, a quiet PR intelligence layer for OSS maintainers.
|
Summary
refreshGeneratedDoc(currentContent, generatedSection, markers)(src/review/generated-doc-refresh.ts), a single, generic marker-block refresh primitive:generate(no current file),no-change(a valid marker block already matches the fresh section byte-for-byte),replace(a valid marker block differs -- everything outside it is preserved verbatim), ormanual-review-required(no marker block, or a malformed one -- missing start/end, duplicated, or out of order -- fails closed instead of guessing).src/review/repo-doc-render.tsnow wraps its ENTIRE output in a start/end marker pair (REPO_DOC_MARKER_START/REPO_DOC_MARKER_END, exported together asREPO_DOC_MARKERS) instead of the single marker comment feat(review): generate CLAUDE.md/AGENT.md from the repo profile, delivered as a PR #3000 shipped, and drops the rendered content's embeddedgeneratedAttimestamp -- that timestamp made the SAME profile render different content on every call, which would have made the no-change comparison never match across refreshes even when nothing meaningful changed. A dedicated test proves the same profile now renders byte-identical output regardless ofgeneratedAt.openRepoDocPullRequest(src/github/repo-doc-pr.ts) now fetches the currentAGENTS.mdfrom the target repo's default branch (treating a 404 as first-run, and rethrowing any other failure rather than guessing) and runs it throughrefreshGeneratedDocbefore doing anything else:no-changeandmanual-review-requiredboth short-circuit with zero branch/commit/PR creation;generate/replaceproceed using the resolved content for both theAGENTS.mdtree entry and theCLAUDE.mdcopy-mode fallback.Part of #2993 (repo-doc generation roadmap). Closes #3004.
Scope
type(scope): short summaryConventional Commit format, for examplefix(api): restore profile access checks.CONTRIBUTING.mdand does not reintroduce GitHub Pages, VitePress,site/, orCNAME.Validation
git diff --checknpm run actionlint(not run -- no workflow files touched)npm run typechecknpm run test:coverage-- scoped to the changed files: 100% statements/branches/functions/lines onsrc/review/generated-doc-refresh.ts,src/review/repo-doc-render.ts, andsrc/github/repo-doc-pr.ts. Full unshardedtest:coverageleft to CI per this repo's own "don't duplicate CI locally" convention; ran the affected suites directly instead (test/unit/generated-doc-refresh.test.ts,test/unit/repo-doc-render.test.ts,test/unit/repo-doc-pr.test.ts, plustest/unit/repo-profile.test.tsandtest/unit/no-direct-octokit.test.tsas regression checks, andnpm run test:changedagainstorigin/mainto confirm scope -- 97/97 passing).npm run test:workers(not run -- no Cloudflare-Workers-pool-specific code touched)npm run build:mcp/npm run test:mcp-pack(not run -- no MCP package changes)npm run ui:openapi:check/npm run ui:lint/npm run ui:typecheck/npm run ui:build(not run -- noapps/gittensory-uichanges, no API/OpenAPI surface changed)npm audit --audit-level=moderate(not run locally -- no dependency changes; CI's dependency-review job covers this)If any required check was skipped, explain why:
validatejob runs them as a backstop.Safety
.content-field response, no-change, manual-review-required, and a real refresh that preserves surrounding manual content.)UI Evidencesection below with screenshots. (N/A -- no visible UI changes.)Notes
no-changewould never fire for any real content. Fixed by having the marker match consume one immediately-following newline; a regression test renders real content viarenderRepoDocContentand asserts it round-trips asno-changeagainst itself, both alone and with manual content wrapped around it.refreshGeneratedDocis intentionally generic (marker pair passed in, not hardcoded) so feat(review): generate repo-specific Claude Code / Codex skill files #3001's future skill-file generator and feat(selfhost): scheduled + on-demand refresh for repo-doc generation #3003's future scheduled-refresh no-meaningful-change check can both call this SAME function rather than growing a second, divergent diff implementation, per the issue's own requirement.CLAUDE.mdis not independently diffed -- per feat(review): generate CLAUDE.md/AGENT.md from the repo profile, delivered as a PR #3000's design, it is always fully derived from whateverAGENTS.mdcontent refresh resolves to (a symlink pointer, or a byte-identical copy), so there is no separate "did CLAUDE.md drift" question to answer.