Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions .claude/rules/48-parallel-execution.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,29 @@ expected wall-clock saved > setup + review + conflict + resource-contention +

If the answer isn't clearly positive, don't parallelize.

### The cost terms are WALL-CLOCK, and analytical fan-out prices differently

Every term above is denominated in **wall-clock time** — and this decision test was written for the
`/dispatch` **worktree-lane** mechanism (multi-item, isolation-first). Applied to a read-only
*analytical* fan-out (a `Workflow`/`Explore` spawn that writes nothing), the terms price much
smaller: no worktree `setup`, no `conflict` (nothing written), no `resource` contention when it
overlaps the serial emulator/simulator run or precedes the exclusive resource being touched. The
residual real costs are the orchestrator's **review/reconcile time** on the findings and the
**failure** risk of the fan-out infrastructure itself — small but not zero, so the honest verdict
for overlapping/pre-write analytical fan-out is **net-positive in expectation** even at N=1, not
free. Under ultracode, the token-cost *objection* (a consideration external to this test) is
removed by the standing directive, which is what makes that expectation clearly positive; the
supporting evidence for the pre-write "how could this false-green?" pass is the #138 WI-6 incident,
where the post-write Codex block caught 3 false-green defects — a pass that *plausibly*
(hindsight-assessed; instrumented going forward, see rule 57) front-loads that class. **None of
this relaxes the hard rules below** (author/auditor separation, one-writer-per-file, sim isolation)
or licenses fan-out that contends the exclusive resource.

The within-WI analytical fan-out this unlocks — even for a single work item — is specified in
**`.claude/rules/57-ultracode-within-wi-fanout.md`**. This rule (48) remains the *when parallelism
is legal*; rule 55 is the *`/dispatch` multi-item mechanism*; rule 57 is the *within-WI analytical
fan-out under ultracode*.

## Hard rules (non-negotiable)

