diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json
index 9b58bbb9..39c76f2a 100644
--- a/.claude-plugin/plugin.json
+++ b/.claude-plugin/plugin.json
@@ -1,7 +1,7 @@
{
"name": "commitlore",
"displayName": "CommitLore",
- "version": "0.7.0",
+ "version": "0.7.1",
"description": "Recorded decisions from git history, delivered to the agent before it edits. Constraints, alternatives already ruled out, and warnings left by whoever was here last.",
"author": {
"name": "MongLong0214",
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 0d3f0070..4e6931ce 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -18,6 +18,9 @@ permissions:
contents: write
id-token: write
attestations: write
+ # `exact-head-ci` reads the check runs GitHub recorded for the tagged commit.
+ # Reading a branch's green badge would answer a different, weaker question.
+ checks: read
jobs:
# Refuses the whole release before a single binary is built. A release
@@ -37,13 +40,192 @@ jobs:
- name: Tag, package.json, and `commitlore --version` agree
run: node scripts/check-release-version.mjs "$GITHUB_REF_NAME"
+ # A version-consistent tag can still name a commit that exists only on dev.
+ # `merge-base` can answer that only from complete history: a shallow checkout
+ # is not a smaller proof, it is an incomplete graph that the script refuses.
+ # The accepted commit is an output so the API gate below queries the commit an
+ # annotated tag resolves to, rather than assuming the event SHA is one.
+ release-target:
+ runs-on: ubuntu-latest
+ outputs:
+ commit: ${{ steps.ancestry.outputs.sha }}
+ steps:
+ - uses: actions/checkout@v4
+ with:
+ ref: ${{ github.ref }}
+ fetch-depth: 0
+ - uses: actions/setup-node@v4
+ with:
+ node-version: 22
+ - id: ancestry
+ name: The pushed tag is already contained in main
+ run: node scripts/check-release-target.mjs "$GITHUB_REF_NAME" main --github-output
+
+ # A tag push does not create a new CI result for the commit it names. The
+ # relevant evidence is the existing set of check runs at that exact commit,
+ # not the last green run on main and not a local suite this release happens
+ # to start. The script has a fixed required list and treats every missing or
+ # non-success result as a block; an empty API response is therefore a failure.
+ exact-head-ci:
+ needs: release-target
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ with:
+ ref: ${{ github.ref }}
+ fetch-depth: 1
+ - uses: actions/setup-node@v4
+ with:
+ node-version: 22
+ - name: Every required CI check succeeded at the tagged commit
+ env:
+ GITHUB_TOKEN: ${{ github.token }}
+ run: node scripts/check-exact-head-ci.mjs "$GITHUB_REPOSITORY_OWNER" "${GITHUB_REPOSITORY#*/}" "${{ needs.release-target.outputs.commit }}"
+
+ # RELEASE-GATE §4 used to be a human checklist run after `gh release create`.
+ # That made a failed row a correction to something already published: the
+ # release existed, but its documented installation did not work. This job
+ # makes the six checks a prerequisite instead, so publication cannot get
+ # ahead of the artifact it claims to qualify.
+ install-gate:
+ runs-on: ubuntu-latest
+ steps:
+ # The default checkout follows the event SHA today, but qualifying the
+ # branch that happened to contain that SHA would weaken the claim when
+ # checkout's default changes. The pushed tag is the artifact users name.
+ - uses: actions/checkout@v4
+ with:
+ ref: ${{ github.ref }}
+ fetch-depth: 0
+ - uses: actions/setup-node@v4
+ with:
+ node-version: 22
+
+ # A checkout can hide exactly the distribution failures this protects
+ # against: an untracked bundle, a path that reaches back to the source
+ # tree, or dependencies left over from CI. Clone the pushed tag anew,
+ # then run every check from that clone as an installer does.
+ - name: The tagged installation passes RELEASE-GATE section 4
+ run: |
+ set -euo pipefail
+ clone_dir="$(mktemp -d)/commitlore"
+ git clone --quiet --branch "$GITHUB_REF_NAME" --depth 1 \
+ "$GITHUB_SERVER_URL/$GITHUB_REPOSITORY.git" "$clone_dir"
+ cd "$clone_dir"
+
+ # The bundle is the shipped CLI; no build or npm install belongs in
+ # this job, because either would conceal a clone missing what ships.
+ clone_version="$(node dist/commitlore.mjs --version)"
+ printf 'fresh clone version: %s\n' "$clone_version"
+
+ if validation_output="$(printf 'Subject\n\nBlast: wide\n' | node dist/commitlore.mjs validate 2>&1)"; then
+ echo "expected the invalid message to be rejected"
+ exit 1
+ else
+ validation_exit=$?
+ fi
+ printf '%s\n' "$validation_output"
+ test "$validation_exit" -eq 1 || {
+ echo "validate exited $validation_exit, expected 1"
+ exit 1
+ }
+ case "$validation_output" in
+ *Blast*) ;;
+ *)
+ echo "validate rejected the message without reporting its Blast violation"
+ exit 1
+ ;;
+ esac
+
+ # A fresh clone is allowed to warn about unfetched notes and setup it
+ # has not opted into. `doctor` exits zero exactly when none of those
+ # findings is a fail, which is the RELEASE-GATE row's condition.
+ node dist/commitlore.mjs doctor
+
+ # The installed stub records node's absolute path. This command
+ # removes node from PATH while retaining git, so a rejection proves
+ # the hook used that recorded interpreter rather than ambient PATH.
+ git config user.name "Release gate"
+ git config user.email "release-gate@example.invalid"
+ node dist/commitlore.mjs hooks install
+ if hook_output="$(env -i PATH=/usr/bin:/bin git commit --allow-empty \
+ -m 'Release gate invalid message' -m 'Blast: wide' 2>&1)"; then
+ echo "expected the PATH-less hook to reject the invalid commit"
+ exit 1
+ else
+ hook_exit=$?
+ fi
+ printf '%s\n' "$hook_output"
+ test "$hook_exit" -ne 0 || {
+ echo "the PATH-less hook accepted an invalid commit"
+ exit 1
+ }
+ case "$hook_output" in
+ *Blast*) ;;
+ *)
+ echo "the hook rejected the commit without running validation"
+ exit 1
+ ;;
+ esac
+
+ # This is the earlier, marker-bearing stub body. Installing first
+ # records an otherwise healthy target; replacing only the body makes
+ # a real stale-stub fixture rather than merely testing a missing hook.
+ hook_path="$(git rev-parse --git-path hooks/commit-msg)"
+ printf '%s\n' '#!/bin/sh' '# commitlore:commit-msg:v1' \
+ 'exec commitlore validate "$1"' > "$hook_path"
+ chmod +x "$hook_path"
+
+ # Doctor deliberately runs a hook probe with PATH=/usr/bin:/bin.
+ # This historical body therefore also produces the expected separate
+ # hook-runtime fail and doctor exits 1. The row being qualified is
+ # commit-msg-hook, whose required verdict is warn rather than ok, so
+ # read that row instead of mistaking the fixture's other finding for
+ # this row's outcome.
+ if stale_report="$(node dist/commitlore.mjs doctor --json)"; then
+ stale_doctor_exit=0
+ else
+ stale_doctor_exit=$?
+ fi
+ printf '%s\n' "$stale_report"
+ printf 'stale-hook doctor exit: %s\n' "$stale_doctor_exit"
+ printf '%s' "$stale_report" | node -e '
+ let input = "";
+ process.stdin.on("data", (chunk) => { input += chunk; });
+ process.stdin.on("end", () => {
+ const report = JSON.parse(input);
+ const hook = report.checks.find((check) => check.id === "commit-msg-hook");
+ if (hook?.status !== "warn") {
+ console.error("expected the stale commit-msg hook to warn, got:", hook);
+ process.exit(1);
+ }
+ console.log("stale commit-msg hook: warn");
+ });
+ '
+
+ # The runner intentionally prefers a CLI on PATH, so keep PATH narrow
+ # and include only the node directory needed for the clone fallback.
+ # Comparing versions catches a different installation that still
+ # answers --version successfully (#483).
+ node_dir="$(dirname "$(command -v node)")"
+ plugin_version="$(env PATH="/usr/bin:/bin:$node_dir" \
+ CLAUDE_PLUGIN_ROOT="$clone_dir" "$clone_dir/scripts/commitlore-run.sh" --version)"
+ printf 'plugin version: %s\n' "$plugin_version"
+ test "$plugin_version" = "$clone_version" || {
+ echo "plugin resolved $plugin_version, expected clone version $clone_version"
+ exit 1
+ }
+
# Nothing is compiled and nothing is attached. ADR-0026 makes the plugin the
# canonical install path and `install.sh`/`install.ps1` the secondary one, and
# both take a pinned source checkout -- so the release itself is the tag, and the
# tag is what those installers resolve. A release with no assets is the whole
# artifact set, not an incomplete one.
publish:
- needs: version-consistency
+ # A skipped or failed prerequisite skips this job by GitHub's default needs
+ # semantics. Keep it free of `if:`: a condition such as `always()` would
+ # turn a failed qualification into a path that can still publish.
+ needs: [version-consistency, install-gate, release-target, exact-head-ci]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0efa2ee5..59250b4e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,41 @@
# Changelog
+## 0.7.1
+
+### `[directive]` did not work in 0.7.0
+
+0.7.0's headline change made the `[directive]` tier reachable. **It did not
+reach anyone.** `commander` declares `--trusted-author` with a default of `[]`,
+so the flag arrived as an empty array rather than `undefined` when it was
+absent, the nullish fallback to the author `init` records never fired, and
+every record on every install still graded `[claim]`.
+
+That is the defect #415 was opened about, reintroduced one layer up by the fix
+for it.
+
+Reproduced against the released artefact: `commitlore inject --path
` — the
+form the hook runs — rendered `[claim]`, while the same command with an
+explicit `--trusted-author` rendered `[directive]`.
+
+The tests that passed drove `buildInjection` with options assembled by hand and
+never went through the command line, which is the only path the hook uses.
+`test/trusted-authors.test.ts` now spawns the built CLI. Its own header had
+already warned that a unit test one layer down would have passed throughout the
+period the original bug existed; the same sentence applied one layer up and was
+not heard.
+
+### Fixed
+
+- `package-lock.json` still declared `0.1.0` while the manifests read `0.7.0`.
+ Stale since the first release.
+
+### Corrections to 0.7.0's own record
+
+The promotion PR said 132 commits; it was **137**. It said `RELEASE-GATE.md` §4
+lists seven install checks; it lists **six**. Both were miscounts in the
+evidence submitted for review, and both are corrected here rather than left in
+the history unremarked.
+
## 0.7.0
### The behaviour claim is measured: 2.8% against 18.8%
diff --git a/README.ja.md b/README.ja.md
index 79631620..985b0688 100644
--- a/README.ja.md
+++ b/README.ja.md
@@ -48,7 +48,7 @@ Claude Code · Codex · Cursor · Gemini CLI · OpenCode · Windsurf
**その他のコーディングエージェント** — CLI をインストールします:
```bash
-curl -fsSL https://raw.githubusercontent.com/MongLong0214/commitlore/v0.7.0/install.sh | sh
+curl -fsSL https://raw.githubusercontent.com/MongLong0214/commitlore/v0.7.1/install.sh | sh
```
どの host に対応しているか、各インストール経路が何を必要とするか: [docs/COMPATIBILITY.md](docs/COMPATIBILITY.md)。
@@ -138,11 +138,11 @@ commitlore context .
```bash
# installer を固定してダウンロードし、確認してから実行します。
-curl -fsSLO https://raw.githubusercontent.com/MongLong0214/commitlore/v0.7.0/install.sh
-sh install.sh v0.7.0
+curl -fsSLO https://raw.githubusercontent.com/MongLong0214/commitlore/v0.7.1/install.sh
+sh install.sh v0.7.1
# あるいはスクリプトを使わずに。スクリプトが作るチェックアウトは自分でも作れます。
-git clone --depth 1 --branch v0.7.0 https://github.com/MongLong0214/commitlore
+git clone --depth 1 --branch v0.7.1 https://github.com/MongLong0214/commitlore
node commitlore/dist/commitlore.mjs --version
```
@@ -337,40 +337,55 @@ path の履歴は `commitlore context ` で読みます。より小さな
-**112 runs recorded.** No manifest declares how many runs the matrix was meant to produce, so completeness cannot be checked from the logs alone.
+**1160 measurements across 1240 rows.** 80 row(s) are superseded by a re-run of the same task, arm and seed, and the analysis counts the survivor. No manifest declares how many runs the matrix was meant to produce, so completeness cannot be checked from the logs alone.
| Where it comes from | |
|---|---|
-| Results | `bench/results/t702-m4-final.jsonl` (112 rows) |
-| Run id | `20260727T120103Z-aa5eab`, `20260728T025523Z-db4659`, `20260728T025635Z-e3d669`, `20260728T025817Z-d8d0dc` |
+| Results | `bench/results/m5-seeds-1-10-rerun.jsonl` (200 rows), `bench/results/m5-seeds-11-20-rerun.jsonl` (200 rows), `bench/results/m5-seeds-21-30.jsonl` (200 rows), `bench/results/m5-seeds-31-40.jsonl` (200 rows), `bench/results/m5-seeds-41-50.jsonl` (200 rows), `bench/results/m5-seeds-51-58.jsonl` (160 rows), `bench/results/m5-seeds-55-58-rerun.jsonl` (80 rows) |
+| Run id | `20260802T124657Z-ae3ba0`, `20260802T230855Z-00da79`, `20260803T100356Z-aeb38a`, `20260803T203631Z-77df15`, `20260806T230824Z-60e31e`, `20260807T095937Z-bf2b05`, `20260807T234037Z-6dd0a2` |
| Driver | `claude-headless` |
-| Model | not recorded |
-| Matrix | 8 tasks, seeds 1, 2, 3, 4, 5, 6, 7 |
-| Status | final (declared in `bench/report.ts`, pending a manifest field) |
+| Model | `sonnet` |
+| Matrix | 10 tasks, seeds 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58 |
+| Status | final (declared in `bench/report.ts`, pending a manifest field) (`bench/results/m5-seeds-1-10-rerun.jsonl`), final (declared in `bench/report.ts`, pending a manifest field) (`bench/results/m5-seeds-11-20-rerun.jsonl`), final (declared in `bench/report.ts`, pending a manifest field) (`bench/results/m5-seeds-21-30.jsonl`), final (declared in `bench/report.ts`, pending a manifest field) (`bench/results/m5-seeds-31-40.jsonl`), final (declared in `bench/report.ts`, pending a manifest field) (`bench/results/m5-seeds-41-50.jsonl`), final (declared in `bench/report.ts`, pending a manifest field) (`bench/results/m5-seeds-51-58.jsonl`), final (declared in `bench/report.ts`, pending a manifest field) (`bench/results/m5-seeds-55-58-rerun.jsonl`) |
**Re-proposal and violation rates, every recorded run:**
| Condition | n | Re-proposed | Re-proposal rate | Runs with violations | Violation rate | Mean turns | Mean tokens |
|---|---|---|---|---|---|---|---|
-| `commitlore-guard` | 56 | 41 | 0.732 | 0 | 0.000 | 14.8 | 18965 |
-| `commitlore-on` | 56 | 35 | 0.625 | 0 | 0.000 | 14.2 | 18091 |
+| `commitlore-off` | 620 | 110 | 0.177 | 58 | 0.094 | 19.3 | 38488 |
+| `commitlore-on` | 620 | 16 | 0.026 | 7 | 0.011 | 16.2 | 39265 |
-**Analysis set — all 112 rows.** Nothing was excluded: no simulated rows, no failed runs, no run that never started.
+**Analysis set — 1169 of 1240 rows** (71 excluded: error = 71). A row that failed carries `reproposed: false` because the field is required, not because the agent declined to re-propose; leaving it in the denominator would let the arm that crashed more often look like the arm that behaved better. The excluded runs are counted here, never dropped silently.
-**Significance:** not computed — guard exposure is unknown for 112 analysis rows
+| Condition | n | Re-proposed | Re-proposal rate | Runs with violations | Violation rate | Mean turns | Mean tokens |
+|---|---|---|---|---|---|---|---|
+| `commitlore-off` | 584 | 110 | 0.188 | 58 | 0.099 | 20.4 | 40842 |
+| `commitlore-on` | 585 | 16 | 0.027 | 7 | 0.012 | 17.1 | 41568 |
+
+**Significance:**
+
+| Quantity | Value |
+|---|---|
+| Arms | `commitlore-on` (treatment) vs `commitlore-off` (baseline) |
+| Re-proposed / did not | `commitlore-on` 16/569, `commitlore-off` 110/474 |
+| Fisher exact, two-tailed | p = 1.52e-20 |
+| Rate difference, treatment minus baseline | -16.1pp, 95% CI [-19.6pp, -12.7pp] |
+| Odds ratio | 0.1212 |
+| Paired (task, seed) cells | 579 |
+| Rows excluded from the analysis set | 71 |
**How the runs ended** — failures are reported, not filtered:
| Condition | completed | timeout | over-turns | over-tokens | error |
|---|---|---|---|---|---|
-| `commitlore-guard` | 56 | 0 | 0 | 0 | 0 |
-| `commitlore-on` | 55 | 0 | 1 | 0 | 0 |
+| `commitlore-off` | 414 | 3 | 157 | 10 | 36 |
+| `commitlore-on` | 459 | 2 | 109 | 15 | 35 |
**Read these numbers with their limits:**
-- No model is recorded — neither on the rows nor in a manifest. A re-proposal rate whose model is unknown is not a comparable number, and these figures must not be quoted against another model's.
- Every rate here is conditional on the model that produced it. Re-proposal is a behaviour, and behaviours differ between models, so these figures are not evidence about any other model.
-- 112 runs in the analysis set: this matrix is only powered to detect a large effect, so a non-significant result from it is a statement about the sample size, not about CommitLore. The exact power table is in [`bench/README.md`](bench/README.md).
+- 585 and 584 runs per arm: this matrix is only powered to detect a large effect, so a non-significant result from it is a statement about the sample size, not about CommitLore. The exact power table is in [`bench/README.md`](bench/README.md).
+- Fisher exact treats the runs as independent while the design is paired by (task, seed). It is the pre-registered result, but it is not a valid paired-data test. See the correction in [`docs/VERDICT-M4.md`](docs/VERDICT-M4.md).
diff --git a/README.ko.md b/README.ko.md
index 30421ad6..b9e8c11b 100644
--- a/README.ko.md
+++ b/README.ko.md
@@ -48,7 +48,7 @@ Claude Code · Codex · Cursor · Gemini CLI · OpenCode · Windsurf
**그 밖의 코딩 에이전트** — CLI를 설치한다:
```bash
-curl -fsSL https://raw.githubusercontent.com/MongLong0214/commitlore/v0.7.0/install.sh | sh
+curl -fsSL https://raw.githubusercontent.com/MongLong0214/commitlore/v0.7.1/install.sh | sh
```
어떤 host를 지원하는지, 각 설치 경로가 무엇을 요구하는지: [docs/COMPATIBILITY.md](docs/COMPATIBILITY.md).
@@ -138,11 +138,11 @@ commitlore context .
```bash
# 설치기를 고정해 내려받고 살펴본 뒤 실행한다.
-curl -fsSLO https://raw.githubusercontent.com/MongLong0214/commitlore/v0.7.0/install.sh
-sh install.sh v0.7.0
+curl -fsSLO https://raw.githubusercontent.com/MongLong0214/commitlore/v0.7.1/install.sh
+sh install.sh v0.7.1
# 또는 스크립트를 건너뛴다. 스크립트가 만드는 체크아웃은 직접 만들 수 있는 것과 같다.
-git clone --depth 1 --branch v0.7.0 https://github.com/MongLong0214/commitlore
+git clone --depth 1 --branch v0.7.1 https://github.com/MongLong0214/commitlore
node commitlore/dist/commitlore.mjs --version
```
@@ -332,40 +332,55 @@ CommitLore-Version: 2.0.0
-**112 runs recorded.** No manifest declares how many runs the matrix was meant to produce, so completeness cannot be checked from the logs alone.
+**1160 measurements across 1240 rows.** 80 row(s) are superseded by a re-run of the same task, arm and seed, and the analysis counts the survivor. No manifest declares how many runs the matrix was meant to produce, so completeness cannot be checked from the logs alone.
| Where it comes from | |
|---|---|
-| Results | `bench/results/t702-m4-final.jsonl` (112 rows) |
-| Run id | `20260727T120103Z-aa5eab`, `20260728T025523Z-db4659`, `20260728T025635Z-e3d669`, `20260728T025817Z-d8d0dc` |
+| Results | `bench/results/m5-seeds-1-10-rerun.jsonl` (200 rows), `bench/results/m5-seeds-11-20-rerun.jsonl` (200 rows), `bench/results/m5-seeds-21-30.jsonl` (200 rows), `bench/results/m5-seeds-31-40.jsonl` (200 rows), `bench/results/m5-seeds-41-50.jsonl` (200 rows), `bench/results/m5-seeds-51-58.jsonl` (160 rows), `bench/results/m5-seeds-55-58-rerun.jsonl` (80 rows) |
+| Run id | `20260802T124657Z-ae3ba0`, `20260802T230855Z-00da79`, `20260803T100356Z-aeb38a`, `20260803T203631Z-77df15`, `20260806T230824Z-60e31e`, `20260807T095937Z-bf2b05`, `20260807T234037Z-6dd0a2` |
| Driver | `claude-headless` |
-| Model | not recorded |
-| Matrix | 8 tasks, seeds 1, 2, 3, 4, 5, 6, 7 |
-| Status | final (declared in `bench/report.ts`, pending a manifest field) |
+| Model | `sonnet` |
+| Matrix | 10 tasks, seeds 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58 |
+| Status | final (declared in `bench/report.ts`, pending a manifest field) (`bench/results/m5-seeds-1-10-rerun.jsonl`), final (declared in `bench/report.ts`, pending a manifest field) (`bench/results/m5-seeds-11-20-rerun.jsonl`), final (declared in `bench/report.ts`, pending a manifest field) (`bench/results/m5-seeds-21-30.jsonl`), final (declared in `bench/report.ts`, pending a manifest field) (`bench/results/m5-seeds-31-40.jsonl`), final (declared in `bench/report.ts`, pending a manifest field) (`bench/results/m5-seeds-41-50.jsonl`), final (declared in `bench/report.ts`, pending a manifest field) (`bench/results/m5-seeds-51-58.jsonl`), final (declared in `bench/report.ts`, pending a manifest field) (`bench/results/m5-seeds-55-58-rerun.jsonl`) |
**Re-proposal and violation rates, every recorded run:**
| Condition | n | Re-proposed | Re-proposal rate | Runs with violations | Violation rate | Mean turns | Mean tokens |
|---|---|---|---|---|---|---|---|
-| `commitlore-guard` | 56 | 41 | 0.732 | 0 | 0.000 | 14.8 | 18965 |
-| `commitlore-on` | 56 | 35 | 0.625 | 0 | 0.000 | 14.2 | 18091 |
+| `commitlore-off` | 620 | 110 | 0.177 | 58 | 0.094 | 19.3 | 38488 |
+| `commitlore-on` | 620 | 16 | 0.026 | 7 | 0.011 | 16.2 | 39265 |
-**Analysis set — all 112 rows.** Nothing was excluded: no simulated rows, no failed runs, no run that never started.
+**Analysis set — 1169 of 1240 rows** (71 excluded: error = 71). A row that failed carries `reproposed: false` because the field is required, not because the agent declined to re-propose; leaving it in the denominator would let the arm that crashed more often look like the arm that behaved better. The excluded runs are counted here, never dropped silently.
-**Significance:** not computed — guard exposure is unknown for 112 analysis rows
+| Condition | n | Re-proposed | Re-proposal rate | Runs with violations | Violation rate | Mean turns | Mean tokens |
+|---|---|---|---|---|---|---|---|
+| `commitlore-off` | 584 | 110 | 0.188 | 58 | 0.099 | 20.4 | 40842 |
+| `commitlore-on` | 585 | 16 | 0.027 | 7 | 0.012 | 17.1 | 41568 |
+
+**Significance:**
+
+| Quantity | Value |
+|---|---|
+| Arms | `commitlore-on` (treatment) vs `commitlore-off` (baseline) |
+| Re-proposed / did not | `commitlore-on` 16/569, `commitlore-off` 110/474 |
+| Fisher exact, two-tailed | p = 1.52e-20 |
+| Rate difference, treatment minus baseline | -16.1pp, 95% CI [-19.6pp, -12.7pp] |
+| Odds ratio | 0.1212 |
+| Paired (task, seed) cells | 579 |
+| Rows excluded from the analysis set | 71 |
**How the runs ended** — failures are reported, not filtered:
| Condition | completed | timeout | over-turns | over-tokens | error |
|---|---|---|---|---|---|
-| `commitlore-guard` | 56 | 0 | 0 | 0 | 0 |
-| `commitlore-on` | 55 | 0 | 1 | 0 | 0 |
+| `commitlore-off` | 414 | 3 | 157 | 10 | 36 |
+| `commitlore-on` | 459 | 2 | 109 | 15 | 35 |
**Read these numbers with their limits:**
-- No model is recorded — neither on the rows nor in a manifest. A re-proposal rate whose model is unknown is not a comparable number, and these figures must not be quoted against another model's.
- Every rate here is conditional on the model that produced it. Re-proposal is a behaviour, and behaviours differ between models, so these figures are not evidence about any other model.
-- 112 runs in the analysis set: this matrix is only powered to detect a large effect, so a non-significant result from it is a statement about the sample size, not about CommitLore. The exact power table is in [`bench/README.md`](bench/README.md).
+- 585 and 584 runs per arm: this matrix is only powered to detect a large effect, so a non-significant result from it is a statement about the sample size, not about CommitLore. The exact power table is in [`bench/README.md`](bench/README.md).
+- Fisher exact treats the runs as independent while the design is paired by (task, seed). It is the pre-registered result, but it is not a valid paired-data test. See the correction in [`docs/VERDICT-M4.md`](docs/VERDICT-M4.md).
diff --git a/README.md b/README.md
index da45a1da..95eb59af 100644
--- a/README.md
+++ b/README.md
@@ -50,7 +50,7 @@ Prerequisites for either path: Node.js 22+ and Git. The script checks both befor
**Any other coding agent** — install the CLI:
```bash
-curl -fsSL https://raw.githubusercontent.com/MongLong0214/commitlore/v0.7.0/install.sh | sh
+curl -fsSL https://raw.githubusercontent.com/MongLong0214/commitlore/v0.7.1/install.sh | sh
```
Which hosts are supported, and what each install path requires: [docs/COMPATIBILITY.md](docs/COMPATIBILITY.md).
@@ -191,11 +191,11 @@ The one-liner is for convenience. For a reviewed or pinned install, download and
```bash
# Pin and inspect the installer before executing it.
-curl -fsSLO https://raw.githubusercontent.com/MongLong0214/commitlore/v0.7.0/install.sh
-sh install.sh v0.7.0
+curl -fsSLO https://raw.githubusercontent.com/MongLong0214/commitlore/v0.7.1/install.sh
+sh install.sh v0.7.1
# Or skip the script entirely: the checkout it makes is one you can make yourself.
-git clone --depth 1 --branch v0.7.0 https://github.com/MongLong0214/commitlore
+git clone --depth 1 --branch v0.7.1 https://github.com/MongLong0214/commitlore
node commitlore/dist/commitlore.mjs --version
```
@@ -391,40 +391,55 @@ What is measured — retrieval, exposure, latency and scaling, hook overhead —
-**112 runs recorded.** No manifest declares how many runs the matrix was meant to produce, so completeness cannot be checked from the logs alone.
+**1160 measurements across 1240 rows.** 80 row(s) are superseded by a re-run of the same task, arm and seed, and the analysis counts the survivor. No manifest declares how many runs the matrix was meant to produce, so completeness cannot be checked from the logs alone.
| Where it comes from | |
|---|---|
-| Results | `bench/results/t702-m4-final.jsonl` (112 rows) |
-| Run id | `20260727T120103Z-aa5eab`, `20260728T025523Z-db4659`, `20260728T025635Z-e3d669`, `20260728T025817Z-d8d0dc` |
+| Results | `bench/results/m5-seeds-1-10-rerun.jsonl` (200 rows), `bench/results/m5-seeds-11-20-rerun.jsonl` (200 rows), `bench/results/m5-seeds-21-30.jsonl` (200 rows), `bench/results/m5-seeds-31-40.jsonl` (200 rows), `bench/results/m5-seeds-41-50.jsonl` (200 rows), `bench/results/m5-seeds-51-58.jsonl` (160 rows), `bench/results/m5-seeds-55-58-rerun.jsonl` (80 rows) |
+| Run id | `20260802T124657Z-ae3ba0`, `20260802T230855Z-00da79`, `20260803T100356Z-aeb38a`, `20260803T203631Z-77df15`, `20260806T230824Z-60e31e`, `20260807T095937Z-bf2b05`, `20260807T234037Z-6dd0a2` |
| Driver | `claude-headless` |
-| Model | not recorded |
-| Matrix | 8 tasks, seeds 1, 2, 3, 4, 5, 6, 7 |
-| Status | final (declared in `bench/report.ts`, pending a manifest field) |
+| Model | `sonnet` |
+| Matrix | 10 tasks, seeds 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58 |
+| Status | final (declared in `bench/report.ts`, pending a manifest field) (`bench/results/m5-seeds-1-10-rerun.jsonl`), final (declared in `bench/report.ts`, pending a manifest field) (`bench/results/m5-seeds-11-20-rerun.jsonl`), final (declared in `bench/report.ts`, pending a manifest field) (`bench/results/m5-seeds-21-30.jsonl`), final (declared in `bench/report.ts`, pending a manifest field) (`bench/results/m5-seeds-31-40.jsonl`), final (declared in `bench/report.ts`, pending a manifest field) (`bench/results/m5-seeds-41-50.jsonl`), final (declared in `bench/report.ts`, pending a manifest field) (`bench/results/m5-seeds-51-58.jsonl`), final (declared in `bench/report.ts`, pending a manifest field) (`bench/results/m5-seeds-55-58-rerun.jsonl`) |
**Re-proposal and violation rates, every recorded run:**
| Condition | n | Re-proposed | Re-proposal rate | Runs with violations | Violation rate | Mean turns | Mean tokens |
|---|---|---|---|---|---|---|---|
-| `commitlore-guard` | 56 | 41 | 0.732 | 0 | 0.000 | 14.8 | 18965 |
-| `commitlore-on` | 56 | 35 | 0.625 | 0 | 0.000 | 14.2 | 18091 |
+| `commitlore-off` | 620 | 110 | 0.177 | 58 | 0.094 | 19.3 | 38488 |
+| `commitlore-on` | 620 | 16 | 0.026 | 7 | 0.011 | 16.2 | 39265 |
-**Analysis set — all 112 rows.** Nothing was excluded: no simulated rows, no failed runs, no run that never started.
+**Analysis set — 1169 of 1240 rows** (71 excluded: error = 71). A row that failed carries `reproposed: false` because the field is required, not because the agent declined to re-propose; leaving it in the denominator would let the arm that crashed more often look like the arm that behaved better. The excluded runs are counted here, never dropped silently.
-**Significance:** not computed — guard exposure is unknown for 112 analysis rows
+| Condition | n | Re-proposed | Re-proposal rate | Runs with violations | Violation rate | Mean turns | Mean tokens |
+|---|---|---|---|---|---|---|---|
+| `commitlore-off` | 584 | 110 | 0.188 | 58 | 0.099 | 20.4 | 40842 |
+| `commitlore-on` | 585 | 16 | 0.027 | 7 | 0.012 | 17.1 | 41568 |
+
+**Significance:**
+
+| Quantity | Value |
+|---|---|
+| Arms | `commitlore-on` (treatment) vs `commitlore-off` (baseline) |
+| Re-proposed / did not | `commitlore-on` 16/569, `commitlore-off` 110/474 |
+| Fisher exact, two-tailed | p = 1.52e-20 |
+| Rate difference, treatment minus baseline | -16.1pp, 95% CI [-19.6pp, -12.7pp] |
+| Odds ratio | 0.1212 |
+| Paired (task, seed) cells | 579 |
+| Rows excluded from the analysis set | 71 |
**How the runs ended** — failures are reported, not filtered:
| Condition | completed | timeout | over-turns | over-tokens | error |
|---|---|---|---|---|---|
-| `commitlore-guard` | 56 | 0 | 0 | 0 | 0 |
-| `commitlore-on` | 55 | 0 | 1 | 0 | 0 |
+| `commitlore-off` | 414 | 3 | 157 | 10 | 36 |
+| `commitlore-on` | 459 | 2 | 109 | 15 | 35 |
**Read these numbers with their limits:**
-- No model is recorded — neither on the rows nor in a manifest. A re-proposal rate whose model is unknown is not a comparable number, and these figures must not be quoted against another model's.
- Every rate here is conditional on the model that produced it. Re-proposal is a behaviour, and behaviours differ between models, so these figures are not evidence about any other model.
-- 112 runs in the analysis set: this matrix is only powered to detect a large effect, so a non-significant result from it is a statement about the sample size, not about CommitLore. The exact power table is in [`bench/README.md`](bench/README.md).
+- 585 and 584 runs per arm: this matrix is only powered to detect a large effect, so a non-significant result from it is a statement about the sample size, not about CommitLore. The exact power table is in [`bench/README.md`](bench/README.md).
+- Fisher exact treats the runs as independent while the design is paired by (task, seed). It is the pre-registered result, but it is not a valid paired-data test. See the correction in [`docs/VERDICT-M4.md`](docs/VERDICT-M4.md).
diff --git a/README.zh-CN.md b/README.zh-CN.md
index bd924052..8ed24b2f 100644
--- a/README.zh-CN.md
+++ b/README.zh-CN.md
@@ -47,7 +47,7 @@ Claude Code · Codex · Cursor · Gemini CLI · OpenCode · Windsurf
**其他编程代理** — 安装 CLI:
```bash
-curl -fsSL https://raw.githubusercontent.com/MongLong0214/commitlore/v0.7.0/install.sh | sh
+curl -fsSL https://raw.githubusercontent.com/MongLong0214/commitlore/v0.7.1/install.sh | sh
```
支持哪些 host,以及各条安装路径需要什么:[docs/COMPATIBILITY.md](docs/COMPATIBILITY.md)。
@@ -137,11 +137,11 @@ commitlore context .
```bash
# 固定版本并检查 installer 后再执行。
-curl -fsSLO https://raw.githubusercontent.com/MongLong0214/commitlore/v0.7.0/install.sh
-sh install.sh v0.7.0
+curl -fsSLO https://raw.githubusercontent.com/MongLong0214/commitlore/v0.7.1/install.sh
+sh install.sh v0.7.1
# 或者完全不用脚本:它创建的检出,你自己也能创建。
-git clone --depth 1 --branch v0.7.0 https://github.com/MongLong0214/commitlore
+git clone --depth 1 --branch v0.7.1 https://github.com/MongLong0214/commitlore
node commitlore/dist/commitlore.mjs --version
```
@@ -326,40 +326,55 @@ CommitLore-Version: 2.0.0
-**112 runs recorded.** No manifest declares how many runs the matrix was meant to produce, so completeness cannot be checked from the logs alone.
+**1160 measurements across 1240 rows.** 80 row(s) are superseded by a re-run of the same task, arm and seed, and the analysis counts the survivor. No manifest declares how many runs the matrix was meant to produce, so completeness cannot be checked from the logs alone.
| Where it comes from | |
|---|---|
-| Results | `bench/results/t702-m4-final.jsonl` (112 rows) |
-| Run id | `20260727T120103Z-aa5eab`, `20260728T025523Z-db4659`, `20260728T025635Z-e3d669`, `20260728T025817Z-d8d0dc` |
+| Results | `bench/results/m5-seeds-1-10-rerun.jsonl` (200 rows), `bench/results/m5-seeds-11-20-rerun.jsonl` (200 rows), `bench/results/m5-seeds-21-30.jsonl` (200 rows), `bench/results/m5-seeds-31-40.jsonl` (200 rows), `bench/results/m5-seeds-41-50.jsonl` (200 rows), `bench/results/m5-seeds-51-58.jsonl` (160 rows), `bench/results/m5-seeds-55-58-rerun.jsonl` (80 rows) |
+| Run id | `20260802T124657Z-ae3ba0`, `20260802T230855Z-00da79`, `20260803T100356Z-aeb38a`, `20260803T203631Z-77df15`, `20260806T230824Z-60e31e`, `20260807T095937Z-bf2b05`, `20260807T234037Z-6dd0a2` |
| Driver | `claude-headless` |
-| Model | not recorded |
-| Matrix | 8 tasks, seeds 1, 2, 3, 4, 5, 6, 7 |
-| Status | final (declared in `bench/report.ts`, pending a manifest field) |
+| Model | `sonnet` |
+| Matrix | 10 tasks, seeds 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58 |
+| Status | final (declared in `bench/report.ts`, pending a manifest field) (`bench/results/m5-seeds-1-10-rerun.jsonl`), final (declared in `bench/report.ts`, pending a manifest field) (`bench/results/m5-seeds-11-20-rerun.jsonl`), final (declared in `bench/report.ts`, pending a manifest field) (`bench/results/m5-seeds-21-30.jsonl`), final (declared in `bench/report.ts`, pending a manifest field) (`bench/results/m5-seeds-31-40.jsonl`), final (declared in `bench/report.ts`, pending a manifest field) (`bench/results/m5-seeds-41-50.jsonl`), final (declared in `bench/report.ts`, pending a manifest field) (`bench/results/m5-seeds-51-58.jsonl`), final (declared in `bench/report.ts`, pending a manifest field) (`bench/results/m5-seeds-55-58-rerun.jsonl`) |
**Re-proposal and violation rates, every recorded run:**
| Condition | n | Re-proposed | Re-proposal rate | Runs with violations | Violation rate | Mean turns | Mean tokens |
|---|---|---|---|---|---|---|---|
-| `commitlore-guard` | 56 | 41 | 0.732 | 0 | 0.000 | 14.8 | 18965 |
-| `commitlore-on` | 56 | 35 | 0.625 | 0 | 0.000 | 14.2 | 18091 |
+| `commitlore-off` | 620 | 110 | 0.177 | 58 | 0.094 | 19.3 | 38488 |
+| `commitlore-on` | 620 | 16 | 0.026 | 7 | 0.011 | 16.2 | 39265 |
-**Analysis set — all 112 rows.** Nothing was excluded: no simulated rows, no failed runs, no run that never started.
+**Analysis set — 1169 of 1240 rows** (71 excluded: error = 71). A row that failed carries `reproposed: false` because the field is required, not because the agent declined to re-propose; leaving it in the denominator would let the arm that crashed more often look like the arm that behaved better. The excluded runs are counted here, never dropped silently.
-**Significance:** not computed — guard exposure is unknown for 112 analysis rows
+| Condition | n | Re-proposed | Re-proposal rate | Runs with violations | Violation rate | Mean turns | Mean tokens |
+|---|---|---|---|---|---|---|---|
+| `commitlore-off` | 584 | 110 | 0.188 | 58 | 0.099 | 20.4 | 40842 |
+| `commitlore-on` | 585 | 16 | 0.027 | 7 | 0.012 | 17.1 | 41568 |
+
+**Significance:**
+
+| Quantity | Value |
+|---|---|
+| Arms | `commitlore-on` (treatment) vs `commitlore-off` (baseline) |
+| Re-proposed / did not | `commitlore-on` 16/569, `commitlore-off` 110/474 |
+| Fisher exact, two-tailed | p = 1.52e-20 |
+| Rate difference, treatment minus baseline | -16.1pp, 95% CI [-19.6pp, -12.7pp] |
+| Odds ratio | 0.1212 |
+| Paired (task, seed) cells | 579 |
+| Rows excluded from the analysis set | 71 |
**How the runs ended** — failures are reported, not filtered:
| Condition | completed | timeout | over-turns | over-tokens | error |
|---|---|---|---|---|---|
-| `commitlore-guard` | 56 | 0 | 0 | 0 | 0 |
-| `commitlore-on` | 55 | 0 | 1 | 0 | 0 |
+| `commitlore-off` | 414 | 3 | 157 | 10 | 36 |
+| `commitlore-on` | 459 | 2 | 109 | 15 | 35 |
**Read these numbers with their limits:**
-- No model is recorded — neither on the rows nor in a manifest. A re-proposal rate whose model is unknown is not a comparable number, and these figures must not be quoted against another model's.
- Every rate here is conditional on the model that produced it. Re-proposal is a behaviour, and behaviours differ between models, so these figures are not evidence about any other model.
-- 112 runs in the analysis set: this matrix is only powered to detect a large effect, so a non-significant result from it is a statement about the sample size, not about CommitLore. The exact power table is in [`bench/README.md`](bench/README.md).
+- 585 and 584 runs per arm: this matrix is only powered to detect a large effect, so a non-significant result from it is a statement about the sample size, not about CommitLore. The exact power table is in [`bench/README.md`](bench/README.md).
+- Fisher exact treats the runs as independent while the design is paired by (task, seed). It is the pre-registered result, but it is not a valid paired-data test. See the correction in [`docs/VERDICT-M4.md`](docs/VERDICT-M4.md).
diff --git a/bench/report.ts b/bench/report.ts
index 51141072..3445ab9c 100644
--- a/bench/report.ts
+++ b/bench/report.ts
@@ -77,23 +77,50 @@ export interface DeclaredSource {
*/
export const README_SOURCES: readonly DeclaredSource[] = [
{
- file: "bench/results/t702-m4-final.jsonl",
+ file: "bench/results/m5-seeds-1-10-rerun.jsonl",
status: "final",
status_note:
- "The registered M4 measurement (PREREGISTRATION.md §16), the qualification-gated matrix whose primary " +
- "comparison is `commitlore-guard` against `commitlore-on`. Run from an isolated checkout against frozen " +
- "code `081d858c1`, under the environment controls of §5-b; every row carries a uniform `harness_commit` " +
- "and `dist_digest`. bench/VERDICT-M4.md is historical; docs/VERDICT-M4.md is the correction. M1 " +
- "(bench/VERDICT-M1.md), M1-b " +
- "(bench/VERDICT-M1b.md) and M2 (bench/VERDICT-M2.md) are not revised and are not pooled here — a " +
- "different task set and a third arm make them a different matrix, the same reason the ablation log below " +
- "stays out of this list. M3 is void (§15). No manifest exists for this file: `runner.ts` does not write " +
- "`model` onto a row, and none was written for this run either, so the model behind these 112 rows is " +
- "unrecorded rather than declared (bench/README.md, \"Open after T-702\", item 1). Each file's own " +
- "manifest is the authority on its status; this declaration is the fallback.",
+ "The registered M5 measurement (bench/PREREGISTRATION-M5.md), whose primary comparison is `commitlore-on` against `commitlore-off` on the re-proposal task set. Seven shards, 1,160 rows, one harness commit `788a9db3` and one dist digest `f54cda4795cc` across every one. Three shards are re-runs (deviations 3 and 4): 400 rows were lost to a temp reaper and re-produced, and seeds 55-58 were re-run whole after 70 of their surviving rows carried no measurement. 80 original cells are superseded by a rule in bench/m5-analysis.ts -- an original is dropped whenever a re-run shard holds the same task, condition and seed -- rather than by a trimmed file nobody can review. One row carrying `stopped_by: error` is excluded by the registered rule. The arms truncate unequally, 28.5% control against 21.2% treatment, which deviations 1 and 2 require the verdict to report because truncation suppresses re-proposal and so shrinks rather than manufactures the gap. Every record in the run rendered `[claim]`: no arm passed --trusted-author, so this measures the weaker of the two trust tiers and not the `[directive]` path 0.7.1 made reachable (#415). bench/VERDICT-M5.md is the verdict. M1 (bench/VERDICT-M1.md), M1-b, M2 and M4 (docs/VERDICT-M4.md) are not pooled here -- different task sets and, for M4, a third arm, the same reason the ablation log stays out of this list. Each file's own manifest is the authority on its status; this declaration is the fallback.",
+ },
+ {
+ file: "bench/results/m5-seeds-11-20-rerun.jsonl",
+ status: "final",
+ status_note:
+ "Part of the registered M5 set declared above; see the first entry for the full status.",
+ },
+ {
+ file: "bench/results/m5-seeds-21-30.jsonl",
+ status: "final",
+ status_note:
+ "Part of the registered M5 set declared above; see the first entry for the full status.",
+ },
+ {
+ file: "bench/results/m5-seeds-31-40.jsonl",
+ status: "final",
+ status_note:
+ "Part of the registered M5 set declared above; see the first entry for the full status.",
+ },
+ {
+ file: "bench/results/m5-seeds-41-50.jsonl",
+ status: "final",
+ status_note:
+ "Part of the registered M5 set declared above; see the first entry for the full status.",
+ },
+ {
+ file: "bench/results/m5-seeds-51-58.jsonl",
+ status: "final",
+ status_note:
+ "Part of the registered M5 set declared above; see the first entry for the full status.",
+ },
+ {
+ file: "bench/results/m5-seeds-55-58-rerun.jsonl",
+ status: "final",
+ status_note:
+ "Part of the registered M5 set declared above; see the first entry for the full status.",
},
];
+
/*
* The ablation log is deliberately NOT listed above.
*
@@ -346,21 +373,40 @@ export interface Progress {
readonly recorded: number;
/** Total planned runs across the manifests that declare a plan, or null. */
readonly planned: number | null;
+ /**
+ * Rows left after a re-run of the same cell supersedes the original.
+ *
+ * A study that re-runs a shard has more rows on disk than measurements, and
+ * a line reporting the file count invites the reader to take the larger
+ * number for the study's size. M5 has 1,240 rows across seven shards and
+ * 1,160 cells, because 400 rows were re-produced after a temp reaper and one
+ * seed range was re-run whole. The supersession rule lives in
+ * `bench/m5-analysis.ts`; this counts the same way so the published line and
+ * the registered analysis cannot disagree.
+ */
+ readonly distinct: number;
}
+/** One measurement: a task, an arm and a seed. Re-runs repeat it. */
+const cellKey = (row: Record): string =>
+ `${String(row['task'])}\u0000${String(row['cond'])}\u0000${String(row['seed'])}`;
+
export const progressOf = (sources: Sources): Progress => {
const recorded = sources.rows.length;
- if (recorded === 0) return { state: "no-measurement", recorded, planned: null };
+ const distinct = new Set(
+ sources.rows.map((row) => cellKey(row as unknown as Record)),
+ ).size;
+ if (recorded === 0) return { state: "no-measurement", recorded, planned: null, distinct };
const planned = sources.present.reduce((total, source) => {
if (total === null || source.plannedRuns === null) return null;
return total + source.plannedRuns;
}, 0);
- if (planned === null) return { state: "unknown-plan", recorded, planned: null };
- if (recorded < planned) return { state: "in-progress", recorded, planned };
- if (recorded > planned) return { state: "over-planned", recorded, planned };
- return { state: "measured", recorded, planned };
+ if (planned === null) return { state: "unknown-plan", recorded, planned: null, distinct };
+ if (recorded < planned) return { state: "in-progress", recorded, planned, distinct };
+ if (recorded > planned) return { state: "over-planned", recorded, planned, distinct };
+ return { state: "measured", recorded, planned, distinct };
};
export interface ModelReport {
@@ -545,7 +591,12 @@ const statusLine = (progress: Progress, sources: Sources): string => {
}
if (progress.state === "unknown-plan") {
return (
- `**${progress.recorded} runs recorded.** No manifest declares how many runs the matrix was meant to produce, ` +
+ (progress.distinct === progress.recorded
+ ? `**${progress.recorded} runs recorded.** `
+ : `**${progress.distinct} measurements across ${progress.recorded} rows.** ` +
+ `${progress.recorded - progress.distinct} row(s) are superseded by a re-run of the same task, ` +
+ "arm and seed, and the analysis counts the survivor. ") +
+ "No manifest declares how many runs the matrix was meant to produce, " +
"so completeness cannot be checked from the logs alone."
);
}
diff --git a/dist/commands/doctor.d.ts b/dist/commands/doctor.d.ts
index ba2a3518..bafb5ac7 100644
--- a/dist/commands/doctor.d.ts
+++ b/dist/commands/doctor.d.ts
@@ -67,13 +67,14 @@ export interface DoctorCheck {
/** Derived from `status`; never passed in, never read by the exit code. */
severity: Severity;
/**
- * The observation behind the conclusion. Populated per check by a later
- * ticket; `{}` until then, so an absent field never has to be told apart
- * from an empty one.
+ * The observation behind the conclusion. A row without one cannot explain
+ * why its status is trustworthy, so construction rejects empty evidence.
*/
evidence: Record;
/** No shipping check is optional at introduction (PRD §1.4). */
optional: boolean;
+ /** Absence preserves the additive JSON contract for findings that stand alone. */
+ blockedBy?: string;
/** Present only on `skipped`. Omitted, never null. */
skipReason?: SkipReason;
/**
@@ -160,17 +161,16 @@ export interface CheckDefinition {
/** Ids of entries that appear earlier in this registry (PRD §2 req 2). */
readonly dependencies: readonly string[];
readonly optional: boolean;
- readonly run: (ctx: DoctorContext) => DoctorCheck;
+ readonly run: (ctx: DoctorContext, dependencies: ReadonlyMap) => DoctorCheck;
}
/**
* The registry. **Order is the report's order**, frozen to the array
* `runDoctor` shipped with, because PRD §9.1 holds the text byte-identical
* until the rendering ticket.
*
- * `commit-msg-hook → hook-runtime` is deliberately not declared here: the
- * dependency runs backwards against this order, and §2 req 2 admits only
- * earlier entries. It is threaded through `memo` instead and declared once the
- * ordering rule is settled.
+ * `commit-msg-hook → hook-runtime` stays in the runner's memo because the
+ * frozen presentation order puts the consumer first. Declaring it backwards
+ * would make the registry claim an ordering guarantee it cannot keep.
*/
export declare const CHECK_REGISTRY: readonly CheckDefinition[];
export declare const runDoctor: (opts?: DoctorOptions) => DoctorReport;
diff --git a/dist/commands/doctor.js b/dist/commands/doctor.js
index 7b90af01..348bf612 100644
--- a/dist/commands/doctor.js
+++ b/dist/commands/doctor.js
@@ -53,6 +53,34 @@ const EXACT_NOTES_REFSPEC_PATTERN = `^\\${EXACT_NOTES_REFSPEC}$`;
*/
const escapeConfigValuePattern = (value) => value.replace(/[\\.*+?[\]^$(){}|]/g, (character) => `\\${character}`);
const gitOptions = (opts) => (opts.cwd === undefined ? {} : { cwd: opts.cwd });
+/** The bound keeps a broken child process from making a JSON report unbounded. */
+const boundedExcerpt = (output) => {
+ const [firstLine = ''] = (output ?? '').split(/\r?\n/, 1);
+ return {
+ firstLine: firstLine.slice(0, 200),
+ truncated: firstLine.length > 200 ? 'true' : 'false',
+ };
+};
+const streamEvidence = (stream, output) => {
+ const excerpt = boundedExcerpt(output);
+ return {
+ [`${stream}_first_line`]: excerpt.firstLine,
+ [`${stream}_truncated`]: excerpt.truncated,
+ };
+};
+/** Reports keep paths useful in bug reports without carrying a user's home directory. */
+const homeRelativePath = (value) => {
+ const home = process.env['HOME'];
+ if (home === undefined || home === '')
+ return value;
+ const escapedHome = home.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
+ return value.replace(new RegExp(`${escapedHome}(?=$|/)`, 'g'), '~');
+};
+const normaliseEvidence = (evidence) => Object.fromEntries(Object.entries(evidence).map(([key, value]) => [key, homeRelativePath(value)]));
+const evidenceKey = (value) => value
+ .replace(/[^A-Za-z0-9]+/g, '_')
+ .replace(/^_+|_+$/g, '')
+ .toLowerCase() || 'remote';
/**
* `severity` as a total function of `status` — the only place it is decided.
*
@@ -62,6 +90,10 @@ const gitOptions = (opts) => (opts.cwd === undefined ? {} : { cwd: opts.cwd });
*/
const severityOf = (status) => status === 'fail' ? 'error' : status === 'warn' ? 'warning' : 'info';
function check(id, category, title, status, detail, fix = null, fixed = false, needsAttention = status === 'warn' || status === 'fail', extra = {}) {
+ const evidence = extra.evidence ?? {};
+ if (Object.keys(evidence).length === 0) {
+ throw new Error(`doctor check ${id} has no evidence`);
+ }
return {
id,
title,
@@ -72,16 +104,23 @@ function check(id, category, title, status, detail, fix = null, fixed = false, n
fixed,
category,
severity: severityOf(status),
- evidence: extra.evidence ?? {},
+ evidence: normaliseEvidence(evidence),
optional: extra.optional ?? false,
...(extra.skipReason === undefined ? {} : { skipReason: extra.skipReason }),
};
}
+const blocked = (dependency, row) => {
+ if (dependency.status === 'ok') {
+ throw new Error(`doctor check ${row.id} cannot repeat an ok finding`);
+ }
+ return { ...row, blockedBy: dependency.id };
+};
const checkRefspec = (opts) => {
const title = 'notes fetch refspec';
const remotes = listRemotes(opts);
+ const remoteEvidence = { remotes: remotes.join(', ') || 'none' };
if (remotes.length === 0) {
- return check('notes-refspec', 'transport', title, 'warn', 'no remote is configured, so records cannot be shared with anyone', 'add a remote, then rerun: commitlore doctor --fix', false, false);
+ return check('notes-refspec', 'transport', title, 'warn', 'no remote is configured, so records cannot be shared with anyone', 'add a remote, then rerun: commitlore doctor --fix', false, false, { evidence: remoteEvidence });
}
let missing = remotes.filter((remote) => !fetchRefspecs(remote, opts).some(coversNotes));
let forced = remotes.filter((remote) => fetchRefspecs(remote, opts).some(forcesNotes));
@@ -115,10 +154,10 @@ const checkRefspec = (opts) => {
return check('notes-refspec', 'transport', title, 'warn', `${forced.join(', ')} fetches ${NOTES_REF} with a forced refspec, so an ordinary git fetch ` +
'overwrites this clone\'s mirror — a record written here and not yet pushed is destroyed silently', forced
.map((remote) => `git config --replace-all remote.${remote}.fetch '${NOTES_REFSPEC}' '^\\+refs/notes/'`)
- .join('\n'), fixed);
+ .join('\n'), fixed, undefined, { evidence: { ...remoteEvidence, forced: forced.join(', ') } });
}
if (missing.length > 0) {
- return check('notes-refspec', 'transport', title, 'warn', `${missing.join(', ')} does not fetch ${NOTES_REF}, so records pushed by others stay invisible here`, missing.map((remote) => `git config --add remote.${remote}.fetch '${NOTES_REFSPEC}'`).join('\n'));
+ return check('notes-refspec', 'transport', title, 'warn', `${missing.join(', ')} does not fetch ${NOTES_REF}, so records pushed by others stay invisible here`, missing.map((remote) => `git config --add remote.${remote}.fetch '${NOTES_REFSPEC}'`).join('\n'), false, undefined, { evidence: { ...remoteEvidence, missing: missing.join(', ') } });
}
const failed = remotes
.map((remote) => ({ remote, result: execGit(['fetch', '--dry-run', remote], gitOptions(opts)) }))
@@ -126,7 +165,15 @@ const checkRefspec = (opts) => {
if (failed.length > 0) {
return check('notes-refspec', 'transport', title, 'warn', `could not verify (${failed
.map(({ remote, result }) => `${remote}: ${result.stderr.trim().split('\n')[0] ?? 'git fetch failed'}`)
- .join('; ')})`, failed.map(({ remote }) => `git fetch ${remote}`).join('\n'), fixed);
+ .join('; ')})`, failed.map(({ remote }) => `git fetch ${remote}`).join('\n'), fixed, undefined, {
+ evidence: {
+ ...remoteEvidence,
+ ...Object.fromEntries(failed.map(({ remote, result }) => [
+ `fetch_exit_code_${evidenceKey(remote)}`,
+ String(result.code),
+ ])),
+ },
+ });
}
// A refspec written by `--fix` has not been fetched through yet, and this
// check is the last thing the operator reads before believing the mirror is
@@ -135,7 +182,7 @@ const checkRefspec = (opts) => {
// retrieved -- the configuration is right and the records are still missing.
return check('notes-refspec', 'transport', title, 'ok', fixed
? `${NOTES_REF} is now covered for ${remotes.join(', ')} — nothing has been fetched through it yet`
- : `git fetch succeeds for ${remotes.join(', ')} and covers ${NOTES_REF}`, fixed ? `git fetch ${remotes[0] ?? 'origin'}` : null, fixed);
+ : `git fetch succeeds for ${remotes.join(', ')} and covers ${NOTES_REF}`, fixed ? `git fetch ${remotes[0] ?? 'origin'}` : null, fixed, undefined, { evidence: remoteEvidence });
};
/**
* Pushing is never automatic: `git push` writes to a ref other people read,
@@ -147,17 +194,28 @@ const checkPush = (opts) => {
const remote = remotes[0] ?? 'origin';
const command = `git push ${remote} ${NOTES_REF}`;
const local = execGit(['rev-parse', '--verify', '--quiet', NOTES_REF], gitOptions(opts));
+ const localEvidence = {
+ remote,
+ local_sha: local.code === 0 ? local.stdout.trim() || 'unknown' : 'none',
+ };
if (local.code !== 0) {
- return check('notes-push', 'transport', title, 'ok', `no local mirror yet — nothing to push (${command}, once there is)`);
+ return check('notes-push', 'transport', title, 'ok', `no local mirror yet — nothing to push (${command}, once there is)`, null, false, undefined, { evidence: { ...localEvidence, remote_sha: 'not_queried' } });
}
const advertised = execGit(['ls-remote', remote, NOTES_REF], gitOptions(opts));
if (advertised.code !== 0) {
- return check('notes-push', 'transport', title, 'warn', `could not verify (${remote}: ${advertised.stderr.trim().split('\n')[0] ?? 'git ls-remote failed'})`, command);
+ return check('notes-push', 'transport', title, 'warn', `could not verify (${remote}: ${advertised.stderr.trim().split('\n')[0] ?? 'git ls-remote failed'})`, command, false, undefined, {
+ evidence: {
+ ...localEvidence,
+ ls_remote_exit_code: String(advertised.code),
+ ...streamEvidence('ls_remote_stderr', advertised.stderr),
+ },
+ });
}
- if (advertised.stdout.split(/\s/)[0] === local.stdout.trim()) {
- return check('notes-push', 'transport', title, 'ok', `${remote} has the current ${NOTES_REF}`);
+ const remoteSha = advertised.stdout.split(/\s/)[0] ?? '';
+ if (remoteSha === local.stdout.trim()) {
+ return check('notes-push', 'transport', title, 'ok', `${remote} has the current ${NOTES_REF}`, null, false, undefined, { evidence: { ...localEvidence, remote_sha: remoteSha || 'none' } });
}
- return check('notes-push', 'transport', title, 'warn', `this clone has local records in ${NOTES_REF}; no command pushes them for you`, command);
+ return check('notes-push', 'transport', title, 'warn', `this clone has local records in ${NOTES_REF}; no command pushes them for you`, command, false, undefined, { evidence: { ...localEvidence, remote_sha: remoteSha || 'none' } });
};
/**
* Installation belongs to `commitlore hooks install` (T-202). This reads.
@@ -165,7 +223,8 @@ const checkPush = (opts) => {
* The marker is imported from the stub rather than restated, so that doctor
* can never disagree with the installer about what "installed" means.
*/
-const checkHook = (opts, runtime) => {
+const checkHook = (ctx) => {
+ const { opts } = ctx;
const title = 'commit-msg hook';
const id = 'commit-msg-hook';
const category = 'capture';
@@ -174,28 +233,34 @@ const checkHook = (opts, runtime) => {
// somewhere else entirely.
const located = execGit(['rev-parse', '--git-path', 'hooks/commit-msg'], gitOptions(opts));
if (located.code !== 0) {
- return check(id, category, title, 'warn', 'not inside a git repository', install);
+ return check(id, category, title, 'warn', 'not inside a git repository', install, false, undefined, { evidence: { hook_path: 'unavailable', bin: 'not_recorded', node: 'not_recorded' } });
}
const path = resolve(opts.cwd ?? process.cwd(), located.stdout.trim());
const target = readRecordedHookTarget(opts.cwd ?? process.cwd());
const override = process.env['COMMITLORE_BIN'];
+ const hookEvidence = {
+ hook_path: path,
+ bin: target.bin || '(unset)',
+ node: target.node || '(unset)',
+ ...(override === undefined || override === '' ? {} : { commitlore_bin_override: override }),
+ };
const targetDetail = [
...describeRecordedHookTarget(target),
...(override === undefined || override === '' ? [] : [`COMMITLORE_BIN: ${override}`]),
].join('; ');
if (!existsSync(path)) {
- return check(id, category, title, 'warn', `no commit-msg hook at ${path}; ${targetDetail}`, install);
+ return check(id, category, title, 'warn', `no commit-msg hook at ${path}; ${targetDetail}`, install, false, undefined, { evidence: hookEvidence });
}
const contents = readFileSync(path, 'utf8');
if (!contents.includes(HOOK_MARKER)) {
- return check(id, category, title, 'warn', `a commit-msg hook exists at ${path} but does not invoke commitlore; ${targetDetail}`, install);
+ return check(id, category, title, 'warn', `a commit-msg hook exists at ${path} but does not invoke commitlore; ${targetDetail}`, install, false, undefined, { evidence: hookEvidence });
}
// `hooks status` has always reported this; doctor did not, and doctor is what
// people run to ask whether their installation is healthy. A stale stub is
// exactly how a fixed resolution order fails to reach anyone who installed
// before it landed.
if (contents !== commitMsgStub()) {
- return check(id, category, title, 'warn', `installed at ${path}, but the stub is out of date — it predates a change to how the hook finds the CLI; ${targetDetail}`, install);
+ return check(id, category, title, 'warn', `installed at ${path}, but the stub is out of date — it predates a change to how the hook finds the CLI; ${targetDetail}`, install, false, undefined, { evidence: hookEvidence });
}
const problems = [
...target.problems,
@@ -208,6 +273,7 @@ const checkHook = (opts, runtime) => {
'ignores it and falls through to the remaining resolution steps',
]),
];
+ const runtime = hookRuntimeOf(ctx);
if (runtime.status !== 'ok') {
const inherited = `installed at ${path}; ${targetDetail}; outcome: ${runtime.detail}`;
// A skipped runtime would make this row a skip too, and a skip has to name
@@ -217,13 +283,16 @@ const checkHook = (opts, runtime) => {
// written out rather than cast away so that adding one cannot silently
// produce a reasonless skip here.
if (runtime.status === 'skipped') {
- return check(id, category, title, 'skipped', inherited, install, false, false, { skipReason: runtime.skipReason ?? 'nothing_applicable' });
+ return blocked(runtime, check(id, category, title, 'skipped', inherited, install, false, false, {
+ evidence: { ...hookEvidence, runtime_status: runtime.status },
+ skipReason: runtime.skipReason ?? 'nothing_applicable',
+ }));
}
- return check(id, category, title, runtime.status, inherited, install);
+ return blocked(runtime, check(id, category, title, runtime.status, inherited, install, false, undefined, { evidence: { ...hookEvidence, runtime_status: runtime.status } }));
}
return problems.length === 0
- ? check(id, category, title, 'ok', `installed at ${path}; ${targetDetail}`)
- : check(id, category, title, 'warn', `installed at ${path}; ${targetDetail}; ${problems.join('; ')}`, install);
+ ? check(id, category, title, 'ok', `installed at ${path}; ${targetDetail}`, null, false, undefined, { evidence: hookEvidence })
+ : check(id, category, title, 'warn', `installed at ${path}; ${targetDetail}; ${problems.join('; ')}`, install, false, undefined, { evidence: hookEvidence });
};
/**
* Runs the real parse path once. Trailer boundaries are git's to decide
@@ -246,13 +315,13 @@ const checkGit = (opts) => {
}
catch (error) {
const reason = error instanceof Error ? error.message : String(error);
- return check(id, category, title, 'fail', `${version || 'git'} could not parse a probe: ${reason}`, upgrade);
+ return check(id, category, title, 'fail', `${version || 'git'} could not parse a probe: ${reason}`, upgrade, false, undefined, { evidence: { git_version: version || 'unavailable', parsed: 'unavailable' } });
}
const parsed = trailers.map((trailer) => `${trailer.key}: ${trailer.value}`).join(', ');
if (parsed !== 'Limit: probe, Blast: local') {
- return check(id, category, title, 'fail', `${version} parsed the probe as [${parsed}]`, upgrade);
+ return check(id, category, title, 'fail', `${version} parsed the probe as [${parsed}]`, upgrade, false, undefined, { evidence: { git_version: version || 'unavailable', parsed } });
}
- return check(id, category, title, 'ok', `${version} parses trailers as the spec expects`);
+ return check(id, category, title, 'ok', `${version} parses trailers as the spec expects`, null, false, undefined, { evidence: { git_version: version || 'unavailable', parsed } });
};
/**
* Whether the CLI this installation actually uses runs.
@@ -284,7 +353,13 @@ const checkRuntime = (opts) => {
const candidates = ['dist/commitlore.mjs', 'dist/cli.js'].map((rel) => installedPath(rel));
const entry = candidates.find((path) => existsSync(path));
if (entry === undefined) {
- return check(id, category, title, 'fail', `no built CLI at ${candidates.join(' or ')} — this checkout has not been built`, 'npm install && npm run build');
+ return check(id, category, title, 'fail', `no built CLI at ${candidates.join(' or ')} — this checkout has not been built`, 'npm install && npm run build', false, undefined, {
+ evidence: {
+ entry: candidates.join(' or '),
+ exit_code: 'not_run',
+ ...streamEvidence('stderr', ''),
+ },
+ });
}
const run = spawnSync(process.execPath, [entry, '--version'], {
shell: false,
@@ -292,13 +367,32 @@ const checkRuntime = (opts) => {
...gitOptions(opts),
});
if (run.error !== undefined) {
- return check(id, category, title, 'fail', `could not run ${entry}: ${run.error.message}`, null);
+ return check(id, category, title, 'fail', `could not run ${entry}: ${run.error.message}`, null, false, undefined, {
+ evidence: {
+ entry,
+ exit_code: String(run.status ?? 'unavailable'),
+ error: run.error.message,
+ ...streamEvidence('stderr', run.stderr),
+ },
+ });
}
if (run.status !== 0) {
const detail = `${run.stderr ?? ''}`.trim().split('\n')[0] ?? `exit ${String(run.status)}`;
- return check(id, category, title, 'fail', `${entry} exits ${String(run.status)}: ${detail}`, 'npm install');
+ return check(id, category, title, 'fail', `${entry} exits ${String(run.status)}: ${detail}`, 'npm install', false, undefined, {
+ evidence: {
+ entry,
+ exit_code: String(run.status),
+ ...streamEvidence('stderr', run.stderr),
+ },
+ });
}
- return check(id, category, title, 'ok', `${entry} runs (${run.stdout.trim()})`);
+ return check(id, category, title, 'ok', `${entry} runs (${run.stdout.trim()})`, null, false, undefined, {
+ evidence: {
+ entry,
+ version: boundedExcerpt(run.stdout).firstLine,
+ ...streamEvidence('stdout', run.stdout),
+ },
+ });
};
/**
* Whether the installed hook actually runs, in the environment git gives it.
@@ -326,13 +420,21 @@ const checkHookRuntime = (opts) => {
const fix = 'commitlore hooks install';
const cwd = opts.cwd ?? process.cwd();
const located = execGit(['rev-parse', '--git-path', 'hooks/commit-msg'], gitOptions(opts));
- if (located.code !== 0)
- return check(id, category, title, 'warn', 'not inside a git repository', fix);
+ if (located.code !== 0) {
+ return check(id, category, title, 'warn', 'not inside a git repository', fix, false, undefined, {
+ evidence: {
+ hook_path: 'unavailable',
+ exit_code: String(located.code),
+ ...streamEvidence('stderr', located.stderr),
+ },
+ });
+ }
const hook = resolve(cwd, located.stdout.trim());
// The hook's absence is `checkHook`'s finding; saying it twice teaches the
// reader to skim both.
- if (!existsSync(hook))
- return check(id, category, title, 'ok', 'no hook installed — nothing to run');
+ if (!existsSync(hook)) {
+ return check(id, category, title, 'ok', 'no hook installed — nothing to run', null, false, undefined, { evidence: { hook_path: hook } });
+ }
const probe = join(tmpdirPath(), `commitlore-doctor-${String(process.pid)}.txt`);
try {
writeFileSync(probe, PROBE_MESSAGE);
@@ -345,7 +447,14 @@ const checkHookRuntime = (opts) => {
env: { PATH: '/usr/bin:/bin', HOME: process.env['HOME'] ?? '' },
});
if (run.error !== undefined) {
- return check(id, category, title, 'fail', `could not run the hook: ${run.error.message}`, fix);
+ return check(id, category, title, 'fail', `could not run the hook: ${run.error.message}`, fix, false, undefined, {
+ evidence: {
+ hook_path: hook,
+ exit_code: String(run.status ?? 'unavailable'),
+ error: run.error.message,
+ ...streamEvidence('stderr', run.stderr),
+ },
+ });
}
if (run.status !== 0) {
const said = `${run.stderr ?? ''}`.trim().split('\n')[0] ?? '';
@@ -362,12 +471,25 @@ const checkHookRuntime = (opts) => {
else {
detail = `the hook exited ${String(run.status)} under the restricted PATH — cause unclear: ${said || 'no output'}`;
}
- return check(id, category, title, 'fail', detail, fix);
+ return check(id, category, title, 'fail', detail, fix, false, undefined, {
+ evidence: {
+ hook_path: hook,
+ exit_code: String(run.status),
+ ...streamEvidence('stderr', run.stderr),
+ },
+ });
}
- return check(id, category, title, 'ok', 'the hook runs and validates without node on PATH');
+ return check(id, category, title, 'ok', 'the hook runs and validates without node on PATH', null, false, undefined, { evidence: { hook_path: hook, exit_code: '0' } });
}
catch (error) {
- return check(id, category, title, 'warn', `could not probe the hook: ${error instanceof Error ? error.message : String(error)}`, fix);
+ return check(id, category, title, 'warn', `could not probe the hook: ${error instanceof Error ? error.message : String(error)}`, fix, false, undefined, {
+ evidence: {
+ hook_path: hook,
+ exit_code: 'unavailable',
+ error: error instanceof Error ? error.message : String(error),
+ ...streamEvidence('stderr', ''),
+ },
+ });
}
finally {
rmSync(probe, { force: true });
@@ -404,21 +526,54 @@ const checkHookRuntime = (opts) => {
*/
export const evaluateInjectRun = (run, ctx) => {
const { id, category, title, executable, path, fix, unavailableFix } = ctx;
+ const executionEvidence = { executable, path };
if (run.status === null || run.status === undefined) {
if (run.error !== undefined && 'code' in run.error && run.error.code === 'ENOENT') {
- return check(id, category, title, 'fail', `configured PreToolUse hook executable ${JSON.stringify(executable)} is not resolvable from PATH`, unavailableFix);
+ return check(id, category, title, 'fail', `configured PreToolUse hook executable ${JSON.stringify(executable)} is not resolvable from PATH`, unavailableFix, false, undefined, {
+ evidence: {
+ ...executionEvidence,
+ exit_code: 'unavailable',
+ ...streamEvidence('stderr', run.stderr),
+ },
+ });
}
- return check(id, category, title, 'fail', `could not run the PreToolUse hook: ${run.error?.message ?? 'no diagnosis'}`, fix);
+ return check(id, category, title, 'fail', `could not run the PreToolUse hook: ${run.error?.message ?? 'no diagnosis'}`, fix, false, undefined, {
+ evidence: {
+ ...executionEvidence,
+ exit_code: 'unavailable',
+ error: run.error?.message ?? 'no diagnosis',
+ ...streamEvidence('stderr', run.stderr),
+ },
+ });
}
if (run.status !== 0) {
const said = `${run.stderr ?? ''}`.trim().split('\n')[0] ?? '';
- return check(id, category, title, 'fail', `the PreToolUse hook exits ${String(run.status)}: ${said || 'no diagnosis'}`, fix);
+ return check(id, category, title, 'fail', `the PreToolUse hook exits ${String(run.status)}: ${said || 'no diagnosis'}`, fix, false, undefined, {
+ evidence: {
+ ...executionEvidence,
+ exit_code: String(run.status),
+ ...streamEvidence('stderr', run.stderr),
+ },
+ });
}
if (`${run.stdout ?? ''}`.trim() === '') {
const said = `${run.stderr ?? ''}`.trim().split('\n')[0] ?? '';
- return check(id, category, title, 'fail', `the PreToolUse hook returned no context for a known-good payload${said === '' ? '' : `: ${said}`}`, fix);
+ return check(id, category, title, 'fail', `the PreToolUse hook returned no context for a known-good payload${said === '' ? '' : `: ${said}`}`, fix, false, undefined, {
+ evidence: {
+ ...executionEvidence,
+ exit_code: '0',
+ ...streamEvidence('stdout', run.stdout),
+ ...streamEvidence('stderr', run.stderr),
+ },
+ });
}
- return check(id, category, title, 'ok', `the PreToolUse hook returned context for ${path}`);
+ return check(id, category, title, 'ok', `the PreToolUse hook returned context for ${path}`, null, false, undefined, {
+ evidence: {
+ ...executionEvidence,
+ exit_code: '0',
+ ...streamEvidence('stdout', run.stdout),
+ },
+ });
};
const checkInjectRuntime = (opts) => {
const title = 'PreToolUse hook runtime';
@@ -431,22 +586,61 @@ const checkInjectRuntime = (opts) => {
if (settings.state !== 'installed') {
const command = settings.commands[0];
if (settings.state === 'outdated' && command !== undefined) {
- return check(id, category, title, 'skipped', `not checked: configured command ${JSON.stringify(command)} is not recognised; running it might have side effects`, null, false, false, { skipReason: 'command_unrecognized' });
+ return check(id, category, title, 'skipped', `not checked: configured command ${JSON.stringify(command)} is not recognised; running it might have side effects`, null, false, false, {
+ evidence: {
+ settings_path: settings.settingsPath,
+ settings_state: settings.state,
+ configured_command: command,
+ executable: 'not_run',
+ exit_code: 'not_run',
+ ...streamEvidence('stderr', ''),
+ },
+ skipReason: 'command_unrecognized',
+ });
}
const detail = settings.state === 'absent'
? `not installed in ${settings.settingsPath}`
: `${settings.state} in ${settings.settingsPath}${settings.problem === undefined ? '' : `: ${settings.problem}`}`;
- return check(id, category, title, 'warn', detail, 'commitlore inject install-claude-hook');
+ return check(id, category, title, 'warn', detail, 'commitlore inject install-claude-hook', false, undefined, {
+ evidence: {
+ settings_path: settings.settingsPath,
+ settings_state: settings.state,
+ executable: 'not_run',
+ exit_code: 'not_run',
+ ...streamEvidence('stderr', ''),
+ ...(settings.problem === undefined ? {} : { problem: settings.problem }),
+ },
+ });
}
const command = settings.commands[0];
if (command !== CLAUDE_HOOK_COMMAND) {
- return check(id, category, title, 'skipped', 'not checked: the configured command is not recognised', null, false, false, { skipReason: 'command_unrecognized' });
+ return check(id, category, title, 'skipped', 'not checked: the configured command is not recognised', null, false, false, {
+ evidence: {
+ settings_path: settings.settingsPath,
+ settings_state: settings.state,
+ configured_command: command ?? 'none',
+ executable: 'not_run',
+ exit_code: 'not_run',
+ ...streamEvidence('stderr', ''),
+ },
+ skipReason: 'command_unrecognized',
+ });
}
const path = runQuery({ cwd, noIndex: true }).records
.flatMap((record) => record.paths)
.find((candidate) => candidate !== '' && candidate !== '.');
if (path === undefined) {
- return check(id, category, title, 'skipped', 'no recorded path is available for a runtime probe', null, false, false, { skipReason: 'probe_path_unavailable' });
+ return check(id, category, title, 'skipped', 'no recorded path is available for a runtime probe', null, false, false, {
+ evidence: {
+ settings_path: settings.settingsPath,
+ settings_state: settings.state,
+ executable: 'not_run',
+ probe_path: 'unavailable',
+ exit_code: 'not_run',
+ ...streamEvidence('stderr', ''),
+ },
+ skipReason: 'probe_path_unavailable',
+ });
}
const payload = JSON.stringify({
session_id: 'commitlore-doctor',
@@ -503,7 +697,7 @@ const checkInjectRuntime = (opts) => {
* run over.
*/
const SEMVER_ISH = /^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)*$/;
-const checkInjectVersion = (opts) => {
+const checkInjectVersion = (opts, dependencies) => {
const title = 'PreToolUse hook version';
const id = 'inject-version';
const category = 'delivery';
@@ -511,11 +705,22 @@ const checkInjectVersion = (opts) => {
const mine = packageVersion();
const settings = readClaudeHookStatus(claudeSettingsPath(cwd));
if (settings.state !== 'installed') {
- return check(id, category, title, 'skipped', `no installed hook to compare against ${mine}`, null, false, false, { skipReason: 'hook_not_installed' });
+ return check(id, category, title, 'skipped', `no installed hook to compare against ${mine}`, null, false, false, {
+ evidence: { executable: 'not_run', theirs: 'not_run', mine },
+ skipReason: 'hook_not_installed',
+ });
}
const command = settings.commands[0];
if (command !== CLAUDE_HOOK_COMMAND) {
- return check(id, category, title, 'skipped', 'not checked: the configured command is not recognised', null, false, false, { skipReason: 'command_unrecognized' });
+ return check(id, category, title, 'skipped', 'not checked: the configured command is not recognised', null, false, false, {
+ evidence: {
+ executable: 'not_run',
+ theirs: 'not_run',
+ mine,
+ configured_command: command ?? 'none',
+ },
+ skipReason: 'command_unrecognized',
+ });
}
const configured = command.replace(` ${CLAUDE_HOOK_MARKER}`, '');
const executable = configured.slice(0, configured.indexOf(' '));
@@ -528,10 +733,20 @@ const checkInjectVersion = (opts) => {
HOME: process.env['HOME'] ?? '',
},
});
+ const reported = typeof run.stdout === 'string' ? run.stdout : '';
+ const versionEvidence = {
+ executable,
+ theirs: boundedExcerpt(reported).firstLine || 'unavailable',
+ mine,
+ exit_code: String(run.status ?? 'unavailable'),
+ ...streamEvidence('stdout', reported),
+ };
if (run.status !== 0 || typeof run.stdout !== 'string') {
// `checkInjectRuntime` owns "the hook does not run at all" and reports it
// with the remedy. Saying it twice would be noise.
- return check(id, category, title, 'skipped', `${executable} did not report a version`, null, false, false, { skipReason: 'version_unreadable' });
+ const skipped = check(id, category, title, 'skipped', `${executable} did not report a version`, null, false, false, { evidence: versionEvidence, skipReason: 'version_unreadable' });
+ const runtime = dependencies.get('inject-runtime');
+ return runtime === undefined || runtime.status === 'ok' ? skipped : blocked(runtime, skipped);
}
const theirs = run.stdout.trim();
// Exit 0 is not the same as an answer. A wrapper that ignores its arguments
@@ -539,12 +754,12 @@ const checkInjectVersion = (opts) => {
// version reports a mismatch against something that was never a version.
// Two builds cannot be compared unless both sides actually said one.
if (!SEMVER_ISH.test(theirs)) {
- return check(id, category, title, 'skipped', `${executable} answered --version with something that is not a version`, null, false, false, { skipReason: 'version_unreadable' });
+ return check(id, category, title, 'skipped', `${executable} answered --version with something that is not a version`, null, false, false, { evidence: versionEvidence, skipReason: 'version_unreadable' });
}
if (theirs === mine) {
- return check(id, category, title, 'ok', `the hook runs ${theirs}, the same build as this CLI`);
+ return check(id, category, title, 'ok', `the hook runs ${theirs}, the same build as this CLI`, null, false, undefined, { evidence: versionEvidence });
}
- return check(id, category, title, 'warn', `the agent's hook runs ${theirs} but this CLI is ${mine} — every edit is graded by ${theirs}'s rules, not this one's`, 'update the installation the hook resolves to (for the plugin: /plugin marketplace update commitlore), then rerun: commitlore doctor');
+ return check(id, category, title, 'warn', `the agent's hook runs ${theirs} but this CLI is ${mine} — every edit is graded by ${theirs}'s rules, not this one's`, 'update the installation the hook resolves to (for the plugin: /plugin marketplace update commitlore), then rerun: commitlore doctor', false, undefined, { evidence: versionEvidence });
};
/**
* MCP servers that started here and never recorded an exit (#424).
@@ -568,12 +783,18 @@ const checkMcpLifecycle = (opts) => {
const cwd = opts.cwd ?? process.cwd();
const unfinished = unfinishedRuns(cwd);
if (unfinished.length === 0) {
- return check(id, category, title, 'ok', 'every recorded MCP session ended cleanly, or is still running');
+ return check(id, category, title, 'ok', 'every recorded MCP session ended cleanly, or is still running', null, false, undefined, { evidence: { unfinished_count: '0', last_pid: 'none', last_at: 'none' } });
}
const last = unfinished[unfinished.length - 1];
return check(id, category, title, 'warn', `${unfinished.length} MCP server session(s) started here and never recorded an exit — ` +
`most recently pid ${String(last?.pid ?? 0)} at ${last?.at ?? 'unknown'}. ` +
- 'A killed server loses its tool registration in the client, which reports the same as a tool that never existed (#424)', 'restart the client session; if this repeats, capture it with a client started under --debug');
+ 'A killed server loses its tool registration in the client, which reports the same as a tool that never existed (#424)', 'restart the client session; if this repeats, capture it with a client started under --debug', false, undefined, {
+ evidence: {
+ unfinished_count: String(unfinished.length),
+ last_pid: String(last?.pid ?? 0),
+ last_at: last?.at ?? 'unknown',
+ },
+ });
};
/**
* #458: captures that were prepared and then never reached a commit.
@@ -608,17 +829,31 @@ const checkPendingBacklog = (opts) => {
listing = runPendingList({ cwd });
}
catch {
- return check(id, category, title, 'ok', 'no pending directory — nothing has been captured here yet');
+ return check(id, category, title, 'ok', 'no pending directory — nothing has been captured here yet', null, false, undefined, { evidence: { stranded: '0', staged_expired: '0', oldest: 'none' } });
}
if (listing.unreadable.length > 0) {
- return check(id, category, title, 'warn', `${listing.unreadable.length} pending file(s) cannot be read as a transaction`, 'commitlore pending ls');
+ return check(id, category, title, 'warn', `${listing.unreadable.length} pending file(s) cannot be read as a transaction`, 'commitlore pending ls', false, undefined, {
+ evidence: {
+ stranded: '0',
+ staged_expired: '0',
+ oldest: 'none',
+ unreadable: String(listing.unreadable.length),
+ },
+ });
}
// A stale transaction can no longer apply: its base_head is not HEAD, so the
// commit it was prepared for either never happened or happened without it.
const stranded = listing.transactions.filter((transaction) => transaction.stale);
if (stranded.length === 0) {
const held = listing.transactions.length;
- return check(id, category, title, 'ok', held === 0 ? 'no captures are waiting' : `${String(held)} capture(s) waiting, all still able to apply`);
+ return check(id, category, title, 'ok', held === 0 ? 'no captures are waiting' : `${String(held)} capture(s) waiting, all still able to apply`, null, false, undefined, {
+ evidence: {
+ stranded: '0',
+ staged_expired: '0',
+ oldest: 'none',
+ waiting: String(held),
+ },
+ });
}
const lost = stranded.filter((transaction) => transaction.phase === 'staged');
const oldest = stranded
@@ -635,7 +870,13 @@ const checkPendingBacklog = (opts) => {
: `${String(stranded.length)} capture(s) can no longer apply — their base commit is no longer HEAD`;
return check(id, category, title, 'warn', `${detail}; oldest from ${oldest ?? 'an unknown time'}. ` +
'A staged record binds to the tree it was prepared for and is skipped once that tree moves, ' +
- 'so these decisions were never written to the history (#458)', 'commitlore pending ls');
+ 'so these decisions were never written to the history (#458)', 'commitlore pending ls', false, undefined, {
+ evidence: {
+ stranded: String(stranded.length),
+ staged_expired: String(lost.length),
+ oldest: oldest ?? 'unknown',
+ },
+ });
};
const checkIndex = (opts) => {
const cwd = opts.cwd ?? process.cwd();
@@ -644,19 +885,42 @@ const checkIndex = (opts) => {
handle = openIndex({ cwd, readonly: true });
}
catch {
- return check('index-health', 'index', 'index health', 'warn', 'no index yet — queries fall back to scanning the history', 'commitlore index --rebuild');
+ return check('index-health', 'index', 'index health', 'warn', 'no index yet — queries fall back to scanning the history', 'commitlore index --rebuild', false, undefined, {
+ evidence: {
+ trailers: '0',
+ commits: '0',
+ last_indexed_sha: 'none',
+ head_sha: 'not_queried',
+ fts: 'unavailable',
+ },
+ });
}
try {
const info = indexInfo(handle);
const head = execGit(['rev-parse', 'HEAD'], gitOptions(opts));
const behind = head.code === 0 && info.lastIndexedSha !== head.stdout.trim();
const fts = info.fts ? 'FTS5' : 'no FTS5 (value search falls back to LIKE)';
+ const indexEvidence = {
+ trailers: String(info.trailers),
+ commits: String(info.commits),
+ last_indexed_sha: info.lastIndexedSha || 'none',
+ head_sha: head.code === 0 ? head.stdout.trim() || 'none' : 'unavailable',
+ fts: info.fts ? 'true' : 'false',
+ };
return behind
- ? check('index-health', 'index', 'index health', 'warn', `${info.trailers} trailers over ${info.commits} commits, behind HEAD — ${fts}`, 'commitlore index')
- : check('index-health', 'index', 'index health', 'ok', `${info.trailers} trailers over ${info.commits} commits, current with HEAD — ${fts}`);
+ ? check('index-health', 'index', 'index health', 'warn', `${info.trailers} trailers over ${info.commits} commits, behind HEAD — ${fts}`, 'commitlore index', false, undefined, { evidence: indexEvidence })
+ : check('index-health', 'index', 'index health', 'ok', `${info.trailers} trailers over ${info.commits} commits, current with HEAD — ${fts}`, null, false, undefined, { evidence: indexEvidence });
}
catch (error) {
- return check('index-health', 'index', 'index health', 'warn', `index unreadable (${error instanceof Error ? error.message : String(error)}) — queries still work without it`, 'commitlore index --rebuild');
+ return check('index-health', 'index', 'index health', 'warn', `index unreadable (${error instanceof Error ? error.message : String(error)}) — queries still work without it`, 'commitlore index --rebuild', false, undefined, {
+ evidence: {
+ trailers: 'unavailable',
+ commits: 'unavailable',
+ last_indexed_sha: 'unavailable',
+ head_sha: 'unavailable',
+ fts: 'unavailable',
+ },
+ });
}
finally {
try {
@@ -668,8 +932,8 @@ const checkIndex = (opts) => {
}
};
const checkHistoryDepth = (opts) => hasShallowHistory(opts.cwd ?? process.cwd())
- ? check('history-depth', 'history', 'history depth', 'warn', 'this clone has shallow history, so queries may be missing records that exist upstream', 'git fetch --unshallow')
- : check('history-depth', 'history', 'history depth', 'ok', 'full history is available');
+ ? check('history-depth', 'history', 'history depth', 'warn', 'this clone has shallow history, so queries may be missing records that exist upstream', 'git fetch --unshallow', false, undefined, { evidence: { shallow: 'true' } })
+ : check('history-depth', 'history', 'history depth', 'ok', 'full history is available', null, false, undefined, { evidence: { shallow: 'false' } });
/** Local branches this check will look at, past which a repository is skipped rather than walked exhaustively. */
const MAX_SQUASH_CANDIDATE_BRANCHES = 200;
/**
@@ -743,11 +1007,17 @@ const checkSquashConservation = (opts) => {
const cwd = opts.cwd ?? process.cwd();
const head = execGit(['rev-parse', '--verify', '--quiet', 'HEAD'], gitOptions(opts));
if (head.code !== 0) {
- return check(id, category, title, 'skipped', 'no HEAD yet — nothing to compare against', null, false, false, { skipReason: 'unborn_head' });
+ return check(id, category, title, 'skipped', 'no HEAD yet — nothing to compare against', null, false, false, {
+ evidence: { candidates: '0', checked: '0', uncheckable: '0', lost_count: '0' },
+ skipReason: 'unborn_head',
+ });
}
const candidates = squashCandidates(opts, head.stdout.trim());
if (candidates.length === 0) {
- return check(id, category, title, 'skipped', 'no local branch looks like the source of a squash — nothing to check', null, false, false, { skipReason: 'nothing_applicable' });
+ return check(id, category, title, 'skipped', 'no local branch looks like the source of a squash — nothing to check', null, false, false, {
+ evidence: { candidates: '0', checked: '0', uncheckable: '0', lost_count: '0' },
+ skipReason: 'nothing_applicable',
+ });
}
let known = null;
const lost = [];
@@ -785,7 +1055,15 @@ const checkSquashConservation = (opts) => {
}
}
if (checked === 0) {
- return check(id, category, title, 'skipped', `${candidates.length} branch(es) looked like a squash source, but recorded nothing checkable`, null, false, false, { skipReason: 'nothing_applicable' });
+ return check(id, category, title, 'skipped', `${candidates.length} branch(es) looked like a squash source, but recorded nothing checkable`, null, false, false, {
+ evidence: {
+ candidates: String(candidates.length),
+ checked: '0',
+ uncheckable: String(uncheckable),
+ lost_count: '0',
+ },
+ skipReason: 'nothing_applicable',
+ });
}
if (lost.length > 0) {
const named = lost
@@ -794,13 +1072,27 @@ const checkSquashConservation = (opts) => {
.join(', ');
const more = lost.length > 5 ? `, and ${lost.length - 5} more` : '';
return check(id, category, title, 'warn', `${lost.length} record(s) declared on a branch not reachable from HEAD do not appear in HEAD's history: ${named}${more}`, 'commitlore squash-preserve .. --target , ' +
- 'then commit or attach the result');
+ 'then commit or attach the result', false, undefined, {
+ evidence: {
+ candidates: String(candidates.length),
+ checked: String(checked),
+ uncheckable: String(uncheckable),
+ lost_count: String(lost.length),
+ },
+ });
}
const detail = uncheckable > 0
? `${checked} squash-shaped branch(es) checked, every declared Record-Id is reachable from HEAD ` +
`(${uncheckable} branch(es) recorded nothing with an id and could not be checked this way)`
: `${checked} squash-shaped branch(es) checked, every declared Record-Id is reachable from HEAD`;
- return check(id, category, title, 'ok', detail);
+ return check(id, category, title, 'ok', detail, null, false, undefined, {
+ evidence: {
+ candidates: String(candidates.length),
+ checked: String(checked),
+ uncheckable: String(uncheckable),
+ lost_count: '0',
+ },
+ });
};
/** Runs `hook-runtime` at most once per report, whichever row asks first. */
const hookRuntimeOf = (ctx) => {
@@ -816,19 +1108,18 @@ const hookRuntimeOf = (ctx) => {
* `runDoctor` shipped with, because PRD §9.1 holds the text byte-identical
* until the rendering ticket.
*
- * `commit-msg-hook → hook-runtime` is deliberately not declared here: the
- * dependency runs backwards against this order, and §2 req 2 admits only
- * earlier entries. It is threaded through `memo` instead and declared once the
- * ordering rule is settled.
+ * `commit-msg-hook → hook-runtime` stays in the runner's memo because the
+ * frozen presentation order puts the consumer first. Declaring it backwards
+ * would make the registry claim an ordering guarantee it cannot keep.
*/
export const CHECK_REGISTRY = [
{ id: 'cli-runtime', title: 'cli runtime', category: 'runtime', dependencies: [], optional: false, run: (ctx) => checkRuntime(ctx.opts) },
{ id: 'notes-refspec', title: 'notes fetch refspec', category: 'transport', dependencies: [], optional: false, run: (ctx) => checkRefspec(ctx.opts) },
{ id: 'notes-push', title: 'notes push', category: 'transport', dependencies: [], optional: false, run: (ctx) => checkPush(ctx.opts) },
- { id: 'commit-msg-hook', title: 'commit-msg hook', category: 'capture', dependencies: [], optional: false, run: (ctx) => checkHook(ctx.opts, hookRuntimeOf(ctx)) },
+ { id: 'commit-msg-hook', title: 'commit-msg hook', category: 'capture', dependencies: [], optional: false, run: (ctx) => checkHook(ctx) },
{ id: 'hook-runtime', title: 'hook runtime', category: 'capture', dependencies: [], optional: false, run: hookRuntimeOf },
{ id: 'inject-runtime', title: 'PreToolUse hook runtime', category: 'delivery', dependencies: [], optional: false, run: (ctx) => checkInjectRuntime(ctx.opts) },
- { id: 'inject-version', title: 'PreToolUse hook version', category: 'delivery', dependencies: ['inject-runtime'], optional: false, run: (ctx) => checkInjectVersion(ctx.opts) },
+ { id: 'inject-version', title: 'PreToolUse hook version', category: 'delivery', dependencies: ['inject-runtime'], optional: false, run: (ctx, dependencies) => checkInjectVersion(ctx.opts, dependencies) },
{ id: 'mcp-lifecycle', title: 'MCP server sessions', category: 'delivery', dependencies: [], optional: false, run: (ctx) => checkMcpLifecycle(ctx.opts) },
{ id: 'pending-backlog', title: 'pending captures', category: 'capture', dependencies: [], optional: false, run: (ctx) => checkPendingBacklog(ctx.opts) },
{ id: 'git-trailers', title: 'git interpret-trailers', category: 'runtime', dependencies: [], optional: false, run: (ctx) => checkGit(ctx.opts) },
@@ -844,26 +1135,65 @@ export const CHECK_REGISTRY = [
* is the worst possible trade, so the throw is contained and reported as what
* it is: this check could not complete.
*/
-const containedRun = (definition, ctx) => {
+const containedRun = (definition, ctx, dependencies) => {
try {
- return definition.run(ctx);
+ return definition.run(ctx, dependencies);
}
catch (error) {
const message = error instanceof Error ? error.message : String(error);
return check(definition.id, definition.category, definition.title, 'fail', 'this check could not complete, so its subsystem is unreported', null, false, true, { evidence: { error: message.split('\n')[0] ?? 'unknown error' } });
}
};
+const statusRank = (status) => status === 'fail' ? 3 : status === 'warn' ? 2 : status === 'skipped' ? 1 : 0;
+const collapseBlockedBy = (checks) => {
+ const byId = new Map(checks.map((row) => [row.id, row]));
+ return checks.map((row) => {
+ if (row.blockedBy === undefined)
+ return row;
+ const visited = new Set([row.id]);
+ let root = byId.get(row.blockedBy);
+ while (root !== undefined && root.blockedBy !== undefined) {
+ if (visited.has(root.id)) {
+ throw new Error(`doctor check ${row.id} has a cyclic blockedBy chain`);
+ }
+ visited.add(root.id);
+ root = byId.get(root.blockedBy);
+ }
+ if (root === undefined) {
+ throw new Error(`doctor check ${row.id} names an unknown blocker`);
+ }
+ if (root.status === 'ok') {
+ throw new Error(`doctor check ${row.id} names an ok blocker`);
+ }
+ if (statusRank(row.status) > statusRank(root.status)) {
+ throw new Error(`doctor check ${row.id} is more severe than its blocker`);
+ }
+ return root.id === row.blockedBy ? row : { ...row, blockedBy: root.id };
+ });
+};
export const runDoctor = (opts = {}) => {
const ctx = { opts, now: process.hrtime.bigint, memo: new Map() };
+ const completed = new Map();
const checks = CHECK_REGISTRY.map((definition) => {
+ const dependencies = new Map();
+ for (const dependency of definition.dependencies) {
+ const row = completed.get(dependency);
+ if (row === undefined) {
+ throw new Error(`doctor check ${definition.id} depends on ${dependency}, which has not run`);
+ }
+ dependencies.set(dependency, row);
+ }
const started = ctx.now();
- const row = containedRun(definition, ctx);
+ const row = containedRun(definition, ctx, dependencies);
const elapsed = Number((ctx.now() - started) / 1000000n);
- return { ...row, durationMs: elapsed < 0 ? 0 : elapsed };
+ const timed = { ...row, durationMs: elapsed < 0 ? 0 : elapsed };
+ completed.set(definition.id, timed);
+ return timed;
});
+ const collapsed = collapseBlockedBy(checks);
return {
- checks,
- exitCode: checks.some((entry) => entry.status === 'fail') ? 1 : 0,
+ checks: collapsed,
+ exitCode: collapsed.some((entry) => entry.status === 'fail') ? 1 : 0,
};
};
const STATUS_WIDTH = 8;
diff --git a/dist/commands/doctor.js.map b/dist/commands/doctor.js.map
index f110b752..877e6702 100644
--- a/dist/commands/doctor.js.map
+++ b/dist/commands/doctor.js.map
@@ -1 +1 @@
-{"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"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"}
\ No newline at end of file
+{"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"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"}
\ No newline at end of file
diff --git a/dist/commands/inject.js b/dist/commands/inject.js
index 51d5168d..690397da 100644
--- a/dist/commands/inject.js
+++ b/dist/commands/inject.js
@@ -175,10 +175,20 @@ const hookOutput = (text) => `${JSON.stringify({
const injectOptions = (path, options, cwd) => {
const at = evaluationInstant(options.at);
const budget = tokenBudget(options.budget);
- // #415: with no flag and no configured authors this is empty, and grading
- // fails closed to `claim`. The installed hook passes no flag, so the config
- // value written at `init` is the only route to a `[directive]` in practice.
- const trustedAuthors = options.trustedAuthor ?? configuredTrustedAuthors(cwd);
+ // #415: the installed hook passes no flag, so the config value written at
+ // `init` is the only route to a `[directive]` in practice.
+ //
+ // The nullish check that used to stand here never fired. Commander declares
+ // `--trusted-author` with a default of `[]`, so `options.trustedAuthor` is an
+ // empty array rather than `undefined` when the flag is absent, `?? ` passes
+ // it through, and every record graded `claim` on every install — exactly the
+ // defect #415 was opened about, reintroduced one layer up by the fix for it.
+ //
+ // Length is the test that matches what the caller meant: an explicit flag is
+ // always non-empty, and an absent flag is always empty, whichever of the two
+ // shapes Commander hands over.
+ const flagged = options.trustedAuthor ?? [];
+ const trustedAuthors = flagged.length > 0 ? flagged : configuredTrustedAuthors(cwd);
return {
path,
cwd,
diff --git a/dist/commands/inject.js.map b/dist/commands/inject.js.map
index 6eeb2a99..69b8d646 100644
--- a/dist/commands/inject.js.map
+++ b/dist/commands/inject.js.map
@@ -1 +1 @@
-{"version":3,"file":"inject.js","sourceRoot":"","sources":["../../src/commands/inject.ts"],"names":[],"mappings":"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"}
\ No newline at end of file
+{"version":3,"file":"inject.js","sourceRoot":"","sources":["../../src/commands/inject.ts"],"names":[],"mappings":"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"}
\ No newline at end of file
diff --git a/dist/commands/query.js b/dist/commands/query.js
index bd42df08..5cd07ba9 100644
--- a/dist/commands/query.js
+++ b/dist/commands/query.js
@@ -19,6 +19,7 @@
import { BLOCKED_RECORD_WITHHELD } from '../core/grade.js';
import { LIMIT_KEY, RULED_OUT_KEY, WARN_KEY, runQuery, valuesOf, } from '../core/query.js';
import { validateRecord } from '../core/schema.js';
+import { configuredTrustedAuthors } from '../core/trusted-authors.js';
import { splitRuledOut } from '../core/trailers.js';
import { STRUCTURAL_TRAILER_KEYS } from '../core/types.js';
/** Identity is printed in its own column, never as a trailer line. */
@@ -117,10 +118,20 @@ const recordLimit = (raw) => {
const queryOptions = (paths, options, keys) => {
const at = evaluationInstant(options.at);
const limit = recordLimit(options.limit);
- // Same spelling and same default as `commitlore inject`: with no trusted
- // author, a `Warn:` grades `claim`. The two routes must answer alike, or the
- // grade means one thing on the hook and another on the terminal.
- const trustedAuthors = options.trustedAuthor ?? [];
+ // Same spelling and same resolution as `commitlore inject`: the two routes
+ // must answer alike, or the grade means one thing on the hook and another on
+ // the terminal. That sentence was already here while the two routes did in
+ // fact disagree — `inject` fell back to the configured authors and this did
+ // not, so `context` reported `claim` for a record the hook would have
+ // rendered `directive`.
+ //
+ // Length rather than nullishness, for the reason #484 records: commander
+ // declares this option with a default of `[]`, so an absent flag is an empty
+ // array and never a nullish value.
+ const flagged = options.trustedAuthor ?? [];
+ // This route has no cwd of its own; it reads the repository it was invoked
+ // in, the same one `runQuery` resolves against.
+ const trustedAuthors = flagged.length > 0 ? flagged : configuredTrustedAuthors(process.cwd());
return {
paths,
allHistory: options.allHistory === true,
diff --git a/dist/commands/query.js.map b/dist/commands/query.js.map
index c7c4908c..7242d94b 100644
--- a/dist/commands/query.js.map
+++ b/dist/commands/query.js.map
@@ -1 +1 @@
-{"version":3,"file":"query.js","sourceRoot":"","sources":["../../src/commands/query.ts"],"names":[],"mappings":"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"}
\ No newline at end of file
+{"version":3,"file":"query.js","sourceRoot":"","sources":["../../src/commands/query.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAIH,OAAO,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAC;AAC3D,OAAO,EACL,SAAS,EACT,aAAa,EACb,QAAQ,EACR,QAAQ,EACR,QAAQ,GAKT,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,EAAE,wBAAwB,EAAE,MAAM,4BAA4B,CAAC;AACtE,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,uBAAuB,EAAgC,MAAM,kBAAkB,CAAC;AAEzF,sEAAsE;AACtE,MAAM,aAAa,GAAG,WAAW,CAAC;AAElC,mFAAmF;AACnF,MAAM,eAAe,GAAG,CAAC,CAAC;AAE1B,MAAM,oBAAoB,GAAG,CAAC,CAAC;AAQ/B,MAAM,QAAQ,GAAuB;IACnC,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,EAAE,SAAS,EAAE;IACnC,EAAE,KAAK,EAAE,WAAW,EAAE,GAAG,EAAE,aAAa,EAAE;IAC1C,EAAE,KAAK,EAAE,UAAU,EAAE,GAAG,EAAE,QAAQ,EAAE;CACrC,CAAC;AAEF,MAAM,YAAY,GAAsB,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;AAE/E,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,MAAmB,EAAe,EAAE;IAClE,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,CACnC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,KAAK,SAAS,IAAI,MAAM,CAAC,mBAAmB,KAAK,SAAS,CACnF,CAAC;IACF,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,MAAM,CAAC;IAExC,MAAM,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,iBAAiB,KAAK,IAAI,CAAC,CAAC;IACjF,MAAM,gBAAgB,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,iBAAiB,KAAK,IAAI,CAAC,CAAC;IACvF,MAAM,IAAI,GAAG;QACX,GAAG,IAAI,GAAG,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,kBAAkB,IAAI,EAAE,CAAC,CAAC;KAClF,CAAC,IAAI,EAAE,CAAC;IACT,MAAM,MAAM,GACV,IAAI,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,WAAW,CAAC;IAC3G,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE;QAC5C,IAAI,MAAM,CAAC,KAAK,KAAK,SAAS,IAAI,MAAM,CAAC,mBAAmB,KAAK,SAAS;YAAE,OAAO,MAAM,CAAC;QAE1F,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC,MAAM,CACrC,CAAC,OAAO,EAAE,EAAE,CACV,uBAAuB,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,cAAc,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,KAAK,CAAC,CACrF,CAAC;QACF,MAAM,QAAQ,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,KAAK,aAAa,CAAC,EAAE,KAAK,CAAC;QAClF,MAAM,eAAe,GAAG,QAAQ,CAAC,IAAI,CACnC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,KAAK,YAAY,CAC1C,EAAE,KAAK,CAAC;QACT,MAAM,EACJ,QAAQ,EAAE,eAAe,EACzB,eAAe,EAAE,sBAAsB,EACvC,SAAS,EAAE,gBAAgB,EAC3B,GAAG,UAAU,EACd,GAAG,MAAM,CAAC;QAEX,OAAO;YACL,GAAG,UAAU;YACb,GAAG,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC;YAC/C,GAAG,CAAC,eAAe,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,eAAe,EAAE,CAAC;YAC7D,mBAAmB,EAAE;gBACnB,GAAG,IAAI,GAAG,CACR,MAAM,CAAC,QAAQ;qBACZ,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;qBAChD,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CACjC;aACF;YACD,QAAQ;SACT,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,OAAO;QACL,GAAG,MAAM;QACT,OAAO;QACP,WAAW,EAAE;YACX,GAAG,MAAM,CAAC,WAAW;YACrB,GAAG,CAAC,gBAAgB,CAAC,MAAM,KAAK,CAAC;gBAC/B,CAAC,CAAC,EAAE;gBACJ,CAAC,CAAC;oBACE,2BAA2B,gBAAgB,CAAC,MAAM,gCAAgC,MAAM,eAAe;wBACrG,uDAAuD;iBAC1D,CAAC;YACN,GAAG,CAAC,UAAU,CAAC,MAAM,KAAK,CAAC;gBACzB,CAAC,CAAC,EAAE;gBACJ,CAAC,CAAC;oBACE,6DAA6D;oBAC7D,gEAAgE;oBAChE,2DAA2D;oBAC3D,2DAA2D;oBAC3D,wCAAwC;oBACxC,2BAA2B,UAAU,CAAC,MAAM,yCAAyC;wBACnF,iEAAiE;iBACpE,CAAC;SACP;KACF,CAAC;AACJ,CAAC,CAAC;AAaF,mEAAmE;AACnE,MAAM,OAAO,GAAG,CAAC,KAAa,EAAE,QAAkB,EAAY,EAAE,CAAC,CAAC,GAAG,QAAQ,EAAE,KAAK,CAAC,CAAC;AAEtF,8EAA8E;AAC9E,iBAAiB;AACjB,8EAA8E;AAE9E;;;;GAIG;AACH,MAAM,iBAAiB,GAAG,CAAC,GAAuB,EAAoB,EAAE;IACtE,IAAI,GAAG,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IACxC,MAAM,MAAM,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC;IAC7B,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC;QACnC,MAAM,IAAI,KAAK,CAAC,yCAAyC,GAAG,EAAE,CAAC,CAAC;IAClE,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC,CAAC;AAEF,MAAM,WAAW,GAAG,CAAC,GAAuB,EAAsB,EAAE;IAClE,IAAI,GAAG,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IACxC,MAAM,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;IAC3B,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,MAAM,GAAG,CAAC,EAAE,CAAC;QAC5C,MAAM,IAAI,KAAK,CAAC,0CAA0C,GAAG,EAAE,CAAC,CAAC;IACnE,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC,CAAC;AAEF,MAAM,YAAY,GAAG,CACnB,KAAe,EACf,OAA4B,EAC5B,IAAmC,EACrB,EAAE;IAChB,MAAM,EAAE,GAAG,iBAAiB,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IACzC,MAAM,KAAK,GAAG,WAAW,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IACzC,2EAA2E;IAC3E,6EAA6E;IAC7E,2EAA2E;IAC3E,4EAA4E;IAC5E,sEAAsE;IACtE,wBAAwB;IACxB,EAAE;IACF,yEAAyE;IACzE,6EAA6E;IAC7E,mCAAmC;IACnC,MAAM,OAAO,GAAG,OAAO,CAAC,aAAa,IAAI,EAAE,CAAC;IAC5C,2EAA2E;IAC3E,gDAAgD;IAChD,MAAM,cAAc,GAAG,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,wBAAwB,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;IAC9F,OAAO;QACL,KAAK;QACL,UAAU,EAAE,OAAO,CAAC,UAAU,KAAK,IAAI;QACvC,OAAO,EAAE,OAAO,CAAC,KAAK,KAAK,KAAK;QAC9B,2EAA2E;QAC3E,0EAA0E;QAC1E,qEAAqE;QACrE,kBAAkB,EAAE,IAAI;QAC1B,GAAG,CAAC,cAAc,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,CAAC;QAC1D,GAAG,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC;QACvC,GAAG,CAAC,EAAE,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC;QACnC,GAAG,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC;KAC1C,CAAC;AACJ,CAAC,CAAC;AAwDF,MAAM,aAAa,GAAG,CAAC,MAAoB,EAAa,EAAE,CACxD,MAAM,CAAC,QAAQ,CAAC,MAAM,CACpB,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,KAAK,aAAa,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,CAClF,CAAC;AAEJ,MAAM,QAAQ,GAAG,CAAC,OAAgC,EAAE,GAAW,EAAU,EAAE,CACzE,OAAO,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,CAAC,KAAK,GAAG,QAAQ,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;AAE7E,MAAM,YAAY,GAAG,CAAC,MAAoB,EAAc,EAAE,CAAC,CAAC;IAC1D,QAAQ,EAAE,MAAM,CAAC,QAAQ,IAAI,IAAI;IACjC,GAAG,EAAE,MAAM,CAAC,GAAG;IACf,IAAI,EAAE,MAAM,CAAC,IAAI;IACjB,WAAW,EAAE,MAAM,CAAC,WAAW;IAC/B,MAAM,EAAE,MAAM,CAAC,MAAM;IACrB,OAAO,EAAE,MAAM,CAAC,OAAO;IACvB,SAAS,EAAE,MAAM,CAAC,SAAS;IAC3B,KAAK,EAAE,MAAM,CAAC,KAAK;IACnB,KAAK,EAAE,MAAM,CAAC,KAAK,IAAI,IAAI;IAC3B,iBAAiB,EAAE,MAAM,CAAC,iBAAiB,KAAK,IAAI;IACpD,UAAU,EAAE,MAAM,CAAC,eAAe,IAAI,IAAI;IAC1C,YAAY,EAAE,MAAM,CAAC,YAAY,IAAI,IAAI;IACzC,SAAS,EAAE,MAAM,CAAC,SAAS,IAAI,IAAI;IACnC,KAAK,EAAE,MAAM,CAAC,KAAK;IACnB,QAAQ,EAAE,MAAM,CAAC,QAAQ;CAC1B,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,OAAe,EAAE,MAAmB,EAAc,EAAE;IACzE,MAAM,SAAS,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC;IAC1C,OAAO;QACL,OAAO;QACP,EAAE,EAAE,SAAS,CAAC,EAAE,CAAC,WAAW,EAAE;QAC9B,KAAK,EAAE,SAAS,CAAC,KAAK;QACtB,OAAO,EAAE,SAAS,CAAC,OAAO;QAC1B,MAAM,EAAE,SAAS,CAAC,MAAM;QACxB,SAAS,EAAE,SAAS,CAAC,SAAS;QAC9B,OAAO,EAAE,SAAS,CAAC,OAAO;QAC1B,MAAM,EAAE;YACN,OAAO,EAAE,SAAS,CAAC,OAAO,CAAC,MAAM;YACjC,MAAM,EAAE,QAAQ,CAAC,SAAS,CAAC,OAAO,EAAE,SAAS,CAAC;YAC9C,QAAQ,EAAE,QAAQ,CAAC,SAAS,CAAC,OAAO,EAAE,aAAa,CAAC;YACpD,QAAQ,EAAE,QAAQ,CAAC,SAAS,CAAC,OAAO,EAAE,QAAQ,CAAC;YAC/C,KAAK,EAAE,SAAS,CAAC,OAAO,CAAC,MAAM,CAC7B,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,CAAC,KAAK,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC,MAAM,EACvD,CAAC,CACF;SACF;QACD,OAAO,EAAE,SAAS,CAAC,OAAO;QAC1B,KAAK,EAAE,SAAS,CAAC,KAAK;QACtB,WAAW,EAAE,SAAS,CAAC,WAAW;QAClC,OAAO,EAAE,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC;KAC7C,CAAC;AACJ,CAAC,CAAC;AAEF,8EAA8E;AAC9E,OAAO;AACP,8EAA8E;AAE9E,MAAM,QAAQ,GAAG,CAAC,GAAW,EAAU,EAAE,CAAC,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;AAEnF,MAAM,WAAW,GAAG,CAAC,MAAmB,EAAU,EAAE,CAClD,MAAM,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;AAErE;;;;GAIG;AACH,MAAM,gBAAgB,GAAG,CAAC,MAAmB,EAAU,EAAE,CACvD,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU,KAAK,MAAM,CAAC,OAAO,2BAA2B,CAAC;AAE3F,MAAM,MAAM,GAAG,CAAC,KAAa,EAAE,GAAW,EAAE,IAAY,EAAU,EAAE,CAClE,GAAG,KAAK,IAAI,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;AAEzC;;;;GAIG;AACH,MAAM,QAAQ,GAAG,CAAC,MAAoB,EAAU,EAAE;IAChD,MAAM,IAAI,GAAG;QACX,GAAG,CAAC,MAAM,CAAC,SAAS,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAC5D,GAAG,MAAM,CAAC,KAAK;KAChB,CAAC;IACF,OAAO,IAAI,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC;AAC3D,CAAC,CAAC;AAEF,MAAM,QAAQ,GAAG,CAAC,MAAoB,EAAU,EAAE,CAChD,MAAM,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,MAAM,CAAC,KAAK,KAAK,CAAC;AAE1D,MAAM,cAAc,GAAG,CAAC,MAAoB,EAAU,EAAE,CACtD,MAAM,CAAC,iBAAiB,KAAK,IAAI;IAC/B,CAAC,CAAC,6DAA6D;IAC/D,CAAC,CAAC,uBAAuB,CAAC;AAE9B,MAAM,QAAQ,GAAG,CAAC,MAAoB,EAAE,KAAa,EAAU,EAAE,CAC/D,CAAC,MAAM,CAAC,QAAQ,IAAI,GAAG,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAEzC,MAAM,OAAO,GAAG,CAAC,OAAgC,EAAU,EAAE,CAC3D,OAAO,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,MAAM,CAAC,QAAQ,IAAI,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;AAEzF;;;;;;;;GAQG;AACH,MAAM,aAAa,GAAG,CAAC,GAAW,EAAE,KAAa,EAAU,EAAE;IAC3D,IAAI,GAAG,KAAK,aAAa;QAAE,OAAO,EAAE,CAAC;IACrC,MAAM,KAAK,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC;IACnC,IAAI,CAAC,KAAK,CAAC,SAAS;QAAE,OAAO,EAAE,CAAC;IAChC,OAAO,uCAAuC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC;AACrF,CAAC,CAAC;AAEF;;;;;GAKG;AACH,MAAM,UAAU,GAAG,CACjB,OAAgC,EAChC,GAAW,EACD,EAAE;IACZ,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC/B,OAAO,OAAO,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,EAAE;QAChC,MAAM,QAAQ,GAAG,MAAM,CAAC,KAAK,KAAK,SAAS,CAAC;QAC5C,MAAM,MAAM,GAAG,QAAQ;YACrB,CAAC,CAAC,MAAM,CAAC,mBAAmB,EAAE,QAAQ,CAAC,GAAG,CAAC,KAAK,IAAI;gBAClD,CAAC,CAAC,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC;gBAC1B,CAAC,CAAC,EAAE;YACN,CAAC,CAAC,QAAQ,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QAC1B,OAAO,MAAM,CAAC,GAAG,CACf,CAAC,KAAK,EAAE,EAAE,CACR,KAAK,QAAQ,CAAC,MAAM,EAAE,KAAK,CAAC,KAAK,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI;YACzD,GAAG,QAAQ,CAAC,MAAM,CAAC,GAAG,QAAQ,CAAC,MAAM,CAAC,GAAG,KAAK,EAAE;YAChD,mEAAmE;YACnE,+CAA+C;YAC/C,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC,CAC9C,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC,CAAC;AAEF,MAAM,UAAU,GAAG,CAAC,OAAgC,EAAY,EAAE;IAChE,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC/B,OAAO,OAAO,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,EAAE;QAChC,MAAM,QAAQ,GACZ,MAAM,CAAC,KAAK,KAAK,SAAS;YAC1B,MAAM,CAAC,mBAAmB,EAAE,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,YAAY,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,KAAK,IAAI;YAC7E,CAAC,CAAC,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC;YAC1B,CAAC,CAAC,EAAE,CAAC;QACT,MAAM,MAAM,GAAG;YACb,GAAG,QAAQ;YACX,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,GAAG,OAAO,CAAC,GAAG,KAAK,OAAO,CAAC,KAAK,EAAE,CAAC;SAC9E,CAAC;QACF,OAAO,MAAM,CAAC,GAAG,CACf,CAAC,KAAK,EAAE,EAAE,CACR,KAAK,QAAQ,CAAC,MAAM,EAAE,KAAK,CAAC,KAAK,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI;YACzD,GAAG,QAAQ,CAAC,MAAM,CAAC,GAAG,QAAQ,CAAC,MAAM,CAAC,GAAG,KAAK,EAAE,CACnD,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC,CAAC;AAEF;;;;;;;;;GASG;AACH,MAAM,SAAS,GAAG,CAAC,MAAmB,EAAE,IAAY,EAAU,EAAE,CAC9D,MAAM,CAAC,OAAO,KAAK,aAAa;IAC9B,CAAC,CAAC,mEAAmE,IAAI,GAAG,WAAW,CAAC,MAAM,CAAC,KAAK;QAClG,8BAA8B;IAChC,CAAC,CAAC,MAAM,CAAC,KAAK,KAAK,WAAW;QAC9B,CAAC,CAAC,aAAa,IAAI,GAAG,WAAW,CAAC,MAAM,CAAC,uCAAuC;YAC9E,mFAAmF;QACrF,CAAC,CAAC,aAAa,IAAI,GAAG,WAAW,CAAC,MAAM,CAAC,IAAI,CAAC;AAElD,0EAA0E;AAC1E,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,MAAmB,EAAE,OAAgB,EAAU,EAAE;IAC1E,MAAM,SAAS,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC;IAC1C,MAAM,KAAK,GAAG,UAAU,CAAC,SAAS,CAAC,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC;IACzD,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC,SAAS,EAAE,GAAG,OAAO,CAAC,GAAG,UAAU,CAAC,CAAC;IAE9E,MAAM,MAAM,GACV,GAAG,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,EAAE,OAAO,CAAC,KAAK,CAAC,EAAE;QACzE,GAAG,WAAW,CAAC,SAAS,CAAC,UAAU,SAAS,CAAC,EAAE,CAAC,WAAW,EAAE,KAAK,gBAAgB,CAAC,SAAS,CAAC,GAAG,CAAC;IACnG,OAAO,GAAG,CAAC,MAAM,EAAE,EAAE,EAAE,GAAG,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;AAClD,CAAC,CAAC;AAEF;;;;GAIG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,MAAmB,EAAU,EAAE;IAC3D,MAAM,SAAS,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC;IAC1C,MAAM,QAAQ,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;QAC1C,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,KAAK,EAAE,UAAU,CAAC,SAAS,CAAC,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC;KAClD,CAAC,CAAC,CAAC;IACJ,MAAM,KAAK,GAAG,UAAU,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;IAC5C,MAAM,KAAK,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,OAAO,EAAE,EAAE,CAAC,GAAG,GAAG,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC;IAE9F,IAAI,KAAK,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;IAExD,MAAM,OAAO,GAAG;QACd,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,MAAM,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;QACxE,GAAG,KAAK,CAAC,MAAM,QAAQ;KACxB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAEb,MAAM,MAAM,GACV,UAAU,WAAW,CAAC,SAAS,CAAC,UAAU,SAAS,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,OAAO,GAAG;QACpF,MAAM,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,MAAM,EAAE,QAAQ,EAAE,SAAS,CAAC,KAAK,gBAAgB,CAAC,SAAS,CAAC,GAAG,CAAC;IAEjG,MAAM,IAAI,GAAG,CAAC,GAAG,QAAQ,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAC/E,OAAO,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,OAAO,CAAC,KAAK,EAAE,GAAG,OAAO,CAAC,KAAK,CAAC,CACxE,CAAC;IAEF,OAAO,GAAG,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;AAC7C,CAAC,CAAC;AAEF,8EAA8E;AAC9E,eAAe;AACf,8EAA8E;AAE9E,MAAM,IAAI,GAAG,CACX,IAAY,EACZ,MAAmB,EACnB,OAA4B,EAC5B,MAAuC,EACjC,EAAE;IACR,MAAM,SAAS,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC;IAC1C,2EAA2E;IAC3E,4EAA4E;IAC5E,KAAK,MAAM,UAAU,IAAI,SAAS,CAAC,WAAW,EAAE,CAAC;QAC/C,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,eAAe,UAAU,IAAI,CAAC,CAAC;IACtD,CAAC;IACD,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,OAAO,CAAC,IAAI,KAAK,IAAI;QACnB,CAAC,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,EAAE,SAAS,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI;QACzD,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CACtB,CAAC;IACF,uEAAuE;IACvE,oEAAoE;IACpE,6EAA6E;IAC7E,IAAI,SAAS,CAAC,OAAO,KAAK,aAAa;QAAE,OAAO,CAAC,QAAQ,GAAG,eAAe,CAAC;SACvE,IAAI,SAAS,CAAC,KAAK,KAAK,WAAW;QAAE,OAAO,CAAC,QAAQ,GAAG,oBAAoB,CAAC;AACpF,CAAC,CAAC;AAEF,MAAM,MAAM,GAAG,CACb,OAAgB,EAChB,IAAY,EACZ,WAAmB,EACnB,IAAmC,EACnC,MAAuC,EACjC,EAAE;IACR,OAAO;SACJ,OAAO,CAAC,IAAI,CAAC;SACb,WAAW,CAAC,WAAW,CAAC;SACxB,QAAQ,CAAC,YAAY,EAAE,yDAAyD,CAAC;SACjF,MAAM,CAAC,QAAQ,EAAE,yBAAyB,CAAC;SAC3C,MAAM,CAAC,eAAe,EAAE,uDAAuD,CAAC;SAChF,MAAM,CAAC,YAAY,EAAE,iDAAiD,CAAC;SACvE,MAAM,CAAC,gBAAgB,EAAE,mDAAmD,CAAC;SAC7E,MAAM,CAAC,aAAa,EAAE,0BAA0B,CAAC;SACjD,MAAM,CACL,2BAA2B,EAC3B,iEAAiE,EACjE,OAAO,EACP,EAAE,CACH;SACA,WAAW,CACV,OAAO,EACP,mGAAmG;QACjG,mEAAmE,CACtE;SACA,MAAM,CAAC,CAAC,KAAe,EAAE,OAA4B,EAAE,EAAE;QACxD,IAAI,CAAC;YACH,IAAI,CAAC,IAAI,EAAE,QAAQ,CAAC,YAAY,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;QAC5E,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,eAAe,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAC1E,CAAC;YACF,OAAO,CAAC,QAAQ,GAAG,eAAe,CAAC;QACrC,CAAC;IACH,CAAC,CAAC,CAAC;AACP,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,OAAgB,EAAQ,EAAE;IACjD,MAAM,CACJ,OAAO,EACP,SAAS,EACT,6EAA6E,EAC7E,SAAS,EACT,aAAa,CACd,CAAC;IACF,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,MAAM,CACJ,OAAO,EACP,OAAO,CAAC,KAAK,EACb,cAAc,OAAO,CAAC,GAAG,sBAAsB,EAC/C,CAAC,OAAO,CAAC,GAAG,CAAC,EACb,CAAC,MAAM,EAAE,EAAE,CAAC,UAAU,CAAC,MAAM,EAAE,OAAO,CAAC,CACxC,CAAC;IACJ,CAAC;AACH,CAAC,CAAC"}
\ No newline at end of file
diff --git a/dist/commitlore.mjs b/dist/commitlore.mjs
index d67298a9..45741add 100755
--- a/dist/commitlore.mjs
+++ b/dist/commitlore.mjs
@@ -17249,8 +17249,36 @@ var EXACT_NOTES_REFSPEC = `+${NOTES_REF}:${NOTES_REF}`;
var EXACT_NOTES_REFSPEC_PATTERN = `^\\${EXACT_NOTES_REFSPEC}$`;
var escapeConfigValuePattern = (value) => value.replace(/[\\.*+?[\]^$(){}|]/g, (character) => `\\${character}`);
var gitOptions3 = (opts) => opts.cwd === void 0 ? {} : { cwd: opts.cwd };
+var boundedExcerpt = (output) => {
+ const [firstLine5 = ""] = (output ?? "").split(/\r?\n/, 1);
+ return {
+ firstLine: firstLine5.slice(0, 200),
+ truncated: firstLine5.length > 200 ? "true" : "false"
+ };
+};
+var streamEvidence = (stream, output) => {
+ const excerpt = boundedExcerpt(output);
+ return {
+ [`${stream}_first_line`]: excerpt.firstLine,
+ [`${stream}_truncated`]: excerpt.truncated
+ };
+};
+var homeRelativePath = (value) => {
+ const home = process.env["HOME"];
+ if (home === void 0 || home === "") return value;
+ const escapedHome = home.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
+ return value.replace(new RegExp(`${escapedHome}(?=$|/)`, "g"), "~");
+};
+var normaliseEvidence = (evidence) => Object.fromEntries(
+ Object.entries(evidence).map(([key, value]) => [key, homeRelativePath(value)])
+);
+var evidenceKey = (value) => value.replace(/[^A-Za-z0-9]+/g, "_").replace(/^_+|_+$/g, "").toLowerCase() || "remote";
var severityOf = (status) => status === "fail" ? "error" : status === "warn" ? "warning" : "info";
function check(id, category, title, status, detail, fix = null, fixed = false, needsAttention = status === "warn" || status === "fail", extra = {}) {
+ const evidence = extra.evidence ?? {};
+ if (Object.keys(evidence).length === 0) {
+ throw new Error(`doctor check ${id} has no evidence`);
+ }
return {
id,
title,
@@ -17261,14 +17289,21 @@ function check(id, category, title, status, detail, fix = null, fixed = false, n
fixed,
category,
severity: severityOf(status),
- evidence: extra.evidence ?? {},
+ evidence: normaliseEvidence(evidence),
optional: extra.optional ?? false,
...extra.skipReason === void 0 ? {} : { skipReason: extra.skipReason }
};
}
+var blocked = (dependency, row) => {
+ if (dependency.status === "ok") {
+ throw new Error(`doctor check ${row.id} cannot repeat an ok finding`);
+ }
+ return { ...row, blockedBy: dependency.id };
+};
var checkRefspec = (opts) => {
const title = "notes fetch refspec";
const remotes = listRemotes(opts);
+ const remoteEvidence = { remotes: remotes.join(", ") || "none" };
if (remotes.length === 0) {
return check(
"notes-refspec",
@@ -17278,7 +17313,8 @@ var checkRefspec = (opts) => {
"no remote is configured, so records cannot be shared with anyone",
"add a remote, then rerun: commitlore doctor --fix",
false,
- false
+ false,
+ { evidence: remoteEvidence }
);
}
let missing = remotes.filter((remote) => !fetchRefspecs(remote, opts).some(coversNotes));
@@ -17318,7 +17354,9 @@ var checkRefspec = (opts) => {
"warn",
`${forced.join(", ")} fetches ${NOTES_REF} with a forced refspec, so an ordinary git fetch overwrites this clone's mirror \u2014 a record written here and not yet pushed is destroyed silently`,
forced.map((remote) => `git config --replace-all remote.${remote}.fetch '${NOTES_REFSPEC}' '^\\+refs/notes/'`).join("\n"),
- fixed
+ fixed,
+ void 0,
+ { evidence: { ...remoteEvidence, forced: forced.join(", ") } }
);
}
if (missing.length > 0) {
@@ -17328,7 +17366,10 @@ var checkRefspec = (opts) => {
title,
"warn",
`${missing.join(", ")} does not fetch ${NOTES_REF}, so records pushed by others stay invisible here`,
- missing.map((remote) => `git config --add remote.${remote}.fetch '${NOTES_REFSPEC}'`).join("\n")
+ missing.map((remote) => `git config --add remote.${remote}.fetch '${NOTES_REFSPEC}'`).join("\n"),
+ false,
+ void 0,
+ { evidence: { ...remoteEvidence, missing: missing.join(", ") } }
);
}
const failed = remotes.map((remote) => ({ remote, result: execGit(["fetch", "--dry-run", remote], gitOptions3(opts)) })).filter(({ result }) => result.code !== 0);
@@ -17340,7 +17381,19 @@ var checkRefspec = (opts) => {
"warn",
`could not verify (${failed.map(({ remote, result }) => `${remote}: ${result.stderr.trim().split("\n")[0] ?? "git fetch failed"}`).join("; ")})`,
failed.map(({ remote }) => `git fetch ${remote}`).join("\n"),
- fixed
+ fixed,
+ void 0,
+ {
+ evidence: {
+ ...remoteEvidence,
+ ...Object.fromEntries(
+ failed.map(({ remote, result }) => [
+ `fetch_exit_code_${evidenceKey(remote)}`,
+ String(result.code)
+ ])
+ )
+ }
+ }
);
}
return check(
@@ -17350,7 +17403,9 @@ var checkRefspec = (opts) => {
"ok",
fixed ? `${NOTES_REF} is now covered for ${remotes.join(", ")} \u2014 nothing has been fetched through it yet` : `git fetch succeeds for ${remotes.join(", ")} and covers ${NOTES_REF}`,
fixed ? `git fetch ${remotes[0] ?? "origin"}` : null,
- fixed
+ fixed,
+ void 0,
+ { evidence: remoteEvidence }
);
};
var checkPush = (opts) => {
@@ -17359,13 +17414,21 @@ var checkPush = (opts) => {
const remote = remotes[0] ?? "origin";
const command = `git push ${remote} ${NOTES_REF}`;
const local = execGit(["rev-parse", "--verify", "--quiet", NOTES_REF], gitOptions3(opts));
+ const localEvidence = {
+ remote,
+ local_sha: local.code === 0 ? local.stdout.trim() || "unknown" : "none"
+ };
if (local.code !== 0) {
return check(
"notes-push",
"transport",
title,
"ok",
- `no local mirror yet \u2014 nothing to push (${command}, once there is)`
+ `no local mirror yet \u2014 nothing to push (${command}, once there is)`,
+ null,
+ false,
+ void 0,
+ { evidence: { ...localEvidence, remote_sha: "not_queried" } }
);
}
const advertised = execGit(["ls-remote", remote, NOTES_REF], gitOptions3(opts));
@@ -17376,11 +17439,31 @@ var checkPush = (opts) => {
title,
"warn",
`could not verify (${remote}: ${advertised.stderr.trim().split("\n")[0] ?? "git ls-remote failed"})`,
- command
+ command,
+ false,
+ void 0,
+ {
+ evidence: {
+ ...localEvidence,
+ ls_remote_exit_code: String(advertised.code),
+ ...streamEvidence("ls_remote_stderr", advertised.stderr)
+ }
+ }
);
}
- if (advertised.stdout.split(/\s/)[0] === local.stdout.trim()) {
- return check("notes-push", "transport", title, "ok", `${remote} has the current ${NOTES_REF}`);
+ const remoteSha = advertised.stdout.split(/\s/)[0] ?? "";
+ if (remoteSha === local.stdout.trim()) {
+ return check(
+ "notes-push",
+ "transport",
+ title,
+ "ok",
+ `${remote} has the current ${NOTES_REF}`,
+ null,
+ false,
+ void 0,
+ { evidence: { ...localEvidence, remote_sha: remoteSha || "none" } }
+ );
}
return check(
"notes-push",
@@ -17388,27 +17471,57 @@ var checkPush = (opts) => {
title,
"warn",
`this clone has local records in ${NOTES_REF}; no command pushes them for you`,
- command
+ command,
+ false,
+ void 0,
+ { evidence: { ...localEvidence, remote_sha: remoteSha || "none" } }
);
};
-var checkHook = (opts, runtime) => {
+var checkHook = (ctx) => {
+ const { opts } = ctx;
const title = "commit-msg hook";
const id = "commit-msg-hook";
const category = "capture";
const install = "commitlore hooks install";
const located = execGit(["rev-parse", "--git-path", "hooks/commit-msg"], gitOptions3(opts));
if (located.code !== 0) {
- return check(id, category, title, "warn", "not inside a git repository", install);
+ return check(
+ id,
+ category,
+ title,
+ "warn",
+ "not inside a git repository",
+ install,
+ false,
+ void 0,
+ { evidence: { hook_path: "unavailable", bin: "not_recorded", node: "not_recorded" } }
+ );
}
const path2 = resolve6(opts.cwd ?? process.cwd(), located.stdout.trim());
const target = readRecordedHookTarget(opts.cwd ?? process.cwd());
const override = process.env["COMMITLORE_BIN"];
+ const hookEvidence = {
+ hook_path: path2,
+ bin: target.bin || "(unset)",
+ node: target.node || "(unset)",
+ ...override === void 0 || override === "" ? {} : { commitlore_bin_override: override }
+ };
const targetDetail = [
...describeRecordedHookTarget(target),
...override === void 0 || override === "" ? [] : [`COMMITLORE_BIN: ${override}`]
].join("; ");
if (!existsSync7(path2)) {
- return check(id, category, title, "warn", `no commit-msg hook at ${path2}; ${targetDetail}`, install);
+ return check(
+ id,
+ category,
+ title,
+ "warn",
+ `no commit-msg hook at ${path2}; ${targetDetail}`,
+ install,
+ false,
+ void 0,
+ { evidence: hookEvidence }
+ );
}
const contents = readFileSync10(path2, "utf8");
if (!contents.includes(HOOK_MARKER)) {
@@ -17418,7 +17531,10 @@ var checkHook = (opts, runtime) => {
title,
"warn",
`a commit-msg hook exists at ${path2} but does not invoke commitlore; ${targetDetail}`,
- install
+ install,
+ false,
+ void 0,
+ { evidence: hookEvidence }
);
}
if (contents !== commitMsgStub()) {
@@ -17428,7 +17544,10 @@ var checkHook = (opts, runtime) => {
title,
"warn",
`installed at ${path2}, but the stub is out of date \u2014 it predates a change to how the hook finds the CLI; ${targetDetail}`,
- install
+ install,
+ false,
+ void 0,
+ { evidence: hookEvidence }
);
}
const problems = [
@@ -17437,24 +17556,64 @@ var checkHook = (opts, runtime) => {
"COMMITLORE_BIN override is active, but is not a .js or .mjs file \u2014 the hook ignores it and falls through to the remaining resolution steps"
]
];
+ const runtime = hookRuntimeOf(ctx);
if (runtime.status !== "ok") {
const inherited = `installed at ${path2}; ${targetDetail}; outcome: ${runtime.detail}`;
if (runtime.status === "skipped") {
- return check(
+ return blocked(
+ runtime,
+ check(
+ id,
+ category,
+ title,
+ "skipped",
+ inherited,
+ install,
+ false,
+ false,
+ {
+ evidence: { ...hookEvidence, runtime_status: runtime.status },
+ skipReason: runtime.skipReason ?? "nothing_applicable"
+ }
+ )
+ );
+ }
+ return blocked(
+ runtime,
+ check(
id,
category,
title,
- "skipped",
+ runtime.status,
inherited,
install,
false,
- false,
- { skipReason: runtime.skipReason ?? "nothing_applicable" }
- );
- }
- return check(id, category, title, runtime.status, inherited, install);
+ void 0,
+ { evidence: { ...hookEvidence, runtime_status: runtime.status } }
+ )
+ );
}
- return problems.length === 0 ? check(id, category, title, "ok", `installed at ${path2}; ${targetDetail}`) : check(id, category, title, "warn", `installed at ${path2}; ${targetDetail}; ${problems.join("; ")}`, install);
+ return problems.length === 0 ? check(
+ id,
+ category,
+ title,
+ "ok",
+ `installed at ${path2}; ${targetDetail}`,
+ null,
+ false,
+ void 0,
+ { evidence: hookEvidence }
+ ) : check(
+ id,
+ category,
+ title,
+ "warn",
+ `installed at ${path2}; ${targetDetail}; ${problems.join("; ")}`,
+ install,
+ false,
+ void 0,
+ { evidence: hookEvidence }
+ );
};
var checkGit = (opts) => {
const title = "git interpret-trailers";
@@ -17467,13 +17626,43 @@ var checkGit = (opts) => {
trailers = parseCommitMessage(PROBE_MESSAGE);
} catch (error2) {
const reason = error2 instanceof Error ? error2.message : String(error2);
- return check(id, category, title, "fail", `${version2 || "git"} could not parse a probe: ${reason}`, upgrade);
+ return check(
+ id,
+ category,
+ title,
+ "fail",
+ `${version2 || "git"} could not parse a probe: ${reason}`,
+ upgrade,
+ false,
+ void 0,
+ { evidence: { git_version: version2 || "unavailable", parsed: "unavailable" } }
+ );
}
const parsed = trailers.map((trailer) => `${trailer.key}: ${trailer.value}`).join(", ");
if (parsed !== "Limit: probe, Blast: local") {
- return check(id, category, title, "fail", `${version2} parsed the probe as [${parsed}]`, upgrade);
+ return check(
+ id,
+ category,
+ title,
+ "fail",
+ `${version2} parsed the probe as [${parsed}]`,
+ upgrade,
+ false,
+ void 0,
+ { evidence: { git_version: version2 || "unavailable", parsed } }
+ );
}
- return check(id, category, title, "ok", `${version2} parses trailers as the spec expects`);
+ return check(
+ id,
+ category,
+ title,
+ "ok",
+ `${version2} parses trailers as the spec expects`,
+ null,
+ false,
+ void 0,
+ { evidence: { git_version: version2 || "unavailable", parsed } }
+ );
};
var checkRuntime = (opts) => {
const title = "cli runtime";
@@ -17488,7 +17677,16 @@ var checkRuntime = (opts) => {
title,
"fail",
`no built CLI at ${candidates.join(" or ")} \u2014 this checkout has not been built`,
- "npm install && npm run build"
+ "npm install && npm run build",
+ false,
+ void 0,
+ {
+ evidence: {
+ entry: candidates.join(" or "),
+ exit_code: "not_run",
+ ...streamEvidence("stderr", "")
+ }
+ }
);
}
const run = spawnSync3(process.execPath, [entry, "--version"], {
@@ -17497,13 +17695,62 @@ var checkRuntime = (opts) => {
...gitOptions3(opts)
});
if (run.error !== void 0) {
- return check(id, category, title, "fail", `could not run ${entry}: ${run.error.message}`, null);
+ return check(
+ id,
+ category,
+ title,
+ "fail",
+ `could not run ${entry}: ${run.error.message}`,
+ null,
+ false,
+ void 0,
+ {
+ evidence: {
+ entry,
+ exit_code: String(run.status ?? "unavailable"),
+ error: run.error.message,
+ ...streamEvidence("stderr", run.stderr)
+ }
+ }
+ );
}
if (run.status !== 0) {
const detail = `${run.stderr ?? ""}`.trim().split("\n")[0] ?? `exit ${String(run.status)}`;
- return check(id, category, title, "fail", `${entry} exits ${String(run.status)}: ${detail}`, "npm install");
+ return check(
+ id,
+ category,
+ title,
+ "fail",
+ `${entry} exits ${String(run.status)}: ${detail}`,
+ "npm install",
+ false,
+ void 0,
+ {
+ evidence: {
+ entry,
+ exit_code: String(run.status),
+ ...streamEvidence("stderr", run.stderr)
+ }
+ }
+ );
}
- return check(id, category, title, "ok", `${entry} runs (${run.stdout.trim()})`);
+ return check(
+ id,
+ category,
+ title,
+ "ok",
+ `${entry} runs (${run.stdout.trim()})`,
+ null,
+ false,
+ void 0,
+ {
+ evidence: {
+ entry,
+ version: boundedExcerpt(run.stdout).firstLine,
+ ...streamEvidence("stdout", run.stdout)
+ }
+ }
+ );
};
var checkHookRuntime = (opts) => {
const title = "hook runtime";
@@ -17512,9 +17759,39 @@ var checkHookRuntime = (opts) => {
const fix = "commitlore hooks install";
const cwd = opts.cwd ?? process.cwd();
const located = execGit(["rev-parse", "--git-path", "hooks/commit-msg"], gitOptions3(opts));
- if (located.code !== 0) return check(id, category, title, "warn", "not inside a git repository", fix);
+ if (located.code !== 0) {
+ return check(
+ id,
+ category,
+ title,
+ "warn",
+ "not inside a git repository",
+ fix,
+ false,
+ void 0,
+ {
+ evidence: {
+ hook_path: "unavailable",
+ exit_code: String(located.code),
+ ...streamEvidence("stderr", located.stderr)
+ }
+ }
+ );
+ }
const hook = resolve6(cwd, located.stdout.trim());
- if (!existsSync7(hook)) return check(id, category, title, "ok", "no hook installed \u2014 nothing to run");
+ if (!existsSync7(hook)) {
+ return check(
+ id,
+ category,
+ title,
+ "ok",
+ "no hook installed \u2014 nothing to run",
+ null,
+ false,
+ void 0,
+ { evidence: { hook_path: hook } }
+ );
+ }
const probe = join6(tmpdirPath(), `commitlore-doctor-${String(process.pid)}.txt`);
try {
writeFileSync5(probe, PROBE_MESSAGE);
@@ -17527,7 +17804,24 @@ var checkHookRuntime = (opts) => {
env: { PATH: "/usr/bin:/bin", HOME: process.env["HOME"] ?? "" }
});
if (run.error !== void 0) {
- return check(id, category, title, "fail", `could not run the hook: ${run.error.message}`, fix);
+ return check(
+ id,
+ category,
+ title,
+ "fail",
+ `could not run the hook: ${run.error.message}`,
+ fix,
+ false,
+ void 0,
+ {
+ evidence: {
+ hook_path: hook,
+ exit_code: String(run.status ?? "unavailable"),
+ error: run.error.message,
+ ...streamEvidence("stderr", run.stderr)
+ }
+ }
+ );
}
if (run.status !== 0) {
const said = `${run.stderr ?? ""}`.trim().split("\n")[0] ?? "";
@@ -17541,9 +17835,35 @@ var checkHookRuntime = (opts) => {
} else {
detail = `the hook exited ${String(run.status)} under the restricted PATH \u2014 cause unclear: ${said || "no output"}`;
}
- return check(id, category, title, "fail", detail, fix);
+ return check(
+ id,
+ category,
+ title,
+ "fail",
+ detail,
+ fix,
+ false,
+ void 0,
+ {
+ evidence: {
+ hook_path: hook,
+ exit_code: String(run.status),
+ ...streamEvidence("stderr", run.stderr)
+ }
+ }
+ );
}
- return check(id, category, title, "ok", "the hook runs and validates without node on PATH");
+ return check(
+ id,
+ category,
+ title,
+ "ok",
+ "the hook runs and validates without node on PATH",
+ null,
+ false,
+ void 0,
+ { evidence: { hook_path: hook, exit_code: "0" } }
+ );
} catch (error2) {
return check(
id,
@@ -17551,7 +17871,17 @@ var checkHookRuntime = (opts) => {
title,
"warn",
`could not probe the hook: ${error2 instanceof Error ? error2.message : String(error2)}`,
- fix
+ fix,
+ false,
+ void 0,
+ {
+ evidence: {
+ hook_path: hook,
+ exit_code: "unavailable",
+ error: error2 instanceof Error ? error2.message : String(error2),
+ ...streamEvidence("stderr", "")
+ }
+ }
);
} finally {
rmSync2(probe, { force: true });
@@ -17559,6 +17889,7 @@ var checkHookRuntime = (opts) => {
};
var evaluateInjectRun = (run, ctx) => {
const { id, category, title, executable, path: path2, fix, unavailableFix } = ctx;
+ const executionEvidence = { executable, path: path2 };
if (run.status === null || run.status === void 0) {
if (run.error !== void 0 && "code" in run.error && run.error.code === "ENOENT") {
return check(
@@ -17567,7 +17898,16 @@ var evaluateInjectRun = (run, ctx) => {
title,
"fail",
`configured PreToolUse hook executable ${JSON.stringify(executable)} is not resolvable from PATH`,
- unavailableFix
+ unavailableFix,
+ false,
+ void 0,
+ {
+ evidence: {
+ ...executionEvidence,
+ exit_code: "unavailable",
+ ...streamEvidence("stderr", run.stderr)
+ }
+ }
);
}
return check(
@@ -17576,7 +17916,17 @@ var evaluateInjectRun = (run, ctx) => {
title,
"fail",
`could not run the PreToolUse hook: ${run.error?.message ?? "no diagnosis"}`,
- fix
+ fix,
+ false,
+ void 0,
+ {
+ evidence: {
+ ...executionEvidence,
+ exit_code: "unavailable",
+ error: run.error?.message ?? "no diagnosis",
+ ...streamEvidence("stderr", run.stderr)
+ }
+ }
);
}
if (run.status !== 0) {
@@ -17587,7 +17937,16 @@ var evaluateInjectRun = (run, ctx) => {
title,
"fail",
`the PreToolUse hook exits ${String(run.status)}: ${said || "no diagnosis"}`,
- fix
+ fix,
+ false,
+ void 0,
+ {
+ evidence: {
+ ...executionEvidence,
+ exit_code: String(run.status),
+ ...streamEvidence("stderr", run.stderr)
+ }
+ }
);
}
if (`${run.stdout ?? ""}`.trim() === "") {
@@ -17598,10 +17957,36 @@ var evaluateInjectRun = (run, ctx) => {
title,
"fail",
`the PreToolUse hook returned no context for a known-good payload${said === "" ? "" : `: ${said}`}`,
- fix
+ fix,
+ false,
+ void 0,
+ {
+ evidence: {
+ ...executionEvidence,
+ exit_code: "0",
+ ...streamEvidence("stdout", run.stdout),
+ ...streamEvidence("stderr", run.stderr)
+ }
+ }
);
}
- return check(id, category, title, "ok", `the PreToolUse hook returned context for ${path2}`);
+ return check(
+ id,
+ category,
+ title,
+ "ok",
+ `the PreToolUse hook returned context for ${path2}`,
+ null,
+ false,
+ void 0,
+ {
+ evidence: {
+ ...executionEvidence,
+ exit_code: "0",
+ ...streamEvidence("stdout", run.stdout)
+ }
+ }
+ );
};
var checkInjectRuntime = (opts) => {
const title = "PreToolUse hook runtime";
@@ -17623,19 +18008,88 @@ var checkInjectRuntime = (opts) => {
null,
false,
false,
- { skipReason: "command_unrecognized" }
+ {
+ evidence: {
+ settings_path: settings.settingsPath,
+ settings_state: settings.state,
+ configured_command: command2,
+ executable: "not_run",
+ exit_code: "not_run",
+ ...streamEvidence("stderr", "")
+ },
+ skipReason: "command_unrecognized"
+ }
);
}
const detail = settings.state === "absent" ? `not installed in ${settings.settingsPath}` : `${settings.state} in ${settings.settingsPath}${settings.problem === void 0 ? "" : `: ${settings.problem}`}`;
- return check(id, category, title, "warn", detail, "commitlore inject install-claude-hook");
+ return check(
+ id,
+ category,
+ title,
+ "warn",
+ detail,
+ "commitlore inject install-claude-hook",
+ false,
+ void 0,
+ {
+ evidence: {
+ settings_path: settings.settingsPath,
+ settings_state: settings.state,
+ executable: "not_run",
+ exit_code: "not_run",
+ ...streamEvidence("stderr", ""),
+ ...settings.problem === void 0 ? {} : { problem: settings.problem }
+ }
+ }
+ );
}
const command = settings.commands[0];
if (command !== CLAUDE_HOOK_COMMAND) {
- return check(id, category, title, "skipped", "not checked: the configured command is not recognised", null, false, false, { skipReason: "command_unrecognized" });
+ return check(
+ id,
+ category,
+ title,
+ "skipped",
+ "not checked: the configured command is not recognised",
+ null,
+ false,
+ false,
+ {
+ evidence: {
+ settings_path: settings.settingsPath,
+ settings_state: settings.state,
+ configured_command: command ?? "none",
+ executable: "not_run",
+ exit_code: "not_run",
+ ...streamEvidence("stderr", "")
+ },
+ skipReason: "command_unrecognized"
+ }
+ );
}
const path2 = runQuery({ cwd, noIndex: true }).records.flatMap((record2) => record2.paths).find((candidate) => candidate !== "" && candidate !== ".");
if (path2 === void 0) {
- return check(id, category, title, "skipped", "no recorded path is available for a runtime probe", null, false, false, { skipReason: "probe_path_unavailable" });
+ return check(
+ id,
+ category,
+ title,
+ "skipped",
+ "no recorded path is available for a runtime probe",
+ null,
+ false,
+ false,
+ {
+ evidence: {
+ settings_path: settings.settingsPath,
+ settings_state: settings.state,
+ executable: "not_run",
+ probe_path: "unavailable",
+ exit_code: "not_run",
+ ...streamEvidence("stderr", "")
+ },
+ skipReason: "probe_path_unavailable"
+ }
+ );
}
const payload = JSON.stringify({
session_id: "commitlore-doctor",
@@ -17664,7 +18118,7 @@ var checkInjectRuntime = (opts) => {
return result;
};
var SEMVER_ISH = /^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)*$/;
-var checkInjectVersion = (opts) => {
+var checkInjectVersion = (opts, dependencies) => {
const title = "PreToolUse hook version";
const id = "inject-version";
const category = "delivery";
@@ -17672,11 +18126,42 @@ var checkInjectVersion = (opts) => {
const mine = packageVersion();
const settings = readClaudeHookStatus(claudeSettingsPath(cwd));
if (settings.state !== "installed") {
- return check(id, category, title, "skipped", `no installed hook to compare against ${mine}`, null, false, false, { skipReason: "hook_not_installed" });
+ return check(
+ id,
+ category,
+ title,
+ "skipped",
+ `no installed hook to compare against ${mine}`,
+ null,
+ false,
+ false,
+ {
+ evidence: { executable: "not_run", theirs: "not_run", mine },
+ skipReason: "hook_not_installed"
+ }
+ );
}
const command = settings.commands[0];
if (command !== CLAUDE_HOOK_COMMAND) {
- return check(id, category, title, "skipped", "not checked: the configured command is not recognised", null, false, false, { skipReason: "command_unrecognized" });
+ return check(
+ id,
+ category,
+ title,
+ "skipped",
+ "not checked: the configured command is not recognised",
+ null,
+ false,
+ false,
+ {
+ evidence: {
+ executable: "not_run",
+ theirs: "not_run",
+ mine,
+ configured_command: command ?? "none"
+ },
+ skipReason: "command_unrecognized"
+ }
+ );
}
const configured = command.replace(` ${CLAUDE_HOOK_MARKER}`, "");
const executable = configured.slice(0, configured.indexOf(" "));
@@ -17689,8 +18174,28 @@ var checkInjectVersion = (opts) => {
HOME: process.env["HOME"] ?? ""
}
});
+ const reported = typeof run.stdout === "string" ? run.stdout : "";
+ const versionEvidence = {
+ executable,
+ theirs: boundedExcerpt(reported).firstLine || "unavailable",
+ mine,
+ exit_code: String(run.status ?? "unavailable"),
+ ...streamEvidence("stdout", reported)
+ };
if (run.status !== 0 || typeof run.stdout !== "string") {
- return check(id, category, title, "skipped", `${executable} did not report a version`, null, false, false, { skipReason: "version_unreadable" });
+ const skipped = check(
+ id,
+ category,
+ title,
+ "skipped",
+ `${executable} did not report a version`,
+ null,
+ false,
+ false,
+ { evidence: versionEvidence, skipReason: "version_unreadable" }
+ );
+ const runtime = dependencies.get("inject-runtime");
+ return runtime === void 0 || runtime.status === "ok" ? skipped : blocked(runtime, skipped);
}
const theirs = run.stdout.trim();
if (!SEMVER_ISH.test(theirs)) {
@@ -17703,11 +18208,21 @@ var checkInjectVersion = (opts) => {
null,
false,
false,
- { skipReason: "version_unreadable" }
+ { evidence: versionEvidence, skipReason: "version_unreadable" }
);
}
if (theirs === mine) {
- return check(id, category, title, "ok", `the hook runs ${theirs}, the same build as this CLI`);
+ return check(
+ id,
+ category,
+ title,
+ "ok",
+ `the hook runs ${theirs}, the same build as this CLI`,
+ null,
+ false,
+ void 0,
+ { evidence: versionEvidence }
+ );
}
return check(
id,
@@ -17715,7 +18230,10 @@ var checkInjectVersion = (opts) => {
title,
"warn",
`the agent's hook runs ${theirs} but this CLI is ${mine} \u2014 every edit is graded by ${theirs}'s rules, not this one's`,
- "update the installation the hook resolves to (for the plugin: /plugin marketplace update commitlore), then rerun: commitlore doctor"
+ "update the installation the hook resolves to (for the plugin: /plugin marketplace update commitlore), then rerun: commitlore doctor",
+ false,
+ void 0,
+ { evidence: versionEvidence }
);
};
var checkMcpLifecycle = (opts) => {
@@ -17725,7 +18243,17 @@ var checkMcpLifecycle = (opts) => {
const cwd = opts.cwd ?? process.cwd();
const unfinished = unfinishedRuns(cwd);
if (unfinished.length === 0) {
- return check(id, category, title, "ok", "every recorded MCP session ended cleanly, or is still running");
+ return check(
+ id,
+ category,
+ title,
+ "ok",
+ "every recorded MCP session ended cleanly, or is still running",
+ null,
+ false,
+ void 0,
+ { evidence: { unfinished_count: "0", last_pid: "none", last_at: "none" } }
+ );
}
const last = unfinished[unfinished.length - 1];
return check(
@@ -17734,7 +18262,16 @@ var checkMcpLifecycle = (opts) => {
title,
"warn",
`${unfinished.length} MCP server session(s) started here and never recorded an exit \u2014 most recently pid ${String(last?.pid ?? 0)} at ${last?.at ?? "unknown"}. A killed server loses its tool registration in the client, which reports the same as a tool that never existed (#424)`,
- "restart the client session; if this repeats, capture it with a client started under --debug"
+ "restart the client session; if this repeats, capture it with a client started under --debug",
+ false,
+ void 0,
+ {
+ evidence: {
+ unfinished_count: String(unfinished.length),
+ last_pid: String(last?.pid ?? 0),
+ last_at: last?.at ?? "unknown"
+ }
+ }
);
};
var checkPendingBacklog = (opts) => {
@@ -17746,7 +18283,17 @@ var checkPendingBacklog = (opts) => {
try {
listing = runPendingList({ cwd });
} catch {
- return check(id, category, title, "ok", "no pending directory \u2014 nothing has been captured here yet");
+ return check(
+ id,
+ category,
+ title,
+ "ok",
+ "no pending directory \u2014 nothing has been captured here yet",
+ null,
+ false,
+ void 0,
+ { evidence: { stranded: "0", staged_expired: "0", oldest: "none" } }
+ );
}
if (listing.unreadable.length > 0) {
return check(
@@ -17755,7 +18302,17 @@ var checkPendingBacklog = (opts) => {
title,
"warn",
`${listing.unreadable.length} pending file(s) cannot be read as a transaction`,
- "commitlore pending ls"
+ "commitlore pending ls",
+ false,
+ void 0,
+ {
+ evidence: {
+ stranded: "0",
+ staged_expired: "0",
+ oldest: "none",
+ unreadable: String(listing.unreadable.length)
+ }
+ }
);
}
const stranded = listing.transactions.filter((transaction) => transaction.stale);
@@ -17766,7 +18323,18 @@ var checkPendingBacklog = (opts) => {
category,
title,
"ok",
- held === 0 ? "no captures are waiting" : `${String(held)} capture(s) waiting, all still able to apply`
+ held === 0 ? "no captures are waiting" : `${String(held)} capture(s) waiting, all still able to apply`,
+ null,
+ false,
+ void 0,
+ {
+ evidence: {
+ stranded: "0",
+ staged_expired: "0",
+ oldest: "none",
+ waiting: String(held)
+ }
+ }
);
}
const lost = stranded.filter((transaction) => transaction.phase === "staged");
@@ -17778,7 +18346,16 @@ var checkPendingBacklog = (opts) => {
title,
"warn",
`${detail}; oldest from ${oldest ?? "an unknown time"}. A staged record binds to the tree it was prepared for and is skipped once that tree moves, so these decisions were never written to the history (#458)`,
- "commitlore pending ls"
+ "commitlore pending ls",
+ false,
+ void 0,
+ {
+ evidence: {
+ stranded: String(stranded.length),
+ staged_expired: String(lost.length),
+ oldest: oldest ?? "unknown"
+ }
+ }
);
};
var checkIndex = (opts) => {
@@ -17793,7 +18370,18 @@ var checkIndex = (opts) => {
"index health",
"warn",
"no index yet \u2014 queries fall back to scanning the history",
- "commitlore index --rebuild"
+ "commitlore index --rebuild",
+ false,
+ void 0,
+ {
+ evidence: {
+ trailers: "0",
+ commits: "0",
+ last_indexed_sha: "none",
+ head_sha: "not_queried",
+ fts: "unavailable"
+ }
+ }
);
}
try {
@@ -17801,19 +18389,33 @@ var checkIndex = (opts) => {
const head = execGit(["rev-parse", "HEAD"], gitOptions3(opts));
const behind = head.code === 0 && info.lastIndexedSha !== head.stdout.trim();
const fts = info.fts ? "FTS5" : "no FTS5 (value search falls back to LIKE)";
+ const indexEvidence = {
+ trailers: String(info.trailers),
+ commits: String(info.commits),
+ last_indexed_sha: info.lastIndexedSha || "none",
+ head_sha: head.code === 0 ? head.stdout.trim() || "none" : "unavailable",
+ fts: info.fts ? "true" : "false"
+ };
return behind ? check(
"index-health",
"index",
"index health",
"warn",
`${info.trailers} trailers over ${info.commits} commits, behind HEAD \u2014 ${fts}`,
- "commitlore index"
+ "commitlore index",
+ false,
+ void 0,
+ { evidence: indexEvidence }
) : check(
"index-health",
"index",
"index health",
"ok",
- `${info.trailers} trailers over ${info.commits} commits, current with HEAD \u2014 ${fts}`
+ `${info.trailers} trailers over ${info.commits} commits, current with HEAD \u2014 ${fts}`,
+ null,
+ false,
+ void 0,
+ { evidence: indexEvidence }
);
} catch (error2) {
return check(
@@ -17822,7 +18424,18 @@ var checkIndex = (opts) => {
"index health",
"warn",
`index unreadable (${error2 instanceof Error ? error2.message : String(error2)}) \u2014 queries still work without it`,
- "commitlore index --rebuild"
+ "commitlore index --rebuild",
+ false,
+ void 0,
+ {
+ evidence: {
+ trailers: "unavailable",
+ commits: "unavailable",
+ last_indexed_sha: "unavailable",
+ head_sha: "unavailable",
+ fts: "unavailable"
+ }
+ }
);
} finally {
try {
@@ -17837,8 +18450,21 @@ var checkHistoryDepth = (opts) => hasShallowHistory(opts.cwd ?? process.cwd()) ?
"history depth",
"warn",
"this clone has shallow history, so queries may be missing records that exist upstream",
- "git fetch --unshallow"
-) : check("history-depth", "history", "history depth", "ok", "full history is available");
+ "git fetch --unshallow",
+ false,
+ void 0,
+ { evidence: { shallow: "true" } }
+) : check(
+ "history-depth",
+ "history",
+ "history depth",
+ "ok",
+ "full history is available",
+ null,
+ false,
+ void 0,
+ { evidence: { shallow: "false" } }
+);
var MAX_SQUASH_CANDIDATE_BRANCHES = 200;
var squashCandidates = (opts, head) => {
const listed = execGit(
@@ -17870,7 +18496,20 @@ var checkSquashConservation = (opts) => {
const cwd = opts.cwd ?? process.cwd();
const head = execGit(["rev-parse", "--verify", "--quiet", "HEAD"], gitOptions3(opts));
if (head.code !== 0) {
- return check(id, category, title, "skipped", "no HEAD yet \u2014 nothing to compare against", null, false, false, { skipReason: "unborn_head" });
+ return check(
+ id,
+ category,
+ title,
+ "skipped",
+ "no HEAD yet \u2014 nothing to compare against",
+ null,
+ false,
+ false,
+ {
+ evidence: { candidates: "0", checked: "0", uncheckable: "0", lost_count: "0" },
+ skipReason: "unborn_head"
+ }
+ );
}
const candidates = squashCandidates(opts, head.stdout.trim());
if (candidates.length === 0) {
@@ -17883,7 +18522,10 @@ var checkSquashConservation = (opts) => {
null,
false,
false,
- { skipReason: "nothing_applicable" }
+ {
+ evidence: { candidates: "0", checked: "0", uncheckable: "0", lost_count: "0" },
+ skipReason: "nothing_applicable"
+ }
);
}
let known = null;
@@ -17925,7 +18567,15 @@ var checkSquashConservation = (opts) => {
null,
false,
false,
- { skipReason: "nothing_applicable" }
+ {
+ evidence: {
+ candidates: String(candidates.length),
+ checked: "0",
+ uncheckable: String(uncheckable),
+ lost_count: "0"
+ },
+ skipReason: "nothing_applicable"
+ }
);
}
if (lost.length > 0) {
@@ -17937,11 +18587,38 @@ var checkSquashConservation = (opts) => {
title,
"warn",
`${lost.length} record(s) declared on a branch not reachable from HEAD do not appear in HEAD's history: ${named}${more}`,
- "commitlore squash-preserve .. --target , then commit or attach the result"
+ "commitlore squash-preserve .. --target , then commit or attach the result",
+ false,
+ void 0,
+ {
+ evidence: {
+ candidates: String(candidates.length),
+ checked: String(checked),
+ uncheckable: String(uncheckable),
+ lost_count: String(lost.length)
+ }
+ }
);
}
const detail = uncheckable > 0 ? `${checked} squash-shaped branch(es) checked, every declared Record-Id is reachable from HEAD (${uncheckable} branch(es) recorded nothing with an id and could not be checked this way)` : `${checked} squash-shaped branch(es) checked, every declared Record-Id is reachable from HEAD`;
- return check(id, category, title, "ok", detail);
+ return check(
+ id,
+ category,
+ title,
+ "ok",
+ detail,
+ null,
+ false,
+ void 0,
+ {
+ evidence: {
+ candidates: String(candidates.length),
+ checked: String(checked),
+ uncheckable: String(uncheckable),
+ lost_count: "0"
+ }
+ }
+ );
};
var hookRuntimeOf = (ctx) => {
const cached2 = ctx.memo.get("hook-runtime");
@@ -17954,10 +18631,10 @@ var CHECK_REGISTRY = [
{ id: "cli-runtime", title: "cli runtime", category: "runtime", dependencies: [], optional: false, run: (ctx) => checkRuntime(ctx.opts) },
{ id: "notes-refspec", title: "notes fetch refspec", category: "transport", dependencies: [], optional: false, run: (ctx) => checkRefspec(ctx.opts) },
{ id: "notes-push", title: "notes push", category: "transport", dependencies: [], optional: false, run: (ctx) => checkPush(ctx.opts) },
- { id: "commit-msg-hook", title: "commit-msg hook", category: "capture", dependencies: [], optional: false, run: (ctx) => checkHook(ctx.opts, hookRuntimeOf(ctx)) },
+ { id: "commit-msg-hook", title: "commit-msg hook", category: "capture", dependencies: [], optional: false, run: (ctx) => checkHook(ctx) },
{ id: "hook-runtime", title: "hook runtime", category: "capture", dependencies: [], optional: false, run: hookRuntimeOf },
{ id: "inject-runtime", title: "PreToolUse hook runtime", category: "delivery", dependencies: [], optional: false, run: (ctx) => checkInjectRuntime(ctx.opts) },
- { id: "inject-version", title: "PreToolUse hook version", category: "delivery", dependencies: ["inject-runtime"], optional: false, run: (ctx) => checkInjectVersion(ctx.opts) },
+ { id: "inject-version", title: "PreToolUse hook version", category: "delivery", dependencies: ["inject-runtime"], optional: false, run: (ctx, dependencies) => checkInjectVersion(ctx.opts, dependencies) },
{ id: "mcp-lifecycle", title: "MCP server sessions", category: "delivery", dependencies: [], optional: false, run: (ctx) => checkMcpLifecycle(ctx.opts) },
{ id: "pending-backlog", title: "pending captures", category: "capture", dependencies: [], optional: false, run: (ctx) => checkPendingBacklog(ctx.opts) },
{ id: "git-trailers", title: "git interpret-trailers", category: "runtime", dependencies: [], optional: false, run: (ctx) => checkGit(ctx.opts) },
@@ -17965,9 +18642,9 @@ var CHECK_REGISTRY = [
{ id: "index-health", title: "index health", category: "index", dependencies: [], optional: false, run: (ctx) => checkIndex(ctx.opts) },
{ id: "squash-conservation", title: "squash conservation", category: "history", dependencies: [], optional: false, run: (ctx) => checkSquashConservation(ctx.opts) }
];
-var containedRun = (definition, ctx) => {
+var containedRun = (definition, ctx, dependencies) => {
try {
- return definition.run(ctx);
+ return definition.run(ctx, dependencies);
} catch (error2) {
const message = error2 instanceof Error ? error2.message : String(error2);
return check(
@@ -17983,17 +18660,55 @@ var containedRun = (definition, ctx) => {
);
}
};
+var statusRank = (status) => status === "fail" ? 3 : status === "warn" ? 2 : status === "skipped" ? 1 : 0;
+var collapseBlockedBy = (checks) => {
+ const byId = new Map(checks.map((row) => [row.id, row]));
+ return checks.map((row) => {
+ if (row.blockedBy === void 0) return row;
+ const visited = /* @__PURE__ */ new Set([row.id]);
+ let root = byId.get(row.blockedBy);
+ while (root !== void 0 && root.blockedBy !== void 0) {
+ if (visited.has(root.id)) {
+ throw new Error(`doctor check ${row.id} has a cyclic blockedBy chain`);
+ }
+ visited.add(root.id);
+ root = byId.get(root.blockedBy);
+ }
+ if (root === void 0) {
+ throw new Error(`doctor check ${row.id} names an unknown blocker`);
+ }
+ if (root.status === "ok") {
+ throw new Error(`doctor check ${row.id} names an ok blocker`);
+ }
+ if (statusRank(row.status) > statusRank(root.status)) {
+ throw new Error(`doctor check ${row.id} is more severe than its blocker`);
+ }
+ return root.id === row.blockedBy ? row : { ...row, blockedBy: root.id };
+ });
+};
var runDoctor = (opts = {}) => {
const ctx = { opts, now: process.hrtime.bigint, memo: /* @__PURE__ */ new Map() };
+ const completed = /* @__PURE__ */ new Map();
const checks = CHECK_REGISTRY.map((definition) => {
+ const dependencies = /* @__PURE__ */ new Map();
+ for (const dependency of definition.dependencies) {
+ const row2 = completed.get(dependency);
+ if (row2 === void 0) {
+ throw new Error(`doctor check ${definition.id} depends on ${dependency}, which has not run`);
+ }
+ dependencies.set(dependency, row2);
+ }
const started = ctx.now();
- const row = containedRun(definition, ctx);
+ const row = containedRun(definition, ctx, dependencies);
const elapsed = Number((ctx.now() - started) / 1000000n);
- return { ...row, durationMs: elapsed < 0 ? 0 : elapsed };
+ const timed = { ...row, durationMs: elapsed < 0 ? 0 : elapsed };
+ completed.set(definition.id, timed);
+ return timed;
});
+ const collapsed = collapseBlockedBy(checks);
return {
- checks,
- exitCode: checks.some((entry) => entry.status === "fail") ? 1 : 0
+ checks: collapsed,
+ exitCode: collapsed.some((entry) => entry.status === "fail") ? 1 : 0
};
};
var STATUS_WIDTH = 8;
@@ -20007,7 +20722,8 @@ var hookOutput = (text) => `${JSON.stringify({
var injectOptions = (path2, options, cwd) => {
const at = evaluationInstant2(options.at);
const budget = tokenBudget(options.budget);
- const trustedAuthors = options.trustedAuthor ?? configuredTrustedAuthors(cwd);
+ const flagged = options.trustedAuthor ?? [];
+ const trustedAuthors = flagged.length > 0 ? flagged : configuredTrustedAuthors(cwd);
return {
path: path2,
cwd,
@@ -28692,12 +29408,12 @@ var SECTIONS = [
];
var SECTION_KEYS = SECTIONS.map((section2) => section2.key);
var withholdBlocked = (result) => {
- const blocked = result.records.filter(
+ const blocked2 = result.records.filter(
(record2) => record2.trust === "blocked" && record2.withheldTrailerKeys === void 0
);
- if (blocked.length === 0) return result;
- const collisions = blocked.filter((record2) => record2.identityCollision === true);
- const injectionBlocked = blocked.filter((record2) => record2.identityCollision !== true);
+ if (blocked2.length === 0) return result;
+ const collisions = blocked2.filter((record2) => record2.identityCollision === true);
+ const injectionBlocked = blocked2.filter((record2) => record2.identityCollision !== true);
const keys = [
...new Set(injectionBlocked.flatMap((record2) => record2.matchedTrailerKeys ?? []))
].sort();
@@ -28768,7 +29484,8 @@ var recordLimit = (raw) => {
var queryOptions = (paths, options, keys) => {
const at = evaluationInstant3(options.at);
const limit = recordLimit(options.limit);
- const trustedAuthors = options.trustedAuthor ?? [];
+ const flagged = options.trustedAuthor ?? [];
+ const trustedAuthors = flagged.length > 0 ? flagged : configuredTrustedAuthors(process.cwd());
return {
paths,
allHistory: options.allHistory === true,
diff --git a/docs/DOCTOR-PRD.md b/docs/DOCTOR-PRD.md
index 9806266b..207cd524 100644
--- a/docs/DOCTOR-PRD.md
+++ b/docs/DOCTOR-PRD.md
@@ -506,9 +506,20 @@ Node-only by decision (ADR-0026) and has no brew channel.
exit `0`. The first revision said "No network. No socket, ever" — false
against the shipping command, a review finding, corrected here rather
than narrowed silently.
-2. **No writes without `--fix`.** A plain run is read-only including under
- failure; `--fix` applies only reversible local config and reports every
- change via `fixed: true` on the row it fixed.
+2. **No writes without `--fix`, with one measured exception.** A plain run
+ modifies no repository content and no CommitLore state: `index.db` is
+ byte-identical after it, including under failure. `--fix` applies only
+ reversible local config and reports every change via `fixed: true` on the
+ row it fixed.
+
+ The exception is SQLite's own bookkeeping. Opening a WAL database creates
+ or touches `index.db-shm`, and `--fix` creates `-wal` alongside it — for
+ readers as much as writers, and they hold no committed data. The first
+ revision of this section said "zero writes" without it, and writing the
+ §11 read-only test strictly is what found the wording false (#473).
+ Removing the exception would mean opening the index outside WAL for
+ doctor, which trades a documentation problem for the concurrency one #420
+ was about.
3. **No claim it cannot evidence.** Every row carries the observation that
produced it, `ok` included (§1.3.1) — the first revision required
evidence only for non-ok rows, and the review showed `ok` with `{}`
@@ -607,7 +618,7 @@ Every line is a command or a test that decides the answer.
| release gate unchanged | `dist/commitlore.mjs doctor` on a fresh clone | exit 0, no `fail` (RELEASE-GATE §4 row still passes) |
| no non-git network | full run with Node socket APIs stubbed to throw | all checks complete |
| offline honesty | full run with every remote pointed at an unreachable host | run completes, exit 0; transport rows `warn` "could not verify" |
-| read-only | full run without `--fix` under a watched fs | zero writes |
+| read-only | full run without `--fix` under a watched fs | `index.db` byte-identical; nothing else changes but SQLite's `-shm`/`-wal` sidecars (§8.2) |
| partial honesty | `doctor --only cli-runtime --json` | `selection` present; headline prefixed `1 of 15 checks run` |
| summary invariant | property test over fixtures | counts sum to `total == checks.length`; per-check `durationMs` sums to ≤ `summary.durationMs` |
| budget | timed run per §10.1 | `summary.durationMs` within the recorded budget |
diff --git a/docs/RELEASE-GATE.md b/docs/RELEASE-GATE.md
index b0cf94ae..e4bff5cd 100644
--- a/docs/RELEASE-GATE.md
+++ b/docs/RELEASE-GATE.md
@@ -46,6 +46,11 @@ exclusion, so this table is a spot check of the rule, not the rule itself.
## 4. The installation the documentation describes actually works
+These checks run as the `install-gate` job in the tag-triggered release workflow,
+against a fresh clone of the pushed tag. `publish` depends on this job as well as
+the version, ancestry, and exact-head-CI gates, so a GitHub Release cannot exist
+until every automated prerequisite has passed.
+
| check | command | pass |
|---|---|---|
| fresh clone runs | `git clone`, then `dist/commitlore.mjs --version` | exit 0 |
@@ -53,25 +58,62 @@ exclusion, so this table is a spot check of the rule, not the rule itself.
| fresh clone doctor | `dist/commitlore.mjs doctor` | exit 0, no `fail` |
| hook survives a PATH without node | commit under `env -i PATH=/usr/bin:/bin` | validated, bad message rejected |
| a stale hook is reported | doctor on a repo whose stub predates the current one | `warn`, not `ok` |
-| plugin entry point resolves | `CLAUDE_PLUGIN_ROOT= scripts/commitlore-run.sh --version` | exit 0 |
+| plugin entry point resolves | `env PATH=/usr/bin:/bin: CLAUDE_PLUGIN_ROOT= scripts/commitlore-run.sh --version` | exit 0 **and the version equals the clone's** |
+
+The `PATH` is narrowed on purpose. `commitlore-run.sh` tries `commitlore` on
+`PATH` before `CLAUDE_PLUGIN_ROOT`, deliberately — the installer's wrapper execs
+node itself, so it works where this script would otherwise have to find node,
+and on the hook hot path a missing node means no context at all. The
+consequence is that **a machine with both a CLI install and the plugin runs
+whichever the CLI install is**, and the release check passed for two releases
+while reporting the wrong version, because it only asked whether *something*
+resolved (#483). Leaving `PATH` alone here would keep asking that question.
+
+## 5. The tag is a promoted, exactly green commit
+
+A matching version and a working fresh clone say nothing about *where* a tag was
+cut. A dev-only commit can satisfy both. Nor does a green `main` badge prove the
+tagged SHA passed: it may be a failed, cancelled, skipped, timed-out, still
+running, or entirely untested commit between two green ones.
+
+The tag workflow therefore blocks `publish` on both jobs below.
+
+| check | command | pass |
+|---|---|---|
+| release target | `scripts/check-release-target.mjs main` from a `fetch-depth: 0` checkout | the tag resolves to a commit contained in `main`; a shallow checkout fails rather than guessing |
+| exact-head CI | `scripts/check-exact-head-ci.mjs ` | all six explicitly named check runs below are present at that SHA, `completed`, and concluded `success` |
+
+The exact-head list is fixed rather than inferred from the API response:
+`check (22)`, `check (24)`, `git-matrix (ubuntu-latest)`, `git-matrix
+(macos-latest)`, `install-script`, and `install-ps1`. Any other conclusion —
+including `failure`, `cancelled`, `timed_out`, `skipped`, `neutral`, `stale`, or
+`action_required` — blocks publication. So do `queued` and `in_progress`, a
+check reported for another SHA, and an absent check; an empty result is six
+absent checks, not a clean result.
+
+`release-target` exports the commit behind the tag only after the ancestry check
+passes. `exact-head-ci` consumes that exact commit, so annotated tags do not
+accidentally query CI using a tag-object SHA. Both are direct `publish`
+dependencies and `publish` has no `if:` condition that can override a failed or
+skipped dependency.
-## 5. Every published claim is reproducible
+## 6. Every published claim is reproducible
- `scripts/check-readme-numbers.mjs` exits 0 — no number in any README is typed
by hand.
- No README asserts something a command in this file contradicts. The three that
did (green on `main`, a clone carries its dependencies, a clone carries the
whole memory) are the reason this section exists.
-- CI is green **at the exact commit being released**, checked by looking at CI
- rather than at a local test run. A local suite passed at every one of the three
- commits where CI was red.
+- CI is green **at the exact commit being released**, as enforced by section 5's
+ explicit check-run set rather than inferred from a local test run or a branch
+ badge. A local suite passed at every one of the three commits where CI was red.
-## 6. The suite proves something
+## 7. The suite proves something
- `npx vitest run` green, and the run reports `Test Files N passed` — a bare test
count is not evidence. A delegated task once reported 943 of a 1108 baseline
because another process was writing to the worktree during its run.
-- Each fix in sections 1–4 has a test that fails when that one fix is reverted.
+- Each fix in sections 1–5 has a test that fails when that one fix is reverted.
Reverting is the evidence; a passing test proves nothing on its own.
## What this gate deliberately does not require
diff --git a/package-lock.json b/package-lock.json
index b215c5cb..68b91f1f 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "commitlore",
- "version": "0.1.0",
+ "version": "0.7.1",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "commitlore",
- "version": "0.1.0",
+ "version": "0.7.1",
"license": "MIT",
"dependencies": {
"@modelcontextprotocol/sdk": "^1.29.0",
diff --git a/package.json b/package.json
index f571dbf6..62084f5e 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "commitlore",
- "version": "0.7.0",
+ "version": "0.7.1",
"description": "Git-native, lifecycle-aware decision memory for coding agents",
"license": "MIT",
"private": true,
diff --git a/scripts/check-exact-head-ci.mjs b/scripts/check-exact-head-ci.mjs
new file mode 100644
index 00000000..128515ea
--- /dev/null
+++ b/scripts/check-exact-head-ci.mjs
@@ -0,0 +1,209 @@
+#!/usr/bin/env node
+/**
+ * Refuses a release unless every named CI check succeeded at its exact commit.
+ *
+ * A green branch, a recent green workflow, or a passing local suite is not a
+ * substitute for a successful check run at the SHA a tag resolves to. This
+ * script names the required check runs up front and treats every other state —
+ * including a missing run — as a blocking failure.
+ *
+ * Usage:
+ * node scripts/check-exact-head-ci.mjs
+ * node scripts/check-exact-head-ci.mjs --from-file
+ * node scripts/check-exact-head-ci.mjs --from-stdin
+ *
+ * `--from-file` and `--from-stdin` are test seams. Their JSON is the response
+ * body from GET /repos/{owner}/{repo}/commits/{sha}/check-runs (or a raw array
+ * of its `check_runs` entries). Without either seam the script calls GitHub.
+ *
+ * Exit codes follow SPEC §10:
+ * 0 every explicitly required check completed successfully at `sha`
+ * 1 a required check is absent, belongs to another SHA, or is not success
+ * 2 bad input, unreadable payload, or an API/repository failure
+ */
+
+import { readFileSync } from 'node:fs';
+import { fileURLToPath } from 'node:url';
+import { resolve } from 'node:path';
+
+// This is intentionally a fixed allowlist, not a list inferred from whatever
+// happened to report at a SHA. A missing check is the failure this gate exists
+// to catch, so presence cannot define the requirement.
+export const REQUIRED_CHECKS = Object.freeze([
+ 'check (22)',
+ 'check (24)',
+ 'git-matrix (ubuntu-latest)',
+ 'git-matrix (macos-latest)',
+ 'install-script',
+ 'install-ps1',
+]);
+
+class GateError extends Error {
+ constructor(message, exitCode = 2) {
+ super(message);
+ this.exitCode = exitCode;
+ }
+}
+
+const usage = () => {
+ throw new GateError(
+ 'usage: node scripts/check-exact-head-ci.mjs [--from-file | --from-stdin]',
+ );
+};
+
+const parseArgs = (argv) => {
+ const positional = [];
+ let fromFile = null;
+ let fromStdin = false;
+
+ for (let index = 0; index < argv.length; index += 1) {
+ const arg = argv[index];
+ if (arg === '--from-file') {
+ const path = argv[index + 1];
+ if (!path || fromFile !== null) usage();
+ fromFile = path;
+ index += 1;
+ } else if (arg === '--from-stdin') {
+ if (fromStdin) usage();
+ fromStdin = true;
+ } else if (arg.startsWith('--')) {
+ usage();
+ } else {
+ positional.push(arg);
+ }
+ }
+
+ if (fromFile !== null && fromStdin) usage();
+ if (positional.length !== 3 || positional.some((value) => value === '')) usage();
+ return { owner: positional[0], repo: positional[1], sha: positional[2], fromFile, fromStdin };
+};
+
+const readStdin = async () => {
+ let body = '';
+ for await (const chunk of process.stdin) body += chunk;
+ return body;
+};
+
+const parsePayload = (text, source) => {
+ try {
+ return JSON.parse(text);
+ } catch (error) {
+ throw new GateError(`ERROR: ${source} is not valid JSON: ${error.message}`);
+ }
+};
+
+const checkRunsFrom = (payload, source) => {
+ if (Array.isArray(payload)) return payload;
+ if (payload !== null && typeof payload === 'object' && Array.isArray(payload.check_runs)) {
+ return payload.check_runs;
+ }
+ throw new GateError(`ERROR: ${source} does not contain a check_runs array.`);
+};
+
+const networkPayload = async (owner, repo, sha) => {
+ const token = process.env.GITHUB_TOKEN;
+ if (!token) {
+ throw new GateError('ERROR: GITHUB_TOKEN is required to query the exact-head CI checks.');
+ }
+
+ const apiBase = (process.env.GITHUB_API_URL ?? 'https://api.github.com').replace(/\/$/, '');
+ const path = `/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/commits/${encodeURIComponent(sha)}/check-runs`;
+ const checkRuns = [];
+ let page = 1;
+ let totalCount = null;
+
+ do {
+ const response = await fetch(`${apiBase}${path}?per_page=100&page=${page}`, {
+ headers: {
+ Accept: 'application/vnd.github+json',
+ Authorization: `Bearer ${token}`,
+ 'X-GitHub-Api-Version': '2022-11-28',
+ },
+ });
+ if (!response.ok) {
+ throw new GateError(`ERROR: GitHub check-runs API returned ${response.status} ${response.statusText} for ${sha}.`);
+ }
+
+ let payload;
+ try {
+ payload = await response.json();
+ } catch (error) {
+ throw new GateError(`ERROR: GitHub check-runs API returned invalid JSON: ${error.message}`);
+ }
+ const pageRuns = checkRunsFrom(payload, 'GitHub check-runs API response');
+ checkRuns.push(...pageRuns);
+ if (typeof payload.total_count === 'number') totalCount = payload.total_count;
+ if (pageRuns.length === 0) break;
+ page += 1;
+ } while (checkRuns.length < (totalCount ?? Number.POSITIVE_INFINITY));
+
+ return checkRuns;
+};
+
+const checkRequiredRuns = (checkRuns, sha) => {
+ const problems = [];
+
+ for (const required of REQUIRED_CHECKS) {
+ const matching = checkRuns.filter((run) => run !== null && typeof run === 'object' && run.name === required);
+ if (matching.length === 0) {
+ problems.push(`${required}: required check is absent`);
+ continue;
+ }
+
+ for (const run of matching) {
+ if (run.head_sha !== sha) {
+ problems.push(`${required}: reported head SHA "${String(run.head_sha)}", expected "${sha}"`);
+ }
+ if (run.status !== 'completed') {
+ problems.push(`${required}: status "${String(run.status)}", expected "completed"`);
+ }
+ if (run.conclusion !== 'success') {
+ problems.push(`${required}: conclusion "${String(run.conclusion)}", expected "success"`);
+ }
+ }
+ }
+
+ return problems;
+};
+
+const main = async () => {
+ const { owner, repo, sha, fromFile, fromStdin } = parseArgs(process.argv.slice(2));
+ let payload;
+ let source;
+
+ if (fromFile !== null) {
+ source = `payload file ${fromFile}`;
+ try {
+ payload = parsePayload(readFileSync(fromFile, 'utf8'), source);
+ } catch (error) {
+ if (error instanceof GateError) throw error;
+ throw new GateError(`ERROR: could not read ${source}: ${error.message}`);
+ }
+ } else if (fromStdin) {
+ source = 'stdin payload';
+ payload = parsePayload(await readStdin(), source);
+ } else {
+ source = 'GitHub check-runs API response';
+ payload = { check_runs: await networkPayload(owner, repo, sha) };
+ }
+
+ const checkRuns = checkRunsFrom(payload, source);
+ const problems = checkRequiredRuns(checkRuns, sha);
+ if (problems.length > 0) {
+ console.error(`ERROR: exact-head CI did not pass for ${owner}/${repo}@${sha}:`);
+ for (const problem of problems) console.error(` - ${problem}`);
+ console.error(' Every required check must be present, completed, and concluded success at this exact SHA.');
+ process.exitCode = 1;
+ return;
+ }
+
+ console.log(`exact-head CI accepted: all ${REQUIRED_CHECKS.length} required checks succeeded at ${owner}/${repo}@${sha}`);
+};
+
+const invokedAsScript = process.argv[1] !== undefined && resolve(process.argv[1]) === fileURLToPath(import.meta.url);
+if (invokedAsScript) {
+ main().catch((error) => {
+ console.error(error.message);
+ process.exitCode = error instanceof GateError ? error.exitCode : 2;
+ });
+}
diff --git a/scripts/check-release-target.mjs b/scripts/check-release-target.mjs
new file mode 100644
index 00000000..5d953651
--- /dev/null
+++ b/scripts/check-release-target.mjs
@@ -0,0 +1,125 @@
+#!/usr/bin/env node
+/**
+ * Refuses a release tag whose commit is not part of the target branch.
+ *
+ * A matching version proves only that a tag and package describe the same
+ * bytes. It does not prove those bytes are the promoted mainline: a dev-only
+ * commit can report exactly the version a release expects. This gate asks git
+ * the stronger question before publication begins.
+ *
+ * Usage:
+ * node scripts/check-release-target.mjs [--github-output]
+ *
+ * Exit codes follow SPEC §10:
+ * 0 the resolved commit is contained in the target branch
+ * 1 the resolved commit is not contained in the target branch
+ * 2 git could not resolve an input or inspect the repository
+ * 3 the checkout is shallow, so the ancestry answer would be incomplete
+ *
+ * `--github-output` writes the resolved commit as `sha` to GITHUB_OUTPUT after
+ * a passing ancestry check. The following exact-head CI job consumes that
+ * value, so it queries the commit behind an annotated tag rather than relying
+ * on the tag object SHA supplied by an event implementation.
+ */
+
+import { appendFileSync } from 'node:fs';
+import { spawnSync } from 'node:child_process';
+
+const usage = () => {
+ console.error('usage: node scripts/check-release-target.mjs [--github-output]');
+ process.exit(2);
+};
+
+const args = process.argv.slice(2);
+const githubOutput = args.at(-1) === '--github-output';
+if (githubOutput) args.pop();
+if (args.length !== 2) usage();
+
+const [releaseRef, targetBranch] = args;
+if (!releaseRef || !targetBranch) usage();
+
+const git = (args) =>
+ spawnSync('git', args, {
+ cwd: process.cwd(),
+ encoding: 'utf8',
+ shell: false,
+ });
+
+const resolveCommit = (revision, label) => {
+ const result = git(['rev-parse', '--verify', '--quiet', '--end-of-options', `${revision}^{commit}`]);
+ if (result.status !== 0) {
+ console.error(`ERROR: cannot resolve ${label} "${revision}" to a commit.`);
+ if (result.stderr) console.error(result.stderr.trim());
+ process.exit(2);
+ }
+ return result.stdout.trim();
+};
+
+// A shallow clone can make `merge-base --is-ancestor` answer from an
+// incomplete graph. Equality may happen to be visible, but that is not proof
+// of the requested history relation; fail explicitly rather than treating the
+// partial answer as a pass.
+const shallow = git(['rev-parse', '--is-shallow-repository']);
+if (shallow.status !== 0) {
+ console.error('ERROR: cannot determine whether this checkout has complete history.');
+ if (shallow.stderr) console.error(shallow.stderr.trim());
+ process.exit(2);
+}
+if (shallow.stdout.trim() !== 'false') {
+ console.error('ERROR: cannot establish release ancestry from a shallow repository.');
+ console.error(' The release checkout must use fetch-depth: 0 before checking main ancestry.');
+ process.exit(3);
+}
+
+const releaseCommit = resolveCommit(releaseRef, 'release tag or SHA');
+
+// A tag checkout normally has `origin/main`, not a local `main` branch. A
+// throwaway/local repository normally has the reverse. Prefer the remote
+// tracking ref when both exist: it is the branch the release workflow fetched.
+const targetCandidates = targetBranch.startsWith('refs/')
+ ? [targetBranch]
+ : [`refs/remotes/origin/${targetBranch}`, `refs/heads/${targetBranch}`, targetBranch];
+
+let targetCommit = null;
+let targetRef = null;
+for (const candidate of targetCandidates) {
+ const result = git(['rev-parse', '--verify', '--quiet', '--end-of-options', `${candidate}^{commit}`]);
+ if (result.status === 0) {
+ targetCommit = result.stdout.trim();
+ targetRef = candidate;
+ break;
+ }
+}
+if (targetCommit === null || targetRef === null) {
+ console.error(`ERROR: cannot resolve target branch "${targetBranch}" in this checkout.`);
+ console.error(' Fetch the target branch and its full history before asking the ancestry gate.');
+ process.exit(2);
+}
+
+const ancestry = git(['merge-base', '--is-ancestor', releaseCommit, targetCommit]);
+if (ancestry.status === 1) {
+ console.error(`ERROR: release commit ${releaseCommit} is not contained in target branch "${targetBranch}" (${targetRef}).`);
+ console.error(' Refusing to publish a tag that has not reached the release branch.');
+ process.exit(1);
+}
+if (ancestry.status !== 0) {
+ console.error(`ERROR: git could not determine whether ${releaseCommit} is an ancestor of ${targetRef}.`);
+ if (ancestry.stderr) console.error(ancestry.stderr.trim());
+ process.exit(2);
+}
+
+if (githubOutput) {
+ const outputPath = process.env.GITHUB_OUTPUT;
+ if (!outputPath) {
+ console.error('ERROR: --github-output requires the GITHUB_OUTPUT environment variable.');
+ process.exit(2);
+ }
+ try {
+ appendFileSync(outputPath, `sha=${releaseCommit}\n`);
+ } catch (error) {
+ console.error(`ERROR: could not write the resolved release SHA to GITHUB_OUTPUT: ${error.message}`);
+ process.exit(2);
+ }
+}
+
+console.log(`release target accepted: ${releaseRef} resolves to ${releaseCommit} and is contained in target branch "${targetBranch}" (${targetRef})`);
diff --git a/scripts/check-release-version.mjs b/scripts/check-release-version.mjs
index 8bfb8a70..8c1f63e2 100644
--- a/scripts/check-release-version.mjs
+++ b/scripts/check-release-version.mjs
@@ -1,8 +1,9 @@
#!/usr/bin/env node
/**
* Release gate (`.github/workflows/release.yml`): the pushed tag, this
- * package's declared version, and the CLI's own `--version` output must all
- * agree before anything is built or attached to a release.
+ * package's declared version, every release manifest's declared version, and
+ * the CLI's own `--version` output must all agree before anything is built or
+ * attached to a release.
*
* This matters more than the usual "the numbers should match" check. A tag
* is immutable the moment someone has fetched it, and a release asset is
@@ -11,11 +12,16 @@
* with a `v0.1.1` and an explanation. Catching the mismatch before the build
* matrix runs is the only point where it is still cheap.
*
- * Compares three sources:
+ * Compares every release-version source:
* - the git tag this workflow triggered on (`GITHUB_REF_NAME`, e.g.
* `v0.1.0`; a plain argument for local testing), with exactly one
* leading `v` stripped
- * - `package.json`'s `"version"` field
+ * - `package.json`'s `.version` field
+ * - `.claude-plugin/plugin.json`'s `.version` field — the manifest Claude
+ * Code resolves when installing the canonical plugin distribution
+ * - `package-lock.json`'s `.version` and `.packages[""].version` fields.
+ * They are independent root-package declarations and must both move with
+ * the release, while dependency versions in that lockfile do not.
* - `node dist/commitlore.mjs --version` — the same value every build of
* the CLI reports, script or compiled binary, since both read it from
* the same `packageVersion()` (`src/core/paths.ts`) against the same
@@ -37,6 +43,36 @@ import { fileURLToPath } from 'node:url';
const REPO_ROOT = resolve(fileURLToPath(new URL('..', import.meta.url)));
const BUNDLE = join(REPO_ROOT, 'dist', 'commitlore.mjs');
+/**
+ * A missing or malformed manifest is an inability to run this gate (exit 2),
+ * not a version disagreement (exit 1). Name every field it would have
+ * supplied so the release operator knows exactly what to restore or repair.
+ */
+const readManifest = (relativePath, fields) => {
+ const path = join(REPO_ROOT, relativePath);
+ const sources = fields.map((field) => `${relativePath} ${field}`).join(' and ');
+ if (!existsSync(path)) {
+ console.error(`ERROR: ${sources} cannot be checked: required manifest is missing`);
+ process.exit(2);
+ }
+
+ try {
+ return JSON.parse(readFileSync(path, 'utf8'));
+ } catch (error) {
+ const reason = error instanceof Error ? error.message : String(error);
+ console.error(`ERROR: ${sources} cannot be checked: invalid JSON (${reason})`);
+ process.exit(2);
+ }
+};
+
+const requiredVersion = (value, source) => {
+ if (typeof value !== 'string' || value === '') {
+ console.error(`ERROR: ${source} must be a non-empty version string`);
+ process.exit(2);
+ }
+ return value;
+};
+
const tagArg = process.argv[2] ?? process.env.GITHUB_REF_NAME;
if (!tagArg) {
console.error('ERROR: no tag given — pass one as an argument or set GITHUB_REF_NAME');
@@ -54,31 +90,44 @@ if (!existsSync(BUNDLE)) {
process.exit(2);
}
-const pkg = JSON.parse(readFileSync(join(REPO_ROOT, 'package.json'), 'utf8'));
-const pkgVersion = pkg.version;
-if (typeof pkgVersion !== 'string' || pkgVersion === '') {
- console.error('ERROR: package.json has no "version" string');
- process.exit(2);
-}
+const pkg = readManifest('package.json', ['.version']);
+const plugin = readManifest('.claude-plugin/plugin.json', ['.version']);
+const packageLock = readManifest('package-lock.json', ['.version', '.packages[""].version']);
+
+const pkgVersion = requiredVersion(pkg.version, 'package.json .version');
+const pluginVersion = requiredVersion(plugin.version, '.claude-plugin/plugin.json .version');
+const packageLockVersion = requiredVersion(packageLock.version, 'package-lock.json .version');
+const packageLockRootVersion = requiredVersion(
+ packageLock.packages?.['']?.version,
+ 'package-lock.json .packages[""].version',
+);
const cliVersion = execFileSync(process.execPath, [BUNDLE, '--version'], { encoding: 'utf8' }).trim();
const mismatches = [];
-if (tagVersion !== pkgVersion) {
- mismatches.push(`tag "${tagArg}" (${tagVersion}) != package.json "version" (${pkgVersion})`);
-}
-if (pkgVersion !== cliVersion) {
- mismatches.push(`package.json "version" (${pkgVersion}) != \`commitlore --version\` (${cliVersion})`);
-}
-if (tagVersion !== cliVersion) {
- mismatches.push(`tag "${tagArg}" (${tagVersion}) != \`commitlore --version\` (${cliVersion})`);
+const versionSources = [
+ ['package.json .version', pkgVersion],
+ ['.claude-plugin/plugin.json .version', pluginVersion],
+ ['package-lock.json .version', packageLockVersion],
+ ['package-lock.json .packages[""].version', packageLockRootVersion],
+ ['dist/commitlore.mjs --version', cliVersion],
+];
+for (const [source, version] of versionSources) {
+ if (tagVersion !== version) {
+ mismatches.push(`tag "${tagArg}" (${tagVersion}) != ${source} (${version})`);
+ }
}
if (mismatches.length > 0) {
console.error(`ERROR: version mismatch — refusing to release (${mismatches.length} disagreement(s)):`);
for (const m of mismatches) console.error(` - ${m}`);
- console.error(' Delete the tag, fix package.json (and rebuild), and push a corrected tag.');
+ console.error(' Delete the tag, fix every named manifest (and rebuild), and push a corrected tag.');
process.exit(1);
}
-console.log(`version consistent: tag ${tagArg} == package.json ${pkgVersion} == commitlore --version ${cliVersion}`);
+console.log(
+ `version consistent: tag ${tagArg} == package.json .version ${pkgVersion} == ` +
+ `.claude-plugin/plugin.json .version ${pluginVersion} == package-lock.json .version ` +
+ `${packageLockVersion} == package-lock.json .packages[""].version ${packageLockRootVersion} == ` +
+ `dist/commitlore.mjs --version ${cliVersion}`,
+);
diff --git a/src/commands/doctor.ts b/src/commands/doctor.ts
index b8ce245f..905bc6e5 100644
--- a/src/commands/doctor.ts
+++ b/src/commands/doctor.ts
@@ -115,13 +115,14 @@ export interface DoctorCheck {
/** Derived from `status`; never passed in, never read by the exit code. */
severity: Severity;
/**
- * The observation behind the conclusion. Populated per check by a later
- * ticket; `{}` until then, so an absent field never has to be told apart
- * from an empty one.
+ * The observation behind the conclusion. A row without one cannot explain
+ * why its status is trustworthy, so construction rejects empty evidence.
*/
evidence: Record;
/** No shipping check is optional at introduction (PRD §1.4). */
optional: boolean;
+ /** Absence preserves the additive JSON contract for findings that stand alone. */
+ blockedBy?: string;
/** Present only on `skipped`. Omitted, never null. */
skipReason?: SkipReason;
/**
@@ -162,6 +163,45 @@ const escapeConfigValuePattern = (value: string): string =>
const gitOptions = (opts: DoctorOptions) => (opts.cwd === undefined ? {} : { cwd: opts.cwd });
+/** The bound keeps a broken child process from making a JSON report unbounded. */
+const boundedExcerpt = (output: string | null | undefined): {
+ firstLine: string;
+ truncated: 'true' | 'false';
+} => {
+ const [firstLine = ''] = (output ?? '').split(/\r?\n/, 1);
+ return {
+ firstLine: firstLine.slice(0, 200),
+ truncated: firstLine.length > 200 ? 'true' : 'false',
+ };
+};
+
+const streamEvidence = (stream: string, output: string | null | undefined): Record => {
+ const excerpt = boundedExcerpt(output);
+ return {
+ [`${stream}_first_line`]: excerpt.firstLine,
+ [`${stream}_truncated`]: excerpt.truncated,
+ };
+};
+
+/** Reports keep paths useful in bug reports without carrying a user's home directory. */
+const homeRelativePath = (value: string): string => {
+ const home = process.env['HOME'];
+ if (home === undefined || home === '') return value;
+ const escapedHome = home.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
+ return value.replace(new RegExp(`${escapedHome}(?=$|/)`, 'g'), '~');
+};
+
+const normaliseEvidence = (evidence: Record): Record =>
+ Object.fromEntries(
+ Object.entries(evidence).map(([key, value]) => [key, homeRelativePath(value)]),
+ );
+
+const evidenceKey = (value: string): string =>
+ value
+ .replace(/[^A-Za-z0-9]+/g, '_')
+ .replace(/^_+|_+$/g, '')
+ .toLowerCase() || 'remote';
+
/**
* `severity` as a total function of `status` — the only place it is decided.
*
@@ -228,25 +268,37 @@ function check(
needsAttention = status === 'warn' || status === 'fail',
extra: CheckExtra = {},
): DoctorCheck {
+ const evidence = extra.evidence ?? {};
+ if (Object.keys(evidence).length === 0) {
+ throw new Error(`doctor check ${id} has no evidence`);
+ }
return {
- id,
- title,
- status,
- needsAttention,
- detail,
- fix,
- fixed,
- category,
- severity: severityOf(status),
- evidence: extra.evidence ?? {},
- optional: extra.optional ?? false,
+ id,
+ title,
+ status,
+ needsAttention,
+ detail,
+ fix,
+ fixed,
+ category,
+ severity: severityOf(status),
+ evidence: normaliseEvidence(evidence),
+ optional: extra.optional ?? false,
...(extra.skipReason === undefined ? {} : { skipReason: extra.skipReason }),
};
}
+const blocked = (dependency: DoctorCheck, row: DoctorCheck): DoctorCheck => {
+ if (dependency.status === 'ok') {
+ throw new Error(`doctor check ${row.id} cannot repeat an ok finding`);
+ }
+ return { ...row, blockedBy: dependency.id };
+};
+
const checkRefspec = (opts: DoctorOptions): DoctorCheck => {
const title = 'notes fetch refspec';
const remotes = listRemotes(opts);
+ const remoteEvidence = { remotes: remotes.join(', ') || 'none' };
if (remotes.length === 0) {
return check(
@@ -257,6 +309,7 @@ const checkRefspec = (opts: DoctorOptions): DoctorCheck => {
'add a remote, then rerun: commitlore doctor --fix',
false,
false,
+ { evidence: remoteEvidence },
);
}
@@ -305,6 +358,8 @@ const checkRefspec = (opts: DoctorOptions): DoctorCheck => {
.map((remote) => `git config --replace-all remote.${remote}.fetch '${NOTES_REFSPEC}' '^\\+refs/notes/'`)
.join('\n'),
fixed,
+ undefined,
+ { evidence: { ...remoteEvidence, forced: forced.join(', ') } },
);
}
@@ -315,6 +370,9 @@ const checkRefspec = (opts: DoctorOptions): DoctorCheck => {
'warn',
`${missing.join(', ')} does not fetch ${NOTES_REF}, so records pushed by others stay invisible here`,
missing.map((remote) => `git config --add remote.${remote}.fetch '${NOTES_REFSPEC}'`).join('\n'),
+ false,
+ undefined,
+ { evidence: { ...remoteEvidence, missing: missing.join(', ') } },
);
}
@@ -331,6 +389,18 @@ const checkRefspec = (opts: DoctorOptions): DoctorCheck => {
.join('; ')})`,
failed.map(({ remote }) => `git fetch ${remote}`).join('\n'),
fixed,
+ undefined,
+ {
+ evidence: {
+ ...remoteEvidence,
+ ...Object.fromEntries(
+ failed.map(({ remote, result }) => [
+ `fetch_exit_code_${evidenceKey(remote)}`,
+ String(result.code),
+ ]),
+ ),
+ },
+ },
);
}
@@ -348,6 +418,8 @@ const checkRefspec = (opts: DoctorOptions): DoctorCheck => {
: `git fetch succeeds for ${remotes.join(', ')} and covers ${NOTES_REF}`,
fixed ? `git fetch ${remotes[0] ?? 'origin'}` : null,
fixed,
+ undefined,
+ { evidence: remoteEvidence },
);
};
@@ -361,6 +433,10 @@ const checkPush = (opts: DoctorOptions): DoctorCheck => {
const remote = remotes[0] ?? 'origin';
const command = `git push ${remote} ${NOTES_REF}`;
const local = execGit(['rev-parse', '--verify', '--quiet', NOTES_REF], gitOptions(opts));
+ const localEvidence = {
+ remote,
+ local_sha: local.code === 0 ? local.stdout.trim() || 'unknown' : 'none',
+ };
if (local.code !== 0) {
return check(
@@ -368,6 +444,10 @@ const checkPush = (opts: DoctorOptions): DoctorCheck => {
title,
'ok',
`no local mirror yet — nothing to push (${command}, once there is)`,
+ null,
+ false,
+ undefined,
+ { evidence: { ...localEvidence, remote_sha: 'not_queried' } },
);
}
@@ -379,10 +459,30 @@ const checkPush = (opts: DoctorOptions): DoctorCheck => {
'warn',
`could not verify (${remote}: ${advertised.stderr.trim().split('\n')[0] ?? 'git ls-remote failed'})`,
command,
+ false,
+ undefined,
+ {
+ evidence: {
+ ...localEvidence,
+ ls_remote_exit_code: String(advertised.code),
+ ...streamEvidence('ls_remote_stderr', advertised.stderr),
+ },
+ },
);
}
- if (advertised.stdout.split(/\s/)[0] === local.stdout.trim()) {
- return check('notes-push', 'transport', title, 'ok', `${remote} has the current ${NOTES_REF}`);
+ const remoteSha = advertised.stdout.split(/\s/)[0] ?? '';
+ if (remoteSha === local.stdout.trim()) {
+ return check(
+ 'notes-push',
+ 'transport',
+ title,
+ 'ok',
+ `${remote} has the current ${NOTES_REF}`,
+ null,
+ false,
+ undefined,
+ { evidence: { ...localEvidence, remote_sha: remoteSha || 'none' } },
+ );
}
return check(
@@ -391,6 +491,9 @@ const checkPush = (opts: DoctorOptions): DoctorCheck => {
'warn',
`this clone has local records in ${NOTES_REF}; no command pushes them for you`,
command,
+ false,
+ undefined,
+ { evidence: { ...localEvidence, remote_sha: remoteSha || 'none' } },
);
};
@@ -400,7 +503,8 @@ const checkPush = (opts: DoctorOptions): DoctorCheck => {
* The marker is imported from the stub rather than restated, so that doctor
* can never disagree with the installer about what "installed" means.
*/
-const checkHook = (opts: DoctorOptions, runtime: DoctorCheck): DoctorCheck => {
+const checkHook = (ctx: DoctorContext): DoctorCheck => {
+ const { opts } = ctx;
const title = 'commit-msg hook';
const id = 'commit-msg-hook';
const category: Category = 'capture';
@@ -410,18 +514,44 @@ const checkHook = (opts: DoctorOptions, runtime: DoctorCheck): DoctorCheck => {
// somewhere else entirely.
const located = execGit(['rev-parse', '--git-path', 'hooks/commit-msg'], gitOptions(opts));
if (located.code !== 0) {
- return check(id, category, title, 'warn', 'not inside a git repository', install);
+ return check(
+ id,
+ category,
+ title,
+ 'warn',
+ 'not inside a git repository',
+ install,
+ false,
+ undefined,
+ { evidence: { hook_path: 'unavailable', bin: 'not_recorded', node: 'not_recorded' } },
+ );
}
const path = resolve(opts.cwd ?? process.cwd(), located.stdout.trim());
const target = readRecordedHookTarget(opts.cwd ?? process.cwd());
const override = process.env['COMMITLORE_BIN'];
+ const hookEvidence = {
+ hook_path: path,
+ bin: target.bin || '(unset)',
+ node: target.node || '(unset)',
+ ...(override === undefined || override === '' ? {} : { commitlore_bin_override: override }),
+ };
const targetDetail = [
...describeRecordedHookTarget(target),
...(override === undefined || override === '' ? [] : [`COMMITLORE_BIN: ${override}`]),
].join('; ');
if (!existsSync(path)) {
- return check(id, category, title, 'warn', `no commit-msg hook at ${path}; ${targetDetail}`, install);
+ return check(
+ id,
+ category,
+ title,
+ 'warn',
+ `no commit-msg hook at ${path}; ${targetDetail}`,
+ install,
+ false,
+ undefined,
+ { evidence: hookEvidence },
+ );
}
const contents = readFileSync(path, 'utf8');
@@ -433,6 +563,9 @@ const checkHook = (opts: DoctorOptions, runtime: DoctorCheck): DoctorCheck => {
'warn',
`a commit-msg hook exists at ${path} but does not invoke commitlore; ${targetDetail}`,
install,
+ false,
+ undefined,
+ { evidence: hookEvidence },
);
}
@@ -448,6 +581,9 @@ const checkHook = (opts: DoctorOptions, runtime: DoctorCheck): DoctorCheck => {
'warn',
`installed at ${path}, but the stub is out of date — it predates a change to how the hook finds the CLI; ${targetDetail}`,
install,
+ false,
+ undefined,
+ { evidence: hookEvidence },
);
}
@@ -462,6 +598,7 @@ const checkHook = (opts: DoctorOptions, runtime: DoctorCheck): DoctorCheck => {
'ignores it and falls through to the remaining resolution steps',
]),
];
+ const runtime = hookRuntimeOf(ctx);
if (runtime.status !== 'ok') {
const inherited = `installed at ${path}; ${targetDetail}; outcome: ${runtime.detail}`;
// A skipped runtime would make this row a skip too, and a skip has to name
@@ -471,23 +608,62 @@ const checkHook = (opts: DoctorOptions, runtime: DoctorCheck): DoctorCheck => {
// written out rather than cast away so that adding one cannot silently
// produce a reasonless skip here.
if (runtime.status === 'skipped') {
- return check(
+ return blocked(
+ runtime,
+ check(
+ id,
+ category,
+ title,
+ 'skipped',
+ inherited,
+ install,
+ false,
+ false,
+ {
+ evidence: { ...hookEvidence, runtime_status: runtime.status },
+ skipReason: runtime.skipReason ?? 'nothing_applicable',
+ },
+ ),
+ );
+ }
+ return blocked(
+ runtime,
+ check(
id,
category,
title,
- 'skipped',
+ runtime.status,
inherited,
install,
false,
- false,
- { skipReason: runtime.skipReason ?? 'nothing_applicable' },
- );
- }
- return check(id, category, title, runtime.status, inherited, install);
+ undefined,
+ { evidence: { ...hookEvidence, runtime_status: runtime.status } },
+ ),
+ );
}
return problems.length === 0
- ? check(id, category, title, 'ok', `installed at ${path}; ${targetDetail}`)
- : check(id, category, title, 'warn', `installed at ${path}; ${targetDetail}; ${problems.join('; ')}`, install);
+ ? check(
+ id,
+ category,
+ title,
+ 'ok',
+ `installed at ${path}; ${targetDetail}`,
+ null,
+ false,
+ undefined,
+ { evidence: hookEvidence },
+ )
+ : check(
+ id,
+ category,
+ title,
+ 'warn',
+ `installed at ${path}; ${targetDetail}; ${problems.join('; ')}`,
+ install,
+ false,
+ undefined,
+ { evidence: hookEvidence },
+ );
};
/**
@@ -511,15 +687,45 @@ const checkGit = (opts: DoctorOptions): DoctorCheck => {
trailers = parseCommitMessage(PROBE_MESSAGE);
} catch (error) {
const reason = error instanceof Error ? error.message : String(error);
- return check(id, category, title, 'fail', `${version || 'git'} could not parse a probe: ${reason}`, upgrade);
+ return check(
+ id,
+ category,
+ title,
+ 'fail',
+ `${version || 'git'} could not parse a probe: ${reason}`,
+ upgrade,
+ false,
+ undefined,
+ { evidence: { git_version: version || 'unavailable', parsed: 'unavailable' } },
+ );
}
const parsed = trailers.map((trailer) => `${trailer.key}: ${trailer.value}`).join(', ');
if (parsed !== 'Limit: probe, Blast: local') {
- return check(id, category, title, 'fail', `${version} parsed the probe as [${parsed}]`, upgrade);
+ return check(
+ id,
+ category,
+ title,
+ 'fail',
+ `${version} parsed the probe as [${parsed}]`,
+ upgrade,
+ false,
+ undefined,
+ { evidence: { git_version: version || 'unavailable', parsed } },
+ );
}
- return check(id, category, title, 'ok', `${version} parses trailers as the spec expects`);
+ return check(
+ id,
+ category,
+ title,
+ 'ok',
+ `${version} parses trailers as the spec expects`,
+ null,
+ false,
+ undefined,
+ { evidence: { git_version: version || 'unavailable', parsed } },
+ );
};
/**
@@ -560,6 +766,15 @@ const checkRuntime = (opts: DoctorOptions): DoctorCheck => {
'fail',
`no built CLI at ${candidates.join(' or ')} — this checkout has not been built`,
'npm install && npm run build',
+ false,
+ undefined,
+ {
+ evidence: {
+ entry: candidates.join(' or '),
+ exit_code: 'not_run',
+ ...streamEvidence('stderr', ''),
+ },
+ },
);
}
@@ -570,14 +785,63 @@ const checkRuntime = (opts: DoctorOptions): DoctorCheck => {
});
if (run.error !== undefined) {
- return check(id, category, title, 'fail', `could not run ${entry}: ${run.error.message}`, null);
+ return check(
+ id,
+ category,
+ title,
+ 'fail',
+ `could not run ${entry}: ${run.error.message}`,
+ null,
+ false,
+ undefined,
+ {
+ evidence: {
+ entry,
+ exit_code: String(run.status ?? 'unavailable'),
+ error: run.error.message,
+ ...streamEvidence('stderr', run.stderr),
+ },
+ },
+ );
}
if (run.status !== 0) {
const detail = `${run.stderr ?? ''}`.trim().split('\n')[0] ?? `exit ${String(run.status)}`;
- return check(id, category, title, 'fail', `${entry} exits ${String(run.status)}: ${detail}`, 'npm install');
+ return check(
+ id,
+ category,
+ title,
+ 'fail',
+ `${entry} exits ${String(run.status)}: ${detail}`,
+ 'npm install',
+ false,
+ undefined,
+ {
+ evidence: {
+ entry,
+ exit_code: String(run.status),
+ ...streamEvidence('stderr', run.stderr),
+ },
+ },
+ );
}
- return check(id, category, title, 'ok', `${entry} runs (${run.stdout.trim()})`);
+ return check(
+ id,
+ category,
+ title,
+ 'ok',
+ `${entry} runs (${run.stdout.trim()})`,
+ null,
+ false,
+ undefined,
+ {
+ evidence: {
+ entry,
+ version: boundedExcerpt(run.stdout).firstLine,
+ ...streamEvidence('stdout', run.stdout),
+ },
+ },
+ );
};
/**
@@ -607,12 +871,42 @@ const checkHookRuntime = (opts: DoctorOptions): DoctorCheck => {
const cwd = opts.cwd ?? process.cwd();
const located = execGit(['rev-parse', '--git-path', 'hooks/commit-msg'], gitOptions(opts));
- if (located.code !== 0) return check(id, category, title, 'warn', 'not inside a git repository', fix);
+ if (located.code !== 0) {
+ return check(
+ id,
+ category,
+ title,
+ 'warn',
+ 'not inside a git repository',
+ fix,
+ false,
+ undefined,
+ {
+ evidence: {
+ hook_path: 'unavailable',
+ exit_code: String(located.code),
+ ...streamEvidence('stderr', located.stderr),
+ },
+ },
+ );
+ }
const hook = resolve(cwd, located.stdout.trim());
// The hook's absence is `checkHook`'s finding; saying it twice teaches the
// reader to skim both.
- if (!existsSync(hook)) return check(id, category, title, 'ok', 'no hook installed — nothing to run');
+ if (!existsSync(hook)) {
+ return check(
+ id,
+ category,
+ title,
+ 'ok',
+ 'no hook installed — nothing to run',
+ null,
+ false,
+ undefined,
+ { evidence: { hook_path: hook } },
+ );
+ }
const probe = join(tmpdirPath(), `commitlore-doctor-${String(process.pid)}.txt`);
try {
@@ -627,7 +921,24 @@ const checkHookRuntime = (opts: DoctorOptions): DoctorCheck => {
});
if (run.error !== undefined) {
- return check(id, category, title, 'fail', `could not run the hook: ${run.error.message}`, fix);
+ return check(
+ id,
+ category,
+ title,
+ 'fail',
+ `could not run the hook: ${run.error.message}`,
+ fix,
+ false,
+ undefined,
+ {
+ evidence: {
+ hook_path: hook,
+ exit_code: String(run.status ?? 'unavailable'),
+ error: run.error.message,
+ ...streamEvidence('stderr', run.stderr),
+ },
+ },
+ );
}
if (run.status !== 0) {
const said = `${run.stderr ?? ''}`.trim().split('\n')[0] ?? '';
@@ -644,9 +955,35 @@ const checkHookRuntime = (opts: DoctorOptions): DoctorCheck => {
} else {
detail = `the hook exited ${String(run.status)} under the restricted PATH — cause unclear: ${said || 'no output'}`;
}
- return check(id, category, title, 'fail', detail, fix);
+ return check(
+ id,
+ category,
+ title,
+ 'fail',
+ detail,
+ fix,
+ false,
+ undefined,
+ {
+ evidence: {
+ hook_path: hook,
+ exit_code: String(run.status),
+ ...streamEvidence('stderr', run.stderr),
+ },
+ },
+ );
}
- return check(id, category, title, 'ok', 'the hook runs and validates without node on PATH');
+ return check(
+ id,
+ category,
+ title,
+ 'ok',
+ 'the hook runs and validates without node on PATH',
+ null,
+ false,
+ undefined,
+ { evidence: { hook_path: hook, exit_code: '0' } },
+ );
} catch (error) {
return check(
id,
@@ -655,6 +992,16 @@ const checkHookRuntime = (opts: DoctorOptions): DoctorCheck => {
'warn',
`could not probe the hook: ${error instanceof Error ? error.message : String(error)}`,
fix,
+ false,
+ undefined,
+ {
+ evidence: {
+ hook_path: hook,
+ exit_code: 'unavailable',
+ error: error instanceof Error ? error.message : String(error),
+ ...streamEvidence('stderr', ''),
+ },
+ },
);
} finally {
rmSync(probe, { force: true });
@@ -703,6 +1050,7 @@ export const evaluateInjectRun = (
},
): DoctorCheck => {
const { id, category, title, executable, path, fix, unavailableFix } = ctx;
+ const executionEvidence = { executable, path };
if (run.status === null || run.status === undefined) {
if (run.error !== undefined && 'code' in run.error && run.error.code === 'ENOENT') {
@@ -713,6 +1061,15 @@ export const evaluateInjectRun = (
'fail',
`configured PreToolUse hook executable ${JSON.stringify(executable)} is not resolvable from PATH`,
unavailableFix,
+ false,
+ undefined,
+ {
+ evidence: {
+ ...executionEvidence,
+ exit_code: 'unavailable',
+ ...streamEvidence('stderr', run.stderr),
+ },
+ },
);
}
return check(
@@ -722,6 +1079,16 @@ export const evaluateInjectRun = (
'fail',
`could not run the PreToolUse hook: ${run.error?.message ?? 'no diagnosis'}`,
fix,
+ false,
+ undefined,
+ {
+ evidence: {
+ ...executionEvidence,
+ exit_code: 'unavailable',
+ error: run.error?.message ?? 'no diagnosis',
+ ...streamEvidence('stderr', run.stderr),
+ },
+ },
);
}
@@ -734,6 +1101,15 @@ export const evaluateInjectRun = (
'fail',
`the PreToolUse hook exits ${String(run.status)}: ${said || 'no diagnosis'}`,
fix,
+ false,
+ undefined,
+ {
+ evidence: {
+ ...executionEvidence,
+ exit_code: String(run.status),
+ ...streamEvidence('stderr', run.stderr),
+ },
+ },
);
}
if (`${run.stdout ?? ''}`.trim() === '') {
@@ -745,9 +1121,35 @@ export const evaluateInjectRun = (
'fail',
`the PreToolUse hook returned no context for a known-good payload${said === '' ? '' : `: ${said}`}`,
fix,
+ false,
+ undefined,
+ {
+ evidence: {
+ ...executionEvidence,
+ exit_code: '0',
+ ...streamEvidence('stdout', run.stdout),
+ ...streamEvidence('stderr', run.stderr),
+ },
+ },
);
}
- return check(id, category, title, 'ok', `the PreToolUse hook returned context for ${path}`);
+ return check(
+ id,
+ category,
+ title,
+ 'ok',
+ `the PreToolUse hook returned context for ${path}`,
+ null,
+ false,
+ undefined,
+ {
+ evidence: {
+ ...executionEvidence,
+ exit_code: '0',
+ ...streamEvidence('stdout', run.stdout),
+ },
+ },
+ );
};
const checkInjectRuntime = (opts: DoctorOptions): DoctorCheck => {
@@ -772,26 +1174,95 @@ const checkInjectRuntime = (opts: DoctorOptions): DoctorCheck => {
null,
false,
false,
- { skipReason: 'command_unrecognized' },
+ {
+ evidence: {
+ settings_path: settings.settingsPath,
+ settings_state: settings.state,
+ configured_command: command,
+ executable: 'not_run',
+ exit_code: 'not_run',
+ ...streamEvidence('stderr', ''),
+ },
+ skipReason: 'command_unrecognized',
+ },
);
}
const detail =
settings.state === 'absent'
? `not installed in ${settings.settingsPath}`
: `${settings.state} in ${settings.settingsPath}${settings.problem === undefined ? '' : `: ${settings.problem}`}`;
- return check(id, category, title, 'warn', detail, 'commitlore inject install-claude-hook');
+ return check(
+ id,
+ category,
+ title,
+ 'warn',
+ detail,
+ 'commitlore inject install-claude-hook',
+ false,
+ undefined,
+ {
+ evidence: {
+ settings_path: settings.settingsPath,
+ settings_state: settings.state,
+ executable: 'not_run',
+ exit_code: 'not_run',
+ ...streamEvidence('stderr', ''),
+ ...(settings.problem === undefined ? {} : { problem: settings.problem }),
+ },
+ },
+ );
}
const command = settings.commands[0];
if (command !== CLAUDE_HOOK_COMMAND) {
- return check(id, category, title, 'skipped', 'not checked: the configured command is not recognised', null, false, false, { skipReason: 'command_unrecognized' });
+ return check(
+ id,
+ category,
+ title,
+ 'skipped',
+ 'not checked: the configured command is not recognised',
+ null,
+ false,
+ false,
+ {
+ evidence: {
+ settings_path: settings.settingsPath,
+ settings_state: settings.state,
+ configured_command: command ?? 'none',
+ executable: 'not_run',
+ exit_code: 'not_run',
+ ...streamEvidence('stderr', ''),
+ },
+ skipReason: 'command_unrecognized',
+ },
+ );
}
const path = runQuery({ cwd, noIndex: true }).records
.flatMap((record) => record.paths)
.find((candidate) => candidate !== '' && candidate !== '.');
if (path === undefined) {
- return check(id, category, title, 'skipped', 'no recorded path is available for a runtime probe', null, false, false, { skipReason: 'probe_path_unavailable' });
+ return check(
+ id,
+ category,
+ title,
+ 'skipped',
+ 'no recorded path is available for a runtime probe',
+ null,
+ false,
+ false,
+ {
+ evidence: {
+ settings_path: settings.settingsPath,
+ settings_state: settings.state,
+ executable: 'not_run',
+ probe_path: 'unavailable',
+ exit_code: 'not_run',
+ ...streamEvidence('stderr', ''),
+ },
+ skipReason: 'probe_path_unavailable',
+ },
+ );
}
const payload = JSON.stringify({
@@ -854,7 +1325,10 @@ const checkInjectRuntime = (opts: DoctorOptions): DoctorCheck => {
*/
const SEMVER_ISH = /^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)*$/;
-const checkInjectVersion = (opts: DoctorOptions): DoctorCheck => {
+const checkInjectVersion = (
+ opts: DoctorOptions,
+ dependencies: ReadonlyMap,
+): DoctorCheck => {
const title = 'PreToolUse hook version';
const id = 'inject-version';
const category: Category = 'delivery';
@@ -863,11 +1337,42 @@ const checkInjectVersion = (opts: DoctorOptions): DoctorCheck => {
const settings = readClaudeHookStatus(claudeSettingsPath(cwd));
if (settings.state !== 'installed') {
- return check(id, category, title, 'skipped', `no installed hook to compare against ${mine}`, null, false, false, { skipReason: 'hook_not_installed' });
+ return check(
+ id,
+ category,
+ title,
+ 'skipped',
+ `no installed hook to compare against ${mine}`,
+ null,
+ false,
+ false,
+ {
+ evidence: { executable: 'not_run', theirs: 'not_run', mine },
+ skipReason: 'hook_not_installed',
+ },
+ );
}
const command = settings.commands[0];
if (command !== CLAUDE_HOOK_COMMAND) {
- return check(id, category, title, 'skipped', 'not checked: the configured command is not recognised', null, false, false, { skipReason: 'command_unrecognized' });
+ return check(
+ id,
+ category,
+ title,
+ 'skipped',
+ 'not checked: the configured command is not recognised',
+ null,
+ false,
+ false,
+ {
+ evidence: {
+ executable: 'not_run',
+ theirs: 'not_run',
+ mine,
+ configured_command: command ?? 'none',
+ },
+ skipReason: 'command_unrecognized',
+ },
+ );
}
const configured = command.replace(` ${CLAUDE_HOOK_MARKER}`, '');
@@ -881,11 +1386,31 @@ const checkInjectVersion = (opts: DoctorOptions): DoctorCheck => {
HOME: process.env['HOME'] ?? '',
},
});
+ const reported = typeof run.stdout === 'string' ? run.stdout : '';
+ const versionEvidence = {
+ executable,
+ theirs: boundedExcerpt(reported).firstLine || 'unavailable',
+ mine,
+ exit_code: String(run.status ?? 'unavailable'),
+ ...streamEvidence('stdout', reported),
+ };
if (run.status !== 0 || typeof run.stdout !== 'string') {
// `checkInjectRuntime` owns "the hook does not run at all" and reports it
// with the remedy. Saying it twice would be noise.
- return check(id, category, title, 'skipped', `${executable} did not report a version`, null, false, false, { skipReason: 'version_unreadable' });
+ const skipped = check(
+ id,
+ category,
+ title,
+ 'skipped',
+ `${executable} did not report a version`,
+ null,
+ false,
+ false,
+ { evidence: versionEvidence, skipReason: 'version_unreadable' },
+ );
+ const runtime = dependencies.get('inject-runtime');
+ return runtime === undefined || runtime.status === 'ok' ? skipped : blocked(runtime, skipped);
}
const theirs = run.stdout.trim();
@@ -903,11 +1428,21 @@ const checkInjectVersion = (opts: DoctorOptions): DoctorCheck => {
null,
false,
false,
- { skipReason: 'version_unreadable' },
+ { evidence: versionEvidence, skipReason: 'version_unreadable' },
);
}
if (theirs === mine) {
- return check(id, category, title, 'ok', `the hook runs ${theirs}, the same build as this CLI`);
+ return check(
+ id,
+ category,
+ title,
+ 'ok',
+ `the hook runs ${theirs}, the same build as this CLI`,
+ null,
+ false,
+ undefined,
+ { evidence: versionEvidence },
+ );
}
return check(
@@ -917,6 +1452,9 @@ const checkInjectVersion = (opts: DoctorOptions): DoctorCheck => {
'warn',
`the agent's hook runs ${theirs} but this CLI is ${mine} — every edit is graded by ${theirs}'s rules, not this one's`,
'update the installation the hook resolves to (for the plugin: /plugin marketplace update commitlore), then rerun: commitlore doctor',
+ false,
+ undefined,
+ { evidence: versionEvidence },
);
};
@@ -943,7 +1481,17 @@ const checkMcpLifecycle = (opts: DoctorOptions): DoctorCheck => {
const unfinished = unfinishedRuns(cwd);
if (unfinished.length === 0) {
- return check(id, category, title, 'ok', 'every recorded MCP session ended cleanly, or is still running');
+ return check(
+ id,
+ category,
+ title,
+ 'ok',
+ 'every recorded MCP session ended cleanly, or is still running',
+ null,
+ false,
+ undefined,
+ { evidence: { unfinished_count: '0', last_pid: 'none', last_at: 'none' } },
+ );
}
const last = unfinished[unfinished.length - 1];
@@ -956,6 +1504,15 @@ const checkMcpLifecycle = (opts: DoctorOptions): DoctorCheck => {
`most recently pid ${String(last?.pid ?? 0)} at ${last?.at ?? 'unknown'}. ` +
'A killed server loses its tool registration in the client, which reports the same as a tool that never existed (#424)',
'restart the client session; if this repeats, capture it with a client started under --debug',
+ false,
+ undefined,
+ {
+ evidence: {
+ unfinished_count: String(unfinished.length),
+ last_pid: String(last?.pid ?? 0),
+ last_at: last?.at ?? 'unknown',
+ },
+ },
);
};
@@ -992,7 +1549,17 @@ const checkPendingBacklog = (opts: DoctorOptions): DoctorCheck => {
try {
listing = runPendingList({ cwd });
} catch {
- return check(id, category, title, 'ok', 'no pending directory — nothing has been captured here yet');
+ return check(
+ id,
+ category,
+ title,
+ 'ok',
+ 'no pending directory — nothing has been captured here yet',
+ null,
+ false,
+ undefined,
+ { evidence: { stranded: '0', staged_expired: '0', oldest: 'none' } },
+ );
}
if (listing.unreadable.length > 0) {
@@ -1003,6 +1570,16 @@ const checkPendingBacklog = (opts: DoctorOptions): DoctorCheck => {
'warn',
`${listing.unreadable.length} pending file(s) cannot be read as a transaction`,
'commitlore pending ls',
+ false,
+ undefined,
+ {
+ evidence: {
+ stranded: '0',
+ staged_expired: '0',
+ oldest: 'none',
+ unreadable: String(listing.unreadable.length),
+ },
+ },
);
}
@@ -1017,6 +1594,17 @@ const checkPendingBacklog = (opts: DoctorOptions): DoctorCheck => {
title,
'ok',
held === 0 ? 'no captures are waiting' : `${String(held)} capture(s) waiting, all still able to apply`,
+ null,
+ false,
+ undefined,
+ {
+ evidence: {
+ stranded: '0',
+ staged_expired: '0',
+ oldest: 'none',
+ waiting: String(held),
+ },
+ },
);
}
@@ -1043,8 +1631,17 @@ const checkPendingBacklog = (opts: DoctorOptions): DoctorCheck => {
'warn',
`${detail}; oldest from ${oldest ?? 'an unknown time'}. ` +
'A staged record binds to the tree it was prepared for and is skipped once that tree moves, ' +
- 'so these decisions were never written to the history (#458)',
+ 'so these decisions were never written to the history (#458)',
'commitlore pending ls',
+ false,
+ undefined,
+ {
+ evidence: {
+ stranded: String(stranded.length),
+ staged_expired: String(lost.length),
+ oldest: oldest ?? 'unknown',
+ },
+ },
);
};
@@ -1060,6 +1657,17 @@ const checkIndex = (opts: DoctorOptions): DoctorCheck => {
'warn',
'no index yet — queries fall back to scanning the history',
'commitlore index --rebuild',
+ false,
+ undefined,
+ {
+ evidence: {
+ trailers: '0',
+ commits: '0',
+ last_indexed_sha: 'none',
+ head_sha: 'not_queried',
+ fts: 'unavailable',
+ },
+ },
);
}
try {
@@ -1067,6 +1675,13 @@ const checkIndex = (opts: DoctorOptions): DoctorCheck => {
const head = execGit(['rev-parse', 'HEAD'], gitOptions(opts));
const behind = head.code === 0 && info.lastIndexedSha !== head.stdout.trim();
const fts = info.fts ? 'FTS5' : 'no FTS5 (value search falls back to LIKE)';
+ const indexEvidence = {
+ trailers: String(info.trailers),
+ commits: String(info.commits),
+ last_indexed_sha: info.lastIndexedSha || 'none',
+ head_sha: head.code === 0 ? head.stdout.trim() || 'none' : 'unavailable',
+ fts: info.fts ? 'true' : 'false',
+ };
return behind
? check(
'index-health', 'index',
@@ -1074,12 +1689,19 @@ const checkIndex = (opts: DoctorOptions): DoctorCheck => {
'warn',
`${info.trailers} trailers over ${info.commits} commits, behind HEAD — ${fts}`,
'commitlore index',
+ false,
+ undefined,
+ { evidence: indexEvidence },
)
: check(
'index-health', 'index',
'index health',
'ok',
`${info.trailers} trailers over ${info.commits} commits, current with HEAD — ${fts}`,
+ null,
+ false,
+ undefined,
+ { evidence: indexEvidence },
);
} catch (error) {
return check(
@@ -1088,6 +1710,17 @@ const checkIndex = (opts: DoctorOptions): DoctorCheck => {
'warn',
`index unreadable (${error instanceof Error ? error.message : String(error)}) — queries still work without it`,
'commitlore index --rebuild',
+ false,
+ undefined,
+ {
+ evidence: {
+ trailers: 'unavailable',
+ commits: 'unavailable',
+ last_indexed_sha: 'unavailable',
+ head_sha: 'unavailable',
+ fts: 'unavailable',
+ },
+ },
);
} finally {
try {
@@ -1106,8 +1739,21 @@ const checkHistoryDepth = (opts: DoctorOptions): DoctorCheck =>
'warn',
'this clone has shallow history, so queries may be missing records that exist upstream',
'git fetch --unshallow',
+ false,
+ undefined,
+ { evidence: { shallow: 'true' } },
)
- : check('history-depth', 'history', 'history depth', 'ok', 'full history is available');
+ : check(
+ 'history-depth',
+ 'history',
+ 'history depth',
+ 'ok',
+ 'full history is available',
+ null,
+ false,
+ undefined,
+ { evidence: { shallow: 'false' } },
+ );
/** Local branches this check will look at, past which a repository is skipped rather than walked exhaustively. */
const MAX_SQUASH_CANDIDATE_BRANCHES = 200;
@@ -1196,7 +1842,20 @@ const checkSquashConservation = (opts: DoctorOptions): DoctorCheck => {
const head = execGit(['rev-parse', '--verify', '--quiet', 'HEAD'], gitOptions(opts));
if (head.code !== 0) {
- return check(id, category, title, 'skipped', 'no HEAD yet — nothing to compare against', null, false, false, { skipReason: 'unborn_head' });
+ return check(
+ id,
+ category,
+ title,
+ 'skipped',
+ 'no HEAD yet — nothing to compare against',
+ null,
+ false,
+ false,
+ {
+ evidence: { candidates: '0', checked: '0', uncheckable: '0', lost_count: '0' },
+ skipReason: 'unborn_head',
+ },
+ );
}
const candidates = squashCandidates(opts, head.stdout.trim());
@@ -1210,7 +1869,10 @@ const checkSquashConservation = (opts: DoctorOptions): DoctorCheck => {
null,
false,
false,
- { skipReason: 'nothing_applicable' },
+ {
+ evidence: { candidates: '0', checked: '0', uncheckable: '0', lost_count: '0' },
+ skipReason: 'nothing_applicable',
+ },
);
}
@@ -1265,7 +1927,15 @@ const checkSquashConservation = (opts: DoctorOptions): DoctorCheck => {
null,
false,
false,
- { skipReason: 'nothing_applicable' },
+ {
+ evidence: {
+ candidates: String(candidates.length),
+ checked: '0',
+ uncheckable: String(uncheckable),
+ lost_count: '0',
+ },
+ skipReason: 'nothing_applicable',
+ },
);
}
@@ -1283,6 +1953,16 @@ const checkSquashConservation = (opts: DoctorOptions): DoctorCheck => {
`${lost.length} record(s) declared on a branch not reachable from HEAD do not appear in HEAD's history: ${named}${more}`,
'commitlore squash-preserve .. --target , ' +
'then commit or attach the result',
+ false,
+ undefined,
+ {
+ evidence: {
+ candidates: String(candidates.length),
+ checked: String(checked),
+ uncheckable: String(uncheckable),
+ lost_count: String(lost.length),
+ },
+ },
);
}
@@ -1291,7 +1971,24 @@ const checkSquashConservation = (opts: DoctorOptions): DoctorCheck => {
? `${checked} squash-shaped branch(es) checked, every declared Record-Id is reachable from HEAD ` +
`(${uncheckable} branch(es) recorded nothing with an id and could not be checked this way)`
: `${checked} squash-shaped branch(es) checked, every declared Record-Id is reachable from HEAD`;
- return check(id, category, title, 'ok', detail);
+ return check(
+ id,
+ category,
+ title,
+ 'ok',
+ detail,
+ null,
+ false,
+ undefined,
+ {
+ evidence: {
+ candidates: String(candidates.length),
+ checked: String(checked),
+ uncheckable: String(uncheckable),
+ lost_count: '0',
+ },
+ },
+ );
};
/**
@@ -1324,7 +2021,7 @@ export interface CheckDefinition {
/** Ids of entries that appear earlier in this registry (PRD §2 req 2). */
readonly dependencies: readonly string[];
readonly optional: boolean;
- readonly run: (ctx: DoctorContext) => DoctorCheck;
+ readonly run: (ctx: DoctorContext, dependencies: ReadonlyMap) => DoctorCheck;
}
/** Runs `hook-runtime` at most once per report, whichever row asks first. */
@@ -1341,19 +2038,18 @@ const hookRuntimeOf = (ctx: DoctorContext): DoctorCheck => {
* `runDoctor` shipped with, because PRD §9.1 holds the text byte-identical
* until the rendering ticket.
*
- * `commit-msg-hook → hook-runtime` is deliberately not declared here: the
- * dependency runs backwards against this order, and §2 req 2 admits only
- * earlier entries. It is threaded through `memo` instead and declared once the
- * ordering rule is settled.
+ * `commit-msg-hook → hook-runtime` stays in the runner's memo because the
+ * frozen presentation order puts the consumer first. Declaring it backwards
+ * would make the registry claim an ordering guarantee it cannot keep.
*/
export const CHECK_REGISTRY: readonly CheckDefinition[] = [
{ id: 'cli-runtime', title: 'cli runtime', category: 'runtime', dependencies: [], optional: false, run: (ctx) => checkRuntime(ctx.opts) },
{ id: 'notes-refspec', title: 'notes fetch refspec', category: 'transport', dependencies: [], optional: false, run: (ctx) => checkRefspec(ctx.opts) },
{ id: 'notes-push', title: 'notes push', category: 'transport', dependencies: [], optional: false, run: (ctx) => checkPush(ctx.opts) },
- { id: 'commit-msg-hook', title: 'commit-msg hook', category: 'capture', dependencies: [], optional: false, run: (ctx) => checkHook(ctx.opts, hookRuntimeOf(ctx)) },
+ { id: 'commit-msg-hook', title: 'commit-msg hook', category: 'capture', dependencies: [], optional: false, run: (ctx) => checkHook(ctx) },
{ id: 'hook-runtime', title: 'hook runtime', category: 'capture', dependencies: [], optional: false, run: hookRuntimeOf },
{ id: 'inject-runtime', title: 'PreToolUse hook runtime', category: 'delivery', dependencies: [], optional: false, run: (ctx) => checkInjectRuntime(ctx.opts) },
- { id: 'inject-version', title: 'PreToolUse hook version', category: 'delivery', dependencies: ['inject-runtime'], optional: false, run: (ctx) => checkInjectVersion(ctx.opts) },
+ { id: 'inject-version', title: 'PreToolUse hook version', category: 'delivery', dependencies: ['inject-runtime'], optional: false, run: (ctx, dependencies) => checkInjectVersion(ctx.opts, dependencies) },
{ id: 'mcp-lifecycle', title: 'MCP server sessions', category: 'delivery', dependencies: [], optional: false, run: (ctx) => checkMcpLifecycle(ctx.opts) },
{ id: 'pending-backlog', title: 'pending captures', category: 'capture', dependencies: [], optional: false, run: (ctx) => checkPendingBacklog(ctx.opts) },
{ id: 'git-trailers', title: 'git interpret-trailers', category: 'runtime', dependencies: [], optional: false, run: (ctx) => checkGit(ctx.opts) },
@@ -1370,9 +2066,13 @@ export const CHECK_REGISTRY: readonly CheckDefinition[] = [
* is the worst possible trade, so the throw is contained and reported as what
* it is: this check could not complete.
*/
-const containedRun = (definition: CheckDefinition, ctx: DoctorContext): DoctorCheck => {
+const containedRun = (
+ definition: CheckDefinition,
+ ctx: DoctorContext,
+ dependencies: ReadonlyMap,
+): DoctorCheck => {
try {
- return definition.run(ctx);
+ return definition.run(ctx, dependencies);
} catch (error) {
const message = error instanceof Error ? error.message : String(error);
return check(
@@ -1389,17 +2089,60 @@ const containedRun = (definition: CheckDefinition, ctx: DoctorContext): DoctorCh
}
};
+const statusRank = (status: CheckStatus): number =>
+ status === 'fail' ? 3 : status === 'warn' ? 2 : status === 'skipped' ? 1 : 0;
+
+const collapseBlockedBy = (checks: readonly DoctorCheck[]): DoctorCheck[] => {
+ const byId = new Map(checks.map((row) => [row.id, row]));
+
+ return checks.map((row) => {
+ if (row.blockedBy === undefined) return row;
+
+ const visited = new Set([row.id]);
+ let root = byId.get(row.blockedBy);
+ while (root !== undefined && root.blockedBy !== undefined) {
+ if (visited.has(root.id)) {
+ throw new Error(`doctor check ${row.id} has a cyclic blockedBy chain`);
+ }
+ visited.add(root.id);
+ root = byId.get(root.blockedBy);
+ }
+ if (root === undefined) {
+ throw new Error(`doctor check ${row.id} names an unknown blocker`);
+ }
+ if (root.status === 'ok') {
+ throw new Error(`doctor check ${row.id} names an ok blocker`);
+ }
+ if (statusRank(row.status) > statusRank(root.status)) {
+ throw new Error(`doctor check ${row.id} is more severe than its blocker`);
+ }
+ return root.id === row.blockedBy ? row : { ...row, blockedBy: root.id };
+ });
+};
+
export const runDoctor = (opts: DoctorOptions = {}): DoctorReport => {
const ctx: DoctorContext = { opts, now: process.hrtime.bigint, memo: new Map() };
+ const completed = new Map();
const checks = CHECK_REGISTRY.map((definition) => {
+ const dependencies = new Map();
+ for (const dependency of definition.dependencies) {
+ const row = completed.get(dependency);
+ if (row === undefined) {
+ throw new Error(`doctor check ${definition.id} depends on ${dependency}, which has not run`);
+ }
+ dependencies.set(dependency, row);
+ }
const started = ctx.now();
- const row = containedRun(definition, ctx);
+ const row = containedRun(definition, ctx, dependencies);
const elapsed = Number((ctx.now() - started) / 1_000_000n);
- return { ...row, durationMs: elapsed < 0 ? 0 : elapsed };
+ const timed = { ...row, durationMs: elapsed < 0 ? 0 : elapsed };
+ completed.set(definition.id, timed);
+ return timed;
});
+ const collapsed = collapseBlockedBy(checks);
return {
- checks,
- exitCode: checks.some((entry) => entry.status === 'fail') ? 1 : 0,
+ checks: collapsed,
+ exitCode: collapsed.some((entry) => entry.status === 'fail') ? 1 : 0,
};
};
diff --git a/src/commands/inject.ts b/src/commands/inject.ts
index 35f7fca1..1edd11b6 100644
--- a/src/commands/inject.ts
+++ b/src/commands/inject.ts
@@ -232,10 +232,20 @@ const injectOptions = (
): InjectOptions => {
const at = evaluationInstant(options.at);
const budget = tokenBudget(options.budget);
- // #415: with no flag and no configured authors this is empty, and grading
- // fails closed to `claim`. The installed hook passes no flag, so the config
- // value written at `init` is the only route to a `[directive]` in practice.
- const trustedAuthors = options.trustedAuthor ?? configuredTrustedAuthors(cwd);
+ // #415: the installed hook passes no flag, so the config value written at
+ // `init` is the only route to a `[directive]` in practice.
+ //
+ // The nullish check that used to stand here never fired. Commander declares
+ // `--trusted-author` with a default of `[]`, so `options.trustedAuthor` is an
+ // empty array rather than `undefined` when the flag is absent, `?? ` passes
+ // it through, and every record graded `claim` on every install — exactly the
+ // defect #415 was opened about, reintroduced one layer up by the fix for it.
+ //
+ // Length is the test that matches what the caller meant: an explicit flag is
+ // always non-empty, and an absent flag is always empty, whichever of the two
+ // shapes Commander hands over.
+ const flagged = options.trustedAuthor ?? [];
+ const trustedAuthors = flagged.length > 0 ? flagged : configuredTrustedAuthors(cwd);
return {
path,
cwd,
diff --git a/src/commands/query.ts b/src/commands/query.ts
index 776faec5..a344e573 100644
--- a/src/commands/query.ts
+++ b/src/commands/query.ts
@@ -32,6 +32,7 @@ import {
type TrustGrade,
} from '../core/query.js';
import { validateRecord } from '../core/schema.js';
+import { configuredTrustedAuthors } from '../core/trusted-authors.js';
import { splitRuledOut } from '../core/trailers.js';
import { STRUCTURAL_TRAILER_KEYS, type Lifecycle, type Trailer } from '../core/types.js';
@@ -177,10 +178,20 @@ const queryOptions = (
): QueryOptions => {
const at = evaluationInstant(options.at);
const limit = recordLimit(options.limit);
- // Same spelling and same default as `commitlore inject`: with no trusted
- // author, a `Warn:` grades `claim`. The two routes must answer alike, or the
- // grade means one thing on the hook and another on the terminal.
- const trustedAuthors = options.trustedAuthor ?? [];
+ // Same spelling and same resolution as `commitlore inject`: the two routes
+ // must answer alike, or the grade means one thing on the hook and another on
+ // the terminal. That sentence was already here while the two routes did in
+ // fact disagree — `inject` fell back to the configured authors and this did
+ // not, so `context` reported `claim` for a record the hook would have
+ // rendered `directive`.
+ //
+ // Length rather than nullishness, for the reason #484 records: commander
+ // declares this option with a default of `[]`, so an absent flag is an empty
+ // array and never a nullish value.
+ const flagged = options.trustedAuthor ?? [];
+ // This route has no cwd of its own; it reads the repository it was invoked
+ // in, the same one `runQuery` resolves against.
+ const trustedAuthors = flagged.length > 0 ? flagged : configuredTrustedAuthors(process.cwd());
return {
paths,
allHistory: options.allHistory === true,
diff --git a/test/bench-report.test.ts b/test/bench-report.test.ts
index e465380e..2869aaa6 100644
--- a/test/bench-report.test.ts
+++ b/test/bench-report.test.ts
@@ -32,8 +32,7 @@ import {
buildReport,
declarationFor,
readSources,
- renderSection,
-} from '../bench/report.ts';
+ renderSection, progressOf } from '../bench/report.ts';
const REPO_ROOT = path.resolve(import.meta.dirname, '..');
const FIXTURES = 'test/fixtures/bench';
@@ -281,7 +280,15 @@ describe('a partial matrix is labelled as one', () => {
it('says how many of the planned runs are recorded', () => {
const markdown = report(PARTIAL);
expect(markdown).toContain('**Measurement in progress — 12 of 24 planned runs recorded.**');
- expect(json(PARTIAL).progress).toEqual({ state: 'in-progress', recorded: 12, planned: 24 });
+ // `distinct` counts task-arm-seed cells rather than rows, so a study that
+ // re-ran a shard does not publish its file count as its size. Equal here
+ // because nothing in this fixture is a re-run.
+ expect(json(PARTIAL).progress).toEqual({
+ state: 'in-progress',
+ recorded: 12,
+ planned: 24,
+ distinct: 12,
+ });
});
it('calls a finished matrix complete', () => {
@@ -512,3 +519,28 @@ describe('the CLI refuses what it cannot answer honestly', () => {
expect(runReport().status).toBe(2);
});
});
+
+describe('a re-run shard does not inflate the published size', () => {
+ it('counts cells rather than rows, and names the difference', () => {
+ // M5 has 1,240 rows across seven shards and 1,160 measurements, because
+ // 400 rows were re-produced after a temp reaper and one seed range was
+ // re-run whole. Reporting the row count invites a reader to take the
+ // larger number for the study's size, and the registered analysis in
+ // bench/m5-analysis.ts already drops the superseded original.
+ const base = { task: 't1', cond: 'commitlore-on', seed: 1 };
+ const rows = [
+ { ...base, run_id: 'first' },
+ { ...base, run_id: 'rerun' },
+ { task: 't1', cond: 'commitlore-off', seed: 1, run_id: 'first' },
+ ] as unknown as Parameters[0]['rows'];
+
+ const progress = progressOf({
+ rows,
+ present: [],
+ missing: [],
+ } as unknown as Parameters[0]);
+
+ expect(progress.recorded).toBe(3);
+ expect(progress.distinct).toBe(2);
+ });
+});
diff --git a/test/check-release-version.test.ts b/test/check-release-version.test.ts
new file mode 100644
index 00000000..ea7b29d1
--- /dev/null
+++ b/test/check-release-version.test.ts
@@ -0,0 +1,123 @@
+/**
+ * #492: release versions were compared only between the tag, package.json,
+ * and the built CLI. The plugin manifest Claude Code installs and both
+ * root-package fields npm records in package-lock.json could drift unnoticed.
+ *
+ * Each fixture is an isolated miniature checkout because the gate derives its
+ * repository root from its own path. That makes these real process tests of
+ * the release script without mutating this checkout's manifests.
+ */
+
+import { spawnSync } from 'node:child_process';
+import { copyFileSync, mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs';
+import { tmpdir } from 'node:os';
+import { dirname, join, resolve } from 'node:path';
+import { fileURLToPath } from 'node:url';
+
+import { afterAll, describe, expect, it } from 'vitest';
+
+const REPO_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '..');
+const GATE = join(REPO_ROOT, 'scripts', 'check-release-version.mjs');
+const VERSION = '0.7.1';
+
+const scratch: string[] = [];
+afterAll(() => {
+ for (const dir of scratch) rmSync(dir, { recursive: true, force: true });
+});
+
+interface FixtureVersions {
+ package?: string;
+ plugin?: string;
+ packageLock?: string;
+ packageLockRoot?: string;
+ cli?: string;
+ pluginManifest?: boolean;
+}
+
+const fixture = (versions: FixtureVersions = {}): string => {
+ const root = mkdtempSync(join(tmpdir(), 'commitlore-release-version-'));
+ scratch.push(root);
+
+ mkdirSync(join(root, 'scripts'));
+ mkdirSync(join(root, 'dist'));
+ copyFileSync(GATE, join(root, 'scripts', 'check-release-version.mjs'));
+
+ writeFileSync(
+ join(root, 'package.json'),
+ `${JSON.stringify({ name: 'commitlore', version: versions.package ?? VERSION }, null, 2)}\n`,
+ );
+ writeFileSync(
+ join(root, 'package-lock.json'),
+ `${JSON.stringify(
+ {
+ name: 'commitlore',
+ lockfileVersion: 3,
+ version: versions.packageLock ?? VERSION,
+ packages: { '': { name: 'commitlore', version: versions.packageLockRoot ?? VERSION } },
+ },
+ null,
+ 2,
+ )}\n`,
+ );
+ if (versions.pluginManifest !== false) {
+ mkdirSync(join(root, '.claude-plugin'));
+ writeFileSync(
+ join(root, '.claude-plugin', 'plugin.json'),
+ `${JSON.stringify({ name: 'commitlore', version: versions.plugin ?? VERSION }, null, 2)}\n`,
+ );
+ }
+ writeFileSync(
+ join(root, 'dist', 'commitlore.mjs'),
+ `#!/usr/bin/env node\nif (process.argv[2] === '--version') console.log(${JSON.stringify(versions.cli ?? VERSION)});\n`,
+ );
+
+ return root;
+};
+
+const run = (root: string) =>
+ spawnSync(process.execPath, [join(root, 'scripts', 'check-release-version.mjs'), `v${VERSION}`], {
+ encoding: 'utf8',
+ });
+
+describe('#492 check-release-version', () => {
+ it('passes when the tag, every manifest field, and the CLI agree', () => {
+ const result = run(fixture());
+
+ expect(result.status).toBe(0);
+ expect(result.stdout).toContain('version consistent');
+ });
+
+ it.each([
+ ['the plugin manifest', { plugin: '0.7.0' }, '.claude-plugin/plugin.json .version'],
+ ['the package-lock root version', { packageLock: '0.7.0' }, 'package-lock.json .version'],
+ [
+ 'the package-lock root package version',
+ { packageLockRoot: '0.7.0' },
+ 'package-lock.json .packages[""].version',
+ ],
+ ] satisfies [string, FixtureVersions, string][])('%s disagreement fails and names its field', (_, versions, source) => {
+ const result = run(fixture(versions));
+
+ expect(result.status).toBe(1);
+ expect(result.stderr).toContain(source);
+ });
+
+ it('reports every disagreement instead of stopping at the first one', () => {
+ const result = run(
+ fixture({ plugin: '0.7.0', packageLock: '0.7.0', packageLockRoot: '0.6.0' }),
+ );
+
+ expect(result.status).toBe(1);
+ expect(result.stderr).toContain('.claude-plugin/plugin.json .version');
+ expect(result.stderr).toContain('package-lock.json .version');
+ expect(result.stderr).toContain('package-lock.json .packages[""].version');
+ });
+
+ it('fails when the required plugin manifest is missing', () => {
+ const result = run(fixture({ pluginManifest: false }));
+
+ expect(result.status).toBe(2);
+ expect(result.stderr).toContain('.claude-plugin/plugin.json .version');
+ expect(result.stderr).toContain('required manifest is missing');
+ });
+});
diff --git a/test/doctor-snapshot.test.ts b/test/doctor-snapshot.test.ts
index 800e1998..aabc1c70 100644
--- a/test/doctor-snapshot.test.ts
+++ b/test/doctor-snapshot.test.ts
@@ -13,8 +13,8 @@
* — which checks run, in what order, with what status and what fix line.
*/
-import { execFileSync } from 'node:child_process';
-import { mkdirSync, mkdtempSync, realpathSync, rmSync, writeFileSync } from 'node:fs';
+import { execFileSync, type SpawnSyncReturns } from 'node:child_process';
+import { chmodSync, mkdirSync, mkdtempSync, realpathSync, rmSync, writeFileSync } from 'node:fs';
import { tmpdir } from 'node:os';
import { dirname, join, resolve } from 'node:path';
import { fileURLToPath } from 'node:url';
@@ -23,11 +23,15 @@ import { afterAll, describe, expect, it } from 'vitest';
import {
CHECK_REGISTRY,
+ evaluateInjectRun,
formatReport,
runDoctor,
type CheckDefinition,
+ type DoctorCheck,
} from '../src/commands/doctor.js';
import { closeIndex, openIndex, rebuildIndex } from '../src/core/index-db.js';
+import { claudeSettingsPath, installClaudeHook } from '../src/hooks/claude-settings.js';
+import { HOOK_MARKER, commitMsgStub } from '../src/hooks/commit-msg.js';
import { createTestRepo } from './git-fixtures.js';
const PACKAGE_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '..');
@@ -347,3 +351,388 @@ describe('#464 typed skip reasons', () => {
expect(row?.skipReason).toBe('unborn_head');
});
});
+
+/**
+ * #465: a diagnostic conclusion is only as useful as the observation beside it.
+ *
+ * Text rendering deliberately ignores these fields until its own ticket, so
+ * these assertions look at the report object directly. That keeps the text
+ * snapshot meaningful while making the JSON contract hard to erode unnoticed.
+ */
+describe('#465 doctor evidence', () => {
+ const assertEvidence = (checks: readonly DoctorCheck[]): void => {
+ for (const row of checks) {
+ if (Object.keys(row.evidence).length === 0) {
+ throw new Error(`${row.id} is ${row.status} without evidence`);
+ }
+ }
+ };
+
+ const injectContext: Parameters[1] = {
+ id: 'inject-runtime',
+ category: 'delivery',
+ title: 'PreToolUse hook runtime',
+ executable: 'configured-commitlore',
+ path: 'probe.ts',
+ fix: 'reinstall the configured executable',
+ unavailableFix: 'make the configured executable available',
+ };
+
+ const injectRun = (stderr: string): SpawnSyncReturns => ({
+ pid: 1,
+ output: [null, '', stderr],
+ stdout: '',
+ stderr,
+ status: 7,
+ signal: null,
+ });
+
+ it('gives every full-run row evidence, and rejects a deliberately bare finding', () => {
+ // A new failure path can otherwise read plausibly in text while dropping
+ // the observation a JSON consumer needs to distinguish it from another.
+ const reports = [
+ runDoctor({ cwd: populated('evidence-working', resolve(PACKAGE_ROOT, 'dist/commitlore.mjs')) }),
+ runDoctor({ cwd: populated('evidence-broken', join(temp('evidence-missing'), 'missing.mjs')) }),
+ ];
+ const rows = reports.flatMap((report) => report.checks);
+
+ assertEvidence(rows);
+ expect(rows.some((row) => row.status !== 'ok')).toBe(true);
+ for (const row of rows) {
+ for (const [key, value] of Object.entries(row.evidence)) {
+ expect(key, `${row.id} emitted a non-contract evidence key`).toMatch(/^[a-z][a-z0-9_]*$/);
+ expect(value, `${row.id}.${key} is not a string`).toBeTypeOf('string');
+ }
+ }
+
+ const broken: DoctorCheck = {
+ id: 'test-only-bare-finding',
+ title: 'test-only bare finding',
+ status: 'fail',
+ needsAttention: true,
+ detail: 'this row exists only to exercise the invariant',
+ fix: null,
+ fixed: false,
+ category: 'runtime',
+ severity: 'error',
+ evidence: {},
+ optional: false,
+ };
+ expect(() => assertEvidence([broken])).toThrow('test-only-bare-finding is fail without evidence');
+ });
+
+ it('renders paths under HOME as home-relative evidence', () => {
+ // Fixture paths are the path shape users paste into bug reports. Pointing
+ // HOME at their parent proves sanitisation reaches paths from every check,
+ // not only the one that introduced this field.
+ const home = temp('evidence-home');
+ const repo = createTestRepo({ path: join(home, 'repo') });
+ const previousHome = process.env['HOME'];
+ process.env['HOME'] = home;
+ try {
+ const values = runDoctor({ cwd: repo }).checks.flatMap((row) => Object.values(row.evidence));
+ expect(values.some((value) => value.includes('~/'))).toBe(true);
+ for (const value of values) expect(value).not.toContain(home);
+ } finally {
+ if (previousHome === undefined) delete process.env['HOME'];
+ else process.env['HOME'] = previousHome;
+ }
+ });
+
+ it('bounds captured stderr while preserving whether anything was omitted', () => {
+ // The bound is what keeps a broken hook that prints a large stack trace
+ // from turning a diagnostic response into an unbounded JSON payload.
+ const truncated = evaluateInjectRun(injectRun(`${'x'.repeat(10_000)}\nsecond line`), injectContext);
+ const untruncated = evaluateInjectRun(injectRun('short diagnostic\nsecond line'), injectContext);
+
+ expect(truncated.evidence['stderr_first_line']).toHaveLength(200);
+ expect(truncated.evidence['stderr_truncated']).toBe('true');
+ expect(untruncated.evidence['stderr_first_line']).toBe('short diagnostic');
+ expect(untruncated.evidence['stderr_truncated']).toBe('false');
+ });
+
+ it('records the configured executable it runs and both sides of a hook version comparison', () => {
+ // #149 reconstructed a path that did not appear in settings; #382 had both
+ // versions in hand but left the skew trapped inside prose. This fixture
+ // makes the configured command do both jobs so the two observations stay
+ // coupled to the executions that produced them.
+ const repo = populated('evidence-inject', resolve(PACKAGE_ROOT, 'dist/commitlore.mjs'));
+ const bin = temp('evidence-inject-bin');
+ const command = join(bin, 'commitlore');
+ writeFileSync(
+ command,
+ '#!/bin/sh\nif [ "$1" = "--version" ]; then\n printf \'0.0.0\\n\'\nelse\n printf \'{"hookSpecificOutput":{"additionalContext":"context"}}\\n\'\nfi\n',
+ );
+ chmodSync(command, 0o755);
+ installClaudeHook({ settingsPath: claudeSettingsPath(repo) });
+
+ const previousPath = process.env['PATH'];
+ process.env['PATH'] = `${bin}:/usr/bin:/bin`;
+ try {
+ const rows = runDoctor({ cwd: repo }).checks;
+ const runtime = rows.find((row) => row.id === 'inject-runtime');
+ const version = rows.find((row) => row.id === 'inject-version');
+
+ expect(runtime?.status).toBe('ok');
+ expect(runtime?.evidence['executable']).toBe('commitlore');
+ expect(runtime?.evidence['exit_code']).toBe('0');
+ expect(version?.evidence['executable']).toBe('commitlore');
+ expect(version?.evidence['theirs']).toBe('0.0.0');
+ expect(version?.evidence['mine']).not.toBe('');
+ } finally {
+ if (previousPath === undefined) delete process.env['PATH'];
+ else process.env['PATH'] = previousPath;
+ }
+ });
+
+ it('surfaces the hook target recorded at installation and an active override', () => {
+ // #49 was invisible because doctor observed the target but kept it only in
+ // prose. The override matters for the same reason: it wins resolution.
+ const bin = resolve(PACKAGE_ROOT, 'dist/commitlore.mjs');
+ const repo = populated('evidence-hook-target', bin);
+ const override = join(repo, 'override.mjs');
+ const previousOverride = process.env['COMMITLORE_BIN'];
+ process.env['COMMITLORE_BIN'] = override;
+ try {
+ const hook = runDoctor({ cwd: repo }).checks.find((row) => row.id === 'commit-msg-hook');
+ const home = process.env['HOME'];
+ const homeRelative = (value: string): string =>
+ home !== undefined && value.startsWith(`${home}/`) ? `~/${value.slice(home.length + 1)}` : value;
+
+ expect(hook?.evidence['hook_path']).toContain('hooks/commit-msg');
+ expect(hook?.evidence['bin']).toBe(homeRelative(bin));
+ expect(hook?.evidence['node']).toBe(homeRelative(process.execPath));
+ expect(hook?.evidence['commitlore_bin_override']).toBe(override);
+ } finally {
+ if (previousOverride === undefined) delete process.env['COMMITLORE_BIN'];
+ else process.env['COMMITLORE_BIN'] = previousOverride;
+ }
+ });
+
+ it('keeps the counts that licence an index-health verdict', () => {
+ // Counting a different trailer convention produced a persuasive but wrong
+ // green report in #335/#458. Keeping these numbers structured lets a test
+ // compare the conclusion with the observation that licensed it.
+ const repo = populated('evidence-index-counts', resolve(PACKAGE_ROOT, 'dist/commitlore.mjs'));
+ const index = runDoctor({ cwd: repo }).checks.find((row) => row.id === 'index-health');
+
+ expect(index?.evidence['trailers']).not.toBe('');
+ expect(index?.evidence['commits']).not.toBe('');
+ expect(index?.detail).toContain(`${index?.evidence['trailers']} trailers`);
+ expect(index?.detail).toContain(`${index?.evidence['commits']} commits`);
+ });
+});
+
+/**
+ * #466: a repeated symptom names its cause without discarding the observation
+ * that made the symptom useful. The blocked row stays in the report because a
+ * later independent defect must have somewhere honest to appear.
+ */
+describe('#466 root-cause collapse', () => {
+ const row = (id: string, status: DoctorCheck['status'], blockedBy?: string): DoctorCheck => ({
+ id,
+ title: id,
+ status,
+ needsAttention: status === 'warn' || status === 'fail',
+ detail: `${id} fixture result`,
+ fix: null,
+ fixed: false,
+ category: 'runtime',
+ severity: status === 'fail' ? 'error' : status === 'warn' ? 'warning' : 'info',
+ evidence: { fixture: id },
+ optional: false,
+ ...(blockedBy === undefined ? {} : { blockedBy }),
+ });
+
+ const currentHookWithDeadRuntime = (label: string): string => {
+ const repo = populated(label, resolve(PACKAGE_ROOT, 'dist/commitlore.mjs'));
+ writeFileSync(join(repo, '.git', 'hooks', 'commit-msg'), commitMsgStub());
+ git(repo, ['config', '--local', 'commitlore.node', '/nonexistent/node']);
+ return repo;
+ };
+
+ it('resolves a blocked chain to its root', () => {
+ // A consumer should not have to re-walk A → B → C to find the instruction
+ // that matters. This substitutes only the registry, leaving the runner
+ // that performs the collapse under test.
+ const registry = CHECK_REGISTRY as CheckDefinition[];
+ const original = [...registry];
+ const synthetic: CheckDefinition[] = [
+ {
+ id: 'collapse-root',
+ title: 'collapse root',
+ category: 'runtime',
+ dependencies: [],
+ optional: false,
+ run: () => row('collapse-root', 'fail'),
+ },
+ {
+ id: 'collapse-middle',
+ title: 'collapse middle',
+ category: 'runtime',
+ dependencies: ['collapse-root'],
+ optional: false,
+ run: (_ctx, dependencies) => {
+ const root = dependencies.get('collapse-root');
+ if (root === undefined) throw new Error('collapse root did not run');
+ return row('collapse-middle', 'skipped', root.id);
+ },
+ },
+ {
+ id: 'collapse-leaf',
+ title: 'collapse leaf',
+ category: 'runtime',
+ dependencies: ['collapse-middle'],
+ optional: false,
+ run: (_ctx, dependencies) => {
+ const middle = dependencies.get('collapse-middle');
+ if (middle === undefined) throw new Error('collapse middle did not run');
+ return row('collapse-leaf', 'skipped', middle.id);
+ },
+ },
+ ];
+
+ registry.splice(0, registry.length, ...synthetic);
+ try {
+ const report = runDoctor();
+
+ expect(report.checks.map((entry) => entry.id)).toEqual(
+ ['collapse-root', 'collapse-middle', 'collapse-leaf'],
+ );
+ expect(report.checks.find((entry) => entry.id === 'collapse-leaf')?.blockedBy).toBe(
+ 'collapse-root',
+ );
+ } finally {
+ registry.splice(0, registry.length, ...original);
+ }
+ });
+
+ it('keeps a dead hook runtime\'s dependent row, detail, and evidence', () => {
+ // Removing the hook row makes a dead runtime look tidier by hiding the
+ // installation it actually affected. The duplicate is an annotation, not
+ // permission to stop looking.
+ const repo = currentHookWithDeadRuntime('collapse-hook');
+ const report = runDoctor({ cwd: repo });
+ const runtime = report.checks.find((entry) => entry.id === 'hook-runtime');
+ const hook = report.checks.find((entry) => entry.id === 'commit-msg-hook');
+
+ expect(runtime?.status).toBe('fail');
+ expect(hook?.blockedBy).toBe('hook-runtime');
+ expect(hook?.detail).toContain(`outcome: ${runtime?.detail}`);
+ expect(hook?.evidence['runtime_status']).toBe('fail');
+ expect(report.checks.filter((entry) => entry.id === 'commit-msg-hook')).toHaveLength(1);
+ expect(formatReport(report)).toContain(`${hook?.status?.padEnd(8)}${hook?.title} — ${hook?.detail}`);
+ });
+
+ it('keeps a stale stub unblocked when its runtime is also dead', () => {
+ // The stale body is actionable in its own right. Attributing it to the
+ // missing runtime would make a future fix plan bury the update it needs.
+ const repo = currentHookWithDeadRuntime('collapse-stale');
+ writeFileSync(
+ join(repo, '.git', 'hooks', 'commit-msg'),
+ `#!/bin/sh\n${HOOK_MARKER}\nexec commitlore validate "$1"\n`,
+ );
+ const report = runDoctor({ cwd: repo });
+ const runtime = report.checks.find((entry) => entry.id === 'hook-runtime');
+ const hook = report.checks.find((entry) => entry.id === 'commit-msg-hook');
+
+ expect(runtime?.status).toBe('fail');
+ expect(hook?.status).toBe('warn');
+ expect(hook?.detail).toContain('out of date');
+ expect(hook?.blockedBy).toBeUndefined();
+ expect(Object.keys(hook ?? {})).not.toContain('blockedBy');
+ });
+
+ it('marks the unreadable inject version as blocked by its failed runtime', () => {
+ const repo = populated('collapse-inject-runtime', resolve(PACKAGE_ROOT, 'dist/commitlore.mjs'));
+ const bin = temp('collapse-inject-runtime-bin');
+ const command = join(bin, 'commitlore');
+ writeFileSync(command, '#!/bin/sh\necho broken >&2\nexit 7\n');
+ chmodSync(command, 0o755);
+ installClaudeHook({ settingsPath: claudeSettingsPath(repo) });
+
+ const previousPath = process.env['PATH'];
+ process.env['PATH'] = `${bin}:/usr/bin:/bin`;
+ try {
+ const report = runDoctor({ cwd: repo });
+ const runtime = report.checks.find((entry) => entry.id === 'inject-runtime');
+ const version = report.checks.find((entry) => entry.id === 'inject-version');
+
+ expect(runtime?.status).toBe('fail');
+ expect(version?.status).toBe('skipped');
+ expect(version?.detail).toBe('commitlore did not report a version');
+ expect(version?.blockedBy).toBe('inject-runtime');
+ expect(version?.evidence).toMatchObject({ executable: 'commitlore', exit_code: '7' });
+ expect(formatReport(report)).toContain(
+ `skipped ${version?.title} — commitlore did not report a version`,
+ );
+ } finally {
+ if (previousPath === undefined) delete process.env['PATH'];
+ else process.env['PATH'] = previousPath;
+ }
+ });
+
+ it('leaves an independent inject version mismatch unblocked', () => {
+ // A version comparison that runs and disagrees has fresh evidence. The
+ // runtime being a declared prerequisite does not turn that finding into
+ // an echo.
+ const repo = populated('collapse-inject-version', resolve(PACKAGE_ROOT, 'dist/commitlore.mjs'));
+ const bin = temp('collapse-inject-version-bin');
+ const command = join(bin, 'commitlore');
+ writeFileSync(
+ command,
+ '#!/bin/sh\nif [ "$1" = "--version" ]; then\n printf \'0.0.0\\n\'\nelse\n printf context\\n\nfi\n',
+ );
+ chmodSync(command, 0o755);
+ installClaudeHook({ settingsPath: claudeSettingsPath(repo) });
+
+ const previousPath = process.env['PATH'];
+ process.env['PATH'] = `${bin}:/usr/bin:/bin`;
+ try {
+ const report = runDoctor({ cwd: repo });
+ const runtime = report.checks.find((entry) => entry.id === 'inject-runtime');
+ const version = report.checks.find((entry) => entry.id === 'inject-version');
+
+ expect(runtime?.status).toBe('ok');
+ expect(version?.status).toBe('warn');
+ expect(version?.detail).toContain('0.0.0');
+ expect(version?.blockedBy).toBeUndefined();
+ expect(Object.keys(version ?? {})).not.toContain('blockedBy');
+ } finally {
+ if (previousPath === undefined) delete process.env['PATH'];
+ else process.env['PATH'] = previousPath;
+ }
+ });
+
+ it('never names an ok blocker or omits a row while collapse is active', () => {
+ // A recovered dependency must not leave stale metadata behind, and a
+ // blocked row still counts because its own observation remains evidence.
+ const reports = [
+ runDoctor({ cwd: populated('collapse-clean', resolve(PACKAGE_ROOT, 'dist/commitlore.mjs')) }),
+ runDoctor({ cwd: currentHookWithDeadRuntime('collapse-count') }),
+ ];
+
+ for (const report of reports) {
+ expect(report.checks).toHaveLength(CHECK_REGISTRY.length);
+ for (const entry of report.checks) {
+ if (entry.blockedBy === undefined) continue;
+ const blocker = report.checks.find((candidate) => candidate.id === entry.blockedBy);
+ expect(blocker?.status, `${entry.id} is blocked by an ok or missing row`).not.toBe('ok');
+ }
+ }
+ });
+
+ it('omits blockedBy rather than serializing null on rows that stand alone', () => {
+ // Consumers distinguish absent additive fields from a present key whose
+ // value they do not understand. Null would break that compatibility shape.
+ const report = runDoctor({
+ cwd: populated('collapse-omitted', resolve(PACKAGE_ROOT, 'dist/commitlore.mjs')),
+ });
+
+ for (const entry of report.checks) {
+ if (entry.blockedBy !== undefined) continue;
+ expect(Object.keys(entry), `${entry.id} carries a null blocker`).not.toContain('blockedBy');
+ }
+ expect(JSON.stringify(report)).not.toContain('"blockedBy":null');
+ });
+});
diff --git a/test/plugin-entry-point.test.ts b/test/plugin-entry-point.test.ts
new file mode 100644
index 00000000..0bb24abe
--- /dev/null
+++ b/test/plugin-entry-point.test.ts
@@ -0,0 +1,76 @@
+/**
+ * #483: the release gate asked whether the plugin entry point resolved, not
+ * whether it resolved to the plugin.
+ *
+ * `scripts/commitlore-run.sh` tries `commitlore` on `PATH` before
+ * `CLAUDE_PLUGIN_ROOT`. That order is deliberate — the installer's wrapper
+ * execs node itself, so it works where this script would otherwise have to
+ * find node, and on the hook hot path a missing node means no context at all.
+ *
+ * The consequence is that a machine carrying both a CLI install and the plugin
+ * runs whichever the CLI install is, silently. Found running the gate against a
+ * fresh v0.7.0 clone on a machine with 0.6.0 installed: the clone answered
+ * 0.7.0 and the entry point answered 0.6.0, and the gate passed because it
+ * only checked the exit code.
+ *
+ * These cases pin both halves: the entry point reaches the plugin when nothing
+ * shadows it, and PATH wins when something does. The second is not a bug being
+ * enshrined — it is the documented order, asserted so that changing it becomes
+ * a decision someone makes rather than a side effect.
+ */
+
+import { execFileSync } from 'node:child_process';
+import { chmodSync, mkdtempSync, realpathSync, rmSync, writeFileSync } from 'node:fs';
+import { tmpdir } from 'node:os';
+import { dirname, join, resolve } from 'node:path';
+import { fileURLToPath } from 'node:url';
+
+import { afterAll, describe, expect, it } from 'vitest';
+
+const REPO_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '..');
+const SCRIPT = join(REPO_ROOT, 'scripts', 'commitlore-run.sh');
+const OWN_VERSION = JSON.parse(
+ execFileSync('node', ['-p', 'JSON.stringify(require("./package.json"))'], {
+ cwd: REPO_ROOT,
+ encoding: 'utf8',
+ }),
+).version as string;
+
+const scratch: string[] = [];
+afterAll(() => {
+ for (const dir of scratch) rmSync(dir, { recursive: true, force: true });
+});
+
+const temp = (label: string): string => {
+ const dir = mkdtempSync(join(realpathSync(tmpdir()), `cl-plug-${label}-`));
+ scratch.push(dir);
+ return dir;
+};
+
+/** The interpreter's directory, so a narrowed PATH can still find node. */
+const nodeDir = dirname(process.execPath);
+
+const run = (path: string): string =>
+ execFileSync('sh', [SCRIPT, '--version'], {
+ cwd: REPO_ROOT,
+ encoding: 'utf8',
+ env: { PATH: path, CLAUDE_PLUGIN_ROOT: REPO_ROOT, HOME: process.env['HOME'] ?? '' },
+ }).trim();
+
+describe('#483 the plugin entry point', () => {
+ it('answers with the plugin\'s own version when nothing shadows it', () => {
+ // What the release gate meant to check all along.
+ expect(run(`/usr/bin:/bin:${nodeDir}`)).toBe(OWN_VERSION);
+ });
+
+ it('prefers a commitlore on PATH over the plugin root, as documented', () => {
+ // A machine with both runs the CLI install. Asserted rather than assumed,
+ // so that changing the order is a decision rather than a side effect.
+ const shadow = temp('shadow');
+ const fake = join(shadow, 'commitlore');
+ writeFileSync(fake, '#!/bin/sh\necho 0.0.0-shadow\n');
+ chmodSync(fake, 0o755);
+
+ expect(run(`${shadow}:/usr/bin:/bin:${nodeDir}`)).toBe('0.0.0-shadow');
+ });
+});
diff --git a/test/release-publish-prerequisites.test.ts b/test/release-publish-prerequisites.test.ts
new file mode 100644
index 00000000..cbb31673
--- /dev/null
+++ b/test/release-publish-prerequisites.test.ts
@@ -0,0 +1,229 @@
+/**
+ * Release publication is deliberately tested outside Actions. A tag can be
+ * syntactically valid while naming a dev-only commit, and a local test run can
+ * be green while the CI record for that exact commit is absent or failed. Both
+ * are facts GitHub's YAML cannot safely infer with an `if:` expression.
+ */
+
+import { spawnSync } from 'node:child_process';
+import { mkdtempSync, readFileSync, realpathSync, rmSync, writeFileSync } from 'node:fs';
+import { tmpdir } from 'node:os';
+import { join } from 'node:path';
+import { fileURLToPath } from 'node:url';
+
+import { load } from 'js-yaml';
+import { afterAll, beforeAll, describe, expect, it } from 'vitest';
+
+import { REQUIRED_CHECKS } from '../scripts/check-exact-head-ci.mjs';
+
+const REPO_ROOT = fileURLToPath(new URL('../', import.meta.url));
+const RELEASE_TARGET = join(REPO_ROOT, 'scripts', 'check-release-target.mjs');
+const EXACT_HEAD_CI = join(REPO_ROOT, 'scripts', 'check-exact-head-ci.mjs');
+const RELEASE_WORKFLOW = join(REPO_ROOT, '.github', 'workflows', 'release.yml');
+
+const scratch: string[] = [];
+
+afterAll(() => {
+ for (const dir of scratch) rmSync(dir, { recursive: true, force: true });
+});
+
+const tempDir = (label: string): string => {
+ const dir = mkdtempSync(join(realpathSync(tmpdir()), `commitlore-release-${label}-`));
+ scratch.push(dir);
+ return dir;
+};
+
+const git = (cwd: string, args: string[]): string => {
+ const result = spawnSync('git', args, { cwd, encoding: 'utf8', shell: false });
+ if (result.status !== 0) {
+ throw new Error(`git ${args.join(' ')} failed (exit ${result.status}): ${result.stderr}`);
+ }
+ return result.stdout;
+};
+
+const commit = (repo: string, path: string, contents: string, message: string): string => {
+ writeFileSync(join(repo, path), contents);
+ git(repo, ['add', path]);
+ git(repo, ['-c', 'user.name=Release gate', '-c', 'user.email=release-gate@example.invalid', 'commit', '--quiet', '-m', message]);
+ return git(repo, ['rev-parse', 'HEAD']).trim();
+};
+
+interface RunResult {
+ readonly status: number | null;
+ readonly stdout: string;
+ readonly stderr: string;
+}
+
+const run = (script: string, args: string[], cwd = REPO_ROOT): RunResult => {
+ const result = spawnSync(process.execPath, [script, ...args], { cwd, encoding: 'utf8', shell: false });
+ return { status: result.status, stdout: result.stdout ?? '', stderr: result.stderr ?? '' };
+};
+
+let repo: string;
+let remote: string;
+let mainSha: string;
+let sideSha: string;
+
+beforeAll(() => {
+ repo = tempDir('source');
+ remote = tempDir('remote.git');
+ git(REPO_ROOT, ['init', '--quiet', '--initial-branch=main', repo]);
+ mainSha = commit(repo, 'main.txt', 'on main\n', 'main commit');
+
+ git(repo, ['checkout', '--quiet', '-b', 'dev']);
+ sideSha = commit(repo, 'dev.txt', 'dev only\n', 'dev commit');
+ git(repo, ['tag', 'v9.9.9']);
+
+ git(repo, ['checkout', '--quiet', 'main']);
+ git(repo, ['init', '--quiet', '--bare', remote]);
+ git(repo, ['remote', 'add', 'origin', remote]);
+ git(repo, ['push', '--quiet', '--all', 'origin']);
+ git(repo, ['push', '--quiet', '--tags', 'origin']);
+});
+
+describe('the tagged commit is in main history', () => {
+ it('accepts a commit that is on the target branch', () => {
+ const result = run(RELEASE_TARGET, [mainSha, 'main'], repo);
+ expect(result.status).toBe(0);
+ expect(result.stdout).toContain('release target accepted');
+ });
+
+ it('refuses a commit that is only on a side branch', () => {
+ const result = run(RELEASE_TARGET, [sideSha, 'main'], repo);
+ expect(result.status).toBe(1);
+ expect(result.stderr).toContain('is not contained in target branch');
+ });
+
+ it('refuses a tag that points only at dev', () => {
+ const result = run(RELEASE_TARGET, ['v9.9.9', 'main'], repo);
+ expect(result.status).toBe(1);
+ expect(result.stderr).toContain('is not contained in target branch');
+ });
+
+ it('refuses a shallow clone rather than guessing from its truncated history', () => {
+ const shallow = join(tempDir('shallow-parent'), 'clone');
+ git(REPO_ROOT, ['clone', '--quiet', '--depth', '1', '--branch', 'main', `file://${remote}`, shallow]);
+
+ const result = run(RELEASE_TARGET, ['HEAD', 'main'], shallow);
+ expect(result.status).toBe(3);
+ expect(result.stderr).toContain('shallow repository');
+ });
+});
+
+const RELEASE_SHA = 'a'.repeat(40);
+const OTHER_SHA = 'b'.repeat(40);
+
+interface CheckRun {
+ name: string;
+ head_sha: string;
+ status: string;
+ conclusion: string | null;
+}
+
+const successfulPayload = (): { check_runs: CheckRun[] } => ({
+ check_runs: REQUIRED_CHECKS.map((name) => ({
+ name,
+ head_sha: RELEASE_SHA,
+ status: 'completed',
+ conclusion: 'success',
+ })),
+});
+
+const runPayload = (payload: unknown): RunResult => {
+ const path = join(tempDir('payload'), 'check-runs.json');
+ writeFileSync(path, JSON.stringify(payload));
+ return run(EXACT_HEAD_CI, ['MongLong0214', 'commitlore', RELEASE_SHA, '--from-file', path]);
+};
+
+const rejectedPayload = (payload: unknown, detail: string): void => {
+ const result = runPayload(payload);
+ expect(result.status).toBe(1);
+ expect(result.stderr).toContain(detail);
+};
+
+describe('the required CI checks passed at the exact tagged SHA', () => {
+ it('accepts only a complete set of successful required checks', () => {
+ const result = runPayload(successfulPayload());
+ expect(result.status).toBe(0);
+ expect(result.stdout).toContain('exact-head CI accepted');
+ });
+
+ it('refuses a required check that failed', () => {
+ const payload = successfulPayload();
+ payload.check_runs[0]!.conclusion = 'failure';
+ rejectedPayload(payload, 'conclusion "failure"');
+ });
+
+ it('refuses a required check that was cancelled', () => {
+ const payload = successfulPayload();
+ payload.check_runs[0]!.conclusion = 'cancelled';
+ rejectedPayload(payload, 'conclusion "cancelled"');
+ });
+
+ it('refuses a required check that timed out', () => {
+ const payload = successfulPayload();
+ payload.check_runs[0]!.conclusion = 'timed_out';
+ rejectedPayload(payload, 'conclusion "timed_out"');
+ });
+
+ it('refuses a required check that was skipped', () => {
+ const payload = successfulPayload();
+ payload.check_runs[0]!.conclusion = 'skipped';
+ rejectedPayload(payload, 'conclusion "skipped"');
+ });
+
+ it('refuses a required check that is still in progress', () => {
+ const payload = successfulPayload();
+ payload.check_runs[0]!.status = 'in_progress';
+ payload.check_runs[0]!.conclusion = null;
+ rejectedPayload(payload, 'status "in_progress"');
+ });
+
+ it('refuses a payload that omits one required check entirely', () => {
+ const payload = successfulPayload();
+ payload.check_runs = payload.check_runs.slice(1);
+ rejectedPayload(payload, 'required check is absent');
+ });
+
+ it('refuses an empty payload', () => {
+ rejectedPayload({ check_runs: [] }, 'required check is absent');
+ });
+
+ it('refuses successes reported for a different SHA', () => {
+ const payload = successfulPayload();
+ for (const check of payload.check_runs) check.head_sha = OTHER_SHA;
+ rejectedPayload(payload, 'head SHA');
+ });
+});
+
+describe('publication has no path around a failed prerequisite', () => {
+ const publish = () => {
+ const workflow = load(readFileSync(RELEASE_WORKFLOW, 'utf8')) as {
+ jobs: Record;
+ };
+ return workflow.jobs.publish;
+ };
+
+ it('needs all four release prerequisites', () => {
+ expect(publish().needs).toEqual([
+ 'version-consistency',
+ 'install-gate',
+ 'release-target',
+ 'exact-head-ci',
+ ]);
+ });
+
+ it('has no if condition that bypasses any of the four prerequisite failures', () => {
+ const job = publish();
+ // An omitted need is itself a bypass: GitHub cannot withhold publication
+ // for a job it was never asked to wait for. Assert the complete dependency
+ // set here as well as the absence of an `always()`-style escape hatch.
+ expect(job.needs).toEqual([
+ 'version-consistency',
+ 'install-gate',
+ 'release-target',
+ 'exact-head-ci',
+ ]);
+ expect(job.if).toBeUndefined();
+ });
+});
diff --git a/test/trusted-authors.test.ts b/test/trusted-authors.test.ts
index 681cff4d..4eec29d7 100644
--- a/test/trusted-authors.test.ts
+++ b/test/trusted-authors.test.ts
@@ -13,7 +13,10 @@
* existed.
*/
+import { spawnSync } from 'node:child_process';
import { mkdtempSync, realpathSync, rmSync, writeFileSync } from 'node:fs';
+import { dirname, resolve } from 'node:path';
+import { fileURLToPath } from 'node:url';
import { tmpdir } from 'node:os';
import { join } from 'node:path';
@@ -28,6 +31,7 @@ import {
} from '../src/core/trusted-authors.js';
import { createTestRepo } from './git-fixtures.js';
+const REPO_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '..');
const scratch: string[] = [];
afterAll(() => {
@@ -135,3 +139,76 @@ describe('#415 trusted authors after a plain install', () => {
expect(injected()).toMatch(/\[claim\]\s+r-trust01/);
});
});
+
+/**
+ * The layer the earlier tests in this file did not reach.
+ *
+ * Everything above drives `buildInjection` with options assembled by hand. That
+ * passes whether or not the CLI ever produces those options — and it did not.
+ * Commander declares `--trusted-author` with a default of `[]`, so the absent
+ * flag arrived as an empty array rather than `undefined`, the nullish fallback
+ * to the configured authors never fired, and **every record on every install
+ * still graded `claim`**. The defect #415 was opened about, reintroduced one
+ * layer up by the fix for it, and shipped in 0.7.0.
+ *
+ * The file header already said a unit test of `gradeRecord` would have passed
+ * throughout the period the original bug existed. This is the same sentence one
+ * layer out, and the reason these cases spawn the built CLI instead.
+ */
+describe('#415 through the command line, which is the only path the hook uses', () => {
+ const cli = (args: string[], cwd: string): string => {
+ const run = spawnSync(process.execPath, [join(REPO_ROOT, 'dist', 'commitlore.mjs'), ...args], {
+ cwd,
+ encoding: 'utf8',
+ });
+ return `${run.stdout}${run.stderr}`;
+ };
+
+ it('renders the installer\'s own record as [directive] with no flag at all', () => {
+ commitRecord(INSTALLER, RECORD);
+ seedTrustedAuthor(repo);
+
+ // No `--trusted-author`. This is exactly what CLAUDE_HOOK_COMMAND runs.
+ expect(cli(['inject', '--path', 'session.ts'], repo)).toMatch(/\[directive\]\s+r-trust01/);
+ });
+
+ it('still renders another author\'s record as [claim] through the same path', () => {
+ commitRecord(OUTSIDER, RECORD);
+ seedTrustedAuthor(repo);
+
+ expect(cli(['inject', '--path', 'session.ts'], repo)).toMatch(/\[claim\]\s+r-trust01/);
+ });
+
+ it('grades claim when nothing is configured and no flag is given', () => {
+ commitRecord(INSTALLER, RECORD);
+
+ expect(cli(['inject', '--path', 'session.ts'], repo)).toMatch(/\[claim\]\s+r-trust01/);
+ });
+
+ it('lets an explicit flag override an empty configuration', () => {
+ commitRecord(INSTALLER, RECORD);
+
+ const out = cli(['inject', '--path', 'session.ts', '--trusted-author', INSTALLER], repo);
+ expect(out).toMatch(/\[directive\]\s+r-trust01/);
+ });
+
+ it('answers the same on the query route as on the hook route', () => {
+ // query.ts carried the sentence "the two routes must answer alike, or the
+ // grade means one thing on the hook and another on the terminal" while the
+ // two routes did in fact disagree: `inject` fell back to the configured
+ // authors and `context` did not. A comment asserting a property is not the
+ // property.
+ commitRecord(INSTALLER, RECORD);
+ seedTrustedAuthor(repo);
+
+ expect(cli(['inject', '--path', 'session.ts'], repo)).toMatch(/\[directive\]\s+r-trust01/);
+ expect(cli(['context', 'session.ts'], repo)).toMatch(/r-trust01\s+\S+\s+\[directive\]/);
+ });
+
+ it('keeps the two routes agreeing when nothing is configured', () => {
+ commitRecord(INSTALLER, RECORD);
+
+ expect(cli(['inject', '--path', 'session.ts'], repo)).toMatch(/\[claim\]\s+r-trust01/);
+ expect(cli(['context', 'session.ts'], repo)).toMatch(/r-trust01\s+\S+\s+\[claim\]/);
+ });
+});