@jabworks/condux 0.16.0 → 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/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": {
|
|
@@ -95,8 +95,24 @@ Parse `commit`, `date`, and the **absolute spec path** from the output — use t
|
|
|
95
95
|
|
|
96
96
|
Read [references/templates.md](references/templates.md) for the structure of each file.
|
|
97
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
|
+
|
|
98
113
|
- Write only files that have real content
|
|
99
|
-
- 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
|
|
100
116
|
- Replace the HTML comment the scaffold left below the title with a one-line
|
|
101
117
|
`> …` note saying what the spec is for. That note is what `spec-browser`'s
|
|
102
118
|
catalog shows for the spec; leave it and the spec is listed with nothing to
|
|
@@ -177,3 +193,5 @@ feedback file, if a decision is submitted).
|
|
|
177
193
|
| Vague decisions | Each decision needs context + rationale + consequences |
|
|
178
194
|
| Creating empty placeholder files | Only create a file when it has real content |
|
|
179
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.
|