diff --git a/.claude/hooks/check-affected-pre-push.sh b/.claude/hooks/check-affected-pre-push.sh index c7b2435424..080e0c07ee 100755 --- a/.claude/hooks/check-affected-pre-push.sh +++ b/.claude/hooks/check-affected-pre-push.sh @@ -16,7 +16,7 @@ # best-effort and also fires on any command holding $(), backticks or $VAR # (https://code.claude.com/docs/en/hooks#bash-if-matching), so this script # re-checks that a subcommand really is `git push` before it spends a run -# (docs/conventions/hook-precision/README.md, rule 2). A quoted or heredoc +# (docs/contracts/hook-precision/README.md, rule 2). A quoted or heredoc # mention of "git push" is data, not a push. # # Stays quiet (exit 0) on: no real push; a push that only deletes remote refs, diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 7ccfffbad1..052140bf21 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -124,7 +124,7 @@ updates: - "patch" # The harness-ops inventory's parser packages (acorn, eslint-scope). Nothing is # vendored: the committed lockfile is what `npm ci` installs on first use - # (docs/conventions/on-demand-dependencies/), so a bump here is the release. + # (docs/contracts/on-demand-dependencies/), so a bump here is the release. - package-ecosystem: npm directory: /plugins/harness-ops/skills/inventory/scripts/js labels: @@ -143,7 +143,7 @@ updates: - "patch" # The harness-ops control-claude-code driver's terminal engine (@microsoft/tui-test). # Nothing is vendored: the committed lockfile is what `npm ci` installs on first use - # (docs/conventions/on-demand-dependencies/), so a bump here is the release. + # (docs/contracts/on-demand-dependencies/), so a bump here is the release. - package-ecosystem: npm directory: /plugins/harness-ops/skills/control-claude-code/driver labels: @@ -162,7 +162,7 @@ updates: - "patch" # The testing check-visual-parity skill's pixelmatch and pngjs. Nothing is # vendored: the committed lockfile is what `npm ci` installs on first use - # (docs/conventions/on-demand-dependencies/), so a bump here is the release. + # (docs/contracts/on-demand-dependencies/), so a bump here is the release. - package-ecosystem: npm directory: /plugins/testing/skills/check-visual-parity/scripts labels: @@ -267,7 +267,7 @@ updates: - "patch" # The animation plugin's hash-locked Python packages (numpy, opencv). Nothing is vendored: # the SessionStart hook installs requirements.txt on demand - # (docs/conventions/on-demand-dependencies/), so a bump here is the release. + # (docs/contracts/on-demand-dependencies/), so a bump here is the release. - package-ecosystem: pip directory: /plugins/animation labels: @@ -286,7 +286,7 @@ updates: - "patch" # The explainer-video plugin's hash-locked Python packages (ManimCE). Nothing is vendored: # the SessionStart hook installs requirements.txt on demand - # (docs/conventions/on-demand-dependencies/), so a bump here is the release. + # (docs/contracts/on-demand-dependencies/), so a bump here is the release. - package-ecosystem: pip directory: /plugins/explainer-video labels: diff --git a/.github/scripts/plugin-eval/select-plugins.test.mjs b/.github/scripts/plugin-eval/select-plugins.test.mjs index 2a9fd42b36..73b633e08f 100644 --- a/.github/scripts/plugin-eval/select-plugins.test.mjs +++ b/.github/scripts/plugin-eval/select-plugins.test.mjs @@ -16,7 +16,7 @@ test("a change under a plugin's evals selects that plugin only", () => { }); test("a change only under docs selects nothing", () => { - assert.deepEqual(selectPlugins(["docs/adr/0001-x.md", "docs/conventions/loop-lane/README.md"]), []); + assert.deepEqual(selectPlugins(["docs/adr/0001-x.md", "docs/contracts/loop-lane/README.md"]), []); }); test("skills and agents select their plugin once, sorted", () => { diff --git a/.github/scripts/pr-merge/enable-auto-merge.mjs b/.github/scripts/pr-merge/enable-auto-merge.mjs index 2cb5ee13f8..1b22055deb 100755 --- a/.github/scripts/pr-merge/enable-auto-merge.mjs +++ b/.github/scripts/pr-merge/enable-auto-merge.mjs @@ -103,7 +103,7 @@ // answers them all; a run whose verifier read did not come never narrows a // person's comment that already names its reasons. The // comment is the record; only a cause a person must clear -// (docs/conventions/loop-lane/README.md#when-work-stops-for-the-owner, +// (docs/contracts/loop-lane/README.md#when-work-stops-for-the-owner, // with cost and trust holds kept: untrusted // provenance or an untrusted spec, a security finding, a high path, a // trusted-actor widening, a real charge or a listing too long to check, see @@ -610,7 +610,7 @@ export function verifyHold(evidence, head) { export const TRUST_REFUSALS = Object.freeze(["untrusted-provenance", "untrusted-provenance-removed-by-non-human", "issue-labels-unreadable"]); // Who clears the refusal verifyHold reads in `evidence` at `head` -// (docs/conventions/loop-lane/README.md#when-work-stops-for-the-owner; +// (docs/contracts/loop-lane/README.md#when-work-stops-for-the-owner; // cost and trust holds stay a person's): `person` // for an issue link the trust hold refuses (TRUST_REFUSALS), a verifier // refusal the gate marks `needsHuman` (babysit_verify_evidence NEEDS_HUMAN) diff --git a/.github/scripts/pr-merge/post-unarmed-status.mjs b/.github/scripts/pr-merge/post-unarmed-status.mjs index e01ccf9b19..470265b1cb 100755 --- a/.github/scripts/pr-merge/post-unarmed-status.mjs +++ b/.github/scripts/pr-merge/post-unarmed-status.mjs @@ -7,7 +7,7 @@ // // The status shows a hold the lanes own on the pull request, in place of the // human-gated label (when a person is needed: -// docs/conventions/loop-lane/README.md#when-work-stops-for-the-owner). It is informational: +// docs/contracts/loop-lane/README.md#when-work-stops-for-the-owner). It is informational: // its context is not `ci-status`, the only check the main ruleset requires, // so it neither holds nor passes a merge. Each head's newest status in the // context is read first, trusted only when the GitHub Actions bot posted it diff --git a/.github/workflows/pr-require-checks.yml b/.github/workflows/pr-require-checks.yml index 3749224e80..124b4bfb9f 100644 --- a/.github/workflows/pr-require-checks.yml +++ b/.github/workflows/pr-require-checks.yml @@ -1686,7 +1686,7 @@ jobs: # whole hook entry whenever the key is unset (the declared userConfig # `default` is unimplemented upstream — anthropics/claude-code#46477), so # the hook never fires on a default install. The channel decision matrix - # (docs/conventions/hook-config-delivery/) rules argv out for hooks; this + # (docs/contracts/hook-config-delivery/) rules argv out for hooks; this # gate pins the exact regression #1242 fixed. - name: Check plugin hook configs for bare userConfig argv tokens id: userconfig_argv @@ -2264,7 +2264,7 @@ jobs: - name: Verify generated shared-library copies match their canonical sources if: needs.select-tests.outputs.run_tests == 'true' run: scripts/sync-shared-copies.sh --check - # docs/conventions/prerequisites/: the gate validates every + # docs/contracts/prerequisites/: the gate validates every # prerequisites.json and fails on an undeclared tool not listed in # scripts/prerequisites-baseline.txt. Its suites run through the selector. - name: Check plugin prerequisites are declared diff --git a/lefthook.yml b/lefthook.yml index 888d53e745..df746e6386 100644 --- a/lefthook.yml +++ b/lefthook.yml @@ -2,7 +2,7 @@ # `lefthook install`, which also fetches the guardrails git hooks named in `remotes:` below; until # then the .claude/settings.json pre-push row runs the check-affected check on a Claude Code # session's pushes and says to install. Placement rules: -# docs/conventions/check-placement/README.md. +# docs/contracts/check-placement/README.md. pre-push: jobs: # Runs .claude/hooks/check-affected-pre-push.sh as committed at the merge-base with diff --git a/scripts/check-declared-prerequisites.mjs b/scripts/check-declared-prerequisites.mjs index 58c0c4e77a..e4a8f408a7 100755 --- a/scripts/check-declared-prerequisites.mjs +++ b/scripts/check-declared-prerequisites.mjs @@ -7,7 +7,7 @@ // Three checks, all against scripts/prerequisites-baseline.txt, which lists // today's gaps as ` ` lines so main stays green: // 1. Every plugins/*/prerequisites.json passes the schema in -// docs/conventions/prerequisites/, read through lib/prerequisites.mjs. +// docs/contracts/prerequisites/, read through lib/prerequisites.mjs. // Gap `schema`: a file not yet in the schema's shape. // 2. A plugin with a valid file carries the generated checker copies // (lib/prerequisites.mjs, .sh, .ps1) registered in scripts/shared-copies.txt. @@ -295,7 +295,7 @@ export function main(argv, out = { log: console.log, error: console.error }) { } if (findings.length) { for (const f of findings) out.error(f); - out.error(`${findings.length} finding(s). Declare the tool per docs/conventions/prerequisites/README.md.`); + out.error(`${findings.length} finding(s). Declare the tool per docs/contracts/prerequisites/README.md.`); return 1; } out.log( diff --git a/scripts/check-detector-eval-coverage.sh b/scripts/check-detector-eval-coverage.sh index 6186c84dfd..b1aeca22c4 100755 --- a/scripts/check-detector-eval-coverage.sh +++ b/scripts/check-detector-eval-coverage.sh @@ -178,7 +178,7 @@ # runs to EOF, so that assertion alone passed while the gate was most broken. # # Adjacent and DIFFERENT: scripts/check-detector-findings-crosswalk.sh checks -# that each severity-crosswalk row in docs/conventions/detector-findings/ argues +# that each severity-crosswalk row in docs/contracts/detector-findings/ argues # its disposition from a stated test. That is a judgment about a markdown table # and says nothing about eval coverage. # scripts/check-fleet-finding-test-coverage.sh is the same SHAPE one surface diff --git a/scripts/check-docs-naming.test.sh b/scripts/check-docs-naming.test.sh index 1e00b2e61f..4739f96f6c 100755 --- a/scripts/check-docs-naming.test.sh +++ b/scripts/check-docs-naming.test.sh @@ -22,10 +22,10 @@ mk_repo() { local dir fixture_tree::build "$1" --sut "$SUT_SRC" --git || return 1 dir="${!1}" - mkdir -p "$dir/docs/conventions/standards" "$dir/docs/adr" + mkdir -p "$dir/docs/contracts/standards" "$dir/docs/adr" printf 'seed\n' >"$dir/docs/README.md" printf 'seed\n' >"$dir/docs/plugin-philosophy.md" - printf 'seed\n' >"$dir/docs/conventions/standards/README.md" + printf 'seed\n' >"$dir/docs/contracts/standards/README.md" printf 'seed\n' >"$dir/docs/adr/0001-first.md" git_test_config "$dir" add -A >/dev/null git_test_config "$dir" commit -qm base @@ -310,7 +310,7 @@ if [[ -n "$drift_ready" ]]; then docs/NEW-FILE.md docs/a/snake_case.md docs/a/Mixed.md docs/a/foo..md docs/a/foo.md. docs/a/foo... docs/a/noext docs/a/README.md.bak docs/a/v1.2.schema.json docs/Foo.md docs/foo.md - docs/conventions/standards/readme.md docs/x/Readme.md + docs/contracts/standards/readme.md docs/x/Readme.md docs/a/Bad_Name.PY "docs/x/caf"$'\303\251'".py" "docs/x/Caf"$'\303\251'".py" "docs/New"$'\n'"line/foo.md" "docs/new"$'\n'"line/foo.md" Top_Level.txt other/Bad_Name.json diff --git a/scripts/check-docs-only-gate.sh b/scripts/check-docs-only-gate.sh index 36a1ce66fd..b73933fae1 100755 --- a/scripts/check-docs-only-gate.sh +++ b/scripts/check-docs-only-gate.sh @@ -9,7 +9,7 @@ # WHY. The heavy lanes short-circuit on a diff confined to the docs-only # allowlist. That short-circuit is a fail-open shape by construction: getting it # wrong makes a lane report success without running, which is exactly the -# false-green docs/conventions/liveness-assertion/ names. Consumers spell the +# false-green docs/contracts/liveness-assertion/ names. Consumers spell the # gate as `steps.scope.outputs.docs_only != 'true'`, an INVERSE-polarity test # of a string flag. A consumer that wrote `== 'false'` instead of `!= 'true'` # would skip its lane whenever the detector emitted anything unexpected: the diff --git a/scripts/check-drive-root-litter.sh b/scripts/check-drive-root-litter.sh index f804e7b2dc..df252bf806 100755 --- a/scripts/check-drive-root-litter.sh +++ b/scripts/check-drive-root-litter.sh @@ -16,7 +16,7 @@ # `:\d\dir` and the consumer creates that whole phantom chain # before writing. The residue is therefore always the same shape: `:\\` # where `` is the single letter of the drive the author MEANT to write to. -# `docs/conventions/windows-path-emit/README.md` owns the rule that prevents it; +# `docs/contracts/windows-path-emit/README.md` owns the rule that prevents it; # this script is that rule's detection net, for the runs that ignore it. # # Requiring the directory name to match a MOUNTED DRIVE is what keeps the @@ -179,7 +179,7 @@ The litter is the cheap part. Whatever wrote it wrote to a path it did not intend, so any run that produced it may have measured something other than what it claims. Re-check the run's results before trusting them, then: - * fix the emitter - see docs/conventions/windows-path-emit/README.md, and + * fix the emitter - see docs/contracts/windows-path-emit/README.md, and scripts/emit-windows-path.sh for the conversion itself; * CHECK FOR A REGISTERED GIT WORKTREE BEFORE REMOVING ANYTHING. A phantom tree can contain one: a `git worktree add` given an unconverted path diff --git a/scripts/check-hook-userconfig-argv.sh b/scripts/check-hook-userconfig-argv.sh index 463e28356c..9d6c3dcb90 100755 --- a/scripts/check-hook-userconfig-argv.sh +++ b/scripts/check-hook-userconfig-argv.sh @@ -8,7 +8,7 @@ # closed not-planned), so an unset-but-defaulted ${user_config.*} argv token # silently drops the ENTIRE hook entry instead of substituting. On a default # install the hook never fires. The channel decision matrix -# (docs/conventions/hook-config-delivery/) rules argv out for hooks until +# (docs/contracts/hook-config-delivery/) rules argv out for hooks until # upstream implements `default`; this gate pins that rule. # # Scope: hook configurations only — the default hooks/hooks.json, any @@ -193,7 +193,7 @@ if ((errors > 0)); then echo "A \${user_config.*} token in a plugin hook config silently drops the" echo "whole hook entry whenever the key is unset (declared defaults are not" echo "implemented upstream). Deliver the value per the channel decision" - echo "matrix instead: docs/conventions/hook-config-delivery/README.md." + echo "matrix instead: docs/contracts/hook-config-delivery/README.md." } >&2 exit 1 fi diff --git a/scripts/check-lane-coverage.sh b/scripts/check-lane-coverage.sh index 32195ae22e..d61429f5fb 100755 --- a/scripts/check-lane-coverage.sh +++ b/scripts/check-lane-coverage.sh @@ -19,7 +19,7 @@ # is not a gate: `managed-scope-sync` and `state-key-sync` shipped outside the # aggregate for their whole lifetime (claude-code-plugins#2856), each advertised # as a dedicated check in scripts/cross-plugin-source-registry.txt. That is the -# false-green shape docs/conventions/liveness-assertion/ names — green surface, +# false-green shape docs/contracts/liveness-assertion/ names — green surface, # dead enforcement — with the added twist that the surface is the merge gate # itself. # diff --git a/scripts/check-loop-lane-floor-drift.sh b/scripts/check-loop-lane-floor-drift.sh index 36423292cb..d2d9c88530 100755 --- a/scripts/check-loop-lane-floor-drift.sh +++ b/scripts/check-loop-lane-floor-drift.sh @@ -9,7 +9,7 @@ # Exit: 0 every consumer matches the source, 1 drift or a stale registration, # 2 usage or a prerequisite this gate cannot verify around. # -# WHY. docs/conventions/loop-lane/README.md section 6 orders every consuming +# WHY. docs/contracts/loop-lane/README.md section 6 orders every consuming # lane body to INLINE the floor, because an installed plugin cannot read a # sibling plugin's files at runtime: the values have to be in the lane body or # the lane cannot apply them. Inlining is therefore the design, not a defect, @@ -43,7 +43,7 @@ # author does not add the entry, the six registered paths still agree, CI is # green, and the next contract change strands that seventh copy. That is the # same blindness that produced the drift this gate exists for, one level up, -# and it is the false-green shape docs/conventions/liveness-assertion/ names. +# and it is the false-green shape docs/contracts/liveness-assertion/ names. # # So before comparing anything, every TRACKED file is scanned for the floor's # opening bullet and any carrier outside the registry FAILS. Discovery uses the @@ -104,7 +104,7 @@ # adds the shape to the anchor here, in the same change. # # LIVENESS-ASSERTION CONVENTION, taxonomy row **Gate / classifier** -# (docs/conventions/liveness-assertion/README.md). That row requires the verdict +# (docs/contracts/liveness-assertion/README.md). That row requires the verdict # to reflect the state actually read, and fail-closed on ambiguity rather than # green on a misread signal. This gate satisfies it through the core contract's # **fail loud** limb, not the agent-readable one: it blocks. Every input it @@ -421,7 +421,7 @@ if ((errors != 0)); then The rate-limit guard's operable floor is inlined on purpose: an installed plugin cannot read a sibling plugin's files at runtime, so every consumer -carries its own copy (docs/conventions/loop-lane/README.md section 6). The +carries its own copy (docs/contracts/loop-lane/README.md section 6). The values are DECIDED in one place only: $SOURCE diff --git a/scripts/check-loop-lane-floor-drift.test.sh b/scripts/check-loop-lane-floor-drift.test.sh index d9defc408c..30b4695898 100755 --- a/scripts/check-loop-lane-floor-drift.test.sh +++ b/scripts/check-loop-lane-floor-drift.test.sh @@ -8,7 +8,7 @@ # # The cases that earn their keep are the ones proving the gate goes RED. A # drift check nobody has watched fail is the false-green shape -# docs/conventions/liveness-assertion/ names. So every failure class gets a case: exact +# docs/contracts/liveness-assertion/ names. So every failure class gets a case: exact # drift, values drift, a consumer that stopped inlining the floor, a # registration pointing at nothing, a COPY NOBODY REGISTERED, and the two ways # the extractor could go blind and pass everything forever. diff --git a/scripts/check-shell-portability.test.sh b/scripts/check-shell-portability.test.sh index 7960d9d619..e6e93df7a9 100755 --- a/scripts/check-shell-portability.test.sh +++ b/scripts/check-shell-portability.test.sh @@ -15,7 +15,7 @@ # to prove the shipping config, not just the mechanism. # # Assertion scaffolding lives in scripts/lib/test-harness.sh — repo tooling, -# not a plugin library. See docs/conventions/shell-test-helpers/README.md. +# not a plugin library. See docs/contracts/shell-test-helpers/README.md. # shellcheck disable=SC2016 # fixture bodies are literal shell content in single quotes; expansion is never wanted set -uo pipefail diff --git a/scripts/check-silent-skips.sh b/scripts/check-silent-skips.sh index 718a328634..a5c53d3e4a 100755 --- a/scripts/check-silent-skips.sh +++ b/scripts/check-silent-skips.sh @@ -37,7 +37,7 @@ # A bare stderr write (`>&2`) is NOT a sanctioned visibility call: every site # this gate inspects is, by construction, an exit-0 skip path, and per the # official Claude Code hooks reference (re-fetched 2026-08-10, -# docs/conventions/hook-observability/) "Stderr from a hook that exits 0 goes +# docs/contracts/hook-observability/) "Stderr from a hook that exits 0 goes # to the debug log only, never the transcript, and Claude never sees it" — so # it reaches neither the user nor the agent on any path this gate inspects. # A `>&2`-only notice on such a path is invisible regardless of intent. @@ -204,7 +204,7 @@ if ((errors > 0)); then echo "or carry a documented quiet classification:" echo "'# silent-skip-ok: ' at the site. A bare stderr write is" echo "NOT sufficient — stderr on exit 0 is never shown to the user or" - echo "the agent (docs/conventions/hook-observability/)." + echo "the agent (docs/contracts/hook-observability/)." echo echo "A scripts/*.test.sh that cannot run an assertion must fail closed" echo "(or annotate with '# silent-skip-ok: '), never score the" diff --git a/scripts/check-skill-portability.test.sh b/scripts/check-skill-portability.test.sh index e551ed98ce..d5b69c269e 100755 --- a/scripts/check-skill-portability.test.sh +++ b/scripts/check-skill-portability.test.sh @@ -7,7 +7,7 @@ # bare-vs-guarded discrimination on live files, not only synthetic ones. # # Assertion scaffolding lives in scripts/lib/test-harness.sh — repo tooling, -# not a plugin library. See docs/conventions/shell-test-helpers/README.md. +# not a plugin library. See docs/contracts/shell-test-helpers/README.md. # shellcheck disable=SC2016 # fixture bodies are literal skill content in single quotes; expansion is never wanted set -uo pipefail diff --git a/scripts/check-upstream-drift.sh b/scripts/check-upstream-drift.sh index 70c6d861d9..135470ddb6 100755 --- a/scripts/check-upstream-drift.sh +++ b/scripts/check-upstream-drift.sh @@ -8,7 +8,7 @@ # scripts/check-upstream-drift.sh --help # # The page forms (the git pin marker, row links, drift inputs, the `## Map` -# section and page status) are defined in docs/conventions/upstream-drift/ +# section and page status) are defined in docs/contracts/upstream-drift/ # README.md, "Pinned git upstreams". In short: a page whose marker line reads # **Last audited upstream state:** `/@<40-hex sha>` [under `/`] # is checked; links to that repository outside `## Map` are drift inputs for any @@ -350,7 +350,7 @@ for page in ${PAGES[@]+"${PAGES[@]}"}; do parse_marker "$file" case $? in 0) GIT_PAGES+=("$page") ;; - 2) die "$page: marker line names a pin but does not match the git form (see docs/conventions/upstream-drift/README.md, \"Pinned git upstreams\")" ;; + 2) die "$page: marker line names a pin but does not match the git form (see docs/contracts/upstream-drift/README.md, \"Pinned git upstreams\")" ;; *) ((EXPLICIT)) && die "$page: no git pin marker" ;; esac done @@ -493,7 +493,7 @@ fi if ((drifted > 0)); then printf '%s\n' "${FINDINGS[@]}" >&2 - printf '%s: %d of %d page(s) show upstream drift; re-audit the rows named above (docs/conventions/upstream-drift/README.md, "Pinned git upstreams").\n' \ + printf '%s: %d of %d page(s) show upstream drift; re-audit the rows named above (docs/contracts/upstream-drift/README.md, "Pinned git upstreams").\n' \ "$SELF" "$drifted" "${#GIT_PAGES[@]}" >&2 exit 1 fi diff --git a/scripts/emit-windows-path.sh b/scripts/emit-windows-path.sh index 7f5500aba3..7446ec6e0c 100755 --- a/scripts/emit-windows-path.sh +++ b/scripts/emit-windows-path.sh @@ -18,7 +18,7 @@ # Windows-native consumer - PowerShell, cmd, or a native interpreter such as # Windows Python - the leading `/` anchors to the root of the CURRENT DRIVE, so # the literal becomes `:\d\dir`. Nothing errors: the consumer -# happily creates the phantom tree and writes there. `docs/conventions/windows-path-emit/README.md` owns the rule +# happily creates the phantom tree and writes there. `docs/contracts/windows-path-emit/README.md` owns the rule # this script implements, including the rule that ranks ABOVE it: prefer a path # the native side computes itself from a working directory it already owns, and # reach for this conversion only when an absolute path genuinely has to cross. diff --git a/scripts/gen-hook-event-registry.sh b/scripts/gen-hook-event-registry.sh index c46a18a330..e8f1b77bc7 100755 --- a/scripts/gen-hook-event-registry.sh +++ b/scripts/gen-hook-event-registry.sh @@ -18,8 +18,8 @@ # (https://code.claude.com/docs/en/hooks, the lifecycle table under "Hook # lifecycle"), and a hardcoded list drifts silently as events are added or # renamed. Every registry entry is a four-part record per -# docs/conventions/upstream-drift (claim, basis, as-of date, recheck trigger), -# and per docs/conventions/native-references it states what the reference +# docs/contracts/upstream-drift (claim, basis, as-of date, recheck trigger), +# and per docs/contracts/native-references it states what the reference # documented on the as-of date, never that the running binary fires the event. # # The log is a mod (plugins/harness-ops/hooks/register.ts; ADR 0065). It hooks diff --git a/scripts/lib/test-harness.sh b/scripts/lib/test-harness.sh index 16ab4dc899..5241dc6152 100644 --- a/scripts/lib/test-harness.sh +++ b/scripts/lib/test-harness.sh @@ -23,7 +23,7 @@ # leak into the next, in one place. # # Plugin *.test.sh helpers stay duplicated on purpose; see -# docs/conventions/shell-test-helpers/README.md. This file is the repo-tooling +# docs/contracts/shell-test-helpers/README.md. This file is the repo-tooling # layer only. if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then diff --git a/scripts/pilot-plugin-quality-sim.test.sh b/scripts/pilot-plugin-quality-sim.test.sh index 6ea7c0153c..55095e1b43 100755 --- a/scripts/pilot-plugin-quality-sim.test.sh +++ b/scripts/pilot-plugin-quality-sim.test.sh @@ -16,7 +16,7 @@ # This scripts the deterministic halves of the pilot's license; the # model-judgment halves (interview, migration prose, gating) are covered by the # setup and audit eval cases. Per-script assertion helpers are deliberately -# duplicated, not shared: docs/conventions/shell-test-helpers/README.md. +# duplicated, not shared: docs/contracts/shell-test-helpers/README.md. # # shellcheck disable=SC2016 # single-quoted backticks are the pointer grammar under test set -uo pipefail diff --git a/scripts/upstream-drift-issues.sh b/scripts/upstream-drift-issues.sh index 772129b385..0a298e0634 100755 --- a/scripts/upstream-drift-issues.sh +++ b/scripts/upstream-drift-issues.sh @@ -22,7 +22,7 @@ # --body-file. No labels, assignees or mentions. # # The whole report is parsed before any gh call. Each line follows the fixed -# field order of the report (docs/conventions/upstream-drift/README.md, the +# field order of the report (docs/contracts/upstream-drift/README.md, the # --report row): the path is everything after the first ` path=`. A line that # breaks the order exits 2 with no gh call. # @@ -186,7 +186,7 @@ write_body() { local body note repo="${REPOS[$1]}" body="Upstream $(span "$repo") changed since the pin on its docs/upstream page." body+=$'\n\n'"Run: $RUN_DATE, $RUN_URL"$'\n'"${DETAIL[$1]}" - body+=$'\n'"Re-audit the rows named above as docs/conventions/upstream-drift/README.md, \"When a trigger fires\", requires. Moving the pin makes the next run clean, which closes this issue."$'\n' + body+=$'\n'"Re-audit the rows named above as docs/contracts/upstream-drift/README.md, \"When a trigger fires\", requires. Moving the pin makes the next run clean, which closes this issue."$'\n' if ((${#body} > CAP)); then note=$'\n'"Cut at $CAP characters. The full report is in the run's job summary: $RUN_URL"$'\n' body="${body:0:$((CAP - ${#note}))}" diff --git a/scripts/upstream-drift-issues.test.sh b/scripts/upstream-drift-issues.test.sh index d3ac84b64a..838fe4185a 100755 --- a/scripts/upstream-drift-issues.test.sh +++ b/scripts/upstream-drift-issues.test.sh @@ -6,7 +6,7 @@ # Hermetic: a stub `gh` first on PATH records every call (one argv element per # line) and copies any --body-file into the log, so no case reaches GitHub. # Report lines are written by hand in the form check-upstream-drift.sh --report -# prints (docs/conventions/upstream-drift/README.md, the --report row); titles, +# prints (docs/contracts/upstream-drift/README.md, the --report row); titles, # issue numbers and the 60,000-character cap are literals of the plan. # shellcheck disable=SC2016 # stub source and expected code spans are literal text; expansion is never wanted set -uo pipefail diff --git a/scripts/validate-plugin-contracts.mjs b/scripts/validate-plugin-contracts.mjs index 87d2f5eb6b..026ebef134 100755 --- a/scripts/validate-plugin-contracts.mjs +++ b/scripts/validate-plugin-contracts.mjs @@ -197,7 +197,7 @@ for (const path of setupSkills) { // prerequisites) have no such signal and are covered by the check-only // declaration plus the registry exclusion, not by a second existence probe. if (!/^argument-hint:\s*"[[<]check[|\]>]/m.test(frontmatter)) { - fail(path, 'setup skills must declare check as the leading action in argument-hint ("[check|apply] ...", " ...", or "[check] ...") (docs/conventions/argument-hint/README.md)'); + fail(path, 'setup skills must declare check as the leading action in argument-hint ("[check|apply] ...", " ...", or "[check] ...") (docs/contracts/argument-hint/README.md)'); } const body = content.slice(content.indexOf("---", 3) + 3); if (!/`check`/.test(body)) { @@ -227,7 +227,7 @@ for (const path of setupSkills) { if (trackedConfigOwners?.has(plugin)) { fail( path, - "the check-only carve-out is unavailable here: this plugin owns the tracked consumer config surface registered in docs/conventions/config-cascade/README.md, and \"A plugin with even one writable owned artifact takes the narrow-write shape instead\"", + "the check-only carve-out is unavailable here: this plugin owns the tracked consumer config surface registered in docs/contracts/config-cascade/README.md, and \"A plugin with even one writable owned artifact takes the narrow-write shape instead\"", ); } // The one carve-out surface with a manifest-side counterpart. Any claim @@ -531,7 +531,7 @@ if (existsSync(marketplacePath)) { // --------------------------------------------------------------------------- // Retired conventions: plugins//retirements.yaml // (docs/migration-playbook.md § Retired conventions; owner doc -// docs/conventions/retired-conventions/README.md). +// docs/contracts/retired-conventions/README.md). // // A manifest is the append-only record of consumer-facing artifacts a plugin // has retired; the shared helper lib/check-retirements.sh (canonical in @@ -1167,7 +1167,7 @@ for (const path of argumentSkills) { // Empty fails (omit the key instead). Over budget and malformed warn, so a // drifting hint does not turn the fleet red on its own; the contract test // asserts the shipping tree draws zero warnings. -const ARGUMENT_HINT_DOC = "docs/conventions/argument-hint/README.md"; +const ARGUMENT_HINT_DOC = "docs/contracts/argument-hint/README.md"; const ARGUMENT_HINT_BUDGET = 100; const warnings = []; @@ -1275,9 +1275,9 @@ for (const path of argumentSkills) { } } -// Plugin names and option text, per docs/conventions/plugin-option-naming. A +// Plugin names and option text, per docs/contracts/plugin-option-naming. A // displayName fails; every title and description shape warns on its own line. -const OPTION_NAMING_DOC = "docs/conventions/plugin-option-naming/README.md"; +const OPTION_NAMING_DOC = "docs/contracts/plugin-option-naming/README.md"; const DESCRIPTION_BUDGET = 300; const optionWarn = (path, message) => warnings.push(`${relative(root, path)}: ${message} (${OPTION_NAMING_DOC})`); diff --git a/scripts/validate-plugin-contracts.test.sh b/scripts/validate-plugin-contracts.test.sh index 4dd9117668..ba618ac72b 100755 --- a/scripts/validate-plugin-contracts.test.sh +++ b/scripts/validate-plugin-contracts.test.sh @@ -74,7 +74,7 @@ reset_fixture() { # arguments it still carries one unrelated row, so an empty table is only ever # asserted deliberately. write_registry() { - mkdir -p "$TMP/docs/conventions/config-cascade" + mkdir -p "$TMP/docs/contracts/config-cascade" { echo '# Consumer config cascade (fixture)' echo @@ -96,7 +96,7 @@ write_registry() { echo '### Overlay spelling drift' echo echo 'Prose after the table.' - } >"$TMP/docs/conventions/config-cascade/README.md" + } >"$TMP/docs/contracts/config-cascade/README.md" } # make_plugin -- an empty string declares no @@ -178,7 +178,7 @@ fi # it, the shape the shipping "`standards` (`planning`, `review`)" row # takes. Every backticked token in the cell is an owner. ------------- reset_fixture -mkdir -p "$TMP/docs/conventions/config-cascade" +mkdir -p "$TMP/docs/contracts/config-cascade" { echo '# Consumer config cascade (fixture)' echo @@ -187,7 +187,7 @@ mkdir -p "$TMP/docs/conventions/config-cascade" echo '| Surface | Consumer config path | Layers | Conformance |' echo '|---|---|---|---|' echo '| `a-shared-surface` (`alpha`, `gamma`) | `.claude/shared.yaml` | all three | conforms |' -} >"$TMP/docs/conventions/config-cascade/README.md" +} >"$TMP/docs/contracts/config-cascade/README.md" make_plugin alpha alpha_api_key carve_out_body | write_setup_skill alpha '[check]' out="$(run_fixture)" @@ -326,9 +326,9 @@ fi # --- 7. Present but restructured: the Implementers section is gone. --------- reset_fixture -mkdir -p "$TMP/docs/conventions/config-cascade" +mkdir -p "$TMP/docs/contracts/config-cascade" printf '# Consumer config cascade (fixture)\n\nNo Implementers section here.\n' \ - >"$TMP/docs/conventions/config-cascade/README.md" + >"$TMP/docs/contracts/config-cascade/README.md" make_plugin alpha alpha_api_key carve_out_body | write_setup_skill alpha '[check]' out="$(run_fixture)" @@ -342,7 +342,7 @@ fi reset_fixture # Drop the one unrelated row's section so the Implementers table is genuinely # empty rather than merely narrow. -mkdir -p "$TMP/docs/conventions/config-cascade" +mkdir -p "$TMP/docs/contracts/config-cascade" { echo '# Consumer config cascade (fixture)' echo @@ -350,7 +350,7 @@ mkdir -p "$TMP/docs/conventions/config-cascade" echo echo '| Surface | Consumer config path | Layers | Conformance |' echo '|---|---|---|---|' -} >"$TMP/docs/conventions/config-cascade/README.md" +} >"$TMP/docs/contracts/config-cascade/README.md" make_plugin alpha alpha_api_key carve_out_body | write_setup_skill alpha '[check]' out="$(run_fixture)" @@ -1334,7 +1334,7 @@ fi # Empty fails; over budget and malformed warn without a failure bullet; a # conforming hint is silent. write_arg_body's "-" omits the key, so empty # hints are written as the literal quoted string. -HINT_DOC='docs/conventions/argument-hint/README.md' +HINT_DOC='docs/contracts/argument-hint/README.md' HINT_MALFORMED='argument-hint is malformed' hint_case() { @@ -1539,7 +1539,7 @@ fi # --- 8e. Plugin names and option text. -------------------------------------- # displayName fails; each title and description shape warns on its own line. -OPT_DOC='docs/conventions/plugin-option-naming/README.md' +OPT_DOC='docs/contracts/plugin-option-naming/README.md' # write_manifest -- written verbatim after name. write_manifest() {