@lifeaitools/rdc-skills 0.20.4 → 0.20.5
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 +1 -1
- package/git-sha.json +1 -1
- package/guides/output-contract.md +10 -0
- package/package.json +1 -1
- package/skills/build/SKILL.md +71 -0
- package/skills/collab/SKILL.md +20 -2
- package/skills/deploy/SKILL.md +75 -0
- package/skills/plan/SKILL.md +18 -0
- package/skills/release/SKILL.md +25 -0
package/git-sha.json
CHANGED
|
@@ -37,6 +37,16 @@ thing they need: **is this working or not, and what step are we on?**
|
|
|
37
37
|
- `⚠️ <skill>: <N findings> — <next action>`
|
|
38
38
|
- `❌ <skill>: <one-sentence reason>`
|
|
39
39
|
|
|
40
|
+
⛔ **The verdict emoji (✅ / ⚠️ / ❌) MUST be the FIRST character of the final
|
|
41
|
+
line — never prefix it with `**Verdict:**` or any other text.** The enforcing
|
|
42
|
+
Stop-hook checks that a line *begins* with the emoji; `**Verdict:** ✅ PASS …`
|
|
43
|
+
reads as a verdict to a human but FAILS the machine check because the line
|
|
44
|
+
starts with `**Verdict:`, not `✅` (lesson 2026-06-08-collab-verdict-line-must-start-with-emoji).
|
|
45
|
+
|
|
46
|
+
> This guide is the source under `guides/output-contract.md`; it is mirrored to
|
|
47
|
+
> `regen-root/.rdc/guides/output-contract.md` by the installer. Edit only the
|
|
48
|
+
> rdc-skills source here — never the mirror.
|
|
49
|
+
|
|
40
50
|
7. **Interactive checklists only when human input is required.** If the skill
|
|
41
51
|
needs a decision (pick an epic, confirm a destructive op), ask ONE question,
|
|
42
52
|
then resume.
|
package/package.json
CHANGED
package/skills/build/SKILL.md
CHANGED
|
@@ -199,6 +199,18 @@ Read the task title and description, then:
|
|
|
199
199
|
isolation: "worktree"
|
|
200
200
|
```
|
|
201
201
|
|
|
202
|
+
### ⛔ Concurrent committers ⇒ worktree isolation, no exceptions (docs included)
|
|
203
|
+
For ANY parallel agent dispatch where the agents COMMIT — **including a pure
|
|
204
|
+
docs wave** — force `isolation: "worktree"` so each agent commits in its own
|
|
205
|
+
tree and the orchestrator merges. NEVER fan out concurrent committers onto one
|
|
206
|
+
shared working tree (lesson 2026-06-13-build-concurrent-agents-same-branch-git-race:
|
|
207
|
+
three parallel doc agents on one `develop` tree raced on the git index/stash —
|
|
208
|
+
one commit swept in another agent's staged-but-uncommitted files under the wrong
|
|
209
|
+
message, two agents reported the SAME SHA, and a pre-commit `sync:docs` ref-lock
|
|
210
|
+
race misattributed authorship). "It's just docs" is NOT an exemption. The only
|
|
211
|
+
alternative to worktree isolation is running the committing agents **sequentially**
|
|
212
|
+
on the shared tree (one commits and pushes before the next starts).
|
|
213
|
+
|
|
202
214
|
**Agent model routing — pick per task, not per wave.** The supervisor session model does NOT cascade to agents; you must set `model` explicitly on every dispatch.
|
|
203
215
|
|
|
204
216
|
| Task character | Model | When to pick it |
|
|
@@ -219,6 +231,31 @@ Read the task title and description, then:
|
|
|
219
231
|
Without `max_turns: 70`, agents hit the default turn cap mid-task and stop.
|
|
220
232
|
`isolation: "worktree"` gives each agent its own git worktree and branch — eliminates push race conditions and index lock contention when multiple agents commit in parallel. The supervisor merges worktree branches after each wave (Step 9).
|
|
221
233
|
|
|
234
|
+
### ⛔ Worktree base must equal develop HEAD — assert BEFORE every isolated wave
|
|
235
|
+
The worktree-isolation harness has shipped worktrees pinned to a STALE base
|
|
236
|
+
commit (lessons 2026-06-10-build-worktree-stale-base, 2026-06-11-build-worktree-stale-base:
|
|
237
|
+
agents branched 464 commits / 4 days behind develop HEAD, on a tree where the
|
|
238
|
+
target app did not yet exist — their diffs would have silently reverted merged
|
|
239
|
+
work or operated on a deleted structure). **Before dispatching ANY
|
|
240
|
+
`isolation:"worktree"` wave**, assert each worktree's base equals current
|
|
241
|
+
develop HEAD:
|
|
242
|
+
```bash
|
|
243
|
+
DEV_HEAD=$(git rev-parse develop)
|
|
244
|
+
# After worktrees are created, for each agent worktree:
|
|
245
|
+
git worktree list # compare each agent worktree's SHA to $DEV_HEAD
|
|
246
|
+
# If a worktree base != $DEV_HEAD (it is behind), the wave is UNSAFE.
|
|
247
|
+
```
|
|
248
|
+
- If any worktree base is behind `$DEV_HEAD`: **ABORT isolation for this wave.**
|
|
249
|
+
Do NOT merge stale worktree output. Pivot to **sequential, non-isolated
|
|
250
|
+
dispatch on a real `develop` checkout** (one disjoint WP at a time to avoid
|
|
251
|
+
`.git/index` races; the supervisor pushes) — the same reason the validator
|
|
252
|
+
runs non-isolated (it must see merged develop).
|
|
253
|
+
- Also at every merge: `git show <branch>:<key-file> | grep -c <symbol-a-prior-wave-introduced>`
|
|
254
|
+
— a 0 where there should be ≥1 means the branch is stale or deleted a shared
|
|
255
|
+
export; resolve to `--ours` and re-apply that wave's real delta on current HEAD.
|
|
256
|
+
esbuild/tsc PASS is necessary, not sufficient — pair it with a grep gate on
|
|
257
|
+
the symbols a refactor must preserve.
|
|
258
|
+
|
|
222
259
|
### Forked agents vs. standalone agents
|
|
223
260
|
|
|
224
261
|
**When the supervisor has already read the plan** (via a prior `Read` tool call in the same session),
|
|
@@ -237,6 +274,21 @@ Read the task title and description, then:
|
|
|
237
274
|
**When the supervisor has NOT read the plan** (e.g. dispatching from a fresh `rdc:build` call with
|
|
238
275
|
only an epic ID), the agent has no plan context — write a full briefing prompt with all specs.
|
|
239
276
|
|
|
277
|
+
### ⛔ Reuse contract — when a WP builds on an existing subsystem
|
|
278
|
+
When a work package extends an existing subsystem, "compose adapter + X"
|
|
279
|
+
under-specifies reuse and lets an agent legitimately re-author markup/logic the
|
|
280
|
+
subsystem already exposes (lesson 2026-06-11-build-reuse-existing-engine-prompt:
|
|
281
|
+
an agent set up to reinvent a grid when the card engine already shipped four
|
|
282
|
+
`CardLayout` display types + a full `parseCommand → CardSpec → adapter → CardModel[]`
|
|
283
|
+
calling sequence). The dispatch prompt MUST:
|
|
284
|
+
1. **Enumerate the existing public API the agent must reuse, BY FILE** — types/enums
|
|
285
|
+
(`packages/.../types.ts:NN`), calling-sequence functions, AND the existing
|
|
286
|
+
display/render components — not just the data adapter.
|
|
287
|
+
2. **Mark which seams are extend/delegate-only.** State explicitly: "thread a
|
|
288
|
+
pass-through prop (e.g. `layout`) to the existing components; do NOT
|
|
289
|
+
reimplement layout/render." Verify at WP review that the agent reused the
|
|
290
|
+
named parser/adapter/components and did not hand-roll a parallel implementation.
|
|
291
|
+
|
|
240
292
|
---
|
|
241
293
|
|
|
242
294
|
### Required agent prompt contents
|
|
@@ -270,6 +322,25 @@ Read the task title and description, then:
|
|
|
270
322
|
- Use `run_in_background: true` for parallel execution
|
|
271
323
|
- NEVER let agents overlap on the same files
|
|
272
324
|
|
|
325
|
+
### ⛔ Agent Definition-of-Done additions (include in every prompt)
|
|
326
|
+
- **Declare every import in the package's OWN package.json.** Every import an
|
|
327
|
+
agent adds MUST be present in that package's own `package.json`
|
|
328
|
+
dependencies/devDependencies — never rely on monorepo-hoisted deps. A pnpm
|
|
329
|
+
worktree can import a root-hoisted dep (e.g. `vitest`,
|
|
330
|
+
`@supabase/supabase-js`) so `tsc`/`vitest` PASS in the worktree, then `tsc`
|
|
331
|
+
FAILS on a clean develop checkout after merge (lesson
|
|
332
|
+
2026-06-10-build-card-engine-agent-deps). Agent prompt line: *"Verify that
|
|
333
|
+
every import you add is declared in this package's own package.json — do not
|
|
334
|
+
rely on hoisted monorepo deps."*
|
|
335
|
+
- **A server/MCP/API task is NOT done without a committed automated test that
|
|
336
|
+
ships in the SAME commit and exercises EVERY surface.** Manual curl / a single
|
|
337
|
+
`/health` 200 is a proxy, not coverage (lesson 2026-06-10-build-weak-dod-no-tests).
|
|
338
|
+
For a collection (MCP skills, API routes, CLI commands): loop over ALL items
|
|
339
|
+
and assert `output == source` — never a single spot check. Wire an npm script
|
|
340
|
+
and run it green before the item leaves `review`. Agent prompt line: *"This
|
|
341
|
+
task is not done until a committed test in the same commit exercises every
|
|
342
|
+
surface; for collections, loop all items and assert output == source."*
|
|
343
|
+
|
|
273
344
|
8. **Post-wave test gate (mandatory):**
|
|
274
345
|
After all agents in a wave complete, before proceeding:
|
|
275
346
|
```bash
|
package/skills/collab/SKILL.md
CHANGED
|
@@ -98,8 +98,17 @@ Print `[rdc:collab] Still listening...` and retry SSE immediately. After 10
|
|
|
98
98
|
consecutive 30s timeouts (5 min idle), print a longer heartbeat but keep
|
|
99
99
|
looping.
|
|
100
100
|
|
|
101
|
-
|
|
102
|
-
|
|
101
|
+
**⛔ curl exit 28 (`--max-time`) is SUCCESS, not failure, on an SSE read.**
|
|
102
|
+
`curl --max-time 30` ALWAYS exits 28 at the timeout boundary — that is normal for
|
|
103
|
+
a long-lived SSE stream and says nothing about delivery. If a `data:` event was
|
|
104
|
+
received in the output, process it and proceed to Step 4 — do NOT treat exit 28 as
|
|
105
|
+
a curl failure (lesson 2026-06-08-collab-sse-exit-28-is-success: exit 28 arrived
|
|
106
|
+
together with a full `event: message` / `data: {...}` payload, and reading it as a
|
|
107
|
+
failure misclassified a zero-latency delivery). Only **connection-refused or a
|
|
108
|
+
non-200** is a real curl failure that triggers the polling fallback.
|
|
109
|
+
|
|
110
|
+
**If curl fails (daemon restart, connection refused, non-200 — NOT a bare exit 28
|
|
111
|
+
with a delivered `data:` event):** fall back to polling path below.
|
|
103
112
|
|
|
104
113
|
### Fallback path — polling (2s interval)
|
|
105
114
|
|
|
@@ -215,6 +224,15 @@ If Dave types in this terminal during a turn:
|
|
|
215
224
|
- Treat it as an override injected into the current task
|
|
216
225
|
- Acknowledge it in your `chitchat_reply` response
|
|
217
226
|
- If it changes direction mid-task, note what you stopped and why
|
|
227
|
+
- ⛔ **When an interjection appears to CONTRADICT the task premise, restate your
|
|
228
|
+
understanding in ONE sentence and confirm before branching into a wide
|
|
229
|
+
`AskUserQuestion` menu.** A tight "I read this as X — correct?" reconciles faster
|
|
230
|
+
than a multiple-choice and avoids acting on a misread premise (lesson
|
|
231
|
+
2026-06-08-collab-premise-contradicting-interjection: "there is no pm2 this
|
|
232
|
+
replaces it" was read as "PM2 is abolished as the transport" and triggered a
|
|
233
|
+
3-option transport menu, when it meant "there was no dev *site* yet — push to
|
|
234
|
+
the unchanged PM2 path"; the wide menu over-committed to one interpretation and
|
|
235
|
+
cost a round).
|
|
218
236
|
|
|
219
237
|
## Capture lessons (exit step)
|
|
220
238
|
|
package/skills/deploy/SKILL.md
CHANGED
|
@@ -66,6 +66,28 @@ rdc:deploy: <slug> → <domain>
|
|
|
66
66
|
✅ rdc:deploy: <slug> deployed in Nm Ns
|
|
67
67
|
```
|
|
68
68
|
|
|
69
|
+
#### Static PM2 dev sites — do NOT trust the push webhook (SSH-reset + served-hash gate)
|
|
70
|
+
|
|
71
|
+
For a **static** PM2 dev site, `git push` succeeding does NOT mean the live site
|
|
72
|
+
updated: the push webhook skips/instruments static apps unreliably, so the host
|
|
73
|
+
working tree (and the committed `dist/` it serves) can stay STUCK across several
|
|
74
|
+
pushes while HTTP stays 200 and `origin/develop` looks shipped (lesson
|
|
75
|
+
2026-06-11-deploy-static-host-stuck: issho served the v1.10.0 bundle across three
|
|
76
|
+
pushes because `/srv/regen/regen-root` never pulled). The only signal is the
|
|
77
|
+
SERVED bundle hash vs the local `dist/` hash.
|
|
78
|
+
|
|
79
|
+
After pushing committed `dist/`, SSH-reset the host explicitly, then verify the
|
|
80
|
+
served hash:
|
|
81
|
+
```bash
|
|
82
|
+
_K=$(mktemp); curl -s http://127.0.0.1:52437/v/vultr-dev-ssh > "$_K"; printf '\n' >> "$_K"; chmod 600 "$_K"
|
|
83
|
+
ssh -i "$_K" root@64.237.54.189 'cd /srv/regen/regen-root && git fetch -q origin develop && git reset -q --hard origin/develop && pm2 restart <app> --update-env'
|
|
84
|
+
rm -f "$_K"
|
|
85
|
+
# Then verify SERVED hash == local build hash (HTTP 200 is NOT proof):
|
|
86
|
+
curl -s https://<app>.dev.place.fund/ | grep -oE 'index-[A-Za-z0-9_-]+\.js' # served
|
|
87
|
+
grep -oE 'index-[A-Za-z0-9_-]+\.js' sites/<app>/dist/index.html # local
|
|
88
|
+
```
|
|
89
|
+
Only when the two hashes match do the content/screenshot gates mean anything.
|
|
90
|
+
|
|
69
91
|
### Mode 2 — new <slug>
|
|
70
92
|
|
|
71
93
|
**MANDATORY:** All new apps are created from `docs/runbooks/coolify-app-templates.json`. Read that file first — pick the right template, substitute the required vars, POST the exact payload. No manual field configuration. No improvisation. The template encodes all learned lessons (base_directory, build_pack, watch_paths, health_check, ports). Deviating from it breaks things.
|
|
@@ -112,6 +134,40 @@ rdc:deploy diagnose: <slug>
|
|
|
112
134
|
⚠️ rdc:deploy diagnose: <root cause in one sentence> — fix: <one command>
|
|
113
135
|
```
|
|
114
136
|
|
|
137
|
+
#### `next start` crash-loop — check `.next/BUILD_ID` FIRST
|
|
138
|
+
|
|
139
|
+
When a PM2 `next start` app is crash-looping (`pm2 jlist` shows high `restart_time`
|
|
140
|
+
/ "waiting restart"), check **`.next/BUILD_ID`** before chasing env/port theories —
|
|
141
|
+
it is the single gate `next start` enforces (`Could not find a production build in
|
|
142
|
+
the '.next' directory` repeats for every restart when it is missing). A `.next`
|
|
143
|
+
tree can exist as a PARTIAL build (manifests + server artifacts but no `BUILD_ID`)
|
|
144
|
+
— the signature of a `next build` that started but was interrupted/OOM-killed; the
|
|
145
|
+
crash loop then churns CPU and can re-trigger the OOM (lesson
|
|
146
|
+
2026-06-13-deploy-nextstart-missing-buildid: ~7300 restarts, all `BUILD_ID`-missing,
|
|
147
|
+
while the documented prior lead was the NEXT_PUBLIC env issue — which was NOT the
|
|
148
|
+
cause here). Fix sequence:
|
|
149
|
+
```bash
|
|
150
|
+
pm2 stop <app> # halt the loop so it stops competing for resources
|
|
151
|
+
rm -rf apps/<name>/.next # clear the partial tree
|
|
152
|
+
pnpm --filter @regen/<name> build # ONE clean scoped build (LOCAL BUILD SAFETY)
|
|
153
|
+
pm2 restart <app> --update-env
|
|
154
|
+
```
|
|
155
|
+
Guard: assert `apps/<name>/.next/BUILD_ID` exists before (re)starting any
|
|
156
|
+
`next start` process.
|
|
157
|
+
|
|
158
|
+
#### ⛔ On the 2nd IDENTICAL failed probe, STOP polling and diagnose full-state
|
|
159
|
+
|
|
160
|
+
A repeated identical failure (same 404, same 502, same non-200) is a STRUCTURAL
|
|
161
|
+
signal, not eventual-consistency — polling it will never clear it and reads to the
|
|
162
|
+
user as stalling/throttling (lesson 2026-06-10-deploy-stop-polling-diagnose: a
|
|
163
|
+
12×-404 poll loop on a remote-managed tunnel that was structurally ignoring the
|
|
164
|
+
local config — it could never clear). On the **2nd identical failed check**, stop
|
|
165
|
+
polling and pull GROUND TRUTH instead: list ALL processes / the whole effective
|
|
166
|
+
remote config / the full event log (`debugging-protocol.md` Rule 6 — full-state, not
|
|
167
|
+
a narrow filter). Poll ONLY when something is genuinely in-progress with a known
|
|
168
|
+
finish (a deploy build, a DNS first-create) — never to hope a structural error
|
|
169
|
+
resolves itself.
|
|
170
|
+
|
|
115
171
|
### Mode 4 — audit
|
|
116
172
|
|
|
117
173
|
```
|
|
@@ -159,6 +215,10 @@ rdc:deploy promote: <slug> → <prod-domain>
|
|
|
159
215
|
[ ] Scope resolved: --hotfix <sha> → that commit; else the app-path commits on develop not on main
|
|
160
216
|
[ ] Scope guard: promote ONLY this app's paths. NEVER merge develop→main wholesale (drags unrelated WIP to prod)
|
|
161
217
|
[ ] Clean worktree off origin/main (never switch the dirty working tree)
|
|
218
|
+
[ ] Export Supabase creds in the worktree BEFORE commit (the pre-commit `sync:docs` hook needs them, and a fresh worktree does NOT inherit the main checkout's `.env*`/shell env — without the key sync:docs silently regenerates a GUTTED `app-deployments.md` ("Registry: unavailable") and `git add`s it into the surgical promote; `--no-verify` is forbidden):
|
|
219
|
+
`export NEXT_PUBLIC_SUPABASE_URL=https://uvojezuorjgqzmhhgluu.supabase.co`
|
|
220
|
+
`export NEXT_PUBLIC_SUPABASE_ANON_KEY=$(curl -s http://127.0.0.1:52437/v/supabase-anon)`
|
|
221
|
+
Then ALWAYS `git show --stat HEAD` before pushing and confirm the file set is scoped — never ship the no-key gutted app-deployments.md. (lesson 2026-06-13-deploy-worktree-syncdocs-guts-app-deployments)
|
|
162
222
|
[ ] Apply change: cherry-pick <sha> (or `git checkout <develop-sha> -- <app-paths>`); confirm diff = expected files only
|
|
163
223
|
[ ] Mandatory pre-promote code-review (pr-review-toolkit:code-reviewer on the promote diff). Block on critical/high.
|
|
164
224
|
[ ] Commit on promote branch; push branch (NOT main directly — the main-push hook blocks raw main pushes)
|
|
@@ -393,8 +453,23 @@ curl -s -X PATCH -H "Authorization: Bearer $_COOLIFY" \
|
|
|
393
453
|
-H "Content-Type: application/json" \
|
|
394
454
|
-d '{"watch_paths":"apps/<name>/**\npackages/**"}' \
|
|
395
455
|
"$DEPLOY_API_BASE/api/v1/applications/<uuid>"
|
|
456
|
+
|
|
457
|
+
# Change the app's domain — the writable field is "domains", NOT "fqdn"
|
|
458
|
+
# (Coolify v4 PATCH rejects {"fqdn":...} with "This field is not allowed"; fqdn is read-only/derived)
|
|
459
|
+
curl -s -X PATCH -H "Authorization: Bearer $_COOLIFY" \
|
|
460
|
+
-H "Content-Type: application/json" \
|
|
461
|
+
-d '{"domains":"https://<host>"}' \
|
|
462
|
+
"$DEPLOY_API_BASE/api/v1/applications/<uuid>"
|
|
396
463
|
```
|
|
397
464
|
|
|
465
|
+
**Domain change / namespace migration** (lesson 2026-06-13-deploy-media-manager-namespace-migration):
|
|
466
|
+
PATCH `applications/<uuid>` with `{"domains":"https://<host>"}` — never `fqdn`.
|
|
467
|
+
For an app NEW to main (first prod deploy) also bring the app + a lockfile importer
|
|
468
|
+
to main (clean worktree off origin/main, `pnpm install --lockfile-only`, verify the
|
|
469
|
+
diff = additions for `apps/<name>:` only); resolve the lockfile-guard vs scope-guard
|
|
470
|
+
collision by committing the app+lockfile as a SINGLE `chore(infra):`-subject commit
|
|
471
|
+
(the scope-guard's documented escape hatch) so both pre-commit guards pass.
|
|
472
|
+
|
|
398
473
|
**Never print `$_COOLIFY` to stdout.** Inline from clauth only — do not assign raw strings.
|
|
399
474
|
|
|
400
475
|
If clauth daemon is not responding (`curl -s http://127.0.0.1:52437/ping` fails):
|
package/skills/plan/SKILL.md
CHANGED
|
@@ -251,6 +251,24 @@ Q5. What SSL path?
|
|
|
251
251
|
|
|
252
252
|
Embed all five answers into the infra task description verbatim before handing to the agent.
|
|
253
253
|
|
|
254
|
+
## MCP / infra plans — mirror the closest sibling deployment FIRST
|
|
255
|
+
|
|
256
|
+
Before writing any plan that stands up an MCP server or infra service, read how the
|
|
257
|
+
**closest existing sibling** is actually deployed (`.mcp.json` + its PM2/tunnel or
|
|
258
|
+
Coolify/Docker config) and **cite it in the plan**. Two MCP topologies coexist and
|
|
259
|
+
applying the wrong reference over-engineers the design (lesson
|
|
260
|
+
2026-06-10-plan-mirror-sibling-mcp-pattern: a first MCP plan proposed
|
|
261
|
+
Docker + Coolify + a Cloudflare-proxied origin + runtime GitHub-pull when the real
|
|
262
|
+
pattern was a local Node process + clauth-managed tunnel, exactly like codeflow-mcp):
|
|
263
|
+
|
|
264
|
+
- **LOCAL-MCP reference = `codeflow-mcp`** — local Node process (`:3109`) + clauth-managed
|
|
265
|
+
tunnel ingress. Mirror this for MCPs that live on Dave's box.
|
|
266
|
+
- **REMOTE-MCP reference = `web-research` / `regen-media`** — Coolify/Docker, Cloudflare-proxied
|
|
267
|
+
origin (`.claude/rules/mcp-endpoint-design.md` covers the REMOTE class only).
|
|
268
|
+
|
|
269
|
+
Decide which class applies and name the sibling in the plan's Design Decisions before
|
|
270
|
+
designing topology. Do not reach for the REMOTE rule by default.
|
|
271
|
+
|
|
254
272
|
## Capture lessons (exit step)
|
|
255
273
|
|
|
256
274
|
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.
|
package/skills/release/SKILL.md
CHANGED
|
@@ -99,6 +99,31 @@ npm view <package-name> version
|
|
|
99
99
|
|
|
100
100
|
Never use `--force` or bypass hooks. If a hook fails, fix the cause.
|
|
101
101
|
|
|
102
|
+
## ⛔ Standalone-repo staging guard (no `git add -A`)
|
|
103
|
+
|
|
104
|
+
Standalone repos (`rdc-skills`, `clauth`, `build-corpus`) have NO pre-commit
|
|
105
|
+
doc-sync/scope guard to catch contamination. In them:
|
|
106
|
+
|
|
107
|
+
- **REFUSE `git add -A` / `git add .`.** Stage explicit declared paths only
|
|
108
|
+
(`git add skills/<name>/SKILL.md package.json ...`).
|
|
109
|
+
- Run `git status --porcelain` FIRST. If untracked files exist that are not part
|
|
110
|
+
of the declared change, STOP — list or stash them; do not sweep them in.
|
|
111
|
+
- **Pre-tag guard: refuse to tag if `git diff --cached --name-only` includes any
|
|
112
|
+
path outside the declared change set.** A broad add swept 4 pre-existing
|
|
113
|
+
untracked skill files into a tagged release that CI published before anyone
|
|
114
|
+
noticed (lesson 2026-06-08-release-git-add-all-swept-untracked-wip). Same
|
|
115
|
+
dirty-tree contamination class as a lockfile generated against a dirty tree.
|
|
116
|
+
|
|
117
|
+
## ⛔ Cross-platform prepack + verify the PUBLISHED tarball
|
|
118
|
+
|
|
119
|
+
- **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.
|
|
120
|
+
- **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:
|
|
121
|
+
```bash
|
|
122
|
+
npm pack <pkg>@<version> # downloads the PUBLISHED tarball
|
|
123
|
+
tar -xzOf <pkg>-<version>.tgz package/<file> # inspect the shipped file
|
|
124
|
+
```
|
|
125
|
+
Confirm the published artifact carries what CI's prepack was supposed to stamp (e.g. `git_sha == tag commit`).
|
|
126
|
+
|
|
102
127
|
## RDC Skills Package
|
|
103
128
|
|
|
104
129
|
For this package, prefer the npm installer binary after publish:
|