# Experiment 57J.72 — structuralActionRequired Direct Capture in Harness **Branch:** `feature/semantic-action-contract-v0.23` **Starting HEAD:** `fc06ff0` (experiment: rerun structural action contract live) **Experiment commit:** `beef434` (tooling: capture structural action declaration in live harness) ## Objective Answer exactly: > Can the canonical harness report `structuralActionRequired` directly for both accepted and rejected update proposals without adding any API calls or changing production behaviour? ## Answer **YES.** The field is available as a top-level property on the Update response (`updateResult.json.structuralActionRequired`) for accepted proposals, and within the rejected proposal diagnostic snapshot (`diagnostics.rejectedProposalSnapshot.structuralActionRequired`) for rejected ones. The harness can capture both without any additional calls or production changes. ## Changes Made ### Harness (`scripts/reproduce-multi-turn-investigation.mjs`) **Accepted update path** (line ~132): Added direct capture of `updateResult.json.structuralActionRequired`, printing: - `structuralActionRequired: ` when the field is present and truthy/falsy - `structuralActionRequired: null` when absent or explicitly null No inference from HTTP status, mutation arrays, or validator outcome. **Rejected update path** (line ~91): Added capture from `diagnostics.rejectedProposalSnapshot.structuralActionRequired`, printing: - `structuralActionRequired (from rejected proposal snapshot): ` when the field exists in the snapshot - `structuralActionRequired: UNAVAILABLE` when the field is absent ### Harness Tests (`tests/reproduce-multi-turn-investigation.harness.test.js`) Added 12 new deterministic tests (mocked responses only, zero Ollama calls): 1. accepted update with `structuralActionRequired=true` reports `true`; 2. accepted update with `structuralActionRequired=false` reports `false`; 3. accepted update with absent field reports `null`; 4. accepted update with explicit null reports `null`; 5. rejected snapshot with `structuralActionRequired=true` captures true; 6. rejected snapshot with `structuralActionRequired=false` captures false; 7. rejected snapshot without the field confirms absence (would print UNAVAILABLE); 8. existing answerMeaning capture unchanged; 9. existing mutation/persistent-graph capture unchanged; 10. no extra HTTP calls introduced; 11. no-retry and call accounting preserved across both paths. ## Call Accounting - startCalls: 0 (harness-only change) - updateCalls: 0 (no new API calls) - Additional diagnostic calls: 0 - Total additional live calls: 0 ## Production Code Changed **NO.** Only harness capture added to the observable output layer. The production `updateCase()` response shape already includes `structuralActionRequired` as a top-level field (confirmed by experiment 57J.69 and 57J.71 observations). ## Prompt / Schema / Validator Changes None. This is purely an observability hardening of the harness. ## Test Results **29 tests pass** (17 existing + 12 new) via mocked responses only. ## Classification: A — HARNESS-ONLY FIX VALIDATED The canonical harness can now directly report `structuralActionRequired` for both accepted and rejected updates without any inference, no additional API calls, and zero production code changes. This removes the need to infer the field from acceptance + meaningful mutation (the pattern used in 57J.71). ## Dependencies Preserved - 57J.62 capture hardening (accepted-update console block structure) - 57J.70 authoritative guard (validator in lib/graph/utils.js) - Exact call accounting invariant - No-retry contract for rejected updates