/**
 * Tier 1 runner: the RHA pipeline with no hands.
 *
 * Runs the passive algorithm — encode → structural gates → frozen IR → build —
 * entirely in memory against any LlmClient. No filesystem, no child processes,
 * no server: the browser extension bundles this and drives the user's own LLM.
 * The Tier 2 exclusives (tsc typecheck, vitest execution, sandboxed repair
 * sweeps) are deliberately absent; the artifact carries its frozen suites so
 * any Node environment can run them after export.
 */
import type { FeatureNode, FeatureSpec, Finding, GeneratedFile, LedgerRow, LlmClient, RepairInput } from '../core/types';
import {
  boundaryViolations,
  offendingFeatureIds,
  preSanitizeSpec,
  resolveDependencyIds,
  topoOrder,
  validateSpec,
  validateSuiteShape,
} from '../core/specGates';
import { converge } from '../core/bounded';
import { assembleTestFile } from '../core/irScaffold';
import type { IRCaseGen, IRParts } from '../core/irScaffold';
import {
  attributeBoundaryFault,
  attributeEvalCrash,
  attributeEvalCrashDetailed,
  caseSyntaxErrors,
  ddminForQuarantine,
  ddminHealWithOracle,
  distillProgramParseLessonKey,
  dumpConcatenationSeams,
  dynamicEvalLint,
  findTranspilePlaceholders,
  probeErrOrNull,
  probeModuleEval,
  probeWholeArtifactEval,
  suiteSyntaxError,
  traceSymbolCallsAsync,
  vetArtifactWritesAsync,
  vetProgramParseAfterWriteAsync,
} from './testExec';
import type { SuiteRunner } from './testExec';
import { buildFlawedExhibit } from './exhibit';
import { buildTracePage, extractTraceCalls, traceEligible } from './traceCapture';
import {
  corpseCheck,
  drawHashForFiles,
  formatCorpseEvent,
} from './metaSb';
import type { MetaCandidateRecord } from './metaSb';
import {
  chooseInvariants,
  conformDrawToSkeleton,
  formatGrammarConform,
  renderSkeleton,
  skeletonPrompt,
} from './grammar';
import type { RenderedSkeleton } from './grammar';
import {
  buildFileFrame,
  formatShellLock,
  formatShellLockFallback,
  formatShellLockPrevented,
  lockDrawToFrame,
} from './shellLock';
import { Tier1Supergit, formatSupergitSummary } from './supergit';
import {
  buildNodeRepairDossier,
  buildNodeSchema,
  formatNodeRepairEvent,
} from './nodeRepair';
import {
  buildEpochDigest,
  formatUnionPage,
  formatWatchEvent,
  parseWatchReport,
  watchPrompt,
} from './watcher';
import type { WatchDisposition, WatchEpoch } from './watcher';
import {
  ObservationLedger,
  OBSERVATION_POLLS,
  astFacts,
  formatAstFacts,
  formatObservatoryEvent,
  formatObservatoryPage,
  parsePoll,
  pollPrompt,
} from './observatory';
import type { Observation } from './observatory';
import {
  createAgentHealth,
  failureDetail,
  noteFailure,
  noteSuccess,
} from './agentHealth';
import type { AgentHealth } from './agentHealth';
import {
  formatJudgmentEvent,
  formatRulingStamp,
  licenseChainFor,
} from './judgment';
import type { JudgmentDecision, JudgmentEvidence } from './judgment';
import {
  formatBornRedEvent,
  formatThrowCamouflage,
  hasRedCase,
  isStubDerivedThrowCase,
  isThrowCamouflaged,
  scoreBornRed,
  stubArtifact,
  VACUOUS_CASE_FINDING,
} from './bornRed';
import { conformExportsToStubs } from './exportConformance';
import { wireSuiteScaffoldImports } from './suiteScaffoldWire';
import {
  commitFrozenSuite,
  certifyArtifact,
} from './frozenSuiteGateway';
import type {
  CommitFrozenSuiteResult,
  FrozenState,
  FrozenSuiteReport,
} from './frozenSuiteGateway';
import {
  DefectRegistry,
  classifyFindingCategory,
  buildCanonicalKey,
  SUITE_SENTINEL,
} from './defectRegistry';
import type { DefectRegistrySnapshot } from './defectRegistry';
import { ActionLedger } from './actionLedger';
import type { ActionLedgerSnapshot } from './actionLedger';
import { ArtifactState } from './artifactState';
import {
  promoteLessonsToHandlerCandidates,
  distillEditShape,
} from './handlerCandidate';
import type { HealedInstance } from './handlerCandidate';
import {
  countMatchingTemplatesForPlan,
  matchConsumableTemplate,
  encodeOutputCanonical,
  formatAttributionMissEvidence,
  formatClassKeyCoverageRule,
  formatContinueProjectReplanNote,
  formatParsePoisonIncidents,
  formatPermanentDeferral,
  formatPlannerBypass,
  formatSolutionStrataTable,
  formatSpecHashLine,
  formatSubstrateHitRate,
  formatSuperbufferEfficacy,
  formatUnparseableDropReason,
  loadSolutionStrataTable,
  programStateHash,
  resolveSpecHashMatch,
  sha256Hex8,
  shouldEmitSeamDumps,
} from './reportEvidence';
import type { ClassKeyCoverageStratum } from './reportEvidence';
import type { EfficacyBucket } from './reportEvidence';
import {
  emptySubstratePageEfficacy,
  formatSubstratePageEfficacy,
  noteSubstratePageEfficacy,
} from './statsAggregate';
import {
  buildSubstrateHandoff,
  type SubstrateHandoffAttempt,
} from './substrateHandoff';
import {
  acceptCaseBody,
  attemptMechanicalFix,
  bindFixTestCases,
  caseNamesMatch,
  checkedIdiomsText,
  classifyFailure,
  crashRepairPrecondition,
  distillLesson,
  dominantClass,
  findPromptLineNumber,
  formatAssertionDiff,
  formatAttemptStatus,
  formatEmptyDraws,
  healCaseBody,
  isCrashClass,
  isEmptyDrawMessage,
  matchLessons,
  normalizeCrashSignature,
  polishParseCrashContent,
  refusesImplRedrawForOwnedSymbol,
  refusesModelDraw,
  isStubNotImplementedClass,
  isOwnedSymbolStillStub,
  promptHasVerifiableResidue,
  scanCapabilities,
  strategyOrderForClass,
  unwrapCaseBody,
} from './substrate';
import type { CapabilityHit, ClassifiedFailure, MechanicalFixAttempt, Tier1Lesson } from './substrate';
import { applyDelimiterOracle } from './delimiterOracle';
import { formatRepairOracleHint } from './repairOracle.generated';
import {
  assembleSuperbuffer,
  draftCladePromotion,
  encodeFeatureSpecText,
  formatCladeCandidateMessage,
  formatConceptDrawEvent,
  formatSuperbufferForPrompt,
  freeformPatternKey,
  shouldProposeCladePromotion,
} from './superbuffer';
import type { CladePromotionProposal } from './superbuffer';
import { assembleContext } from './assembleContext';
import {
  allowedSymbols,
  injectClassAnchor,
  planSuite,
  surfaceConformanceErrors,
} from './planSuite';
import type { PlannedCase } from './planSuite';
import { applyTemplates } from './testgen';
import { formatFillBatchTargets, formatFillDropMessage } from './fillHonesty';
import { substrateFillOne } from './substrateFill';
import { assembleCaseFrame, extractHole, isBuildOverreach, isOverreach } from './frame';
import type { CaseFrame } from './frame';
import { BUILD_SYSTEM_HOLE, IR_SYSTEM_HOLE } from '../core/prompts';
import {
  deferralMessage,
  dependencyUncoveredProblem,
  effortFloor,
  makeWorldSignature,
  metaloop2Message,
  metaloop3Message,
  noCoverageProblem,
  orderRootsFirst,
  replanMessage,
  skipNoTrackMessage,
  uncoveredSummary,
  worldChanged,
} from './fillRelay';
import type { MetaloopPhase, WorldSignature } from './fillRelay';
import { METHOD_ANCHOR_CLADE, classifyCaseClade, cladeRatio, isMethodAnchorName, methodAnchorBody, rebindCladeBody } from './clades';
import {
  ESCALATED_TEMP,
  PERMUTATION_TEMPS,
  defaultBatchParams,
  escalateBatchParams,
  escalateEntropyEvent,
  incumbentKeptEvent,
  isStrictImprovement,
  permutationEvent,
  selectPermutation,
} from './permutation';
import type { BatchParams, PermutationCandidate } from './permutation';
import {
  FAILURE_STACK_INSTANCE_CAP,
  emptyFailureStack,
  formatRelayReenter,
  formatStackDropReason,
  formatStackRepairPrompt,
  mayReenter,
  popDeferredFailure,
  pushDeferredFailure,
  rememberWorld,
  worldDelta,
} from './failureStack';
import type { FailureStackState } from './failureStack';
import { formatCatalogDriftTripwire } from './errorCatalog.generated';

/** SET 16d — prepend oracle hint to every fixTestCases error list. */
function withOracleHints(
  broken: { name: string; kind: IRCaseGen['kind']; errors: string[] }[],
): { name: string; kind: IRCaseGen['kind']; errors: string[] }[] {
  return broken.map(b => {
    const key = classifyFailure(b.name, b.errors[0] ?? '').classKey;
    return { ...b, errors: [formatRepairOracleHint(key), ...b.errors] };
  });
}

export interface Tier1Event {
  ts: string;
  phase: 'encode' | 'gate' | 'ir' | 'build' | 'auth' | 'rha' | 'done';
  featureId: string | null;
  message: string;
}

export interface Tier1Metrics {
  elapsedMs: number;
  /** Convergence passes, total and per feature — the cycle counts. */
  passesTotal: number;
  passesPerFeature: Record<string, number>;
  repairDraws: number;
  freshDraws: number;
  /**
   * SET 18e — IR surgery OPERATIONS (suite re-freeze events) only.
   * Caps: ≤2 crash + ≤1 persistent per feature.
   */
  irSurgeries: number;
  /** SET 14a / 18e — IR-phase generation attempts (not cycles, not surgeries). */
  irGenAttempts: number;
  /** Failures resolved by the substrate with ZERO tokens. */
  mechanicalFixes: number;
  /**
   * SET 98 — substrate fixes from catalog-drift|missing-new|<Sym>
   * (insert-`new` / const→constructor). Subset of mechanicalFixes.
   */
  catalogDriftMechanicalFixes: number;
  /**
   * SET 102 — program-parse write-acceptance heals via applyDelimiterOracle
   * for "Invalid regular expression" (0 tok). Distinct from mechanicalFixes
   * aggregate so this gate win is auditable (doctrine 11).
   */
  regexLiteralGateHeals: number;
  /** SET 100a — fill candidates healed then rejected by surface/accept gate. */
  healedButRejected?: number;
  /** SET 100c — assertable lines collapsed to whole-exclude (empty residue). */
  deferredResidueEmpty?: number;
  /** SET 100d — encode refused before LLM (no verifiable prompt residue). */
  encodeRefusedNoResidue?: number;
  /** SET 93 — cases dropped before surgery because their entire throw contract derives from a throwing stub. */
  bornRedStubDerivedDrops: number;
  /**
   * SET 16a / SET 89 §9.1 — substrate attempt partition. Every call to
   * `attemptMechanicalFix` creates exactly ONE attempt record and exactly
   * ONE terminal status. Conservation:
   *   `substrateAttempts = substrateFixes + substrateRefusals + substrateNoHandler`.
   * `substrateFixes` is the fixed-attempt count (aka
   * `substrateFixedAttempts` in the SET 89 §9.1 vocabulary). It is NOT the
   * "edits applied" count — that lives in `substrateEditsApplied` +
   * `deterministicEditsOutsideSubstrate` and may exceed fixed attempts
   * when one proven attempt edits multiple files. Scaffold-wire and
   * shell-lock edits are deterministic edits OUTSIDE this partition and
   * do NOT increment `substrateFixes` (they would inflate hit-rate).
   */
  substrateAttempts: number;
  substrateFixes: number;
  substrateRefusals: number;
  substrateNoHandler: number;
  /**
   * SET 89 §9.1 — total edits applied by FIXED substrate attempts. One
   * fixed attempt with two edits contributes `substrateFixes: 1` and
   * `substrateEditsApplied: 2`. Not a rate numerator; do not use as
   * `substrateFixes` synonym.
   */
  substrateEditsApplied: number;
  /** SET 97 — planned fill cases resolved before the LLM ladder. */
  substrateFillHits: number;
  /** SET 97 — planned fill cases that require an LLM after substrate exhaustion. */
  substrateFillEscalations: number;
  /** SET 97 — attempted mechanisms that produced no executable candidate. */
  substrateFillEmptyMechanisms: number;
  /** SET 97 — executable candidates that passed stubs (therefore vacuous). */
  substrateFillVacuousMechanisms: number;
  /**
   * SET 95 — draws rejected because the response omitted the `⟨HOLE⟩ … ⟨/END⟩`
   * marker, exceeded the hole's 1.5× byte budget, or reproduced boilerplate
   * (`describe(`/`it(`/`test(`/`import `) outside the marker.
   */
  overreachBodyRejections: number;
  /**
   * SET 89 §9.1 — deterministic edits outside `attemptMechanicalFix`
   * (scaffold-wire injection, shell-lock frame drops, template fills,
   * etc). These are honest bytes-of-fix; they must NOT inflate
   * `substrateFixes` (which would falsify actionable hit-rate).
   */
  deterministicEditsOutsideSubstrate: number;
  /** SET 2 — cases filled from the verified template bank (0 tokens). */
  templatedCases: number;
  /** SET 3a — permutation draws / wins (legacy; prefer perm*). */
  permutationDraws: number;
  permutationWins: number;
  /** SET 14g — permutation taxonomy. */
  permBatches: number;
  permCandidates: number;
  permImproved: number;
  /** SET 17 — superbuffer draws / wins. */
  superbufferDraws: number;
  superbufferWins: number;
  /** SET 37f — bounded concept ideation draws (context only). */
  conceptDraws: number;
  /** SET 38c — program-parse poison rejections this run. */
  parsePoisonIncidents: number;
  /** SET 3b / 18f — aggregate Σ schemad : Σ freeform across features. */
  cladeRatio?: string;
  /** Findings observed on first authentication, healed by the ladder, remaining. */
  bugsObserved: number;
  bugsPatched: number;
  bugsRemaining: number;
  /**
   * SET 31c — distinct artifact faults (crash-class findings collapsed by
   * normalized crash signature). One artifact fault may affect many features;
   * `bugsObserved`/`bugsRemaining` dedupe crash entries by signature so
   * "N failing features with the same regex crash" reports as 1 fault, not N
   * bugs. Assertion failures remain per-case.
   */
  artifactFaults: number;
  artifactFaultsRemaining: number;
  /** SET 31c — total feature count affected across all artifact faults. */
  artifactFaultsAffectedFeatures: number;
  /** SET 57a — run-report counters. Incremented at event-emission sites, never
   * derived by re-parsing log text. Candidate granularity = one model draw;
   * accepted = the drawn candidate won selection and improved the incumbent. */
  featuresTotal: number;
  featuresFrozenWithoutRedraw: number;
  irRedraws: number;
  /**
   * SET 89 §12.1 — feature-scoped repair metrics. The "nodes" prefix is
   * historical; the bounded repair ladder schedules per FEATURE, not
   * per declaration or AST node. Truthful alias names are documented
   * here so downstream consumers do not imply declaration-level repair:
   *   - `nodesTotal`                → `featuresMeasuredForRepair`
   *   - `nodesBuildable`            → `featuresBuildableAtRepair`
   *   - `nodesBuilt`                → `featuresBuilt`
   *   - `nodesBuiltCleanFirstPass`  → `featuresGreenFirstPass`
   *   - `boundedLoopNodes`          → `featuresEnteredBoundedRepair`
   *   - `boundedLoopIterations`     → `featureRepairIterations`
   *   - `nodesHealed`               → `featuresHealed`
   * Declaration-level metrics require a real AST identity system
   * (§12.3) that this codebase does not yet own — until then, do NOT
   * label any of these fields as declaration- or node-level in the UI.
   */
  nodesTotal: number;
  nodesBuildable: number;
  nodesBuilt: number;
  nodesBuiltCleanFirstPass: number;
  boundedLoopNodes: number;
  boundedLoopIterations: number;
  candidatesDrawn: number;
  candidatesAccepted: number;
  /** SET 63 — candidatesDrawn split by layer (fill = IR, repair = bounded loop). */
  fillCandidatesDrawn: number;
  repairCandidatesDrawn: number;
  /**
   * SET 89 §8.4 — per-layer accepted counters. `fillCandidatesAccepted`
   * counts every candidate at the fill layer (initial IR fill, case-relay
   * recovery) whose disposition is `adopted`; `repairCandidatesAccepted`
   * counts the same at the bounded-repair layer. Sum across layers equals
   * `candidatesAccepted` (subset of `candidatesDrawn`).
   */
  fillCandidatesAccepted: number;
  repairCandidatesAccepted: number;
  /** SET 60 — losing candidates' validated cases composed into the suite. */
  salvagedCases: number;
  /** SET 66 — test-RHA at freeze: red-for-the-wrong-reason cases and their
   * freeze-gate repairs; RHA-phase IR surgery is metered separately (target 0). */
  sickRedCases: number;
  testRhaSubstrateFixes: number;
  testRhaDraws: number;
  /** SET 92 — freeze-gate test-rha conservation partition (doctrine 7/11). */
  testRhaSuperbufferAssemblies: number;
  testRhaDrawThrew: number;
  testRhaDraftRejected: number;
  testRhaDraftAcceptedCleared: number;
  testRhaDraftAcceptedStillSick: number;
  testRhaSkippedNoHandle: number;
  testRhaSkippedAlreadyRedrawn: number;
  testRhaCaseExhausted: number;
  testRhaCaseCleared: number;
  irSurgeriesInRha: number;
  /** SET 70 — dropped-at-fill cases re-enqueued for the warm-world case-relay,
   * and how many it recovered into the frozen contract. */
  reEnqueuedCases: number;
  recoveredCases: number;
  /** SET 64 — L2 schema-guided interpretation rung (K=1, ≤3 loops/class). */
  l2Draws: number;
  l2Wins: number;
  l2Bullseyes: number;
  /** SET 64 — fixes attributed by layer: L1 substrate, L2 schema-guided,
   * L3 free permutation, L4 entropy reset. */
  fixesL1: number;
  fixesL2: number;
  fixesL3: number;
  fixesL4: number;
  /** SET 64 — identical draws rejected without execution (both caches). */
  corpseRejections: number;
  /** SET 64 — classification floor accounting (target ≥95% cataloged). */
  classifyAttempts: number;
  classifyCataloged: number;
  /** SET 65 — synthesis-grammar fill outcomes (flagged). */
  grammarConformant: number;
  grammarFallbacks: number;
  /** SET 65 — shell-locked build re-emissions (flagged). */
  shellLockApplied: number;
  shellLockFallbacks: number;
  /** SET 76 — the resident watcher: syntheses fired (one per context-submission
   * trigger), model readings actually taken, observations named. */
  watcherSyntheses: number;
  watcherReadings: number;
  watcherObservations: number;
  /** SET 94 — watcher cache and deterministic stale-world dispositions. */
  watcherCacheHits: number;
  watcherCacheMisses: number;
  watcherWorldStaleSkips: number;
  /** SET 96b canary — candidate-zero primary-fill prompts carrying the digest. */
  watcherInfusedCandidates: number;
  /** SET 94 — bad candidates beyond the six-slot per-case draw budget. */
  corpseRejectionCeilingBreaches: number;
  /**
   * SET 88 — agent-engine failures, per agent. A run with readings==0 and
   * failures==0 had no engine; readings==0 with failures>0 had one that threw,
   * and the event log now names what it threw.
   */
  watcherEngineFailures: number;
  observatoryEngineFailures: number;
  /** SET 80 — repairs that saw the actual node + its schema (repair-in-place). */
  nodeRepairDraws: number;
  nodeRepairWins: number;
  /** SET 85 — the append-only observatory: decoupled polls and what they accrued. */
  observationPolls: number;
  observationsNew: number;
  observationsCorroborated: number;
  /** SET 101a — stub-not-implemented findings routed past L2 (absence, not defect). */
  stubRouteShortcuts: number;
  /** SET 101b — observatory poll batches skipped (world unchanged). */
  observatoryPollsSkipped: number;
  /** SET 101c — L2 loops short-circuited after pass-1 no-improvement + unchanged findings. */
  l2ShortCircuits: number;
  /** SET 101d — files whose ladder was suspended pending a fresh draw. */
  quarantineSuspensions: number;
  /** SET 68 — judgment gates: total fired, rulings by source, drops. */
  judgmentGates: number;
  judgmentOperator: number;
  judgmentLlm: number;
  judgmentDropped: number;
  /**
   * SET 89 §10.5 — canonical finding-occurrence and unique-defect counters.
   * Sourced from the DefectRegistry at `syncMetricsFromLedgers()`; never
   * incremented independently. `errors*` are legacy aliases carried for one
   * release of UI/host compatibility — same values, new names authoritative.
   */
  findingOccurrencesTotal: number;
  findingOccurrencesParse: number;
  findingOccurrencesConformance: number;
  findingOccurrencesExecution: number;
  findingOccurrencesCrash: number;
  findingOccurrencesTestFailure: number;
  uniqueDefectsObserved: number;
  uniqueDefectsResolved: number;
  uniqueDefectsUnresolved: number;
  /**
   * SET 89 §11.4 — action ledger counters. Sourced from the ActionLedger
   * at `syncMetricsFromLedgers()`.
   */
  actionStarts: number;
  actionTerminals: number;
  actionDecisions: number;
  actionPending: number;
  actionFailed: number;
  /**
   * SET 89 §11.4 Gap E — nonfatal action failures (host-callback throws,
   * concept-draw provider errors, judgment-resolver throws, etc.). These
   * do not fail the run but MUST be visible in the UI; the aggregated
   * `actionFailed` counter above sums fatal + nonfatal, so a UI that
   * only shows `actionFailed` cannot distinguish "the run crashed
   * substantively" from "one host callback threw once".
   */
  actionFailedNonfatal: number;
  /**
   * Legacy aliases (kept for one release). Derived from
   * `findingOccurrences*` in `syncMetricsFromLedgers()`. Never incremented
   * independently.
   */
  errorsTotal: number;
  errorsParse: number;
  errorsConformance: number;
  errorsExecution: number;
  errorsCrash: number;
  deferredTotal: number;
  deferredRelitigated: number;
  deferredResolvedAfterRelitigation: number;
  deferredPermanent: number;
  nodesHealed: number;
  fixesUnsuccessful: number;
  fixesUnparseable: number;
}

/** SET 3c — intent provenance chain per planned case. */
export interface CaseProvenance {
  caseName: string;
  kind: string;
  license: string;
  source: string;
  featureId: string;
  featureDescription: string;
  prompt: string;
}

export interface Tier1Result {
  /** SET 100d — early terminal when encode refuses before any LLM draw. */
  status?: 'refused';
  reason?: string;
  spec: FeatureSpec;
  /** Implementation files (built where possible, stubs where not). */
  files: GeneratedFile[];
  /** Frozen IR suites, one per feature that passed IR validation. */
  frozenTests: GeneratedFile[];
  /** Structural problems left unresolved after bounded repair. */
  problems: string[];
  metrics: Tier1Metrics;
  log: Tier1Event[];
  /** SET 3c — case → export/edge → feature.description → prompt. */
  provenance: CaseProvenance[];
  /** SET 4a — corpus appVersion + sha256 of the harness contract block. */
  contractVersion?: string;
  /** SET 4b — out-of-scope prompt items disclosed by the capability scanner. */
  deferred?: CapabilityHit[];
  /**
   * SET 34 — claim-bound report evidence lines (seam dumps, spec hash,
   * efficacy, planner-bypass). Also emitted on `log` for hosts that only
   * surface events/problems.
   */
  evidence?: string[];
  /**
   * SET 74 — supergit L3 ledger for THIS run: the append-only decision graph
   * (same schema as the Tier 2 substrate). Materialized into the exported
   * repository under `.supergit/`; carried on the record so the ledger
   * survives the run.
   */
  supergit?: {
    rows: LedgerRow[];
    csv: string;
    graph: { nodes: unknown[]; edges: { from: string | null; to: string | null }[] };
  };
  /**
   * SET 89D — whole-artifact certification. `artifactCertified: true` means
   * every frozen suite is currently certified against the FINAL artifact.
   * Set to `false` when any suite is provisional, gate infrastructure was
   * unavailable, or one or more re-certifications rejected. Absent when the
   * host provided no `runSuite` (no certification predicate can run).
   */
  artifactCertification?: {
    artifactCertified: boolean;
    unresolved: string[];
    gateInfrastructureUnavailable: boolean;
  };
  /**
   * SET 89 §§10 / 11 — the canonical append-only records for this run.
   * `defectRegistry` carries occurrences + resolutions + identity states;
   * `actionLedger` carries every start + terminal + decision. Exported into
   * `.supergit/defects.jsonl` and `.supergit/actions.jsonl` by exportRepo.
   */
  defectRegistry?: DefectRegistrySnapshot;
  actionLedger?: ActionLedgerSnapshot;
}

export interface Tier1Gates {
  /** Bounded spec-repair rounds (corpus gates.json: gateRounds). */
  gateRounds: number;
  /** Per-feature IR regeneration attempts. */
  irAttempts: number;
  /** Per-feature convergence ceiling (corpus: maxPasses, capped for Tier 1). */
  maxPasses: number;
  /** Identical-signature passes before stall (corpus: stallLimit). */
  stallLimit: number;
  /** Passes without meaningful improvement before stall (corpus: progressStall). */
  progressStall: number;
  /** SET 65 — synthesis grammar for IR fill (skeletons + typed holes). OFF by default. */
  grammarEnabled?: boolean;
  /** SET 65 — shell-locked codegen (deterministic frame, body-only draws). OFF by default. */
  shellLock?: boolean;
  /** SET 96b canary — fold the primary fill watcher into candidate zero. OFF by default. */
  set96bFoldWatcherIntoCandidate0?: boolean;
  /**
   * SET 95c canary — hole-only draws at the primary fill site ONLY. When on,
   * every draw at that site must return a single `⟨HOLE⟩ … ⟨/END⟩` block or
   * it is rejected as `overreach|body` (no fallback, no freeform accept).
   * OFF by default: this is a hard-reject gate (unlike grammar/shell-lock's
   * soft reassembly-or-passthrough), so every pre-95 fixture and mock that
   * returns a plain case body would otherwise regress wholesale. Flip on
   * once callers (MockLlm/LocalLlmClient/ClaudeClient) speak the wire format.
   */
  holeOnlyFill?: boolean;
}

export const TIER1_DEFAULT_GATES: Tier1Gates = {
  gateRounds: 3, irAttempts: 2, maxPasses: 8, stallLimit: 2, progressStall: 4,
  // SET 73 — grammar + shell-lock ON by default (Andy: "too many LLM calls
  // rejected with how much we are preparsing"). The skeleton constrains the
  // draw so conformant output is REASSEMBLED instead of rejected; the frame
  // makes build-side parse poison structurally impossible. Nonconformant
  // draws still fall back to the freeform path — nothing new is rejected.
  grammarEnabled: true, shellLock: true,
  set96bFoldWatcherIntoCandidate0: false,
  holeOnlyFill: false,
};

/**
 * SET 95d — shared hole-only wiring for every SINGLE-case fixTestCases call
 * site (fill was the SET 95c canary; this rolls the same three-step contract
 * to the rest: fallback fill, born-red surgery, test-rha, case-relay,
 * repair). Multi-case batches are left ungated here, same as the canary
 * (`assembleCaseFrame` is one hole per frame — a batch of N cases has no
 * single frame to attach the contract to without redesigning the batch
 * wire format, which is out of scope for this rollout).
 */
function holeOnlyFrameFor(
  gates: Tier1Gates, feature: FeatureNode, name: string, kind: IRCaseGen['kind'],
): CaseFrame | null {
  return gates.holeOnlyFill ? assembleCaseFrame(feature, name, kind) : null;
}

/** SET 95d — the hole contract + frame, rendered as a prompt block (empty when the frame is null). */
function holeOnlyPromptBlock(frame: CaseFrame | null): string {
  if (!frame) return '';
  return [
    IR_SYSTEM_HOLE,
    'The frame already exists — do not repeat it:',
    frame.bytes,
    `Assertion budget: ${frame.holeBudgetBytes} bytes (hard cap ${Math.round(frame.holeBudgetBytes * 1.5)}).`,
  ].join('\n');
}

/**
 * SET 95d — overreach|body gate for a single-case draw's response. A no-op
 * (frame null) passes `body` through unchanged. On rejection the caller
 * decides how to react (skip the candidate, continue the ladder) — this
 * function only records the finding and reports the disposition.
 */
function applyHoleOnlyGate(
  frame: CaseFrame | null,
  body: string,
  metrics: Tier1Metrics,
  caseName: string,
  emitMsg: (msg: string) => void,
): { body: string; rejected: boolean } {
  if (!frame) return { body, rejected: false };
  const overreach = isOverreach(body, frame.holeBudgetBytes);
  if (overreach.over) {
    metrics.overreachBodyRejections++;
    emitMsg(`case "${caseName}" rejected overreach|body: ${overreach.reason}`);
    return { body, rejected: true };
  }
  return { body: extractHole(body).body ?? body, rejected: false };
}

/** Decorrelation ladder for repeated draws on the same unit. */
const TEMPS: (number | undefined)[] = [undefined, 0.5, 0.75, 1.0];

/** SET 64 — L2 schema-guided interpretation: K=1 per loop, ≤3 loops/class. */
const L2_TEMPS = [0.3, 0.7, 1.0] as const;

export async function runTier1Job(opts: {
  /**
   * User-facing / provenance prompt (RAW — never includes the harness
   * contract). Capability scan defaults to this string.
   */
  prompt: string;
  /**
   * SET 4a — prompt the encoder actually sees (user prompt + harness
   * contract). Defaults to `prompt` when omitted (unit tests / offline).
   */
  encodePrompt?: string;
  /** SET 4a — corpus appVersion + sha256 of the contract block. */
  contractVersion?: string;
  /** SET 4b — text to scan for out-of-scope capabilities (defaults to prompt). */
  rawPrompt?: string;
  llm: LlmClient;
  gates?: Partial<Tier1Gates>;
  /**
   * Cooperative cancellation: checked between draws and passes — the current
   * LLM call completes, then the run stops with a "cancelled" error.
   */
  isCancelled?: () => boolean;
  /** SET 59b — HIL approval gates: awaited after the IR contract freezes
   * (before any build) and after build (before authenticate/RHA). The host
   * decides whether to pause; omitted = straight through (prior behavior). */
  onPhaseGate?: (gate: 'ir-contract' | 'build') => Promise<void> | void;
  /** Substrate lessons (corpus + local) matched into repair prompts by classKey. */
  lessons?: Tier1Lesson[];
  /** Live metrics snapshot after every event — powers mid-run dashboards. */
  onMetrics?: (m: Tier1Metrics) => void;
  /** Called when a failure class heals — the distilled lesson persists across runs. */
  onLesson?: (lesson: Tier1Lesson) => void;
  /**
   * SET 17 — clade-promotion proposal when the same freeform pattern wins ≥3 times
   * via superbuffer. Host persists (extension storage); never auto-admitted.
   */
  onCladeCandidate?: (proposal: CladePromotionProposal) => void;
  /**
   * Authenticate hook: executes one frozen suite against the artifact.
   * When provided, the run continues past build into authenticate + RHA —
   * the complete algorithm. Without it, the run honestly reports that the
   * suites were not executed.
   */
  runSuite?: SuiteRunner;
  onEvent?: (e: Tier1Event) => void;
  /**
   * SET 92g — test-only: suppress emit lines matching this regex (log/onEvent
   * only; counter increments at call sites still fire). Mutation harness uses
   * this to prove each new test-rha disposition line is load-bearing.
   */
  _suppressEmit?: RegExp;
  /**
   * SET 34c — prior encode-output hashes for the same prompt lineage.
   * When the current sha256-8 matches, the report says `matches run <id>`;
   * otherwise `NEW carve`.
   */
  priorSpecHashes?: { runId: string; hash: string }[];
  /**
   * SET 37g — continue-project: case names dropped in a prior epoch.
   * Replanned FIRST (coverage backfill) before compiling new features.
   */
  priorDroppedCaseNames?: string[];
  /** SET 38c — prior-run parse-poison count for recurrence report line. */
  priorParsePoisonIncidents?: number;
  /** SET 64 — metasupercache inputs from prior epochs (host-loaded). */
  metaSb?: { corpseHashes?: string[] };
  /** SET 64 — candidate record sink; host persists under metaSb:<runId>. */
  onMetaCandidate?: (rec: MetaCandidateRecord) => void;
  /** SET 85 — observations carried in from prior epochs (append-only corpus). */
  observations?: Observation[];
  /** SET 85 — observation sink; the host persists them in the supercache. */
  onObservation?: (o: Observation) => void;
  /** SET 68 — judgment gate resolver. Supervised hosts pause on the card and
   * return the operator's decision; unsupervised hosts take ONE fresh LLM
   * ruling over the identical evidence. null/undefined → no gate (old
   * behavior: the ladder proceeds to L3). ≤1 gate per case, runner-enforced. */
  onJudgment?: (evidence: JudgmentEvidence) => Promise<JudgmentDecision | null | undefined> | JudgmentDecision | null | undefined;
}): Promise<Tier1Result> {
  const gates = { ...TIER1_DEFAULT_GATES, ...opts.gates };
  const startedAt = Date.now();
  /** SET 40a — emit parse-gate CSP skip at most once per run (dim). */
  let parseGateUnavailableEmitted = false;
  const metrics: Tier1Metrics = {
    elapsedMs: 0, passesTotal: 0, passesPerFeature: {},
    repairDraws: 0, freshDraws: 0, irSurgeries: 0, irGenAttempts: 0,
    mechanicalFixes: 0,
    catalogDriftMechanicalFixes: 0,
    regexLiteralGateHeals: 0,
    bornRedStubDerivedDrops: 0,
    substrateAttempts: 0, substrateFixes: 0, substrateRefusals: 0, substrateNoHandler: 0,
    substrateEditsApplied: 0, deterministicEditsOutsideSubstrate: 0,
    substrateFillHits: 0, substrateFillEscalations: 0,
    substrateFillEmptyMechanisms: 0, substrateFillVacuousMechanisms: 0,
    overreachBodyRejections: 0,
    templatedCases: 0, permutationDraws: 0, permutationWins: 0,
    permBatches: 0, permCandidates: 0, permImproved: 0,
    superbufferDraws: 0, superbufferWins: 0,
    conceptDraws: 0, parsePoisonIncidents: 0,
    bugsObserved: 0, bugsPatched: 0, bugsRemaining: 0,
    artifactFaults: 0, artifactFaultsRemaining: 0, artifactFaultsAffectedFeatures: 0,
    featuresTotal: 0, featuresFrozenWithoutRedraw: 0, irRedraws: 0,
    nodesTotal: 0, nodesBuildable: 0, nodesBuilt: 0, nodesBuiltCleanFirstPass: 0,
    boundedLoopNodes: 0, boundedLoopIterations: 0,
    candidatesDrawn: 0, candidatesAccepted: 0,
    fillCandidatesDrawn: 0, repairCandidatesDrawn: 0,
    fillCandidatesAccepted: 0, repairCandidatesAccepted: 0,
    salvagedCases: 0,
    sickRedCases: 0, testRhaSubstrateFixes: 0, testRhaDraws: 0,
    testRhaSuperbufferAssemblies: 0, testRhaDrawThrew: 0, testRhaDraftRejected: 0,
    testRhaDraftAcceptedCleared: 0, testRhaDraftAcceptedStillSick: 0,
    testRhaSkippedNoHandle: 0, testRhaSkippedAlreadyRedrawn: 0,
    testRhaCaseExhausted: 0, testRhaCaseCleared: 0,
    irSurgeriesInRha: 0,
    reEnqueuedCases: 0, recoveredCases: 0,
    l2Draws: 0, l2Wins: 0, l2Bullseyes: 0,
    fixesL1: 0, fixesL2: 0, fixesL3: 0, fixesL4: 0,
    corpseRejections: 0, classifyAttempts: 0, classifyCataloged: 0,
    grammarConformant: 0, grammarFallbacks: 0,
    shellLockApplied: 0, shellLockFallbacks: 0,
    judgmentGates: 0, judgmentOperator: 0, judgmentLlm: 0, judgmentDropped: 0,
    watcherSyntheses: 0, watcherReadings: 0, watcherObservations: 0,
    watcherCacheHits: 0, watcherCacheMisses: 0, watcherWorldStaleSkips: 0,
    watcherInfusedCandidates: 0,
    corpseRejectionCeilingBreaches: 0,
    watcherEngineFailures: 0, observatoryEngineFailures: 0,
    nodeRepairDraws: 0, nodeRepairWins: 0,
    observationPolls: 0, observationsNew: 0, observationsCorroborated: 0,
    stubRouteShortcuts: 0, observatoryPollsSkipped: 0, l2ShortCircuits: 0, quarantineSuspensions: 0,
    errorsTotal: 0, errorsParse: 0, errorsConformance: 0, errorsExecution: 0, errorsCrash: 0,
    findingOccurrencesTotal: 0, findingOccurrencesParse: 0, findingOccurrencesConformance: 0,
    findingOccurrencesExecution: 0, findingOccurrencesCrash: 0, findingOccurrencesTestFailure: 0,
    uniqueDefectsObserved: 0, uniqueDefectsResolved: 0, uniqueDefectsUnresolved: 0,
    actionStarts: 0, actionTerminals: 0, actionDecisions: 0, actionPending: 0, actionFailed: 0,
    actionFailedNonfatal: 0,
    deferredTotal: 0, deferredRelitigated: 0, deferredResolvedAfterRelitigation: 0,
    deferredPermanent: 0,
    nodesHealed: 0, fixesUnsuccessful: 0, fixesUnparseable: 0,
  };
  // SET 89 §§10.5 / 11.4 — the canonical append-only registries. All
  // authoritative findings and every meaningful mutation / host callback
  // go through these; metrics are DERIVED from them at end-of-run and
  // event-flush time (see `syncMetricsFromLedgers`).
  const actionLedger = new ActionLedger(() => new Date().toISOString(), { strict: true });
  const defectRegistry = new DefectRegistry(() => new Date().toISOString());
  /**
   * SET 89 §§10.5 / 11.4 — derive canonical `findingOccurrences*` /
   * `uniqueDefects*` / `action*` fields from the registries. Legacy
   * `errors*` fields are aliases: same values, retained for a single
   * release of downstream compatibility.
   */
  const syncMetricsFromLedgers = (): void => {
    const d = defectRegistry.metrics();
    const a = actionLedger.metrics();
    metrics.findingOccurrencesTotal = d.findingOccurrencesTotal;
    metrics.findingOccurrencesParse = d.findingOccurrencesParse;
    metrics.findingOccurrencesConformance = d.findingOccurrencesConformance;
    metrics.findingOccurrencesExecution = d.findingOccurrencesExecution;
    metrics.findingOccurrencesCrash = d.findingOccurrencesCrash;
    metrics.findingOccurrencesTestFailure = d.findingOccurrencesTestFailure;
    metrics.uniqueDefectsObserved = d.uniqueDefectsObserved;
    metrics.uniqueDefectsResolved = d.uniqueDefectsResolved;
    metrics.uniqueDefectsUnresolved = d.uniqueDefectsUnresolved;
    // Legacy aliases — never incremented independently.
    metrics.errorsTotal = d.findingOccurrencesTotal;
    metrics.errorsParse = d.findingOccurrencesParse;
    metrics.errorsConformance = d.findingOccurrencesConformance;
    // Test-failure occurrences fold into the legacy `execution` alias for
    // one release; new canonical field is `findingOccurrencesTestFailure`.
    metrics.errorsExecution = d.findingOccurrencesExecution + d.findingOccurrencesTestFailure;
    metrics.errorsCrash = d.findingOccurrencesCrash;
    // Bug counts derive from unique defects (crash sig collapse handled by
    // canonical key inside the registry).
    metrics.bugsObserved = d.uniqueDefectsObserved;
    metrics.bugsPatched = d.uniqueDefectsResolved;
    metrics.bugsRemaining = d.uniqueDefectsUnresolved;
    metrics.actionStarts = a.actionStarts;
    metrics.actionTerminals = a.actionTerminals;
    metrics.actionDecisions = a.actionDecisions;
    metrics.actionPending = a.actionPending;
    metrics.actionFailed = a.actionFailed;
    metrics.actionFailedNonfatal = a.actionFailedNonfatal;
  };
  // SET 89 §10.5 — `noteRunError` no longer mutates canonical counters.
  // `errorsTotal` / `errorsParse` / `errorsConformance` / `errorsExecution`
  // / `errorsCrash` are DERIVED aliases synced from `defectRegistry` in
  // `syncMetricsFromLedgers()`. This shim is kept for non-authoritative
  // diagnostic call sites (parse-poison detection, quarantine detection,
  // conformance rejects) whose observations are still valuable in the
  // event log but must never inflate the authoritative counters.
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
  const noteRunError = (_cls: 'parse' | 'conformance' | 'execution' | 'crash'): void => {
    // no-op: authoritative counters flow through the defect registry.
  };
  /** SET 57a — features whose fill used the generateTests fallback path. */
  const usedFallbackFill = new Set<string>();
  /** SET 57a — features that entered the bounded repair loop. */
  const boundedNodeIds = new Set<string>();
  /** SET 57a — deferred features re-prosecuted in metaloop 2/3 (counted once). */
  const relitigatedIds = new Set<string>();
  /** SET 57a — bounded-loop nodes already counted healed (dedupe main/relay). */
  const healedNodeIds = new Set<string>();
  const noteNodeHealed = (fid: string): void => {
    if (!boundedNodeIds.has(fid) || healedNodeIds.has(fid)) return;
    healedNodeIds.add(fid);
    metrics.nodesHealed++;
  };
  const provenance: CaseProvenance[] = [];
  const log: Tier1Event[] = [];
  const deferred: CapabilityHit[] = [];
  // SET 70 — a fill drop is a scheduling decision made too early: dropped
  // cases are RE-ENQUEUED and re-prosecuted at end-of-run when the world is
  // warmest (all siblings frozen, impls built, lessons banked). Final drops
  // only happen after the warm retry — preserving the lineage message shape.
  const endOfRunCaseStack: {
    featureId: string; name: string; kind: IRCaseGen['kind']; reason: string;
  }[] = [];
  const END_OF_RUN_STACK_CAP = 8;
  // SET 34 — claim-bound evidence lines (also mirrored onto log events).
  const evidence: string[] = [];
  // SET 43e — healed edit shapes for handler-candidate promotion (≥3).
  const healedInstances: HealedInstance[] = [];
  // SET 43f — classKey sightings → coverage rule at done.
  const classKeySightings = new Map<string, {
    count: number;
    fixed: boolean;
    mechanicalCandidate: boolean;
  }>();
  const noteClassKey = (
    classKey: string,
    outcome: 'seen' | 'fixed' | 'mechanical-candidate' = 'seen',
  ) => {
    if (!classKey) return;
    const row = classKeySightings.get(classKey)
      ?? { count: 0, fixed: false, mechanicalCandidate: false };
    if (outcome === 'seen') row.count += 1;
    if (outcome === 'fixed') row.fixed = true;
    if (outcome === 'mechanical-candidate') row.mechanicalCandidate = true;
    classKeySightings.set(classKey, row);
  };
  // SET 45b — per-feature deterministic trail for the substrate handoff page.
  const handoffAttemptsByFeature = new Map<string, SubstrateHandoffAttempt[]>();
  const handoffMetaByFeature = new Map<string, { classKey: string; stratum?: string }>();
  const substrateHandoffFor = (featureId: string) => {
    const attempts = handoffAttemptsByFeature.get(featureId) ?? [];
    const meta = handoffMetaByFeature.get(featureId);
    return buildSubstrateHandoff({
      classKey: meta?.classKey ?? 'unknown',
      stratum: meta?.stratum,
      attempts,
    });
  };
  const recordSubstrateAttempt = (
    classKey: string,
    attempt: MechanicalFixAttempt,
    featureId?: string | null,
  ) => {
    noteClassKey(classKey, 'seen');
    if (attempt.status === 'fixed') noteClassKey(classKey, 'fixed');
    else if (
      attempt.status === 'refused'
      && /ambiguous|fitness tie|>4 candidates/i.test(attempt.reason ?? '')
    ) {
      noteClassKey(classKey, 'mechanical-candidate');
    }
    // SET 45b — accumulate handoff trail for the next fill/repair draw.
    if (featureId) {
      handoffMetaByFeature.set(featureId, {
        classKey,
        stratum: typeof attempt.stratum === 'string' ? attempt.stratum : undefined,
      });
      const handler = /^unresolved-import\b/.test(classKey)
        ? 'import-rewire'
        : (classKey.split('|')[0] ?? classKey);
      const list = handoffAttemptsByFeature.get(featureId) ?? [];
      list.push({
        handler,
        status: attempt.status,
        reason: attempt.reason,
        candidateSites: attempt.candidateSites,
        note: attempt.fix?.note,
      });
      handoffAttemptsByFeature.set(featureId, list);
    }
  };
  // SET 37h — shared failure stack (parse/fill/stalled); model draws from the end.
  let failureStack: FailureStackState = emptyFailureStack();
  // SET 37f — per-feature concept page (context only; never extracted as code).
  const conceptByFeature = new Map<string, string>();
  // SET 37g — continue-project replan-first disclosure.
  const priorDropped = [...new Set(opts.priorDroppedCaseNames ?? [])].filter(Boolean);
  if (priorDropped.length) {
    evidence.push(formatContinueProjectReplanNote(priorDropped.length));
  }
  // SET 34d — superbuffer efficacy: fills WITH templates vs WITHOUT.
  const sbWithTpl: EfficacyBucket = { cases: 0, filled: 0 };
  const sbNoTpl: EfficacyBucket = { cases: 0, filled: 0 };
  const noteSbEfficacy = (hadTemplates: boolean, filled: boolean): void => {
    const bucket = hadTemplates ? sbWithTpl : sbNoTpl;
    bucket.cases++;
    if (filled) bucket.filled++;
  };
  // SET 45c — superbuffer efficacy: draws WITH substrate page vs WITHOUT.
  const sbPageEff = emptySubstratePageEfficacy();
  // SET 18f — aggregate clade counts across features (do not overwrite per feature).
  let cladeSchemadTotal = 0;
  let cladeFreeformTotal = 0;
  // SET 17 — freeform pattern success counts for clade-promotion proposals.
  const freeformWinCounts = new Map<string, number>();
  // SET 89 §10.5 — the former `observedBugKeys` / `remainingBugKeys` sets
  // are gone. Unique-defect counters (`bugsObserved` / `bugsRemaining` /
  // `bugsPatched`) come from the DefectRegistry through
  // `syncMetricsFromLedgers()`; a set at this level would compete with the
  // registry and could not honor identity normalization (path, case,
  // whitespace) — that job belongs to the registry.
  //
  // SET 31c — the artifact-fault sig sets remain: they measure a separate
  // property (one crash signature affecting many features) and do not
  // participate in the `metrics.bugs*` partition.
  const artifactFaultAffects = new Map<string, Set<string>>();
  const artifactFaultRemainingSigs = new Set<string>();
  const bail = () => {
    if (opts.isCancelled?.()) {
      // SET 89 §11.5 — cancel every still-pending action before
      // unwinding. `bail()` throws out of the run body, so this is the
      // last chance to close the ledger honestly (`assertConserved`
      // otherwise trips on the pending set).
      try { actionLedger.cancelPending('run cancelled'); } catch { /* best effort */ }
      throw new Error('cancelled by user');
    }
  };
  /** SET 71c — deterministic minimal contract from a function stub: red
   * against a throwing stub BY CONSTRUCTION, and a real behavioral assertion
   * (callable-without-throwing). The vacuous-abandonment breaker: one bad
   * root suite must never fan dependency-uncovered across the tree. */
  const buildDeterministicAnchor = (feature: { stubs?: { content: string }[] }): IRCaseGen | null => {
    const stub = feature.stubs?.[0]?.content ?? '';
    const m2 = /export\s+(?:async\s+)?function\s+([A-Za-z_$][\w$]*)\s*\(([^)]*)\)/.exec(stub);
    if (!m2) return null;
    const fnName = m2[1]!;
    const params = m2[2]!.trim();
    const args = params
      ? params.split(',').map(p => {
        const t = (p.split(':')[1] ?? '').trim().toLowerCase();
        if (t.startsWith('number')) return '1';
        if (t.startsWith('string')) return "'x'";
        if (t.startsWith('boolean')) return 'true';
        if (t.endsWith('[]')) return '[]';
        return '{} as never';
      }).join(', ')
      : '';
    return {
      name: `${fnName} anchor (callable)`,
      kind: 'behavior',
      body: `expect(() => ${fnName}(${args})).not.toThrow();`,
    };
  };

  /**
   * SET 89 §11.3 — host-callback safety. Every call into `opts.on*` is a
   * load-bearing edge that must not tear down the run when the consumer
   * throws. We record the failure as a `failed-nonfatal` action in the
   * ledger so the operator can see it; no recursive callback is ever
   * invoked to report the failure of a callback.
   *
   * `runNonfatalAction` is async; the callback surface is synchronous, so
   * we open+close the action inline. Same book-keeping shape, no promise
   * for the caller to await.
   */
  const runHostCallback = (
    kind: string,
    target: string,
    phase: string,
    fn: () => void,
  ): void => {
    const actionId = actionLedger.startAction({ kind: `host-callback:${kind}`, target, phase });
    try {
      fn();
      actionLedger.finishAction({ actionId, disposition: 'applied' });
    } catch (error) {
      actionLedger.finishAction({
        actionId,
        disposition: 'failed',
        failureMode: 'nonfatal',
        error,
      });
      // Push the failure onto the internal event log so a human reviewer
      // can see it — but never recursively into the failing callback.
      log.push({
        ts: new Date().toISOString(),
        phase: phase as Tier1Event['phase'],
        featureId: null,
        message: `host-callback:${kind} failed nonfatally: ${
          error instanceof Error ? error.message : String(error)
        }`,
      });
    }
  };

  /**
   * SET 89 §11.2 — token-spending model call helper. Every LLM invocation
   * is a structured action with kind `llm:<method>`, targeted at the
   * scope (`@spec` / feature id / suite id) so replay reveals which call
   * did what work. Provider throws propagate — a token-spending call
   * that fails is a FATAL disposition on that action.
   *
   * `startEvidence` is small and JSON-clonable (nothing carries the full
   * prompt). Fixture handling is unchanged from the previous SET.
   */
  const runLlmAction = <T>(input: {
    method: string;
    target: string;
    phase: string;
    startEvidence?: unknown;
    fn: () => Promise<T> | T;
  }): Promise<T> => {
    return actionLedger.runAction({
      kind: `llm:${input.method}`,
      target: input.target,
      phase: input.phase,
      startEvidence: input.startEvidence ?? null,
      fn: input.fn,
    }).then(r => r.result);
  };

  const emit = (phase: Tier1Event['phase'], featureId: string | null, message: string) => {
    // SET 92g — test-only suppress hook: counters still increment at call sites;
    // only the log/onEvent line is dropped so mutation coverage can prove emits
    // are load-bearing for the conservation assertions.
    if (opts._suppressEmit?.test(message)) return;
    const e: Tier1Event = { ts: new Date().toISOString(), phase, featureId, message };
    log.push(e);
    // SET 64 — L1 attribution is definitionally the substrate; derived at the
    // single snapshot site so the two counters can never drift.
    metrics.fixesL1 = metrics.substrateFixes;
    if (opts.onEvent) {
      runHostCallback('onEvent', featureId ?? '@run', phase, () => opts.onEvent!(e));
    }
    if (opts.onMetrics) {
      runHostCallback('onMetrics', featureId ?? '@run', phase, () => opts.onMetrics!({
        ...metrics,
        passesPerFeature: { ...metrics.passesPerFeature },
        elapsedMs: Date.now() - startedAt,
      }));
    }
  };
  // SET 92a — one owner for every superbuffer assembly emission (doctrine 6).
  type SbStageContext = 'fill' | 'repair' | 'test-rha' | 'case-relay' | 'born-red';
  const emitSuperbufferAssembly = (
    stage: 'ir' | 'build' | 'rha',
    featureId: string,
    assembly: { logLine: string },
    ctx: SbStageContext,
  ): string => {
    emit(stage, featureId, assembly.logLine);
    metrics.superbufferDraws++;
    if (ctx === 'test-rha') metrics.testRhaSuperbufferAssemblies++;
    return formatSuperbufferForPrompt(assembly as Parameters<typeof formatSuperbufferForPrompt>[0]);
  };
  // SET 74 — supergit L3 in Tier 1: the append-only decision ledger. Same
  // schema as the Tier 2 substrate; held in memory, serialized into the run
  // record, materialized into the exported repo under `.supergit/`.
  const supergit = new Tier1Supergit();
  /** spec-node id per feature — the cause of its IR/test rows. */
  const specNodeByFeature = new Map<string, string>();
  /** latest error-node id per feature — the cause of the repair that follows. */
  const errorNodeByFeature = new Map<string, string>();

  // SET 76 — THE WATCHER, continuously operant (Andy, 2026-07-27: "every
  // stage monitors for a trigger, which is the need to submit context to
  // LLM"). It is not scheduled: the TRIGGER is a draw about to happen, and
  // synthesis runs at that moment, scoped to the node in question.
  //
  // Every trigger recomputes the deterministic, node-scoped digest fresh
  // (0 tok). The model READING refreshes only when the ledger materially
  // moved since the last one — that is the "applicable epoch-cycle" — so a
  // resident agent does not multiply model calls.
  /**
   * Cached reading + SET 88 health. `engineDead` is gone: an engine that has
   * been failing backs off and comes back, it never dies for the run.
   */
  const watch: {
    reading: ReturnType<typeof parseWatchReport>;
    health: AgentHealth;
    cache: Map<string, ReturnType<typeof parseWatchReport>>;
    lastSyntheticStep: number;
  } = {
    reading: null, health: createAgentHealth(), cache: new Map(), lastSyntheticStep: 0,
  };
  const digestCacheKey = (stage: string, featureId: string | null, digest: object): string => {
    const json = JSON.stringify(digest);
    let h = 5381 >>> 0;
    for (let i = 0; i < json.length; i++) h = ((h << 5) + h + json.charCodeAt(i)) >>> 0;
    return `${stage}|${featureId ?? '_'}|${h.toString(36)}|${json.length}`;
  };
  // A successful watcher reading records a lesson node; that self-authored
  // evidence must not itself re-trigger another synthesis.
  const ADVANCING_TYPES = new Set<LedgerRow['type']>(['test', 'code', 'resolution', 'spec']);
  const ADVANCING_STATUSES = new Set(['pass', 'healed']);
  const hasWorldAdvancedSince = (rows: readonly LedgerRow[], step: number): boolean =>
    rows.some(row => row.step > step
      && (ADVANCING_TYPES.has(row.type) || (row.status != null && ADVANCING_STATUSES.has(row.status))));

  /**
   * Fires on every need-to-submit-context trigger. Returns the union page for
   * THIS draw, or null when there is nothing worth saying yet.
   */
  const synthesizeForDraw = async (
    stage: WatchEpoch,
    featureId: string | null,
    artifact: GeneratedFile[],
  ): Promise<string | null> => {
    const rows = supergit.allRows();
    // Nothing has happened yet — no context to submit.
    if (rows.length <= 1) return null;
    if (watch.lastSyntheticStep > 0 && !hasWorldAdvancedSince(rows, watch.lastSyntheticStep)) {
      metrics.watcherSyntheses++;
      metrics.watcherWorldStaleSkips++;
      const digest = buildEpochDigest({ epoch: stage, rows, artifact, featureId });
      emit(stage, featureId,
        `watcher synthesis @ ${stage}${featureId ? `/${featureId}` : ''}: skipped — no world advancement since node ${watch.lastSyntheticStep} (deterministic corpse cache carries failure evidence)`);
      return formatUnionPage(digest, watch.reading);
    }
    const digest = buildEpochDigest({ epoch: stage, rows, artifact, featureId });
    metrics.watcherSyntheses++;
    const cacheKey = digestCacheKey(stage, featureId, digest);
    const cached = watch.cache.get(cacheKey);
    if (cached !== undefined) {
      metrics.watcherCacheHits++;
      watch.lastSyntheticStep = rows[rows.length - 1]?.step ?? watch.lastSyntheticStep;
      emit(stage, featureId,
        `watcher synthesis @ ${stage}${featureId ? `/${featureId}` : ''}: digest unchanged since node ${digest.nodes} — reading reused (advisory)`);
      return formatUnionPage(digest, cached);
    }
    metrics.watcherCacheMisses++;

    // SET 88e — BIND THE RECEIVER. Extracting the method and calling it bare
    // left `this` undefined, so the real client's `this.call(...)` threw
    // "Cannot read properties of undefined (reading 'call')" on EVERY trigger.
    // Test doubles are object literals whose methods close over their data and
    // never touch `this`, so the whole suite passed while this agent had never
    // once run in production.
    const engine = (opts.llm as { watchEpoch?: (p: string) => Promise<string> })
      .watchEpoch?.bind(opts.llm);
    let disposition: WatchDisposition = 'no-engine';
    let detail: string | undefined;
    if (typeof engine === 'function') {
      {
        // SET 78 + SET 88f — no staleness gate and no backoff ladder: every
        // trigger attempts the engine. The digest is node-scoped and the ledger
        // moves constantly, so any shortcut — "nothing changed" or "still
        // failing, skip a few" — lies about the very thing the page reports.
        try {
          const fresh = parseWatchReport(await engine(watchPrompt(digest)));
          metrics.watcherReadings++;
          noteSuccess(watch.health);
          if (fresh) {
            watch.reading = fresh;
            watch.cache.set(cacheKey, fresh);
            watch.lastSyntheticStep = rows[rows.length - 1]?.step ?? watch.lastSyntheticStep;
            metrics.watcherObservations += fresh.idioms.length + fresh.tropes.length + fresh.schemes.length;
            disposition = 'read';
            supergit.recordNode({
              type: 'lesson', status: 'info',
              summary: `watcher @ ${stage}${featureId ? `/${featureId}` : ''} (advisory): ${fresh.union || `${fresh.idioms.length} idioms, ${fresh.tropes.length} tropes`}`,
            });
          } else {
            disposition = 'unreadable';
          }
        } catch (err) {
          // SET 88 — bind it, say it, record it. An agent that dies must leave
          // a body in the ledger; the old bare catch left none.
          noteFailure(watch.health, err);
          detail = failureDetail(watch.health);
          metrics.watcherEngineFailures++;
          disposition = 'engine-failed';
          supergit.recordNode({
            type: 'lesson', status: 'fail',
            summary: `watcher engine threw @ ${stage}${featureId ? `/${featureId}` : ''}: ${detail}`,
          });
        }
      }
    }
    emit(stage, featureId, formatWatchEvent(digest, watch.reading, disposition, detail));
    return formatUnionPage(digest, watch.reading);
  };

  // SET 85 — THE OBSERVATORY: the passive agent, APPEND-ONLY. It never
  // replaces what it learned; each question is its own decoupled poll over
  // the SAME deterministic AST facts, and every accepted item accumulates as
  // an artifact (subject + claim + evidence + sighting count).
  const observations = new ObservationLedger(opts.observations ?? []);
  const observatory = createAgentHealth();
  /** SET 101b — ledger step at last observatory poll batch (world-advance gate). */
  let lastObservatoryStep = 0;
  const runObservatory = async (artifact: GeneratedFile[], findings: string): Promise<string | null> => {
    // SET 88e — bound receiver; see the watcher site.
    const engine = (opts.llm as {
      observe?: (p: string, sys: string) => Promise<string>;
    }).observe?.bind(opts.llm);
    if (typeof engine !== 'function' || !artifact.length) {
      return formatObservatoryPage(observations);
    }
    // SET 101b — same world-advance predicate as watcher synthesis skip.
    const rows = supergit.allRows();
    if (lastObservatoryStep > 0 && !hasWorldAdvancedSince(rows, lastObservatoryStep)) {
      metrics.observatoryPollsSkipped++;
      emit('rha', null,
        `observatory: polls skipped — world unchanged since node ${lastObservatoryStep}`);
      return formatObservatoryPage(observations);
    }
    const facts = astFacts(artifact);
    const astPage = formatAstFacts(facts);
    const now = new Date().toISOString();
    let added = 0;
    let corroborated = 0;
    let polled = 0;
    let pollDetail: string | undefined;
    for (const poll of OBSERVATION_POLLS) {
      bail();
      try {
        const raw = await engine(pollPrompt(poll, astPage, findings), poll.system);
        polled++;
        metrics.observationPolls++;
        noteSuccess(observatory);
        for (const item of parsePoll(raw)) {
          const evidence = facts.declarations
            .filter(d => d.symbol === item.subject || d.path === item.subject)
            .slice(0, 2)
            .map(d => `${d.path}: ${d.kind} ${d.symbol}`);
          if (observations.append(poll.kind, item.subject, item.claim, evidence, now)) {
            added++; metrics.observationsNew++;
          } else {
            corroborated++; metrics.observationsCorroborated++;
          }
        }
      } catch (err) {
        // SET 88f — every poll is attempted every sweep. A failing engine costs
        // one call per question; a skipped poll costs an observation we never
        // take, and the polls are decoupled precisely so one can fail alone.
        noteFailure(observatory, err);
        pollDetail = failureDetail(observatory);
        metrics.observatoryEngineFailures++;
        supergit.recordNode({
          type: 'lesson', status: 'fail',
          summary: `observatory poll "${poll.kind}" threw: ${pollDetail}`,
        });
      }
    }
    if (polled || pollDetail) {
      // SET 101b — mark the poll epoch so an unchanged world skips the next batch.
      if (polled) {
        const afterRows = supergit.allRows();
        lastObservatoryStep = afterRows[afterRows.length - 1]?.step ?? lastObservatoryStep;
      }
      emit('rha', null,
        formatObservatoryEvent(polled, added, corroborated, observations.size, pollDetail));
      for (const o of observations.all().slice(0, 3)) {
        opts.onObservation?.(o);
      }
    }
    return formatObservatoryPage(observations);
  };

  const metaRecords: MetaCandidateRecord[] = [];

  // SET 64 — corpse detection state (per-run + cross-run caches) and the
  // metasupercache candidate sink (host persists under metaSb:<runId>).
  const runDrawHashes = new Set<string>();
  const metaCorpseHashes = new Set<string>(opts.metaSb?.corpseHashes ?? []);
  const perCaseCorpseCount = new Map<string, number>();
  const noteCorpseRejection = (
    stage: Tier1Event['phase'],
    featureId: string | null,
    caseName: string,
  ): void => {
    metrics.corpseRejections++;
    const count = (perCaseCorpseCount.get(caseName) ?? 0) + 1;
    perCaseCorpseCount.set(caseName, count);
    if (count > 5) {
      metrics.corpseRejectionCeilingBreaches++;
      emit(stage, featureId,
        `corpse-ceiling exceeded: case "${caseName}" hit ${count} rejections in one run — upstream is re-issuing this class more aggressively than the ladder-shape justifies`);
    }
  };
  const noteMetaCandidate = (rec: MetaCandidateRecord): void => {
    metaRecords.push(rec);
    try { opts.onMetaCandidate?.(rec); } catch { /* host sink must never kill the run */ }
  };
  const noteParseGateUnavailable = (phase: Tier1Event['phase'], featureId: string | null) => {
    if (parseGateUnavailableEmitted) return;
    parseGateUnavailableEmitted = true;
    emit(phase, featureId, 'parse-gate unavailable (CSP) — check skipped');
  };
  let moduleProbeUnavailableEmitted = false;
  const noteModuleProbeUnavailable = (phase: Tier1Event['phase'], featureId: string | null) => {
    if (moduleProbeUnavailableEmitted) return;
    moduleProbeUnavailableEmitted = true;
    emit(phase, featureId, 'module-probe unavailable (CSP) — check skipped');
  };
  /** SET 34 — record claim-bound evidence and mirror onto the event log. */
  const noteEvidence = (
    phase: Tier1Event['phase'],
    featureId: string | null,
    lines: string[],
  ): void => {
    for (const line of lines) {
      evidence.push(line);
      emit(phase, featureId, line);
    }
  };

  // SET 4b / 15 / 44 — disclose out-of-scope prompt items before any model call.
  const scanText = opts.rawPrompt ?? opts.prompt;
  const fmtLine = (line?: number) => (line != null ? ` (line ${line})` : '');
  for (const hit of scanCapabilities(scanText)) {
    if (hit.residueCollapsed) {
      metrics.deferredResidueEmpty = (metrics.deferredResidueEmpty ?? 0) + 1;
    }
    deferred.push(hit);
    // SET 69 — split hits disclose the retained behavior, not a full loss.
    if (hit.behavioralSplit) {
      metrics.deferredTotal++;
      emit('encode', null,
        `behavior/binding split: "${hit.behavioralSplit.binding}" excised — behavioral invariant kept (${hit.behavioralSplit.simClade})${fmtLine(hit.line)}`);
      continue;
    }
    metrics.deferredTotal++;
    emit('encode', null,
      `excluded: "${hit.item}" — requires ${hit.capability}; not testable in this runtime${fmtLine(hit.line)}`);
  }

  // SET 100d — refuse encode when the prompt has zero assertable residue.
  const verifyGate = promptHasVerifiableResidue(scanText);
  if (!verifyGate.ok) {
    emit('encode', null,
      `refused: prompt has no verifiable items — ${verifyGate.itemsScanned} items scanned, ${verifyGate.fenced} capability-fenced, 0 assertable residue`);
    metrics.encodeRefusedNoResidue = (metrics.encodeRefusedNoResidue ?? 0) + 1;
    metrics.elapsedMs = Date.now() - startedAt;
    syncMetricsFromLedgers();
    return {
      status: 'refused',
      reason: 'prompt-no-verifiable-items',
      spec: { title: opts.prompt.slice(0, 80), prompt: opts.prompt, features: [] },
      files: [],
      frozenTests: [],
      problems: ['refused: prompt has no verifiable items'],
      metrics,
      log,
      provenance,
      contractVersion: opts.contractVersion,
      deferred,
      evidence,
      supergit: {
        rows: supergit.allRows(),
        csv: supergit.toCsv(),
        graph: supergit.toGraph(),
      },
      defectRegistry: defectRegistry.snapshot(),
      actionLedger: actionLedger.snapshot(),
    };
  }

  // Phase A: encode + bounded structural repair.
  // SET 32a — pin encode to temperature 0. Same prompt MUST produce the same
  // spec carve; longitudinal comparison is meaningless while the spec re-rolls.
  emit('encode', null, 'encoding prompt into feature-coded spec');
  // SET 89 §11.2 — every token-spending model call is a structured action.
  // Throws propagate (fatal terminal); success ⇒ applied terminal.
  const { result: spec } = await actionLedger.runAction({
    kind: 'llm:encodeFeatures',
    target: '@spec',
    phase: 'encode',
    startEvidence: { promptChars: (opts.encodePrompt ?? opts.prompt).length },
    fn: () => opts.llm.encodeFeatures(
      opts.encodePrompt ?? opts.prompt,
      undefined,
      { temperature: 0 },
    ),
  });
  preSanitizeSpec(spec);
  resolveDependencyIds(spec);
  let problems = validateSpec(spec);

  for (let round = 0; problems.length && round < gates.gateRounds; round++) {
    const ids = offendingFeatureIds(problems, spec.features.map(f => f.id));
    if (!ids.length) break; // whole-spec problems are not per-feature repairable here
    emit('gate', null, `round ${round + 1}: repairing ${ids.join(', ')} (${problems.length} problems)`);
    const { result: fixed } = await actionLedger.runAction({
      kind: 'llm:repairFeatures',
      target: ids.join(','),
      phase: 'gate',
      startEvidence: { ids, problems: problems.length, round: round + 1 },
      fn: () => opts.llm.repairFeatures(spec, ids, problems),
    });
    for (const node of fixed) {
      const i = spec.features.findIndex(f => f.id === node.id);
      if (i >= 0) spec.features[i] = node; // bounded: only offending ids replaced
    }
    preSanitizeSpec(spec);
    resolveDependencyIds(spec);
    problems = validateSpec(spec);
  }
  emit('gate', null, problems.length
    ? `spec gate exhausted with ${problems.length} unresolved problems`
    : 'spec gate clean');

  // SET 34c — encode-determinism tripwire (sha256-8 of encode output).
  {
    const hash8 = await sha256Hex8(encodeOutputCanonical(spec));
    const matchId = resolveSpecHashMatch(hash8, opts.priorSpecHashes);
    noteEvidence('encode', null, [formatSpecHashLine(hash8, matchId)]);
  }

  const ordered = topoOrder(spec.features);
  metrics.featuresTotal = ordered.length;

  // SET 74 — supergit: the carve is one `decision` node; each feature gets a
  // `spec` node; declared dependencies become FORWARD `edge` rows (blast
  // radius), appended when discovered, never mutating earlier rows.
  {
    const carve = supergit.recordNode({
      type: 'decision',
      artifactPath: '.supergit/spec.json',
      summary: `encode: ${ordered.length} features carved from the prompt`,
    });
    for (const f of ordered) {
      specNodeByFeature.set(f.id, supergit.recordNode({
        type: 'spec', featureId: f.id, causeId: carve,
        artifactPath: f.files[0] ?? null,
        summary: `${f.id} ${f.name}: ${f.description ?? ''}`.trim(),
      }));
    }
    for (const f of ordered) {
      for (const depId of f.deps ?? []) {
        const from = specNodeByFeature.get(depId);
        const to = specNodeByFeature.get(f.id);
        if (from && to) supergit.recordEdge(from, to, `${depId} → ${f.id}`);
      }
    }
  }

  // Phase B: frozen IR per feature, before any implementation exists.
  const frozenTests: GeneratedFile[] = [];
  const frozenByFeature = new Map<string, string>();
  // Structured parts enable IR-case surgery during convergence (bounded
  // regeneration of individual cases — never whole-suite rewrites).
  const irPartsByFeature = new Map<string, IRParts>();
  // SET 89 §4.4 v2 — the three frozen-state maps have EXACTLY ONE writer
  // (`commitFrozenSuite` in `frozenSuiteGateway.ts`). Every runner site
  // routes through `commitFrozenPatch(...)` below, which is a thin
  // convenience wrapper that calls the gateway with the appropriate
  // per-caller mode (initial-freeze, mechanical-patch, ir-surgery,
  // judgment-refreeze, case-relay-adopt, fixture-fallback). No other
  // path in this file writes to `frozenState` — verified by ripgrep for
  // `frozenTests.push|frozenByFeature.set|irPartsByFeature.set`.
  const frozenState: FrozenState = { frozenTests, frozenByFeature, irPartsByFeature };
  const lastFrozenReport = new Map<string, FrozenSuiteReport>();
  // SET 89 §4.4 v2 — placeholder `SuiteRunner` for the bypass path.
  // `commitFrozenSuite` is only invoked with `bypassCaseCertification: true`
  // when no host `runSuite` was provided, so this callback must never
  // execute. If it does, the gate infrastructure is being consulted for
  // certification in a mode that promised not to — throw loudly.
  const noRunSuite: (files: GeneratedFile[], test: GeneratedFile) => Promise<never> = async () => {
    throw new Error('bypass-mode gateway must not invoke runSuite');
  };

  /**
   * SET 89 §4.4 v2 — every post-initial-freeze mutation of frozen state
   * routes through this wrapper. The wrapper:
   *   1. resolves canonical `IRParts` (caller-supplied OR current
   *      `irPartsByFeature.get(featureId)`);
   *   2. calls `commitFrozenSuite` with `overrideContent` set to the
   *      patched bytes (so per-case certification is applied against
   *      canonical parts, and shape/syntax/parse gates run against the
   *      exact bytes that will be committed);
   *   3. returns the report for the caller to log; the write itself is
   *      atomic inside the gateway.
   *
   * When no `runSuite` host is available, the gateway is invoked in
   * bypass mode: per-case certification is skipped (it requires
   * executable cases), but suite shape / syntax / whole-program parse
   * gates still run and the write remains atomic. The disclosure is
   * emitted by the caller via the returned report.
   */
  const commitFrozenPatch = async (
    feature: (typeof ordered)[number],
    content: string,
    parts: IRParts | undefined,
    reason: string,
  ): Promise<CommitFrozenSuiteResult | null> => {
    const carryParts = parts ?? irPartsByFeature.get(feature.id);
    if (!carryParts) return null;
    // Bypass certification only when there is no host to execute cases;
    // shape/syntax/parse gates still run against `overrideContent`.
    const runSuite = opts.runSuite ?? noRunSuite;
    return commitFrozenSuite({
      spec,
      feature,
      prompt: opts.rawPrompt ?? opts.prompt,
      parts: carryParts,
      runSuite,
      stubs: stubArtifact(spec),
      state: frozenState,
      reason,
      overrideContent: content,
      bypassCaseCertification: !opts.runSuite,
      onAcceptance: (report) => { lastFrozenReport.set(feature.id, report); },
      onRejection: (report) => { lastFrozenReport.set(feature.id, report); },
      // SET 89 §11.2 — commitFrozenSuite is a mutation-boundary action:
      // one start, one terminal, with before/after signatures.
      actionLedger,
    });
  };

  /**
   * SET 89 §4.4 v2 — fixture-fallback commit. Legacy path that supplies
   * suite content without canonical `IRParts`; per-case certification is
   * SKIPPED (there are no cases to certify) but suite shape / syntax /
   * whole-program parse gates still run. Every call site MUST log a
   * disclosure event so the exception is visible in the run record.
   */
  const commitFrozenFixture = async (
    feature: (typeof ordered)[number],
    content: string,
    reason: string,
  ): Promise<CommitFrozenSuiteResult> => {
    const runSuite = opts.runSuite ?? noRunSuite;
    return commitFrozenSuite({
      spec,
      feature,
      prompt: opts.rawPrompt ?? opts.prompt,
      parts: { imports: [], cases: [] },
      runSuite,
      stubs: stubArtifact(spec),
      state: frozenState,
      reason,
      overrideContent: content,
      bypassCaseCertification: true,
      onAcceptance: (report) => { lastFrozenReport.set(feature.id, report); },
      onRejection: (report) => { lastFrozenReport.set(feature.id, report); },
      // SET 89 §11.2 — every frozen-state mutation is a ledger action.
      actionLedger,
    });
  };
  // SET 32h/32i — lessons available so far (tracked by classKey) — the third
  // input to WorldSignature (frozen count, sibling case count, lesson count).
  const lessonKeysSeen = new Set<string>((opts.lessons ?? []).map(l => l.classKey));
  const origOnLesson = opts.onLesson;
  const noteLesson = (l: Tier1Lesson): void => {
    lessonKeysSeen.add(l.classKey);
    origOnLesson?.(l);
  };
  // Override the opts.onLesson callback so world signatures track NEW lessons
  // distilled during the run without changing every distillLesson call site.
  opts = { ...opts, onLesson: noteLesson };

  type FeatureFillOutcome =
    | { status: 'frozen' }
    | { status: 'skipped'; reason: string }    // capability exclusion (not testable)
    | { status: 'deferred'; reason: string };  // fill exhaustion — retry candidate

  /** SET 32c/32g/32h/32i — attempt to fill + freeze ONE feature. Never
   *  abandons here; callers decide (defer → metaloop 2/3 → 32d fan-out). */
  const fillOneFeature = async (
    feature: (typeof ordered)[number],
    metaloopPhase: MetaloopPhase,
  ): Promise<FeatureFillOutcome> => {
    let content: string | null = null;
    let parts: IRParts | undefined;
    // SET 28b / 32e — honest fill-attempt accounting per planned case:
    //   fillDraws:     total individual model draws that targeted this case
    //                  (one per permutation-temp candidate, across every batch)
    //   fillCandBatch: K-draw permutation batches that targeted this case
    //   fillFallBatch: fallback/redraw batches that targeted this case
    // The drop message states the TRUE counts — never claim retries that
    // didn't happen. Zero draws → "never drawn" (plan exceeded fill budget).
    const fillDraws = new Map<string, number>();
    const fillCandBatch = new Map<string, number>();
    const fillFallBatch = new Map<string, number>();

    // SET 2a — binding plan (0 tokens). Model never authors the case list or imports.
    // SET 4c / 15 — drop fully deferred licenses; keep mixed items (partial clause).
    // SET 18g.i — carry ORIGINAL prompt line numbers (omit when not found).
    // SET 32f — anchor invariant: every plan MUST carry ≥1 case named after an
    // owned export. When feature.exports produced none (e.g. class-only stubs
    // with no exports[] entry), inject one deterministically from the stub
    // scaffold. The anchor leads batch 1 downstream.
    let plan = planSuite(spec, feature);
    const anchored = injectClassAnchor(plan, feature);
    plan = anchored.plan;
    if (anchored.injected) {
      emit('ir', feature.id,
        `plan: injected class-anchor case "${anchored.injected.name}" (from owned stub)`);
    }
    // SET 83 — the anchor is DERIVABLE from the stub; drawing it wasted six
    // calls on the coldest feature of every run. Fill it deterministically
    // so the cold node gets a frozen exemplar before its first model draw.

    const keptCases: PlannedCase[] = [];
    for (const p of plan.cases) {
      const hits = scanCapabilities(p.license).map(hit => {
        const line = findPromptLineNumber(scanText, p.license);
        const row: CapabilityHit = { ...hit, item: p.license.slice(0, 80) };
        if (line != null) row.line = line;
        else delete row.line;
        return row;
      });
      const full = hits.filter(h => !h.partial);
      const partial = hits.filter(h => h.partial);
      if (full.length) {
        for (const hit of full) {
          deferred.push(hit);
          metrics.deferredTotal++;
          emit('ir', feature.id,
            `excluded: "${hit.item}" — requires ${hit.capability}; not testable in this runtime${fmtLine(hit.line)}`);
        }
        problems.push(
          `${feature.id}: case "${p.name}" excluded — requires ${full[0]!.capability}`,
        );
        continue;
      }
      for (const hit of partial) {
        deferred.push(hit);
        metrics.deferredTotal++;
        // SET 69 — behavior/binding split: the binding clause is excised,
        // the behavioral invariant stays planned under a simulated dependency.
        if (hit.behavioralSplit) {
          emit('ir', feature.id,
            `behavior/binding split: case "${p.name}" kept — binding "${hit.behavioralSplit.binding}" excised (${hit.behavioralSplit.simClade})${fmtLine(hit.line)}`);
        } else {
          emit('ir', feature.id,
            `excluded: case "${p.name}" — requires ${hit.capability}; not testable in this runtime${fmtLine(hit.line)}`);
        }
      }
      const behavioralHit = partial.find(h => h.behavioralSplit);
      keptCases.push(behavioralHit?.behavioralSplit
        ? { ...p, license: behavioralHit.behavioralSplit.behavior }
        : p);
    }
    plan = { ...plan, cases: keptCases };
    if (!plan.cases.length) {
      problems.push(`${feature.id}: abandoned — all planned cases excluded`);
      emit('ir', feature.id, 'abandoned — all planned cases excluded');
      return { status: 'skipped', reason: 'all planned cases out-of-scope' };
    }
    let fill = applyTemplates(plan, feature.edgeCases);
    metrics.templatedCases += fill.templated;
    emit('ir', feature.id,
      `plan: ${plan.cases.length} cases (${fill.templated} substrate-templated, ${fill.holes.length} model draws)`);
    for (const ev of fill.events) emit('ir', feature.id, ev);
    // SET 34e / 71b — planner-unwired tripwire, now CLOSING the gap it
    // detects: a matched consumable template gets INSTANTIATED (0 tok), not
    // reported-and-wasted. Only genuinely uninstantiable matches still trip.
    // SET 78 — the closure runs whenever ANY match is unconsumed, not only
    // when nothing templated at all (Andy's F2: templated ≥1 and still
    // reported "1 matching templates unused").
    {
      const unused = countMatchingTemplatesForPlan(fill.holes, feature.edgeCases);
      if (unused >= 1) {
        const rescuedCases: IRCaseGen[] = [];
        const remainingHoles: PlannedCase[] = [];
        for (const h of fill.holes) {
          const t = h.symbol ? matchConsumableTemplate(h) : null;
          const body = t && h.symbol ? t.body.replace(/SYM/g, h.symbol) : '';
          if (t && h.symbol && acceptCaseBody(body)) {
            rescuedCases.push({
              name: h.name, kind: h.kind, body,
              clade: classifyCaseClade({ name: h.name, kind: h.kind, body }, h.symbol),
            });
            metrics.templatedCases++;
            emit('ir', feature.id,
              `templated ${h.name} via ${t.id} (planner-bypass closed, 0 tok)`);
          } else {
            remainingHoles.push(h);
          }
        }
        if (rescuedCases.length) {
          fill = {
            ...fill,
            cases: [...fill.cases, ...rescuedCases],
            templated: fill.templated + rescuedCases.length,
            holes: remainingHoles,
          };
        }
        const stillUnused = countMatchingTemplatesForPlan(remainingHoles, feature.edgeCases);
        if (stillUnused >= 1) {
          noteEvidence('ir', feature.id, [formatPlannerBypass(stillUnused)]);
        }
      }
    }

    // SET 3c — provenance chains (case → license → feature.description → prompt).
    // Uses the RAW / user-facing prompt — never the harness contract.
    for (const p of plan.cases) {
      provenance.push({
        caseName: p.name, kind: p.kind, license: p.license, source: p.source,
        featureId: feature.id, featureDescription: feature.description, prompt: opts.prompt,
      });
    }

    let trialParts: IRParts = {
      imports: plan.imports.map(i => ({ ...i, symbols: [...i.symbols] })),
      cases: fill.cases.map(c => ({ ...c })),
    };
    let allowed = allowedSymbols(plan, feature);

    // SET 32c/32g — per-feature effort floor: at least N candidate-batch
    // CYCLES per feature (+1 per distinct dependent, capped). Between
    // cycles we do ONE substrate-anchored replan (fresh planSuite + anchor
    // injection + templates) — same finite parts, no bigger model. First
    // cycle fills SOMETHING → we exit and move on; only zero-progress
    // cycles trigger the replan → retry loop.
    const floor = effortFloor(feature, ordered);
    let candidateCycles = 0;
    while (candidateCycles < floor) {
      candidateCycles++;
      if (candidateCycles > 1) {
        // SET 32c — substrate-anchored replan: fresh plan → inject anchor →
        // templates. Re-compute holes; anchor leads batch 1 again.
        const freshBase = planSuite(spec, feature);
        const freshAnchored = injectClassAnchor(freshBase, feature);
        const scoped = freshAnchored.plan.cases.filter(c =>
          keptCases.some(k => k.name === c.name) || c.name === freshAnchored.injected?.name);
        const freshPlan = { ...freshAnchored.plan, cases: scoped };
        const freshFill = applyTemplates(freshPlan, feature.edgeCases);
        const templatedDelta = Math.max(0, freshFill.templated - fill.templated);
        metrics.templatedCases += templatedDelta;
        plan = freshPlan;
        fill = freshFill;
        allowed = allowedSymbols(plan, feature);
        for (const c of freshFill.cases) {
          if (!trialParts.cases.some(x => caseNamesMatch(x.name, c.name))) {
            trialParts.cases.push({ ...c });
          }
        }
        emit('ir', feature.id, replanMessage(freshPlan.cases.length, freshFill.templated));
      }
    // SET 2c + 3a — per-case fill with permutation-select (K=3 temps).
    // Only draw for holes still unfilled (in trialParts).
    // SET 37g — previously-dropped cases fill FIRST (coverage backfill).
    const stillHoles = fill.holes
      .filter(h => !trialParts.cases.some(c => caseNamesMatch(c.name, h.name)))
      .sort((a, b) => {
        const ap = priorDropped.some(n => caseNamesMatch(n, a.name)) ? 0 : 1;
        const bp = priorDropped.some(n => caseNamesMatch(n, b.name)) ? 0 : 1;
        return ap - bp;
      });
    // SET 71 — per-NODE K-draws (Andy, 2026-07-27: "there should be 9"): the
    // bounded unit of a permutation batch is the CASE, not a 3-case bundle.
    // Single-target draws land almost always; bundled tails truncate. Cost is
    // 3× fill calls, bought deliberately for structural empty-tail immunity.
    for (let i = 0; i < stillHoles.length; i += 1) {
      bail();
      let batch = stillHoles.slice(i, i + 1);
      // SET 28b — name every case this batch targets BEFORE drawing, so a
      // dropped case always has ≥1 attempt event naming it even if every
      // draw in the batch subsequently throws.
      for (const h of batch) fillCandBatch.set(h.name, (fillCandBatch.get(h.name) ?? 0) + 1);
      emit('ir', feature.id, formatFillBatchTargets(batch.map(h => h.name)));
      // SET 97 — no model draw until every deterministic body mechanism has
      // either failed to produce a red case or been rejected as vacuous.
      if (opts.runSuite) {
        const escalated: PlannedCase[] = [];
        for (const h of batch) {
          const hit = await substrateFillOne({
            spec,
            feature,
            caseGen: { name: h.name, kind: h.kind, body: '', symbol: h.symbol },
            plannedCase: h,
            stubs: stubArtifact(spec),
            runSuite: opts.runSuite,
            imports: trialParts.imports,
            onMechanismResult: (_mechanism, result) => {
              if (result === 'empty') metrics.substrateFillEmptyMechanisms++;
              else if (result === 'vacuous') metrics.substrateFillVacuousMechanisms++;
            },
          });
          if (!hit) {
            metrics.substrateFillEscalations++;
            escalated.push(h);
            continue;
          }
          trialParts.cases.push({
            name: h.name,
            kind: h.kind,
            body: hit.body,
            clade: classifyCaseClade({ name: h.name, kind: h.kind, body: hit.body }, h.symbol),
          });
          metrics.substrateFillHits++;
          emit('ir', feature.id,
            `case "${h.name}" filled from substrate: ${hit.mechanism} (0 tok)`);
        }
        batch = escalated;
      } else {
        metrics.substrateFillEscalations += batch.length;
      }
      if (!batch.length) continue;
      // SET 95c — hole-only canary (primary fill site ONLY, gated OFF by
      // default): the harness assembles the deterministic `it()` frame
      // before the draw; the model is asked to return the assertion body
      // alone. `holeFrame` rides in `holeReq.errors` below and gates
      // acceptance after the draw returns.
      const holeFrame = gates.holeOnlyFill && batch.length === 1
        ? assembleCaseFrame(feature, batch[0]!.name, batch[0]!.kind)
        : null;
      // SET 17 — freeform planned cases get a superbuffer instead of naked draws.
      let irSuperbuffer = '';
      let irDigestPreamble = '';
      /** SET 34d — whether this batch's superbuffer carried templates. */
      let irSbHadTemplates: boolean | null = null;
      {
        // SET 78 — EVERY fill draw is buffered (Andy: "no supercache?"). The
        // old gate assembled a buffer only for signature-less or edge holes,
        // so export anchors like `authenticateUser` drew naked — no spec
        // page, no substrate page, no union page. A draw is a draw.
        const freeHole = batch.find(h => !h.signature || h.kind === 'edge') ?? batch[0];
        if (freeHole) {
          // SET 96b canary: default-off. The folded shape uses candidate zero's
          // deterministic digest rather than spending this standalone watcher call.
          if (!gates.set96bFoldWatcherIntoCandidate0) {
            await synthesizeForDraw('ir', feature.id, stubArtifact(spec));
          }
          const context = assembleContext({
            stage: 'ir',
            featureId: feature.id,
            spec, feature, parts: trialParts,
            stubs: feature.stubs,
            lessons: opts.lessons ?? [],
            siblingParts: irPartsByFeature,
            target: freeHole.name,
            conceptText: conceptByFeature.get(feature.id) ?? null,
            substrateHandoff: substrateHandoffFor(feature.id),
            ledgerRows: supergit.allRows(),
            artifact: stubArtifact(spec),
            cachedReading: watch.reading,
            signature: freeHole.signature
              ? {
                name: freeHole.signature.name,
                params: freeHole.signature.params.map(p => p.type),
                returnType: freeHole.signature.returnType,
              }
              : null,
          });
          irSuperbuffer = emitSuperbufferAssembly('ir', feature.id, context.assembly, 'fill');
          irDigestPreamble = context.digestPreamble;
          irSbHadTemplates = context.assembly.templates.length > 0;
        }
      }
      // SET 65 — synthesis grammar (flagged): deterministic invariant gate
      // renders a typed-hole skeleton for this hole; the model fills holes only.
      let grammarSk: RenderedSkeleton | null = null;
      if (gates.grammarEnabled) {
        const h0 = batch[0];
        const sym = h0?.symbol ?? feature.exports[0]?.symbol;
        if (h0 && sym) {
          const invariants = chooseInvariants({ name: h0.name, kind: h0.kind, license: h0.license });
          grammarSk = renderSkeleton(invariants[0]!, sym);
        }
      }
      const holeReq = batch.map(h => ({
        name: h.name,
        kind: h.kind,
        errors: [
          `Fill ONLY this ${h.kind} case.`,
          h.symbol ? `Symbol under test: ${h.symbol}` : '',
          h.signature
            ? `Signature: ${h.signature.name}(${h.signature.params.map(p => `${p.name}: ${p.type}`).join(', ')}): ${h.signature.returnType}`
            : '',
          h.source === 'edge' ? `Edge text (license): ${h.license}` : '',
          grammarSk ? skeletonPrompt(grammarSk) : '',
          // SET 95c — hole-only contract: the frame already exists; the
          // model returns ONLY the ⟨HOLE⟩…⟨/END⟩ block for the assertion.
          holeFrame
            ? [
              IR_SYSTEM_HOLE,
              'The frame already exists — do not repeat it:',
              holeFrame.bytes,
              `Assertion budget: ${holeFrame.holeBudgetBytes} bytes (hard cap ${Math.round(holeFrame.holeBudgetBytes * 1.5)}).`,
            ].join('\n')
            : '',
          irSuperbuffer,
          'Prior case bodies withheld. Assert behavior — no existence-only checks.',
        ].filter(Boolean),
      }));
      try {
        const cands: PermutationCandidate<IRCaseGen[]>[] = [];
        /** SET 65 — bodies produced by skeleton reassembly (winner attribution). */
        const grammarBodies = new Set<string>();
        metrics.permBatches++;
        for (let ci = 0; ci < PERMUTATION_TEMPS.length; ci++) {
          const temp = PERMUTATION_TEMPS[ci]!;
          const isWatcherInfused = gates.set96bFoldWatcherIntoCandidate0 && ci === 0;
          if (isWatcherInfused) metrics.watcherInfusedCandidates++;
          bail();
          metrics.permutationDraws++;
          metrics.permCandidates++;
          metrics.candidatesDrawn++;
          metrics.fillCandidatesDrawn++;
          metrics.irGenAttempts++;
          for (const h of batch) fillDraws.set(h.name, (fillDraws.get(h.name) ?? 0) + 1);
          const fixed = await runLlmAction({
            method: 'fixTestCases:fill',
            target: feature.id, phase: 'ir',
            startEvidence: { temperature: temp, candidateIndex: ci + 1, holes: batch.map(h => h.name) },
            fn: () => opts.llm.fixTestCases(
              spec, feature, holeReq.map(hole => ({
                ...hole,
                errors: isWatcherInfused
                  ? [...hole.errors, irDigestPreamble].filter(Boolean)
                  : hole.errors,
              })), [], trialParts.imports,
              { temperature: temp, candidate: { n: ci + 1, k: PERMUTATION_TEMPS.length } },
            ),
          });
          // SET 5a — bind by INDEX; returned name is advisory only.
          const bound = bindFixTestCases(
            batch.map(h => ({ name: h.name, kind: h.kind })),
            fixed.cases,
          );
          metrics.mechanicalFixes += bound.unwrapFixes;
          let score = 0;
          let findings = 0;
          const accepted: IRCaseGen[] = [];
          for (let i = 0; i < bound.cases.length; i++) {
            const fc = bound.cases[i]!;
            const hole = batch[i]!;
            let body = fc.body;
            // SET 95c — overreach|body gate (canary, this call site ONLY):
            // reject a response that omits the hole marker, exceeds the
            // 1.5× budget, or reproduces boilerplate outside the marker.
            // Acceptance replaces `body` with the extracted assertion ONLY
            // — the frame around it is context, never re-stored (IRParts
            // case bodies are assertion-only by contract).
            if (holeFrame) {
              const overreach = isOverreach(body, holeFrame.holeBudgetBytes);
              if (overreach.over) {
                metrics.overreachBodyRejections++;
                findings++;
                emit('ir', feature.id,
                  `case "${hole.name}" rejected overreach|body: ${overreach.reason}`);
                continue;
              }
              body = extractHole(body).body ?? body;
            }
            /** SET 65 — grammar conformance: reassemble skeleton + validated fills. */
            let grammarConformed = false;
            if (grammarSk) {
              const conf = conformDrawToSkeleton(body, grammarSk);
              if (conf) {
                body = conf.body;
                grammarConformed = true;
              }
            }
            const syn = caseSyntaxErrors([{ name: hole.name, body }])[0];
            if (syn) {
              const healed = healCaseBody(body, syn.error);
              if (healed) {
                body = healed.body;
                metrics.mechanicalFixes++;
                opts.onLesson?.(distillLesson(
                  `ir-syntax|${healed.token}`, syn.error,
                  `${healed.via} repair of case body (${healed.token})`,
                ));
                emit('ir', feature.id,
                  `case "${hole.name}" healed via ${healed.via} (${healed.token}, 0 tok)`);
              }
            }
            const surface = surfaceConformanceErrors(body, allowed);
            const acceptable = acceptCaseBody(body);
            if (surface.length || !acceptable) {
              findings++;
              const reason = surface.length
                ? `surface-conformance: ${surface[0]!.slice(0, 80)}`
                : 'accept-body: predicate rejected body';
              emit('ir', feature.id,
                `case "${hole.name}" candidate ${ci + 1}/${PERMUTATION_TEMPS.length} rejected after fill — ${reason}`);
              metrics.healedButRejected = (metrics.healedButRejected ?? 0) + 1;
              continue;
            }
            score++;
            if (grammarConformed) grammarBodies.add(body);
            accepted.push({
              name: hole.name, kind: hole.kind, body,
              clade: classifyCaseClade({ name: hole.name, kind: hole.kind, body }, hole.symbol),
            });
          }
          cands.push({
            value: accepted, temp, score, findings,
            label: `${score}/${batch.length} passing`,
          });
          // SET 76 — every drawn BODY informs the metasupercache, whether it
          // wins or dies (Andy: "they aren't informing the metasupercache").
          // Cross-run memory of dead shapes is what makes corpse detection
          // work on the NEXT run, not just this one.
          {
            const drawnBodies = bound.cases.map(c => c.body ?? '').join('\n');
            const fillHash = drawHashForFiles(
              batch.map((h, i) => ({ path: `${feature.testFile}#${h.name}`, content: bound.cases[i]?.body ?? '' })));
            const fillCorpse = corpseCheck(fillHash, runDrawHashes, metaCorpseHashes);
            if (fillCorpse) {
              noteCorpseRejection('ir', feature.id, batch[0]?.name ?? feature.id);
              emit('ir', feature.id, formatCorpseEvent(`fill|${batch[0]?.name ?? feature.id}`, fillCorpse));
            }
            runDrawHashes.add(fillHash);
            noteMetaCandidate({
              classKey: `fill|${batch[0]?.kind ?? 'behavior'}`,
              layer: 'fill', temp, score, findings,
              parseStatus: score > 0 ? 'parsed' : 'unparseable',
              hash: fillHash,
              body: drawnBodies.slice(0, 400),
            });
          }
          // SET 76 — authenticate, then STOP (Andy: "stop looping once
          // something is accepted. we don't need to accumulate the bodies").
          // Every hole in this batch filled and validated → the remaining
          // temps are pure waste.
          if (score === batch.length) {
            emit('ir', feature.id,
              `fill accepted at try ${ci + 1}/${PERMUTATION_TEMPS.length} (t=${temp}) — ladder stopped`);
            break;
          }
        }
        if (cands.length) {
          const pick = selectPermutation(cands);
          metrics.permutationWins++;
          if (pick.picked.score > 0) {
            metrics.permImproved++;
            metrics.candidatesAccepted++;
            // SET 89 §8.4 — fill-layer adopted candidate.
            metrics.fillCandidatesAccepted++;
          }
          if (irSuperbuffer && pick.picked.score > 0) {
            metrics.superbufferWins++;
            const pk = freeformPatternKey({ caseName: batch[0]?.name });
            const n = (freeformWinCounts.get(pk) ?? 0) + 1;
            freeformWinCounts.set(pk, n);
            if (shouldProposeCladePromotion(n)) {
              const proposal = draftCladePromotion({
                patternKey: pk, featureId: feature.id, wins: n,
                stubSketch: feature.stubs[0]?.content,
                caseBody: pick.picked.value[0]?.body,
                source: 'in-run-win',
              });
              emit('ir', feature.id, formatCladeCandidateMessage(proposal));
              opts.onCladeCandidate?.(proposal);
            }
          }
          emit('ir', feature.id, permutationEvent(pick));
          // Score 0 (e.g. MockLlm empty fill) → leave holes for generateTests fallback.
          if (pick.picked.score > 0) {
            for (const fc of pick.picked.value) {
              if (!trialParts.cases.some(c => caseNamesMatch(c.name, fc.name))) {
                trialParts.cases.push(fc);
                emit('ir', feature.id, `case "${fc.name}" filled by model`);
                // SET 65 — grammar attribution on the accepted winner only.
                // SET 95e — the fallback-narration branch is retired: a
                // non-conformant-but-accepted draw is no longer reported via
                // the old "grammar fallback: ..." event (doctrine: SET 95's
                // hole-only contract replaces shell-lock's soft
                // reassembly-or-passthrough; positive conformance reporting
                // is unchanged, the fallback pass-through narration is not).
                if (grammarSk && grammarBodies.has(fc.body)) {
                  metrics.grammarConformant++;
                  emit('ir', feature.id, formatGrammarConform(fc.name, grammarSk.invariant));
                }
              }
            }
            // SET 60 — per-case cross-candidate salvage: a losing candidate's
            // accepted case is already paid for and already validated (syntax
            // heal + conformance + accept ran at construction). Compose it in
            // before rebind/drop ever runs. Deterministic order: higher score
            // first, then cooler temperature.
            {
              const losers = cands
                .filter(c => c !== pick.picked)
                .sort((a, b) => (b.score - a.score) || (a.temp - b.temp));
              for (const h of batch) {
                if (trialParts.cases.some(c => caseNamesMatch(c.name, h.name))) continue;
                for (const cand of losers) {
                  const alt = cand.value.find(fc => caseNamesMatch(fc.name, h.name));
                  if (!alt) continue;
                  trialParts.cases.push(alt);
                  metrics.salvagedCases++;
                  emit('ir', feature.id,
                    `case "${h.name}" salvaged from candidate t=${cand.temp} (cross-candidate, 0 extra tok)`);
                  break;
                }
              }
            }
            for (const h of batch) {
              if (trialParts.cases.some(c => caseNamesMatch(c.name, h.name))) continue;
              // SET 3b — rebind schema'd miss before drop.
              const rebound = rebindCladeBody({
                name: h.name, kind: h.kind, body: '',
                clade: classifyCaseClade({ name: h.name, kind: h.kind, body: '' }, h.symbol),
              });
              if (rebound && acceptCaseBody(rebound) && !surfaceConformanceErrors(rebound, allowed).length) {
                trialParts.cases.push({
                  name: h.name, kind: h.kind, body: rebound,
                  clade: classifyCaseClade({ name: h.name, kind: h.kind, body: rebound }, h.symbol),
                });
                metrics.mechanicalFixes++;
                emit('ir', feature.id, `case "${h.name}" rebound via clade (0 tok)`);
                continue;
              }
              // SET 64a — no verdict here: an all-candidates-empty case queues
              // for single-target rescue; only the END of the fill ladder
              // (post-rescue, post-fallback) may pronounce a drop.
              emit('ir', feature.id,
                `case "${h.name}" empty in all candidates — queued for single-target rescue (0 tok)`);
            }
          }
        }
      } catch (e) {
        emit('ir', feature.id,
          `per-case fill failed for [${batch.map(h => `"${h.name}"`).join(', ')}]: `
          + `${e instanceof Error ? e.message : String(e)}`);
      }
    }
      // SET 32g — filled anything this cycle? break; else replan on next.
      if (trialParts.cases.length > 0) break;
    }

    // Binding reject: missing planned cases that still have no body.
    const have = new Set(trialParts.cases.map(c => c.name));
    let missing = plan.cases.filter(p => !have.has(p.name));



    // SET 71 — the SET 64a empty-tail rescue stage is SUPERSEDED: per-node
    // K-draws are the primary fill shape now, so a missing case already had
    // its own dedicated candidate batch; re-drawing here duplicated it.
    // Missing cases flow to the fallback below, then SET 70 re-enqueue.

    // SET 2 — generateTests only as structural fallback.
    // Prefer plan-bound parts; content-only fixtures (MockLlm) freeze as-is
    // whenever the plan-bound path left required cases unfilled.
    let fixtureContent: string | null = null;
    if (missing.length) {
      emit('ir', feature.id, formatFillBatchTargets(missing.map(p => p.name), 'fallback'));
      usedFallbackFill.add(feature.id);
      for (const p of missing) fillFallBatch.set(p.name, (fillFallBatch.get(p.name) ?? 0) + 1);
      // SET 73 — the fallback fill was the last NAKED draw in the IR phase:
      // no superbuffer (Andy: "superbuffer isn't invoked before this LLM call
      // and it should always be") and only gates.irAttempts=2 tries. It now
      // carries the salient node — this feature's encoded spec, stub contract,
      // substrate handoff, concept, and the sibling cases already filled this
      // cycle — and walks the full 3-rung ladder like every other call.
      await synthesizeForDraw('ir', feature.id, stubArtifact(spec));
      const fbContext = assembleContext({
        stage: 'ir',
        featureId: feature.id,
        spec, feature, parts: trialParts,
        stubs: feature.stubs,
        lessons: opts.lessons ?? [],
        siblingParts: irPartsByFeature,
        target: missing.map(p => p.name).join(' | ') || feature.id,
        conceptText: conceptByFeature.get(feature.id) ?? null,
        substrateHandoff: substrateHandoffFor(feature.id),
        ledgerRows: supergit.allRows(),
        artifact: stubArtifact(spec),
        cachedReading: watch.reading,
        signature: feature.exports[0]
          ? { name: feature.exports[0].symbol, params: [], returnType: 'unknown' }
          : null,
      });
      const fbBuffer = emitSuperbufferAssembly('ir', feature.id, fbContext.assembly, 'fill');
      const fbTries = Math.max(gates.irAttempts, PERMUTATION_TEMPS.length);
      for (let attempt = 0; attempt < fbTries; attempt++) {
        bail();
        if (attempt > 0) metrics.irRedraws++;
        for (const p of missing) fillDraws.set(p.name, (fillDraws.get(p.name) ?? 0) + 1);
        const { result: out } = await actionLedger.runAction({
          kind: 'llm:generateTests',
          target: feature.id,
          phase: 'ir',
          startEvidence: {
            attempt: attempt + 1, candidateN: attempt + 1, candidateK: fbTries,
          },
          fn: () => opts.llm.generateTests(spec, feature,
            [
              `Plan-bound fallback. Required cases: ${plan.cases.map(c => `${c.kind}:${c.name}`).join(', ')}`,
              fbBuffer,
            ].filter(Boolean).join('\n\n'),
            {
              attempt: attempt + 1,
              temperature: PERMUTATION_TEMPS[Math.min(attempt, PERMUTATION_TEMPS.length - 1)],
              candidate: { n: attempt + 1, k: fbTries },
            }),
        });
        if (out.parts?.cases.length) {
          for (const c of out.parts.cases) {
            const planned = plan.cases.find(p => caseNamesMatch(p.name, c.name));
            if (!planned) continue;
            let body = c.body;
            const uw = unwrapCaseBody(body);
            if (uw.unwrapped) { body = uw.body; metrics.mechanicalFixes++; }
            if (!acceptCaseBody(body)) {
              const lint = dynamicEvalLint(body);
              if (lint) {
                problems.push(`${feature.id}: case "${planned.name}" dropped — ${lint} (coverage reduced)`);
                emit('ir', feature.id, `case "${planned.name}" dropped — ${lint} (coverage reduced)`);
                have.add(planned.name); // do not retry a forbidden synthesis pattern
              }
              continue;
            }
            if (surfaceConformanceErrors(body, allowed).length) continue;
            if (!have.has(planned.name)) {
              trialParts.cases.push({ ...c, name: planned.name, kind: planned.kind, body });
              have.add(planned.name);
            }
          }
          if (out.parts.imports.length) trialParts.imports = plan.imports;
          if (!plan.cases.some(p => !have.has(p.name))) break;
        } else if (
          out.content
          && !validateSuiteShape(out.content).length
          && !suiteSyntaxError(out.content)
        ) {
          fixtureContent = out.content;
          break;
        }
        if (!missing.some(p => !have.has(p.name))) break;
      }
    }

    if (fixtureContent) {
      // SET 89 §3.1 v2 — the fixture-freeze pre-check uses the honest
      // "did any case fail against stubs" predicate (`hasRedCase`). It is
      // NOT a freeze authority — freeze eligibility is decided by
      // `commitFrozenSuite` below. This gate only refuses obviously-vacuous
      // fixture bodies before we spend a freeze attempt.
      if (opts.runSuite) {
        const brRun = await opts.runSuite(
          stubArtifact(spec),
          { path: feature.testFile, content: fixtureContent },
        );
        emit('ir', feature.id, formatBornRedEvent(scoreBornRed(brRun)));
        if (!hasRedCase(brRun)) {
          emit('ir', feature.id,
            'born-red: all-vacuous fixture suite — freeze refused (assert observable behavior)');
          return { status: 'deferred', reason: 'born-red vacuous suite' };
        }
      }
      // SET 47b — freeze-time scaffold-owned free-ident → import (0 tok).
      const wiredFx = wireSuiteScaffoldImports(fixtureContent, feature.testFile, spec);
      fixtureContent = wiredFx.content;
      if (wiredFx.injected.length) {
        emit('ir', feature.id,
          `suite scaffold-wire: injected ${wiredFx.injected.map(i => i.symbol).join(', ')} (0 tok)`);
        // SET 89 §9.1 — scaffold-wire is a deterministic edit OUTSIDE the
        // `attemptMechanicalFix` denominator; counting it as
        // `substrateFixes` inflated the actionable hit-rate. Track it on
        // `mechanicalFixes` (the wider "edits applied" concept) only.
        metrics.mechanicalFixes += wiredFx.injected.length;
        metrics.deterministicEditsOutsideSubstrate += wiredFx.injected.length;
      }
      // SET 89 §4.4 v2 — fixture-fallback initial freeze routes through
      // the SAME `commitFrozenSuite` gateway used by canonical freezes.
      // The bypass mode SKIPS per-case certification (no canonical parts)
      // but still runs suite shape, standalone syntax, and whole-program
      // parse gates. The write is atomic (all three maps or none).
      const fixtureCommit = await commitFrozenFixture(
        feature, fixtureContent, 'fixture-fallback');
      if (fixtureCommit.status === 'rejected') {
        const reason = fixtureCommit.report.rejectionReasons[0]
          ?? 'fixture-fallback gateway refused';
        emit('ir', feature.id,
          `fixture-fallback freeze refused (gateway): ${reason.slice(0, 200)}`);
        return { status: 'deferred', reason };
      }
      if (!opts.runSuite) {
        emit('ir', feature.id,
          'fixture-fallback freeze uncertified: no runSuite host (case cert skipped, parse gate ran)');
      } else {
        emit('ir', feature.id,
          `fixture-fallback freeze accepted (case-cert bypassed — no canonical IRParts)`);
      }
      if ((metaloopCount.get(feature.id) ?? 1) <= 1 && !usedFallbackFill.has(feature.id)) {
        metrics.featuresFrozenWithoutRedraw++;
      }
      emit('ir', feature.id,
        `frozen suite ${feature.testFile} (fixture fallback; ${plan.cases.length} planned)`);
      return { status: 'frozen' };
    }

    // SET 1 heal pass on whatever we have, then drop residual broken cases.
    let pinpoints = caseSyntaxErrors(trialParts.cases);
    if (pinpoints.length) {
      emit('ir', feature.id, `syntax — ${pinpoints.length} broken case(s) pinpointed`);
      for (const pp of pinpoints) {
        const idx = trialParts.cases.findIndex(c => caseNamesMatch(c.name, pp.name));
        if (idx < 0) continue;
        const healed = healCaseBody(trialParts.cases[idx]!.body, pp.error);
        if (!healed) continue;
        trialParts.cases[idx] = { ...trialParts.cases[idx]!, body: healed.body };
        metrics.mechanicalFixes++;
        opts.onLesson?.(distillLesson(
          `ir-syntax|${healed.token}`, pp.error,
          `${healed.via} repair of case body (${healed.token})`,
        ));
        emit('ir', feature.id, `case "${pp.name}" healed via ${healed.via} (${healed.token}, 0 tok)`);
      }
      pinpoints = caseSyntaxErrors(trialParts.cases);
      // SET 37h — mechanical already ran in place; residual parse failures go to
      // the failure stack (model draws from the END with a warm buffer).
      if (pinpoints.length) {
        for (const pp of pinpoints) {
          const body = trialParts.cases.find(c => caseNamesMatch(c.name, pp.name))?.body ?? '';
          if (isEmptyDrawMessage(pp.error) || !body.trim()) {
            // SET 37d — empty-draw skips stack; try method-anchor clade template.
            if (isMethodAnchorName(pp.name)) {
              const tmpl = methodAnchorBody(pp.name);
              const idx = trialParts.cases.findIndex(c => caseNamesMatch(c.name, pp.name));
              if (idx >= 0 && acceptCaseBody(tmpl) && !surfaceConformanceErrors(tmpl, allowed).length) {
                trialParts.cases[idx] = {
                  ...trialParts.cases[idx]!,
                  body: tmpl,
                  clade: classifyCaseClade({ name: pp.name, kind: trialParts.cases[idx]!.kind, body: tmpl }, pp.name),
                };
                metrics.templatedCases++;
                metrics.mechanicalFixes++;
                emit('ir', feature.id, `case "${pp.name}" filled via ${METHOD_ANCHOR_CLADE} (0 tok, empty-draw)`);
                continue;
              }
            }
            emit('ir', feature.id, `case "${pp.name}" ${formatEmptyDraws(1)} — skipped failure stack`);
            continue;
          }
          const snippet = body.replace(/\s+/g, ' ').slice(0, 80);
          const pushed = pushDeferredFailure(failureStack, {
            featureId: feature.id,
            caseName: pp.name,
            kind: 'parse',
            brokenDraw: body,
            parseError: pp.error,
            snippet,
          });
          failureStack = pushed.state;
          if (pushed.pushed) {
            emit('ir', feature.id,
              `case "${pp.name}" deferred to failure stack (instance ${pushed.pushed.instance}/${FAILURE_STACK_INSTANCE_CAP})`);
          } else {
            const dropReason = formatUnparseableDropReason(pp.error, body);
            problems.push(`${feature.id}: case "${pp.name}" ${dropReason} (coverage reduced)`);
            emit('ir', feature.id, `case "${pp.name}" ${dropReason} (coverage reduced)`);
          }
        }
        // Drain stack: ONE warm targeted redraw per entry (end of queue).
        while (failureStack.queue.some(e => e.featureId === feature.id)) {
          bail();
          const popped = popDeferredFailure(failureStack);
          failureStack = popped.state;
          const entry = popped.entry;
          if (!entry || entry.featureId !== feature.id) {
            if (entry) {
              // Not ours — push back to end.
              const back = pushDeferredFailure(failureStack, entry);
              failureStack = back.state;
            }
            break;
          }
          try {
            const warmSb = assembleSuperbuffer({
              spec, feature, parts: trialParts,
              stubs: feature.stubs,
              lessons: opts.lessons ?? [],
              siblingParts: irPartsByFeature,
              target: entry.caseName,
              stage: 'fill',
              conceptText: conceptByFeature.get(feature.id) ?? null,
              findingEvidence: formatStackRepairPrompt(entry),
            });
            emit('ir', feature.id, warmSb.logLine);
            fillDraws.set(entry.caseName, (fillDraws.get(entry.caseName) ?? 0) + 1);
            const c = trialParts.cases.find(x => caseNamesMatch(x.name, entry.caseName));
            if (!c) continue;
            // SET 95d — hole-only gate rolled to fallback fill (same contract as the 95c canary).
            const wwFrame = holeOnlyFrameFor(gates, feature, c.name, c.kind as IRCaseGen['kind']);
            const fixed = await runLlmAction({
              method: 'fixTestCases:warm-world',
              target: feature.id, phase: 'ir',
              startEvidence: {
                temperature: TEMPS[TEMPS.length - 1],
                caseName: c.name, instance: entry.instance,
              },
              fn: () => opts.llm.fixTestCases(
                spec, feature,
                [{
                  name: c.name, kind: c.kind,
                  errors: [
                    formatStackRepairPrompt(entry), formatSuperbufferForPrompt(warmSb),
                    holeOnlyPromptBlock(wwFrame),
                  ].filter(Boolean),
                }],
                [], trialParts.imports,
                { temperature: TEMPS[TEMPS.length - 1], attempt: entry.instance },
              ),
            });
            metrics.irGenAttempts++;
            const bound = bindFixTestCases([{ name: c.name, kind: c.kind }], fixed.cases);
            metrics.mechanicalFixes += bound.unwrapFixes;
            const fc = bound.cases[0];
            let body = fc?.body ?? '';
            const wwGate = applyHoleOnlyGate(wwFrame, body, metrics, entry.caseName,
              msg => emit('ir', feature.id, msg));
            if (wwGate.rejected) continue;
            body = wwGate.body;
            const syn = caseSyntaxErrors([{ name: c.name, body }])[0];
            if (syn) {
              const healed = healCaseBody(body, syn.error);
              if (healed) { body = healed.body; metrics.mechanicalFixes++; }
            }
            const idx = trialParts.cases.findIndex(x => caseNamesMatch(x.name, entry.caseName));
            if (idx >= 0 && acceptCaseBody(body) && !caseSyntaxErrors([{ name: c.name, body }]).length
              && !surfaceConformanceErrors(body, allowed).length) {
              trialParts.cases[idx] = { ...trialParts.cases[idx]!, body };
              emit('ir', feature.id, `case "${entry.caseName}" warm-repaired from failure stack`);
            } else {
              const dropReason = formatStackDropReason({ oraclePass: true, warmRedraw: true });
              problems.push(`${feature.id}: case "${entry.caseName}" ${dropReason} (coverage reduced)`);
              emit('ir', feature.id, `case "${entry.caseName}" ${dropReason} (coverage reduced)`);
              trialParts = {
                ...trialParts,
                cases: trialParts.cases.filter(x => !caseNamesMatch(x.name, entry.caseName)),
              };
            }
          } catch {
            const dropReason = formatStackDropReason({ oraclePass: true, warmRedraw: true });
            problems.push(`${feature.id}: case "${entry.caseName}" ${dropReason} (coverage reduced)`);
            emit('ir', feature.id, `case "${entry.caseName}" ${dropReason} (coverage reduced)`);
            trialParts = {
              ...trialParts,
              cases: trialParts.cases.filter(x => !caseNamesMatch(x.name, entry.caseName)),
            };
          }
        }
        // Drop any residual broken cases still present.
        pinpoints = caseSyntaxErrors(trialParts.cases);
        if (pinpoints.length) {
          const brokenNames = new Set(pinpoints.map(p => p.name));
          trialParts = {
            ...trialParts,
            cases: trialParts.cases.filter(c => !brokenNames.has(c.name) && acceptCaseBody(c.body)),
          };
        }
      }
    }

    // SET 28b / 32e.i — drop message states the TRUE draw / candidate-batch /
    // fallback-batch counts; never claim retries that didn't happen. Zero
    // draws → "never drawn" (plan exceeded fill budget) — a materially
    // different failure than "tried and failed".
    for (const m of plan.cases.filter(p => !trialParts.cases.some(c => c.name === p.name))) {
      const msg = formatFillDropMessage(
        m.name,
        fillDraws.get(m.name) ?? 0,
        fillCandBatch.get(m.name) ?? 0,
        fillFallBatch.get(m.name) ?? 0,
      );
      // SET 70 — re-enqueue instead of dropping; the end-of-run case-relay
      // gets the warm-world shot. No suite runner → the relay could never
      // adjudicate adoption, so keep the classic drop. Overflow ditto.
      if (opts.runSuite && endOfRunCaseStack.length < END_OF_RUN_STACK_CAP) {
        endOfRunCaseStack.push({
          featureId: feature.id, name: m.name, kind: m.kind as IRCaseGen['kind'],
          reason: msg.replace(/^planned case "[^"]*" /, ''),
        });
        metrics.reEnqueuedCases++;
        emit('ir', feature.id,
          `planned case "${m.name}" re-enqueued to end-of-run stack (${fillDraws.get(m.name) ?? 0} cold draws spent — warm retry pending)`);
      } else {
        problems.push(`${feature.id}: ${msg}`);
        emit('ir', feature.id, msg);
      }
    }

    if (!trialParts.cases.length) {
      // SET 32h — fill exhaustion DEFERS instead of abandoning. Metaloop 2
      // will retry with a fresh anchor-injected plan against the warmer
      // buffer; only a failed WARM retry may abandon (SET 32d fan-out).
      const world = makeWorldSignature({
        frozenByFeature, lessonKeys: lessonKeysSeen, irPartsByFeature,
      });
      emit('ir', feature.id,
        deferralMessage({ frozenCount: world.frozenCount, siblingCaseCount: world.siblingCaseCount }));
      return { status: 'deferred', reason: `fill exhaustion (cycles=${candidateCycles}, floor=${floor}, metaloop=${metaloopPhase})` };
    }

    let trialContent = assembleTestFile(feature, trialParts.imports, trialParts.cases);
    const errs = validateSuiteShape(trialContent);
    let syntaxErr = errs.length ? null : suiteSyntaxError(trialContent);
    // SET 35b — reject dynamic-eval synthesis at the IR gate (same severity
    // as unparseable). Drop poisoned cases before freeze.
    if (!errs.length && !syntaxErr) {
      const poisoned = trialParts.cases.filter(c => dynamicEvalLint(c.body));
      if (poisoned.length) {
        for (const c of poisoned) {
          const reason = dynamicEvalLint(c.body)!;
          problems.push(`${feature.id}: case "${c.name}" dropped — ${reason} (coverage reduced)`);
          emit('ir', feature.id, `case "${c.name}" dropped — ${reason} (coverage reduced)`);
        }
        trialParts = {
          imports: trialParts.imports,
          cases: trialParts.cases.filter(c => !dynamicEvalLint(c.body)),
        };
        trialContent = assembleTestFile(feature, trialParts.imports, trialParts.cases);
        if (!trialParts.cases.length) {
          syntaxErr = 'dynamic-eval: all cases rejected (runtime code synthesis)';
        }
      }
    }
    // SET 25b — never freeze a suite with a broken literal. Try the delimiter
    // oracle for last-mile mechanical heals (regex char-class, quote closer,
    // brace balance) before abandoning the feature.
    if (!errs.length && syntaxErr) {
      const delim = applyDelimiterOracle(trialContent, syntaxErr);
      if (delim && !suiteSyntaxError(delim.content)) {
        trialContent = delim.content;
        syntaxErr = null;
        metrics.mechanicalFixes++;
        emit('ir', feature.id,
          `pre-freeze delimiter oracle heal (${delim.classKey}, ${delim.edits} edit${delim.edits === 1 ? '' : 's'}, 0 tok)`);
      }
    }
    if (errs.length || syntaxErr) {
      // SET 32h — suite couldn't be assembled to parse; defer for warm retry.
      const world = makeWorldSignature({
        frozenByFeature, lessonKeys: lessonKeysSeen, irPartsByFeature,
      });
      emit('ir', feature.id,
        `IR suite invalid (${errs.length || 1} shape/syntax finding) — ${deferralMessage({ frozenCount: world.frozenCount, siblingCaseCount: world.siblingCaseCount })}`);
      return { status: 'deferred', reason: 'suite failed validation' };
    }
    content = trialContent;
    // SET 3b — ensure every frozen case carries a clade tag.
    parts = {
      ...trialParts,
      cases: trialParts.cases.map(c => ({
        ...c,
        clade: c.clade ?? classifyCaseClade(c),
      })),
    };

    // SET 66 — scaffold-wire BEFORE born-red: free scaffold identifiers are a
    // known deterministic fix; measuring the unwired suite manufactures
    // sick-red that the wire was always going to cure.
    {
      const wired0 = wireSuiteScaffoldImports(content, feature.testFile, spec);
      if (wired0.injected.length) {
        content = wired0.content;
        emit('ir', feature.id,
          `suite scaffold-wire: injected ${wired0.injected.map(i => i.symbol).join(', ')} (0 tok)`);
        // SET 89 §9.1 — scaffold-wire is outside the substrate attempts
        // partition. See the fixture-freeze site for rationale.
        metrics.mechanicalFixes += wired0.injected.length;
        metrics.deterministicEditsOutsideSubstrate += wired0.injected.length;
      }
    }

    // SET 40d — born-red: measure against STUB artifact before freeze.
    // Green-on-stubs = vacuous → IR-case surgery once; still green → never freeze.
    if (opts.runSuite && parts.cases.length > 0) {
      const stubs = stubArtifact(spec);
      let brRun = await opts.runSuite(stubs, { path: feature.testFile, content });
      let br = scoreBornRed(brRun);
      // SET 89 §3.1 v2 — `hasRedCase` is the honest "at least one case
      // failed against stubs" predicate. Not a freeze authority: freeze is
      // decided per-case by `commitFrozenSuite` below.
      if (!hasRedCase(brRun)) {
        // SET 73 — throw-camouflage exemption: green-on-stubs is undecidable
        // for throw-expecting cases (the stub's own throw satisfies them);
        // they are retained, never surged, never re-enqueued as vacuous.
        const camoCount = parts.cases.filter(c =>
          !brRun.failures.some(f => f.name.includes(c.name)) && isThrowCamouflaged(c.body)).length;
        if (camoCount) emit('ir', feature.id, formatThrowCamouflage(camoCount));

        // SET 93 — a stub-derived throw case cannot be de-vacuum'd: its contract IS
        // "the stub throws," which becomes permanently false when a real impl lands.
        // Drop such cases at born-red with disclosure; do not send them to surgery.
        const stubDerivedDrops = parts.cases.filter(c =>
          !brRun.failures.some(f => f.name.includes(c.name))
          && isStubDerivedThrowCase(c.body, feature, spec));
        if (stubDerivedDrops.length) {
          metrics.bornRedStubDerivedDrops += stubDerivedDrops.length;
          emit('ir', feature.id,
            `born-red: ${stubDerivedDrops.length} stub-derived throw case(s) dropped — cannot be de-vacuum'd (stub is the contract)`);
          const dropSet = new Set(stubDerivedDrops.map(c => c.name));
          parts = { imports: parts.imports, cases: parts.cases.filter(c => !dropSet.has(c.name)) };
          if (!parts.cases.length) {
            return { status: 'deferred', reason: 'all cases stub-derived-throw dropped at born-red' };
          }
          // Re-assemble and re-measure so downstream sees the reduced suite.
          const asm = assembleTestFile(feature, parts.imports, parts.cases);
          content = wireSuiteScaffoldImports(asm, feature.testFile, spec).content;
          brRun = await opts.runSuite(stubs, { path: feature.testFile, content });
          br = scoreBornRed(brRun);
        }
        const vacuousNames = new Set(
          parts.cases
            .filter(c => !brRun.failures.some(f => f.name.includes(c.name)))
            .filter(c => !isThrowCamouflaged(c.body))
            .map(c => c.name),
        );
        const brokenCases = parts.cases
          .filter(c => vacuousNames.has(c.name))
          .map(c => ({
            name: c.name,
            kind: c.kind as IRCaseGen['kind'],
            errors: [VACUOUS_CASE_FINDING],
          }));
        if (brokenCases.length) {
          emit('ir', feature.id,
            `born-red: ${brokenCases.length} vacuous case(s) → surgery (${VACUOUS_CASE_FINDING})`);
          // SET 97 — surgery is also a fill path: exhaust deterministic
          // candidates for each vacuous member before spending a surgery draw.
          if (opts.runSuite) {
            let substrateChanged = false;
            const nextCases = [...parts.cases];
            for (const broken of brokenCases) {
              const index = nextCases.findIndex(c => caseNamesMatch(c.name, broken.name));
              const current = index >= 0 ? nextCases[index]! : null;
              if (!current) continue;
              const symbol = feature.exports.find(e => e.symbol === broken.name)?.symbol
                ?? feature.exports[0]?.symbol;
              const hit = await substrateFillOne({
                spec,
                feature,
                caseGen: { ...current, symbol },
                stubs,
                runSuite: opts.runSuite,
                imports: parts.imports,
                onMechanismResult: (_mechanism, result) => {
                  if (result === 'empty') metrics.substrateFillEmptyMechanisms++;
                  else if (result === 'vacuous') metrics.substrateFillVacuousMechanisms++;
                },
              });
              if (!hit) {
                metrics.substrateFillEscalations++;
                continue;
              }
              nextCases[index] = {
                ...current,
                body: hit.body,
                clade: classifyCaseClade({ ...current, body: hit.body }, symbol),
              };
              metrics.substrateFillHits++;
              substrateChanged = true;
              emit('ir', feature.id,
                `case "${broken.name}" filled from substrate: ${hit.mechanism} (0 tok)`);
            }
            if (substrateChanged) {
              parts = { imports: parts.imports, cases: nextCases };
              const substrateContent = assembleTestFile(feature, parts.imports, parts.cases);
              content = wireSuiteScaffoldImports(substrateContent, feature.testFile, spec).content;
              trialContent = content;
              brRun = await opts.runSuite(stubs, { path: feature.testFile, content });
              br = scoreBornRed(brRun);
            }
          }
          // SET 72 — every LLM call gets 3 tries: the surgery walks the
          // decorrelation ladder, re-targets only still-vacuous cases each
          // try, and stops at first red.
          // SET 87 — born-red surgery drew NAKED: no spec page, no contract
          // page, no substrate. It is asking for a behavioral assertion with
          // none of the material that says what the behavior IS.
          // SET 96a — CPU merge only; reuse any prior watcher reading (no new LLM).
          const surgeryContext = assembleContext({
            stage: 'ir',
            featureId: feature.id,
            spec, feature, parts,
            stubs: feature.stubs,
            lessons: opts.lessons ?? [],
            siblingParts: irPartsByFeature,
            target: `born-red|${feature.id}`,
            conceptText: conceptByFeature.get(feature.id) ?? null,
            substrateHandoff: substrateHandoffFor(feature.id),
            ledgerRows: supergit.allRows(),
            artifact: stubArtifact(spec),
            cachedReading: watch.reading,
          });
          const surgeryBuffer = emitSuperbufferAssembly('ir', feature.id, surgeryContext.assembly, 'born-red');
          for (let attempt = 0; attempt < PERMUTATION_TEMPS.length && !hasRedCase(brRun); attempt++) {
            const stillVacuous = parts.cases
              .filter(c => !brRun.failures.some(f => f.name.includes(c.name)))
              .filter(c => !isThrowCamouflaged(c.body))
              .map(c => ({
                name: c.name, kind: c.kind as IRCaseGen['kind'],
                errors: [VACUOUS_CASE_FINDING, surgeryBuffer].filter(Boolean),
              }));
            if (!stillVacuous.length) break;
            // SET 95d — hole-only gate rolled to born-red surgery (single-vacuous
            // batches only, same restriction as the 95c canary).
            const brFrame = stillVacuous.length === 1
              ? holeOnlyFrameFor(gates, feature, stillVacuous[0]!.name, stillVacuous[0]!.kind)
              : null;
            const brReq = brFrame
              ? stillVacuous.map(v => ({ ...v, errors: [...v.errors, holeOnlyPromptBlock(brFrame)].filter(Boolean) }))
              : stillVacuous;
            try {
              const fixed = await runLlmAction({
                method: 'fixTestCases:born-red-surgery',
                target: feature.id, phase: 'ir',
                startEvidence: {
                  temperature: PERMUTATION_TEMPS[attempt],
                  attempt: attempt + 1,
                  vacuous: stillVacuous.map(v => v.name),
                },
                fn: () => opts.llm.fixTestCases(
                  spec, feature, brReq, [], parts!.imports,
                  {
                    purpose: `born-red surgery: ${feature.id}`,
                    temperature: PERMUTATION_TEMPS[attempt],
                    candidate: { n: attempt + 1, k: PERMUTATION_TEMPS.length },
                  },
                ),
              });
              const bound = bindFixTestCases(stillVacuous, fixed.cases);
              metrics.mechanicalFixes += bound.unwrapFixes;
              if (brFrame) {
                const brGate = applyHoleOnlyGate(brFrame, bound.cases[0]?.body ?? '', metrics, stillVacuous[0]!.name,
                  msg => emit('ir', feature.id, msg));
                if (brGate.rejected) continue;
                if (bound.cases[0]) bound.cases[0] = { ...bound.cases[0], body: brGate.body };
              }
              const nextCases: IRCaseGen[] = parts.cases.map(c => {
                const i = stillVacuous.findIndex(b => caseNamesMatch(b.name, c.name));
                return i >= 0 && bound.cases[i]
                  ? { ...c, ...bound.cases[i]!, name: stillVacuous[i]!.name, kind: stillVacuous[i]!.kind, clade: c.clade }
                  : c;
              });
              const nextContent = assembleTestFile(feature, parts.imports, nextCases);
              if (validateSuiteShape(nextContent).length || suiteSyntaxError(nextContent)) {
                emit('ir', feature.id,
                  `born-red surgery try ${attempt + 1}/${PERMUTATION_TEMPS.length}: invalid suite — discarded`);
                continue;
              }
              parts = { imports: parts.imports, cases: nextCases };
              // SET 66b — every reassembly re-runs scaffold-wire.
              const rwSurg = wireSuiteScaffoldImports(nextContent, feature.testFile, spec);
              content = rwSurg.content;
              trialContent = content;
              metrics.irSurgeries++;
              brRun = await opts.runSuite(stubs, { path: feature.testFile, content });
              br = scoreBornRed(brRun);
              if (!hasRedCase(brRun) && attempt < PERMUTATION_TEMPS.length - 1) {
                emit('ir', feature.id,
                  `born-red surgery try ${attempt + 1}/${PERMUTATION_TEMPS.length}: still vacuous — retrying hotter`);
              }
            } catch (e) {
              emit('ir', feature.id,
                `born-red surgery try ${attempt + 1}/${PERMUTATION_TEMPS.length} failed: ${e instanceof Error ? e.message : String(e)}`);
            }
          }
        }
      }
      emit('ir', feature.id, formatBornRedEvent(br));
      if (!hasRedCase(brRun)) {
        // SET 71c / SET 89 §3.1 v2 — vacuous-abandonment breaker. This is
        // a repair/anchor gate, NOT a freeze authority (the freeze is
        // decided by `commitFrozenSuite` below). We freeze the deterministic
        // anchor contract, re-enqueue the vacuous cases, keep the tree
        // covered — but only when the anchor actually causes at least one
        // red case (measured via `hasRedCase`, not the deprecated
        // `isRed` field).
        let anchored = false;
        const anchor = buildDeterministicAnchor(feature);
        if (anchor) {
          // SET 73 — throw-camouflaged cases (verified rejection clades) ride
          // along with the anchor instead of being re-enqueued as vacuous.
          const keepCamo = parts.cases.filter(c => isThrowCamouflaged(c.body));
          const anchorParts = { imports: parts.imports, cases: [anchor, ...keepCamo] };
          const anchorAsm = assembleTestFile(feature, anchorParts.imports, anchorParts.cases);
          const anchorContent = wireSuiteScaffoldImports(anchorAsm, feature.testFile, spec).content;
          if (!validateSuiteShape(anchorContent).length && !suiteSyntaxError(anchorContent)) {
            const anchorRun = await opts.runSuite(stubs, { path: feature.testFile, content: anchorContent });
            if (hasRedCase(anchorRun)) {
              let reqd = 0;
              for (const c of parts.cases) {
                if (isThrowCamouflaged(c.body)) continue; // retained, not dropped
                if (endOfRunCaseStack.length < END_OF_RUN_STACK_CAP) {
                  endOfRunCaseStack.push({
                    featureId: feature.id, name: c.name, kind: c.kind as IRCaseGen['kind'],
                    reason: 'vacuous at born-red — dropped (coverage reduced)',
                  });
                  metrics.reEnqueuedCases++;
                  reqd++;
                }
              }
              parts = anchorParts;
              content = anchorContent;
              brRun = anchorRun;
              br = scoreBornRed(anchorRun);
              anchored = true;
              emit('ir', feature.id,
                `born-red: deterministic anchor frozen ("${anchor.name}", 0 tok) — ${reqd} vacuous case(s) re-enqueued`
                + (keepCamo.length ? `, ${keepCamo.length} throw-expecting retained` : ''));
            }
          }
        }
        if (!anchored) {
          emit('ir', feature.id,
            'born-red: suite still vacuous after surgery — freeze refused');
          return { status: 'deferred', reason: 'born-red vacuous suite' };
        }
      }

      // ── SET 66 — test-RHA at freeze ─────────────────────────────────────
      // Red is REQUIRED, but red for the RIGHT reason. Sick-red = the case's
      // own defect (contract-shape misuse, broken import, case-side crash),
      // not the stub's honest throw or an assertion awaiting an impl. Sick
      // cases are repaired HERE — substrate first, one guided redraw second,
      // honest pre-freeze drop last. The frozen contract stops being editable
      // in the RHA phase.
      const SICK_KINDS = new Set(['is-not-a-function', 'unresolved-import', 'undefined-symbol']);
      const partitionSick = () => {
        const out: { caseName: string | null; cls: ClassifiedFailure }[] = [];
        if (brRun.crashed) {
          const cls = classifyFailure('__suite__', brRun.crashed);
          if (SICK_KINDS.has(cls.kind) || cls.kind === 'transpile') {
            out.push({ caseName: null, cls });
          }
          return out;
        }
        for (const f of brRun.failures) {
          const cls = classifyFailure(f.name, f.message);
          if (SICK_KINDS.has(cls.kind) && !/not implemented|stub/i.test(cls.message)) {
            out.push({ caseName: f.name, cls });
          }
        }
        return out;
      };
      let sick = partitionSick();
      // Case attribution: failure titles embed the describe name, so match
      // the LONGEST case name contained in the title — never first-substring.
      const caseForFailure = (failName: string | null): IRCaseGen | undefined => {
        if (!failName) return undefined;
        let best: IRCaseGen | undefined;
        for (const c of parts!.cases) {
          if (!failName.includes(c.name)) continue;
          if (!best || c.name.length > best.name.length) best = c;
        }
        return best;
      };
      // SET 92 — per test-rha invocation: every entered case gets ONE terminal
      // disposition before the drop loop may misreport it (doctrine 5/7).
      const caseDisposition = new Map<string, string>();
      if (sick.length) {
        metrics.sickRedCases += sick.length;
        emit('ir', feature.id,
          `test-rha: ${sick.length} sick-red case(s) [${[...new Set(sick.map(s => s.cls.classKey))].join(', ')}] — freeze-gate repair`);
      }
      for (let trPass = 0; trPass < 2 && sick.length; trPass++) {
        // SET 92c — per-pass set (was lifetime `redrawnAtGate` outside the loop).
        const redrawnThisPass = new Set<string>();
        // L1 — suite-side mechanical repair; the stub contract is the truth
        // and is NEVER mutated at the freeze gate.
        let changed = false;
        for (const { cls } of sick) {
          const attempt = attemptMechanicalFix(cls, stubs, { path: feature.testFile, content }, spec);
          const fixes = attempt.status === 'fixed'
            ? (attempt.fixes?.length ? attempt.fixes : (attempt.fix ? [attempt.fix] : []))
            : [];
          for (const fx of fixes) {
            if (fx.path !== feature.testFile || fx.content === content) continue;
            content = fx.content;
            changed = true;
            metrics.testRhaSubstrateFixes++;
            emit('ir', feature.id, `test-rha: ${cls.classKey} → suite-side fix (0 tok)`);
          }
        }
        // Guided redraw per still-sick case when L1 is out.
        // SET 72 — every LLM call gets 3 tries: the redraw walks the
        // decorrelation ladder, stopping when the case stops being sick.
        // SET 92d — honest ladder label (doctrine 12): miser, not N-of-K batch.
        if (!changed && sick[0]) {
          emit('ir', feature.id,
            `test-rha: miser ladder [K=${PERMUTATION_TEMPS.length}] (stops on first cleared redraw)`);
          const target = sick.find(s => {
            const hit = caseForFailure(s.caseName);
            return hit && !redrawnThisPass.has(hit.name);
          }) ?? sick[0];
          const caseHit: IRCaseGen | undefined = caseForFailure(target.caseName);
          // SET 92c — no silent skip (doctrine 5/7).
          if (!caseHit) {
            emit('ir', feature.id,
              `test-rha: case "${target.caseName}" skipped — no case handle`);
            metrics.testRhaSkippedNoHandle++;
            caseDisposition.set(target.caseName ?? '__no-handle__', 'skipped-no-handle');
          } else if (redrawnThisPass.has(caseHit.name)) {
            emit('ir', feature.id,
              `test-rha: case "${caseHit.name}" skipped — already redrawn this pass`);
            metrics.testRhaSkippedAlreadyRedrawn++;
            caseDisposition.set(caseHit.name, 'skipped-already-redrawn');
          } else {
            redrawnThisPass.add(caseHit.name);
            // SET 92b — legible per-attempt outcomes (doctrine 7).
            for (let attempt = 0; attempt < PERMUTATION_TEMPS.length; attempt++) {
              metrics.testRhaDraws++;
              const temp = PERMUTATION_TEMPS[attempt]!;
              const label = `try ${attempt + 1}/${PERMUTATION_TEMPS.length}, t=${temp}`;
              // SET 96a — CPU merge only; reuse any prior watcher reading (no new LLM).
              const trContext = assembleContext({
                stage: 'ir',
                featureId: feature.id,
                spec, feature, parts: parts ?? null,
                stubs: feature.stubs,
                lessons: opts.lessons ?? [],
                siblingParts: irPartsByFeature,
                target: target.cls.classKey,
                substrateHandoff: substrateHandoffFor(feature.id),
                ledgerRows: supergit.allRows(),
                artifact: stubArtifact(spec),
                cachedReading: watch.reading,
              });
              const trBuffer = emitSuperbufferAssembly('ir', feature.id, trContext.assembly, 'test-rha');
              // SET 95d — hole-only gate rolled to test-rha rescue (single-case draw).
              const trFrame = holeOnlyFrameFor(gates, feature, caseHit.name, caseHit.kind as IRCaseGen['kind']);
              let fixed: Awaited<ReturnType<typeof opts.llm.fixTestCases>>;
              try {
                fixed = await runLlmAction({
                  method: 'fixTestCases:test-rha-rescue',
                  target: feature.id, phase: 'ir',
                  startEvidence: {
                    temperature: temp,
                    attempt: attempt + 1,
                    caseName: caseHit.name,
                    classKey: target.cls.classKey,
                  },
                  fn: () => opts.llm.fixTestCases(
                    spec, feature,
                    [{
                      name: caseHit.name,
                      kind: caseHit.kind as IRCaseGen['kind'],
                      errors: [
                        `Sick-red at freeze: ${target.cls.classKey} — ${target.cls.message.split('\n')[0]}`,
                        'The frozen contract is the stub: call ONLY symbols and shapes the stubs export.',
                        trBuffer,
                        holeOnlyPromptBlock(trFrame),
                      ].filter(Boolean),
                    }],
                    [], parts!.imports,
                    {
                      purpose: `test-rha: ${feature.id}`,
                      rescue: true,
                      temperature: temp,
                      candidate: { n: attempt + 1, k: PERMUTATION_TEMPS.length },
                    },
                  ),
                });
              } catch (err) {
                metrics.testRhaDrawThrew++;
                const msg = err instanceof Error ? err.message.slice(0, 200) : String(err).slice(0, 200);
                emit('ir', feature.id, `test-rha: draw threw (${label}) — ${msg}`);
                caseDisposition.set(caseHit.name, 'attempt-threw');
                continue;
              }
              let body = fixed.cases[0]?.body ?? '';
              const trGate = applyHoleOnlyGate(trFrame, body, metrics, caseHit.name,
                msg => emit('ir', feature.id, msg));
              if (trGate.rejected) {
                metrics.testRhaDraftRejected++;
                caseDisposition.set(caseHit.name, 'attempt-rejected');
                continue;
              }
              body = trGate.body;
              if (!body.trim() || !acceptCaseBody(body)) {
                metrics.testRhaDraftRejected++;
                const reason = !body.trim() ? 'empty body' : 'failed acceptCaseBody';
                emit('ir', feature.id, `test-rha: draft rejected (${label}) — ${reason}`);
                caseDisposition.set(caseHit.name, 'attempt-rejected');
                continue;
              }
              parts = {
                imports: parts.imports,
                cases: parts.cases.map(c => (c.name === caseHit.name ? { ...c, body } : c)),
              };
              const asm = assembleTestFile(feature, parts.imports, parts.cases);
              content = wireSuiteScaffoldImports(asm, feature.testFile, spec).content;
              emit('ir', feature.id, `test-rha: draft accepted (${label})`);
              brRun = await opts.runSuite(stubs, { path: feature.testFile, content });
              br = scoreBornRed(brRun);
              sick = partitionSick();
              const stillSick = sick.some(s => caseForFailure(s.caseName)?.name === caseHit.name);
              if (!stillSick) {
                metrics.testRhaDraftAcceptedCleared++;
                metrics.testRhaCaseCleared++;
                emit('ir', feature.id, `test-rha: case "${caseHit.name}" cleared`);
                caseDisposition.set(caseHit.name, 'case-cleared');
                break;
              }
              metrics.testRhaDraftAcceptedStillSick++;
              emit('ir', feature.id, `test-rha: case "${caseHit.name}" still sick — continuing ladder`);
              caseDisposition.set(caseHit.name, 'attempt-accepted-still-sick');
            }
            // Ladder exhausted without cleared.
            if (caseDisposition.get(caseHit.name) !== 'case-cleared') {
              metrics.testRhaCaseExhausted++;
              emit('ir', feature.id,
                `test-rha: case "${caseHit.name}" exhausted after ${PERMUTATION_TEMPS.length} attempts`);
              caseDisposition.set(caseHit.name, 'case-exhausted');
            }
          }
        }
        brRun = await opts.runSuite(stubs, { path: feature.testFile, content });
        br = scoreBornRed(brRun);
        sick = partitionSick();
      }
      // Still sick → the contract never freezes a lie: drop those cases now.
      // SET 92c — drop loop may only say "unrepairable" for case-exhausted.
      if (sick.length) {
        const dropNames = new Set(
          sick.map(s => caseForFailure(s.caseName)?.name)
            .filter((n): n is string => !!n),
        );
        for (const nm of dropNames) {
          const disp = caseDisposition.get(nm) ?? 'case-exhausted';
          if (disp === 'case-exhausted') {
            problems.push(`${feature.id}: case "${nm}" dropped at freeze-gate — sick-red unrepairable`);
            emit('ir', feature.id, `test-rha: case "${nm}" dropped at freeze-gate — sick-red unrepairable`);
            caseDisposition.set(nm, 'case-dropped-unrepairable');
          } else {
            problems.push(`${feature.id}: case "${nm}" dropped at freeze-gate — ${disp}`);
            emit('ir', feature.id, `test-rha: case "${nm}" dropped at freeze-gate — ${disp}`);
          }
        }
        if (dropNames.size) {
          parts = { imports: parts.imports, cases: parts.cases.filter(c => !dropNames.has(c.name)) };
          if (!parts.cases.length) {
            return { status: 'deferred', reason: 'all cases sick-red at freeze' };
          }
          const asm2 = assembleTestFile(feature, parts.imports, parts.cases);
          content = wireSuiteScaffoldImports(asm2, feature.testFile, spec).content;
          brRun = await opts.runSuite(stubs, { path: feature.testFile, content });
          br = scoreBornRed(brRun);
        } else if (brRun.crashed) {
          // Suite-level crash we couldn't attribute to a case and couldn't
          // repair — never freeze a crashing contract.
          return { status: 'deferred', reason: `sick-red suite crash at freeze: ${brRun.crashed.slice(0, 80)}` };
        } else {
          // Unattributable sick-red — freeze with full disclosure rather than
          // defer everything; RHA inherits it knowingly, not silently.
          emit('ir', feature.id,
            `test-rha: ${sick.length} sick-red case(s) unattributed — freezing with disclosure`);
        }
        // SET 89 §3.1 v2 — not a freeze authority; the freeze is decided
        // by `commitFrozenSuite`. This gate short-circuits when the
        // freeze-gate repair could not restore at least one honest failing
        // case (via `hasRedCase`), avoiding a certain gateway rejection.
        if (!hasRedCase(brRun)) {
          emit('ir', feature.id, 'born-red: suite not red after freeze-gate repair — freeze refused');
          return { status: 'deferred', reason: 'born-red vacuous suite' };
        }
      }
    }

    const ratio = cladeRatio(parts.cases);
    cladeSchemadTotal += ratio.schemad;
    cladeFreeformTotal += ratio.freeform;
    metrics.cladeRatio = `${cladeSchemadTotal}:${cladeFreeformTotal}`;
    // SET 66 — scaffold-wire now runs BEFORE born-red (and after every
    // reassembly); by this point `content` is already wired.
    // SET 89 §4.4 — the initial freeze routes through the transactional
    // gateway when a suite runner is available. `commitFrozenSuite` runs
    // per-case certification against stubs and writes ALL THREE state maps
    // atomically on acceptance; on rejection it writes NOTHING and this
    // feature is deferred with a named reason. When no `runSuite` is
    // provided (Tier-2 not wired) the gateway cannot certify, so we fall
    // back to the atomic writer with a "gate-unavailable" disclosure.
    if (opts.runSuite) {
      // SET 89 §4.4 — the initial freeze is a bounded retry loop. Each
      // iteration:
      //   1. attempts commitFrozenSuite against the current parts;
      //   2. on rejection whose ONLY cause is `rejected-vacuous` cases,
      //      partitions the vacuous cases out (re-enqueueing them for the
      //      warm-world case-relay) and retries with the reduced parts —
      //      the surviving cases can still form a legitimate contract;
      //   3. on any other rejection (crash, syntax, stub-derived throw,
      //      registration, program parse, gate infrastructure unavailable):
      //      defer with the named reason (no lie is frozen).
      // The retry cap is small; each retry can only strictly reduce the
      // case set, so termination is guaranteed.
      let commitOutcome: Awaited<ReturnType<typeof commitFrozenSuite>> | null = null;
      let commitTries = 0;
      const MAX_COMMIT_TRIES = 4;
      while (commitTries++ < MAX_COMMIT_TRIES) {
        commitOutcome = await commitFrozenSuite({
          spec,
          feature,
          prompt: opts.rawPrompt ?? opts.prompt,
          parts,
          runSuite: opts.runSuite,
          stubs: stubArtifact(spec),
          state: frozenState,
          reason: commitTries === 1 ? 'initial-freeze' : `initial-freeze/retry-${commitTries - 1}`,
          onAcceptance: (report) => {
            lastFrozenReport.set(feature.id, report);
          },
          onRejection: (report) => {
            lastFrozenReport.set(feature.id, report);
          },
          // SET 89 §11.2 — every initial-freeze / retry is a ledger action;
          // rejected commits produce `rejected` terminals so replay can see
          // the retry loop honestly.
          actionLedger,
        });
        if (commitOutcome.status === 'accepted') break;
        // SET 89 §5.1 — the ONE case-disposition class we can safely react
        // to by dropping-and-retrying is `rejected-vacuous`. Every other
        // rejection means the contract cannot be honestly frozen; defer.
        const vacuous = commitOutcome.report.cases.filter(c => c.disposition === 'rejected-vacuous');
        const otherRejected = commitOutcome.report.cases.filter(c =>
          c.disposition.startsWith('rejected') && c.disposition !== 'rejected-vacuous');
        const suiteLevelRejection = commitOutcome.report.rejectionReasons.some(r =>
          r.startsWith('suite shape')
          || r.startsWith('suite syntax')
          || r.startsWith('program parse')
          || r.startsWith('gate infrastructure'));
        if (otherRejected.length || suiteLevelRejection) {
          break;
        }
        if (!vacuous.length) break;
        // Re-enqueue every vacuous case for warm-world refill, then retry.
        for (const vc of vacuous) {
          if (endOfRunCaseStack.length < END_OF_RUN_STACK_CAP) {
            endOfRunCaseStack.push({
              featureId: feature.id,
              name: vc.caseName,
              kind: parts.cases.find(c => c.name === vc.caseName)?.kind as IRCaseGen['kind'] ?? 'behavior',
              reason: `dropped at freeze-gate — rejected-vacuous (${vc.reason.slice(0, 120)})`,
            });
            metrics.reEnqueuedCases++;
            emit('ir', feature.id,
              `case "${vc.caseName}" re-enqueued (freeze-gate: rejected-vacuous) — warm retry pending`);
          } else {
            problems.push(`${feature.id}: case "${vc.caseName}" dropped at freeze-gate — rejected-vacuous`);
            emit('ir', feature.id,
              `case "${vc.caseName}" dropped at freeze-gate — rejected-vacuous`);
          }
        }
        const dropNames = new Set(vacuous.map(v => v.caseName));
        parts = { imports: parts.imports, cases: parts.cases.filter(c => !dropNames.has(c.name)) };
        if (!parts.cases.length) {
          emit('ir', feature.id,
            'freeze refused (gateway): all cases rejected-vacuous — no observable contract');
          return { status: 'deferred', reason: 'all cases rejected-vacuous — no observable contract' };
        }
        content = wireSuiteScaffoldImports(
          assembleTestFile(feature, parts.imports, parts.cases),
          feature.testFile, spec,
        ).content;
      }
      if (!commitOutcome || commitOutcome.status === 'rejected') {
        const rej = commitOutcome?.report.rejectionReasons ?? ['unknown rejection'];
        const reason = rej[0] ?? 'commitFrozenSuite refused freeze';
        emit('ir', feature.id,
          `freeze refused (gateway): ${reason.slice(0, 200)}`);
        return { status: 'deferred', reason };
      }
      // On acceptance the gateway wrote all three maps atomically — nothing
      // more to do here.
    } else {
      // SET 89 §4.4 v2 — no `runSuite` host: per-case certification is
      // not possible (cases can't be executed), but the whole-program
      // parse gate and suite shape / syntax gates still run through the
      // gateway in bypass mode. This preserves the "gate infrastructure
      // unavailable" disclosure while keeping the single-writer
      // invariant intact. The gateway is still the sole writer.
      const uncertifiedCommit = await commitFrozenPatch(
        feature, content, parts, 'initial-freeze: no runSuite');
      if (uncertifiedCommit && uncertifiedCommit.status === 'rejected') {
        const reason = uncertifiedCommit.report.rejectionReasons[0]
          ?? 'gateway refused freeze (no runSuite host)';
        emit('ir', feature.id, `freeze refused (gateway): ${reason.slice(0, 200)}`);
        return { status: 'deferred', reason };
      }
      emit('ir', feature.id,
        'freeze uncertified: no runSuite host (case cert skipped, parse gate ran)');
    }
    // SET 74 — supergit: the frozen contract is a `test` node, and every
    // planned case that made it in is its own decision node (per-test
    // decision calculus, not per-phase).
    {
      const testId = supergit.recordNode({
        type: 'test', featureId: feature.id,
        causeId: specNodeByFeature.get(feature.id) ?? null,
        artifactPath: feature.testFile,
        status: 'pass',
        summary: `IR frozen: ${parts.cases.length}/${plan.cases.length} planned cases`,
      });
      for (const c of parts.cases) {
        supergit.recordNode({
          type: 'decision', featureId: feature.id, parentId: testId,
          artifactPath: feature.testFile,
          summary: `case "${c.name}" [${c.kind}${c.clade?.family ? `/${c.clade.family}` : ''}] frozen into the contract`,
        });
      }
    }
    if ((metaloopCount.get(feature.id) ?? 1) <= 1 && !usedFallbackFill.has(feature.id)) {
      metrics.featuresFrozenWithoutRedraw++;
    }
    // SET 71 — the freeze line states the fill ledger: planned vs filled vs
    // unfilled (re-enqueued for the warm-world case-relay or dropped).
    {
      const planned = plan.cases.length;
      const filled = parts.cases.length;
      const unfilled = Math.max(0, planned - filled);
      emit('ir', feature.id,
        `frozen suite ${feature.testFile} (${planned} planned → ${filled} filled`
        + `${unfilled ? `, ${unfilled} unfilled→re-enqueued` : ''}`
        + `; clades ${ratio.schemad}:${ratio.freeform}; aggregate ${metrics.cladeRatio})`);
    }
    return { status: 'frozen' };
  };

  // ---------------------------------------------------------------------------
  // SET 32h/32i — metaloop bracket (hard cap 3): sequential per-feature (M1)
  // → deferred replay against warm buffer (M2) → final bracket pass (M3) →
  // terminal abandonment fan-out (SET 32d).
  // ---------------------------------------------------------------------------
  const metaloopCount = new Map<string, number>();
  const worldAtLastAttempt = new Map<string, WorldSignature>();
  const bumpMetaloop = (fid: string): number => {
    const n = (metaloopCount.get(fid) ?? 0) + 1;
    metaloopCount.set(fid, n);
    return n;
  };
  const captureWorld = (fid: string): void => {
    worldAtLastAttempt.set(fid, makeWorldSignature({
      frozenByFeature, lessonKeys: lessonKeysSeen, irPartsByFeature,
    }));
  };
  const worldHasChangedFor = (fid: string): boolean => {
    const prev = worldAtLastAttempt.get(fid);
    if (!prev) return true;
    const now = makeWorldSignature({
      frozenByFeature, lessonKeys: lessonKeysSeen, irPartsByFeature,
    });
    return worldChanged(prev, now);
  };

  // Metaloop 1: normal sequential pass. Every feature gets ≥floor candidate
  // cycles; a feature that still has zero surviving cases DEFERS (32h).
  const deferredFromM1: string[] = [];
  for (const feature of ordered) {
    bail();
    bumpMetaloop(feature.id);
    captureWorld(feature.id);
    const outcome = await fillOneFeature(feature, 1);
    if (outcome.status === 'deferred') {
      deferredFromM1.push(feature.id);
      metrics.deferredTotal++;
    }
  }

  // Metaloop 2: deferred features retry at end-of-phase against the warmer
  // buffer, dependency-roots first (root freezes lay track for downstream).
  // Fresh anchor-injected plans; identical primitives — no bigger model.
  const failedAfterM2: string[] = [];
  if (deferredFromM1.length) {
    const orderedRootsFirst = orderRootsFirst(deferredFromM1, spec.features);
    emit('ir', null, metaloop2Message(orderedRootsFirst));
    for (const fid of orderedRootsFirst) {
      bail();
      const feature = ordered.find(f => f.id === fid);
      if (!feature) continue;
      // Changed-world precondition (32i): substrate must have moved since
      // metaloop 1 finished on this feature. Otherwise retry is variance.
      if (!worldHasChangedFor(fid)) {
        emit('ir', fid, skipNoTrackMessage());
        failedAfterM2.push(fid);
        continue;
      }
      bumpMetaloop(fid);
      captureWorld(fid);
      if (!relitigatedIds.has(fid)) { relitigatedIds.add(fid); metrics.deferredRelitigated++; }
      const outcome = await fillOneFeature(feature, 2);
      if (outcome.status === 'frozen') metrics.deferredResolvedAfterRelitigation++;
      else failedAfterM2.push(fid);
    }
  }

  // Metaloop 3: ONE final bracket pass over every feature still failing.
  // Same recipe; hard cap 3. Anything still failing after this is abandoned
  // and dependents fan-out per SET 32d.
  const abandonedIds: string[] = [];
  if (failedAfterM2.length) {
    const orderedRootsFirst3 = orderRootsFirst(failedAfterM2, spec.features);
    emit('ir', null, metaloop3Message(orderedRootsFirst3));
    for (const fid of orderedRootsFirst3) {
      bail();
      const feature = ordered.find(f => f.id === fid);
      if (!feature) { abandonedIds.push(fid); continue; }
      if (!worldHasChangedFor(fid)) {
        emit('ir', fid, skipNoTrackMessage());
        abandonedIds.push(fid);
        continue;
      }
      bumpMetaloop(fid);
      captureWorld(fid);
      if (!relitigatedIds.has(fid)) { relitigatedIds.add(fid); metrics.deferredRelitigated++; }
      const outcome = await fillOneFeature(feature, 3);
      if (outcome.status === 'frozen') metrics.deferredResolvedAfterRelitigation++;
      else abandonedIds.push(fid);
    }
  }

  // SET 32d — terminal abandonment fan-out. Feature marked no-coverage;
  // every dependent's `uses <feature>` case is flagged `dependency
  // uncovered`. Summary count surfaces in the final `done` event.
  for (const fid of abandonedIds) {
    if (!problems.some(p => p.startsWith(`${fid}: no-coverage`))) {
      problems.push(noCoverageProblem(fid));
    }
    emit('ir', fid, `no-coverage — abandoned after metaloop 3`);
    for (const dep of spec.features) {
      if (!dep.deps.includes(fid)) continue;
      const line = dependencyUncoveredProblem(dep.id, fid);
      if (!problems.some(p => p === line)) problems.push(line);
      emit('ir', dep.id, `uses ${fid} — dependency uncovered`);
    }
  }

  // SET 59b — IR-contract gate: every suite that will ever freeze has frozen;
  // the host may pause here for approval before a single line of impl exists.
await opts.onPhaseGate?.('ir-contract');
  bail();

  // Phase C: build per feature in dependency order, boundary-enforced.
  // SET 89 §9.4 — `artifactState` is the SOLE owner of implementation
  // artifact writes. Every `commitWrites` / `adoptCandidate` /
  // `evaluateCandidateTrial` / `restoreSnapshot` / `deletePath` call
  // records exactly one action pair on the shared ledger. Direct
  // `built.set` / `built.delete` sites are gone (verified by ripgrep).
  const artifactState = new ArtifactState({ ledger: actionLedger });
  // SET 101d — per-file draw epoch. A transpile|file refusal with
  // "impl repair exhausted" suspends that file's ladder until the epoch advances.
  const fileDrawEpoch = new Map<string, number>();
  const fileQuarantineEpoch = new Map<string, number>();
  const noteFileDraw = (paths: readonly string[]): void => {
    for (const p of paths) {
      fileDrawEpoch.set(p, (fileDrawEpoch.get(p) ?? 0) + 1);
    }
  };
  const isFileQuarantined = (path: string): boolean => {
    const q = fileQuarantineEpoch.get(path);
    if (q === undefined) return false;
    return q === (fileDrawEpoch.get(path) ?? 0);
  };
  const suspendFileRepair = (path: string, featureId: string | null): void => {
    const epoch = fileDrawEpoch.get(path) ?? 0;
    if (fileQuarantineEpoch.get(path) === epoch) return;
    fileQuarantineEpoch.set(path, epoch);
    metrics.quarantineSuspensions++;
    emit('rha', featureId,
      `repair suspended: ${path} awaiting fresh draw (impl repair exhausted)`);
  };
  for (const feature of ordered) {
    bail();
    const frozen = frozenByFeature.get(feature.id);
    if (frozen == null) continue; // no frozen contract, no build
    const depContext = feature.deps
      .flatMap(id => spec.features.find(f => f.id === id)?.files ?? [])
      .map(p => artifactState.get(p))
      .filter((f): f is GeneratedFile => f != null);
    // SET 37f — ONE bounded concept draw per feature (high t); context only.
    if (typeof opts.llm.drawConcept === 'function' && !conceptByFeature.has(feature.id)) {
      // SET 89 §11.2 — the concept draw is a token-spending action; a
      // provider failure here is nonfatal (concept is optional context),
      // but the FAILURE must be visible in the ledger so it isn't lost.
      // `runNonfatalAction` returns only `{ actionId, ok, terminal }` —
      // the fn result comes out via a closure-captured local.
      let concept: string | undefined | null;
      const { ok } = await actionLedger.runNonfatalAction({
        kind: 'llm:drawConcept',
        target: feature.id,
        phase: 'build',
        startEvidence: { purpose: `concept: ${feature.id}` },
        fn: async () => {
          concept = await opts.llm.drawConcept!(
            encodeFeatureSpecText(feature, spec), feature,
            { temperature: 1.1, purpose: `concept: ${feature.id}` },
          );
        },
      });
      if (ok && concept && concept.trim()) {
        conceptByFeature.set(feature.id, concept.trim());
        metrics.conceptDraws++;
        emit('build', feature.id, formatConceptDrawEvent(feature.id, concept.trim().length));
      } else if (!ok) {
        emit('build', feature.id, 'concept draw failed (nonfatal — see action ledger)');
      }
    }
    // SET 36d / 37e — pack build prompts with named superbuffer pages.
    const siblingImpls = artifactState.files().filter(f => !feature.files.includes(f.path));
    const unionBuild = await synthesizeForDraw('build', feature.id, artifactState.files());
    const buildSb = assembleSuperbuffer({
      spec,
      feature,
      parts: irPartsByFeature.get(feature.id) ?? null,
      stubs: feature.stubs,
      lessons: opts.lessons ?? [],
      siblingParts: irPartsByFeature,
      siblingImpls,
      target: `build|${feature.id}`,
      stage: 'build',
      unionText: unionBuild,
      conceptText: conceptByFeature.get(feature.id) ?? null,
      signature: feature.exports[0]
        ? { name: feature.exports[0].symbol, params: [], returnType: 'unknown' }
        : null,
    });
    const buildBuffer = emitSuperbufferAssembly('build', feature.id, buildSb, 'fill');
    // SET 72 — every LLM call gets 3 tries: a build draw whose owned files
    // ALL die at the vet/parse gates redraws hotter instead of condemning
    // the feature to build-failed on one bad sample.
    const BUILD_TRY_TEMPS: (number | undefined)[] = [undefined, 0.75, 1.0];
    for (let buildTry = 0; buildTry < BUILD_TRY_TEMPS.length; buildTry++) {
      // SET 89 §11.2 — the initial-build draw is a token action; failure
      // rethrows so the outer try-loop can catch and record a build-fail.
      const { result: rawFiles } = await actionLedger.runAction({
        kind: 'llm:generateImplementation',
        target: feature.id,
        phase: 'build',
        startEvidence: {
          attempt: buildTry + 1,
          temperature: BUILD_TRY_TEMPS[buildTry],
          files: feature.files,
        },
        fn: () => opts.llm.generateImplementation(spec, feature, frozen, depContext, {
          // SET 95d — `generateImplementation`'s contract stays whole-file
          // `GeneratedFile[]` (widening it to hole-body strings would break
          // every `LlmClient` schema — see `isBuildOverreach` in frame.ts),
          // so the hole-only instruction here is advisory context; the
          // enforced gate is the content-level check on the returned files.
          context: gates.holeOnlyFill ? [buildBuffer, BUILD_SYSTEM_HOLE].join('\n\n') : buildBuffer,
          purpose: `build: ${feature.files.join(', ')}`,
          temperature: BUILD_TRY_TEMPS[buildTry],
          attempt: buildTry + 1,
          attemptLabel: 'attempt',
        }),
      });
      let files = rawFiles;
      // SET 95d — build overreach gate: an implementation file must never
      // carry test-scaffolding tokens. Content-level check (see
      // `isBuildOverreach`) — dropped files count toward `overreachBodyRejections`
      // and fall through to the existing "0 accepted files → retry hotter" ladder.
      if (gates.holeOnlyFill) {
        const leaking = files.filter(f => feature.files.includes(f.path) && isBuildOverreach(f.content).over);
        for (const f of leaking) {
          metrics.overreachBodyRejections++;
          emit('build', feature.id, `case "${f.path}" rejected overreach|body: ${isBuildOverreach(f.content).reason}`);
        }
        if (leaking.length) files = files.filter(f => !leaking.some(l => l.path === f.path));
      }
      // SET 65 — shell-locked codegen (flagged): the frame (header + export
      // declaration heads) is emitted deterministically from the stub; the
      // draw contributes function bodies only. Duplicate decls and top-level
      // parse poison are structurally impossible in a locked file.
      if (gates.shellLock) {
        files = files.map(f => {
          const stub = feature.stubs.find(s => s.path === f.path);
          if (!stub) return f;
          const frame = buildFileFrame(stub);
          if (!frame) return f; // no function exports — not lockable
          const locked = lockDrawToFrame(frame, f.content);
          if (locked.missing.length) {
            metrics.shellLockFallbacks++;
            emit('build', feature.id, formatShellLockFallback(f.path, locked.missing));
          } else {
            metrics.shellLockApplied++;
            emit('build', feature.id, formatShellLock(f.path, frame.slots.length));
          }
          // SET 73 — poison excluded at the frame is a substrate win, never
          // a silent deletion: it is emitted, counted, and lesson-distilled.
          if (locked.dropped.length) {
            // SET 89 §9.1 — shell-lock is a deterministic edit outside the
            // `attemptMechanicalFix` partition. Do not inflate hit-rate.
            metrics.mechanicalFixes += locked.dropped.length;
            metrics.deterministicEditsOutsideSubstrate += locked.dropped.length;
            emit('build', feature.id, formatShellLockPrevented(f.path, locked.dropped));
            opts.onLesson?.(distillLesson(
              `shell-lock|unbalanced-decl`,
              `unbalanced top-level declaration(s): ${locked.dropped.join(', ')}`,
              'shell-lock frame excluded the declaration before it could poison the program',
            ));
          }
          return { ...f, content: locked.content };
        });
      }
      const violations = boundaryViolations(files, feature);
      if (violations.length) {
        // Enforce the write boundary deterministically: drop out-of-boundary files.
        emit('build', feature.id, `boundary violations dropped: ${violations.join('; ')}`);
      }
      // SET 36c — build gate: transpile + lint (probe deferred to auth/substrate).
      // SET 38a — whole-program parse after every accepted write.
      const owned = files.filter(f => feature.files.includes(f.path));
      const baseArt = artifactState.files();
      const vetted = await vetArtifactWritesAsync(owned, baseArt, 'build');
      if (vetted.gateUnavailable) noteModuleProbeUnavailable('build', feature.id);
      for (const r of vetted.rejected) {
        noteRunError('conformance');
        emit('build', feature.id, `build draw rejected: ${r.reason} in ${r.path}`);
      }
      let acceptedCount = 0;
      for (const f of vetted.ok) {
        let file = f;
        const trial = [...baseArt.filter(b => b.path !== file.path), file];
        let prog = await vetProgramParseAfterWriteAsync(file, trial);
        if (prog.ok && prog.gateUnavailable) noteParseGateUnavailable('build', feature.id);
        // SET 102 — 0-tok delimiter-oracle heal before hotter re-draw.
        if (!prog.ok && /Invalid regular expression/i.test(prog.message)) {
          const healed = applyDelimiterOracle(file.content, prog.message);
          if (healed) {
            const healedFile = { ...file, content: healed.content };
            const trial2 = [...baseArt.filter(b => b.path !== healedFile.path), healedFile];
            const prog2 = await vetProgramParseAfterWriteAsync(healedFile, trial2);
            if (prog2.ok) {
              emit('build', feature.id,
                `program-parse healed via delimiterOracle (${healed.classKey}, 0 tok)`);
              metrics.regexLiteralGateHeals++;
              metrics.mechanicalFixes++;
              file = healedFile;
              prog = prog2;
              if (prog.gateUnavailable) noteParseGateUnavailable('build', feature.id);
            }
          }
        }
        if (!prog.ok) {
          metrics.parsePoisonIncidents++;
          noteRunError('parse');
          emit('build', feature.id, prog.event);
          opts.onLesson?.(distillLesson(
            distillProgramParseLessonKey(file.path, prog.message),
            prog.message,
            'program-parse rejection — incumbent kept',
          ));
          continue;
        }
        artifactState.commitWrites({
          files: [file], phase: 'build', target: feature.id, kind: 'build-write',
        });
        noteFileDraw([file.path]);
        baseArt.push(file);
        acceptedCount++;
      }
      if (acceptedCount > 0) break;
      if (buildTry < BUILD_TRY_TEMPS.length - 1) {
        emit('build', feature.id,
          `build draw yielded 0 accepted files — retry ${buildTry + 2}/${BUILD_TRY_TEMPS.length} (hotter)`);
      }
    }
    // SET 43c — export-conformance at build-accept (names + arity) before measure.
    const ownedBuilt = feature.files
      .map(p => artifactState.get(p))
      .filter((f): f is GeneratedFile => f != null);
    if (ownedBuilt.length) {
          const conformed = conformExportsToStubs(ownedBuilt, feature.stubs);
      // SET 47e — one emit per symbol×file (conform already dedupes fixes).
      const seenConform = new Set<string>();
      for (const fx of conformed.fixes) {
        const k = `${fx.path}\0${fx.note}`;
        if (seenConform.has(k)) continue;
        seenConform.add(k);
        emit('build', feature.id, `export-conformance: ${fx.note} (0 tok)`);
        // SET 89 §9.1 — export-conformance is a deterministic edit
        // outside the `attemptMechanicalFix` partition.
        metrics.mechanicalFixes++;
        metrics.deterministicEditsOutsideSubstrate++;
      }
      if (conformed.files.length) {
        artifactState.commitWrites({
          files: conformed.files, phase: 'build', target: feature.id,
          kind: 'export-conformance',
        });
        noteFileDraw(conformed.files.map(f => f.path));
      }
    }
    // SET 74 — supergit: one `code` node per generated node, caused by the
    // frozen contract it was drawn against.
    {
      const nBuilt = feature.files.filter(p => artifactState.has(p)).length;
      // SET 79 — the honest build score: files accepted for this node.
      if (feature.files.length > 0) {
        metrics.nodesBuildable++;
        if (nBuilt === feature.files.length) metrics.nodesBuilt++;
      }
      supergit.recordNode({
        type: 'code', featureId: feature.id,
        causeId: supergit.testNodeFor(feature.id),
        artifactPath: feature.files[0] ?? null,
        status: nBuilt > 0 ? 'pass' : 'fail',
        summary: `build: ${nBuilt}/${feature.files.length} owned files`,
      });
    }
    // SET 81 — "built 1/1 owned files" says nothing (Andy). State the node's
    // position in the shipment: which node of how many, and what it produced.
    {
      const nBuilt = feature.files.filter(p => artifactState.has(p)).length;
      const idx = ordered.findIndex(f => f.id === feature.id) + 1;
      emit('build', feature.id,
        nBuilt === feature.files.length
          ? `node ${idx} of ${ordered.length} built — ${feature.name} (${feature.files.join(', ')})`
          : `node ${idx} of ${ordered.length} INCOMPLETE — ${nBuilt} of ${feature.files.length} files accepted for ${feature.name}`);
    }
  }

  // SET 40f — RHA requires a built artifact. Features with 0/N owned builds
  // enter state build-failed (ladder skipped). If every frozen feature failed
  // to build, end at build phase — do not measure stubs.
  const buildFailedIds = new Set<string>();
  let frozenWithOwned = 0;
  for (const feature of ordered) {
    if (!frozenByFeature.has(feature.id)) continue;
    if (feature.files.length === 0) continue;
    frozenWithOwned += 1;
    const nBuilt = feature.files.filter(p => artifactState.has(p)).length;
    if (nBuilt === 0) {
      buildFailedIds.add(feature.id);
      emit('build', feature.id,
        `build-failed: 0/${feature.files.length} owned files — RHA ladder skipped`);
      problems.push(`${feature.id}: build-failed (0/${feature.files.length} owned files)`);
    }
  }
  const skipRhaAllBuildsFailed = frozenWithOwned > 0
    && buildFailedIds.size === frozenWithOwned;
  if (skipRhaAllBuildsFailed) {
    const nFiles = ordered.reduce((n, f) => n + (frozenByFeature.has(f.id) ? f.files.length : 0), 0);
    emit('build', null, `build phase failed: 0/${nFiles} files — RHA skipped`);
    problems.push(`build phase failed: 0/${nFiles} files — RHA skipped`);
  }

  // Current artifact snapshot: built implementations where available, stubs
  // where not. Reads flow through `artifactState`; only `commitWrites` /
  // `adoptCandidate` / `evaluateCandidateTrial` / `restoreSnapshot` /
  // `deletePath` mutate — the SET 89 §9.4 ownership constraint.
  const artifactFiles = (): GeneratedFile[] => {
    const out: GeneratedFile[] = [];
    for (const feature of ordered) {
      for (const stub of feature.stubs) out.push(artifactState.get(stub.path) ?? stub);
    }
    return out;
  };
  const depContextOf = (feature: (typeof ordered)[number]): GeneratedFile[] =>
    feature.deps
      .flatMap(id => spec.features.find(f => f.id === id)?.files ?? [])
      .map(p => artifactState.get(p))
      .filter((f): f is GeneratedFile => f != null);

  // Phase D: authenticate + RHA convergence. Not a naive retry: each unit
  // walks the SAME progression ladder as the local engine —
  //   1. bounded fresh repair, decorrelated up a temperature ladder, with
  //      tabu facts accumulated across every discarded attempt;
  //   2. signature/progress stall detection (converge);
  //   3. ENTROPY RESET on stall: discard the implementation entirely and
  //      redraw fresh from the frozen contract at ceiling temperature;
  //   4. IR-case surgery for cases that fail EVERY pass while the
  //      implementation keeps changing — suspect the test, regenerate just
  //      those cases conforming to the stubs, re-freeze, continue.
  // SET 20 — crash doctrine: investigation before takeoff; 0 LLM while
  // unattributed; quarantine identical cross-feature crash signatures.
  if (opts.runSuite && !skipRhaAllBuildsFailed) {
    /** SET 20b — parked features (blocked-crash); re-measure when artifact changes. */
    const parked = new Map<string, { sig: string }>();
    /** SET 36g — seam-dump sets already emitted, keyed by program hash. */
    const seamDumpEmitted = new Set<string>();

    interface AuthErr { name: string; message: string; crash?: boolean; cls?: ClassifiedFailure }
    const describeErrs = (errs: AuthErr[], total: number) =>
      errs[0]?.crash ? `suite crashed: ${errs[0].message.slice(0, 160)}`
        : `${total - errs.length}/${total} passing`;

    const classifyMeasure = (
      feature: (typeof ordered)[number],
      r: { total: number; failures: { name: string; message: string }[]; crashed?: string },
      frozenContent: string,
    ): AuthErr[] => {
      return (r.crashed
        ? [{ name: '__suite__', message: r.crashed, crash: true }]
        : r.failures.map(f => ({ name: f.name, message: f.message }))
      ).map(e => {
        const cls = classifyFailure(e.name, e.message);
        // SET 64 — classification floor accounting (≥95% cataloged target).
        metrics.classifyAttempts++;
        if (cls.stratum !== 'catalog-drift') metrics.classifyCataloged++;
        const isCrash = 'crash' in e && !!e.crash;
        if (isCrash && !cls.detail.file) {
          // SET 36b — placeholder in artifact → transpile|<file>, never unattributed.
          const placeholders = findTranspilePlaceholders(artifactFiles());
          if (placeholders.length === 1) {
            cls.detail.file = placeholders[0]!.path;
            cls.kind = 'transpile';
            cls.classKey = `transpile|${placeholders[0]!.path}`;
          }
          // SET 25c/25d — use detailed attribution; surface the miss event so
          // callers see WHY the invariant tripped rather than a silent refusal.
          const detailed = attributeEvalCrashDetailed(
            artifactFiles(),
            { path: feature.testFile, content: frozenContent },
            e.message,
          );
          if (detailed.file) {
            cls.detail.file = detailed.file;
            if (placeholders.some(p => p.path === detailed.file)) {
              cls.kind = 'transpile';
              cls.classKey = `transpile|${detailed.file}`;
            }
          } else if (detailed.miss) {
            // SET 34a/36g — attribution-miss evidence; seam dumps only for
            // parse-class misses, deduped by program hash.
            const suiteFile = { path: feature.testFile, content: frozenContent };
            const arts = artifactFiles();
            const ph = programStateHash(arts, suiteFile);
            const suppress = !shouldEmitSeamDumps(e.message);
            const seams = suppress ? [] : dumpConcatenationSeams(arts, suiteFile);
            const seamRef = !suppress && seamDumpEmitted.has(ph) ? ph : undefined;
            if (!suppress && !seamRef) seamDumpEmitted.add(ph);
            noteEvidence('rha', feature.id, formatAttributionMissEvidence({
              miss: detailed.miss,
              crashMessage: e.message,
              seams: seamRef ? [] : seams,
              programHash: seamRef ? undefined : ph,
              suppressSeams: suppress,
              seamRefHash: seamRef,
            }));
            // SET 31b — recursive seam attribution (no heal yet — that
            // happens where mechanical fixes are applied). Setting
            // detail.file to the left module of the pair pins the ladder
            // to a real target rather than leaving the crash unattributed.
            const boundary = attributeBoundaryFault(
              arts,
              suiteFile,
              e.message,
              null,
            );
            if (boundary) {
              emit('rha', feature.id, boundary.event);
              if (boundary.pair) cls.detail.file = boundary.pair[0];
            }
          }
        }
        return { ...e, crash: isCrash, cls };
      });
    };

    const applyMechFixes = async (toApply: { path: string; content: string; note: string; classKey: string }[], featureId: string, testFile: string) => {
      // SET 89 §9.1 — one call to `applyMechFixes` represents ONE
      // fixed substrate attempt (the caller has already bumped
      // `substrateAttempts`). `substrateFixes` (== `substrateFixedAttempts`)
      // must bump exactly once per fixed attempt regardless of the number
      // of edited files; per-edit accounting lives on
      // `substrateEditsApplied` + `mechanicalFixes`.
      let anyEditApplied = false;
      for (const fix of toApply) {
        if (fix.path === testFile) {
          const feat = ordered.find(f => f.id === featureId);
          if (feat) {
            // eslint-disable-next-line no-await-in-loop -- deterministic
            const res = await commitFrozenPatch(
              feat, fix.content, undefined, `mechanical-fix: ${fix.classKey}`);
            if (res && res.status === 'rejected') {
              emit('rha', featureId,
                `mechanical patch rejected by gateway (${fix.classKey}): ${res.report.rejectionReasons[0] ?? 'no reason'}`);
              continue; // don't count as fixed; incumbent kept
            }
          }
        } else {
          artifactState.commitWrites({
            files: [{ path: fix.path, content: fix.content }],
            phase: 'rha', target: featureId, kind: 'substrate-mechanical-fix',
          });
          noteFileDraw([fix.path]);
        }
        metrics.mechanicalFixes++;
        metrics.substrateEditsApplied++;
        if (/^catalog-drift\|missing-new\|/.test(fix.classKey)) {
          metrics.catalogDriftMechanicalFixes++;
        }
        anyEditApplied = true;
        noteClassKey(fix.classKey, 'fixed');
        const editShape = fix.note.replace(/\s+/g, ' ').trim().slice(0, 120);
        healedInstances.push({
          classKey: fix.classKey,
          editShape,
          afterSnippet: fix.content.slice(0, 240),
          path: fix.path,
        });
      }
      if (anyEditApplied) metrics.substrateFixes++;
    };

    /**
     * SET 31b — try to attribute a boundary-fault crash (miss path where
     * every single-module probe is clean but the concat crashes) and heal
     * via delimiter-oracle candidate edits at the tail of A / head of B.
     * Zero tokens. Returns true when at least one seam fix was applied.
     */
    const tryBoundaryHeal = async (
      featureId: string,
      testFile: string,
      frozenContent: string,
      crashMessage: string,
    ): Promise<boolean> => {
      const suiteFile: GeneratedFile = { path: testFile, content: frozenContent };
      const result = attributeBoundaryFault(
        artifactFiles(),
        suiteFile,
        crashMessage,
        applyDelimiterOracle,
      );
      if (!result) return false;
      emit('rha', featureId, result.event);
      if (!result.fixes || !result.fixes.length) return false;
      const classKey = `boundary-fault|${result.pair ? result.pair.join('⨝') : ''}`;
      await applyMechFixes(
        result.fixes.map(fx => ({ ...fx, classKey })),
        featureId,
        testFile,
      );
      emit('rha', featureId, `substrate: ${classKey} → fixed (0 tok)`);
      opts.onLesson?.(distillLesson(classKey, crashMessage, `boundary seam-heal ${result.pair?.join(' ⨝ ') ?? ''}`));
      return true;
    };

    /**
     * SET 25d — un-park every feature currently parked under `sig` and any
     * feature not-yet-parked but still crashing with the same signature. The
     * caller re-measures them via the standard loop; here we only clear the
     * parked map and its provenance problem entry.
     */
    const unparkBySignature = (sig: string): number => {
      let cleared = 0;
      for (const [id, entry] of [...parked]) {
        if (entry.sig !== sig) continue;
        parked.delete(id);
        // Remove the stub problem entry — the feature will get a fresh verdict on re-measure.
        const ix = problems.findIndex(p => p === `${id}: crash|unattributed`);
        if (ix >= 0) problems.splice(ix, 1);
        emit('auth', id, `unparked — delimiter oracle cleared ${sig}`);
        cleared++;
      }
      return cleared;
    };

    /**
     * SET 25d — propagate a suite-side heal to every feature in the quarantine
     * group. When each feature owns its own frozen suite content, we can't
     * blindly reuse the sample's healed content — apply the delimiter oracle
     * to each independently so byte-minimal fixes stay minimal.
     */
    const propagateSuiteHeal = async (
      featureIds: string[],
      sampleFeatureId: string,
      sampleHealed: { path: string; content: string; classKey: string },
      errorHint: string,
    ): Promise<number> => {
      let propagated = 0;
      for (const id of featureIds) {
        if (id === sampleFeatureId) continue;
        const feature = ordered.find(f => f.id === id);
        const frozen = feature ? frozenByFeature.get(id) : undefined;
        if (!feature || frozen == null) continue;
        // Heal this feature's own frozen suite (may differ byte-for-byte).
        const heal = applyDelimiterOracle(frozen, errorHint);
        if (!heal) continue;
        // eslint-disable-next-line no-await-in-loop -- deterministic
        await applyMechFixes(
          [{
            path: feature.testFile,
            content: heal.content,
            note: `propagated frozen-suite spot-heal (${heal.classKey}) to ${feature.testFile}`,
            classKey: `regex-literal|${errorHint.slice(0, 40)}`,
          }],
          id,
          feature.testFile,
        );
        emit('rha', id,
          `frozen-suite spot-heal: ${feature.testFile} (delimiter:${heal.classKey}, ${heal.edits} edit${heal.edits === 1 ? '' : 's'}, 0 tok)`);
        emit('ir', id, `suite re-frozen after quarantine spot-heal — parses clean`);
        propagated++;
        void sampleHealed;
      }
      return propagated;
    };

    /** SET 20c / 25d — one run-scope substrate diagnosis for a shared crash
     *  signature. Attributes → mech-fix → delimiter oracle last sweep →
     *  propagates a suite heal to every feature in the group → un-parks. */
    const runScopeDiagnosis = async (sig: string, featureIds: string[]): Promise<boolean> => {
      const sampleId = featureIds[0]!;
      const sample = ordered.find(f => f.id === sampleId);
      const frozenContent = sample ? frozenByFeature.get(sample.id) : undefined;
      if (!sample || frozenContent == null) return false;
      const live = await opts.runSuite!(artifactFiles(), { path: sample.testFile, content: frozenContent });
      if (!live.crashed) return false;
      const liveCls = classifyFailure('__suite__', live.crashed);
      // SET 25c — use the detailed attribution result so we can emit the
      // miss diagnostic when the invariant trips.
      if (!liveCls.detail.file) {
        const detailed = attributeEvalCrashDetailed(
          artifactFiles(),
          { path: sample.testFile, content: frozenContent },
          live.crashed,
        );
        if (detailed.file) {
          liveCls.detail.file = detailed.file;
        } else if (detailed.miss) {
          // SET 34a/36g — quarantine attribution-miss; seam dumps deduped / suppressed.
          const suiteFileQ = { path: sample.testFile, content: frozenContent };
          const artsQ = artifactFiles();
          const phQ = programStateHash(artsQ, suiteFileQ);
          const suppressQ = !shouldEmitSeamDumps(live.crashed);
          const seams = suppressQ ? [] : dumpConcatenationSeams(artsQ, suiteFileQ);
          const seamRefQ = !suppressQ && seamDumpEmitted.has(phQ) ? phQ : undefined;
          if (!suppressQ && !seamRefQ) seamDumpEmitted.add(phQ);
          noteEvidence('rha', null, formatAttributionMissEvidence({
            miss: detailed.miss,
            crashMessage: live.crashed,
            seams: seamRefQ ? [] : seams,
            programHash: seamRefQ ? undefined : phQ,
            suppressSeams: suppressQ,
            seamRefHash: seamRefQ,
          }));
          // SET 31b — recursive seam attribution + spot-heal (0 tok). If the
          // fix survives whole-program re-probe, propagate + un-park.
          if (await tryBoundaryHeal(sample.id, sample.testFile, frozenContent, live.crashed)) {
            unparkBySignature(sig);
            return true;
          }
        }
      }
      const suiteFile: GeneratedFile = { path: sample.testFile, content: frozenContent };
      metrics.substrateAttempts++;
      const attempt = attemptMechanicalFix(liveCls, artifactFiles(), suiteFile, spec);
      recordSubstrateAttempt(liveCls.classKey, attempt, sample.id);
      type MechFixRow = { path: string; content: string; note: string; classKey: string };
      let toApply: MechFixRow[];
      if (attempt.status === 'fixed' && attempt.fix) {
        toApply = attempt.fixes?.length ? attempt.fixes : [attempt.fix];
      } else {
        if (attempt.status === 'refused') metrics.substrateRefusals++;
        else if (attempt.status === 'cataloged' || attempt.status === 'catalog-drift' || attempt.status === 'no-handler') {
          metrics.substrateNoHandler++;
          emit('rha', null, `substrate: ${liveCls.classKey} → ${formatAttemptStatus(attempt)} (0 tok)`);
          if (attempt.status === 'catalog-drift') {
            noteEvidence('rha', null, [formatCatalogDriftTripwire(liveCls.message)]);
          }
        }
        // SET 25d — delimiter oracle last-sweep on the SUITE + attributed file
        // before returning false. Zero tokens. Byte-minimal spot-edits.
        const targets: { path: string; content: string }[] = [
          { path: sample.testFile, content: frozenContent },
        ];
        if (liveCls.detail.file && liveCls.detail.file !== sample.testFile) {
          const cur = artifactFiles().find(f => f.path === liveCls.detail.file);
          if (cur) targets.push({ path: cur.path, content: cur.content });
        }
        const sweeps: MechFixRow[] = [];
        for (const t of targets) {
          const heal = applyDelimiterOracle(t.content, live.crashed);
          if (heal && heal.content !== t.content) {
            sweeps.push({
              path: t.path,
              content: heal.content,
              note: `delimiter oracle last-sweep (${heal.classKey}, ${heal.edits} edit${heal.edits === 1 ? '' : 's'}) on ${t.path}`,
              classKey: liveCls.classKey,
            });
          }
        }
        if (!sweeps.length) {
          emit('rha', null, `crash quarantine diagnosis: ${liveCls.classKey} → ${attempt.status}(${attempt.reason ?? ''})`);
          // SET 101d — quarantine diagnosis refuse with impl repair exhausted.
          if (
            attempt.status === 'refused'
            && /impl repair exhausted/i.test(attempt.reason ?? '')
            && (/^transpile\|/.test(liveCls.classKey) || liveCls.kind === 'transpile')
          ) {
            const qFile = liveCls.detail.file
              ?? /^transpile\|(.+)$/.exec(liveCls.classKey)?.[1]
              ?? null;
            if (qFile) suspendFileRepair(qFile, sample.id);
          }
          return false;
        }
        toApply = sweeps;
      }
      if (liveCls.kind === 'duplicate-decl' || liveCls.kind === 'regex-literal'
        || liveCls.kind === 'transpile' || liveCls.kind === 'crash') {
        let probeSet = artifactFiles().map(f => {
          const fx = toApply!.find(x => x.path === f.path);
          return fx ? { path: f.path, content: fx.content } : f;
        });
        for (const fx of toApply) {
          if (!probeSet.some(f => f.path === fx.path)) {
            probeSet = [...probeSet, { path: fx.path, content: fx.content }];
          }
        }
        let probeFailed = false;
        if (liveCls.kind === 'duplicate-decl') {
          const err = probeWholeArtifactEval(probeSet);
          if (err && /has already been declared/i.test(err)) probeFailed = true;
          for (const fx of toApply) {
            // Suite paths aren't in the impl registry — probe them against the
            // full program set (frozen suite as target module) instead.
            if (fx.path === sample.testFile) continue;
            if (probeErrOrNull(probeModuleEval(probeSet, fx.path))) { probeFailed = true; break; }
          }
        } else {
          for (const fx of toApply) {
            if (fx.path === sample.testFile) continue;
            if (probeErrOrNull(probeModuleEval(probeSet, fx.path))) { probeFailed = true; break; }
          }
        }
        if (probeFailed) {
          metrics.substrateRefusals++;
          emit('rha', null, `crash quarantine diagnosis: ${liveCls.classKey} → refused(probe-failed)`);
          return false;
        }
      }
      await applyMechFixes(toApply, sample.id, sample.testFile);
      const healedSuite = toApply.find(fx => fx.path === sample.testFile);
      const suiteWasHealed = healedSuite != null;
      if (suiteWasHealed) {
        emit('rha', sample.id,
          `frozen-suite spot-heal: ${sample.testFile} (delimiter:${liveCls.classKey.split('|')[0]}, 0 tok)`);
        emit('ir', sample.id, `suite re-frozen after quarantine spot-heal — parses clean`);
      }
      for (const fix of toApply) {
        opts.onLesson?.(distillLesson(fix.classKey, liveCls.message, fix.note));
      }
      emit('rha', null, `crash quarantine diagnosis: ${liveCls.classKey} → fixed (0 tok)`);
      // SET 25d — propagate the heal to every OTHER feature in the group.
      // Each feature owns its frozen suite; heal each independently.
      if (suiteWasHealed) {
        await propagateSuiteHeal(featureIds, sample.id, healedSuite, live.crashed);
      }
      // SET 25d — un-park every feature parked under this signature. The
      // outer loop re-measures via the standard ladder (0 passes if clean).
      unparkBySignature(sig);
      return true;
    };

    /** SET 20c — freeze ladders when ≥2 features share a crash signature. */
    const detectAndQuarantine = async (): Promise<void> => {
      const bySig = new Map<string, string[]>();
      for (const feature of ordered) {
        const frozenContent = frozenByFeature.get(feature.id);
        if (frozenContent == null) continue;
        bail();
        const r = await opts.runSuite!(artifactFiles(), { path: feature.testFile, content: frozenContent });
        if (!r.crashed) continue;
        const s = normalizeCrashSignature(r.crashed);
        bySig.set(s, [...(bySig.get(s) ?? []), feature.id]);
      }
      for (const [s, ids] of bySig) {
        if (ids.length < 2) continue;
        noteRunError('crash');
        emit('rha', null, `crash quarantine: ${s} across ${ids.length} features — ladders frozen`);
        await runScopeDiagnosis(s, ids);
      }
    };

    // SET 59b — build gate: implementations written, nothing executed yet.
    await opts.onPhaseGate?.('build');
    bail();

    await detectAndQuarantine();

    const remeasureParked = async () => {
      for (const [id] of [...parked]) {
        const feature = ordered.find(f => f.id === id);
        const frozenContent = feature ? frozenByFeature.get(id) : undefined;
        if (!feature || frozenContent == null) continue;
        const r = await opts.runSuite!(artifactFiles(), { path: feature.testFile, content: frozenContent });
        if (!r.crashed && r.failures.length === 0) {
          parked.delete(id);
          emit('auth', id, 'unparked — shared artifact change cleared crash');
        }
      }
    };

    for (const feature of ordered) {
      let frozen = frozenByFeature.get(feature.id);
      if (frozen == null) continue;
      if (parked.has(feature.id)) continue;
      // SET 40f — no ladder against pure stubs when this feature's builds failed.
      if (buildFailedIds.has(feature.id)) continue;
      metrics.nodesTotal++;
      let parts = irPartsByFeature.get(feature.id) ?? null;
      const tabu = new Set<string>();
      // SET 62 — a reset win is a heal; keep its before→after for the flywheel.
      // (Holder object: the write happens inside the onStall closure, which TS
      // flow analysis cannot see from the post-ladder read.)
      const resetHeal: { cur: { classKey: string; before: string; after: string; path: string } | null } = { cur: null };
      const failStreak = new Map<string, number>();
      let irSurgeryUsed = false;
      let crashSurgeryCount = 0;
      let abortLadder = false;
      let lastTotal = 0;
      let prevClasses = new Map<string, string>();
      let lastAction = '';
      // SET 36e — stall-adaptive entropy escalation (before entropy reset).
      let batchParams: BatchParams = defaultBatchParams();
      let noImproveStreak = 0;
      let lastFocusKey = '';
      // SET 64 — L2 loop budget consumed per focus classKey (≤3 each).
      const l2Loops = new Map<string, number>();
      // SET 68 — one judgment gate per case; directed intent addenda are
      // licensed spec context injected into every subsequent repair draw.
      const judgedCases = new Set<string>();
      const intentAddenda: string[] = [];

      // After quarantine: skip ladder when already clean (repair passes = 0).
      {
        bail();
        const pre = await opts.runSuite!(artifactFiles(), { path: feature.testFile, content: frozen });
        lastTotal = pre.total;
        if (!pre.crashed && pre.failures.length === 0) {
          metrics.passesPerFeature[feature.id] = 0;
          metrics.nodesBuiltCleanFirstPass++;
          emit('auth', feature.id, 'converged in 0 passes');
          continue;
        }
        if (pre.crashed) {
          noteRunError('execution');
          const preErrs = classifyMeasure(feature, pre, frozen);
          const c0 = preErrs[0]?.cls;
          if (c0 && isCrashClass(c0.kind)) {
            const suiteFile: GeneratedFile = { path: feature.testFile, content: frozen };
            if (!crashRepairPrecondition(c0, artifactFiles(), suiteFile)) {
              metrics.substrateAttempts++;
              const attempt = attemptMechanicalFix(c0, artifactFiles(), suiteFile, spec);
              recordSubstrateAttempt(c0.classKey, attempt, feature.id);
              let fixed = false;
              if (attempt.status === 'fixed' && attempt.fix) {
                const toApply = attempt.fixes?.length ? attempt.fixes : [attempt.fix];
                let probeOk = true;
                if (c0.kind === 'duplicate-decl') {
                  const probeSet = artifactFiles().map(f => {
                    const fx = toApply.find(x => x.path === f.path);
                    return fx ? { path: f.path, content: fx.content } : f;
                  });
                  const err = probeWholeArtifactEval(probeSet);
                  if (err && /has already been declared/i.test(err)) probeOk = false;
                  for (const fx of toApply) {
                    if (probeErrOrNull(probeModuleEval(probeSet, fx.path))) { probeOk = false; break; }
                  }
                }
                if (probeOk) {
                  await applyMechFixes(toApply, feature.id, feature.testFile);
                  frozen = frozenByFeature.get(feature.id) ?? frozen;
                  for (const fix of toApply) {
                    lastAction = `substrate: ${fix.note}`;
                    const tag = /delimiter oracle/.test(fix.note) ? ' [delimiter oracle heal]' : '';
                    emit('rha', feature.id, `substrate: ${c0.classKey} → fixed (0 tok)${tag}`);
                    opts.onLesson?.(distillLesson(fix.classKey, c0.message, fix.note));
                  }
                  fixed = true;
                  const post = await opts.runSuite!(artifactFiles(), { path: feature.testFile, content: frozen });
                  if (!post.crashed && post.failures.length === 0) {
                    metrics.passesPerFeature[feature.id] = 0;
                    emit('auth', feature.id, 'converged in 0 passes');
                    await remeasureParked();
                    continue;
                  }
                } else {
                  metrics.substrateRefusals++;
                }
              } else if (attempt.status === 'refused') {
                metrics.substrateRefusals++;
                emit('rha', feature.id,
                  `substrate: ${c0.classKey} → refused(${attempt.reason ?? 'unproven'}) (0 tok)`);
                if (
                  /impl repair exhausted/i.test(attempt.reason ?? '')
                  && (/^transpile\|/.test(c0.classKey) || c0.kind === 'transpile')
                ) {
                  const qFile = c0.detail.file
                    ?? /^transpile\|(.+)$/.exec(c0.classKey)?.[1]
                    ?? null;
                  if (qFile) suspendFileRepair(qFile, feature.id);
                }
              } else if (
                attempt.status === 'cataloged'
                || attempt.status === 'catalog-drift'
                || attempt.status === 'no-handler'
              ) {
                metrics.substrateNoHandler++;
                emit('rha', feature.id,
                  `substrate: ${c0.classKey} → ${formatAttemptStatus(attempt)} (0 tok)`);
                if (attempt.status === 'catalog-drift') {
                  noteEvidence('rha', feature.id, [formatCatalogDriftTripwire(c0.message)]);
                }
              }
              const again = await opts.runSuite!(artifactFiles(), { path: feature.testFile, content: frozen });
              const againCls = classifyMeasure(feature, again, frozen)[0]?.cls ?? c0;
              if (!crashRepairPrecondition(againCls, artifactFiles(), suiteFile)) {
                // SET 31b — last-chance recursive seam attribution + heal.
                // If a boundary pair is found and a delimiter-oracle spot-heal
                // survives the whole-program re-probe, un-park and re-measure.
                if (await tryBoundaryHeal(feature.id, feature.testFile, frozen, again.crashed ?? pre.crashed)) {
                  frozen = frozenByFeature.get(feature.id) ?? frozen;
                  const post = await opts.runSuite!(artifactFiles(), { path: feature.testFile, content: frozen });
                  if (!post.crashed && post.failures.length === 0) {
                    metrics.passesPerFeature[feature.id] = 0;
                    emit('auth', feature.id, 'converged in 0 passes');
                    await remeasureParked();
                    continue;
                  }
                } else {
                  parked.set(feature.id, { sig: normalizeCrashSignature(pre.crashed) });
                  problems.push(`${feature.id}: crash|unattributed`);
                  metrics.passesPerFeature[feature.id] = 0;
                  emit('rha', feature.id, 'blocked-crash: parked (crash|unattributed)');
                  continue;
                }
              }
              void fixed;
            }
          }
        }
      }

      const measure = async (): Promise<AuthErr[]> => {
        bail();
        // SET 89 §10.3 — every authoritative measurement is a structured
        // action. The action wraps suite execution and defect-registry
        // observation; the terminal disposition names what happened.
        const measurementActionId = actionLedger.startAction({
          kind: 'authoritative-measurement',
          target: feature.id,
          phase: 'rha',
          startEvidence: { testFile: feature.testFile },
        });
        let r: Awaited<ReturnType<SuiteRunner>>;
        try {
          r = await opts.runSuite!(artifactFiles(), { path: feature.testFile, content: frozen! });
        } catch (err) {
          actionLedger.finishAction({
            actionId: measurementActionId, disposition: 'failed',
            failureMode: 'fatal', error: err,
          });
          throw err;
        }
        lastTotal = r.total;
        const errs = classifyMeasure(feature, r, frozen!);
        const nowKeys = new Set(errs.map(e => e.cls!.classKey));
        for (const [key, ex] of prevClasses) {
          if (!nowKeys.has(key) && lastAction) {
            opts.onLesson?.(distillLesson(key, ex, lastAction));
          }
        }
        prevClasses = new Map(errs.map(e => [e.cls!.classKey, e.message]));
        const failing = new Set(errs.map(e => e.name));
        for (const name of failing) failStreak.set(name, (failStreak.get(name) ?? 0) + 1);
        for (const name of [...failStreak.keys()]) if (!failing.has(name)) failStreak.delete(name);
        for (const e of errs) tabu.add(`${e.name === '__suite__' ? '' : e.name + ': '}${e.message.split('\n')[0].slice(0, 160)}`);
        for (const e of errs) {
          if (e.crash) {
            const sig = normalizeCrashSignature(e.message);
            let set = artifactFaultAffects.get(sig);
            if (!set) { set = new Set(); artifactFaultAffects.set(sig, set); }
            set.add(feature.id);
          }
        }
        // SET 74 / SET 89 §10.3 — the measurement produces:
        //   1. one supergit `result` node;
        //   2. one supergit `error` node per finding;
        //   3. one authoritative defect-registry occurrence per finding
        //      (canonical-key identity, category via classifyFindingCategory);
        //   4. scope reconciliation for this feature: identities absent from
        //      the current measurement graduate to resolutions and a
        //      `resolution` supergit node is recorded per resolution.
        const measurementId = `M-${feature.id}-${supergit.allRows().length}`;
        const resultId = supergit.recordNode({
          type: 'result', featureId: feature.id,
          causeId: supergit.codeNodeFor(feature.id) ?? supergit.testNodeFor(feature.id),
          artifactPath: feature.testFile,
          status: errs.length === 0 ? 'pass' : 'fail',
          summary: describeErrs(errs, r.total),
        });
        const presentKeys: string[] = [];
        for (const e of errs) {
          const errorNodeId = supergit.recordNode({
            type: 'error', featureId: feature.id, causeId: resultId,
            artifactPath: e.cls?.detail.file ?? feature.files[0] ?? null,
            bugClass: e.cls?.classKey ?? null,
            status: 'open',
            summary: `${e.name}: ${e.message.split('\n')[0] ?? ''}`,
          });
          errorNodeByFeature.set(feature.id, errorNodeId);
          const category = classifyFindingCategory({
            classKey: e.cls?.classKey,
            crash: !!e.crash,
            message: e.message,
            kindHint: e.cls?.kind === 'assertion' || e.cls?.kind === 'throw-mismatch'
              ? 'test-failure'
              : undefined,
          });
          const caseId = e.name && e.name !== '__suite__' ? e.name : SUITE_SENTINEL;
          const classKey = e.cls?.classKey ?? `${category}|${caseId}`;
          const expected = e.cls?.detail.expected ?? null;
          const received = e.cls?.detail.received ?? null;
          const crashSignature = e.crash
            ? normalizeCrashSignature(e.message)
            : null;
          const occurrence = defectRegistry.observeAuthoritativeFinding({
            featureId: feature.id,
            caseId,
            classKey,
            category,
            artifactPath: e.cls?.detail.file ?? feature.files[0] ?? null,
            expected,
            received,
            crashSignature,
            message: e.message,
            measurementId,
            resultNodeId: resultId,
            errorNodeId,
            actionId: measurementActionId,
          });
          presentKeys.push(occurrence.canonicalKey);
        }
        // SET 89 §10.4 — reconcile this feature's scope. Any identity
        // previously observed in this scope that is NOT present in the
        // current measurement resolves — one `resolution` supergit node is
        // recorded per resolution, chained to the causing error node.
        const resolutions = defectRegistry.reconcileMeasurementScope({
          scopeKey: feature.id,
          presentKeys,
          confirmingMeasurementId: measurementId,
          confirmingResultNodeId: resultId,
          actionId: measurementActionId,
        });
        for (const res of resolutions) {
          supergit.recordNode({
            type: 'resolution', featureId: feature.id,
            causeId: res.causeErrorNodeId,
            artifactPath: feature.testFile,
            status: 'pass',
            summary: `resolved defect ${res.defectId} (${res.resolutionId})`,
          });
        }
        actionLedger.finishAction({
          actionId: measurementActionId,
          disposition: errs.length === 0 ? 'applied' : 'noop',
          endEvidence: {
            total: r.total, failures: r.failures.length,
            crashed: r.crashed ?? null, resolutions: resolutions.length,
          },
        });
        emit('auth', feature.id, describeErrs(errs, r.total));
        return errs;
      };

      /**
       * Apply owned files into the shared artifact.
       * SET 36c — when `vet` is true, reject writes that fail transpile /
       * module-probe / dynamic-eval lint (incumbent kept for rejected paths).
       */
      const applyFiles = async (
        fresh: GeneratedFile[],
        applyOpts?: { vet?: boolean; label?: string },
      ): Promise<boolean> => {
        const violations = boundaryViolations(fresh, feature);
        if (violations.length) emit('rha', feature.id, `boundary violations dropped: ${violations.join('; ')}`);
        const owned = fresh.filter(f => feature.files.includes(f.path));
        const acceptWrite = async (
          f: GeneratedFile,
          base: GeneratedFile[],
        ): Promise<GeneratedFile | null> => {
          let file = f;
          const trial = [...base.filter(b => b.path !== file.path), file];
          let prog = await vetProgramParseAfterWriteAsync(file, trial);
          if (prog.ok && prog.gateUnavailable) noteParseGateUnavailable('rha', feature.id);
          // SET 102 — 0-tok delimiter-oracle heal before incumbent-kept reject.
          if (!prog.ok && /Invalid regular expression/i.test(prog.message)) {
            const healed = applyDelimiterOracle(file.content, prog.message);
            if (healed) {
              const healedFile = { ...file, content: healed.content };
              const trial2 = [...base.filter(b => b.path !== healedFile.path), healedFile];
              const prog2 = await vetProgramParseAfterWriteAsync(healedFile, trial2);
              if (prog2.ok) {
                emit('rha', feature.id,
                  `program-parse healed via delimiterOracle (${healed.classKey}, 0 tok)`);
                metrics.regexLiteralGateHeals++;
                metrics.mechanicalFixes++;
                file = healedFile;
                prog = prog2;
                if (prog.gateUnavailable) noteParseGateUnavailable('rha', feature.id);
              }
            }
          }
          if (!prog.ok) {
            metrics.parsePoisonIncidents++;
            noteRunError('parse');
            emit('rha', feature.id, prog.event);
            opts.onLesson?.(distillLesson(
              distillProgramParseLessonKey(file.path, prog.message),
              prog.message,
              'program-parse rejection — incumbent kept',
            ));
            return null;
          }
          artifactState.commitWrites({
            files: [file], phase: 'rha', target: feature.id, kind: 'rha-write',
          });
          noteFileDraw([file.path]);
          return file;
        };
        if (applyOpts?.vet) {
          const base = artifactFiles().filter(f => !owned.some(o => o.path === f.path));
          // SET 43c — conform exports to stubs before vet/measure.
          const conformed = conformExportsToStubs(owned, feature.stubs);
          const seenConformRha = new Set<string>();
          for (const fx of conformed.fixes) {
            const k = `${fx.path}\0${fx.note}`;
            if (seenConformRha.has(k)) continue;
            seenConformRha.add(k);
            emit('rha', feature.id, `export-conformance: ${fx.note} (0 tok)`);
            // SET 89 §9.1 — deterministic export-conformance edit
            // outside the substrate attempts partition.
            metrics.mechanicalFixes++;
            metrics.deterministicEditsOutsideSubstrate++;
          }
          const ownedConformed = conformed.files;
          // SET 47a — async vet + GATE_UNAVAILABLE fail-open (sandbox when wired).
          const { ok, rejected, gateUnavailable } = await vetArtifactWritesAsync(ownedConformed, base);
          if (gateUnavailable) noteModuleProbeUnavailable('rha', feature.id);
          for (const r of rejected) {
            emit('rha', feature.id, `${applyOpts.label ?? 'draw'} rejected: ${r.reason} in ${r.path}`);
          }
          let allOk = rejected.length === 0;
          const accepted: GeneratedFile[] = [];
          for (const f of ok) {
            const trialBase = [...base, ...accepted];
            const acceptedFile = await acceptWrite(f, trialBase);
            if (!acceptedFile) { allOk = false; continue; }
            accepted.push(acceptedFile);
          }
          return allOk;
        }
        let allOk = true;
        for (const f of owned) {
          if (!(await acceptWrite(f, artifactFiles()))) allOk = false;
        }
        return allOk;
      };

      const findingsOf = (errs: AuthErr[]): Finding[] => errs.map(e => {
        const file = e.cls?.detail.file || feature.files[0] || '';
        const syntaxish = e.crash
          || e.cls?.kind === 'regex-literal'
          || e.cls?.kind === 'duplicate-decl'
          || e.cls?.kind === 'transpile'
          || (e.cls?.kind === 'crash' && !!e.cls.detail.file);
        // SET 36f — fold expected/received into the finding message for repair.
        const diff = e.cls ? formatAssertionDiff(e.cls) : null;
        const message = diff && !e.message.includes(diff) ? `${e.message}\n${diff}` : e.message;
        return syntaxish
          ? { bugClass: 'syntax' as const, file, line: null, message, featureId: feature.id }
          : { bugClass: 'test-failure' as const, file: feature.files[0] ?? '', line: null, message, featureId: feature.id, testName: e.name };
      });

      const parkFeature = async (sig: string): Promise<boolean> => {
        // SET 31b — last-chance boundary heal before we abort the ladder.
        // Signature is the normalized crash class, but we still have the
        // most recent crash message via the current measure — use it if the
        // failStreak/prevClasses maps captured one.
        const lastCrashMsg = [...prevClasses.entries()]
          .filter(([k]) => k === sig || k.startsWith('boundary-fault|') || k === 'crash|suite')
          .map(([, m]) => m)[0]
          ?? [...prevClasses.values()][0];
        if (lastCrashMsg && await tryBoundaryHeal(feature.id, feature.testFile, frozen!, lastCrashMsg)) {
          frozen = frozenByFeature.get(feature.id) ?? frozen;
          return true;
        }
        // SET 38b — ddmin over module set when all probes are clean (tripwire: must emit).
        if (lastCrashMsg) {
          const suiteFile: GeneratedFile = { path: feature.testFile, content: frozen! };
          const dd = ddminForQuarantine(artifactFiles(), suiteFile, lastCrashMsg);
          if (dd) {
            emit('rha', feature.id, dd.event);
            noteEvidence('rha', feature.id, [dd.event]);
            if (dd.set.length) {
              const fixes = ddminHealWithOracle(
                [...artifactFiles(), suiteFile],
                dd.set,
                applyDelimiterOracle,
                lastCrashMsg,
              );
              if (fixes.length) {
                await applyMechFixes(
                  fixes.map(fx => ({
                    ...fx,
                    classKey: `ddmin|${dd.set.join('⨝')}`,
                  })),
                  feature.id,
                  feature.testFile,
                );
                frozen = frozenByFeature.get(feature.id) ?? frozen;
                emit('rha', feature.id, `ddmin heal applied on [${dd.set.join(', ')}] (0 tok)`);
                const cleared = unparkBySignature(sig);
                if (cleared === 0) {
                  // Feature was not yet parked — stay in ladder.
                }
                return true;
              }
              // Parking permitted only with minimal set NAMED.
              abortLadder = true;
              parked.set(feature.id, { sig });
              const named = `crash|unattributed — ${dd.event}`;
              if (!problems.some(p => p.startsWith(`${feature.id}: crash|unattributed`))) {
                problems.push(`${feature.id}: ${named}`);
              }
              emit('rha', feature.id, `blocked-crash: parked (${dd.event})`);
              return false;
            }
          }
        }
        abortLadder = true;
        parked.set(feature.id, { sig });
        if (!problems.some(p => p.startsWith(`${feature.id}: crash|unattributed`))) {
          problems.push(`${feature.id}: crash|unattributed`);
        }
        emit('rha', feature.id, 'blocked-crash: parked (crash|unattributed)');
        return false;
      };

      const outcome = await converge<AuthErr>({
        measure,
        signature: errs => errs.map(e => `${e.name}|${e.message.split('\n')[0]}`).sort().join('~'),
        maxPasses: gates.maxPasses,
        stallLimit: gates.stallLimit,
        progressStall: gates.progressStall,
        abort: () => abortLadder,
        repair: async (errs, pass) => {
          bail();
          if (abortLadder) return;

          const classified = errs.map(e => e.cls!).filter(Boolean);
          const suiteFile: GeneratedFile = { path: feature.testFile, content: frozen! };
          let mechApplied = false;
          let crashRefusedBlock = false;
          let crashAllowLlm = false;
          for (const c of classified) {
            metrics.substrateAttempts++;
            const attempt = attemptMechanicalFix(c, artifactFiles(), suiteFile, spec);
            recordSubstrateAttempt(c.classKey, attempt, feature.id);
            if (
              attempt.status === 'cataloged'
              || attempt.status === 'catalog-drift'
              || attempt.status === 'no-handler'
            ) {
              metrics.substrateNoHandler++;
              emit('rha', feature.id,
                `substrate: ${c.classKey} → ${formatAttemptStatus(attempt)} (0 tok)`);
              if (attempt.status === 'catalog-drift') {
                noteEvidence('rha', feature.id, [formatCatalogDriftTripwire(c.message)]);
              }
              continue; // no mechanical fix; LLM path gated below via refusesModelDraw
            }
            if (attempt.status === 'refused' || !attempt.fix) {
              metrics.substrateRefusals++;
              emit('rha', feature.id,
                `substrate: ${c.classKey} → refused(${attempt.reason ?? 'unproven'}) (0 tok)`);
              // SET 101d — transpile|<file> + impl repair exhausted → suspend until fresh draw.
              if (
                /impl repair exhausted/i.test(attempt.reason ?? '')
                && (/^transpile\|/.test(c.classKey) || c.kind === 'transpile')
              ) {
                const qFile = c.detail.file
                  ?? /^transpile\|(.+)$/.exec(c.classKey)?.[1]
                  ?? null;
                if (qFile) suspendFileRepair(qFile, feature.id);
              }
              if (isCrashClass(c.kind)) {
                if (!c.detail.file) {
                  const file = attributeEvalCrash(artifactFiles(), suiteFile, c.message);
                  if (file) c.detail.file = file;
                }
                if (!crashRepairPrecondition(c, artifactFiles(), suiteFile)) {
                  if (await parkFeature(c.classKey)) {
                    // SET 31b — boundary heal applied; feature stays in ladder.
                    mechApplied = true;
                    continue;
                  }
                  crashRefusedBlock = true;
                  break;
                }
                crashAllowLlm = true;
                crashRefusedBlock = true;
              }
              continue;
            }
            const toApply = attempt.fixes?.length ? attempt.fixes : [attempt.fix];
            if (c.kind === 'regex-literal' || c.kind === 'transpile' || c.kind === 'crash'
              || c.kind === 'duplicate-decl') {
              let probeSet = artifactFiles().map(f => {
                const fx = toApply.find(x => x.path === f.path);
                return fx ? { path: f.path, content: fx.content } : f;
              });
              for (const fx of toApply) {
                if (!probeSet.some(f => f.path === fx.path)) {
                  probeSet = [...probeSet, { path: fx.path, content: fx.content }];
                }
              }
              let probeFailed = false;
              if (c.kind === 'duplicate-decl') {
                const err = probeWholeArtifactEval(probeSet);
                if (err && /has already been declared/i.test(err)) probeFailed = true;
                for (const fx of toApply) {
                  if (probeErrOrNull(probeModuleEval(probeSet, fx.path))) { probeFailed = true; break; }
                }
              } else {
                for (const fx of toApply) {
                  if (probeErrOrNull(probeModuleEval(probeSet, fx.path))) { probeFailed = true; break; }
                }
              }
              if (probeFailed) {
                metrics.substrateRefusals++;
                emit('rha', feature.id,
                  `substrate: ${c.classKey} → refused(probe-failed) (0 tok)`);
                if (isCrashClass(c.kind) && !crashRepairPrecondition(c, artifactFiles(), suiteFile)) {
                  if (await parkFeature(c.classKey)) {
                    mechApplied = true;
                    continue;
                  }
                  crashRefusedBlock = true;
                  break;
                }
                if (isCrashClass(c.kind)) {
                  crashAllowLlm = crashRepairPrecondition(c, artifactFiles(), suiteFile);
                  crashRefusedBlock = true;
                }
                continue;
              }
            }
            // SET 89 §9.1 — one attempt bumps `substrateFixes` at most
            // once. `substrateEditsApplied` and `mechanicalFixes` count
            // per file. Track `anyL1EditApplied` so an all-rejected
            // attempt does not falsely count as fixed.
            let anyL1EditApplied = false;
            for (const fix of toApply) {
              if (fix.path === feature.testFile) {
                // eslint-disable-next-line no-await-in-loop -- deterministic
                const res = await commitFrozenPatch(
                  feature, fix.content, undefined, `substrate-L1: ${c.classKey}`);
                if (res && res.status === 'rejected') {
                  emit('rha', feature.id,
                    `substrate L1 patch rejected by gateway (${c.classKey}): ${res.report.rejectionReasons[0] ?? 'no reason'}`);
                  continue; // don't count as fixed
                }
                frozen = fix.content;
              } else {
                artifactState.commitWrites({
                  files: [{ path: fix.path, content: fix.content }],
                  phase: 'rha', target: feature.id, kind: 'substrate-L1',
                });
                noteFileDraw([fix.path]);
              }
              metrics.mechanicalFixes++;
              metrics.substrateEditsApplied++;
              if (/^catalog-drift\|missing-new\|/.test(fix.classKey)) {
                metrics.catalogDriftMechanicalFixes++;
              }
              anyL1EditApplied = true;
              lastAction = `substrate: ${fix.note}`;
              const tag = /delimiter oracle/.test(fix.note) ? ' [delimiter oracle heal]' : '';
              emit('rha', feature.id, `substrate: ${c.classKey} → fixed (0 tok)${tag}`);
              supergit.recordNode({
                type: 'repair', featureId: feature.id,
                causeId: errorNodeByFeature.get(feature.id) ?? null,
                // SET 89 §10.4 — a repair attempt is NEVER a resolution. Only
                // a later authoritative measurement that no longer contains
                // the defect identity resolves it, and that emits a separate
                // `type: 'resolution'` node via defectRegistry reconciliation.
                artifactPath: fix.path, bugClass: c.classKey, status: 'info',
                summary: `L1 substrate applied (0 tok): ${fix.note}`,
              });
              opts.onLesson?.(distillLesson(fix.classKey, c.message, fix.note));
            }
            if (anyL1EditApplied) metrics.substrateFixes++;
            mechApplied = true;
          }
          if (mechApplied) return;
          if (crashRefusedBlock && !crashAllowLlm) return;
          if (abortLadder) return;

          const cls0 = errs[0]?.cls;
          const suiteAttributed = !!cls0?.detail.file && (
            cls0.detail.file === feature.testFile
            || cls0.detail.file.replace(/\.(ts|js)$/, '') === feature.testFile.replace(/\.(ts|js)$/, '')
          );
          // SET 35a — case-attributed exec crashes route to IR surgery even when
          // the path form differs slightly from feature.testFile.
          const suiteCrashSurgery = (suiteAttributed || !!cls0?.detail.caseName) && (
            cls0!.kind === 'transpile'
            || cls0!.kind === 'regex-literal'
            || cls0!.kind === 'crash'
            || !!errs[0]?.crash
          );
          if (parts && crashSurgeryCount < 2 && suiteCrashSurgery) {
            crashSurgeryCount++;
            const pinpoints = caseSyntaxErrors(parts.cases);
            let brokenCases = pinpoints.map(pp => {
              const c = parts!.cases.find(x => x.name === pp.name)!;
              return { name: c.name, kind: c.kind as IRCaseGen['kind'], errors: [pp.error] };
            });
            // SET 35a — execution-position names the offender even when the
            // case body still parses (eval/new Function detonation).
            if (!brokenCases.length && cls0?.detail.caseName) {
              const hit = parts.cases.find(c =>
                c.name === cls0!.detail.caseName
                || caseNamesMatch(c.name, cls0!.detail.caseName!)
                || cls0!.detail.caseName!.endsWith(c.name));
              if (hit) {
                brokenCases = [{
                  name: hit.name,
                  kind: hit.kind as IRCaseGen['kind'],
                  errors: [errs[0]?.message ?? 'execution-position crash'],
                }];
              }
            }
            // SET 35b — also surger cases that carry dynamic-eval poison.
            if (!brokenCases.length) {
              const poison = parts.cases.filter(c => dynamicEvalLint(c.body));
              brokenCases = poison.map(c => ({
                name: c.name,
                kind: c.kind as IRCaseGen['kind'],
                errors: [dynamicEvalLint(c.body)!],
              }));
            }
            if (brokenCases.length) {
              emit('rha', feature.id, `substrate: pinpointed ${brokenCases.length} unparseable case(s) — IR-side regeneration (impl untouched)`);
              try {
                let nextCases = parts.cases.map(c => {
                  if (!brokenCases.some(b => b.name === c.name)) return c;
                  const rebound = rebindCladeBody(c);
                  if (rebound && acceptCaseBody(rebound)) {
                    metrics.mechanicalFixes++;
                    return { ...c, body: rebound, clade: c.clade ?? classifyCaseClade(c) };
                  }
                  return c;
                });
                let stillBroken = brokenCases.filter(b =>
                  caseSyntaxErrors(nextCases.filter(c => c.name === b.name)).length > 0);
                if (stillBroken.length) {
                  const stillReq = withOracleHints(stillBroken);
                  // SET 95d — hole-only gate rolled to syntax-repair (single-broken
                  // batches only, same restriction as the 95c canary).
                  const srFrame = stillBroken.length === 1
                    ? holeOnlyFrameFor(gates, feature, stillBroken[0]!.name, stillBroken[0]!.kind)
                    : null;
                  const srReq = srFrame
                    ? stillReq.map(r => ({ ...r, errors: [...r.errors, holeOnlyPromptBlock(srFrame)].filter(Boolean) }))
                    : stillReq;
                  const cands: PermutationCandidate<IRCaseGen[]>[] = [];
                  for (let ci = 0; ci < PERMUTATION_TEMPS.length; ci++) {
                    const t = PERMUTATION_TEMPS[ci]!;
                    bail();
                    metrics.permutationDraws++;
                    const fixed = await runLlmAction({
                      method: 'fixTestCases:syntax-repair-permutation',
                      target: feature.id, phase: 'ir',
                      startEvidence: {
                        temperature: t, candidateIndex: ci + 1,
                        broken: stillBroken.length,
                      },
                      fn: () => opts.llm.fixTestCases(
                        spec, feature, srReq, [], parts!.imports,
                        { temperature: t, candidate: { n: ci + 1, k: PERMUTATION_TEMPS.length } },
                      ),
                    });
                    const bound = bindFixTestCases(stillBroken, fixed.cases);
                    metrics.mechanicalFixes += bound.unwrapFixes;
                    if (srFrame) {
                      const srGate = applyHoleOnlyGate(srFrame, bound.cases[0]?.body ?? '', metrics, stillBroken[0]!.name,
                        msg => emit('rha', feature.id, msg));
                      if (srGate.rejected) {
                        cands.push({ value: nextCases, temp: t, score: 0, findings: 1, label: 'overreach|body rejected' });
                        continue;
                      }
                      if (bound.cases[0]) bound.cases[0] = { ...bound.cases[0], body: srGate.body };
                    }
                    const merged = nextCases.map(c => {
                      const i = stillBroken.findIndex(b => caseNamesMatch(b.name, c.name));
                      return i >= 0 && bound.cases[i]
                        ? { ...c, ...bound.cases[i]!, name: stillBroken[i]!.name, kind: stillBroken[i]!.kind }
                        : c;
                    });
                    const content = assembleTestFile(feature, parts.imports, merged);
                    const parseBad = !!suiteSyntaxError(content) || !!validateSuiteShape(content).length;
                    const synLeft = caseSyntaxErrors(merged.filter(c => stillBroken.some(b => caseNamesMatch(b.name, c.name)))).length;
                    cands.push({
                      value: merged, temp: t,
                      score: parseBad ? 0 : Math.max(0, stillBroken.length - synLeft),
                      findings: parseBad ? stillBroken.length + 1 : synLeft,
                      label: parseBad ? 'unparseable' : `${stillBroken.length - synLeft}/${stillBroken.length} healed`,
                    });
                  }
                  if (cands.length) {
                    const pick = selectPermutation(cands);
                    metrics.permutationWins++;
                    emit('rha', feature.id, permutationEvent(pick));
                    nextCases = pick.picked.value;
                  }
                }
                parts = { imports: parts.imports, cases: nextCases };
                const contentNext = assembleTestFile(feature, parts.imports, parts.cases);
                if (!validateSuiteShape(contentNext).length && !suiteSyntaxError(contentNext)) {
                  // SET 89 §4.4 v2 — IR-side case regeneration routes
                  // through the gateway. Both the parts AND the bytes
                  // change; the gateway certifies each new case against
                  // stubs and runs the whole-program parse gate before
                  // committing.
                  const res = await commitFrozenPatch(
                    feature, contentNext, parts, 'ir-surgery: case-regen (parse)');
                  if (res && res.status === 'rejected') {
                    emit('rha', feature.id,
                      `IR-side case regeneration rejected by gateway: ${res.report.rejectionReasons[0] ?? 'no reason'} — discarded`);
                  } else {
                    frozen = contentNext;
                    metrics.irSurgeries++;
                    lastAction = 'IR-side case regeneration (suite did not parse)';
                    emit('rha', feature.id, 'suite re-frozen — parses clean');
                    return;
                  }
                } else {
                  emit('rha', feature.id, 'case regeneration still does not parse — discarded');
                }
              } catch (e) {
                emit('rha', feature.id, `IR-side regeneration failed: ${e instanceof Error ? e.message : String(e)}`);
              }
            }
          }

          const persistent = [...failStreak.entries()].filter(([, n]) => n >= 3).map(([n]) => n);
          if (!irSurgeryUsed && parts && pass >= 3 && persistent.length && !errs[0]?.crash) {
            irSurgeryUsed = true;
            const brokenCases = parts.cases
              .filter(c => persistent.some(nm => nm.includes(c.name)))
              .map(c => ({
                name: c.name,
                kind: c.kind as IRCaseGen['kind'],
                errors: errs.filter(e => e.name.includes(c.name)).map(e => e.message.slice(0, 300)),
              }))
              .filter(c => c.errors.length);
            if (brokenCases.length) {
              emit('rha', feature.id, `IR-case surgery: ${brokenCases.length} cases fail every pass — bounded conform-to-stub redraw`);
              try {
                // SET 62 — surgery wins must feed promotion: keep the pre-surgery
                // bodies so the before→after delta is minable at re-freeze.
                const preSurgeryBodies = new Map(parts.cases.map(c => [c.name, c.body]));
                let nextCases = parts.cases.map(c => {
                  if (!brokenCases.some(b => b.name === c.name)) return c;
                  const rebound = rebindCladeBody(c);
                  if (rebound && acceptCaseBody(rebound)) {
                    metrics.mechanicalFixes++;
                    emit('rha', feature.id, `case "${c.name}" rebound via clade (0 tok)`);
                    return { ...c, body: rebound, clade: c.clade ?? classifyCaseClade(c) };
                  }
                  return c;
                });
                const stillBroken = brokenCases.filter(b =>
                  nextCases.find(c => c.name === b.name)?.body === parts!.cases.find(c => c.name === b.name)?.body);
                if (stillBroken.length) {
                  const stillReq = withOracleHints(stillBroken);
                  // SET 95d — hole-only gate rolled to body-repair (single-broken
                  // batches only, same restriction as the 95c canary).
                  const bodyFrame = stillBroken.length === 1
                    ? holeOnlyFrameFor(gates, feature, stillBroken[0]!.name, stillBroken[0]!.kind)
                    : null;
                  const bodyReq = bodyFrame
                    ? stillReq.map(r => ({ ...r, errors: [...r.errors, holeOnlyPromptBlock(bodyFrame)].filter(Boolean) }))
                    : stillReq;
                  const cands: PermutationCandidate<IRCaseGen[]>[] = [];
                  for (let ci = 0; ci < PERMUTATION_TEMPS.length; ci++) {
                    const t = PERMUTATION_TEMPS[ci]!;
                    bail();
                    metrics.permutationDraws++;
                    const fixed = await runLlmAction({
                      method: 'fixTestCases:body-repair-permutation',
                      target: feature.id, phase: 'ir',
                      startEvidence: {
                        temperature: t, candidateIndex: ci + 1,
                        broken: stillBroken.length,
                      },
                      fn: () => opts.llm.fixTestCases(
                        spec, feature, bodyReq, [], parts!.imports,
                        { temperature: t, candidate: { n: ci + 1, k: PERMUTATION_TEMPS.length } },
                      ),
                    });
                    const bound = bindFixTestCases(stillBroken, fixed.cases);
                    metrics.mechanicalFixes += bound.unwrapFixes;
                    if (bodyFrame) {
                      const bodyGate = applyHoleOnlyGate(bodyFrame, bound.cases[0]?.body ?? '', metrics, stillBroken[0]!.name,
                        msg => emit('rha', feature.id, msg));
                      if (bodyGate.rejected) {
                        cands.push({ value: nextCases, temp: t, score: 0, findings: 1, label: 'overreach|body rejected' });
                        continue;
                      }
                      if (bound.cases[0]) bound.cases[0] = { ...bound.cases[0], body: bodyGate.body };
                    }
                    const merged = nextCases.map(c => {
                      const i = stillBroken.findIndex(b => caseNamesMatch(b.name, c.name));
                      return i >= 0 && bound.cases[i]
                        ? { ...c, ...bound.cases[i]!, name: stillBroken[i]!.name, kind: stillBroken[i]!.kind, clade: c.clade }
                        : c;
                    });
                    const content = assembleTestFile(feature, parts.imports, merged);
                    const shapeBad = !!validateSuiteShape(content).length || !!suiteSyntaxError(content);
                    cands.push({
                      value: merged, temp: t,
                      score: shapeBad ? 0 : stillBroken.length,
                      findings: shapeBad ? 1 : 0,
                      label: shapeBad ? 'invalid suite' : `${stillBroken.length} redrawn`,
                    });
                  }
                  if (cands.length) {
                    const pick = selectPermutation(cands);
                    metrics.permutationWins++;
                    emit('rha', feature.id, permutationEvent(pick));
                    nextCases = pick.picked.value;
                  }
                }
                parts = { imports: parts.imports, cases: nextCases };
                // SET 66b — every re-freeze re-runs scaffold-wire; the surgery
                // that dropped injections caused the fix-three-times churn.
                const asmContent = assembleTestFile(feature, parts.imports, parts.cases);
                const content = wireSuiteScaffoldImports(asmContent, feature.testFile, spec).content;
                if (!validateSuiteShape(content).length) {
                  // SET 89 §4.4 v2 — IR-side surgery: gateway commit.
                  const res = await commitFrozenPatch(
                    feature, content, parts, 'ir-surgery: broken-cases');
                  if (res && res.status === 'rejected') {
                    emit('rha', feature.id,
                      `IR-side surgery rejected by gateway: ${res.report.rejectionReasons[0] ?? 'no reason'} — discarded`);
                  } else {
                    frozen = content;
                    metrics.irSurgeries++;
                    metrics.irSurgeriesInRha++;
                    // SET 62 — mine each surged case's delta into the flywheel.
                    for (const b of brokenCases) {
                      const beforeBody = preSurgeryBodies.get(b.name) ?? '';
                      const afterBody = parts.cases.find(c => c.name === b.name)?.body ?? '';
                      if (!afterBody || afterBody === beforeBody) continue;
                      const cls = classifyFailure(b.name, b.errors[0] ?? '');
                      healedInstances.push({
                        classKey: cls.classKey,
                        editShape: `surgery ${distillEditShape(beforeBody, afterBody)}`,
                        beforeSnippet: beforeBody.slice(0, 240),
                        afterSnippet: afterBody.slice(0, 240),
                        path: feature.testFile,
                      });
                    }
                    emit('rha', feature.id, 'suite re-frozen after case surgery');
                    return;
                  }
                } else {
                  emit('rha', feature.id, 'case surgery produced an invalid suite — discarded');
                }
              } catch (e) {
                emit('rha', feature.id, `IR-case surgery failed: ${e instanceof Error ? e.message : String(e)}`);
              }
            }
          }

          const focusCrash = classified.find(c => isCrashClass(c.kind));
          if (focusCrash && !crashRepairPrecondition(focusCrash, artifactFiles(), suiteFile)) {
            if (await parkFeature(focusCrash.classKey)) {
              // SET 31b — boundary heal applied; feature stays alive.
              return;
            }
            return;
          }

          const focus = dominantClass(classified);
          const focusErrs = focus.length
            ? errs.filter(e => e.cls && e.cls.classKey === focus[0].classKey)
            : errs;
          const idioms = checkedIdiomsText(matchLessons(opts.lessons ?? [], focus.map(f => f.classKey)));
          const focusKey = focus[0]?.classKey ?? '';
          // SET 37b — strategy order from empirical strata feeds the oracle hint.
          const strataOrder = focusKey ? strategyOrderForClass(focusKey) : [];
          const oracleHint = [
            formatRepairOracleHint(focusKey),
            strataOrder.length ? `solution-strata order: ${strataOrder.join(' → ')}` : '',
          ].filter(Boolean).join('\n');
          // SET 36f — assertion / throw-mismatch diffs into the repair prompt.
          const assertionDiffs = focusErrs
            .map(e => (e.cls ? formatAssertionDiff(e.cls) : null))
            .filter((x): x is string => !!x);
          let superbufferBlock = '';
          /** SET 34d — template presence for this repair-pass superbuffer. */
          let rhaSbHadTemplates: boolean | null = null;
          /** SET 45c — substrate handoff page presence for this repair-pass. */
          let rhaSbHadSubstratePage: boolean | null = null;
          const focusIsCrash = focus[0] ? isCrashClass(focus[0].kind) : false;

          // SET 37c — mock-API mechanical class: never spend a model call.
          if (focusKey && refusesModelDraw(focusKey)) {
            emit('rha', feature.id,
              `repair skipped: ${focusKey} is mechanical-only (0 model draws)`);
            return;
          }
          // SET 47b — scaffold-owned undefined-symbol → suite-import surgery only.
          if (focusKey && refusesImplRedrawForOwnedSymbol(focusKey, spec)) {
            emit('rha', feature.id,
              `repair skipped: ${focusKey} is suite-scaffold-owned (0 impl draws)`);
            return;
          }

          // SET 101a — stub-not-implemented + body still stub → absence, not defect.
          // Skip L2 (repair-in-place of a stub is regeneration wearing a costume);
          // stall → entropy reset / IR surgery.
          if (focusKey && isStubNotImplementedClass(focusKey)) {
            const symbol = focus[0]?.detail.symbol
              ?? feature.exports[0]?.symbol
              ?? 'unknown';
            const ownerPath = feature.exports.find(e => e.symbol === symbol)?.file
              ?? feature.files[0]
              ?? null;
            const stub = (ownerPath
              ? feature.stubs.find(s => s.path === ownerPath)
              : null) ?? feature.stubs[0];
            const impl = ownerPath
              ? artifactState.get(ownerPath)
              : (stub ? artifactState.get(stub.path) : undefined);
            if (
              stub
              && impl
              && isOwnedSymbolStillStub(impl.content, stub.content, symbol)
            ) {
              metrics.stubRouteShortcuts++;
              emit('rha', feature.id,
                `stub-route: ${symbol} unimplemented — L2 skipped (absence, not defect)`);
              l2Loops.set(focusKey, L2_TEMPS.length);
              return;
            }
          }

          // SET 101d — quarantined file: no L2 until a fresh draw advances the epoch.
          {
            const focusFile = focus[0]?.detail.file
              ?? (/^transpile\|(.+)$/.exec(focusKey)?.[1] ?? null);
            if (focusFile && isFileQuarantined(focusFile)) {
              l2Loops.set(focusKey, L2_TEMPS.length);
              return;
            }
          }

          // SET 36e — after 2 consecutive no-improvement passes on the same
          // finding, escalate batch structure before another identical pass.
          if (
            focusKey
            && focusKey === lastFocusKey
            && noImproveStreak >= 2
            && !batchParams.escalated
          ) {
            batchParams = escalateBatchParams(batchParams);
            emit('rha', feature.id, escalateEntropyEvent(pass, 'spread widened'));
          }

          // SET 64c — flawed-exhibit page on EVERY repair-stage assembly:
          // evidence of the defect, never a base to patch.
          const exhibit = buildFlawedExhibit({
            cls: focus[0] ?? cls0 ?? null,
            files: artifactFiles(),
            symbol: feature.exports[0]?.symbol ?? null,
            fallbackFile: feature.files[0] ?? null,
          });
          // SET 64d — runtime trace for semantic classes: deterministic replay
          // of the failing case's literal-arg calls at the symbol boundary.
          let traceText: string | null = null;
          if (focus[0] && traceEligible(focus[0].kind) && parts) {
            const failCase = parts.cases.find(c =>
              focusErrs.some(e =>
                e.name === c.name
                || e.name.endsWith(`> ${c.name}`)
                || e.name.endsWith(`: ${c.name}`)));
            const traceTarget = feature.exports[0]?.file ?? feature.files[0];
            if (failCase && traceTarget) {
              const calls = extractTraceCalls(failCase.body, feature.exports.map(x => x.symbol));
              traceText = buildTracePage(
                await traceSymbolCallsAsync(artifactFiles(), traceTarget, calls));
            }
          }
          // SET 37e — repair-stage pages on every model repair draw.
          // SET 64 — crash-focus draws get the buffer too (bare-draw gap closed).
          const unionRepair = await synthesizeForDraw('rha', feature.id, artifactFiles());
          // SET 85 — the accumulated observatory: what is EXTANT in this
          // artifact, at the AST level, corroborated across polls.
          await runObservatory(
            artifactFiles(),
            focusErrs.map(e => `${e.name}: ${e.message.split('\n')[0] ?? ''}`).join('\n'),
          );
          {
            const assembly = assembleSuperbuffer({
              spec, feature, parts,
              stubs: feature.stubs,
              lessons: opts.lessons ?? [],
              siblingParts: irPartsByFeature,
              siblingImpls: artifactFiles().filter(f => !feature.files.includes(f.path)),
              target: focusKey || focusErrs[0]?.name || 'freeform',
              stage: 'repair',
              conceptText: conceptByFeature.get(feature.id) ?? null,
              substrateHandoff: substrateHandoffFor(feature.id),
              findingEvidence: [
                ...assertionDiffs,
                ...focusErrs.map(e => e.message.split('\n')[0] ?? ''),
              ].filter(Boolean).join('\n'),
              exhibitText: exhibit?.text ?? null,
              traceText,
              // SET 75 — supergit READ-BACK: the causal trail that produced
              // this finding, straight out of the ledger (0 tok). The run's
              // own history finally conditions its repairs.
              ledgerText: (() => {
                const anchorNode = errorNodeByFeature.get(feature.id)
                  ?? supergit.lastNodeFor(feature.id);
                if (!anchorNode) return null;
                const chain = supergit.lineage(anchorNode, 6);
                if (!chain.length) return null;
                const blast = supergit.downstream(specNodeByFeature.get(feature.id) ?? '');
                return [
                  'Page ledger — supergit causal trail for this node (append-only decision history):',
                  ...chain,
                  blast.length ? `blast radius: ${blast.length} downstream node(s)` : '',
                ].filter(Boolean).join('\n');
              })(),
              unionText: unionRepair,
              signature: feature.exports[0]
                ? {
                  name: feature.exports[0].symbol,
                  params: [],
                  returnType: 'unknown',
                }
                : null,
            });
            superbufferBlock = emitSuperbufferAssembly('rha', feature.id, assembly, 'repair');
            if (!focusIsCrash) {
              rhaSbHadTemplates = assembly.templates.length > 0;
              rhaSbHadSubstratePage = !!assembly.pages.substrate;
            }
          }
          if (!boundedNodeIds.has(feature.id)) {
            boundedNodeIds.add(feature.id);
            metrics.boundedLoopNodes++;
          }
          metrics.boundedLoopIterations++;

          // SET 64 — L2 schema-guided interpretation: the LLM as procedure
          // executor over a classified finding without a mechanical handler.
          // K=1 per loop, ≤3 loops per classKey, temps 0.3→0.7→1.0. Bullseye
          // exit when the focused finding resolves; strict improvement keeps
          // the gain and re-enters at L1 (next measure). L3 permutation runs
          // only after L2 exhausts its loops for the current focus.
          const l2Used = l2Loops.get(focusKey) ?? 0;
          if (focusKey && l2Used < L2_TEMPS.length) {
            l2Loops.set(focusKey, l2Used + 1);
            const l2Temp = L2_TEMPS[l2Used]!;
            const preScoreL2 = Math.max(0, lastTotal - errs.length);
            // SET 101c — finding hash before the pass; unchanged + no-improvement → escalate.
            const preFindingHash = focusErrs
              .map(e => `${e.name}|${e.message.split('\n')[0] ?? ''}`)
              .sort()
              .join('~');
            // SET 80 — NODE-COMPLIANT REPAIR on the first L2 loop: the node
            // itself, its derived schema, and all three substrata, with an
            // explicit instruction to repair IN PLACE. Loops 2–3 keep the
            // exhibit-framed rewrite-from-contract form, so anti-anchoring
            // remains available when editing in place fails.
            const ownedNode = feature.files
              .map(fp => artifactState.get(fp))
              .find((f): f is GeneratedFile => f != null);
            const nodeCompliant = l2Used === 0 && !!ownedNode;
            let nodeDossier: ReturnType<typeof buildNodeRepairDossier> | null = null;
            if (nodeCompliant && ownedNode) {
              const nodeSchema = buildNodeSchema(feature, parts, depContextOf(feature));
              const focusSymbols = [
                ...new Set([
                  ...focusErrs.map(e => e.cls?.detail.symbol).filter((x): x is string => !!x),
                  ...feature.exports.map(x => x.symbol),
                ]),
              ];
              nodeDossier = buildNodeRepairDossier({
                schema: nodeSchema,
                source: ownedNode.content,
                focusSymbols,
                substrate: [
                  `classified as ${focusKey} (${focus[0]?.kind ?? 'unknown'}, stratum ${focus[0]?.stratum ?? 'uncataloged'})`,
                  oracleHint,
                  idioms,
                ].filter(Boolean).join('\n'),
                ledger: (() => {
                  const anchorNode = errorNodeByFeature.get(feature.id) ?? supergit.lastNodeFor(feature.id);
                  return anchorNode ? supergit.lineage(anchorNode, 6).join('\n') : '';
                })(),
                supercache: superbufferBlock,
                findings: [
                  ...assertionDiffs,
                  ...focusErrs.map(e => e.message.split('\n')[0] ?? ''),
                  ...intentAddenda.map(t => `licensed intent addendum: ${t}`),
                ].filter(Boolean).join('\n'),
              });
              metrics.nodeRepairDraws++;
              emit('rha', feature.id,
                formatNodeRepairEvent(ownedNode.path, nodeDossier.whole, focusSymbols));
            }
            const dossier = nodeDossier ? nodeDossier.text : [
              'L2 procedure dossier — schema-guided interpretation. Execute the playbook below against the finding; do not ideate beyond it.',
              `bug schema: classKey=${focusKey}; kind=${focus[0]?.kind ?? 'unknown'}; stratum=${focus[0]?.stratum ?? '(uncataloged)'}${focus[0]?.templateId ? `; template=${focus[0].templateId}` : ''}`,
              oracleHint,
              ...assertionDiffs,
              ...intentAddenda.map(t => `licensed intent addendum: ${t}`),
              idioms,
              superbufferBlock,
              [...tabu].slice(-15).join('\n'),
            ].filter(Boolean).join('\n\n');
            metrics.l2Draws++;
            metrics.repairDraws++;
            metrics.candidatesDrawn++;
            metrics.repairCandidatesDrawn++;
            lastAction = `L2 procedure loop ${l2Used + 1}/${L2_TEMPS.length} on ${focusKey}`;
            emit('rha', feature.id,
              `L2 procedure loop ${l2Used + 1}/${L2_TEMPS.length} [${focusKey}] t=${l2Temp} (K=1)`);
            const l2Input: RepairInput = {
              spec,
              feature,
              findings: findingsOf(focusErrs),
              parallelInstances: [],
              frozenTest: frozen!,
              // SET 80 — the node IS supplied on the node-compliant loop.
              ownedFiles: nodeCompliant && ownedNode ? [ownedNode] : [],
              dependencyContext: depContextOf(feature),
              failureOutput: dossier,
              attempt: pass,
              lineage: [`tier1 L2 loop ${l2Used + 1}: ${focusKey}`],
            };
            // SET 89 §9.4 v3 — L2 trial: snapshot the WHOLE artifact map,
            // let `applyFiles` mutate through `artifactState`, and restore
            // in `finally` regardless of return / throw / early-exit. The
            // `committedL2` guard flips to `true` ONLY after adoption
            // succeeds; every other exit rolls back to `snapL2`.
            //
            // Under the old try/catch, if control flow ever returned
            // before `restoreL2()` was called (a later refactor could
            // introduce that), the trial would leave mutations in the
            // artifact. The finally makes that impossible.
            const snapL2 = artifactState.files();
            let committedL2 = false;
            // SET 89 §11 — candidate trial is distinct from the LLM draw and
            // from adoption. Trial always restores; adoption is separate.
            const l2CandidateId = artifactState.allocateCandidateId();
            const l2TrialActionId = actionLedger.startAction({
              kind: 'candidate-trial',
              target: feature.id,
              phase: 'rha',
              beforeSignature: artifactState.signature(),
              relatedCandidateIds: [l2CandidateId],
              startEvidence: { layer: 'L2', focusKey, temperature: l2Temp },
            });
            let l2TrialDisposition: 'applied' | 'rejected' | 'failed' = 'rejected';
            let l2TrialError: unknown;
            try {
              // SET 89 §11.2 — L2 repair draw is a token action; success
              // propagates the model output back to the trial logic.
              const { result: fresh } = await actionLedger.runAction({
                kind: 'llm:repair:L2',
                target: feature.id,
                phase: 'rha',
                relatedCandidateIds: [l2CandidateId],
                startEvidence: {
                  temperature: l2Temp, pass, focusKey,
                  nodeCompliant, purposeLabel: 'L2 procedure',
                },
                fn: () => opts.llm.repair(l2Input, {
                  temperature: l2Temp,
                  candidate: { n: 1, k: 1 },
                  attempt: pass,
                  attemptLabel: 'pass',
                  purpose: `L2 procedure: ${focusKey}`,
                }),
              });
              const h = drawHashForFiles(fresh.filter(f => feature.files.includes(f.path)));
              const corpse = corpseCheck(h, runDrawHashes, metaCorpseHashes);
              if (corpse) {
                noteCorpseRejection('rha', feature.id, focusKey);
                metrics.fixesUnsuccessful++;
                emit('rha', feature.id, formatCorpseEvent(focusKey, corpse)
                  + (l2Used + 1 >= L2_TEMPS.length ? ' (L2 exhausted → L3 permutation next)' : ''));
                if (!batchParams.escalated) batchParams = escalateBatchParams(batchParams);
                return;
              }
              runDrawHashes.add(h);
              await applyFiles(fresh);
              const r = await opts.runSuite!(artifactFiles(), { path: feature.testFile, content: frozen! });
              const post = classifyMeasure(feature, r, frozen!);
              const focusGone = !r.crashed && !post.some(e => e.cls?.classKey === focusKey);
              const score = r.crashed ? 0 : Math.max(0, r.total - r.failures.length);
              noteMetaCandidate({
                classKey: focusKey, layer: 'L2', temp: l2Temp, score,
                findings: r.crashed ? 1 : r.failures.length,
                parseStatus: r.crashed ? 'crashed' : 'parsed',
                hash: h,
                exhibitHash: exhibit?.hash,
                // SET 77 — the shape itself, not just its score.
                body: fresh.filter(f => feature.files.includes(f.path))
                  .map(f => f.content).join('\n').slice(0, 400),
              });
              if (focusGone || isStrictImprovement(score, preScoreL2)) {
                // Adoption is a two-step commit: first roll back the
                // trial, then re-apply as a vetted permanent write.
                // `committedL2` flips only AFTER the vetted apply
                // returns; if the vetted apply throws, `finally` rolls
                // the whole thing back — the winner attempt lost.
                artifactState.restoreSnapshot(snapL2);
                l2TrialDisposition = 'applied';
                actionLedger.finishAction({
                  actionId: l2TrialActionId,
                  disposition: 'applied',
                  afterSignature: artifactState.signature(),
                  endEvidence: { selected: true, score, focusGone },
                });
                await applyFiles(fresh, { vet: true, label: 'L2 winner' });
                committedL2 = true;
                metrics.l2Wins++;
                metrics.fixesL2++;
                if (nodeCompliant) metrics.nodeRepairWins++;
                // SET 74 — supergit: repair node, caused by the finding.
                supergit.recordNode({
                  type: 'repair', featureId: feature.id,
                  causeId: errorNodeByFeature.get(feature.id) ?? null,
                  artifactPath: feature.files[0] ?? null,
                  // SET 89 §10.4 — repair attempt only. The resolution row
                  // is written by defectRegistry.reconcileMeasurementScope
                  // after the next authoritative measurement confirms it.
                  bugClass: focusKey, status: 'info',
                  summary: `L2 schema-guided repair applied (loop ${l2Used + 1}, t=${l2Temp}; candidate ${l2CandidateId})`,
                });
                metrics.candidatesAccepted++;
                // SET 89 §8.4 — bounded-repair adopted candidate.
                metrics.repairCandidatesAccepted++;
                noImproveStreak = 0;
                lastFocusKey = focusKey;
                if (focusGone) {
                  metrics.l2Bullseyes++;
                  batchParams = defaultBatchParams();
                  emit('rha', feature.id,
                    `L2 bullseye: ${focusKey} resolved (loop ${l2Used + 1}, ${score}/${r.total} passing)`);
                } else {
                  emit('rha', feature.id,
                    `L2 improvement kept: ${score}/${r.total} passing — re-enters L1`);
                }
                return;
              }
              // Trial rejected — restore happens in `finally`.
              metrics.fixesUnsuccessful++;
              if (focusKey === lastFocusKey) noImproveStreak++;
              else { lastFocusKey = focusKey; noImproveStreak = 1; }
              const postFindingHash = (r.crashed
                ? [`__suite__|${(r.crashed.split('\n')[0] ?? '')}`]
                : post.map(e => `${e.name}|${e.message.split('\n')[0] ?? ''}`)
              ).sort().join('~');
              emit('rha', feature.id,
                `L2 loop ${l2Used + 1}/${L2_TEMPS.length} no improvement — incumbent kept`
                + (l2Used + 1 >= L2_TEMPS.length ? ' (L2 exhausted → L3 permutation next)' : ''));
              // SET 101c — pass 1 no-improvement + unchanged finding hash → skip passes 2/3.
              // Exhaust the L2 budget and return; the next converge pass enters L3.
              if (l2Used === 0 && preFindingHash === postFindingHash) {
                l2Loops.set(focusKey, L2_TEMPS.length);
                metrics.l2ShortCircuits++;
                emit('rha', feature.id, 'L2 short-circuit: world unchanged — escalating');
              }
              return;
            } catch (e) {
              // Restore happens in `finally`; here we only surface the
              // failure so the operator sees the ladder decision.
              l2TrialDisposition = 'failed';
              l2TrialError = e;
              metrics.fixesUnsuccessful++;
              emit('rha', feature.id, `L2 draw failed: ${e instanceof Error ? e.message : String(e)}`);
              return;
            } finally {
              if (!committedL2) artifactState.restoreSnapshot(snapL2);
              // Terminalize the trial unless the winner path already did.
              const l2AlreadyDone = actionLedger.snapshot().terminals
                .some(t => t.actionId === l2TrialActionId);
              if (!l2AlreadyDone) {
                actionLedger.finishAction({
                  actionId: l2TrialActionId,
                  disposition: l2TrialDisposition,
                  failureMode: l2TrialDisposition === 'failed' ? 'fatal' : undefined,
                  error: l2TrialError,
                  afterSignature: artifactState.signature(),
                  endEvidence: { restored: !committedL2, candidateId: l2CandidateId },
                });
              }
            }
          }

          // SET 68 — judgment gate: a semantic finding survived L1 AND L2,
          // and the intent-oracle license lookup finds no chain. That is a
          // spec DECISION, not a bug — surfaced to the operator (supervised)
          // or ruled ONCE by a fresh decoupled LLM instance (unsupervised).
          // Never triggered by mere difficulty; ≤1 gate per case. Rulings
          // never bypass mechanical validators.
          if (
            opts.onJudgment
            && focus[0]
            && (focus[0].kind === 'assertion' || focus[0].kind === 'throw-mismatch')
            && parts
          ) {
            // The gate targets the first UNLICENSED disputed case among the
            // focus findings — licensed cases stay in the mechanical ladder.
            // Exact-name attribution (SET 66 lesson): a short case name must
            // never be vouched into a sibling's failure title.
            const errOwns = (errName: string, caseName: string): boolean =>
              errName === caseName
              || errName.endsWith(`> ${caseName}`)
              || errName.endsWith(`: ${caseName}`);
            const disputed = (() => {
              for (const c of parts!.cases) {
                const err = focusErrs.find(e => errOwns(e.name, c.name));
                if (!err || judgedCases.has(c.name)) continue;
                const ch = licenseChainFor({
                  caseName: c.name,
                  expected: err.cls?.detail.expected ?? focus[0]!.detail.expected,
                  feature,
                  prompt: opts.rawPrompt ?? opts.prompt,
                });
                if (!ch.licensed) return { judgeCase: c, chain: ch, err };
              }
              return null;
            })();
            if (disputed) {
              const { judgeCase, chain } = disputed;
              {
                judgedCases.add(judgeCase.name);
                metrics.judgmentGates++;
                const dtl = disputed.err.cls?.detail ?? focus[0].detail;
                const evidence: JudgmentEvidence = {
                  featureId: feature.id,
                  caseName: judgeCase.name,
                  classKey: focusKey,
                  assertion: judgeCase.body.slice(0, 400),
                  expected: dtl.expected,
                  received: dtl.received,
                  exhibit: exhibit?.text,
                  trace: traceText ?? undefined,
                  licenseSearch: chain.searched,
                };
                emit('rha', feature.id,
                  `judgment gate: case "${judgeCase.name}" [${focusKey}] — ${chain.searched}`);
                // SET 89 §11.2 / §11.3 — the judgment is a structured
                // action. A resolver throw is nonfatal (the ladder can
                // continue without a ruling), but the failure MUST be
                // recorded so the operator sees it. We open/close the
                // ledger action manually here so TS's control-flow
                // narrowing on `decision` survives (a closure-mutated
                // variable widens back to its declared type — which is
                // what we want, but TS also loses the "assigned once"
                // signal that the discriminated union relies on).
                const judgmentActionId = actionLedger.startAction({
                  kind: 'judgment',
                  target: judgeCase.name,
                  phase: 'rha',
                  startEvidence: {
                    featureId: feature.id, focusKey,
                    caseKind: focus[0].kind,
                  },
                });
                let decision: JudgmentDecision | null | undefined;
                try {
                  decision = await opts.onJudgment(evidence);
                  actionLedger.finishAction({
                    actionId: judgmentActionId,
                    disposition: decision ? 'applied' : 'noop',
                    endEvidence: {
                      decisionAction: decision?.action ?? null,
                      source: decision?.source ?? null,
                    },
                  });
                } catch (e) {
                  actionLedger.finishAction({
                    actionId: judgmentActionId,
                    disposition: 'failed',
                    failureMode: 'nonfatal',
                    error: e,
                  });
                  emit('rha', feature.id,
                    `judgment resolver failed nonfatally (see action ledger) — ladder continues`);
                }
                if (decision) {
                  const ts = new Date().toISOString();
                  if (decision.source === 'operator') metrics.judgmentOperator++;
                  else metrics.judgmentLlm++;
                  emit('rha', feature.id, formatJudgmentEvent(decision, ts));
                  // Provenance: the ruling is now the case's license.
                  const prov = provenance.find(pv =>
                    pv.featureId === feature.id && pv.caseName === judgeCase.name);
                  if (prov) prov.license = `${prov.license} → ${formatRulingStamp(decision.source, ts)}`;
                  const refreeze = async (nextCases: IRCaseGen[]): Promise<boolean> => {
                    const asm = assembleTestFile(feature, parts!.imports, nextCases);
                    const content = wireSuiteScaffoldImports(asm, feature.testFile, spec).content;
                    if (validateSuiteShape(content).length) return false;
                    const nextParts = { imports: parts!.imports, cases: nextCases };
                    // SET 89 §4.4 v2 — judgment refreeze routes through the
                    // gateway. On rejection the incumbent suite stays
                    // byte-identical and the caller falls back / voids
                    // the ruling.
                    const res = await commitFrozenPatch(
                      feature, content, nextParts, 'judgment: refreeze');
                    if (res && res.status === 'rejected') {
                      emit('rha', feature.id,
                        `judgment refreeze rejected by gateway: ${res.report.rejectionReasons[0] ?? 'no reason'}`);
                      return false;
                    }
                    parts = nextParts;
                    frozen = content;
                    return true;
                  };
                  const dropJudged = async (): Promise<boolean> => {
                    if (!(await refreeze(parts!.cases.filter(c => c.name !== judgeCase.name)))) return false;
                    metrics.judgmentDropped++;
                    emit('rha', feature.id,
                      `judgment: case "${judgeCase.name}" dropped — suite re-frozen (coverage reduced, honest)`);
                    return true;
                  };
                  if (decision.action === 'drop') {
                    if (await dropJudged()) return;
                    emit('rha', feature.id, 'judgment drop produced invalid suite — ruling voided, ladder continues');
                  } else if (decision.action === 'amend') {
                    // SET 72 — every LLM call gets 3 tries: the amend redraw
                    // walks the ladder before falling back to drop.
                    let amended = false;
                    for (let amendTry = 0; amendTry < PERMUTATION_TEMPS.length && !amended; amendTry++) {
                      // SET 95d — hole-only gate rolled to judgment-amend (single-case draw).
                      const jaFrame = holeOnlyFrameFor(gates, feature, judgeCase.name, judgeCase.kind as IRCaseGen['kind']);
                      try {
                        const req = [{
                          name: judgeCase.name,
                          kind: judgeCase.kind as IRCaseGen['kind'],
                          errors: [
                            "JUDGMENT RULING: amend this case to accept the implementation's observed behavior.",
                            dtl.expected != null ? `previously expected: ${dtl.expected}` : '',
                            dtl.received != null ? `observed (accept this): ${dtl.received}` : '',
                            traceText ?? '',
                            holeOnlyPromptBlock(jaFrame),
                          ].filter(Boolean),
                        }];
                        const fixed = await runLlmAction({
                          method: 'fixTestCases:judgment-amend',
                          target: feature.id, phase: 'rha',
                          startEvidence: {
                            temperature: PERMUTATION_TEMPS[amendTry],
                            amendTry: amendTry + 1,
                            caseName: judgeCase.name,
                          },
                          fn: () => opts.llm.fixTestCases(
                            spec, feature, req, [], parts!.imports,
                            {
                              temperature: PERMUTATION_TEMPS[amendTry],
                              candidate: { n: amendTry + 1, k: PERMUTATION_TEMPS.length },
                              purpose: `judgment-amend: ${feature.id}`,
                            },
                          ),
                        });
                        const bound = bindFixTestCases(req.map(r => ({ name: r.name, kind: r.kind })), fixed.cases);
                        const jaGate = applyHoleOnlyGate(jaFrame, bound.cases[0]?.body ?? '', metrics, judgeCase.name,
                          msg => emit('rha', feature.id, msg));
                        if (jaGate.rejected) {
                          emit('rha', feature.id,
                            `judgment amend try ${amendTry + 1}/${PERMUTATION_TEMPS.length}: draw unusable`);
                          continue;
                        }
                        const nb = jaGate.body;
                        if (!nb || !acceptCaseBody(nb) || caseSyntaxErrors([{ name: judgeCase.name, body: nb }]).length) {
                          emit('rha', feature.id,
                            `judgment amend try ${amendTry + 1}/${PERMUTATION_TEMPS.length}: draw unusable`);
                          continue;
                        }
                        const nextCases = parts.cases.map(c =>
                          c.name === judgeCase.name ? { ...c, body: nb } : c);
                        // Containment: the amended case still faces born-red —
                        // an amendment that is vacuous vs stubs is refused.
                        const asm = assembleTestFile(feature, parts.imports, nextCases);
                        const wired = wireSuiteScaffoldImports(asm, feature.testFile, spec).content;
                        const br = await opts.runSuite!(stubArtifact(spec), { path: feature.testFile, content: wired });
                        // Exact-name attribution (SET 66 lesson): a sibling
                        // failure must never vouch for a vacuous amendment.
                        const amendedRed = br.crashed != null
                          || br.failures.some(f =>
                            f.name === judgeCase.name
                            || f.name.endsWith(`> ${judgeCase.name}`)
                            // Assembled titles may carry a kind prefix ("edge: <name>").
                            || f.name.endsWith(`: ${judgeCase.name}`));
                        if (amendedRed && await refreeze(nextCases)) {
                          amended = true;
                          emit('rha', feature.id,
                            `judgment: case "${judgeCase.name}" amended and re-frozen (born-red honest) — re-measuring`);
                          return;
                        }
                        emit('rha', feature.id,
                          `judgment amend try ${amendTry + 1}/${PERMUTATION_TEMPS.length} refused: amended case vacuous vs stubs`);
                      } catch (e) {
                        emit('rha', feature.id,
                          `judgment amend try ${amendTry + 1}/${PERMUTATION_TEMPS.length} failed: ${e instanceof Error ? e.message : String(e)}`);
                      }
                    }
                    emit('rha', feature.id, 'judgment amend exhausted — dropping instead');
                    if (await dropJudged()) return;
                  } else if (decision.action === 'direct' && decision.intentText) {
                    intentAddenda.push(`${decision.intentText} [${formatRulingStamp(decision.source, ts)}]`);
                    // Directed repairs still face strict-improvement; the
                    // addendum re-arms one L2 loop for the focus class.
                    l2Loops.set(focusKey, L2_TEMPS.length - 1);
                    emit('rha', feature.id,
                      'judgment: repair now carries the licensed intent addendum — ladder continues directed');
                    return;
                  }
                }
              }
            }
          }

          lastAction = `LLM repair pass ${pass} (permutation) on ${focus[0]?.classKey ?? 'all'}`;
          emit('rha', feature.id,
            `repair pass ${pass}: ${focusErrs.length}/${errs.length} findings`
            + `${focus[0] ? ` [${focus[0].classKey}]` : ''}${idioms ? ' + checked idioms' : ''}`
            + `${superbufferBlock ? ' + superbuffer' : ''}, permutation K=${batchParams.k}`);
          const input: RepairInput = {
            spec,
            feature,
            findings: findingsOf(focusErrs),
            parallelInstances: [],
            frozenTest: frozen!,
            ownedFiles: [],
            dependencyContext: depContextOf(feature),
            failureOutput: [
              oracleHint,
              ...assertionDiffs,
              ...intentAddenda.map(t => `licensed intent addendum: ${t}`),
              superbufferBlock,
              idioms,
              [...tabu].slice(-30).join('\n'),
            ].filter(Boolean).join('\n\n'),
            attempt: pass,
            lineage: [`tier1 authenticate pass ${pass}: ${errs.length} findings`],
          };
          // SET 89 §9.4 v3 — L3 permutation trial: snapshot / restore
          // the whole artifact via `artifactState`. Owned mutations still
          // go through `commitWrites`; restore is atomic AND guaranteed
          // via `finally` so a stray `return` inside the try can never
          // leave a trial mutation live.
          const snap = artifactState.files();
          const restoreOwned = () => { artifactState.restoreSnapshot(snap); };
          const cands: PermutationCandidate<GeneratedFile[]>[] = [];
          const candCrashSigs: (string | null)[] = [];
          const preScore = Math.max(0, lastTotal - errs.length);
          const incumbentCrashSig = errs[0]?.crash
            ? normalizeCrashSignature(errs[0].message)
            : null;
          // Adoption guard: only flips to `true` after a winner has been
          // permanently committed. Every other exit (rejection, crash,
          // early return, external-fault path) leaves this `false`, and
          // `finally` rolls back the trial artifact.
          let committedL3 = false;
          try {
            metrics.permBatches++;
            for (let ci = 0; ci < batchParams.k; ci++) {
              const t = batchParams.temps[ci] ?? batchParams.temps[batchParams.temps.length - 1]!;
              bail();
              restoreOwned();
              metrics.permutationDraws++;
              metrics.permCandidates++;
              metrics.candidatesDrawn++;
              metrics.repairCandidatesDrawn++;
              metrics.repairDraws++;
              // SET 89 §11.2 — L3 permutation draw is a token action; each
              // candidate in the batch gets its own start/terminal pair so
              // replay reveals per-candidate timings and dispositions.
              const { result: freshRaw } = await actionLedger.runAction({
                kind: 'llm:repair:L3',
                target: feature.id,
                phase: 'rha',
                startEvidence: {
                  temperature: t, pass, focusKey: focusKey || 'all',
                  candidateIndex: ci + 1, batchK: batchParams.k,
                  batchTempsEscalated: batchParams.escalated,
                },
                fn: () => opts.llm.repair(input, {
                  temperature: t,
                  candidate: { n: ci + 1, k: batchParams.k },
                  attempt: pass,
                  attemptLabel: 'pass',
                  purpose: focusKey || 'all',
                }),
              });
              let fresh = freshRaw;
              // SET 64 — corpse detection: identical draw is rejected WITHOUT
              // execution, and the batch escalates (forced escalation).
              const l3Hash = drawHashForFiles(fresh.filter(f => feature.files.includes(f.path)));
              const l3Corpse = corpseCheck(l3Hash, runDrawHashes, metaCorpseHashes);
              if (l3Corpse) {
                noteCorpseRejection('rha', feature.id, focusKey);
                metrics.fixesUnsuccessful++;
                emit('rha', feature.id, formatCorpseEvent(focusKey, l3Corpse));
                if (!batchParams.escalated) batchParams = escalateBatchParams(batchParams);
                continue;
              }
              runDrawHashes.add(l3Hash);
              await applyFiles(fresh); // trial write — restored between candidates
              let r = await opts.runSuite!(artifactFiles(), { path: feature.testFile, content: frozen! });
              if (r.crashed && /transpile |Invalid or unexpected token|Unexpected token|Invalid regular expression/i.test(r.crashed)) {
                let polished = false;
                fresh = fresh.map(f => {
                  const syn = suiteSyntaxError(f.content);
                  const crashHint = syn ?? r.crashed!;
                  if (!syn && !/Invalid|Unexpected/i.test(r.crashed!)) return f;
                  const p = polishParseCrashContent(f.path, f.content, crashHint);
                  if (!p) return f;
                  polished = true;
                  return { ...f, content: p.content };
                });
                if (polished) {
                  await applyFiles(fresh);
                  r = await opts.runSuite!(artifactFiles(), { path: feature.testFile, content: frozen! });
                  if (!r.crashed || !/transpile |Invalid or unexpected token|Unexpected token/i.test(r.crashed)) {
                    // SET 89 §9.1 — polish is a deterministic edit,
                    // NOT an `attemptMechanicalFix` outcome.
                    metrics.mechanicalFixes++;
                    metrics.deterministicEditsOutsideSubstrate++;
                    emit('rha', feature.id, `substrate: polished permutation candidate t=${t} (0 tok)`);
                  }
                }
                // SET 57a — candidate remained parse-crashed after polish attempt.
                if (r.crashed && /transpile |Invalid or unexpected token|Unexpected token|Invalid regular expression/i.test(r.crashed)) {
                  metrics.fixesUnparseable++;
                  noteRunError('parse');
                }
              }
              const findings = r.crashed ? 1 : r.failures.length;
              const score = r.crashed ? 0 : Math.max(0, r.total - r.failures.length);
              candCrashSigs.push(r.crashed ? normalizeCrashSignature(r.crashed) : null);
              cands.push({
                value: fresh, temp: t, score, findings,
                label: r.crashed ? 'crashed' : `${score}/${r.total} passing`,
              });
              // SET 64 — metasupercache candidate record for this L3 draw.
              noteMetaCandidate({
                classKey: focusKey || 'freeform', layer: 'L3', temp: t, score, findings,
                parseStatus: r.crashed
                  ? (/transpile |Invalid or unexpected token|Unexpected token/i.test(r.crashed) ? 'unparseable' : 'crashed')
                  : 'parsed',
                hash: l3Hash,
                exhibitHash: exhibit?.hash,
                body: fresh.filter(f => feature.files.includes(f.path))
                  .map(f => f.content).join('\n').slice(0, 400),
              });
            }
            // SET 20d — incumbent + all K candidates share crash signature → external fault.
            if (
              incumbentCrashSig
              && cands.length > 0
              && candCrashSigs.length === cands.length
              && candCrashSigs.every(s => s === incumbentCrashSig)
            ) {
              restoreOwned();
              emit('rha', feature.id, 'external-fault inferred');
              await detectAndQuarantine();
              return;
            }
            if (cands.length) {
              const pick = selectPermutation(cands);
              metrics.permutationWins++;
              // SET 35c — replace incumbent ONLY on strictly better fitness.
              if (!isStrictImprovement(pick.picked.score, preScore)) {
                restoreOwned();
                metrics.fixesUnsuccessful++;
                emit('rha', feature.id, permutationEvent(pick));
                emit('rha', feature.id, incumbentKeptEvent(pass));
                if (rhaSbHadTemplates != null) noteSbEfficacy(rhaSbHadTemplates, false);
                if (rhaSbHadSubstratePage != null) {
                  noteSubstratePageEfficacy(sbPageEff, rhaSbHadSubstratePage, false);
                }
                // SET 36e — track identical-finding no-improvement streak.
                if (focusKey === lastFocusKey) noImproveStreak++;
                else { lastFocusKey = focusKey; noImproveStreak = 1; }
              } else {
                metrics.permImproved++;
                metrics.candidatesAccepted++;
                // SET 89 §8.4 — bounded-repair adopted candidate.
                metrics.repairCandidatesAccepted++;
                metrics.fixesL3++;
                supergit.recordNode({
                  type: 'repair', featureId: feature.id,
                  causeId: errorNodeByFeature.get(feature.id) ?? null,
                  artifactPath: feature.files[0] ?? null,
                  // SET 89 §10.4 — the adoption of a permutation winner is
                  // an APPLIED repair, not a resolution. Only a confirming
                  // measurement can resolve a defect; that measurement
                  // emits a `type: 'resolution'` node via the registry.
                  bugClass: focusKey || null, status: 'info',
                  summary: `L3 permutation winner applied (t=${pick.picked.temp}, ${pick.picked.label})`,
                });
                emit('rha', feature.id, permutationEvent(pick));
                // Adoption: roll back the last trial, apply the winner
                // as a vetted permanent write, then flip the guard so
                // `finally` DOES NOT restore over the adopted content.
                restoreOwned();
                await applyFiles(pick.picked.value, { vet: true, label: 'repair winner' });
                committedL3 = true;
                noImproveStreak = 0;
                lastFocusKey = focusKey;
                batchParams = defaultBatchParams();
                if (superbufferBlock) {
                  metrics.superbufferWins++;
                  const pk = freeformPatternKey({ classKey: focusKey, caseName: focusErrs[0]?.name });
                  const n = (freeformWinCounts.get(pk) ?? 0) + 1;
                  freeformWinCounts.set(pk, n);
                  if (shouldProposeCladePromotion(n)) {
                    const proposal = draftCladePromotion({
                      patternKey: pk,
                      featureId: feature.id,
                      wins: n,
                      stubSketch: feature.stubs[0]?.content,
                      source: 'in-run-win',
                    });
                    opts.onCladeCandidate?.(proposal);
                    emit('rha', feature.id, formatCladeCandidateMessage(proposal));
                  }
                }
                // SET 34d — repair-pass superbuffer efficacy sample.
                if (rhaSbHadTemplates != null) {
                  noteSbEfficacy(rhaSbHadTemplates, true);
                }
                // SET 45c — substrate-page efficacy sample.
                if (rhaSbHadSubstratePage != null) {
                  noteSubstratePageEfficacy(sbPageEff, rhaSbHadSubstratePage, true);
                }
              }
            }
          } catch (e) {
            // Restore happens in `finally`.
            metrics.fixesUnsuccessful++;
            emit('rha', feature.id, `repair draw failed: ${e instanceof Error ? e.message : String(e)}`);
          } finally {
            if (!committedL3) artifactState.restoreSnapshot(snap);
          }
        },
        onStall: async (errs, pass) => {
          // SET 20e — crash-like stalls reset only when attributed to an owned file
          // (no naked redraw against a foreign/unattributed collision). Assertion-only
          // stalls remain eligible — the feature's own behavior is under test.
          const crashLike = errs.filter(e =>
            e.crash
            || e.cls?.kind === 'crash'
            || e.cls?.kind === 'transpile'
            || e.cls?.kind === 'duplicate-decl'
            || e.cls?.kind === 'regex-literal',
          );
          if (crashLike.length > 0) {
            const attributedOwned = crashLike.some(e => {
              const f = e.cls?.detail.file;
              return !!f && feature.files.includes(f);
            });
            if (!attributedOwned) {
              emit('rha', feature.id,
                `entropy reset skipped @ pass ${pass}: failure not attributed to owned file`);
              return false;
            }
          }
          emit('rha', feature.id, `entropy reset @ pass ${pass}: fresh implementation from frozen contract`);
          try {
            metrics.freshDraws++;
            const resetSb = assembleSuperbuffer({
              spec, feature, parts,
              stubs: feature.stubs,
              lessons: opts.lessons ?? [],
              siblingParts: irPartsByFeature,
              siblingImpls: artifactFiles().filter(f => !feature.files.includes(f.path)),
              target: `entropy-reset|${feature.id}`,
              stage: 'build',
              conceptText: conceptByFeature.get(feature.id) ?? null,
              signature: feature.exports[0]
                ? { name: feature.exports[0].symbol, params: [], returnType: 'unknown' }
                : null,
            });
            // SET 72 — every LLM call gets 3 tries: a corpse or vet-rejected
            // reset draw retries hotter instead of ending the ladder.
            const RESET_TRY_TEMPS = [1.0, 1.1, ESCALATED_TEMP] as const;
            for (let resetTry = 0; resetTry < RESET_TRY_TEMPS.length; resetTry++) {
              const resetTemp = RESET_TRY_TEMPS[resetTry]!;
              // SET 89 §11.2 — L4 entropy-reset draw is a token action.
              // A provider throw here bubbles out to the enclosing
              // try/catch that owns the reset-ladder abandonment path.
              const { result: fresh } = await actionLedger.runAction({
                kind: 'llm:generateImplementation:entropy-reset',
                target: feature.id,
                phase: 'rha',
                startEvidence: {
                  temperature: resetTemp, pass, tryIndex: resetTry + 1,
                },
                fn: () => opts.llm.generateImplementation(
                  spec, feature, frozen!, depContextOf(feature),
                  {
                    temperature: resetTemp,
                    avoid: [...tabu].slice(-20).map(t => `- ${t}`).join('\n'),
                    // SET 95d — see the build-site comment: contract stays
                    // whole-file GeneratedFile[]; hole-only instruction is
                    // advisory, the enforced gate is the content-level check below.
                    context: gates.holeOnlyFill
                      ? [formatSuperbufferForPrompt(resetSb), BUILD_SYSTEM_HOLE].join('\n\n')
                      : formatSuperbufferForPrompt(resetSb),
                    purpose: `entropy reset: ${feature.files.join(', ')}`,
                    attempt: pass,
                    attemptLabel: 'pass',
                    candidate: { n: resetTry + 1, k: RESET_TRY_TEMPS.length },
                  },
                ),
              });
              // SET 95d — build overreach gate (same content-level check as
              // the build phase): a reset draw's owned file must not carry
              // test-scaffolding tokens.
              if (gates.holeOnlyFill) {
                const leaking = fresh.filter(f => feature.files.includes(f.path) && isBuildOverreach(f.content).over);
                if (leaking.length) {
                  for (const f of leaking) {
                    metrics.overreachBodyRejections++;
                    emit('rha', feature.id, `case "${f.path}" rejected overreach|body: ${isBuildOverreach(f.content).reason}`);
                  }
                  emit('rha', feature.id,
                    `entropy reset rejected @ pass ${pass}: overreach|body`
                    + (resetTry < RESET_TRY_TEMPS.length - 1 ? ` — reset retry ${resetTry + 2}/${RESET_TRY_TEMPS.length}` : ''));
                  continue;
                }
              }
              // SET 64 — corpse detection on the reset draw: identical fresh
              // implementation is rejected without vet/execution.
              const resetHash = drawHashForFiles(fresh.filter(f => feature.files.includes(f.path)));
              const resetCorpse = corpseCheck(resetHash, runDrawHashes, metaCorpseHashes);
              if (resetCorpse) {
                noteCorpseRejection('rha', feature.id, errs[0]?.cls?.classKey ?? 'entropy-reset');
                metrics.fixesUnsuccessful++;
                emit('rha', feature.id, formatCorpseEvent(errs[0]?.cls?.classKey ?? 'entropy-reset', resetCorpse)
                  + (resetTry < RESET_TRY_TEMPS.length - 1 ? ` — reset retry ${resetTry + 2}/${RESET_TRY_TEMPS.length} (t=${RESET_TRY_TEMPS[resetTry + 1]})` : ''));
                continue;
              }
              runDrawHashes.add(resetHash);
              noteMetaCandidate({
                classKey: errs[0]?.cls?.classKey ?? 'entropy-reset',
                layer: 'L4', temp: resetTemp, score: 0, findings: errs.length,
                parseStatus: 'parsed',
                hash: resetHash,
                body: fresh.filter(f => feature.files.includes(f.path))
                  .map(f => f.content).join('\n').slice(0, 400),
              });
              // SET 36c / 47a — full vet gate; GATE_UNAVAILABLE fails OPEN.
              const owned = fresh.filter(f => feature.files.includes(f.path));
              const base = artifactFiles().filter(f => !owned.some(o => o.path === f.path));
              const { rejected, gateUnavailable } = await vetArtifactWritesAsync(owned, base);
              if (gateUnavailable) noteModuleProbeUnavailable('rha', feature.id);
              if (rejected.length) {
                const r0 = rejected[0]!;
                emit('rha', feature.id,
                  `reset draw rejected: ${r0.reason} in ${r0.path}`);
                emit('rha', feature.id,
                  `entropy reset rejected @ pass ${pass}: ${r0.reason} in ${r0.path}`
                  + (resetTry < RESET_TRY_TEMPS.length - 1 ? ` — reset retry ${resetTry + 2}/${RESET_TRY_TEMPS.length}` : ''));
                continue;
              }
              // SET 62 — stash before→after; pushed to the flywheel only if the
              // feature subsequently converges (a reset that didn't heal teaches
              // nothing worth promoting).
              {
                const p0 = owned[0]?.path ?? feature.files[0]!;
                const prev = artifactState.get(p0)?.content ?? '';
                const next = owned[0]?.content ?? '';
                resetHeal.cur = {
                  classKey: errs[0]?.cls?.classKey ?? 'entropy-reset',
                  before: prev,
                  after: next,
                  path: p0,
                };
              }
              await applyFiles(fresh, { vet: true, label: 'reset draw' });
              batchParams = defaultBatchParams();
              noImproveStreak = 0;
              return true;
            }
            return false;
          } catch (e) {
            emit('rha', feature.id, `entropy reset draw failed: ${e instanceof Error ? e.message : String(e)}`);
            return false;
          }
        },
      });

      metrics.passesTotal += outcome.passes;
      metrics.passesPerFeature[feature.id] = outcome.passes;
      for (const e of outcome.errors) {
        // SET 89 §10.5 — the DefectRegistry (upstream, at the `measure`
        // authoritative-measurement site) already owns `bugsRemaining`.
        // The only bookkeeping remaining here is the artifact-fault sig
        // set, which measures a distinct property (one crash signature
        // affecting N features).
        if (e.crash) {
          const sig = normalizeCrashSignature(e.message);
          artifactFaultRemainingSigs.add(sig);
          let set = artifactFaultAffects.get(sig);
          if (!set) { set = new Set(); artifactFaultAffects.set(sig, set); }
          set.add(feature.id);
        }
      }
      // SET 81 — every feature epoch closes with an explicit verdict in
      // successful/total terms (Andy), so the log has a readable boundary
      // between nodes instead of trailing off into the next one's events.
      {
        const failing = outcome.errors.length;
        const total = Math.max(lastTotal, failing);
        const passing = Math.max(0, total - failing);
        emit('auth', feature.id,
          `epoch closed: ${passing}/${total} cases passing`
          + (failing ? ` — ${failing} still failing after ${outcome.passes} pass${outcome.passes === 1 ? '' : 'es'}` : '')
          + (parked.has(feature.id) ? ' (parked: crash unattributed)' : ''));
      }
      if (parked.has(feature.id)) {
        // crash|unattributed already recorded
      } else if (outcome.errors.length) {
        problems.push(
          `${feature.id}: ${describeErrs(outcome.errors, lastTotal)} after ${outcome.passes} passes${outcome.stalled ? ' (stalled)' : ''}`,
        );
        if (outcome.stalled) {
          const pushed = pushDeferredFailure(failureStack, {
            featureId: feature.id,
            caseName: '__feature__',
            kind: 'stalled',
            brokenDraw: '(stalled ladder)',
            parseError: describeErrs(outcome.errors, lastTotal),
            snippet: describeErrs(outcome.errors, lastTotal).slice(0, 80),
          });
          failureStack = pushed.state;
        }
      } else {
        noteNodeHealed(feature.id);
        // SET 62 — the reset healed this node: mine its delta into promotion.
        const heal = resetHeal.cur;
        if (heal && outcome.passes > 0 && heal.after) {
          metrics.fixesL4++;
          supergit.recordNode({
            type: 'repair', featureId: feature.id,
            causeId: errorNodeByFeature.get(feature.id) ?? null,
            // SET 89 §10.4 — the entropy-reset REGENERATES the artifact;
            // it is still a repair attempt whose success requires a later
            // authoritative measurement to confirm. The `resolution` node
            // is emitted by the defectRegistry reconciliation, not here.
            artifactPath: heal.path, bugClass: heal.classKey, status: 'info',
            summary: 'L4 entropy reset applied to the node',
          });
          healedInstances.push({
            classKey: heal.classKey,
            editShape: `reset ${distillEditShape(heal.before, heal.after)}`,
            beforeSnippet: heal.before.slice(0, 240),
            afterSnippet: heal.after.slice(0, 240),
            path: heal.path,
          });
          resetHeal.cur = null;
        }
        emit('auth', feature.id, `converged in ${outcome.passes} pass${outcome.passes === 1 ? '' : 'es'}`);
      }
      await remeasureParked();
    }

    // SET 37a / SET 89 §7 — repair-phase relay: stalled features re-enter
    // AFTER main RHA (up to 3 instances) then one metaloop.
    //
    // SET 89 §7 v2 — HONESTY: the re-entry body is DETERMINISTIC (measure +
    // mechanical/substrate ONLY). No model repair draw is issued here.
    // Older builds emitted "proceeding on fresh entropy" and computed
    // unused batch parameters — that language claimed work no consumer
    // performed. Both are removed. When the world signature is unchanged
    // since the last certified state (all stalled features gated), we
    // emit ONE aggregate decision and skip re-entry entirely (§7.2).
    // When the world IS changed, each re-entry emits an action-scoped
    // start / terminal disposition pair via `formatRelayReenter` +
    // `relay:action`; a terminal disposition is guaranteed per §11.2
    // (`healed | improved | unchanged | blocked | failed | noop`).
    {
      let prevWorld = makeWorldSignature({
        frozenByFeature, lessonKeys: lessonKeysSeen, irPartsByFeature,
      });
      for (let instance = 1; instance <= FAILURE_STACK_INSTANCE_CAP; instance++) {
        const stalledIds = [...new Set(
          problems
            .filter(p => /\(stalled\)/.test(p))
            .map(p => p.split(':')[0]!.trim())
            .filter(Boolean),
        )];
        if (!stalledIds.length) break;
        const nowWorld = makeWorldSignature({
          frozenByFeature, lessonKeys: lessonKeysSeen, irPartsByFeature,
        });
        const delta = worldDelta(prevWorld, nowWorld);
        // SET 89 §7.2 — if EVERY stalled feature is gated for the same
        // "world unchanged" reason, emit ONE aggregate event (naming the
        // set of features) and skip this instance's re-entry cycle.
        // Historical builds emitted per-feature "proceeding on fresh
        // entropy" lines here; those falsely implied model work.
        if (instance > 1) {
          const gates = stalledIds.map(fid => ({
            fid, gate: mayReenter(failureStack, fid, nowWorld),
          }));
          const allWorldUnchanged = gates.length > 0
            && gates.every(g => !g.gate.ok && g.gate.reason === 'world unchanged');
          if (allWorldUnchanged) {
            emit('rha', null,
              `relay: world unchanged since the last certified state — no re-entry for [${stalledIds.join(', ')}]`);
            break;
          }
        }
        let anyReentered = false;
        for (const fid of stalledIds) {
          const gate = mayReenter(failureStack, fid, nowWorld);
          if (!gate.ok && instance > 1) {
            emit('rha', fid, `relay skipped: ${gate.reason ?? 'blocked'}`);
            continue;
          }
          const feature = ordered.find(f => f.id === fid);
          const frozenContent = feature ? frozenByFeature.get(fid) : undefined;
          if (!feature || frozenContent == null || parked.has(fid)) continue;
          // SET 89 §7.3 / §11.2 v3 — every re-entry is now a REAL
          // structured action in the ledger, not a string-only tag. The
          // start ID is used both by the human line (via
          // `renderTerminalLine`) and by the ledger for replay.
          const actionId = actionLedger.startAction({
            kind: 'relay',
            target: fid,
            phase: 'rha',
            startEvidence: {
              instance,
              healsDelta: delta.heals,
              lessonsDelta: delta.lessons,
              siblingsDelta: delta.siblings,
            },
          });
          emit('rha', fid, formatRelayReenter({
            featureId: fid,
            instance,
            healsDelta: delta.heals,
            lessonsDelta: delta.lessons,
            worldChanged: instance === 1 || (delta.heals + delta.lessons + delta.siblings) > 0,
          }) + ` [action:${actionId}]`);
          failureStack = rememberWorld(failureStack, fid, nowWorld);
          anyReentered = true;
          // SET 89 §7.1 — the re-entry body issues NO model draw. This is
          // deterministic re-measurement + substrate only. Historical
          // "freshRelayBatchParams" computation was removed as it was
          // never consumed by any draw.
          bail();
          const r = await opts.runSuite!(artifactFiles(), {
            path: feature.testFile, content: frozenContent,
          });
          if (!r.crashed && r.failures.length === 0) {
            // Clear stalled problem lines.
            for (let i = problems.length - 1; i >= 0; i--) {
              if (problems[i]!.startsWith(`${fid}:`) && /\(stalled\)/.test(problems[i]!)) {
                problems.splice(i, 1);
              }
            }
            noteNodeHealed(fid);
            actionLedger.finishAction({
              actionId, disposition: 'applied',
              endEvidence: { convergence: 'clean', instance },
            });
            emit('auth', fid, actionLedger.renderTerminalLine(actionId));
            continue;
          }
          const errs = classifyMeasure(feature, r, frozenContent);
          const suiteFile: GeneratedFile = { path: feature.testFile, content: frozenContent };
          for (const e of errs) {
            if (!e.cls) continue;
            const attempt = attemptMechanicalFix(e.cls, artifactFiles(), suiteFile, spec);
            metrics.substrateAttempts++;
            recordSubstrateAttempt(e.cls.classKey, attempt, fid);
            if (attempt.status === 'fixed' && attempt.fix) {
              await applyMechFixes(
                (attempt.fixes?.length ? attempt.fixes : [attempt.fix]).map(fx => ({
                  ...fx, classKey: e.cls!.classKey,
                })),
                fid, feature.testFile,
              );
              emit('rha', fid, `relay substrate: ${e.cls.classKey} → fixed (0 tok)`);
            }
          }
          const post = await opts.runSuite!(artifactFiles(), {
            path: feature.testFile,
            content: frozenByFeature.get(fid) ?? frozenContent,
          });
          if (!post.crashed && post.failures.length === 0) {
            for (let i = problems.length - 1; i >= 0; i--) {
              if (problems[i]!.startsWith(`${fid}:`) && /\(stalled\)/.test(problems[i]!)) {
                problems.splice(i, 1);
              }
            }
            noteNodeHealed(fid);
            actionLedger.finishAction({
              actionId, disposition: 'applied',
              endEvidence: { convergence: 'after-mechanical', instance },
            });
            emit('auth', fid, actionLedger.renderTerminalLine(actionId));
          } else {
            // SET 89 §7.3 / §11.2 — every start has exactly one terminal.
            // Deterministic re-entry did not converge; the substrate had
            // its chance and the world is still stalled — disposition is
            // `noop` (no state mutation) or `rejected` (substrate ran
            // but stall persists).
            const unchanged =
              post.failures.length === r.failures.length && post.crashed === r.crashed;
            actionLedger.finishAction({
              actionId,
              disposition: unchanged ? 'noop' : 'rejected',
              endEvidence: {
                convergence: 'unchanged',
                failuresBefore: r.failures.length,
                failuresAfter: post.failures.length,
                crashedBefore: !!r.crashed,
                crashedAfter: !!post.crashed,
              },
            });
            emit('rha', fid, actionLedger.renderTerminalLine(actionId));
          }
        }
        prevWorld = nowWorld;
        if (!anyReentered) break;
      }
      // One metaloop over everything still stalled.
      const stillStalled = [...new Set(
        problems.filter(p => /\(stalled\)/.test(p)).map(p => p.split(':')[0]!.trim()),
      )];
      if (stillStalled.length) {
        emit('rha', null, `relay metaloop: [${stillStalled.join(', ')}]`);
        for (const fid of stillStalled) {
          const feature = ordered.find(f => f.id === fid);
          const frozenContent = feature ? frozenByFeature.get(fid) : undefined;
          if (!feature || frozenContent == null) continue;
          bail();
          const r = await opts.runSuite!(artifactFiles(), {
            path: feature.testFile, content: frozenContent,
          });
          if (!r.crashed && r.failures.length === 0) {
            for (let i = problems.length - 1; i >= 0; i--) {
              if (problems[i]!.startsWith(`${fid}:`) && /\(stalled\)/.test(problems[i]!)) {
                problems.splice(i, 1);
              }
            }
            emit('auth', fid, 'relay metaloop converged');
          }
        }
      }
    }

    // ── SET 70 — case-relay: warm-world refill of re-enqueued cases ──────
    // Every sibling suite is frozen and every impl is built; the cases that
    // failed to fill against a cold world get single-target draws now.
    // Adoption is conservative: the candidate must be red-vs-stubs (not
    // vacuous) AND green against the current artifact; otherwise final drop
    // with the original lineage-parseable message.
    if (endOfRunCaseStack.length) {
      emit('rha', null,
        `case-relay: ${endOfRunCaseStack.length} re-enqueued case(s) — warm-world refill`);
      for (const entry of endOfRunCaseStack) {
        bail();
        const feature = ordered.find(f => f.id === entry.featureId);
        const featParts = feature ? irPartsByFeature.get(feature.id) : null;
        const frozen0 = feature ? frozenByFeature.get(feature.id) : null;
        let adopted = false;
        if (feature && featParts && frozen0 != null && !parked.has(feature.id)) {
          // SET 87 — name the target BEFORE drawing (Andy: "what the fuck
          // happens around 30:03 — just starts randomly shooting off"). The
          // relay fired 3 draws per case with no line saying which case, so a
          // dozen identical calls appeared out of nowhere.
          emit('ir', feature.id,
            `case-relay: refilling "${entry.name}" against the warm world (K=${PERMUTATION_TEMPS.length}, ${entry.reason})`);
          // SET 97 — the warm-world relay must not draw before deterministic
          // substrate has had the same red-vs-stubs opportunity.
          const relaySymbol = feature.exports.find(e => e.symbol === entry.name)?.symbol
            ?? feature.exports[0]?.symbol;
          const substrateHit = await substrateFillOne({
            spec,
            feature,
            caseGen: { name: entry.name, kind: entry.kind, body: '', symbol: relaySymbol },
            stubs: stubArtifact(spec),
            runSuite: opts.runSuite!,
            imports: featParts.imports,
            onMechanismResult: (_mechanism, result) => {
              if (result === 'empty') metrics.substrateFillEmptyMechanisms++;
              else if (result === 'vacuous') metrics.substrateFillVacuousMechanisms++;
            },
          });
          if (substrateHit) {
            const substrateCase: IRCaseGen = {
              name: entry.name,
              kind: entry.kind,
              body: substrateHit.body,
              clade: classifyCaseClade(
                { name: entry.name, kind: entry.kind, body: substrateHit.body },
                relaySymbol,
              ),
            };
            const substrateParts = {
              imports: featParts.imports,
              cases: [...featParts.cases, substrateCase],
            };
            const substrateContent = wireSuiteScaffoldImports(
              assembleTestFile(feature, substrateParts.imports, substrateParts.cases),
              feature.testFile,
              spec,
            ).content;
            const artifactRun = await opts.runSuite!(artifactFiles(), {
              path: feature.testFile,
              content: substrateContent,
            });
            if (!artifactRun.crashed
              && !artifactRun.failures.some(f => f.name.includes(entry.name))) {
              const substrateRes = await commitFrozenPatch(
                feature, substrateContent, substrateParts, 'case-relay: substrate adopt',
              );
              if (!substrateRes || substrateRes.status !== 'rejected') {
                metrics.substrateFillHits++;
                metrics.recoveredCases++;
                adopted = true;
                emit('rha', feature.id,
                  `case "${entry.name}" filled from substrate: ${substrateHit.mechanism} (0 tok)`);
              }
            }
          }
          if (!adopted) metrics.substrateFillEscalations++;
          // SET 87 — and it drew NAKED. The warm world is precisely what this
          // stage exists to exploit; give it the buffer.
          const relayArtifact = artifactFiles();
          await synthesizeForDraw('ir', feature.id, relayArtifact);
          const relayContext = assembleContext({
            stage: 'ir',
            featureId: feature.id,
            spec, feature, parts: featParts,
            stubs: feature.stubs,
            lessons: opts.lessons ?? [],
            siblingParts: irPartsByFeature,
            siblingImpls: relayArtifact.filter(f => !feature.files.includes(f.path)),
            target: entry.name,
            conceptText: conceptByFeature.get(feature.id) ?? null,
            substrateHandoff: substrateHandoffFor(feature.id),
            ledgerRows: supergit.allRows(),
            artifact: relayArtifact,
            cachedReading: watch.reading,
          });
          const relayBuffer = emitSuperbufferAssembly('ir', feature.id, relayContext.assembly, 'case-relay');
          // SET 95d — hole-only gate rolled to case-relay (single-case draw).
          const relayFrame = holeOnlyFrameFor(gates, feature, entry.name, entry.kind);
          try {
            for (let ci = 0; ci < PERMUTATION_TEMPS.length && !adopted; ci++) {
              const temp = PERMUTATION_TEMPS[ci]!;
              metrics.permutationDraws++;
              metrics.permCandidates++;
              metrics.candidatesDrawn++;
              metrics.fillCandidatesDrawn++;
              const fixed = await runLlmAction({
                method: 'fixTestCases:case-relay',
                target: feature.id, phase: 'rha',
                startEvidence: {
                  temperature: temp, candidateIndex: ci + 1,
                  caseName: entry.name,
                },
                fn: () => opts.llm.fixTestCases(
                  spec, feature,
                  [{
                    name: entry.name, kind: entry.kind,
                    errors: [
                      'End-of-run refill: siblings are frozen and implementations are built.',
                      'Write the COMPLETE case body now — assert observable behavior.',
                      relayBuffer,
                      holeOnlyPromptBlock(relayFrame),
                    ].filter(Boolean),
                  }],
                  [], featParts.imports,
                  {
                    temperature: temp,
                    candidate: { n: ci + 1, k: PERMUTATION_TEMPS.length },
                    rescue: true,
                    purpose: `case-relay: ${feature.id}`,
                  },
                ),
              });
              let body = fixed.cases[0]?.body ?? '';
              const relayGate = applyHoleOnlyGate(relayFrame, body, metrics, entry.name,
                msg => emit('rha', feature.id, msg));
              if (relayGate.rejected) continue;
              body = relayGate.body;
              if (!body.trim()) continue;
              const syn = caseSyntaxErrors([{ name: entry.name, body }])[0];
              if (syn) {
                const healedBody = healCaseBody(body, syn.error);
                if (healedBody) { body = healedBody.body; metrics.mechanicalFixes++; }
              }
              if (!acceptCaseBody(body)) continue;
              const newCase: IRCaseGen = {
                name: entry.name, kind: entry.kind, body,
                clade: classifyCaseClade({ name: entry.name, kind: entry.kind, body }),
              };
              const nextParts = { imports: featParts.imports, cases: [...featParts.cases, newCase] };
              const asm = assembleTestFile(feature, nextParts.imports, nextParts.cases);
              const content2 = wireSuiteScaffoldImports(asm, feature.testFile, spec).content;
              if (validateSuiteShape(content2).length || suiteSyntaxError(content2)) continue;
              // Vacuous guard: the new case must be RED against stubs.
              const brRun2 = await opts.runSuite!(stubArtifact(spec), { path: feature.testFile, content: content2 });
              const caseRed = brRun2.crashed
                ? false
                : brRun2.failures.some(f => f.name.includes(entry.name));
              if (!caseRed) {
                emit('rha', feature.id,
                  `case-relay: "${entry.name}" candidate vacuous vs stubs — rejected`);
                continue;
              }
              // Adoption trial against the real artifact.
              const r2 = await opts.runSuite!(artifactFiles(), { path: feature.testFile, content: content2 });
              if (r2.crashed || r2.failures.some(f => f.name.includes(entry.name))) continue;
              // SET 89 §4.4 v2 — case-relay adoption routes through the
              // gateway. Both the parts AND the content change; the
              // gateway re-runs per-case certification against the new
              // parts (including this candidate) and the whole-program
              // parse gate against the adopted content. On rejection the
              // incumbent suite is byte-identical.
              const relayRes = await commitFrozenPatch(
                feature, content2, nextParts, 'case-relay: adopt');
              if (relayRes && relayRes.status === 'rejected') {
                emit('rha', feature.id,
                  `case-relay adoption rejected by gateway ("${entry.name}"): ${relayRes.report.rejectionReasons[0] ?? 'no reason'}`);
                continue;
              }
              // SET 89 §8.1 — the case-relay adoption path was missing
              // `candidatesAccepted++`. An adopted case-relay candidate is
              // a fill-layer accepted candidate and MUST increment both the
              // aggregate and per-layer counters so the ledger conservation
              // invariant (drawn ≥ accepted; accepted-adopted subset)
              // holds at terminal return.
              metrics.candidatesAccepted++;
              metrics.fillCandidatesAccepted++;
              metrics.recoveredCases++;
              adopted = true;
              emit('rha', feature.id,
                `case-relay: case "${entry.name}" recovered at end-of-run (warm world, candidate t=${temp})`);
            }
          } catch (e) {
            emit('rha', entry.featureId,
              `case-relay draw failed: ${e instanceof Error ? e.message : String(e)}`);
          }
        }
        if (!adopted) {
          // Final drop — original lineage-parseable message shape.
          problems.push(`${entry.featureId}: planned case "${entry.name}" ${entry.reason}`);
          emit('rha', entry.featureId,
            `case-relay: case "${entry.name}" final drop — ${entry.reason}`);
        }
      }
    }

    await remeasureParked();
    for (const [id, entry] of parked) {
      if (!problems.some(p => p.startsWith(`${id}: crash|unattributed`))) {
        problems.push(`${id}: crash|unattributed`);
      }
      // SET 31c / SET 89 §10.5 — parked entries collapse into their crash
      // signature for the artifact-fault view (one fault affecting N
      // features). The unique-bug view is owned by the DefectRegistry
      // authoritative-measurement path; we do not track it here.
      const sig = entry.sig;
      artifactFaultRemainingSigs.add(sig);
      let set = artifactFaultAffects.get(sig);
      if (!set) { set = new Set(); artifactFaultAffects.set(sig, set); }
      set.add(id);
    }
  } else if (!opts.runSuite) {
    emit('auth', null, 'no suite runner available — artifact NOT authenticated (frozen suites were not executed)');
    problems.push('artifact not authenticated: no suite runner in this environment');
  }
  // else: SET 40f — RHA skipped because build phase failed (already emitted).

  const files = artifactFiles();
  metrics.elapsedMs = Date.now() - startedAt;
  metrics.fixesL1 = metrics.substrateFixes;
  // SET 89 §10.5 — `bugsObserved` / `bugsRemaining` / `bugsPatched` are
  // NEVER mutated at this site. The pre-SET-89 code overwrote them from
  // local `observedBugKeys.size` / `remainingBugKeys.size` sets that were
  // maintained in parallel across ~4 mutation sites (parked entries,
  // measure loop, remeasure path). Two of those sites had subtly
  // different dedupe rules (one collapsed crashes by signature, the
  // other kept per-feature crash rows) so the "unique bug" count could
  // change depending on which sites had run. The canonical unique-defect
  // counter now lives in the DefectRegistry (§10.3); `syncMetricsFromLedgers()`
  // below is the SOLE writer of `metrics.bugs*`. `artifactFault*` remains
  // a separate view (one crash sig affecting N features).
  syncMetricsFromLedgers();
  metrics.artifactFaults = artifactFaultAffects.size;
  metrics.artifactFaultsRemaining = artifactFaultRemainingSigs.size;
  metrics.artifactFaultsAffectedFeatures = [...artifactFaultAffects.values()]
    .reduce((n, set) => n + set.size, 0);
  const remainingAffected = [...artifactFaultRemainingSigs]
    .reduce((n, s) => n + (artifactFaultAffects.get(s)?.size ?? 0), 0);
  const faultSuffix = metrics.artifactFaultsRemaining > 0
    ? `, ${metrics.artifactFaultsRemaining} artifact fault${metrics.artifactFaultsRemaining === 1 ? '' : 's'} affecting ${remainingAffected} feature${remainingAffected === 1 ? '' : 's'}`
    : '';
  // SET 32d — surface `N features uncovered` on the done line so the terminal
  // fan-out is visible in the summary. `abandonedIds` was populated by the
  // metaloop bracket (SET 32h/32i).
  const uncoveredSuffix = abandonedIds.length > 0
    ? `, ${uncoveredSummary(abandonedIds.length)}`
    : '';
  // SET 34d — superbuffer efficacy block (only when any sb case was sampled).
  if (sbWithTpl.cases + sbNoTpl.cases > 0) {
    noteEvidence('done', null, [formatSuperbufferEfficacy(sbWithTpl, sbNoTpl)]);
  }
  // SET 45c — substrate-page efficacy (WITH vs WITHOUT handoff).
  if (sbPageEff.withPage.cases + sbPageEff.withoutPage.cases > 0) {
    noteEvidence('done', null, [
      formatSubstratePageEfficacy(sbPageEff.withPage, sbPageEff.withoutPage),
    ]);
  }
  // SET 57a — permanent deferrals: capability exclusions never re-prosecuted
  // plus features abandoned after metaloop 3.
  metrics.deferredPermanent = deferred.length + abandonedIds.length;
  emit('done', null,
    `${artifactState.files().length} files built, ${frozenTests.length} suites frozen, ${problems.length} problems — `
    + `${metrics.passesTotal} cycles, ${metrics.bugsPatched}/${metrics.bugsObserved} bugs patched${faultSuffix}${uncoveredSuffix}, `
    + `${Math.round(metrics.elapsedMs / 1000)}s`);
  const substrateFillCases = metrics.substrateFillHits + metrics.substrateFillEscalations;
  emit('done', null,
    `substrate fill hit-rate: ${metrics.substrateFillHits} of ${substrateFillCases} cases `
    + `filled at 0 tokens via substrate — approximately ${metrics.substrateFillHits * 3} LLM draws avoided`);
  // SET 38c / 37b — evidence AFTER the summary done line so hosts that
  // `find(phase==='done')` still see the cycle/fault summary first.
  // SET 43e — promote repeated heal shapes to handler-candidate (mutation-oracle later).
  for (const cand of promoteLessonsToHandlerCandidates(healedInstances)) {
    emit('done', null,
      `handler-candidate: ${cand.classKey} support=${cand.support} shape="${cand.editShape}"`);
    // SET 77 — the before→after FIXTURES were assembled and then read by
    // nothing: a promotion candidate nobody can inspect cannot be promoted.
    // One worked example, verbatim, so the shape is judgeable.
    const fx = cand.fixtures[0];
    if (fx) {
      noteEvidence('done', null, [
        `handler-candidate fixture [${cand.classKey}] — this transform, seen ${cand.support}×:`,
        `  before: ${fx.before.replace(/\s+/g, ' ').slice(0, 160)}`,
        `  after:  ${fx.after.replace(/\s+/g, ' ').slice(0, 160)}`,
      ]);
    }
  }
  // SET 43f — driving metric + standing classKey coverage rule.
  const coverageRows = [...classKeySightings.entries()].map(([classKey, row]) => {
    let stratum: ClassKeyCoverageStratum = 'uncovered';
    if (row.fixed) stratum = 'mechanical';
    else if (row.mechanicalCandidate) stratum = 'mechanical-candidate';
    return { classKey, count: row.count, stratum };
  });
  noteEvidence('done', null, [
    formatParsePoisonIncidents(metrics.parsePoisonIncidents, opts.priorParsePoisonIncidents ?? 0),
    ...formatSolutionStrataTable(await loadSolutionStrataTable().catch(() => undefined)),
    formatSubstrateHitRate({
      attempts: metrics.substrateAttempts,
      fixes: metrics.substrateFixes,
      refusals: metrics.substrateRefusals,
      noHandler: metrics.substrateNoHandler,
    }),
    ...formatClassKeyCoverageRule(coverageRows),
  ]);
  // SET 69 — split hits are NOT losses: the binding was excised and the
  // behavioral invariant stayed in the plan. They are disclosed on the
  // deferred ledger but never counted as excluded prompt items.
  const excludedHits = deferred.filter(d => !d.behavioralSplit);
  if (excludedHits.length) {
    // SET 37g / 44 — capability exclusion (not a later revisit / tier promise).
    for (const d of excludedHits) {
      problems.push(formatPermanentDeferral(d.capability));
    }
    const caps = [...new Set(excludedHits.map(d => d.capability))].sort().join(', ');
    problems.push(
      `${excludedHits.length} prompt items excluded (capabilities: ${caps}) — see TRACEABILITY.md`,
    );
  }
  const splitHits = deferred.filter(d => d.behavioralSplit);
  if (splitHits.length) {
    problems.push(
      `${splitHits.length} infra binding${splitHits.length === 1 ? '' : 's'} excised (behavioral invariants kept under simulated dependencies) — see TRACEABILITY.md`,
    );
  }
  // SET 84 — THE FUNNEL (Andy: "not much substrate activity this run" — the
  // counters read 0/0/0/0, which is not a weak substrate but a repair ladder
  // that never executed). A stage that never ran must say so; "—" reads like
  // missing data when it means "this never happened".
  {
    const frozenN = frozenTests.length;
    const parkedN = problems.filter(pb => /crash\|unattributed/.test(pb)).length;
    emit('done', null,
      `funnel: ${metrics.featuresTotal} feature(s) planned → ${frozenN} froze a contract`
      + ` → ${metrics.nodesBuilt} built all owned files → ${metrics.nodesTotal} entered the repair ladder`
      + ` → ${metrics.nodesHealed} converged.`
      + (metrics.nodesTotal === 0
        ? ' The repair ladder never ran, so the substrate had nothing to attempt —'
          + (frozenN === 0
            ? ' no feature froze a contract.'
            : parkedN > 0
              ? ` ${parkedN} feature(s) parked on unattributed crashes before repair.`
              : ' every frozen feature was skipped (build-failed or parked).')
        : ''));
  }
  emit('done', null, formatSupergitSummary(supergit));
  // SET 89 §§10.6 / 11.5 — TERMINAL CERTIFICATION.
  //
  // Order:
  //   1. Every non-terminal action must have a terminal — no pending is
  //      permitted at conservation check. If the run was cancelled, cancel
  //      any stray pending FIRST (cancellation is the only permitted route
  //      to a `cancelled` terminal disposition).
  //   2. Start the terminal-certification action; run `certifyArtifact`.
  //   3. For each terminal finding, create a supergit `result` / `error`
  //      row and observe an authoritative defect-registry occurrence with
  //      that error node as the confirming site. Group findings by feature
  //      so scoped result rows are honest.
  //   4. Call `reconcileTerminalMeasurement` — any remaining open defect
  //      absent from the terminal finding set is resolved by the terminal
  //      measurement.
  //   5. Sync legacy `errors*` aliases + canonical counters from the
  //      registries. THEN append the terminal decision node.
  //   6. Compute the final `artifactCertified` predicate — it AND-s the
  //      certification structural predicate with defect-conservation
  //      (`uniqueDefectsUnresolved === 0`) and action-conservation
  //      (`actionPending === 0`, no duplicate terminals).
  let artifactCertificationSummary: Tier1Result['artifactCertification'];
  const wasCancelled = !!opts.isCancelled?.();
  if (wasCancelled) actionLedger.cancelPending('run cancelled');
  if (opts.runSuite && frozenTests.length > 0) {
    const termCertActionId = actionLedger.startAction({
      kind: 'terminal-certification',
      target: '*',
      phase: 'done',
      startEvidence: { artifactBytes: files.length, frozenSuites: frozenTests.length },
    });
    try {
      const artCert = await certifyArtifact({
        spec, prompt: opts.rawPrompt ?? opts.prompt,
        runSuite: opts.runSuite,
        artifact: files,
        state: frozenState,
      });
      // Terminal findings → per-feature synthetic result + error rows +
      // authoritative defect-registry occurrences (structured for the
      // registry — same identity fields as measurement time).
      const byFeature = new Map<string, typeof artCert.findings>();
      for (const f of artCert.findings) {
        const list = byFeature.get(f.featureId) ?? [];
        list.push(f);
        byFeature.set(f.featureId, list);
      }
      const termMeasurementId = `M-terminal-${supergit.allRows().length}`;
      const presentKeys: string[] = [];
      for (const [fid, findings] of byFeature) {
        const feature = ordered.find(x => x.id === fid);
        const resultId = supergit.recordNode({
          type: 'result', featureId: fid,
          causeId: supergit.codeNodeFor(fid) ?? supergit.testNodeFor(fid),
          artifactPath: feature?.testFile ?? null,
          status: 'fail',
          summary: `terminal: ${findings.length} finding(s) against final artifact`,
        });
        for (const f of findings) {
          const errorNodeId = supergit.recordNode({
            type: 'error', featureId: fid, causeId: resultId,
            artifactPath: f.artifactPath ?? feature?.files[0] ?? null,
            bugClass: f.classKey, status: 'open',
            summary: `terminal ${f.category}: ${f.message.split('\n')[0]!.slice(0, 160)}`,
          });
          defectRegistry.observeAuthoritativeFinding({
            featureId: f.featureId,
            caseId: f.caseId,
            classKey: f.classKey,
            category: f.category,
            artifactPath: f.artifactPath ?? null,
            expected: f.expected ?? null,
            received: f.received ?? null,
            crashSignature: f.crashSignature ?? null,
            message: f.message,
            measurementId: termMeasurementId,
            resultNodeId: resultId,
            errorNodeId,
            actionId: termCertActionId,
          });
          presentKeys.push(f.canonicalKey);
        }
      }
      // Reconcile every previously open identity against the FULL terminal
      // finding set — absent identities are resolved by the terminal
      // measurement even if their scope did not reconcile earlier.
      const termResolutions = defectRegistry.reconcileTerminalMeasurement({
        presentKeys,
        confirmingMeasurementId: termMeasurementId,
        confirmingResultNodeId: 'terminal',
        actionId: termCertActionId,
      });
      for (const res of termResolutions) {
        supergit.recordNode({
          type: 'resolution',
          causeId: res.causeErrorNodeId,
          status: 'pass',
          summary: `terminal resolution: defect ${res.defectId} (${res.resolutionId})`,
        });
      }
      artifactCertificationSummary = {
        // SET 89 §10.6 — the certification structural predicate lives on
        // the summary here; the FINAL `artifactCertified` value is
        // computed below by ANDing this with defect + action
        // conservation, and the summary is REWRITTEN before the terminal
        // decision node is emitted so the record cannot lie.
        artifactCertified: artCert.artifactCertified,
        unresolved: artCert.unresolved,
        gateInfrastructureUnavailable: artCert.gateInfrastructureUnavailable,
      };
      actionLedger.finishAction({
        actionId: termCertActionId,
        // The terminal-certification action's disposition reflects the
        // STRUCTURAL predicate only — a failed AND on defect/action
        // conservation lives in the run-level decision node, not on the
        // certification action.
        disposition: artCert.artifactCertified ? 'applied' : 'rejected',
        endEvidence: {
          artifactCertified: artCert.artifactCertified,
          unresolvedCount: artCert.unresolved.length,
          findings: artCert.findings.length,
          terminalResolutions: termResolutions.length,
        },
      });
    } catch (e) {
      actionLedger.finishAction({
        actionId: termCertActionId, disposition: 'failed',
        failureMode: 'fatal', error: e,
      });
      const msg = e instanceof Error ? e.message : String(e);
      emit('done', null,
        `artifact certification could not run: ${msg.slice(0, 200)}`);
    }
  }
  // Now that no more work will run, all pending actions must be terminal.
  // If they are not, `assertConserved` throws; that is a bug we want to
  // surface loudly in tests, but must not kill a production run — trap the
  // error and emit a diagnostic instead.
  try {
    defectRegistry.assertInvariants();
  } catch (e) {
    emit('done', null,
      `defect registry invariant violation: ${e instanceof Error ? e.message : String(e)}`);
  }
  try {
    actionLedger.assertConserved();
  } catch (e) {
    emit('done', null,
      `action ledger conservation violation: ${e instanceof Error ? e.message : String(e)}`);
  }
  // SET 89 §10.5 — refresh derived metrics from the two ledgers before we
  // emit the terminal decision node so its summary matches what the record
  // will actually carry.
  syncMetricsFromLedgers();
  // Duplicate-terminal check: the ledger enforces this in strict mode
  // (throws on `finishAction` if a terminal exists) but we still surface a
  // guard predicate for the `artifactCertified` AND — a stray double
  // terminal would already have thrown during the run, so this is 0 by
  // construction in the happy path.
  const hasDuplicateActionTerminals = false;
  const conservedCertification =
    (artifactCertificationSummary?.artifactCertified ?? false)
    && defectRegistry.metrics().uniqueDefectsUnresolved === 0
    && actionLedger.metrics().actionPending === 0
    && !hasDuplicateActionTerminals;
  if (artifactCertificationSummary) {
    artifactCertificationSummary = {
      ...artifactCertificationSummary,
      artifactCertified: conservedCertification,
    };
    // SET 89 §10.6 / Gap G — emit the certification result AFTER the
    // conserved-certification AND. The pre-conservation flag from
    // `certifyArtifact` alone is a STRUCTURAL predicate (suites re-run
    // against the final artifact and PASS); the FINAL certification also
    // requires `uniqueDefectsUnresolved === 0` and `actionPending === 0`.
    // Emitting `artifact-certified` off the structural flag alone would
    // lie whenever an authoritative measurement identity was still open
    // or an action was still pending at run end.
    const unresolvedList = artifactCertificationSummary.unresolved ?? [];
    if (conservedCertification) {
      emit('done', null,
        `artifact-certified: ${frozenTests.length} suite(s) re-verified against final artifact`);
    } else {
      const reasonBits: string[] = [];
      if (unresolvedList.length > 0) {
        reasonBits.push(`${unresolvedList.length} unresolved`);
      }
      const unresolvedDefects = defectRegistry.metrics().uniqueDefectsUnresolved;
      if (unresolvedDefects > 0) {
        reasonBits.push(`${unresolvedDefects} open defect(s)`);
      }
      const pendingActions = actionLedger.metrics().actionPending;
      if (pendingActions > 0) {
        reasonBits.push(`${pendingActions} pending action(s)`);
      }
      const reason = reasonBits.length ? ` (${reasonBits.join('; ')})` : '';
      emit('done', null, `artifact-uncertified${reason} (SET 89D)`);
      for (const item of unresolvedList.slice(0, 12)) {
        emit('done', null, `  uncertified: ${item.slice(0, 200)}`);
      }
    }
  }
  // SET 74 — close the ledger with the run's terminal decision AFTER
  // certification, reconciliation, and conservation checks — the summary
  // now carries the honest per-registry disposition.
  supergit.recordNode({
    type: 'decision',
    status: problems.length ? 'open' : 'pass',
    summary: `run complete: ${files.length} files, ${frozenTests.length} suites frozen, ${problems.length} problems`,
  });
  return {
    spec, files, frozenTests, problems, metrics, log, provenance,
    contractVersion: opts.contractVersion,
    deferred,
    evidence,
    supergit: {
      rows: supergit.allRows(),
      csv: supergit.toCsv(),
      graph: supergit.toGraph(),
    },
    ...(artifactCertificationSummary ? { artifactCertification: artifactCertificationSummary } : {}),
    defectRegistry: defectRegistry.snapshot(),
    actionLedger: actionLedger.snapshot(),
  };
}
