* fix(#4728): stop presenting the retired Gemini CLI as a supported runtime
#1928 removed the Gemini CLI runtime after Google sunset it on 2026-06-18, and
updated the ENGLISH docs. The locale mirrors and the runtime-loaded workflow
prose were not updated in the same change, and no gate asserts the ABSENCE of a
retired runtime, so both drifted quietly for a year.
The finding that shaped this change: English is already correct. docs/
ARCHITECTURE.md, CONFIGURATION.md, USER-GUIDE.md, how-to/install-on-your-runtime.md
and CLI-TOOLS.md carry zero runtime-axis Gemini references; the only English hits
anywhere are a Gemini 2.5 Pro MODEL line, the GEMINI_API_KEY row, and prose that
correctly documents the retirement. So the docs half of this is translation lag,
not a content decision, and every locale edit here is parity with an existing
English line rather than new wording:
- install-on-your-runtime.md English has NO `### Gemini CLI` section -> deleted
- USER-GUIDE.md :843 "…, Antigravity CLI, Kilo)" -> substituted
- ARCHITECTURE.md English has NO Gemini CLI table row -> row deleted
- ARCHITECTURE.md :24 English holds `Kimi CLI` in that slot -> Kimi CLI
- context-monitor.md :3 "`AfterTool` for Antigravity CLI" -> substituted
- spike-and-sketch.md :93 "(Codex, Antigravity CLI, etc.)" -> substituted
- configure-model-profiles "Codex, OpenCode, Antigravity CLI, or Kilo" -> substituted
- COMMANDS.md English keeps only hyphen + Codex bullets -> colon bullet deleted
- FEATURES.md source docs/features/multi-runtime-support.md:10
lists no Gemini CLI -> name removed
ARCHITECTURE.md:24 is the clearest case for reading English rather than
substituting blind: Antigravity ALREADY appears later in that list, so replacing
Gemini CLI with Antigravity would have named it twice. English holds Kimi CLI
there, so that is what the locales get.
The largest single class was hand-duplicated boilerplate. A "Text mode" paragraph
repeated across 34 runtime-loaded workflow files ends "…required for non-Claude
runtimes (OpenAI Codex, Gemini CLI, etc.)". No lint enforces that sentence and no
script syncs it, so every copy was edited. These files are read by the agent at
runtime, so they steer behavior rather than only informing a reader — which is why
this class matters more than its word count suggests.
The slash-command-form section is restructured in all four languages to match
English, which had already dropped its colon-form bullet. That bullet claimed the
colon form is "Gemini CLI only", which was false on its own terms independent of
the retirement: `/gsd:…` is GSD's canonical AUTHORING token, rewritten per runtime
at install time, and NO runtime registers it — VALID_COMMAND_STYLES is
{slash-hyphen, shell-var} and 18 of 19 runtimes declare slash-hyphen. Substituting
the runtime name would have left the claim false with Antigravity's name in it, so
the claim is gone, matching English.
Two anchor regressions were caught and fixed while doing that. zh-CN lost its
explicit {#slash-command-forms-hyphen-vs-colon} anchor while its TOC still linked
it; the anchor is restored. ko-KR and pt-BR never had an explicit anchor and rely
on the slug generated from the heading text, so shortening the heading broke their
own TOC links; those links now point at the new slugs. English's heading lost its
anchor while its TOC still links the old one — that latent English bug is
deliberately NOT copied.
Preserved, because `gemini` is not one thing here and a blanket sweep breaks the
product: ~/.gemini/antigravity{,-ide,-cli} and ~/.gemini as their parent;
~/.gemini/config (#3738); GEMINI.md; hookEvents "gemini"; GEMINI_API_KEY in all
four locales; every gemini-* model id and the Gemini 2.5 Pro references in
ko-KR/pt-BR/zh-CN (ja-JP genuinely lacks that line — the locales have diverged, so
a uniform patch would be wrong); the hook-event dialect notes, which are
RE-ATTRIBUTED rather than deleted because Antigravity inherits that dialect;
reapply-patches.md:93's legacy-install note; host-integration-capability-matrix.md
:27 and :342, which correctly record the sunset and Antigravity's contract;
whats-new-1.7.0.md and FEATURES.md:3506, which document the retirement itself; and
the generated launcher preamble, which belongs to epic #4632 — zero
_GSD_SHIM_NAME lines appear in this diff.
Coverage: a #4728 block in tests/gemini-runtime-removed.test.cjs asserts the
retired name is gone from STRUCTURAL POSITIONS (a level-3 heading, a table row's
first cell, a runtime-example parenthetical) rather than asserting the string is
absent, which would be wrong. It pairs those with positive PRESERVE assertions
over the same files — Antigravity's heading, ~/.gemini/antigravity, GEMINI_API_KEY,
AfterTool — so a patch that deletes too much fails as loudly as one that deletes
too little. The model-axis test pins both the presence in three locales and the
absence in ja-JP, so a later uniform patch that "helpfully" adds it back fails.
The new docs/ reads tripped lint-docs-guard-registration for the first time in
this file, so the test is registered in scripts/docs-guard-registry.cjs.
Not covered here, by design: nothing above would catch a Gemini-as-runtime
reference appearing in a NEW file tomorrow. That is the repo-wide drift guard,
#4729, which must land last — written now it would red on the very references this
change removes.
Fixes #4728
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* fix(#4728): fix four review blockers, including a vacuous test and my own duplicate
A full matrix run on 31f12d7943 FAILED with 3 real failures, and an isolated
adversarial review returned BLOCK on four blockers. All of it was correct.
1. I committed the exact error I claimed to have avoided. The commit message
boasted that ARCHITECTURE.md:24 proved the value of reading English rather
than substituting blind, because Antigravity already appeared later in that
list. Five hundred lines further down the SAME four files, my
`Gemini:` -> `Antigravity:` substitution produced TWO consecutive
`- Antigravity:` bullets, because an Antigravity bullet was already there.
English (ARCHITECTURE.md:827) merges them into one. Now merged in all four
locales, reusing each locale's existing words.
2. `--gemini` survived in the runtime-detection CLI flag list in all four
locale ARCHITECTURE.md files. English:817 holds `--kimi` in that slot and
already lists `--antigravity` later, so this is another place where
substituting Antigravity would have duplicated it. Now `--kimi`.
3. Two runtime-loaded workflow files still enumerated Gemini one line ABOVE the
line I had already corrected -- the "Adaptive (Recommended)" option in
settings.md:192 and new-project/steps/auto-mode-config.md:95.
4. THE NEW TEST WAS VACUOUS for two of its five files. It matched only
`non-Claude runtimes (` and `(e.g. `, and neither regex could reach the two
lines the change actually fixed: health.md:52 reads `non-Claude (Codex, ...)`
without the word "runtimes", and execute-phase.md:1028 has no parenthetical
at all. The reviewer proved it by re-introducing Gemini at both lines and
watching the assertion stay GREEN. That same blind spot is what hid finding 3.
Replaced with a case-sensitive `/\bGemini\b/` walk over every
`gsd-core/workflows/**/*.md`, which works because every LEGITIMATE gemini
reference in that tree is spelled differently and cannot match: Antigravity's
paths are lowercase with a slash (`~/.gemini/antigravity`), Google's model ids
are lowercase and hyphenated (`gemini-3.1-pro-preview`), and the env vars are
uppercase (`GEMINI_CONFIG_DIR`, `GEMINI_SESSION_ID`). A bare capitalised
`Gemini` there means the retired RUNTIME is being named. The walk asserts it
found at least 50 files so an empty walk cannot pass vacuously, and it now
covers the nested `new-project/steps/` directory where finding 3 lived.
Two allowlist entries, both by line CONTENT and both justified:
reapply-patches.md's `Legacy: ... pre-#1928` note, and settings-advanced.md's
`Known provider` menu. The second was escalated by the agent rather than
decided: Section 8 of that file says model policy is defined "independently"
of the runtime, so `(Claude / OpenAI / Gemini / Qwen)` is the PROVIDER axis --
the same axis as the lowercase model ids -- and must keep working.
Proven to fail, not just asserted: the predicate reports 0 offenders on the
real tree and exactly 2 on a /tmp copy with Gemini re-injected at
health.md:52 and execute-phase.md:1028.
Also from the review: a `| Gemini |` COLUMN survived in the locale FEATURES.md
comparison tables (English has none) -- removed from all three, with header,
separator and every body row kept aligned; two ENGLISH runtime-axis sites were
missed by my own parity standard (how-to/execute-a-phase.md:88 and
how-to/verify-and-ship.md:89, the latter doubly stale since #4716 retired the
Gemini reviewer lane); docs/USER-GUIDE.md:12 linked a dead anchor, which I had
found and deliberately left -- record-and-proceed on a known defect is exactly
what the rules forbid, so it is fixed; docs/COMMANDS.md:12 and all four mirrors
still claimed "the hyphen and colon forms are runtime-specific spellings" with
no colon form documented anywhere, so that false sentence is deleted; and ko-KR
had the installer rather than the user doing the targeting.
The other two matrix failures were the compact-content benchmark baseline, which
drifted because this PR changes byte counts, refreshed via the script's own
`--write` path rather than by hand; and this commit's emitted-drift-ack trailers.
Method note on the acks: the failing run measured growth against
origin/next@1110c3b4ee, which is the STALE LOCAL `next` ref -- gsd-test merges
into the local base branch, and this machine's `next` is seven commits behind
origin/next, which is checked out in the main worktree and so cannot be
fast-forwarded from here. The 32 trailers below are computed against the REAL
base (origin/next @ ca8d9d4459) by comparing each tracked file's blob size, which
is one more file than that run reported -- the extra is settings.md, grown again
by fix 3. docs-update.md and map-codebase.md are deliberately NOT acked: they
SHRANK, since there the fix deleted ", Gemini CLI" rather than substituting, and
acking a file no delta consumed is itself an error.
Refs #4728
Emitted-Drift-Ack-Growth: add-tests.md — retiring the Gemini CLI runtime name; Antigravity is one byte longer
Emitted-Drift-Ack-Growth: add-todo.md — retiring the Gemini CLI runtime name; Antigravity is one byte longer
Emitted-Drift-Ack-Growth: ai-integration-phase.md — retiring the Gemini CLI runtime name; Antigravity is one byte longer
Emitted-Drift-Ack-Growth: check-todos.md — retiring the Gemini CLI runtime name; Antigravity is one byte longer
Emitted-Drift-Ack-Growth: cleanup.md — retiring the Gemini CLI runtime name; Antigravity is one byte longer
Emitted-Drift-Ack-Growth: complete-milestone.md — retiring the Gemini CLI runtime name; Antigravity is one byte longer
Emitted-Drift-Ack-Growth: do.md — retiring the Gemini CLI runtime name; Antigravity is one byte longer
Emitted-Drift-Ack-Growth: eval-review.md — retiring the Gemini CLI runtime name; Antigravity is one byte longer
Emitted-Drift-Ack-Growth: execute-phase.md — retiring the Gemini CLI runtime name; Antigravity is one byte longer
Emitted-Drift-Ack-Growth: execute-plan.md — retiring the Gemini CLI runtime name; Antigravity is one byte longer
Emitted-Drift-Ack-Growth: health.md — retiring the Gemini CLI runtime name; Antigravity is one byte longer
Emitted-Drift-Ack-Growth: import.md — retiring the Gemini CLI runtime name; Antigravity is one byte longer
Emitted-Drift-Ack-Growth: inbox.md — retiring the Gemini CLI runtime name; Antigravity is one byte longer
Emitted-Drift-Ack-Growth: manager.md — retiring the Gemini CLI runtime name; Antigravity is one byte longer
Emitted-Drift-Ack-Growth: new-milestone.md — retiring the Gemini CLI runtime name; Antigravity is one byte longer
Emitted-Drift-Ack-Growth: new-workspace.md — retiring the Gemini CLI runtime name; Antigravity is one byte longer
Emitted-Drift-Ack-Growth: note.md — retiring the Gemini CLI runtime name; Antigravity is one byte longer
Emitted-Drift-Ack-Growth: onboard.md — retiring the Gemini CLI runtime name; Antigravity is one byte longer
Emitted-Drift-Ack-Growth: plant-seed.md — retiring the Gemini CLI runtime name; Antigravity is one byte longer
Emitted-Drift-Ack-Growth: profile-user.md — retiring the Gemini CLI runtime name; Antigravity is one byte longer
Emitted-Drift-Ack-Growth: quick.md — retiring the Gemini CLI runtime name; Antigravity is one byte longer
Emitted-Drift-Ack-Growth: remove-workspace.md — retiring the Gemini CLI runtime name; Antigravity is one byte longer
Emitted-Drift-Ack-Growth: secure-phase.md — retiring the Gemini CLI runtime name; Antigravity is one byte longer
Emitted-Drift-Ack-Growth: settings.md — retiring the Gemini CLI runtime name; Antigravity is one byte longer
Emitted-Drift-Ack-Growth: ship.md — retiring the Gemini CLI runtime name; Antigravity is one byte longer
Emitted-Drift-Ack-Growth: smart-entry.md — retiring the Gemini CLI runtime name; Antigravity is one byte longer
Emitted-Drift-Ack-Growth: ui-phase.md — retiring the Gemini CLI runtime name; Antigravity is one byte longer
Emitted-Drift-Ack-Growth: ui-review.md — retiring the Gemini CLI runtime name; Antigravity is one byte longer
Emitted-Drift-Ack-Growth: undo.md — retiring the Gemini CLI runtime name; Antigravity is one byte longer
Emitted-Drift-Ack-Growth: update.md — retiring the Gemini CLI runtime name; Antigravity is one byte longer
Emitted-Drift-Ack-Growth: validate-phase.md — retiring the Gemini CLI runtime name; Antigravity is one byte longer
Emitted-Drift-Ack-Growth: verify-work.md — retiring the Gemini CLI runtime name; Antigravity is one byte longer
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* chore(#4728): add the changeset fragment
The PR body claimed one was present and it was not — caught by
scripts/changeset/lint.cjs reporting fail_missing_fragment, not by the
checklist, which is exactly why the lint exists.
Type Fixed: the diff is prose, and a docs-only fix uses Fixed since there is
no Documentation type.
Refs #4728
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
---------
Co-authored-by: sim <sim@local>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
438 lines
20 KiB
JavaScript
438 lines
20 KiB
JavaScript
#!/usr/bin/env node
|
|
'use strict';
|
|
|
|
/**
|
|
* docs-guard-registry.cjs — the sole source of truth for which doc-reading
|
|
* test files the docs-guard lane must run.
|
|
*
|
|
* ## Why this is its own module, not a `scripts/ci-test-scope.cjs` RULE
|
|
*
|
|
* A prior version of this PR added a `docs guards` RULE to `RULES` in
|
|
* scripts/ci-test-scope.cjs, on the theory that classify()'s `!codeChanged`
|
|
* normalization (which at the time zeroed fullMatrix/targeted_tests/
|
|
* windows_tests for docs-only diffs) made the RULE inert to classify()'s
|
|
* scope decision. (#4641 later removed `windows_tests` from classify()'s
|
|
* output entirely; the normalization today only zeroes fullMatrix and
|
|
* targeted_tests. This paragraph is historical narration of a rejected
|
|
* design, not a description of current behaviour.)
|
|
*
|
|
* That is true for docs-ONLY diffs and FALSE for MIXED docs+code diffs:
|
|
* `codeChanged` is true whenever ANY changed file is product/pipeline code,
|
|
* so the normalization never runs, and every one of this registry's test
|
|
* files joined `targeted_tests` for every mixed PR. Probed on that version:
|
|
* `node scripts/ci-test-scope.cjs --files "docs/a.md src/semver.cts"`
|
|
* returned 25 targeted_tests, vs. 3 on `origin/next` — an unstated blowup
|
|
* of the scoped/targeted lane on every mixed docs+code PR.
|
|
*
|
|
* Root cause: `RULES` answers "given these changed files, what should
|
|
* test.yml run" for the MAIN scoped-lane pipeline. The docs-guard registry
|
|
* is a LANE MANIFEST for a completely different consumer (the `docs-lint`
|
|
* job in .github/workflows/docs-required.yml, gated on a `docs_changed`
|
|
* step output). Putting a lane manifest inside a scope-classification rule
|
|
* set was the defect; extracting it here removes any path by which it can
|
|
* influence classify() at all.
|
|
*
|
|
* ## Who reads this
|
|
*
|
|
* - .github/workflows/docs-required.yml (`docs-lint` job) — derives the
|
|
* PER-PR-SELECTED subset of this registry from scripts/select-docs-guards.cjs,
|
|
* which is itself driven by this module's DOCS_GUARD_TESTS map. This job has
|
|
* no `paths:` filter, so it always reports a status and can supply the
|
|
* already-required `docs-lint` context; a dedicated `paths:`-filtered
|
|
* workflow cannot be made required without hanging non-docs PRs forever.
|
|
* - scripts/lint-docs-guard-registration.cjs — derives its registration
|
|
* lint's comparison set from this module (so a docs-reading test file
|
|
* that is neither registered here nor exempted fails the lint).
|
|
* - scripts/select-docs-guards.cjs — the pure selector that maps a PR's
|
|
* changed docs/ paths to the subset of this registry that actually needs
|
|
* to run (#3753 follow-up: a flat "run everything" list is disproportionate
|
|
* for a single-file docs typo fix).
|
|
*
|
|
* ## Registry shape (#3753 follow-up)
|
|
*
|
|
* `DOCS_GUARD_TESTS` is a MAP from test file path to the array of docs/
|
|
* paths it actually reads, so a changed-docs-file can be resolved to the
|
|
* narrow subset of guards that read it, instead of always running the
|
|
* entire registry. Each value is a non-empty array of PATTERNS:
|
|
*
|
|
* - a plain path (e.g. `'docs/AGENTS.md'`) matches that exact file only;
|
|
* - a trailing-slash path (e.g. `'docs/adr/'`) matches any changed path
|
|
* under that directory prefix — use this for a test that walks or
|
|
* `readdirSync`s a whole docs/ subdirectory;
|
|
* - the sentinel `'*'` means "run on ANY docs/ change" — reserved for a
|
|
* test that cannot be resolved to a narrower set of paths (the path is
|
|
* computed, looped over an unresolvable variable, or the test walks
|
|
* docs/ generally). Conservative fallback: when in doubt, use `'*'`,
|
|
* never a guessed-narrow path — a false negative here (a guard that
|
|
* silently stops running) is exactly the #3753 defect class this
|
|
* registry exists to prevent.
|
|
*
|
|
* `DOCS_GUARD_TEST_FILES` (derived: `Object.keys(DOCS_GUARD_TESTS)`) is kept
|
|
* as a flat array export so the registration lint and its parity test
|
|
* continue to consume a plain file list without needing to know about the
|
|
* map shape.
|
|
*
|
|
* ## Adding a docs guard
|
|
*
|
|
* Add the test file's path (relative to the repo root, `tests/<file>`) as a
|
|
* key in DOCS_GUARD_TESTS below, with the docs/ paths it reads as the value
|
|
* (or `['*']` if that cannot be resolved narrowly). Do not duplicate this
|
|
* list anywhere else — a second, independently maintained list is exactly
|
|
* the #3753 defect class (10 registered-but-not-run guards, silently
|
|
* drifted) this registry exists to prevent from recurring.
|
|
*
|
|
* Sorted alphabetically by basename for unambiguous diffs.
|
|
*/
|
|
|
|
/**
|
|
* Duplicate of scripts/run-tests.cjs:50's `SUITES` array. That array is not
|
|
* exported by run-tests.cjs (module.exports there is deliberately narrow;
|
|
* run-tests.cjs's own behavior is intentional and out of scope for this
|
|
* registry to alter), so it cannot be imported directly without changing a
|
|
* shared, behavior-locked file.
|
|
*
|
|
* Why this must exist at all: `run-tests.cjs`'s `selectExplicitFiles`
|
|
* (scripts/run-tests.cjs:651) treats any registry entry that EQUALS a
|
|
* SUITES member (e.g. `all`, `unit`) as a suite selector, not a filename —
|
|
* so a typo in DOCS_GUARD_TESTS matching a suite name would silently run
|
|
* the ENTIRE suite inside the required `docs-lint` job instead of erroring.
|
|
* `assertNoSuiteCollision` below rejects that at the registry boundary
|
|
* instead.
|
|
*
|
|
* Divergence risk: if run-tests.cjs's real SUITES list ever changes and this
|
|
* copy is not updated, this check could under- or over-reject. That risk is
|
|
* covered by a parity test (tests/ci-docs-guard-registry.test.cjs) that
|
|
* drives run-tests.cjs's own exported `selectExplicitFiles` behaviorally —
|
|
* for every token here it asserts run-tests.cjs treats it as a suite
|
|
* selector (never "file not found"), and for a control non-member it
|
|
* asserts the opposite — so a real divergence fails that test rather than
|
|
* silently drifting.
|
|
*/
|
|
const RUN_TESTS_SUITES = ['all', 'unit', 'integration', 'install', 'security', 'slow', 'qa'];
|
|
|
|
/**
|
|
* Normalize a registry entry EXACTLY the way scripts/run-tests.cjs's
|
|
* `splitFileList` (:617-625) normalizes a requested token before its SUITES
|
|
* check (:651): strip a leading `tests/` and normalize `\`->`/`. Without this,
|
|
* comparing RAW registry keys (which all carry the `tests/` prefix by
|
|
* convention) against RUN_TESTS_SUITES misses the realistic typo `'tests/all'`
|
|
* entirely — proven by probe: `assertNoSuiteCollision(['tests/all'])` did not
|
|
* throw, and `selectExplicitFiles(allFiles, 'tests/all')` selected all 824
|
|
* files (the whole suite) inside the required docs-lint job.
|
|
*
|
|
* @param {string} t
|
|
* @returns {string}
|
|
*/
|
|
function normalizeForSuiteCheck(t) {
|
|
return t.replace(/\\/g, '/').replace(/^tests\//, '');
|
|
}
|
|
|
|
/**
|
|
* Reject any docs-guard registry entry that collides with a run-tests.cjs
|
|
* suite token (see RUN_TESTS_SUITES doc comment above). Throws with every
|
|
* offending entry named, rather than failing on only the first. Compares
|
|
* entries AFTER normalizeForSuiteCheck, mirroring run-tests.cjs's own
|
|
* splitFileList normalization, so a `tests/`-prefixed or backslash-spelled
|
|
* entry that would collide post-normalization is caught here too.
|
|
*
|
|
* @param {string[]} tests
|
|
*/
|
|
function assertNoSuiteCollision(tests) {
|
|
const collisions = tests.filter((t) => RUN_TESTS_SUITES.includes(normalizeForSuiteCheck(t)));
|
|
if (collisions.length > 0) {
|
|
throw new Error(
|
|
'docs-guard-registry: DOCS_GUARD_TESTS entry collides with a run-tests.cjs SUITES token ' +
|
|
`(${collisions.join(', ')}) — scripts/run-tests.cjs:651's selectExplicitFiles treats a ` +
|
|
'registry entry that equals a suite name as a suite selector, not a filename, so this ' +
|
|
'would silently run the entire suite instead of the intended file(s). Fix the registry entry.',
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Map from docs-guard test file to the docs/ path patterns it reads. See
|
|
* this module's header comment for pattern semantics (exact / trailing-slash
|
|
* dir-prefix / `'*'` sentinel). Every value here was derived by reading the
|
|
* test file's actual read call(s) — not guessed — per #3753's own lesson: an
|
|
* unresolvable read is recorded as `'*'`, never a narrowed guess.
|
|
*/
|
|
const DOCS_GUARD_TESTS = {
|
|
'tests/adr-15-progress-converge.test.cjs': [
|
|
'docs/COMMANDS.md',
|
|
'docs/how-to/run-phases-autonomously.md',
|
|
],
|
|
// Walks docs/adr/ as a directory (builds/reads docs/adr/README.md and
|
|
// fixture ADRs throughout) and separately reads docs/contributor-standards.md.
|
|
'tests/adr-index-gate.test.cjs': ['docs/adr/', 'docs/contributor-standards.md'],
|
|
|
|
// Walks docs/features/ as a directory (the fragment corpus) and asserts the
|
|
// committed docs/FEATURES.md equals the generated projection of it (#3840).
|
|
'tests/features-index-gate.test.cjs': ['docs/features/', 'docs/FEATURES.md'],
|
|
'tests/agent-classification-parity.test.cjs': ['docs/AGENTS.md', 'docs/INVENTORY.md'],
|
|
// #3683: pins the learnings feature section's agreement with the canonical
|
|
// artifact registry (reads docs/FEATURES.md around the extract-learnings
|
|
// entry).
|
|
'tests/learnings.test.cjs': ['docs/FEATURES.md'],
|
|
'tests/analyze-dependencies.test.cjs': ['docs/COMMANDS.md'],
|
|
'tests/autonomous-converge.test.cjs': [
|
|
'docs/COMMANDS.md',
|
|
'docs/how-to/run-phases-autonomously.md',
|
|
],
|
|
'tests/capability-matrix-sync.test.cjs': ['docs/reference/capability-matrix.md'],
|
|
'tests/capability-registry.test.cjs': [
|
|
'docs/tutorials/build-your-first-capability.md',
|
|
'docs/tutorials/install-your-first-capability.md',
|
|
'docs/reference/capability-manifest.md',
|
|
],
|
|
'tests/claude-md.test.cjs': ['docs/COMMANDS.md'],
|
|
'tests/claude-orchestration.test.cjs': ['docs/explanation/claude-orchestration-capability.md'],
|
|
'tests/command-contract.test.cjs': [
|
|
'docs/INVENTORY.md',
|
|
'docs/ja-JP/INVENTORY.md',
|
|
'docs/ko-KR/INVENTORY.md',
|
|
'docs/zh-CN/INVENTORY.md',
|
|
'docs/pt-BR/INVENTORY.md',
|
|
],
|
|
// uncoveredFiles(...) scans 'docs' as a generic coverage-scan root
|
|
// (commit-files-pathspec.test.cjs:1618) — cannot be resolved to specific
|
|
// files without re-deriving the scan's own file-discovery logic.
|
|
'tests/commit-files-pathspec.test.cjs': ['*'],
|
|
'tests/compact-content-4139.test.cjs': ['docs/CONFIGURATION.md'],
|
|
'tests/config-field-docs.test.cjs': ['docs/CONFIGURATION.md'],
|
|
'tests/config.test.cjs': ['docs/CONFIGURATION.md'],
|
|
'tests/context-index-sync.test.cjs': ['docs/CONTEXT-INDEX.json'],
|
|
'tests/context-predicates-query.test.cjs': ['docs/contributor-standards.md'],
|
|
// SCAN_DIRS includes 'docs' and recursively walks every .md file under it
|
|
// (context7-tool-name-parity.test.cjs:31-38) — a generic tree walk, not a
|
|
// fixed file set.
|
|
'tests/context7-tool-name-parity.test.cjs': ['*'],
|
|
'tests/contributor-standards.test.cjs': ['docs/contributor-standards.md'],
|
|
'tests/cursor-reviewer.test.cjs': [
|
|
'docs/COMMANDS.md',
|
|
'docs/FEATURES.md',
|
|
'docs/ja-JP/COMMANDS.md',
|
|
'docs/ja-JP/FEATURES.md',
|
|
'docs/ko-KR/COMMANDS.md',
|
|
'docs/ko-KR/FEATURES.md',
|
|
],
|
|
'tests/discuss-all-flag.test.cjs': ['docs/COMMANDS.md'],
|
|
'tests/discuss-mode.test.cjs': ['docs/workflow-discuss-mode.md'],
|
|
// Walks docs/*.md and every docs/<locale>/*.md dir dynamically
|
|
// (docs-parity-live-registry.test.cjs:42, 428) — deliberately generic.
|
|
'tests/docs-parity-live-registry.test.cjs': ['*'],
|
|
// #3839: pins every hook-table Event cell in the five locales' ARCHITECTURE
|
|
// and INVENTORY files against src/runtime-hooks-surface.cts registrations.
|
|
'tests/docs-hooks-table-parity.test.cjs': [
|
|
'docs/ARCHITECTURE.md',
|
|
'docs/INVENTORY.md',
|
|
'docs/ja-JP/ARCHITECTURE.md',
|
|
'docs/ja-JP/INVENTORY.md',
|
|
'docs/zh-CN/ARCHITECTURE.md',
|
|
'docs/zh-CN/INVENTORY.md',
|
|
'docs/ko-KR/ARCHITECTURE.md',
|
|
'docs/ko-KR/INVENTORY.md',
|
|
'docs/pt-BR/ARCHITECTURE.md',
|
|
'docs/pt-BR/INVENTORY.md',
|
|
],
|
|
'tests/docs-state-md-locale-parity.test.cjs': [
|
|
'docs/reference/state-md.md',
|
|
'docs/ja-JP/reference/state-md.md',
|
|
'docs/zh-CN/reference/state-md.md',
|
|
'docs/ko-KR/reference/state-md.md',
|
|
'docs/pt-BR/reference/state-md.md',
|
|
],
|
|
'tests/drift-detection.test.cjs': ['docs/CONFIGURATION.md', 'docs/AGENTS.md'],
|
|
'tests/edge-probe-docs-fixtures.test.cjs': ['docs/adr/550-spec-phase-probe-contract.md'],
|
|
'tests/edit-phase.test.cjs': [
|
|
'docs/INVENTORY.md',
|
|
'docs/INVENTORY-MANIFEST.json',
|
|
'docs/COMMANDS.md',
|
|
],
|
|
'tests/effort-surface-axis.test.cjs': ['docs/reference/host-integration-capability-matrix.md'],
|
|
'tests/execute-phase-active-flags.test.cjs': [
|
|
'docs/reference/host-integration-capability-matrix.md',
|
|
],
|
|
'tests/execute-phase-wave.test.cjs': ['docs/COMMANDS.md'],
|
|
// #3913 (ADR-3889 terminal phase): reads the generated docs/reference/exit-codes.md
|
|
// (content invariants, F1/F3) and docs/README.md (F4, the index link).
|
|
'tests/exit-code-registry.test.cjs': ['docs/reference/exit-codes.md', 'docs/README.md'],
|
|
'tests/external-job-waiting.test.cjs': ['docs/reference/planning-artifacts.md'],
|
|
// Rows 8/9 (negative controls) read real docs/registries/eos.json and
|
|
// docs/adr/0001-dispatch-policy-module.md and assert on their EXACT
|
|
// committed content (an entry's name field, ADR-0001's H1 title) as a
|
|
// sanity check before mutating an overlay fixture — a content edit to
|
|
// either file changes the string this test asserts on.
|
|
'tests/fragment-single-edit-propagation.install.test.cjs': [
|
|
'docs/registries/eos.json',
|
|
'docs/adr/0001-dispatch-policy-module.md',
|
|
],
|
|
// Seeds a temp fixture copy of these five files (never mutates the real
|
|
// tree) to exercise scripts/gen-state-md-docs.cjs's marked-region splicing
|
|
// against them — #3873 (ADR-3473 §8.8), rows 10-22/27. Read for fixture
|
|
// seeding, so a content edit to any of them (e.g. renaming a landmark
|
|
// heading/string a hostile-input test targets) can change this test's
|
|
// fixture assumptions.
|
|
// #4728: pins the retirement of Gemini CLI prose from every localized
|
|
// how-to/ARCHITECTURE/USER-GUIDE/CONFIGURATION/context-monitor mirror, plus
|
|
// the PRESERVE (Antigravity) and MODEL-AXIS (Gemini 2.5 Pro) negative-space
|
|
// checks in the same locales.
|
|
'tests/gemini-runtime-removed.test.cjs': [
|
|
'docs/ja-JP/how-to/install-on-your-runtime.md',
|
|
'docs/ko-KR/how-to/install-on-your-runtime.md',
|
|
'docs/pt-BR/how-to/install-on-your-runtime.md',
|
|
'docs/zh-CN/how-to/install-on-your-runtime.md',
|
|
'docs/ja-JP/ARCHITECTURE.md',
|
|
'docs/ko-KR/ARCHITECTURE.md',
|
|
'docs/pt-BR/ARCHITECTURE.md',
|
|
'docs/zh-CN/ARCHITECTURE.md',
|
|
'docs/ja-JP/USER-GUIDE.md',
|
|
'docs/ko-KR/USER-GUIDE.md',
|
|
'docs/pt-BR/USER-GUIDE.md',
|
|
'docs/zh-CN/USER-GUIDE.md',
|
|
'docs/ja-JP/CONFIGURATION.md',
|
|
'docs/ko-KR/CONFIGURATION.md',
|
|
'docs/pt-BR/CONFIGURATION.md',
|
|
'docs/zh-CN/CONFIGURATION.md',
|
|
'docs/ja-JP/context-monitor.md',
|
|
'docs/ko-KR/context-monitor.md',
|
|
'docs/pt-BR/context-monitor.md',
|
|
'docs/zh-CN/context-monitor.md',
|
|
],
|
|
'tests/gen-state-md-docs.test.cjs': [
|
|
'docs/reference/state-md.md',
|
|
'docs/ja-JP/reference/state-md.md',
|
|
'docs/zh-CN/reference/state-md.md',
|
|
'docs/ko-KR/reference/state-md.md',
|
|
'docs/pt-BR/reference/state-md.md',
|
|
],
|
|
'tests/gsd-write-guard.test.cjs': ['docs/USER-GUIDE.md'],
|
|
'tests/host-integration-descriptors.test.cjs': [
|
|
'docs/reference/host-integration-capability-matrix.md',
|
|
],
|
|
'tests/install.test.cjs': ['docs/AGENTS.md', 'docs/INVENTORY.md', 'docs/INVENTORY-MANIFEST.json'],
|
|
// SOURCE_DIRS includes 'docs' and walks it recursively for every .md file
|
|
// (intel.test.cjs:1223-1228) — a generic tree walk.
|
|
'tests/intel.test.cjs': ['*'],
|
|
'tests/inventory-headings-countfree.test.cjs': ['docs/INVENTORY.md'],
|
|
'tests/inventory-manifest-sync.test.cjs': ['docs/INVENTORY.md', 'docs/INVENTORY-MANIFEST.json'],
|
|
'tests/kilo-upgrades.test.cjs': ['docs/how-to/connect-gsd-mcp-server.md'],
|
|
'tests/live-config-guard.test.cjs': ['docs/TESTING-SUITES.md'],
|
|
// #3726: pins the `milestone complete` synopsis (English + four localized
|
|
// mirrors), the `--confirm` flag row and the guard-override instructions —
|
|
// `type: Fixed` exempts that PR from the docs-required lint, so this is the
|
|
// only gate on that prose.
|
|
'tests/milestone.test.cjs': [
|
|
'docs/CLI-TOOLS.md',
|
|
'docs/COMMANDS.md',
|
|
'docs/ja-JP/CLI-TOOLS.md',
|
|
'docs/ko-KR/CLI-TOOLS.md',
|
|
'docs/pt-BR/CLI-TOOLS.md',
|
|
'docs/zh-CN/CLI-TOOLS.md',
|
|
],
|
|
'tests/model-catalog-runtime-defaults.test.cjs': ['docs/CONFIGURATION.md'],
|
|
// Scans every git-tracked file in the whole repo via `git ls-files`
|
|
// (no-pending-3212-markers.test.cjs:37-46), which includes all of docs/ —
|
|
// cannot be resolved to a fixed docs/ path set.
|
|
'tests/no-pending-3212-markers.test.cjs': ['*'],
|
|
'tests/phase6-capability-docs.test.cjs': ['docs/how-to/develop-a-capability.md', 'docs/README.md'],
|
|
'tests/phase6-review-capabilities.test.cjs': [
|
|
'docs/reference/review-verification-capabilities.md',
|
|
'docs/how-to/develop-a-capability.md',
|
|
'docs/README.md',
|
|
],
|
|
'tests/plan-checker-coupling.test.cjs': ['docs/AGENTS.md'],
|
|
'tests/plan-phase-drift-guard.test.cjs': [
|
|
'docs/CONFIGURATION.md',
|
|
'docs/COMMANDS.md',
|
|
'docs/USER-GUIDE.md',
|
|
'docs/ARCHITECTURE.md',
|
|
'docs/INVENTORY.md',
|
|
'docs/INVENTORY-MANIFEST.json',
|
|
],
|
|
'tests/plan-phase-stall-detection.test.cjs': ['docs/CONFIGURATION.md'],
|
|
'tests/plan-review-convergence.test.cjs': [
|
|
'docs/CONFIGURATION.md',
|
|
'docs/USER-GUIDE.md',
|
|
'docs/ARCHITECTURE.md',
|
|
],
|
|
'tests/planner-estimate-emission.test.cjs': ['docs/reference/plan-md.md', 'docs/CONFIGURATION.md'],
|
|
'tests/precondition-element.test.cjs': ['docs/reference/plan-md.md'],
|
|
'tests/product-name-purity.test.cjs': [
|
|
'docs/README.md',
|
|
'docs/zh-CN/README.md',
|
|
'docs/ko-KR/README.md',
|
|
'docs/ja-JP/README.md',
|
|
'docs/pt-BR/README.md',
|
|
],
|
|
'tests/progress-forensic.test.cjs': ['docs/COMMANDS.md'],
|
|
'tests/repo-layout.test.cjs': ['docs/contributing/bootstrap.md'],
|
|
// Reads REQ-LANG-04 and runs every form it offers an author through the
|
|
// matcher that enforces it, so a reword of the requirement alone is exactly
|
|
// the change this guard must run on (#2529). Both paths are named because
|
|
// #3840 made docs/FEATURES.md a generated projection: the requirement's
|
|
// source is the fragment, and an edit there that is not regenerated would
|
|
// otherwise reach this guard through neither path.
|
|
'tests/response-language-coverage.test.cjs': [
|
|
'docs/FEATURES.md',
|
|
'docs/features/response-language-config.md',
|
|
],
|
|
'tests/reversibility-tagging.test.cjs': ['docs/reference/plan-md.md'],
|
|
'tests/reviewer-docs-parity.test.cjs': [
|
|
'docs/COMMANDS.md',
|
|
'docs/ja-JP/COMMANDS.md',
|
|
'docs/ko-KR/COMMANDS.md',
|
|
'docs/pt-BR/COMMANDS.md',
|
|
'docs/zh-CN/COMMANDS.md',
|
|
'docs/FEATURES.md',
|
|
'docs/ja-JP/FEATURES.md',
|
|
'docs/ko-KR/FEATURES.md',
|
|
'docs/pt-BR/FEATURES.md',
|
|
'docs/zh-CN/FEATURES.md',
|
|
],
|
|
'tests/runtime-converters.test.cjs': ['docs/CONFIGURATION.md'],
|
|
'tests/secure-phase.test.cjs': ['docs/CONFIGURATION.md'],
|
|
'tests/security-dead-exports.regression.test.cjs': ['docs/FEATURES.md'],
|
|
'tests/security.test.cjs': ['docs/INVENTORY-MANIFEST.json'],
|
|
// Walks docs/ recursively (todos-done-rename-guard.test.cjs:19-22
|
|
// SCAN_DIRS) looking for stale references — a generic tree walk.
|
|
'tests/todos-done-rename-guard.test.cjs': ['*'],
|
|
'tests/tracer-bullet.test.cjs': [
|
|
'docs/COMMANDS.md',
|
|
'docs/reference/plan-md.md',
|
|
'docs/how-to/plan-a-phase.md',
|
|
'docs/AGENTS.md',
|
|
],
|
|
'tests/ui-spec-inventory-provenance.test.cjs': [
|
|
'docs/FEATURES.md',
|
|
'docs/how-to/design-a-ui-phase.md',
|
|
'docs/ja-JP/FEATURES.md',
|
|
'docs/ja-JP/how-to/design-a-ui-phase.md',
|
|
'docs/zh-CN/FEATURES.md',
|
|
'docs/zh-CN/how-to/design-a-ui-phase.md',
|
|
'docs/ko-KR/FEATURES.md',
|
|
'docs/ko-KR/how-to/design-a-ui-phase.md',
|
|
'docs/pt-BR/how-to/design-a-ui-phase.md',
|
|
],
|
|
'tests/verifier-behavior-unverified.test.cjs': ['docs/reference/planning-artifacts.md'],
|
|
'tests/verifier-coincidental-reliance.test.cjs': ['docs/AGENTS.md'],
|
|
'tests/verify.test.cjs': ['docs/reference/plan-md.md'],
|
|
'tests/workflow-fragments.test.cjs': ['docs/reference/workflow-fragments.md'],
|
|
};
|
|
|
|
/**
|
|
* Flat file-list view of DOCS_GUARD_TESTS, kept for consumers (the
|
|
* registration lint and its parity test) that only need "which test files
|
|
* are registered", not their per-file docs path patterns.
|
|
*/
|
|
const DOCS_GUARD_TEST_FILES = Object.keys(DOCS_GUARD_TESTS);
|
|
|
|
assertNoSuiteCollision(DOCS_GUARD_TEST_FILES);
|
|
|
|
module.exports = {
|
|
DOCS_GUARD_TESTS,
|
|
DOCS_GUARD_TEST_FILES,
|
|
RUN_TESTS_SUITES,
|
|
assertNoSuiteCollision,
|
|
normalizeForSuiteCheck,
|
|
};
|