From eab58413bbc307b0a33fe572c88dfd6d098b3353 Mon Sep 17 00:00:00 2001 From: MerlinH Date: Sun, 23 Aug 2026 23:33:41 +0000 Subject: [PATCH] fix: keep repo-rules maintainer-local --- .gitattributes | 1 + AGENTS.md | 4 +-- CLAUDE.md | 4 +-- ...agent-instruction-surface-consolidation.md | 2 +- docs/repo/ai/agent-onboarding.md | 2 +- docs/repo/ai/repo-rules.md | 6 ++-- docs/repo/architecture/product-boundary.md | 10 +++--- docs/repo/standards/default-principles.md | 2 +- .../standards/documentation-governance.md | 2 +- .../standards/maintaining-repository-truth.md | 2 +- .../standards/testing-and-verification.md | 4 +-- docs/repo/standards/versioning.md | 4 +-- package.json | 1 - scripts/repo-rules-block.ts | 31 ++++++++++++++++--- 14 files changed, 48 insertions(+), 27 deletions(-) diff --git a/.gitattributes b/.gitattributes index 3538a69..678186c 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1 +1,2 @@ *.ts text diff +*.md text eol=lf diff --git a/AGENTS.md b/AGENTS.md index fdc9be8..030ddc5 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -7,7 +7,7 @@ Agent-specific: - Use repository onboarding or docs-map files only when present and needed for unclear or cross-area routing. - + ## Authority @@ -63,7 +63,7 @@ Agents inspect the active checkout directly. There is no daemon, database, remot `AGENTS.md` and `CLAUDE.md` carry two generated regions, and neither is hand-edited: - the `truthmark:start` / `truthmark:end` comment markers wrap the Truthmark workflow surface, refreshed by `truthmark init` -- the `repo-rules:start` / `repo-rules:end` comment markers wrap this file's always-on section, rendered by `npm run render:repo-rules` +- the `repo-rules:start` / `repo-rules:end` comment markers wrap this file's always-on section, rendered locally with `node --import tsx scripts/render-repo-rules.ts` Marker names appear here without their comment syntax on purpose: a literal marker inside the rendered region would duplicate it in the instruction files and make the managed block unparseable. diff --git a/CLAUDE.md b/CLAUDE.md index fdc9be8..030ddc5 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -7,7 +7,7 @@ Agent-specific: - Use repository onboarding or docs-map files only when present and needed for unclear or cross-area routing. - + ## Authority @@ -63,7 +63,7 @@ Agents inspect the active checkout directly. There is no daemon, database, remot `AGENTS.md` and `CLAUDE.md` carry two generated regions, and neither is hand-edited: - the `truthmark:start` / `truthmark:end` comment markers wrap the Truthmark workflow surface, refreshed by `truthmark init` -- the `repo-rules:start` / `repo-rules:end` comment markers wrap this file's always-on section, rendered by `npm run render:repo-rules` +- the `repo-rules:start` / `repo-rules:end` comment markers wrap this file's always-on section, rendered locally with `node --import tsx scripts/render-repo-rules.ts` Marker names appear here without their comment syntax on purpose: a literal marker inside the rendered region would duplicate it in the instruction files and make the managed block unparseable. diff --git a/changes/2026-08-23-agent-instruction-surface-consolidation.md b/changes/2026-08-23-agent-instruction-surface-consolidation.md index f38c7ba..68c0081 100644 --- a/changes/2026-08-23-agent-instruction-surface-consolidation.md +++ b/changes/2026-08-23-agent-instruction-surface-consolidation.md @@ -6,7 +6,7 @@ Version action: none - Removed `github-copilot` from `.truthmark/config.yml`, let the init lifecycle prune the 29 generated surfaces it owned, and deleted the leftover `.github/copilot-instructions.md`. Copilot remains a supported platform of the product; only this repository's installation changed. - Narrowed the checked-in path lists in `tests/templates/generated-surfaces.test.ts` to the platforms this repository installs. The `allPlatforms` render assertions keep full Copilot coverage. -- Added a generated `repo-rules:start` / `repo-rules:end` region to `AGENTS.md` and `CLAUDE.md`, rendered from the always-on section of `docs/repo/ai/repo-rules.md` by `npm run render:repo-rules`, so repository authority, documentation scope, product boundary, the numbered rules, and the completion gate survive context compaction. +- Added a generated `repo-rules:start` / `repo-rules:end` region to `AGENTS.md` and `CLAUDE.md`, rendered from the always-on section of `docs/repo/ai/repo-rules.md` by the local `node --import tsx scripts/render-repo-rules.ts` command, so repository authority, documentation scope, product boundary, the numbered rules, and the completion gate survive context compaction. - Added `scripts/repo-rules-block.ts` and `scripts/render-repo-rules.ts`, plus `tests/repo-rules-block.test.ts` covering source sync, cross-file equality, marker ordering, link rewriting, malformed-marker rejection, managed-block round-trip, and idempotence. - Rewrote the Instruction Surface Boundary rule to describe the two-region model, since the previous wording forbade the preamble duplication this change introduces. - Included `scripts/**/*.ts` in `tsconfig.json` so the new repo-local tooling is typechecked. diff --git a/docs/repo/ai/agent-onboarding.md b/docs/repo/ai/agent-onboarding.md index 55da6ab..4d054e2 100644 --- a/docs/repo/ai/agent-onboarding.md +++ b/docs/repo/ai/agent-onboarding.md @@ -5,7 +5,7 @@ doc_type: agent-guide last_reviewed: 2026-05-16 source_of_truth: - repo-rules.md - - ../README.md + - ../../../README.md --- # Agent Onboarding diff --git a/docs/repo/ai/repo-rules.md b/docs/repo/ai/repo-rules.md index c8c5ba6..32f2526 100644 --- a/docs/repo/ai/repo-rules.md +++ b/docs/repo/ai/repo-rules.md @@ -4,8 +4,8 @@ scope: repo-local doc_type: agent-rules last_reviewed: 2026-08-23 source_of_truth: - - ../../AGENTS.md - - ../README.md + - ../../../AGENTS.md + - ../../../README.md - ../architecture/product-boundary.md --- @@ -69,7 +69,7 @@ Agents inspect the active checkout directly. There is no daemon, database, remot `AGENTS.md` and `CLAUDE.md` carry two generated regions, and neither is hand-edited: - the `truthmark:start` / `truthmark:end` comment markers wrap the Truthmark workflow surface, refreshed by `truthmark init` -- the `repo-rules:start` / `repo-rules:end` comment markers wrap this file's always-on section, rendered by `npm run render:repo-rules` +- the `repo-rules:start` / `repo-rules:end` comment markers wrap this file's always-on section, rendered locally with `node --import tsx scripts/render-repo-rules.ts` Marker names appear here without their comment syntax on purpose: a literal marker inside the rendered region would duplicate it in the instruction files and make the managed block unparseable. diff --git a/docs/repo/architecture/product-boundary.md b/docs/repo/architecture/product-boundary.md index bf30ebf..de52d32 100644 --- a/docs/repo/architecture/product-boundary.md +++ b/docs/repo/architecture/product-boundary.md @@ -4,11 +4,11 @@ scope: repo-local doc_type: architecture last_reviewed: 2026-07-30 source_of_truth: - - ../../README.md - - ../truthmark/product/capabilities/agent-native-workflow-injection.md - - ../truthmark/product/capabilities/lane-separated-truth.md - - ../truthmark/engineering/architecture/overview.md - - ../truthmark/engineering/workflows/installed-workflow-runtime.md + - ../../../README.md + - ../../truthmark/product/capabilities/agent-native-workflow-injection.md + - ../../truthmark/product/capabilities/lane-separated-truth.md + - ../../truthmark/engineering/architecture/overview.md + - ../../truthmark/engineering/workflows/installed-workflow-runtime.md --- # Truthmark Product Boundary diff --git a/docs/repo/standards/default-principles.md b/docs/repo/standards/default-principles.md index f7fbf60..c7a33f2 100644 --- a/docs/repo/standards/default-principles.md +++ b/docs/repo/standards/default-principles.md @@ -4,7 +4,7 @@ scope: repo-local doc_type: standard last_reviewed: 2026-07-30 source_of_truth: - - ../README.md + - ../../../README.md - documentation-governance.md --- diff --git a/docs/repo/standards/documentation-governance.md b/docs/repo/standards/documentation-governance.md index 6fca3f8..1ea5459 100644 --- a/docs/repo/standards/documentation-governance.md +++ b/docs/repo/standards/documentation-governance.md @@ -4,7 +4,7 @@ scope: repo-local doc_type: standard last_reviewed: 2026-07-30 source_of_truth: - - ../README.md + - ../../../README.md - ../ai/repo-rules.md --- diff --git a/docs/repo/standards/maintaining-repository-truth.md b/docs/repo/standards/maintaining-repository-truth.md index 0fad7b9..14da522 100644 --- a/docs/repo/standards/maintaining-repository-truth.md +++ b/docs/repo/standards/maintaining-repository-truth.md @@ -4,7 +4,7 @@ scope: repo-local doc_type: guide last_reviewed: 2026-05-09 source_of_truth: - - ../README.md + - ../../../README.md - documentation-governance.md - testing-and-verification.md --- diff --git a/docs/repo/standards/testing-and-verification.md b/docs/repo/standards/testing-and-verification.md index 43bfe89..c7ef8b0 100644 --- a/docs/repo/standards/testing-and-verification.md +++ b/docs/repo/standards/testing-and-verification.md @@ -4,8 +4,8 @@ scope: repo-local doc_type: standard last_reviewed: 2026-05-13 source_of_truth: - - ../../package.json - - ../truthmark/engineering/contracts/config-route-and-check-contracts.md + - ../../../package.json + - ../../truthmark/engineering/contracts/config-route-and-check-contracts.md - versioning.md --- diff --git a/docs/repo/standards/versioning.md b/docs/repo/standards/versioning.md index d80d0cd..9fae649 100644 --- a/docs/repo/standards/versioning.md +++ b/docs/repo/standards/versioning.md @@ -4,8 +4,8 @@ scope: repo-local doc_type: standard last_reviewed: 2026-05-16 source_of_truth: - - ../../package.json - - ../../package-lock.json + - ../../../package.json + - ../../../package-lock.json - change-notes.md - https://semver.org/ --- diff --git a/package.json b/package.json index 8c1c4d4..62a34ab 100644 --- a/package.json +++ b/package.json @@ -55,7 +55,6 @@ "format:check": "prettier --check eslint.config.js package.json package-lock.json tests/package-files.test.ts tsconfig.json", "lint": "eslint .", "package:check": "node --import tsx --test --test-concurrency=1 tests/package-files.test.ts", - "render:repo-rules": "tsx scripts/render-repo-rules.ts", "release:check": "npm run lint && npm run format:check && npm run typecheck && npm run test && npm run build && npm run package:check && npm audit --omit=dev", "test": "node --import tsx --test --test-concurrency=1 \"tests/**/*.test.ts\"", "test:watch": "node --watch --import tsx --test --test-concurrency=1 \"tests/**/*.test.ts\"", diff --git a/scripts/repo-rules-block.ts b/scripts/repo-rules-block.ts index cc7314b..0ab76d3 100644 --- a/scripts/repo-rules-block.ts +++ b/scripts/repo-rules-block.ts @@ -16,10 +16,19 @@ export const INSTRUCTION_FILES = ["AGENTS.md", "CLAUDE.md"]; const ALWAYS_ON_START = ""; const ALWAYS_ON_END = ""; -const GENERATED_NOTICE = ``; +const GENERATED_NOTICE = ``; const sourceDir = path.posix.dirname(REPO_RULES_SOURCE); +const normalizeLineEndings = (content: string): string => + content.replace(/\r\n/g, "\n").replace(/\r/g, "\n"); + +const lineEndingFor = (content: string): "\n" | "\r\n" => + content.includes("\r\n") ? "\r\n" : "\n"; + +const withLineEnding = (content: string, lineEnding: "\n" | "\r\n"): string => + normalizeLineEndings(content).replace(/\n/g, lineEnding); + /** * Rewrites links that were relative to the source doc so they resolve from the * repository root, where the instruction files live. @@ -101,17 +110,29 @@ export const upsertRepoRulesBlock = ( const current = extractRepoRulesBlock(existingContent); if (current !== null) { - return existingContent.replace(current, block); + if (normalizeLineEndings(current) === normalizeLineEndings(block)) { + return existingContent; + } + + return existingContent.replace( + current, + withLineEnding(block, lineEndingFor(existingContent)), + ); } + const lineEnding = lineEndingFor(existingContent); + const renderedBlock = withLineEnding(block, lineEnding); + const truthmarkStart = existingContent.indexOf(""); if (truthmarkStart === -1) { - return `${existingContent.replace(/\n+$/u, "")}\n\n${block}\n`; + return `${existingContent.replace(/(?:\r\n|\r|\n)+$/u, "")}${lineEnding}${lineEnding}${renderedBlock}${lineEnding}`; } - const before = existingContent.slice(0, truthmarkStart).replace(/\n+$/u, ""); + const before = existingContent + .slice(0, truthmarkStart) + .replace(/(?:\r\n|\r|\n)+$/u, ""); const after = existingContent.slice(truthmarkStart); - return `${before}\n\n${block}\n\n${after}`; + return `${before}${lineEnding}${lineEnding}${renderedBlock}${lineEnding}${lineEnding}${after}`; };