@lifeaitools/rdc-skills 0.35.25 → 0.36.1

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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rdc",
3
- "version": "0.35.25",
3
+ "version": "0.36.1",
4
4
  "description": "RDC typed-agent dispatch skill suite for Claude Code — plan, build, review, overnight unattended builds with work-item tracking and TDD enforcement.",
5
5
  "author": {
6
6
  "name": "LIFEAI",
@@ -384,6 +384,30 @@
384
384
  "codeflow_required": true,
385
385
  "purpose": "run a structured agent-to-agent conversation"
386
386
  },
387
+ "convo": {
388
+ "name": "convo",
389
+ "slash": "rdc:convo",
390
+ "category": "dev-loop",
391
+ "usage": "rdc:convo <template> <topic>",
392
+ "args": {
393
+ "positional": [
394
+ { "name": "template", "required": true, "description": "Discussion type", "accepts": "outcome-exploration | design-comparison | troubleshooting | plan-critique | disagreement-resolution | work-handoff" },
395
+ { "name": "topic", "required": true, "description": "Bounded question or outcome", "accepts": "text" }
396
+ ],
397
+ "flags": []
398
+ },
399
+ "requires": [],
400
+ "produces": ["discussion_record", "decision_record"],
401
+ "default_model": "inherit",
402
+ "triggers": ["fair discussion", "attributed peer discussion", "discussion templates", "co-design conversation"],
403
+ "follows": [],
404
+ "leads_to": ["rdc:plan", "rdc:build"],
405
+ "sandbox_aware": true,
406
+ "output_contract": "guides/output-contract.md",
407
+ "enabled_default": true,
408
+ "codeflow_required": false,
409
+ "purpose": "conduct bounded fair discussion and record decisions using existing peer transports"
410
+ },
387
411
  "convert": {
388
412
  "name": "convert",
389
413
  "slash": "rdc:convert",
@@ -0,0 +1,56 @@
1
+ name: Lesson learned
2
+ description: A lesson from real work whose fix is not yet encoded as a guard, test or script. An issue proposes; a work item commits.
3
+ title: "[lesson] "
4
+ labels: ["lesson", "proposal"]
5
+ body:
6
+ - type: markdown
7
+ attributes:
8
+ value: |
9
+ File this in the repository the fix belongs to. **If this repository is public, file it in LIFEAI/regen-root with the area naming this repository instead** — a lesson carries hosts, paths and ports, and a public issue cannot be unsaid. Agents submit the same form from any engine:
10
+
11
+ `node "$LIFEAI_ENV/bin/rdc-lesson.mjs" submit --repo <slug> --title "..." --what "..." --root-cause "..." --fix "..."`
12
+
13
+ A lesson whose fix is already encoded (a guard, test or script shipped with a linked commit) needs no issue; record it in that commit message.
14
+ Accepting this issue creates a work item and relabels it `accepted`; the fixing commit closes it with `Fixes #N`.
15
+ - type: textarea
16
+ id: what-happened
17
+ attributes:
18
+ label: What happened
19
+ description: The concrete situation, with evidence (exit code, file:line, command).
20
+ validations:
21
+ required: true
22
+ - type: textarea
23
+ id: root-cause
24
+ attributes:
25
+ label: Root cause
26
+ description: The evidenced cause, not a guess.
27
+ validations:
28
+ required: true
29
+ - type: textarea
30
+ id: fix
31
+ attributes:
32
+ label: The fix or rule
33
+ description: What should change so this never recurs, as a guard, test, script, or rule line.
34
+ validations:
35
+ required: true
36
+ - type: input
37
+ id: area
38
+ attributes:
39
+ label: Repository / area
40
+ description: The repository slug and the area inside it, e.g. `lifeai-env · hooks/lib` or `rdc-skills · skills/build`.
41
+ validations:
42
+ required: true
43
+ - type: input
44
+ id: encoded
45
+ attributes:
46
+ label: Encoded artifact
47
+ description: The guard, test or script that already enforces part of this fix, if any.
48
+ validations:
49
+ required: false
50
+ - type: textarea
51
+ id: evidence
52
+ attributes:
53
+ label: Evidence
54
+ description: Links to commits, logs, transcripts or work items, one per line.
55
+ validations:
56
+ required: false
@@ -0,0 +1,34 @@
1
+ ---
2
+ id: 2026-09-17-release-mcp-registry-split
3
+ date: "2026-09-17"
4
+ skill: release
5
+ session: 01a07b0d-e74e-7601-af20-9caae7e94b71
6
+ scope: architectural
7
+ status: open
8
+ area: infra
9
+ links:
10
+ commits: [d39104709bf0035f84a8001cc6c30e5c5e0d9c13]
11
+ memory: []
12
+ work_items: [5f7618b4-cf32-4460-8a3a-761f0161b847]
13
+ ---
14
+
15
+ ## What happened
16
+
17
+ rdc-skillsv0.36.0 tag triggered npm workflow35178348993: packing succeeded,
18
+ registryPUT returned404, and npm version lookup remained404. Independently,
19
+ the existing public MCP tag updater served0.36.0 at the exacttagSHA with45skills;
20
+ connected convo retrieval and remote tests passed. Prior0.35.26 workflow also
21
+ shows a PUT404 although that version is now in npm.
22
+
23
+ ## Root cause
24
+
25
+ Two release consumers advance independently: the MCP host follows mergedtags,
26
+ while npm requires a successful authenticatedpublish. A live MCP cannot prove
27
+ npm distribution, nor does failednpm publication prove the MCP is stale. The
28
+ underlying registry permission/trustedpublisher cause is not established by404.
29
+
30
+ ## The fix / rule
31
+
32
+ Keep runtimeSHA/catalog and npmversion/provenance as distinct release evidence.
33
+ Preserve the failedjob; inspect publisherconfiguration with the packageowner
34
+ before changing permissions or retrying. No authboundary repair shipped here.
package/git-sha.json ADDED
@@ -0,0 +1,3 @@
1
+ {
2
+ "sha": "a5325ff86c953a4f64b3deef96551975d530f528"
3
+ }
@@ -5,21 +5,21 @@ system: claude-workflow
5
5
  status: active
6
6
  owner: infrastructure
7
7
  created: 2026-06-08
8
- last_reviewed: 2026-06-08
8
+ last_reviewed: 2026-09-17
9
9
  source_of_truth: true
10
10
  supersedes: []
11
11
  depends_on:
12
12
  - ".claude/rules/architectural-change-approval.md"
13
13
  - ".rdc/guides/output-contract.md"
14
- tags: [rdc, lessons-learned, skills, housekeeping, adaptive]
14
+ tags: [rdc, lessons-learned, skills, housekeeping, adaptive, github-issues]
15
15
  ---
16
16
 
17
17
  # Lessons-Learned Capture & Triage — Spec
18
18
 
19
19
  > Auto-referenced by long-running `rdc:*` skills at exit, and by `rdc:housekeeping` for triage.
20
20
  > Goal: make the fleet an **interactive adaptive modeler** — every run that teaches us
21
- > something writes it down, and the weekly housekeeping pass turns those lessons into
22
- > actual fixes (rules, skill docs, work_items).
21
+ > something records it where the fix belongs, and the weekly housekeeping pass turns those
22
+ > lessons into actual fixes (guards, tests, scripts, rule lines, work items).
23
23
 
24
24
  ---
25
25
 
@@ -28,126 +28,250 @@ tags: [rdc, lessons-learned, skills, housekeeping, adaptive]
28
28
  Lessons learned during a run (a non-obvious infra trap, a wrong assumption, a missing
29
29
  gate, a tooling gotcha) used to survive only if someone hand-wrote a memory. This system
30
30
  makes capture a **routine exit step** of every long skill, and triage a **routine phase**
31
- of the weekly housekeeping. Capture is cheap and append-only; triage is where fixes happen.
31
+ of the weekly housekeeping. Capture is cheap; triage is where fixes happen.
32
32
 
33
33
  Precedent: brochurify's `extract-verifier-rules` already does read-log → cluster →
34
34
  propose-rule for one domain. This generalizes that pattern fleet-wide.
35
35
 
36
- ---
36
+ ### Why lessons are not files any more
37
37
 
38
- ## Storage directory of per-lesson files
38
+ Until 2026-09 every lesson was a markdown file in the capturing repository's
39
+ `.rdc/lessons/`. A census of one repository found 315 of them: 157 already enforced in code,
40
+ where the file only repeated what a guard or test already guaranteed, and 32 enforced
41
+ nowhere, sitting in a directory the owner of the fix never reads. A lesson filed where it
42
+ was noticed, rather than where it is fixed, is a lesson nobody who can fix it sees.
39
43
 
40
- Lessons live in **`.rdc/lessons/`**, one markdown file per lesson:
44
+ So the record now follows the fix:
41
45
 
42
- ```
43
- .rdc/lessons/<YYYY-MM-DD>-<skill>-<short-slug>.md
44
- ```
46
+ - **An encoded lesson needs no file.** The guard, test or script that enforces it is the
47
+ record, and the commit that shipped it carries the narrative.
48
+ - **An unencoded lesson is a GitHub issue in the repository the fix belongs to**, labelled
49
+ `lesson` + `proposal`. **An issue proposes; a work item commits.**
45
50
 
46
- - One file per lesson (NOT a single appended file) so parallel agents finishing at the
47
- same time never collide on one file in git.
48
- - `<skill>` is the capturing skill (`build`, `deploy`, `overnight`, `fixit`, `plan`,
49
- `preplan`, `review`, `release`, `collab`).
50
- - `<short-slug>` is 2–4 kebab words naming the lesson.
51
+ ---
51
52
 
52
- A run that taught nothing writes nothing — **absence is the default**. Only write a lesson
53
- when something was genuinely learned (see § When to capture).
53
+ ## When to capture (at skill exit)
54
54
 
55
- ---
55
+ A lesson exists when ANY of these were true during the run:
56
56
 
57
- ## Lesson file schema
57
+ 1. A root cause turned out to be different from the first theory (a wrong assumption).
58
+ 2. The standard/documented path didn't work and you had to do something non-obvious.
59
+ 3. A gate, check, or doc was missing and its absence cost a round.
60
+ 4. A tool/infra behaved in a surprising way (exit codes, caching, serve/PM2/webhook quirks).
61
+ 5. A hook blocked you and the block revealed a real gap (not just your mistake).
62
+
63
+ Do NOT capture: routine success, your own one-off typo, anything already fully documented
64
+ in a rule/guide, or a settled agreement (that is a Decision and belongs in the plan). If a
65
+ durable user preference or correction was involved, also write a `memory` (this spec and
66
+ memory are complementary — link them). A run that taught nothing records nothing —
67
+ **absence is the default**.
58
68
 
59
- ```markdown
60
- ---
61
- id: <YYYY-MM-DD>-<skill>-<short-slug>
62
- date: "<YYYY-MM-DD>"
63
- skill: build | deploy | overnight | fixit | plan | preplan | review | release | collab
64
- session: <session-id or short ref>
65
- scope: simple | architectural # triage routing — see § Scope gate
66
- status: open | triaged | applied | wont-fix
67
- area: infra | skill | guide | rule | schema | ui | content | other
68
- links:
69
- commits: [] # SHAs that relate to the lesson
70
- memory: [] # memory file slugs, if a memory was also written
71
- work_items: [] # work_item UUIDs spawned during triage
72
69
  ---
73
70
 
74
- ## What happened
75
- <one paragraph — the concrete situation, with evidence (exit code, file:line, command)>
71
+ ## The two outcomes
76
72
 
77
- ## Root cause
78
- <one paragraph — the evidenced cause, not a guess>
73
+ | The fix is… | Record | Where |
74
+ |---|---|---|
75
+ | **Encoded in this run** — a guard, test or script shipped, commit linked | the commit message | no file, no issue |
76
+ | **Partly encoded** — some of it ships, the rest does not | one issue, Encoded artifact filled | the repository the fix belongs to |
77
+ | **Not encoded** — a fix is known or needed but not shipped | one `lesson` + `proposal` issue | the repository the fix belongs to |
79
78
 
80
- ## The fix / rule
81
- <what should change so this never recurs: a rule edit, skill-doc line, code change,
82
- or a check. If already applied in the same run, say so and link the commit.>
83
- ```
79
+ "Encoded" means something now **fails** when the lesson is violated: a guard rule blocks it,
80
+ a test goes red, a script refuses it. A sentence added to a rule or skill document is not
81
+ encoding prose drifts from behaviour so a new doc-only lesson is an issue until a guard or
82
+ test carries it.
84
83
 
85
- `scope` is the single most important field it routes triage:
84
+ **The owning repository** is the one whose code or documents change to fix it, not the one
85
+ where the run happened. A clauth behaviour found during a regen-root build is a clauth lesson.
86
86
 
87
- - **`simple`** a doc line, a one-file fix, a config tweak, a clarifying sentence in a
88
- skill, a missing grep guard. Housekeeping applies these directly.
89
- - **`architectural`** — anything matching `.claude/rules/architectural-change-approval.md`
90
- (rule/CLAUDE.md/ARCHITECTURE.md edits, cross-cutting refactors, schema reshape, public
91
- API/MCP changes, skill-contract changes affecting multiple skills). Housekeeping does
92
- NOT apply these; it surfaces them via `AskUserQuestion` for explicit approval first.
87
+ ### Public repositories file in regen-root
93
88
 
94
- When unsure, mark `architectural`.
89
+ A lesson is written from inside the estate and routinely names hosts, ports, paths and vault
90
+ services; a public issue cannot be unsaid. **LIFEAI/rdc-skills is public**, so its lessons
91
+ default to the private monorepo: `--repo regen-root --area rdc-skills`. Likewise CodeFlow, whose
92
+ active development is regen-root `packages/codeflow`: `--repo regen-root --area codeflow`.
95
93
 
96
- ---
94
+ `rdc-lesson submit` reads the target's visibility before any write and refuses a PUBLIC
95
+ repository (exit 3) with that route. `--public-ok` overrides it for a lesson that carries no
96
+ estate detail, and even then the title and body are secret-scanned (credentials, private keys,
97
+ IP addresses, clauth `/v/<service>` paths) and refused on any hit.
97
98
 
98
- ## When to capture (at skill exit)
99
+ ---
99
100
 
100
- Write a lesson when ANY of these were true during the run:
101
+ ## Capture procedure (the exit step long skills call)
101
102
 
102
- 1. A root cause turned out to be different from the first theory (a wrong assumption).
103
- 2. The standard/documented path didn't work and you had to do something non-obvious.
104
- 3. A gate, check, or doc was missing and its absence cost a round.
105
- 4. A tool/infra behaved in a surprising way (exit codes, caching, serve/PM2/webhook quirks).
106
- 5. A hook blocked you and the block revealed a real gap (not just your mistake).
103
+ At the end of a long skill run, before the final verdict line:
107
104
 
108
- Do NOT capture: routine success, your own one-off typo, anything already fully documented
109
- in a rule/guide. If a durable user preference or correction was involved, also write a
110
- `memory` (this spec and memory are complementary — link them).
105
+ 1. Decide if anything qualifies When to capture). If not, record nothing and move on.
106
+ 2. For each lesson, name the owning repository's registry slug (a `projects.json` key:
107
+ `lifeai-env`, `clauth`, `regen-root`, `regen-deploy-mgr`, …; a public repository's lesson
108
+ uses `regen-root` with `--area <repo>`, § Public repositories).
109
+ 3. **Encoded in this run** → record it in the commit message of the change that encodes it.
110
+ `rdc-lesson` prints the record (one `Key: value` line per field), opens nothing, and calls
111
+ GitHub not at all:
112
+
113
+ ```bash
114
+ node "$LIFEAI_ENV/bin/rdc-lesson.mjs" submit --repo <owning slug> --encoded <guard/test/script path> \
115
+ --title "<one line>" --what "<what happened, with evidence>" \
116
+ --root-cause "<evidenced cause>" --fix "<what now enforces it>"
117
+ ```
118
+
119
+ Part of it ships and part does not → add `--partial`: the issue opens with the Encoded
120
+ artifact section filled.
121
+ 4. **Not encoded** → submit it. It opens ONE issue titled `[lesson] <title>`, labelled
122
+ `lesson` + `proposal`, in the repository the slug resolves to:
123
+
124
+ ```bash
125
+ node "$LIFEAI_ENV/bin/rdc-lesson.mjs" submit --repo <owning slug> \
126
+ --title "<one line>" --what "<what happened, with evidence: command, exit code, file:line>" \
127
+ --root-cause "<evidenced cause, not a guess>" --fix "<the guard, test, script or rule that would stop it>" \
128
+ [--area <area>] [--evidence <commit/log/work-item URL> ...]
129
+ ```
130
+
131
+ - The same exact title already **open** → nothing opens; the existing URL is printed, so a
132
+ retry is safe.
133
+ - The same exact title **closed** → the lesson recurred: the new occurrence is commented on
134
+ that issue and it is reopened (`action: recurred`). A fix that did not hold is the most
135
+ important lesson there is; it must not be filed as a stranger.
136
+ - `--dry-run` shows the issue and calls nothing. An unknown flag is refused by name, so a
137
+ typo such as `--encode` never silently opens an issue.
138
+ - An unregistered slug fails and names itself; do not file the lesson in a different
139
+ repository to get past that — report it.
140
+ 5. Mention in the verdict/summary: "N lessons captured (E encoded, S submitted: <issue URLs>)".
141
+
142
+ Where `@lifeai/lifeai-env` is installed globally the command is also `rdc-lesson submit …`.
143
+ Without `$LIFEAI_ENV` (the `core` profile, or claude.ai), open the issue from the owning
144
+ repository's **Lesson learned** issue form (`.github/ISSUE_TEMPLATE/lesson.yml`); it applies
145
+ the same title prefix, labels and sections.
146
+
147
+ **Accepted residual:** two submits of the same new title at the same moment can both pass the
148
+ duplicate check and open two issues. Triage closes the later one as a duplicate of the first.
149
+
150
+ ### What the issue carries
151
+
152
+ The form and the CLI produce the same sections, in this order:
153
+
154
+ - **What happened** — the concrete situation, with evidence (exit code, file:line, command).
155
+ - **Root cause** — the evidenced cause, not a guess.
156
+ - **The fix or rule** — what should change so this never recurs.
157
+ - **Repository / area** — the owning slug and the area inside it.
158
+ - **Encoded artifact** — anything that already enforces part of the fix.
159
+ - **Evidence** — commits, logs, transcripts, work items.
111
160
 
