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, and this page is available as Markdown at https://docs.phax.run/releases/0-33-0.md.

phax 0.33.0

Changes since 0.32.0: v0.32.0...v0.33.0.

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

  • 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.
  • 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

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:

    ## 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`
    Before
    ## 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:

    - 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
    Before
    - 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:

    $ 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:

    {
      "acceptance": { "command": "node scripts/acceptance-verdicts.mjs" }
    }
    
    $ phax validate
    phax.json: "oracles" is no longer read: write "acceptance"
    Before
    {
      "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:

    $ 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
    Before
    $ 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:

    $ 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
    Before
    $ 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:

    {
      "$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"]
    }
    Before
    {
      "$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:

    "acceptance": { "passedBy": "phase-04", "files": ["tests/e2e/publish.test.ts"] }
    Before
    "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:

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

    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"]
    Before
    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:

    $ 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
    Before
    $ 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:

    $ 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:

    phax·acceptance.edits.unjudged  files=[tests/e2e/publish.test.ts]
    Before
    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:

    ## Acceptance phases
    …
    | Kind of code | Size | Technique | Acceptance candidate |
    
    `boundary` (equivalence partitions and boundary values: the empty case, each limit, just outside it)
    Before
    ## Oracle phases
    …
    | Kind of code | Size | Technique | Oracle candidate |