@xhulz/nina 0.28.20 → 0.28.21

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.
Files changed (115) hide show
  1. package/package.json +1 -1
  2. package/releases/0.28.21/core/GAPS.md +125 -0
  3. package/releases/0.28.21/core/answered.json +29 -0
  4. package/releases/0.28.21/core/defaults/tree/.claude/agents/architect.md +1 -0
  5. package/releases/0.28.21/core/defaults/tree/.claude/agents/dba.md +3 -0
  6. package/releases/0.28.21/core/defaults/tree/.claude/agents/devops.md +1 -0
  7. package/releases/0.28.21/core/defaults/tree/.claude/agents/implementer.md +1 -0
  8. package/releases/0.28.21/core/defaults/tree/.claude/agents/integration-tester.md +3 -0
  9. package/releases/0.28.21/core/defaults/tree/.claude/agents/qa.md +2 -0
  10. package/releases/0.28.21/core/defaults/tree/.claude/agents/reviewer.md +3 -0
  11. package/releases/0.28.21/core/defaults/tree/.claude/agents/secops.md +3 -0
  12. package/releases/0.28.21/core/defaults/tree/.claude/agents/solidity-auditor.md +3 -0
  13. package/releases/0.28.21/core/defaults/tree/.claude/agents/solidity-dev.md +3 -0
  14. package/releases/0.28.21/core/tree/.claude/agents/architect.md +125 -0
  15. package/releases/0.28.21/core/tree/.claude/agents/dba.md +107 -0
  16. package/releases/0.28.21/core/tree/.claude/agents/devops.md +113 -0
  17. package/releases/0.28.21/core/tree/.claude/agents/implementer.md +155 -0
  18. package/releases/0.28.21/core/tree/.claude/agents/integration-tester.md +160 -0
  19. package/releases/0.28.21/core/tree/.claude/agents/planner.md +132 -0
  20. package/releases/0.28.21/core/tree/.claude/agents/qa.md +146 -0
  21. package/releases/0.28.21/core/tree/.claude/agents/reviewer.md +180 -0
  22. package/releases/0.28.21/core/tree/.claude/agents/secops.md +121 -0
  23. package/releases/0.28.21/core/tree/.claude/agents/solidity-auditor.md +126 -0
  24. package/releases/0.28.21/core/tree/.claude/agents/solidity-dev.md +123 -0
  25. package/releases/0.28.21/core/tree/.claude/agents-overview.md +64 -0
  26. package/releases/0.28.21/core/tree/.claude/graph.md +73 -0
  27. package/releases/0.28.21/core/tree/.claude/patterns.md +212 -0
  28. package/releases/0.28.21/core/tree/.claude/pills/README.md +145 -0
  29. package/releases/0.28.21/core/tree/.claude/pipeline.md +102 -0
  30. package/releases/0.28.21/core/tree/.claude/retrieval.md +104 -0
  31. package/releases/0.28.21/core/tree/.claude/router.md +201 -0
  32. package/releases/0.28.21/core/tree/.claude/templates/integration.md +45 -0
  33. package/releases/0.28.21/core/tree/CLAUDE.md +155 -0
  34. package/releases/0.28.21/core/tree/scripts/edit-guard.mjs +16 -0
  35. package/releases/0.28.21/core/tree/scripts/harness-check.mjs +71 -0
  36. package/releases/0.28.21/core/tree/scripts/loop-gate.mjs +19 -0
  37. package/releases/0.28.21/core/vocabulary.json +12 -0
  38. package/releases/0.28.21/surfaces/blockchain/tree/.claude/agents/architect.md +5 -0
  39. package/releases/0.28.21/surfaces/blockchain/tree/.claude/agents/devops.md +5 -0
  40. package/releases/0.28.21/surfaces/blockchain/tree/.claude/agents/reviewer.md +5 -0
  41. package/releases/0.28.21/surfaces/blockchain/tree/.claude/agents/solidity-auditor.md +18 -0
  42. package/releases/0.28.21/surfaces/blockchain/tree/.claude/agents/solidity-dev.md +16 -0
  43. package/releases/0.28.21/surfaces/blockchain/tree/.claude/agents-overview.md +6 -0
  44. package/releases/0.28.21/surfaces/blockchain/tree/.claude/graph.md +11 -0
  45. package/releases/0.28.21/surfaces/blockchain/tree/.claude/router.md +9 -0
  46. package/releases/0.28.21/surfaces/blockchain/tree/CLAUDE.md +12 -0
  47. package/releases/0.28.21/surfaces/db/tree/.claude/agents/architect.md +8 -0
  48. package/releases/0.28.21/surfaces/db/tree/.claude/agents/dba.md +84 -0
  49. package/releases/0.28.21/surfaces/db/tree/.claude/agents/devops.md +14 -0
  50. package/releases/0.28.21/surfaces/db/tree/.claude/agents/implementer.md +5 -0
  51. package/releases/0.28.21/surfaces/db/tree/.claude/agents/integration-tester.md +13 -0
  52. package/releases/0.28.21/surfaces/db/tree/.claude/agents/planner.md +2 -0
  53. package/releases/0.28.21/surfaces/db/tree/.claude/agents/reviewer.md +25 -0
  54. package/releases/0.28.21/surfaces/db/tree/.claude/agents/secops.md +2 -0
  55. package/releases/0.28.21/surfaces/db/tree/.claude/agents-overview.md +5 -0
  56. package/releases/0.28.21/surfaces/db/tree/.claude/graph.md +8 -0
  57. package/releases/0.28.21/surfaces/db/tree/.claude/patterns.md +29 -0
  58. package/releases/0.28.21/surfaces/db/tree/.claude/pipeline.md +13 -0
  59. package/releases/0.28.21/surfaces/db/tree/.claude/retrieval.md +5 -0
  60. package/releases/0.28.21/surfaces/db/tree/.claude/router.md +10 -0
  61. package/releases/0.28.21/surfaces/db/tree/CLAUDE.md +23 -0
  62. package/releases/0.28.21/surfaces/edge-cf/tree/.claude/agents/architect.md +14 -0
  63. package/releases/0.28.21/surfaces/edge-cf/tree/.claude/agents/dba.md +2 -0
  64. package/releases/0.28.21/surfaces/edge-cf/tree/.claude/agents/devops.md +31 -0
  65. package/releases/0.28.21/surfaces/edge-cf/tree/.claude/agents/implementer.md +14 -0
  66. package/releases/0.28.21/surfaces/edge-cf/tree/.claude/agents/integration-tester.md +11 -0
  67. package/releases/0.28.21/surfaces/edge-cf/tree/.claude/agents/qa.md +3 -0
  68. package/releases/0.28.21/surfaces/edge-cf/tree/.claude/agents/reviewer.md +8 -0
  69. package/releases/0.28.21/surfaces/edge-cf/tree/.claude/agents/secops.md +8 -0
  70. package/releases/0.28.21/surfaces/edge-cf/tree/.claude/patterns.md +17 -0
  71. package/releases/0.28.21/surfaces/edge-cf/tree/.claude/retrieval.md +8 -0
  72. package/releases/0.28.21/surfaces/edge-cf/tree/.claude/router.md +21 -0
  73. package/releases/0.28.21/surfaces/edge-cf/tree/CLAUDE.md +27 -0
  74. package/releases/0.28.21/surfaces/frontend/tree/.claude/agents/architect.md +20 -0
  75. package/releases/0.28.21/surfaces/frontend/tree/.claude/agents/devops.md +28 -0
  76. package/releases/0.28.21/surfaces/frontend/tree/.claude/agents/implementer.md +25 -0
  77. package/releases/0.28.21/surfaces/frontend/tree/.claude/agents/qa.md +17 -0
  78. package/releases/0.28.21/surfaces/frontend/tree/.claude/agents/reviewer.md +62 -0
  79. package/releases/0.28.21/surfaces/frontend/tree/.claude/patterns.md +15 -0
  80. package/releases/0.28.21/surfaces/frontend/tree/.claude/retrieval.md +5 -0
  81. package/releases/0.28.21/surfaces/frontend/tree/.claude/router.md +17 -0
  82. package/releases/0.28.21/surfaces/frontend/tree/CLAUDE.md +5 -0
  83. package/releases/0.28.21/surfaces/integrations/tree/.claude/agents/architect.md +16 -0
  84. package/releases/0.28.21/surfaces/integrations/tree/.claude/agents/implementer.md +12 -0
  85. package/releases/0.28.21/surfaces/integrations/tree/.claude/agents/integration-tester.md +20 -0
  86. package/releases/0.28.21/surfaces/integrations/tree/.claude/agents/planner.md +2 -0
  87. package/releases/0.28.21/surfaces/integrations/tree/.claude/agents/reviewer.md +21 -0
  88. package/releases/0.28.21/surfaces/integrations/tree/.claude/agents/secops.md +2 -0
  89. package/releases/0.28.21/surfaces/integrations/tree/.claude/agents-overview.md +8 -0
  90. package/releases/0.28.21/surfaces/integrations/tree/.claude/graph.md +9 -0
  91. package/releases/0.28.21/surfaces/integrations/tree/.claude/patterns.md +38 -0
  92. package/releases/0.28.21/surfaces/integrations/tree/.claude/pipeline.md +16 -0
  93. package/releases/0.28.21/surfaces/integrations/tree/.claude/retrieval.md +16 -0
  94. package/releases/0.28.21/surfaces/integrations/tree/.claude/router.md +6 -0
  95. package/releases/0.28.21/surfaces/integrations/tree/CLAUDE.md +17 -0
  96. package/releases/0.28.21/surfaces/money/tree/.claude/agents/architect.md +12 -0
  97. package/releases/0.28.21/surfaces/money/tree/.claude/agents/dba.md +14 -0
  98. package/releases/0.28.21/surfaces/money/tree/.claude/agents/implementer.md +11 -0
  99. package/releases/0.28.21/surfaces/money/tree/.claude/agents/integration-tester.md +3 -0
  100. package/releases/0.28.21/surfaces/money/tree/.claude/agents/reviewer.md +23 -0
  101. package/releases/0.28.21/surfaces/money/tree/.claude/agents/secops.md +5 -0
  102. package/releases/0.28.21/surfaces/money/tree/.claude/agents/solidity-auditor.md +4 -0
  103. package/releases/0.28.21/surfaces/money/tree/.claude/agents/solidity-dev.md +4 -0
  104. package/releases/0.28.21/surfaces/money/tree/.claude/graph.md +2 -0
  105. package/releases/0.28.21/surfaces/money/tree/.claude/patterns.md +49 -0
  106. package/releases/0.28.21/surfaces/money/tree/.claude/pipeline.md +2 -0
  107. package/releases/0.28.21/surfaces/money/tree/.claude/retrieval.md +2 -0
  108. package/releases/0.28.21/surfaces/money/tree/CLAUDE.md +11 -0
  109. package/releases/0.28.21/surfaces/pii/tree/.claude/agents/dba.md +2 -0
  110. package/releases/0.28.21/surfaces/pii/tree/.claude/agents/devops.md +8 -0
  111. package/releases/0.28.21/surfaces/pii/tree/.claude/agents/reviewer.md +8 -0
  112. package/releases/0.28.21/surfaces/pii/tree/.claude/agents/secops.md +2 -0
  113. package/releases/0.28.21/surfaces/pii/tree/.claude/agents/solidity-auditor.md +5 -0
  114. package/releases/0.28.21/surfaces/pii/tree/CLAUDE.md +5 -0
  115. package/src/commands/upgrade.mjs +19 -4
