Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .agents/skills/local-strict-review/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -143,8 +143,8 @@ In the hub, `.husky/pre-push` checks the receipt, and the canonical-unit coverag
| The commit is not this worktree's HEAD | Any pushed branch ref carrying an object id that is neither this worktree's HEAD nor the all-zero id of a delete, which a push from a checkout sitting elsewhere reaches and so does a multi-ref push such as `git push --all` | Push one branch, the one this worktree holds. Where another branch is the one wanted, check it out in its own worktree first, per `repo-worktree` |
| Any wording saying the gate did not or could not run | An execution boundary rather than a verdict, which blocks because a gate that waves a push through when it could not run has stopped gating. The cause is named in that same message or in the engine error printed above it, and it is a missing Python interpreter, an unresolvable target, an unreadable receipt, a git command that failed, a manifest or ledger the engine could not read, or any unexpected failure | Whatever the message names, most often installing an interpreter per `docs/host-setup.md` or fetching the target branch. Never another pass |
| This branch changes N carried canonical unit(s) that no recorded pass covers | The carried-content pass was skipped for a unit this change moved or newly carried, and the refusal names each one with the digest to hand back | One carried-content pass per named unit, then `canonical_review.py record` for each, in the order "The Carried-Content Pass" above gives. The ledger that writes is tracked content, so the commit has to carry it and the diff pass comes after |
| A canonical refusal naming units this branch never touched | The fork point is not where the reader thinks it is. Either `origin/<target>` does not hold the commit this branch forked from, since neither engine ever fetches it, or the branch is based on something other than `develop` and the hook, which passes no `--target`, measured it against `develop` regardless. Unlike the row below it still prints a record command, and taking that one records passes over units nobody read | `git fetch origin <target>`, then `canonical_review.py check --target <target>` by hand for the real set, then pass and record what that names and commit the ledger with the change, per row 5. Where the branch targets something the hook does not measure, no pass clears it, so the gate cannot judge that branch at all and the bypass is its answer, as in the row below |
| The recorded pass was run against X and this check measured Y, printed under row 1's headline | The hook reads `develop` and nothing else, so a branch based elsewhere is measured against `develop` whatever the pass targeted, and the engine deliberately prints no record command, since the one it would print records a pass over a diff nobody read | One more pass against the branch this work actually targets, where it does target the measured one. Where it does not, the gate cannot judge the branch at all and the bypass is its answer |
| A canonical refusal naming units this branch never touched | The fork point is not where the reader thinks it is. Either `origin/<target>` does not hold the commit this branch forked from, since neither engine ever fetches it, or the branch is based on something other than `develop` and the hook, which passes no `--target`, measured it against `develop` regardless. Unlike the row below it still prints a record command, and taking that one records passes over units nobody read | `git fetch origin <target>`, then `canonical_review.py check --target <target>` by hand for the real set, then pass and record what that names and commit the ledger with the change, per the carried-unit row above. Where the branch targets something the hook does not measure, no pass clears it, so the gate cannot judge that branch at all and the bypass is its answer, as in the row below |
| The recorded pass was run against X and this check measured Y, printed under the missing-pass headline | The hook reads `develop` and nothing else, so a branch based elsewhere is measured against `develop` whatever the pass targeted, and the engine deliberately prints no record command, since the one it would print records a pass over a diff nobody read | One more pass against the branch this work actually targets, where it does target the measured one. Where it does not, the gate cannot judge the branch at all and the bypass is its answer |

This table is the fleet's one enumeration of these, and every other surface states the principle and routes here rather than listing the shapes. That is deliberate: every review round that added a shape also left a restatement of it somewhere else, and keeping one table is what stops the next round doing the same.

