@jabworks/condux 0.15.1 → 0.17.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/agents/planner.md +2 -0
- package/package.json +1 -1
- package/skills/blueprint/SKILL.md +38 -13
- package/skills/blueprint/evals/trigger_eval.json +19 -4
- package/skills/blueprint/references/diagram-kit.md +23 -0
- package/skills/blueprint/references/wireframe-kit.md +10 -0
- package/skills/discovery/SKILL.md +150 -43
- package/skills/draft-plan/SKILL.md +18 -2
- package/skills/plan-review/references/plan-review-template.html +13 -1
- package/skills/subagent-execution/agents/planner.md +2 -0
- package/skills/technical-spec/SKILL.md +28 -1
- package/skills/technical-spec/references/scaffold.sh +5 -0
- package/skills/technical-spec/references/templates.md +98 -40
package/agents/planner.md
CHANGED
|
@@ -19,6 +19,8 @@ Both can run in parallel if they don't depend on each other's output.
|
|
|
19
19
|
|
|
20
20
|
For LARGE tasks (cross-cutting, unclear scope, multiple subsystems), `/discovery` should have already run before you are invoked — it produces the signed-off design you turn into an executable plan. That design is a saved artifact: glob `.condux/designs/*<slug>*.md` (and `specs/<slug>/` for a tech-spec) and **read it first** — it is your source of truth for scope, chosen approach, and out-of-scope items. Do not re-derive or second-guess design decisions already settled there; if the file is missing for a large task, ask whether discovery has run rather than filling in the design yourself.
|
|
21
21
|
|
|
22
|
+
**Check its `status` before trusting it.** Discovery creates the design file at its first section, not at sign-off, so finding the file does not mean the design was approved. Read the frontmatter: `signed-off` (or no `status` field at all, which means the file predates the field and was therefore saved at sign-off) means the design is settled and the paragraph above applies in full. `in-progress` means discovery started and did not finish — stop and ask whether to resume discovery, and do not plan from it. An unfinished design is the one case where the file is present and still must not be treated as source of truth.
|
|
23
|
+
|
|
22
24
|
## Task Size Classification
|
|
23
25
|
|
|
24
26
|
- **Large (3+ files OR any architectural change)**: ask up to 3 impact-prioritized clarifying questions in one message, then delegate to `explorer`/`researcher`, then produce the full plan with ADR.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jabworks/condux",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.17.0",
|
|
4
4
|
"description": "OpenCode plugin for the condux workflow toolkit — bundles the condux skills and injects the specialist agents (coder, explorer, planner, researcher) plus an opt-in plan-review listener.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"publishConfig": {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: blueprint
|
|
3
|
-
description: "Produce dependency-free visual clarity artifacts at design time — HTML wireframes and full renders for UI screens and flows in the house design language (surface-kit tokens), and inline-SVG system diagrams (data models, flows, architecture, state machines) for backend work. During /discovery when
|
|
3
|
+
description: "Produce dependency-free visual clarity artifacts at design time — HTML wireframes and full renders for UI screens and flows in the house design language (surface-kit tokens), and inline-SVG system diagrams (data models, flows, architecture, state machines) for backend work. During /discovery when a section turns on what entities exist, what happens in what order, what talks to what, what states are legal, or what goes where on a screen; from /draft-plan task cards; or standalone on \"mock this up\", \"wireframe this screen\", \"visualize the data model\", \"sketch the architecture\", \"diagram the flow\". Not for aesthetic or brand direction, editable design canvases or Figma, charts from real data, or generating code from a mockup."
|
|
4
4
|
argument-hint: "[surface or model to visualize — optional; defaults to the current design context]"
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -26,12 +26,13 @@ product family.
|
|
|
26
26
|
┌──────────────────────────────────────────────────────────────────┐
|
|
27
27
|
│ BLUEPRINT │
|
|
28
28
|
├──────────────────────────────────────────────────────────────────┤
|
|
29
|
-
│ Step 1: ASSESS
|
|
30
|
-
│ What
|
|
31
|
-
│ -
|
|
32
|
-
│ -
|
|
33
|
-
│
|
|
34
|
-
│
|
|
29
|
+
│ Step 1: ASSESS THE QUESTION │
|
|
30
|
+
│ What is the reader trying to answer? │
|
|
31
|
+
│ - What goes where on a screen → wireframe family │
|
|
32
|
+
│ - What exists / what happens → diagram family │
|
|
33
|
+
│ / what talks to what / │
|
|
34
|
+
│ what states are legal │
|
|
35
|
+
│ - Two of these → one artifact each │
|
|
35
36
|
│ │
|
|
36
37
|
│ Step 2: PRODUCE │
|
|
37
38
|
│ One self-contained HTML file per screen / flow state / diagram. │
|
|
@@ -42,9 +43,13 @@ product family.
|
|
|
42
43
|
│ No external assets, no CDN, no font files. │
|
|
43
44
|
│ │
|
|
44
45
|
│ Step 3: DELIVER │
|
|
45
|
-
│
|
|
46
|
-
│ (headless, SSH), print the absolute paths and continue —
|
|
47
|
-
│ never fail on delivery.
|
|
46
|
+
│ Standalone: open in the browser (xdg-open / open). If neither │
|
|
47
|
+
│ works (headless, SSH), print the absolute paths and continue — │
|
|
48
|
+
│ never fail on delivery. │
|
|
49
|
+
│ Inside /discovery: open NOTHING. Link the file from the design │
|
|
50
|
+
│ doc and let the running preview reload — see Inside the │
|
|
51
|
+
│ Workflow. │
|
|
52
|
+
│ Either way, always state which mode was produced │
|
|
48
53
|
│ and offer the flip: "wireframe mode — say 'promote to render' │
|
|
49
54
|
│ for the full house look" (or the reverse). The mode is never │
|
|
50
55
|
│ chosen silently. │
|
|
@@ -93,9 +98,26 @@ mockup into the spec directory first and cite the committed copy.
|
|
|
93
98
|
|
|
94
99
|
## Inside the Workflow
|
|
95
100
|
|
|
96
|
-
- **/discovery** loads this skill at the propose step when
|
|
97
|
-
|
|
98
|
-
|
|
101
|
+
- **/discovery** loads this skill at the propose step when a section's decision
|
|
102
|
+
turns on one of the five questions below — not when the feature "has" a UI
|
|
103
|
+
surface or a data model. That noun test has a blind spot: a design whose
|
|
104
|
+
subjects are, say, a terminal output shape and a markdown file contains
|
|
105
|
+
neither, and still needs a flow diagram. A question test has no such gap,
|
|
106
|
+
because the reader asks the question regardless of what the feature is made of.
|
|
107
|
+
|
|
108
|
+
| The question the section turns on | Shape |
|
|
109
|
+
|---|---|
|
|
110
|
+
| What entities exist and how do they relate? | entity / data-model |
|
|
111
|
+
| What happens, in what order, when X occurs? | request / data flow |
|
|
112
|
+
| What services exist and what talks to what? | architecture |
|
|
113
|
+
| What states are legal and what moves between them? | state machine |
|
|
114
|
+
| What goes where on a screen, and in what order does it read? | wireframe |
|
|
115
|
+
|
|
116
|
+
**Inside discovery, deliver by linking — never by opening.** The reader
|
|
117
|
+
already has the design preview open (discovery launches it at §1 and it
|
|
118
|
+
live-reloads on every write). Add the mockup's path to the design doc and the
|
|
119
|
+
link appears there. A tab per section is the interruption this avoids;
|
|
120
|
+
standalone invocations keep opening on deliver. Side-by-side option *picking*
|
|
99
121
|
stays with discovery's own mockup-picker.
|
|
100
122
|
- **/draft-plan** task cards may cite mockup paths so an implementer sees the
|
|
101
123
|
visual target for their task.
|
|
@@ -111,5 +133,8 @@ mockup into the spec directory first and cite the committed copy.
|
|
|
111
133
|
✗ External dependencies — no Mermaid CDN, no image generation, no Figma
|
|
112
134
|
✗ Code generation from the mockup (that's implementation's job, later)
|
|
113
135
|
✗ Charts of real data (that's a dataviz concern, not a design mockup)
|
|
136
|
+
✗ Labels generic enough to fit another feature — see the specificity rule in
|
|
137
|
+
both kits; a box the reader can't disagree with isn't evidence
|
|
138
|
+
✗ Opening a browser tab while running inside /discovery
|
|
114
139
|
✗ Editing the mockups after design sign-off without saying so
|
|
115
140
|
```
|
|
@@ -48,13 +48,18 @@
|
|
|
48
48
|
"query": "show me a wireframe of both options for the onboarding screen",
|
|
49
49
|
"should_trigger": true,
|
|
50
50
|
"expected_skill": "blueprint",
|
|
51
|
-
"accept": [
|
|
51
|
+
"accept": [
|
|
52
|
+
"discovery"
|
|
53
|
+
]
|
|
52
54
|
},
|
|
53
55
|
{
|
|
54
56
|
"query": "before planning, can we visualize what this feature will look like",
|
|
55
57
|
"should_trigger": true,
|
|
56
58
|
"expected_skill": "blueprint",
|
|
57
|
-
"accept": [
|
|
59
|
+
"accept": [
|
|
60
|
+
"discovery",
|
|
61
|
+
"workflow"
|
|
62
|
+
]
|
|
58
63
|
},
|
|
59
64
|
{
|
|
60
65
|
"query": "mock up the ER diagram for the new billing tables",
|
|
@@ -82,19 +87,29 @@
|
|
|
82
87
|
"query": "build the settings page from the approved design",
|
|
83
88
|
"should_trigger": false,
|
|
84
89
|
"expected_skill": null,
|
|
85
|
-
"accept": [
|
|
90
|
+
"accept": [
|
|
91
|
+
"workflow"
|
|
92
|
+
],
|
|
86
93
|
"note": "Building from an approved design is an implementation request; workflow's any-implementation-request claim covers it. The case still guards blueprint against the \"design\" bait."
|
|
87
94
|
},
|
|
88
95
|
{
|
|
89
96
|
"query": "implement this Figma design as a React component",
|
|
90
97
|
"should_trigger": false,
|
|
91
98
|
"expected_skill": null,
|
|
92
|
-
"accept": [
|
|
99
|
+
"accept": [
|
|
100
|
+
"workflow"
|
|
101
|
+
],
|
|
93
102
|
"note": "Implementing a design in code is an implementation request; workflow covers it. The case still guards blueprint against the \"Figma design\" bait."
|
|
94
103
|
},
|
|
95
104
|
{
|
|
96
105
|
"query": "pick a color palette and typography for the marketing site",
|
|
97
106
|
"should_trigger": false,
|
|
98
107
|
"expected_skill": null
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
"query": "sketch how the CLI, the cache file and the background daemon hand off to each other",
|
|
111
|
+
"should_trigger": true,
|
|
112
|
+
"expected_skill": "blueprint",
|
|
113
|
+
"note": "No UI surface and no data model — the old noun-shaped trigger could not see this. The section turns on \"what talks to what\", which is a blueprint question."
|
|
99
114
|
}
|
|
100
115
|
]
|
|
@@ -34,6 +34,29 @@ of the `<style>` block, verbatim.
|
|
|
34
34
|
- Every relationship line gets a label. An unlabeled arrow is a guess the
|
|
35
35
|
reader has to make.
|
|
36
36
|
|
|
37
|
+
## The Specificity Rule
|
|
38
|
+
|
|
39
|
+
Every label must name something real from *this* design — a path, a command, a
|
|
40
|
+
field, a state, a status value, an endpoint. **If a label would be equally true
|
|
41
|
+
of a different feature, it is too vague.**
|
|
42
|
+
|
|
43
|
+
A diagram is evidence for a decision. A box the reader cannot disagree with
|
|
44
|
+
carries no information, so it cannot be evidence — and "generic enough to fit
|
|
45
|
+
any feature" is the single most common reason a produced artifact turns out not
|
|
46
|
+
to help anyone.
|
|
47
|
+
|
|
48
|
+
| Too vague | Specific |
|
|
49
|
+
|---|---|
|
|
50
|
+
| `Design Doc` | `.condux/designs/<date>-<slug>.md` |
|
|
51
|
+
| `Preview` | `plan-review --steer` |
|
|
52
|
+
| `Gate` | `signed-off → plan proceeds` |
|
|
53
|
+
| `Status` | `status: in-progress` |
|
|
54
|
+
| `saves` | `5. append agreed §` |
|
|
55
|
+
|
|
56
|
+
The rule bites hardest early, when the specifics are not settled yet — which is
|
|
57
|
+
the correct time for it to bite. A diagram drawn before there is anything
|
|
58
|
+
concrete to put in it is decoration, and should not be drawn.
|
|
59
|
+
|
|
37
60
|
## 1. Entity / Data-Model
|
|
38
61
|
|
|
39
62
|
One `<g>` per entity: title bar + field rows. Keys marked `PK` / `FK`; edge
|
|
@@ -58,6 +58,16 @@ mixes both signals.
|
|
|
58
58
|
8. **Self-contained.** All CSS inline in a `<style>` block. No external
|
|
59
59
|
requests of any kind. The file must render identically from `file://`.
|
|
60
60
|
The token core carries dark and light themes; the page follows the OS.
|
|
61
|
+
9. **Specific enough to disagree with.** Every label names something real from
|
|
62
|
+
*this* design — a route, a field, a state, a real CTA. If a label would be
|
|
63
|
+
equally true of a different feature, it is too vague: `Submit` on a form
|
|
64
|
+
whose button says "Save and invite", a nav reading `Item · Item · Item`, a
|
|
65
|
+
panel titled `Details`. This is rule 5 pushed one step further — rule 5 asks
|
|
66
|
+
for the intended text, this asks whether the intended text distinguishes
|
|
67
|
+
anything. A wireframe is evidence for a layout decision, and an element the
|
|
68
|
+
reader cannot disagree with is not evidence. It bites hardest before the
|
|
69
|
+
specifics are settled, which is exactly when a wireframe should not be
|
|
70
|
+
drawn yet. Same rule, same reasoning as `diagram-kit.md`.
|
|
61
71
|
|
|
62
72
|
## Page Skeleton
|
|
63
73
|
|
|
@@ -21,9 +21,15 @@ Before Step 1, check for an existing design: glob `.condux/designs/*<slug>*.md`
|
|
|
21
21
|
and both spec scopes — `<package-root>/specs/<slug>/` and
|
|
22
22
|
`<git-root>/specs/<slug>/`, the workflow router's two-scope lookup (slug =
|
|
23
23
|
kebab-case of the feature name). If any
|
|
24
|
-
exists,
|
|
25
|
-
|
|
26
|
-
|
|
24
|
+
exists, read its frontmatter `status` and offer accordingly:
|
|
25
|
+
|
|
26
|
+
- `signed-off`, or no `status` field at all (the file predates the field, so
|
|
27
|
+
it was saved at sign-off): "Found a signed-off design for this feature at
|
|
28
|
+
`<path>` — resume from there, or start a fresh discovery?"
|
|
29
|
+
- `in-progress`: "Found a discovery that stopped partway at `<path>`
|
|
30
|
+
(`<n>` sections agreed) — pick up where it left off, or start fresh?"
|
|
31
|
+
|
|
32
|
+
Accept either answer, same as any other soft gate in this skill.
|
|
27
33
|
|
|
28
34
|
```
|
|
29
35
|
┌──────────────────────────────────────────────────────────────────┐
|
|
@@ -46,12 +52,15 @@ as any other soft gate in this skill.
|
|
|
46
52
|
│ No implementation detail yet — that's Step 4's job. │
|
|
47
53
|
│ │
|
|
48
54
|
│ Step 3: PROPOSE │
|
|
49
|
-
│
|
|
50
|
-
│
|
|
51
|
-
│
|
|
52
|
-
│
|
|
53
|
-
│
|
|
54
|
-
│
|
|
55
|
+
│ Announce the section list, then create the design file │
|
|
56
|
+
│ (status: in-progress) and open the live preview. │
|
|
57
|
+
│ Present one section at a time in the card shape, get │
|
|
58
|
+
│ acknowledgment, append the agreed section to the file. │
|
|
59
|
+
│ §1 is approaches-and-tradeoffs; the rest follow the design. │
|
|
60
|
+
│ Full contract: The Section Card, below. │
|
|
61
|
+
│ Does a section's decision turn on one of blueprint's five │
|
|
62
|
+
│ questions? Load `blueprint` — the artifact is linked from │
|
|
63
|
+
│ the design doc, not opened in a new tab. │
|
|
55
64
|
│ │
|
|
56
65
|
│ Step 4: DETAIL ROUND — feed the spec │
|
|
57
66
|
│ With the approach chosen, ask ONE more batch, grouped by │
|
|
@@ -79,13 +88,15 @@ as any other soft gate in this skill.
|
|
|
79
88
|
│ Get explicit approval: "Looks good, proceed to planning" │
|
|
80
89
|
│ Do not proceed to /draft-plan without this. │
|
|
81
90
|
│ │
|
|
82
|
-
│ Step 7:
|
|
83
|
-
│
|
|
84
|
-
│
|
|
85
|
-
│
|
|
91
|
+
│ Step 7: SIGN OFF THE FILE + SPEC (mandatory) │
|
|
92
|
+
│ The design file already exists — Step 3 created it and │
|
|
93
|
+
│ every agreed section is in it. Flip its frontmatter │
|
|
94
|
+
│ status: in-progress → signed-off. That flip is what │
|
|
95
|
+
│ /draft-plan's gate check reads. │
|
|
86
96
|
│ Spec write-back is default-on: persist the concern files │
|
|
87
97
|
│ too (Spec Integration below) unless the user opts out. │
|
|
88
|
-
│
|
|
98
|
+
│ The preview is already running — reuse it (Design Review │
|
|
99
|
+
│ Loop); never launch a second server or open a second tab. │
|
|
89
100
|
└──────────────────────────────────────────────────────────────────┘
|
|
90
101
|
```
|
|
91
102
|
|
|
@@ -148,8 +159,105 @@ Accept either answer. Never block. Never lecture.
|
|
|
148
159
|
✗ Proceeding to planning without explicit sign-off
|
|
149
160
|
✗ Treating a well-defined ticket as needing full discovery
|
|
150
161
|
✗ Widening past the named target surface without saying so
|
|
162
|
+
✗ A section card that runs past one screen, or a paragraph past three lines
|
|
163
|
+
✗ Launching a second preview server, or opening a tab the user didn't ask for
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## The Section Card (Step 3)
|
|
167
|
+
|
|
168
|
+
Step 3 used to say "show design in sections" and stop, which left the shape to
|
|
169
|
+
be reinvented every time — and what came out was prose. The shape is now fixed.
|
|
170
|
+
|
|
171
|
+
**Before §1, announce the section list.** Name every section you intend to
|
|
172
|
+
present, in order: *"4 sections: approach · section shape · blueprint trigger ·
|
|
173
|
+
rollout."* Three lines, and the reader knows the shape of the conversation
|
|
174
|
+
before they are inside it. Then create the design file and open the preview
|
|
175
|
+
(next section), and begin.
|
|
176
|
+
|
|
177
|
+
**Every card, same skeleton:**
|
|
178
|
+
|
|
179
|
+
```
|
|
180
|
+
## §n of N · <name> ← position, always
|
|
181
|
+
<one line: what this section decides>
|
|
182
|
+
|
|
183
|
+
<the evidence — table, list, or a linked artifact. Never a wall.>
|
|
184
|
+
|
|
185
|
+
**Recommendation:** <X>, because <one sentence>.
|
|
186
|
+
<the decision, as named options>
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
**Three rules underneath it:**
|
|
190
|
+
|
|
191
|
+
| Rule | Why |
|
|
192
|
+
|---|---|
|
|
193
|
+
| The card fits one screen — about 25 lines. Overflow goes into the design file, and the card links it. | Without a number this is advice, not a contract, and advice is what produced the walls. |
|
|
194
|
+
| No paragraph runs past three lines. Longer means it is a table or a list. | Prose is the failure mode. A table cannot sprawl. |
|
|
195
|
+
| Rejected alternatives get one line each with a why-not; the full reasoning lives in the file. | Alternatives are why the recommendation can be trusted, and are also what bloats the card. |
|
|
196
|
+
|
|
197
|
+
The per-section stops stay. They were never the problem — the problem was that
|
|
198
|
+
the design existed only as scrollback, so the thread was lost between them. The
|
|
199
|
+
`§n of N` marker and the live file are what hold it.
|
|
200
|
+
|
|
201
|
+
**Visuals.** Load `blueprint` when a section's decision turns on one of its five
|
|
202
|
+
questions — what entities exist · what happens in what order · what talks to
|
|
203
|
+
what · what states are legal · what goes where on a screen. Inside discovery
|
|
204
|
+
the artifact is *linked from the design doc*, never opened in its own tab: the
|
|
205
|
+
running preview reloads and shows the link, so the reader stays where they are.
|
|
206
|
+
|
|
207
|
+
## The Design File and the Live Preview (Step 3 onward)
|
|
208
|
+
|
|
209
|
+
**The file is created at §1, not at sign-off.** Write
|
|
210
|
+
`.condux/designs/YYYY-MM-DD-<feature>.md` with frontmatter
|
|
211
|
+
`status: in-progress` when Step 3 opens, and append each section to it as it is
|
|
212
|
+
agreed. This is the whole mechanism behind the card contract: the card can stay
|
|
213
|
+
small precisely because the design has somewhere else to live.
|
|
214
|
+
|
|
215
|
+
```markdown
|
|
216
|
+
---
|
|
217
|
+
status: in-progress
|
|
218
|
+
date: YYYY-MM-DD
|
|
219
|
+
feature: <slug>
|
|
220
|
+
---
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
At Step 7, flip `status` to `signed-off`. `/draft-plan` and the `planner` agent
|
|
224
|
+
both read that value; **a design file with `status: in-progress` does not
|
|
225
|
+
satisfy their gate**, which is what keeps an abandoned discovery from being
|
|
226
|
+
planned against. (A file with no `status` field at all predates this contract
|
|
227
|
+
and was only ever written at sign-off, so absence means `signed-off`.)
|
|
228
|
+
|
|
229
|
+
**The preview runs from §1, by default.** Launch it with the design file, in
|
|
230
|
+
manual mode — no `--steer`, which would block on a decision:
|
|
231
|
+
|
|
232
|
+
```bash
|
|
233
|
+
node /path/to/plan-review/references/annotate-server.js .condux/designs/<file>.md --no-reject
|
|
151
234
|
```
|
|
152
235
|
|
|
236
|
+
Manual mode renders, watches the directory and live-reloads over SSE without
|
|
237
|
+
blocking, so every appended section appears in the tab the reader already has
|
|
238
|
+
open. It still accepts a submitted decision, which means **one server covers
|
|
239
|
+
the whole of discovery** — launched at §1, still serving at sign-off. Never
|
|
240
|
+
start a second one.
|
|
241
|
+
|
|
242
|
+
Announce it and move on — do not ask first:
|
|
243
|
+
|
|
244
|
+
> "Design preview running at http://127.0.0.1:7777 — it updates as we go. Say
|
|
245
|
+
> the word if you'd rather I close it."
|
|
246
|
+
|
|
247
|
+
The preview's purpose is to help make the *next* decision, so gating it behind
|
|
248
|
+
an opt-in defeats what it is for; and discovery only runs on the LARGE tier, so
|
|
249
|
+
there is no small case to protect from the ceremony. The default is visible and
|
|
250
|
+
reversible, never silent.
|
|
251
|
+
|
|
252
|
+
**Fail open.** No Node, no browser, headless, port taken — say so once in a
|
|
253
|
+
single line and continue terminal-only. The design file is still written and
|
|
254
|
+
still appended to; only the preview is missing. Never block discovery on it,
|
|
255
|
+
and never retry in a loop. `--no-open` exists for the headless case.
|
|
256
|
+
|
|
257
|
+
`.condux/` is gitignored working state, created on demand at the git root (see
|
|
258
|
+
`/workflow` → Artifacts). The bootstrap check now happens at §1 rather than at
|
|
259
|
+
sign-off — still ask only once.
|
|
260
|
+
|
|
153
261
|
## Output
|
|
154
262
|
|
|
155
263
|
A short design summary covering:
|
|
@@ -162,51 +270,50 @@ A short design summary covering:
|
|
|
162
270
|
Detail-round answers (Step 4) belong in the spec concern files, not the
|
|
163
271
|
summary — the summary stays short; the spec carries the detail.
|
|
164
272
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
273
|
+
Lives at: `.condux/designs/YYYY-MM-DD-<feature>.md`, created at §1 and
|
|
274
|
+
appended to per section (see The Design File and the Live Preview). Step 7
|
|
275
|
+
does not write it — it flips its `status` to `signed-off`, and that flip is
|
|
276
|
+
what `/draft-plan`'s gate check reads. A design that lives only in
|
|
277
|
+
conversation doesn't count as signed off, and neither does one still marked
|
|
278
|
+
`in-progress`.
|
|
168
279
|
|
|
169
|
-
|
|
170
|
-
(see `/workflow` → Artifacts). Before the first write, make sure it's
|
|
171
|
-
ignored — see the bootstrap step there. Honour an `AGENTS.md` path override
|
|
172
|
-
if the project defines one.
|
|
280
|
+
Honour an `AGENTS.md` path override if the project defines one.
|
|
173
281
|
|
|
174
282
|
For full design mockups — UI wireframes and renders in the house token
|
|
175
283
|
language, data-model / flow / architecture diagrams — load the `blueprint`
|
|
176
|
-
skill; the design doc links the files it produces
|
|
284
|
+
skill; the design doc links the files it produces, and the running preview
|
|
285
|
+
shows the link rather than a new tab opening. At sign-off, offer to
|
|
177
286
|
promote the chosen wireframes to render mode (a style-block swap). For
|
|
178
287
|
*picking between* side-by-side options in the browser, see
|
|
179
288
|
`references/mockup-picker.md` (it can point at blueprint's files).
|
|
180
289
|
|
|
181
290
|
## Design Review Loop
|
|
182
291
|
|
|
183
|
-
|
|
292
|
+
At Step 7, after the status flip, always offer — mirroring `/draft-plan`'s
|
|
293
|
+
post-save review:
|
|
184
294
|
|
|
185
|
-
> "Design
|
|
186
|
-
> or go straight to /draft-plan?"
|
|
295
|
+
> "Design signed off at `<path>`. Want a pass over it in the browser before we
|
|
296
|
+
> plan, or go straight to /draft-plan?"
|
|
187
297
|
|
|
188
|
-
**
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
298
|
+
**The server is already running** — it has been since §1, and the reader has
|
|
299
|
+
been watching the design accumulate in it. Do not launch another and do not
|
|
300
|
+
open another tab. `--no-reject` is independent of `--steer`, so the design
|
|
301
|
+
stage's **accept-or-fix** semantics (no Reject verdict — that belongs to plan
|
|
302
|
+
review) are already in force from the §1 launch.
|
|
193
303
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
304
|
+
**If a review pass is chosen:** point the reader at the tab they already have,
|
|
305
|
+
ask them to annotate and submit a decision, and read the result — the submitted
|
|
306
|
+
decision lands in the feedback file in manual mode rather than being long-polled:
|
|
197
307
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
plan review, not the design stage (directory/spec review hides it on its own;
|
|
202
|
-
the flag matters for single-file design review):
|
|
308
|
+
- **Approve** → proceed to `/draft-plan`, carrying any feedback notes into the plan.
|
|
309
|
+
- **Request Revisions** → revise the design file in place per the feedback (the
|
|
310
|
+
open tab live-reloads over SSE), then ask again.
|
|
203
311
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
(the open tab live-reloads over SSE), then poll again.
|
|
312
|
+
**If the preview failed open at §1** (no Node, no browser, headless) there is no
|
|
313
|
+
tab to point at. Say so in one line and go straight to planning; do not retry
|
|
314
|
+
the launch here.
|
|
208
315
|
|
|
209
|
-
**If straight to planning chosen:** proceed directly
|
|
316
|
+
**If straight to planning chosen:** proceed directly.
|
|
210
317
|
|
|
211
318
|
## Spec Integration (Live Preview)
|
|
212
319
|
|
|
@@ -21,11 +21,27 @@ Turn a signed-off design into a clear, executable plan. Lean task cards, not mic
|
|
|
21
21
|
`.condux/designs/*<slug>*.md` and both spec scopes —
|
|
22
22
|
`<package-root>/specs/<slug>/` and `<git-root>/specs/<slug>/`, same
|
|
23
23
|
two-scope lookup as the workflow router (slug = kebab-case of the
|
|
24
|
-
feature name) — for an existing signed-off design; if found,
|
|
25
|
-
treat this check as satisfied without
|
|
24
|
+
feature name) — for an existing signed-off design; if found, **read
|
|
25
|
+
its `status`** (see below) and treat this check as satisfied without
|
|
26
|
+
asking only when it is `signed-off`. Otherwise ask: "We
|
|
26
27
|
haven't aligned on the design yet — run /discovery first, or confirm
|
|
27
28
|
you want to skip it."
|
|
28
29
|
|
|
30
|
+
**Reading `status`.** Discovery creates the design file at its first
|
|
31
|
+
section, not at sign-off, so the file existing no longer means the design
|
|
32
|
+
was approved. Its frontmatter carries the answer:
|
|
33
|
+
|
|
34
|
+
| `status` | Means | Gate |
|
|
35
|
+
|---|---|---|
|
|
36
|
+
| `signed-off` | discovery reached sign-off | satisfied |
|
|
37
|
+
| `in-progress` | discovery started and did not finish | **not** satisfied — ask |
|
|
38
|
+
| *absent* | written before this field existed | satisfied |
|
|
39
|
+
|
|
40
|
+
A missing `status` means `signed-off`. Every design file written before
|
|
41
|
+
this field existed was only ever saved at sign-off, so absence is a
|
|
42
|
+
positive signal, not an unknown — reading it the other way retroactively
|
|
43
|
+
invalidates every design already on disk.
|
|
44
|
+
|
|
29
45
|
The plan is written as Markdown — optimized for AI agent consumption during
|
|
30
46
|
execution. To read it in the browser, use `plan-review` (see After Saving);
|
|
31
47
|
no separate HTML file is produced.
|
|
@@ -1345,11 +1345,23 @@
|
|
|
1345
1345
|
let DIRMODE=false, docs=[], activeDoc=null;
|
|
1346
1346
|
const docState={}; // name -> { md, pane, scroll, key, headings }
|
|
1347
1347
|
|
|
1348
|
+
// A design file carries its sign-off state in frontmatter, and renderBlocks
|
|
1349
|
+
// maps a bare `---` to <hr> — so without this the reader sees a rule, a
|
|
1350
|
+
// stray `status: …` paragraph and a second rule above every design. Only a
|
|
1351
|
+
// block at position 0 counts; the `---` separators these documents use
|
|
1352
|
+
// between sections must still render as horizontal rules. st.md keeps the
|
|
1353
|
+
// raw text, because the revision diff and scanDocPaths both read it and a
|
|
1354
|
+
// frontmatter-only change has to stay visible there.
|
|
1355
|
+
function stripFrontmatter(md){
|
|
1356
|
+
const m=/^---\r?\n[\s\S]*?\r?\n---\r?\n?/.exec(md);
|
|
1357
|
+
return m?md.slice(m[0].length):md;
|
|
1358
|
+
}
|
|
1359
|
+
|
|
1348
1360
|
function renderDocPane(doc, md){
|
|
1349
1361
|
const st=docState[doc];
|
|
1350
1362
|
st.md=md; st.pane.innerHTML=''; st.headings=[];
|
|
1351
1363
|
let section='(top)';
|
|
1352
|
-
renderBlocks(md).forEach(function(b,idx){
|
|
1364
|
+
renderBlocks(stripFrontmatter(md)).forEach(function(b,idx){
|
|
1353
1365
|
const id=st.key+'-blk-'+idx;
|
|
1354
1366
|
const wrap=document.createElement('div'); wrap.className='blk'; wrap.id=id; wrap.innerHTML=b.html;
|
|
1355
1367
|
if(b.heading){ section=id; st.headings.push({id:id,level:b.heading.level,text:b.heading.text}); }
|
|
@@ -22,6 +22,8 @@ Both can run in parallel if they don't depend on each other's output.
|
|
|
22
22
|
|
|
23
23
|
For LARGE tasks (cross-cutting, unclear scope, multiple subsystems), `/discovery` should have already run before you are invoked — it produces the signed-off design you turn into an executable plan. That design is a saved artifact: glob `.condux/designs/*<slug>*.md` (and `specs/<slug>/` for a tech-spec) and **read it first** — it is your source of truth for scope, chosen approach, and out-of-scope items. Do not re-derive or second-guess design decisions already settled there; if the file is missing for a large task, ask whether discovery has run rather than filling in the design yourself.
|
|
24
24
|
|
|
25
|
+
**Check its `status` before trusting it.** Discovery creates the design file at its first section, not at sign-off, so finding the file does not mean the design was approved. Read the frontmatter: `signed-off` (or no `status` field at all, which means the file predates the field and was therefore saved at sign-off) means the design is settled and the paragraph above applies in full. `in-progress` means discovery started and did not finish — stop and ask whether to resume discovery, and do not plan from it. An unfinished design is the one case where the file is present and still must not be treated as source of truth.
|
|
26
|
+
|
|
25
27
|
## Task Size Classification
|
|
26
28
|
|
|
27
29
|
- **Large (3+ files OR any architectural change)**: ask up to 3 impact-prioritized clarifying questions in one message, then delegate to `explorer`/`researcher`, then produce the full plan with ADR.
|
|
@@ -51,6 +51,15 @@ writing → run the scaffold script → write or update the concern files and
|
|
|
51
51
|
`index.md` → offer the live HTML preview. Each step is specified in the
|
|
52
52
|
sections below.
|
|
53
53
|
|
|
54
|
+
**When `discovery` calls this at sign-off**, the design document already
|
|
55
|
+
exists and has since the design's first section — discovery creates it at §1
|
|
56
|
+
and appends to it as each section is agreed. So the input here is a finished
|
|
57
|
+
file on disk, not a summary reconstructed from the conversation: read
|
|
58
|
+
`.condux/designs/YYYY-MM-DD-<feature>.md` and map its sections into the
|
|
59
|
+
concern files. Discovery's own preview server is already running against that
|
|
60
|
+
file, so the live-preview offer below applies to the *spec directory* only —
|
|
61
|
+
never start a second server for the design.
|
|
62
|
+
|
|
54
63
|
## Required Notifications
|
|
55
64
|
|
|
56
65
|
Always announce and confirm before writing or editing. Never silently modify files.
|
|
@@ -86,8 +95,24 @@ Parse `commit`, `date`, and the **absolute spec path** from the output — use t
|
|
|
86
95
|
|
|
87
96
|
Read [references/templates.md](references/templates.md) for the structure of each file.
|
|
88
97
|
|
|
98
|
+
**The layering rule.** Every concern file opens with its summary table; the
|
|
99
|
+
reasoning sits underneath; prose appears only where it earns its keep — the
|
|
100
|
+
reasoning a future reader must be able to follow. Fill the table layer first:
|
|
101
|
+
it is what a scanning human, `preflight`'s drift check, and an agent loading
|
|
102
|
+
the spec all read, so write each row as a claim someone could check.
|
|
103
|
+
|
|
104
|
+
**The two-homes rule.** A type in `api.md` says what each field *means* —
|
|
105
|
+
trailing `//` per field, JSDoc only when a line won't do. `fields.md` says
|
|
106
|
+
what *happens to it* — mapping and transformation only. One fact never lives
|
|
107
|
+
in both places: a fact with two homes goes missing from the one being read.
|
|
108
|
+
|
|
109
|
+
**Quirk headings are `## Q<n> — Title`.** The `Q<n>` anchors are a citation
|
|
110
|
+
contract (`durable-citations.test.mjs` resolves them), so numbers are unique,
|
|
111
|
+
ascending, and never renumbered.
|
|
112
|
+
|
|
89
113
|
- Write only files that have real content
|
|
90
|
-
- After writing, update the `## Contents`
|
|
114
|
+
- After writing, update the `## Contents` table in `index.md` — one row per
|
|
115
|
+
file created, the `Answers` cell saying what a reader comes to it for
|
|
91
116
|
- Replace the HTML comment the scaffold left below the title with a one-line
|
|
92
117
|
`> …` note saying what the spec is for. That note is what `spec-browser`'s
|
|
93
118
|
catalog shows for the spec; leave it and the spec is listed with nothing to
|
|
@@ -168,3 +193,5 @@ feedback file, if a decision is submitted).
|
|
|
168
193
|
| Vague decisions | Each decision needs context + rationale + consequences |
|
|
169
194
|
| Creating empty placeholder files | Only create a file when it has real content |
|
|
170
195
|
| Forgetting to update index.md Contents | Always link to files you create |
|
|
196
|
+
| Prose blob where the template has a table | Fill the table layer first; prose only for reasoning the table can't carry |
|
|
197
|
+
| Bare interface with the field meanings in fields.md | Meaning goes on the type (`//` per field); fields.md carries only the journey |
|
|
@@ -101,6 +101,11 @@ cat > "$SPEC_DIR/index.md" <<EOF
|
|
|
101
101
|
|
|
102
102
|
## Contents
|
|
103
103
|
|
|
104
|
+
| File | Answers |
|
|
105
|
+
|---|---|
|
|
106
|
+
<!-- One row per concern file you actually create — link + what a reader
|
|
107
|
+
comes to it for. Files that don't exist get no row. -->
|
|
108
|
+
|
|
104
109
|
## Changelog
|
|
105
110
|
- $DATE ($COMMIT): Initial spec
|
|
106
111
|
EOF
|
|
@@ -2,6 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
Copy-paste templates for each spec file. Omit sections that don't apply — don't leave empty headings.
|
|
4
4
|
|
|
5
|
+
**The layering rule, which every template below follows:** a concern file opens
|
|
6
|
+
with a scannable table and carries its reasoning underneath. The table serves
|
|
7
|
+
the reader scanning for one thing, `preflight`'s drift check, and an agent
|
|
8
|
+
loading the spec as context — all three read the same rows. Prose is reserved
|
|
9
|
+
for the one job that needs it: reasoning a future reader must be able to
|
|
10
|
+
follow. Write each table row as a claim someone could check, not a label.
|
|
11
|
+
|
|
5
12
|
---
|
|
6
13
|
|
|
7
14
|
## index.md
|
|
@@ -17,16 +24,20 @@ Copy-paste templates for each spec file. Omit sections that don't apply — don'
|
|
|
17
24
|
**Status:** draft | review | stable
|
|
18
25
|
|
|
19
26
|
## Contents
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
27
|
+
|
|
28
|
+
| File | Answers |
|
|
29
|
+
|---|---|
|
|
30
|
+
| [Decisions](decisions.md) | why it works this way, and what was rejected |
|
|
31
|
+
| [Quirks](quirks.md) | what will bite you, and whether it is mitigated |
|
|
25
32
|
|
|
26
33
|
## Changelog
|
|
27
34
|
- {YYYY-MM-DD} ({short-hash}): Initial spec
|
|
28
35
|
```
|
|
29
36
|
|
|
37
|
+
The Contents table answers *which file do I open* — one row per concern file
|
|
38
|
+
that actually exists, each `Answers` cell saying what a reader comes to it
|
|
39
|
+
for. Files that don't exist get no row.
|
|
40
|
+
|
|
30
41
|
**Cite committed paths only.** A spec is durable; the design and plan it came
|
|
31
42
|
from are working state under `.condux/`, gitignored and gone on any other
|
|
32
43
|
machine. If the changelog or body needs to point at a design or a verification
|
|
@@ -41,24 +52,35 @@ rule existed and two were already dead when they were found.
|
|
|
41
52
|
```markdown
|
|
42
53
|
# Decisions — {Feature Name}
|
|
43
54
|
|
|
44
|
-
|
|
55
|
+
| # | Decision | Because | Status |
|
|
56
|
+
|---|---|---|---|
|
|
57
|
+
| 1 | {what was decided, as a claim} | {why, one line} | accepted |
|
|
45
58
|
|
|
46
|
-
|
|
47
|
-
**Status:** accepted | superseded | deprecated
|
|
59
|
+
## 1. {Decision Title} — {YYYY-MM-DD}
|
|
48
60
|
|
|
49
|
-
|
|
50
|
-
|
|
61
|
+
**Decided:** one sentence, stated as a claim.
|
|
62
|
+
**Because:** one sentence — why this option won.
|
|
51
63
|
|
|
52
|
-
|
|
53
|
-
|
|
64
|
+
| Alternative | Why not |
|
|
65
|
+
|---|---|
|
|
66
|
+
| {option considered} | {one line} |
|
|
54
67
|
|
|
55
|
-
|
|
56
|
-
|
|
68
|
+
**Consequences**
|
|
69
|
+
- {what changes as a result — and where it costs, named}
|
|
57
70
|
|
|
58
|
-
|
|
59
|
-
|
|
71
|
+
**Context** *(only when the question's origin is not obvious)*
|
|
72
|
+
{prose — why a decision was needed at all, when the feature doesn't make
|
|
73
|
+
that self-evident}
|
|
60
74
|
```
|
|
61
75
|
|
|
76
|
+
The summary table is mandatory and answers "which decisions exist" without
|
|
77
|
+
reading the file. The alternatives table is mandatory too — an empty one is
|
|
78
|
+
visible in a way missing prose is not, and a decision recorded without its
|
|
79
|
+
rejected alternatives is assertion, not rationale. `Context` is the one
|
|
80
|
+
conditional block: `Because` covers why *this* option won; `Context` covers
|
|
81
|
+
why the question arose, which is frequently self-evident. Statuses:
|
|
82
|
+
`accepted | superseded | deprecated`.
|
|
83
|
+
|
|
62
84
|
---
|
|
63
85
|
|
|
64
86
|
## api.md
|
|
@@ -75,9 +97,12 @@ What changes as a result — positive and negative trade-offs.
|
|
|
75
97
|
## Key Types / Schemas
|
|
76
98
|
|
|
77
99
|
\`\`\`typescript
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
//
|
|
100
|
+
// The type says what a field MEANS; fields.md says what HAPPENS to it.
|
|
101
|
+
interface Invoice {
|
|
102
|
+
id: string; // Stripe invoice id, `in_`-prefixed
|
|
103
|
+
amountDue: number; // minor units (cents) — never format directly
|
|
104
|
+
status: InvoiceStatus; // drives the badge; `draft` is hidden in the list
|
|
105
|
+
voidedAt: string | null; // ISO 8601; null unless voided
|
|
81
106
|
}
|
|
82
107
|
\`\`\`
|
|
83
108
|
|
|
@@ -88,6 +113,12 @@ interface ExampleType {
|
|
|
88
113
|
| {Service} | {What we use it for} | {Rate limits, quirks} |
|
|
89
114
|
```
|
|
90
115
|
|
|
116
|
+
**Every field carries its meaning inline** — trailing `//` by default; a JSDoc
|
|
117
|
+
block only when a line won't do (units, constraints, nullability semantics).
|
|
118
|
+
This is the two-homes rule: a fact with two homes goes missing from the one
|
|
119
|
+
you are reading, and the un-annotated type is the home readers actually open.
|
|
120
|
+
`fields.md` keeps only what a type cannot express — the journey.
|
|
121
|
+
|
|
91
122
|
---
|
|
92
123
|
|
|
93
124
|
## fields.md
|
|
@@ -95,18 +126,20 @@ interface ExampleType {
|
|
|
95
126
|
```markdown
|
|
96
127
|
# Fields — {Feature Name}
|
|
97
128
|
|
|
98
|
-
Document which fields flow from source (BE or 3rd-party API) to destination
|
|
99
|
-
|
|
129
|
+
Document which fields flow from source (BE or 3rd-party API) to destination
|
|
130
|
+
(UI or your BE). The Description column is about the TRANSFORMATION — what
|
|
131
|
+
happens to the field on the way — never about what the field means; meaning
|
|
132
|
+
lives on the type in api.md.
|
|
100
133
|
|
|
101
134
|
## Response Fields — {Endpoint or Source Name}
|
|
102
135
|
|
|
103
136
|
> Source: `GET /api/...` or `{ThirdParty} → BE → FE`
|
|
104
137
|
|
|
105
|
-
| Source Field | UI Label / FE Key | Type | Nullable |
|
|
138
|
+
| Source Field | UI Label / FE Key | Type | Nullable | Transformation |
|
|
106
139
|
|---|---|---|---|---|
|
|
107
|
-
| `user_full_name` | Full Name | `string` | no |
|
|
108
|
-
| `created_at` | Created | `string (ISO 8601)` | no |
|
|
109
|
-
| `metadata.region` | Region | `string` | yes |
|
|
140
|
+
| `user_full_name` | Full Name | `string` | no | rendered as-is in profile card |
|
|
141
|
+
| `created_at` | Created | `string (ISO 8601)` | no | formatted to `MMM D, YYYY` in UI |
|
|
142
|
+
| `metadata.region` | Region | `string` | yes | omitted from UI when null |
|
|
110
143
|
|
|
111
144
|
### Forwarding Chain (3rd-party → BE → FE)
|
|
112
145
|
|
|
@@ -121,10 +154,10 @@ Use this sub-section when your BE proxies a 3rd-party API and renames fields.
|
|
|
121
154
|
|
|
122
155
|
> Sent from FE to `POST /api/...`
|
|
123
156
|
|
|
124
|
-
| FE Key | BE Field | Type | Required |
|
|
157
|
+
| FE Key | BE Field | Type | Required | Transformation |
|
|
125
158
|
|---|---|---|---|---|
|
|
126
|
-
| `email` | `email` | `string` | yes |
|
|
127
|
-
| `preferredName` | `preferred_name` | `string` | no |
|
|
159
|
+
| `email` | `email` | `string` | yes | validated client-side before send |
|
|
160
|
+
| `preferredName` | `preferred_name` | `string` | no | omitted from payload if empty |
|
|
128
161
|
```
|
|
129
162
|
|
|
130
163
|
---
|
|
@@ -134,25 +167,35 @@ Use this sub-section when your BE proxies a 3rd-party API and renames fields.
|
|
|
134
167
|
```markdown
|
|
135
168
|
# Implementation — {Feature Name}
|
|
136
169
|
|
|
137
|
-
## Overview
|
|
138
|
-
One paragraph on how the feature works end-to-end.
|
|
139
|
-
|
|
140
|
-
## Key Files
|
|
141
|
-
|
|
142
170
|
| File | Role |
|
|
143
171
|
|------|------|
|
|
144
172
|
| `src/...` | ... |
|
|
145
173
|
|
|
146
|
-
## Data
|
|
147
|
-
|
|
174
|
+
## Data flow
|
|
175
|
+
|
|
176
|
+
1. {step} — {what happens}
|
|
177
|
+
2. {step} — {what happens}
|
|
148
178
|
|
|
149
|
-
## Patterns
|
|
150
|
-
|
|
179
|
+
## Patterns
|
|
180
|
+
|
|
181
|
+
| Pattern | Where | Why not the obvious thing |
|
|
182
|
+
|---|---|---|
|
|
183
|
+
| {pattern used} | {file or layer} | {what it displaced, one line} |
|
|
151
184
|
|
|
152
185
|
## Dependencies
|
|
186
|
+
|
|
153
187
|
Internal modules or external packages this feature leans on heavily.
|
|
188
|
+
|
|
189
|
+
## Overview *(only when the file table does not already tell the story)*
|
|
190
|
+
|
|
191
|
+
{prose — the end-to-end narrative, when the table and data flow leave it
|
|
192
|
+
untold}
|
|
154
193
|
```
|
|
155
194
|
|
|
195
|
+
Data flow is a numbered list — it is step-by-step by definition and was never
|
|
196
|
+
prose. The Patterns table's third column is mandatory: a pattern recorded
|
|
197
|
+
without the alternative it displaced is trivia, not guidance.
|
|
198
|
+
|
|
156
199
|
---
|
|
157
200
|
|
|
158
201
|
## quirks.md
|
|
@@ -160,10 +203,25 @@ Internal modules or external packages this feature leans on heavily.
|
|
|
160
203
|
```markdown
|
|
161
204
|
# Quirks — {Feature Name}
|
|
162
205
|
|
|
163
|
-
|
|
206
|
+
| # | Quirk | Trigger | Severity | Mitigated |
|
|
207
|
+
|---|---|---|---|---|
|
|
208
|
+
| Q1 | {symptom, one line} | {what sets it off} | low / medium / high | yes / no / partial |
|
|
209
|
+
|
|
210
|
+
## Q1 — {Quirk Title}
|
|
164
211
|
|
|
165
|
-
**Severity:** low | medium | high
|
|
166
212
|
**Discovered:** {date or commit}
|
|
167
213
|
|
|
168
|
-
|
|
214
|
+
**Symptom:** what a reader will observe.
|
|
215
|
+
**Trigger:** what sets it off.
|
|
216
|
+
**Cause:** why it happens.
|
|
217
|
+
**Mitigation:** what to do — or "none", said plainly.
|
|
218
|
+
|
|
219
|
+
{prose — only the part that genuinely needs explaining}
|
|
169
220
|
```
|
|
221
|
+
|
|
222
|
+
Quirk headings are `## Q<n> — Title`, always — `durable-citations.test.mjs`
|
|
223
|
+
resolves every `Q<n>` a spec cites against these headings, so the format is a
|
|
224
|
+
contract, not a style. Numbers are unique and ascending, never reused and
|
|
225
|
+
never renumbered (citations from other specs may point at them). The
|
|
226
|
+
`Mitigated` column is a checkable claim: `yes / no / partial`, with `partial`
|
|
227
|
+
explained in the body's **Mitigation** field.
|