{
  "schema": "nutricoach-telegram-checkin-stepper-task-8-r71-recovery-analysis-v1",
  "task_id": "st_01a05ab3",
  "verdict": "recoverable",
  "decision": {
    "generation": "r71",
    "fresh_candidate_root": "/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v15r71-candidate-r2",
    "failed_candidate_root": "/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v15r71-candidate",
    "advance_to_r72": false,
    "reason": "The candidate sealer and verifier accept an arbitrary successor path, candidate identity contains canonical content derivation inputs rather than the candidate directory name, and the still-absent preseal/authorization/execution roots carry the r71 generation. A newly sealed and independently verified digest from task-v15r71-candidate-r2 can therefore be bound into the unchanged r71 preseal and selected by digest. No code or policy guard limits a generation to one candidate directory.",
    "qualification_boundary": "The failed root is not trusted despite its internal QUALIFIED_PENDING_LIVE_AUTHORIZATION strings: the independent candidate verifier returned FAIL, no r71 preseal exists, and its digest is absent from the current authority registry. Only an r2 root that prints NUTRICOACH_V150_CANDIDATE_PASS may proceed."
  },
  "answers": {
    "fresh_unique_attempt_can_remain_r71": {
      "answer": true,
      "evidence": [
        "scripts/seal_nutricoach_v150_candidate.py:168-179 takes --successor as a caller-supplied Path; no generation parser or candidate basename check exists.",
        "scripts/verify_nutricoach_v150_candidate.py:223-333 verifies content under the caller-supplied root and returns a digest; it never parses the root name or generation.",
        "scripts/prepare_nutricoach_v150_v15_preseal.py:33-35 fixes PRESEAL, PREFLIGHT, and AUTHORITY_ID to r71, while lines 192-199 accept any CANDIDATE_ROOT and read its manifest digest.",
        "scripts/prepare_nutricoach_v150_v15_preseal.py:267-300 binds that candidate digest and manifest path into the r71 package.",
        "scripts/verify_nutricoach_v150_preseal_v15.py:110-119 re-verifies the exact candidate_manifest selected by the r71 sealed target.",
        "All r71 effect roots are currently absent, so no r71 authority or one-use package has been consumed."
      ]
    },
    "candidate_root_name_digest_semantics": {
      "candidate_digest": "The candidate root name and absolute root path are not candidate-digest inputs. scripts/seal_nutricoach_v150_candidate.py:247-300 hashes canonical derivation_inputs consisting of base/evidence/wheel/interpreter/source/overlay/v17 hashes. scripts/verify_nutricoach_v150_candidate.py:242-291 independently reconstructs the same mapping. Inventory member paths are candidate-relative (for example snapshot/source/...), not the outer root path.",
      "package_digest": "The selected candidate path is part of the later package digest. scripts/prepare_nutricoach_v150_v15_preseal.py:265-279 includes candidate_manifest=str(candidate_root/manifest.json) and its SHA-256 in the canonical package payload before hashing it. Therefore task-v15r71-candidate-r2 produces a package specifically bound to the r2 manifest path; this is desirable and prevents substitution.",
      "authority_selection": "Current candidate authority is digest-based, not basename- or generation-based. gateway/platforms/task26_candidate_authority.py:125-231 stores candidate_digest in append-only qualify/revoke rows and has no generation/name field. The r71 authority ID belongs to the live package/controller, not to candidate registry identity.",
      "conclusion": "The candidate basename is only an outer path for candidate identity, but that exact path becomes authenticated package payload later. Renaming an existing root is forbidden and unnecessary; a fresh r2 root is selected directly and package-bound in place."
    },
    "hardcoded_references": {
      "must_change": [
        {
          "path": "tests/test_nutricoach_v150_v15_closure.py",
          "current_reference": "lines 31-35 hardcode EVIDENCE to task-v15r71-candidate",
          "required_change": "Change only the final basename to task-v15r71-candidate-r2 so detached closure tests and wheel constants use the verified retry."
        },
        {
          "path": "scripts/seal_nutricoach_v150_candidate.py",
          "current_reference": "lines 192-197 chmod and recursively delete any existing --successor root",
          "required_change": "Replace deletion with an immediate fail-closed successor_exists error. This makes the retry root one-use by construction and prevents accidental mutation of either the failed tombstone or a partially occupied r2 root."
        },
        {
          "path": "tests/test_nutricoach_v150_v15_closure.py (or the focused sealer tests)",
          "current_reference": "No regression currently proves an occupied successor is preserved byte-for-byte.",
          "required_change": "Add a deterministic test that creates an occupied successor sentinel, invokes sealing, expects failure, and proves the sentinel/root hash is unchanged."
        },
        {
          "path": "tests/test_nutricoach_v150_v15_closure.py",
          "current_reference": "_STEPPER_OVERLAY_PATHS lines 46-54 omits tests/gateway/test_nutrition_coaching.py.",
          "required_change": "Add tests/gateway/test_nutrition_coaching.py to the protected qualified-overlay set (or add an equivalent explicit assertion/omission case), so the exact regression that invalidated attempt 1 cannot recur."
        }
      ],
      "already_corrected_in_current_source": [
        {
          "path": "scripts/verify_nutricoach_v150_candidate_inputs.py",
          "change": "Current line 40 includes tests/gateway/test_nutrition_coaching.py in _SUCCESSOR_OVERLAY_PATHS.",
          "proof": "Current SHA-256 is 9ed231a5d0ecb93aeeb7dcd46e91808f533e24ae47c6abb6938fab61599b297f; failed snapshot SHA-256 is ad75b37b5800068a2862852a4f1696f5361c92ad088de1a6a1391291526c50c6 and lacks the member."
        }
      ],
      "must_remain_r71_and_need_no_change": [
        "scripts/prepare_nutricoach_v150_v15_preseal.py:33-35 (r71 PRESEAL/PREFLIGHT/AUTHORITY_ID)",
        "scripts/rehearse_nutricoach_v150_v15.py:35 (r71 PRESEAL)",
        "scripts/rehearse_nutricoach_v150_v15.py:36-38 (task-v15r71-rehearsal; currently absent and still a single fresh rehearsal root)",
        "scripts/nutricoach_v150_detached_bootstrap.py:15-18 (r71 PRESEAL)",
        "scripts/verify_nutricoach_v150_preseal_v15.py:25 (r71 PRESEAL)",
        "scripts/nutricoach_v150_sealed_controller.py:40-44 (r71 sealed-target)",
        "scripts/execute_nutricoach_v150_sealed_live.py:27-31 (r71 detached bootstrap)",
        "tests/test_nutricoach_v150_v15_closure.py:57-63 (assertions that launcher/preseal remain r71)"
      ],
      "later_todo_11_changes_only_after_successful_r71_live_commit": [
        "scripts/nutricoach_v150_observer_runtime.py currently binds r70 execution, authorization, and observer roots; Todo 11 changes these to r71 after Todo 10 succeeds. It is not part of candidate recovery or preseal selection."
      ]
    },
    "failed_root_tombstone": {
      "can_remain": true,
      "trust_exclusion": [
        "Preserve task-v15r71-candidate at mode 0555/0444 and record its current hashes; do not rename, delete, chmod, append, or pass it to any later command.",
        "Its digest aa377308a8967fb8e2557f5283b1c67e5fec0ad2410ce2bee3b4835888cae14f does not occur in the authority registry, whose current qualified candidate remains r70 digest 81a7a06ec2e7a1595784c92ab61df0df7e138d13a2620d9a917e94999e7f7a04.",
        "Do not append a qualification or revocation event for the failed digest. Revocation requires a prior bound qualification (gateway/platforms/task26_candidate_authority.py:166-170), which does not exist; inventing one would broaden/mutate authority unnecessarily.",
        "Preseal and all downstream verification must reference only task-v15r71-candidate-r2/manifest.json and its independently verified digest."
      ],
      "warning": "manifest.json and qualification.json inside the failed root claim QUALIFIED_PENDING_LIVE_AUTHORIZATION because sealing writes that status before independent verification. They are self-claims, not authority. The durable failure evidence and verifier FAIL control trust."
    },
    "single_candidate_per_generation_guard": {
      "exists": false,
      "search_result": "No candidate-generation cardinality guard, generation field, basename parser, or r72 requirement exists in the candidate sealer, candidate verifier, candidate authority registry, preseal preparer, preseal verifier, sealed controller, live launcher, or their searched tests.",
      "actual_one_use_guards": [
        "Candidate output root: must be made fail-if-present; current sealer is unsafe because it deletes an occupied root.",
        "Preseal: prepare_nutricoach_v150_v15_preseal.py:194-195 rejects if either r71 PRESEAL or PREFLIGHT exists.",
        "Preseal verifier: verify_nutricoach_v150_preseal_v15.py:137-141 rejects occupied r71 authorization, execution, or successor-runtime roots.",
        "Live authorization/execution are keyed by the single r71 AUTHORITY_ID and are consumed only by the later exact launcher."
      ],
      "historical_naming_evidence": [
        "The evidence tree contains same-operation retry suffixes such as task-v14r2-rehearsal-r2 alongside task-v14r2-rehearsal.",
        "It contains candidate successors named task26-owner-customer-v1-candidate, -candidate-v2, and -candidate-v3, preserving prior roots.",
        "It contains strict-final-candidate-successor, successor-v2, and successor-v3 roots.",
        "These patterns support unique successor/retry roots rather than mutation. They do not by themselves authorize r71; authorization comes from the current code's path-independent candidate identity plus the unused r71 authority roots."
      ]
    },
    "exact_overlay_fix": {
      "answer": true,
      "exact_mismatch": "Failed verifier output was qualified v17 overlay mismatch: tests/gateway/test_nutrition_coaching.py. The v17 patch tree already lists that path, and the candidate snapshot already contains the current test bytes, but failed inputs/successor-overlay.sha256 omitted it.",
      "minimal_fix": "Generate the r2 successor overlay from the current exact _SUCCESSOR_OVERLAY_PATHS, including tests/gateway/test_nutrition_coaching.py with SHA-256 be7b3afa566a4d326ee8cf123070977d59b36f0570f67447368f5a9f83870ab4.",
      "why_not_broader_trust": "verify_v17_overlay requires exact set equality, then requires each listed digest to match the sealed source inventory, and finally binds each v17 patch-tree member to either its exact overlay digest or its original patch digest (scripts/verify_nutricoach_v150_candidate_inputs.py:97-125). Adding this one already-qualified changed test closes an omission; it does not permit extra paths, wildcard paths, ambient source, or stale bytes.",
      "regression_needed": "The closure test must explicitly protect this path, because the current seven-member _STEPPER_OVERLAY_PATHS would not fail if this test path were removed again."
    },
    "prewrite_absence_and_one_use": {
      "before_any_retry_write": [
        "/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v15r71-candidate-r2",
        "/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v15r71-build-r2-a",
        "/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v15r71-build-r2-b",
        "/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v15r71-inputs-r2",
        "/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v15r71-receipts-r2",
        "/home/cube/projects/richard/traning coach/.omo/evidence/nutricoach-v150-combined/task-v15r71-rehearsal",
        "/home/cube/.hermes/migrations/nutricoach-v1.5.0-combined/live-transaction-preseal-v15-runtime-authority-r71",
        "/home/cube/.hermes/migrations/nutricoach-v1.5.0-combined/preflight-v15-runtime-authority-r71",
        "/home/cube/.hermes/migrations/nutricoach-v1.5.0-combined/live-executions-v15/nutricoach-v150-v15-runtime-authority-r71",
        "/home/cube/.hermes/migrations/nutricoach-v1.5.0-combined/live-authorization-v15/nutricoach-v150-v15-runtime-authority-r71",
        "/home/cube/.hermes/migrations/nutricoach-v1.5.0-combined/observer-r71"
      ],
      "after_r2_digest_is_known_before_preseal": "Also require /home/cube/.hermes/profiles/dualcoachtest/.strict-runtime/<first-8-of-r2-candidate-digest>-v150 absent, because the preseal derives successor_runtime from that digest.",
      "shell_contract": "For each listed path use test ! -e \"$path\" and test ! -L \"$path\" immediately before its owning command. Separately require the failed root exists, is not a symlink, remains 0555/0444, and matches the recorded manifest/qualification/overlay/tree hashes.",
      "candidate_one_use": "Invoke the hardened sealer exactly once against the absent r2 root. Any failure after root creation leaves r2 as another immutable tombstone; never rerun the sealer against it. A further same-generation attempt would require another unique name and a fresh analysis/absence record, not automatic deletion.",
      "preseal_one_use": "Invoke the r71 preparer only after r2 candidate PASS and all r71 roots are absent. PRESEAL/PREFLIGHT creation consumes the only preparation attempt for these names; any partial failure must stop for a new decision rather than delete/reuse them.",
      "live_one_use": "After preseal verification, exact sealed tests, rehearsal, installed-wheel QA, and independent audits pass, perform Todo 10's read-only preflight, require r71 authorization/execution/runtime absent again, and invoke the immutable launcher once with the exact newly derived approval phrase. Never reuse the phrase or call the launcher twice."
    }
  },
  "minimal_recovery_edits": [
    "Keep the already-present one-line addition of tests/gateway/test_nutrition_coaching.py in scripts/verify_nutricoach_v150_candidate_inputs.py::_SUCCESSOR_OVERLAY_PATHS.",
    "Change tests/test_nutricoach_v150_v15_closure.py EVIDENCE basename from task-v15r71-candidate to task-v15r71-candidate-r2.",
    "Add tests/gateway/test_nutrition_coaching.py to the closure test's protected overlay/omission coverage.",
    "Change scripts/seal_nutricoach_v150_candidate.py to reject an existing --successor instead of chmod/rmtree, and add the occupied-root preservation regression.",
    "Do not change any r71 preseal, authority ID, detached bootstrap, controller, live launcher, or rehearsal generation literal. Do not change product behavior or broaden the overlay beyond the one exact missing qualified test."
  ],
  "verification_sequence": [
    {
      "order": 1,
      "action": "Snapshot trust and tombstone state",
      "requirements": "Record hashes below; verify the failed root is immutable; verify authority registry/ledger still select r70 and contain no aa377308... event; verify all retry/r71 roots absent."
    },
    {
      "order": 2,
      "action": "Apply only the four minimal recovery edits",
      "requirements": "Run diagnostics on changed Python files and focused tests proving exact overlay membership, each omission rejection including test_nutrition_coaching.py, r71 launcher literals, and occupied successor preservation. No sealing yet."
    },
    {
      "order": 3,
      "action": "Regenerate fresh r2 inputs and reproducible wheels",
      "requirements": "Use isolated absent build-r2-a/build-r2-b/input/receipt roots; include the exact test_nutrition_coaching.py digest in successor-overlay.sha256; build both wheel pairs; require pairwise SHA-256 equality, ZIP CRC/RECORD validity, and current source/member binding. Do not reuse attempt-1 wheels or inputs."
    },
    {
      "order": 4,
      "action": "Seal r2 once",
      "requirements": "Recheck r2 absence, invoke scripts/seal_nutricoach_v150_candidate.py once with --successor task-v15r71-candidate-r2 and fresh r2 build/input/receipt arguments, then make no write to the root."
    },
    {
      "order": 5,
      "action": "Verify r2 candidate",
      "requirements": "Run scripts/verify_nutricoach_v150_candidate.py with r2/inputs/base-manifest.json, r2 root, and r2/manifest.json; require exit 0 and final sentinel NUTRICOACH_V150_CANDIDATE_PASS. Recompute immutable modes/file set/tree hash; prove attempt-1 hashes and authority registry/ledger hashes unchanged."
    },
    {
      "order": 6,
      "action": "Prepare and verify the unchanged r71 preseal",
      "requirements": "Recheck PRESEAL/PREFLIGHT/authorization/execution and digest-derived successor runtime absence. Invoke prepare_nutricoach_v150_v15_preseal.py with the r2 root and its build-1 wheels exactly once. Require the sealed target authority_id ends r71, candidate_manifest points to task-v15r71-candidate-r2/manifest.json, candidate_digest equals the independently verified r2 digest, and package_digest recomputes including that path. Run verify_nutricoach_v150_preseal_v15.py and require its PASS status."
    },
    {
      "order": 7,
      "action": "Run Todo 9 qualification",
      "requirements": "From outside the worktree run the exact sealed controller/adversarial/safety suite against r2, the 13-case task-v15r71-rehearsal with external_events=0, installed-wheel stepper QA, and independent closure/integrity/privacy audits. Verify no live profile/source/service/network/customer effects."
    },
    {
      "order": 8,
      "action": "Execute approved r71 outcome only after all gates",
      "requirements": "Perform Todo 10's immediate read-only preflight and one exact launcher call using the newly derived package phrase. Verify r71 authorization CONSUMED/SUCCEEDED, execution COMMITTED, runtime/current authority equal the r2 digest, and preserved customer/service invariants. Then perform Todo 11 observer-r71 rebinding and linked manual/timer PASS."
    }
  ],
  "proof_of_approved_outcome": {
    "plan_identity": "The approved outcome is a fresh one-use r71 sealed successor, not a specific candidate digest known in advance. The root basename appears in Todo 8 as the intended first fresh path, but generation authority is concretely enforced by r71 PRESEAL/PREFLIGHT/AUTHORITY_ID/controller/launcher literals and receipts.",
    "retry_identity": "r2 is freshly content-derived after the exact overlay fix and has a new candidate digest; it cannot reuse aa377308... because successor_overlay_sha256 and verifier/source-tree inputs differ.",
    "selection": "The r71 package names and hashes r2/manifest.json, and the r71 preseal verifier independently reruns the candidate verifier against that exact root before authority can be consumed.",
    "old_failure_is_not_erased": "The original root and its FAIL evidence remain immutable and untrusted. The authority chain advances directly from current r70 to the verified r2 digest only during the r71 transaction.",
    "no_silent_r72": "Every operational generation literal remains r71; no r72 path or authority ID is introduced."
  },
  "current_state": {
    "failed_candidate": {
      "candidate_digest_claim": "aa377308a8967fb8e2557f5283b1c67e5fec0ad2410ce2bee3b4835888cae14f",
      "manifest_sha256": "74c146b15a07ef2ee0463de0f4af60f4f71eee932eb899e2890c8151173e6273",
      "qualification_sha256": "b9b9797f55ddb89a200b4fd36a03fba318ea680c297fa8da6623ffb8e6952def",
      "successor_overlay_sha256": "7f49c34759f12883a50fc90e17f4576d7b8c205f2abaeee12b633f68cfbe1171",
      "ordered_file_hash_stream_sha256": "47b84e21fbc7963d1491ad2295093df9dd28dafb1288f404b5efc4dab8bd172e",
      "root_mode": "0555",
      "file_mode": "0444",
      "verifier_result": "NUTRICOACH_V150_CANDIDATE_FAIL:qualified v17 overlay mismatch: tests/gateway/test_nutrition_coaching.py"
    },
    "current_r70": {
      "candidate_digest": "81a7a06ec2e7a1595784c92ab61df0df7e138d13a2620d9a917e94999e7f7a04",
      "package_digest": "77ee2b40b44165233d0a920b19cb5ac7d25bbd76c29b5818315497028fef3042",
      "r70_package_manifest_sha256": "9e00a5ac513e888e6d11b1924f40e8ee93ef70bebab0cb04dfea9695a163bd29",
      "r70_sealed_target_sha256": "bcfca9e16dc25876b55368f28b035e794bf02f5e3bbd98afcaa6613a3e3b8cb7",
      "root_package_supersession_sha256": "07ec0a085d7b9f36c96effd8536b78a9cd23386896a5fc316a83620a6f1fd3d4"
    },
    "authority_registry": {
      "root": "/home/cube/.hermes/runtime-authority/dualcoach-v1.3.0-owner-risk-first-customer/candidate-authority",
      "registry_sha256": "4c3b042f4ae059365c3476f78ab7bc373771788d9f0ab689126f6149bd1994df",
      "qualification_ledger_sha256": "ae1dc8689887655ed23262cbe562b2e288637cc5f5ef7345718509a864be999f",
      "current_qualified_candidate": "81a7a06ec2e7a1595784c92ab61df0df7e138d13a2620d9a917e94999e7f7a04",
      "registry_head_sha256": "94e42900878e851ef3f3295b85b91d27bbd0faf633cbce7c0e34be966967d168",
      "ledger_head_sha256": "e2510596208cd5a9f8cab2c1edd1ccee16d1e80c333a35fcbaa4040b588c4639",
      "invalidated_candidate_digests": []
    },
    "absence_observation": {
      "status": "PASS",
      "observed_absent": [
        "task-v15r71-candidate-r2",
        "task-v15r71-build-r2-a",
        "task-v15r71-build-r2-b",
        "task-v15r71-inputs-r2",
        "task-v15r71-receipts-r2",
        "task-v15r71-rehearsal and task-v15r71-rehearsal-r2",
        "live-transaction-preseal-v15-runtime-authority-r71",
        "preflight-v15-runtime-authority-r71",
        "live-executions-v15/nutricoach-v150-v15-runtime-authority-r71",
        "live-authorization-v15/nutricoach-v150-v15-runtime-authority-r71",
        "observer-r71"
      ]
    }
  },
  "no_effects": {
    "analysis_mode": "read-only except this evidence file",
    "git_or_github_actions": 0,
    "source_edits": 0,
    "migration_root_writes": 0,
    "candidate_or_sealed_root_mutations": 0,
    "sealing_build_preseal_authority_execution_actions": 0,
    "network_customer_service_actions": 0,
    "cleanup_actions": "None required. No temporary roots, processes, services, sockets, builds, preseal paths, or authority paths were created by this analysis. The failed candidate was not chmoded, deleted, renamed, or read through a mutating tool."
  }
}