Expand Down
2 changes: 1 addition & 1 deletion .claude-plugin/fleet-skills/.source-digest
Original file line number Diff line number Diff line change
@@ -1 +1 @@
205de67919051618
8d66cb3bd100d1b8
Original file line number Diff line number Diff line change
Expand Up @@ -143,8 +143,8 @@ In the hub, `.husky/pre-push` checks the receipt, and the canonical-unit coverag
| The commit is not this worktree's HEAD | Any pushed branch ref carrying an object id that is neither this worktree's HEAD nor the all-zero id of a delete, which a push from a checkout sitting elsewhere reaches and so does a multi-ref push such as `git push --all` | Push one branch, the one this worktree holds. Where another branch is the one wanted, check it out in its own worktree first, per `repo-worktree` |
| Any wording saying the gate did not or could not run | An execution boundary rather than a verdict, which blocks because a gate that waves a push through when it could not run has stopped gating. The cause is named in that same message or in the engine error printed above it, and it is a missing Python interpreter, an unresolvable target, an unreadable receipt, a git command that failed, a manifest or ledger the engine could not read, or any unexpected failure | Whatever the message names, most often installing an interpreter per `docs/host-setup.md` or fetching the target branch. Never another pass |
| This branch changes N carried canonical unit(s) that no recorded pass covers | The carried-content pass was skipped for a unit this change moved or newly carried, and the refusal names each one with the digest to hand back | One carried-content pass per named unit, then `canonical_review.py record` for each, in the order "The Carried-Content Pass" above gives. The ledger that writes is tracked content, so the commit has to carry it and the diff pass comes after |
| A canonical refusal naming units this branch never touched | The fork point is not where the reader thinks it is. Either `origin/<target>` does not hold the commit this branch forked from, since neither engine ever fetches it, or the branch is based on something other than `develop` and the hook, which passes no `--target`, measured it against `develop` regardless. Unlike the row below it still prints a record command, and taking that one records passes over units nobody read | `git fetch origin <target>`, then `canonical_review.py check --target <target>` by hand for the real set, then pass and record what that names and commit the ledger with the change, per row 5. Where the branch targets something the hook does not measure, no pass clears it, so the gate cannot judge that branch at all and the bypass is its answer, as in the row below |
| The recorded pass was run against X and this check measured Y, printed under row 1's headline | The hook reads `develop` and nothing else, so a branch based elsewhere is measured against `develop` whatever the pass targeted, and the engine deliberately prints no record command, since the one it would print records a pass over a diff nobody read | One more pass against the branch this work actually targets, where it does target the measured one. Where it does not, the gate cannot judge the branch at all and the bypass is its answer |
| A canonical refusal naming units this branch never touched | The fork point is not where the reader thinks it is. Either `origin/<target>` does not hold the commit this branch forked from, since neither engine ever fetches it, or the branch is based on something other than `develop` and the hook, which passes no `--target`, measured it against `develop` regardless. Unlike the row below it still prints a record command, and taking that one records passes over units nobody read | `git fetch origin <target>`, then `canonical_review.py check --target <target>` by hand for the real set, then pass and record what that names and commit the ledger with the change, per the carried-unit row above. Where the branch targets something the hook does not measure, no pass clears it, so the gate cannot judge that branch at all and the bypass is its answer, as in the row below |
| The recorded pass was run against X and this check measured Y, printed under the missing-pass headline | The hook reads `develop` and nothing else, so a branch based elsewhere is measured against `develop` whatever the pass targeted, and the engine deliberately prints no record command, since the one it would print records a pass over a diff nobody read | One more pass against the branch this work actually targets, where it does target the measured one. Where it does not, the gate cannot judge the branch at all and the bypass is its answer |

This table is the fleet's one enumeration of these, and every other surface states the principle and routes here rather than listing the shapes. That is deliberate: every review round that added a shape also left a restatement of it somewhere else, and keeping one table is what stops the next round doing the same.

