chore(repo): move the maintainer's process tooling out of the public repo - #365
Merged
Merged
Conversation
…repo The commit/push gates, AI stage runners and their workflows, prompts, Claude Code project hooks, eval cases and the intent/spec/plan artifacts were one maintainer's personal development process. They now live only on that machine. Every new ignore pattern is root-anchored, and the five workflow files are named one by one rather than by an `sdlc-*.yml` glob, so a future source directory or public workflow with a similar name cannot be swallowed. What protects the repository stays public and unchanged in strength: - `npm run verify` / `verify:journeys` / `verify:receipt` and scripts/verify*.mjs. The code they need moved from scripts/sdlc/lib.mjs to scripts/lib/verify-core.mjs with its tests; the only differences are the config path (scripts/verify.config.json) and a temp-dir prefix. - The required CI check `SDLC verify` (same job id and name). Removed from the public repo, stated plainly: the AI pull-request review workflow, the hourly monitor, the post-release smoke receipt workflow, the evals workflow, the loop workflow, the `prepare` script that installed the git hooks, and the in-repo list of required check names (the requirement itself is GitHub branch protection and is unchanged). The verification audit now skips git-ignored paths when it walks the disk, so a maintainer's private files cannot turn it red. A file in the index is never dropped; if git fails, the filter says so on stderr and never scans less. Its end-to-end test runs in a throwaway copy of the tree (regular files only, no symlinks followed) and never writes inside the checkout. Git commands that target that throwaway repository inherit no GIT_* variable and read no user or system git config, so the machine's config, templates and hooks do not apply to it. Listing the source tree and the audit run itself deliberately keep the machine's git config, because its real ignore rules are what is being tested; they drop only the variables that would point git at a different repository (GIT_DIR and its relatives), and the audit's own ignore filter does the same. A guard test flags the literal `HEAD:` form in test sources, because a fixture read from git's HEAD can only pass before its own commit; it does not catch every spelling of that mistake.
The windows-latest leg of the previous commit failed with two causes, both
in tests/audit/verification-audit.test.ts:
- git for Windows refuses the null device as a config path ("fatal: unable
to access '\\.\nul': Invalid argument"), so every temp `git init` died.
GIT_CONFIG_GLOBAL / GIT_CONFIG_SYSTEM now point at a real, empty file the
test file creates and removes; an empty regular file means the same thing
on every platform.
- the scope assertion compared `path.relative()` output with forward-slash
paths; on Windows that output uses backslashes. Repo-relative paths are
now normalised to `/`.
No product or audit code changes.
This was referenced Sep 20, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Moves one maintainer's personal development-process tooling (git commit/push gates, AI stage runners and their five workflows, prompts, Claude Code project hooks, eval cases, the intent/spec/plan artifacts) out of the public repository. What protects the repository stays:
npm run verify/verify:journeys/verify:receipt,scripts/verify*.mjs, and the required checkSDLC verify(same job id and name). The code those need moved fromscripts/sdlc/lib.mjstoscripts/lib/verify-core.mjs.Also fixes the verification audit, which crawled the disk and went red on a machine that keeps private, git-ignored files at the departed paths: it now skips git-ignored paths (a file in the index is never dropped; if git fails it says so on stderr and never scans less).
Closes #364. Refs #355 (filed by the hourly monitor this change removes; to be closed once merged), #362 (separate follow-up).
Type of change
feat)fix)refactor)docs)test)release)Docs synced (project doc-sync rule —
CLAUDE.md)[Unreleased]or current[X.Y.Z]section)docs/ARCHITECTURE.mdupdated if module structure or counts changed (incl. version header)docs/api/API_REFERENCE.mdupdated if MCP / HTTP / CLI surface changed (incl. version header)README.mdupdated if user-facing features, installation, or collaboration framing changedREADME.de.md/README.zh-TW.md) re-synced ifREADME.mdchangedCONTRIBUTING.mdupdated consistently if bumping a versiondist/skills-manifest.jsonregenerated vianpm run build(required after ANY change to.claude-plugin/,scripts/hooks/,skills/, or version files)memesh doctorreportsOverall: PASSNo product surface, module structure or version changed, so the unticked boxes do not apply.
Verification
npm run typecheckclean (exit=0)npm run buildclean (step 1 ofnpm run verify)node scripts/run-tests-isolated.mjspassing (step 3 ofnpm run verify, exit=0)npm run verifyon the committed tree, closing lines:Re-run AFTER the commit existed (the receipt is tree-keyed, so a HEAD-dependent test could otherwise hide): six affected test files 195/195 exit=0,
node --test scripts/verify.test.mjs scripts/lib/verify-core.test.mjsexit=0,node scripts/audit/verification-audit.mjsexit=0.What is removed from the public repo, stated plainly
The AI pull-request review workflow, the hourly monitor, the post-release smoke-receipt workflow, the evals workflow, the loop workflow, the
preparescript that installed git hooks into clones, and the in-repo list of required check names (the requirement itself is GitHub branch protection and is unchanged). No job inci.ymllost a step, a condition, a matrix cell or a timeout; the published npm file list is identical (402 files).Test plan
node scripts/run-tests-isolated.mjs tests/audit/verification-audit.test.ts tests/gitignore-scope.test.ts --maxWorkers=1→ exit 0node --test scripts/verify.test.mjs scripts/lib/verify-core.test.mjs→ 8 passnode scripts/audit/verification-audit.mjs→ exit 0, every detectornew=0scripts/sdlc/anything.sh, run the audit again → still exit 0; create the same file at a path that is not ignored → exit 1 naming itKnown limitations / follow-ups
\\.\nul) as a config path, and whether the symlink regression test runs or skips there. Thewindows-latestlegs of this PR answer both; the temp-repo commit is protected three independent ways regardless.npm run lintglobs directories rather than the git tree. Both noted for a follow-up..gitignorepatterns) is not part of this change.Coverage (one row per changed file)
.claude/agents/journey-verifier.md(deleted)tests/gitignore-scope.test.tspins the path as ignored (suite exit=0);git grepat HEAD finds no tracked referrer.claude/hooks/hooks.test.mjs(deleted)tests/gitignore-scope.test.tspins the path as ignored (suite exit=0);git grepat HEAD finds no tracked referrer.claude/hooks/lib.mjs(deleted)tests/gitignore-scope.test.tspins the path as ignored (suite exit=0);git grepat HEAD finds no tracked referrer.claude/hooks/pre-bash-gate.mjs(deleted)tests/gitignore-scope.test.tspins the path as ignored (suite exit=0);git grepat HEAD finds no tracked referrer.claude/hooks/protect-verify-dir.mjs(deleted)tests/gitignore-scope.test.tspins the path as ignored (suite exit=0);git grepat HEAD finds no tracked referrer.claude/hooks/session-start.mjs(deleted)tests/gitignore-scope.test.tspins the path as ignored (suite exit=0);git grepat HEAD finds no tracked referrer.claude/hooks/stop-receipt.mjs(deleted)tests/gitignore-scope.test.tspins the path as ignored (suite exit=0);git grepat HEAD finds no tracked referrer.claude/sdlc/PR_TEMPLATE.md(deleted)tests/gitignore-scope.test.tspins the path as ignored (suite exit=0);git grepat HEAD finds no tracked referrer.claude/sdlc/prompts/build.md(deleted)tests/gitignore-scope.test.tspins the path as ignored (suite exit=0);git grepat HEAD finds no tracked referrer.claude/sdlc/prompts/diagnose.md(deleted)tests/gitignore-scope.test.tspins the path as ignored (suite exit=0);git grepat HEAD finds no tracked referrer.claude/sdlc/prompts/plan.md(deleted)tests/gitignore-scope.test.tspins the path as ignored (suite exit=0);git grepat HEAD finds no tracked referrer.claude/sdlc/prompts/review.md(deleted)tests/gitignore-scope.test.tspins the path as ignored (suite exit=0);git grepat HEAD finds no tracked referrer.claude/sdlc/prompts/spec.md(deleted)tests/gitignore-scope.test.tspins the path as ignored (suite exit=0);git grepat HEAD finds no tracked referrer.claude/settings.json(deleted)tests/gitignore-scope.test.tspins the path as ignored (suite exit=0);git grepat HEAD finds no tracked referrer.github/pull_request_template.mdREVIEW.md.github/workflows/ci.ymlsdlc-verify/ nameSDLC verifybyte-identical; only its test step and the comment above it changed.github/workflows/sdlc-evals.yml(deleted)tests/gitignore-scope.test.tspins the path as ignored (suite exit=0);git grepat HEAD finds no tracked referrer.github/workflows/sdlc-loop.yml(deleted)tests/gitignore-scope.test.tspins the path as ignored (suite exit=0);git grepat HEAD finds no tracked referrer.github/workflows/sdlc-monitor.yml(deleted)tests/gitignore-scope.test.tspins the path as ignored (suite exit=0);git grepat HEAD finds no tracked referrer.github/workflows/sdlc-release.yml(deleted)tests/gitignore-scope.test.tspins the path as ignored (suite exit=0);git grepat HEAD finds no tracked referrer.github/workflows/sdlc-review.yml(deleted)tests/gitignore-scope.test.tspins the path as ignored (suite exit=0);git grepat HEAD finds no tracked referrer.gitignoretests/gitignore-scope.test.tsexit=0 — departed paths ignored, nested look-alikes and futuresdlc-*.ymlnotCHANGELOG.mdnode scripts/check-doc-claims.mjsexit=0;npm pack --dry-runfile list 402 before and afterCLAUDE.mdnpm run verifyREVIEW.md(deleted)tests/gitignore-scope.test.tspins the path as ignored (suite exit=0);git grepat HEAD finds no tracked referrerdocs/plans/README.md(deleted)tests/gitignore-scope.test.tspins the path as ignored (suite exit=0);git grepat HEAD finds no tracked referrerdocs/plans/TEMPLATE.md(deleted)tests/gitignore-scope.test.tspins the path as ignored (suite exit=0);git grepat HEAD finds no tracked referrerdocs/plans/release-v4.10.1.md(deleted)tests/gitignore-scope.test.tspins the path as ignored (suite exit=0);git grepat HEAD finds no tracked referrerdocs/sdlc/LOOP.md(deleted)tests/gitignore-scope.test.tspins the path as ignored (suite exit=0);git grepat HEAD finds no tracked referrerdocs/specs/README.md(deleted)tests/gitignore-scope.test.tspins the path as ignored (suite exit=0);git grepat HEAD finds no tracked referrerdocs/specs/TEMPLATE.md(deleted)tests/gitignore-scope.test.tspins the path as ignored (suite exit=0);git grepat HEAD finds no tracked referrerevals/README.md(deleted)tests/gitignore-scope.test.tspins the path as ignored (suite exit=0);git grepat HEAD finds no tracked referrerevals/cases/no-plan-no-build.json(deleted)tests/gitignore-scope.test.tspins the path as ignored (suite exit=0);git grepat HEAD finds no tracked referrerevals/cases/verify-before-done.json(deleted)tests/gitignore-scope.test.tspins the path as ignored (suite exit=0);git grepat HEAD finds no tracked referrerevals/checks/consulted-receipt.mjs(deleted)tests/gitignore-scope.test.tspins the path as ignored (suite exit=0);git grepat HEAD finds no tracked referrerevals/checks/mentions-plan-proof.mjs(deleted)tests/gitignore-scope.test.tspins the path as ignored (suite exit=0);git grepat HEAD finds no tracked referrerevals/lib.mjs(deleted)tests/gitignore-scope.test.tspins the path as ignored (suite exit=0);git grepat HEAD finds no tracked referrerevals/run.mjs(deleted)tests/gitignore-scope.test.tspins the path as ignored (suite exit=0);git grepat HEAD finds no tracked referrerintent/README.md(deleted)tests/gitignore-scope.test.tspins the path as ignored (suite exit=0);git grepat HEAD finds no tracked referrerintent/TEMPLATE.md(deleted)tests/gitignore-scope.test.tspins the path as ignored (suite exit=0);git grepat HEAD finds no tracked referrerintent/observation-forget-survives-stop.md(deleted)tests/gitignore-scope.test.tspins the path as ignored (suite exit=0);git grepat HEAD finds no tracked referrerpackage.jsonnpm run verifyexit=0prepareremovedscripts/audit/baseline.jsonnode scripts/audit/verification-audit.mjsexit=0, new=0, zero stale--prune-stalescripts/audit/verification-audit.mjsdocs/internal/docs/plansprefix filter removed — the ignore filter covers itscripts/check-doc-claims.mjsscripts/lib/git-ignored-paths.mjstests/audit/verification-audit.test.ts18/18, exit=0; mutations (return all / return none /--no-index/ drop a routing variable / drop the env) all redscripts/lib/verify-core.mjsnode --test scripts/verify.test.mjs scripts/lib/verify-core.test.mjsexit=0 (8/8); two guards break-tested redscripts/lib/verify-core.test.mjsscripts/lib/verify-test-helpers.mjsscripts/sdlc/agent.mjs(deleted)tests/gitignore-scope.test.tspins the path as ignored (suite exit=0);git grepat HEAD finds no tracked referrerscripts/sdlc/agent.test.mjs(deleted)tests/gitignore-scope.test.tspins the path as ignored (suite exit=0);git grepat HEAD finds no tracked referrerscripts/sdlc/bootstrap.sh(deleted)tests/gitignore-scope.test.tspins the path as ignored (suite exit=0);git grepat HEAD finds no tracked referrerscripts/sdlc/cli.mjs(deleted)tests/gitignore-scope.test.tspins the path as ignored (suite exit=0);git grepat HEAD finds no tracked referrerscripts/sdlc/git-gate.mjs(deleted)tests/gitignore-scope.test.tspins the path as ignored (suite exit=0);git grepat HEAD finds no tracked referrerscripts/sdlc/git-gate.test.mjs(deleted)tests/gitignore-scope.test.tspins the path as ignored (suite exit=0);git grepat HEAD finds no tracked referrerscripts/sdlc/git-hooks/pre-commit(deleted)tests/gitignore-scope.test.tspins the path as ignored (suite exit=0);git grepat HEAD finds no tracked referrerscripts/sdlc/git-hooks/pre-push(deleted)tests/gitignore-scope.test.tspins the path as ignored (suite exit=0);git grepat HEAD finds no tracked referrerscripts/sdlc/host.mjs(deleted)tests/gitignore-scope.test.tspins the path as ignored (suite exit=0);git grepat HEAD finds no tracked referrerscripts/sdlc/install-git-hooks.mjs(deleted)tests/gitignore-scope.test.tspins the path as ignored (suite exit=0);git grepat HEAD finds no tracked referrerscripts/sdlc/lib.mjs(deleted)tests/gitignore-scope.test.tspins the path as ignored (suite exit=0);git grepat HEAD finds no tracked referrerscripts/sdlc/lib.test.mjs(deleted)tests/gitignore-scope.test.tspins the path as ignored (suite exit=0);git grepat HEAD finds no tracked referrerscripts/sdlc/monitor.mjs(deleted)tests/gitignore-scope.test.tspins the path as ignored (suite exit=0);git grepat HEAD finds no tracked referrerscripts/sdlc/monitor.test.mjs(deleted)tests/gitignore-scope.test.tspins the path as ignored (suite exit=0);git grepat HEAD finds no tracked referrerscripts/sdlc/next-stage.mjs(deleted)tests/gitignore-scope.test.tspins the path as ignored (suite exit=0);git grepat HEAD finds no tracked referrerscripts/sdlc/next-stage.test.mjs(deleted)tests/gitignore-scope.test.tspins the path as ignored (suite exit=0);git grepat HEAD finds no tracked referrerscripts/sdlc/review.mjs(deleted)tests/gitignore-scope.test.tspins the path as ignored (suite exit=0);git grepat HEAD finds no tracked referrerscripts/sdlc/run-stage.mjs(deleted)tests/gitignore-scope.test.tspins the path as ignored (suite exit=0);git grepat HEAD finds no tracked referrerscripts/sdlc/run-stage.test.mjs(deleted)tests/gitignore-scope.test.tspins the path as ignored (suite exit=0);git grepat HEAD finds no tracked referrerscripts/sdlc/smoke-public.mjs(deleted)tests/gitignore-scope.test.tspins the path as ignored (suite exit=0);git grepat HEAD finds no tracked referrerscripts/sdlc/smoke-public.test.mjs(deleted)tests/gitignore-scope.test.tspins the path as ignored (suite exit=0);git grepat HEAD finds no tracked referrerscripts/upgrade-plugin.shtests/cli/upgrade-plugin*.test.tsexit=0rm -rfargument for a directory no longer trackedscripts/verify-receipt.mjsnode scripts/verify-receipt.mjsprints a state, exit 0 fresh / 1 notscripts/verify.config.jsonnpm run verifyexit=0scripts/verify.mjsnpm run verifyexit=0scripts/verify.test.mjssdlc/config.json(deleted)tests/gitignore-scope.test.tspins the path as ignored (suite exit=0);git grepat HEAD finds no tracked referrertests/audit/verification-audit.test.tsGIT_DIR/GIT_INDEX_FILE/GIT_CONFIG_PARAMETERS/GIT_TEMPLATE_DIRwith a throwaway victim repo unchangedtests/gitignore-scope.test.ts