> For AI agents: the complete documentation index is available at https://docs.phax.run/llms.txt, the full documentation bundle is available at https://docs.phax.run/llms-full.txt.

# phax 0.33.0 \{#phax-0330}

Changes since 0.32.0: [v0.32.0...v0.33.0](https://github.com/lbdremy/phax/compare/v0.32.0...v0.33.0).

## Highlights \{#highlights}

- **Acceptance tests, not oracles** — An oracle is what judges a test; an acceptance test is a test written from a spec's acceptance criterion before the code, and phax never uses one word for the other.

## Upgrading \{#upgrading}

- **Plan documents, run plans and extraction answers: `plan-document`, `phax-plan` and `phax-plan-extraction` are stamped 0.33.0.** A phase's `oracle: { dischargedBy, files }` key is `acceptance: { passedBy, files }`, a test line's loop `oracle` is `acceptance`, the technique `boundary` is accepted, and the criterion words `acceptance`, `in-phase` and `oracle` are reserved: no criterion id may be one of them.
- **Records and schema readers: `run-status`, `phase-status`, `gate-attribution` and `phase-record-manifest` are stamped 0.33.0.** A run's hold selection `oracle` is recorded `acceptance`, a corrected stop's `oracleStep` is `acceptanceStep`, a gate step's surface `oracle` and a record's verified surface `oracle` are `acceptance`, and a record's role is `acceptance` with `passedBy` or `passing` with `acceptancePhase`, in place of `oracle` with `dischargedBy` or `discharging` with `oraclePhase`.
- **Provider and run folders: the new `acceptance-request` replaces `oracle-request`.** The provider reads an `acceptance-request` stamped 0.33.0 on stdin, with verdict `authored` or `passed` and the keys `phase`, `acceptancePhase`, `base` and `files`, plus `acceptanceCommit` on `passed`. phax saves it as `checks-attempt-NN.acceptance-request.json`. `oracle-request` is frozen at 0.26.0 and read only: phax writes it nowhere. A provider you wrote reads `passed`, `acceptancePhase` and `acceptanceCommit` in place of `discharged`, `oraclePhase` and `oracleCommit`, and refuses any other document, as the example does: a provider that still reads an `oracle-request` receives none, and phax refuses a plan with an acceptance phase when no `acceptance` provider is configured.
- **The Vitest example moved from `examples/vitest-oracles/` to `examples/vitest-acceptance/`.** If you copied it, or your phax.json points at `node examples/vitest-oracles/main.mjs`, change the path to `node examples/vitest-acceptance/main.mjs` under the key `acceptance`. It reads only an `acceptance-request`, names `--skip-acceptance` in its remedy, and reports findings whose ids start with `acceptance-` (`acceptance-unmarked`, `acceptance-not-run`, `acceptance-marker-left`, `acceptance-changed`, `acceptance-unparsable`).
- **Telemetry: the event `oracle.edits.unjudged` is `acceptance.edits.unjudged`.** Its console line is `phax·acceptance.edits.unjudged`, and a failed step named `oracle` in a span or an event is named `acceptance`. A dashboard or an alert on the old name stops matching.
- **Overview and records: `acceptanceRole` and the `acceptance` rows.** `phax plans overview --json` gives `acceptanceRole`, whose kind is `acceptance` (with `passedBy`), `passing` (with `acceptancePhase`) or `none`, in place of `oracleRole`. The overview prints `acceptance role` and `phax records explain` prints `acceptance`, where they printed `oracle role` and `oracle`; the review handoff's table is `## Acceptance pairs`. A script that matches those names changes with them.
- **Skills: rerun `phax skills install`.** The bundled skills (phax-planning, phax-decide-plan, phax-decide-review, phax-review) teach acceptance phases, and a copy made by an earlier release teaches the old names. See [After every upgrade](https://github.com/lbdremy/phax/blob/v0.33.0/docs/upgrading.md#after-every-upgrade).
- **Schema readers: renamed exports in `@lbdremy/phax-schemas`.** `parseAcceptanceRequest` reads an `acceptance-request` and an `oracle-request` at 0.26.0, and `toLatestAcceptanceRequest` lifts either to the latest acceptance request (`discharged` becomes `passed`, `oraclePhase` becomes `acceptancePhase`, `oracleCommit` becomes `acceptanceCommit`). `OracleRequestSchema`, `parseOracleRequest`, `toLatestOracleRequest` and the types `OracleRequest`, `LatestOracleRequest` and `OracleRequestShape` are gone; `OracleRequestV0_26_0Schema` stays for the frozen shape. An older `@lbdremy/phax-schemas` cannot read 0.33.0 documents.
- **Older records read under the new names.** A plan sidecar, run plan, status file, gate attribution or record manifest written by an earlier release still reads, lifted to the acceptance names when phax or `@lbdremy/phax-schemas` reads it. `phax records explain` lists a record's `.acceptance-request.json`, and `.oracle-request.json` for a record written before.
- **Configuration: the `oracles` key is `acceptance`.** It applies in phax.json, phax.local.json and \~/.phax/config.json. A layer that still carries `oracles` is refused with `<file>: "oracles" is no longer read: write "acceptance"`. Run `phax schema upgrade` to refresh the editor schemas.
- **Command line: `--hold acceptance` and `--skip-acceptance`.** They replace `--hold oracle` and `--skip-oracle`, refused with `--hold 'oracle' is no longer read: write --hold acceptance` and `--skip-oracle is no longer read: write --skip-acceptance`.
- **Hand-written plans: the header lines and the loop.** `**Oracle phase:** yes | discharged by phase-NN` is `**Acceptance phase:** yes | passed by phase-NN`, `**Oracle files:**` is `**Acceptance test files:**`, and a test line's loop `oracle` is `acceptance`. `phax plans lint` reports the old lines on its `acceptance` check (formerly `oracles`) with `**Oracle phase:** is no longer read: write **Acceptance phase:**` and `**Oracle files:** is no longer read: write **Acceptance test files:**`, and `phax run` and `phax resume` refuse them with exit 11, "Acceptance preflight failed". The old loop is refused with `test line <n> uses the loop 'oracle', which is no longer read: write 'acceptance'`, before any extraction.
- **Run `phax artifact migrate-documents` once.** It restamps every live plan sidecar stamped below 0.33.0, rewrites its plan.md test lines from the loop `oracle` to `acceptance` and its header lines to `**Acceptance phase:**` and `**Acceptance test files:**`, and commits both files. Spec sidecars are already at their current stamp, 0.32.0, and stay as they are. It refuses a plan whose body was edited by hand since its sidecar was written, and a plan with a test line whose criterion is `acceptance`, naming the phase and the line: rename that criterion in the spec and the plan, or re-author the plan, then rerun. Until then `approve`, `reopen` and `decide` refuse, naming the command.
- **Runs in flight.** A `phax-plan.json` extracted by 0.32.0 or older is refused by `phax resume` and `phax validate --plan`, which name `phax archive <run> --force`. Finish the run with the release that started it, or archive it and run its plan again. `phax ls` and `phax session-info` still show it.

## What's new \{#whats-new}

### Acceptance tests, not oracles \{#acceptance-tests-not-oracles}

> An oracle is what judges a test; an acceptance test is a test written from a spec's acceptance criterion before the code, and phax never uses one word for the other.

- A plan declares the phase that writes failing tests with `**Acceptance phase:**` and `**Acceptance test files:**`, naming the phase that passes them. `plan.md acceptance phase header lines`

  Now:

  ```text
  ## phase-03 — Acceptance tests for publish {#phase-03-publish-tests}

  **Recommended model:** claude-sonnet-5-5
  **Recommended effort:** medium
  **Acceptance phase:** passed by phase-04
  **Acceptance test files:** `tests/e2e/publish.test.ts`
  ```

  :::details Before

  ```text
  ## phase-03 — Acceptance tests for publish {#phase-03-publish-tests}

  **Recommended model:** claude-sonnet-5-5
  **Recommended effort:** medium
  **Oracle phase:** discharged by phase-04
  **Oracle files:** `tests/e2e/publish.test.ts`
  ```

  :::

- A test written in an acceptance phase is marked `acceptance` in its loop field, and `boundary` is a new technique for empty cases and limits. `plan.md test strategy line`

  Now:

  ```text
  - every (state, transition) pair is accepted or refused as the table says — small · table · transition table · acceptance · AC-3
  - an empty name and a 64-character name are accepted, a 65-character one refused — small · boundary · the 64-character limit · in-phase
  ```

  :::details Before

  ```text
  - every (state, transition) pair is accepted or refused as the table says — small · table · transition table · oracle · AC-3
  ```

  :::

- Running a plan that still uses the oracle names is refused before anything runs, and each refusal names what to write instead. `phax run — a plan with the old names`

  Now:

  ```text
  $ phax plans lint docs/plans/2610271100-publish-plan.md
  docs/plans/2610271100-publish-plan.md: 3 errors, 0 warnings
  error    acceptance  phase-03  **Oracle phase:** is no longer read: write **Acceptance phase:**
  error    acceptance  phase-03  **Oracle files:** is no longer read: write **Acceptance test files:**
  error    tests       phase-03  test line 1 uses the loop 'oracle', which is no longer read: write 'acceptance'
  $? = 1

  $ phax run --plan docs/plans/2610271100-publish-plan.md
  docs/plans/2610271100-publish-plan.md: phase-03 test line 1 uses the loop 'oracle', which is no longer read: write 'acceptance' — run phax plans lint docs/plans/2610271100-publish-plan.md

  $ phax run --plan docs/plans/2610271100-publish-plan.md        # test line rewritten, header lines not yet
  Acceptance preflight failed: 2 error(s).
    phase-03  **Oracle phase:** is no longer read: write **Acceptance phase:**
    phase-03  **Oracle files:** is no longer read: write **Acceptance test files:**
  Fix the plan, then check it with `phax plans lint docs/plans/2610271100-publish-plan.md`.
  $? = 11
  ```

- The provider that judges acceptance tests is configured under `acceptance`, and an `oracles` block is refused with the new key named. `phax.json acceptance provider`

  Now:

  ```text
  {
    "acceptance": { "command": "node scripts/acceptance-verdicts.mjs" }
  }

  $ phax validate
  phax.json: "oracles" is no longer read: write "acceptance"
  ```

  :::details Before

  ```text
  {
    "oracles": { "command": "node scripts/acceptance-verdicts.mjs" }
  }
  ```

  :::

- `phax run --hold acceptance` stops the run for review after every acceptance phase, and `--hold oracle` is refused with the new spelling named. `phax run --hold acceptance`

  Now:

  ```text
  $ phax run --plan docs/plans/2610271100-publish-plan.md --hold acceptance

  $ phax run --plan docs/plans/2610271100-publish-plan.md --hold oracle
  --hold 'oracle' is no longer read: write --hold acceptance
  ```

  :::details Before

  ```text
  $ phax run --plan docs/plans/2610271100-publish-plan.md --hold oracle
  ```

  :::

- `phax resume --skip-acceptance` resumes without the acceptance step while the configured gate still runs, and `--skip-oracle` is refused with the new flag named. `phax resume --skip-acceptance`

  Now:

  ```text
  $ phax resume publish --yes --skip-acceptance
    Skipping the acceptance step of phase-04 (--skip-acceptance); its configured gate still runs.

  $ phax resume publish --yes --skip-oracle
  --skip-oracle is no longer read: write --skip-acceptance
  ```

  :::details Before

  ```text
  $ phax resume publish --yes --skip-oracle
    Skipping the oracle step of phase-04 (--skip-oracle); its configured gate still runs.
  ```

  :::

- An acceptance provider reads an `acceptance-request` document, whose verdict is `authored` or `passed`. `acceptance request on the provider's stdin`

  Now:

  ```text
  {
    "$schema": "https://docs.phax.run/schemas/acceptance-request/0.33.0.json",
    "verdict": "passed",
    "phase": "phase-04",
    "acceptancePhase": "phase-03",
    "base": "<40-hex>",
    "acceptanceCommit": "<40-hex>",
    "files": ["tests/e2e/publish.test.ts"]
  }
  ```

  :::details Before

  ```text
  {
    "$schema": "https://docs.phax.run/schemas/oracle-request/0.26.0.json",
    "verdict": "discharged",
    "phase": "phase-04",
    "oraclePhase": "phase-03",
    "base": "<40-hex>",
    "oracleCommit": "<40-hex>",
    "files": ["tests/e2e/publish.test.ts"]
  }
  ```

  :::

- A plan's phase states its acceptance tests under `acceptance`, naming the phase that passes them in `passedBy`. `phax-plan.json and the plan sidecar phase`

  Now:

  ```text
  "acceptance": { "passedBy": "phase-04", "files": ["tests/e2e/publish.test.ts"] }
  ```

  :::details Before

  ```text
  "oracle": { "dischargedBy": "phase-04", "files": ["tests/e2e/publish.test.ts"] }
  ```

  :::

- Scripts reading a run's status find the hold selection `acceptance` and, on a closed stop, `acceptanceStep`. `run and phase status`

  Now:

  ```text
  run-status.json:  "hold": { "selection": "acceptance", "phases": ["phase-03"] }
  status.json:      "stop": { "cause": "held", "status": "closed", "outcome": "corrected", "reviewCommit": "<40-hex>", "acceptanceStep": "authored", "closedBy": { … } }
  ```

  :::details Before

  ```text
  run-status.json:  "hold": { "selection": "oracle", "phases": ["phase-03"] }
  status.json:      "stop": { "cause": "held", "status": "closed", "outcome": "corrected", "reviewCommit": "<40-hex>", "oracleStep": "authored", "closedBy": { … } }
  ```

  :::

- A gate attribution's appended step carries the surface `acceptance`, and a phase record names its role as `acceptance` or `passing` and lists `acceptance` among its verified surfaces. `gate attribution and phase record`

  Now:

  ```text
  gate attribution:  { "command": "node scripts/acceptance-verdicts.mjs", "surface": "acceptance", "result": "pass" }
  record manifest:   "acceptance": { "role": "acceptance", "passedBy": "phase-04" }
                     "acceptance": { "role": "passing", "acceptancePhase": "phase-03" }
                     "verifiedSurfaces": ["acceptance", "local"]
  ```

  :::details Before

  ```text
  gate attribution:  { "command": "node scripts/acceptance-verdicts.mjs", "surface": "oracle", "result": "pass" }
  record manifest:   "oracle": { "role": "oracle", "dischargedBy": "phase-04" }
                     "oracle": { "role": "discharging", "oraclePhase": "phase-03" }
                     "verifiedSurfaces": ["local", "oracle"]
  ```

  :::

- The plan overview, as text and as JSON, and the records explanation show each phase's acceptance role, and records written before the rename read the same way. `phax plans overview and phax records explain`

  Now:

  ```text
  $ phax plans overview docs/plans/2610271100-publish-plan.md
  phase-03 — Acceptance tests for publish  claude-sonnet-5-5 · medium · headless
    acceptance role  acceptance phase, passed by phase-04

  $ phax plans overview docs/plans/2610271100-publish-plan.md --json
        "acceptanceRole": { "kind": "acceptance", "passedBy": "phase-04" },

  $ phax records explain <commit>
  acceptance   passes phase-03 — node scripts/acceptance-verdicts.mjs: pass
  ```

  :::details Before

  ```text
  $ phax plans overview docs/plans/2610271100-publish-plan.md
  phase-03 — Acceptance tests for publish  claude-sonnet-5-5 · medium · headless
    oracle role  oracle phase, discharged by phase-04

  $ phax plans overview docs/plans/2610271100-publish-plan.md --json
        "oracleRole": { "kind": "oracle", "dischargedBy": "phase-04" },

  $ phax records explain <commit>
  oracle   discharges phase-03 — node scripts/acceptance-verdicts.mjs: pass
  ```

  :::

- Running `phax artifact migrate-documents` once rewrites every live plan to the acceptance names and commits it. `phax artifact migrate-documents`

  Now:

  ```text
  $ phax artifact migrate-documents
  plan-document 0.32.0 → 0.33.0
    docs/plans/2610271100-publish-plan.md  Draft     open 0 · arbitrated 0 (0 lifted)
  committed 3f2a9c1 chore(artifacts): migrate documents to their current shapes
  ```

- Telemetry reports a review correction to acceptance test files after they were judged as `acceptance.edits.unjudged`. `telemetry event acceptance.edits.unjudged`

  Now:

  ```text
  phax·acceptance.edits.unjudged  files=[tests/e2e/publish.test.ts]
  ```

  :::details Before

  ```text
  phax·oracle.edits.unjudged  files=[tests/e2e/publish.test.ts]
  ```

  :::

- The planning skill teaches acceptance phases, explains that an acceptance test may be small, and describes the `boundary` technique. `the phax-planning skill`

  Now:

  ```text
  ## Acceptance phases
  …
  | Kind of code | Size | Technique | Acceptance candidate |

  `boundary` (equivalence partitions and boundary values: the empty case, each limit, just outside it)
  ```

  :::details Before

  ```text
  ## Oracle phases
  …
  | Kind of code | Size | Technique | Oracle candidate |
  ```

  :::