Expand Down
4 changes: 2 additions & 2 deletions .github/skills/local-strict-review/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -143,8 +143,8 @@ In the hub, `.husky/pre-push` checks the receipt, and the canonical-unit coverag
| The commit is not this worktree's HEAD | Any pushed branch ref carrying an object id that is neither this worktree's HEAD nor the all-zero id of a delete, which a push from a checkout sitting elsewhere reaches and so does a multi-ref push such as `git push --all` | Push one branch, the one this worktree holds. Where another branch is the one wanted, check it out in its own worktree first, per `repo-worktree` |
| Any wording saying the gate did not or could not run | An execution boundary rather than a verdict, which blocks because a gate that waves a push through when it could not run has stopped gating. The cause is named in that same message or in the engine error printed above it, and it is a missing Python interpreter, an unresolvable target, an unreadable receipt, a git command that failed, a manifest or ledger the engine could not read, or any unexpected failure | Whatever the message names, most often installing an interpreter per `docs/host-setup.md` or fetching the target branch. Never another pass |
| This branch changes N carried canonical unit(s) that no recorded pass covers | The carried-content pass was skipped for a unit this change moved or newly carried, and the refusal names each one with the digest to hand back | One carried-content pass per named unit, then `canonical_review.py record` for each, in the order "The Carried-Content Pass" above gives. The ledger that writes is tracked content, so the commit has to carry it and the diff pass comes after |
| A canonical refusal naming units this branch never touched | The fork point is not where the reader thinks it is. Either `origin/<target>` does not hold the commit this branch forked from, since neither engine ever fetches it, or the branch is based on something other than `develop` and the hook, which passes no `--target`, measured it against `develop` regardless. Unlike the row below it still prints a record command, and taking that one records passes over units nobody read | `git fetch origin <target>`, then `canonical_review.py check --target <target>` by hand for the real set, then pass and record what that names and commit the ledger with the change, per row 5. Where the branch targets something the hook does not measure, no pass clears it, so the gate cannot judge that branch at all and the bypass is its answer, as in the row below |
| The recorded pass was run against X and this check measured Y, printed under row 1's headline | The hook reads `develop` and nothing else, so a branch based elsewhere is measured against `develop` whatever the pass targeted, and the engine deliberately prints no record command, since the one it would print records a pass over a diff nobody read | One more pass against the branch this work actually targets, where it does target the measured one. Where it does not, the gate cannot judge the branch at all and the bypass is its answer |
| A canonical refusal naming units this branch never touched | The fork point is not where the reader thinks it is. Either `origin/<target>` does not hold the commit this branch forked from, since neither engine ever fetches it, or the branch is based on something other than `develop` and the hook, which passes no `--target`, measured it against `develop` regardless. Unlike the row below it still prints a record command, and taking that one records passes over units nobody read | `git fetch origin <target>`, then `canonical_review.py check --target <target>` by hand for the real set, then pass and record what that names and commit the ledger with the change, per the carried-unit row above. Where the branch targets something the hook does not measure, no pass clears it, so the gate cannot judge that branch at all and the bypass is its answer, as in the row below |
| The recorded pass was run against X and this check measured Y, printed under the missing-pass headline | The hook reads `develop` and nothing else, so a branch based elsewhere is measured against `develop` whatever the pass targeted, and the engine deliberately prints no record command, since the one it would print records a pass over a diff nobody read | One more pass against the branch this work actually targets, where it does target the measured one. Where it does not, the gate cannot judge the branch at all and the bypass is its answer |

This table is the fleet's one enumeration of these, and every other surface states the principle and routes here rather than listing the shapes. That is deliberate: every review round that added a shape also left a restatement of it somewhere else, and keeping one table is what stops the next round doing the same.