1. **Author/auditor separation**: the agent that writes a plan, code, or PR is never the agent that audits it. (cc-suite running Codex as a separate `codex exec` process satisfies this by accident; preserve the boundary explicitly.)
Expand Down
5 changes: 4 additions & 1 deletion .claude/rules/52-test-sim-isolation.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,10 @@ The Android lane has the same ghost-class shapes as iOS, with Android tools:
flags only a wedged `am instrument` or a detached `adb … logcat` capture.
- **Emulator contention = simulator contention.** Driving the SAME emulator
(`adb` / `am instrument` / screenshots) while an instrumentation run is in
flight wedges it. Serialize, or use a second emulator (AVD).
flight wedges it. Serialize, or use a second emulator (AVD): boot a 2nd AVD and
route each run to a distinct device via `ANDROID_SERIAL` (validated + exported
by `scripts/run-android-tests.sh`; leased per-serial by `sim-lease.sh acquire
android`) — never two runs on one emulator serial.
- **Always run the Android gate through `scripts/run-android-tests.sh`** (the
Android `run-tests.sh`): hard wall-clock timeout, exact-pid wait (rule 49),
kills the process tree + Gradle daemon on timeout, prints one
Expand Down
38 changes: 25 additions & 13 deletions .claude/rules/55-lane-dispatch.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,10 @@ dispatch → sim leases → id-reserve → tracker-write
integration tail (merge/tag/teardown), BEFORE Gate-5 — that is what lets
the next batch's Gate-3 lanes overlap a Gate-5 pass (rule 48 matrix).
- **Sim leases** (via `scripts/sim-lease.sh`): purpose-tagged (`test` ≤2,
`verify` 1); a UDID never serves both purposes (rule 52 mutual exclusion
mechanized). Every lane exit path releases its lease; a batch ends with
zero held.
`verify` 1, `android` ≤ online-emulator count — an Android lane leases an
`emulator-NNNN` serial); a device never serves two purposes (rule 52
mutual exclusion mechanized). Every lane exit path releases its lease; a
batch ends with zero held.
- **`id-reserve`**: all new row IDs are minted via `scripts/reserve-id.sh`
BEFORE `tracker-write` is acquired; calling reserve-id while holding
tracker-write is forbidden.
Expand Down Expand Up @@ -237,13 +238,18 @@ the interest of brevity.
```
2. The rule-48 six-field contract instantiated: objective (the one work
unit), inputs (Spec block or bug micro-spec: repro + expected-vs-actual +
regression-test name; exact file list; leased `TEST_UDID`), allowed
writes (the `writes:` prefixes), forbidden (the orchestrator surfaces
above + "no Bash file edits" + no paths outside the write-set), output
format (the HANDOFF), stop condition (ready-for-integration or blocked).
3. The test-gate command shape: `TEST_UDID=<udid> scripts/run-tests.sh
<targeted-suite>` (Android: `scripts/run-android-tests.sh`) — wrappers
only (rule 52), targeted suites only (never the >20-min full suite).
regression-test name; exact file list; the leased device — `TEST_UDID`
for an iOS/`shared` lane, `ANDROID_SERIAL=<emulator-NNNN>` for an
Android lane), allowed writes (the `writes:` prefixes), forbidden (the
orchestrator surfaces above + "no Bash file edits" + no paths outside
the write-set), output format (the HANDOFF), stop condition
(ready-for-integration or blocked).
3. The test-gate command shape: iOS/`shared` → `TEST_UDID=<udid>
scripts/run-tests.sh <targeted-suite>`; Android →
`ANDROID_SERIAL=<emulator-NNNN> ANDROID_CMD="…"
scripts/run-android-tests.sh` (the runner validates + re-exports the
serial) — wrappers only (rule 52), targeted suites only (never the
>20-min full suite).
4. The in-lane Gate-4 instruction: `scripts/run-codex.sh` (rule 53) is the
PRIMARY rung — **probed 2026-07-09 (twice, incl. with `Skill` in the
agent frontmatter): custom agents get NO Skill tool in this harness, so
Expand All @@ -257,9 +263,15 @@ the interest of brevity.
isn't worth it (rule 48 decision test).
- **Memory pressure**: width 2 → 1 (`vm_stat` free-pages check before
opening the second lane).
- **Android**: `android-app`/`android-spike` items dispatch at width 1 only
until `run-android-tests.sh` gains `ANDROID_SERIAL` routing (named
follow-up; the emulator is a single shared device today — rule 52 Cause D).
- **Android**: `run-android-tests.sh` now honors `ANDROID_SERIAL` (validate +
export + ambiguity guard) and `sim-lease.sh acquire android` leases an online
emulator serial, so an `android-app`/`android-spike` lane CAN be routed to a
specific emulator. Width is still **1 in practice** because only one AVD is
booted by default — the `android` lease capacity = the number of online
emulators. To run width 2, boot a **second AVD** (`avdmanager create avd …`;
`emulator -avd vreader-test-2` → `emulator-5556`), then each lane leases a
distinct serial and passes it as `ANDROID_SERIAL` (rule 52 Cause D — never two
runs on one emulator).
- **Width gate weighs LANE TYPES, not lane count** (M-SHAKEDOWN finding): the
4GB `vm_stat` headroom check applies per SWIFT lane (xcodebuild + booted
sim ≈ real load); a bash-only lane (hooks/scripts work) adds near-zero
Expand Down
111 changes: 111 additions & 0 deletions .claude/rules/57-ultracode-within-wi-fanout.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
# 57 — Ultracode Within-WI Fan-out

Binding when **ultracode is ON** (a system-reminder confirms it). This rule closes the gap rule 48
and rule 55 leave open: they govern the `/dispatch` **worktree-lane** mechanism (multi-item,
isolation-first, wall-clock-denominated), and they correctly degrade a single work item (N=1) to the
inline flow. Neither says anything about fanning out the **analytical** work *within* one WI — the
reads, the edge-case brainstorm, the audit. Ultracode's standing directive ("use the Workflow tool
on every substantive task; token cost is not a constraint") already makes that within-WI fan-out the
default; this rule resolves the rulebook ambiguity (rule 48's decision test read as if it priced
analytical spawns like worktree lanes) and specifies the mechanism.

Origin: feature #138 WI-6 (2026-07-23), honestly decomposed (the first draft of this rule
over-claimed; a 5-angle adversarial grill of the rationale corrected it). A single acceptance-test
WI ran almost entirely inline. The post-write Gate-4 audits then surfaced three false-green defects,
and the three had **different** root causes: one had been *surfaced by the deep 5-lens pass and
mis-triaged in the solo reconcile step* (stated targets logged but only looser ceilings asserted);
one was a genuine lens-scope miss (a synthetic-fallback that hollowed the real-book acceptance); one
was implementation-emergent (a short-circuit only visible in the written code). The durable lessons:
(a) run the deep AND broad audits in parallel and let the block gate (the broad pass caught all
three); (b) the deep pass's triage/reconcile step needs hardening, not just more layers — see
"Follow-ups" below; (c) a **pre-write** "how could this false-green?" pass *plausibly* front-loads
the requirement-level defect classes (the first two), though this is a **hypothesis, hindsight-
assessed** — it is justified below on cost asymmetry, not on a claimed counterfactual save.

## The principle

**Fan out every analytical step that does NOT hold the exclusive resource.** The binding serial
resource (the single emulator/simulator — rule 52; one Codex/test session — rule 48) caps
*verification* parallelism, not *analysis* parallelism. Analytical fan-out either (a) runs
*concurrently* with the serial critical section (the emulator run) — genuinely ~zero added
wall-clock — or (b) *precedes* the exclusive resource being touched: **serial, but small relative to
the audit-block cycle it hedges** (a Gate-4 block costs a fix + connected re-run + another audit
round). With ultracode removing the token-cost objection, the residual costs are the ones to manage
honestly: the orchestrator's reconcile tax on fan-out findings, context dilution from each
synthesis, and occasional fan-out infrastructure failure (a workflow died on a schema retry-cap in
the origin session). So the default is **net-positive in expectation, not free**: on infrastructure
failure, retry once then degrade to inline analysis with a note; keep syntheses summary-sized; the
reconcile stays a deliberate solo step (see below).

## The three sanctioned within-WI fan-outs

Run these via the `Workflow` tool (or parallel read-only `Agent`/`Explore` spawns). They are the
default for any substantive inline WI under ultracode — a bug fix (`/fix`, `/fix-issue`) or a
feature WI (`/feature-workflow`).

1. **Parallel context sweep — BEFORE the write.** Instead of sequential Reads to gather the files,
APIs, prior art, and constraints a WI needs, fan out read-only `Explore` agents to gather them at
once and return a structured map. Replaces serial reads; strictly faster. (Per rule 48's
context-absorption warning, treat the map as orientation — reconfirm load-bearing details
first-hand before editing.)

2. **Pre-write adversarial brainstorm — BEFORE the write.** Before authoring the RED test / the fix,
fan out adversarial lenses over the *intended* change: "how could this test pass while proving
nothing?", "what edge cases (empty/nil/max/Unicode-CJK/RTL/concurrent/failure-injection) must it
cover?", "what invariant between subsystems could this break?" Fold the findings into the
test/impl you then write **once, solo**. Justification: cost asymmetry — the pass is minutes and
sits before any exclusive-resource work; the Gate-4 block cycle it hedges is tens of minutes.
Whether it actually front-loads block-class defects is **instrumented, not assumed**: when you run
it, record in the WI's notes whether its findings intersect the subsequent Gate-4 findings —
sustained zero intersection over ~5 WIs retires this fan-out to optional.

3. **Deep + broad audit — AFTER the write, before merge, in PARALLEL.** Run the per-claim
adversarial fan-out AND the broad Codex audit (`scripts/run-codex.sh`) concurrently. The evidence
(n=2: #131 plan gate, #138 WI-6) is that the broad pass catches classes the deep pass misses —
whether that is true complementarity or a deep-triage defect, the remedy is the same: run both,
and when they disagree, **trust the block on cost-asymmetry grounds** (a false block costs one
bounded re-check; a false ship ships a hollow gate). Reconcile deliberately: a deep-pass finding
you decide to accept/deflect rather than fix is exactly the shape that produced a Codex block in
the origin session — record the reason in the audit artifact so the choice is reviewable.

## What to keep SOLO (do NOT fan out)

- **The write itself.** One coherent file/change has ONE author (rule 48 hard rule 3 —
one-writer-per-file). Fanning out the authoring produces merge conflict, not speed.
- **The reconcile judgment.** Deciding which audit findings to fix vs accept is one judgment call,
made by the main agent that owns the change — but it is the step that failed in the origin
session, so it carries its own discipline: every accepted/deflected Medium-or-above finding gets a
one-line written rationale in the audit artifact (reviewable, not silent).
- **Anything that would CONTEND the exclusive resource.** Never fan out "run the connected test" onto
the same emulator/simulator (rule 52 — contention wedges the run into a ghost). Verification stays
serial on one device; only a second leased device unlocks parallel runs (rule 55 Android tier +
`scripts/sim-lease.sh`).

## Scope boundaries

- **Binds the INLINE flows and the ORCHESTRATOR, not restricted-tool lanes.** A `/dispatch`
`implementer` lane is a subagent with no `Agent`/Workflow tool and cannot fan out (Workflow nesting
is one level). So this rule binds the inline authoring flows (`/feature-workflow`, `/fix`,
`/fix-issue`) and the dispatch *orchestrator's* own analytical steps (e.g., the deep+broad plan
audit before spawning lanes) — never the lane interior. The lane's analytical work is front-loaded
by the orchestrator before dispatch.
- **Ultracode-gated.** When ultracode is OFF, the rule-48 decision test governs (the token-cost term
is back in play, so a marginal fan-out may not clear the bar). When ON, treat these three fan-outs
as the default and note any WI where you *skipped* one and why.

## Follow-ups (named, so they don't silently drop)

- **Mechanize the logged-vs-asserted check**: a test that logs `target_met(<X>)` while asserting a
looser bound is detectable mechanically — worth a lint/hook so the origin session's High-2 class
can't recur on discipline alone.
- **Deep-pass falsification discipline**: each adversarial lens states what evidence WOULD falsify
the change, so a "sound" verdict is a checked claim, not a skim.
- **Instrumentation review**: after ~5 ultracode WIs, review the fan-out-#2 hit-rate notes and keep,
tune, or retire it.

## What this rule does NOT change

TDD order (rule 10), the six gates (rule 47), sim/emulator isolation (rule 52), codex isolation
(rule 53), background-shell discipline (rule 49), the `/dispatch` multi-item mechanism (rule 55).
Rule 48 remains the *when parallelism is legal*; rule 55 is the *`/dispatch` multi-item how*; this
rule is the *within-WI analytical how under ultracode*.
Loading