@erclx/canon 5.41.0 → 5.43.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/references/adopted.md +34 -14
- package/claude/skills/auto-ship/REQUIREMENT.md +1 -0
- package/claude/skills/auto-ship/SKILL.md +24 -4
- package/claude/skills/auto-ship/references/draft-mark.md +32 -6
- package/claude/skills/auto-ship/references/failure-recovery.md +15 -13
- package/claude/skills/auto-ship/references/tier-failures.md +31 -10
- package/claude/skills/auto-ship/references/ui-checklist.md +9 -4
- package/claude/skills/auto-ship/references/worktree-name.md +9 -3
- package/claude/skills/build-in-slices/references/adopted.md +35 -21
- package/claude/skills/canvas-board/references/canvas.md +17 -6
- package/claude/skills/canvas-board/references/design.md +26 -7
- package/claude/skills/ci-workflow/REQUIREMENT.md +2 -1
- package/claude/skills/ci-workflow/SKILL.md +12 -2
- package/claude/skills/ci-workflow/references/workflows.md +12 -9
- package/claude/skills/code-craft/references/adopted.md +58 -20
- package/claude/skills/codebase-layout/references/adopted.md +49 -16
- package/claude/skills/codebase-layout/references/frontend.md +11 -4
- package/claude/skills/codebase-layout/references/tests.md +4 -2
- package/claude/skills/context-fold/references/classify.md +10 -15
- package/claude/skills/context-fold/references/completion-report.md +11 -9
- package/claude/skills/context-fold/references/context-refresh.md +26 -9
- package/claude/skills/context-fold/references/unusable-baseline.md +5 -3
- package/claude/skills/create-rule/REQUIREMENT.md +5 -0
- package/claude/skills/create-rule/SKILL.md +10 -1
- package/claude/skills/create-rule/references/checklist.md +26 -0
- package/claude/skills/create-rule/references/rule.md +98 -20
- package/claude/skills/create-skill/SKILL.md +1 -0
- package/claude/skills/create-skill/references/skill-disclosure.md +10 -2
- package/claude/skills/create-skill/references/skill-frontmatter.md +43 -0
- package/claude/skills/create-skill/references/skill-paths.md +7 -4
- package/claude/skills/create-skill/references/skill-practice.md +6 -3
- package/claude/skills/create-skill/references/skill-requirement.md +4 -2
- package/claude/skills/create-skill/references/skill.md +67 -44
- package/claude/skills/decision-escalate/SKILL.md +1 -2
- package/claude/skills/deploy-app/references/vercel.md +2 -1
- package/claude/skills/deprecation-migration/references/adopted.md +44 -25
- package/claude/skills/design-taste/references/adopted.md +9 -1
- package/claude/skills/design-taste/references/craft.md +3 -1
- package/claude/skills/design-taste/references/kinds.md +8 -7
- package/claude/skills/design-taste/references/preflight.md +12 -0
- package/claude/skills/design-taste/references/systems.md +7 -6
- package/claude/skills/design-taste/references/tells.md +24 -25
- package/claude/skills/design-taste/references/vocabulary.md +7 -5
- package/claude/skills/document-health/references/axes.md +55 -30
- package/claude/skills/draft-and-pick/references/live-arms.md +2 -2
- package/claude/skills/draft-doc/references/context.md +4 -3
- package/claude/skills/draft-doc/references/docs.md +6 -3
- package/claude/skills/draft-doc/references/readme/agent-facing.md +6 -0
- package/claude/skills/draft-doc/references/readme/application.md +8 -2
- package/claude/skills/draft-doc/references/readme/cli.md +5 -1
- package/claude/skills/draft-doc/references/readme/library.md +4 -0
- package/claude/skills/draft-doc/references/readme/plugin.md +9 -1
- package/claude/skills/draft-doc/references/readme.md +30 -13
- package/claude/skills/draft-doc/references/requirements.md +17 -4
- package/claude/skills/draft-doc/references/wiki-kind.md +20 -10
- package/claude/skills/draft-doc/references/wiki.md +1 -1
- package/claude/skills/draft-figure/references/architecture-set.md +7 -3
- package/claude/skills/draft-figure/references/figures.md +8 -6
- package/claude/skills/draft-figure/references/hand-drawn.md +3 -1
- package/claude/skills/draft-figure/references/mermaid-path.md +19 -9
- package/claude/skills/draft-figure/references/mermaid.md +10 -5
- package/claude/skills/draft-ready/references/ready.md +22 -15
- package/claude/skills/git-branch/references/branch.md +11 -1
- package/claude/skills/git-branch/references/slug.md +17 -5
- package/claude/skills/git-commit/references/commit.md +9 -5
- package/claude/skills/git-commit/references/versioning.md +23 -17
- package/claude/skills/git-followup/REQUIREMENT.md +1 -1
- package/claude/skills/git-followup/SKILL.md +5 -6
- package/claude/skills/git-issue/references/issue.md +29 -16
- package/claude/skills/git-pr/REQUIREMENT.md +1 -5
- package/claude/skills/git-pr/SKILL.md +11 -22
- package/claude/skills/git-pr/references/final-command.md +21 -8
- package/claude/skills/git-pr/references/labels.md +45 -28
- package/claude/skills/git-pr/references/pr.md +29 -9
- package/claude/skills/git-pr/references/publish.md +42 -28
- package/claude/skills/git-pr/references/task-number.md +20 -8
- package/claude/skills/git-ship/SKILL.md +1 -1
- package/claude/skills/plan-feature/SKILL.md +1 -1
- package/claude/skills/plan-feature/references/plan-lifecycle.md +10 -3
- package/claude/skills/plan-feature/references/plan.md +58 -21
- package/claude/skills/plan-groundwork/references/groundwork-spikes.md +4 -1
- package/claude/skills/plan-groundwork/references/groundwork.md +14 -16
- package/claude/skills/plan-intake/references/intake.md +29 -24
- package/claude/skills/pr-evidence/REQUIREMENT.md +40 -0
- package/claude/skills/pr-evidence/SKILL.md +53 -0
- package/claude/skills/pr-evidence/references/evidence.md +150 -0
- package/claude/skills/review-address/references/post-review-findings.md +10 -3
- package/claude/skills/review-address/references/rebase-conflicts.md +15 -7
- package/claude/skills/review-address/references/rest-reads.md +3 -1
- package/claude/skills/review-craft/references/adopted.md +35 -18
- package/claude/skills/review-craft/references/security.md +42 -7
- package/claude/skills/review-craft/references/ui.md +23 -8
- package/claude/skills/review-pr/SKILL.md +6 -6
- package/claude/skills/review-pr/references/body-variants.md +29 -9
- package/claude/skills/review-pr/references/close-out.md +20 -5
- package/claude/skills/review-pr/references/key-changes.md +27 -3
- package/claude/skills/review-pr/references/post.md +83 -31
- package/claude/skills/review-pr/references/scope.md +54 -19
- package/claude/skills/review-ui/references/close-out.md +7 -5
- package/claude/skills/review-ui/references/driving.md +24 -4
- package/claude/skills/review-ui/references/post.md +43 -15
- package/claude/skills/role-orchestrator/SKILL.md +2 -0
- package/claude/skills/role-orchestrator/references/orchestrator-cloud-launch.md +67 -17
- package/claude/skills/role-orchestrator/references/orchestrator-dispatch.md +80 -40
- package/claude/skills/role-orchestrator/references/orchestrator-handback.md +52 -15
- package/claude/skills/role-orchestrator/references/orchestrator-handoff.md +48 -26
- package/claude/skills/role-orchestrator/references/orchestrator-inbound.md +12 -13
- package/claude/skills/role-orchestrator/references/orchestrator-launch.md +72 -36
- package/claude/skills/role-orchestrator/references/orchestrator-output.md +16 -4
- package/claude/skills/role-orchestrator/references/orchestrator-parked.md +64 -24
- package/claude/skills/role-orchestrator/references/orchestrator-poll.md +80 -26
- package/claude/skills/role-orchestrator/references/orchestrator-refill.md +41 -18
- package/claude/skills/role-orchestrator/references/orchestrator-resume.md +19 -7
- package/claude/skills/role-orchestrator/references/orchestrator-review-dispatch.md +22 -12
- package/claude/skills/role-orchestrator/references/orchestrator-reviewer-launch.md +15 -6
- package/claude/skills/role-orchestrator/references/orchestrator-sweep.md +25 -7
- package/claude/skills/role-orchestrator/references/orchestrator-watch.md +34 -8
- package/claude/skills/role-orchestrator/scripts/poll.ts +16 -24
- package/claude/skills/role-planner/REQUIREMENT.md +1 -1
- package/claude/skills/role-planner/SKILL.md +3 -3
- package/claude/skills/role-worker/REQUIREMENT.md +3 -0
- package/claude/skills/role-worker/SKILL.md +34 -2
- package/claude/skills/search-craft/REQUIREMENT.md +1 -1
- package/claude/skills/search-craft/SKILL.md +2 -2
- package/claude/skills/search-craft/references/adopted.md +18 -6
- package/claude/skills/session-map/references/session.md +26 -7
- package/claude/skills/session-worktree/references/main-root-writes.md +25 -8
- package/claude/skills/systematic-debugging/references/adopted.md +30 -16
- package/claude/skills/target-check/references/domains.md +39 -11
- package/claude/skills/target-setup/references/detect.md +80 -65
- package/claude/skills/target-setup/references/indexes.md +8 -6
- package/claude/skills/task-board/references/board.md +86 -30
- package/claude/skills/task-board/references/decline.md +29 -13
- package/claude/skills/task-board/references/tasks-decline.md +12 -5
- package/claude/skills/task-board/references/tasks.md +65 -33
- package/claude/skills/task-complete/references/archive.md +41 -17
- package/claude/skills/task-complete/references/receipt-sweep.md +23 -9
- package/claude/skills/task-complete/references/unusable-baseline.md +10 -3
- package/claude/skills/teach-workspace/references/glossary.md +6 -2
- package/claude/skills/teach-workspace/references/lesson-build.md +44 -16
- package/claude/skills/teach-workspace/references/lesson-craft.md +12 -7
- package/claude/skills/teach-workspace/references/pedagogy.md +6 -3
- package/claude/skills/teach-workspace/references/promotion-fold.md +17 -11
- package/claude/skills/teach-workspace/references/promotion.md +31 -8
- package/claude/skills/teach-workspace/references/revisit.md +8 -2
- package/claude/skills/teach-workspace/references/teach.md +17 -9
- package/claude/skills/test-craft/references/adopted.md +48 -14
- package/claude/skills/test-craft/references/component.md +7 -4
- package/claude/skills/test-craft/references/e2e.md +25 -7
- package/claude/skills/test-craft/references/unit.md +3 -1
- package/claude/skills/test-first/references/adopted.md +12 -4
- package/claude/skills/ui-checklist/REQUIREMENT.md +1 -1
- package/claude/skills/ui-checklist/SKILL.md +1 -1
- package/claude/skills/video-craft/references/adopted.md +62 -18
- package/claude/skills/write-human/references/adopted.md +21 -8
- package/docs/agents/audits.md +1 -0
- package/docs/agents/migrate.md +11 -8
- package/docs/target/migrations.md +11 -0
- package/docs/workflow/parallel-features.md +1 -1
- package/docs/workflow/skill-map.md +1 -0
- package/governance/detect.toml +4 -0
- package/governance/rules/canon/context.md +2 -1
- package/governance/rules/canon/plan.md +3 -5
- package/governance/rules/canon/scratch.md +3 -1
- package/governance/rules/canon/task-scope.md +2 -1
- package/governance/rules/canon/tasks.md +2 -1
- package/governance/rules/canon/worktrees.md +5 -2
- package/governance/rules/claude/output.md +7 -4
- package/governance/rules/claude/skill.md +6 -4
- package/governance/rules/tooling/ci-workflow.md +6 -39
- package/governance/rules/ui/design-reference.md +37 -0
- package/governance/rules/writing/markdown.md +2 -1
- package/package.json +6 -6
- package/src/audits/catalog.ts +42 -0
- package/src/claude/cases/workflow.ts +5 -0
- package/src/claude/settings.ts +8 -4
- package/src/commands/claude.ts +11 -1
- package/src/commands/gov.ts +198 -0
- package/src/commands/migrate.ts +121 -2
- package/src/commands/pr.ts +146 -105
- package/src/commands/tooling.ts +3 -3
- package/src/commands/worktrees.ts +49 -0
- package/src/gate/stages.ts +15 -0
- package/src/gov/audit.ts +440 -0
- package/src/listeners/belongs.ts +21 -0
- package/src/listeners/machine.ts +93 -0
- package/src/listeners/parse.ts +41 -0
- package/src/markdown/scope.ts +144 -0
- package/src/migrate/session-defaults.ts +138 -0
- package/src/pr/lift.ts +6 -3
- package/src/pr/local.ts +4 -69
- package/src/pr/review-state.ts +182 -0
- package/src/sync/check.ts +15 -0
- package/src/tooling/stamp.ts +56 -12
- package/src/worktrees/stop.ts +92 -0
- package/tooling/base/configs/.github/workflows/phase-label-gate.yml +6 -2
- package/tooling/base/configs/commitlint.config.js +0 -20
- package/tooling/base/reference.md +1 -1
- package/tooling/base/seeds/.github/workflows/verify.yml +4 -1
- package/tooling/claude/reference.md +13 -7
- package/tooling/claude/seeds/.claude/settings.json +4 -0
- package/tooling/claude/user/settings.template.json +0 -4
- package/tooling/cloudflare/configs/.github/workflows/deploy.yml +5 -5
- package/tooling/public/configs/.github/dependabot.yml +12 -0
- package/tooling/public/configs/.github/workflows/release-please.yml +30 -0
- package/tooling/public/manifest.toml +8 -0
- package/tooling/public/reference.md +53 -0
- package/tooling/public/seeds/.github/ISSUE_TEMPLATE/bug.yml +48 -0
- package/tooling/public/seeds/.github/ISSUE_TEMPLATE/config.yml +5 -0
- package/tooling/public/seeds/.github/ISSUE_TEMPLATE/feature.yml +16 -0
- package/tooling/public/seeds/.release-please-manifest.json +3 -0
- package/tooling/public/seeds/CONTRIBUTING.md +50 -0
- package/tooling/public/seeds/LICENSE +21 -0
- package/tooling/public/seeds/SECURITY.md +13 -0
- package/tooling/public/seeds/release-please-config.json +12 -0
- package/tooling/shell/configs/.github/workflows/shell.yml +4 -1
- package/tooling/web/configs/.github/workflows/readme-screenshot.yml +6 -3
- package/tooling/web/configs/.github/workflows/verify.yml +15 -12
- package/claude/skills/git-pr/references/evidence.md +0 -124
|
@@ -15,11 +15,19 @@ Step 4 of `review-pr`. The threshold that picks the heading and decides the disp
|
|
|
15
15
|
|
|
16
16
|
## The body file and finding links
|
|
17
17
|
|
|
18
|
-
Write the comment to `.canon/tmp/pr/review/body-<number>-<short-sha>.md` at the main worktree root, not the current worktree, which the rest of this step calls `<body-file>`. Resolve that root and send the write as a heredoc, both the way `session-worktree` states.
|
|
18
|
+
Write the comment to `.canon/tmp/pr/review/body-<number>-<short-sha>.md` at the main worktree root, not the current worktree, which the rest of this step calls `<body-file>`. Resolve that root and send the write as a heredoc, both the way `session-worktree` states.
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
- The PR number stops two sessions reviewing different pull requests from overwriting each other between the write and the post
|
|
21
|
+
- The head commit stops a second pass overwriting the first one's body
|
|
22
|
+
- Derive both segments from Step 1. Never pick a suffix by hand, and never reuse a name the folder already holds.
|
|
21
23
|
|
|
22
|
-
|
|
24
|
+
### A repeated head
|
|
25
|
+
|
|
26
|
+
When `<prior-oid>` from Step 2 equals `headRefOid`, the folder already holds `body-<number>-<short-sha>.md`. Add a third segment taking the id of the reply Step 2 resolved, giving `body-<number>-<short-sha>-r<comment-id>.md` as `<body-file>`.
|
|
27
|
+
|
|
28
|
+
That satisfies both prohibitions above rather than carving an exception into either. Step 2 already stopped the pass when that resolution came back empty, so reaching this line means the comment id is in hand.
|
|
29
|
+
|
|
30
|
+
### Finding links
|
|
23
31
|
|
|
24
32
|
A finding bound to a line links to it, so a reader skips the hunt:
|
|
25
33
|
|
|
@@ -27,13 +35,23 @@ A finding bound to a line links to it, so a reader skips the hunt:
|
|
|
27
35
|
- **should-fix** ([line 12](<repo-url>/blob/<headRefOid>/<path>#L12)): what breaks and the fix
|
|
28
36
|
```
|
|
29
37
|
|
|
30
|
-
A
|
|
38
|
+
- A span anchors as `#L12-L14`, with no spaces and no en dash, and a single line as `#L12`
|
|
39
|
+
- Take the line number from the file read at `<headRefOid>`, `git show <headRefOid>:<path>`, never from another checkout
|
|
40
|
+
- The URL carries the full 40-character `<headRefOid>`, never `<short-sha>`, `HEAD`, or the branch name, so the link survives a push
|
|
41
|
+
- A later pass restating an open finding links it again at its own `<headRefOid>` rather than copying the old bullet
|
|
42
|
+
|
|
43
|
+
### Findings with no link
|
|
44
|
+
|
|
45
|
+
Four findings take the plain bullet with no link, since the head holds no line number for them.
|
|
31
46
|
|
|
32
|
-
|
|
47
|
+
- A `**PR body**` entry, and a finding about a whole file with no one line
|
|
48
|
+
- A finding on a file the head deleted, or on a line the diff removed from a file that survives
|
|
49
|
+
- A path holding a character a URL needs encoded, such as a space or `#`, is percent-encoded in the link or keeps the plain bullet
|
|
50
|
+
- Keep the file block header a bare backticked path, so the section-marker reading in `${CLAUDE_SKILL_DIR}/../markdown-craft/references/markdown.md` holds
|
|
33
51
|
|
|
34
52
|
## The body shapes
|
|
35
53
|
|
|
36
|
-
The comment is a rendered-for-human GitHub surface, so load the `write-human` skill for voice and word choice and follow `${CLAUDE_SKILL_DIR}/../markdown-craft/references/markdown.md` for punctuation
|
|
54
|
+
The comment is a rendered-for-human GitHub surface, so load the `write-human` skill for voice and word choice and follow `${CLAUDE_SKILL_DIR}/../markdown-craft/references/markdown.md` for punctuation. Cut editorializing, and keep every sentence load-bearing. Match this shape on a first pass:
|
|
37
55
|
|
|
38
56
|
```markdown
|
|
39
57
|
## Review
|
|
@@ -54,10 +72,6 @@ X critical, Y should-fix, Z minor. Reviewed against project docs and the board.
|
|
|
54
72
|
<!-- review-pr: commit=<headRefOid> read-at=<read-at> -->
|
|
55
73
|
```
|
|
56
74
|
|
|
57
|
-
A stale ticked box goes in a `**PR body**` block, in place of a `**`path/to/file.ext`**` block and ahead of every one of those, since it precedes the code the diff carries rather than sitting inside it.
|
|
58
|
-
|
|
59
|
-
Run `canon labels scan --title "<title>" --body "<body>" --head <headRefName>` against the PR under review, since Step 1 already holds all three and this pass is the last human-shaped gate before merge. A hit lands in the same `**PR body**` block, `should-fix`, naming each finding the scan returns: a token quoted from the title or body for a phase label, a board identifier, or a session link, and the broken rule's name, `structure`, a casing issue, or `length`, for a title-format hit. A heading in `sections.outside`, a heading in `sections.missing`, or a character in `bannedCharacters` is a hit of the same weight, naming the heading or the character. This reads the pull request being reviewed, distinct from the comment this pass is about to post, which the scan later in this step still covers.
|
|
60
|
-
|
|
61
75
|
A later pass carrying findings keeps that shape and changes only the summary line:
|
|
62
76
|
|
|
63
77
|
```markdown
|
|
@@ -76,25 +90,43 @@ Re-reviewed `<short-sha>`, N commits since the prior pass. X critical, Y should-
|
|
|
76
90
|
|
|
77
91
|
A Testing question or a `## For the reviewer` bullet Step 3 read takes its own block after the file blocks, per `${CLAUDE_SKILL_DIR}/references/body-variants.md`.
|
|
78
92
|
|
|
79
|
-
|
|
93
|
+
### The PR body block
|
|
80
94
|
|
|
81
|
-
|
|
95
|
+
A stale ticked box goes in a `**PR body**` block, ahead of every file block, since it precedes the code the diff carries rather than sitting inside it.
|
|
82
96
|
|
|
83
|
-
|
|
97
|
+
Run `canon labels scan --title "<title>" --body "<body>" --head <headRefName>` against the PR under review, since Step 1 already holds all three and this pass is the last human-shaped gate before merge. A hit lands in the same block as a `should-fix`.
|
|
84
98
|
|
|
85
|
-
|
|
99
|
+
- Name the token quoted from the title or body for a phase label, a board identifier, or a session link
|
|
100
|
+
- Name the broken rule, being `structure`, a casing issue, or `length`, for a title-format hit
|
|
101
|
+
- A heading in `sections.outside` or `sections.missing`, or a character in `bannedCharacters`, is a hit of the same weight, naming the heading or the character
|
|
102
|
+
- This reads the pull request under review, distinct from the comment this pass posts, which the scan later in this step covers
|
|
86
103
|
|
|
87
|
-
|
|
104
|
+
### Why the threshold ignores the grade
|
|
88
105
|
|
|
89
|
-
|
|
106
|
+
Keying either half of the opening's threshold on the grade was measured wrong. Across 8 findings on one archived pass, 3 were posted as minor and 2 of those were defects a worker fixed, so a floor at should-fix loses real fixes to a grade that runs low.
|
|
107
|
+
|
|
108
|
+
- Firing the dispatch lower than the heading left a thread reading closed while work was owed on it
|
|
109
|
+
- A Testing question sitting outside both is the same split, and it left the one party who could answer it with no route
|
|
110
|
+
- The cost is that the merge decision reads off the summary line's counts rather than the heading, since an open heading covers a minor and a critical alike
|
|
111
|
+
- No summary line reports the merge as unblocked under either heading, since a thread reading open cannot also report that nothing blocks it
|
|
112
|
+
|
|
113
|
+
### Declined minors and reopening
|
|
90
114
|
|
|
91
|
-
|
|
115
|
+
A minor the dispatched worker declines needs a surface that survives the merge, since one fixed on the branch needs no record and one left on the thread is lost at merge. Write it into the `## Findings` section of the task the branch closes.
|
|
92
116
|
|
|
93
|
-
|
|
117
|
+
- Open the line with the bold source-and-date label from `${CLAUDE_SKILL_DIR}/../task-board/references/tasks.md`, where the queue-refill sweep already routes such a finding
|
|
118
|
+
- Read the state off the most recent review comment rather than off the presence of a closed one
|
|
119
|
+
- A close-out does not close the pull request, so a later commit gets its own pass, which reopens under `## Review` on a finding of any grade
|
|
94
120
|
|
|
95
|
-
|
|
121
|
+
### Summary line and budget
|
|
96
122
|
|
|
97
|
-
|
|
123
|
+
Name the scope in every summary line after the first pass, since a reader cannot otherwise tell a narrow read from a full one. When the fallback in Step 2 fired, replace the commit count with `Re-reviewed the full change, the prior pass's commit is no longer on the branch`.
|
|
124
|
+
|
|
125
|
+
- Do not append the PR number to either heading, which GitHub already renders above the comment
|
|
126
|
+
- State each finding as the failure and the fix in two or three sentences, not a paragraph of reasoning
|
|
127
|
+
- Omit files with no findings and do not lecture on process. The integration, contract, and consumer lenses stay as findings, not asides.
|
|
128
|
+
- `What is right` is optional, capped at three bullets, and included only when it changes the merge decision
|
|
129
|
+
- Close with `🤖 Reviewed by Claude Code` on its own line, so the review reads as an independent machine pass, not a human sign-off
|
|
98
130
|
|
|
99
131
|
## The marker, the scans, and the post
|
|
100
132
|
|
|
@@ -106,26 +138,46 @@ End every body with this line, carrying `<headRefOid>` and `<read-at>` from Step
|
|
|
106
138
|
<!-- review-pr: commit=<headRefOid> read-at=<read-at> -->
|
|
107
139
|
```
|
|
108
140
|
|
|
109
|
-
Every body this step writes carries it,
|
|
141
|
+
Every body this step writes carries it, being the full body under either heading, both ✅ close-out lines, a withdrawal body, and the `PUT` rewrite in `close-out.md`. A body missing it reads as a pre-marker pass, so the next reader falls back to the stamps and the pass loses its coverage.
|
|
142
|
+
|
|
143
|
+
- Last is load-bearing, since `canon pr review-state` reads the last non-empty line and searches nowhere else
|
|
144
|
+
- That position also lets a finding quote the format safely, even in a fence, since a quotation is never the line the reader takes
|
|
145
|
+
- Write it as an HTML comment, which GitHub renders as nothing, so a reader of the thread never meets it
|
|
146
|
+
|
|
147
|
+
### Why the marker exists
|
|
148
|
+
|
|
149
|
+
GitHub stamps `commit.oid` and `submittedAt` at submission, not at read. A push landing in the compose window moves both onto a commit this pass never opened, and the next pass reads it as covered.
|
|
110
150
|
|
|
111
|
-
|
|
151
|
+
The marker is the read-time record those fields are not.
|
|
112
152
|
|
|
113
|
-
|
|
153
|
+
- `canon pr review-state` is the one place it is parsed, so Step 2 and the orchestrator poll read one answer rather than each copying the format
|
|
154
|
+
- It is inert data, so `canon labels scan` has nothing to fire on
|
|
155
|
+
- Confirm that against the posted body, since a phase label or board identifier inside a commit sha is not a shape either scan was written against
|
|
114
156
|
|
|
115
|
-
|
|
157
|
+
### The scans
|
|
116
158
|
|
|
117
|
-
|
|
159
|
+
Before posting, run `canon labels scan --body-file .canon/tmp/pr/review/body-<number>-<short-sha>.md`, which applies the rule in `${CLAUDE_SKILL_DIR}/../git-pr/references/publish.md`. Fix the body and scan again on a finding.
|
|
118
160
|
|
|
119
|
-
|
|
161
|
+
- A finding phrased against an internal phase label is what the label half of the scan catches here
|
|
162
|
+
- The call carries no `--title`, so the scan reads the text as a review
|
|
120
163
|
|
|
121
|
-
A `PreToolUse` hook on `Bash` runs the same scan against the `-F body=@<file>` of the post
|
|
164
|
+
A `PreToolUse` hook on `Bash` runs the same scan against the `-F body=@<file>` of the post and denies the call on a hit, so the check holds whether or not this step ran. The hook reads the file before the command runs, so write the body in an earlier call and pass it as a file rather than inline.
|
|
122
165
|
|
|
123
|
-
|
|
166
|
+
### The post-trigger re-read
|
|
167
|
+
|
|
168
|
+
`phase-label-gate.yml` reads the same text again once posted, on its `pull_request_review` trigger, which covers a review a person posts by hand with no hook in front of it.
|
|
169
|
+
|
|
170
|
+
- That workflow reaches every target on the `base` stack, seeded at `tooling/base/configs/.github/workflows/phase-label-gate.yml`
|
|
171
|
+
- It invokes the published CLI rather than a checkout's own source tree, so a target gets the same re-read past the hook
|
|
172
|
+
|
|
173
|
+
### The post
|
|
174
|
+
|
|
175
|
+
Do not run the command below when `<prior-heading>` from Step 2 reads `## Review closed` and this pass carries nothing owed. Read `${CLAUDE_SKILL_DIR}/references/close-out.md` instead, since posting first leaves two close-outs both naming the new head.
|
|
124
176
|
|
|
125
177
|
```bash
|
|
126
178
|
gh api -X POST 'repos/{owner}/{repo}/pulls/<number>/reviews' -f event=COMMENT -F body=@.canon/tmp/pr/review/body-<number>-<short-sha>.md --jq .html_url
|
|
127
179
|
```
|
|
128
180
|
|
|
129
|
-
The post
|
|
130
|
-
|
|
131
|
-
A pass carrying nothing
|
|
181
|
+
- The post uses the REST reviews endpoint, since the `gh pr` review subcommand runs on GraphQL and fails where a cloud session's proxy refuses it
|
|
182
|
+
- `event=COMMENT` submits the review as a comment, the same state the old `--comment` flag produced
|
|
183
|
+
- A pass carrying nothing, a withdrawal, or only answered requests takes a close-out body, and only minors keep the full shape, per `${CLAUDE_SKILL_DIR}/references/body-variants.md`
|
|
@@ -7,27 +7,42 @@ description: Step 2 of review-pr, which finds the commit and verdict the prior p
|
|
|
7
7
|
|
|
8
8
|
Step 2 of `review-pr`. The session reads this file on reaching that step, ahead of Step 3, so the unchanged-head stop below still fires before any review runs.
|
|
9
9
|
|
|
10
|
+
## Find the prior pass
|
|
11
|
+
|
|
10
12
|
Find the commit the last pass covered and the verdict it posted:
|
|
11
13
|
|
|
12
14
|
```bash
|
|
13
15
|
canon pr review-state <number> --json
|
|
14
16
|
```
|
|
15
17
|
|
|
16
|
-
|
|
18
|
+
Take `<prior-oid>` off `commit`, `<prior-heading>` off `heading`, and `<prior-at>` off `readAt // submittedAt`. Branch on the record rather than on the exit code, which a shell function wrapping `canon` can flatten to zero.
|
|
19
|
+
|
|
20
|
+
- The commit scopes the read below, the heading feeds the repeat guard at the end of this step, and the instant scopes the reply query
|
|
21
|
+
- One call answers all three rather than three reads of the same review
|
|
22
|
+
|
|
23
|
+
### Which stamp answered
|
|
24
|
+
|
|
25
|
+
`source` says which stamp answered, and `marker` is the authority. Never read `commit_id` or `submitted_at` off the reviews listing here, since both are stamped at submission and a push between a pass's read and its post moves them onto a commit that pass never saw.
|
|
17
26
|
|
|
18
|
-
|
|
27
|
+
- `marker`: the pass's own read-time record
|
|
28
|
+
- `fallback`: a pass posted before the marker shipped, whose commit is the head when GitHub recorded the review, so a push inside its compose window is invisible
|
|
29
|
+
- `none`: a thread carrying no pass at all
|
|
19
30
|
|
|
20
|
-
|
|
31
|
+
### When the verb is missing
|
|
21
32
|
|
|
22
|
-
A target whose CLI predates the verb meets a missing subcommand rather than a record. Fall back
|
|
33
|
+
A target whose CLI predates the verb meets a missing subcommand rather than a record. Fall back to this REST read, which reads the stamps and carries the defect above, and say the fallback answered so a reader can tell a marker read from a stamped one:
|
|
23
34
|
|
|
24
35
|
```bash
|
|
25
36
|
gh api --paginate 'repos/{owner}/{repo}/pulls/<number>/reviews?per_page=100' --jq '.[] | select(.body // "" | split("\n")[0] | rtrimstr("\r") | . == "## Review" or . == "## Review closed") | ((.commit_id // "") + "\t" + (.body | split("\n")[0] | rtrimstr("\r")) + "\t" + (.submitted_at // ""))' | tail -n 1
|
|
26
37
|
```
|
|
27
38
|
|
|
28
|
-
The three fields are `<prior-oid>`, `<prior-heading>`, and `<prior-at>`.
|
|
39
|
+
The three fields are `<prior-oid>`, `<prior-heading>`, and `<prior-at>`.
|
|
29
40
|
|
|
30
|
-
|
|
41
|
+
- The filter emits one line per matching review and `tail` keeps the newest, since `--paginate` runs the filter once per page
|
|
42
|
+
- Match the first line for equality, since a prefix test also matches `## Review response` and scopes the pass to that comment's commit
|
|
43
|
+
- The `\r` trim covers a body composed in the GitHub web editor, which stores CRLF
|
|
44
|
+
|
|
45
|
+
## A first pass
|
|
31
46
|
|
|
32
47
|
A `source` of `none`, or an empty result from the fallback, is a first pass. Read the whole change:
|
|
33
48
|
|
|
@@ -39,7 +54,9 @@ gh api 'repos/{owner}/{repo}/pulls/<number>' -H 'Accept: application/vnd.github.
|
|
|
39
54
|
gh api --paginate 'repos/{owner}/{repo}/pulls/<number>/files?per_page=100' --jq '.[].filename'
|
|
40
55
|
```
|
|
41
56
|
|
|
42
|
-
Both reads go through REST, since the `gh pr` diff subcommand runs on GraphQL and a cloud session's GitHub proxy refuses it. The diff media type returns the same unified diff, and the paginated
|
|
57
|
+
Both reads go through REST, since the `gh pr` diff subcommand runs on GraphQL and a cloud session's GitHub proxy refuses it. The diff media type returns the same unified diff, and the paginated listing returns every path rather than the first page.
|
|
58
|
+
|
|
59
|
+
## A later pass
|
|
43
60
|
|
|
44
61
|
A commit is a later pass. Fetch the pull request head so both commits are local:
|
|
45
62
|
|
|
@@ -47,7 +64,7 @@ A commit is a later pass. Fetch the pull request head so both commits are local:
|
|
|
47
64
|
git fetch -q origin pull/<number>/head
|
|
48
65
|
```
|
|
49
66
|
|
|
50
|
-
A failed fetch stops the skill: `❌ Could not fetch the PR head. Retry once the remote is reachable.`
|
|
67
|
+
A failed fetch stops the skill: `❌ Could not fetch the PR head. Retry once the remote is reachable.` Never fall through to the full pass, since a fetch failure and a rebase both leave the prior commit unreachable, and the fallback states a rebase as fact on the pull request.
|
|
51
68
|
|
|
52
69
|
Then test that the prior commit still reaches the head:
|
|
53
70
|
|
|
@@ -55,30 +72,48 @@ Then test that the prior commit still reaches the head:
|
|
|
55
72
|
git merge-base --is-ancestor <prior-oid> <headRefOid>
|
|
56
73
|
```
|
|
57
74
|
|
|
58
|
-
On exit zero,
|
|
75
|
+
- On exit zero, `git diff` and `git log --oneline` over `<prior-oid>..<headRefOid>` are the whole read, since the first pass covered everything behind it
|
|
76
|
+
- A non-zero exit means a rebase or force-push, so the delta is undefined rather than empty. Fall back to the full pass and say so in the body.
|
|
77
|
+
|
|
78
|
+
## An unchanged head
|
|
59
79
|
|
|
60
|
-
A commit is its own ancestor, so an unchanged head passes that test
|
|
80
|
+
A commit is its own ancestor, so an unchanged head passes that test with an empty range. When `<prior-oid>` equals `<headRefOid>`, decide whether this pass has anything to add before reading anything else:
|
|
61
81
|
|
|
62
82
|
```bash
|
|
63
83
|
gh api --paginate 'repos/{owner}/{repo}/issues/<number>/comments?per_page=100' --jq '.[] | select(.body // "" | split("\n")[0] | rtrimstr("\r") | . == "## Review response" or . == "## Rebase" or . == "## Post-review findings") | select(.created_at > "<prior-at>") | .id' | tail -n 1
|
|
64
84
|
```
|
|
65
85
|
|
|
66
|
-
`<prior-at>` is the
|
|
86
|
+
`<prior-at>` is the prior pass's `readAt` where it wrote one. Reading `submittedAt` here is the submission-time defect on the time axis, since a reply posted inside that pass's compose window would read as already answered.
|
|
87
|
+
|
|
88
|
+
- Scope the replies to those newer than the prior pass, since an unscoped read hands a re-run after a close-out the filename its prior pass already wrote
|
|
89
|
+
- The REST `id` is the number the thread displays in each comment's anchor
|
|
90
|
+
- Keep `tail` outside the filter for the same per-page reason as the reviews read
|
|
91
|
+
|
|
92
|
+
### No reply since the prior pass
|
|
93
|
+
|
|
94
|
+
An empty result means the head is unchanged and this pass has nothing new to add. Stop here, before Step 3 or Step 4 run: `❌ The head is unchanged since the prior pass on <short-sha>. Nothing new to review.`
|
|
95
|
+
|
|
96
|
+
This is the earliest point every path crosses. A stop inside Step 4's filename derivation would sit on a step reached only when composing a body, which a shortcut path can route around.
|
|
97
|
+
|
|
98
|
+
### A response or rebase reply
|
|
99
|
+
|
|
100
|
+
A non-empty result carries the comment id Step 4 needs for the third filename segment. A `## Review response` answers a finding already argued, and a `## Rebase` reports a stale branch resolved without one.
|
|
67
101
|
|
|
68
|
-
|
|
102
|
+
- Read it for what the worker changed or accepted, and treat an accepted finding as closed rather than restating it
|
|
103
|
+
- Skip the diff and file reads below. This is the entire read on a repeated head, since the empty range cannot say whether a prior finding landed.
|
|
69
104
|
|
|
70
|
-
|
|
105
|
+
### A post-review findings reply
|
|
71
106
|
|
|
72
|
-
|
|
107
|
+
A `## Post-review findings` reply asserts a new defect rather than answering one, and this pass is its first independent reader. Restating it unread repeats the worker's claim.
|
|
73
108
|
|
|
74
|
-
|
|
109
|
+
Read the file it names at `<headRefOid>`, the same `git show <headRefOid>:<path>` read Step 3 runs to confirm a ticked box, and confirm the defect before it becomes this pass's own finding.
|
|
75
110
|
|
|
76
|
-
A
|
|
111
|
+
## A closed verdict on a moved head
|
|
77
112
|
|
|
78
|
-
A moved head has its own way to add nothing, which the ancestor test cannot see. When `<prior-heading>` reads `## Review closed`, the
|
|
113
|
+
A moved head has its own way to add nothing, which the ancestor test cannot see. When `<prior-heading>` reads `## Review closed`, a pass over the new commits that raises nothing would repeat the standing verdict. It arises when a prior pass leaves a change to the author's call, the author makes it, and the delta has nothing left to say.
|
|
79
114
|
|
|
80
|
-
|
|
115
|
+
Carry `<prior-heading>` into Step 4 and run Step 3 unchanged. This guard turns on what the pass carries, which is Step 3's output, so deciding ahead of the review would swallow the pass that does find something, the costlier error.
|
|
81
116
|
|
|
82
|
-
|
|
117
|
+
## The read
|
|
83
118
|
|
|
84
119
|
Read each changed file in scope. Skip deleted files. Run reads in parallel.
|
|
@@ -9,7 +9,8 @@ Part of Step 7 of `review-ui`, reached only on the branch `post.md` names. The b
|
|
|
9
9
|
|
|
10
10
|
When the newest UI verdict from Step 1 reads `## UI review closed` at an older head and this pass closes too, the thread already holds this verdict. Replace the standing close rather than posting a second one beside it.
|
|
11
11
|
|
|
12
|
-
Only a closed prior is replaced
|
|
12
|
+
- Only a closed prior is replaced, so after a prior `## UI review` this pass's close posts normally
|
|
13
|
+
- A pass that owes anything posts under `## UI review` whatever the prior read, since a rewrite would hide a failed box behind a closed heading
|
|
13
14
|
|
|
14
15
|
Resolve the standing close's numeric id off the REST listing, keeping the newest match across every page:
|
|
15
16
|
|
|
@@ -40,8 +41,9 @@ gh api -X PUT repos/{owner}/{repo}/pulls/<number>/reviews/<review-id> -F body=@<
|
|
|
40
41
|
|
|
41
42
|
## The marker
|
|
42
43
|
|
|
43
|
-
The body ends on `<!-- review-ui: head=<head> -->` at the full head this pass drove, with no line below it. `PUT` leaves the review's `commit.oid` pinned at the head the close was first posted against,
|
|
44
|
+
The body ends on `<!-- review-ui: head=<head> -->` at the full head this pass drove, with no line below it. `PUT` leaves the review's `commit.oid` pinned at the head the close was first posted against, so `resolveUiScope`, the lift gate, and the orchestrator poll read the marker in its place.
|
|
44
45
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
46
|
+
- A body missing it reads as the pinned stamp, so the lift refuses `ui-behind` and the poll reports the close as behind
|
|
47
|
+
- `PUT` keeps the comment's timestamp and place, so the poll's age test reads a rewritten close as old, the reading the code review accepts
|
|
48
|
+
- A submitted review cannot be deleted, which is why this rewrites the standing close rather than posting a fresh one
|
|
49
|
+
- The standing verdict's frames sit under their own pass stamp on the frames branch, so the new body links this pass's frames and the old stay reachable by path
|
|
@@ -32,7 +32,16 @@ A box written before that format may carry no route, no width, and a verb such a
|
|
|
32
32
|
- Text, presence, and attributes: `pw --raw eval "<expression>"`, quoting the value back.
|
|
33
33
|
- Computed style: `getComputedStyle(<element>).<property>`.
|
|
34
34
|
- Geometry and overflow: `getBoundingClientRect()`, and `scrollWidth` against `clientWidth` on `document.documentElement`.
|
|
35
|
-
- A frame: `pw screenshot --filename=frames/<box-number>.png`, then open it with the file-reading tool before saying what it shows.
|
|
35
|
+
- A frame: `pw screenshot --filename=frames/<box-number>.png`, then open it with the file-reading tool before saying what it shows.
|
|
36
|
+
|
|
37
|
+
### Taste frames
|
|
38
|
+
|
|
39
|
+
A taste box takes the shot twice, once per theme, naming the theme in the file as `frames/<box-number>-<theme>.png`.
|
|
40
|
+
|
|
41
|
+
- Reach each theme through the page's own control when the box names one, and through `pw set-color-scheme <dark|light>` otherwise
|
|
42
|
+
- Read the page's background before the shot to confirm the theme changed
|
|
43
|
+
- A page painting the same under both has no second theme, so the box is not driven, with the reason naming that
|
|
44
|
+
- `pw clear-color-scheme` restores the default
|
|
36
45
|
|
|
37
46
|
## The four verdicts
|
|
38
47
|
|
|
@@ -45,8 +54,19 @@ Each box takes exactly one.
|
|
|
45
54
|
| needs eyes | The box ends in `(taste)` | The dark and the light shot as a pair, each the matching evidence stem or a pushed frame's link, and what the frames showed, with nothing about whether it looks right |
|
|
46
55
|
| 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
56
|
|
|
48
|
-
A
|
|
57
|
+
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.
|
|
49
58
|
|
|
50
|
-
|
|
59
|
+
### Which image a verdict carries
|
|
51
60
|
|
|
52
|
-
A
|
|
61
|
+
A pass or fail resting on a frame carries one image at most, and never one the worker's evidence already shows. A needs-eyes box carries the pair, dark and light, since a taste call is made by comparing them.
|
|
62
|
+
|
|
63
|
+
- Match each theme separately. An evidence stem matching the box's route, width, and theme is named and nothing is pushed for it.
|
|
64
|
+
- A view with the dark shot in evidence therefore pushes the light one alone
|
|
65
|
+
- Otherwise push the frame through `canon pr frames` with `--theme`, and put the returned `link` in the box's own section, never inside a folded block
|
|
66
|
+
|
|
67
|
+
### The words beside an image
|
|
68
|
+
|
|
69
|
+
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.
|
|
70
|
+
|
|
71
|
+
- A push that refuses leaves the words alone, with the reason named
|
|
72
|
+
- Never cite the local frame path, since a path under `.canon/` is a board identifier the label scan rejects and resolves only on this machine
|
|
@@ -14,7 +14,11 @@ The heading reports whether the branch owes anything, the way the code review's
|
|
|
14
14
|
- `## UI review` when a box failed, the sweep found a console error or an overflow, or a box was not driven for a cause on the page, such as a target the snapshot does not hold.
|
|
15
15
|
- `## UI review closed` otherwise.
|
|
16
16
|
|
|
17
|
-
A needs-eyes box leaves the review closed, and so does a box not driven for a cause off the page
|
|
17
|
+
A needs-eyes box leaves the review closed, and so does a box not driven for a cause off the page, such as an address that did not answer or a `(local only)` box on a hosted preview.
|
|
18
|
+
|
|
19
|
+
- Each is owed to the person who merges, and no commit can settle it, so opening the heading would hold the draft mark at every head
|
|
20
|
+
- Name each such box in the count line's not-driven count and in its Not driven entry
|
|
21
|
+
- Do not append the pull request number, which GitHub already renders
|
|
18
22
|
|
|
19
23
|
## The body
|
|
20
24
|
|
|
@@ -74,15 +78,35 @@ Driven at `<short-sha>` on <address>, rendered by <renderer>.
|
|
|
74
78
|
|
|
75
79
|
The body opens on its count line, in that order, so the operator reads what they owe before anything else. The second line carries the address, the head, and the renderer, and says the address was driven unverified when it came from the local rung or the launch.
|
|
76
80
|
|
|
77
|
-
|
|
81
|
+
- Drop each section holding no box, along with its heading. Order is fixed: Failed, Needs your eyes, Not driven, then the folded blocks.
|
|
82
|
+
- A box takes exactly one section by its verdict, so a box that fails and also ends in `(taste)` appears once, under Failed
|
|
83
|
+
- Quote page text in backticks as content, never as the pass's own words
|
|
84
|
+
|
|
85
|
+
### A failed box
|
|
86
|
+
|
|
87
|
+
A box in a section opens on its number and the box as written, in bold, with the reading beneath it in words. A failed box that rests on a read has no image.
|
|
88
|
+
|
|
89
|
+
- A failed box resting on a frame shows it inline under its heading, the `` embed with the link exactly as `canon pr frames` returned it
|
|
90
|
+
- That link 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
|
|
91
|
+
- A later pass therefore never changes the image
|
|
92
|
+
|
|
93
|
+
### A needs-eyes box
|
|
78
94
|
|
|
79
|
-
A box
|
|
95
|
+
A needs-eyes box shows its dark and light shots in a two-cell table ahead of anything else it carries, since the operator decides from them without opening the app. A box whose evidence holds one theme still renders both cells.
|
|
80
96
|
|
|
81
|
-
|
|
97
|
+
- A cell is the `link` Step 5 pushed, or for a theme the worker's evidence shows, `https://github.com/<owner>/<repo>/blob/<head>/<path>?raw=true`
|
|
98
|
+
- `<path>` there is the matching state item's `path` off the evidence record
|
|
99
|
+
- A refused push leaves its cell reading `not shown, <reason>`, so the table keeps its shape, and the box's line names what the frame showed
|
|
100
|
+
- Never cite the local frame path, since a path under `.canon/` is a board identifier the label scan rejects
|
|
82
101
|
|
|
83
|
-
The
|
|
102
|
+
### The folded blocks
|
|
84
103
|
|
|
85
|
-
|
|
104
|
+
The Passed block holds one row per passed box, with its measurement and the evidence stem it matched in backticks, so every reading stays one click away. A row citing a stem links it as the evidence image in the form above when the record holds the item.
|
|
105
|
+
|
|
106
|
+
- Omit the Passed block when nothing passed, and the Sweep block when it found nothing
|
|
107
|
+
- Omit the Guessed wording block when every box named its route and width, and drop the folded block when both are empty
|
|
108
|
+
|
|
109
|
+
### An all-pass body
|
|
86
110
|
|
|
87
111
|
A pass where every box passed is the heading, the count line, the folded Passed block, and the marker, with no empty headings:
|
|
88
112
|
|
|
@@ -104,23 +128,27 @@ The count line and the sections beneath it hold the same totals, and Step 10's p
|
|
|
104
128
|
|
|
105
129
|
## The marker
|
|
106
130
|
|
|
107
|
-
End every body on `<!-- review-ui: head=<head> -->`, carrying the full sha Step 1 resolved. A body that replaces a standing close by `PUT` carries it too, at the head this pass drove.
|
|
131
|
+
End every body on `<!-- review-ui: head=<head> -->`, carrying the full sha Step 1 resolved. A body that replaces a standing close by `PUT` carries it too, at the head this pass drove.
|
|
108
132
|
|
|
109
|
-
|
|
133
|
+
The orchestrator's poll reads it off the last non-empty line to decide whether the verdict covers the current head. The submission stamp cannot answer that, since GitHub stamps it with whatever the head is at the moment of posting.
|
|
110
134
|
|
|
111
|
-
|
|
135
|
+
## Posting
|
|
112
136
|
|
|
113
|
-
|
|
137
|
+
Run `canon labels scan --body-file .canon/tmp/pr/review-ui/body-<number>-<short-sha>.md` against the body first, which applies the rule in `${CLAUDE_SKILL_DIR}/../git-pr/references/publish.md`. Nothing gates a file under `.canon/tmp/` before the review-event run does. Fix the body and scan again on a finding.
|
|
114
138
|
|
|
115
|
-
|
|
139
|
+
- Post it as a review rather than an issue comment, since the poll reads the UI family off reviews
|
|
140
|
+
- Skip the post when Step 1's newest verdict reads `## UI review closed` at an older head and this pass closes too, and read `${CLAUDE_SKILL_DIR}/references/close-out.md` instead
|
|
141
|
+
- Posting first in that case leaves two closes, both naming a head
|
|
142
|
+
- Record the instant just before the post, in UTC, as `<posted-at>`, since Step 9 keeps only review-event runs created after it
|
|
143
|
+
- The code review posts its own review on the same head and fires a run of the same gate, which is why that cutoff matters
|
|
116
144
|
|
|
117
145
|
```bash
|
|
118
146
|
date -u +%Y-%m-%dT%H:%M:%SZ
|
|
119
147
|
gh api -X POST 'repos/{owner}/{repo}/pulls/<number>/reviews' -f event=COMMENT -F body=@.canon/tmp/pr/review-ui/body-<number>-<short-sha>.md --jq .html_url
|
|
120
148
|
```
|
|
121
149
|
|
|
122
|
-
The post goes through the REST reviews endpoint
|
|
123
|
-
|
|
124
|
-
The ticks come after the post, in Step 8, so the verdict and the ticks report the same `<head>`. The post never ticks, and a pass that stops before posting ticks nothing.
|
|
150
|
+
The post goes through the REST reviews endpoint, since the `gh pr` review subcommand runs on GraphQL and fails where a cloud session's GitHub proxy refuses it.
|
|
125
151
|
|
|
126
|
-
|
|
152
|
+
- `-F` reads the file into the body, where `-f` would post the path itself
|
|
153
|
+
- The ticks come after the post, in Step 8, so the verdict and the ticks report the same `<head>`. A pass that stops before posting ticks nothing.
|
|
154
|
+
- Never pass `event=APPROVE` or `event=REQUEST_CHANGES`, which carry a state the poll does not read and a weight this pass has not earned
|
|
@@ -132,6 +132,8 @@ A worker is a separate process the controller can steer, and scope reaches it th
|
|
|
132
132
|
- Do not edit tracked files from this session, at any size. The boundary offers no proportionality exception and nothing enforces it.
|
|
133
133
|
- Do not hand a worker anything but a plan, which carries exact diffs only when already known and otherwise states scope and open questions
|
|
134
134
|
|
|
135
|
+
A late ask about a building row is a follow-up filed through `task-board`, with the ask as its origin and the running task cited in the intro. Amend the plan only on the operator's word, naming the re-review cost, and message the worker.
|
|
136
|
+
|
|
135
137
|
The tracked-file boundary collides with `CLAUDE.md`, which says to handle a small edit immediately, and this rule wins wherever the two meet. A session that writes a change cannot review it independently afterwards, which is the separation `review-pr` exists to supply.
|
|
136
138
|
|
|
137
139
|
### Filing a row
|