112
161
  ---
113
162
 
114
- ## Capture procedure (the exit step long skills call)
163
+ ## Accepting a lesson (issue work item)
115
164
 
116
- At the end of a long skill run, before the final verdict line:
165
+ An issue is a proposal. Work begins only when it is accepted:
166
+
167
+ 1. Create the work item through the work-item RPCs, naming the issue URL in its description.
168
+ 2. Link and relabel the issue:
169
+
170
+ ```bash
171
+ node "$LIFEAI_ENV/bin/rdc-lesson.mjs" accept <issue-number-or-url> --repo <owning slug> --work-item <uuid>
172
+ ```
173
+
174
+ This comments `Accepted as work item <uuid>` first, then removes `proposal` and adds
175
+ `accepted`. If the relabel fails, run it again: it sees the comment and finishes the
176
+ relabel without a second comment. It refuses an issue that is not labelled `lesson`, and
177
+ does not create the work item.
117
178
 
118
- 1. Decide if anything qualifies (§ When to capture). If not, write nothing and move on.
119
- 2. For each lesson, write `.rdc/lessons/<date>-<skill>-<slug>.md` using the schema above.
120
- Set `status: open` (or `applied` if you already shipped the fix in this same run, with
121
- the commit linked).
122
- 3. Set `scope` honestly (`simple` vs `architectural`).
123
- 4. Commit the lesson file(s) on `develop` alongside the run's other commits.
124
- 5. Mention in the verdict/summary that N lessons were captured.
179
+ ## Closing a lesson
180
+
181
+ The fixing commit closes the issue with `Fixes #N` (or `Fixes LIFEAI/<repo>#N` from another
182
+ repository) — but GitHub acts on that only when the commit reaches the repository's **default
183
+ branch**. Where fixes land somewhere else first, close it explicitly once the fix is on the
184
+ integration branch:
185
+
186
+ ```bash
187
+ node "$LIFEAI_ENV/bin/rdc-lesson.mjs" close <issue-number-or-url> --repo <owning slug> --commit <sha> [--reason "<text>"]
188
+ ```
189
+
190
+ It comments `Fixed by <sha>` and closes the issue as completed. This applies to **regen-root**
191
+ (default branch `main`, integration `develop`) and **regen-deploy-mgr** (default branch
192
+ `codex/regen-deploy-mgr-wp1`, which does not carry what ships). Not worth fixing → close the
193
+ issue as not planned with a one-line reason.
125
194
 
