@phi-code-admin/phi-code 0.87.0 → 0.89.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +111 -0
- package/docs/adr/0001-phase-contract.md +57 -0
- package/docs/adr/0002-independent-review.md +47 -0
- package/docs/design/plan-debug-build.md +266 -0
- package/extensions/phi/orchestrator.ts +482 -26
- package/extensions/phi/providers/acceptance.ts +102 -0
- package/extensions/phi/providers/build-loop.ts +89 -0
- package/extensions/phi/providers/candidate-select.ts +112 -0
- package/extensions/phi/providers/debug-build-commands.ts +129 -0
- package/extensions/phi/providers/debug-contract.ts +131 -0
- package/extensions/phi/providers/execution.ts +75 -0
- package/extensions/phi/providers/orchestrator-helpers.ts +14 -2
- package/extensions/phi/providers/phase-machine.ts +70 -7
- package/extensions/phi/providers/redteam.ts +115 -0
- package/extensions/phi/providers/triage.ts +96 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,116 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.89.0] - 2026-07-11
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- **Two new execution-grounded commands, `/debug` and `/build`**, implementing
|
|
8
|
+
the design in `docs/design/plan-debug-build.md`. They exist because the
|
|
9
|
+
SWE-bench-lite head-to-head measured that `/plan`'s TEST/REVIEW phases approve
|
|
10
|
+
wrong code — they grade the model's own reconstruction, not a real run. These
|
|
11
|
+
modes move the burden of proof from opinion to **execution**.
|
|
12
|
+
- **`/debug <failing state>`** — turn a REAL failure green through
|
|
13
|
+
`REPRODUCE → LOCALIZE → FIX → VERIFY`. It refuses to guess: if the failure
|
|
14
|
+
does not reproduce on the current code, or cannot be run at all, it stops
|
|
15
|
+
with `BLOCKED` instead of fabricating a fix. `VERIFY` requires two real runs
|
|
16
|
+
(the reproduction now passes AND the suite does not regress) before it will
|
|
17
|
+
ever say `FIXED`. Each phase routes to a model that does not share the
|
|
18
|
+
coder's blind spot (`routing.json`).
|
|
19
|
+
- **`/build <spec>`** — `/plan`'s decomposition (`EXPLORE → PLAN → CODE`) plus
|
|
20
|
+
an execution-grounded `BUILD-VERIFY`: run the recipe, check acceptance
|
|
21
|
+
criteria derived from the spec, run an **executable** red-team against the
|
|
22
|
+
input regime the change touched (a runnable test that goes red, never a
|
|
23
|
+
critique), and route every real failure to the `/debug` protocol. It reports
|
|
24
|
+
`SUCCESS` only when a real run meets the acceptance criteria, otherwise an
|
|
25
|
+
honest `PARTIAL` that lists what still fails.
|
|
26
|
+
- **Six pure, unit-tested decision cores** backing the above (no live model, no
|
|
27
|
+
fs at the boundary): `execution.ts` (the run oracle: `runCommand`/`passed`),
|
|
28
|
+
`acceptance.ts` (executable acceptance criteria; manual criteria are never
|
|
29
|
+
counted as passing), `debug-contract.ts` (`decideReproduce`/`decideVerify` —
|
|
30
|
+
BLOCKED rather than least-bad), `triage.ts` (adaptive depth — pay the pipeline
|
|
31
|
+
cost only when earned), `redteam.ts` (a break is recorded only when a test
|
|
32
|
+
actually ran red), and `build-loop.ts` (`decideBuildRound` — SUCCESS /
|
|
33
|
+
CONTINUE-to-/debug / honest PARTIAL). 73 new tests, including an end-to-end
|
|
34
|
+
integration test of the `/debug` and `/build` chain against a simulated Pi
|
|
35
|
+
runtime.
|
|
36
|
+
|
|
37
|
+
### Changed
|
|
38
|
+
|
|
39
|
+
- The orchestrator now carries an `orchestrationMode`. `/debug` and `/build` run
|
|
40
|
+
on a **separate linear driver** and never engage `/plan`'s review-fix cycle or
|
|
41
|
+
its five-phase bookkeeping, so the existing `/plan` path is byte-for-byte
|
|
42
|
+
unchanged (its integration suite still passes).
|
|
43
|
+
|
|
44
|
+
### Honest caveat
|
|
45
|
+
|
|
46
|
+
- These modes are the protocol + scaffolding. Their value depends on a real
|
|
47
|
+
executable environment; on a host that cannot run the target they downgrade to
|
|
48
|
+
`BLOCKED` rather than a fabricated pass. They are **not yet benchmarked** to
|
|
49
|
+
beat a single shot — per the design doc, that measurement (which needs a
|
|
50
|
+
per-project execution sandbox) is the next step, and no claim is made here that
|
|
51
|
+
they do.
|
|
52
|
+
|
|
53
|
+
## [0.88.0] - 2026-07-10
|
|
54
|
+
|
|
55
|
+
### Changed
|
|
56
|
+
|
|
57
|
+
- **The /plan phase contract is now structured-primary with a text fallback**
|
|
58
|
+
(see `docs/adr/0001-phase-contract.md`). A phase agent CALLS a new
|
|
59
|
+
`phase_result` tool to emit its verdict / blocking / handoff as data;
|
|
60
|
+
`resolvePhaseOutcome` merges that structured emission field-by-field with the
|
|
61
|
+
regex-scraped markdown report, preferring the structured value. TEST and
|
|
62
|
+
REVIEW are instructed to call it. When a model does not call the tool,
|
|
63
|
+
behavior is identical to the previous text-only path — the change cannot make
|
|
64
|
+
any run worse. This replaces "regex luck" with an exact machine-read path for
|
|
65
|
+
the control-flow-critical signals (verdict, BLOCKED, the review-fix cycle).
|
|
66
|
+
|
|
67
|
+
### Added
|
|
68
|
+
|
|
69
|
+
- **End-to-end integration test of the orchestrator.** The real orchestrator
|
|
70
|
+
extension is now driven through a full multi-phase run against a simulated Pi
|
|
71
|
+
runtime (`test/orchestrator-integration.test.ts`): phase progression, handoff
|
|
72
|
+
propagation, the review-FAIL → fix → re-review cycle, and the BLOCKED pause
|
|
73
|
+
are all exercised together, not just the pure decision function. (Scripted
|
|
74
|
+
phase outcomes — deterministic, no live model.)
|
|
75
|
+
- **An eval harness** (`evals/`) — the measurement infrastructure that did not
|
|
76
|
+
exist. Tasks with deterministic pass/fail verifiers, a runnable baseline
|
|
77
|
+
strategy (`npx tsx evals/run.ts`), unit-tested scoring/aggregation
|
|
78
|
+
(`test/evals-lib.test.ts`), and a demonstrated real run (2/2 baseline tasks on
|
|
79
|
+
a live model). `evals/README.md` documents the methodology and is honest that
|
|
80
|
+
the /plan-vs-baseline head-to-head is not yet a single number.
|
|
81
|
+
- **Two ADRs** documenting the phase-contract decision and the independent-review
|
|
82
|
+
release gate (`docs/adr/`).
|
|
83
|
+
|
|
84
|
+
### Fixed
|
|
85
|
+
|
|
86
|
+
- Bugs found by an **independent adversarial review** of the phase-contract
|
|
87
|
+
change (see `docs/adr/0002-independent-review.md`), each now pinned by a
|
|
88
|
+
regression test:
|
|
89
|
+
- **State leak between runs**: `currentPhaseResult` was reset only in
|
|
90
|
+
`sendNextPhase`, but the first phase of each `/plan` run launches directly —
|
|
91
|
+
a stale structured result (e.g. a BLOCKED verdict) from a previous run could
|
|
92
|
+
abort a fresh run at phase 1. Reset on every run start + a phase-identity
|
|
93
|
+
stamp so a stale/late result is never mistaken for the current phase.
|
|
94
|
+
- **Field erasure on multi-call**: a second `phase_result` call replaced the
|
|
95
|
+
whole object, wiping a verdict set by the first; it now merges only the
|
|
96
|
+
fields each call sets.
|
|
97
|
+
- **Dead text fallback for PLAN/CODE**: `readPhaseReport` looked for
|
|
98
|
+
`<key>-<ts>.md` but PLAN writes `todo-<ts>.md` and CODE `progress-<ts>.md`,
|
|
99
|
+
so their handoff blocks were never read. Mapped key → report file.
|
|
100
|
+
- **`extractSection` over-matching**: a prose line starting with a section
|
|
101
|
+
word (e.g. "Blocking issues remain: 2") could be read as that section's
|
|
102
|
+
header. The plain-label form now requires `:` or end-of-line.
|
|
103
|
+
- A TEST/REVIEW phase that finished with tool work but emitted no verdict at all
|
|
104
|
+
(neither structured nor a VERDICT line) is now surfaced instead of silently
|
|
105
|
+
passing.
|
|
106
|
+
- **The eval runner** had two Windows bugs its first real run caught: temp-dir
|
|
107
|
+
cleanup raced `EPERM` (now retries), and `shell:true` with an args array
|
|
108
|
+
mangled the prompt (now a single quoted command string).
|
|
109
|
+
|
|
110
|
+
### Tooling
|
|
111
|
+
|
|
112
|
+
- Biome now also lints `evals/`.
|
|
113
|
+
|
|
3
114
|
## [0.87.0] - 2026-07-10
|
|
4
115
|
|
|
5
116
|
### Added
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# ADR 0001 — Structured-primary phase contract for /plan
|
|
2
|
+
|
|
3
|
+
Status: accepted (2026-07-10)
|
|
4
|
+
|
|
5
|
+
## Context
|
|
6
|
+
|
|
7
|
+
The /plan orchestrator chains five agent phases (explore → plan → code → test
|
|
8
|
+
→ review). Each phase must report two things the orchestrator acts on:
|
|
9
|
+
|
|
10
|
+
- a **verdict** (TEST/REVIEW): PASS / FAIL / BLOCKED / SKIP, and
|
|
11
|
+
- a **handoff** (+ BLOCKING findings for REVIEW) carried to the next phase.
|
|
12
|
+
|
|
13
|
+
Originally this was communicated **only** as markdown the model wrote to
|
|
14
|
+
`.phi/plans/<phase>-<ts>.md`, which the orchestrator scraped with regexes
|
|
15
|
+
(`## VERDICT:`, `## HANDOFF`, `## BLOCKING`). That is fragile: models phrase
|
|
16
|
+
headers inconsistently (`**HANDOFF**`, `HANDOFF:`, mid-sentence "verdict"), and
|
|
17
|
+
a mis-scrape silently degrades control flow — a missed REVIEW FAIL skips the fix
|
|
18
|
+
cycle; a missed BLOCKED keeps a doomed run going. The original justification for
|
|
19
|
+
text-only was that the upstream proxy did not guarantee valid structured tool
|
|
20
|
+
output.
|
|
21
|
+
|
|
22
|
+
## Decision
|
|
23
|
+
|
|
24
|
+
Keep the markdown report (it is the human-readable artifact) but make the
|
|
25
|
+
**machine-read path structured and primary**:
|
|
26
|
+
|
|
27
|
+
- The orchestrator registers a `phase_result` tool. TEST and REVIEW phases are
|
|
28
|
+
instructed to call it with `{verdict, blocking, handoff}`; any phase may call
|
|
29
|
+
it to hand off.
|
|
30
|
+
- `resolvePhaseOutcome(structured, reportText)` (pure, unit-tested) merges the
|
|
31
|
+
two sources **field by field**, preferring the structured value and falling
|
|
32
|
+
back to the regex-scraped report per field. When the model calls the tool the
|
|
33
|
+
outcome is exact; when it does not, behavior is byte-for-byte the pre-existing
|
|
34
|
+
text path.
|
|
35
|
+
- The text parser was hardened anyway (`extractSection` accepts heading, bold,
|
|
36
|
+
and plain-label forms) so the fallback is as robust as possible.
|
|
37
|
+
|
|
38
|
+
## Why not go structured-only
|
|
39
|
+
|
|
40
|
+
Two reasons the text path stays as a fallback rather than being removed:
|
|
41
|
+
|
|
42
|
+
1. **Provider variance.** Not every provider/proxy reliably emits tool calls on
|
|
43
|
+
every turn; a model that writes a good report but forgets the tool call must
|
|
44
|
+
still drive the pipeline correctly.
|
|
45
|
+
2. **Zero-regression migration.** Making structured additive means the change
|
|
46
|
+
cannot make any existing run worse — the worst case equals the old behavior.
|
|
47
|
+
|
|
48
|
+
## Consequences
|
|
49
|
+
|
|
50
|
+
- Robustness of control flow (verdict/BLOCKED/fix-cycle) now depends on a
|
|
51
|
+
structured emission when available, not on regex luck.
|
|
52
|
+
- Two code paths must stay in sync; `resolvePhaseOutcome` centralizes the merge
|
|
53
|
+
and is covered by unit tests, and `orchestrator-integration.test.ts` drives
|
|
54
|
+
the whole chain via the structured path.
|
|
55
|
+
- Follow-up (not done here): once telemetry shows the structured path is taken
|
|
56
|
+
reliably across the providers phi ships, the text fallback can be demoted to a
|
|
57
|
+
warning-only safety net.
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# ADR 0002 — Independent adversarial review as a release gate
|
|
2
|
+
|
|
3
|
+
Status: accepted (2026-07-10)
|
|
4
|
+
|
|
5
|
+
## Context
|
|
6
|
+
|
|
7
|
+
phi-code is largely built by a single author, who is also the only reviewer.
|
|
8
|
+
Self-review misses the bugs the author's mental model is blind to — the code
|
|
9
|
+
does what the author *thinks* it does, and they test that. There is no external
|
|
10
|
+
human reviewer on hand for every change.
|
|
11
|
+
|
|
12
|
+
## Decision
|
|
13
|
+
|
|
14
|
+
Before shipping a non-trivial change to a load-bearing subsystem (the /plan
|
|
15
|
+
orchestrator, the model/provider layer, compaction, the extension runtime), run
|
|
16
|
+
an **independent adversarial review**: a reviewer with fresh context that did
|
|
17
|
+
not write the code, prompted to *refute* — to find state leaks, races, contract
|
|
18
|
+
mismatches, and edge cases — not to approve.
|
|
19
|
+
|
|
20
|
+
Findings are triaged (verify each against the code, discard false positives),
|
|
21
|
+
the real ones are fixed, and each fix is pinned with a regression test before
|
|
22
|
+
the change ships.
|
|
23
|
+
|
|
24
|
+
## Evidence this works
|
|
25
|
+
|
|
26
|
+
The structured-phase-contract change (ADR 0001) passed the author's own unit
|
|
27
|
+
and integration tests. An independent review of that change then found four
|
|
28
|
+
real defects the author's tests missed:
|
|
29
|
+
|
|
30
|
+
- a structured result leaking from one `/plan` run into the next (a stale
|
|
31
|
+
BLOCKED verdict could abort a fresh run at phase 1);
|
|
32
|
+
- a second `phase_result` call erasing fields set by the first;
|
|
33
|
+
- no phase-identity guard against a late tool call landing after a transition;
|
|
34
|
+
- the text HANDOFF fallback being dead for two phases due to a report-file name
|
|
35
|
+
mismatch.
|
|
36
|
+
|
|
37
|
+
All four are now fixed and covered by regression tests
|
|
38
|
+
(`orchestrator-integration.test.ts`, `phase-machine.test.ts`).
|
|
39
|
+
|
|
40
|
+
## Consequences
|
|
41
|
+
|
|
42
|
+
- "Green tests" is necessary but not sufficient for a load-bearing change; an
|
|
43
|
+
independent refutation pass is part of the definition of done.
|
|
44
|
+
- The reviewer need not be human to be useful — it needs to be *independent of
|
|
45
|
+
the authoring context* and prompted adversarially. This is not a substitute
|
|
46
|
+
for real external users, whose absence remains an honest limitation of the
|
|
47
|
+
project's validation.
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
# Design: /plan, /debug, /build — composable, execution-grounded modes
|
|
2
|
+
|
|
3
|
+
Status: proposed (2026-07-11)
|
|
4
|
+
Informed by: the SWE-bench-lite head-to-head (ADR 0001/0002 and evals/), which
|
|
5
|
+
measured that a 5-phase, deliberation-heavy /plan ties or loses to a single shot
|
|
6
|
+
at 6–14× the cost on bug-fixing, and — decisively — that its TEST/REVIEW phases
|
|
7
|
+
approve wrong code because they grade the model's own reconstruction, not a real
|
|
8
|
+
run. Multi-model diversity did NOT fix this: a different family (deepseek)
|
|
9
|
+
independently endorsed the same wrong guard, because the error was a *shared
|
|
10
|
+
plausible misconception*, not a model-specific blind spot.
|
|
11
|
+
|
|
12
|
+
The one thing that would have caught it was running the real test. So this design
|
|
13
|
+
moves the burden of proof from the model to **execution**, and splits the work
|
|
14
|
+
into three composable commands.
|
|
15
|
+
|
|
16
|
+
## Principles (each is a measured lesson, not a preference)
|
|
17
|
+
|
|
18
|
+
1. **Execution is the only oracle.** Every accept/reject decision must be backed
|
|
19
|
+
by running real code — the existing test suite, a reproduction, or the built
|
|
20
|
+
app — not by a model reviewing its own output. Opinion (even adversarial,
|
|
21
|
+
even multi-model) shares misconceptions; a red test run does not.
|
|
22
|
+
2. **Adversarial means executable.** "Challenge the fix" must produce a *failing
|
|
23
|
+
run*, never a critique. A run is objective; prose is not.
|
|
24
|
+
3. **Pay complexity only when earned.** A one-line change must not trigger a
|
|
25
|
+
five-phase pipeline. Depth adapts to task size/type, decided by cheap signals.
|
|
26
|
+
4. **Diversity proposes, the oracle disposes.** Multiple models are useful for
|
|
27
|
+
generating *candidate fixes*, filtered by real execution — not for casting
|
|
28
|
+
*review votes*, which correlate.
|
|
29
|
+
5. **/plan is for building; /debug is for fixing.** They are different jobs with
|
|
30
|
+
different oracles. Do not conflate them; compose them.
|
|
31
|
+
|
|
32
|
+
## The three commands
|
|
33
|
+
|
|
34
|
+
| Command | Job | Oracle | Standalone use |
|
|
35
|
+
|---|---|---|---|
|
|
36
|
+
| `/plan <spec>` | Build from a description (decompose → implement) | Acceptance criteria derived from the spec + a smoke run | "Scaffold / build this feature" |
|
|
37
|
+
| `/debug <failing-state>` | Turn a real failure green | The failing state + the existing test suite, re-run | "This test/trace is broken, fix it" |
|
|
38
|
+
| `/build <spec>` | Build AND make it actually work | The full loop: run → red-team → debug → re-run | "Build this and don't stop until it runs" |
|
|
39
|
+
|
|
40
|
+
`/build` is the outer loop that composes the two primitives with **execution
|
|
41
|
+
between them**. All three remain usable alone.
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## /plan — build from a spec
|
|
46
|
+
|
|
47
|
+
Phases (each may route to its own model via routing.json):
|
|
48
|
+
|
|
49
|
+
1. **EXPLORE** — map the existing code, conventions, entry points. Read-only.
|
|
50
|
+
2. **PLAN** — architecture + an ordered task list. Each task is a self-contained
|
|
51
|
+
prompt (the prompt-architect skill: `[CONTEXT] → [TASK] → [FORMAT] →
|
|
52
|
+
[CONSTRAINTS]`). This decomposition is /plan's core value on large,
|
|
53
|
+
under-specified builds — the part a single shot cannot hold coherently.
|
|
54
|
+
3. **CODE** — implement the tasks in dependency order.
|
|
55
|
+
4. **SELF-CHECK** — the cheapest real signal available: it compiles / typechecks
|
|
56
|
+
/ lints, and a smoke run of the entry point does not crash. NOT a substitute
|
|
57
|
+
for verification — just a floor.
|
|
58
|
+
|
|
59
|
+
**Input:** a natural-language spec.
|
|
60
|
+
**Output contract (machine-readable, consumed by /build):**
|
|
61
|
+
```
|
|
62
|
+
{
|
|
63
|
+
runRecipe: { build?: string, run: string, test?: string, readySignal?: string },
|
|
64
|
+
acceptance: string[], // testable criteria derived from the SPEC (not the code)
|
|
65
|
+
changedFiles: string[],
|
|
66
|
+
selfCheck: "pass" | "fail" | "skipped"
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
The `acceptance` list is the contract: crisp, checkable statements traced to the
|
|
70
|
+
request ("POST /login returns 200 + a JWT for valid creds; 401 otherwise").
|
|
71
|
+
Deriving these from the *spec* — before and independent of the implementation —
|
|
72
|
+
is what keeps verification from becoming circular.
|
|
73
|
+
|
|
74
|
+
Deliberately NOT in /plan: heavy TEST and REVIEW. Verification belongs to the
|
|
75
|
+
execution loop (/build), where it can run for real. Standalone /plan stops at
|
|
76
|
+
SELF-CHECK and hands its output to the user (or to /build).
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## /debug — turn a real failure green
|
|
81
|
+
|
|
82
|
+
The heart of the redesign. /debug never guesses what is wrong; it is *given* a
|
|
83
|
+
failure and reproduces it.
|
|
84
|
+
|
|
85
|
+
**Input contract — a concrete failing state (at least one):**
|
|
86
|
+
```
|
|
87
|
+
{
|
|
88
|
+
failingTest?: string, // e.g. "pytest tests/x.py::test_y"
|
|
89
|
+
trace?: string, // a stack trace / error output
|
|
90
|
+
reproCommand?: string, // a command that exhibits the bug
|
|
91
|
+
expected?: string, // what should happen instead (from the user/spec)
|
|
92
|
+
cwd: string
|
|
93
|
+
}
|
|
94
|
+
```
|
|
95
|
+
If none is runnable, /debug does not fabricate one from imagination — it asks for
|
|
96
|
+
one, or emits `BLOCKED: no reproducible failing state`.
|
|
97
|
+
|
|
98
|
+
Phases:
|
|
99
|
+
|
|
100
|
+
1. **REPRODUCE** — run the failing state, confirm it fails, capture the exact
|
|
101
|
+
symptom. If it does NOT fail on the current code, stop: `BLOCKED: cannot
|
|
102
|
+
reproduce`. (This alone kills the class of "fixes" for non-bugs.)
|
|
103
|
+
2. **LOCALIZE** — drive from the real symptom: read the traceback, grep the
|
|
104
|
+
changed/nearby symbols, narrow to the fault site. Localization, not more
|
|
105
|
+
review, is the underrated lever.
|
|
106
|
+
3. **FIX (generate N candidates)** — produce several minimal candidate patches
|
|
107
|
+
(different models and/or temperatures). Prefer the smallest; every added
|
|
108
|
+
guard/condition is a liability (the 3362 failure was an over-clever guard).
|
|
109
|
+
4. **VERIFY (the oracle)** — for EACH candidate, run: (a) the reproduced failure
|
|
110
|
+
→ must now pass, and (b) the existing test suite → must not regress. Select
|
|
111
|
+
the **minimal candidate that passes both** via `candidate-select.ts`. If none
|
|
112
|
+
passes, emit `BLOCKED` with the closest diagnostic — do NOT ship the least-bad.
|
|
113
|
+
|
|
114
|
+
**Output contract:**
|
|
115
|
+
```
|
|
116
|
+
{ verdict: "FIXED" | "BLOCKED",
|
|
117
|
+
patch?: string, // minimal, verified
|
|
118
|
+
evidence: { reproBefore: "fail", reproAfter: "pass", suite: "green" },
|
|
119
|
+
reason?: string } // when BLOCKED
|
|
120
|
+
```
|
|
121
|
+
`FIXED` is only ever emitted with a real before/after run pasted. There is no
|
|
122
|
+
path to a green verdict without execution.
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
## /build — build until it runs
|
|
127
|
+
|
|
128
|
+
`/build` = `/plan` then a bounded loop that closes the build→run→fix cycle with
|
|
129
|
+
execution as the glue.
|
|
130
|
+
|
|
131
|
+
```
|
|
132
|
+
plan = /plan(spec) # code + runRecipe + acceptance[]
|
|
133
|
+
for round in 1..MAX_ROUNDS (budgeted):
|
|
134
|
+
run = execute(plan.runRecipe) # ORACLE #1: does it run + meet acceptance?
|
|
135
|
+
unmet = acceptance criteria not satisfied by `run`
|
|
136
|
+
redTeam = red_team(plan, acceptance) # ORACLE #2: can an adversary break it? (below)
|
|
137
|
+
failures = unmet ∪ redTeam.breakingCases
|
|
138
|
+
if failures is empty: return SUCCESS(plan)
|
|
139
|
+
/debug({ from each failure: failingTest/trace/reproCommand, expected }) # fix REAL failures
|
|
140
|
+
# /debug mutates the working tree; loop re-runs from the top
|
|
141
|
+
return PARTIAL(plan, remaining failures) # honest: what still fails, not a false PASS
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
Key properties:
|
|
145
|
+
- The `execute` step is the oracle that /plan alone lacked. A criterion is met
|
|
146
|
+
only if the running program demonstrates it.
|
|
147
|
+
- Each `/debug` call is grounded in a **real** failure (a failed acceptance run
|
|
148
|
+
or a red-team breaking case), never in self-review.
|
|
149
|
+
- The loop is **budgeted** and returns `PARTIAL` honestly when it cannot close —
|
|
150
|
+
listing the still-failing criteria — instead of a confident-wrong `PASS`.
|
|
151
|
+
|
|
152
|
+
---
|
|
153
|
+
|
|
154
|
+
## The executable red-team protocol
|
|
155
|
+
|
|
156
|
+
This replaces the current REVIEW phase (which we measured as a rubber stamp). The
|
|
157
|
+
adversary's deliverable is a **failing run**, not an opinion.
|
|
158
|
+
|
|
159
|
+
```
|
|
160
|
+
red_team(code, acceptance, changedFiles):
|
|
161
|
+
dry = 0
|
|
162
|
+
while dry < K and within budget:
|
|
163
|
+
# An adversary agent (ideally a different model family than the coder —
|
|
164
|
+
# different break intuitions) targets the BOUNDARY the change touches.
|
|
165
|
+
attempt = adversary.write_breaking_case(
|
|
166
|
+
focus = changedFiles, # not the whole app
|
|
167
|
+
regimes = enumerate_input_regimes(changedFiles), # e.g. buffered vs streaming,
|
|
168
|
+
# empty, null, boundary, wrong-type
|
|
169
|
+
goal = "make an acceptance criterion or an invariant FALSE, as a runnable test")
|
|
170
|
+
result = execute(attempt) # RUN it — this is the whole point
|
|
171
|
+
if result.green:
|
|
172
|
+
dry += 1 # could not break it this round
|
|
173
|
+
else:
|
|
174
|
+
dry = 0
|
|
175
|
+
record breakingCase(attempt, result.symptom) # a concrete red run
|
|
176
|
+
return breakingCases
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
Why this works where adversarial *prose* failed (3362): the guard survived a
|
|
180
|
+
different model's careful written review because the reviewer shared the
|
|
181
|
+
misconception. It would NOT have survived `r.raw = io.BytesIO(...);
|
|
182
|
+
assert all(isinstance(c, str) for c in r.iter_content(decode_unicode=True))`
|
|
183
|
+
being *run* — that assertion is red regardless of what any model believes.
|
|
184
|
+
The rule that turns "adversarial" from theatre into signal: **the adversary
|
|
185
|
+
must attack the specific input regime the diff changed, and must express the
|
|
186
|
+
attack as an executed test, not a claim.**
|
|
187
|
+
|
|
188
|
+
---
|
|
189
|
+
|
|
190
|
+
## Execution grounding (the non-negotiable prerequisite)
|
|
191
|
+
|
|
192
|
+
Every oracle above requires running real code with the project's real
|
|
193
|
+
dependencies. On a host that cannot run the target (e.g. an old library under a
|
|
194
|
+
too-new Python — exactly what defeated the 3362 measurement), the modes must:
|
|
195
|
+
- run inside a sandbox/container that has the project's real environment, or
|
|
196
|
+
- when no such environment is available, DOWNGRADE honestly: /debug and /build
|
|
197
|
+
emit `BLOCKED: no executable environment` (or a low-confidence draft clearly
|
|
198
|
+
labelled unverified) — never a fabricated-reconstruction `PASS`.
|
|
199
|
+
|
|
200
|
+
Reusing phi's `run` / `verify` skills for local projects is the first target;
|
|
201
|
+
a per-project container is the general solution.
|
|
202
|
+
|
|
203
|
+
---
|
|
204
|
+
|
|
205
|
+
## Triage / adaptive depth (cost discipline)
|
|
206
|
+
|
|
207
|
+
Cheap up-front classification decides the mode and the depth:
|
|
208
|
+
|
|
209
|
+
| Signal | Route |
|
|
210
|
+
|---|---|
|
|
211
|
+
| Small edit, a known failing test/trace | `/debug` (skip planning entirely) |
|
|
212
|
+
| Small self-contained feature, single shot + verify passes | ship the single shot; skip the loop |
|
|
213
|
+
| Large, multi-file, under-specified build | `/build` (full loop) |
|
|
214
|
+
| A single shot's output already meets acceptance on a real run | done — do not deliberate further |
|
|
215
|
+
|
|
216
|
+
Measured rationale: the 6–14× overhead is only worth paying when a single shot
|
|
217
|
+
*fails the real oracle*. Otherwise the cheapest passing candidate wins.
|
|
218
|
+
|
|
219
|
+
---
|
|
220
|
+
|
|
221
|
+
## Model routing
|
|
222
|
+
|
|
223
|
+
Per-phase model assignment stays (routing.json). Corrected use, per the
|
|
224
|
+
measurements:
|
|
225
|
+
- **Candidate generation** (CODE, /debug FIX): diversity helps — different
|
|
226
|
+
models/temperatures produce different candidates, and the oracle filters.
|
|
227
|
+
- **Red-team adversary**: a different family than the coder helps (different
|
|
228
|
+
break intuitions) — but its output is a *run*, so it is robust even to shared
|
|
229
|
+
misconceptions.
|
|
230
|
+
- **Review-by-opinion**: removed. We measured it as correlated and unreliable;
|
|
231
|
+
execution replaces it.
|
|
232
|
+
|
|
233
|
+
---
|
|
234
|
+
|
|
235
|
+
## What is reused vs new
|
|
236
|
+
|
|
237
|
+
Reused from today's orchestrator: the phase engine, per-phase model switching,
|
|
238
|
+
the pure phase state machine (`phase-machine.ts`), the structured `phase_result`
|
|
239
|
+
contract, the fix-cycle, `candidate-select.ts` (minimality selection).
|
|
240
|
+
|
|
241
|
+
New work: (1) extract the fix-cycle into a standalone `/debug` with the input
|
|
242
|
+
contract above; (2) make `acceptance[]` + `runRecipe` first-class /plan outputs;
|
|
243
|
+
(3) the `/build` loop; (4) the executable red-team; (5) the execution sandbox and
|
|
244
|
+
the real-run verify path. Items 1–4 are prompt/orchestration changes on existing
|
|
245
|
+
machinery; item 5 is the real infrastructure investment.
|
|
246
|
+
|
|
247
|
+
## How we will know it worked (this must be measured, not shipped on faith)
|
|
248
|
+
|
|
249
|
+
- `/debug`: on SWE-bench-lite (bug-fixing), with a real executable environment,
|
|
250
|
+
resolved-rate vs the single-shot baseline. The hypothesis is that real-run
|
|
251
|
+
verification + candidate selection beats single-shot; if it does not, the
|
|
252
|
+
premise is wrong and we stop.
|
|
253
|
+
- `/build`: on a *build* task set (multi-file features with runnable acceptance
|
|
254
|
+
criteria — the eval /plan actually deserves, which SWE-bench does not provide),
|
|
255
|
+
scored on acceptance-met + does-it-run + coherence, single-shot vs /build.
|
|
256
|
+
|
|
257
|
+
No mode ships to npm before its number beats the baseline it claims to improve.
|
|
258
|
+
|
|
259
|
+
## Non-goals / honest caveats
|
|
260
|
+
|
|
261
|
+
- This does not add "more specialized agents" for its own sake. The measured
|
|
262
|
+
lesson is the opposite: minimal + execution beats elaborate + deliberation.
|
|
263
|
+
- It does not claim /build will beat single-shot — it makes /build *measurable*
|
|
264
|
+
and gives it the one ingredient (execution) that could make it win.
|
|
265
|
+
- Without the execution sandbox, this is just a reorganization; the sandbox is
|
|
266
|
+
where the value is, and it is real work.
|