@ttt-productions/dev-standards 0.0.2 → 0.0.4
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/CLAUDE.base.md +30 -34
- package/development-preferences.md +59 -9
- package/model-tiers.md +1 -1
- package/package.json +1 -1
- package/playbooks/codebase-hygiene-playbook.md +26 -6
- package/playbooks/crosswalk.md +3 -2
- package/playbooks/package-boundaries-playbook.md +6 -6
- package/rules/architecture/data-and-contracts.md +1 -1
- package/rules/comments/core-rules.md +1 -1
- package/rules/frontend/data-and-callable-access.md +16 -2
- package/rules/quality/core-rules.md +4 -4
- package/workflows/claude/fan-out-implementation.md +11 -7
- package/workflows/claude/fix-known-errors-inline.md +3 -1
- package/workflows/claude/implement-an-approved-plan.md +3 -2
- package/workflows/claude/mechanical-fan-out.md +2 -2
- package/workflows/claude/work-a-project-step.md +3 -2
package/claude/CLAUDE.base.md
CHANGED
|
@@ -144,10 +144,12 @@ Before starting a project's work:
|
|
|
144
144
|
Every release of an `@ttt-productions/*` package hands its adoption to each app through a file in
|
|
145
145
|
`<PACKAGES_REPO>/docs/work/adoptions/<app>/`.
|
|
146
146
|
|
|
147
|
-
- **The package session writes them
|
|
148
|
-
command, it writes one adoption file per released
|
|
149
|
-
package
|
|
150
|
-
|
|
147
|
+
- **The package session writes them only for the apps that aren't in the conversation.** In the same
|
|
148
|
+
change as the package edit, before the release command, it writes one adoption file per released
|
|
149
|
+
package for each app outside the conversation — an app-data package's file goes only to its own
|
|
150
|
+
app. A package session cannot see which packages another product installs, so every other released
|
|
151
|
+
package gets a file for each of those apps. The app the conversation is working in adopts the
|
|
152
|
+
release itself, right after the install.
|
|
151
153
|
- **The version it names** is the version the release will publish: one patch above the package's
|
|
152
154
|
`package.json` version before the release.
|
|
153
155
|
- **The file** is one item in the `docs/work/` item format (`<DEV_STANDARDS>/work/README.md`) —
|
|
@@ -198,9 +200,8 @@ step 5.
|
|
|
198
200
|
## The Normal `<APP_NAME>` Flows (named workflows — "do the normal dev/test flow" resolves HERE)
|
|
199
201
|
|
|
200
202
|
These two named flows are the standing default for how work in these repos is verified and
|
|
201
|
-
sequenced. They are DEFAULTS, not cages: DJ may override any step with explicit
|
|
202
|
-
|
|
203
|
-
using the machine"), and an override governs exactly what it names, nothing more. A repo changes a
|
|
203
|
+
sequenced. They are DEFAULTS, not cages: DJ may override any step with an explicit instruction; the
|
|
204
|
+
override governs exactly what it names, for that conversation only. A repo changes a
|
|
204
205
|
flow only under its `<APP_NAME>` additions heading. In a repo whose `<APP_NAME>` is none
|
|
205
206
|
(ttt-packages) the Test Flow does not apply — its gate is its own `CLAUDE.md` § Verification — and
|
|
206
207
|
the Dev Flow's steps 1–4 are its whole share.
|
|
@@ -221,9 +222,10 @@ the Dev Flow's steps 1–4 are its whole share.
|
|
|
221
222
|
(RULE-STD-QUALITY-008 — Claude operates the restart).
|
|
222
223
|
5. Kill `dev:e2e` when done and STOP — wait for DJ's push.
|
|
223
224
|
|
|
224
|
-
**
|
|
225
|
-
|
|
226
|
-
|
|
225
|
+
**In a conversation DJ has called an orchestrator, the Normal Test Flow is run by one test agent,
|
|
226
|
+
never the orchestrator.** A failure goes back to the orchestrator, which sends it to the agent that
|
|
227
|
+
built the failing code; that agent fixes it and reports. The same test agent then reruns the flow,
|
|
228
|
+
restarting `dev:e2e` per stage 4. In an inline conversation, the session runs the Test Flow itself.
|
|
227
229
|
|
|
228
230
|
Not part of this flow: hosted-dev E2E runs (always separately commanded — `<HOSTED_E2E_DOC>`) and
|
|
229
231
|
`npm run dev:local` (DJ's manual dev surface).
|
|
@@ -235,29 +237,23 @@ Not part of this flow: hosted-dev E2E runs (always separately commanded — `<HO
|
|
|
235
237
|
change as the package edit.
|
|
236
238
|
3. ttt-packages `npm run test:quiet` green.
|
|
237
239
|
4. Hand DJ ONLY the release command (`./scripts/release-multiple.sh <folders…> patch`, its own fenced
|
|
238
|
-
block)
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
`package.json` version in the checkout at the moment DJ speaks, which can still be the old one
|
|
257
|
-
(compared against npm `@latest`, it reads a stale match as "live"). A version is available only
|
|
258
|
-
when npm `@latest` names it AND its tarball
|
|
259
|
-
(`https://registry.npmjs.org/@ttt-productions/<pkg>/-/<pkg>-<version>.tgz`) answers 200: the
|
|
260
|
-
registry can report the new `@latest` minutes before it serves the tarball, and an install in that
|
|
261
|
-
gap fails `E404`.
|
|
240
|
+
block), with one line under it naming the versions it will publish — the same versions its
|
|
241
|
+
adoption files name, one patch above each package's `package.json` version before the release
|
|
242
|
+
(e.g. "Publishes chat-core 0.11.8 and chat-react 0.13.20.") — then STOP. No install commands:
|
|
243
|
+
Claude does the installs.
|
|
244
|
+
5. DJ runs the publish and says so, at any point: the script just started, its preflight still
|
|
245
|
+
running, or the packages already published and GitHub Actions running. Claude then starts a
|
|
246
|
+
20-minute clock and checks npm every 30 seconds for exactly the versions named in step 4 — it never
|
|
247
|
+
re-reads `package.json` or git to find them. A version is available only when npm `@latest` names
|
|
248
|
+
it AND its tarball (`https://registry.npmjs.org/@ttt-productions/<pkg>/-/<pkg>-<version>.tgz`)
|
|
249
|
+
answers 200: the registry can report the new `@latest` minutes before it serves the tarball, and
|
|
250
|
+
an install in that gap fails `E404`. Then Claude runs the installs itself (`@latest
|
|
251
|
+
--prefer-online`, at the root and in every consuming folder that declares the package —
|
|
252
|
+
`<INSTALL_FOLDERS>`), confirms each lockfile names the new version, adopts the release in its own
|
|
253
|
+
app (§ Adoption files), and continues straight into the app work with no further go. While it
|
|
254
|
+
polls, the session works on whatever does not depend on the release — the publish-wait overlap in
|
|
255
|
+
`<DEV_STANDARDS>/development-preferences.md` § Shared-package publish. A version still missing from
|
|
256
|
+
npm after 20 minutes = stop and tell DJ which package; never install anything but the published
|
|
257
|
+
version.
|
|
262
258
|
6. All `<APP_NAME>` work; when the entire change set is done, run the Normal `<APP_NAME>` Test Flow.
|
|
263
259
|
7. Stop and wait for DJ's push.
|
|
@@ -23,6 +23,16 @@ shared copy, in `@ttt-productions/dev-standards`, that every repo reads.
|
|
|
23
23
|
it goes. Nothing is filed, parked, or written up without DJ's word.
|
|
24
24
|
- A doc's "staged / later / deferred" label is never DJ's decision; only DJ's own explicit deferral
|
|
25
25
|
parks an item.
|
|
26
|
+
- **DJ's rules live only in his rule docs** — the rulebooks, this file, `CLAUDE.md` / `AGENTS.md`,
|
|
27
|
+
and the workflows. An instruction DJ gives in a conversation lasts for that conversation only; it
|
|
28
|
+
becomes a standing rule only when he says to write it into the rules. No plan, work item, ledger,
|
|
29
|
+
or prompt ever holds a rule, an instruction, or reasoning, and a session never takes a rule from
|
|
30
|
+
one.
|
|
31
|
+
- **There are no handoff docs.** When DJ asks to get ready for a new conversation, the session gives
|
|
32
|
+
a small copy-paste prompt in chat that points at the items being worked; the items hold only what
|
|
33
|
+
is left. The prompt carries nothing else except open questions DJ chose to move. An item whose
|
|
34
|
+
only remaining work is the Normal Test Flow or a hosted E2E run is deleted; if a conversation
|
|
35
|
+
switches at that point, the prompt says to run it.
|
|
26
36
|
- "Finish everything" / "do it all" means every single thing DJ has decided, with nothing left
|
|
27
37
|
undone or parked. It never means deciding anything for DJ: when finishing needs a decision he has
|
|
28
38
|
not made, ask that one question and keep doing the rest. Never stop for complexity, size, time of
|
|
@@ -51,22 +61,39 @@ shared copy, in `@ttt-productions/dev-standards`, that every repo reads.
|
|
|
51
61
|
- An answer that REDIRECTS is not approval to build the revision — show the revised artifact in
|
|
52
62
|
chat and get a clean confirm before implementing.
|
|
53
63
|
- No new-conversation or handoff proposals unless DJ asks.
|
|
64
|
+
- **Every question is tracked until DJ answers it.** A question about the item being worked is asked
|
|
65
|
+
when it is found; the parts of that item that depend on the answer wait, and everything else keeps
|
|
66
|
+
going. A problem found outside the item never stops work: it is reported in chat with what was
|
|
67
|
+
verified and a recommendation, and stays open for DJ. When DJ has said he is away, no question
|
|
68
|
+
blocks: it goes in chat, the session finishes every part that does not depend on it, and moves to
|
|
69
|
+
the next item.
|
|
70
|
+
- **No Normal Test Flow while any question is open.** An answer can change code, and a test run
|
|
71
|
+
before it is worthless. The open questions are asked first, any code they change is done, and then
|
|
72
|
+
the Test Flow runs once.
|
|
73
|
+
- Open questions are asked one at a time, as questions, never buried in a status message. The
|
|
74
|
+
session never answers, files, or drops one itself.
|
|
75
|
+
- When DJ asks whether the conversation is good to end, or says to start a new one, the session first
|
|
76
|
+
says how many questions are open and asks whether to answer them here or move them into the new
|
|
77
|
+
conversation's prompt.
|
|
54
78
|
|
|
55
79
|
## Git, publish, deploy, and the dev stacks
|
|
56
80
|
|
|
57
|
-
- DJ does ALL git
|
|
58
|
-
deployments.
|
|
59
|
-
|
|
60
|
-
change as a sign of someone else's work,
|
|
61
|
-
with DJ.
|
|
81
|
+
- DJ does ALL git — staging, commits, pushes, branches, publishing, installs he has not handed over,
|
|
82
|
+
and deployments. An AI runs none of it unless DJ commands that exact action in the conversation;
|
|
83
|
+
otherwise it hands him the exact command. DJ stages files continuously while work is running so he
|
|
84
|
+
can see what is changing; never treat a staged/unstaged change as a sign of someone else's work,
|
|
85
|
+
and never bring up staging, the index, or other git state with DJ.
|
|
86
|
+
- Git and GitHub (`git log`, `git status`, diffs, `gh`, Actions runs) are read only when DJ says it is
|
|
87
|
+
needed. A problem DJ brings is fixed from the current code; when and why it changed is not looked
|
|
88
|
+
up unless he asks.
|
|
62
89
|
- Never instruct DJ to push or deploy — deploy IS `git push`. Never nag about deploys, indexes, or
|
|
63
90
|
seed buttons.
|
|
64
91
|
- Never discard, overwrite, reset, clean, or revert existing work unless DJ explicitly asks.
|
|
65
92
|
Preserve unrelated uncommitted work; DJ or another tool may be working concurrently.
|
|
66
93
|
- `dev:local` (DJ's manual dev stack) is DJ-only, always — never start or stop it.
|
|
67
94
|
- `dev:e2e` (the verification stack) is session-operated only inside the repo's Normal Test Flow or
|
|
68
|
-
on DJ's explicit command. DJ's in-conversation instruction overrides any flow step
|
|
69
|
-
|
|
95
|
+
on DJ's explicit command. DJ's in-conversation instruction overrides any flow step and governs
|
|
96
|
+
exactly what it names, for that conversation only.
|
|
70
97
|
- Never kill a running dev stack on your own judgment ("ports look wrong" = say what you see and
|
|
71
98
|
WAIT). Never run e2e against a stale build.
|
|
72
99
|
- Hosted-dev E2E runs happen only when DJ commands one, and follow the repo's hosted-E2E run doc
|
|
@@ -130,15 +157,25 @@ shared copy, in `@ttt-productions/dev-standards`, that every repo reads.
|
|
|
130
157
|
- No half-working, dead, or known-bad code — build it or remove it. On a second sighting of a defect
|
|
131
158
|
class, tell DJ and propose killing the CLASS system-wide plus a regression guard; do it only on
|
|
132
159
|
DJ's command.
|
|
160
|
+
- **Never make yourself an exception.** Code that breaks a rule, guard, or lint check is fixed. An
|
|
161
|
+
exception is asked for only when there is genuinely no other way, and it goes to DJ with that
|
|
162
|
+
reason, why no fix works. Nothing is exempted without his yes. Every exception he approves carries
|
|
163
|
+
its reason at the exception itself, so anyone reading it years later knows at once why it exists:
|
|
164
|
+
the guard entry's reason field, the comment on the `eslint-disable` / `prettier-ignore` line, or,
|
|
165
|
+
for a design-level exception, the design doc it belongs to. The reason states why the exception
|
|
166
|
+
exists, never who approved it.
|
|
133
167
|
- Reviewing an external plan (ChatGPT/Codex/etc.) means answering "is this the BEST code to solve
|
|
134
168
|
my problem" — never just verifying its claims. Evaluate the design space (alternatives, root cause,
|
|
135
169
|
structure) and fold an optimality verdict into the reviewed doc.
|
|
136
170
|
- V1-scope discipline: confirm the trigger exists in V1 before asking DJ to design.
|
|
137
171
|
- Docs stay lean — never a "done" log. Tracking docs hold only remaining work; finished work is
|
|
138
172
|
DELETED.
|
|
173
|
+
- **Working files** a session needs — extracted text, a one-off script, intermediate output — go in
|
|
174
|
+
`C:\DjDev\claude-scratchpad\<YYYY-MM-DD>-<topic>\`, never in a temp folder, loose in `C:\DjDev`,
|
|
175
|
+
or inside a repo. A session writes there only when the work needs a file, never for a conversation
|
|
176
|
+
that is only talking, and deletes its folder when that work is done.
|
|
139
177
|
- Working state that must outlive the session — orchestration ledgers, agent change logs, file
|
|
140
|
-
claims
|
|
141
|
-
the work it tracks and is deleted when the work finishes.
|
|
178
|
+
claims — lives in the repo beside the work it tracks and is deleted when the work finishes.
|
|
142
179
|
- Help with EVERY step, including non-code and operational ones — real artifacts (policies,
|
|
143
180
|
runbooks, click-by-click), never a "your job" checklist. Walk-throughs go one step at a time, dev
|
|
144
181
|
AND prod. A non-code or console step becomes a self-contained Claude web prompt (full context,
|
|
@@ -150,6 +187,19 @@ shared copy, in `@ttt-productions/dev-standards`, that every repo reads.
|
|
|
150
187
|
|
|
151
188
|
## Agents
|
|
152
189
|
|
|
190
|
+
- **Every conversation is inline unless DJ says, in that conversation, that it is an orchestrator.**
|
|
191
|
+
No doc, plan, ledger, or prompt makes a conversation an orchestrator.
|
|
192
|
+
- **Inline:** the session does the research and the work itself. When a piece of the work would be
|
|
193
|
+
done better by agents — LOW for mechanical work applied from written examples, HIGH for thinking
|
|
194
|
+
work or review — it proposes them to DJ with each agent's exact task and files, and launches them
|
|
195
|
+
only on his yes. Launching agents, a predefined wave included, never makes it an orchestrator; it
|
|
196
|
+
still runs its own Normal Test Flow.
|
|
197
|
+
- **Orchestrator:** the session saves its context for managing agents and does not read or edit code
|
|
198
|
+
itself. It first launches read-only agents to understand the system, then gives each building
|
|
199
|
+
agent the high-level picture and the design: build this, this way. An agent that finds a better or
|
|
200
|
+
different way stops and comes back instead of building it. Agents run in waves of a few at a time,
|
|
201
|
+
each owning its files, no file owned twice. LOW agents never decide; they apply the examples the
|
|
202
|
+
HIGH session gives them.
|
|
153
203
|
- The main session owns edits unless DJ explicitly approves parallel implementers with disjoint file
|
|
154
204
|
ownership. Nothing spawns without DJ's yes.
|
|
155
205
|
- Every prompt that spawns an agent names that agent's mandatory reading as explicit
|
package/model-tiers.md
CHANGED
|
@@ -22,5 +22,5 @@ follows the session unless a doc names one.
|
|
|
22
22
|
task applies a fixed set of written patterns to many files; its prompt names every pattern and
|
|
23
23
|
makes anything outside them a stop that returns to the HIGH session that spawned it. That session
|
|
24
24
|
and its reviewer stay HIGH.
|
|
25
|
-
- **The
|
|
25
|
+
- **The session runs on the model DJ picks when he starts it.** Every SPAWNED
|
|
26
26
|
agent's tier is binding.
|
package/package.json
CHANGED
|
@@ -29,8 +29,9 @@ A step can protect more than one area; overlap is intentional.
|
|
|
29
29
|
|
|
30
30
|
- **Architecture:** 9, 10, 12, 16–18, 25, 31, 35, 38, 41, 51, 52, 55, 61, 63, 64, 80, 83, 96, 99
|
|
31
31
|
- **Backend:** 10, 13, 20, 21, 23, 29, 32, 33, 36, 40, 49, 50, 56, 67, 77, 80, 87, 97, 98, 102, 105,
|
|
32
|
-
107, 108, 111, 112
|
|
33
|
-
- **Frontend:** 1–3, 7, 15, 17, 21, 28, 35, 36, 57, 60, 65, 66, 68, 82, 91, 99, 101, 103, 104, 114
|
|
32
|
+
107, 108, 111, 112, 121
|
|
33
|
+
- **Frontend:** 1–3, 7, 15, 17, 21, 28, 35, 36, 57, 60, 65, 66, 68, 82, 91, 99, 101, 103, 104, 114,
|
|
34
|
+
121
|
|
34
35
|
- **Media:** 4–6, 11, 14, 37, 39, 53, 58, 59, 83
|
|
35
36
|
- **Quality / documentation:** 25, 27, 28, 30, 40, 42, 46, 63, 69, 73, 75, 88, 89, 90, 95, 117–120
|
|
36
37
|
|
|
@@ -798,9 +799,10 @@ RULE-STD-ENG-009. **Scope:** `src`.
|
|
|
798
799
|
# Swallowed rejections — a user-initiated action's failure always reaches one surface.
|
|
799
800
|
rg -n "\.catch\(\s*\(\s*\w*\s*\)\s*=>\s*(undefined|null|\{\s*\}|void 0)\s*\)" src -g '*.ts' -g '*.tsx' -g '!**/__tests__/**' -g '!src/test/**'
|
|
800
801
|
```
|
|
801
|
-
**Expected:** the guards are green: every callable is declared once through the
|
|
802
|
-
|
|
803
|
-
called through its declaration — a raw callable site opts out of the
|
|
802
|
+
**Expected:** the guards are green: every callable is declared once through the factory kind from
|
|
803
|
+
query-core `./react`'s `createCallables` that fixes its retry, surface, and capture, from the app's
|
|
804
|
+
one callable policy, and is called through its declaration — a raw callable site opts out of the
|
|
805
|
+
policy's filter and interceptions.
|
|
804
806
|
One rejection gets exactly one surface: no second capture or second destructive toast. A CALLABLE
|
|
805
807
|
failure's copy comes only from the policy's one describer, so a raw SDK string never reaches the user;
|
|
806
808
|
a READ failure renders the canonical load-error state, which owns the one "could not load" sentence
|
|
@@ -816,12 +818,14 @@ half is guard-enforced).
|
|
|
816
818
|
```bash
|
|
817
819
|
<GUARD_SUITE> -t "every schema bound in the app, its Functions, and its Workers derives from a named limit|a stored enum value renders through its label map, never as raw text|no app module re-declares a constant the core package exports|no app module restates a core literal union"
|
|
818
820
|
<GUARD_SUITE> -t "every core schema bound derives from a named constant outside the reviewed structural bounds|every free-text property of a core wire input is a declared text field"
|
|
821
|
+
<GUARD_SUITE> -t "app routes are built by the one route owner"
|
|
819
822
|
rg -n "maxLength=\{[0-9]|minLength=\{[0-9]" src -g '*.tsx' -g '*.ts' -g '!**/__tests__/**'
|
|
820
823
|
rg -n "\.length\s*[<>]=?\s*[0-9]{2,}|\.slice\(0,\s*[0-9]" src functions/src -g '*.ts' -g '*.tsx' -g '!**/__tests__/**' -g '!*.test.ts' -g '!*.test.tsx'
|
|
821
824
|
```
|
|
822
825
|
**Expected:** the guards are green: every schema bound is a named limit, a text-field declaration, or an
|
|
823
826
|
enum schema; a stored enum value renders through its label map (never raw, never CSS-transformed); no app
|
|
824
|
-
module restates a package constant or union
|
|
827
|
+
module restates a package constant or union; every page path is built through the app's one route
|
|
828
|
+
owner in `<APP_DATA_PACKAGE>`, never written as a route literal. The greps: no free-text input carries a literal
|
|
825
829
|
`maxLength` — its cap is its `<APP_DATA_PACKAGE>` text-field declaration passed as the input's format;
|
|
826
830
|
every remaining length attribute reads a named constant; each length or excerpt guard on user text
|
|
827
831
|
imports its constant or is a reviewed structural literal; and a mode-varied value is never a literal
|
|
@@ -1475,6 +1479,22 @@ file in the repository with its license beside it; no stylesheet declares its ow
|
|
|
1475
1479
|
nothing names a hosted font service.
|
|
1476
1480
|
**Status:** PASS · FAIL · NOT RUN · BLOCKED
|
|
1477
1481
|
|
|
1482
|
+
### 121. Admin actions outside the admin area go through the admin-actions affordance
|
|
1483
|
+
**Rules:** RULE-STD-FRONTEND-111, RULE-STD-BACKEND-011. **Scope:** `src`, read against the admin-only
|
|
1484
|
+
callables the guard derives. A FULL audit classifies every reviewed entry; a PARTIAL audit, the
|
|
1485
|
+
touched areas.
|
|
1486
|
+
```bash
|
|
1487
|
+
<GUARD_SUITE> -t "admin actions outside the admin area go through the admin-actions affordance"
|
|
1488
|
+
```
|
|
1489
|
+
**Expected:** the guard is green. Outside the admin area, every admin-only callable is reached only
|
|
1490
|
+
through the one shield-marked admin-actions affordance. Every other read of admin standing outside the
|
|
1491
|
+
admin area is a reviewed entry whose stated purpose is navigation to the admin area, an admin's viewing
|
|
1492
|
+
reach, or the admin's inbox. Read each reviewed entry against its code: an entry whose read now offers
|
|
1493
|
+
an action is the finding, and so is an entry whose code is gone. An action that the affordance offers
|
|
1494
|
+
stays reachable on the admin standing alone (step 70). No installed React package renders a control
|
|
1495
|
+
gated on admin standing.
|
|
1496
|
+
**Status:** PASS · FAIL · NOT RUN · BLOCKED
|
|
1497
|
+
|
|
1478
1498
|
## Pass / Fail
|
|
1479
1499
|
|
|
1480
1500
|
Per [README.md](README.md) § Verdict.
|
package/playbooks/crosswalk.md
CHANGED
|
@@ -36,7 +36,7 @@ rule's coverage in its additions; they are not listed here.
|
|
|
36
36
|
| RULE-STD-ARCH-005 | Cross-tree trust contracts: one definition, one proof | codebase-hygiene 31; auth-boundary 13; testing-coverage 2 | — |
|
|
37
37
|
| RULE-STD-ARCH-006 | Code from another product is adapted, never carried with its identity | **No audit step yet.** No shared step; an app's own step is the candidate. | — |
|
|
38
38
|
| RULE-STD-ARCH-101 | `<APP_DATA_PACKAGE>` owns cross-boundary contracts | codebase-hygiene 16, 18, 31, 51, 56, 80; client-write-security-audit 8; data-integrity 2, 7, 8; dependency-audit 1, 4, 5; field-lineage 5; migration 1 | `isolatedRoots`, `tsconfigAliasesInRoot` |
|
|
39
|
-
| RULE-STD-ARCH-102 | One named declaration; enforcement points derive | codebase-hygiene 31, 51, 61, 99; callable-functions 3; client-write-security-audit 8; data-integrity 7; dependency-audit 5; migration 8 | `definitionRedeclaration`, `schemaLengthLiterals`, `textFieldDeclarations`, `schemaBounds`, `enumLabels` |
|
|
39
|
+
| RULE-STD-ARCH-102 | One named declaration; enforcement points derive | codebase-hygiene 31, 51, 61, 99; callable-functions 3; client-write-security-audit 8; data-integrity 7; dependency-audit 5; migration 8 | `definitionRedeclaration`, `schemaLengthLiterals`, `textFieldDeclarations`, `schemaBounds`, `enumLabels`, `appRouteOwner` |
|
|
40
40
|
| RULE-STD-ARCH-103 | Persist identity references, not snapshots | codebase-hygiene 35; data-integrity 2, 13; field-lineage 1, 2, 3, 5 | — |
|
|
41
41
|
| RULE-STD-ARCH-104 | Canonical Firestore paths and compound-camelCase naming | codebase-hygiene 10, 12, 56, 80, 117; data-integrity 8; field-lineage 3; firestore-storage-rules 1 | `firestorePathAssembly`, `firestoreLiteralSegments`, `firestoreRetiredSegments`, `firestoreTestPaths`, `rulesMirrorCore` |
|
|
42
42
|
| RULE-STD-ARCH-105 | Timestamps are epoch milliseconds via firebase-helpers | codebase-hygiene 9 | `firestoreTimestampNow` |
|
|
@@ -62,7 +62,7 @@ rule's coverage in its additions; they are not listed here.
|
|
|
62
62
|
| RULE-STD-BACKEND-004 | Admin authority is explicit; the claim is metadata | codebase-hygiene 32, 49, 70; auth-boundary 4; callable-functions 4; firestore-storage-rules 4 | `adminClaimRead` |
|
|
63
63
|
| RULE-STD-BACKEND-005 | Identity fields must match the authenticated caller | codebase-hygiene 77; auth-boundary 2, 12; callable-functions 2; client-write-security-audit 5, 11; firestore-storage-rules 6; testing-coverage 3 | — |
|
|
64
64
|
| RULE-STD-BACKEND-010 | Callables enforce App Check attestation | codebase-hygiene 29; auth-boundary 3, 12, 13; callable-functions 6, 12 | `appCheck` |
|
|
65
|
-
| RULE-STD-BACKEND-011 | Admin capability is self-sufficient; never coupled to a participant status | codebase-hygiene 70 | — |
|
|
65
|
+
| RULE-STD-BACKEND-011 | Admin capability is self-sufficient; never coupled to a participant status | codebase-hygiene 70, 121 | — |
|
|
66
66
|
| RULE-STD-BACKEND-012 | Privileged route handlers and server modules carry the callable obligations | codebase-hygiene 23, 77; auth-boundary 12; callable-functions 12; client-write-security-audit 11 | — |
|
|
67
67
|
| RULE-STD-BACKEND-013 | Named surface classes carry a rate-limit decision | codebase-hygiene 40, 77; auth-boundary 12; callable-functions 5 | `rateLimitSurfaces` |
|
|
68
68
|
| RULE-STD-BACKEND-101 | All transaction reads before all transaction writes | codebase-hygiene 97; async-workflow 6; callable-functions 8; data-integrity 5 | — |
|
|
@@ -124,6 +124,7 @@ rule's coverage in its additions; they are not listed here.
|
|
|
124
124
|
| RULE-STD-FRONTEND-108 | Auth-scoped subscribers reset on identity change | codebase-hygiene 35, 114; auth-boundary 14 | `authScopedKeys`, `signOutLiveness` |
|
|
125
125
|
| RULE-STD-FRONTEND-109 | One owner per data-layer failure's user-facing copy; never a raw SDK string | codebase-hygiene 60; ux-audit 8 | `callableErrorCopy`, `readFailureCopy`, `errorInternalsRender` |
|
|
126
126
|
| RULE-STD-FRONTEND-110 | An offered action mirrors the backend's predicate | codebase-hygiene 101, 108; auth-boundary 9 | — |
|
|
127
|
+
| RULE-STD-FRONTEND-111 | Admin actions outside the admin area go through the one admin-actions affordance | codebase-hygiene 121 | `adminActionSurface` |
|
|
127
128
|
| RULE-STD-FRONTEND-201 | Every async control shows its own pending state through the shared primitives | codebase-hygiene 57, 65, 68; ux-audit 2, 5, 6, 11, 12 | `loadingFeedback` |
|
|
128
129
|
| RULE-STD-FRONTEND-202 | ConsequenceDialog for consequential confirmations | codebase-hygiene 57, 65, 68, 104 | — |
|
|
129
130
|
| RULE-STD-FRONTEND-203 | Accessibility baseline: landmarks, labels, focus, Escape | codebase-hygiene 68, 103; ux-audit 4, 5, 12 | `accessibleControls`; guard-enforced: the `@ttt-productions/dev-standards/node/a11y` axe run (default, high-contrast, reduced-motion) in the app's e2e stage, and the shared ESLint base's `jsx-a11y` recommended rules |
|
|
@@ -89,16 +89,16 @@ names, and exceptions arrive as its facts.
|
|
|
89
89
|
|
|
90
90
|
### 5. A callable is declared through the shared callable factories
|
|
91
91
|
**Rules:** RULE-STD-ENG-002, RULE-STD-ENG-003, RULE-STD-FRONTEND-105. **Scope:** `packages/*/src`.
|
|
92
|
-
`
|
|
93
|
-
|
|
94
|
-
SDK's callable primitives stay inside firebase-helpers
|
|
92
|
+
`query-core/react`'s `createCallables` is the one factory set for a callable hook (action, reader,
|
|
93
|
+
invoker, resumable). It builds on query-core's session-aware mutation owner, `useSessionMutation`. The
|
|
94
|
+
SDK's callable primitives stay inside firebase-helpers, behind `callCallable`.
|
|
95
95
|
```bash
|
|
96
96
|
rg -n "^[^/*]*\bhttpsCallable(FromURL)?\(" packages/*/src -g '*.ts' -g '*.tsx' | rg -v "packages/firebase-helpers/"
|
|
97
97
|
rg -n "useMutation\(" packages/*/src -g '*.ts' -g '*.tsx' | rg -i "callable"
|
|
98
98
|
```
|
|
99
|
-
**Expected:** the first prints nothing. The second prints
|
|
100
|
-
|
|
101
|
-
`createCallables` from the app instead.
|
|
99
|
+
**Expected:** the first prints nothing. The second prints nothing: every callable hook is built by
|
|
100
|
+
`createCallables` on the session-aware owner. A package that builds its own callable mutation hook is
|
|
101
|
+
the finding; it takes a hook built by `createCallables` from the app instead.
|
|
102
102
|
**Status:** PASS · FAIL · NOT RUN · BLOCKED
|
|
103
103
|
|
|
104
104
|
### 6. Imports inside a package name the defining file by its built extension
|
|
@@ -24,7 +24,7 @@ Cross-boundary contracts, canonical definitions, identity, paths, compound ids,
|
|
|
24
24
|
|
|
25
25
|
**Rule.** Every definition — numbers (length limits, count caps, rate windows, price bounds), string unions and enums (kinds, statuses, item types), option and allowlist arrays, label and display-name maps, verbatim business copy (agreement statements, attestations), and typed shapes — is ONE named declaration in the package that owns the concept: `<APP_DATA_PACKAGE>` for an app's business truth, the owning generic package for a mechanism.
|
|
26
26
|
|
|
27
|
-
**Apps:** this holds regardless of which layer consumes the definition today: there is no "frontend-only" or "backend-only" definition, because `src/` and `functions/src` are not importable by a second consumer, so a definition living there is a copy waiting to happen. The app owns wiring (
|
|
27
|
+
**Apps:** this holds regardless of which layer consumes the definition today: there is no "frontend-only" or "backend-only" definition, because `src/` and `functions/src` are not importable by a second consumer, so a definition living there is a copy waiting to happen. The app owns wiring (mounting pages, composition, layout) — never truths. An app's page paths are a declaration in `<APP_DATA_PACKAGE>`, built through its one route owner; a route literal anywhere else is drift.
|
|
28
28
|
|
|
29
29
|
Enforcement points **derive**, never restate: zod `.max(MAX_X)`, React `maxLength={MAX_X}`, backend guards, `.slice(0, EXCERPT_LEN)`, and type positions referencing the canonical union (never an inline re-declared union). A literal at an enforcement point is drift by definition. Two compliance questions for any declaration: "updating this touches how many places?" (must be one) and "can a second consumer import this?" (if it would ever need to, it belongs in a package).
|
|
30
30
|
|
|
@@ -16,7 +16,7 @@ A comment these rules do not settle — bad in a way no rule names, or good but
|
|
|
16
16
|
- An exception that does not name the rule ID and the reason.
|
|
17
17
|
- One explanation repeated file after file.
|
|
18
18
|
|
|
19
|
-
**References.** The required markers — each a comment this rule keeps, and a sweep never removes one: RULE-STD-ARCH-206 (`SANCTIONED EXCEPTION`), RULE-STD-BACKEND-002 (`.passthrough()` reason), RULE-STD-BACKEND-010 (App Check omission reason), RULE-STD-BACKEND-013 (in-file rate-limit decision), RULE-STD-BACKEND-119 (refuse-instead-of-clamp exception), RULE-STD-BACKEND-301 (the post-commit marker), RULE-STD-FRONTEND-102 (raw `staleTime` justification), RULE-STD-QUALITY-006 (reasoned `eslint-disable-next-line`, `prettier-ignore` reason), RULE-STD-QUALITY-007 (guard allowlist justification), RULE-STD-QUALITY-009 (a reviewed entry's why). A rule that adds a required comment joins this list in the same change. RULE-STD-ENG-002 (no "keep in sync" pairs); RULE-STD-COMMENT-012 (no security mechanism).
|
|
19
|
+
**References.** The required markers — each a comment this rule keeps, and a sweep never removes one: RULE-STD-ARCH-206 (`SANCTIONED EXCEPTION`), RULE-STD-BACKEND-002 (`.passthrough()` reason), RULE-STD-BACKEND-010 (App Check omission reason), RULE-STD-BACKEND-013 (in-file rate-limit decision), RULE-STD-BACKEND-119 (refuse-instead-of-clamp exception), RULE-STD-BACKEND-301 (the post-commit marker), RULE-STD-FRONTEND-002 (the utility an `overrides.css` rule beats), RULE-STD-FRONTEND-102 (raw `staleTime` justification), RULE-STD-QUALITY-006 (reasoned `eslint-disable-next-line`, `prettier-ignore` reason), RULE-STD-QUALITY-007 (guard allowlist justification), RULE-STD-QUALITY-009 (a reviewed entry's why). A rule that adds a required comment joins this list in the same change. RULE-STD-ENG-002 (no "keep in sync" pairs); RULE-STD-COMMENT-012 (no security mechanism).
|
|
20
20
|
|
|
21
21
|
### RULE-STD-COMMENT-002 — No dates
|
|
22
22
|
**Scope.** both
|
|
@@ -64,7 +64,7 @@ How the client reads server state, builds cache keys, invalidates, calls callabl
|
|
|
64
64
|
### RULE-STD-FRONTEND-105 — One callable invocation path; never raw `httpsCallable`
|
|
65
65
|
**Scope.** apps
|
|
66
66
|
|
|
67
|
-
**Rule.** Every callable is declared once in `<CALLABLE_DECLARATIONS>`, through the
|
|
67
|
+
**Rule.** Every callable is declared once in `<CALLABLE_DECLARATIONS>`, through the factory kind from query-core `./react`'s `createCallables` that fixes its retry, surface, and capture — an action, a reader, an invoker, or a resumable action — built from the one app callable policy (`<CALLABLE_POLICY>`). Screens and hooks call the declared hook, and the callable's name is written nowhere else. The factories ride firebase-helpers' `callCallable` primitive, which owns the **undefined-strip** (the SDK encodes `undefined` as `null`, which strict `.optional()` `<APP_DATA_PACKAGE>` schemas reject — the primitive drops undefined keys deep), and the policy owns the **error taxonomy**: the expected-answer monitoring filter, the standard error toast, and the answers that have their own surface (the app's addition lists them) — announced and never toasted, which a caller-owned surface skips through the policy's surfaced-elsewhere predicate. A hook that wraps both a callable and a non-callable leg (e.g. a Storage upload) toasts only the leg the callable can't see — gate its local `onError` on the policy's callable-rejection predicate returning false, or declare the call `{ showErrorToast: false }` and own the copy. A React Query READ calls its declared reader, which neither toasts nor captures, and its failure is a rendered state (RULE-STD-FRONTEND-109). **One rejection gets ONE toast, and that budget spans files**: a hook's declared action with its toast on and an `onError`/`catch` toast in a component that calls that hook are one surface between them, so exactly one side owns the copy — either the hook declares the toast off, or the call site drops its toast and lets the action own it.
|
|
68
68
|
|
|
69
69
|
**Why.** A raw `httpsCallable` skips the undefined-strip (the schema rejects valid input) and the error taxonomy (double toasts, unfiltered monitoring noise, and answers that have their own surface toasted as errors).
|
|
70
70
|
|
|
@@ -72,7 +72,7 @@ How the client reads server state, builds cache keys, invalidates, calls callabl
|
|
|
72
72
|
- Importing `httpsCallable`/`getFunctions` from `firebase/functions`, or `callCallable`, anywhere in `src/`; a callable's name written outside `<CALLABLE_DECLARATIONS>`, including as a bare string at a call site; a file-local `callable()` wrapper.
|
|
73
73
|
- A callable hook that double-surfaces one rejection as two destructive toasts — in ONE file, or split across the hook module and its consuming component.
|
|
74
74
|
|
|
75
|
-
**References.** RULE-STD-FRONTEND-109; RULE-STD-QUALITY-103; ttt-packages `docs/packages/firebase-helpers.md`.
|
|
75
|
+
**References.** RULE-STD-FRONTEND-109; RULE-STD-QUALITY-103; ttt-packages `docs/packages/query-core.md`, `docs/packages/firebase-helpers.md`.
|
|
76
76
|
|
|
77
77
|
### RULE-STD-FRONTEND-106 — Gated actions go through the canonical auth gate
|
|
78
78
|
**Scope.** apps
|
|
@@ -153,3 +153,17 @@ Classification predicates are generic and come from `@ttt-productions/firebase-h
|
|
|
153
153
|
- A picker whose selectable range disagrees with the backend's rule for the value.
|
|
154
154
|
|
|
155
155
|
**References.** RULE-STD-ENG-002, RULE-STD-ENG-006; RULE-STD-FRONTEND-106 (the auth-readiness gate), RULE-STD-FRONTEND-206.
|
|
156
|
+
|
|
157
|
+
### RULE-STD-FRONTEND-111 — Admin actions outside the admin area go through the one admin-actions affordance
|
|
158
|
+
**Scope.** both
|
|
159
|
+
|
|
160
|
+
**Rule.** **Apps:** outside the app's admin area, an admin action is offered only through the app's one shield-marked admin-actions affordance, never as an inline control beside a member's own actions. Outside the admin area, a read of the viewer's admin standing is allowed for three purposes only: navigation to the admin area, an admin's viewing reach (seeing what a member could not), or the admin's own inbox. Each such read is a reviewed entry naming its purpose, and every other read of admin standing outside the admin area is a violation. The backend stays the authority on every admin action (RULE-STD-BACKEND-004). **Packages:** a React package never renders a control gated on admin standing. It takes no admin flag; an admin action on a package's surface is the app's, offered through the app's affordance.
|
|
161
|
+
|
|
162
|
+
**Why.** An inline admin control looks like a member action. One page offers it and the next one doesn't, and every screen that gates on admin standing is one more place where that gate can drift away from the one owner. When a package carries an admin control, every app that installs it gets an admin action outside its admin affordance.
|
|
163
|
+
|
|
164
|
+
**Prohibits.**
|
|
165
|
+
- An admin action rendered outside the admin area other than through the admin-actions affordance; a second admin-actions affordance.
|
|
166
|
+
- A read of admin standing outside the admin area that is not a reviewed entry for navigation, viewing reach, or the admin's inbox.
|
|
167
|
+
- A React package component, prop, or config field that shows, hides, or enables a control on admin standing.
|
|
168
|
+
|
|
169
|
+
**References.** RULE-STD-ENG-002, RULE-STD-ENG-006; RULE-STD-ARCH-201; RULE-STD-BACKEND-004, RULE-STD-BACKEND-011; RULE-STD-FRONTEND-001, RULE-STD-FRONTEND-110.
|
|
@@ -77,7 +77,7 @@ A test proves the business rule, never the code's current output: its expected v
|
|
|
77
77
|
### RULE-STD-QUALITY-006 — Lint and format: zero suppression in apps, reasoned disables in packages; one enforced format
|
|
78
78
|
**Scope.** both
|
|
79
79
|
|
|
80
|
-
**Rule.** The lint half is split by scope; the format half is the same for both. **Apps** are zero suppression: no `eslint-disable` comment anywhere in the linted trees — source, Functions, E2E, scripts, and config. When a rule fires, fix the root cause, and solve a genuine false positive structurally — rename, refactor, or scope the rule — never by suppressing the line; external-authority state pruning uses the sanctioned render-phase adjustment, not a suppressed effect. A `warn`-level finding is a finding to fix, and a rule is never turned off, nor `ignores` widened, to pass failing code. New app code also follows the conventions the lint config forces, listed below. **Packages** permit an `eslint-disable-next-line` only for a narrow intentional case, carrying its reason on the line; it is preferred over weakening the rule, and a real violation is fixed at its source.
|
|
80
|
+
**Rule.** The lint half is split by scope; the format half is the same for both. **Apps** are zero suppression: no `eslint-disable` comment anywhere in the linted trees — source, Functions, E2E, scripts, and config. When a rule fires, fix the root cause, and solve a genuine false positive structurally — rename, refactor, or scope the rule — never by suppressing the line; external-authority state pruning uses the sanctioned render-phase adjustment, not a suppressed effect. A `warn`-level finding is a finding to fix, and a rule is never turned off, nor `ignores` widened, to pass failing code. New app code also follows the conventions the lint config forces, listed below. **Packages** permit an `eslint-disable-next-line` only for a narrow intentional case where no fix works, on DJ's yes, carrying its reason on the line; it is preferred over weakening the rule, and a real violation is fixed at its source.
|
|
81
81
|
|
|
82
82
|
Every code file — source, tests, scripts, and config — is in the one format Prettier writes from the shared Prettier config (this package's `config/prettier.json`); `test:quiet`'s format stage writes that format and then checks it, a check-only run (a package release preflight, `test:all`) only checks, so a release never publishes formatting nobody committed, and the check fails a file that is not formatted; `eslint-config-prettier` keeps ESLint out of formatting. A file is formatted by running Prettier, never reflowed by hand.
|
|
83
83
|
|
|
@@ -92,14 +92,14 @@ Every code file — source, tests, scripts, and config — is in the one format
|
|
|
92
92
|
- An anonymous React wrapper component returned from a test helper (assign `displayName`).
|
|
93
93
|
- Straight `'`/`"` in JSX text content (use `'`/`"`).
|
|
94
94
|
- Suppressing `exhaustive-deps` instead of fixing at the source (destructure the stable `mutate`; memoize a derived dep; destructure the specific prop fields used).
|
|
95
|
-
- An unformatted code file; a `prettier-ignore` without its reason; an ESLint formatting rule that fights Prettier.
|
|
95
|
+
- An unformatted code file; a `prettier-ignore` without its reason, or added when a fix works or without DJ's yes; an ESLint formatting rule that fights Prettier.
|
|
96
96
|
|
|
97
97
|
**References.** RULE-STD-ENG-008; this package's `node/eslint` bases and `config/prettier.json`; each repo's ESLint config and `.prettierignore`.
|
|
98
98
|
|
|
99
99
|
### RULE-STD-QUALITY-007 — Guard tests enforce ownership and boundaries, never inventories
|
|
100
100
|
**Scope.** both
|
|
101
101
|
|
|
102
|
-
**Rule.** Structural guard tests (the repo-guards suite each repo runs in its gate — an app's guard suite, ttt-packages' boundary suite) enforce a forbidden boundary or single-owner rule against the current clean baseline — every allowlist entry carrying a one-line justification — so that a NEW regression fails the build. A guard must not mirror an exhaustive list of today's files, exports, packages, or domains: an inventory-mirror breaks on every legitimate addition and audits nothing.
|
|
102
|
+
**Rule.** Structural guard tests (the repo-guards suite each repo runs in its gate — an app's guard suite, ttt-packages' boundary suite) enforce a forbidden boundary or single-owner rule against the current clean baseline — every allowlist entry carrying a one-line justification — so that a NEW regression fails the build. An entry is added only when no fix works, on DJ's yes, with its reason in the entry. A guard must not mirror an exhaustive list of today's files, exports, packages, or domains: an inventory-mirror breaks on every legitimate addition and audits nothing.
|
|
103
103
|
|
|
104
104
|
**Why.** A brittle inventory-mirror is churn, not enforcement; the value is catching the next violation, not counting the current files.
|
|
105
105
|
|
|
@@ -127,7 +127,7 @@ Every code file — source, tests, scripts, and config — is in the one format
|
|
|
127
127
|
### RULE-STD-QUALITY-009 — A test loads the code it tests when its file loads
|
|
128
128
|
**Scope.** both
|
|
129
129
|
|
|
130
|
-
**Rule.** A test imports the code it tests at the top of its file — a static import, or a top-level `await import()` — never inside a case, a hook, or a helper they call, and never resets the module registry. A case that needs other state gets it without a reload: an environment the code reads at load is set in `vi.hoisted` before the import, per-instance state is cleared through the module's test-only `__reset…()` seam, and a flag the code reads once is read when it is called instead. A file whose fresh module per case is itself what it proves is a reviewed entry with its why, and an entry whose file no longer does is stale. The repo-guards `testCaseModuleLoads` guard enforces it.
|
|
130
|
+
**Rule.** A test imports the code it tests at the top of its file — a static import, or a top-level `await import()` — never inside a case, a hook, or a helper they call, and never resets the module registry. A case that needs other state gets it without a reload: an environment the code reads at load is set in `vi.hoisted` before the import, per-instance state is cleared through the module's test-only `__reset…()` seam, and a flag the code reads once is read when it is called instead. A file whose fresh module per case is itself what it proves is a reviewed entry with its why — an entry is added only when no fix works, on DJ's yes, with its reason in the entry — and an entry whose file no longer does is stale. The repo-guards `testCaseModuleLoads` guard enforces it.
|
|
131
131
|
|
|
132
132
|
**Why.** A module's first load pulls its whole graph; inside a case that cold load is timed as the case's own work, so a file's first case was slow for nothing it did and, under the full parallel run, crossed its timeout.
|
|
133
133
|
|
|
@@ -13,8 +13,11 @@ description: Claude Code workflow (Build or fix). Use when the work is big enoug
|
|
|
13
13
|
|
|
14
14
|
## Before anything spawns
|
|
15
15
|
|
|
16
|
-
1. The normal preflight
|
|
17
|
-
|
|
16
|
+
1. The normal preflight. This session saves its context for managing agents and does not read or
|
|
17
|
+
edit code itself (`<DEV_STANDARDS>/development-preferences.md` § Agents).
|
|
18
|
+
2. Launch read-only agents to read the routed rules, the `docs/design/*.md` for every area involved,
|
|
19
|
+
and the current code, and report the system back; the design each building agent gets comes from
|
|
20
|
+
their reports.
|
|
18
21
|
3. Propose to DJ: the number of agents and each one's exact scope and owned files. Nothing spawns
|
|
19
22
|
without DJ's yes.
|
|
20
23
|
4. App-side work: confirm every shared package it depends on is at `@latest` first. Package work and
|
|
@@ -22,12 +25,13 @@ description: Claude Code workflow (Build or fix). Use when the work is big enoug
|
|
|
22
25
|
|
|
23
26
|
## Every spawned prompt
|
|
24
27
|
|
|
28
|
+
- The high-level picture and the design to build: build this, this way.
|
|
25
29
|
- The agent's exact scope and owned files, and its mandatory reading as explicit read-before-acting
|
|
26
30
|
paths: the routed rule files (shared and the app's) and `docs/design/*.md` for its area
|
|
27
31
|
(RULE-STD-ENG-010).
|
|
28
32
|
- A hard ban on spawning agents.
|
|
29
|
-
- A kill-and-escalate clause: a needed package change,
|
|
30
|
-
this session.
|
|
33
|
+
- A kill-and-escalate clause: a needed package change, a better or different way than the design,
|
|
34
|
+
or anything unexpected → stop and report to this session.
|
|
31
35
|
- Targeted tests only, on its own work.
|
|
32
36
|
- Tier per `<DEV_STANDARDS>/model-tiers.md` (implementation agents; a mechanical-only part uses
|
|
33
37
|
`mechanical-fan-out.md` instead).
|
|
@@ -37,7 +41,7 @@ description: Claude Code workflow (Build or fix). Use when the work is big enoug
|
|
|
37
41
|
- Adversarial review agents at the HIGH tier over the landed work, each also checking every new or
|
|
38
42
|
changed test against the business rule it claims to prove (RULE-STD-QUALITY-001; testing-coverage
|
|
39
43
|
playbook).
|
|
40
|
-
- Exactly ONE final full gate after every agent has landed: the Normal `<APP_NAME>` Test Flow
|
|
41
|
-
|
|
42
|
-
|
|
44
|
+
- Exactly ONE final full gate after every agent has landed: the Normal `<APP_NAME>` Test Flow, run
|
|
45
|
+
as `<DEV_STANDARDS>/claude/CLAUDE.base.md` § The Normal `<APP_NAME>` Flows says for an
|
|
46
|
+
orchestrator.
|
|
43
47
|
- Delete the finished `docs/work/` items and the ledger, then stop for DJ's push.
|
|
@@ -25,7 +25,9 @@ description: Claude Code workflow (Build or fix). Use when DJ wants known, decid
|
|
|
25
25
|
Normal `<APP_NAME>` Dev Flow (`<DEV_STANDARDS>/claude/CLAUDE.base.md`).
|
|
26
26
|
- Every fix ships a regression test that fails before the fix and proves the business rule
|
|
27
27
|
(RULE-STD-QUALITY-001). Design docs the fix changes are updated in the same change.
|
|
28
|
-
- A
|
|
28
|
+
- A piece of the work agents would do better → propose LOW or HIGH agents for it to DJ, staying
|
|
29
|
+
inline (`<DEV_STANDARDS>/development-preferences.md` § Agents); a large mechanical change uses
|
|
30
|
+
`mechanical-fan-out.md`.
|
|
29
31
|
|
|
30
32
|
## Finishing
|
|
31
33
|
|
|
@@ -23,8 +23,9 @@ description: Claude Code workflow (Build or fix). Use when a multi-task plan DJ
|
|
|
23
23
|
|
|
24
24
|
- Packages-first: every package-side task in the plan lands, gates, and is released before any
|
|
25
25
|
app-side task (Normal `<APP_NAME>` Dev Flow, `<DEV_STANDARDS>/claude/CLAUDE.base.md`).
|
|
26
|
-
- Build inline.
|
|
27
|
-
|
|
26
|
+
- Build inline. A piece of the work agents would do better → propose LOW or HIGH agents for it to
|
|
27
|
+
DJ, staying inline (`<DEV_STANDARDS>/development-preferences.md` § Agents); large mechanical parts
|
|
28
|
+
use `mechanical-fan-out.md`.
|
|
28
29
|
- Approval covers exactly the approved tasks — no adjacent refactors.
|
|
29
30
|
- Every task ships its regression test (RULE-STD-QUALITY-001) and its doc updates.
|
|
30
31
|
|
|
@@ -34,5 +34,5 @@ through this; it stays inline or goes to `fan-out-implementation.md`.
|
|
|
34
34
|
5. **One HIGH reviewer** checks all the agents' changes together once every agent is done: each
|
|
35
35
|
change matches a listed pattern, nothing outside the patterns slipped in, and every new or changed
|
|
36
36
|
test proves the business rule it claims, not the code's current output (RULE-STD-QUALITY-001).
|
|
37
|
-
6. **One final gate.** Back in the calling workflow: the
|
|
38
|
-
|
|
37
|
+
6. **One final gate.** Back in the calling workflow: the inline session runs the Normal Test Flow
|
|
38
|
+
once, for the whole change set.
|
|
@@ -21,8 +21,9 @@ description: Claude Code workflow (Build or fix). Use when DJ names a step of a
|
|
|
21
21
|
3. Work the step, or one focused slice of it. A step with a publish stop: ALL its package work first,
|
|
22
22
|
then the release command, per the Normal `<APP_NAME>` Dev Flow
|
|
23
23
|
(`<DEV_STANDARDS>/claude/CLAUDE.base.md`).
|
|
24
|
-
4.
|
|
25
|
-
|
|
24
|
+
4. A piece of the work agents would do better → propose LOW or HIGH agents for it to DJ, staying
|
|
25
|
+
inline (`<DEV_STANDARDS>/development-preferences.md` § Agents); large mechanical parts use
|
|
26
|
+
`mechanical-fan-out.md`.
|
|
26
27
|
5. The Normal `<APP_NAME>` Test Flow, once, on the change set.
|
|
27
28
|
6. Delete each finished item from the step's work doc. When the step is done, delete its folder and
|
|
28
29
|
its section in `PLAN.md` — never renumber.
|