@@ -0,0 +1,12 @@
1
+ <!-- nina:slot blockchain.1 -->
2
+ 16. **Every contract change goes through the solidity-auditor gate, and deployed code is never patched in place.** A diff touching a contract source, a deploy script, or the version of a contracts library does not reach the reviewer without `VERDICT: APPROVED` from **solidity-auditor**, and does not reach any network without it. Contract sources are written by **solidity-dev**, not by the implementer — the implementer's rules assume a defect is a patch away, and here it is a redeploy or a proxy upgrade at best. Private keys, mnemonics and funded accounts never enter the repository in any form, test fixtures included.
3
+
4
+ <!-- nina:slot blockchain.2 -->
5
+ | **ANY step touching a contract, a deploy script, or a contracts library version** | **architect → solidity-dev → solidity-auditor → reviewer → qa** — the auditor is mandatory and blocks the reviewer |
6
+
7
+ <!-- nina:slot blockchain.3 -->
8
+ - **solidity-dev** → write contract sources and their adversarial tests strictly to spec; never deploys, never widens access control to make a test pass
9
+ - **solidity-auditor** → **mandatory gate** on any contract diff; `APPROVED` required before reviewer and before any deploy
10
+
11
+ <!-- nina:slot blockchain.4 -->
12
+ - **contract code**: a contract source, a deploy script, or the version of a contracts library
@@ -0,0 +1,8 @@
1
+ <!-- nina:slot db.1 -->
2
+ | `prisma-client-api` | a new or changed Prisma query |
3
+
4
+ <!-- nina:slot db.2 -->
5
+ - **Tenant-scope impact** — explicitly state where `userId` is enforced. Every new Prisma query in app code includes `userId` (or its model-specific FK equivalent) in the `where` clause. The only exempt tables are the {{AUTH_LIB}} system tables.
6
+
7
+ <!-- nina:slot db.3 -->
8
+ - **Prisma flag** — if `schema.prisma` or a new Prisma query is touched, mark **"DBA REQUIRED"** prominently at the top of the spec. Specify the proposed `cacheStrategy`, or **`NO_CACHE`** for any read that feeds a write whose correctness depends on it being fresh — a stale row contaminates every decision made from it.
@@ -0,0 +1,84 @@
1
+ <!-- nina:slot db.1 -->
2
+ | `prisma-cli` | **before ANY `prisma` CLI command** — `validate`, `format`, `migrate dev`, `migrate diff`, `migrate deploy`. Flags differ between versions, and one of them (`migrate diff --shadow-database-url` against a live database) destroys the database it points at |
3
+ | `prisma-client-api` | auditing a new or changed query — filters, operators, `$transaction` semantics |
4
+
5
+ <!-- nina:slot db.2 -->
6
+ Neither skill covers a **caching or edge layer sitting on top of the client** — cache strategy,
7
+ edge-client behaviour and the rule about never caching a read that authorizes a write belong to that
8
+ layer's own integration doc, declared like any other integration. A skill does not replace it.
9
+
10
+ <!-- nina:slot db.3 -->
11
+ - Any change to `{{DB_PKG}}/prisma/schema.prisma`.
12
+ - Any new Prisma query (`findUnique`, `findMany`, `create`, `update`, `delete`, `aggregate`, `$queryRaw`, etc.) anywhere in application code.
13
+ - Any migration generated via `prisma migrate`.
14
+
15
+ <!-- nina:slot db.4 -->
16
+ - The Prisma diff (schema changes + generated migration SQL).
17
+ - The application code that uses the new or modified queries.
18
+
19
+ <!-- nina:slot db.5 -->
20
+ **Read `.claude/code-map.md`** when the change touches new query patterns — it lists which services consume which Prisma models, so you can spot N+1 risk and consumer-side cache implications without re-grepping. (Greenfield phase: fall back to `.claude/architecture.md` § *Database* for the planned schema — the model table, monetary conventions, and the Accelerate cache-policy table are canonical there.)
21
+
22
+ <!-- nina:slot db.6 -->
23
+ - **Schema validates.** Run `pnpm --filter {{DB_PKG_NAME}} exec prisma validate`. Must pass.
24
+
25
+ <!-- nina:slot db.7 -->
26
+ - **Migration diff.** Run `prisma migrate diff` in its **offline, file-only form** and read the generated SQL, not just the Prisma delta:
27
+
28
+ ```
29
+ # Compare the PREVIOUS schema against the working one — pure file-to-file, no database.
30
+ git show HEAD:{{DB_PKG}}/prisma/schema.prisma > /tmp/schema-head.prisma
31
+ pnpm --filter {{DB_PKG_NAME}} exec prisma migrate diff \
32
+ --from-schema-datamodel /tmp/schema-head.prisma \
33
+ --to-schema-datamodel prisma/schema.prisma \
34
+ --script
35
+ ```
36
+
37
+ ⚠️ **Do NOT reach for `--from-migrations`.** It looks like the natural choice and it is a trap:
38
+ Prisma refuses it without `--shadow-database-url`, which pushes you toward supplying a database
39
+ URL — the exact move that destroys databases (below). The two-datamodel form above answers the
40
+ same question with no database involved. Compare its output against the hand-written
41
+ `migration.sql` to confirm the declarative parts match.
42
+
43
+ ⛔ **NEVER pass `--shadow-database-url`, `--from-url`, `--to-url`, or `--from-schema-datasource` pointing at a real database — most of all not `DATABASE_URL` from `{{API_DIR}}/{{SECRETS_LOCAL}}`.** Prisma **executes** the entire migration history against whatever database those flags name, which **DESTROYS ALL DATA** in it. A shadow database must be a disposable, empty database and nothing else. This is not hypothetical, and it does not announce itself: the command completes with a reassuring "empty migration" result and no error, having already destroyed everything in the database it was pointed at. If the offline form above cannot answer your question, **STOP and report that to the orchestrator** instead of reaching for a database URL.
44
+
45
+ <!-- nina:slot db.8 -->
46
+ - **Migration safety on large tables:**
47
+ - No `ALTER TABLE ... ADD COLUMN NOT NULL` without a safe default (causes lock + rewrite).
48
+ - No operations that hold long locks without an explicit batched strategy.
49
+ - Non-breaking for rolling deploy — old application code and new schema must coexist during the deploy window.
50
+
51
+ <!-- nina:slot db.9 -->
52
+ - **Index coverage.** Every new query pattern (`WHERE`, `ORDER BY`, `JOIN`, `aggregate`) must be backed by an index. Use `@@index` in schema. Reject queries that would table-scan. The most-used compound index is `(<tenant>, <other>)` or, for models keyed by a parent entity, `(<parentId>, <other>)`; verify the leading column matches the query.
53
+
54
+ <!-- nina:slot db.10 -->
55
+ - **userId scope.** Every query in app code must include `userId` in `where` (or the model's equivalent FK chain — `accountId`/`entryId`/`ruleId` resolving back to the owning user). The {{AUTH_LIB}} system tables are the only exemption. Reject any app query missing the scope.
56
+
57
+ <!-- nina:slot db.11 -->
58
+ - **Cache strategy.** Every `findUnique` / `findMany` on a hot read path has an explicit `cacheStrategy` (Accelerate `ttl` / `swr`). **Implicit cache is a bug — reject.** Cross-check the policy against the cache-policy table in `.claude/architecture.md` § *Database*.
59
+
60
+ <!-- nina:slot db.12 -->
61
+ - **N+1 patterns.** If the code fetches a list then queries per item, reject with "use `include` / `select` or batch."
62
+
63
+ <!-- nina:slot db.13 -->
64
+ - **Secrets.** `DATABASE_URL` (Prisma Postgres / Accelerate URL) must come from `{{SECRETS_LOCAL}}` locally and `{{SECRETS_PROD}}` in production — never `.env` committed.
65
+
66
+ <!-- nina:slot db.14 -->
67
+ - **Run ANY command that can write to a real database.** You are a read-only gate. Against a live
68
+ `DATABASE_URL` you may run `SELECT`-only queries and nothing else. Explicitly forbidden, no
69
+ exceptions: `prisma migrate dev`, `migrate deploy`, `migrate reset`, `migrate resolve`,
70
+ `db push`, `db execute`, `$executeRaw*`, and **any `prisma migrate diff` variant carrying a
71
+ database URL** (see the *Migration diff* check — that one silently wipes the database it points at). If a check
72
+ seems to require writing, it does not: report the limitation to the orchestrator instead.
73
+
74
+ <!-- nina:slot db.15 -->
75
+ - Approve without actually running `prisma validate` and the offline `prisma migrate diff` of the *Migration diff* check.
76
+
77
+ <!-- nina:slot db.16 -->
78
+ - Wave through "small" schema changes. Small changes cause the worst production incidents.
79
+
80
+ <!-- nina:slot db.17 -->
81
+ - Approve a query missing `userId` scope (or its equivalent owning FK) in app code.
82
+
83
+ <!-- nina:slot db.18 -->
84
+ **Final report format:** ≤300 words if approved. Sections: Schema validation result, Migration SQL preview (verbatim if non-trivial), Index analysis, userId-scope check, Cache strategy verdict, Privacy check, Final verdict. If rejected, list each issue with required action — no length cap.
@@ -0,0 +1,14 @@
1
+ <!-- nina:slot db.1 -->
2
+ - **`prisma-cli`** — before `migrate deploy` or any other Prisma CLI command against a real database.
3
+
4
+ <!-- nina:slot db.2 -->
5
+ - **Migrations, in order, against the right database.** Apply with `prisma migrate deploy`. Confirm the target `DATABASE_URL` is the one you intend. Verify the migration is backward-compatible with the currently-deployed code, because the two are live together during the rollout.
6
+
7
+ <!-- nina:slot db.3 -->
8
+ - Run `prisma migrate diff --shadow-database-url <url>` against any live database. It **executes** the migration history against that database, destroying everything in it, and reports success. Use a disposable shadow database or don't run it.
9
+
10
+ <!-- nina:slot db.4 -->
11
+ - Run `prisma migrate reset` against a shared database, ever.
12
+
13
+ <!-- nina:slot db.5 -->
14
+ - **Migrations:** applied / none, with the database they hit.
@@ -0,0 +1,5 @@
1
+ <!-- nina:slot db.1 -->
2
+ | `prisma-client-api` | a new or changed Prisma query |
3
+
4
+ <!-- nina:slot db.2 -->
5
+ - If you change `schema.prisma` or write a new Prisma query, flag it explicitly in the diff summary so the reviewer dispatches **dba** before approving.
@@ -0,0 +1,13 @@
1
+ <!-- nina:slot db.1 -->
2
+ | `prisma-cli` | a Prisma CLI command |
3
+
4
+ <!-- nina:slot db.2 -->
5
+ - Any new Prisma query against an Accelerate-cached read path — verify cache hit/`cacheStrategy` behavior live (dba covers schema; you cover runtime cache behavior)
6
+
7
+ <!-- nina:slot db.3 -->
8
+ If you find a Prisma issue mid-run (a query behaves differently against a real DB than the dba's static analysis suggested) — escalate to **dba**, do not fix yourself.
9
+
10
+ <!-- nina:slot db.4 -->
11
+ - **{{AUTH_LIB}}'s backing store is a real Postgres** — the dev DB Accelerate branch, the same
12
+ `DATABASE_URL` the implementer uses in `{{SECRETS_LOCAL}}`. A suite that is green against an
13
+ in-memory stand-in has not exercised the library, which is the whole point of this stage.
@@ -0,0 +1,2 @@
1
+ <!-- nina:slot db.1 -->
2
+ - **Prisma flag** — if any subtask may touch `schema.prisma` or create a new Prisma query, mark **"DBA REQUIRED"** on that subtask.
@@ -0,0 +1,25 @@
1
+ <!-- nina:slot db.1 -->
2
+ | `prisma-client-api` | a new or changed Prisma query |
3
+
4
+ <!-- nina:slot db.2 -->
5
+ - **If Prisma was touched anywhere in the diff: confirm `dba` ran and approved. If not → dispatch `dba` now, or request changes. No approval without dba sign-off on Prisma changes.**
6
+
7
+ <!-- nina:slot db.3 -->
8
+ - Check for **single-user tenant scoping** in every new Prisma query in app code: the `where` clause must include `userId` (or its model-specific FK equivalent). No "global" queries except the {{AUTH_LIB}} system tables. Missing scope = request changes.
9
+
10
+ <!-- nina:slot db.4 -->
11
+ - Check for N+1 queries when the DB layer was touched.
12
+
13
+ <!-- nina:slot db.5 -->
14
+ - **tenant-and-privacy** — `userId` in every app query ({{AUTH_LIB}} tables are the only exemption);
15
+ no PII or secrets in logs; no cross-tenant read
16
+ or write reachable through a route, an MCP tool, a webhook, or an RPC between services.
17
+
18
+ <!-- nina:slot db.6 -->
19
+ - `{{DB_PKG}}/prisma/schema.prisma` touched (Prisma migration in play)
20
+
21
+ <!-- nina:slot db.7 -->
22
+ - Skip the dba check on Prisma changes "because it seems fine."
23
+
24
+ <!-- nina:slot db.8 -->
25
+ - Prisma touched but dba missed → dispatch **dba** now.
@@ -0,0 +1,2 @@
1
+ <!-- nina:slot db.1 -->
2
+ - **AuthZ / tenant isolation (Hard Rule #7)** — single-user tenancy: EVERY app-code Prisma query must scope by `userId` (or its FK). Hunt for any query, route, MCP tool, or DO/queue/webhook path where another user's data could be read or mutated (IDOR). The {{AUTH_LIB}} system tables are the only allowed unscoped reads — verify nothing else is.
@@ -0,0 +1,5 @@
1
+ <!-- nina:slot db.1 -->
2
+ - **DBA guardrail** → Prisma / Postgres is the surface where a bad change causes hard-to-reverse damage. Schema mistakes, missing indexes, cache on reads that feed a correctness-critical write, missing `userId` scope — all caught here.
3
+
4
+ <!-- nina:slot db.2 -->
5
+ | **dba** | Mandatory gate on Prisma changes and new queries | `.claude/agents/dba.md` |
@@ -0,0 +1,8 @@
1
+ <!-- nina:slot db.1 -->
2
+ - `dba` — gate: runs when the schema, a migration or a query is touched
3
+
4
+ <!-- nina:slot db.2 -->
5
+ - `implementer` → `dba` on `DIFF-READY` — the diff touches the schema, a migration or a query
6
+ - `dba` → `reviewer` on `APPROVED`
7
+ - `dba` → `implementer` on `REJECTED` — a query or schema change in the diff is unsafe · max 2
8
+ - `dba` → `architect` on `REJECTED` — the spec's migration or data design is unsafe · max 2
@@ -0,0 +1,29 @@
1
+ <!-- nina:slot db.1 -->
2
+ - **Database table/column names** (Prisma `@map` / `@@map`): `snake_case` in SQL, `camelCase` in TS.
3
+
4
+ <!-- nina:slot db.2 -->
5
+ - Routes must NOT import query functions (`list*`, `find*`, `get*`, `upsert*`, `delete*`) from `{{DB_PKG_NAME}}`. Only `createDbClient` and error classes.
6
+
7
+ <!-- nina:slot db.3 -->
8
+ - `cacheStrategy` lives in `{{DB_PKG}}`. Services do not add, strip, or override cache policies.
9
+
10
+ <!-- nina:slot db.4 -->
11
+ - **Every service query includes `userId` (tenant scope) in the `where` clause.** Missing scope = automatic CHANGES REQUESTED.
12
+
13
+ <!-- nina:slot db.5 -->
14
+
15
+ ---
16
+
17
+ ## Prisma conventions (enforced by dba subagent)
18
+
19
+ - Schema lives in `{{DB_PKG}}/prisma/schema.prisma`. Nowhere else.
20
+ - **Never write raw SQL** unless justified in a code comment with perf data.
21
+ - **Every `findUnique` / `findMany` on a hot path defines `cacheStrategy`.** No implicit cache.
22
+ - **NEVER cache a read that feeds a write whose correctness depends on it being fresh.** A stale row contaminates the decision made from it. Hard reject in dba review.
23
+ - **Every query in app code includes `userId` in the `where` clause** (or its model-specific equivalent FK). Tenant isolation is in the data layer. The {{AUTH_LIB}} system tables are the only exemption.
24
+ - Migrations reviewed by **dba** for: non-blocking on large tables, index coverage for new query patterns, backward compatibility during rolling deploy.
25
+ - N+1 queries are a bug. Use `include` / `select` deliberately.
26
+ - `Prisma Postgres` is connected only via Accelerate. Local dev uses the same Accelerate URL pointed at a dev DB; never embed a direct connection string in code.
27
+
28
+ <!-- nina:slot db.6 -->
29
+ - Real Prisma (Accelerate against a test DB). Never mock Prisma.
@@ -0,0 +1,13 @@
1
+ <!-- nina:slot db.1 -->
2
+
3
+ ### DBA (mandatory for Prisma)
4
+
5
+ - **Trigger:** any change in `schema.prisma`, any new Prisma query, any migration.
6
+ - **Input:** Prisma diff + application code using the queries.
7
+ - **Output:** approve or reject with specific issues.
8
+ - **Tools:** Read, Grep, Glob, Bash (`prisma validate`, `prisma migrate diff`, query plan checks).
9
+ - **Checks:** schema validates; migration safe on large tables; index coverage; explicit `cacheStrategy` on hot reads; **no cache on a read that feeds a correctness-critical write**; **`userId` scope in every query**; no N+1; no raw PII without encryption; the connection secret comes from the environment, never from code.
10
+ - **Position:** dispatched mid-pipeline by whoever detects Prisma. Reviewer verifies dba ran.
11
+
12
+ <!-- nina:slot db.2 -->
13
+ - **If Prisma touched → dba approved.**
@@ -0,0 +1,5 @@
1
+ <!-- nina:slot db.1 -->
2
+ | Prisma schema change | `.claude/architecture.md` § *Database*, `{{DB_PKG}}/prisma/schema.prisma` | **dba** (mandatory) → reviewer → qa |
3
+
4
+ <!-- nina:slot db.2 -->
5
+ | New Prisma query in app code | `.claude/patterns.md` § *Prisma conventions* | **dba** (mandatory) → reviewer → qa |
@@ -0,0 +1,10 @@
1
+ <!-- nina:slot db.1 -->
2
+
3
+ ### DBA is a guardrail, not a stage
4
+ Invoke **dba** any time Prisma is touched — regardless of where you are in the pipeline. No Prisma change merges without dba approval. Reviewer verifies dba ran.
5
+
6
+ <!-- nina:slot db.2 -->
7
+ | any `prisma` CLI command | **`prisma-cli`** |
8
+
9
+ <!-- nina:slot db.3 -->
10
+ | a new or changed Prisma query | **`prisma-client-api`** (a caching or edge layer on top of the client is not covered — its own integration doc owns that) |
@@ -0,0 +1,23 @@
1
+ <!-- nina:slot db.1 -->
2
+ | Run any `prisma` CLI command (dba, devops, and the integration gate where there is one) | `prisma-cli` | flags differ between versions; `migrate diff --shadow-database-url` against a live DB wiped dev/staging once |
3
+
4
+ <!-- nina:slot db.2 -->
5
+ | Write or audit a Prisma query (architect, implementer, dba, reviewer) | `prisma-client-api` | filters, operators, `$transaction` semantics. a caching or edge layer on top of the client is **NOT covered** — its cache strategy belongs to that layer's own integration doc |
6
+
7
+ <!-- nina:slot db.3 -->
8
+ | **ANY Prisma change (`*.prisma` or new query)** | **+ dba before reviewer** |
9
+
10
+ <!-- nina:slot db.4 -->
11
+ - **dba** → mandatory gate on Prisma schema changes, migrations, and new queries
12
+
13
+ <!-- nina:slot db.5 -->
14
+ 2. **Every Prisma change goes through the dba subagent.** No exceptions. Reviewer must verify dba ran before approving.
15
+
16
+ <!-- nina:slot db.6 -->
17
+ 6. **Every hot Prisma read defines a `cacheStrategy`** (Accelerate `ttl` / `swr`). Implicit cache is a bug. **Never cache a read that feeds a write whose correctness depends on it being fresh** — a stale row contaminates every decision made from it. User-scoped invalidation on every write.
18
+
19
+ <!-- nina:slot db.7 -->
20
+ 7. **Tenant isolation is enforced in the data layer.** Every Prisma query in app code includes `userId` (the tenant) in the `where` clause. No "global" queries except the {{AUTH_LIB}} system tables. Reviewer rejects any query missing the scope.
21
+
22
+ <!-- nina:slot db.8 -->
23
+ - **the database**: the schema, a migration, or a query
@@ -0,0 +1,14 @@
1
+ <!-- nina:slot edge-cf.1 -->
2
+ | `cloudflare:workers-best-practices` | `{{API_DIR}}/**` — routes, services, middleware, queue handlers |
3
+
4
+ <!-- nina:slot edge-cf.2 -->
5
+ | `cloudflare:durable-objects` | `{{API_DIR}}/src/do/**` or any DO call site |
6
+
7
+ <!-- nina:slot edge-cf.3 -->
8
+ | `cloudflare:cloudflare` | Queues, R2 or KV |
9
+
10
+ <!-- nina:slot edge-cf.4 -->
11
+ | `cloudflare:wrangler` | `wrangler.toml` or any wrangler command |
12
+
13
+ <!-- nina:slot edge-cf.5 -->
14
+ - **Cloudflare skill flag** — if the spec touches `{{API_DIR}}/**` (Hono routes/services/queue handlers), the per-account Durable Object, Queues, R2/KV, or `wrangler` config, name which `cloudflare:*` plugin skill the implementer must consult (`cloudflare:workers-best-practices`, `cloudflare:durable-objects`, `cloudflare:cloudflare`, `cloudflare:wrangler`), or state why none applies. Retrieval beats recall — the reviewer rejects a spec that touches these surfaces without naming the skill.
@@ -0,0 +1,2 @@
1
+ <!-- nina:slot edge-cf.1 -->
2
+ - **Edge runtime compatibility.** New code paths use `@prisma/client/edge`. `compatibility_flags = ["nodejs_compat"]` is set in `wrangler.toml`.
@@ -0,0 +1,31 @@
1
+ <!-- nina:slot edge-cf.1 -->
2
+ - **`cloudflare:wrangler`** — before running ANY `wrangler` command or reading `wrangler.toml`.
3
+ CLI flags and config fields churn between minor versions; pre-trained knowledge is stale.
4
+
5
+ <!-- nina:slot edge-cf.2 -->
6
+ - **`cloudflare:cloudflare`** — when the deploy touches R2, KV, Queues or Durable Object bindings.
7
+
8
+ <!-- nina:slot edge-cf.3 -->
9
+ - **Both targets, or neither.** A change to the API surface needs the **staging Worker** (`wrangler deploy --env staging`) *and* **Pages** (`pnpm --filter {{PKG_SCOPE}}/app deploy`). Deploying the frontend alone against an old API is the failure that renders new fields as "—". State explicitly which targets this change requires and why.
10
+
11
+ <!-- nina:slot edge-cf.4 -->
12
+ - **Secret and variable parity.** Everything the new code reads via `env.*` exists in the target environment (`wrangler secret list`). A missing secret fails at request time, not at deploy time.
13
+
14
+ <!-- nina:slot edge-cf.5 -->
15
+
16
+ ## Pages: which branch, and why it matters
17
+
18
+ `{{PAGES_PROJECT}}` is a **direct-upload** Pages project whose production branch is `main`. `wrangler pages
19
+ deploy` decides production vs preview purely from `--branch`:
20
+
21
+ - **Staging FE** → `--branch staging`. A preview deployment on its own URL. Production is untouched,
22
+ and this is the FE half of the staging pair with `{{API_STAGING}}`.
23
+ - **Production FE** → `--branch main`. Only with an explicit go from {{OWNER}}, per the rule above.
24
+
25
+ Deploying staging with `--branch=main` is a production deploy wearing a staging label — the
26
+ permission classifier is right to stop it. Use the staging branch and the block disappears, because
27
+ the block was correct.
28
+
29
+ **`VITE_*` must be in the environment of the build command.** `[vars]` and `[env.*.vars]` in
30
+ `{{APP_DIR}}/wrangler.toml` do NOT reach a Vite build — Vite inlines at build time, Pages vars apply at
31
+ runtime to a project that has no server. A missing one ships a blank page with no error.
@@ -0,0 +1,14 @@
1
+ <!-- nina:slot edge-cf.1 -->
2
+ | `cloudflare:workers-best-practices` | anything under `{{API_DIR}}/**` |
3
+
4
+ <!-- nina:slot edge-cf.2 -->
5
+ | `cloudflare:durable-objects` | anything under `{{API_DIR}}/src/do/**` or a DO call site |
6
+
7
+ <!-- nina:slot edge-cf.3 -->
8
+ | `cloudflare:cloudflare` | a queue consumer, or R2 / KV access |
9
+
10
+ <!-- nina:slot edge-cf.4 -->
11
+ | `cloudflare:wrangler` | a change to `wrangler.toml` |
12
+
13
+ <!-- nina:slot edge-cf.5 -->
14
+ - Respect Workers conventions: secrets in `{{SECRETS_LOCAL}}` for local dev (never commit), `compatibility_flags = ["nodejs_compat"]` in `wrangler.toml`.
@@ -0,0 +1,11 @@
1
+ <!-- nina:slot edge-cf.1 -->
2
+ | `cloudflare:durable-objects` | DO lifecycle, alarms, RPC, storage — the API surface drifts fast |
3
+
4
+ <!-- nina:slot edge-cf.2 -->
5
+ | `cloudflare:cloudflare` | Queues, R2 or KV bindings |
6
+
7
+ <!-- nina:slot edge-cf.3 -->
8
+ | `cloudflare:wrangler` | anything you run through the wrangler CLI |
9
+
10
+ <!-- nina:slot edge-cf.4 -->
11
+ - Any new Cloudflare binding read/write: R2, KV, Queues, Durable Objects — drive the binding via Miniflare and observe real I/O
@@ -0,0 +1,3 @@
1
+ <!-- nina:slot edge-cf.1 -->
2
+ Here `$STRAY` is `vitest|workerd`: a Worker test boots a second runtime process alongside vitest,
3
+ and it is the one that holds ~2 GB and survives a killed test run.
@@ -0,0 +1,8 @@
1
+ <!-- nina:slot edge-cf.1 -->
2
+ | `cloudflare:workers-best-practices` | `{{API_DIR}}/**` |
3
+
4
+ <!-- nina:slot edge-cf.2 -->
5
+ | `cloudflare:durable-objects` | `{{API_DIR}}/src/do/**` or a DO call site |
6
+
7
+ <!-- nina:slot edge-cf.3 -->
8
+ - `{{API_DIR}}/src/do/`, a queue consumer, or a webhook receiver touched (serialization + idempotency surface)
@@ -0,0 +1,8 @@
1
+ <!-- nina:slot edge-cf.1 -->
2
+ - **Secrets & config exposure** — no secrets in committed files, logs, error messages, or generated artifacts (`worker-configuration.d.ts` must contain only types, never values). `{{SECRETS_LOCAL}}`/`.env` gitignored. `wrangler secret`/`[vars]` split correct. No secret echoed in a response or thrown error.
3
+
4
+ <!-- nina:slot edge-cf.2 -->
5
+ - **Dependency & binding posture** — obviously risky dependency usage; Cloudflare binding scoping (R2 bucket names, Queue, DO) — nothing over-privileged or world-exposed; `nodejs_compat` and compatibility flags sane.
6
+
7
+ <!-- nina:slot edge-cf.3 -->
8
+ - Prefer retrieval over recall for Cloudflare/{{AUTH_LIB}} specifics: consult the `cloudflare:*` skills and the installed `node_modules` source / `.claude/integrations/*.md` rather than assuming.
@@ -0,0 +1,17 @@
1
+ <!-- nina:slot edge-cf.1 -->
2
+
3
+ ---
4
+
5
+ ## Secrets
6
+
7
+ - **Wrangler secrets** for Workers (`{{SECRETS_PROD}} X`). Never `.env` committed.
8
+ - **Local dev:** `{{SECRETS_LOCAL}}` (gitignored).
9
+
10
+ <!-- nina:slot edge-cf.2 -->
11
+ - `compatibility_flags = ["nodejs_compat"]` in `wrangler.toml` is required for `@prisma/client/edge`.
12
+
13
+ <!-- nina:slot edge-cf.3 -->
14
+ - **Miniflare** for Worker integration tests.
15
+
16
+ <!-- nina:slot edge-cf.4 -->
17
+ - **Miniflare** for Worker tests — the real Cloudflare runtime, no mocks.
@@ -0,0 +1,8 @@
1
+ <!-- nina:slot edge-cf.1 -->
2
+ | New Durable Object behavior | `.claude/architecture.md` § *Durable Objects*, existing `{{API_DIR}}/src/do/` | architect → implementer → the integration gate, where there is one → reviewer → qa |
3
+
4
+ <!-- nina:slot edge-cf.2 -->
5
+ | New Queue handler | `.claude/architecture.md` § *Processing pipeline*, `{{API_DIR}}/src/queues/` | architect → implementer → the integration gate, where there is one → reviewer → qa |
6
+
7
+ <!-- nina:slot edge-cf.3 -->
8
+ | Wrangler / deploy / config | `CLAUDE.md` § *Common commands*, `{{API_DIR}}/wrangler.toml`, `.claude/patterns.md` § *Secrets* | reviewer (sanity check) |
@@ -0,0 +1,21 @@
1
+ <!-- nina:slot edge-cf.1 -->
2
+ | `{{API_DIR}}/**` Hono routes / services / middleware / queue handlers | `cloudflare:workers-best-practices` |
3
+
4
+ <!-- nina:slot edge-cf.2 -->
5
+ | `{{API_DIR}}/src/do/**` or any DO call site | `cloudflare:durable-objects` |
6
+
7
+ <!-- nina:slot edge-cf.3 -->
8
+ | `{{API_DIR}}/src/queues/**`, R2/KV | `cloudflare:cloudflare` |
9
+
10
+ <!-- nina:slot edge-cf.4 -->
11
+ | `wrangler.toml` / `wrangler.jsonc` / any wrangler CLI | `cloudflare:wrangler` |
12
+
13
+ <!-- nina:slot edge-cf.5 -->
14
+ | **devops** running any wrangler command or deploy | **`cloudflare:wrangler`** (+ `cloudflare:cloudflare` for R2/KV/Queues/DO bindings) |
15
+
16
+ <!-- nina:slot edge-cf.6 -->
17
+
18
+ Irrelevant to {{PROJECT}} (do NOT invoke): `cloudflare:agents-sdk`, `cloudflare:sandbox-sdk`, `cloudflare:cloudflare-email-service`.
19
+
20
+ <!-- nina:slot edge-cf.7 -->
21
+ The `cloudflare@cloudflare` plugin (user-scope) is where this project's skills come from.
@@ -0,0 +1,27 @@
1
+ <!-- nina:slot edge-cf.1 -->
2
+
3
+ ### Cloudflare plugin skills — USE THEM
4
+
5
+ The `cloudflare@cloudflare` plugin is installed at user scope and exposes skills that retrieve the **current** Cloudflare docs at invocation time. Pre-trained knowledge of Workers / Wrangler / DO / Queues / Cron APIs is stale — prefer the skill over recalling from memory.
6
+
7
+ <!-- nina:slot edge-cf.2 -->
8
+ | Write or review code under `{{API_DIR}}/**` (Hono routes, services, middleware, webhook receivers, queue consumers) | `cloudflare:workers-best-practices` | catches floating promises, global-state misuse, missing `waitUntil`, streaming pitfalls |
9
+
10
+ <!-- nina:slot edge-cf.3 -->
11
+ | Touch `{{API_DIR}}/src/do/**` or any Durable Object call site | `cloudflare:durable-objects` | covers RPC, alarms, WebSocket, SQLite storage, lifecycle — DO API surface drifts fast |
12
+
13
+ <!-- nina:slot edge-cf.4 -->
14
+ | Touch `{{API_DIR}}/src/queues/**`, R2/KV usage | `cloudflare:cloudflare` | Queues, R2, KV decision tree |
15
+
16
+ <!-- nina:slot edge-cf.5 -->
17
+ | Author or modify `wrangler.toml` / `wrangler.jsonc` / run any `wrangler` CLI command | `cloudflare:wrangler` | CLI flags + config fields churn between minor versions |
18
+
19
+ <!-- nina:slot edge-cf.6 -->
20
+ | Run the **devops** deploy stage | `cloudflare:wrangler` (+ `cloudflare:cloudflare` for R2/KV/Queues/DO bindings) | deploy flags and binding config churn between versions |
21
+
22
+ <!-- nina:slot edge-cf.7 -->
23
+
24
+ Skills NOT relevant to {{PROJECT}} (skip them): `cloudflare:agents-sdk` (no agent runtime), `cloudflare:sandbox-sdk` (no untrusted code execution), `cloudflare:cloudflare-email-service` ({{AUTH_LIB}} handles magic-link email).
25
+
26
+ <!-- nina:slot edge-cf.8 -->
27
+ 10. **Secrets in `{{SECRETS_LOCAL}}` for local dev, `{{SECRETS_PROD}}` for production.** Never `.env` committed. `compatibility_flags = ["nodejs_compat"]` is required in `wrangler.toml` for any database client that runs at the edge.
@@ -0,0 +1,20 @@
1
+ <!-- nina:slot frontend.1 -->
2
+ | `cloudflare:web-perf` | a page-load performance question in `{{APP_DIR}}` |
3
+
4
+ <!-- nina:slot frontend.2 -->
5
+
6
+ ## Visual acceptance — required in any spec touching `{{APP_DIR}}/**`
7
+
8
+ A frontend spec that describes only structure produces a diff that only structure can verify, and
9
+ structure is exactly what jsdom checks while being blind to the result. So state, as a short
10
+ checklist, what must be TRUE ON THE SCREEN at **1440** and at **375**:
11
+
12
+ - what is visible, and what must not be
13
+ - what sits beside what, and what wraps or stacks at 375
14
+ - the empty, loading and error states, if the change can produce them
15
+ - anything that must not overflow, clip or overlap
16
+
17
+ Each line must be checkable from a screenshot by someone who did not write the code — the **reviewer**
18
+ checks the render against this list, and rejects on a mismatch. "Follows the design system" is not a
19
+ criterion. A spec that touches `{{APP_DIR}}/**` without this section is incomplete, and the reviewer
20
+ rejects it back to you.
@@ -0,0 +1,28 @@
1
+ <!-- nina:slot frontend.1 -->
2
+ - Playwright is **not** a skill — it is an MCP server, and its `browser_*` tools are granted to you
3
+ directly in `tools:` above. Use them; there is nothing to invoke via `Skill`.
4
+
5
+ <!-- nina:slot frontend.2 -->
6
+ - **Build-time env.** Vite inlines `VITE_*` at build time, so a variable the deploy platform supplies at RUNTIME never reaches the bundle — it is not late, it is absent. Verify every `VITE_*` the app reads is present in the build environment — a missing one ships a blank page, not an error.
7
+
8
+ <!-- nina:slot frontend.3 -->
9
+
10
+ ## Render smoke — for any diff touching `{{APP_DIR}}/**`
11
+
12
+ You are not the visual gate; the **reviewer** is, and it judges the render against the spec before
13
+ the code ever reaches you. Your question is narrower and different: **did the deployed thing come up
14
+ at all?** That is not the same failure — a build that renders perfectly on a reviewer's localhost
15
+ still ships a blank page when `VITE_API_BASE_URL` was missing from the deploy build, which is exactly
16
+ what happened here once.
17
+
18
+ So on the preview URL, not localhost: `browser_navigate`, one screenshot at 1440, and
19
+ `browser_console_messages`. You are checking that the page renders and the console is clean — not
20
+ whether the layout is right. A blank page or a console error is `VERDICT: BLOCKED`.
21
+
22
+ <!-- nina:slot frontend.4 -->
23
+
24
+ If the changed path genuinely cannot be smoked without authenticating, do NOT authenticate: say so,
25
+ report what you could verify, and hand the authenticated check to a human.
26
+
27
+ <!-- nina:slot frontend.5 -->
28
+ , mcp__plugin_playwright_playwright__browser_navigate, mcp__plugin_playwright_playwright__browser_resize, mcp__plugin_playwright_playwright__browser_take_screenshot, mcp__plugin_playwright_playwright__browser_snapshot, mcp__plugin_playwright_playwright__browser_console_messages, mcp__plugin_playwright_playwright__browser_close
@@ -0,0 +1,25 @@
1
+ <!-- nina:slot frontend.1 -->
2
+ | `frontend-design:frontend-design` | new UI in `{{APP_DIR}}` — a page or component that did not exist |
3
+
4
+ <!-- nina:slot frontend.2 -->
5
+
6
+ ## Look at the screen you built
7
+
8
+ When you change anything under `{{APP_DIR}}/**`, open it in the browser before you hand off — the dev
9
+ server or a local build, with `browser_navigate` plus a screenshot at 1440 and 375. Your test suite
10
+ runs in jsdom, which has no layout engine and cannot tell you whether the thing renders.
11
+
12
+ This is a self-check, not a gate: you are the author, and an author reviewing their own work catches
13
+ the obvious and misses the rest. **reviewer** is the gate. The point of doing it here is that the
14
+ obvious defects are cheap to fix now and expensive after review, qa and a deploy.
15
+
16
+ Report what you saw. "Rendered at both widths, matches the spec's Visual acceptance" — or what
17
+ differed.
18
+
19
+ jsdom is also why a component test must assert content, not presence: `toHaveTextContent('4 matched')`,
20
+ not `toBeInTheDocument()` on the badge that shows it, and never `toHaveClass` as proof that something
21
+ looks right — it passes whether or not a pixel landed. A test that pins a removal renders the tab or
22
+ route where the removed thing used to appear; rendering the default one proves nothing about another.
23
+
24
+ <!-- nina:slot frontend.3 -->
25
+ , mcp__plugin_playwright_playwright__browser_navigate, mcp__plugin_playwright_playwright__browser_resize, mcp__plugin_playwright_playwright__browser_take_screenshot, mcp__plugin_playwright_playwright__browser_snapshot, mcp__plugin_playwright_playwright__browser_console_messages, mcp__plugin_playwright_playwright__browser_close
@@ -0,0 +1,17 @@
1
+ <!-- nina:slot frontend.1 -->
2
+
3
+ ## What your green does not mean
4
+
5
+ Your suite runs in jsdom, which has **no layout engine**. `toHaveClass('flex')` passes whether or not
6
+ anything was laid out; nothing you run can tell you the screen is right. When you report PASS on a
7
+ diff touching `{{APP_DIR}}/**`, say so — the rendering is checked by the **reviewer**, against the
8
+ spec's Visual acceptance criteria. A PASS read as "the screen works" is how frontend
9
+ defects reached staging through every gate.
10
+
11
+ ## When a failure arrives labelled "pre-existing"
12
+
13
+ On this surface the cause is usually the test harness rather than the feature — a text query matching
14
+ several elements at once, a missing router context for a link, a `vi.mock` hoisted above the value it
15
+ closes over, jsdom without `showModal`, a hardcoded origin. Every one of them is fixable in the test
16
+ without weakening the assertion, and every one of them stays invisible for exactly as long as the
17
+ failure keeps the label.