@lifeaitools/rdc-skills 0.22.0 → 0.23.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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rdc",
3
- "version": "0.22.0",
3
+ "version": "0.23.0",
4
4
  "description": "RDC typed-agent dispatch skill suite for Claude Code — plan, build, review, overnight unattended builds with work-item tracking and TDD enforcement.",
5
5
  "author": {
6
6
  "name": "LIFEAI",
package/git-sha.json CHANGED
@@ -1,3 +1,3 @@
1
1
  {
2
- "sha": "00a9e253509122dd9948e1e558756f8f317f1b20"
2
+ "sha": "7b0495d94de2ee447dadb0f1228bbbe9650a5563"
3
3
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lifeaitools/rdc-skills",
3
- "version": "0.22.0",
3
+ "version": "0.23.0",
4
4
  "description": "RDC typed-agent dispatch skill suite for Claude Code - plan, build, review, overnight builds",
5
5
  "keywords": [
6
6
  "claude-code",
@@ -163,6 +163,28 @@ Read the task title and description, then:
163
163
  - DB/migration task: at least schema object, relationship/guard, policy/permission, seed/fixture or backfill, and smoke query.
164
164
  - Editor/sidebar/CLI workflow: at least start, attach/open, enqueue action, observe result, timeout/error, and live refresh where applicable.
165
165
 
166
+ ### ⛔ Deliverable / acceptance check-off table — show BEFORE any implementation
167
+ Before dispatching the first wave, render a deliverable/acceptance table and
168
+ keep it visible through the build (lesson 2026-06-16-build-poor-goal-execution-mdk-brain:
169
+ a build satisfied generic checklist rows — tsc clean, route 200 — while never
170
+ touching the surface the user actually named, because no row anchored the
171
+ user's TARGET SURFACE). The table MUST contain:
172
+ - **One mandatory row for the user-named TARGET SURFACE** — the exact screen,
173
+ endpoint, file, or behavior the user asked for, by name. Its acceptance check
174
+ is what proves THAT surface renders/works, not a proxy.
175
+ - **At least one NEGATIVE verifier row** — a check that proves the WRONG thing
176
+ does NOT happen (e.g. "mock data is NOT rendered", "old route returns 404",
177
+ "stub component is absent from the bundle"). A positive-only suite passes
178
+ even when the deliverable is wired to the wrong source.
179
+
180
+ | Deliverable | Target surface? | Acceptance check | Negative verifier | Status |
181
+ |---|---|---|---|---|
182
+
183
+ **Gating rule:** any work item whose deliverable maps to the TARGET SURFACE row
184
+ stays in `review` (never `done`) until that target-surface acceptance check
185
+ passes. Generic gates (tsc, route 200) clearing is NOT sufficient to advance
186
+ the target-surface item.
187
+
166
188
  If the gate fails:
167
189
  - Interactive: show the failing rows and invoke `rdc:plan <epic-id>` to repair the matrix before dispatch.
168
190
  - Unattended: invoke `rdc:plan <epic-id> --unattended`, reload tasks, and run this gate once more.
@@ -211,6 +233,23 @@ Read the task title and description, then:
211
233
  alternative to worktree isolation is running the committing agents **sequentially**
212
234
  on the shared tree (one commits and pushes before the next starts).
213
235
 
236
+ ### ⛔ Foreign concurrent session guard — `git status` BEFORE the build
237
+ Worktree isolation protects against THIS build's own agents, not against a
238
+ DIFFERENT session (another cell, a Codex run, a human) already committing on
239
+ the same shared tree (lesson 2026-06-16-build-concurrent-session-shared-tree-commit-corruption:
240
+ a foreign session's staged-but-uncommitted files were swept into this build's
241
+ commit under the wrong message). Before dispatching any wave, run `git status`
242
+ to detect foreign-dirty files you did not create. If foreign-dirty files are
243
+ present: do NOT fan out concurrent committers — **serialize ALL committers to
244
+ the supervisor** (agents return diffs/patches; the supervisor stages and
245
+ commits each one alone). After every supervisor commit, assert the exact file
246
+ set landed and nothing foreign leaked in:
247
+ ```bash
248
+ git show --stat <sha> # confirm ONLY the files this commit owns are listed
249
+ ```
250
+ A `git show --stat` that lists a file the agent did not touch = a foreign file
251
+ leaked into the commit; reset and re-stage by explicit path.
252
+
214
253
  **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.
215
254
 
216
255
  | Task character | Model | When to pick it |
@@ -346,6 +346,25 @@ OG_IMG=$(echo "$HEAD" | grep -ioE 'property="og:image"[^>]*content="([^"]*)"' |
346
346
 
347
347
  **Why this exists (2026-06-05):** life.ai deployed to production with zero social/SEO metadata — no description, no OG, no favicon, no sitemap. HTTP 200 + TLS + content passed; metadata was invisible to the existing gates. This audit catches that class of defect.
348
348
 
349
+ ## Hotlink referer allowlist — new media.place.fund consumer domains
350
+
351
+ When onboarding a NEW brand domain that loads assets from `media.place.fund`, add
352
+ that domain to the hotlink-protection Worker's referer allowlist **before
353
+ go-live** (lesson 2026-06-14-deploy-issholiving-referer-hotlink-403: a new brand
354
+ domain served its own HTML fine but every `media.place.fund` image returned 403
355
+ because the hotlink Worker rejected the unknown `Referer`). The image 403 is
356
+ invisible to the HTTP-200 / TLS / metadata gates — they probe the HTML document,
357
+ not the cross-origin asset.
358
+
359
+ - Add the new origin (apex + `www`, dev + prod) to the Worker's referer allowlist
360
+ and redeploy the Worker before the brand domain goes live.
361
+ - Verify with an explicit `Referer` probe (NOT a bare curl — a missing Referer can
362
+ pass while the real browser Referer fails):
363
+ ```bash
364
+ curl -s -o /dev/null -w "%{http_code}" -e "https://<new-brand-domain>/" \
365
+ "https://media.place.fund/<a-known-asset-path>" # expect 200, not 403
366
+ ```
367
+
349
368
  ## PUBLISH.md Integration
350
369
 
351
370
  Every deploy reads `PUBLISH.md` from the app's source root to derive `watch_paths` and to register surfaces in Studio `artifact_registry`.
@@ -73,6 +73,23 @@ Use URL ingest when the file already exists in cloud storage:
73
73
  fs_ingest_url url="https://..." path="docs/source/file.md" expected_sha256="<optional>"
74
74
  ```
75
75
 
76
+ ### ⛔ Ingest discipline (lesson 2026-06-16-collab-claudeai-fs-ingest-race-and-preview-pollution)
77
+
78
+ - **Prefer synchronous `fs_write` over `fs_ingest_url` for commit-bound bytes.**
79
+ `fs_ingest_url` can return before the bytes have landed on disk; a `git add`
80
+ immediately after races the download and silently stages nothing. If you MUST
81
+ use `fs_ingest_url` for content you will commit, `fs_stat`-poll the target path
82
+ until size/hash is stable BEFORE staging or committing.
83
+ - **A silent `git add` skip is NOT gitignore.** If `git add <path>` adds nothing
84
+ and the file is not obviously ignored, do not assume `.gitignore` — confirm with
85
+ `git check-ignore -v <path>`. No output means it is NOT ignored, so the real
86
+ cause is a missing/empty/racing file, not an ignore rule.
87
+ - **Never ingest claude.ai preview / Artifacts URLs.** URLs like
88
+ `*.claude.ai/.../preview` or Artifact render endpoints serve a wrapped,
89
+ data-omelette-injected document (host chrome, sanitizer rewrites, injected
90
+ markers) — not the clean source bytes. Ingesting them pollutes the repo. Get
91
+ the durable source via the GitHub-branch import path (§4) instead.
92
+
76
93
  Use guarded append when appending to a known file:
77
94
 
78
95
  ```text
@@ -42,17 +42,38 @@ If the sentinel file does not exist, the Stop hook will NOT block — which mean
42
42
 
43
43
  Before touching any code, verify the environment is safe:
44
44
 
45
- 1. **Clauth daemon alive:**
45
+ 1. **Clauth daemon alive AND unlocked:** `/ping` alive is NOT enough — a LOCKED
46
+ vault answers `/ping` but every `/v/<service>` returns nothing, so credentials
47
+ silently resolve empty and a long unattended run fails hours later
48
+ (lesson 2026-06-16-overnight-preflight-clauth-locked-and-shared-develop-cells).
49
+ Assert `locked:false` before proceeding:
46
50
  ```bash
47
51
  curl -s http://127.0.0.1:52437/ping
52
+ curl -s http://127.0.0.1:52437/status | python3 -c "import sys,json; s=json.load(sys.stdin); print('locked:', s.get('locked')); sys.exit(1 if s.get('locked') else 0)"
48
53
  ```
49
- If not responding: report `BLOCKED: credential daemon offline` and exit. Do not proceed.
54
+ If not responding OR `locked:true`: report `BLOCKED: credential daemon offline or locked` and exit. Do not proceed.
50
55
 
51
- 2. **Git state clean:**
56
+ 2. **Git state clean AND no concurrent committer on shared develop:** Overnight
57
+ shares the `develop` working tree with other cells/sessions. A second session
58
+ committing concurrently can drop a just-committed file during a rebase
59
+ (lessons 2026-06-16-overnight-preflight-clauth-locked-and-shared-develop-cells,
60
+ 2026-06-17-build-shared-develop-rebase-dropped-committed-file).
52
61
  ```bash
53
62
  git status --short
63
+ git fetch -q origin && git log --oneline @..@{u} # any rows = origin moved under you
54
64
  ```
55
- Must be on the development branch with no uncommitted changes. If dirty: commit or stash first.
65
+ Must be on the development branch with no uncommitted changes. If dirty: commit
66
+ or stash first. If `origin/develop` is ahead of local at preflight, another
67
+ session is actively committing — enforce these rules for the whole run:
68
+ - **Atomic stage+commit by explicit path** — `git add <paths>` then immediate
69
+ `git commit`; never leave a wide `git add -A` window open while another
70
+ session may stage.
71
+ - **Post-push origin verification** — after every push, confirm each committed
72
+ file actually reached origin (a rebase can silently drop it):
73
+ ```bash
74
+ git cat-file -e origin/develop:<path> && echo "OK: <path> on origin" || echo "DROPPED: <path> — re-apply and re-push"
75
+ ```
76
+ A `DROPPED` result means re-apply the file on fresh `origin/develop` HEAD and push again.
56
77
 
57
78
  3. **Baseline review:**
58
79
  Run `rdc:review --unattended`. If `REVIEW_STATUS.verdict = "HAS_ISSUES"` and
@@ -39,12 +39,52 @@ description: "Usage `rdc:plan <topic>` — No epic exists and you need architect
39
39
  - What tests exist?
40
40
  - What's the dependency graph?
41
41
 
42
+ ### ⛔ Before planning "wire fetchers into an existing view" — prove the view can render real data
43
+ When a work package wires real data into a view that already renders, do NOT
44
+ assume the view is fetch-ready (lesson 2026-06-16-build-verify-view-prop-api-before-wiring:
45
+ a view imported its rows from a module-level `../mock/` constant with no data
46
+ prop, so wiring an API fetcher changed nothing the user saw — and `tsc` + a
47
+ route-200 probe both passed because they never prove real data renders). Before
48
+ writing the WP, grep the target view for module-level `../mock/` (or `mockData`,
49
+ `fixtures/`, hard-coded seed arrays) imports AND confirm a real data prop /
50
+ loader seam exists:
51
+ ```bash
52
+ grep -nE "from ['\"].*/(mock|fixtures)" <target-view-file>
53
+ ```
54
+ If the view binds to a module-level mock and exposes no data prop, the WP MUST
55
+ include removing the mock import and threading a real prop — not just adding a
56
+ fetcher. "tsc + route 200" is NOT acceptance for "real data renders"; require a
57
+ negative verifier (mock value is absent from the rendered output).
58
+
42
59
  3. **Make design decisions** — for each major choice:
43
60
  - State the decision clearly
44
61
  - Document what was chosen and what was rejected
45
62
  - Explain WHY (tradeoff rationale)
46
63
  - Note consequences and reversibility
47
64
 
65
+ ### Ops / runtime / observability surfaces — ask cloud-DB vs locally-observable, do NOT default to Supabase-SSOT
66
+ For any ops, runtime, monitoring, or observability surface (process state, log
67
+ tails, deploy health, queue depth, session liveness, local daemon status),
68
+ surface the **data-source tradeoff as an explicit AskUserQuestion** rather than
69
+ reaching for Supabase-as-single-source-of-truth by reflex (lesson
70
+ 2026-06-20-plan-cloud-vs-local-source-tradeoff). Some of this data is only
71
+ truthfully observable LOCALLY (the process/host itself) and a cloud-DB mirror
72
+ is stale or lossy; other data genuinely belongs in Supabase. In interactive
73
+ mode ask which source; in unattended mode escalate via advisor. Record the
74
+ chosen source and its staleness window as a Design Decision.
75
+
76
+ ### New shared `@regen/*` package — force an explicit consume-strategy Design Decision
77
+ When the plan introduces a NEW shared `@regen/*` package, check who consumes it.
78
+ If ANY consumer is a non-Next / CJS context (a Node CLI, a PM2 script, a Jest
79
+ suite, an MCP server, a `.cjs` tool) — not just Next.js apps that transpile ESM
80
+ workspace packages — the plan MUST contain an explicit **consume-strategy Design
81
+ Decision** (lesson 2026-06-20-plan-shared-lib-cjs-esm-dist-gap: an ESM-only
82
+ `dist` shipped fine to Next consumers but `require()` from a CJS consumer threw
83
+ `ERR_REQUIRE_ESM` at runtime). The decision picks ONE: emit a CJS (or dual
84
+ ESM+CJS) `dist`, OR have the CJS consumer install a TS/ESM loader (e.g.
85
+ `tsx`/`ts-node`). Name the consumers and the chosen strategy; do not leave the
86
+ module format implicit.
87
+
48
88
  4. **Define work packages** — break into agent-dispatchable units:
49
89
  - Each work package = one agent assignment
50
90
  - No file overlap between packages