@orkestrel/scaffold 0.0.44 → 0.0.46
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/README.md +10 -10
- package/dist/bin/main.js +31 -31
- package/dist/bin/main.js.map +1 -1
- package/dist/host/AGENTS.md +7 -2
- package/dist/host/agents/orchestration.md +232 -56
- package/dist/host/agents/skills/enterprise-bootstrap/SKILL.md +7 -7
- package/dist/host/agents/skills/enterprise-bootstrap/references/bootstrap-reference.md +11 -9
- package/dist/host/agents/skills/enterprise-bootstrap/references/components.md +3 -3
- package/dist/host/agents/skills/enterprise-bootstrap/references/frontend-design.md +3 -3
- package/dist/host/agents/skills/enterprise-bootstrap/references/utilities.md +1 -1
- package/dist/host/agents/skills/orkestrel-align-packages/SKILL.md +1 -1
- package/dist/host/agents/skills/orkestrel-build-application/SKILL.md +2 -2
- package/dist/host/agents/skills/orkestrel-debrief/SKILL.md +1 -1
- package/dist/host/agents/skills/orkestrel-debrief/references/field-testing.md +2 -2
- package/dist/host/agents/skills/orkestrel-debrief/references/instruction-audit.md +8 -8
- package/dist/host/agents/skills/orkestrel-falsify/SKILL.md +16 -14
- package/dist/host/agents/skills/orkestrel-falsify/references/brief.md +3 -3
- package/dist/host/agents/skills/orkestrel-falsify/references/reconcile.md +14 -14
- package/dist/host/agents/skills/orkestrel-harden-package/SKILL.md +1 -1
- package/dist/host/agents/skills/orkestrel-human-journey/SKILL.md +3 -3
- package/dist/host/agents/skills/orkestrel-human-journey/references/captures.md +3 -3
- package/dist/host/agents/skills/orkestrel-human-journey/references/layer.md +3 -3
- package/dist/host/agents/skills/orkestrel-polish-surface/SKILL.md +3 -3
- package/dist/host/claude/agents/analyst.md +2 -2
- package/dist/host/claude/agents/checker.md +2 -2
- package/dist/host/claude/agents/codex.md +5 -5
- package/dist/host/claude/agents/orkestrel.md +10 -8
- package/dist/host/claude/agents/planner.md +1 -1
- package/dist/host/claude/agents/researcher.md +2 -2
- package/dist/host/claude/agents/reviewer.md +1 -1
- package/dist/host/claude/agents/scout.md +2 -2
- package/dist/host/claude/agents/sol.md +3 -3
- package/dist/host/claude/agents/verifier.md +8 -0
- package/dist/host/claude/rules/application.md +7 -7
- package/dist/host/claude/rules/architecture.md +6 -6
- package/dist/host/claude/rules/documentation.md +1 -0
- package/dist/host/claude/rules/patterns.md +3 -3
- package/dist/host/claude/rules/quality.md +3 -3
- package/dist/host/claude/rules/tests.md +9 -2
- package/dist/host/claude/rules/workspace.md +7 -7
- package/dist/host/claude/rules/writing.md +12 -2
- package/dist/host/codex/agents/planner.toml +1 -1
- package/dist/host/codex/config.toml +4 -0
- package/dist/host/configs/helpers.ts +21 -1
- package/dist/host/cursor/mcp.json +4 -0
- package/dist/host/cursor/rules/orchestration.mdc +1 -1
- package/dist/host/dotfiles/gitignore +4 -1
- package/dist/host/dotfiles/mcp.json +4 -0
- package/dist/host/guides/scaffold.md +134 -119
- package/dist/host/scripts/codex.sh +0 -0
- package/dist/host/scripts/cursor.sh +0 -0
- package/dist/host/scripts/deps.sh +0 -0
- package/dist/host/scripts/ollama.sh +0 -0
- package/dist/host/tests/config.test.ts +40 -1
- package/dist/host/tests/policy.test.ts +2 -2
- package/dist/host/tests/setupPolicy.ts +8 -5
- package/dist/src/core/index.cjs +144 -149
- package/dist/src/core/index.cjs.map +1 -1
- package/dist/src/core/index.d.cts +1624 -1643
- package/dist/src/core/index.d.ts +1624 -1643
- package/dist/src/core/index.js +145 -149
- package/dist/src/core/index.js.map +1 -1
- package/dist/src/server/index.cjs +82 -97
- package/dist/src/server/index.cjs.map +1 -1
- package/dist/src/server/index.d.cts +1844 -1871
- package/dist/src/server/index.d.ts +1844 -1871
- package/dist/src/server/index.js +83 -96
- package/dist/src/server/index.js.map +1 -1
- package/package.json +4 -3
|
@@ -16,9 +16,10 @@ Read in this order before acting:
|
|
|
16
16
|
`CLAUDE.md`, `.codex/config.toml`, and `.cursor/rules/` are bridges. Each points here and adds
|
|
17
17
|
only what its harness needs. None of them restates this file.
|
|
18
18
|
|
|
19
|
-
Every dispatch tells its executor to read
|
|
19
|
+
Every dispatch tells its executor to read every item after the user's current instruction before
|
|
20
|
+
acting.
|
|
20
21
|
|
|
21
|
-
## The
|
|
22
|
+
## The engines
|
|
22
23
|
|
|
23
24
|
One workflow runs across all providers. Each engine has one job and never takes another's.
|
|
24
25
|
|
|
@@ -31,7 +32,7 @@ One workflow runs across all providers. Each engine has one job and never takes
|
|
|
31
32
|
- Route each nontrivial implementation unit to Opus or Sol. Objective, constraint-heavy,
|
|
32
33
|
mechanical-precision work goes to Sol. API-shape, naming, and documentation-voice work goes to
|
|
33
34
|
Opus. Cursor Composer is not an implementation route, and no `composer` role exists.
|
|
34
|
-
- Design and audit always run the
|
|
35
|
+
- Design and audit always run the adversarial pass.
|
|
35
36
|
|
|
36
37
|
## Orchestration by harness
|
|
37
38
|
|
|
@@ -54,15 +55,15 @@ reasoning effort.
|
|
|
54
55
|
|
|
55
56
|
## The adversarial pass
|
|
56
57
|
|
|
57
|
-
|
|
58
|
-
names, on the same clean-context terms.
|
|
58
|
+
The subjective lane and the objective lane run on every design round; an audit round runs the lanes
|
|
59
|
+
the execution loop's audit step names, on the same clean-context terms.
|
|
59
60
|
|
|
60
61
|
| Lane | Argues |
|
|
61
62
|
| -------------- | --------------------------------------------------------------------------- |
|
|
62
63
|
| **Subjective** | Shape, taste, naming, ergonomics, design fit, what the API should feel like |
|
|
63
64
|
| **Objective** | Correctness, constraints, and what the code and contracts actually permit |
|
|
64
65
|
|
|
65
|
-
**A required lane always runs.** Never collapse
|
|
66
|
+
**A required lane always runs.** Never collapse required lanes into one. Never let an engine's
|
|
66
67
|
absence stand in for a required lane.
|
|
67
68
|
|
|
68
69
|
### Clean contexts
|
|
@@ -73,25 +74,25 @@ absence stand in for a required lane.
|
|
|
73
74
|
- A lane run in the Orchestrator's context is the Orchestrator assessing itself, whatever model
|
|
74
75
|
name it carries. The clean context is what makes the lane independent and unbiased, and it is
|
|
75
76
|
what keeps the main context at decision level.
|
|
76
|
-
- Run
|
|
77
|
+
- Run the lanes in parallel, blind to each other. Reconcile them yourself.
|
|
77
78
|
|
|
78
79
|
### Engine assignment
|
|
79
80
|
|
|
80
81
|
By default Opus 5 holds the subjective lane and Sol holds the objective lane.
|
|
81
82
|
|
|
82
|
-
When one engine is unavailable, the remaining engine runs **
|
|
83
|
+
When one engine is unavailable, the remaining engine runs **every** lane — still separate
|
|
83
84
|
subagents, still clean contexts, still blind to each other, each told which perspective it holds.
|
|
84
85
|
Record the substitution.
|
|
85
86
|
|
|
86
|
-
| Harness | Engine unavailable
|
|
87
|
-
| ----------- |
|
|
88
|
-
| Claude Code | Sol (Codex bench dark)
|
|
89
|
-
| Codex | Opus 5 (Claude CLI dark)
|
|
90
|
-
| Cursor |
|
|
87
|
+
| Harness | Engine unavailable | Runs every lane |
|
|
88
|
+
| ----------- | --------------------------------- | --------------- |
|
|
89
|
+
| Claude Code | Sol (Codex bench dark) | Opus 5 |
|
|
90
|
+
| Codex | Opus 5 (Claude CLI dark) | GPT-5.6 Sol |
|
|
91
|
+
| Cursor | Opus 5 and Sol (MCP servers dark) | Cursor Grok |
|
|
91
92
|
|
|
92
93
|
- Never assign Grok to either lane in Claude Code or Codex. If the remaining native engine is also
|
|
93
94
|
unavailable there, the pass cannot run: stop and report rather than substituting Grok.
|
|
94
|
-
- Grok takes
|
|
95
|
+
- Grok takes every lane only in Cursor, and only when Opus 5 and Sol are both unavailable.
|
|
95
96
|
- Treat a lane that returns no verdicts as a lane that did not run. A bench lane reporting that its
|
|
96
97
|
driver executed and its engine was never reached is a dark bench, not a result. Record the bench
|
|
97
98
|
dark from that report, re-run the lane on the substitute engine from the table above, and name in
|
|
@@ -184,6 +185,11 @@ Every role honours this floor. No dispatch may widen it.
|
|
|
184
185
|
from a clean committed baseline, each owning disjoint files.
|
|
185
186
|
- Treat every shared file as report-only.
|
|
186
187
|
- No role commits, pushes, tags, publishes, installs dependencies, or runs a destructive command.
|
|
188
|
+
- No role runs `git checkout`, `git restore`, `git stash`, `git reset`, or `git clean`. Each discards
|
|
189
|
+
a working-tree change silently. A role that must undo its own edit undoes exactly that edit.
|
|
190
|
+
- A dispatch that has a unit plant a line to prove an instrument can fail names a file the unit under
|
|
191
|
+
verification did not touch, and names how the plant is removed. Check the tree's status before
|
|
192
|
+
choosing the file.
|
|
187
193
|
- No role reads, prints, copies, uploads, or packages a secret — `CURSOR_API_KEY`, Codex auth
|
|
188
194
|
files, `.env*`, `.npmrc`, `auth.json`, keys, or tokens.
|
|
189
195
|
- Concurrent executors never run tree-wide `format`, lint `--fix`, or `build`. They validate
|
|
@@ -205,8 +211,9 @@ Every role honours this floor. No dispatch may widen it.
|
|
|
205
211
|
same class of defect through a new door, the search is following the frame rather than the
|
|
206
212
|
defect. Bound the scope, then fan out independent lenses over disjoint slices in one pass.
|
|
207
213
|
Parallelism is worth more here for the framing it breaks than for the wall-clock it saves.
|
|
208
|
-
-
|
|
209
|
-
|
|
214
|
+
- The subjective and objective lanes are the adversarial pass's FLOOR, not its shape. Where a
|
|
215
|
+
subject has more seams than that pass can attack, fan out one lens per seam over disjoint slices,
|
|
216
|
+
keep every lens blind and
|
|
210
217
|
clean-contexted, and number every slice's claims in one shared sequence. Change the lenses in a
|
|
211
218
|
successor round rather than repeating them.
|
|
212
219
|
- Decompose by required context and independently verifiable acceptance criteria, not by task type.
|
|
@@ -217,8 +224,8 @@ Every role honours this floor. No dispatch may widen it.
|
|
|
217
224
|
|
|
218
225
|
## Writing concurrency
|
|
219
226
|
|
|
220
|
-
Concurrent executors share a filesystem unless isolated. Follow these
|
|
221
|
-
|
|
227
|
+
Concurrent executors share a filesystem unless isolated. Follow these rules to prevent clobbered
|
|
228
|
+
edits, formatter and build races, cache phantoms, and validation cross-talk.
|
|
222
229
|
|
|
223
230
|
1. Serialize writing executors in the main checkout. Commit a checkpoint before each writing
|
|
224
231
|
dispatch so git is the rollback mechanism.
|
|
@@ -226,12 +233,13 @@ clobbered edits, formatter and build races, cache phantoms, and validation cross
|
|
|
226
233
|
3. Keep shared files report-only. Executors return exact patches for serial integration.
|
|
227
234
|
4. Restrict concurrent executors to read-only, scoped validation. A tree-wide result may contain a
|
|
228
235
|
sibling's in-flight failure, so an executor reports only its owned scope.
|
|
229
|
-
5. Give concurrent audit lanes worktree isolation whenever the campaign is uncommitted.
|
|
236
|
+
5. Give concurrent audit lanes worktree isolation whenever the campaign is uncommitted. Lanes
|
|
230
237
|
sharing one working tree contaminate each other's readings in both directions.
|
|
231
238
|
6. After integration, clear shared caches if needed, then have one independent `verifier` run the
|
|
232
239
|
authoritative tree-wide sweep. A writer's self-report never establishes green.
|
|
233
240
|
7. The Orchestrator's own sweep is a writing dispatch and queues behind the units that own those
|
|
234
|
-
files. A script that fixes one thing across every target is the easiest way to break
|
|
241
|
+
files. A script that fixes one thing across every target is the easiest way to break the
|
|
242
|
+
serialization rule,
|
|
235
243
|
because it does not feel like a dispatch — nobody was named, no brief was written, and it
|
|
236
244
|
finishes in seconds. It still writes into trees a live unit owns, and a unit whose brief it
|
|
237
245
|
invalidates will repair the same drift the other way and report a state that is already false.
|
|
@@ -246,7 +254,18 @@ clobbered edits, formatter and build races, cache phantoms, and validation cross
|
|
|
246
254
|
stopped. A slice hands control back while most of the fleet is still unstarted.
|
|
247
255
|
10. Re-run a timing or resource failure alone before believing it. Concurrent slices, builds, and
|
|
248
256
|
suites make a container miss deadlines it meets when idle, so a red result under load is a
|
|
249
|
-
question rather than an answer.
|
|
257
|
+
question rather than an answer. A unit re-running the file alone is not alone: its own exec,
|
|
258
|
+
code-mode host, and sandbox stay resident throughout, and on a small container that residue
|
|
259
|
+
alone misses a deadline the same file meets on an idle one. So the deciding re-run belongs to
|
|
260
|
+
the Orchestrator after the unit exits, never to the unit, and a timing failure a unit cannot
|
|
261
|
+
clear is carried to that reading rather than diagnosed by the unit. This makes a writer's own
|
|
262
|
+
gate evidence systematically pessimistic on timing, which is another reason the independent
|
|
263
|
+
`verifier` runs the authoritative gates.
|
|
264
|
+
11. While any unit is live, the Orchestrator's own instruments go in its scratchpad, never in the
|
|
265
|
+
subject repository's `tmp/`. A probe that both writes and deletes inside the subject tree can
|
|
266
|
+
remove a file it did not create, and a cleanup keyed to a caller-supplied path list is how. The
|
|
267
|
+
same directory is where dispatched units build their instruments, so removing it destroys a live
|
|
268
|
+
lane's work.
|
|
250
269
|
|
|
251
270
|
## Execution loop
|
|
252
271
|
|
|
@@ -260,7 +279,7 @@ with the network denied. Record a bench live only on a bounded round-tripped mod
|
|
|
260
279
|
back, and record what came back beside the routing decision. Probes are read-only, and the role file
|
|
261
280
|
owns each bench's exact probe.
|
|
262
281
|
|
|
263
|
-
The
|
|
282
|
+
The local steps still run, because they route the recovery rather than decide the verdict: an
|
|
264
283
|
unresolved CLI is an install problem, a failed authentication-state check starts the login ladder
|
|
265
284
|
below, and a bench that passes both and still cannot round-trip is dark for a reason no local check
|
|
266
285
|
can see. Record every dark bench with its fallback and the lane substitution it forces, and never
|
|
@@ -273,7 +292,7 @@ lane instead of re-dispatching against a session-start answer that no longer hol
|
|
|
273
292
|
1. **Absorb.** Dispatch `grok` for terrain, prior art, and the reading the decision needs. In an
|
|
274
293
|
Orkestrel repo dispatch `orkestrel` alongside it for live package state. Skip only when the
|
|
275
294
|
ground is already known.
|
|
276
|
-
2. **Design adversarially.** Run the
|
|
295
|
+
2. **Design adversarially.** Run the adversarial pass on one design brief: `planner` for
|
|
277
296
|
the subjective lane and `analyst` for the objective lane. Reconcile them yourself into one plan:
|
|
278
297
|
units, dependencies, ownership, parallel and serial order, acceptance criteria, risks.
|
|
279
298
|
- Surface the plan before dispatch, including a routing ledger naming each unit's role **and**
|
|
@@ -293,7 +312,7 @@ lane instead of re-dispatching against a session-start answer that no longer hol
|
|
|
293
312
|
criterion discovered at integration is a successor brief routed to a writer, never an
|
|
294
313
|
integration edit.
|
|
295
314
|
5. **Audit adversarially.** Audit every nontrivial implementation with at least one lane whose
|
|
296
|
-
engine did not write it. Run
|
|
315
|
+
engine did not write it. Run another lane when the first returns FAIL, when the subject is a
|
|
297
316
|
rendered or externally driven surface, or when the unit's claims span both correctness and
|
|
298
317
|
shape. Dispatch `checker` when the acceptance criteria are mechanical — counts, paths, parity
|
|
299
318
|
rows, scope honesty. Record in the round's verdict file when a lane or the checker did not run.
|
|
@@ -321,7 +340,7 @@ lane instead of re-dispatching against a session-start answer that no longer hol
|
|
|
321
340
|
- Record what changed and why. An unrecorded re-baseline cannot be audited, and the next one
|
|
322
341
|
re-derives it.
|
|
323
342
|
8. **Accept.** Decide, then report outcomes, decisions, evidence, and remaining risk concisely.
|
|
324
|
-
When step
|
|
343
|
+
When the design step's exit criterion is met and the gates are green, accept. The next goal is the
|
|
325
344
|
deliverable.
|
|
326
345
|
|
|
327
346
|
### Re-baselining is not rescoping
|
|
@@ -360,7 +379,7 @@ Never route a native model through its own CLI or an MCP loopback.
|
|
|
360
379
|
|
|
361
380
|
- Use a single-agent dispatch when later control flow depends on the previous result.
|
|
362
381
|
- Use a workflow for a known deterministic fan-out, staged pipeline, or loop. Serialize writing
|
|
363
|
-
nodes; never run
|
|
382
|
+
nodes; never run concurrent writers in the tree.
|
|
364
383
|
- Name a role and its engine in every node.
|
|
365
384
|
|
|
366
385
|
The harness bridge names the concrete mechanism for each of these.
|
|
@@ -370,11 +389,21 @@ The harness bridge names the concrete mechanism for each of these.
|
|
|
370
389
|
- Write the brief to a file under `tmp/`, named for its unit, before launching the unit, whatever
|
|
371
390
|
engine executes it. A brief composed only inside a launch argument cannot be corrected, resumed,
|
|
372
391
|
or re-run once that call ends.
|
|
392
|
+
- Write the unit's returned report in the SAME action that commits its code, never afterwards. A
|
|
393
|
+
commit message states what changed; the report states what the unit measured, what it decided, what
|
|
394
|
+
it could not close, and which of its own claims it flagged. An auditor's subject is the report,
|
|
395
|
+
so a report living only in the Orchestrator's context stops the next lane on arrival.
|
|
373
396
|
- Capture the unit's returned report to a file beside its brief under the same unit name, so a
|
|
374
397
|
unit's instruction and its outcome are one pair on disk.
|
|
375
398
|
- Amend a brief on re-run rather than restating it. A mid-campaign correction produces a successor
|
|
376
399
|
file recording what changed and why, and the original stays. A fix round's brief names the
|
|
377
400
|
findings it carries and where each came from.
|
|
401
|
+
- Read the copy the executor will open, not the one you wrote. A brief written in the orchestrator's
|
|
402
|
+
repository and staged into the subject's checkout so a `-C` invocation can reach it is a second
|
|
403
|
+
file, and staging can rewrite a path or drop a clause. The executor rules on what it opens, so a
|
|
404
|
+
staged copy whose facts are false stops a unit that was correctly briefed. Verify the staged path
|
|
405
|
+
and its load-bearing facts before launching, and stage into a scratch directory the subject tree
|
|
406
|
+
ignores rather than into the checkout root.
|
|
378
407
|
- Send a decision taken mid-campaign to every unit already in flight whose brief it invalidates. An
|
|
379
408
|
executor cannot see a change made after it was dispatched, so it writes the state its brief
|
|
380
409
|
described and the defect surfaces as its own.
|
|
@@ -383,8 +412,9 @@ The harness bridge names the concrete mechanism for each of these.
|
|
|
383
412
|
audit verdict, the exact executed script or instrument, and the acceptance evidence into
|
|
384
413
|
`.orkestrel/<package>/` as the unit is dispatched and as it returns, then sweep only the `tmp/`
|
|
385
414
|
launch copies. A capture claim's instrument is acceptance evidence; the frames may be swept once
|
|
386
|
-
the record transcribes them, because the committed instrument re-produces the film. **Bench
|
|
387
|
-
laws** rule
|
|
415
|
+
the record transcribes them, because the committed instrument re-produces the film. The **Bench
|
|
416
|
+
laws** rule "Ephemeral streams, durable records" owns journals and points here for everything
|
|
417
|
+
durable.
|
|
388
418
|
- Promote anything that must outlive the campaign into a durable artifact before the sweep — a
|
|
389
419
|
commit message, a guide, a rule, a retrospective. What is only in a swept file did not survive,
|
|
390
420
|
and a debrief that must quote the record verbatim has nothing to quote.
|
|
@@ -395,6 +425,8 @@ The harness bridge names the concrete mechanism for each of these.
|
|
|
395
425
|
|
|
396
426
|
- Put every campaign artifact in the **orchestrator's** repository under `.orkestrel/<package>/`,
|
|
397
427
|
named for the package the campaign is about.
|
|
428
|
+
- Give a campaign spanning several packages one shared `.orkestrel/campaign/` folder instead, so the
|
|
429
|
+
wave's plan, ledger, and verdicts sit together rather than split across the packages they rule on.
|
|
398
430
|
- Never put them in the package they are about. A published package's tree is its product.
|
|
399
431
|
- Claim nothing outside `.orkestrel/` unless Orkestrel scaffold mandates it. Everything Orkestrel
|
|
400
432
|
owns in a consumer's tree lives beneath that folder, so a convention can be settled there without
|
|
@@ -409,6 +441,34 @@ The harness bridge names the concrete mechanism for each of these.
|
|
|
409
441
|
- Prune the campaign folder in a commit at acceptance. The tree ends clean and the record stays
|
|
410
442
|
recoverable by hash. Git history is the archive; the working tree is the workspace.
|
|
411
443
|
|
|
444
|
+
### Before you prune
|
|
445
|
+
|
|
446
|
+
Pruning is deletion, so it needs the same evidence as any other destructive step. Run these
|
|
447
|
+
checks, and prune only when every one closes.
|
|
448
|
+
|
|
449
|
+
1. **Carry check.** List every item the folder leaves open — a defect, a measurement to re-take, a
|
|
450
|
+
deferred decision, a withdrawn claim, an unmet acceptance condition. Each ends the check with a
|
|
451
|
+
carrier: a commit that closed it, a live brief that owns it, or an explicit drop on the record.
|
|
452
|
+
An item with no carrier blocks the prune. Read the register files for this — the plan, the
|
|
453
|
+
readiness grade, the carry ledger, the triage — not every brief and report in the folder.
|
|
454
|
+
2. **Promotion check.** Rule on each remaining file by what it asserts. Product truth goes to the
|
|
455
|
+
guide, where the parity gate reaches it. A process law goes to the rule or contract file that
|
|
456
|
+
owns it. A decision goes to the commit message that made it, which is where it already is.
|
|
457
|
+
Everything else is process diary and prunes.
|
|
458
|
+
3. **Measurement check.** A number the guide carries out of the folder carries the date it was
|
|
459
|
+
taken. A measurement whose date the folder does not record is re-taken or dropped, never copied.
|
|
460
|
+
4. **Orientation check.** A cross-session orientation document — a handoff, a package-root narrative
|
|
461
|
+
file, a session log — is not a further category. It duplicates the guide for product truth and
|
|
462
|
+
the contract for process truth, it is gated by nothing, and it drifts. Dissolve it into the
|
|
463
|
+
artifacts that own it and delete it.
|
|
464
|
+
|
|
465
|
+
A section recording live state — adopter republish status, installed version tables, what a sibling
|
|
466
|
+
repository was doing that week — prunes with no promotion. It was stale when it was written, and
|
|
467
|
+
promoting it publishes the staleness.
|
|
468
|
+
|
|
469
|
+
Write the prune commit's message as the promotion record: what moved, and where each part landed.
|
|
470
|
+
That message is what makes the deletion recoverable in practice rather than only in principle.
|
|
471
|
+
|
|
412
472
|
### Required sections
|
|
413
473
|
|
|
414
474
|
- **Role and engine.** The named role and its explicit engine.
|
|
@@ -425,7 +485,15 @@ The harness bridge names the concrete mechanism for each of these.
|
|
|
425
485
|
shipping a guess the executor would have to invent an answer around.
|
|
426
486
|
- **Scope.** Owned files, shared and off-limits files, allowed tools, permission limits.
|
|
427
487
|
- **Execution.** State that the executor performs the assignment directly and spawns nothing. Put
|
|
428
|
-
it in every brief; an executor deep in a task does not re-read this contract.
|
|
488
|
+
it in every brief; an executor deep in a task does not re-read this contract. Write the sentence
|
|
489
|
+
for the reader the transport actually delivers it to, because "directly" names a different action
|
|
490
|
+
on each side of a bridge. To a native subagent or a bench engine reading the brief inside its own
|
|
491
|
+
CLI, it means do the work yourself. To a bridge driver, whose entire assignment is the launch, it
|
|
492
|
+
means carry the brief across unaltered and return the journal — the engine behind the CLI is not a
|
|
493
|
+
subagent the driver is spawning, and a driver told to work directly answers from its own engine
|
|
494
|
+
instead. That answer reads normal and its only tell is the missing journal, so pair this sentence
|
|
495
|
+
with **Bench laws** rule "Journal first" and refuse a bench result whose journal path and session
|
|
496
|
+
id are absent.
|
|
429
497
|
- **Output.** The exact distilled return shape. No process diary.
|
|
430
498
|
- **Deviation contract.** The required stop-and-report behaviour for writers, scoped. A conflict
|
|
431
499
|
with the primary objective stops the unit. An ancillary conflict — where a paragraph sits, which
|
|
@@ -441,9 +509,9 @@ The harness bridge names the concrete mechanism for each of these.
|
|
|
441
509
|
|
|
442
510
|
### Check the brief before you send it
|
|
443
511
|
|
|
444
|
-
Run these
|
|
445
|
-
|
|
446
|
-
|
|
512
|
+
Run these checks on every brief. Each is cheap, and skipping one costs a full dispatch cycle that
|
|
513
|
+
produces no work, because a unit given a brief that is internally consistent and factually wrong is
|
|
514
|
+
right to stop.
|
|
447
515
|
|
|
448
516
|
- Name the executor that will actually read the brief, and write its transport for that reader. The
|
|
449
517
|
same unit goes either to a bridge driver that invokes a bench CLI or to the bench engine already
|
|
@@ -459,14 +527,26 @@ wrong is right to stop.
|
|
|
459
527
|
- Take every measurement under the conditions the unit will run in, or have the unit take it. A
|
|
460
528
|
number measured in your environment and asserted as a criterion is unreachable when the
|
|
461
529
|
executor's sandbox denies what yours permitted, and no edit to the owned files can close it.
|
|
462
|
-
Where the unit is better placed to measure than you are,
|
|
463
|
-
fix the criterion to the property you want rather than to the number you saw.
|
|
530
|
+
Where the unit is better placed to measure than you are, have it take the measurement before doing
|
|
531
|
+
anything else and fix the criterion to the property you want rather than to the number you saw.
|
|
464
532
|
- Read the acceptance criteria against the off-limits list, line by line. Every criterion closes
|
|
465
533
|
using owned files alone. A criterion that needs an off-limits file gets that file granted or gets
|
|
466
534
|
struck. A file the change will break that appears in neither list is an unscoped file; grant it or
|
|
467
535
|
strike the criterion.
|
|
468
536
|
- Give a small unrelated obligation its own unit. Ride it along in a large one and its scope error
|
|
469
537
|
blocks the primary work, which is a whole unit lost to a detail.
|
|
538
|
+
- Never make a timing-sensitive or whole-suite gate result a criterion for a unit that runs inside its
|
|
539
|
+
own exec. The exec is load, so the unit cannot take that reading validly however carefully it
|
|
540
|
+
isolates, and a criterion it cannot close either stalls it or invites it to explain the failure away.
|
|
541
|
+
Name the gate as an observation the unit reports with both readings, and take the authoritative run
|
|
542
|
+
yourself after the unit exits, per **Writing concurrency**'s rule on re-running a timing or
|
|
543
|
+
resource failure alone. A scoped run over the unit's own
|
|
544
|
+
owned files stays a legitimate criterion.
|
|
545
|
+
- Order the criteria so an unreachable one cannot hide the others. A deviation contract fires on the
|
|
546
|
+
first criterion the unit cannot close and stops it there, so an unreachable criterion placed ahead
|
|
547
|
+
of a typecheck or a lint criterion skips that gate entirely and the unit ships a defect its own
|
|
548
|
+
brief would have caught. Put the cheap non-timing gates first, and never let a whole-suite result
|
|
549
|
+
gate a scoped one.
|
|
470
550
|
- Ask what the change will do to the facts you just measured. A criterion fixed to a measured set is
|
|
471
551
|
unreachable if the change alters that set, and a file marked off-limits is wrong if the change
|
|
472
552
|
writes to it. Measure the state the unit will finish in, not only the state it starts from.
|
|
@@ -487,17 +567,27 @@ wrong is right to stop.
|
|
|
487
567
|
sandbox that writes, so naming any of those stops the unit on arrival over a detail the allowlist
|
|
488
568
|
already settled. Where a read-only lane needs executed evidence, produce it separately and hand it
|
|
489
569
|
over: the Orchestrator supplies the evidence and the lane rules on it.
|
|
490
|
-
- Scope a
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
570
|
+
- Scope a change by the files its result makes **false**, not by the files that declare the thing
|
|
571
|
+
changing. Counting importers finds only part of that set. A test asserting the behaviour being
|
|
572
|
+
reversed, a fixture carrying a value being raised, a golden digest over generated output, and a
|
|
573
|
+
consumer script naming a union member being removed each go false without importing anything new,
|
|
574
|
+
and a brief scoped to the declaration alone sends the unit into a failure in a file it cannot edit.
|
|
575
|
+
The unit is then right to stop, and a whole dispatch cycle produces no work.
|
|
576
|
+
Ask of every criterion: what asserts the state this change ends? Own every answer, or strike the
|
|
577
|
+
criterion. Grant a behaviour and the tests that pin it together; grant a constant and every fixture
|
|
578
|
+
and expectation derived from it together.
|
|
495
579
|
|
|
496
580
|
### Carry every finding
|
|
497
581
|
|
|
498
582
|
After reconciling findings into briefs, walk the retained finding list once. Every finding names
|
|
499
583
|
the brief item that carries it. A finding with no carrier is a dropped finding.
|
|
500
584
|
|
|
585
|
+
Every finding names exactly one carrier. A further brief claiming the same finding is not redundancy
|
|
586
|
+
that costs a little duplicated work — it is a conflict the executor discovers mid-unit, between
|
|
587
|
+
documents you told it to obey, with no way to tell which you meant. It will either implement the row
|
|
588
|
+
twice or stop. Where a reconciliation table and a brief disagree about who owns a row, the brief the
|
|
589
|
+
executor opens wins, and you fix the other one before the second unit launches.
|
|
590
|
+
|
|
501
591
|
## Long-running commands
|
|
502
592
|
|
|
503
593
|
A bench exec, a Workflow, an install, a build, and a publish chain are one class of thing: a
|
|
@@ -510,6 +600,10 @@ command that outlives the turn that started it. Every law here binds all of them
|
|
|
510
600
|
completion re-invokes the session, and the cap kills a wedged command loudly instead of trusting
|
|
511
601
|
the agent to report its own failure. A wedged bridge is silent, and silence must never read as
|
|
512
602
|
progress.
|
|
603
|
+
- Never replicate git commits through a hosting provider's REST API when a file's content must ride
|
|
604
|
+
inside the tool-call JSON. The per-call read cap truncates it, and a lockfile is the file that
|
|
605
|
+
proves the point: it transits incomplete and the tree it lands in installs something else. Push
|
|
606
|
+
over git, or move the file another way.
|
|
513
607
|
- Write a multi-step chain to a script file and run the file. A chain composed inside one shell
|
|
514
608
|
argument cannot be read back, corrected, or re-run, and the record of what actually ran is the
|
|
515
609
|
argument text in a transcript rather than a file on disk.
|
|
@@ -560,8 +654,20 @@ nothing.
|
|
|
560
654
|
|
|
561
655
|
- Prove the previous run is gone before starting another. List the processes and read the list. A
|
|
562
656
|
second run started beside a live first one produces failures that read as the subject's — a
|
|
563
|
-
publish chain relaunched over a live one reports `EOTP` and `E403` that are its own
|
|
657
|
+
publish chain relaunched over a live one reports `EOTP` and `E403` that are its own processes
|
|
564
658
|
colliding, and both readings point at the registry.
|
|
659
|
+
- Never ask `pgrep -f` or `ps | grep` whether a command is running from a shell whose own command line
|
|
660
|
+
contains that command's text. The shell matches itself, so the answer is yes whatever the truth is.
|
|
661
|
+
This bites in separate places and each one fails differently:
|
|
662
|
+
- **A liveness watcher** loops forever, reporting "still running" and never delivering its completion
|
|
663
|
+
notification, because it always finds itself.
|
|
664
|
+
- **An elapsed-time reading** returns the watcher's age rather than the exec's, so the number falls
|
|
665
|
+
instead of rising and reads as a relaunch that never happened.
|
|
666
|
+
- **A pre-launch "is anything already running" check** reports a phantom concurrent writer, which is
|
|
667
|
+
the worst of them: the honest response to it is to kill something, and there is nothing there.
|
|
668
|
+
Read liveness from the recorded process id with `kill -0 <pid>`, or enumerate by executable name and
|
|
669
|
+
parent with `ps -eo pid,ppid,comm` and read the rows. Both are immune; a pattern over the full command
|
|
670
|
+
line is not.
|
|
565
671
|
- Kill by process id, never by pattern. `pkill -f` matches the relaunch that is already starting, so
|
|
566
672
|
the pattern that cleans up the old run kills the new one and the cleanup reads as a launch
|
|
567
673
|
failure.
|
|
@@ -586,7 +692,7 @@ This section adds what is true of a bench and nothing else.
|
|
|
586
692
|
|
|
587
693
|
Every bridge verifies before running that its CLI resolves and its bench is authenticated, and stops
|
|
588
694
|
with a deviation report naming the fallback when either fails. The role file owns the exact
|
|
589
|
-
invocation, flags, paths, probe, and recovery ladder; these
|
|
695
|
+
invocation, flags, paths, probe, and recovery ladder; these laws bind every bench regardless of
|
|
590
696
|
transport.
|
|
591
697
|
|
|
592
698
|
1. **Transport by work class.** Use an MCP transport only for a short interactive exchange — one
|
|
@@ -605,7 +711,41 @@ transport.
|
|
|
605
711
|
3. **Tracked, never loose.** Register every bench unit in the session task registry at launch with
|
|
606
712
|
its subject, journal path, and session id, and complete it there at acceptance. "What is
|
|
607
713
|
running" always has a first-class answer instead of a recollection of a command.
|
|
608
|
-
4. **
|
|
714
|
+
4. **A bench sandbox spawns a child and denies that child's child.** Under `workspace-write` a bench
|
|
715
|
+
exec runs a test suite and spawns children normally, and every operation one level deeper fails:
|
|
716
|
+
a grandchild process is denied `EPERM`, and a nested `npm install` is denied the same way. So a
|
|
717
|
+
proof needing a process tree, a tree-kill, a detached group, or an installed package cannot be
|
|
718
|
+
produced inside a bench unit at all — however carefully that unit isolates. Name the limit in the
|
|
719
|
+
brief before dispatch, tell the unit to record such a proof as an observation naming the exact
|
|
720
|
+
settling command, and take that proof yourself on the host. Never let a unit substitute the
|
|
721
|
+
reachable half: linking a packed tarball is not installing it, and a gate written to catch an
|
|
722
|
+
install failure that only ever links cannot see the defect it exists for.
|
|
723
|
+
Not every symptom names the sandbox. A nested process and a nested install fail `EPERM`, which
|
|
724
|
+
reads as a denial; a nested `git` invocation instead reports **"not a git repository"** while the
|
|
725
|
+
unit's own `git status` succeeds a moment earlier. That one reads as a broken checkout, and a unit
|
|
726
|
+
acting on it will go looking for damage that is not there. Tell a unit which of its tools shell out
|
|
727
|
+
one level down — a scaffolding CLI that probes git, a formatter that spawns a worker — so it
|
|
728
|
+
recognises the shape instead of diagnosing the tree.
|
|
729
|
+
The child a bench does create has unreliable stdio, and that failure wears a worse disguise than a
|
|
730
|
+
denial. A Node process spawned by a bench unit's own Node process has been measured both buffering
|
|
731
|
+
its pipe until EOF and publishing nothing at all, so no workaround built on either reading is
|
|
732
|
+
dependable. Any subject whose behaviour lives in a child's pipes is therefore unmeasurable inside a
|
|
733
|
+
bench: a stage driving a language server, a protocol fixture, a built entry driven as a spawned
|
|
734
|
+
child. It fails as a **false green**. The stage never arms, the boot inspection times out, and that
|
|
735
|
+
timeout produces the same rejection a genuine stage timeout produces, so a test asserting on the
|
|
736
|
+
message passes inside the bench while the host's gate reports the honest red — and neither run
|
|
737
|
+
reports why they disagree. Route such a subject to the harness's native implementer, or keep it on
|
|
738
|
+
the bench and supply every executed measurement yourself. Never dispatch it to a bench and expect
|
|
739
|
+
it to prove its own work. The shape to recognise is a child that exits 0 almost immediately, a
|
|
740
|
+
request to it that never resolves, and a stack landing in the spawning code's exit handler.
|
|
741
|
+
**When a bench sandbox denies a loopback listener, `listen` fails `EPERM` on every address.** A
|
|
742
|
+
subject needing a real local server is unmeasurable inside the bench. Name the limit in the brief
|
|
743
|
+
before dispatch. Have the unit report the reading as an observation naming the exact command.
|
|
744
|
+
Take the proof on the host.
|
|
745
|
+
**When a brief assigns a bench unit a path outside the obvious source tree, name the write limit
|
|
746
|
+
in the brief.** If the sandbox rejects the patch, the unit stops and reports the rejection. Never
|
|
747
|
+
find another write mechanism.
|
|
748
|
+
5. **Ephemeral streams, durable records.** A journal proves a bench is alive and recovers an
|
|
609
749
|
interrupted session. Keep journals under `tmp/`, never commit them, and sweep them at acceptance
|
|
610
750
|
after the final gate evidence is recorded. Durable retention — brief, distillate, verdict,
|
|
611
751
|
instrument, acceptance evidence — is owned by **Dispatch anatomy**; this rule owns only the
|
|
@@ -634,6 +774,34 @@ A publish chain is a long-running command, so every law under **Long-running com
|
|
|
634
774
|
write the chain to a file, detach it with `setsid`, and confirm the previous one is dead before
|
|
635
775
|
starting another.
|
|
636
776
|
|
|
777
|
+
### Fixing a dependency before it publishes
|
|
778
|
+
|
|
779
|
+
A defect a consumer meets sometimes lives in a package the consumer only has from the registry.
|
|
780
|
+
Waiting for that package to publish before the consumer can prove its own fix serializes releases
|
|
781
|
+
that could have been one. Do not wait, and do not work around it in the consumer.
|
|
782
|
+
|
|
783
|
+
Build the dependency from source, pack it, and **install the tarball** into the consumer.
|
|
784
|
+
|
|
785
|
+
- **Install it, never link it.** A link resolves through a directory and skips the packing, the
|
|
786
|
+
`files` list, and the exports map — which is most of what a distribution proof exists to check. A
|
|
787
|
+
gate written to catch an install failure that only ever linked cannot see the defect it exists for.
|
|
788
|
+
- **Write the swap to a script and run the file**, so the build, the pack, and the install are one
|
|
789
|
+
artifact the next run reuses rather than a command nobody can read back.
|
|
790
|
+
- **Record the range you replaced** in the same step that replaces it. A consumer sitting on an
|
|
791
|
+
unpublished tarball with no record of what it had is a consumer nobody can restore.
|
|
792
|
+
- **Rebuild and repack whenever the source moves.** A stale tarball is the same defect as a stale
|
|
793
|
+
`dist/`, and it is worse for being invisible: the consumer's gates go green against a fix that no
|
|
794
|
+
longer exists in the dependency's tree.
|
|
795
|
+
- **Restore the registry copy before any gate that must prove the published artifact, and before
|
|
796
|
+
publishing anything.** A distribution proof run against a local tarball proves the local tarball.
|
|
797
|
+
The release still follows layer order: the dependency publishes first, then the consumer re-pins to
|
|
798
|
+
the version the registry now serves and re-runs its gates against that.
|
|
799
|
+
- **Keep the tarballs out of the tree.** They belong under `tmp/`, they are swept at acceptance, and
|
|
800
|
+
they are never committed.
|
|
801
|
+
|
|
802
|
+
The tarball is a head start, not a shortcut. It lets the consumer's work proceed and its proofs run
|
|
803
|
+
against the real packed artifact while the dependency's own release is still being prepared.
|
|
804
|
+
|
|
637
805
|
### What a bump obliges
|
|
638
806
|
|
|
639
807
|
A runtime dependency and a development dependency have different blast radius, and confusing them
|
|
@@ -654,8 +822,8 @@ either publishes packages nobody needed to publish or leaves a consumer pinned t
|
|
|
654
822
|
|
|
655
823
|
Every package is `0.0.x`, where a caret pins one exact release. A dependent therefore sees a new
|
|
656
824
|
version only after it re-pins and republishes, so the fleet publishes in topological layer order
|
|
657
|
-
derived from runtime `dependencies` alone. Layers exist for a reason a flat pass cannot fix:
|
|
658
|
-
ranges that disagree install
|
|
825
|
+
derived from runtime `dependencies` alone. Layers exist for a reason a flat pass cannot fix:
|
|
826
|
+
ranges that disagree install duplicate copies of the same package, and the compiler reads them as
|
|
659
827
|
distinct types.
|
|
660
828
|
|
|
661
829
|
Read the order from the catalog table in `.claude/agents/orkestrel.md`, which `scaffold catalog`
|
|
@@ -696,14 +864,14 @@ once per round with one procedure, publish each layer in one window, and only th
|
|
|
696
864
|
- The visit, in order: re-pin the target's `@orkestrel/scaffold` devDependency and install, so the
|
|
697
865
|
overwrite runs the current vendored host; `scaffold overwrite`; force-verify every `@orkestrel`
|
|
698
866
|
range against a registry sweep taken after the previous layer published; full install; mutating
|
|
699
|
-
`format` to converge generated writes; the
|
|
867
|
+
`format` to converge generated writes; the quality gates; the material-dist comparison against the
|
|
700
868
|
published tarball.
|
|
701
869
|
- Bump on either trigger: the rebuilt dist differs materially from the published tarball, or the
|
|
702
870
|
final runtime dependency set differs from the published packument. Test the final set against the
|
|
703
871
|
packument, never "did my step move a pin" — overwrite's `declare` re-pins before any later check,
|
|
704
872
|
so the step-local reading reports nothing moved while the manifest surface did. A re-pinned
|
|
705
|
-
runtime range is published surface: without the bump a consumer installs
|
|
706
|
-
dependency.
|
|
873
|
+
runtime range is published surface: without the bump a consumer installs duplicate copies of the
|
|
874
|
+
moved dependency.
|
|
707
875
|
- A dist built before the version bump is the release artifact; the bump edits no emitted byte.
|
|
708
876
|
- Refresh the registry evidence between layers and derive each round's pins from it. A pin can only
|
|
709
877
|
name a version the registry already serves, so a dependency shipping in the same window keeps the
|
|
@@ -713,6 +881,9 @@ once per round with one procedure, publish each layer in one window, and only th
|
|
|
713
881
|
|
|
714
882
|
### Preparing
|
|
715
883
|
|
|
884
|
+
0. **An unpublished package's first version is `0.0.1`.** Do not bump it before that first publish.
|
|
885
|
+
The registry has nothing to serve, so there is no version to move away from, and bumping produces
|
|
886
|
+
a package whose history starts at a number nothing explains.
|
|
716
887
|
1. **Bump from what the registry serves, not from the local manifest.** A repository's `version`
|
|
717
888
|
can sit a release behind what was published from another checkout, and bumping that produces a
|
|
718
889
|
version the registry already holds, which fails on upload after the whole gate chain has run.
|
|
@@ -750,16 +921,20 @@ flag is what stops the gate chain running a second time inside the five minutes.
|
|
|
750
921
|
the layer, prove the gates, surface the exact `npm publish` command, and the operator runs it in a
|
|
751
922
|
real terminal. Everything before and after the upload — bumps, re-pins, gates, registry reads —
|
|
752
923
|
stays with the Orchestrator. The fifo stdin law still binds on that host.
|
|
753
|
-
- Expect
|
|
754
|
-
authorizes the publish and opens the five-minute window. Tell the user
|
|
755
|
-
second link reads as the first having failed.
|
|
924
|
+
- Expect an approval for each stage. `npmjs.com/login/cli/<id>` authenticates the session;
|
|
925
|
+
`npmjs.com/auth/cli/<id>` authorizes the publish and opens the five-minute window. Tell the user
|
|
926
|
+
both are coming, or the second link reads as the first having failed.
|
|
756
927
|
- Confirm authentication with `npm whoami`, never with an exit code. The legacy fallthrough exits
|
|
757
928
|
zero.
|
|
758
929
|
- Re-probe `whoami` immediately before opening the window. A stored credential expires mid-session,
|
|
759
930
|
so a session-start answer does not hold.
|
|
760
931
|
- Surface each approval URL the moment it appears in the log, and take the **last** one in log order.
|
|
761
932
|
npm mints a new URL whenever an attempt restarts, and the log accumulates every one, so a URL
|
|
762
|
-
chosen by sorting rather than by position is already dead when the user opens it.
|
|
933
|
+
chosen by sorting rather than by position is already dead when the user opens it. Read it out of
|
|
934
|
+
the journal in the foreground and surface it before arming any watcher: a watcher-based relay can
|
|
935
|
+
fail silently, and its silence is indistinguishable from a chain that has not reached the URL yet.
|
|
936
|
+
Relay the URL as plain text. A decorated link did not render for the operator, who then had nothing
|
|
937
|
+
to click while the window ran down.
|
|
763
938
|
- Re-read the log before treating an approval as failed. The chain is usually still alive on a newer
|
|
764
939
|
URL, so surface that one rather than relaunching.
|
|
765
940
|
- A `404` on an approval URL usually means the publish already succeeded and consumed it. Read the
|
|
@@ -782,13 +957,14 @@ flag is what stops the gate chain running a second time inside the five minutes.
|
|
|
782
957
|
- **Never retry a publish that is still waiting for its authorization.** Each `npm publish` attempt
|
|
783
958
|
mints a new `authId` and invalidates the previous one, so a retry loop makes the URL a moving
|
|
784
959
|
target the user cannot approve in time. The abandoned poll then reports
|
|
785
|
-
`403 Forbidden - GET /-/v1/done?authId=…`, which reads as a permissions problem and is
|
|
786
|
-
colliding. Publish the first package of a layer with exactly
|
|
960
|
+
`403 Forbidden - GET /-/v1/done?authId=…`, which reads as a permissions problem and is the
|
|
961
|
+
abandoned attempt colliding with the live one. Publish the first package of a layer with exactly
|
|
962
|
+
one attempt.
|
|
787
963
|
- Retry only an upload that failed **inside** an already-open window. `EOTP` there is intermittent
|
|
788
964
|
contention rather than the window closing: retry about three times, and retry a failed set once the
|
|
789
965
|
layer ends. Packages have landed on the third attempt and on a later pass with no new approval.
|
|
790
|
-
These are
|
|
791
|
-
|
|
966
|
+
These are different failures wearing similar codes; a retry fixes in-window contention and causes
|
|
967
|
+
the moving approval target.
|
|
792
968
|
- Expect a large layer to outlast one window. Size batches to what uploads in five minutes and tell
|
|
793
969
|
the user how many approvals to expect, rather than discovering it mid-run.
|
|
794
970
|
- Read the result from the registry, not from an exit code: a piped `npm publish` reports the exit
|
|
@@ -811,7 +987,7 @@ flag is what stops the gate chain running a second time inside the five minutes.
|
|
|
811
987
|
- Substitute an engine only when the same session records the bench dark — CLI missing, auth
|
|
812
988
|
expired, model unavailable. Name the fallback in the plan; never improvise it silently. The
|
|
813
989
|
tedious-work ladder is the only pre-approved substitution, and each step down it is still recorded.
|
|
814
|
-
- Never run the
|
|
990
|
+
- Never run the lanes on different briefs, and never show either one the other's answer before
|
|
815
991
|
both have returned.
|
|
816
992
|
- Never run a lane inline in the Orchestrator's context, and never drop a lane because its default
|
|
817
993
|
engine is unavailable. Substitute the engine, keep the lane.
|
|
@@ -47,7 +47,7 @@ not to hand-roll before building one.
|
|
|
47
47
|
|
|
48
48
|
---
|
|
49
49
|
|
|
50
|
-
##
|
|
50
|
+
## The mandate
|
|
51
51
|
|
|
52
52
|
1. **Design direction** — take a point of view rooted in the _subject_ (audience, job-to-be-done, vernacular). Take one justified aesthetic risk, in one place.
|
|
53
53
|
2. **Bootstrap execution** — components and utilities first; custom CSS only when the system cannot express the need; paint through `--bs-*` so light and dark both survive.
|
|
@@ -68,7 +68,7 @@ setting a direction. The loop:
|
|
|
68
68
|
2. **Plan** — build a token system: **color** (4–6 named values), **type** (display / body / utility), **layout** (prose plus ASCII if useful), **signature** (one memorable element).
|
|
69
69
|
3. **Critique the plan** — if swapping the logo would make it "any SaaS", revise. Avoid the clustered AI defaults unless the brief asks for them: cream + #F4F1EA + serif + terracotta; near-black + acid green or vermilion; broadsheet hairlines, zero radius, dense columns. The brief wins when it pins a direction.
|
|
70
70
|
4. **Build** — compose Bootstrap components and utilities; map the plan's tokens onto theme variables or a thin skin, with no scattered one-off hex ([bootstrap-reference.md](references/bootstrap-reference.md) → Theming & design tokens). Watch selector specificity: a utility and a custom rule that cancel each other show up as padding and margin bugs.
|
|
71
|
-
5. **Critique the render** — remove one accessory. Check contrast, focus, `prefers-reduced-motion`, mobile, and
|
|
71
|
+
5. **Critique the render** — remove one accessory. Check contrast, focus, `prefers-reduced-motion`, mobile, and every data state. Critique what rendered, not the markup.
|
|
72
72
|
|
|
73
73
|
Brainstorm privately; show a direction only once it satisfies the brief and the quality floor
|
|
74
74
|
([frontend-design.md](references/frontend-design.md) → Process).
|
|
@@ -79,13 +79,13 @@ both viewports and both themes plus an accessibility snapshot; source only corro
|
|
|
79
79
|
mechanism. For a full review-round campaign built on that evidence, use the
|
|
80
80
|
`orkestrel-polish-surface` skill instead of improvising one here.
|
|
81
81
|
|
|
82
|
-
**Mechanical proof.**
|
|
82
|
+
**Mechanical proof.** These instruments settle what a capture cannot. Pair each one with a negative
|
|
83
83
|
control drawn from outside the population it covers, and treat an instrument whose control passes as
|
|
84
84
|
broken; `.claude/rules/quality.md` owns this law where it is present:
|
|
85
85
|
|
|
86
86
|
- **Contrast, composited.** Read every pairing through a reader that composites the painted layers, in both themes ([bootstrap-reference.md](references/bootstrap-reference.md) → Measuring the bars).
|
|
87
87
|
- **Authored classes against the shipped cascade.** Extract every class authored in the templates and components, and fail the run on one that has no rule in the compiled CSS the page loads. Assert a population floor so an extractor that quietly matched nothing cannot pass, and control it with a class you know is absent.
|
|
88
|
-
- **One glyph, one meaning.** Register each status glyph against the meaning it carries. No meaning takes
|
|
88
|
+
- **One glyph, one meaning.** Register each status glyph against the meaning it carries. No meaning takes more than one glyph, no glyph serves more than one meaning, and every registered glyph resolves in the icon set actually shipped.
|
|
89
89
|
|
|
90
90
|
---
|
|
91
91
|
|
|
@@ -105,7 +105,7 @@ the need.
|
|
|
105
105
|
|
|
106
106
|
1. **The component's own classes, in its documented structure.** Use the right elements, nesting, class names, and required ARIA: a card is `.card` wrapping `.card-body` wrapping `.card-title`, not a `div` with borrowed padding. Variants, states, color modes, and responsive behavior all hang off that structure.
|
|
107
107
|
2. **Bootstrap utilities, for refinement.** Spacing, flex, display, sizing, text, borders, color. Compose utilities rather than reaching past them, and use only classes that exist in [utilities.md](references/utilities.md).
|
|
108
|
-
3. **Bootstrap's own extension points.** Component `--bs-{component}-*` variables and the utilities API, when a real gap remains after
|
|
108
|
+
3. **Bootstrap's own extension points.** Component `--bs-{component}-*` variables and the utilities API, when a real gap remains after the component-class and utility tiers.
|
|
109
109
|
4. **Anything beyond Bootstrap's conventions is the developer's call, not yours.** Stop at rung 3 and say plainly what rung 4 would require.
|
|
110
110
|
|
|
111
111
|
Never open at rung 4. Specifically, do not reach first for:
|
|
@@ -162,7 +162,7 @@ A status mark with **no text** is an icon glyph, never a `badge`
|
|
|
162
162
|
|
|
163
163
|
### States & feedback
|
|
164
164
|
|
|
165
|
-
- **Every data surface ships
|
|
165
|
+
- **Every data surface ships these states:** ideal, empty, loading, partial, error. It is not done until every one exists. Loading thresholds, empty and error specifics, and the channel matrix for toast / inline alert / banner / modal: [bootstrap-reference.md](references/bootstrap-reference.md) → The data states, Feedback discipline.
|
|
166
166
|
- **Build a blocking decision on the native `<dialog>`.** `showModal()` brings focus containment, Esc, an inert background, and top-layer stacking from the platform, with no instance to construct and none to leak on unmount. Dress it with Bootstrap chrome inside ([components.md](references/components.md) → Modal). Reach for `.modal` and its JS only when the project already drives its dialogs that way.
|
|
167
167
|
- **Destructive actions:** prefer undoable over interrupting. Ladder and confirmation contracts: [bootstrap-reference.md](references/bootstrap-reference.md) → Destructive actions.
|
|
168
168
|
|
|
@@ -222,7 +222,7 @@ Progress:
|
|
|
222
222
|
- [ ] Styling ladder held: no `style` attribute, no `<style>` block, no custom rule doing a utility's job
|
|
223
223
|
- [ ] Plan tokens mapped to theme / --bs-* (no hex scatter); light and dark both shipped where both are offered
|
|
224
224
|
- [ ] Copy in user language, verbs consistent, empty/error/loading text useful
|
|
225
|
-
- [ ]
|
|
225
|
+
- [ ] Every state per data surface: ideal / empty / loading / partial / error
|
|
226
226
|
- [ ] Contrast composited and measured in both themes: ≥ 4.5:1 information-bearing (small included), ≥ 3:1 marks and state chrome; meaning not color-alone
|
|
227
227
|
- [ ] Tiers held: `-emphasis` for information-bearing status, solid buttons for real actions, no tone class inside a filled surface
|
|
228
228
|
- [ ] Every treatment resolved in the shipped cascade, not from docs memory
|