@erclx/canon 4.104.0 → 4.106.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/draft-identity/SKILL.md +84 -9
- package/claude/skills/role-planner/REQUIREMENT.md +14 -7
- package/claude/skills/role-planner/SKILL.md +56 -53
- package/claude/skills/role-worker/SKILL.md +12 -4
- package/claude/skills/session-relay/REQUIREMENT.md +44 -17
- package/claude/skills/session-relay/SKILL.md +83 -14
- package/docs/agents/tasks.md +14 -10
- package/docs/workflow/ai-workflow.md +9 -9
- package/docs/workflow/visual-design-workflow.md +1 -1
- package/governance/rules/ui/410-a11y.md +5 -0
- package/governance/rules/ui/440-surface-capture.md +7 -1
- package/package.json +1 -1
- package/src/claude/cases/workflow.ts +1 -1
- package/src/commands/tasks.ts +1 -0
- package/src/design/document.ts +2 -0
- package/src/design/tokens.ts +4 -0
- package/src/gate/measures.ts +28 -5
- package/src/tasks/archive.ts +77 -10
- package/src/tasks/validate.ts +68 -0
- package/standards/design.md +1 -1
- package/tooling/astro/configs/card-src/pages/og-card.astro +98 -0
- package/tooling/astro/configs/card.config.mjs +39 -0
- package/tooling/astro/configs/scripts/check-card-exclusion.sh +58 -0
- package/tooling/astro/manifest.toml +3 -0
- package/tooling/astro/reference.md +27 -0
- package/tooling/web/configs/scripts/verify.sh +9 -0
- package/tooling/web/reference.md +4 -2
|
@@ -38,7 +38,24 @@ Announce which of the two decided the sequence.
|
|
|
38
38
|
|
|
39
39
|
## Step 3: detect the write folder
|
|
40
40
|
|
|
41
|
-
|
|
41
|
+
A root-only check finds a project's assets only where the project keeps them at the root. A repository holding its site in a subfolder keeps them a level down, and a Next project keeps its favicon under the App Router convention with no `public/` at all, so both fall through to the root fallback while the announcement reads as a detected folder. Walk one level down and know that convention rather than falling through.
|
|
42
|
+
|
|
43
|
+
Read both, from the project root:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
find . -maxdepth 3 \( -name node_modules -o -name .git -o -name dist -o -name .astro \) -prune -o -type d \( -name public -o -name static \) -print | sort
|
|
47
|
+
find . -maxdepth 4 \( -name node_modules -o -name .git \) -prune -o -type d -path '*/src/app' -print | sort
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Take the first tier that answers:
|
|
51
|
+
|
|
52
|
+
1. A root `public/` or `static/`.
|
|
53
|
+
2. A `public/` or `static/` one level down, such as `web/public/`. Where the first read returns more than one, take the shallowest, and the one whose parent holds the project's own framework config where two sit at the same depth.
|
|
54
|
+
3. A `src/app/` folder, at the root or one level down, which is the Next App Router convention and where that framework's own favicon and card files sit. Take the folder itself, not a `public/` beside it.
|
|
55
|
+
4. A stack-declared asset folder, where the project's own config names one.
|
|
56
|
+
5. The project root, which is the fallback rather than a detection.
|
|
57
|
+
|
|
58
|
+
Announce which tier decided, naming the tier rather than the path alone. On tier 5 say the detection found nothing and the root is a fallback, since a folder reported without that word reads as a folder the project declared. Announce it either way so the operator can move the files where the project's own convention differs.
|
|
42
59
|
|
|
43
60
|
## Step 4: name the decision and the arms
|
|
44
61
|
|
|
@@ -50,14 +67,12 @@ Structure every arm as a `.mark` element, the inline SVG alone, nested inside a
|
|
|
50
67
|
|
|
51
68
|
Follow `${CLAUDE_SKILL_DIR}/../draft-and-pick/SKILL.md` Steps 2 through 5 against the arms from Step 4: author the page, render and hand off, take the pick, and loop on it.
|
|
52
69
|
|
|
53
|
-
## Step 6: finalize
|
|
70
|
+
## Step 6: finalize the mark and the icons
|
|
54
71
|
|
|
55
|
-
This step
|
|
72
|
+
This step and Step 7 replace `draft-and-pick`'s own Step 6, since the pick here produces several final files rather than one applied surface.
|
|
56
73
|
|
|
57
74
|
1. Extract the picked arm's `.mark` markup as the final vector source. Write it to `<write-folder>/favicon.svg`.
|
|
58
|
-
2. Under `<dest>/render/`, write one page per Step 2 size
|
|
59
|
-
- `icon-<w>x<h>.html`: the picked `.mark` markup, its `.render` wrapper sized `<w>/2` by `<h>/2`
|
|
60
|
-
- `og-image.html`: the picked `.card` markup, its `.render` wrapper sized 600x315 to capture at the native 1200x630
|
|
75
|
+
2. Under `<dest>/render/`, write one `icon-<w>x<h>.html` page per Step 2 size, carrying the picked `.mark` markup. Give every page's captured element the shared class `.render`, so one capture call renders the whole batch regardless of the size spread. `canon capture` opens every page at a fixed 2x device scale factor and screenshots the element at that scale, so declare each `.render` element at half its target dimension, `<w>/2` by `<h>/2`, to land the captured PNG on the literal target size rather than double it. Declare a machine-resolved font stack (`system-ui` behind a generic fallback) on each, since `canon capture` refuses a page naming no font at all.
|
|
61
76
|
3. Render the batch:
|
|
62
77
|
|
|
63
78
|
```bash
|
|
@@ -65,16 +80,75 @@ This step replaces `draft-and-pick`'s own Step 6, since the pick here produces s
|
|
|
65
80
|
```
|
|
66
81
|
|
|
67
82
|
4. Report each written file's path and the dimensions `canon capture` printed for it, confirming each equals its Step 2 target rather than half of it.
|
|
68
|
-
|
|
83
|
+
|
|
84
|
+
The card leaves this batch and takes Step 7 instead. An icon is the mark alone at a fixed size and a scratch page renders it faithfully, where the card is a composition of the mark with the project's own type and color and a scratch page can only carry typed copies of both.
|
|
85
|
+
|
|
86
|
+
## Step 7: write the card as a route and capture it through the server
|
|
87
|
+
|
|
88
|
+
A card captured from a page this run deletes leaves the project a PNG and nothing that produced it, so renaming the project means another pass through the pick loop with an operator in it to move one string. Write the composition into a route the project keeps, and capture that route through a running server so it reads the project's real stylesheet, tokens and fonts.
|
|
89
|
+
|
|
90
|
+
This is Astro-shaped in v1, 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 falls to the page path below. Say which one decided, since the two leave the project different things.
|
|
91
|
+
|
|
92
|
+
### The route path
|
|
93
|
+
|
|
94
|
+
1. Check that the project already holds the scaffold, being a `card.config.mjs` with a `card-src/pages/og-card.astro` beside it. Take the page path below where either is missing, and leave the install to the operator:
|
|
95
|
+
|
|
96
|
+
```plaintext
|
|
97
|
+
No card route installed, so the card shipped as a PNG this run.
|
|
98
|
+
`canon tooling sync astro . --write` installs the route, and it replaces every other
|
|
99
|
+
golden config in the astro stack, so run it when you mean to sync the stack.
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Never run that sync to obtain the route. It copies the whole stack over the project's own framework, lint, typescript, and test configs, which is a cost nobody asking for a logo agreed to. Hand-writing the scaffold instead is the other wrong answer, since a copy written here drifts from the one the stack maintains.
|
|
103
|
+
|
|
104
|
+
The scaffold is a second framework config pointing `srcDir` at a folder beside `src/`, the route inside that folder importing the project's global stylesheet and carrying a fixed `<meta>` marker, and a shell check failing a build that carries the marker. Of the route's three consumers, the published build is the only one a check reaches. Read the shape with `canon tooling reference astro`.
|
|
105
|
+
|
|
106
|
+
2. Write the picked arm's `.card` markup into the route's `.card` element, leaving the marker, the stylesheet import and the surrounding document alone. Keep the element at 600x315, half of the 1200x630 target, since the capture's 2x scale factor is fixed and a 1200x630 element captures at 2400x1260.
|
|
107
|
+
|
|
108
|
+
3. Start the card server in the background and read the port off its own output:
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
bun run card:dev
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
It serves under a strict port, so it refuses rather than walking to the next free one. Set `WORKTREE_PORT_OFFSET` by hand and start it again where something already holds that port.
|
|
115
|
+
|
|
116
|
+
4. Capture the route to the write folder, naming the destination PNG rather than a directory, which is what a URL source takes for `--out`:
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
canon capture http://localhost:<port>/og-card --selector .card --out <write-folder>/og-image.png
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
5. Stop the server. Report the dimensions `canon capture` printed, confirming 1200x630.
|
|
123
|
+
|
|
124
|
+
A refusal naming a font here is the mechanism working rather than a failure to route around. It says the route asked for a family the machine cannot resolve, which is the same rewrap a published card would have shipped silently.
|
|
125
|
+
|
|
126
|
+
### The page path
|
|
127
|
+
|
|
128
|
+
Where the project holds no route to write into, write `og-image.html` into `<dest>/render/` with its `.render` wrapper sized 600x315, then capture that one page:
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
canon capture <dest>/render/og-image.html --selector .render --out <write-folder>
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
It takes its own call rather than riding Step 6's batch, since Step 6 runs before this step chooses a path and the batch is already captured by the time the choice is made. 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.
|
|
135
|
+
|
|
136
|
+
### Closing the scratch folder
|
|
137
|
+
|
|
138
|
+
Delete `<dest>` per `draft-and-pick`'s own scratch-folder rule. The route is not a leftover variant that rule forbids: a variant is one of several candidates none of which was chosen, and the route holds the arm the operator picked. The losing arms are what that rule is about, and they are already archived and deleted by the step it belongs to.
|
|
139
|
+
|
|
140
|
+
A project whose card was generated before this route existed keeps its PNG. Say so rather than regenerating it, since re-running the pick loop spends an operator's attention on a file nobody complained about, and the next real edit to the card picks up the route.
|
|
69
141
|
|
|
70
142
|
## Response format
|
|
71
143
|
|
|
72
144
|
```plaintext
|
|
73
145
|
📝 Wrote <write-folder>/favicon.svg
|
|
74
146
|
📝 Wrote <write-folder>/icon-16x16.png (16x16)
|
|
147
|
+
📝 Wrote card-src/pages/og-card.astro (route path only)
|
|
75
148
|
📝 Wrote <write-folder>/og-image.png (1200x630)
|
|
76
149
|
|
|
77
|
-
Write folder: <
|
|
150
|
+
Write folder: <tier that decided>. Move the files if this project's own convention differs.
|
|
151
|
+
Card source: <the route, captured through the card server|a scratch page, since this project holds no card route>.
|
|
78
152
|
```
|
|
79
153
|
|
|
80
154
|
## What this delegates
|
|
@@ -83,4 +157,5 @@ Cite these rather than restating them.
|
|
|
83
157
|
|
|
84
158
|
- `draft-and-pick` owns Steps 1 through 5 of the render-and-pick loop, cited above
|
|
85
159
|
- `design-extract` owns building `canon/DESIGN.md`. This skill only reads it.
|
|
86
|
-
- `canon capture` owns the render mechanics, its font refusal, and its reported dimensions
|
|
160
|
+
- `canon capture` owns the render mechanics, its font refusal, its fixed 2x scale factor, and its reported dimensions. It already reads an `http(s)://` source, where `--out` names the destination PNG rather than a directory, so the route capture needs nothing added to it.
|
|
161
|
+
- The `astro` tooling stack owns the card route's scaffold, its second config, and the exclusion check, read with `canon tooling reference astro`. This skill writes into the route and never reshapes it.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: role-planner
|
|
3
|
-
description: What a
|
|
3
|
+
description: What a thinking session is across planning, groundwork, and intake, how it reads what is in flight, the writes-records-never-source boundary, and what it hands back to whoever dispatched it
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Role planner requirement
|
|
@@ -49,25 +49,30 @@ four carried at least one, caught only because the planner ran
|
|
|
49
49
|
|
|
50
50
|
## Must
|
|
51
51
|
|
|
52
|
-
- Assert what a
|
|
52
|
+
- Assert what a thinking session is, what it may not write, and how long the role lasts, since `plan-feature`, `plan-groundwork`, and `plan-intake` each carry their own procedure and no body carries the role the three share
|
|
53
|
+
- Cover all three of those skills rather than `plan-feature` alone, since a groundwork or intake session took no role at all while the body was written for one plan under one task
|
|
54
|
+
- State the writes-records-never-source boundary once, and name the three folders in one line while deferring each scope's exceptions to the skill that owns it, so a change to one scope edits one body
|
|
55
|
+
- Carry `plan-groundwork`'s close-time task file as an exception to the board ban, since widening the role without it makes the role forbid what that skill requires
|
|
53
56
|
- State the in-flight read as a command composing the session roster with open pull requests, and say that a branch and a worktree are not evidence, since a count of either reported merged work as live
|
|
54
57
|
- Run that read once per task rather than once per batch, since a reused session ages its picture of the tree while it works
|
|
55
58
|
- Name every read a plan needed and a launch string did not carry, the task file's findings and the source files among them, since a count quoted from a row was wrong or stale in ten places across four plans
|
|
56
59
|
- Name the validate and audit calls the written plan passes through, since nothing else opens a plan and the audit caught ban hits in three of four trial plans
|
|
57
60
|
- State the shared board as read-only and name the cross-feature call as the controller's, since a planner reading blockers and file sets can write a merge order off a partial picture and will not notice that it has
|
|
58
|
-
- Owe an announcement when the
|
|
61
|
+
- Owe an announcement when the record lands, carrying the path and what the row got wrong, since the controller cannot watch the read happen
|
|
59
62
|
- Owe a message before a block becomes an interactive prompt, since a session already waiting on input never reaches the tool round an inbound message drains at
|
|
60
63
|
- Keep correcting the dispatcher a first-class move carrying its evidence, since a trial corrected a brief's premise, planned every row anyway, and carried the consequence into a plan question
|
|
61
|
-
- Point at
|
|
64
|
+
- Point at each of the three skills for its record's shape and the steps that write it
|
|
65
|
+
- Defer the addressee resolution to `session-relay` and keep only the last-rung inference, which discriminates differently here than it does for a worker because a session in this role holds no feature branch either
|
|
62
66
|
|
|
63
67
|
## Must not
|
|
64
68
|
|
|
65
|
-
- Restate
|
|
69
|
+
- Restate a record's sections, its suggested-and-answer contract, or the steps the running skill carries, since thinness is what keeps one body correct for a dispatched session reading it as its whole contract
|
|
70
|
+
- Restate the write-scope exceptions each of the three skills states about its own folder
|
|
66
71
|
- Restate a boundary `role-orchestrator` or `role-worker` states about itself
|
|
67
72
|
- Tell a planner to halt on a plan question, which the suggested line already answers, rather than on what blocks writing the plan at all
|
|
68
73
|
- Tell a planner to report the path with no account of what the row got wrong. That instruction came from a trial condition holding a blind comparison intact, and it is not a durable obligation.
|
|
69
74
|
- Report progress through the channel, which rebuilds on the sender's side the poll the announcement exists to retire
|
|
70
|
-
- Write the priority board
|
|
75
|
+
- Write the priority board or the backlog, at any size, or the task file outside `plan-groundwork`'s close-time exception
|
|
71
76
|
- Be a skill nothing invokes but its author typing the name. `orchestrator-dispatch.md` names it on the planning launch the way it names `role-worker` on a build, so a stretch where only a typed invocation reaches it is the signal that the role never took.
|
|
72
77
|
|
|
73
78
|
## Guards
|
|
@@ -79,7 +84,9 @@ four carried at least one, caught only because the planner ran
|
|
|
79
84
|
|
|
80
85
|
## Out of scope
|
|
81
86
|
|
|
82
|
-
-
|
|
87
|
+
- Each record's sections and its answer contract, which the standard behind it fixes, and the steps that write the file, which `plan-feature`, `plan-groundwork`, and `plan-intake` each own for their own
|
|
88
|
+
- The write-scope exceptions, which stay in the three skills: groundwork's close-time task file, its fixture and evidence paths, and intake's statement that it has none
|
|
89
|
+
- The mechanical addressee resolution, which `session-relay` owns for every session with or without a role
|
|
83
90
|
- The branch, the build, and the pull request, which `role-worker` and `auto-ship` own
|
|
84
91
|
- Deciding which rows run and in what order, which is the controlling session's call and stated in `role-orchestrator`
|
|
85
92
|
- The dispatch itself, its collision check, and its disjointness gate, which `orchestrator-dispatch.md` holds
|
|
@@ -1,54 +1,71 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: role-planner
|
|
3
|
-
description: Asserts the planner role for a session writing one plan under one
|
|
3
|
+
description: Asserts the planner role for a session writing one plan, groundwork track, or intake pass under one row, holding what it reads before deciding, what may be written and where, how to read what is already in flight, and what it hands back. Use when asked to "be the planner", "you are a planner session", at the start of a dispatched or hand-launched planning, groundwork, or intake run, or when a planning session needs to know what it may not write. Do NOT use to write the record itself, which is `plan-feature`, `plan-groundwork`, or `plan-intake`, to make the cross-feature merge call, or to implement.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Role planner
|
|
7
7
|
|
|
8
|
-
This session
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
This session thinks rather than builds. It reads the row, measures what the row
|
|
9
|
+
claims against the tree, writes one record, and hands back the path. The record
|
|
10
|
+
is a feature plan under `plan-feature`, a groundwork track under
|
|
11
|
+
`plan-groundwork`, or an intake pass under `plan-intake`, and the role is the
|
|
12
|
+
same across all three.
|
|
11
13
|
|
|
12
14
|
It does not implement, it does not decide what merges before what, and it does
|
|
13
15
|
not review. Those belong to a worker, to the controlling session, and to the
|
|
14
16
|
human.
|
|
15
17
|
|
|
16
18
|
This body states the role, the reads, the boundaries, and the channel, and it
|
|
17
|
-
starts no step of its own.
|
|
18
|
-
and cites the standard fixing
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
starts no step of its own. Each of the three skills owns the steps that write
|
|
20
|
+
its record and cites the standard fixing that record's shape, so read the
|
|
21
|
+
procedure there and reach it from the launch rather than from here.
|
|
22
|
+
|
|
23
|
+
"Planner" stretches to cover measuring and triage. The operator accepted that,
|
|
24
|
+
since what the three share is the boundary below rather than the artifact each
|
|
25
|
+
produces.
|
|
21
26
|
|
|
22
27
|
## Where the session stands
|
|
23
28
|
|
|
24
|
-
- Write
|
|
25
|
-
-
|
|
26
|
-
- Resolve
|
|
27
|
-
-
|
|
29
|
+
- Write records, never source. A tracked file under `src/`, a standard, a rule, a reference doc, and a seed all sit outside what this session may touch, whichever of the three skills it is running.
|
|
30
|
+
- Write only into the folder the running skill names: `plan-feature` at `.canon/plans/`, `plan-groundwork` at `.canon/groundwork/<nn>-<slug>/`, and `plan-intake` at `.canon/intake/<nn>-<slug>/`. Each skill's own `## Write scope` carries its exceptions, which is why they are not listed here. A change to one scope then edits one body.
|
|
31
|
+
- Resolve every one of those folders, and `.canon/tasks/` and `.canon/review/` beside them, at the main worktree root. They are gitignored, so a copy beside a linked worktree is absent rather than empty and reads as a folder nobody has written yet.
|
|
32
|
+
- Never enter a worktree, never create a branch, and never write a tracked file. A thinking session that builds has stopped being one, and the row loses the independent read the worker's own session was going to bring to it.
|
|
33
|
+
- This session holds no worktree, so send each record out as a plain `Bash` heredoc past the same main-root refusal a linked worktree meets. That route skips the write-matched hooks, which are no-ops on a record file.
|
|
34
|
+
- Work the row the launch named. Report a second row met while reading rather than taking it on, since which rows run is the controller's call.
|
|
28
35
|
|
|
29
36
|
## What to read before deciding
|
|
30
37
|
|
|
31
|
-
Each item below is something a
|
|
38
|
+
Each item below is something a record needed and a launch string did not carry.
|
|
32
39
|
|
|
33
40
|
- The task file, and its `## Findings` before deciding anything. A row can carry its own disproof under a title that still states the original claim, which is how one trial nearly planned against a premise the file had already recorded as dead.
|
|
34
41
|
- The source files themselves, opened rather than summarized. Never a count quoted from the task file, which was wrong or stale in ten places across four plans.
|
|
35
42
|
- `CLAUDE.md` and `canon/ARCHITECTURE.md`, for the decision and the alternative it was taken against rather than for the decision alone.
|
|
36
|
-
- The plan of any row this one is sequenced behind, including one already moved to `.canon/plans/archive/`. Reading a shipped plan produced the strongest constraint in the first trial and no brief asked for it.
|
|
37
43
|
- `.canon/tasks/priority.md` for the row's Touches column and its stated blocker. That column is the file set the dispatch disjointness gate already reads.
|
|
44
|
+
|
|
45
|
+
Two reads belong to the `plan-feature` path alone, since neither a groundwork
|
|
46
|
+
track nor an intake pass is sequenced behind another row or validated as a plan:
|
|
47
|
+
|
|
48
|
+
- The plan of any row this one is sequenced behind, including one already moved to `.canon/plans/archive/`. Reading a shipped plan produced the strongest constraint in the first trial and no brief asked for it.
|
|
38
49
|
- `${CLAUDE_SKILL_DIR}/../../standards/plan.md` for the shape, then `canon records validate plans` and `canon markdown audit <the plan file>` on the file once it is written. Nothing else opens a plan, since `.canon/plans/` is gitignored and the audit's default path set is what git lists.
|
|
39
50
|
|
|
51
|
+
A groundwork or intake record passes through whatever its own skill and standard
|
|
52
|
+
name instead. The gitignored-folder problem is the same for all three, so run
|
|
53
|
+
the audit on any record a session writes rather than trusting a gate to reach
|
|
54
|
+
it.
|
|
55
|
+
|
|
40
56
|
## Read what is in flight rather than inferring it
|
|
41
57
|
|
|
42
58
|
- Run `canon sessions list --json`, take the `branch` field of every session whose `repository` matches this one and whose branch is neither null nor the trunk branch, union that with every `headRefName` from `gh pr list --json number,headRefName`, dedupe by branch name, then diff each with `git diff --name-only main...<branch>` for its file set. That resolves locally whether or not a pull request exists, since every track in this repository shares one git directory across its worktrees.
|
|
43
59
|
- A bare branch or worktree with neither a live session nor a pull request behind it is still not evidence, since this repository squash-merges and leaves both behind. The roster read is already filtered to live sessions, so what changed is the second source composed with it rather than a raw count. It still misses a live session that reached its worktree through the direct-path fallback rather than `EnterWorktree`, since that session's registered branch never moves off the trunk.
|
|
44
|
-
- Run the read once per
|
|
45
|
-
- Name each in-flight set as a constraint, say which act it forbids, and stamp the block with the commit the tree was read at
|
|
60
|
+
- Run the read once per row rather than once per batch. A session working several rows ages its picture of the tree while it goes, and this read is what dates it.
|
|
61
|
+
- Name each in-flight set as a constraint, say which act it forbids, and stamp the block with the commit the tree was read at. A bare path list leaves the reader guessing. The plan standard fixes that block for a feature plan, and a groundwork or intake record carries the same three parts in whatever shape its own standard states.
|
|
46
62
|
|
|
47
63
|
## The board is read-only
|
|
48
64
|
|
|
49
65
|
- Never write `.canon/tasks/priority.md` or `.canon/tasks/backlog.md`. Both are gitignored, so an overwrite drops a row with no history to recover it from.
|
|
50
|
-
- Never write the task file
|
|
51
|
-
-
|
|
66
|
+
- Never write the task file. The record is the whole output, and a row edited from here changes what the controller reads back as the state of the board.
|
|
67
|
+
- One exception, and it belongs to `plan-groundwork` alone: that skill writes a single task file at close, recording what the track concluded. Its own `## Write scope` states the exception, and this line exists so the rule above does not forbid what that skill requires.
|
|
68
|
+
- Report what the row got wrong rather than repairing it. A stale count, a moved line, or a path that no longer resolves goes into the record and into the handback, and the controller decides which of the two carries the correction.
|
|
52
69
|
- Leave the cross-feature call alone. Which rows collide, what merges before what, and whether a row should run at all stay with the controller. `priority.md` shows blockers and file sets and is enough to write a confident merge order off a partial picture, which is the failure this boundary exists to prevent.
|
|
53
70
|
|
|
54
71
|
## The channel
|
|
@@ -56,47 +73,33 @@ Each item below is something a plan needed and a launch string did not carry.
|
|
|
56
73
|
The controlling session cannot watch this one read, so two messages are owed and
|
|
57
74
|
nothing else.
|
|
58
75
|
|
|
59
|
-
- Announce the
|
|
60
|
-
- Send a block out as a message before it becomes an interactive prompt.
|
|
61
|
-
- Send nothing on progress. A
|
|
62
|
-
|
|
63
|
-
Address the session the launch named
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
returns a sibling or this session itself.
|
|
78
|
-
|
|
79
|
-
Inferring is the last rung and it discriminates less here than it does for a
|
|
80
|
-
worker. That read takes the sessions holding no feature branch, which separates a
|
|
81
|
-
controller from a worker because a worker holds one, and a planner holds none
|
|
82
|
-
either, so every sibling planner comes back beside the controller. Report the
|
|
83
|
-
candidates and stop where more than one does, rather than addressing the first.
|
|
84
|
-
Send to the single row where exactly one comes back, and say the addressee was
|
|
85
|
-
inferred.
|
|
86
|
-
|
|
87
|
-
Compose the relay through `canon:session-relay` when this section finds no
|
|
88
|
-
message-sending tool to send through, rather than leaving a resolved addressee
|
|
89
|
-
with nothing to reach it. It runs the same ladder above and carries the
|
|
90
|
-
message already owed, so nothing here is stated twice.
|
|
76
|
+
- Announce the record as the file lands, carrying its path and what the task file got wrong. Write no summary beside it, which is a second account of a document the reader is about to open.
|
|
77
|
+
- Send a block out as a message before it becomes an interactive prompt.
|
|
78
|
+
- Send nothing on progress. A thinking session reporting progress rebuilds, on this side of the channel, the poll the announcement retires on the other.
|
|
79
|
+
|
|
80
|
+
Address the session the launch named, which it names as a `sessionId` rather
|
|
81
|
+
than a name. `canon:session-relay` turns that id into an address and carries the
|
|
82
|
+
send, so invoke it rather than resolving a name here. It reads the roster at the
|
|
83
|
+
moment of sending, checks the result against the agent listing, and falls back
|
|
84
|
+
to a copyable block where this session holds no tool to send through.
|
|
85
|
+
|
|
86
|
+
One rung stays here, because it is the rung that differs between roles.
|
|
87
|
+
Inferring an addressee discriminates less for a thinking session than for a
|
|
88
|
+
worker. The inference takes the sessions holding no feature branch, which
|
|
89
|
+
separates a controller from a worker because a worker holds one, and a session
|
|
90
|
+
in this role holds none either, so every sibling comes back beside the
|
|
91
|
+
controller. Report the candidates and stop where more than one does, rather than
|
|
92
|
+
addressing the first. Send to the single row where exactly one comes back, and
|
|
93
|
+
say the addressee was inferred.
|
|
91
94
|
|
|
92
95
|
## Refusing is part of the job
|
|
93
96
|
|
|
94
97
|
- Refuse an instruction the tree contradicts, and carry the evidence with it. Name the commands read and what complying would produce, rather than reporting reluctance.
|
|
95
98
|
- Correct a premise the brief carried when the tree disagrees with it. One trial was told two rows were free of a renamed token and found they carried it as command names rather than path segments, planned all three rows anyway, and put the consequence into a plan question. Correct, continue, and record what the correction changed.
|
|
96
|
-
- Answer a plan question rather than halting on it. Every question carries a `- Suggested:` line the operator accepts or overrules, so a judgment written down is the deliverable. Halt only on what blocks writing the
|
|
99
|
+
- Answer a plan question rather than halting on it. Every question carries a `- Suggested:` line the operator accepts or overrules, so a judgment written down is the deliverable. Halt only on what blocks writing the record at all, and send that out as a message before it becomes a prompt.
|
|
97
100
|
|
|
98
101
|
## Lifetime
|
|
99
102
|
|
|
100
|
-
- The role runs from the launch to the
|
|
101
|
-
- A reused session pays the context load once and stales differently. Its picture of the tree ages while it works, which is why the in-flight read runs per
|
|
103
|
+
- The role runs from the launch to the record landing, and one record closes it. A session handed a second row works it under the same role and reads the tree again for that row.
|
|
104
|
+
- A reused session pays the context load once and stales differently. Its picture of the tree ages while it works, which is why the in-flight read runs per row, and it accumulates toward a compaction that drops the reasoning behind its earlier records with nothing reporting it. Cap a reused session rather than letting it run the board.
|
|
102
105
|
- Treat this body as possibly older than the branch under it. A plugin skill loads from the marketplace cache rather than from the working tree.
|
|
@@ -89,10 +89,18 @@ with no roster row at all. Those nine were driving through Remote Control, which
|
|
|
89
89
|
writes no local process record, so a controller working from a phone is exactly
|
|
90
90
|
the case this read answers nothing for.
|
|
91
91
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
92
|
+
Send through `canon:session-relay`. It holds the mechanical half of the send,
|
|
93
|
+
turning the `sessionId` the launch named into an address at the moment of
|
|
94
|
+
sending, checking the result against the agent listing, and falling back to a
|
|
95
|
+
copyable block where this session holds no tool to send through. The message
|
|
96
|
+
owed stays in its own bullet above.
|
|
97
|
+
|
|
98
|
+
The rungs above restate the resolution the relay also carries. What is a
|
|
99
|
+
worker's own is the last of them, the inference over sessions holding no feature
|
|
100
|
+
branch, which discriminates here because a worker holds one and a controller
|
|
101
|
+
does not. The rest is duplicated deliberately, so this body still reads whole
|
|
102
|
+
for a session that reaches it with the relay unresolved, which is the ordinary
|
|
103
|
+
case in a target that installed governance without the plugin.
|
|
96
104
|
|
|
97
105
|
## Refusing is part of the job
|
|
98
106
|
|
|
@@ -1,43 +1,70 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: session-relay
|
|
3
|
-
description: Why a standalone skill with no firing condition never fired, why the first inline draft repeated the same protocol in two bodies,
|
|
3
|
+
description: Why a standalone skill with no firing condition never fired, why the first inline draft repeated the same protocol in two bodies, why the missing sender identity sat unaddressed through both attempts, and why the two guards that scoped it to a session holding a role and no send tool came off
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Session relay requirement
|
|
7
7
|
|
|
8
8
|
## Gap
|
|
9
9
|
|
|
10
|
-
Without this skill,
|
|
10
|
+
Without this skill, every session that owes another session a message resolves
|
|
11
|
+
the addressee itself. `role-worker` and `role-planner` each state the messages
|
|
12
|
+
owed and each carried the resolution inline, and a session holding neither role
|
|
13
|
+
carried it nowhere, so the mechanical half of the send existed in two copies
|
|
14
|
+
plus however many a roleless caller improvised.
|
|
11
15
|
|
|
12
|
-
A standalone skill was proposed for the gap and declined the same day. It fired
|
|
16
|
+
A standalone skill was proposed for the gap and declined the same day. It fired
|
|
17
|
+
on no condition of its own, since nothing routes a session to a skill matching
|
|
18
|
+
no request and reaching for no artifact, so a skill built to close the gap never
|
|
19
|
+
closed it. That history is why the pointer inside each role's
|
|
20
|
+
`## The channel` section still matters: it is a section both bodies read at
|
|
21
|
+
session start rather than one reached by request match alone, and it is what
|
|
22
|
+
makes the firing survive.
|
|
13
23
|
|
|
14
|
-
The first draft of this plan closed the gap with a paragraph drafted inline,
|
|
24
|
+
The first draft of this plan closed the gap with a paragraph drafted inline,
|
|
25
|
+
once inside `role-worker` and once inside `role-planner`. The operator overrode
|
|
26
|
+
that call: two bodies carrying identical protocol text is the shared-surface
|
|
27
|
+
case `canon/ARCHITECTURE.md` already decided against duplicating, since a later
|
|
28
|
+
fix reaching one copy and not the other diverges silently.
|
|
15
29
|
|
|
16
|
-
Neither attempt named who the relay is from. A message an operator relays by
|
|
30
|
+
Neither attempt named who the relay is from. A message an operator relays by
|
|
31
|
+
hand needs a sender as much as an addressee, and the standalone draft and the
|
|
32
|
+
inline draft both composed a body and an addressee with no line stating whose
|
|
33
|
+
turn produced it.
|
|
34
|
+
|
|
35
|
+
Scoping the skill to a session holding a role and no send tool left two holes
|
|
36
|
+
rather than one. A session holding neither role had no `## The channel` section
|
|
37
|
+
to carry the pointer and was refused outright on arrival. A session that held a
|
|
38
|
+
role and a send tool was refused too, which left the resolution ladder
|
|
39
|
+
duplicated in both role bodies for the ordinary case. Both guards came off
|
|
40
|
+
together, since the mechanics are the same whichever route carries the text.
|
|
17
41
|
|
|
18
42
|
## Must
|
|
19
43
|
|
|
20
|
-
- Fire
|
|
21
|
-
- Refuse a caller holding neither role, checked ahead of the tool-availability guard
|
|
44
|
+
- Fire for any session sending to another session, with or without a role and with or without a message-sending tool
|
|
22
45
|
- Read the sender's own name off `canon sessions list --self --json` before composing anything, and degrade to naming itself from the environment when the installed CLI answers `--self` with an unknown option rather than a refusal carrying a reason
|
|
23
|
-
- Resolve the addressee
|
|
24
|
-
-
|
|
46
|
+
- Resolve the addressee from a `sessionId` or a branch at the moment of sending, never by a name prefix
|
|
47
|
+
- Check the resolved name against the agent listing, sending it bare under a single row and completing it with the `[ref]` under more than one
|
|
48
|
+
- Send through a message-sending tool where one exists, and compose the copyable block where none does or where the listing carries no row to address
|
|
49
|
+
- State block-before-prompt, since the shipped channel rule carrying it for a session holding neither role reaches only a target that installed governance
|
|
50
|
+
- Carry the message body verbatim from whatever names it
|
|
25
51
|
- Open the composed text with a header naming the sender, the addressee, and what the message is
|
|
26
52
|
- State the header as a default a session may write around, rather than a fixed vocabulary
|
|
27
53
|
|
|
28
54
|
## Must not
|
|
29
55
|
|
|
30
|
-
-
|
|
31
|
-
-
|
|
32
|
-
-
|
|
56
|
+
- Draft a message body of its own. The text it composes belongs to the calling role's bullet or to the dispatch.
|
|
57
|
+
- Decide who the message goes to. The caller names an id or a branch and this body turns it into an address.
|
|
58
|
+
- Restate the last-rung inference `role-worker` and `role-planner` each carry, which differs between them
|
|
33
59
|
|
|
34
60
|
## Guards
|
|
35
61
|
|
|
36
|
-
- The
|
|
37
|
-
-
|
|
62
|
+
- The roster cannot name the sender: report the refusal and its reason in place of a name
|
|
63
|
+
- The resolution returns no row: report it rather than guessing, since the roster and the send channel enumerate different populations in both directions
|
|
64
|
+
- The caller named no addressee at all: defer to the calling role's own last rung, and ask the operator where one is present
|
|
38
65
|
|
|
39
66
|
## Out of scope
|
|
40
67
|
|
|
41
|
-
-
|
|
42
|
-
- The
|
|
43
|
-
- Inbound reach
|
|
68
|
+
- Which messages are owed and when, which stays in the calling role's own bullet or in the dispatch
|
|
69
|
+
- The last-rung inference, which stays in `role-worker` and `role-planner` because a worker holds a feature branch and a planner does not, so the two discriminate differently
|
|
70
|
+
- Inbound reach as a distinct case. A relay in either direction is one session sending to another, which is what this body now covers.
|