@erclx/canon 5.12.0 → 5.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/claude/.claude-plugin/plugin.json +1 -1
- package/claude/skills/api-design/REQUIREMENT.md +1 -1
- package/claude/skills/api-design/SKILL.md +4 -3
- package/claude/skills/api-design/references/adopted.md +1 -1
- package/claude/skills/auto-ship/REQUIREMENT.md +1 -0
- package/claude/skills/auto-ship/SKILL.md +2 -2
- package/claude/skills/build-in-slices/REQUIREMENT.md +45 -0
- package/claude/skills/build-in-slices/SKILL.md +94 -0
- package/claude/skills/build-in-slices/references/adopted.md +41 -0
- package/claude/skills/code-craft/REQUIREMENT.md +48 -0
- package/claude/skills/code-craft/SKILL.md +107 -0
- package/claude/skills/code-craft/references/adopted.md +52 -0
- package/claude/skills/codebase-layout/REQUIREMENT.md +1 -1
- package/claude/skills/deprecation-migration/REQUIREMENT.md +62 -0
- package/claude/skills/deprecation-migration/SKILL.md +115 -0
- package/claude/skills/deprecation-migration/references/adopted.md +50 -0
- package/claude/skills/git-followup/REQUIREMENT.md +1 -0
- package/claude/skills/git-followup/SKILL.md +3 -0
- package/claude/skills/git-pr/REQUIREMENT.md +1 -0
- package/claude/skills/git-pr/SKILL.md +1 -1
- package/claude/skills/git-pr/references/evidence.md +2 -2
- package/claude/skills/git-ship/REQUIREMENT.md +4 -0
- package/claude/skills/git-ship/SKILL.md +13 -2
- package/claude/skills/review-craft/REQUIREMENT.md +3 -0
- package/claude/skills/review-craft/SKILL.md +1 -1
- package/claude/skills/review-craft/references/adopted.md +8 -0
- package/claude/skills/review-craft/references/security.md +5 -0
- package/claude/skills/review-ui/REQUIREMENT.md +6 -2
- package/claude/skills/review-ui/SKILL.md +23 -4
- package/claude/skills/review-ui/references/driving.md +5 -3
- package/claude/skills/review-ui/references/post.md +3 -2
- package/claude/skills/role-worker/REQUIREMENT.md +1 -0
- package/claude/skills/role-worker/SKILL.md +4 -0
- package/claude/skills/test-first/REQUIREMENT.md +3 -0
- package/claude/skills/test-first/SKILL.md +2 -1
- package/docs/agents/commands.md +1 -1
- package/docs/agents/index.md +1 -0
- package/docs/agents/markdown-audit.md +1 -1
- package/docs/agents/pr-evidence.md +5 -0
- package/docs/agents/pr-frames.md +112 -0
- package/docs/agents/pr-preview.md +40 -12
- package/docs/workflow/skill-map.md +15 -12
- package/governance/rules/code/000-code.md +5 -1
- package/package.json +1 -1
- package/src/claude/cases/misc.ts +15 -0
- package/src/claude/skills-audit.ts +3 -0
- package/src/commands/pr.ts +559 -7
- package/src/commands/tooling.ts +39 -16
- package/src/context/architecture.ts +5 -2
- package/src/gate/boundaries.ts +509 -0
- package/src/gate/measures.ts +8 -19
- package/src/gate/stages.ts +12 -28
- package/src/pr/frames.ts +323 -0
- package/src/pr/preview.ts +66 -0
- package/src/tooling/manifest.ts +18 -3
- package/src/tooling/seeds.ts +37 -0
- package/src/tooling/verify-stack.ts +249 -0
- package/tooling/base/seeds/.cspell/tech-stack.txt +2 -0
- package/tooling/claude/manifest.toml +3 -3
- package/tooling/go/manifest.toml +3 -0
- package/tooling/go/reference.md +1 -0
- package/tooling/php/manifest.toml +3 -0
- package/tooling/php/reference.md +1 -0
- package/tooling/python/manifest.toml +3 -0
- package/tooling/python/reference.md +1 -1
- package/tooling/python/seeds/.cspell/tech-stack.txt +0 -1
- package/scripts/core/check-capability-seeding.sh +0 -134
- package/scripts/core/check-ignore-parity.sh +0 -141
- package/scripts/core/check-plugin-boundary.sh +0 -45
- package/scripts/core/check-seed-independence.sh +0 -62
- package/scripts/core/check-skill-paths.sh +0 -24
- package/scripts/core/list-seed-roots.sh +0 -18
- package/scripts/lib/tooling.sh +0 -37
- package/scripts/tooling/verify.sh +0 -184
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: deprecation-migration
|
|
3
|
+
description: Carries how a session retires a function, a flag, a field, a file, or a command without stranding whoever still calls it, from deciding whether to deprecate at all through proving no caller remains, migrating callers through an adapter or a strangler, and removing the old surface in its own change after the new one has carried every caller. Use when deleting or replacing code something may still call, when a deprecated path has lingered with no date, when finding dead or unowned code, or when asked "can I delete this", "how do I retire this", "how do I migrate callers off X", or "is anything still using this". Do NOT use to move or rename a file with no caller change, which is `codebase-layout`, to migrate a database schema, which the project's persistence rule governs, or to shape a new field or flag added beside an old one, which is `api-design`.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Deprecation and migration
|
|
7
|
+
|
|
8
|
+
A session asked to remove something tends to grep for its name, find nothing it recognizes, and delete it. What it misses calls the thing by a string, a config key, or a copy shipped somewhere the search never looked, and the first anyone hears of it is a break in a place the diff never touched. The reverse failure is as common: a replacement ships, the old path gets a deprecation note, and nobody ever moves the callers, so both live on with no owner. This skill carries the discipline that ends with the old surface gone and every caller working.
|
|
9
|
+
|
|
10
|
+
Load it before deleting or replacing anything a caller outside the current change could reach. Skip it for code introduced on the same branch that nothing has shipped against yet.
|
|
11
|
+
|
|
12
|
+
## Decide whether to deprecate at all
|
|
13
|
+
|
|
14
|
+
Answer four questions before writing a deprecation notice, and keep the surface when the answers do not add up.
|
|
15
|
+
|
|
16
|
+
- **What does keeping it cost?** Name the concrete cost, such as a duplicate path to test, a dependency that blocks an upgrade, or a behavior that confuses readers. "It is old" is not a cost.
|
|
17
|
+
- **Who calls it?** Count the callers you can see and name the kinds you cannot, by the method in the zero-consumers section below.
|
|
18
|
+
- **What replaces it?** A deprecation with no shipped replacement only tells callers they are on their own. Build the replacement first, or keep the old surface.
|
|
19
|
+
- **Who migrates the callers?** Name an owner. A deprecation nobody owns stalls at the notice.
|
|
20
|
+
|
|
21
|
+
## Choose advisory or compulsory
|
|
22
|
+
|
|
23
|
+
- Start advisory: mark the surface deprecated, name the replacement, and leave it working. Callers move when they next touch the code.
|
|
24
|
+
- Move to compulsory only once the replacement has shipped and a removal date is stated where a caller looks, such as the warning text, the changelog, or the docs page for the surface.
|
|
25
|
+
- Make every warning actionable and well timed. Name the replacement and the change a caller makes, and raise it where the caller uses the old surface rather than in a log nobody reads.
|
|
26
|
+
- Never leave an advisory deprecation open with no date and no owner. Either schedule the move to compulsory or withdraw the deprecation.
|
|
27
|
+
|
|
28
|
+
## Migrate the callers yourself
|
|
29
|
+
|
|
30
|
+
The owner of a surface moves its callers, the Churn Rule. Announcing a deprecation and waiting for callers to migrate pushes the work onto everyone downstream, and most of them never do it.
|
|
31
|
+
|
|
32
|
+
- Migrate every caller you can reach in the repository you own, as part of the deprecation work rather than after it.
|
|
33
|
+
- For a caller you cannot edit, such as another team's code or a published consumer, ship a backward-compatible path or migration notes they can apply, and track them as a caller still on the old surface.
|
|
34
|
+
- Never add a feature to the deprecated surface. New behavior goes on the replacement, which gives callers a reason to move.
|
|
35
|
+
|
|
36
|
+
## Prove zero consumers before removal
|
|
37
|
+
|
|
38
|
+
A clean search for one spelling of the name proves only that this spelling is absent from the files searched. Check every caller kind before removing anything.
|
|
39
|
+
|
|
40
|
+
- **Imports and direct calls**, including re-exports and aliases that call it by another name.
|
|
41
|
+
- **String references**, such as a handler looked up by name, a command dispatched from a table, a reflection call, or a test fixture naming it.
|
|
42
|
+
- **Configuration**, including build files, CI workflows, environment defaults, and data files that name the surface.
|
|
43
|
+
- **Documentation and examples**, which callers copy from long after the code moves.
|
|
44
|
+
- **Copies outside the repository**, such as a published package, an installed copy in another project, a shipped binary, a script someone runs from their own machine, or a saved request in an API client.
|
|
45
|
+
|
|
46
|
+
Say which kinds your search could not reach and why, rather than reporting zero. "No callers in this repository, but a published release still exports it" is a finding a reader can act on, since it names where the remaining risk sits. A bare "no callers" is a guess.
|
|
47
|
+
|
|
48
|
+
## Bridge with an adapter or a strangler
|
|
49
|
+
|
|
50
|
+
- **Adapter.** Keep the old interface as a thin layer over the new implementation, so callers keep working while the implementation moves underneath them. The adapter holds no logic of its own and goes once its last caller moves.
|
|
51
|
+
- **Strangler.** Route callers to the new path a group at a time, leaving the old path serving the rest. The old path is done when it serves nothing, and only then is it removed.
|
|
52
|
+
- Prefer the adapter when the interface stays and the implementation changes. Prefer the strangler when callers have to change how they call.
|
|
53
|
+
|
|
54
|
+
## Expand, migrate, contract as three changes
|
|
55
|
+
|
|
56
|
+
Never add a replacement and remove the original in one change. Three separate changes keep every step reversible:
|
|
57
|
+
|
|
58
|
+
1. **Expand.** Add the replacement beside the original. Both work, and nothing calls the new one yet.
|
|
59
|
+
2. **Migrate.** Move callers to the replacement, in one change or several. The original still works for anything missed.
|
|
60
|
+
3. **Contract.** Remove the original once the zero-consumers check passes, in a change of its own.
|
|
61
|
+
|
|
62
|
+
Reverting any one step leaves a working tree. A change that expands and contracts together leaves no point where a missed caller still works, and reverting it reverts the migration too.
|
|
63
|
+
|
|
64
|
+
This sits beside the One-Version Rule `api-design` states rather than against it. Two versions live only between the expand and the contract, and the migrate step moves every caller rather than splitting them between the two.
|
|
65
|
+
|
|
66
|
+
## Treat zombie code as a decision to make
|
|
67
|
+
|
|
68
|
+
Zombie code is unowned and uncalled yet still built, tested, and shipped. It costs build time and reader attention, and it hides which code is live.
|
|
69
|
+
|
|
70
|
+
- Run the zero-consumers check on it like anything else, since "nothing calls it" is the claim to prove.
|
|
71
|
+
- When the check comes back clean, remove it. With no replacement there is nothing to expand or migrate, so the removal runs alone as the contract change.
|
|
72
|
+
- When something does still call it, it is not zombie code. Give it an owner, or deprecate it through the steps above.
|
|
73
|
+
|
|
74
|
+
Read `${CLAUDE_SKILL_DIR}/references/adopted.md` only when extending this guidance or arguing against a rule in it. It records which external sources were adopted, which declined, and why.
|
|
75
|
+
|
|
76
|
+
## Excuses and rebuttals
|
|
77
|
+
|
|
78
|
+
| Excuse | Rebuttal |
|
|
79
|
+
| -------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
|
|
80
|
+
| I searched for the name and nothing calls it | A search finds one spelling in the files it read. A handler looked up by string, a config key, or a published copy stays hidden. |
|
|
81
|
+
| I'll keep the fallback until callers move | With no date and no owner, the fallback outlives every caller it was kept for. State when it goes and who removes it. |
|
|
82
|
+
| The callers can migrate when they get to it | They will not. The owner of the surface moves its callers, or the deprecation never finishes. |
|
|
83
|
+
| It's cleaner to add the new one and drop the old one now | One change that adds and removes leaves no state where a missed caller still works, and a revert undoes the migration too. |
|
|
84
|
+
| This only matters on one machine | One caller is still a caller. Migrate it, or record it as the reason the old path stays. |
|
|
85
|
+
| Nobody owns this, so I can just delete it | No owner is not no caller. Run the zero-consumers check before deciding, since unowned code is often the code nobody dares move. |
|
|
86
|
+
| I'll mark it deprecated and move on | A notice with no shipped replacement and no removal date tells callers nothing they can act on. |
|
|
87
|
+
|
|
88
|
+
## Red flags
|
|
89
|
+
|
|
90
|
+
- You are about to delete a surface after one search for its exact name.
|
|
91
|
+
- A deprecation notice names no replacement or no removal date.
|
|
92
|
+
- The diff adds a replacement and deletes the original in the same change.
|
|
93
|
+
- A fallback or compatibility path has no stated condition for its removal.
|
|
94
|
+
- You are adding behavior to the surface being deprecated.
|
|
95
|
+
- Your report says "no callers" without naming the caller kinds the search could not reach.
|
|
96
|
+
- A caller outside the repository was found and the plan still deletes the original.
|
|
97
|
+
|
|
98
|
+
## Before handing over
|
|
99
|
+
|
|
100
|
+
Check each line against what the change produced. A line answering no is fixed or reported, never left with a note.
|
|
101
|
+
|
|
102
|
+
- The surface is deprecated only if it has a stated cost, a shipped replacement, and a named owner.
|
|
103
|
+
- Every compulsory deprecation states its removal date where a caller looks.
|
|
104
|
+
- Every caller reachable in the repository was migrated, or is named with the reason it was not.
|
|
105
|
+
- The zero-consumers check covered every caller kind, and the report names the kinds it could not reach.
|
|
106
|
+
- No change both adds the replacement and removes the original.
|
|
107
|
+
- Every fallback left in place states when it goes and who removes it.
|
|
108
|
+
|
|
109
|
+
## What this delegates
|
|
110
|
+
|
|
111
|
+
- Adding a field, flag, or parameter beside an old one, and the One-Version Rule for a surface callers cannot pin: `api-design`
|
|
112
|
+
- Moving or renaming a file with no caller change, and where a replacement file sits: `codebase-layout`
|
|
113
|
+
- Database schema changes and their migrations: the project's persistence rule
|
|
114
|
+
- Sequencing expand, migrate, and contract into committed slices on one branch: `build-in-slices`
|
|
115
|
+
- Listing the consumers a finished change breaks, during review: `review-craft`
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Adopted and declined
|
|
3
|
+
description: Which external sources on deprecation and migration this skill adopted, which it declined, and why, so a later session extends the position instead of re-deriving it
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Adopted and declined
|
|
7
|
+
|
|
8
|
+
External sources were read and filtered rather than imported. This file is the record. A later session extending the skill adds to it rather than re-arguing an item already settled here.
|
|
9
|
+
|
|
10
|
+
## Adopted
|
|
11
|
+
|
|
12
|
+
### From the default shelf
|
|
13
|
+
|
|
14
|
+
**Deprecation.** [Software Engineering at Google, chapter 15](https://abseil.io/resources/swe-book/html/ch15.html). Adopted from it:
|
|
15
|
+
|
|
16
|
+
- Advisory and compulsory deprecation as the two types, with compulsory carrying a removal date. The body allows compulsory only once a replacement has shipped, which the chapter implies and the four questions make explicit.
|
|
17
|
+
- Warnings that are actionable and relevant: a warning names what the caller does, and surfaces where the caller uses the old surface.
|
|
18
|
+
- Deprecation as a process with an owner, since the chapter observes that unowned deprecation work makes no progress. Adopted as the fourth decision question and the rule against an advisory deprecation left open with no owner.
|
|
19
|
+
- Finding consumers before removal, which the chapter does with static analysis across one repository. Generalized into the zero-consumers check across caller kinds, since a target project rarely has a whole-company code index and its callers often live outside the repository.
|
|
20
|
+
|
|
21
|
+
**The Churn Rule.** [Software Engineering at Google, chapter 1](https://abseil.io/resources/swe-book/html/ch01.html), under "Policies That Don't Scale": infrastructure teams move their internal users to new versions themselves, or update in place in a backward-compatible way. Adopted as the group on migrating callers yourself, with the backward-compatible path kept for callers the owner cannot edit.
|
|
22
|
+
|
|
23
|
+
### The decision and the bridges
|
|
24
|
+
|
|
25
|
+
**Deprecation and migration.** Addy Osmani's `agent-skills`, pinned at addyosmani/agent-skills@2686b620, [`skills/deprecation-and-migration/SKILL.md`](https://github.com/addyosmani/agent-skills/blob/2686b620/skills/deprecation-and-migration/SKILL.md). Adopted from it:
|
|
26
|
+
|
|
27
|
+
- The five-question deprecation decision, cut to four. Its unique-value and maintenance-cost questions merge into one question about what keeping the surface costs. Its per-consumer migration-cost question drops, since the Churn Rule puts that cost on the owner rather than weighing it per caller. The owner question from the book takes the freed place.
|
|
28
|
+
- The rule never to deprecate without a replacement, as the third decision question.
|
|
29
|
+
- The strangler and adapter patterns, stated as when each fits rather than as worked code tied to one stack.
|
|
30
|
+
- Expand, migrate, contract, lifted out of its schema section and stated for any surface as three separate changes.
|
|
31
|
+
- Zombie code, narrowed to code that is unowned, uncalled, and still built, and settled by the same zero-consumers check rather than a list of staleness signals.
|
|
32
|
+
- The rationalizations and red flags that carry across stacks, reworded for any surface rather than a service or a column. Two excuse rows come from here:
|
|
33
|
+
- The row on a search that found nothing, from its red flag against removing code without verifying zero active consumers.
|
|
34
|
+
- The row on adding the new one and dropping the old one now, generalized from its rationalization about adding a column and dropping the old one in the same migration.
|
|
35
|
+
|
|
36
|
+
## Declined
|
|
37
|
+
|
|
38
|
+
**Its database schema section.** The column rename worked example, the tested down path, batched backfills, and concurrent index builds. Declined because a project's persistence rule owns schema changes, and restating them here puts two owners on one rule. Only the expand, migrate, contract shape was lifted, generalized beyond schemas.
|
|
39
|
+
|
|
40
|
+
**Feature flag migration.** Declined because it is one way to run a strangler, and naming a flag mechanism ties the body to a runtime a target may not have.
|
|
41
|
+
|
|
42
|
+
**The traffic percentages in its strangler phases.** Declined because they describe a service behind a router, and most surfaces a session retires, such as a function, a flag, or a file, have callers rather than traffic.
|
|
43
|
+
|
|
44
|
+
**"Default to advisory" as a standing default with no exit.** Kept advisory as the starting state, and declined leaving it open, since an advisory deprecation with no date and no owner is the stalled case the body exists to prevent.
|
|
45
|
+
|
|
46
|
+
**The thresholds in its zombie signs and rebuttals.** No commits in six months, and comparing costs over two or three years. Declined for the same reason the body states no deprecation window: a number fits one project's cadence and not another's.
|
|
47
|
+
|
|
48
|
+
**"Code is a liability" and design-time deprecation planning as sections.** Declined as framing a session already accepts by loading the skill. The cost question carries the first, and designing a new surface for removal belongs to the skill shaping that surface.
|
|
49
|
+
|
|
50
|
+
**The celebration step and the deprecation notice template.** Declined because neither changes what a session does, and the template's example names a package runner and a migration script tied to one stack.
|
|
@@ -21,6 +21,7 @@ A fix commit answering a review is the sharpest case of the first paragraph, sin
|
|
|
21
21
|
- Sync the body when the new commit moves the scope, and the title when the shift makes it inaccurate
|
|
22
22
|
- Reply on the pull request when it carries review comments, and scan that reply for the banned characters and internal phase labels before posting. The hook watches files and never sees a comment body on its way to the remote.
|
|
23
23
|
- Suppress the reply when the caller owns it, and still run the push and the body sync
|
|
24
|
+
- Read `canon pr evidence <number> --check --json` after posting the evidence and mint the preview when it is owed, since a followup that posts the evidence and stops leaves the preview for a relay
|
|
24
25
|
- Force the push under a lease when the tracking branch no longer reaches the head, so a caller's rebase lands and a commit this session never read is not overwritten
|
|
25
26
|
|
|
26
27
|
## Must not
|
|
@@ -33,6 +33,9 @@ A missing tracking ref is no longer a guard. An open pull request proves the bra
|
|
|
33
33
|
- `no-evidence`: nothing changed under an `evidence/` segment this push. Say nothing and move on.
|
|
34
34
|
- `ok`: write `body` to `.canon/tmp/pr/evidence/body-<number>.md` at the main worktree root (resolved the way `session-worktree` does), then post the comment with `gh pr comment <number> --body-file <main-root>/.canon/tmp/pr/evidence/body-<number>.md` when the record carries no `commentId`, or edit the existing one in place with `gh api -X PATCH repos/{owner}/{repo}/issues/comments/<commentId> -F body=@<main-root>/.canon/tmp/pr/evidence/body-<number>.md` when it does. Clean up the tmp file only after the call reports success.
|
|
35
35
|
- Any other reason is one of the mirrored git refusals (`gh-missing`, `gh-failed`, `no-base`, `unreadable-changes`, `would-empty`). Report it and continue without stopping the chain.
|
|
36
|
+
|
|
37
|
+
After an `ok` post, read what the pull request is still owed with `canon pr evidence <number> --check --json`, branching on `reason` and `owed` rather than the exit. When `owed` lists `preview`, mint it through the preview section of `canon:git-pr`'s `references/evidence.md`, then re-read once. Report anything but `settled` after that re-read and continue, since a refused deploy would otherwise loop. A binary lacking `--check` reports the thread unread rather than settled. A preview already on the comment counts as settled whatever head built it, so a later push does not re-mint one.
|
|
38
|
+
|
|
36
39
|
6. Check for existing review comments: `gh api 'repos/{owner}/{repo}/pulls/<number>/comments' --jq 'length'`, resolving `<number>` from `gh pr view --json number`.
|
|
37
40
|
7. Sync the body and title on every invocation, before the routing below decides on the reply.
|
|
38
41
|
- Run `gh pr view --json url,title,body` and update the body with `gh pr edit --body` when the new commit changes scope, and the title with `gh pr edit --title` when the scope shifted enough to make it inaccurate.
|
|
@@ -28,6 +28,7 @@ A lookup that resolves by head branch alone carries its own failure. A branch na
|
|
|
28
28
|
- Label from the paths the branch changed, against a map the project declares, so the label set belongs to the project rather than to the skill
|
|
29
29
|
- Apply labels after the pull request exists, so a label the remote does not carry costs a warning rather than the pull request
|
|
30
30
|
- Report a refused label, since a warning nothing surfaces leaves the run indistinguishable from one that labelled
|
|
31
|
+
- Run the evidence verb on every pull request the skill opens, and let its `no-evidence` answer be the skip, since a session cannot see a regenerated image it did not author and a gate asking it to look lets that image ship with no comment
|
|
31
32
|
- Put a preview address on a pull request that changes a rendered surface when the project's deploy can mint one, since screenshots and a checklist leave a reviewer nothing to click into before merging
|
|
32
33
|
- Bound the wait on that preview and finish the chain without the link on a timeout, since a slow deploy must not hold the ship
|
|
33
34
|
- Put the branch's running local server on the same pull request when this worktree is serving one, and remove it when the pull request closes, since a reviewer on the operator's machine can interact with the branch and a link that outlives it points at whatever runs there next
|
|
@@ -152,7 +152,7 @@ The last output line carries `head=` so a caller relaying the number holds a bra
|
|
|
152
152
|
|
|
153
153
|
### Post the rendered-surface evidence
|
|
154
154
|
|
|
155
|
-
|
|
155
|
+
Run this step on every pull request this skill opens or edits. Read `${CLAUDE_SKILL_DIR}/references/evidence.md` for finding the checklist and the local server, posting the evidence comparison, posting the checklist alone, and posting the preview address, each against the `<number>` the final command printed. Never judge from the diff whether an evidence image changed, since the verb answers `no-evidence` for a branch that changed none and a session cannot see an image it did not author.
|
|
156
156
|
|
|
157
157
|
### Record the number on the task
|
|
158
158
|
|
|
@@ -5,7 +5,7 @@ description: How git-pr finds the UI checklist and the local server, posts the e
|
|
|
5
5
|
|
|
6
6
|
# Rendered-surface evidence
|
|
7
7
|
|
|
8
|
-
The rendered-surface step of `git-pr`, reached after the final command printed the pull request number. The
|
|
8
|
+
The rendered-surface step of `git-pr`, reached after the final command printed the pull request number. The step runs on every pull request, with no test on the diff ahead of it. `no-evidence` is the silent branch, so a pull request that changes no rendered surface posts nothing.
|
|
9
9
|
|
|
10
10
|
## Find the UI checklist
|
|
11
11
|
|
|
@@ -92,7 +92,7 @@ Deleting the file is what makes the later re-render safe. `git-followup` re-runs
|
|
|
92
92
|
|
|
93
93
|
## Post the preview address
|
|
94
94
|
|
|
95
|
-
Run this step
|
|
95
|
+
Run this step when the evidence step above returned `ok`, a checklist was posted by the fallback, or `canon pr evidence <number> --check --json` lists `preview` in `owed`. The first two mean the pull request changes a rendered surface, and a reviewer holding a checklist with no screenshots needs the live page most. The third is how `git-ship` reaches this step alone when an earlier run's deploy timed out, so no evidence step ran in the current one. Otherwise skip it silently.
|
|
96
96
|
|
|
97
97
|
The evidence comment is already posted, so the reviewer has the screenshots while the deploy runs. Mint the preview against the same `<number>`:
|
|
98
98
|
|
|
@@ -17,10 +17,12 @@ The sequence also reaches the remote on work nothing re-checked. This skill is t
|
|
|
17
17
|
- Say so and continue when the project names no verify command, since silence there reads as a suite that passed
|
|
18
18
|
- Invoke each step through the Skill tool in the stated order and continue without waiting
|
|
19
19
|
- Stage after the sync skills write, so what they produced reaches a commit
|
|
20
|
+
- Reach the pull request on a branch whose work is already committed and whose sync steps wrote nothing, since `git-stage` stops on an empty index and a session building in slices leaves one
|
|
20
21
|
- Emit no text between steps. The sequence is the unit and prose inside it reopens settled decisions.
|
|
21
22
|
- Name the one point a wrapping caller may act at, so a chain built on this one is not left to pick a gap of its own
|
|
22
23
|
- Name the condition under which the closing block is not emitted, since a caller that closes on its own block leaves two instructions about the last line and nothing deciding between them
|
|
23
24
|
- Watch continuous integration to a terminal state in the background, so the session stays reachable while CI runs, and stop on a failure naming the check
|
|
25
|
+
- Read the evidence thread with `canon pr evidence <number> --check --json` once CI passes, run what it reports owed, and report done only on `settled`, since a chain that never reads the thread ships a regenerated image with no comment and no preview and leaves the controller to repair it
|
|
24
26
|
- Stop memory work at the Propose phase
|
|
25
27
|
|
|
26
28
|
## Must not
|
|
@@ -35,6 +37,8 @@ The sequence also reaches the remote on work nothing re-checked. This skill is t
|
|
|
35
37
|
## Guards
|
|
36
38
|
|
|
37
39
|
- A failing verify stops the run before the sync skills write, so the tree is left as the user left it
|
|
40
|
+
- A binary lacking `--check` reports the thread unread, never settled, since reading the absence as a pass repeats the failure the read exists to close
|
|
41
|
+
- Re-read the thread once after running what was owed and stop on anything but `settled`, so a refused preview cannot loop the chain
|
|
38
42
|
- A failing check stops the sequence. A stop report and the line announcing the background watch are the two places text is allowed between steps.
|
|
39
43
|
|
|
40
44
|
## Out of scope
|
|
@@ -28,7 +28,7 @@ Run `git diff --cached --name-only 2>/dev/null` to check for staged files. If ou
|
|
|
28
28
|
3. Invoke `canon:docs-sync` to sync public docs against changes since main
|
|
29
29
|
4. Run `git add -A` to stage any files the sync skills wrote
|
|
30
30
|
5. Run `canon tasks plan-reach <plan> --json` and report both lists it carries. Name the plan this branch built under, by path or by slug. Read `claimed` first and say who holds each path, since that is the half a reader acts on, then say how many of the changed paths `undeclared` names. Branch on the record rather than on the exit code, which a shell function wrapping `canon` can flatten to zero. This step reports and never stops the sequence.
|
|
31
|
-
6. Invoke `canon:git-stage` to group staged changes and commit by concern
|
|
31
|
+
6. Invoke `canon:git-stage` to group staged changes and commit by concern, only when `git diff --cached --name-only` prints a path. When it prints nothing, the work already reached history in slices, so continue to step 7.
|
|
32
32
|
7. Invoke `canon:git-branch` to rename branch to match conventional format
|
|
33
33
|
8. Invoke `canon:git-pr` to push branch and open pull request
|
|
34
34
|
9. After the PR opens, watch CI in the background, so the session stays reachable while CI runs. Read `### Watching CI` below for the commands and the wake.
|
|
@@ -49,7 +49,7 @@ Emit `⏳ Watching CI on #<number> in the background` and end the turn. Print no
|
|
|
49
49
|
|
|
50
50
|
On the wake, branch on the final record's fields rather than on the exit:
|
|
51
51
|
|
|
52
|
-
- `state: passing`: continue to After completion
|
|
52
|
+
- `state: passing`: read the evidence thread under `### Settling the evidence thread` below, then continue to After completion on `settled`.
|
|
53
53
|
- `state: failing`: stop the sequence and report the failing check with its URL.
|
|
54
54
|
- `conflicted: true`: stop the sequence and report that the branch conflicts with its base, since no run will start for it. A rebase is the repair.
|
|
55
55
|
- A `reason` and no `state`: the read was refused, such as `no-remote-branch` for a branch deleted on the remote. Stop and report that `reason`. A missing `state` is never a pass.
|
|
@@ -58,6 +58,17 @@ On the wake, branch on the final record's fields rather than on the exit:
|
|
|
58
58
|
|
|
59
59
|
Do not auto-fix any of these. The watch line and a stop report from any branch above are the two exceptions to the no-text-between-steps rule.
|
|
60
60
|
|
|
61
|
+
### Settling the evidence thread
|
|
62
|
+
|
|
63
|
+
On a `passing` wake, run `canon pr evidence <number> --check --json` against the number step 8 returned. It reads the pull request's comments and edits none, so the comment a reviewer already ticked stays as it is. Branch on `reason` and `owed` rather than the exit.
|
|
64
|
+
|
|
65
|
+
- `settled`: nothing is owed, which is also what a branch that changed no rendered surface reads. Continue to After completion.
|
|
66
|
+
- `owed`: run each step the record's `owed` list names, from `canon:git-pr`'s `references/evidence.md`, evidence first and then preview. Re-read once with the same command. Continue to After completion only on `settled`. Any other reading stops the sequence and reports the `reason` with the `owed` list, and the sequence never loops back for a second pass. A preview step that refuses, or a deploy that failed, leaves `preview` owed on the re-read, so that is the stop and not a retry.
|
|
67
|
+
- Any other `reason`, such as `gh-failed`: the thread went unread. Stop and report the `reason`, since an unread thread is not a settled one.
|
|
68
|
+
- No record at all, or an unknown flag error: the installed binary predates `--check`. Report the thread unread rather than settled, and continue to After completion without emitting a claim that it was checked.
|
|
69
|
+
|
|
70
|
+
The read is a closing step and the draft mark stays the only thing between steps 8 and 9. A caller that closes on its own block, as `auto-ship` does, waits on the same CI wake, so the read lands here and not in that body.
|
|
71
|
+
|
|
61
72
|
### Why the reach reads at step 5
|
|
62
73
|
|
|
63
74
|
The branch is whole there and nowhere earlier. Steps 2 and 3 write past whatever the plan declared, so a reading taken ahead of them misses the chain's own additions, and no pull request exists until step 8 to carry the answer anywhere.
|
|
@@ -13,6 +13,8 @@ The miss is measured. On a seeded branch that deleted a dirty-tree guard while t
|
|
|
13
13
|
|
|
14
14
|
Rendered output is the larger hole. `git-pr` posts an `## Evidence` comment through `canon pr evidence`, carrying base and head screenshots and a checklist a reviewer ticks. The pull request review named that heading only in its heading set, and no step opened an image. On a seeded pull request whose narrow head screenshot shows the navigation running off the edge while a ticked box claims it collapses, the review filed the finding off the stylesheet diff and said it had not rendered the page. On a styling change with no screenshot at all, on a project whose trunk keeps them, it did not mention the absence.
|
|
15
15
|
|
|
16
|
+
A dependency upgrade is not a measured miss. On 2026-10-02 a seeded branch bumped one dependency across a major version beside a second, with a lockfile adding a transitive package that carried an install script, and the body without a dependency reference reported it. The run that measured it passed every assertion, including a graded finding naming the upgrade, so the case is a floor and no reference exists for it. An earlier run matched only a loose pattern and left no report to read, so it counts for nothing. The security reference still had no threat-model step and no class for a delete or clean on a derived path, both groundwork lifts with no miss to measure.
|
|
17
|
+
|
|
16
18
|
The axes also said nothing about a change that passes by lowering the bar it has to clear, such as a test skipped, a threshold moved, or a path excluded from a checker, nothing about performance, and one sentence about design with no procedure behind it. A refactor that only moved complexity read as a design gain, and a removal could call code dead without reading why it was added. The body carried no excuses, red flags, or closing checklist, so a session about to stop at the hunk met no answer first.
|
|
17
19
|
|
|
18
20
|
## Must
|
|
@@ -27,6 +29,7 @@ The axes also said nothing about a change that passes by lowering the bar it has
|
|
|
27
29
|
- State a design finding as a concrete cost, so it survives the procedure's filter against subjective suggestions
|
|
28
30
|
- Carry the evidence bar: confirm against the file at the reviewed head, quote a cited rule, name the breaking input, and drop what a gate owns or what rests on unread state
|
|
29
31
|
- Carry security as classes with an exclusion list, in a reference loaded when the diff reaches one
|
|
32
|
+
- Open the security reference with a threat model drawn from the diff, and carry destructive operations on a derived path as a class, so a cleanup deleting an unchecked variable's glob is read for the empty-value collapse
|
|
30
33
|
- Open the evidence images on a rendered change through `git show` at the row's own sha, never through the embedded address, within a stated read budget
|
|
31
34
|
- Test each ticked checklist box against an opened image, and name a ticked box no image covers as untested
|
|
32
35
|
- Flag a rendered change that carries no screenshot, as a finding where the trunk already keeps them and as a question elsewhere
|
|
@@ -36,7 +36,7 @@ An axis whose condition the diff meets is not optional. When the security or the
|
|
|
36
36
|
|
|
37
37
|
Read each of these when the diff reaches what it names.
|
|
38
38
|
|
|
39
|
-
7. **Security.** Read `${CLAUDE_SKILL_DIR}/references/security.md` when the diff runs a command, writes a file, handles input from outside the process, touches a secret, adds a dependency, or changes a default a consumer installs.
|
|
39
|
+
7. **Security.** Read `${CLAUDE_SKILL_DIR}/references/security.md` when the diff runs a command, writes or deletes a file, handles input from outside the process, touches a secret, adds a dependency, or changes a default a consumer installs.
|
|
40
40
|
8. **Rendered output.** Read `${CLAUDE_SKILL_DIR}/references/ui.md` when the diff touches a file that paints, such as markup, a stylesheet, a component, a template, or a design token, or when the pull request carries an evidence comment. A finding read off a stylesheet diff says what the author changed, and only the screenshot says what a user sees, so the reference opens the images and checks whether any exist.
|
|
41
41
|
9. **Developer experience and operations.** Ports, hooks, scripts, config, and scaffold defaults a consumer installs. A new required step nobody documented, a default that fails on a clean machine, or a hook that slows every commit is a finding even when the code is correct.
|
|
42
42
|
10. **Executable prose.** A skill body, a rule, or a prompt is instructions a model runs. Read it the way you read code: a step that races another, a precondition it never states, a branch with no exit, and two instructions that contradict each other are bugs.
|
|
@@ -34,6 +34,10 @@ From `addyosmani/agent-skills@2686b620`, `skills/constraint-driven-development/S
|
|
|
34
34
|
|
|
35
35
|
From `addyosmani/agent-skills@2686b620`, `skills/code-review-and-quality/SKILL.md` for the axis itself, a call inside a loop and an unbounded fetch, and `skills/performance-optimization/SKILL.md` for keep or revert: measure before and after the same way, and a neutral result argues for removing the added complexity. The repeated-run requirement against noise is stated here so one run on each side reads as an anecdote.
|
|
36
36
|
|
|
37
|
+
### Security additions
|
|
38
|
+
|
|
39
|
+
From `addyosmani/agent-skills@2686b620`, `skills/security-and-hardening/SKILL.md`: the threat model first and the derived-path rule. Adopted as the opening step of `references/security.md`, which names who supplies each input and what the code can reach before any class is read, and as the destructive-operations class, which asks for the empty-value collapse, the glob or symlink escape, the missing root check, and no read of what is there before the call. Both stay stack-neutral. No red run measures them, so they ship as lifts rather than as an answer to a miss.
|
|
40
|
+
|
|
37
41
|
### Closing sections
|
|
38
42
|
|
|
39
43
|
The excuses, red flags, and closing checklist follow the practice skill shape every practice skill in this toolkit carries, taken from `addyosmani/agent-skills@2686b620`, [`docs/skill-anatomy.md`](https://github.com/addyosmani/agent-skills/blob/2686b620fc1fed2e8f60c704839c766b8594c6b6/docs/skill-anatomy.md). Each excuse row rebuts a reason a review stops at the hunk, such as passing tests against a test the diff skipped, rather than an objection nobody raised.
|
|
@@ -46,4 +50,8 @@ The excuses, red flags, and closing checklist follow the practice skill shape ev
|
|
|
46
50
|
|
|
47
51
|
**Named structural remedies as a catalog.** A list of refactorings to propose reads as a menu a session fills in. A design finding states the cost, and the remedy is the author's.
|
|
48
52
|
|
|
53
|
+
**A dependency upgrade reference.** From `addyosmani/agent-skills@2686b620`, `skills/code-review-and-quality/SKILL.md`: read the changelog across the range, one dependency per change, and the lockfile diff. Declined because the seeded upgrade is not a miss. The body without such a reference reported the planted major bump and the install script in the lockfile on the second of two runs, which passed the assertion naming them. Revisit when a run on a changed lockfile misses what a reference would have named.
|
|
54
|
+
|
|
55
|
+
**STRIDE and abuse-case tests as a procedure.** They belong to a design session rather than a diff read, and the threat-model opening in the security reference takes the one step a diff supports, naming who supplies each input.
|
|
56
|
+
|
|
49
57
|
**The web and database tables from `performance-optimization`.** They name a stack, and the axis stays stack-neutral until a target asks for a per-stack reference.
|
|
@@ -2,10 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
Read each class against the diff. A class the diff does not reach is skipped, not reported as clean. Name the input that reaches the sink and the path it takes, since a class named with no path is a suspicion rather than a finding.
|
|
4
4
|
|
|
5
|
+
## Open with the threat model
|
|
6
|
+
|
|
7
|
+
Before the classes, name from the diff who supplies each input and what the code can reach with it: a file, a process, a network, a credential. Skip a class that model rules out, and say which one and why, so the skip reads as a decision rather than an oversight.
|
|
8
|
+
|
|
5
9
|
## Classes to check
|
|
6
10
|
|
|
7
11
|
- **Shell and command injection.** A value from an argument, an environment variable, a file, or a network response reaching a shell: through `eval`, an unquoted expansion, a string built into a command, or a subprocess call that takes a single command string. Quoting the variable at the call site is the fix to look for.
|
|
8
12
|
- **Path traversal in a file write.** A path built from outside input and written without being resolved and checked against the directory it must stay inside. A `..` segment, an absolute path, and a symlink inside the target each escape a naive join.
|
|
13
|
+
- **Destructive operation on a derived path.** A delete, overwrite, move, or clean whose path is built from a variable, a config value, or a listing. Look for the empty or unset value that collapses it to a root, a glob or a symlink that carries it outside the folder it was meant for, no check that the resolved path sits at least one level below an expected root, and no read of what is there, owned by this tool or not, before the call. The fix to look for is resolve, require the root, then act. A write escaping its folder is path traversal. When a finding fits both, name the class whose fix applies.
|
|
9
14
|
- **Secrets and personal data leaving the process.** A token, a key, a password, or personal data reaching a log line, an error message, a session transcript, a published page, a pull request comment, or a sync to a remote. Check what a debug line prints and what a verbose flag adds.
|
|
10
15
|
- **Supply chain.** One-shot package execution of an unpinned version, which runs whatever the registry serves that day. A new dependency, and what its install scripts run. A lockfile that changes without a manifest change.
|
|
11
16
|
- **Time of check to time of use on a file write.** An existence or permission check followed by a write to the same path in a later step, and a predictable name in a shared temporary directory. Another process can swap the path in between.
|
|
@@ -18,11 +18,14 @@ A verdict also goes stale without saying so. A push after the pass changes what
|
|
|
18
18
|
- Drive every checklist box in the running app and give each exactly one verdict: pass or fail read off the page with the value quoted, pass or fail against a frame with what it shows, needs eyes for a box marked as taste, or not driven with the reason
|
|
19
19
|
- Drive a box written before the drivable format all the same, naming the route or width it guessed, so no box is skipped silently
|
|
20
20
|
- Read the checklist and the address from the evidence record rather than from the diff, the plan, or the author's description
|
|
21
|
+
- Drive only a build of the head the verdict names, and stop with nothing posted when the hosted preview was built from an older one
|
|
21
22
|
- Take the hosted preview, then the local preview, then an address the launch names, and refuse when none exists
|
|
22
23
|
- Report an address that does not answer as not driven rather than as a fail, and leave the review closed on a box no commit on the branch can settle, so an absent preview never holds the draft mark at every head
|
|
23
24
|
- Sweep console errors, sideways overflow at each named width, and the focus and details probes over the states reached, and nothing beyond them
|
|
24
25
|
- Post its own comment as a pull request review under `## UI review` while anything is owed and `## UI review closed` once nothing is, ending on a marker naming the head it drove
|
|
25
|
-
-
|
|
26
|
+
- Embed a frame only for a state the worker's evidence record lacks, pushed through `canon pr frames` to a branch that never merges and linked by its path there under this pass's own stamp, so the image lasts until its own pull request is dropped and no later pass replaces it, and cite the evidence stem for a state the record already shows, so the review adds no image the worker's evidence already carries
|
|
27
|
+
- Push only a frame of the address the pass drove, since the branch is as public as the repository
|
|
28
|
+
- Describe a frame in words when the push refuses, naming the reason, and cite no local path, since a path under `.canon/` fails the label scan the review-event run applies to the posted body
|
|
26
29
|
- Read the review-event checks for the head after the post, bounded, and report a failure in the result line, or the checks as unread when they never settle
|
|
27
30
|
- Report the heading it posted by reading the posted file's first line, so the result line and the body come from one source
|
|
28
31
|
- Name the renderer the browser reported, and render on the GPU only when the launch names a config for it
|
|
@@ -54,4 +57,5 @@ A verdict also goes stale without saying so. A push after the pass changes what
|
|
|
54
57
|
- Writing the checklist and its drivable format, which `ui-checklist` owns
|
|
55
58
|
- Dispatching the pass, polling its verdict, and lifting the draft mark, which `role-orchestrator` owns
|
|
56
59
|
- A subagent inside the code reviewer, dropped because its cost stays invisible until it returns
|
|
57
|
-
-
|
|
60
|
+
- Writing a tracked file or checking anything out to host a frame. The push goes through the GitHub API onto the frames branch alone, so the reviewer still enters no worktree and touches no branch a pull request holds.
|
|
61
|
+
- Dropping a closed pull request's frames, which a scheduled workflow runs, and purging a dropped frame GitHub still serves by commit, which needs a platform request
|
|
@@ -21,11 +21,12 @@ rather than inside it, so the two passes finish on their own clocks.
|
|
|
21
21
|
- No address resolves under Step 3: stop and post nothing, `❌ No address to drive. PR #<number> carries no preview and no local preview, and the launch named none.`
|
|
22
22
|
- The wrapper refuses to open the browser because its revision is absent: stop and post nothing, passing its install command to whoever launched the pass. Never install mid-pass.
|
|
23
23
|
- The newest UI verdict is `## UI review closed` at the current head: stop, `The UI review already covers <short-sha>.` An open verdict at the head stops the same way only when nothing has arrived since it: drive again when a `## Review response` or `## Post-review findings` comment is newer than the verdict, or the launch names an address.
|
|
24
|
+
- The hosted preview was not built from the head: stop and post nothing, naming `built`, `tip`, and `canon pr preview <number> --json` for the dispatcher. A verdict posted against an older build carries a marker naming a head nobody drove.
|
|
24
25
|
- Post and stop. Never merge, never tick a box on the evidence comment, and never lift the draft mark.
|
|
25
26
|
|
|
26
27
|
## Step 1: resolve the pull request
|
|
27
28
|
|
|
28
|
-
Resolve the number with `gh pr view --json number,headRefName,headRefOid`, or take the one the launch names. Take `<head>` off `canon pr head <number> --json`, reading its `tip`, and fall back to `headRefOid` when no record comes back. The first seven characters are `<short-sha>`.
|
|
29
|
+
Resolve the number with `gh pr view --json number,headRefName,headRefOid`, or take the one the launch names. Take `<head>` off `canon pr head <number> --json`, reading its `tip`, and fall back to `headRefOid` when no record comes back. The first seven characters are `<short-sha>`. Record `<pass>` once, as the instant this pass starts, with `date -u +%Y%m%dT%H%M%SZ`. Every frame Step 5 pushes files under it, so a later pass at the same head never replaces an image this one's comment shows.
|
|
29
30
|
|
|
30
31
|
Read the newest UI verdict for the head guard:
|
|
31
32
|
|
|
@@ -43,7 +44,7 @@ Read nothing else about the change. The diff, the plan, the task, and the descri
|
|
|
43
44
|
canon pr evidence <number> --json
|
|
44
45
|
```
|
|
45
46
|
|
|
46
|
-
Take three fields off the record, each present only when the posted evidence comment holds it: `checklist`, `preview`, and `local`. They come from the comment already on the thread, so `reason` reading `ok` or `no-evidence` makes no difference here, and the rendered `body` is not this pass's to read. Branch on the record rather than on the exit code, which a shell function wrapping `canon` can flatten to zero. Only `ok` and `no-evidence` read the thread. Every other `reason` is a refusal that never reached the comment, so report it verbatim and stop rather than reading the missing fields as an absent checklist.
|
|
47
|
+
Take three fields off the record, each present only when the posted evidence comment holds it: `checklist`, `preview`, and `local`. They come from the comment already on the thread, so `reason` reading `ok` or `no-evidence` makes no difference here, and the rendered `body` is not this pass's to read. Keep `states` as well when `reason` reads `ok`, being each evidence state's name and the stems under it, which Step 5 matches a frame against. A record carrying no `states`, on `no-evidence` or from an older binary, covers no state, so every frame is pushed. Branch on the record rather than on the exit code, which a shell function wrapping `canon` can flatten to zero. Only `ok` and `no-evidence` read the thread. Every other `reason` is a refusal that never reached the comment, so report it verbatim and stop rather than reading the missing fields as an absent checklist.
|
|
47
48
|
|
|
48
49
|
A binary older than 5.4.0 reports none of the three fields whatever the thread holds, so a record carrying none is ambiguous. Read `canon --version` before taking the no-checklist stop, and on an older release report the release this pass needs and stop rather than parsing the comment by hand.
|
|
49
50
|
|
|
@@ -55,6 +56,16 @@ Take the first rung that answers, testing each with `curl -s -o /dev/null -w '%{
|
|
|
55
56
|
2. The `local` address off the record.
|
|
56
57
|
3. An address the launch names.
|
|
57
58
|
|
|
59
|
+
When the hosted rung answers, check that it was built from the head before driving it:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
canon pr preview <number> --check --json
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Branch on the record's `reason`. Only `fresh` continues. Any other stops with nothing posted, naming `built`, `tip`, and the next act: `stale` and `no-build` ask the dispatcher to run `canon pr preview <number> --json`, and `building` asks it to wait, since a mint is already running for the tip. This pass never mints. A `canon` that rejects `--check` predates the verb. Report that this pass needs a `canon` whose `pr preview` takes `--check`, naming the installed `canon --version`, and stop rather than reading the missing flag as `fresh`, the way Step 2 does for its own older binaries. A `reason` of `no-deploy`, `unfenced`, or `no-alias` means the project has no fenced deploy to read, so the hosted build cannot be verified. Stop on the hosted address then too, and say so.
|
|
66
|
+
|
|
67
|
+
The check covers the hosted address only. The local rung and an address the launch names have no deploy run to read, so say in the comment that they were driven unverified rather than implying the same coverage.
|
|
68
|
+
|
|
58
69
|
An address that exists and does not answer is a different outcome from no address at all. When every rung that exists fails to answer, skip the drive, record each box as not driven with the addresses tried and what each returned, and go to Step 7. A local address on another machine is the usual cause, and it says nothing about the change.
|
|
59
70
|
|
|
60
71
|
## Step 4: open the browser
|
|
@@ -75,6 +86,14 @@ Give every box exactly one verdict, in checklist order. A box the pass could not
|
|
|
75
86
|
|
|
76
87
|
Never judge a box ending in `(taste)`. Drive to the state, capture the frame, and mark it needs eyes. Drive a ticked box the same as an unchecked one, since a tick is the author's claim and this pass exists to check it.
|
|
77
88
|
|
|
89
|
+
A frame the verdict rests on is published only when the worker's evidence lacks it. Compare the box's route, width, and theme against the `states` Step 2 kept, and when a state and stem show the same thing, cite that stem and push nothing. The match is this pass's judgment over the box's wording, so the verb never makes it. Otherwise push the frame and keep the `link` the record returns:
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
canon pr frames <number> --add frames/<box-number>.png --box <box-number> --head <head> --pass <pass> --json
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Push only a frame of the address this pass drove, since the branch is as public as the repository. Branch on `reason` rather than on the exit code. Every reason but `ok` is a refusal, `read-only` among them on a fork's token, so describe that frame in words and name the reason in its evidence rather than failing the pass.
|
|
96
|
+
|
|
78
97
|
## Step 6: sweep
|
|
79
98
|
|
|
80
99
|
Run three checks over every route the boxes reached, and nothing beyond them:
|
|
@@ -89,7 +108,7 @@ Close the browser with `${CLAUDE_SKILL_DIR}/scripts/pw.sh -s=<project>-<number>
|
|
|
89
108
|
|
|
90
109
|
## Step 7: post
|
|
91
110
|
|
|
92
|
-
Read `${CLAUDE_SKILL_DIR}/references/post.md` for the heading rule, the body shape, the marker every body ends on, and the post command.
|
|
111
|
+
Read `${CLAUDE_SKILL_DIR}/references/post.md` for the heading rule, the body shape, the marker every body ends on, and the post command. Each Evidence cell embeds the `link` its Step 5 push returned, as given, or names the evidence stem it matched.
|
|
93
112
|
|
|
94
113
|
## Step 8: read the review-event checks
|
|
95
114
|
|
|
@@ -119,4 +138,4 @@ Add `S sweep finding(s).` when the sweep raised any. Report no merge recommendat
|
|
|
119
138
|
- Drive the checklist and the sweep, and nothing else. Open exploration has no end a dispatcher can predict.
|
|
120
139
|
- Never check out, build, or serve the head. An address is handed to this pass or the pass refuses.
|
|
121
140
|
- Never read a value off the snapshot file whole. Search it for the ref a box needs, and read text, styles, and geometry with `eval`.
|
|
122
|
-
- Write only under `.canon/tmp/pr/review-ui/`, at the main worktree root.
|
|
141
|
+
- Write only under `.canon/tmp/pr/review-ui/`, at the main worktree root, and to the frames branch through `canon pr frames`, which goes through the API and checks nothing out.
|
|
@@ -41,10 +41,12 @@ Each box takes exactly one.
|
|
|
41
41
|
| Verdict | When | Evidence it carries |
|
|
42
42
|
| ------------------- | ------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
|
|
43
43
|
| pass or fail, read | The result is a fact the page reports | The value read, quoted, such as `scrollWidth 436 against clientWidth 320` |
|
|
44
|
-
| pass or fail, frame | The result has a stated criterion only an image settles |
|
|
45
|
-
| needs eyes | The box ends in `(taste)` |
|
|
44
|
+
| pass or fail, frame | The result has a stated criterion only an image settles | The pushed frame's link or the matching evidence stem, and what the frame shows, in words |
|
|
45
|
+
| needs eyes | The box ends in `(taste)` | The pushed frame's link or the matching evidence stem, and what the frame showed, with nothing about whether it looks right |
|
|
46
46
|
| not driven | The state could not be reached | The reason, such as an unreachable address, a `(local only)` box on a hosted preview, or a target the snapshot does not hold |
|
|
47
47
|
|
|
48
|
-
A frame
|
|
48
|
+
A frame verdict carries one image at most, and never one the worker's evidence already shows. When a state and stem in the evidence record match the box's route, width, and theme, the evidence names that stem and nothing is pushed. Otherwise the frame goes up through `canon pr frames` and the evidence carries the `link` the record returned, which names the frame's path on the frames branch. Either way the words stay, describing the value or region judged, such as the element, its position, and the colors or text read, so a reader whose image fails to load can still check it.
|
|
49
|
+
|
|
50
|
+
A push that refuses leaves the words alone, with the reason named. Never cite the local frame path. A path under `.canon/` is a board identifier the label scan rejects, and it resolves only on this machine.
|
|
49
51
|
|
|
50
52
|
A fail names what was expected beside what was read. A not driven never reads as a fail, since it says the pass could not look rather than that the page is wrong. Its reason says whether the cause sits on the page or off it, since only a cause on the page opens the heading Step 7 picks.
|
|
@@ -28,7 +28,8 @@ P passed, F failed, E need eyes, N not driven. Drove <address> at <short-sha>, r
|
|
|
28
28
|
| Box | Verdict | Evidence |
|
|
29
29
|
| ---------------------------------- | ---------- | --------------------------------------------- |
|
|
30
30
|
| 1. <the box as written, shortened> | fail | <the value read against what the box expects> |
|
|
31
|
-
| 2. <box> | needs eyes | <what the frame showed, in words
|
|
31
|
+
| 2. <box> | needs eyes |  <what the frame showed, in words> |
|
|
32
|
+
| 3. <box> | pass | Evidence `<stem>` <what it showed, in words> |
|
|
32
33
|
|
|
33
34
|
**Sweep**
|
|
34
35
|
|
|
@@ -43,7 +44,7 @@ P passed, F failed, E need eyes, N not driven. Drove <address> at <short-sha>, r
|
|
|
43
44
|
<!-- review-ui: head=<head> -->
|
|
44
45
|
```
|
|
45
46
|
|
|
46
|
-
A frame
|
|
47
|
+
An Evidence cell resting on a frame takes one of three forms. A frame Step 5 pushed embeds as ``, with the link exactly as `canon pr frames` returned it. It names the frame's path on the frames branch, which stays put while other pull requests' frames are dropped and carries this pass's stamp, so a later pass never changes the image. A state the worker's evidence already shows names the evidence stem in backticks and embeds nothing, since the evidence comment carries that image. A push that refused leaves the words alone and names the reason. Never cite the local frame path, since a path under `.canon/` is a board identifier the label scan rejects.
|
|
47
48
|
|
|
48
49
|
A pass where every box needs eyes and nothing else is owed takes the closed heading:
|
|
49
50
|
|
|
@@ -52,5 +52,6 @@ The draft mark fails from both ends. On 2026-08-31 four sessions re-drafted a pu
|
|
|
52
52
|
|
|
53
53
|
- Entering the worktree, which `session-worktree` owns
|
|
54
54
|
- The chain from implement through pull request, which `auto-ship` owns
|
|
55
|
+
- How the build moves through the plan, slice by slice with a commit each, which `build-in-slices` owns
|
|
55
56
|
- Answering a posted review, which `review-address` owns
|
|
56
57
|
- The controlling session's half of the channel, the review poll, and the watch beside it, which `role-orchestrator` and its runbooks hold
|
|
@@ -20,6 +20,10 @@ from the skill that owns it and invoke none of the three from here. The ordinary
|
|
|
20
20
|
path arrives through `auto-ship` Step 0, which means that chain is already
|
|
21
21
|
running and re-invoking it would restart the build.
|
|
22
22
|
|
|
23
|
+
This body holds what the session may write. How it builds, in committed slices
|
|
24
|
+
with an out-of-scope finding noted rather than fixed, is `build-in-slices`,
|
|
25
|
+
which `auto-ship` Step 2 loads.
|
|
26
|
+
|
|
23
27
|
## Where the session stands
|
|
24
28
|
|
|
25
29
|
- Resolve `.canon/plans/`, `.canon/tasks/`, `.canon/review/`, `.canon/memory/`, and `.canon/ready/` at the main worktree root, never against the linked worktree this session builds in. Those folders are gitignored, so `git worktree add` never creates them and the copy beside the build is absent rather than empty.
|
|
@@ -14,6 +14,7 @@ Without this skill, a session implementing a planned change writes the test afte
|
|
|
14
14
|
- Write or extend the test before the implementation it covers, for any behavior whose shape is already known
|
|
15
15
|
- Run the test before implementing and confirm it fails for the missing behavior, not for an unrelated mistake in the test itself
|
|
16
16
|
- Implement the minimum the current test demands, and start a new test before extending past it
|
|
17
|
+
- Load `canon:code-craft` before writing the implementation when its shape is still open and the session has not loaded the skill, so the shape of the code is settled before the body rather than during refactor
|
|
17
18
|
- Re-run the test after implementing and confirm the pass is the one the test was written to prove
|
|
18
19
|
- Refactor the implementation and the test once the suite is green, re-running it after each change, since the smallest change that passes leaves duplication and shortcuts the loop exists to remove before they reach history
|
|
19
20
|
|
|
@@ -33,4 +34,6 @@ Without this skill, a session implementing a planned change writes the test afte
|
|
|
33
34
|
- Choosing the layer a test belongs at and judging whether it is a good test: `canon:test-craft`, loaded at step 1 rather than restated here
|
|
34
35
|
- Finding the cause of an unexplained failure: `canon:systematic-debugging`
|
|
35
36
|
- Confirming visual output after a change lands: `567-planning.md` states the order and `ui-checklist` writes the list to confirm against
|
|
37
|
+
- Shaping the function, class, or module the implementation writes: `canon:code-craft`, loaded at step 4 rather than restated here
|
|
38
|
+
- Committing the behavior as a slice and ordering the slices of a larger build: `canon:build-in-slices`
|
|
36
39
|
- The mechanical audit of whether an implementation reached history ahead of its test: `canon gov test-order`, invoked from `auto-ship`
|
|
@@ -10,7 +10,7 @@ description: Write the failing test for a behavior before writing the code that
|
|
|
10
10
|
1. Load `canon:test-craft` and pick the layer the test belongs at before writing it. Then find or write the test at that layer before touching the code it covers. Follow the pairing convention the project already uses, which is commonly a test sitting beside its subject under one name, so that `foo.ts` takes `foo.test.ts` beside it. Report it rather than proceeding silently when `canon:test-craft` does not resolve, and write the test at the smallest layer that can observe the behavior.
|
|
11
11
|
2. Write the test against the behavior as it should exist once the change lands, naming the case for what it proves rather than for the function it calls.
|
|
12
12
|
3. Run only that test and read the failure. Confirm it fails because the behavior is missing, not because of a typo, a missing import, or a signature the test itself got wrong. A test failing for the wrong reason still reads green the moment any code exists to satisfy that wrong reason, so treat any other failure as a defect in the test and fix the test before moving on.
|
|
13
|
-
4.
|
|
13
|
+
4. Load `canon:code-craft` and settle the shape of the code before writing it, unless the shape is already fixed or this session already loaded the skill. Report it rather than proceeding silently when `canon:code-craft` does not resolve, and write the plainest code the test asks for. Then implement the smallest change that turns the failure into a pass. Do not add behavior the test does not ask for. A second behavior wants its own test written first, not a shortcut folded into the change already open.
|
|
14
14
|
5. Run the test again and confirm it passes for the reason it was written for, not by accident. Then run the surrounding suite so a change made to satisfy this test has not broken another.
|
|
15
15
|
6. Refactor with the suite green. Remove the duplication and the shortcuts step 4 left, in the implementation and in the test, without changing what either does. Run the suite after each change, and undo a change that turns anything red rather than fixing forward.
|
|
16
16
|
|
|
@@ -23,4 +23,5 @@ description: Write the failing test for a behavior before writing the code that
|
|
|
23
23
|
|
|
24
24
|
- Which layer a test belongs at and what makes it a good one. `canon:test-craft` owns that judgment, and step 1 loads it.
|
|
25
25
|
- A failure with no known cause. Route through `canon:systematic-debugging` first, whose own fix phase already writes the reproducing test as part of finding the cause. This skill starts once the shape of the fix or the feature is already decided.
|
|
26
|
+
- Committing the green, refactored behavior as one slice of a larger build. `canon:build-in-slices` owns the commit and the order slices land in.
|
|
26
27
|
- Confirming a change looks right once it has landed, which is a separate concern from whether the test passed and runs after implementation rather than before it.
|
package/docs/agents/commands.md
CHANGED
|
@@ -103,7 +103,7 @@ Each domain exposes a consistent shape where applicable: `list`, `install`, `syn
|
|
|
103
103
|
- `worktrees`, in `worktrees.md`: `list`, `reclaim`
|
|
104
104
|
- `hooks`, in `hooks.md`: `post-merge`
|
|
105
105
|
- `autoship`, in `review-classification.md`: `classify`
|
|
106
|
-
- `pr`, in `pr-reads.md`: `key-changes`, `head`, `checks`, `review-state`, `evidence`, `preview`, `local`
|
|
106
|
+
- `pr`, in `pr-reads.md`: `key-changes`, `head`, `checks`, `review-state`, `evidence`, `preview`, `local`, `frames`
|
|
107
107
|
- `audits`, in `audits.md`: `run`, `list`
|
|
108
108
|
- `gate`, in `gate.md`: `run`
|
|
109
109
|
- `secrets`, in `state-scoped-risk.md`: `scan`
|