126
195
  ---
127
196
 
128
197
  ## Triage procedure (rdc:housekeeping, weekly)
129
198
 
130
- `rdc:housekeeping` adds a **Lessons triage** phase:
199
+ `rdc:housekeeping` runs a **Lessons triage** phase over open lesson issues:
200
+
201
+ ```bash
202
+ node "$LIFEAI_ENV/bin/rdc-lesson.mjs" list --state open # every registered repository
203
+ node "$LIFEAI_ENV/bin/rdc-lesson.mjs" list --repo <slug> --json # one repository, machine-readable
204
+ ```
205
+
206
+ Every registered repository is listed, skipped because its issues are switched off (reported,
207
+ not a failure), or **NOT listed** — no GitHub repository resolves, or the read failed. NOT
208
+ listed is named on stderr and in `--json` `skipped` with its reason, `complete` is false, and
209
+ the command exits 1. Treat that as an incomplete triage, never as "no lessons there".
210
+
211
+ 1. Cluster open `proposal` issues by area + root-cause similarity (dedupe repeats into one fix;
212
+ close the duplicates as duplicates, linking the survivor). A reopened `recurred` issue goes
213
+ first: its fix did not hold.
214
+ 2. Decide each cluster's scope:
215
+ - **simple** — a one-file fix, a config tweak, a missing grep guard, a test.
216
+ - **architectural** — anything matching `.claude/rules/architectural-change-approval.md`
217
+ (rule/CLAUDE.md/ARCHITECTURE.md edits, cross-cutting refactors, schema reshape, public
218
+ API/MCP changes, skill-contract changes affecting multiple skills). When unsure, it is
219
+ architectural.
220
+ 3. Route per the mode below.
221
+ 4. Work the conversion backlog (§ Existing `.rdc/lessons/` files) with whatever capacity is left.
222
+ 5. Summarize in the housekeeping report: open / recurred / accepted / closed-fixed /
223
+ closed-won't-fix counts with issue URLs, plus backlog files converted and remaining.
224
+
225
+ ### Attended mode (default — a human is present)
226
+
227
+ - **simple** → accept it (§ Accepting), apply the fix directly as a guard/test/script, commit
228
+ with `Fixes #N` (or close it with `rdc-lesson close`, § Closing).
229
+ - **architectural** → do NOT edit. Present the issue + options via `AskUserQuestion` (per
230
+ `architectural-change-approval.md`). On approval, accept it and apply via the correct
231
+ lifecycle (rdc-skills tag/push for skills; cited commit for rules). If deferred, accept it so
232
+ the work item carries it.
233
+ - **Not worth fixing** → close the issue as not planned with a one-line reason.
234
+
235
+ ### Triage procedure — UNATTENDED weekly mode
236
+
237
+ No human present (overnight / cron / `rdc:overnight`) — never run `AskUserQuestion`:
238
+
239
+ - **Per-difficulty model routing** (reuses the `rdc:build` table): clustering and scope
240
+ triage → `claude-sonnet-5`; mechanical apply → `claude-haiku-4-5`; harder multi-file or
241
+ migration fix → `claude-sonnet-5`; design/architectural fix → `claude-opus-5`.
242
+ - **simple** → accept, apply directly or via `rdc:fixit`, commit with `Fixes #N` or close with
243
+ `rdc-lesson close`.
244
+ - **architectural with a single clear correct fix** (records an already-learned lesson —
245
+ "add a gate", "encode X as a test") → accept, route through `rdc:plan` → `rdc:build` (or
246
+ `rdc:fixit` if genuinely under 5 files).
247
+ - **architectural and genuinely ambiguous** (multiple valid approaches, real tradeoffs) → write
248
+ a `human_items` row (`item_type='decision'`, options in `suggested_agent_prompt`,
249
+ `source_type='lesson'`, `source_fingerprint` = the issue URL for dedupe), accept the issue
250
+ against a linked work item, and leave the decision for the morning. This is the asynchronous
251
+ equivalent of the attended interview.
252
+
253
+ Issues are closed, never deleted — a closed issue with its fixing commit, or its won't-fix
254
+ reason, is the audit trail.
255
+
256
+ ---
257
+
258
+ ## Existing `.rdc/lessons/` files — the conversion backlog
131
259
 
132
- 1. Read all `.rdc/lessons/*.md` with `status: open`.
133
- 2. Cluster by `area` + root-cause similarity (dedupe repeats into one fix).
134
- 3. For each cluster:
135
- - `scope: simple` apply the fix directly (rule line, skill-doc edit, config, guard),
136
- commit it, set the lesson(s) `status: applied` and link the commit.
137
- - `scope: architectural` → do NOT edit. Present the issue + options via
138
- `AskUserQuestion` (per `architectural-change-approval.md`). On approval, apply via the
139
- correct lifecycle (rdc-skills tag/push for skills; cited commit for rules) and set
140
- `status: applied`. If deferred, set `status: triaged` and spawn a `work_item`.
141
- - Not worth fixing → `status: wont-fix` with a one-line reason.
142
- 4. Summarize in the housekeeping report: captured / applied / escalated / deferred counts.
260
+ Files written under the old procedure are retired by state: an encoded lesson's file is
261
+ deleted and links to it point at the enforcing artifact; an unencoded one becomes an issue in
262
+ its owning repository. **The files that remain — doc-only lessons and product lessons — are a
263
+ backlog to convert, not a place to capture.** Each is done when a guard or test carries it:
264
+ ship that artifact, point any live link at it, and delete the file in the same commit.
143
265
 
144
- Lessons are never silently deleted — `applied` and `wont-fix` files stay as the audit trail.
266
+ Housekeeping lists the remaining `.rdc/lessons/*.md` files for exactly that purpose and
267
+ reports the count converted and remaining. Nothing new is written there: a new lesson — a
268
+ doc-only one included — is an issue (§ Capture procedure).
145
269
 
146
270
  ---
147
271
 
148
272
  ## Skills that capture (the long-running set)
149
273
 
150
- `build` · `deploy` · `overnight` · `fixit` · `plan` · `preplan` · `review` · `release` · `collab`
274
+ `build` · `overnight` · `fixit` · `plan` · `preplan` · `review` · `release` · `collab` ·
275
+ `onramp`
151
276
 
152
- Each references this spec from a final "§ Capture lessons" step. A Stop-hook backstop warns
153
- when one of these skills ends a run with findings but no new `.rdc/lessons/` file.
277
+ Each references this spec from a final "§ Capture lessons" step.
@@ -142,9 +142,35 @@ A session with **no contract** — one that only read, planned or answered — s
142
142
  gets the evidence checks: tracked changes it left uncommitted, and a claimed work
143
143
  item's open DoD. How its final message is worded is never judged.
144
144
 
145
+ **Setting work aside.** A session ends one of three ways: the work is proved, it waits,
146
+ or someone else takes it. Say which — never leave the Stop to repeat an open DoD:
147
+
148
+ ```bash
149
+ # It waits: the database marks the item blocked, with the reason in its notes.
150
+ node "$LIFEAI_ENV/bin/rdc-work.mjs" hold --work-item <uuid> --reason "<why it waits>" --session <id>
151
+ # Pick it up later, from this session or any other: in_progress again, declared on the contract.
152
+ node "$LIFEAI_ENV/bin/rdc-work.mjs" resume --work-item <uuid> --session <id>
153
+ # Someone else takes it:
154
+ node "$LIFEAI_ENV/bin/rdc-work.mjs" handoff --work-item <uuid> --to "<who takes it over>" \
155
+ --reason "<why this session is not finishing it>" [--note <handoff doc>] --session <id>
156
+ ```
157
+
158
+ Only work the session holds — declared with `--work-item`, or claimed — can be set aside.
159
+ A held item's open DoD stops holding the Stop **while the database says `blocked`**; a
160
+ hold the database does not confirm lifts nothing and the Stop says so. A handed-off item
161
+ shows as `[>] handed off … theirs now: <rows>`. Neither is ever counted as proof. Drop the
162
+ rows this session will not prove, and commit or discard your own changes first — setting
163
+ work aside moves the obligation, not unsaved work, and uncommitted changes still hold the Stop.
164
+
165
+ The held Stop lists only what is still owed: proved and dropped rows are counted, not
166
+ listed, and rows stale only because of a later edit in the same repository collapse to
167
+ one line. An edit in a different repository does not stale this contract's proofs.
168
+
145
169
  Enforcement is bounded: a Stop held identically three times, or six times in a row,
146
170
  releases, and the unproved rows stay in the contract and in the compaction snapshot.
147
- A defect in the gate itself an unreadable contract, an error reports and never holds.
171
+ A released or resolved checklist is shown once, not after every later turn; a changed
172
+ one is shown again. A defect in the gate itself — an unreadable contract, an error —
173
+ reports and never holds.
148
174
 
