@lifeaitools/rdc-skills 0.35.26 → 0.37.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/plugin.json +25 -1
- package/.github/ISSUE_TEMPLATE/lesson.yml +56 -0
- package/CHANGELOG.md +32 -0
- package/README.md +1 -0
- package/commands/compare-compliance.md +5 -1
- package/commands/quick-check.md +3 -1
- package/git-sha.json +1 -1
- package/guides/lessons-learned-spec.md +209 -85
- package/guides/review-gate.md +133 -0
- package/guides/work-contract.md +27 -1
- package/hooks/require-work-item-on-commit.js +11 -0
- package/package.json +1 -1
- package/scripts/solid-score.mjs +35 -6
- package/scripts/validate-publish-manifests.js +1 -1
- package/skills/build/SKILL.md +33 -24
- package/skills/clean-code-analyzer/SKILL.md +6 -0
- package/skills/collab/SKILL.md +9 -5
- package/skills/convo/SKILL.md +178 -0
- package/skills/deploy/SKILL.md +2 -2
- package/skills/fixit/SKILL.md +28 -21
- package/skills/housekeeping/SKILL.md +18 -8
- package/skills/onramp/SKILL.md +1 -1
- package/skills/overnight/SKILL.md +11 -5
- package/skills/plan/SKILL.md +7 -1
- package/skills/preplan/SKILL.md +7 -1
- package/skills/release/SKILL.md +10 -4
- package/skills/review/SKILL.md +46 -33
- package/skills/tests/MATRIX.md +2 -1
- package/skills/tests/README.md +1 -1
- package/skills/tests/rdc-convo.test.json +15 -0
- package/tests/convo.test.mjs +36 -0
- package/tests/lib/solid-score-diff.test.mjs +103 -0
- package/tests/require-work-item-on-commit.test.mjs +9 -0
- package/.rdc/lessons/2026-08-17-fixit-codex-mcp-only-skills.md +0 -24
package/skills/fixit/SKILL.md
CHANGED
|
@@ -111,26 +111,27 @@ fi
|
|
|
111
111
|
|
|
112
112
|
⛔ **No fixit closes without a code-review pass.** Even single-file changes go through review.
|
|
113
113
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
-
|
|
130
|
-
|
|
131
|
-
-
|
|
132
|
-
|
|
133
|
-
|
|
114
|
+
Run the deterministic review gate in `guides/review-gate.md` with
|
|
115
|
+
`BASE=HEAD~1` (or the commit before the fixit's first commit) and `SCOPE` set
|
|
116
|
+
to the touched package. For a fixit this usually takes seconds.
|
|
117
|
+
Approved: direct operator instruction — "we need to tune our code reviews to be
|
|
118
|
+
specific -- if you ran the validator for solid and lint etc... it should take 1-2
|
|
119
|
+
minutes". 2026-09-21, Dave, in session.
|
|
120
|
+
|
|
121
|
+
Dispatch `pr-review-toolkit:code-reviewer` only for a **named question** the
|
|
122
|
+
validators cannot answer, scoped to the files it touches. Never dispatch it with
|
|
123
|
+
a bare "review the commit".
|
|
124
|
+
|
|
125
|
+
**Gate outcome:**
|
|
126
|
+
- A red gate step, or a critical/high finding from a named-question pass → fix
|
|
127
|
+
it in this same fixit session. Do not escalate the fix to rdc:build; the
|
|
128
|
+
original fixit owns the cleanup. Re-commit and re-run the gate until it is clean.
|
|
129
|
+
- Medium/low findings from a named-question pass → record them in
|
|
130
|
+
`implementation_report.flags` and proceed to close.
|
|
131
|
+
- All steps green → quote the `REVIEW_GATE` receipt in the implementation report
|
|
132
|
+
and proceed to close.
|
|
133
|
+
|
|
134
|
+
Under `RDC_TEST=1`: echo `[RDC_TEST] skipping review gate` and proceed.
|
|
134
135
|
|
|
135
136
|
### 5.7 Deliver to done (MANDATORY — a fixit is not done until the change is LIVE)
|
|
136
137
|
|
|
@@ -222,4 +223,10 @@ Report: what was fixed, file(s) changed, commit hash. One sentence.
|
|
|
222
223
|
|
|
223
224
|
## Capture lessons (exit step)
|
|
224
225
|
|
|
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 —
|
|
226
|
+
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:
|
|
227
|
+
|
|
228
|
+
- **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.
|
|
229
|
+
- **Fix not encoded**: submit it to the repository the fix belongs to, which opens one `lesson` + `proposal` issue there (an identical title opens nothing):
|
|
230
|
+
`node "$LIFEAI_ENV/bin/rdc-lesson.mjs" submit --repo <owning repo slug> --title "…" --what "…" --root-cause "…" --fix "…"`
|
|
231
|
+
|
|
232
|
+
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
|
-
|
|
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
|
-
-
|
|
170
|
-
-
|
|
171
|
-
- Not worth fixing →
|
|
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
|
-
-
|
|
179
|
-
-
|
|
180
|
-
-
|
|
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
|
-
|
|
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
|
package/skills/onramp/SKILL.md
CHANGED
|
@@ -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
|
|
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
|
|
@@ -144,7 +144,7 @@ After each wave: check `BUILD_STATUS`. If `escalated: true`, log the escalation
|
|
|
144
144
|
in the overnight doc and continue — don't stop the loop.
|
|
145
145
|
After each wave and after every resumed epic, require the `runOrchestrator()` receipt from `rdc:build` **where the orchestrator applies** — the target contains `corpus/_shared/build/phase-manifest.json` (today: regen-root; see `rdc:build` §1a). Elsewhere, require the contract checklist (`rdc-work check`) instead; an absent orchestrator is not a hold. `admission_refocus` or `pipeline_blocked` means the epic is held for an explicitly requested Design Review or validator closure; log that state and do not hand-reconstruct a dispatch wave.
|
|
146
146
|
|
|
147
|
-
**Mandatory code-review gate inherited from rdc:build (Step 9b).** Every wave inside `rdc:build` runs
|
|
147
|
+
**Mandatory code-review gate inherited from rdc:build (Step 9b).** Every wave inside `rdc:build` runs the deterministic review gate (`guides/review-gate.md`: solid-score --diff, linter on changed files, tsc, scoped tests, UI spec) before the next wave dispatches. It takes one to two minutes, where an open-ended reviewer took 4–10, which matters most across an overnight queue. A red step reopens the affected work items to `todo` and the next wave fixes them. Overnight does not skip or weaken this gate. If a wave's gate escalates twice, the advisor decides; otherwise the loop continues.
|
|
148
148
|
|
|
149
149
|
### 3d. Review
|
|
150
150
|
|
|
@@ -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 —
|
|
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.
|
package/skills/plan/SKILL.md
CHANGED
|
@@ -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 —
|
|
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.
|
package/skills/preplan/SKILL.md
CHANGED
|
@@ -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 —
|
|
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.
|
package/skills/release/SKILL.md
CHANGED
|
@@ -41,7 +41,7 @@ rdc:release: <repo> vX.Y.Z -> vA.B.C
|
|
|
41
41
|
[ ] Dry-run gate handled
|
|
42
42
|
[ ] Version files updated
|
|
43
43
|
[ ] Tests/self-test passed
|
|
44
|
-
[ ] Mandatory release
|
|
44
|
+
[ ] Mandatory release review gate (`guides/review-gate.md`, BASE=<last-released-tag>): solid-score --diff, linter on changed files, tsc, scoped tests. Block the release on any red step; LLM reviewer only for a named question.
|
|
45
45
|
[ ] Commit created
|
|
46
46
|
[ ] Tag created
|
|
47
47
|
[ ] Branch and tag pushed
|
|
@@ -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 —
|
|
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.
|
package/skills/review/SKILL.md
CHANGED
|
@@ -12,8 +12,9 @@ description: rdc:review () - [--unattended] — post-build gate over tsc, tests,
|
|
|
12
12
|
> **Sandbox contract:** This skill honors `RDC_TEST=1` per `guides/agent-bootstrap.md` § RDC_TEST Sandbox Contract. Destructive external calls short-circuit under the flag.
|
|
13
13
|
|
|
14
14
|
> **Standard being enforced:** `docs/CODING-STANDARDS.md` (SOLID/Clean-Architecture —
|
|
15
|
-
> regen-root; skip if absent).
|
|
15
|
+
> regen-root; skip if absent). Steps 8b and 8c check it, via this package's
|
|
16
16
|
> own `rdc-solid-score` (also invoked by ATF's Test-Ladder as a consumer, not an owner).
|
|
17
|
+
> Step 8b runs the deterministic review gate, `guides/review-gate.md`.
|
|
17
18
|
|
|
18
19
|
|
|
19
20
|
# rdc:review — Quality Gate
|
|
@@ -84,41 +85,47 @@ description: rdc:review () - [--unattended] — post-build gate over tsc, tests,
|
|
|
84
85
|
- Never silently leave orphaned tasks
|
|
85
86
|
- **⛔ Raw `UPDATE work_items SET parent_id = ...` is forbidden** — bypasses RLS and all constraint checks
|
|
86
87
|
|
|
87
|
-
8b. **Mandatory code-review gate —
|
|
88
|
-
|
|
89
|
-
⛔ **No CLEAN verdict without a
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
88
|
+
8b. **Mandatory code-review gate — deterministic validators on the diff:**
|
|
89
|
+
|
|
90
|
+
⛔ **No CLEAN verdict without a review-gate pass.** Run `guides/review-gate.md`
|
|
91
|
+
over the diff under review, with `BASE` set to the review's base ref and `SCOPE`
|
|
92
|
+
set to each modified package from step 1. Its checks are
|
|
93
|
+
`rdc-solid-score --diff`, the repo linter on changed files (`--write`, then
|
|
94
|
+
check), `tsc`, scoped tests, and the UI spec for changed routes. It finishes in
|
|
95
|
+
one to two minutes and gives the same answer twice.
|
|
96
|
+
Approved: direct operator instruction — "we need to tune our code reviews to be
|
|
97
|
+
specific -- if you ran the validator for solid and lint etc... it should take 1-2
|
|
98
|
+
minutes". 2026-09-21, Dave, in session.
|
|
99
|
+
|
|
100
|
+
Dispatch `pr-review-toolkit:code-reviewer` only for a **named question** the
|
|
101
|
+
validators cannot answer, such as auth bypass on a protected path or a return
|
|
102
|
+
figure in public copy. Scope it to the files that question touches, following
|
|
103
|
+
the guide's "When an LLM reviewer is still right" section. A bare "review the
|
|
104
|
+
diff" dispatch is retired.
|
|
105
|
+
|
|
106
|
+
**Gate outcome:**
|
|
107
|
+
- A red gate step, or a critical/high finding from a named-question pass →
|
|
108
|
+
the verdict cannot be CLEAN. Interactive: report and pause. Unattended:
|
|
109
|
+
fix it if the fix is mechanical (`--write` lint fixes, a missing await, an
|
|
110
|
+
obvious null check); otherwise escalate via the advisor and mark HAS_ISSUES.
|
|
111
|
+
- Medium/low findings from a named-question pass → record them in the review
|
|
112
|
+
report's "Issues" section. The verdict can still be CLEAN.
|
|
113
|
+
- All steps green → quote the `REVIEW_GATE` receipt and continue.
|
|
114
|
+
|
|
115
|
+
Under `RDC_TEST=1`: echo `[RDC_TEST] skipping review gate` and continue.
|
|
112
116
|
|
|
113
117
|
8c. **Form/fit/function gate — solid-validator + architecture-reviewer:**
|
|
114
118
|
|
|
115
|
-
⛔ **No CLEAN verdict without this pass either.** Step 8b
|
|
116
|
-
|
|
117
|
-
shape
|
|
118
|
-
architecturally wrong
|
|
119
|
-
|
|
120
|
-
|
|
119
|
+
⛔ **No CLEAN verdict without this pass either.** Step 8b's lint, tsc and
|
|
120
|
+
tests catch convention drift and broken behavior. This step catches a
|
|
121
|
+
different failure shape: code that is logically correct and
|
|
122
|
+
convention-clean but architecturally wrong. The `Harness` case is the
|
|
123
|
+
example: a use-case orchestrator that reimplements what sibling packages
|
|
124
|
+
exist to do, scores fine on every generic metric, and fails the one check
|
|
125
|
+
that names the actual rule.
|
|
121
126
|
|
|
127
|
+
Reuse the `rdc-solid-score` JSON from step 8b rather than running the scorer
|
|
128
|
+
twice. If 8b ran without the repo's boundary config, re-run it with the config:
|
|
122
129
|
```bash
|
|
123
130
|
rdc-solid-score <modified-package-path> --diff origin/main --config <repo>/.solid-score.yml --format json
|
|
124
131
|
```
|
|
@@ -212,4 +219,10 @@ description: rdc:review () - [--unattended] — post-build gate over tsc, tests,
|
|
|
212
219
|
|
|
213
220
|
## Capture lessons (exit step)
|
|
214
221
|
|
|
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 —
|
|
222
|
+
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:
|
|
223
|
+
|
|
224
|
+
- **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.
|
|
225
|
+
- **Fix not encoded**: submit it to the repository the fix belongs to, which opens one `lesson` + `proposal` issue there (an identical title opens nothing):
|
|
226
|
+
`node "$LIFEAI_ENV/bin/rdc-lesson.mjs" submit --repo <owning repo slug> --title "…" --what "…" --root-cause "…" --fix "…"`
|
|
227
|
+
|
|
228
|
+
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.
|
package/skills/tests/MATRIX.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# RDC Skill Test Suite Matrix
|
|
2
2
|
|
|
3
|
-
Current coverage:
|
|
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 |
|
package/skills/tests/README.md
CHANGED
|
@@ -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
|
|
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,103 @@
|
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import { execFileSync, spawnSync } from 'node:child_process';
|
|
3
|
+
import { mkdtempSync, rmSync, writeFileSync } from 'node:fs';
|
|
4
|
+
import { tmpdir } from 'node:os';
|
|
5
|
+
import { dirname, join } from 'node:path';
|
|
6
|
+
import test from 'node:test';
|
|
7
|
+
import { fileURLToPath } from 'node:url';
|
|
8
|
+
|
|
9
|
+
import { isAbsentAtRef } from '../../scripts/solid-score.mjs';
|
|
10
|
+
|
|
11
|
+
const SCORER = join(dirname(fileURLToPath(import.meta.url)), '..', '..', 'scripts', 'solid-score.mjs');
|
|
12
|
+
|
|
13
|
+
// ── isAbsentAtRef: git's two "not at this ref" messages, and nothing else ──
|
|
14
|
+
|
|
15
|
+
test('isAbsentAtRef: "does not exist in" (absent at ref and on disk) is absent', () => {
|
|
16
|
+
assert.equal(isAbsentAtRef("fatal: path 'src/a.ts' does not exist in 'origin/develop'\n"), true);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
test('isAbsentAtRef: "exists on disk, but not in" (a NEW working-tree file) is absent', () => {
|
|
20
|
+
// The message every --diff over a change that adds a file produces; it was
|
|
21
|
+
// unmatched until 2026-09-21 and crashed the gate.
|
|
22
|
+
assert.equal(isAbsentAtRef("fatal: path 'apps/x/tests/ui/home.spec.ts' exists on disk, but not in 'origin/develop'\n"), true);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
test('isAbsentAtRef: a bad ref is NOT absent — it must be rethrown', () => {
|
|
26
|
+
assert.equal(isAbsentAtRef("fatal: invalid object name 'no-such-ref'.\n"), false);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
test('isAbsentAtRef: a path-form mismatch is NOT absent — it must be rethrown', () => {
|
|
30
|
+
assert.equal(
|
|
31
|
+
isAbsentAtRef("fatal: path 'src/a.ts' exists, but not 'a.ts'\nhint: Did you mean 'HEAD:src/a.ts' aka 'HEAD:./a.ts'?\n"),
|
|
32
|
+
false,
|
|
33
|
+
);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
test('isAbsentAtRef: empty or missing stderr is NOT absent', () => {
|
|
37
|
+
assert.equal(isAbsentAtRef(''), false);
|
|
38
|
+
assert.equal(isAbsentAtRef(undefined), false);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
// ── end to end: --diff over a change that adds a file ──
|
|
42
|
+
|
|
43
|
+
function git(cwd, ...args) {
|
|
44
|
+
return execFileSync('git', ['-c', 'user.email=t@example.com', '-c', 'user.name=t', '-c', 'commit.gpgsign=false', ...args], {
|
|
45
|
+
cwd,
|
|
46
|
+
encoding: 'utf8',
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const CLEAN_CLASS = (name) => `export class ${name} {\n private n = 0;\n add(x: number): number {\n this.n += x;\n return this.n;\n }\n}\n`;
|
|
51
|
+
|
|
52
|
+
test('solid-score --diff scores a new file as a new unit instead of crashing', () => {
|
|
53
|
+
const dir = mkdtempSync(join(tmpdir(), 'solid-diff-'));
|
|
54
|
+
try {
|
|
55
|
+
git(dir, 'init', '-q');
|
|
56
|
+
writeFileSync(join(dir, 'a.ts'), CLEAN_CLASS('Alpha'));
|
|
57
|
+
git(dir, 'add', 'a.ts');
|
|
58
|
+
git(dir, 'commit', '-q', '-m', 'base');
|
|
59
|
+
|
|
60
|
+
// One untracked new file, and one committed-after-base new file: both are
|
|
61
|
+
// "exists on disk, but not in <ref>" at the base ref.
|
|
62
|
+
writeFileSync(join(dir, 'b.ts'), CLEAN_CLASS('Beta'));
|
|
63
|
+
writeFileSync(join(dir, 'c.ts'), CLEAN_CLASS('Gamma'));
|
|
64
|
+
git(dir, 'add', 'c.ts');
|
|
65
|
+
git(dir, 'commit', '-q', '-m', 'add c');
|
|
66
|
+
|
|
67
|
+
const run = spawnSync(process.execPath, [SCORER, dir, '--diff', 'HEAD~1', '--format', 'json'], { encoding: 'utf8' });
|
|
68
|
+
assert.equal(run.status, 0, `scorer exited ${run.status}: ${run.stderr}`);
|
|
69
|
+
const out = JSON.parse(run.stdout);
|
|
70
|
+
const scored = out.results.map((r) => r.file).sort();
|
|
71
|
+
assert.deepEqual(scored, ['b.ts', 'c.ts'], 'both new files are scored');
|
|
72
|
+
assert.deepEqual(out.regressions, [], 'clean new units are not regressions');
|
|
73
|
+
assert.deepEqual(out.removedFiles, [], 'nothing was deleted');
|
|
74
|
+
} finally {
|
|
75
|
+
rmSync(dir, { recursive: true, force: true });
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
test('solid-score --diff reports a deleted file in removedFiles instead of crashing', () => {
|
|
80
|
+
// A deleted file is listed by `git diff --name-only <ref>`; before
|
|
81
|
+
// 2026-09-21 it went to extractUnits and the gate died with ENOENT.
|
|
82
|
+
const dir = mkdtempSync(join(tmpdir(), 'solid-diff-del-'));
|
|
83
|
+
try {
|
|
84
|
+
git(dir, 'init', '-q');
|
|
85
|
+
writeFileSync(join(dir, 'a.ts'), CLEAN_CLASS('Alpha'));
|
|
86
|
+
writeFileSync(join(dir, 'gone.ts'), CLEAN_CLASS('Gone'));
|
|
87
|
+
git(dir, 'add', 'a.ts', 'gone.ts');
|
|
88
|
+
git(dir, 'commit', '-q', '-m', 'base');
|
|
89
|
+
|
|
90
|
+
// One deletion committed after base, one edit left uncommitted.
|
|
91
|
+
git(dir, 'rm', '-q', 'gone.ts');
|
|
92
|
+
git(dir, 'commit', '-q', '-m', 'remove gone');
|
|
93
|
+
writeFileSync(join(dir, 'a.ts'), `${CLEAN_CLASS('Alpha')}\nexport const touched = 1;\n`);
|
|
94
|
+
|
|
95
|
+
const run = spawnSync(process.execPath, [SCORER, dir, '--diff', 'HEAD~1', '--format', 'json'], { encoding: 'utf8' });
|
|
96
|
+
assert.equal(run.status, 0, `scorer exited ${run.status}: ${run.stderr}`);
|
|
97
|
+
const out = JSON.parse(run.stdout);
|
|
98
|
+
assert.deepEqual(out.removedFiles, ['gone.ts'], 'the deletion is reported, not dropped');
|
|
99
|
+
assert.deepEqual(out.results.map((r) => r.file), ['a.ts'], 'only the surviving changed file is scored');
|
|
100
|
+
} finally {
|
|
101
|
+
rmSync(dir, { recursive: true, force: true });
|
|
102
|
+
}
|
|
103
|
+
});
|
|
@@ -219,8 +219,17 @@ EOF
|
|
|
219
219
|
['heredoc with a quoted delimiter passes', 'git commit -F - <<"MSG"\nfix(a): b\nMSG', 'pass'],
|
|
220
220
|
['heredoc carrying only a UUID passes', "git commit -F - <<'EOF'\nwip\n\nWork-Item: f27ff5fa-0000-4000-8000-000000000000\nEOF", 'pass'],
|
|
221
221
|
['-m still passes', 'git commit -m "fix(x): y"', 'pass'],
|
|
222
|
+
// -m "$(cat <<'EOF' … EOF)" — the -m regex used to match the FIRST
|
|
223
|
+
// unrelated quote inside the substitution (the heredoc delimiter's own
|
|
224
|
+
// opening quote) and return early with literal shell text as the
|
|
225
|
+
// "message", never reaching the heredoc fallback below. Same defect
|
|
226
|
+
// class as the 2026-08-29 fix, one wrapper layer further out. Filed as
|
|
227
|
+
// regen-root#243.
|
|
228
|
+
['-m "$(cat <<EOF …)" substitution passes', "git commit -m \"$(cat <<'EOF'\nfix(guards): correct the heredoc substitution match\n\nBody line two.\nEOF\n)\"", 'pass'],
|
|
229
|
+
['-m "$(cat <<-EOF …)" dash-form substitution passes', "git commit -m \"$(cat <<-'EOF'\nfix(a): b\nEOF\n)\"", 'pass'],
|
|
222
230
|
// Negative controls — reading the message is not a bypass.
|
|
223
231
|
['heredoc without a type or UUID still blocks', "git commit -F - <<'EOF'\nrandom words\nEOF", 'block'],
|
|
232
|
+
['-m "$(cat <<EOF …)" without a type or UUID still blocks', "git commit -m \"$(cat <<'EOF'\nrandom words\nEOF\n)\"", 'block'],
|
|
224
233
|
['a bare commit still blocks', 'git commit', 'block'],
|
|
225
234
|
// Honest about what it cannot see, rather than calling it absent.
|
|
226
235
|
['a real stdin pipe reports unreadable', 'cat msg.txt | git commit -q -F -', 'unreadable'],
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
id: 2026-08-17-fixit-codex-mcp-only-skills
|
|
3
|
-
date: "2026-08-17"
|
|
4
|
-
skill: fixit
|
|
5
|
-
session: codex-mcp-startup-20260817
|
|
6
|
-
scope: simple
|
|
7
|
-
status: applied
|
|
8
|
-
area: skill
|
|
9
|
-
links:
|
|
10
|
-
commits:
|
|
11
|
-
- 263231a
|
|
12
|
-
memory: []
|
|
13
|
-
work_items:
|
|
14
|
-
- dc076f35-236b-4f8d-be3f-646a66514ba5
|
|
15
|
-
---
|
|
16
|
-
|
|
17
|
-
## What happened
|
|
18
|
-
Codex's real numbered-lane startup completed MCP initialization but emitted a red skill-budget error on every launch. The machine had 36 RDC skill directories in each of the global `.codex/skills` and `.agents/skills` roots while the same 36-skill catalog was already registered through the RDC-Skills MCP endpoint.
|
|
19
|
-
|
|
20
|
-
## Root cause
|
|
21
|
-
`scripts/install-rdc-skills.js` registered the MCP endpoint and then copied the full RDC catalog into every detected Codex skill directory. Codex loaded those duplicate surfaces together, inflating startup metadata to 113 skills. The same install also left a legacy RDC marketplace block that Codex rejected as an unsupported plugin source.
|
|
22
|
-
|
|
23
|
-
## The fix / rule
|
|
24
|
-
Codex receives RDC skills exclusively through MCP. The installer now verifies the MCP config before purging legacy file copies, fails closed if the replacement cannot be established, removes the obsolete marketplace/plugin blocks with CRLF coverage, and verifies that live Codex skill roots contain zero RDC duplicates. Implemented in commit `263231a`.
|