@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
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# Review Gate — deterministic validators on the diff
|
|
2
|
+
|
|
3
|
+
> The code-review gate used by `rdc:build` (step 9b), `rdc:fixit` (5.5),
|
|
4
|
+
> `rdc:review` (8b), `rdc:release` and `rdc:overnight`. It runs the specific
|
|
5
|
+
> validators over the changed files and finishes in one to two minutes.
|
|
6
|
+
>
|
|
7
|
+
> Approved: direct operator instruction — "we need to tune our code reviews to
|
|
8
|
+
> be specific -- if you ran the validator for solid and lint etc... it should
|
|
9
|
+
> take 1-2 minutes". 2026-09-21, Dave, in session.
|
|
10
|
+
|
|
11
|
+
## Why this replaced the open-ended reviewer
|
|
12
|
+
|
|
13
|
+
The previous default dispatched one `pr-review-toolkit:code-reviewer` agent to
|
|
14
|
+
read the whole diff. On the PRT launch build (2026-09-21) four such passes took
|
|
15
|
+
4 to 10 minutes and roughly 200–300k tokens each. Each one was a new judgment
|
|
16
|
+
call, so two runs could not be compared.
|
|
17
|
+
|
|
18
|
+
The gate below took **9.3 seconds** over the same build's 33 changed code files.
|
|
19
|
+
It found two things that had shipped:
|
|
20
|
+
|
|
21
|
+
- a SOLID regression: `investors/page.tsx` went from 96.3 to 85, on OCP;
|
|
22
|
+
- 45 lint diagnostics in 14 touched files. Most were import order. Three were
|
|
23
|
+
accessibility defects: two buttons with no `type`, and an SVG with no title.
|
|
24
|
+
|
|
25
|
+
A number that two runs agree on can block a merge. An opinion cannot.
|
|
26
|
+
|
|
27
|
+
## The gate
|
|
28
|
+
|
|
29
|
+
Run every step and report every result. A red step does not stop the others,
|
|
30
|
+
because the reader needs the whole picture in one pass.
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
BASE=<ref the change is measured against> # wave base sha, origin/develop, last release tag
|
|
34
|
+
SCOPE=<package or app dir the change touches> # never the monorepo root
|
|
35
|
+
CHANGED=$(git diff --name-only --diff-filter=d "$BASE" -- "$SCOPE" | grep -E '\.(ts|tsx|js|jsx|mjs|cjs)$')
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
| # | Check | Command | Blocks when |
|
|
39
|
+
|---|---|---|---|
|
|
40
|
+
| 1 | **FORM**: SOLID and boundaries | `rdc-solid-score "$SCOPE" --diff "$BASE" --format json` (add `--config <repo>/.solid-score.yml` if the repo has one) | `regressions`, `boundaryViolations` or `boundaryMisconfigured` is non-empty |
|
|
41
|
+
| 2 | **LINT**: changed files only | the repo's own linter; fix first, then check: `npx biome check --write $CHANGED` then `npx biome check $CHANGED` (ESLint: `npx eslint --fix` then `npx eslint`) | the second command exits non-zero |
|
|
42
|
+
| 3 | **TYPES** | `npx tsc --noEmit -p <package>/tsconfig.json`, once per touched package | exit non-zero |
|
|
43
|
+
| 4 | **TESTS**, scoped | the touched package's own test command, e.g. `pnpm --filter <pkg> exec vitest run` | any failure |
|
|
44
|
+
| 5 | **RENDERED UI**, if a route changed | the project's pinned `test:ui` Playwright spec against a fresh app-owned server (`rdc:review` step 9a) | any red assertion, or no harness |
|
|
45
|
+
|
|
46
|
+
Read the scorer output fully:
|
|
47
|
+
|
|
48
|
+
- `removedFiles` lists deletions. They are reported, not scored: a deleted file has no units left that can regress.
|
|
49
|
+
- `unresolvedLanguages` lists files no plugin parses, such as `.css`. They are unmeasured, never passed.
|
|
50
|
+
|
|
51
|
+
### Rules that keep it honest
|
|
52
|
+
|
|
53
|
+
- **Lint is fixed, never baselined.** Diagnostics already in a touched file
|
|
54
|
+
are fixed in the same change. Run `--write` first, and most of them clear
|
|
55
|
+
mechanically. Do not add an ignore list or a count ratchet.
|
|
56
|
+
- **SOLID is a ratchet by design.** `--diff` compares each unit with itself at
|
|
57
|
+
`$BASE`. OCP and LSP report `low` confidence, and that confidence is data. A
|
|
58
|
+
regression still blocks. The usual fix for an OCP drop is to move the
|
|
59
|
+
branching into a named module; for `investors/page.tsx` that means taking the
|
|
60
|
+
data read and FAQ shaping out into a loader.
|
|
61
|
+
- **Stay inside the time budget by narrowing scope.** Changed files and touched
|
|
62
|
+
packages only. If the gate takes more than two minutes, it is scanning too
|
|
63
|
+
wide. Narrow `$SCOPE` rather than dropping a step.
|
|
64
|
+
- **Never edit what a gate measures to turn it green.** A red check is either
|
|
65
|
+
fixed properly or reported as a finding.
|
|
66
|
+
|
|
67
|
+
### New UI tests: prove them before trusting them
|
|
68
|
+
|
|
69
|
+
Three lessons from the same build:
|
|
70
|
+
|
|
71
|
+
- **Negative-control every new UI assertion.** Run it once against the broken
|
|
72
|
+
or old state and watch it go red. A test that has never failed has not
|
|
73
|
+
proved anything. The CTA-clipping spec was trusted only after it failed on
|
|
74
|
+
the old CSS.
|
|
75
|
+
- **Measure settled layout.** Take bounding boxes after motion finishes, using
|
|
76
|
+
reduced motion or waiting for the animation to end. A panel measured
|
|
77
|
+
mid-slide reports the wrong size.
|
|
78
|
+
- **Include a 1280×800 viewport.** A laptop screen is where a tall panel
|
|
79
|
+
clips its call-to-action. 1440 and 390 alone missed it.
|
|
80
|
+
|
|
81
|
+
## When an LLM reviewer is still right
|
|
82
|
+
|
|
83
|
+
Only for a **named question the validators cannot answer**, scoped to the
|
|
84
|
+
files that question touches. Examples:
|
|
85
|
+
|
|
86
|
+
- "Does this middleware bypass skip auth on any protected path?"
|
|
87
|
+
- "Does any public string state a return figure?"
|
|
88
|
+
|
|
89
|
+
```
|
|
90
|
+
Agent({
|
|
91
|
+
subagent_type: "pr-review-toolkit:code-reviewer",
|
|
92
|
+
description: "<the question, in five words>",
|
|
93
|
+
prompt: "Answer one question about <files>: <question>. Read only those files.
|
|
94
|
+
Return CODE_REVIEW_COMPLETE with { critical_count, high_count, medium_count,
|
|
95
|
+
low_count, findings: [{severity, file:line, issue, suggested_fix}] }."
|
|
96
|
+
})
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
A reviewer asked to "review the diff" with no question is the pattern this
|
|
100
|
+
guide retired. Critical and high findings from a named-question pass block, the
|
|
101
|
+
same as a red gate step.
|
|
102
|
+
|
|
103
|
+
## What is not in the default gate
|
|
104
|
+
|
|
105
|
+
| Tool | Why it is not in the default gate | When to run it |
|
|
106
|
+
|---|---|---|
|
|
107
|
+
| `rdc-clean-code-score` | No `--diff`, so it reports absolute counts. On the PRT build it reported 475 findings in 17 files, 459 of them N4 "magic number" on SVG coordinates. Its default dead-export scope is the whole git repo, which ran out of 4 GB of heap on regen-root. | Advisory, in `rdc:full-analysis`. Always pass `--project-root <package dir>`; that run took 7.9 s. |
|
|
108
|
+
| `rdc-architecture-score` | No `--diff`. With no `layers:` config, every file is `unclassified`, so it measures nothing. | When the repo declares layers. |
|
|
109
|
+
| `rdc-duplication-score` | Absolute, not a delta. | Advisory. |
|
|
110
|
+
|
|
111
|
+
## Review is not closure
|
|
112
|
+
|
|
113
|
+
The gate replaces the per-wave LLM code review. It does **not** replace the
|
|
114
|
+
validator.
|
|
115
|
+
|
|
116
|
+
A non-epic work item still reaches `done` only through
|
|
117
|
+
`update_work_item_status(..., 'done', ..., <validator session>, 'validator')`,
|
|
118
|
+
and the database refuses an actor session equal to the item's own. A forked
|
|
119
|
+
agent shares its parent's session id, so a fork cannot validate the parent's
|
|
120
|
+
item. Dispatch a fresh agent for that.
|
|
121
|
+
|
|
122
|
+
## Receipt
|
|
123
|
+
|
|
124
|
+
Emit this line. The skill that ran the gate quotes it in the implementation
|
|
125
|
+
report or review report:
|
|
126
|
+
|
|
127
|
+
```
|
|
128
|
+
REVIEW_GATE: { base, scope, files, solid: { regressions, boundaryViolations, removedFiles, unresolved },
|
|
129
|
+
lint: <exit>, tsc: <exit>, tests: "<N passed>", ui: "<spec + viewports> | n/a",
|
|
130
|
+
elapsed_s, verdict: "CLEAN|HAS_ISSUES" }
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Under `RDC_TEST=1`: echo `[RDC_TEST] skipping review gate` and continue.
|
package/guides/work-contract.md
CHANGED
|
@@ -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
|
|
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
|
|
|
@@ -156,6 +156,17 @@ function isGitCommit(command) {
|
|
|
156
156
|
function extractCommitMessage(command) {
|
|
157
157
|
const cmd = String(command || '');
|
|
158
158
|
|
|
159
|
+
// `-m "$(cat <<'EOF' … EOF)"` / `-m "$(cat <<-'EOF' … EOF)"`: the plain -m
|
|
160
|
+
// regexes below match the FIRST unrelated quote inside the substitution
|
|
161
|
+
// (the opening `'` of `<<'EOF'` reads as a closing delimiter to the
|
|
162
|
+
// non-greedy pattern) and return early with literal shell text as the
|
|
163
|
+
// "message" -- before the heredoc fallback ever runs. This is the same
|
|
164
|
+
// defect class the 2026-08-29 fix addressed for a bare heredoc, just one
|
|
165
|
+
// wrapper layer further out: detect the substitution shape first and
|
|
166
|
+
// extract from its OWN heredoc body.
|
|
167
|
+
const mSub = cmd.match(/-m\s+"\$\(\s*cat\s+<<-?\s*(['"]?)([A-Za-z_][A-Za-z0-9_]*)\1\s*\n([\s\S]*?)\n[ \t]*\2\s*\)"/);
|
|
168
|
+
if (mSub) return { message: mSub[3], readable: true };
|
|
169
|
+
|
|
159
170
|
const msgMatch = cmd.match(/-m\s+["']([^"']+)["']/s) ||
|
|
160
171
|
cmd.match(/-m\s+"([\s\S]+?)"\s*(?:&&|$)/);
|
|
161
172
|
if (msgMatch) return { message: msgMatch[1], readable: true };
|
package/package.json
CHANGED
package/scripts/solid-score.mjs
CHANGED
|
@@ -141,6 +141,23 @@ function walk(dir, exclude, out = []) {
|
|
|
141
141
|
return out;
|
|
142
142
|
}
|
|
143
143
|
|
|
144
|
+
/**
|
|
145
|
+
* Does this `git show <ref>:<path>` stderr mean "the file is not at <ref>"?
|
|
146
|
+
*
|
|
147
|
+
* Git words it two ways, and the common one was missing until 2026-09-21:
|
|
148
|
+
* - `fatal: path 'p' does not exist in 'ref'` — absent at ref AND on disk
|
|
149
|
+
* - `fatal: path 'p' exists on disk, but not in 'ref'` — a NEW file in the
|
|
150
|
+
* working tree, i.e. every `--diff` over a change that adds a file
|
|
151
|
+
* Matching only the first made `--diff` crash on any diff with a new file.
|
|
152
|
+
* Anything else (a bad ref, a path-form mismatch) is not "absent" and must be
|
|
153
|
+
* rethrown, so a real error never passes silently as a new unit.
|
|
154
|
+
*/
|
|
155
|
+
export function isAbsentAtRef(stderr) {
|
|
156
|
+
const msg = String(stderr ?? '');
|
|
157
|
+
if (!msg.includes('fatal: path')) return false;
|
|
158
|
+
return msg.includes('does not exist in') || msg.includes('exists on disk, but not in');
|
|
159
|
+
}
|
|
160
|
+
|
|
144
161
|
/** Score a file's text as it existed at a given git ref, without touching the working tree. */
|
|
145
162
|
function scoreAtRef(repoRoot, filePath, ref, weights) {
|
|
146
163
|
const relPath = relative(repoRoot, filePath).split('\\').join('/');
|
|
@@ -151,10 +168,9 @@ function scoreAtRef(repoRoot, filePath, ref, weights) {
|
|
|
151
168
|
// `git show` fails both when the file is genuinely new at `ref` AND for
|
|
152
169
|
// unrelated reasons (a path-form mismatch, a bad ref). Collapsing both
|
|
153
170
|
// into "it's new" hides the second case — the exact class of silent
|
|
154
|
-
// path-form bug found three times in this file already
|
|
155
|
-
// "
|
|
156
|
-
|
|
157
|
-
if (msg.includes('does not exist in') || msg.includes('fatal: path') && msg.includes('does not exist')) return null;
|
|
171
|
+
// path-form bug found three times in this file already. Only git's two
|
|
172
|
+
// "not at this ref" messages are treated as new; anything else is rethrown.
|
|
173
|
+
if (isAbsentAtRef(err.stderr ?? err.message)) return null;
|
|
158
174
|
throw err;
|
|
159
175
|
}
|
|
160
176
|
const plugin = pluginFor(filePath);
|
|
@@ -237,6 +253,7 @@ async function main() {
|
|
|
237
253
|
}
|
|
238
254
|
|
|
239
255
|
let files;
|
|
256
|
+
let removedFiles = [];
|
|
240
257
|
if (diffRef) {
|
|
241
258
|
// `git diff --name-only <ref> -- <path>` (no `...HEAD`) compares `<ref>`
|
|
242
259
|
// directly against the WORKING TREE — committed history AND uncommitted
|
|
@@ -244,8 +261,16 @@ async function main() {
|
|
|
244
261
|
// diff` form, so they're unioned in separately. Before this fix, only
|
|
245
262
|
// `<ref>...HEAD` (committed history alone) was scored — a dirty tree
|
|
246
263
|
// with real regressions scored zero files and exited 0.
|
|
247
|
-
|
|
264
|
+
//
|
|
265
|
+
// Deleted paths are split out by git's own account (`--diff-filter=D`),
|
|
266
|
+
// not by an existsSync guess, so a path-form bug can never pass as a
|
|
267
|
+
// deletion. A deleted file has no current units and so nothing that can
|
|
268
|
+
// regress; before 2026-09-21 it reached extractUnits and crashed the gate
|
|
269
|
+
// with ENOENT. It is reported in `removedFiles`, never dropped silently.
|
|
270
|
+
const nameOnly = (filter) => execFileSync('git', ['diff', '--name-only', `--diff-filter=${filter}`, diffRef, '--', targetPath], { cwd: repoRoot, encoding: 'utf8' })
|
|
248
271
|
.split('\n').filter(Boolean);
|
|
272
|
+
const committed = nameOnly('d');
|
|
273
|
+
removedFiles = nameOnly('D');
|
|
249
274
|
const untracked = execFileSync('git', ['ls-files', '--others', '--exclude-standard', '--', targetPath], { cwd: repoRoot, encoding: 'utf8' })
|
|
250
275
|
.split('\n').filter(Boolean);
|
|
251
276
|
files = [...new Set([...committed, ...untracked])]
|
|
@@ -285,7 +310,7 @@ async function main() {
|
|
|
285
310
|
const boundaryViolations = boundaryFindings.filter((f) => !f.satisfied);
|
|
286
311
|
|
|
287
312
|
const output = {
|
|
288
|
-
results, regressions, boundaryFindings, boundaryViolations, boundaryMisconfigured, unresolvedLanguages,
|
|
313
|
+
results, regressions, removedFiles, boundaryFindings, boundaryViolations, boundaryMisconfigured, unresolvedLanguages,
|
|
289
314
|
config: { weights: config.weights, diff: config.diff, boundaryRuleCount: (config.boundaries ?? []).length },
|
|
290
315
|
configPath, configLoaded,
|
|
291
316
|
parser: parserName,
|
|
@@ -312,6 +337,10 @@ async function main() {
|
|
|
312
337
|
console.log('\nREGRESSIONS:');
|
|
313
338
|
for (const r of regressions) console.log(` ${r.file} :: ${r.unit} — ${r.reason} ${JSON.stringify(r)}`);
|
|
314
339
|
}
|
|
340
|
+
if (removedFiles.length) {
|
|
341
|
+
console.log(`\n${removedFiles.length} file(s) deleted since ${diffRef} — no units left to score:`);
|
|
342
|
+
for (const f of removedFiles) console.log(` ${f}`);
|
|
343
|
+
}
|
|
315
344
|
if (unresolvedLanguages.length) {
|
|
316
345
|
console.log(`\n${unresolvedLanguages.length} file(s) matched no registered language plugin — skipped, not silently passed:`);
|
|
317
346
|
for (const f of unresolvedLanguages) console.log(` ${relative(repoRoot, f)}`);
|
|
@@ -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
|
package/skills/build/SKILL.md
CHANGED
|
@@ -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
|
|
@@ -644,27 +644,30 @@ Read the task title and description, then:
|
|
|
644
644
|
|
|
645
645
|
⛔ **NO wave may dispatch until the previous wave's code-review pass clears.** Memory `feedback_code_review_per_wave.md` — Davesend 2026-05-24 incident.
|
|
646
646
|
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
-
|
|
666
|
-
|
|
667
|
-
|
|
647
|
+
Run the deterministic review gate in `guides/review-gate.md` over the wave's
|
|
648
|
+
merged diff, with `BASE=<wave-base-sha>` and `SCOPE` set to each package or
|
|
649
|
+
app the wave touched. That covers `rdc-solid-score --diff`, the repo linter on
|
|
650
|
+
changed files, `tsc`, scoped tests, and the UI spec when a route changed. It
|
|
651
|
+
takes one to two minutes; an open-ended reviewer agent took 4–10.
|
|
652
|
+
Approved: direct operator instruction — "we need to tune our code reviews to be
|
|
653
|
+
specific -- if you ran the validator for solid and lint etc... it should take 1-2
|
|
654
|
+
minutes". 2026-09-21, Dave, in session.
|
|
655
|
+
|
|
656
|
+
Dispatch `pr-review-toolkit:code-reviewer` only for a **named question** the
|
|
657
|
+
validators cannot answer, scoped to the files it touches (the guide's
|
|
658
|
+
"When an LLM reviewer is still right" section). Never dispatch it with a bare
|
|
659
|
+
"review the diff".
|
|
660
|
+
|
|
661
|
+
**Gate outcome:**
|
|
662
|
+
- A red gate step, or a critical/high finding from a named-question pass →
|
|
663
|
+
reopen the affected work items to `todo` with the `REVIEW_GATE` receipt and
|
|
664
|
+
the failing output in notes. Fix in a new wave before continuing.
|
|
665
|
+
- Medium/low findings from a named-question pass → append them to each work
|
|
666
|
+
item's `implementation_report.flags`. Do not reopen; the validator sees them.
|
|
667
|
+
- All steps green → log the `REVIEW_GATE` receipt with `verdict: "CLEAN"` and
|
|
668
|
+
proceed to the next wave.
|
|
669
|
+
|
|
670
|
+
Under `RDC_TEST=1`: echo `[RDC_TEST] skipping review gate` and proceed.
|
|
668
671
|
|
|
669
672
|
10. **Mandatory validator gate (runs after ALL waves complete — before any work item closes):**
|
|
670
673
|
|
|
@@ -747,4 +750,10 @@ NEVER run pnpm build or pnpm turbo. Use npx vitest run only.
|
|
|
747
750
|
|
|
748
751
|
## Capture lessons (exit step)
|
|
749
752
|
|
|
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 —
|
|
753
|
+
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:
|
|
754
|
+
|
|
755
|
+
- **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.
|
|
756
|
+
- **Fix not encoded**: submit it to the repository the fix belongs to, which opens one `lesson` + `proposal` issue there (an identical title opens nothing):
|
|
757
|
+
`node "$LIFEAI_ENV/bin/rdc-lesson.mjs" submit --repo <owning repo slug> --title "…" --what "…" --root-cause "…" --fix "…"`
|
|
758
|
+
|
|
759
|
+
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.
|
|
@@ -65,6 +65,12 @@ matches the numeric-suffix heuristic) alongside real hits (`data`, `temp`,
|
|
|
65
65
|
`bin.rdc-clean-code-score`; falls back to
|
|
66
66
|
`node <rdc-skills-install-path>/scripts/clean-code-score.mjs`.)
|
|
67
67
|
|
|
68
|
+
**In a monorepo, always pass `--project-root <package or app dir>`.** Without
|
|
69
|
+
it, the dead-export scan walks the whole git repo. On regen-root that ran out
|
|
70
|
+
of 4 GB of heap after 18 s (exit 134); scoped to `apps/prtrust` it took 7.9 s.
|
|
71
|
+
This scorer has no `--diff` and reports absolute counts, so it is advisory,
|
|
72
|
+
not part of the merge gate (`guides/review-gate.md`).
|
|
73
|
+
|
|
68
74
|
2. **Read `results`** — per-unit findings for N1 (cryptic names), N2 (heuristic
|
|
69
75
|
meaningless-distinction names, low confidence), N4 (magic numbers), N7
|
|
70
76
|
(generic class/function names), F1 (>20 statements), F2 (>3 params), E1
|
package/skills/collab/SKILL.md
CHANGED
|
@@ -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) |
|
|
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.
|
|
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).
|
|
582
|
-
|
|
583
|
-
|
|
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.
|
package/skills/deploy/SKILL.md
CHANGED
|
@@ -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
|
|
104
|
-
|
|
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.
|