6.0 KiB
Experiment 57J.35 — No-Retry Live Experiment Harness Enforcement
Objective
Make the canonical live harness (scripts/reproduce-multi-turn-investigation.mjs) physically incapable of hidden retries. Enforce one-shot execution semantics:
- One requested Start = exactly one
/api/cases/startcall - One requested Update = exactly one
/api/cases/updatecall - A rejection is returned immediately and is never retried implicitly
This directly addresses the protocol breach from Experiment 57J.32 where an implicit retry loop consumed multiple Update calls per trial, contaminating evidence.
Pre-written expectation recorded: YES
The canonical harness must enforce one-call/no-retry semantics for all bounded experiments. Future prompts may rely on this; Claude must not create supplementary retry scripts during bounded experiments.
Protocol breach referenced: Experiment 57J.32
Experiment 57J.32 documented a protocol breach where the original harness used an implicit retry loop for accepted results — meaning each "trial" potentially consumed multiple Update calls. This experiment enforces that the canonical apparatus cannot repeat that error.
Starting HEAD
06f67da — experiment: observe guarded multi-turn progress
Original Harness (commit 7533e47)
The original harness was a hardcoded sequential script:
Start → Update 1 → Update 2
Issues with original:
- No configuration system (scenario and answers hardcoded)
- No call accounting
- No rejection diagnostics (
rejectedProposalSnapshotnot handled) - Not flexible for bounded experiments (always exactly 2 updates)
- However: no explicit retry loops existed in the original — but the lack of bounded config allowed ad-hoc supplementary scripts with retries (as happened in 57J.32)
Changes to Canonical Harness
Before (original, commit 7533e47)
- Hardcoded sequential flow:
Start → Update 1 → Update 2 - No configuration object
- No call accounting
- No rejection diagnostics
- No explicit "no retry" documentation
After (current working tree)
- Bounded execution configuration:
config.maxUpdates+config.answers[]positional mapping - Call accounting:
calls.startCalls,calls.updateCallsincremented at actual API call sites, reported astotalCalls - One-shot semantics: Start makes exactly 1 call; each Update iteration makes exactly 1 call; rejection returns immediately with no retry path
- Rejection diagnostics:
rejectedProposalSnapshotpreserved and logged when present in Update rejection - Explicit documentation: Comments clarify "exactly one", "no retry", "bounded" semantics
No-Retry Invariant Verification
Semantic retries present: NO
No loop, no attempt counter, no run-until-success. Rejection at any stage causes immediate chain stop via return.
Transport retries present: NO
The harness makes raw fetch() calls with no retry wrapper. Any transport-level retry would need to be added explicitly (and is not part of this task).
Implicit second start/update: NO
Start is called exactly once at the top level. Updates are loop-bound by config.maxUpdates. Each loop iteration makes exactly one call.
Sequential flow enforcement
- Update 1 rejection → chain stops, Update 2 never called
- Update 1 success → Update 2 may be called exactly once (if
maxUpdates >= 2andanswers.length >= 2)
Test Results
All 8 deterministic harness tests pass via synchronous simulation mirror:
| Case | Description | Result |
|---|---|---|
| 1 | Start success → exactly 1 Start call | PASS |
| 2 | Start failure → exactly 1 Start call, no retry | PASS |
| 3 | Update success → exactly 1 Update call | PASS |
| 4 | proposal_compatibility rejection → exactly 1 Update call, unchanged rejection |
PASS |
| 5 | Update 1 rejection → Update 2 never called | PASS |
| 6 | Update 1 success → Update 2 called exactly once when explicitly requested | PASS |
| 7 | Call counters equal actual mocked API invocations | PASS |
| 8 | No semantic retry after HTTP 422/valid rejection | PASS |
Test totals: 8 passed, 0 failed. Ollama calls made: 0.
What This Tooling Change Guarantees
- Future live experiment runs via the canonical harness are physically incapable of consuming more API calls than explicitly configured.
- Each Start request = exactly one HTTP call (countered by
startCalls). - Each Update request = exactly one HTTP call (countered by
updateCalls). - Rejections stop the chain immediately without retry for any semantic outcome (proposal_compatibility, validation failure, etc.).
- Call accounting always reflects actual API invocations at the point of calling, not inferred from success/failure results.
rejectedProposalSnapshotdiagnostics are preserved and reported when present in Update rejection responses.
What This Does NOT Guarantee
- That production reasoning correctness is improved (no production code changed).
- That cold-start variance in node counts is resolved (start graph stability remains an open issue from Experiments 57J.30, 57J.29).
- That semantic validation outcomes change (only the harness wrapper changed, not any reasoning logic or validator).
- That transport-level HTTP failures are handled (no transport retry was added by this task).
- That zero-node proposals (from Experiment 57J.34) are prevented — a structurally empty proposal can still pass semantic validation.
Files Changed
scripts/reproduce-multi-turn-investigation.mjs— harness hardening: bounded execution, call accounting, no-retry semanticstests/reproduce-multi-turn-investigation.harness.test.js— 8 deterministic harness behavior testsdocs/experiment-57j35.md— this documentdocs/current-handoff.md— handoff entry
Production Impact Assessment
Production reasoning code: UNCHANGED Production API behaviour: UNCHANGED Prompts: UNCHANGED Schemas: UNCHANGED Provider/model integration: UNCHANGED
This is a pure harness/tooling change. No production paths are affected.