voidmachine 5.0.2 → 5.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/main.js CHANGED
@@ -35768,6 +35768,7 @@ init_esm_shims();
35768
35768
 
35769
35769
  // ../mission-engine/dist/orchestration/review-loop.js
35770
35770
  init_esm_shims();
35771
+ var BOUNDED_REVIEW_BUDGET = { maxRounds: 3, maxCorrectionBatches: 2 };
35771
35772
  var SHA256 = /^sha256:[a-f0-9]{64}$/;
35772
35773
  function validNativeContextId(value) {
35773
35774
  return typeof value === "string" && value.trim().length > 0 && value.length <= 160 && [...value].every((char) => char.charCodeAt(0) >= 32 && (char.charCodeAt(0) < 127 || char.charCodeAt(0) > 159));
@@ -36579,6 +36580,92 @@ function opaqueNativeContextDefect(input2) {
36579
36580
  return starts.length === 1 && started !== void 0 && started.source === event.source && started.seq > requested.seq && started.seq < event.seq && ["stage", "reviewRound", "inputHash", "contractVersion", "contextId"].every((key) => field4(started, key) === field4(event, key));
36580
36581
  });
36581
36582
  }
36583
+ function preparationInvocationReplacement(input2) {
36584
+ const { events } = input2.stream;
36585
+ const { observation: observation2, request } = input2;
36586
+ if (request.disposition.kind !== "preparation-invocation")
36587
+ return false;
36588
+ const start = events[0];
36589
+ const closure = events.at(-1);
36590
+ const writerRequests = events.filter((event) => event.kind === "lead-writer.requested");
36591
+ const writers = events.filter((event) => event.kind === "lead-writer.completed");
36592
+ const writer = writers[0];
36593
+ const writerRequest = writerRequests[0];
36594
+ if (start === void 0 || start.kind !== "mission.started" || start.source !== "void-harness:mission" || !["team", "fortress"].includes(String(field4(start, "mode"))) || field4(start, "runtimeAttested") !== true || `runtime:${String(field4(start, "runtime"))}` !== observation2.expectedSource || !/^sha256:[a-f0-9]{64}$/.test(String(field4(start, "planHash"))) || observation2.stage !== "pre-implementation" || observation2.maxRounds !== 2 || closure?.source !== "void-harness:mission.dispatch" || writer === void 0 || writerRequest === void 0 || writers.length !== 1 || writerRequests.length !== 1 || writerRequest.seq >= writer.seq || writerRequest.source !== "void-harness:mission.dispatch" || writer.subject !== field4(start, "leadWriterId") || writer.source !== writer.subject || writerRequest.subject !== writer.subject || writer.causationId !== writerRequest.eventId || field4(writer, "requestEventId") !== writerRequest.eventId || field4(writer, "actionKind") !== "run-preparation-correction" || field4(writer, "planHash") !== field4(start, "planHash") || field4(writer, "writerId") !== writer.subject || field4(writer, "implementationRound") !== 1 || !["actionKind", "planHash", "writerId", "implementationRound"].every((key) => field4(writer, key) === field4(writerRequest, key)))
36595
+ return false;
36596
+ const allowed = [
36597
+ "mission.started",
36598
+ "mission.closed",
36599
+ "lead-writer.requested",
36600
+ "lead-writer.completed",
36601
+ "specialist.requested",
36602
+ "specialist.started",
36603
+ "specialist.completed",
36604
+ "evidence.recorded",
36605
+ "specialist.evidence-classification-requested",
36606
+ "specialist.evidence-started",
36607
+ "specialist.evidence-classified",
36608
+ "specialist.evidence-discharge-requested",
36609
+ "specialist.evidence-discharged"
36610
+ ];
36611
+ if (events.some((event) => !allowed.includes(event.kind)))
36612
+ return false;
36613
+ const required2 = Object.keys(observation2.contractVersions);
36614
+ const panel = completions(events);
36615
+ const invocations = events.filter((event) => ["specialist.requested", "specialist.started", "specialist.completed"].includes(event.kind));
36616
+ if (required2.length === 0 || panel.length !== required2.length * 2 || invocations.length !== panel.length * 3)
36617
+ return false;
36618
+ const ids = request.disposition.completionEventIds;
36619
+ if (ids.length === 0 || new Set(ids).size !== ids.length)
36620
+ return false;
36621
+ for (const specialist of required2) {
36622
+ for (const round of [1, 2]) {
36623
+ const matching = panel.filter((item2) => item2.event.subject === specialist && field4(item2.event, "reviewRound") === round);
36624
+ const item = matching[0];
36625
+ if (matching.length !== 1 || item === void 0)
36626
+ return false;
36627
+ const { event, completion } = item;
36628
+ if (event.source !== observation2.expectedSource || field4(event, "stage") !== "pre-implementation" || completion.specialistId !== specialist || completion.contractVersion !== observation2.contractVersions[specialist] || field4(event, "contractVersion") !== completion.contractVersion || !validNativeContextId(field4(event, "contextId")) || completion.verdict !== "pass" || completion.findings.length > 0 || round === 2 && (event.seq <= writer.seq || completion.evidenceRequests.length > 0 || field4(event, "inputHash") !== observation2.currentInputHashes[specialist]) || round === 1 && event.seq >= writerRequest.seq)
36629
+ return false;
36630
+ const requests = invocations.filter((candidate) => matchesRequest(event, candidate));
36631
+ const requested = requests[0];
36632
+ const starts = invocations.filter((candidate) => candidate.kind === "specialist.started" && candidate.subject === specialist && field4(candidate, "reviewRound") === round);
36633
+ const started = starts[0];
36634
+ if (requests.length !== 1 || starts.length !== 1 || requested === void 0 || started === void 0 || requested.seq >= started.seq || started.seq >= event.seq || round === 2 && requested.seq <= writer.seq || started.source !== observation2.expectedSource || field4(requested, "planHash") !== field4(start, "planHash") || field4(requested, "runtime") !== field4(start, "runtime") || field4(requested, "contractVersion") !== completion.contractVersion || !["stage", "reviewRound", "inputHash", "contractVersion", "contextId"].every((key) => field4(started, key) === field4(event, key)))
36635
+ return false;
36636
+ }
36637
+ }
36638
+ const proofs = events.flatMap((event) => {
36639
+ if (event.kind !== "evidence.recorded")
36640
+ return [];
36641
+ const parsed = parseEvidence(field4(event, "evidence"));
36642
+ return parsed.ok ? [{ eventId: event.eventId, evidence: parsed.value }] : [];
36643
+ });
36644
+ const obligations = reduceEvidenceObligations({
36645
+ events,
36646
+ expectedSource: observation2.expectedSource,
36647
+ phase: "pre-implementation",
36648
+ proofs,
36649
+ evidenceContext: {
36650
+ missionId: start.missionId,
36651
+ dependencies: observation2.evidenceDependencies ?? {}
36652
+ }
36653
+ });
36654
+ if (obligations.issues.length > 0 || obligations.blockingObligationIds.length > 0)
36655
+ return false;
36656
+ const review = reduceReviewLoop({
36657
+ events,
36658
+ stage: "pre-implementation",
36659
+ expectedSource: observation2.expectedSource,
36660
+ stageStartSeqExclusive: start.seq,
36661
+ afterSeqExclusive: writer.seq,
36662
+ requiredSpecialists: required2.filter(specialistId2),
36663
+ contractVersions: observation2.contractVersions,
36664
+ currentInputHashes: observation2.currentInputHashes,
36665
+ maxRounds: observation2.maxRounds
36666
+ });
36667
+ return review.issues.length === ids.length && review.issues.every((issue4) => issue4.code === "reused-context" && ids.includes(issue4.eventId) && events.some((event) => event.eventId === issue4.eventId && event.seq > writer.seq));
36668
+ }
36582
36669
  function partialFanoutCorrections(events) {
36583
36670
  if (events.some((event) => event.kind === "lead-writer.completed" || event.kind === "specialist.failed"))
36584
36671
  return [];
@@ -36641,7 +36728,7 @@ function staleDispatchCompletions(events) {
36641
36728
  function specialistId2(value) {
36642
36729
  return /^core:[a-z0-9]+(?:-[a-z0-9]+)*$/.test(value);
36643
36730
  }
36644
- function validProvenanceRecovery(input2, existing) {
36731
+ function validProvenanceRecovery(input2, existing, afterSeqExclusive = 0) {
36645
36732
  const disposition = input2.request.disposition;
36646
36733
  const observation2 = input2.observation;
36647
36734
  const bindings = observation2.reviewBindings;
@@ -36655,10 +36742,10 @@ function validProvenanceRecovery(input2, existing) {
36655
36742
  const observedSubject = observation2.reviewSubject;
36656
36743
  return bindings.every((binding3) => {
36657
36744
  const original = existing.find((item) => item.event.eventId === binding3.completionEventId);
36658
- if (original === void 0 || !disposition.completionEventIds.includes(binding3.completionEventId) || original.event.subject !== "core:independent-code-reviewer" || original.event.source !== observation2.expectedSource || original.completion.verdict !== "pass" || original.completion.findings.some((finding) => finding.classification !== "advisory") || original.completion.contractVersion !== observation2.contractVersions[original.event.subject] || field4(original.event, "inputHash") !== observation2.currentInputHashes[original.event.subject] || canonicalJsonHash(original.completion) !== binding3.completionHash || !sameReviewSubject(binding3.review, observedSubject) || binding3.review.taskId !== original.event.missionId || binding3.review.writerId !== writerId || binding3.review.provenance.kind !== "native-context" || binding3.review.provenance.contextId !== field4(original.event, "contextId"))
36745
+ if (parseReviewReceipt(binding3.review) === void 0 || original === void 0 || original.event.seq <= afterSeqExclusive || !disposition.completionEventIds.includes(binding3.completionEventId) || original.event.subject !== "core:independent-code-reviewer" || original.event.source !== observation2.expectedSource || original.completion.verdict !== "pass" || original.completion.findings.some((finding) => finding.classification !== "advisory") || original.completion.contractVersion !== observation2.contractVersions[original.event.subject] || field4(original.event, "inputHash") !== observation2.currentInputHashes[original.event.subject] || canonicalJsonHash(original.completion) !== binding3.completionHash || !sameReviewSubject(binding3.review, observedSubject) || binding3.review.taskId !== original.event.missionId || binding3.review.writerId !== writerId || binding3.review.provenance.kind !== "native-context" || binding3.review.provenance.contextId !== field4(original.event, "contextId"))
36659
36746
  return false;
36660
- const requested = events.find((event) => event.seq < original.event.seq && matchesRequest(original.event, event) && field4(event, "contractVersion") === original.completion.contractVersion && `runtime:${String(field4(event, "runtime"))}` === observation2.expectedSource);
36661
- return requested !== void 0 && events.some((event) => event.kind === "specialist.started" && event.source === observation2.expectedSource && event.subject === original.event.subject && event.seq > requested.seq && event.seq < original.event.seq && ["stage", "reviewRound", "inputHash", "contextId"].every((key) => field4(event, key) === field4(original.event, key)));
36747
+ const requested = events.find((event) => event.seq > afterSeqExclusive && event.seq < original.event.seq && matchesRequest(original.event, event) && field4(event, "contractVersion") === original.completion.contractVersion && `runtime:${String(field4(event, "runtime"))}` === observation2.expectedSource);
36748
+ return requested !== void 0 && events.some((event) => event.kind === "specialist.started" && event.source === observation2.expectedSource && event.subject === original.event.subject && event.seq > requested.seq && event.seq < original.event.seq && ["stage", "reviewRound", "inputHash", "contractVersion", "contextId"].every((key) => field4(event, key) === field4(original.event, key)));
36662
36749
  });
36663
36750
  }
36664
36751
  function pendingPreparationClarification(input2, previousRecovery) {
@@ -36709,14 +36796,18 @@ function admitStoppedMission(input2, projectedHistory = input2.stream.events) {
36709
36796
  return refuse2("stale-journal", "Re-observe the journal before requesting recovery");
36710
36797
  if (ambiguousEffects(events))
36711
36798
  return refuse2("ambiguous-effect", "Reconcile the unfinished external effect; recovery cannot replay it");
36799
+ const existing = completions(events).filter((item) => field4(item.event, "stage") === observation2.stage);
36712
36800
  const previousRecovery = events.filter((event) => event.kind === "mission.recovered").at(-1);
36713
- if (previousRecovery !== void 0 && !events.some((event) => event.seq > previousRecovery.seq && event.kind === "lead-writer.completed") && !pendingPreparationClarification(input2, previousRecovery)) {
36801
+ if (previousRecovery !== void 0 && !events.some((event) => event.seq > previousRecovery.seq && event.kind === "lead-writer.completed") && !pendingPreparationClarification(input2, previousRecovery) && !validProvenanceRecovery(input2, existing, previousRecovery.seq)) {
36714
36802
  return refuse2("no-recovery-progress", "Record actual corrective progress before reopening another stopped episode");
36715
36803
  }
36716
- const existing = completions(events).filter((item) => field4(item.event, "stage") === observation2.stage);
36717
- const roundCorrections = partialFanoutCorrections(projectedHistory);
36718
- const inadmissible = staleDispatchCompletions(projectedHistory);
36719
36804
  const disposition = request.disposition;
36805
+ const replacement = disposition.kind === "preparation-invocation";
36806
+ if (replacement && !preparationInvocationReplacement(input2)) {
36807
+ return refuse2("invalid-preparation-invocation", "Name exactly the reused-context preparation completions with intact invocation bindings; replacement is one-time and retains round two");
36808
+ }
36809
+ const roundCorrections = replacement ? [] : partialFanoutCorrections(projectedHistory);
36810
+ const inadmissible = replacement ? disposition.completionEventIds : staleDispatchCompletions(projectedHistory);
36720
36811
  if (disposition.kind === "controller-defect" && (disposition.defect === "partial-fanout-round" ? roundCorrections.length === 0 : disposition.defect === "stale-input-dispatch" ? inadmissible.length === 0 : !opaqueNativeContextDefect(input2))) {
36721
36812
  return refuse2("unproven-controller-defect", "The journal must prove the requested controller defect; do not reset its budget");
36722
36813
  }
@@ -36767,8 +36858,8 @@ function admitStoppedMission(input2, projectedHistory = input2.stream.events) {
36767
36858
  const projected = applyRoundCorrections(projectedHistory, roundCorrections).filter((event) => !inadmissible.includes(event.eventId));
36768
36859
  const required2 = Object.keys(observation2.contractVersions).filter(specialistId2);
36769
36860
  const writers = projected.filter((event) => event.kind === "lead-writer.completed");
36770
- const stageStart = observation2.stage === "post-implementation" ? writers.find((event) => field4(event, "actionKind") !== "run-preparation-correction")?.seq : void 0;
36771
- const lastWriter = observation2.stage === "post-implementation" ? writers.at(-1)?.seq : void 0;
36861
+ const stageStart = observation2.stage === "post-implementation" ? writers.find((event) => field4(event, "actionKind") !== "run-preparation-correction")?.seq : replacement ? events[0]?.seq : void 0;
36862
+ const lastWriter = observation2.stage === "post-implementation" || replacement ? writers.at(-1)?.seq : void 0;
36772
36863
  const migration = validatedSpecialistContractMigrationBoundary(events);
36773
36864
  if (!migration.ok)
36774
36865
  return refuse2("invalid-migration-receipt", migration.reasons.join("; "));
@@ -36789,10 +36880,10 @@ function admitStoppedMission(input2, projectedHistory = input2.stream.events) {
36789
36880
  requiredSpecialists: required2,
36790
36881
  contractVersions: observation2.contractVersions,
36791
36882
  currentInputHashes: observation2.currentInputHashes,
36792
- maxRounds: observation2.maxRounds
36883
+ ...observation2.reviewPolicy === "bounded-corrections-v1" ? BOUNDED_REVIEW_BUDGET : { maxRounds: observation2.maxRounds }
36793
36884
  };
36794
36885
  const originalReview = reduceReviewLoop({ ...reviewInput, events: projectedHistory });
36795
- if (originalReview.issues.some((issue4) => issue4.code !== "wrong-review-round")) {
36886
+ if (originalReview.issues.some((issue4) => replacement ? issue4.code !== "reused-context" || !inadmissible.includes(issue4.eventId) : issue4.code !== "wrong-review-round")) {
36796
36887
  return refuse2("inconsistent-review", "Resolve inconsistent source, contract or context evidence before recovery");
36797
36888
  }
36798
36889
  const review = reduceReviewLoop({ ...reviewInput, events: projected });
@@ -36802,8 +36893,8 @@ function admitStoppedMission(input2, projectedHistory = input2.stream.events) {
36802
36893
  if (disposition.kind === "controller-defect" && disposition.defect === "opaque-native-context" && (!review.readyForVerdict || existing.length !== required2.length || required2.some((id3) => !existing.some((item) => item.event.subject === id3)))) {
36803
36894
  return refuse2("incomplete-required-panel", "Every required preparation specialist must have its original matching PASS triplet before recovery");
36804
36895
  }
36805
- const consumedRounds = Math.max(0, ...projected.filter((event) => ["specialist.completed", "specialist.failed"].includes(event.kind) && field4(event, "stage") === observation2.stage).map((event) => Number(field4(event, "reviewRound"))));
36806
- if (disposition.kind !== "review-provenance" && consumedRounds >= observation2.maxRounds)
36896
+ const consumedRounds = Math.max(0, ...(replacement ? projectedHistory : projected).filter((event) => ["specialist.completed", "specialist.failed"].includes(event.kind) && field4(event, "stage") === observation2.stage).map((event) => Number(field4(event, "reviewRound"))));
36897
+ if (!replacement && disposition.kind !== "review-provenance" && consumedRounds >= reviewInput.maxRounds)
36807
36898
  return refuse2("review-budget-exhausted", "The real review budget is exhausted; recovery cannot reset it");
36808
36899
  const consumedCorrectionBatches = projected.filter((event) => event.kind === "lead-writer.completed" && field4(event, "actionKind") === "run-correction").length;
36809
36900
  if (disposition.kind === "review-provenance" && consumedCorrectionBatches > 2) {
@@ -36825,12 +36916,12 @@ function admitStoppedMission(input2, projectedHistory = input2.stream.events) {
36825
36916
  inadmissibleCompletionEventIds: inadmissible,
36826
36917
  roundCorrections,
36827
36918
  consumedRounds,
36828
- remainingRounds: Math.max(0, observation2.maxRounds - consumedRounds),
36829
- ...disposition.kind !== "review-provenance" ? {} : {
36919
+ remainingRounds: Math.max(0, reviewInput.maxRounds - consumedRounds),
36920
+ ...!replacement && disposition.kind !== "review-provenance" ? {} : {
36830
36921
  consumedCorrectionBatches,
36831
36922
  remainingCorrectionBatches: 2 - consumedCorrectionBatches
36832
36923
  },
36833
- nextAction: disposition.kind === "review-provenance" || disposition.kind === "command-correction" || disposition.kind === "controller-defect" && disposition.defect === "opaque-native-context" ? "verification" : disposition.kind === "review-blocker" ? "clarification" : "correction"
36924
+ nextAction: replacement || disposition.kind === "review-provenance" || disposition.kind === "command-correction" || disposition.kind === "controller-defect" && disposition.defect === "opaque-native-context" ? "verification" : disposition.kind === "review-blocker" ? "clarification" : "correction"
36834
36925
  };
36835
36926
  if (new TextEncoder().encode(canonicalJson(receipt2)).length > 16384) {
36836
36927
  return refuse2("recovery-receipt-too-large", "Narrow the recovery scope to the supported bounded incident");
@@ -36847,6 +36938,9 @@ function recoveryRequest(value) {
36847
36938
  if (value === void 0 || !record10(value) || !exactKeys2(value, ["schemaVersion", "closureEventId", "expectedJournalHash", "disposition"]) || value["schemaVersion"] !== 1 || typeof value["closureEventId"] !== "string" || typeof value["expectedJournalHash"] !== "string" || !/^sha256:[a-f0-9]{64}$/.test(value["expectedJournalHash"]) || value["disposition"] === void 0 || !record10(value["disposition"]))
36848
36939
  return false;
36849
36940
  const disposition = value["disposition"];
36941
+ if (disposition["kind"] === "preparation-invocation") {
36942
+ return exactKeys2(disposition, ["kind", "completionEventIds"]) && Array.isArray(disposition["completionEventIds"]) && disposition["completionEventIds"].length > 0 && disposition["completionEventIds"].length <= 64 && disposition["completionEventIds"].every((item) => typeof item === "string" && /^evt_[A-Za-z0-9_-]{8,100}$/.test(item)) && new Set(disposition["completionEventIds"]).size === disposition["completionEventIds"].length;
36943
+ }
36850
36944
  if (disposition["kind"] === "command-correction") {
36851
36945
  return exactKeys2(disposition, ["kind", "pairs", "resolutionArtifact"]) && isCommandEvidenceCorrections(disposition["pairs"]) && artifact(disposition["resolutionArtifact"]);
36852
36946
  }
@@ -36867,11 +36961,12 @@ function recoveryObservation(value) {
36867
36961
  "currentInputHashes",
36868
36962
  "maxRounds",
36869
36963
  "expectedSource",
36964
+ ...value["reviewPolicy"] === void 0 ? [] : ["reviewPolicy"],
36870
36965
  ...value["resolutionArtifact"] === void 0 ? [] : ["resolutionArtifact"],
36871
36966
  ...value["reviewSubject"] === void 0 ? [] : ["reviewSubject"],
36872
36967
  ...value["reviewBindings"] === void 0 ? [] : ["reviewBindings"],
36873
36968
  ...value["evidenceDependencies"] === void 0 ? [] : ["evidenceDependencies"]
36874
- ]) || !["pre-implementation", "post-implementation"].includes(String(value["stage"])) || !["runtime:codex", "runtime:claude"].includes(String(value["expectedSource"])) || typeof value["maxRounds"] !== "number" || !Number.isSafeInteger(value["maxRounds"]) || value["maxRounds"] < 1 || value["maxRounds"] > 8 || value["contractVersions"] === void 0 || !record10(value["contractVersions"]) || value["currentInputHashes"] === void 0 || !record10(value["currentInputHashes"]))
36969
+ ]) || value["reviewPolicy"] !== void 0 && value["reviewPolicy"] !== "bounded-corrections-v1" || !["pre-implementation", "post-implementation"].includes(String(value["stage"])) || !["runtime:codex", "runtime:claude"].includes(String(value["expectedSource"])) || typeof value["maxRounds"] !== "number" || !Number.isSafeInteger(value["maxRounds"]) || value["maxRounds"] < 1 || value["maxRounds"] > 8 || value["contractVersions"] === void 0 || !record10(value["contractVersions"]) || value["currentInputHashes"] === void 0 || !record10(value["currentInputHashes"]))
36875
36970
  return false;
36876
36971
  return Object.keys(value["contractVersions"]).length <= 64 && Object.keys(value["currentInputHashes"]).length <= 64 && Object.entries(value["contractVersions"]).every(([key, version3]) => specialistId2(key) && typeof version3 === "number" && Number.isSafeInteger(version3) && version3 >= 1 && version3 <= 1e4) && Object.entries(value["currentInputHashes"]).every(([key, hash7]) => specialistId2(key) && typeof hash7 === "string" && /^sha256:[a-f0-9]{64}$/.test(hash7)) && (value["reviewSubject"] === void 0 || isReviewSubject(value["reviewSubject"])) && (value["reviewBindings"] === void 0 || Array.isArray(value["reviewBindings"]) && value["reviewBindings"].length <= 64 && value["reviewBindings"].every(reviewBinding)) && (value["resolutionArtifact"] === void 0 || artifact(value["resolutionArtifact"])) && (value["evidenceDependencies"] === void 0 || record10(value["evidenceDependencies"]) && Object.keys(value["evidenceDependencies"]).length <= 64 && Object.entries(value["evidenceDependencies"]).every(([key, hash7]) => key.length > 0 && key.length <= 500 && typeof hash7 === "string" && /^sha256:[a-f0-9]{64}$/.test(hash7)));
36877
36972
  }
@@ -38725,10 +38820,13 @@ function recoveredPreparationTargets(events) {
38725
38820
  const request = record15(payload?.["request"] ?? null);
38726
38821
  const disposition = record15(request?.["disposition"] ?? null);
38727
38822
  const ids = disposition?.["completionEventIds"];
38728
- if (observation2?.["stage"] !== "pre-implementation" || disposition?.["kind"] !== "review-blocker" || !Array.isArray(ids))
38823
+ if (observation2?.["stage"] !== "pre-implementation" || !["review-blocker", "preparation-invocation"].includes(String(disposition?.["kind"])) || !Array.isArray(ids))
38729
38824
  return void 0;
38730
38825
  return {
38731
38826
  recoverySeq: recovery.seq,
38827
+ replacement: disposition?.["kind"] === "preparation-invocation",
38828
+ inputHashes: record15(observation2["currentInputHashes"] ?? {}) ?? {},
38829
+ contractVersions: record15(observation2["contractVersions"] ?? {}) ?? {},
38732
38830
  specialistIds: events.filter((item) => item.kind === "specialist.completed" && ids.includes(item.eventId)).map((item) => item.subject)
38733
38831
  };
38734
38832
  }
@@ -38800,7 +38898,7 @@ function orchestrateMissionTeam(originalInput) {
38800
38898
  const start = missionStart(input2);
38801
38899
  const recovered = validatedRecoveredReviewEvents(input2.stream.events);
38802
38900
  const reviewEvents = recovered.ok ? recovered.events : input2.stream.events;
38803
- const preparationRecovery = recovered.ok ? recoveredPreparationTargets(reviewEvents) : void 0;
38901
+ const preparationRecovery = recovered.ok ? recoveredPreparationTargets(input2.stream.events) : void 0;
38804
38902
  const writerEvents = writerCompletions(input2);
38805
38903
  const preparationCorrections = writerEvents.filter((event) => lifecycleField(event, "actionKind") === "run-preparation-correction");
38806
38904
  const completions2 = writerEvents.filter((event) => lifecycleField(event, "actionKind") !== "run-preparation-correction");
@@ -38885,6 +38983,9 @@ function orchestrateMissionTeam(originalInput) {
38885
38983
  }
38886
38984
  if (!migrated.ok)
38887
38985
  return stopped("degraded", preReview, baseVerdict, migrated.reasons);
38986
+ if (preparationRecovery?.replacement && firstImplementationSeq === void 0 && requiredSpecialists(input2.plan, "pre-implementation").some((id3) => input2.currentInputHashesByStage["pre-implementation"][id3] !== preparationRecovery.inputHashes[id3] || contractVersions(input2.plan)[id3] !== preparationRecovery.contractVersions[id3])) {
38987
+ return stopped("blocked", preReview, baseVerdict, ["Preparation replacement inputs or contracts changed; reconcile the admitted subject before dispatch"]);
38988
+ }
38888
38989
  const pendingEvidence = obligationStop(obligations, preReview, baseVerdict, firstImplementationSeq === void 0);
38889
38990
  const migration = migrated.migration;
38890
38991
  if (migration !== void 0) {
@@ -38916,7 +39017,7 @@ function orchestrateMissionTeam(originalInput) {
38916
39017
  if (pendingEvidence !== void 0 && !correctiveContinuation) {
38917
39018
  return applyRuntimeCertification(pendingEvidence, input2.specialistRuntime);
38918
39019
  }
38919
- if (preparationRecovery !== void 0 && (lastPreparationSeq === void 0 || lastPreparationSeq < preparationRecovery.recoverySeq)) {
39020
+ if (preparationRecovery !== void 0 && !preparationRecovery.replacement && (lastPreparationSeq === void 0 || lastPreparationSeq < preparationRecovery.recoverySeq)) {
38920
39021
  if (preReview.issues.length > 0) {
38921
39022
  return decideReviewPhase(start, preReview, baseVerdict, "pre-implementation");
38922
39023
  }
@@ -38971,8 +39072,7 @@ function orchestrateMissionTeam(originalInput) {
38971
39072
  requiredSpecialists: requiredSpecialists(input2.plan, "post-implementation", start.boundedReview),
38972
39073
  contractVersions: contractVersions(input2.plan),
38973
39074
  currentInputHashes: input2.currentInputHashesByStage["post-implementation"],
38974
- maxRounds: start.boundedReview ? 3 : input2.maxReviewRounds,
38975
- ...start.boundedReview ? { maxCorrectionBatches: 2 } : {},
39075
+ ...start.boundedReview ? BOUNDED_REVIEW_BUDGET : { maxRounds: input2.maxReviewRounds },
38976
39076
  evidenceObligations: obligations,
38977
39077
  validProofIds: input2.stream.events.flatMap((event) => {
38978
39078
  if (event.kind !== "evidence.recorded")
@@ -46479,7 +46579,7 @@ function dependencyEntries(pkg) {
46479
46579
  function technology(id3, version3, source2) {
46480
46580
  return Object.freeze({ id: id3, version: version3, sources: Object.freeze([source2]) });
46481
46581
  }
46482
- function packageTechnologies(workspace) {
46582
+ function packageTechnologies(workspace, recipe) {
46483
46583
  const technologies = /* @__PURE__ */ new Map();
46484
46584
  const source2 = workspace.path === "." ? "package.json" : `${workspace.path}/package.json`;
46485
46585
  for (const [dependency, version3] of dependencyEntries(workspace.packageJson)) {
@@ -46492,7 +46592,10 @@ function packageTechnologies(workspace) {
46492
46592
  }
46493
46593
  }
46494
46594
  if (workspace.path === ".") {
46495
- technologies.set("node", technology("node", exactVersion(process.versions.node), "runtime:node"));
46595
+ const declaredNode2 = workspace.packageJson.engines?.node;
46596
+ const projectNode = typeof declaredNode2 === "string" && /^\d+\.\d+\.\d+$/.test(declaredNode2) ? declaredNode2 : null;
46597
+ const projectNodeSource = projectNode === null && typeof declaredNode2 === "string" ? `package.json:engines.node:${declaredNode2}` : "package.json:engines.node";
46598
+ technologies.set("node", recipe === "runtime-v1" ? technology("node", exactVersion(process.versions.node), "runtime:node") : technology("node", projectNode, projectNodeSource));
46496
46599
  const packageManager = workspace.packageJson.packageManager;
46497
46600
  if (packageManager !== void 0) {
46498
46601
  const separator = packageManager.indexOf("@");
@@ -46518,7 +46621,7 @@ function packageTechnologies(workspace) {
46518
46621
  function validChangedFile(file2) {
46519
46622
  return file2.length > 0 && !file2.startsWith("/") && !file2.startsWith("../") && !file2.includes("/../") && !file2.includes("\\") && posix.normalize(file2) === file2;
46520
46623
  }
46521
- function detectProfileInput(root, files) {
46624
+ function detectProfileInput(root, files, recipe = "runtime-v1") {
46522
46625
  if (!files.every(validChangedFile)) {
46523
46626
  throw new Error("PROFILE_INPUT_INVALID: changed files must remain inside the project root");
46524
46627
  }
@@ -46526,7 +46629,7 @@ function detectProfileInput(root, files) {
46526
46629
  const rootWorkspace = workspaces.find((workspace) => workspace.path === ".");
46527
46630
  const projects2 = workspaces.map((workspace) => Object.freeze({
46528
46631
  path: workspace.path,
46529
- technologies: packageTechnologies(workspace)
46632
+ technologies: packageTechnologies(workspace, recipe)
46530
46633
  }));
46531
46634
  if (projects2.length > 1) {
46532
46635
  const rootProject = projects2.find((project) => project.path === ".");
@@ -55764,17 +55867,18 @@ async function createMission(root, input2) {
55764
55867
  );
55765
55868
  await writeMissionMetadata(run2, safeInput, createdAt);
55766
55869
  }
55767
- async function writeMissionControllerPlan(root, missionId, plan2, ticket, baseCommit) {
55870
+ async function writeMissionControllerPlan(root, missionId, plan2, ticket, baseCommit, inputRecipe) {
55768
55871
  const run2 = await existingRunDirectory(root, missionId);
55769
- const routingHash = missionControllerRoutingHash(plan2, ticket, baseCommit);
55872
+ const routingHash = missionControllerRoutingHash(plan2, ticket, baseCommit, inputRecipe);
55770
55873
  const handle3 = await open$1(join(run2, "controller-plan.json"), "wx", 384);
55771
55874
  try {
55772
55875
  await handle3.writeFile(`${JSON.stringify({
55773
- schemaVersion: baseCommit === void 0 ? 1 : 2,
55876
+ schemaVersion: inputRecipe === void 0 ? baseCommit === void 0 ? 1 : 2 : 3,
55774
55877
  routingHash,
55775
55878
  plan: plan2,
55776
55879
  ticket,
55777
- ...baseCommit === void 0 ? {} : { baseCommit }
55880
+ ...baseCommit === void 0 ? {} : { baseCommit },
55881
+ ...inputRecipe === void 0 ? {} : { inputRecipe }
55778
55882
  })}
55779
55883
  `, "utf8");
55780
55884
  } finally {
@@ -55803,28 +55907,38 @@ async function loadMissionControllerPlan(root, missionId) {
55803
55907
  "routingHash",
55804
55908
  "plan",
55805
55909
  "ticket",
55806
- ...parsed.schemaVersion === 2 ? ["baseCommit"] : []
55910
+ ...parsed.schemaVersion === 2 || parsed.schemaVersion === 3 ? ["baseCommit"] : [],
55911
+ ...parsed.schemaVersion === 3 ? ["inputRecipe"] : []
55807
55912
  ])) {
55808
55913
  throw new Error("MISSION_CONTROLLER_PLAN_INVALID: plan envelope is malformed");
55809
55914
  }
55810
55915
  const plan2 = parseMissionSpecialistPlan(parsed.plan);
55811
55916
  const ticket = parseMissionControllerTicket(parsed.ticket);
55812
55917
  const routingHash = typeof parsed.routingHash === "string" ? parsed.routingHash : "";
55813
- const baseCommit = parsed.schemaVersion === 2 ? parsed.baseCommit : void 0;
55814
- if (parsed.schemaVersion !== 1 && parsed.schemaVersion !== 2 || parsed.schemaVersion === 2 && (typeof baseCommit !== "string" || !/^(?:[a-f0-9]{40}|[a-f0-9]{64})$/.test(baseCommit)) || !/^sha256:[a-f0-9]{64}$/.test(routingHash)) {
55918
+ const baseCommit = parsed.schemaVersion === 2 || parsed.schemaVersion === 3 ? parsed.baseCommit : void 0;
55919
+ const inputRecipe = parsed.schemaVersion === 3 && parsed.inputRecipe === "project-v1" ? "project-v1" : void 0;
55920
+ if (parsed.schemaVersion !== 1 && parsed.schemaVersion !== 2 && parsed.schemaVersion !== 3 || parsed.schemaVersion === 3 && inputRecipe === void 0 || (parsed.schemaVersion === 2 || parsed.schemaVersion === 3) && (typeof baseCommit !== "string" || !/^(?:[a-f0-9]{40}|[a-f0-9]{64})$/.test(baseCommit)) || !/^sha256:[a-f0-9]{64}$/.test(routingHash)) {
55815
55921
  throw new Error("MISSION_CONTROLLER_PLAN_INVALID: plan integrity check failed");
55816
55922
  }
55817
55923
  const base = typeof baseCommit === "string" ? { baseCommit } : {};
55818
- if (missionControllerRoutingHash(plan2, ticket, base.baseCommit) !== routingHash) {
55924
+ if (missionControllerRoutingHash(plan2, ticket, base.baseCommit, inputRecipe) !== routingHash) {
55819
55925
  throw new Error("MISSION_CONTROLLER_PLAN_INVALID: plan integrity check failed");
55820
55926
  }
55821
- return Object.freeze({ plan: plan2, ticket, routingHash, ...base });
55927
+ return Object.freeze({ plan: plan2, ticket, routingHash, ...base, ...inputRecipe === void 0 ? {} : { inputRecipe } });
55822
55928
  }
55823
- function missionControllerRoutingHash(plan2, ticket, baseCommit) {
55929
+ function missionControllerRoutingHash(plan2, ticket, baseCommit, inputRecipe) {
55930
+ if (inputRecipe !== void 0 && (inputRecipe !== "project-v1" || baseCommit === void 0)) {
55931
+ throw new Error("MISSION_CONTROLLER_PLAN_INVALID: project input recipe requires a committed baseline");
55932
+ }
55824
55933
  if (baseCommit !== void 0 && !/^(?:[a-f0-9]{40}|[a-f0-9]{64})$/.test(baseCommit)) {
55825
55934
  throw new Error("MISSION_REVIEW_BASE_INVALID: expected a full commit object ID");
55826
55935
  }
55827
- return canonicalJsonHash({ plan: plan2, ticket, ...baseCommit === void 0 ? {} : { baseCommit } });
55936
+ return canonicalJsonHash({
55937
+ plan: plan2,
55938
+ ticket,
55939
+ ...baseCommit === void 0 ? {} : { baseCommit },
55940
+ ...inputRecipe === void 0 ? {} : { inputRecipe }
55941
+ });
55828
55942
  }
55829
55943
  function unknownRecord2(value) {
55830
55944
  return typeof value === "object" && Boolean(value) && !Array.isArray(value);
@@ -56236,6 +56350,7 @@ async function loadProfiles(root, coreProfileDirectory) {
56236
56350
  // src/lib/mission-inputs.ts
56237
56351
  var execFile2 = promisify(execFile);
56238
56352
  var MAX_TICKET_BYTES = 1e5;
56353
+ var MAX_REVIEW_PATCH_BYTES = 16e6;
56239
56354
  async function readTicket(root, ticketPath) {
56240
56355
  const canonicalRoot = await realpath(resolve(root));
56241
56356
  const loaded = await readBoundedProjectFile({
@@ -56291,7 +56406,7 @@ async function missionReviewBase(root) {
56291
56406
  throw new Error("MISSION_REVIEW_BASE_INVALID: a committed Git baseline is required");
56292
56407
  }
56293
56408
  }
56294
- async function captureMissionReviewSubject(root, baseCommit, committed = false) {
56409
+ async function captureMissionReviewSubject(root, baseCommit, committed = false, hashFormat = committed ? "committed" : "legacy") {
56295
56410
  if (baseCommit === void 0) {
56296
56411
  throw new Error(
56297
56412
  "MISSION_REVIEW_BASE_MISSING: legacy mission has no review baseline; preserve its history and start a new mission"
@@ -56331,7 +56446,17 @@ async function captureMissionReviewSubject(root, baseCommit, committed = false)
56331
56446
  "--relative",
56332
56447
  ...range,
56333
56448
  ...paths
56334
- ], options2),
56449
+ ], {
56450
+ ...options2,
56451
+ maxBuffer: MAX_REVIEW_PATCH_BYTES
56452
+ }).catch((error62) => {
56453
+ if (error62 instanceof Error && "code" in error62 && error62.code === "ERR_CHILD_PROCESS_STDIO_MAXBUFFER") {
56454
+ throw new Error(
56455
+ `MISSION_REVIEW_PATCH_TOO_LARGE: Git review patch exceeds ${MAX_REVIEW_PATCH_BYTES} bytes`
56456
+ );
56457
+ }
56458
+ throw error62;
56459
+ }),
56335
56460
  execFile2("git", [
56336
56461
  "diff",
56337
56462
  "--no-ext-diff",
@@ -56364,7 +56489,7 @@ async function captureMissionReviewSubject(root, baseCommit, committed = false)
56364
56489
  files,
56365
56490
  hash: canonicalJsonHash({
56366
56491
  baseCommit,
56367
- ...reviewedCommit === void 0 ? {} : { reviewedCommit },
56492
+ ...hashFormat === "legacy" ? {} : { reviewedCommit },
56368
56493
  diff: patch.stdout,
56369
56494
  files: files.files
56370
56495
  })
@@ -56438,10 +56563,10 @@ function detectedStack(root, profileInput) {
56438
56563
  status: "known"
56439
56564
  });
56440
56565
  }
56441
- async function planMission(root, ticketPath, generatedAt = (/* @__PURE__ */ new Date()).toISOString()) {
56442
- return (await planBoundMission(root, ticketPath, generatedAt)).plan;
56566
+ async function planMission(root, ticketPath, generatedAt = (/* @__PURE__ */ new Date()).toISOString(), inputRecipe = "runtime-v1") {
56567
+ return (await planBoundMission(root, ticketPath, generatedAt, void 0, void 0, inputRecipe)).plan;
56443
56568
  }
56444
- async function compileMission(root, ticket, generatedAt, detectedFiles, specialistCatalog) {
56569
+ async function compileMission(root, ticket, generatedAt, detectedFiles, specialistCatalog, inputRecipe = "runtime-v1") {
56445
56570
  const [coreRoot, diff] = await Promise.all([
56446
56571
  findCoreSource(),
56447
56572
  detectedFiles ?? gitFiles(root)
@@ -56451,7 +56576,7 @@ async function compileMission(root, ticket, generatedAt, detectedFiles, speciali
56451
56576
  loadProfiles(root, join(coreRoot, "profiles")),
56452
56577
  specialistCatalog ?? loadSpecialists(coreRoot)
56453
56578
  ]);
56454
- const profileInput = detectProfileInput(root, diff.files);
56579
+ const profileInput = detectProfileInput(root, diff.files, inputRecipe);
56455
56580
  const stack = detectedStack(root, profileInput);
56456
56581
  return compileMissionPlan({
56457
56582
  ticket: { id: ticket.id, title: ticket.title, body: ticket.body },
@@ -56471,9 +56596,9 @@ function controllerTicketBinding(ticket) {
56471
56596
  contentHash: `sha256:${createHash("sha256").update(ticket.body).digest("hex")}`
56472
56597
  });
56473
56598
  }
56474
- async function planBoundMission(root, ticketPath, generatedAt = (/* @__PURE__ */ new Date()).toISOString(), detectedFiles, specialistCatalog) {
56599
+ async function planBoundMission(root, ticketPath, generatedAt = (/* @__PURE__ */ new Date()).toISOString(), detectedFiles, specialistCatalog, inputRecipe = "runtime-v1") {
56475
56600
  const ticket = await readTicket(root, ticketPath);
56476
- const plan2 = await compileMission(root, ticket, generatedAt, detectedFiles, specialistCatalog);
56601
+ const plan2 = await compileMission(root, ticket, generatedAt, detectedFiles, specialistCatalog, inputRecipe);
56477
56602
  return Object.freeze({
56478
56603
  plan: plan2,
56479
56604
  ticket: controllerTicketBinding(ticket)
@@ -67040,6 +67165,10 @@ function parseMissionRecoveryRequest(value) {
67040
67165
  }
67041
67166
  const commandCorrection = disposition["kind"] === "command-correction";
67042
67167
  const ids = disposition["completionEventIds"];
67168
+ if (disposition["kind"] === "preparation-invocation") {
67169
+ if (!exact2(disposition, ["kind", "completionEventIds"]) || !Array.isArray(ids) || ids.length < 1 || ids.length > 64 || !ids.every(eventId) || new Set(ids).size !== ids.length) invalid11();
67170
+ return { ...base, disposition: { kind: "preparation-invocation", completionEventIds: ids } };
67171
+ }
67043
67172
  const artifact2 = disposition["resolutionArtifact"];
67044
67173
  if (!commandCorrection && disposition["kind"] !== "review-blocker" && disposition["kind"] !== "review-provenance" || !exact2(disposition, ["kind", commandCorrection ? "pairs" : "completionEventIds", "resolutionArtifact"]) || !record24(artifact2) || !exact2(artifact2, ["path", "sha256"]) || typeof artifact2["path"] !== "string" || artifact2["path"].length < 1 || artifact2["path"].length > 500 || artifact2["path"].includes("\0") || /^(?:[A-Za-z]:|[/\\])/.test(artifact2["path"]) || artifact2["path"].replaceAll("\\", "/").split("/").includes("..") || !hash4(artifact2["sha256"])) invalid11();
67045
67174
  if (commandCorrection) {
@@ -67817,7 +67946,7 @@ async function recordSpecialistRequests(root, missionId, envelopes, planHash) {
67817
67946
  init_esm_shims();
67818
67947
 
67819
67948
  // package.json
67820
- var version2 = "5.0.2";
67949
+ var version2 = "5.0.4";
67821
67950
 
67822
67951
  // src/lib/runs/verify.ts
67823
67952
  var MAX_CAPTURE_BYTES = 64 * 1024;
@@ -68327,8 +68456,8 @@ async function migrateMissionSpecialist(roots, missionId, request) {
68327
68456
  throw new Error(`SPECIALIST_CONTRACT_MIGRATION_NATIVE: ${capability.limitations.join("; ")}`);
68328
68457
  }
68329
68458
  const assets = await observeSpecialistMigrationAssets(coreRoot, installRoot, identity2.runtime);
68330
- const subject = await captureMissionReviewSubject(workRoot, stored.baseCommit);
68331
- const live = await planBoundMission(workRoot, stored.ticket.path, (/* @__PURE__ */ new Date()).toISOString(), subject.files);
68459
+ const subject = await captureControllerReviewSubject(workRoot, stored.baseCommit, current.inspected.stream.events);
68460
+ const live = await planBoundMission(workRoot, stored.ticket.path, (/* @__PURE__ */ new Date()).toISOString(), subject.files, void 0, stored.inputRecipe);
68332
68461
  if (live.ticket.path !== stored.ticket.path || live.ticket.contentHash !== stored.ticket.contentHash) {
68333
68462
  throw new Error("MISSION_TICKET_CHANGED: migration cannot replace the bound ticket");
68334
68463
  }
@@ -68337,7 +68466,7 @@ async function migrateMissionSpecialist(roots, missionId, request) {
68337
68466
  canonicalJsonHash({ routing: specialist.proof.inputHash, subject: subject.hash })
68338
68467
  ]));
68339
68468
  const comparisonCatalog = await loadSpecialistMigrationComparisonCatalog(coreRoot, assets.declaration, stored.plan);
68340
- const comparison = await planBoundMission(workRoot, stored.ticket.path, (/* @__PURE__ */ new Date()).toISOString(), subject.files, comparisonCatalog);
68469
+ const comparison = await planBoundMission(workRoot, stored.ticket.path, (/* @__PURE__ */ new Date()).toISOString(), subject.files, comparisonCatalog, stored.inputRecipe);
68341
68470
  const originalHashes = Object.fromEntries(comparison.plan.specialists.map((specialist) => [
68342
68471
  specialist.specialistId,
68343
68472
  canonicalJsonHash({ routing: specialist.proof.inputHash, subject: subject.hash })
@@ -68362,6 +68491,18 @@ async function migrateMissionSpecialist(roots, missionId, request) {
68362
68491
  nativeAgentSha256: assets.nativeAgentSha256
68363
68492
  } };
68364
68493
  }
68494
+ function boundedMissionReview(events) {
68495
+ return events.some((event) => event.kind === "mission.started" && objectField(event.payload, "reviewPolicy") === "bounded-corrections-v1") || events.some((event) => event.kind === "mission.recovered" && objectField(objectField(objectField(event.payload, "request"), "disposition"), "kind") === "review-provenance");
68496
+ }
68497
+ function captureControllerReviewSubject(root, baseCommit, events, requireCommitted = false) {
68498
+ const committedFormat = events.some((event) => event.kind === "mission.started" && objectField(event.payload, "reviewPolicy") === "bounded-corrections-v1");
68499
+ return captureMissionReviewSubject(
68500
+ root,
68501
+ baseCommit,
68502
+ requireCommitted || boundedMissionReview(events),
68503
+ committedFormat ? "committed" : "legacy"
68504
+ );
68505
+ }
68365
68506
  async function recoverStoppedMission(roots, missionId, request) {
68366
68507
  const { workRoot, installRoot } = roots;
68367
68508
  const [stored, current, coreRoot] = await Promise.all([
@@ -68393,8 +68534,13 @@ async function recoverStoppedMission(roots, missionId, request) {
68393
68534
  }
68394
68535
  }
68395
68536
  const implemented = inspected.stream.events.some((event) => event.kind === "lead-writer.completed" && objectField(event.payload, "actionKind") !== "run-preparation-correction");
68396
- const subject = implemented ? await captureMissionReviewSubject(workRoot, stored.baseCommit) : void 0;
68397
- const live = await planBoundMission(workRoot, stored.ticket.path, (/* @__PURE__ */ new Date()).toISOString(), subject?.files);
68537
+ const subject = implemented ? await captureControllerReviewSubject(
68538
+ workRoot,
68539
+ stored.baseCommit,
68540
+ inspected.stream.events,
68541
+ provenanceRecovery
68542
+ ) : void 0;
68543
+ const live = await planBoundMission(workRoot, stored.ticket.path, (/* @__PURE__ */ new Date()).toISOString(), subject?.files, void 0, stored.inputRecipe);
68398
68544
  if (live.ticket.path !== stored.ticket.path || live.ticket.contentHash !== stored.ticket.contentHash) {
68399
68545
  throw new Error("MISSION_TICKET_CHANGED: recovery cannot replace the original ticket");
68400
68546
  }
@@ -68411,7 +68557,7 @@ async function recoverStoppedMission(roots, missionId, request) {
68411
68557
  throw new Error("SPECIALIST_CONTRACT_MIGRATION_INVALID: declared or installed contract changed");
68412
68558
  }
68413
68559
  const comparisonCatalog = await loadSpecialistMigrationComparisonCatalog(coreRoot, assets.declaration, stored.plan);
68414
- const comparison = await planBoundMission(workRoot, stored.ticket.path, (/* @__PURE__ */ new Date()).toISOString(), subject.files, comparisonCatalog);
68560
+ const comparison = await planBoundMission(workRoot, stored.ticket.path, (/* @__PURE__ */ new Date()).toISOString(), subject.files, comparisonCatalog, stored.inputRecipe);
68415
68561
  for (const specialist of comparison.plan.specialists) {
68416
68562
  if (specialist.specialistId !== assets.declaration.specialistId) {
68417
68563
  currentInputHashes[specialist.specialistId] = canonicalJsonHash({
@@ -68423,19 +68569,19 @@ async function recoverStoppedMission(roots, missionId, request) {
68423
68569
  }
68424
68570
  const provenance4 = request.disposition.kind !== "review-provenance" ? void 0 : await readRecoveryReviewBindings(workRoot, request.disposition.resolutionArtifact.path);
68425
68571
  const resolutionArtifact = provenance4?.artifact ?? (request.disposition.kind === "review-blocker" || request.disposition.kind === "command-correction" ? await recoveryResolutionArtifact(workRoot, request.disposition.resolutionArtifact.path) : void 0);
68426
- const committedSubject = provenance4 === void 0 ? void 0 : await captureMissionReviewSubject(workRoot, stored.baseCommit, true);
68427
68572
  const opaqueContextRecovery = request.disposition.kind === "controller-defect" && request.disposition.defect === "opaque-native-context";
68428
- const recoverySpecialists = opaqueContextRecovery ? migration.plan.specialists.filter((value) => value.state === "applicable" && value.stages?.includes("pre-implementation")) : migration.plan.specialists;
68573
+ const recoverySpecialists = opaqueContextRecovery || request.disposition.kind === "preparation-invocation" ? migration.plan.specialists.filter((value) => value.state === "applicable" && value.stages?.includes("pre-implementation")) : migration.plan.specialists;
68429
68574
  const observation2 = {
68430
- ...provenance4 === void 0 || committedSubject?.baseCommit === void 0 || committedSubject.reviewedCommit === void 0 ? {} : {
68575
+ ...provenance4 === void 0 || subject?.baseCommit === void 0 || subject.reviewedCommit === void 0 ? {} : {
68431
68576
  reviewBindings: provenance4.bindings,
68432
68577
  reviewSubject: {
68433
68578
  taskId: missionId,
68434
- baseCommit: committedSubject.baseCommit,
68435
- reviewedCommit: committedSubject.reviewedCommit,
68579
+ baseCommit: subject.baseCommit,
68580
+ reviewedCommit: subject.reviewedCommit,
68436
68581
  acceptanceCriteriaHash: stored.ticket.contentHash
68437
68582
  }
68438
68583
  },
68584
+ ...implemented && (provenanceRecovery || boundedMissionReview(inspected.stream.events)) ? { reviewPolicy: "bounded-corrections-v1" } : {},
68439
68585
  stage: implemented ? "post-implementation" : "pre-implementation",
68440
68586
  maxRounds: 2,
68441
68587
  evidenceDependencies: { "git:working-tree": current.project.diffHash },
@@ -68499,13 +68645,14 @@ async function dispatchMissionSpecialists(roots, input2, generatedAt = (/* @__PU
68499
68645
  const inspected = current?.inspected ?? initialInspection;
68500
68646
  requireOpenMission(inspected.stream.events);
68501
68647
  const implemented = inspected.stream.events.some((event) => event.kind === "lead-writer.completed" && isUnknownRecord(event.payload) && event.payload.actionKind !== "run-preparation-correction");
68502
- const boundedReview = inspected.stream.events.some((event) => event.kind === "mission.started" && objectField(event.payload, "reviewPolicy") === "bounded-corrections-v1") || inspected.stream.events.some((event) => event.kind === "mission.recovered" && objectField(objectField(objectField(event.payload, "request"), "disposition"), "kind") === "review-provenance");
68503
- const reviewSubject = implemented ? await captureMissionReviewSubject(workRoot, stored.baseCommit, boundedReview) : void 0;
68648
+ const reviewSubject = implemented ? await captureControllerReviewSubject(workRoot, stored.baseCommit, inspected.stream.events) : void 0;
68504
68649
  const live = await planBoundMission(
68505
68650
  workRoot,
68506
68651
  stored.ticket.path,
68507
68652
  generatedAt,
68508
- reviewSubject?.files
68653
+ reviewSubject?.files,
68654
+ void 0,
68655
+ stored.inputRecipe
68509
68656
  );
68510
68657
  const livePlan = live.plan;
68511
68658
  if (live.ticket.path !== stored.ticket.path || live.ticket.contentHash !== stored.ticket.contentHash) {
@@ -68536,7 +68683,7 @@ async function dispatchMissionSpecialists(roots, input2, generatedAt = (/* @__PU
68536
68683
  throw new Error("SPECIALIST_CONTRACT_MIGRATION_INVALID: declared or installed contract changed");
68537
68684
  }
68538
68685
  const catalog = await loadSpecialistMigrationComparisonCatalog(coreRoot, assets.declaration, stored.plan);
68539
- const comparison = await planBoundMission(workRoot, stored.ticket.path, generatedAt, reviewSubject.files, catalog);
68686
+ const comparison = await planBoundMission(workRoot, stored.ticket.path, generatedAt, reviewSubject.files, catalog, stored.inputRecipe);
68540
68687
  for (const specialist of comparison.plan.specialists) {
68541
68688
  if (specialist.specialistId !== assets.declaration.specialistId) {
68542
68689
  currentInputHashes[specialist.specialistId] = canonicalJsonHash({
@@ -68571,19 +68718,6 @@ async function dispatchMissionSpecialists(roots, input2, generatedAt = (/* @__PU
68571
68718
  reviewedCommit: reviewSubject.reviewedCommit,
68572
68719
  acceptanceCriteriaHash: stored.ticket.contentHash
68573
68720
  };
68574
- if (reviewBinding2 !== void 0) {
68575
- const restored = validatedRecoveredReviewEvents(inspected.stream.events);
68576
- if (!restored.ok) throw new Error(`MISSION_RECOVERY_INVALID: ${restored.reasons.join("; ")}`);
68577
- const hasProvenanceRecovery = inspected.stream.events.some((event) => event.kind === "mission.recovered" && objectField(objectField(objectField(event.payload, "request"), "disposition"), "kind") === "review-provenance");
68578
- if (hasProvenanceRecovery) for (const event of restored.events) {
68579
- if (event.kind !== "specialist.completed") continue;
68580
- const receipt2 = parseSpecialistCompletionValue(objectField(event.payload, "completion"))?.review;
68581
- const hash7 = objectField(event.payload, "inputHash");
68582
- if (receipt2 !== void 0 && sameReviewSubject(receipt2, reviewBinding2) && typeof hash7 === "string") {
68583
- currentInputHashes[event.subject] = hash7;
68584
- }
68585
- }
68586
- }
68587
68721
  const decision = orchestrateMissionTeam({
68588
68722
  ...reviewBinding2 === void 0 ? {} : { reviewSubject: reviewBinding2 },
68589
68723
  plan: stored.plan,
@@ -68907,7 +69041,7 @@ Fix: ${parsed.fix}
68907
69041
  const journal = roots.installRoot;
68908
69042
  try {
68909
69043
  if (parsed.kind === "plan") {
68910
- const plan2 = await planMission(root, parsed.ticketPath);
69044
+ const plan2 = await planMission(root, parsed.ticketPath, void 0, "project-v1");
68911
69045
  process.stdout.write(parsed.json ? `${JSON.stringify(plan2)}
68912
69046
  ` : `${renderPlan(plan2)}
68913
69047
  `);
@@ -68992,7 +69126,7 @@ ${dispatched.envelopes.map((envelope) => `${envelope.agentName} ${envelope.stage
68992
69126
  }
68993
69127
  if (parsed.kind === "start") {
68994
69128
  const baseCommit = parsed.ticketPath === void 0 ? void 0 : await missionReviewBase(root);
68995
- const bound = parsed.ticketPath === void 0 ? void 0 : await planBoundMission(root, parsed.ticketPath);
69129
+ const bound = parsed.ticketPath === void 0 ? void 0 : await planBoundMission(root, parsed.ticketPath, void 0, void 0, void 0, "project-v1");
68996
69130
  const plan2 = bound?.plan;
68997
69131
  const diff = plan2 === void 0 ? await gitFiles(root) : void 0;
68998
69132
  const stack = diff === void 0 ? void 0 : detectedStack(root, detectProfileInput(root, diff.files));
@@ -69011,7 +69145,7 @@ ${dispatched.envelopes.map((envelope) => `${envelope.agentName} ${envelope.stage
69011
69145
  const controllerPlan = plan2 === void 0 ? void 0 : missionSpecialistPlan(plan2);
69012
69146
  const ticketBinding = bound?.ticket;
69013
69147
  const runtimeIdentity = bound === void 0 ? void 0 : coordinatorRuntimeIdentity(process.env);
69014
- const routingHash = controllerPlan === void 0 ? void 0 : ticketBinding === void 0 ? void 0 : missionControllerRoutingHash(controllerPlan, ticketBinding, baseCommit);
69148
+ const routingHash = controllerPlan === void 0 ? void 0 : ticketBinding === void 0 ? void 0 : missionControllerRoutingHash(controllerPlan, ticketBinding, baseCommit, "project-v1");
69015
69149
  await createMission(journal, {
69016
69150
  missionId,
69017
69151
  title: parsed.title,
@@ -69038,7 +69172,8 @@ ${dispatched.envelopes.map((envelope) => `${envelope.agentName} ${envelope.stage
69038
69172
  missionId,
69039
69173
  controllerPlan,
69040
69174
  ticketBinding,
69041
- baseCommit
69175
+ baseCommit,
69176
+ "project-v1"
69042
69177
  );
69043
69178
  if (storedHash !== routingHash) {
69044
69179
  throw new Error("MISSION_CONTROLLER_PLAN_INVALID: routing hash changed while storing");