149
175
  ## Target resolution — never assume regen-root
150
176
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lifeaitools/rdc-skills",
3
- "version": "0.35.25",
3
+ "version": "0.36.1",
4
4
  "description": "RDC typed-agent dispatch skill suite for Claude Code - plan, build, review, overnight builds",
5
5
  "keywords": [
6
6
  "claude-code",
@@ -1277,7 +1277,14 @@ async function main() {
1277
1277
  const pkg = readJson(path.join(repoRoot, 'package.json'));
1278
1278
  const version = pkg.version || '0.7.0';
1279
1279
  let gitSha = '';
1280
- try { gitSha = execSync('git rev-parse HEAD', { cwd: repoRoot, encoding: 'utf8', stdio: 'pipe' }).trim(); } catch {}
1280
+ if (fs.existsSync(path.join(repoRoot, '.git'))) {
1281
+ try { gitSha = execSync('git rev-parse HEAD', { cwd: repoRoot, encoding: 'utf8', stdio: 'pipe' }).trim(); } catch {}
1282
+ } else {
1283
+ // An npm-installed package has no .git — and `git rev-parse` would walk up into
1284
+ // whatever repository encloses it. The commit is the pack-time stamp instead.
1285
+ gitSha = String(readJson(path.join(repoRoot, 'git-sha.json'))?.sha || '');
1286
+ if (gitSha === 'unknown') gitSha = '';
1287
+ }
1281
1288
 
1282
1289
  // 0.5a. User-skills cleanup — remove any rdc: skills from ~/.claude/skills/user/
1283
1290
  // (older installer versions wrote there; plugin cache is the only authoritative source)
@@ -72,7 +72,7 @@ for (let i = 0; i < args.length; i++) {
72
72
  /**
73
73
  * Resolve the regen-root monorepo checkout this run should validate against.
74
74
  *
75
- * 2026-07-26 (lesson 2026-07-26-deploy-worktree-validator-root): hardcoding
75
+ * 2026-07-26 (retired lesson 2026-07-26-deploy-worktree-validator-root): hardcoding
76
76
  * 'C:/Dev/regen-root' made every check run against the main tree even when
77
77
  * this validator was invoked from a registered worktree lane
78
78
  * (`C:/Dev/regen-root.wt/<lane>`), so a newly-landed app's PUBLISH.md read as
@@ -390,7 +390,7 @@ Read the task title and description, then:
390
390
  ### ⛔ Foreign concurrent session guard — `git status` BEFORE the build
391
391
  Worktree isolation protects against THIS build's own agents, not against a
392
392
  DIFFERENT session (another cell, a Codex run, a human) already committing on
393
- the same shared tree (lesson 2026-06-16-build-concurrent-session-shared-tree-commit-corruption:
393
+ the same shared tree (retired lesson 2026-06-16-build-concurrent-session-shared-tree-commit-corruption:
394
394
  a foreign session's staged-but-uncommitted files were swept into this build's
395
395
  commit under the wrong message). Before dispatching any wave, run `git status`
396
396
  to detect foreign-dirty files you did not create. If foreign-dirty files are
@@ -572,7 +572,7 @@ Read the task title and description, then:
572
572
  rely on hoisted monorepo deps."*
573
573
  - **A server/MCP/API task is NOT done without a committed automated test that
574
574
  ships in the SAME commit and exercises EVERY surface.** Manual curl / a single
575
- `/health` 200 is a proxy, not coverage (lesson 2026-06-10-build-weak-dod-no-tests).
575
+ `/health` 200 is a proxy, not coverage (retired lesson 2026-06-10-build-weak-dod-no-tests).
576
576
  For a collection (MCP skills, API routes, CLI commands): loop over ALL items
577
577
  and assert `output == source` — never a single spot check. Wire an npm script
578
578
  and run it green before the item leaves `review`. Agent prompt line: *"This
@@ -747,4 +747,10 @@ NEVER run pnpm build or pnpm turbo. Use npx vitest run only.
747
747
 
748
748
  ## Capture lessons (exit step)
749
749
 
750
- Before the final verdict line, follow `.rdc/guides/lessons-learned-spec.md` § Capture procedure. If this run taught something non-obvious — a first root-cause theory that turned out wrong, the documented/standard path not working, a missing gate or check that cost a round, or a surprising tool/infra behavior — write one `.rdc/lessons/<YYYY-MM-DD>-build-<short-slug>.md` per lesson using the schema in that spec. Set `scope` (`simple` | `architectural`) and `status` (`open`, or `applied` if you shipped the fix in this same run, with the commit linked). Commit the lesson file(s) on `develop` alongside the run's other commits, and note "N lessons captured" in your verdict/summary. A run that taught nothing writes nothing — absence is the default.
750
+ Before the final verdict line, follow `.rdc/guides/lessons-learned-spec.md` § Capture procedure. If this run taught something non-obvious — a first root-cause theory that turned out wrong, the documented/standard path not working, a missing gate or check that cost a round, or a surprising tool/infra behavior — record each lesson where its fix belongs:
751
+
752
+ - **Fix encoded in this run** (a guard, test or script shipped, commit linked): the lesson goes in that commit's message. No file, no issue.
753
+ - **Fix not encoded**: submit it to the repository the fix belongs to, which opens one `lesson` + `proposal` issue there (an identical title opens nothing):
754
+ `node "$LIFEAI_ENV/bin/rdc-lesson.mjs" submit --repo <owning repo slug> --title "…" --what "…" --root-cause "…" --fix "…"`
755
+
756
+ No lesson file is written. Note "N lessons captured (E encoded, S submitted)" with the issue URLs in your verdict/summary. A run that taught nothing records nothing — absence is the default.
@@ -462,7 +462,7 @@ An agreement is a **Decision**. Route it by kind:
462
462
  |---|---|
463
463
  | Settled decision, constraint, or policy | The governing document — plan / ARCHITECTURE.md / rule. AKG ingests from there. |
464
464
  | Work to perform | `insert_work_item` via RPC, per `.claude/rules/work-items-rpc.md` |
465
- | A genuine hard-won episode (a wrong theory, a surprising infra behaviour) | `.rdc/lessons/` per `guides/lessons-learned-spec.md` |
465
+ | A genuine hard-won episode (a wrong theory, a surprising infra behaviour) | A `lesson` issue in the repository the fix belongs to, per `guides/lessons-learned-spec.md` |
466
466
  | A stated, unresolved disagreement | Escalate — Step 6 |
467
467
 
468
468
  **Do not file a settled agreement as a lesson.** That is the single most common
@@ -576,8 +576,12 @@ and avoids acting on a misread premise (lesson
576
576
  ## Capture lessons (exit step)
577
577
 
578
578
  Before the final verdict line, follow `guides/lessons-learned-spec.md` § Capture
579
- procedure. Write a lesson only for a genuine **episode** — a first root-cause
579
+ procedure. Record a lesson only for a genuine **episode** — a first root-cause
580
580
  theory that proved wrong, a documented path that did not work, a surprising
581
- tool/infra behaviour. **A settled agreement is not a lesson** (see Step 5). Set
582
- `scope` and `status`; commit alongside the run's other commits; note "N lessons
583
- captured" in the verdict. A run that taught nothing writes nothing.
581
+ tool/infra behaviour. **A settled agreement is not a lesson** (see Step 5). A
582
+ lesson whose fix shipped as a guard, test or script this run goes in that
583
+ commit's message; any other lesson is submitted to the repository the fix
584
+ belongs to, as one `lesson` + `proposal` issue:
585
+ `node "$LIFEAI_ENV/bin/rdc-lesson.mjs" submit --repo <owning repo slug> --title "…" --what "…" --root-cause "…" --fix "…"`.
586
+ No lesson file is written. Note "N lessons captured" with the issue URLs in the
587
+ verdict. A run that taught nothing records nothing.
@@ -0,0 +1,178 @@
1
+ ---
2
+ name: convo
3
+ description: "rdc:convo — fair attributed discussion using six reusable templates, shared sources, explicit dissent and durable decisions; not an implementation dispatch."
4
+ ---
5
+
6
+ > **OUTPUT CONTRACT:** `guides/output-contract.md`. Show the selected template,
7
+ > discussion progress and decision boundary, not transport logs.
8
+ > **Sandbox contract:** Under `RDC_TEST=1`, do not contact live peers or mutate
9
+ > external state. Return a labeled simulated discussion packet; absent peer
10
+ > responses remain UNKNOWN, never simulated agreement.
11
+
12
+ # rdc:convo — shared deliberation, explicit decisions
13
+
14
+ Invoke `rdc:convo <template> <topic>`. Templates: `outcome-exploration`,
15
+ `design-comparison`, `troubleshooting`, `plan-critique`,
16
+ `disagreement-resolution`, `work-handoff`.
17
+ All six templates are included here so MCP callers receive the complete contract.
18
+ Use for a requested discussion, co-design or second opinion. Ordinary questions
19
+ do not need a peer round. Implementation stays in `rdc:plan` / `rdc:build`.
20
+
21
+ ## Shared contract — applies to every template
22
+
23
+ 1. Preserve the user's exact outcome, scope and permissions. Choose the closest
24
+ template; announce a template switch without resetting the round count.
25
+ Default budget: at most three completed rounds, up to 600 words per peer per
26
+ round, equal opportunity to respond. These are defaults, not authority to
27
+ shorten content the user explicitly requested. Finish early when resolved.
28
+ 2. Name participants by actual engine/person and session identity; use UNKNOWN
29
+ for unavailable identity or version. Roles (proposer, challenger, recorder,
30
+ decision owner) come from the task, not the engine brand. A workflow layer is
31
+ context, not a participant. No automatic Claude-supervisor/Codex-worker split.
32
+ 3. Build one source packet: verbatim user scope; template id and skill version
33
+ (plugin version and/or repository revision, never guessed);
34
+ repository/revision or document version; explicit file excerpts and observation
35
+ list with as-of times; assumptions; authorized decision owner; recorder and
36
+ record destination; round budget. Hash the exact UTF-8 packet with SHA-256.
37
+ Send identical bytes to each peer and the hash separately. Each echoes the
38
+ received hash; if it can independently hash the bytes, record that separately.
39
+ A mismatch pauses decision-making until corrected; do not count an echo as an
40
+ independent integrity check. Reissue a changed packet with a new hash to all.
41
+ 4. Use an existing verified transport: `rdc:co-develop` for addressed peer turns,
42
+ or `rdc:collab` for an already available native/relay participant. Load the
43
+ selected transport procedure. Reuse its send/reply and session correlation,
44
+ not its default role or write permissions. A person's reply in the current
45
+ user session is also a valid transport for that person. This contract grants no
46
+ implementation, commit, deployment, approval or task-completion authority.
47
+ Do not create another queue, scheduler or transport. Never invent a reply.
48
+ 5. Every turn carries discussion/session id, turn id, reply-to id, participant,
49
+ round, packet hash and as-of. Replies distinguish AGREE, AMEND, DISAGREE,
50
+ UNKNOWN and DEFER per point, with reasons and source references. Observed facts,
51
+ supplied-source analysis and inference stay distinct. Preserve exact peer text;
52
+ recorder summaries are separate and attributed. Silence is not agreement.
53
+ A supplied-source peer review is not a claim the peer ran tests or read files.
54
+ 6. Missing or delayed replies: inspect the same live process/session/turn handle.
55
+ A polling timeout is not terminal and does not authorize another dispatch.
56
+ Continue independent work while a confirmed live call runs. Report
57
+ PEER_UNAVAILABLE only after a terminal result or missing handle is established;
58
+ retain its evidence and unresolved points. Never replace a missing participant
59
+ with the coordinator's answer. Stop debate at its agreed budget, recording
60
+ unresolved positions rather than manufacturing consensus. An authorized
61
+ decision owner may close as UNRESOLVED while a call remains live, recording
62
+ its pending turn and handle. That does not mean PEER_UNAVAILABLE, cancel the
63
+ call, or authorize re-dispatch; the owner retains responsibility for its result.
64
+ 7. The user may name the recorder; otherwise the existing authorized coordinator
65
+ records within the task's project. Only that recorder writes the discussion
66
+ artifact, at the established project decision/report location. No authorized
67
+ destination means return the record inline without a file write. Retain turns
68
+ append-only within the record; later corrections reference the original turn.
69
+ Share only task-relevant, authorized sources; omit credentials and unrelated
70
+ private content. A durable decision contains the packet/version, attributed
71
+ turns, accepted and rejected proposals with reasons, dissent, uncertainty,
72
+ decision owner, artifact owner, next action and evidence required.
73
+ 8. Label the outcome AGREED, DECIDED_WITH_DISSENT, UNRESOLVED or PEER_UNAVAILABLE.
74
+ Only explicit assent supports AGREED. An authorized owner may decide without
75
+ consensus, retaining the other position. A disagreement never grants new
76
+ authority. For reversible in-scope decisions use existing delegation; ask the
77
+ user or authorizing principal
78
+ only when authorization or a material choice is genuinely missing.
79
+ 9. Handoff proposes a bounded plan/build brief with accepted constraints, exact
80
+ artifacts, ownership and failing acceptance checks. If execution is already
81
+ authorized, the coordinator continues through the existing governed workflow;
82
+ otherwise request that authority. Discussion does not close work items or
83
+ advance Flowable stages. In CDE-Zoe, save durable decisions/artifacts to the
84
+ authorized blackboard/project; retain conversation as transcript, not fabricated
85
+ workflow state. An unavailable persistence route is reported as unsaved.
86
+
87
+ ## Templates
88
+
89
+ Select one block and fill its inputs. The shared contract above supplies identity,
90
+ fairness, authority, recording and termination; do not duplicate or override it.
91
+
92
+ ### outcome-exploration
93
+ ```json
94
+ {
95
+ "template": "outcome-exploration",
96
+ "inputs": ["Exact desired change and beneficiary", "Company/program/project/topic scope, unknowns explicit", "Constraints and available observations"],
97
+ "process": ["Separate purpose and outcome from proposed implementation", "Compare observable success and non-goals; expose missing assumptions"],
98
+ "outputs": ["Outcome brief with acceptance evidence", "Non-goals and unresolved scope questions"],
99
+ "owner": "Authorized outcome owner; recorder names the brief owner",
100
+ "dissent": "Keep competing interpretations and whose evidence would distinguish them",
101
+ "handoff": "rdc:plan with the accepted outcome; unresolved material scope remains explicit"
102
+ }
103
+ ```
104
+
105
+ ### design-comparison
106
+ ```json
107
+ {
108
+ "template": "design-comparison",
109
+ "inputs": ["Accepted outcome and current architecture revision", "Candidate designs including reuse/no-change where viable", "Constraints and evaluation evidence"],
110
+ "process": ["Evaluate each candidate against the same outcome criteria", "Challenge assumptions, interfaces and failure/recovery behavior; state costs without invented numbers"],
111
+ "outputs": ["Chosen design or unresolved alternatives with rationale", "Required PRODUCT.md, DESIGN.md, WORKFLOW.md and plan changes, as applicable"],
112
+ "owner": "Authorized design decision owner; one owner per artifact",
113
+ "dissent": "Preserve rejected alternatives and the observation that could reopen the decision",
114
+ "handoff": "rdc:plan or existing design stage; no build admission from discussion alone"
115
+ }
116
+ ```
117
+
118
+ ### troubleshooting
119
+ ```json
120
+ {
121
+ "template": "troubleshooting",
122
+ "inputs": ["Observed symptom, time and exact affected surface", "Expected behavior and last known revision", "Logs/probes with secrets removed and hypotheses labeled"],
123
+ "process": ["Distinguish measured failure from theories", "Choose a discriminating safe probe and compare its actual result; do not repeat failed guesses"],
124
+ "outputs": ["Supported cause or remaining hypotheses", "Scoped repair proposal and regression that would fail before repair"],
125
+ "owner": "Investigation owner; separately named repair owner",
126
+ "dissent": "Retain contrary observations and unresolved causal claims",
127
+ "handoff": "Existing fix/build workflow for authorized repair; no service restart merely because observation timed out"
128
+ }
129
+ ```
130
+
131
+ ### plan-critique
132
+ ```json
133
+ {
134
+ "template": "plan-critique",
135
+ "inputs": ["User outcome and exact plan revision", "Checklist inputs, processing, outputs and evidence", "Architecture boundaries, dependencies and current implementation"],
136
+ "process": ["Trace each user requirement to a deliverable and failing check", "Challenge missing handoffs, recovery and unsupported claims; avoid padding the checklist"],
137
+ "outputs": ["Accepted plan amendments with exact affected sections", "Uncovered requirements and verification gaps"],
138
+ "owner": "Plan owner records amendments; independent reviewer retains attribution",
139
+ "dissent": "Keep disputed acceptance criteria and the evidence needed to resolve them",
140
+ "handoff": "rdc:plan amendment, then rdc:build only under existing authorization and admission"
141
+ }
142
+ ```
143
+
144
+ ### disagreement-resolution
145
+ ```json
146
+ {
147
+ "template": "disagreement-resolution",
148
+ "inputs": ["Exact disputed point and attributed positions", "Shared evidence and conflicting assumptions", "Decision owner, constraints and remaining round budget"],
149
+ "process": ["Each peer states the other's position for correction before rebuttal", "Identify a discriminating observation or explicit tradeoff; record an owner decision if consensus is absent"],
150
+ "outputs": ["Agreement, decision with dissent, or unresolved point", "Reopening condition and smallest next evidence step"],
151
+ "owner": "Existing authorized decision owner, never a winner inferred from engine identity",
152
+ "dissent": "Retain each final position; no majority vote or silence masquerading as assent",
153
+ "handoff": "Bounded evidence task or authorized plan decision; escalation only for a genuinely missing authority"
154
+ }
155
+ ```
156
+
157
+ ### work-handoff
158
+ ```json
159
+ {
160
+ "template": "work-handoff",
161
+ "inputs": ["Accepted outcome, decisions and unresolved constraints", "Exact repository, revision, work item and artifact locations", "Completed evidence, remaining work and permission boundaries"],
162
+ "process": ["Receiver restates scope, dependencies and next executable action", "Reconcile gaps without relabeling unverified work as complete"],
163
+ "outputs": ["Accepted handoff brief with one writer per artifact", "Remaining checks and restart instructions with current process handles if relevant"],
164
+ "owner": "Sender owns provenance; named receiver accepts future work explicitly",
165
+ "dissent": "Receiver lists unsupported claims, unavailable inputs and declined scope",
166
+ "handoff": "rdc:build for implementation or rdc:plan for unresolved planning; discussion never substitutes for review or validator closure"
167
+ }
168
+ ```
169
+
170
+ ## Exit check
171
+
172
+ - [ ] Selected template and shared packet identified.
173
+ - [ ] Each peer's received-hash echo recorded; mismatches resolved before deciding.
174
+ - [ ] Actual responses attributed; disagreement and uncertainty retained.
175
+ - [ ] Outcome labeled AGREED, DECIDED_WITH_DISSENT, UNRESOLVED or PEER_UNAVAILABLE.
176
+ - [ ] Decision owner and artifact owner explicit; no implied permission expansion.
177
+ - [ ] Record saved through an authorized route, or explicitly unsaved.
178
+ - [ ] Next action handed to the existing workflow; no false completion claim.
@@ -100,8 +100,8 @@ than glossed:
100
100
  The removed prose also carried real, hard-won operational knowledge — the
101
101
  `next start` `BUILD_ID` crash-loop, the `media.place.fund` hotlink referer
102
102
  allowlist, the `<head>` metadata audit, the lockfile-importer trap on a first
103
- promote to `main`. That knowledge is in git history for this file and in the
104
- named `.rdc/lessons/` entries it cited. **It was removed from here because prose
103
+ promote to `main`. That knowledge is in git history for this file, including the
104
+ lessons it cited. **It was removed from here because prose
105
105
  that duplicates behaviour drifts from it** — not because it stopped being true.
106
106
  Where such a check belongs in the pipeline, it belongs in the program or in the
107
107
  manager, where it runs, rather than in a document that hopes to be read.
@@ -222,4 +222,10 @@ Report: what was fixed, file(s) changed, commit hash. One sentence.
222
222
 
223
223
  ## Capture lessons (exit step)
224
224
 
225
- Before the final verdict line, follow `.rdc/guides/lessons-learned-spec.md` § Capture procedure. If this run taught something non-obvious — a first root-cause theory that turned out wrong, the documented/standard path not working, a missing gate or check that cost a round, or a surprising tool/infra behavior — write one `.rdc/lessons/<YYYY-MM-DD>-fixit-<short-slug>.md` per lesson using the schema in that spec. Set `scope` (`simple` | `architectural`) and `status` (`open`, or `applied` if you shipped the fix in this same run, with the commit linked). Commit the lesson file(s) on `develop` alongside the run's other commits, and note "N lessons captured" in your verdict/summary. A run that taught nothing writes nothing — absence is the default.
225
+ Before the final verdict line, follow `.rdc/guides/lessons-learned-spec.md` § Capture procedure. If this run taught something non-obvious — a first root-cause theory that turned out wrong, the documented/standard path not working, a missing gate or check that cost a round, or a surprising tool/infra behavior — record each lesson where its fix belongs:
226
+
227
+ - **Fix encoded in this run** (a guard, test or script shipped, commit linked): the lesson goes in that commit's message. No file, no issue.
228
+ - **Fix not encoded**: submit it to the repository the fix belongs to, which opens one `lesson` + `proposal` issue there (an identical title opens nothing):
229
+ `node "$LIFEAI_ENV/bin/rdc-lesson.mjs" submit --repo <owning repo slug> --title "…" --what "…" --root-cause "…" --fix "…"`
230
+
231
+ No lesson file is written. Note "N lessons captured (E encoded, S submitted)" with the issue URLs in your verdict/summary. A run that taught nothing records nothing — absence is the default.
@@ -160,26 +160,36 @@ Write to `.rdc/reports/YYYY-MM-DD-housekeeping.md`:
160
160
 
161
161
  ## Lessons triage (weekly)
162
162
 
163
- Read all `.rdc/lessons/*.md` with `status: open` (schema + procedure: `.rdc/guides/lessons-learned-spec.md` § Triage procedure). Cluster by `area` + root-cause similarity (dedupe repeats into one fix).
163
+ List the open lesson issues across every registered repository (procedure: `.rdc/guides/lessons-learned-spec.md` § Triage procedure):
164
+
165
+ ```bash
166
+ node "$LIFEAI_ENV/bin/rdc-lesson.mjs" list --state open
167
+ ```
168
+
169
+ Every registered repository is listed, skipped because its issues are switched off (reported), or **NOT listed** — no GitHub repository resolves or the read failed. NOT listed is named on stderr and in `--json` `skipped`, and the command exits 1: the triage is then incomplete, not empty. Cluster open `proposal` issues by area + root-cause similarity (dedupe repeats into one fix; close the duplicates, linking the survivor), take reopened recurrences first (their fix did not hold), and decide each cluster's scope: **simple** (one-file fix, config, grep guard, test) or **architectural** (anything in `.claude/rules/architectural-change-approval.md`; when unsure, architectural).
164
170
 
165
171
  ### Attended mode (default — a human is present)
166
172
 
167
173
  For each cluster:
168
174
 
169
- - `scope: simple`apply the fix directly (rule line, skill-doc edit, config, guard), commit it, set the lesson(s) `status: applied` with the commit linked.
170
- - `scope: architectural` → do NOT edit. Present the issue + options via `AskUserQuestion` (per `.claude/rules/architectural-change-approval.md`). On approval, apply via the correct lifecycle (rdc-skills tag/push for skills; cited commit for rules) and set `status: applied`. If deferred, set `status: triaged` and spawn a `work_item`.
171
- - Not worth fixing → `status: wont-fix` with a one-line reason.
175
+ - **simple**create the work item, run `node "$LIFEAI_ENV/bin/rdc-lesson.mjs" accept <issue> --repo <slug> --work-item <uuid>`, apply the fix as a guard/test/script, and commit with `Fixes #N`. In regen-root (default branch `main`, integration `develop`) and regen-deploy-mgr (default branch `codex/regen-deploy-mgr-wp1`) `Fixes #N` never reaches the default branch, so once the fix lands run `node "$LIFEAI_ENV/bin/rdc-lesson.mjs" close <issue> --repo <slug> --commit <sha>`.
176
+ - **architectural** → do NOT edit. Present the issue + options via `AskUserQuestion` (per `.claude/rules/architectural-change-approval.md`). On approval, accept it and apply via the correct lifecycle (rdc-skills tag/push for skills; cited commit for rules). If deferred, accept it so the work item carries it.
177
+ - Not worth fixing → close the issue as not planned with a one-line reason.
172
178
 
173
179
  ### Unattended mode (no human — overnight / cron / `rdc:overnight`)
174
180
 
175
181
  When the weekly triage runs unattended, follow `.rdc/guides/lessons-learned-spec.md` § **Triage procedure — UNATTENDED weekly mode** — do not run `AskUserQuestion`. In brief (the spec is authoritative):
176
182
 
177
183
  - **Per-difficulty model routing** (reuses the `rdc:build` table): the run is led by `claude-sonnet-5` for clustering + scope/difficulty triage; mechanical apply → `claude-haiku-4-5`; harder multi-file/migration fix → `claude-sonnet-5`; design/architectural fix → `claude-opus-5`.
178
- - `scope: simple` → apply directly or via `rdc:fixit`, commit, `status: applied`.
179
- - `scope: architectural` with a single clear correct fix (records an already-learned lesson — e.g. "document X", "add a gate", update a guide) → route through `rdc:plan` → `rdc:build` (or `rdc:fixit` if genuinely <5 files), update the documentation, set `status: applied`/`triaged`.
180
- - `scope: architectural` **and genuinely ambiguous** (multiple valid approaches, real tradeoffs) → write a `human_items` row (`item_type='decision'`, with options in `suggested_agent_prompt`, `source_type='lesson'`, `source_fingerprint` for dedupe), set `status: triaged`, spawn + link a `work_item`. Decided in the morning. This is the asynchronous equivalent of the attended interview and honors `.claude/rules/architectural-change-approval.md`.
184
+ - **simple**accept, apply directly or via `rdc:fixit`, commit with `Fixes #N` or close with `rdc-lesson close` where the default branch is not the integration branch.
185
+ - **architectural with a single clear correct fix** (records an already-learned lesson — e.g. "add a gate", "encode X as a test") → accept, route through `rdc:plan` → `rdc:build` (or `rdc:fixit` if genuinely <5 files).
186
+ - **architectural and genuinely ambiguous** (multiple valid approaches, real tradeoffs) → write a `human_items` row (`item_type='decision'`, with options in `suggested_agent_prompt`, `source_type='lesson'`, `source_fingerprint` = the issue URL for dedupe), accept the issue against a linked `work_item`. Decided in the morning. This is the asynchronous equivalent of the attended interview and honors `.claude/rules/architectural-change-approval.md`.
187
+
188
+ ### Conversion backlog — remaining lesson files
189
+
190
+ List the lesson files still in the project (`.rdc/lessons/*.md`: doc-only and product lessons from before issues). They are a backlog to convert, not a place to capture: with the capacity left after the issues, pick files and encode each as a guard or test, point any live link at that artifact, and delete the file in the same commit (spec § Existing `.rdc/lessons/` files). Nothing new is written there — a new lesson, doc-only included, is an issue.
181
191
 
182
- Never delete lesson files`applied` and `wont-fix` stay as the audit trail. Report captured / applied / escalated / deferred counts in the housekeeping report.
192
+ Issues are closed, never deleted a closed issue with its fixing commit or won't-fix reason is the audit trail. Report open / recurred / accepted / closed-fixed / closed-won't-fix counts with issue URLs, and backlog files converted / remaining, in the housekeeping report.
183
193
 
184
194
  ## Rules
185
195
  - Never run `pnpm build` — not needed for this audit
@@ -1466,4 +1466,4 @@ Append Phase 7 results to ONRAMP-REPORT.md (final section).
1466
1466
 
1467
1467
  ## Capture Lessons
1468
1468
 
1469
- Before the final verdict, follow `.rdc/guides/lessons-learned-spec.md`. Write `.rdc/lessons/<YYYY-MM-DD>-onramp-<slug>.md` if the run taught something non-obvious.
1469
+ Before the final verdict, follow `.rdc/guides/lessons-learned-spec.md` § Capture procedure if the run taught something non-obvious. A lesson whose fix shipped as a guard, test or script this run goes in that commit's message; any other lesson is submitted to the repository the fix belongs to — `node "$LIFEAI_ENV/bin/rdc-lesson.mjs" submit --repo <owning repo slug> --title "…" --what "…" --root-cause "…" --fix "…"` opens one `lesson` + `proposal` issue there. No lesson file is written.
@@ -47,7 +47,7 @@ Before touching any code, verify the environment is safe:
47
47
  1. **Clauth daemon alive AND unlocked:** `/ping` alive is NOT enough — a LOCKED
48
48
  vault answers `/ping` but every `/v/<service>` returns nothing, so credentials
49
49
  silently resolve empty and a long unattended run fails hours later
50
- (lesson 2026-06-16-overnight-preflight-clauth-locked-and-shared-develop-cells).
50
+ (retired lesson 2026-06-16-overnight-preflight-clauth-locked-and-shared-develop-cells).
51
51
  Assert `locked:false` before proceeding:
52
52
  ```bash
53
53
  curl -s http://127.0.0.1:52437/ping
@@ -58,8 +58,8 @@ Before touching any code, verify the environment is safe:
58
58
  2. **Git state clean AND no concurrent committer on shared develop:** Overnight
59
59
  shares the `develop` working tree with other cells/sessions. A second session
60
60
  committing concurrently can drop a just-committed file during a rebase
61
- (lessons 2026-06-16-overnight-preflight-clauth-locked-and-shared-develop-cells,
62
- 2026-06-17-build-shared-develop-rebase-dropped-committed-file).
61
+ (retired lessons 2026-06-16-overnight-preflight-clauth-locked-and-shared-develop-cells,
62
+ retired lesson 2026-06-17-build-shared-develop-rebase-dropped-committed-file).
63
63
  ```bash
64
64
  git status --short
65
65
  git fetch -q origin && git log --oneline @..@{u} # any rows = origin moved under you
@@ -253,4 +253,10 @@ Provide the advisor with:
253
253
 
254
254
  ## Capture lessons (exit step)
255
255
 
256
- Before the final verdict line, follow `.rdc/guides/lessons-learned-spec.md` § Capture procedure. If this run taught something non-obvious — a first root-cause theory that turned out wrong, the documented/standard path not working, a missing gate or check that cost a round, or a surprising tool/infra behavior — write one `.rdc/lessons/<YYYY-MM-DD>-overnight-<short-slug>.md` per lesson using the schema in that spec. Set `scope` (`simple` | `architectural`) and `status` (`open`, or `applied` if you shipped the fix in this same run, with the commit linked). Commit the lesson file(s) on `develop` alongside the run's other commits, and note "N lessons captured" in your verdict/summary. A run that taught nothing writes nothing — absence is the default.
256
+ Before the final verdict line, follow `.rdc/guides/lessons-learned-spec.md` § Capture procedure. If this run taught something non-obvious — a first root-cause theory that turned out wrong, the documented/standard path not working, a missing gate or check that cost a round, or a surprising tool/infra behavior — record each lesson where its fix belongs:
257
+
258
+ - **Fix encoded in this run** (a guard, test or script shipped, commit linked): the lesson goes in that commit's message. No file, no issue.
259
+ - **Fix not encoded**: submit it to the repository the fix belongs to, which opens one `lesson` + `proposal` issue there (an identical title opens nothing):
260
+ `node "$LIFEAI_ENV/bin/rdc-lesson.mjs" submit --repo <owning repo slug> --title "…" --what "…" --root-cause "…" --fix "…"`
261
+
262
+ No lesson file is written. Note "N lessons captured (E encoded, S submitted)" with the issue URLs in your verdict/summary. A run that taught nothing records nothing — absence is the default.
@@ -383,4 +383,10 @@ designing topology. Do not reach for the REMOTE rule by default.
383
383
 
384
384
  ## Capture lessons (exit step)
385
385
 
386
- Before the final verdict line, follow `.rdc/guides/lessons-learned-spec.md` § Capture procedure. If this run taught something non-obvious — a first root-cause theory that turned out wrong, the documented/standard path not working, a missing gate or check that cost a round, or a surprising tool/infra behavior — write one `.rdc/lessons/<YYYY-MM-DD>-plan-<short-slug>.md` per lesson using the schema in that spec. Set `scope` (`simple` | `architectural`) and `status` (`open`, or `applied` if you shipped the fix in this same run, with the commit linked). Commit the lesson file(s) on `develop` alongside the run's other commits, and note "N lessons captured" in your verdict/summary. A run that taught nothing writes nothing — absence is the default.
386
+ Before the final verdict line, follow `.rdc/guides/lessons-learned-spec.md` § Capture procedure. If this run taught something non-obvious — a first root-cause theory that turned out wrong, the documented/standard path not working, a missing gate or check that cost a round, or a surprising tool/infra behavior — record each lesson where its fix belongs:
387
+
388
+ - **Fix encoded in this run** (a guard, test or script shipped, commit linked): the lesson goes in that commit's message. No file, no issue.
389
+ - **Fix not encoded**: submit it to the repository the fix belongs to, which opens one `lesson` + `proposal` issue there (an identical title opens nothing):
390
+ `node "$LIFEAI_ENV/bin/rdc-lesson.mjs" submit --repo <owning repo slug> --title "…" --what "…" --root-cause "…" --fix "…"`
391
+
392
+ No lesson file is written. Note "N lessons captured (E encoded, S submitted)" with the issue URLs in your verdict/summary. A run that taught nothing records nothing — absence is the default.
@@ -87,4 +87,10 @@ direction if given. If advisor cannot resolve, log and skip to next step.
87
87
 
88
88
  ## Capture lessons (exit step)
89
89
 
90
- Before the final verdict line, follow `.rdc/guides/lessons-learned-spec.md` § Capture procedure. If this run taught something non-obvious — a first root-cause theory that turned out wrong, the documented/standard path not working, a missing gate or check that cost a round, or a surprising tool/infra behavior — write one `.rdc/lessons/<YYYY-MM-DD>-preplan-<short-slug>.md` per lesson using the schema in that spec. Set `scope` (`simple` | `architectural`) and `status` (`open`, or `applied` if you shipped the fix in this same run, with the commit linked). Commit the lesson file(s) on `develop` alongside the run's other commits, and note "N lessons captured" in your verdict/summary. A run that taught nothing writes nothing — absence is the default.
90
+ Before the final verdict line, follow `.rdc/guides/lessons-learned-spec.md` § Capture procedure. If this run taught something non-obvious — a first root-cause theory that turned out wrong, the documented/standard path not working, a missing gate or check that cost a round, or a surprising tool/infra behavior — record each lesson where its fix belongs:
91
+
92
+ - **Fix encoded in this run** (a guard, test or script shipped, commit linked): the lesson goes in that commit's message. No file, no issue.
93
+ - **Fix not encoded**: submit it to the repository the fix belongs to, which opens one `lesson` + `proposal` issue there (an identical title opens nothing):
94
+ `node "$LIFEAI_ENV/bin/rdc-lesson.mjs" submit --repo <owning repo slug> --title "…" --what "…" --root-cause "…" --fix "…"`
95
+
96
+ No lesson file is written. Note "N lessons captured (E encoded, S submitted)" with the issue URLs in your verdict/summary. A run that taught nothing records nothing — absence is the default.
@@ -139,12 +139,12 @@ doc-sync/scope guard to catch contamination. In them:
139
139
  - **Pre-tag guard: refuse to tag if `git diff --cached --name-only` includes any
140
140
  path outside the declared change set.** A broad add swept 4 pre-existing
141
141
  untracked skill files into a tagged release that CI published before anyone
142
- noticed (lesson 2026-06-08-release-git-add-all-swept-untracked-wip). Same
142
+ noticed (retired lesson 2026-06-08-release-git-add-all-swept-untracked-wip). Same
143
143
  dirty-tree contamination class as a lockfile generated against a dirty tree.
144
144
 
145
145
  ## ⛔ Cross-platform prepack + verify the PUBLISHED tarball
146
146
 
147
- - **Prepack must be OS-agnostic.** A bash-style `prepack` chain (`node A || true && node B || true && node stamp`) short-circuits under Windows **cmd.exe** (npm runs lifecycle scripts via cmd, not bash; `true` is not a cmd builtin and `||`/`&&` evaluate differently), so an appended step silently never runs (lesson 2026-06-13-release-windows-cmd-prepack-shortcircuit). When a prepack step must run cross-platform, use a node wrapper / `shx` / `cross-env` — never rely on `|| true` shell semantics that differ between cmd and bash.
147
+ - **Prepack must be OS-agnostic.** A bash-style `prepack` chain (`node A || true && node B || true && node stamp`) short-circuits under Windows **cmd.exe** (npm runs lifecycle scripts via cmd, not bash; `true` is not a cmd builtin and `||`/`&&` evaluate differently), so an appended step silently never runs (retired lesson 2026-06-13-release-windows-cmd-prepack-shortcircuit). When a prepack step must run cross-platform, use a node wrapper / `shx` / `cross-env` — never rely on `|| true` shell semantics that differ between cmd and bash.
148
148
  - **Validate the PUBLISHED artifact, not a local Windows `npm pack`.** A local Windows `npm pack` is NOT a faithful rehearsal of the CI (ubuntu/bash) publish. After publish, verify the real tarball:
149
149
  ```bash
150
150
  npm pack <pkg>@<version> # downloads the PUBLISHED tarball
@@ -165,4 +165,10 @@ Use `--profile lifeai` only on a workstation that intentionally has the LIFEAI p
165
165
 
166
166
  ## Capture lessons (exit step)
167
167
 
168
- Before the final verdict line, follow `.rdc/guides/lessons-learned-spec.md` § Capture procedure. If this run taught something non-obvious — a first root-cause theory that turned out wrong, the documented/standard path not working, a missing gate or check that cost a round, or a surprising tool/infra behavior — write one `.rdc/lessons/<YYYY-MM-DD>-release-<short-slug>.md` per lesson using the schema in that spec. Set `scope` (`simple` | `architectural`) and `status` (`open`, or `applied` if you shipped the fix in this same run, with the commit linked). Commit the lesson file(s) on `develop` alongside the run's other commits, and note "N lessons captured" in your verdict/summary. A run that taught nothing writes nothing — absence is the default.
168
+ Before the final verdict line, follow `.rdc/guides/lessons-learned-spec.md` § Capture procedure. If this run taught something non-obvious — a first root-cause theory that turned out wrong, the documented/standard path not working, a missing gate or check that cost a round, or a surprising tool/infra behavior — record each lesson where its fix belongs:
169
+
170
+ - **Fix encoded in this run** (a guard, test or script shipped, commit linked): the lesson goes in that commit's message. No file, no issue.
171
+ - **Fix not encoded**: submit it to the repository the fix belongs to, which opens one `lesson` + `proposal` issue there (an identical title opens nothing):
172
+ `node "$LIFEAI_ENV/bin/rdc-lesson.mjs" submit --repo <owning repo slug> --title "…" --what "…" --root-cause "…" --fix "…"`
173
+
174
+ No lesson file is written. Note "N lessons captured (E encoded, S submitted)" with the issue URLs in your verdict/summary. A run that taught nothing records nothing — absence is the default.
@@ -212,4 +212,10 @@ description: rdc:review () - [--unattended] — post-build gate over tsc, tests,
212
212
 
213
213
  ## Capture lessons (exit step)
214
214
 
215
- Before the final verdict line, follow `.rdc/guides/lessons-learned-spec.md` § Capture procedure. If this run taught something non-obvious — a first root-cause theory that turned out wrong, the documented/standard path not working, a missing gate or check that cost a round, or a surprising tool/infra behavior — write one `.rdc/lessons/<YYYY-MM-DD>-review-<short-slug>.md` per lesson using the schema in that spec. Set `scope` (`simple` | `architectural`) and `status` (`open`, or `applied` if you shipped the fix in this same run, with the commit linked). Commit the lesson file(s) on `develop` alongside the run's other commits, and note "N lessons captured" in your verdict/summary. A run that taught nothing writes nothing — absence is the default.
215
+ Before the final verdict line, follow `.rdc/guides/lessons-learned-spec.md` § Capture procedure. If this run taught something non-obvious — a first root-cause theory that turned out wrong, the documented/standard path not working, a missing gate or check that cost a round, or a surprising tool/infra behavior — record each lesson where its fix belongs:
216
+
217
+ - **Fix encoded in this run** (a guard, test or script shipped, commit linked): the lesson goes in that commit's message. No file, no issue.
218
+ - **Fix not encoded**: submit it to the repository the fix belongs to, which opens one `lesson` + `proposal` issue there (an identical title opens nothing):
219
+ `node "$LIFEAI_ENV/bin/rdc-lesson.mjs" submit --repo <owning repo slug> --title "…" --what "…" --root-cause "…" --fix "…"`
220
+
221
+ No lesson file is written. Note "N lessons captured (E encoded, S submitted)" with the issue URLs in your verdict/summary. A run that taught nothing records nothing — absence is the default.
@@ -1,6 +1,6 @@
1
1
  # RDC Skill Test Suite Matrix
2
2
 
3
- Current coverage: 36 manifests for 36 skill directories.
3
+ Current coverage: 37 manifests for 37 skill directories.
4
4
 
5
5
  The manifest layer verifies each skill can be started from a realistic caller prompt in an isolated `RDC_TEST=1` sandbox. The acceptance harness can run either Claude (`--engine claude`) or Codex (`--engine codex`) against the same manifests and records the engine stream, extracted tool calls, stdout/stderr artifacts, rendered assistant output, failures, lessons learned, and next build optimizations under `.rdc/reports/`.
6
6
 
@@ -14,6 +14,7 @@ The manifest layer verifies each skill can be started from a realistic caller pr
14
14
  | `rdc:channel-formatter` | `rdc-channel-formatter.test.json` | Long article to social content pack | `exit_code`, `stdout_contains` | Output contains, output not contains, tool-call routing |
15
15
  | `rdc:co-develop` | `rdc-co-develop.test.json` | Coordination status | `commits_made`, `exit_code`, `stdout_contains` | codevelop status, sandbox skip, no chitchat/live-send negative checks |
16
16
  | `rdc:collab` | `rdc-collab.test.json` | Claude session relay fixture | `commits_made`, `exit_code`, `stdout_contains` | chitchat/SSE session handling, sandbox skip, and no-reply/no-push negative checks |
17
+ | `rdc:convo` | `rdc-convo.test.json` | Missing-peer plan critique | `exit_code`, `stdout_contains` | Unknown participant response preserved and false agreement/completion negative checks |
17
18
  | `rdc:convert` | `rdc-convert.test.json` | Markdown-to-Word conversion fixture | `exit_code`, `stdout_contains` | build-corpus command surface, Word/Markdown flags, and no-GUI/global-install/commit checks |
18
19
  | `rdc:deploy` | `rdc-deploy.test.json` | Deployment diagnosis | `commits_made`, `exit_code`, `stdout_contains` | Read-only diagnose output and destructive deploy/DNS negative checks |
19
20
  | `rdc:edit` | `rdc-edit.test.json` | Local editor launch | `exit_code`, `stdout_contains` | Resolved target, editor host URL, and no-unknown-target negative checks |
@@ -1,7 +1,7 @@
1
1
  # Tier 2 Test Manifests
2
2
 
3
3
  Each RDC skill directory has a colocated test manifest at `skills/tests/rdc-<name>.test.json`.
4
- There are currently 36 manifests for 36 skill directories. These drive the Tier 2
4
+ There are currently 37 manifests for 37 skill directories. These drive the Tier 2
5
5
  behavioral runner and the build acceptance harness for both Claude and Codex.
6
6
 
7
7
  See `MATRIX.md` for the current skill-by-skill coverage table.
@@ -0,0 +1,15 @@
1
+ {
2
+ "manifest_version": 1,
3
+ "skill": "rdc:convo",
4
+ "description": "Sandbox discussion preserves missing peer uncertainty and does not dispatch or implement.",
5
+ "fixture": {
6
+ "prompt": "rdc:convo plan-critique Evaluate a proposal to mark CDE complete after typecheck alone. No peer response is available. Return the simulated packet and unresolved decision; do not contact peers or edit files.",
7
+ "env": { "RDC_TEST": "1" }
8
+ },
9
+ "assertions": { "exit_code": 0, "stdout_contains": ["UNKNOWN"] },
10
+ "acceptance": {
11
+ "output_contains": ["UNKNOWN", "plan-critique"],
12
+ "output_not_contains": ["Claude agreed", "CDE is complete", "validator passed"]
13
+ },
14
+ "teardown": { "reset_branch": true }
15
+ }
@@ -0,0 +1,36 @@
1
+ import test from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import { readFileSync } from 'node:fs';
4
+ import { getSkill, getSkillBody, resolveSkillName, searchSkills } from '../lib/catalog.mjs';
5
+ import { toCloudBody } from '../lib/cloud-rewrite.mjs';
6
+
7
+ const names = ['outcome-exploration', 'design-comparison', 'troubleshooting', 'plan-critique', 'disagreement-resolution', 'work-handoff'];
8
+
9
+ test('convo resolves explicit invocation and ships complete templates in both caller variants', () => {
10
+ for (const alias of ['convo', 'rdc:convo', '/rdc:convo']) assert.equal(resolveSkillName(alias), 'convo');
11
+ assert.equal(resolveSkillName('convo/../../deploy'), null);
12
+ const meta = getSkill('convo');
13
+ assert.equal(meta.codeflow_required, false);
14
+ assert.deepEqual(meta.produces, ['discussion_record', 'decision_record']);
15
+ assert.ok(searchSkills('fair discussion').some(row => row.name === 'convo'));
16
+ const source = readFileSync(new URL('../skills/convo/SKILL.md', import.meta.url), 'utf8').replace(/\r\n/g, '\n');
17
+ const body = getSkillBody('convo');
18
+ assert.equal(body, source.replace(/^---\n[\s\S]*?\n---\n+/, ''));
19
+ for (const rendered of [body, toCloudBody(body)]) {
20
+ const templates = [...rendered.matchAll(/```json\n([\s\S]*?)\n```/g)].map(m => JSON.parse(m[1]));
21
+ assert.deepEqual(templates.map(t => t.template), names);
22
+ for (const template of templates) {
23
+ assert.ok(template.inputs.length >= 3, template.template);
24
+ assert.ok(template.process.length >= 2, template.template);
25
+ assert.ok(template.outputs.length >= 2, template.template);
26
+ assert.ok(template.owner && template.dissent && template.handoff);
27
+ }
28
+ assert.match(rendered, /UNKNOWN/);
29
+ assert.match(rendered, /DEFER/);
30
+ assert.match(rendered, /RDC_TEST=1/);
31
+ assert.match(rendered, /Silence is not agreement/);
32
+ assert.match(rendered, /rdc:plan/);
33
+ assert.match(rendered, /rdc:build/);
34
+ assert.doesNotMatch(rendered, /127\.0\.0\.1:52437/);
35
+ }
36
+ });
@@ -0,0 +1,26 @@
1
+ // .npmignore replaces .gitignore for npm. It must carry every .gitignore rule except
2
+ // git-sha.json — the pack-time commit stamp that is untracked in git and exists to be
3
+ // shipped — or the package either loses the stamp or starts shipping what git ignores.
4
+ import { test } from 'node:test';
5
+ import assert from 'node:assert/strict';
6
+ import fs from 'node:fs';
7
+ import path from 'node:path';
8
+ import { fileURLToPath } from 'node:url';
9
+
10
+ const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
11
+ const rules = (file) => new Set(fs.readFileSync(path.join(ROOT, file), 'utf8')
12
+ .split(/\r?\n/).map((l) => l.trim()).filter((l) => l && !l.startsWith('#')));
13
+
14
+ test('.npmignore is .gitignore without the commit stamp', () => {
15
+ const git = rules('.gitignore');
16
+ const npm = rules('.npmignore');
17
+ assert.ok(git.has('git-sha.json'), 'the stamp stays out of git');
18
+ assert.ok(!npm.has('git-sha.json'), 'and stays IN the package');
19
+ const expected = [...git].filter((r) => r !== 'git-sha.json').sort();
20
+ assert.deepEqual([...npm].sort(), expected);
21
+ });
22
+
23
+ test('the installer records the stamped commit when it runs from a package with no .git', () => {
24
+ const installer = fs.readFileSync(path.join(ROOT, 'scripts', 'install-rdc-skills.js'), 'utf8');
25
+ assert.match(installer, /git-sha\.json/);
26
+ });