Expand Down
2 changes: 1 addition & 1 deletion OPERATIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ python3 spec/validate.py
python3 scripts/docker_lint.py
```

`report --check` is read-only and runs on every event in CI, where the coverage check beside it runs only for a pull request, because a stale burn-down is a property of the commit rather than of a comparison against a base. It also carries `!cancelled()`, so an earlier failing step does not skip it and one run names both verdicts. It fails where the committed report no longer describes the ledger and the tree, which a deleted unit produces while every other gate stays green, since deleting one changes no recorded digest and leaves `check` covered. Renaming a section of a file the manifest carries by name, meaning `AGENTS.md` or `GOVERNANCE.md`, does the same. Renaming one in a file carried whole does not, since `check` then names the new unit and demands a pass for it. `python3 scripts/canonical_review.py report` rewrites it.
`report --check` is read-only and runs on every event in CI, where the coverage check beside it runs only for a pull request, because a stale burn-down is a property of the commit rather than of a comparison against a base. It also carries `!cancelled()`, so an earlier failing step does not skip it and one run names both verdicts. The local block above has no such arrangement: it runs under `set -Eeuo pipefail`, so a failing `check` stops it there and the gates below never run, and reaching a second verdict means fixing the first or running the later command on its own. It fails where the committed report no longer describes the ledger and the tree, which a deleted unit produces while every other gate stays green, since deleting one changes no recorded digest and leaves `check` covered. Renaming a section of a file the manifest carries by name, meaning `AGENTS.md` or `GOVERNANCE.md`, does the same. Renaming one in a file carried whole does not, since `check` then names the new unit and demands a pass for it. `python3 scripts/canonical_review.py report` rewrites it.

The canonical-review check sits in CI's own list only for a pull request, since a canonical unit's change is measured against the branch it is proposed into and a push carrying no pull request names none. The local run above takes the default target, `develop`, which is the same measurement for an ordinary feature branch and the wrong one for a branch based on `main`, where it needs `--target main` to mean anything.

Expand Down
6 changes: 3 additions & 3 deletions reports/canonical-review.json
Original file line number Diff line number Diff line change
Expand Up @@ -75,11 +75,11 @@
},
{
"unit": ".agents/skills/local-strict-review/SKILL.md > When to Run It",
"digest": "sha256:dd91a8b1631100ffe6a092c87141ae96500c32656fd9a2ef34bd598cddee0502",
"digest": "sha256:2de88c5663772d0b2c255fa44a567d6ab04d3b50c67f038af194e910650c83ab",
"reviewer": "agent-skill",
"findings": 0,
"hubCommit": "e97708dfe4c92e275118a0705556822993de9f32",
"stamp": "2026-08-31T16:44:52Z"
"hubCommit": "44ae00bd432e1eeaafeb00208d8e713a22f49076",
"stamp": "2026-09-01T18:51:57Z"
},
{
"unit": ".agents/skills/operational-vs-release-workflow/references/release-publish-mechanics.md > Map your outputs to the right seam",
Expand Down
8 changes: 7 additions & 1 deletion scripts/tests/test_canonical_review.py
Original file line number Diff line number Diff line change
Expand Up @@ -619,7 +619,13 @@ def test_a_symlinked_carried_path_is_refused(self) -> None:
target = self.outside / "elsewhere.md"
target.write_bytes(b"## Alpha\n\nnot ours\n")
(self.tmp / "DOC.md").unlink()
(self.tmp / "DOC.md").symlink_to(target)
try:
(self.tmp / "DOC.md").symlink_to(target)
except OSError as unprivileged:
# Windows refuses a symlink without the privilege or Developer Mode.
# That is an execution boundary rather than this guard failing.
(self.tmp / "DOC.md").write_bytes(b"## Alpha\n\nown\n")
raise unittest.SkipTest(f"this host cannot create a symlink: {unprivileged}") from None
with self.assertRaises(cr.CannotRun) as caught:
cr.units(self.tmp)
self.assertIn("DOC.md", str(caught.exception))
Expand Down
1 change: 1 addition & 0 deletions scripts/tests/test_pr_review.py
Original file line number Diff line number Diff line change
Expand Up @@ -1624,6 +1624,7 @@ def test_a_genuinely_unknown_marker_is_still_reported(self) -> None:
for shape, unknown in (
("heading", "### Reviewed Chances"),
("metadata label", "- **Review depth level:** deep"),
("summary", "<details><summary>Reviewed Chances</summary>"),
):
found = pr_review.unrecognized_in(OVERVIEW + "\n" + unknown)
self.assertTrue(
Expand Down