@erclx/canon 5.39.0 → 5.41.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/README.md +39 -22
- package/claude/.claude-plugin/plugin.json +1 -1
- package/claude/skills/auto-ship/REQUIREMENT.md +1 -0
- package/claude/skills/auto-ship/SKILL.md +6 -0
- package/claude/skills/auto-ship/references/fan-in.md +59 -0
- package/claude/skills/canvas-board/SKILL.md +1 -1
- package/claude/skills/create-skill/references/skill.md +1 -1
- package/claude/skills/decision-escalate/REQUIREMENT.md +1 -1
- package/claude/skills/decision-escalate/SKILL.md +1 -2
- package/claude/skills/draft-slides/SKILL.md +2 -3
- package/claude/skills/draft-slides/references/deck.md +183 -0
- package/claude/skills/git-branch/REQUIREMENT.md +17 -6
- package/claude/skills/git-branch/SKILL.md +63 -7
- package/claude/skills/git-pr/references/evidence.md +2 -2
- package/claude/skills/git-pr/references/final-command.md +1 -1
- package/claude/skills/git-pr/references/labels.md +1 -1
- package/claude/skills/git-pr/references/publish.md +1 -1
- package/claude/skills/plan-feature/references/batches.md +48 -1
- package/claude/skills/plan-feature/references/plan.md +2 -0
- package/claude/skills/plan-intake-answer/REQUIREMENT.md +1 -1
- package/claude/skills/plan-intake-answer/SKILL.md +1 -2
- package/claude/skills/review-address/references/rebase-conflicts.md +7 -0
- package/claude/skills/review-ui/SKILL.md +3 -0
- package/claude/skills/review-ui/references/close-out.md +47 -0
- package/claude/skills/review-ui/references/post.md +3 -1
- package/claude/skills/role-orchestrator/references/orchestrator-dispatch.md +1 -0
- package/claude/skills/role-orchestrator/references/orchestrator-handback.md +1 -1
- package/claude/skills/role-worker/REQUIREMENT.md +1 -0
- package/claude/skills/role-worker/SKILL.md +9 -0
- package/claude/skills/task-board/references/board.md +1 -1
- package/claude/skills/task-board/references/tasks.md +1 -1
- package/claude/skills/teach-workspace/REQUIREMENT.md +1 -1
- package/claude/skills/teach-workspace/SKILL.md +1 -2
- package/claude/skills/ux-measure/SKILL.md +1 -1
- package/docs/agents/audits.md +61 -60
- package/docs/agents/context-audit.md +40 -58
- package/docs/agents/index.md +5 -51
- package/docs/agents/install-and-sync.md +1 -0
- package/docs/agents/markdown-audit.md +53 -99
- package/docs/agents/records.md +37 -79
- package/docs/agents/sessions-transfer.md +26 -70
- package/docs/target/index.md +0 -1
- package/docs/target/migrations.md +57 -66
- package/docs/target/projects.md +36 -78
- package/docs/target/scenarios.md +9 -19
- package/docs/target/sync.md +27 -68
- package/docs/workflow/ai-workflow.md +22 -68
- package/docs/workflow/operating-model.md +32 -186
- package/docs/workflow/parallel-features.md +30 -66
- package/docs/workflow/skill-map-on-request.md +22 -24
- package/docs/workflow/skill-map.md +72 -76
- package/docs/workflow/visual-design-workflow.md +25 -118
- package/docs/workflow/zshrc-aliases.md +18 -37
- package/package.json +1 -1
- package/src/canvas/client/inspector/fields.css +4 -0
- package/src/canvas/index.html +6 -0
- package/src/claude/cases/git.ts +4 -0
- package/src/claude/skills-reach.ts +2 -2
- package/src/cli/ui.ts +3 -1
- package/src/commands/canvas.ts +23 -0
- package/src/commands/capture.ts +14 -0
- package/src/commands/claude.ts +13 -0
- package/src/commands/demo.ts +22 -0
- package/src/commands/deps.ts +6 -0
- package/src/commands/driver.ts +28 -2
- package/src/commands/gov.ts +52 -18
- package/src/commands/intake.ts +17 -0
- package/src/commands/labels.ts +38 -5
- package/src/commands/pr.ts +192 -52
- package/src/commands/records.ts +19 -3
- package/src/commands/secrets.ts +6 -0
- package/src/commands/sessions.ts +8 -0
- package/src/commands/tasks.ts +52 -0
- package/src/commands/teach.ts +13 -0
- package/src/commands/upstream.ts +25 -1
- package/src/commands/worktrees.ts +5 -0
- package/src/context/audit.ts +22 -4
- package/src/context/folders.ts +1 -1
- package/src/context/shape-gated.ts +5 -2
- package/src/counts/scan.ts +1 -1
- package/src/design/components.ts +1 -1
- package/src/design/document.ts +1 -1
- package/src/design/tokens.ts +1 -1
- package/src/gate/boundaries.ts +4 -1
- package/src/gate/measures.ts +1 -1
- package/src/gate/stages.ts +7 -7
- package/src/git/env.ts +6 -0
- package/src/markdown/scope.ts +11 -19
- package/src/pr/frames.ts +53 -9
- package/src/pr/lift.ts +153 -19
- package/src/pr/painted.ts +87 -0
- package/src/records/validate.ts +1 -0
- package/src/roots/record.ts +18 -1
- package/src/sandbox/census.ts +1 -1
- package/src/sandbox/headless/run.ts +3 -2
- package/src/sandbox/headless/watch.ts +3 -4
- package/src/slides/convert/master.ts +3 -0
- package/src/sync/format.ts +46 -0
- package/src/sync/stamp.ts +6 -0
- package/src/tasks/answers.ts +79 -2
- package/src/tasks/fan-in.ts +176 -0
- package/src/tasks/stack.ts +1 -1
- package/tooling/astro/reference.md +80 -39
- package/tooling/base/reference.md +63 -32
- package/tooling/base/seeds/canon/context/ci.md +7 -15
- package/tooling/base/seeds/canon/context/development.md +14 -14
- package/tooling/claude/reference.md +40 -22
- package/tooling/cloudflare/reference.md +31 -12
- package/tooling/go/reference.md +47 -23
- package/tooling/nextjs/reference.md +52 -19
- package/tooling/php/reference.md +35 -16
- package/tooling/python/reference.md +47 -30
- package/tooling/shell/reference.md +6 -5
- package/tooling/vite-react/reference.md +49 -21
- package/tooling/web/reference.md +131 -71
- package/docs/agents/canvas.md +0 -86
- package/docs/agents/capture.md +0 -65
- package/docs/agents/census.md +0 -23
- package/docs/agents/comments.md +0 -34
- package/docs/agents/context-audit-checks.md +0 -108
- package/docs/agents/context-classify.md +0 -101
- package/docs/agents/counts.md +0 -74
- package/docs/agents/demo.md +0 -140
- package/docs/agents/driver.md +0 -103
- package/docs/agents/gate.md +0 -90
- package/docs/agents/hooks.md +0 -78
- package/docs/agents/intake.md +0 -81
- package/docs/agents/key-changes.md +0 -116
- package/docs/agents/label-coverage.md +0 -86
- package/docs/agents/markdown-audit-density.md +0 -39
- package/docs/agents/markdown-audit-weight.md +0 -83
- package/docs/agents/pr-evidence-layout.md +0 -70
- package/docs/agents/pr-evidence.md +0 -273
- package/docs/agents/pr-frames.md +0 -131
- package/docs/agents/pr-lift.md +0 -132
- package/docs/agents/pr-local.md +0 -111
- package/docs/agents/pr-preview.md +0 -155
- package/docs/agents/pr-reads.md +0 -111
- package/docs/agents/pr-tick.md +0 -72
- package/docs/agents/records-push.md +0 -61
- package/docs/agents/records-stale.md +0 -40
- package/docs/agents/records-validate.md +0 -57
- package/docs/agents/restated.md +0 -83
- package/docs/agents/routing.md +0 -61
- package/docs/agents/rule-citations.md +0 -90
- package/docs/agents/sandbox.md +0 -126
- package/docs/agents/sessions.md +0 -128
- package/docs/agents/skills-audit.md +0 -120
- package/docs/agents/skills-reach.md +0 -64
- package/docs/agents/slides.md +0 -176
- package/docs/agents/state-scoped-risk.md +0 -105
- package/docs/agents/superseded.md +0 -85
- package/docs/agents/tasks-archive.md +0 -83
- package/docs/agents/tasks-plans.md +0 -152
- package/docs/agents/tasks-validate.md +0 -133
- package/docs/agents/tasks.md +0 -123
- package/docs/agents/teach-authoring.md +0 -118
- package/docs/agents/teach.md +0 -157
- package/docs/agents/test-order.md +0 -58
- package/docs/agents/upstream.md +0 -94
- package/docs/agents/worktrees.md +0 -118
- package/docs/target/standards-moved.md +0 -34
package/docs/agents/pr-lift.md
DELETED
|
@@ -1,132 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: The pull request draft lift
|
|
3
|
-
description: How canon pr lift removes the draft mark once the reviews, evidence, standing, and CI all read clear at the head, the gate order and what each reads, the wait on a pending run, the re-read before the write, the refusal reasons it names, and what --check reports
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# The pull request draft lift
|
|
7
|
-
|
|
8
|
-
`canon pr lift` takes a pull request out of draft. It reads the gate itself, so
|
|
9
|
-
any session that closes a review can run it, and nobody has to judge whether a
|
|
10
|
-
message asking for the lift came from someone entitled to ask.
|
|
11
|
-
|
|
12
|
-
```bash
|
|
13
|
-
canon pr lift 1341 --json
|
|
14
|
-
canon pr lift 1341 --check --json
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
With no number it resolves the one open pull request on the checked-out branch.
|
|
18
|
-
The ship chain marks every pull request a draft, and this is the verb that
|
|
19
|
-
undoes it.
|
|
20
|
-
|
|
21
|
-
## What it reads
|
|
22
|
-
|
|
23
|
-
Five gates, read in this order. The first four need no wait, so they all run
|
|
24
|
-
before the check runs are read.
|
|
25
|
-
|
|
26
|
-
| Gate | Clear when |
|
|
27
|
-
| ---------- | --------------------------------------------------------------------------------------------- |
|
|
28
|
-
| `review` | The newest `## Review` pass is closed, and its marker names the head. |
|
|
29
|
-
| `ui` | The newest `## UI review` verdict is closed at the head. Binds only where a checklist exists. |
|
|
30
|
-
| `evidence` | `canon pr evidence --check` reads `settled`, meaning no post-pull-request step is owed. |
|
|
31
|
-
| `standing` | The head merges into the freshly fetched base, and the base moved no path the branch writes. |
|
|
32
|
-
| `ci` | Every check run on the branch tip concluded and none failed. |
|
|
33
|
-
|
|
34
|
-
The head is the branch tip read from the remote, not the pull request object's
|
|
35
|
-
head, which trails a push by up to a minute. A review marker names the commit
|
|
36
|
-
the reviewer read, and it covers the head when it is that commit or a prefix of
|
|
37
|
-
it.
|
|
38
|
-
|
|
39
|
-
The UI gate binds only when `canon pr evidence --check --json` carries a
|
|
40
|
-
`checklist` field. The verb branches on that field and not on the exit, so a
|
|
41
|
-
branch with no rendered surface owes no UI review.
|
|
42
|
-
|
|
43
|
-
A review pass with no read-time marker refuses as `review-unmarked`. Its covered
|
|
44
|
-
commit would be the stamp GitHub wrote at submission, which the marker exists to
|
|
45
|
-
replace, and lifting on it reintroduces the defect `canon pr review-state`
|
|
46
|
-
documents.
|
|
47
|
-
|
|
48
|
-
## The wait
|
|
49
|
-
|
|
50
|
-
A pending CI run is waited on rather than refused. `--wait <seconds>` bounds it,
|
|
51
|
-
defaulting to 1200, and the check runs are read every 30 seconds until one of
|
|
52
|
-
four things happens:
|
|
53
|
-
|
|
54
|
-
- every run passed, and the verb goes on to the write
|
|
55
|
-
- a run failed, which refuses `ci-failing` at once
|
|
56
|
-
- the branch conflicts with its base, which refuses `ci-conflicted` at once,
|
|
57
|
-
since no run starts for a conflicted branch and the wait could not end
|
|
58
|
-
- the deadline passed, which refuses `ci-timeout`
|
|
59
|
-
|
|
60
|
-
A refusal on any of the first four gates comes before the wait starts. A code
|
|
61
|
-
reviewer whose UI partner is still driving refuses `ui-open` immediately
|
|
62
|
-
instead of holding a turn through a CI run.
|
|
63
|
-
|
|
64
|
-
## The re-read
|
|
65
|
-
|
|
66
|
-
A push during the wait moves the head off the commit every earlier gate
|
|
67
|
-
cleared. After the wait, and immediately before the write, the verb reads the
|
|
68
|
-
pull request, the branch tip, and the reviews again. A tip that moved refuses
|
|
69
|
-
`head-moved`, and a review that opened refuses with its own reason. The
|
|
70
|
-
standing is read again as well, so a sibling merging during the wait refuses
|
|
71
|
-
`standing-stale` instead of lifting a branch that read fresh before it. A pull
|
|
72
|
-
request already out of draft by then reports `already-ready`.
|
|
73
|
-
|
|
74
|
-
Two reviewers closing within seconds of each other can each read the other's
|
|
75
|
-
review as still open and both refuse. The re-read narrows that window and does
|
|
76
|
-
not close it, so a draft whose reviews both read closed is the controlling
|
|
77
|
-
session's to lift.
|
|
78
|
-
|
|
79
|
-
## The write
|
|
80
|
-
|
|
81
|
-
The lift is the `markPullRequestReadyForReview` GraphQL mutation, because the
|
|
82
|
-
REST pull request update carries no draft field. It is the one GraphQL call the
|
|
83
|
-
verb makes, and every read stays on REST. The verb reads `isDraft` back from the
|
|
84
|
-
mutation's answer, and a response that does not say `false` refuses `gh-failed`
|
|
85
|
-
rather than reporting a lift.
|
|
86
|
-
|
|
87
|
-
A cloud session's proxy refuses GraphQL, so a reviewer running there reaches
|
|
88
|
-
`gh-failed` on the write and hands the lift to the controlling session.
|
|
89
|
-
|
|
90
|
-
## What it reports
|
|
91
|
-
|
|
92
|
-
`reason` on the record is what a caller branches on. Exit 0 covers `lifted` and
|
|
93
|
-
`already-ready`, so the second of two reviewers to close owes nobody a message.
|
|
94
|
-
Every other reason exits 1.
|
|
95
|
-
|
|
96
|
-
| Reason | What it means |
|
|
97
|
-
| ------------------- | ---------------------------------------------------------------------- |
|
|
98
|
-
| `lifted` | The mark came off. |
|
|
99
|
-
| `already-ready` | The pull request was not a draft. Nothing is written. |
|
|
100
|
-
| `clear` | Under `--check`, every gate reads clear. |
|
|
101
|
-
| `pull-closed` | The pull request is closed. |
|
|
102
|
-
| `review-missing` | The thread carries no code review. |
|
|
103
|
-
| `review-open` | The newest code review is open. |
|
|
104
|
-
| `review-unmarked` | The newest code review carries no marker. |
|
|
105
|
-
| `review-behind` | The newest code review closed on an earlier commit than the head. |
|
|
106
|
-
| `ui-missing` | A checklist exists and no UI review has been posted. |
|
|
107
|
-
| `ui-open` | The newest UI review is open. |
|
|
108
|
-
| `ui-unmarked` | The newest UI review carries no head marker. |
|
|
109
|
-
| `ui-behind` | The newest UI review closed on an earlier commit than the head. |
|
|
110
|
-
| `evidence-owed` | The evidence check reads `owed`. |
|
|
111
|
-
| `standing-stale` | The base moved under a path the branch writes. |
|
|
112
|
-
| `standing-conflict` | The head does not merge cleanly into the base. |
|
|
113
|
-
| `standing-unknown` | The head or base did not resolve, which a fork or deleted head leaves. |
|
|
114
|
-
| `ci-pending` | Under `--check`, a run has yet to conclude. |
|
|
115
|
-
| `ci-failing` | A check run failed. |
|
|
116
|
-
| `ci-conflicted` | The branch conflicts, so no run will start. |
|
|
117
|
-
| `ci-timeout` | A run was still pending when `--wait` ran out. |
|
|
118
|
-
| `head-moved` | A push landed during the wait. |
|
|
119
|
-
| `gh-failed` | A read or the write was refused, so nothing is reported as lifted. |
|
|
120
|
-
|
|
121
|
-
`standing-unknown` waits on a person, matching the orchestrator poll's own rule
|
|
122
|
-
for a head it cannot resolve.
|
|
123
|
-
|
|
124
|
-
## `--check`
|
|
125
|
-
|
|
126
|
-
`--check` reports every gate and writes nothing. It reads the check runs once
|
|
127
|
-
and does not wait, so a pending run reports `ci-pending`. The record carries a
|
|
128
|
-
`gates` array with each gate's name, whether it is clear, and its reason, so a
|
|
129
|
-
caller sees every gate that blocks and not the first alone.
|
|
130
|
-
|
|
131
|
-
The orchestrator's poll and a session deciding whether to run the verb read the
|
|
132
|
-
same answer this way, rather than each restating the gate.
|
package/docs/agents/pr-local.md
DELETED
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: The pull request local preview
|
|
3
|
-
description: How canon pr local finds the server a worktree is running, why a server in another worktree is never reported, the refusal reasons it names, and how a close workflow drops the address line with --remove
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# The pull request local preview
|
|
7
|
-
|
|
8
|
-
`canon pr local` reports the `localhost` address of the dev server the current
|
|
9
|
-
worktree is running. `git-pr` calls it ahead of the evidence comparison and
|
|
10
|
-
passes the address through `canon pr evidence --local`, so a reviewer on the
|
|
11
|
-
same machine gets the running branch to click into beside the screenshots and
|
|
12
|
-
the checklist. A workflow on the pull request's `closed` event calls it again
|
|
13
|
-
with `--remove`, which drops the address line and leaves nothing in its place.
|
|
14
|
-
|
|
15
|
-
```bash
|
|
16
|
-
canon pr local --json
|
|
17
|
-
canon pr local 1341 --remove --json
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
## How it finds the server
|
|
21
|
-
|
|
22
|
-
The verb reads every TCP socket in `LISTEN` with the process that owns it. It
|
|
23
|
-
keeps a socket when that process's working directory sits inside the
|
|
24
|
-
worktree's toplevel, including a subfolder, since some tools change into one
|
|
25
|
-
before they listen. It then requests `/` on each kept port and reports the
|
|
26
|
-
lowest one serving an HTML page.
|
|
27
|
-
|
|
28
|
-
The HTML test is there because a working tree often holds more than one
|
|
29
|
-
listener. A test runner's own server, or a dev server's reload socket, answers
|
|
30
|
-
HTTP too, and a reviewer opening either gets a bare 404 rather than the branch.
|
|
31
|
-
|
|
32
|
-
Sockets are read from `/proc/net/tcp` and `/proc/net/tcp6` wherever they exist,
|
|
33
|
-
matched against each process's `fd` table, and through `lsof` on a machine
|
|
34
|
-
without them. Linux reads `/proc` even with `lsof` installed, since `lsof` 4.95
|
|
35
|
-
drops a process whose truncated name holds an unmatched `(`, which is what
|
|
36
|
-
Next's `next-server (vX.Y.Z)` title is cut down to. A machine with neither
|
|
37
|
-
refuses as `no-listener-reader`.
|
|
38
|
-
|
|
39
|
-
The port is never derived from the worktree. A port helper needs a per-stack
|
|
40
|
-
base port the toolkit cannot know, and a server started by hand or by an
|
|
41
|
-
earlier session would not match it anyway.
|
|
42
|
-
|
|
43
|
-
## Why another worktree's server is never reported
|
|
44
|
-
|
|
45
|
-
A server running in a different worktree shows a different branch, and a link
|
|
46
|
-
to it on this pull request would show a reviewer the wrong code.
|
|
47
|
-
|
|
48
|
-
- A sibling linked worktree sits outside this one's toplevel, so its process
|
|
49
|
-
never matches.
|
|
50
|
-
- The main checkout's server, read from a linked worktree, sits outside the
|
|
51
|
-
linked worktree's toplevel for the same reason.
|
|
52
|
-
- A linked worktree's server, read from the main checkout, sits inside the main
|
|
53
|
-
toplevel. The verb excludes everything under `.claude/worktrees/` for that
|
|
54
|
-
case alone.
|
|
55
|
-
|
|
56
|
-
## What the record carries
|
|
57
|
-
|
|
58
|
-
`reason` on the record is what a caller branches on, not the exit code:
|
|
59
|
-
|
|
60
|
-
| Reason | What it means |
|
|
61
|
-
| -------------------- | --------------------------------------------------------------------- |
|
|
62
|
-
| `ok` | A server answered. `url` carries the address and `port` the port. |
|
|
63
|
-
| `no-server` | Nothing inside this worktree served an HTML page. |
|
|
64
|
-
| `no-listener-reader` | Neither `lsof` nor `/proc` is available, so no socket could be read. |
|
|
65
|
-
| `removed` | `--remove` dropped the address line from the evidence comment. |
|
|
66
|
-
| `no-comment` | `--remove` found no comment carrying the evidence marker. |
|
|
67
|
-
| `no-line` | `--remove` found the comment but no address line on it. |
|
|
68
|
-
| `gh-missing` | `--remove` needs `gh` and it is not on the path. |
|
|
69
|
-
| `gh-failed` | `--remove` could not read the comments or could not edit the comment. |
|
|
70
|
-
|
|
71
|
-
The exit is 0 on `ok` and on every `--remove` outcome that finished, including
|
|
72
|
-
the two no-ops, and 1 on every refusal. A caller on an older binary gets an
|
|
73
|
-
unknown-subcommand error instead of a record, which `git-pr` reads as a skip.
|
|
74
|
-
|
|
75
|
-
## Removing the link at close
|
|
76
|
-
|
|
77
|
-
The link goes dead once the branch's server stops, and nothing on the pull
|
|
78
|
-
request says so. `--remove` runs on the pull request's `closed` event, merged or
|
|
79
|
-
abandoned, from a workflow seeded into every target:
|
|
80
|
-
|
|
81
|
-
```yaml
|
|
82
|
-
on:
|
|
83
|
-
pull_request:
|
|
84
|
-
types: [closed]
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
It reads the comment carrying the `pr-evidence` marker, drops the address line
|
|
88
|
-
under `## Evidence`, the hosted `**Preview:**` segment and the
|
|
89
|
-
`**Local preview:**` segment together, and edits the comment itself through
|
|
90
|
-
`gh api`. The hosted link goes too because the deploy workflow deletes the
|
|
91
|
-
branch's preview deployments on the same close. No note replaces the line, and
|
|
92
|
-
the blank line it sat on goes with it so no gap doubles under the heading. A
|
|
93
|
-
comment in the older layout, with each address on its own line at the top,
|
|
94
|
-
loses both lines the same way.
|
|
95
|
-
|
|
96
|
-
The verb writes here rather than handing a body back, because its caller is a
|
|
97
|
-
workflow with no session to post one. Every other byte of the comment stays as
|
|
98
|
-
it was, which keeps the marker, the checklist delimiters, and any ticked box
|
|
99
|
-
intact. A second run finds no line and reports `no-line`.
|
|
100
|
-
|
|
101
|
-
A fork pull request gets a read-only token, so the workflow skips the edit with
|
|
102
|
-
a notice rather than failing the close.
|
|
103
|
-
|
|
104
|
-
## What this does not cover
|
|
105
|
-
|
|
106
|
-
The link can still go dead while the pull request is open, such as when the
|
|
107
|
-
session holding the server retires. Only the close is covered, and a re-render
|
|
108
|
-
after a push carries the line forward whether the server still answers or not.
|
|
109
|
-
|
|
110
|
-
`canon docs pr-preview` covers how the hosted address is minted and when it is
|
|
111
|
-
refused.
|
|
@@ -1,155 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: The pull request preview deploy
|
|
3
|
-
description: How canon pr preview finds a fenced Cloudflare Pages deploy, refuses a branch its push filter does not serve, dispatches it on a pull request's branch, reads the alias the run prints, the refusal reasons it names, and why an unfenced deploy is refused before anything runs
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# The pull request preview deploy
|
|
7
|
-
|
|
8
|
-
`canon pr preview` publishes a pull request's branch to a Cloudflare Pages
|
|
9
|
-
preview and reports the address. `git-pr` calls it after the evidence
|
|
10
|
-
comparison, then re-renders that comment through `canon pr evidence --preview`
|
|
11
|
-
so the link sits on the address line under its heading. A reviewer gets a page
|
|
12
|
-
to click into before merging rather than screenshots and a checklist alone.
|
|
13
|
-
|
|
14
|
-
```bash
|
|
15
|
-
canon pr preview --json
|
|
16
|
-
canon pr preview 1341 --json --timeout 20
|
|
17
|
-
canon pr preview 1341 --check --json
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
## Which workflow it dispatches
|
|
21
|
-
|
|
22
|
-
The verb reads `.github/workflows/*.yml` and `*.yaml` in the checkout and picks
|
|
23
|
-
the first file, in path order, that meets four tests:
|
|
24
|
-
|
|
25
|
-
- It runs `pages deploy`.
|
|
26
|
-
- It carries a `workflow_dispatch` trigger, since nothing else lets a caller
|
|
27
|
-
start it on a branch.
|
|
28
|
-
- Its deploy passes `--branch=${{ github.ref_name }}`.
|
|
29
|
-
- It prints a `canon-preview-alias:` line.
|
|
30
|
-
|
|
31
|
-
The workflow is read before the pull request, so a project with no fenced
|
|
32
|
-
deploy is refused without a network call.
|
|
33
|
-
|
|
34
|
-
## Which branches it serves
|
|
35
|
-
|
|
36
|
-
A dispatch runs the workflow whatever its `on.push.paths` filter says, so a
|
|
37
|
-
branch that touched nothing the site builds from would get a preview showing
|
|
38
|
-
none of its change. The verb reads the pull request's changed paths and matches
|
|
39
|
-
them against the picked workflow's own `on.push.paths` or `on.push.paths-ignore`
|
|
40
|
-
list, applying `!` patterns in order the way GitHub does. When nothing matches,
|
|
41
|
-
it refuses as `unserved` and dispatches nothing. `--check` answers `unserved`
|
|
42
|
-
the same way.
|
|
43
|
-
|
|
44
|
-
The push filter is the one statement of what the site builds from, since it
|
|
45
|
-
already decides when production deploys. A workflow with neither list, with no
|
|
46
|
-
push trigger, or that does not parse as YAML serves every change, so a project
|
|
47
|
-
whose every change ships keeps minting for every branch.
|
|
48
|
-
|
|
49
|
-
A removed path counts, the same as GitHub's own push filter counts it, so a
|
|
50
|
-
branch whose only site change deletes a file still gets a preview.
|
|
51
|
-
|
|
52
|
-
## Why an unfenced deploy is refused
|
|
53
|
-
|
|
54
|
-
Cloudflare Pages publishes a deploy that names no branch to production. A
|
|
55
|
-
dispatch from an unmerged branch through such a workflow ships that branch to
|
|
56
|
-
the live site, so the verb refuses as `unfenced` and dispatches nothing. The
|
|
57
|
-
fix is one flag on the deploy command, and the cloudflare stack's
|
|
58
|
-
`deploy.yml` already carries it.
|
|
59
|
-
|
|
60
|
-
## Where the address comes from
|
|
61
|
-
|
|
62
|
-
The workflow prints the alias Cloudflare returned for the deploy, read from
|
|
63
|
-
`wrangler-action`'s `pages-deployment-alias-url` output, on a fixed line:
|
|
64
|
-
|
|
65
|
-
```plaintext
|
|
66
|
-
canon-preview-alias: https://<alias>.<project>.pages.dev
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
The verb reads that line out of the finished run's log rather than computing
|
|
70
|
-
the address from the branch name. Cloudflare flattens a branch into its alias
|
|
71
|
-
and may truncate it, and a computed address that is wrong is worse than none.
|
|
72
|
-
The output needs wrangler 3.78 or later, so the workflow pins
|
|
73
|
-
`wranglerVersion`.
|
|
74
|
-
|
|
75
|
-
`gh workflow run` reports no run id. The verb lists the branch's dispatched
|
|
76
|
-
runs before dispatching and takes the one id that appears afterwards, which
|
|
77
|
-
keeps the match independent of the local clock.
|
|
78
|
-
|
|
79
|
-
## What the record carries
|
|
80
|
-
|
|
81
|
-
`reason` on the record is what a caller branches on, not the exit code:
|
|
82
|
-
|
|
83
|
-
| Reason | What it means |
|
|
84
|
-
| -------------------- | -------------------------------------------------------------------------- |
|
|
85
|
-
| `ok` | The preview was published. `url` carries the address and `runId` the run. |
|
|
86
|
-
| `no-deploy` | No dispatchable workflow runs `pages deploy`. |
|
|
87
|
-
| `unserved` | The push path filter matches no changed path, so nothing was dispatched. |
|
|
88
|
-
| `unreadable-changes` | The pull request's changed paths could not be read. |
|
|
89
|
-
| `unfenced` | The deploy passes no `--branch`, so nothing was dispatched. |
|
|
90
|
-
| `no-alias` | The workflow prints no alias line, or the finished run's log carried none. |
|
|
91
|
-
| `run-failed` | The deploy run finished without succeeding. `runId` names it. |
|
|
92
|
-
| `timeout` | The run did not finish inside `--timeout` minutes, 15 by default. |
|
|
93
|
-
| `bad-timeout` | `--timeout` was not a positive number. |
|
|
94
|
-
| `gh-missing` | `gh` is not on the path. |
|
|
95
|
-
| `gh-failed` | `gh` could not read the pull request, or list or dispatch the workflow. |
|
|
96
|
-
| `no-branch` | The pull request carries no head branch name. |
|
|
97
|
-
| `check-timeout` | `--check` was combined with `--timeout`. |
|
|
98
|
-
|
|
99
|
-
The exit is 0 on `ok` and 1 on every refusal. A `timeout` leaves the run
|
|
100
|
-
going, so the preview may still land after the verb has given up on it.
|
|
101
|
-
|
|
102
|
-
## Checking which head a preview was built from
|
|
103
|
-
|
|
104
|
-
`--check` dispatches nothing and waits on nothing. It lists the branch's
|
|
105
|
-
`workflow_dispatch` runs, takes the newest successful one by creation time, and
|
|
106
|
-
compares the head it ran at with the branch tip read from the remote. The tip
|
|
107
|
-
comes from the remote rather than the pull request object's `headRefOid`, which
|
|
108
|
-
lags a push. `--check` takes no `--timeout` and refuses one as `check-timeout`.
|
|
109
|
-
|
|
110
|
-
The alias serves the newest successful deployment for the branch and names no
|
|
111
|
-
sha, so the run listing is the only record of the built head. The
|
|
112
|
-
`workflow_dispatch` filter also drops the cleanup run a closed pull request
|
|
113
|
-
fires, which concludes `success` with its deploy skipped. A project that deploys
|
|
114
|
-
on `push` to a feature branch would need that filter widened.
|
|
115
|
-
|
|
116
|
-
| Reason | What it means |
|
|
117
|
-
| ---------- | --------------------------------------------------------------------- |
|
|
118
|
-
| `fresh` | The newest successful deploy built the tip. Exit 0. |
|
|
119
|
-
| `stale` | It built an earlier head. `built` and `tip` name both. Mint again. |
|
|
120
|
-
| `building` | A deploy of the tip is still running. Wait rather than minting again. |
|
|
121
|
-
| `no-build` | No deploy of the branch has succeeded. |
|
|
122
|
-
|
|
123
|
-
The record also carries `runId` for the deploy it read. The check covers the
|
|
124
|
-
hosted address only, so a local address has no run to read and stays unverified.
|
|
125
|
-
`review-ui` runs it before driving a hosted preview and posts nothing on any
|
|
126
|
-
reason but `fresh`.
|
|
127
|
-
|
|
128
|
-
## How the address reaches the pull request
|
|
129
|
-
|
|
130
|
-
`canon pr evidence --preview <url>` puts `**Preview:** <url>` on the address
|
|
131
|
-
line under the evidence body's `## Evidence` heading. With no evidence image in
|
|
132
|
-
the diff, the body is the heading, that line, and the trailing marker alone, so
|
|
133
|
-
a pull request whose screenshots did not change still gets one comment a later
|
|
134
|
-
call can find and edit.
|
|
135
|
-
|
|
136
|
-
A later `canon pr evidence` run without `--preview` reads the address off the
|
|
137
|
-
marked comment and carries it into the new body. `git-followup` re-renders the
|
|
138
|
-
comment after every push, and without that carry the first push would delete
|
|
139
|
-
the link. A visual checklist folded in through `--checklist` carries the same
|
|
140
|
-
way, which is what keeps that push from wiping boxes a reviewer already ticked.
|
|
141
|
-
|
|
142
|
-
## Removing a preview
|
|
143
|
-
|
|
144
|
-
A `pull_request` trigger on `closed` in the same workflow runs a cleanup job
|
|
145
|
-
that deletes every preview deployment Cloudflare holds for the branch. The
|
|
146
|
-
deploy job carries `if: github.event_name != 'pull_request'`, so a closed pull
|
|
147
|
-
request never deploys. The same close runs `canon pr local --remove`, which
|
|
148
|
-
drops the address line from the evidence comment, hosted link included, so the
|
|
149
|
-
comment never links a deployment that no longer exists.
|
|
150
|
-
|
|
151
|
-
## What this does not cover
|
|
152
|
-
|
|
153
|
-
The verb builds only the deployed-and-public case. A private repository whose
|
|
154
|
-
previews need access protection waits for a project that needs it. A local
|
|
155
|
-
server stands in where there is no deploy, through `canon docs pr-local`.
|
package/docs/agents/pr-reads.md
DELETED
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: Head-sensitive pull request reads
|
|
3
|
-
description: Resolving a branch tip from the remote rather than from the pull request object, reading what a review pass covered off its own marker rather than off GitHub's submission stamps, why an empty run list is not a pass, the refusal reasons each verb names, and what the remote read costs
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Head-sensitive pull request reads
|
|
7
|
-
|
|
8
|
-
`canon pr head`, `canon pr checks`, and `canon pr review-state` each answer about a commit, and each exists because the field GitHub offers answers a different question. The first two resolve the branch tip from the remote with `git ls-remote` rather than taking the pull request object's word for which commit the branch is on. The third reads what a review pass covered off a marker the pass wrote, rather than off the head GitHub stamped when the review was submitted.
|
|
9
|
-
|
|
10
|
-
```bash
|
|
11
|
-
canon pr head
|
|
12
|
-
canon pr head 1341 --json
|
|
13
|
-
canon pr checks
|
|
14
|
-
canon pr checks 1341 --json
|
|
15
|
-
canon pr review-state
|
|
16
|
-
canon pr review-state 1341 --json
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
## The pull request object is not the authority for a head
|
|
20
|
-
|
|
21
|
-
The pull request's head sha, `head.sha` on the REST pull read and `headRefOid` in `gh pr view`, is a field on the pull request object. That object trails the branch ref by up to a minute after a push and carries nothing saying how far behind it is, so a session that keys a read on it is describing whichever commit GitHub last folded into the object.
|
|
22
|
-
|
|
23
|
-
Two failures on 2026-09-01 came off that one field. A reviewing session posted a finding calling a pushed commit unpushed. A worker fired a green claim and retracted it on its own thread minutes later. Neither session did anything wrong with the value it was handed. The value was stale and said so nowhere.
|
|
24
|
-
|
|
25
|
-
The remote ref carries no such lag. `git ls-remote --heads origin <branch>` asks the remote itself rather than a tracking ref, which is only as current as the last fetch, and the push worth catching is the one this process never saw.
|
|
26
|
-
|
|
27
|
-
The argument is stated here once. The shipped skill bodies call the verb rather than repeating it, because a sentence telling a session to compare two shas is a sentence a session can decide it already followed.
|
|
28
|
-
|
|
29
|
-
## What each verb answers
|
|
30
|
-
|
|
31
|
-
`canon pr head` reports `fresh` when the object and the remote name the same commit and `stale` when they disagree, with both shas on the record. The tip is the authority and the object's head is the claim being checked against it.
|
|
32
|
-
|
|
33
|
-
`canon pr checks` reads `repos/{owner}/{repo}/commits/<tip>/check-runs` and collapses it to `passing`, `failing`, or `pending`. A failure outranks a run still going, since a run in flight cannot clear a job that already failed.
|
|
34
|
-
|
|
35
|
-
`canon pr review-state` reports `heading` and `state` for the newest pass in the review family, `commit` and `readAt` for what it covered, `submittedAt` for when GitHub recorded it, and `source` for which of those readings answered. A thread carrying no pass reports `state` and `source` both as `none` with nothing else on the record.
|
|
36
|
-
|
|
37
|
-
`gh pr checks` cannot be made to answer this question at all, which is the argument for the move rather than a preference between two working commands. Its `--json` field set is `bucket, completedAt, description, event, link, name, startedAt, state, workflow`, with no sha among them, so a caller cannot even learn which commit its answer describes.
|
|
38
|
-
|
|
39
|
-
## A review's stamps describe the submission, not the read
|
|
40
|
-
|
|
41
|
-
`commit.oid` on a review names whatever the pull request head was at the instant the review was submitted. `submittedAt` names that instant. Neither names the commit the reviewing session actually opened, and the two are only the same when nothing was pushed while the comment was being written.
|
|
42
|
-
|
|
43
|
-
A push landing in that window moves both onto a commit nobody reviewed. The next pass then scopes its delta past that commit and reports it covered, which is the failure direction that loses work: the commit is skipped rather than re-read. It fired on a pull request in this toolkit on 2026-09-07, where a pass read one commit, the branch pushed another during the compose, and the poll reported the second as already seen. What it skipped was a genuine fix, and a reader comparing the sha in the report against the sha in the pass caught it.
|
|
44
|
-
|
|
45
|
-
`review-pr` therefore ends every body it posts with a marker naming what it read:
|
|
46
|
-
|
|
47
|
-
```markdown
|
|
48
|
-
<!-- review-pr: commit=<sha> read-at=<iso8601> -->
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
Both values are taken at the top of the pass rather than at the post, so the compose window falls outside what the marker claims. An HTML comment renders as nothing on GitHub, so a reader of the thread never meets it.
|
|
52
|
-
|
|
53
|
-
The last non-empty line is where it has to sit, and the reader looks nowhere else. Searching a body for the last match instead reads a marker the body was displaying rather than claiming, since a fenced block showing the format on its own line trims to exactly the pattern, and a pass carrying no marker of its own would then hand the next reader a commit taken from an illustration. That is the same defect through a second door, so position rather than shape is what separates a claim from a quotation.
|
|
54
|
-
|
|
55
|
-
`canon pr review-state` is the only parser of that format. Two parsers was the alternative, one in the shipped skill body and one in the orchestrator poll's own filters, and those two ship on different cadences, so a format change to either would leave the other reading a reviewed commit as unreviewed.
|
|
56
|
-
|
|
57
|
-
`source` on the record says which reading answered, and a caller checks it before trusting the rest:
|
|
58
|
-
|
|
59
|
-
| Source | What it means |
|
|
60
|
-
| ---------- | ------------------------------------------------------------------------------------------- |
|
|
61
|
-
| `marker` | The pass wrote its own read-time record, which is the authority |
|
|
62
|
-
| `fallback` | A pass posted before this shipped, read off the submission stamps and carrying their defect |
|
|
63
|
-
| `none` | The thread carries no pass, so the next one is a first pass |
|
|
64
|
-
|
|
65
|
-
The record carries `submittedAt` beside `readAt` rather than in place of it, because each is right about a different question. What a pass had read is a fact about the read, and how long a posted comment has waited on a human is a fact about the submission. The orchestrator poll reads the first for its coverage test and the second for its age test.
|
|
66
|
-
|
|
67
|
-
A `PUT` rewrite of a standing close-out inherits the fix without a mechanism of its own. That request replaces the body and the marker rides in it, so a rewritten comment names the commit the rewriting pass read. `submittedAt` stays pinned to the original submission, which is the reading the age test wants anyway.
|
|
68
|
-
|
|
69
|
-
## An empty run list is not a pass
|
|
70
|
-
|
|
71
|
-
Keying the query on a sha is necessary and not sufficient. The endpoint answered with `total_count` 2 and an empty row list during a measured window on 2026-09-02, so a reader that finds no run for the tip and reports `passing` reproduces the false green behind a better query.
|
|
72
|
-
|
|
73
|
-
Both empty cases report `pending` instead: a tip carrying no run yet, and a listing whose rows all belong to some other commit. The record separates them, since `matched` counts the runs belonging to the tip and `foreign` counts the rest, and a caller that wants to tell "not started" from "still going" reads those two numbers rather than the state alone.
|
|
74
|
-
|
|
75
|
-
The verb keeps the newest run per check name rather than rolling every matched run into the state. A workflow that fires twice on one commit used to leave its first, stale run beside the rerun, where a failing one could outvote a passing rerun. Grouping the matched set by name and keeping the highest `id` per group removes that stale run before the rollup runs. `collapsed` on the record counts what the fold discards, so a caller reading it against `matched` sees the dedupe directly, instead of reading a `matched` above the check count as the verb disagreeing with `gh pr checks`.
|
|
76
|
-
|
|
77
|
-
A conflicted branch produces no `pull_request` check runs rather than a failing one. GitHub builds no merge ref for it, so no `pull_request` workflow starts and a repository running only that trigger leaves the listing empty, which reads as `pending` and never leaves it. A workflow triggered by a push to the branch still runs on the tip, so `matched` rises above zero, `conflicted` stays false, and the wait ends on those runs rather than on the reading. The pull request's `mergeable_state` is the field that separates the two. The verb raises it to upper case, matching the GraphQL `mergeStateStatus` it replaced, and the record carries `conflicted: true` and `mergeState` when it reads `DIRTY` with no run belonging to the tip. A `DIRTY` reading beside runs on the tip leaves the state as those runs say, since a conflict arising after they completed does not unsay them. `UNKNOWN` is transient while GitHub computes the merge state, right after a push, so it reads as not conflicted and costs one more poll. A binary predating the field keeps answering `pending`.
|
|
78
|
-
|
|
79
|
-
A listing carrying even one foreign run reports `pending` whatever the matching half says. A set that describes another commit says nothing about this one, so answering off the rows that happen to match would put a verdict on a set already known to be incomplete.
|
|
80
|
-
|
|
81
|
-
A count above the rows returned reports `pending` for the same reason. The query asks for 100 rows against the endpoint's default of 30, and a commit carrying more than that comes back short, so the verb reports the tip as unread rather than collapsing the page it happens to hold. `reported` against `matched` and `foreign` is where a reader sees which of the three shapes produced the answer.
|
|
82
|
-
|
|
83
|
-
## Reading the answer
|
|
84
|
-
|
|
85
|
-
Branch on the record rather than on the exit. Both verbs exit 0 whenever they resolved a tip, whatever the verdict, and 1 only when they refused. An operator shell profile can wrap `canon` in a function whose status comes from a trailing command, which flattens every non-zero exit to 0, so the exit is not a channel either verb puts a verdict on. `gh pr checks` reserving exit 8 for pending is the pattern being replaced rather than one to copy.
|
|
86
|
-
|
|
87
|
-
Each refusal names a different repair:
|
|
88
|
-
|
|
89
|
-
| Reason | What it means |
|
|
90
|
-
| -------------------- | ------------------------------------------------------------------------------------------ |
|
|
91
|
-
| `gh-missing` | `gh` is not on the path, so no pull request resolved |
|
|
92
|
-
| `gh-failed` | `gh` could not answer for this branch, so name a number instead |
|
|
93
|
-
| `ambiguous-pull` | Two open pull requests share the branch against different bases, so name a number |
|
|
94
|
-
| `no-branch` | The pull request carries no head branch name, so no ref could be read |
|
|
95
|
-
| `unresolvable-ref` | The remote read failed, which is not the same answer as an absent branch |
|
|
96
|
-
| `no-remote-branch` | The remote carries no branch by that name, so there is no tip to compare against |
|
|
97
|
-
| `no-object-head` | The pull request object reported no head, so `head` has nothing to compare the tip against |
|
|
98
|
-
| `runs-unreadable` | The check runs for the tip could not be read, which is unread rather than none |
|
|
99
|
-
| `reviews-unreadable` | The reviews on the pull request could not be parsed, which is unread rather than none |
|
|
100
|
-
|
|
101
|
-
A failed remote read and a branch the remote does not carry stay apart rather than collapsing into one reason. Reading the first as the second would report a network refusal as a deleted branch, and the repairs have nothing in common.
|
|
102
|
-
|
|
103
|
-
## What it costs
|
|
104
|
-
|
|
105
|
-
One remote round trip per call, sampled here at 0.41s, 0.55s, and 0.67s on 2026-09-01 and 2026-09-02, against 0.001s for the local ref read. The spread is the network rather than the command, so read it as roughly half a second and not as a figure to compare a later reading against. Every caller pointed at these verbs already spends a `gh` round trip on the same line, so the added cost lands on a path that was never local to begin with.
|
|
106
|
-
|
|
107
|
-
One head-sensitive read is left on the object deliberately. `canon targets pulls` reads `statusCheckRollup` for every open pull request across every target, where resolving a tip per row would cost one remote read per pull request across a dozen projects, against a surface that reports a listing rather than gating a push.
|
|
108
|
-
|
|
109
|
-
The orchestrator poll spends that same read per open pull request and repeats it on a three-minute timer, which makes it the heaviest caller here rather than an exception to the paragraph above. Six open pull requests is around 120 remote reads an hour. It reads over REST alone, one reviews read and one issue-comments read per pull request, plus a pull read only when `canon pr head` returns no tip. It spends a further read per pull request per tick besides, since `canon pr review-state` makes its own REST reviews read beside the payload the poll already fetched. That one is an API round trip rather than a remote ref read, and it buys a coverage test that answers about what a session read. What separates the two cases is what each reading decides rather than what it costs. The poll's head fires the review trigger, so a stale one sends a pass at a commit nobody read or withholds one that is owed. The listing decides nothing, so the same spend buys a fresher column in a report and no correctness at all.
|
|
110
|
-
|
|
111
|
-
`canon pr key-changes` also stays on the object, for a different reason. It reads the body and the head off one pull read, so the two describe one commit. That is a consistency requirement rather than a freshness one, and keying its head elsewhere would break it. The file list comes off a second read, since only GraphQL returns it beside the body and a cloud session's proxy refuses GraphQL.
|
package/docs/agents/pr-tick.md
DELETED
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: The pull request checklist tick
|
|
3
|
-
description: How canon pr tick marks the checklist boxes a UI pass drove, the stamp that names the commit each passed at, why a render at a newer head clears a tick, the refusal reasons it names, and why a taste box is never ticked
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# The pull request checklist tick
|
|
7
|
-
|
|
8
|
-
`canon pr tick` ticks the boxes of the visual checklist on the pull request's
|
|
9
|
-
evidence comment. `review-ui` calls it once its verdict has posted, for every
|
|
10
|
-
box that passed at the head it drove, so the person merging reads a checklist
|
|
11
|
-
a driver worked through instead of one that stays empty.
|
|
12
|
-
|
|
13
|
-
```bash
|
|
14
|
-
canon pr tick 1341 --boxes 1,2,4 --head <sha> --json
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
Box numbers come from the `boxes` field of `canon pr evidence --json`, which
|
|
18
|
-
numbers the checklist's box lines in order. A caller never counts lines itself.
|
|
19
|
-
|
|
20
|
-
## What a tick looks like
|
|
21
|
-
|
|
22
|
-
A ticked box ends in the commit it passed at, visible on the comment:
|
|
23
|
-
|
|
24
|
-
```markdown
|
|
25
|
-
- [x] click "Pricing" in the header → the pricing page opens · passed at `<short-sha>`
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
The stamp is visible rather than an HTML comment because the person it is for
|
|
29
|
-
reads the merge record, and a hidden head would tell the machine what the
|
|
30
|
-
reader cannot see. The reader matches the stamp only as the trailing segment of
|
|
31
|
-
a line, so a box whose own text says `passed at` is left alone.
|
|
32
|
-
|
|
33
|
-
## When a tick is cleared
|
|
34
|
-
|
|
35
|
-
A tick is a claim about one commit, so a render at another commit does not
|
|
36
|
-
carry it forward. `canon pr evidence` settles the checklist before it renders:
|
|
37
|
-
|
|
38
|
-
- A tick stamped for the render's head stays.
|
|
39
|
-
- A tick stamped for any other head is cleared and loses its stamp.
|
|
40
|
-
- A tick with no stamp, such as one an author or the operator added by hand,
|
|
41
|
-
stays only when the comment it came from described the render's head.
|
|
42
|
-
|
|
43
|
-
A render at the same head after `--preview` keeps every tick. A push that
|
|
44
|
-
reaches the branch without a render leaves its ticks in place until the next
|
|
45
|
-
one, and the stamp still shows which head earned them.
|
|
46
|
-
|
|
47
|
-
## What it refuses
|
|
48
|
-
|
|
49
|
-
`reason` on the record is what a caller branches on, not the exit code:
|
|
50
|
-
|
|
51
|
-
| Reason | What it means |
|
|
52
|
-
| -------------- | ------------------------------------------------------------------------------------------------------------ |
|
|
53
|
-
| `ticked` | The boxes were ticked, with the remote tip in `head`. |
|
|
54
|
-
| `stale-head` | `--head` is not the branch tip on the remote. Nothing is written. |
|
|
55
|
-
| `taste-box` | A named box ends in `(taste)`. Nothing is written. |
|
|
56
|
-
| `no-box` | A named number is past the end of the checklist. Nothing is written. |
|
|
57
|
-
| `no-checklist` | The evidence comment carries no checklist. |
|
|
58
|
-
| `no-comment` | No comment on the pull request carries the evidence marker. |
|
|
59
|
-
| `bad-boxes` | `--boxes` is not a list of positive whole numbers, or `--head` is not a hex sha of seven characters or more. |
|
|
60
|
-
|
|
61
|
-
A taste box is a judgment of look or feel that a driver reports as needing a
|
|
62
|
-
person's eyes. Refusing it in the verb makes that rule a check rather than a
|
|
63
|
-
sentence a driver can talk itself out of, and a refusal writes none of the
|
|
64
|
-
boxes named beside it.
|
|
65
|
-
|
|
66
|
-
The head is compared against the tip read from the remote rather than the pull
|
|
67
|
-
request object, which lags a push by up to a minute. A push landing between
|
|
68
|
-
that read and the write leaves a tick at an older head until the next render
|
|
69
|
-
clears it, the same window `canon pr head` documents.
|
|
70
|
-
|
|
71
|
-
The verb edits the marked comment in place with a `PATCH`, the way
|
|
72
|
-
`canon pr local --remove` does, and ticking a box again restamps it.
|