@erclx/canon 5.75.0 → 5.76.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/CHANGELOG.md +11 -0
- package/claude/.claude-plugin/plugin.json +1 -1
- package/claude/skills/design-identity/REQUIREMENT.md +1 -1
- package/claude/skills/design-identity/SKILL.md +13 -4
- package/claude/skills/design-identity/references/card-route.md +11 -4
- package/claude/skills/git-issue/REQUIREMENT.md +4 -2
- package/claude/skills/git-issue/SKILL.md +32 -3
- package/claude/skills/git-issue/references/issue.md +7 -0
- package/claude/skills/issue-triage/REQUIREMENT.md +35 -0
- package/claude/skills/issue-triage/SKILL.md +130 -0
- package/claude/skills/role-orchestrator/SKILL.md +1 -1
- package/claude/skills/role-orchestrator/references/orchestrator-handoff.md +1 -1
- package/claude/skills/role-orchestrator/references/orchestrator-poll.md +15 -15
- package/claude/skills/role-orchestrator/scripts/poll.ts +211 -96
- package/claude/skills/role-orchestrator/scripts/repo.ts +53 -1
- package/docs/agents/migrate.md +10 -10
- package/docs/migrations/by-verb.md +8 -4
- package/docs/workflow/ai-workflow.md +1 -1
- package/docs/workflow/skill-map.md +1 -0
- package/package.json +1 -1
- package/src/capture/render.ts +30 -5
- package/src/claude/cases/git.ts +5 -0
- package/src/claude/cases/workflow.ts +4 -0
- package/src/commands/capture.ts +38 -1
- package/src/commands/claude.ts +4 -0
- package/src/markdown/scope.ts +2 -0
- package/src/migrate/session-defaults.ts +36 -8
- package/tooling/claude/seeds/.claude/settings.json +4 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [5.76.0](https://github.com/erclx/canon/compare/v5.75.0...v5.76.0) (2026-10-31)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* **capture:** render light and dark social cards in design-identity ([#2861](https://github.com/erclx/canon/issues/2861)) ([de990f5](https://github.com/erclx/canon/commit/de990f543f7970c04548aa4f793766db5d87b68a))
|
|
9
|
+
* **claude:** allow the exact lease push forms in seeded settings ([#2859](https://github.com/erclx/canon/issues/2859)) ([2f5a6e8](https://github.com/erclx/canon/commit/2f5a6e801e51cefef98f46a7b33b1cd6df7717a3))
|
|
10
|
+
* **orchestrate:** run the review poll in the background until movement ([#2860](https://github.com/erclx/canon/issues/2860)) ([28101da](https://github.com/erclx/canon/commit/28101da96a8ad19e8ded474fad0de15344f4ac41))
|
|
11
|
+
* **skills:** add issue-triage for a repository's open GitHub issues ([#2856](https://github.com/erclx/canon/issues/2856)) ([910372f](https://github.com/erclx/canon/commit/910372fe7026b9e3f5e2b17648a86dd685081acf))
|
|
12
|
+
* **skills:** offer a follow-up on a duplicate issue before filing ([#2857](https://github.com/erclx/canon/issues/2857)) ([ddcbf69](https://github.com/erclx/canon/commit/ddcbf69d5c7cb60242b3d7b0bfb23ffbd4fd858e))
|
|
13
|
+
|
|
3
14
|
## [5.75.0](https://github.com/erclx/canon/compare/v5.74.0...v5.75.0) (2026-10-29)
|
|
4
15
|
|
|
5
16
|
|
|
@@ -17,7 +17,7 @@ A session building this alone restates the render-and-pick loop from scratch, wh
|
|
|
17
17
|
- Every arm is drafted inside the card frame, so one pick settles the mark's shape and its composition together
|
|
18
18
|
- The render, hand-off, pick, and loop follow `design-pick` rather than a copy of it
|
|
19
19
|
- The final mark lands as its own SVG source, not only baked into a raster
|
|
20
|
-
- Every final size and the card
|
|
20
|
+
- Every final icon size renders in one capture call and the card renders once per theme, each landing at its literal target size
|
|
21
21
|
|
|
22
22
|
## Must not
|
|
23
23
|
|
|
@@ -65,6 +65,7 @@ Follow `${CLAUDE_SKILL_DIR}/../design-pick/SKILL.md` Step 1, with the decision f
|
|
|
65
65
|
- Draft each arm inside the 1200x630 card frame, mark and type together, and add it with `frameboard frame add <page>/arm-<id> --width 1200 --height 630`, so one pick settles shape and composition
|
|
66
66
|
- Arm 0 is the current mark when the Step 3 folder already holds a logo file (`favicon.svg`, `favicon.ico`, `logo.svg`, or similar). Arms start at 1 otherwise.
|
|
67
67
|
- Structure every arm as a `.mark` element, the inline SVG alone, nested inside a `.card` element, the full composition, so Step 6 can address either
|
|
68
|
+
- Give every arm a light and a dark set keyed on the `data-theme` attribute, as `design-pick` themes any arm. Step 7 captures the picked card once per theme.
|
|
68
69
|
|
|
69
70
|
## Step 5: draft, render, pick, and loop
|
|
70
71
|
|
|
@@ -94,6 +95,11 @@ The card leaves this batch and takes Step 7 instead. An icon is the mark alone a
|
|
|
94
95
|
|
|
95
96
|
A card captured from a page this run deletes leaves a PNG and nothing that produced it, so renaming the project means another pick loop to move one string. Write the composition into a route the project keeps, and capture it through a running server so it reads the real stylesheet, tokens, and fonts.
|
|
96
97
|
|
|
98
|
+
Both paths write two cards, each captured with `--color-scheme` set to its theme. An `og:image` tag names one URL that every viewer sees whatever their own theme, so only one is wired:
|
|
99
|
+
|
|
100
|
+
- `og-image.png`, the light card, goes into `og:image`, keeping the name an existing tag already points at
|
|
101
|
+
- `og-image-dark.png` stays beside it, so a later switch is a meta tag edit rather than another pick loop
|
|
102
|
+
|
|
97
103
|
This is Astro-shaped for now, because Astro is the one web stack whose config gives a route a structural build exclusion. A project already holding the card route scaffold takes the route path, and everything else takes the page path. Say which one decided, since the two leave the project different things.
|
|
98
104
|
|
|
99
105
|
### The route path
|
|
@@ -102,17 +108,18 @@ Read `${CLAUDE_SKILL_DIR}/references/card-route.md` on reaching this path, for t
|
|
|
102
108
|
|
|
103
109
|
### The page path
|
|
104
110
|
|
|
105
|
-
Where the project holds no route to write into, write `og-image.html`
|
|
111
|
+
Where the project holds no route to write into, write the picked composition into `<dest>/card/` twice, as `og-image.html` and `og-image-dark.html`, each with its `.render` wrapper sized 600x315. A file source names its PNG after the page, so the two names are what land the two cards. Capture each page in its own theme:
|
|
106
112
|
|
|
107
113
|
```bash
|
|
108
|
-
canon capture <dest>/
|
|
114
|
+
canon capture <dest>/card/og-image.html --selector .render --color-scheme light --out <write-folder>
|
|
115
|
+
canon capture <dest>/card/og-image-dark.html --selector .render --color-scheme dark --out <write-folder>
|
|
109
116
|
```
|
|
110
117
|
|
|
111
|
-
|
|
118
|
+
These take their own calls because Step 6's batch is already captured by the time this step picks a path, and one call renders one scheme. Say that the card shipped as a PNG with no source, and that the project gains one when it grows a route to hold the composition.
|
|
112
119
|
|
|
113
120
|
### Closing the scratch folder and the board
|
|
114
121
|
|
|
115
|
-
Delete `<dest>` once
|
|
122
|
+
Delete `<dest>` once the icon and card captures land, then close the board through `design-pick` Step 6 items 3 to 8, which archive every arm and delete the pages the run added. The route is not a leftover variant, since it holds the arm the operator picked.
|
|
116
123
|
|
|
117
124
|
A project whose card was generated before this route existed keeps its PNG. Say so rather than regenerating it, since the pick loop spends attention on a file nobody complained about, and the next real edit picks up the route.
|
|
118
125
|
|
|
@@ -123,9 +130,11 @@ A project whose card was generated before this route existed keeps its PNG. Say
|
|
|
123
130
|
📝 Wrote <write-folder>/icon-16x16.png (16x16)
|
|
124
131
|
📝 Wrote card-src/pages/og-card.astro (route path only)
|
|
125
132
|
📝 Wrote <write-folder>/og-image.png (1200x630)
|
|
133
|
+
📝 Wrote <write-folder>/og-image-dark.png (1200x630)
|
|
126
134
|
|
|
127
135
|
Write folder: <tier that decided>. Move the files if this project's own convention differs.
|
|
128
136
|
Card source: <the route, captured through the card server|a scratch page, since this project holds no card route>.
|
|
137
|
+
Wire og-image.png into og:image. The dark card stays beside it for a later switch.
|
|
129
138
|
```
|
|
130
139
|
|
|
131
140
|
## What this delegates
|
|
@@ -29,16 +29,23 @@ Never run that sync to obtain the route, since it writes the stack's configs bes
|
|
|
29
29
|
|
|
30
30
|
## Writing and capturing the route
|
|
31
31
|
|
|
32
|
-
1. Write the
|
|
32
|
+
1. Write the arm's `.card` markup into the route's `.card` and its `[data-theme]` rules into the route's `<style>`, leaving the rest of the route alone.
|
|
33
33
|
2. Keep the element at 600x315, half the 1200x630 target, since the capture's 2x scale factor is fixed and a 1200x630 element captures at 2400x1260.
|
|
34
34
|
3. Start the card server in the background with `bun run card:dev` and read the port off its own output.
|
|
35
|
-
4. Capture the route, naming
|
|
36
|
-
5. Stop the server. Report the dimensions `canon capture` printed, confirming 1200x630.
|
|
35
|
+
4. Capture the route twice while the server is up, once per theme, naming each destination PNG rather than a directory, which is what a URL source takes for `--out`.
|
|
36
|
+
5. Stop the server. Report the dimensions `canon capture` printed for both cards, confirming 1200x630.
|
|
37
37
|
|
|
38
38
|
```bash
|
|
39
|
-
canon capture http://localhost:<port>/og-card --selector .card --out <write-folder>/og-image.png
|
|
39
|
+
canon capture http://localhost:<port>/og-card --selector .card --color-scheme light --out <write-folder>/og-image.png
|
|
40
|
+
canon capture http://localhost:<port>/og-card --selector .card --color-scheme dark --out <write-folder>/og-image-dark.png
|
|
40
41
|
```
|
|
41
42
|
|
|
43
|
+
The two captures differ only where something keys a second theme:
|
|
44
|
+
|
|
45
|
+
- The scaffold's `.card` reads two color properties a stylesheet may set for one theme only, so the arm's rules from step 1 give the dark capture its dark set
|
|
46
|
+
- `--color-scheme` writes the theme onto the route's root after it loads, so rules keyed on `data-theme`, a class, or the media query all answer to it
|
|
47
|
+
- With no second set in the arm or the stylesheet, the PNGs match. Compare the image digests in their `.stamp` files, and on a match say the project got one card twice.
|
|
48
|
+
|
|
42
49
|
### Port and font refusals
|
|
43
50
|
|
|
44
51
|
The card server runs under a strict port, so it refuses rather than walking to the next free one. Where something already holds that port, set `WORKTREE_PORT_OFFSET` by hand and start it again.
|
|
@@ -17,16 +17,18 @@ Prose bans hold on files the hook watches and not on text leaving through `gh`,
|
|
|
17
17
|
- Each issue carries exactly one label mapped from its type, asked once when the type is ambiguous between a bug and a task
|
|
18
18
|
- A remote and an authenticated `gh` are confirmed before any body is composed
|
|
19
19
|
- The body passes through a file that is removed afterward
|
|
20
|
+
- Open issues are searched for the same defect before a body is composed, and a match is offered as a comment in place of a new issue
|
|
20
21
|
|
|
21
22
|
## Must not
|
|
22
23
|
|
|
23
24
|
- Invent an issue from a thin session
|
|
24
25
|
- File anywhere other than the current origin
|
|
25
26
|
- Open a pull request
|
|
26
|
-
- Emit anything after the result
|
|
27
|
+
- Emit anything after the result lines
|
|
28
|
+
- Comment on an existing issue without a yes given for that issue
|
|
27
29
|
|
|
28
30
|
## Out of scope
|
|
29
31
|
|
|
30
32
|
- Reporting a toolkit defect from a target project, which `canon-feedback` owns
|
|
31
|
-
- Triaging
|
|
33
|
+
- Triaging a repository's open issues, which `issue-triage` owns
|
|
32
34
|
- Opening a pull request, which `git-pr` owns
|
|
@@ -27,7 +27,34 @@ Then gather repo context in parallel:
|
|
|
27
27
|
- If nothing in session context describes a concrete bug or task, stop: `❌ No issue in session context. Describe the bug or task, then re-invoke.`
|
|
28
28
|
- If `git remote get-url origin` returns `NO_REMOTE`, stop: `❌ No GitHub remote. gh issue create needs an origin.`
|
|
29
29
|
- If `gh auth status` returns `NO_AUTH`, stop: `❌ gh is not authenticated. Run gh auth login.`
|
|
30
|
-
- If the type is ambiguous between a bug and a task, ask one line before formatting.
|
|
30
|
+
- If the type is ambiguous between a bug and a task, ask one line before formatting, after the duplicate question below.
|
|
31
|
+
|
|
32
|
+
## Duplicate check
|
|
33
|
+
|
|
34
|
+
Search the open issues before composing anything, since a duplicate costs the repository's triage a second item and a second answer.
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
gh issue list --state open --search "<keywords> in:title,body" --limit 5 --json number,title,url
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
- Take keywords from the defect's distinctive terms, such as a command or a path, and quote one holding a colon or a space
|
|
41
|
+
- Keep a candidate only when it describes the same defect, reading its body with `gh issue view <NNN> --json body` when the title leaves it open
|
|
42
|
+
- With none kept, go to the preview and file a new issue
|
|
43
|
+
- With one or more kept, ask once whether to add the findings to one of them as a comment or file a new issue, naming each by number and title
|
|
44
|
+
- With no one to answer, as in a headless run, file nothing and name each kept candidate, since a new issue there is the duplicate this check exists to stop
|
|
45
|
+
|
|
46
|
+
### Comment on the match
|
|
47
|
+
|
|
48
|
+
On a yes for an issue, write the comment in the `### Follow-up` shape `${CLAUDE_SKILL_DIR}/references/issue.md` gives, run the pre-publish scan below over it, then post it in place of the final command. Post nothing on any issue the answer did not name.
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
mkdir -p .canon/tmp/issue
|
|
52
|
+
cat <<'BODY' > .canon/tmp/issue/comment.md
|
|
53
|
+
<comment following the Follow-up section>
|
|
54
|
+
BODY
|
|
55
|
+
gh api -X POST 'repos/{owner}/{repo}/issues/<NNN>/comments' -F body=@.canon/tmp/issue/comment.md --jq .html_url
|
|
56
|
+
rm -rf .canon/tmp/issue
|
|
57
|
+
```
|
|
31
58
|
|
|
32
59
|
## Response format
|
|
33
60
|
|
|
@@ -63,6 +90,8 @@ rm -rf .canon/tmp/issue
|
|
|
63
90
|
|
|
64
91
|
## After execution
|
|
65
92
|
|
|
66
|
-
Respond with
|
|
93
|
+
Respond with the one line for what was posted:
|
|
67
94
|
|
|
68
|
-
`✅ Issue: <url>`
|
|
95
|
+
- A new issue: `✅ Issue: <url>`
|
|
96
|
+
- A comment on a match: `✅ Commented: <url>`
|
|
97
|
+
- Nothing, with candidates kept and nobody to ask: `⏸️ Not filed. Possible duplicate:`, then one line per candidate as `#<NNN> <title>`
|
|
@@ -55,6 +55,13 @@ A bug or task body carries up to four `##` sections, in this order.
|
|
|
55
55
|
- `## Context`: for a bug, repro steps or commands. For a task, the driving reason, or `none`.
|
|
56
56
|
- `## Proposed` (optional): one line naming a fix or approach. Omit when open.
|
|
57
57
|
|
|
58
|
+
### Follow-up
|
|
59
|
+
|
|
60
|
+
A comment on an open issue carries what the session adds and nothing the issue already says.
|
|
61
|
+
|
|
62
|
+
- `## Follow-up`: one line naming what is new, such as a second instance, a repro, or a narrowed cause.
|
|
63
|
+
- `## Details`: the observed behavior and the command or path that shows it.
|
|
64
|
+
|
|
58
65
|
### Feedback
|
|
59
66
|
|
|
60
67
|
One `## Toolkit feedback` wrapper holds every field as a nested `###` heading. A flat `##` field is not recognized.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: issue-triage
|
|
3
|
+
description: Why a repository's open issues are filed as measured intake items rather than routed or fixed from the issue text, and why one pass is capped
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Issue triage requirement
|
|
7
|
+
|
|
8
|
+
## Gap
|
|
9
|
+
|
|
10
|
+
Without this skill, a repository's issue queue fills and nothing drains it into decisions. An issue reads as a request, so a session routes it straight to a fix from a paragraph and skips the scope argument.
|
|
11
|
+
|
|
12
|
+
Triage done by hand fails three ways. A self-contradicting report gets a guess instead of a question. The same issue gets filed twice because two passes cannot see the board carries it. A queue of hundreds files in one pass that no answering session can get through.
|
|
13
|
+
|
|
14
|
+
## Must
|
|
15
|
+
|
|
16
|
+
- Read the queue through the `gh` CLI, and stop when it is absent, unauthenticated, or the checkout has no GitHub repository
|
|
17
|
+
- File one measured item per kept issue into a folder the CLI claimed, headed so an answer finds its issue, and name each skipped issue with its carrier
|
|
18
|
+
- Measure each claim in an issue's body and comments against the tree rather than carrying the issue's figures forward
|
|
19
|
+
- Cap one pass, oldest first, and name what was left over rather than reading a capped queue as drained
|
|
20
|
+
- Report an empty queue as nothing open rather than widening the label to find work
|
|
21
|
+
|
|
22
|
+
## Must not
|
|
23
|
+
|
|
24
|
+
- Post to the remote, whether a comment, a close, or a label
|
|
25
|
+
- Implement a fix or write a plan
|
|
26
|
+
- Fill an answer slot, or read an empty one as agreement
|
|
27
|
+
- Write outside the folder it claimed
|
|
28
|
+
- Carry a step only one repository's queue needs, such as stripping a reporting project's specifics, since a caller wrapping this skill adds those around it
|
|
29
|
+
|
|
30
|
+
## Out of scope
|
|
31
|
+
|
|
32
|
+
- Opening a new issue, which `git-issue` owns
|
|
33
|
+
- Answering the filed items, which `plan-intake-answer` owns
|
|
34
|
+
- Writing the plan a plan-worthy item needs, which `plan-feature` owns
|
|
35
|
+
- Pruning the task backlog, which `backlog-triage` owns
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: issue-triage
|
|
3
|
+
description: Files the open GitHub issues on the current repository into an intake folder as one measured item each, narrowed by an optional label, capped per pass, and skipping any issue the board already carries. Use when asked to "triage the issues", "work through the open issues", "file the GitHub issues", "triage the bug label", or "what issues are open". Do NOT use to open a new issue, which is `git-issue`, to answer the filed items, which is `plan-intake-answer`, or to triage the task backlog, which is `backlog-triage`.
|
|
4
|
+
metadata:
|
|
5
|
+
family: decide
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Issue triage
|
|
9
|
+
|
|
10
|
+
An issue queue only grows while nothing reads it against the tree. This pass measures each open issue and files it as one item for the operator, who answers it before anything is built.
|
|
11
|
+
|
|
12
|
+
The record is an ordinary intake folder at `.canon/intake/<nn>-<slug>-triage/`. Read `${CLAUDE_SKILL_DIR}/../plan-intake/references/intake.md` before writing any file in it, since it holds the item format, the frontmatter, the index shape, and the answer contract this skill is bound by.
|
|
13
|
+
|
|
14
|
+
- Read GitHub issues and write only inside the claimed folder, posting no comment, close, or label to GitHub
|
|
15
|
+
- Measure each issue against this repository, since the repository it was filed on is the one its fix lands in
|
|
16
|
+
|
|
17
|
+
## Arguments
|
|
18
|
+
|
|
19
|
+
Both are optional and come in either order.
|
|
20
|
+
|
|
21
|
+
- A label narrows the queue to issues carrying it. With none, every open issue is in the queue and the slug is `issue`.
|
|
22
|
+
- A label sets the slug too, lowercased with each run of other characters made one hyphen, so `good first issue` gives `good-first-issue`. Pass the raw label, quoted, to `--label`.
|
|
23
|
+
- A number sets the cap, the most issues one pass files. With none, the cap is 25, about what one answering session gets through.
|
|
24
|
+
|
|
25
|
+
## Guards
|
|
26
|
+
|
|
27
|
+
- Resolve `.canon/tasks/` and `.canon/intake/` at the main worktree root, from `git worktree list --porcelain | grep -m 1 '^worktree ' | cut -d' ' -f2-`, falling back to `pwd` outside git
|
|
28
|
+
- If `gh` is not on PATH, stop: `❌ gh CLI not found. Install it to read the issue queue.`
|
|
29
|
+
- If `gh auth status` fails, stop: `❌ gh is not authenticated. Run gh auth login.`
|
|
30
|
+
- If `gh repo view --json nameWithOwner` fails, stop: `❌ No GitHub repository here. Run from a checkout with a GitHub remote.`
|
|
31
|
+
- If no open issue matches, stop: `✅ No open issues.`
|
|
32
|
+
|
|
33
|
+
### Slots and records
|
|
34
|
+
|
|
35
|
+
Two more guards hold through every step.
|
|
36
|
+
|
|
37
|
+
- Never fill a `You:` slot, and never read an empty one as agreement. Answering runs through `plan-intake-answer` or the operator's own edit.
|
|
38
|
+
- Branch on each `canon` record's `ok` and `reason` rather than on the exit code, which a shell function wrapping `canon` can flatten to zero.
|
|
39
|
+
|
|
40
|
+
## Step 1: list the queue
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
gh issue list --state open --limit 1000 --search "sort:created-asc" --json number,title
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Add `--label "<label>"` when one was given, and name that label in the empty-queue stop. The list carries no bodies, so a large queue costs a line per issue rather than its whole text.
|
|
47
|
+
|
|
48
|
+
Sorting by creation keeps the oldest issues when the queue passes the limit. When the list returns 1000 rows, the queue may hold more, so Step 3 writes its left-over count as a floor.
|
|
49
|
+
|
|
50
|
+
## Step 2: drop what the board already carries
|
|
51
|
+
|
|
52
|
+
An issue is carried when its number appears in a live or archived task's `Issue:` line under `.canon/tasks/`, or in an item heading of an existing `.canon/intake/` folder, written `(#NNN)`. Search both at the main root.
|
|
53
|
+
|
|
54
|
+
Set each carried issue aside with its carrier, a task path or a folder and item.
|
|
55
|
+
|
|
56
|
+
- Name every one in the overview, so a re-run while an earlier folder sits unanswered files nothing twice
|
|
57
|
+
- Read its comments with `gh issue view <NNN> --json comments`, and name their count and newest date beside its carrier, so a follow-up posted after the carrier was filed is seen
|
|
58
|
+
- File no item for a comment on a carried issue, since an item would file the issue twice against a live task
|
|
59
|
+
|
|
60
|
+
When every issue is carried, stop: `✅ Every open issue is already on the board.`
|
|
61
|
+
|
|
62
|
+
## Step 3: apply the cap
|
|
63
|
+
|
|
64
|
+
Sort the remaining issues by number, oldest first, and keep the first issues up to the cap, so the reports that waited longest drain first. Count the issues past the cap as left over, and name them in the overview and the output.
|
|
65
|
+
|
|
66
|
+
- Give the count and the lowest number left over, so a drained queue and a capped one never read the same
|
|
67
|
+
- Write the count as `at least <n>` when Step 1 hit its limit
|
|
68
|
+
|
|
69
|
+
Then read each kept issue whole, since a follow-up posted as a comment is part of the report:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
gh issue view <NNN> --json number,title,body,labels,comments
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Step 4: claim the folder
|
|
76
|
+
|
|
77
|
+
Run `canon records ordinal intake <slug>-triage --claim --json` and take its `name`. The verb creates the folder in the same act, so two sessions opening at once never share one. Where the installed binary carries no such subcommand, report it and stop rather than picking an ordinal by hand.
|
|
78
|
+
|
|
79
|
+
## Step 5: measure each issue
|
|
80
|
+
|
|
81
|
+
For each kept issue, measure its claim against the tree during this pass, never carrying a figure from the issue forward, since it states what was true when filed.
|
|
82
|
+
|
|
83
|
+
Measure each comment's claim the same way, whoever posted it, and fold it into the issue's one item rather than filing a second. When a comment contradicts the body, measure the later claim and name the comment as the source on `Problem:`.
|
|
84
|
+
|
|
85
|
+
- Grep for the construct its defect names and count the sites
|
|
86
|
+
- Check whether the behavior it asks for exists
|
|
87
|
+
- Search the log for a commit or pull request that shipped it under another task
|
|
88
|
+
- Run the issue's repro in a form that writes nothing when it is one command that works here, and say on `Problem:` what it showed
|
|
89
|
+
- Mark the item `not reproduced here` when the repro needs more, per `## Repro versus groundwork` in the intake standard
|
|
90
|
+
|
|
91
|
+
Classify each against this repository's own surfaces:
|
|
92
|
+
|
|
93
|
+
- **Direct fix.** A size, not an answer, so it suggests `plan` and `Fix:` says a short plan covers it. One surface, one file, no architectural choice. A typo, a stale reference, a one-line correction.
|
|
94
|
+
- **Plan-worthy.** Multiple files, a new module or command, a behavior change, or a cross-surface move.
|
|
95
|
+
- **Needs clarification.** The observed and expected behavior conflict or the surface is unnamed. The item asks the operator for the missing detail.
|
|
96
|
+
|
|
97
|
+
Name the commit the pass measured against in the overview.
|
|
98
|
+
|
|
99
|
+
## Step 6: write the items
|
|
100
|
+
|
|
101
|
+
Write one item per issue in the intake item format, one cluster file per domain the fix touches, numbered in read order. Head each item `### N. <defect> (#NNN)` so an answer finds its issue.
|
|
102
|
+
|
|
103
|
+
- `Problem:` states what this pass measured, with the count, path, or commit behind it
|
|
104
|
+
- `Fix:` states the class from Step 5 and the change it names
|
|
105
|
+
- `Open:` reads `plan, ask, or decline?` on every item
|
|
106
|
+
- `Suggested:` opens with exactly one of those tokens, then the reason
|
|
107
|
+
- `You:` ships empty
|
|
108
|
+
|
|
109
|
+
Write `00-overview.md` last, per the intake standard. It carries the counts by token, an open-questions list linking each item, the commit measured against, every issue skipped in Step 2 with its carrier, and the left-over count from Step 3. Where the pass runs out of context before the index, write `99-next-session.md` naming the last issue filed.
|
|
110
|
+
|
|
111
|
+
## Output
|
|
112
|
+
|
|
113
|
+
```plaintext
|
|
114
|
+
📂 Opened .canon/intake/<nn>-<slug>-triage/
|
|
115
|
+
|
|
116
|
+
**Filed:** <N> issues across <N> clusters, measured against <sha>
|
|
117
|
+
**Skipped:** <n> already carried
|
|
118
|
+
**Left over:** <n> past the cap of <cap>, from #<lowest>
|
|
119
|
+
**Suggested:** <n> plan, <n> ask, <n> decline
|
|
120
|
+
|
|
121
|
+
Next: /canon:plan-intake-answer to answer the `You:` slots
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Drop the `Left over:` line when nothing was past the cap.
|
|
125
|
+
|
|
126
|
+
An answered plan item promotes through `task-board` with an `Issue: #NNN` line, and the shipping pull request's `Closes #NNN` drains the queue. This skill still closes nothing. `plan-intake-answer` offers the close of a declined issue when the decline is answered, and the operator's yes posts it.
|
|
127
|
+
|
|
128
|
+
## Notes
|
|
129
|
+
|
|
130
|
+
- This skill files and never reimplements. `plan-intake-answer` owns the answers and `task-board` owns the task a plan item becomes.
|
|
@@ -48,7 +48,7 @@ The human asks for each side of a compaction, and this skill reads the runbook.
|
|
|
48
48
|
|
|
49
49
|
### The poll and the parked rows
|
|
50
50
|
|
|
51
|
-
The review trigger takes the same shape. `references/orchestrator-poll.md` holds the
|
|
51
|
+
The review trigger takes the same shape. `references/orchestrator-poll.md` holds the background start, the routing, and the condition, and `scripts/poll.ts --wait` is the command it runs. No hook starts or stops that poll, so the condition holds only while whoever holds it applies it.
|
|
52
52
|
|
|
53
53
|
A board that is not moving is a third such moment. On a request to re-test the parked rows, follow `${CLAUDE_SKILL_DIR}/references/orchestrator-parked.md`, which re-tests every blocker and backlog row against the tree and plans what it clears. The refill sweep fires on a merge instead.
|
|
54
54
|
|
|
@@ -69,7 +69,7 @@ Settle all three steps below before the door writes, so one write carries the co
|
|
|
69
69
|
|
|
70
70
|
Resume by loading the orchestrator skill and asking it to resume after a compaction. This repository spells that `/canon:role-orchestrator` followed by the request. Following <RESUME_RUNBOOK> reaches the same place with no skill loaded at all.
|
|
71
71
|
|
|
72
|
-
That resume reads the board and stops. It restarts nothing, so the review poll is a second thing owed here, and <POLL_RUNBOOK> holds the
|
|
72
|
+
That resume reads the board and stops. It restarts nothing, so the review poll is a second thing owed here, and <POLL_RUNBOOK> holds the background start and the condition. Do not reach for `session-resume`, which reads tracked work and reports the newest map without restarting this poll.
|
|
73
73
|
```
|
|
74
74
|
|
|
75
75
|
### What the decisions section leaves out
|
|
@@ -23,28 +23,28 @@ The script reads pull requests and a building worker has none, so every interval
|
|
|
23
23
|
|
|
24
24
|
### Who starts and stops it
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
The orchestrator starts the poll on that condition and stops re-arming it on the same test, without waiting for the operator. A runbook stating only the start leaves the always-on failure unaddressed on the side that causes it.
|
|
27
27
|
|
|
28
|
-
- Nothing enforces this. No hook starts the poll and no check stops it, so the condition holds only while the
|
|
29
|
-
-
|
|
30
|
-
- The poll is session-scoped and dies with its session, so restart it after a compaction, taking the
|
|
31
|
-
|
|
32
|
-
### Editing the prompt
|
|
33
|
-
|
|
34
|
-
A running loop holds whatever wording it was started with, and a scheduled prompt cannot be edited, so every routing fix is a cancel and a re-create. Three fixes made inside one session once reached the running loop and none reached this file.
|
|
35
|
-
|
|
36
|
-
Edit the block here first and re-create the loop from what this file then says. Rewriting the block from memory drops what the shipped one covered, which is how a `SEEN` report once fell through to no rule at all.
|
|
28
|
+
- Nothing enforces this. No hook starts the poll and no check stops it, so the condition holds only while the session holding it applies it.
|
|
29
|
+
- Stop it at once by stopping that background command, or let the running wait end and start no other
|
|
30
|
+
- The poll is session-scoped and dies with its session, so restart it after a compaction, taking the routing from this file rather than a transcript
|
|
37
31
|
|
|
38
32
|
## The prompt
|
|
39
33
|
|
|
40
|
-
|
|
34
|
+
Start the poll in the background, act on what it prints when it exits by the block below, then start it again. It reads every 180 seconds by itself and exits on movement, so an idle board costs no turn and no message queues behind a run. The block is read on every wake, so edit it here and never from memory.
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
bun <POLL_SCRIPT> --wait 1200
|
|
38
|
+
```
|
|
41
39
|
|
|
42
|
-
-
|
|
43
|
-
-
|
|
44
|
-
-
|
|
40
|
+
- Run it with the client's background option, `run_in_background` here, and start the next one as the last step of every wake, a `No movement.` at the cap included
|
|
41
|
+
- A failed read, of one pull request or the open list, holds to the cap with its `poll:` lines rather than spinning the restart
|
|
42
|
+
- Start with `--wait 180` while a cloud reviewer holds a pull request, since the rule below reads its pass once per wake
|
|
43
|
+
- Paste the absolute path of `${CLAUDE_SKILL_DIR}/scripts/poll.ts` for `<POLL_SCRIPT>`, since the variable expands only while this runbook renders
|
|
44
|
+
- Add `--no-record` to time or inspect a run without writing the baseline, and a client with no background command schedules a plain run every three minutes instead
|
|
45
45
|
|
|
46
46
|
```plaintext
|
|
47
|
-
|
|
47
|
+
Act on what the poll printed when it exited, then start it again.
|
|
48
48
|
|
|
49
49
|
- A release pull request, whatever state follows it: report it and stop. Its sweep carries no findings, so no pass is owed. Test this before any rule below, since a release pull request is reported OPENED like any other and would otherwise match that rule first.
|
|
50
50
|
- MOVED or RESPONSE on a pull request already reviewed: when a live local reviewer holds it, report it and stop, since the worker asks that reviewer for the re-review directly. When none does, which a cloud reviewer always leaves, launch a fresh reviewer under the review dispatch runbook of the canon:role-orchestrator skill. Never run the canon:review-pr skill here. Re-reviews read prior..head and gain nothing from waiting.
|