voidmachine 5.0.1 → 5.0.3

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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "harness",
3
- "version": "5.0.1",
3
+ "version": "5.0.3",
4
4
  "description": "VoidCorp universal craftsman skills (void-tdd, void-typescript-strict, void-hexagonal-architecture, void-domain-driven-design, void-functional, void-code-review, void-api-and-interface-design, void-source-driven-development, void-context, void-learn, void-decide, void-claude-md, void-observability, void-security-guidance, ...) plus 12 PreToolUse enforcement hooks (tdd-guard, no-any, protect-sensitive-files, block-dangerous-bash, no-ai-design-slop, ...) and PostToolUse/SessionStart lifecycle hooks (incl. trim-large-output token frugality), five read-only critics including doctrine-critic, native architecture/security/QA specialists, and the void-graph, void-doctor and void-audit gestures, which are skills like everything else.",
5
5
  "author": {
6
6
  "name": "VoidCorp",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
- "harnessVersion": "5.0.1",
3
+ "harnessVersion": "5.0.3",
4
4
  "capabilities": [
5
5
  {
6
6
  "id": "skill:pack-mobile/void-eas-build-profile",
@@ -7930,9 +7930,9 @@ function protectedReason(path2, root, shellWrite) {
7930
7930
  return "private key / certificate";
7931
7931
  }
7932
7932
  if (/(?:\.npmrc|\.netrc|\.pgpass)$/.test(base)) return "credential file";
7933
- const sourceTest = /\.(?:test|spec)\.(?:[cm]?[jt]s|[jt]sx)$/.test(base);
7934
- if (!base.endsWith(".md") && (!sourceTest || shellWrite) && /(?:secret|credential)/.test(base)) {
7935
- return sourceTest && shellWrite ? "credential-named source test with unavailable shell content; use Write/Edit or apply_patch" : "credential file";
7933
+ const sourceModule = /\.(?:[cm]?[jt]s|[jt]sx)$/.test(base);
7934
+ if (!base.endsWith(".md") && (!sourceModule || shellWrite) && /(?:secret|credential)/.test(base)) {
7935
+ return sourceModule && shellWrite ? "credential-named source module with unavailable shell content; use Write/Edit or apply_patch" : "credential file";
7936
7936
  }
7937
7937
  if ((/* @__PURE__ */ new Set([
7938
7938
  "package-lock.json",
@@ -7972,26 +7972,31 @@ var HIGH_CONFIDENCE = [
7972
7972
  /\bAIza[0-9A-Za-z_-]{35}\b/,
7973
7973
  /-----BEGIN [A-Z ]*PRIVATE KEY-----/
7974
7974
  ];
7975
- var GENERIC_ASSIGNMENT = /(?:_KEY|_SECRET|_TOKEN|_PASSWORD|_PASSWD|_APIKEY)["' ]*[:=]\s*["']([A-Za-z0-9+/=_-]{24,})["']/i;
7975
+ var GENERIC_ASSIGNMENT = /(?:_KEY|_SECRET|_TOKEN|_PASSWORD|_PASSWD|_APIKEY)["' ]*[:=]\s*["']([A-Za-z0-9+/=_-]{24,})["']/gi;
7976
+ var CAMEL_ASSIGNMENT = /\b[a-z][A-Za-z0-9_$]*(?:Key|Secret|Token|Password|Passwd)["' ]*[:=]\s*["']([A-Za-z0-9+/=_-]{24,})["']/g;
7976
7977
  var PLACEHOLDER = /process\.env|import\.meta\.env|xxx|changeme|example|redacted|your[-_]|<[a-z]|placeholder|todo/i;
7977
7978
  var EXEMPT_PATH = /\.(?:test|spec)\.|\/__tests__\/|\/__fixtures__\/|\/fixtures\/|\/__generated__\//;
7978
- var CREDENTIAL_SOURCE_TEST = /(?:secret|credential)[^/]*\.(?:test|spec)\.(?:[cm]?[jt]s|[jt]sx)$/i;
7979
+ var CREDENTIAL_SOURCE_MODULE = /(?:secret|credential)[^/]*\.(?:[cm]?[jt]s|[jt]sx)$/i;
7979
7980
  function lineHasSecret(line) {
7980
7981
  if (line.includes("allow-secret-pattern:")) return false;
7981
7982
  if (HIGH_CONFIDENCE.some((pattern2) => pattern2.test(line))) return true;
7982
- const assignment = line.match(GENERIC_ASSIGNMENT);
7983
- if (assignment === null || PLACEHOLDER.test(line)) return false;
7984
- const value = assignment[1] ?? "";
7985
- if (/^[0-9a-f]+$/i.test(value) || /^[0-9a-f]{8}(?:-[0-9a-f]{4}){3}-[0-9a-f]{12}$/i.test(value)) {
7986
- return false;
7983
+ for (const pattern2 of [GENERIC_ASSIGNMENT, CAMEL_ASSIGNMENT]) {
7984
+ for (const assignment of line.matchAll(pattern2)) {
7985
+ const value = assignment[1] ?? "";
7986
+ if (PLACEHOLDER.test(value)) continue;
7987
+ if (/^[0-9a-f]+$/i.test(value) || /^[0-9a-f]{8}(?:-[0-9a-f]{4}){3}-[0-9a-f]{12}$/i.test(value)) {
7988
+ continue;
7989
+ }
7990
+ if (/[A-Za-z]/.test(value) && /[0-9]/.test(value)) return true;
7991
+ }
7987
7992
  }
7988
- return /[A-Za-z]/.test(value) && /[0-9]/.test(value);
7993
+ return false;
7989
7994
  }
7990
7995
  function secretContent(edits) {
7991
7996
  const evidence = [];
7992
7997
  for (const edit of edits) {
7993
7998
  const path2 = edit.path.replaceAll("\\", "/");
7994
- if (EXEMPT_PATH.test(path2) && !CREDENTIAL_SOURCE_TEST.test(path2)) continue;
7999
+ if (EXEMPT_PATH.test(path2) && !CREDENTIAL_SOURCE_MODULE.test(path2)) continue;
7995
8000
  edit.addedContent.split(/\r?\n/).forEach((line, index) => {
7996
8001
  if (lineHasSecret(line)) evidence.push(`${edit.path}:${index + 1}`);
7997
8002
  });
package/dist/main.js CHANGED
@@ -36579,6 +36579,92 @@ function opaqueNativeContextDefect(input2) {
36579
36579
  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
36580
  });
36581
36581
  }
36582
+ function preparationInvocationReplacement(input2) {
36583
+ const { events } = input2.stream;
36584
+ const { observation: observation2, request } = input2;
36585
+ if (request.disposition.kind !== "preparation-invocation")
36586
+ return false;
36587
+ const start = events[0];
36588
+ const closure = events.at(-1);
36589
+ const writerRequests = events.filter((event) => event.kind === "lead-writer.requested");
36590
+ const writers = events.filter((event) => event.kind === "lead-writer.completed");
36591
+ const writer = writers[0];
36592
+ const writerRequest = writerRequests[0];
36593
+ 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)))
36594
+ return false;
36595
+ const allowed = [
36596
+ "mission.started",
36597
+ "mission.closed",
36598
+ "lead-writer.requested",
36599
+ "lead-writer.completed",
36600
+ "specialist.requested",
36601
+ "specialist.started",
36602
+ "specialist.completed",
36603
+ "evidence.recorded",
36604
+ "specialist.evidence-classification-requested",
36605
+ "specialist.evidence-started",
36606
+ "specialist.evidence-classified",
36607
+ "specialist.evidence-discharge-requested",
36608
+ "specialist.evidence-discharged"
36609
+ ];
36610
+ if (events.some((event) => !allowed.includes(event.kind)))
36611
+ return false;
36612
+ const required2 = Object.keys(observation2.contractVersions);
36613
+ const panel = completions(events);
36614
+ const invocations = events.filter((event) => ["specialist.requested", "specialist.started", "specialist.completed"].includes(event.kind));
36615
+ if (required2.length === 0 || panel.length !== required2.length * 2 || invocations.length !== panel.length * 3)
36616
+ return false;
36617
+ const ids = request.disposition.completionEventIds;
36618
+ if (ids.length === 0 || new Set(ids).size !== ids.length)
36619
+ return false;
36620
+ for (const specialist of required2) {
36621
+ for (const round of [1, 2]) {
36622
+ const matching = panel.filter((item2) => item2.event.subject === specialist && field4(item2.event, "reviewRound") === round);
36623
+ const item = matching[0];
36624
+ if (matching.length !== 1 || item === void 0)
36625
+ return false;
36626
+ const { event, completion } = item;
36627
+ 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)
36628
+ return false;
36629
+ const requests = invocations.filter((candidate) => matchesRequest(event, candidate));
36630
+ const requested = requests[0];
36631
+ const starts = invocations.filter((candidate) => candidate.kind === "specialist.started" && candidate.subject === specialist && field4(candidate, "reviewRound") === round);
36632
+ const started = starts[0];
36633
+ 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)))
36634
+ return false;
36635
+ }
36636
+ }
36637
+ const proofs = events.flatMap((event) => {
36638
+ if (event.kind !== "evidence.recorded")
36639
+ return [];
36640
+ const parsed = parseEvidence(field4(event, "evidence"));
36641
+ return parsed.ok ? [{ eventId: event.eventId, evidence: parsed.value }] : [];
36642
+ });
36643
+ const obligations = reduceEvidenceObligations({
36644
+ events,
36645
+ expectedSource: observation2.expectedSource,
36646
+ phase: "pre-implementation",
36647
+ proofs,
36648
+ evidenceContext: {
36649
+ missionId: start.missionId,
36650
+ dependencies: observation2.evidenceDependencies ?? {}
36651
+ }
36652
+ });
36653
+ if (obligations.issues.length > 0 || obligations.blockingObligationIds.length > 0)
36654
+ return false;
36655
+ const review = reduceReviewLoop({
36656
+ events,
36657
+ stage: "pre-implementation",
36658
+ expectedSource: observation2.expectedSource,
36659
+ stageStartSeqExclusive: start.seq,
36660
+ afterSeqExclusive: writer.seq,
36661
+ requiredSpecialists: required2.filter(specialistId2),
36662
+ contractVersions: observation2.contractVersions,
36663
+ currentInputHashes: observation2.currentInputHashes,
36664
+ maxRounds: observation2.maxRounds
36665
+ });
36666
+ 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));
36667
+ }
36582
36668
  function partialFanoutCorrections(events) {
36583
36669
  if (events.some((event) => event.kind === "lead-writer.completed" || event.kind === "specialist.failed"))
36584
36670
  return [];
@@ -36714,9 +36800,13 @@ function admitStoppedMission(input2, projectedHistory = input2.stream.events) {
36714
36800
  return refuse2("no-recovery-progress", "Record actual corrective progress before reopening another stopped episode");
36715
36801
  }
36716
36802
  const existing = completions(events).filter((item) => field4(item.event, "stage") === observation2.stage);
36717
- const roundCorrections = partialFanoutCorrections(projectedHistory);
36718
- const inadmissible = staleDispatchCompletions(projectedHistory);
36719
36803
  const disposition = request.disposition;
36804
+ const replacement = disposition.kind === "preparation-invocation";
36805
+ if (replacement && !preparationInvocationReplacement(input2)) {
36806
+ return refuse2("invalid-preparation-invocation", "Name exactly the reused-context preparation completions with intact invocation bindings; replacement is one-time and retains round two");
36807
+ }
36808
+ const roundCorrections = replacement ? [] : partialFanoutCorrections(projectedHistory);
36809
+ const inadmissible = replacement ? disposition.completionEventIds : staleDispatchCompletions(projectedHistory);
36720
36810
  if (disposition.kind === "controller-defect" && (disposition.defect === "partial-fanout-round" ? roundCorrections.length === 0 : disposition.defect === "stale-input-dispatch" ? inadmissible.length === 0 : !opaqueNativeContextDefect(input2))) {
36721
36811
  return refuse2("unproven-controller-defect", "The journal must prove the requested controller defect; do not reset its budget");
36722
36812
  }
@@ -36767,8 +36857,8 @@ function admitStoppedMission(input2, projectedHistory = input2.stream.events) {
36767
36857
  const projected = applyRoundCorrections(projectedHistory, roundCorrections).filter((event) => !inadmissible.includes(event.eventId));
36768
36858
  const required2 = Object.keys(observation2.contractVersions).filter(specialistId2);
36769
36859
  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;
36860
+ const stageStart = observation2.stage === "post-implementation" ? writers.find((event) => field4(event, "actionKind") !== "run-preparation-correction")?.seq : replacement ? events[0]?.seq : void 0;
36861
+ const lastWriter = observation2.stage === "post-implementation" || replacement ? writers.at(-1)?.seq : void 0;
36772
36862
  const migration = validatedSpecialistContractMigrationBoundary(events);
36773
36863
  if (!migration.ok)
36774
36864
  return refuse2("invalid-migration-receipt", migration.reasons.join("; "));
@@ -36792,7 +36882,7 @@ function admitStoppedMission(input2, projectedHistory = input2.stream.events) {
36792
36882
  maxRounds: observation2.maxRounds
36793
36883
  };
36794
36884
  const originalReview = reduceReviewLoop({ ...reviewInput, events: projectedHistory });
36795
- if (originalReview.issues.some((issue4) => issue4.code !== "wrong-review-round")) {
36885
+ if (originalReview.issues.some((issue4) => replacement ? issue4.code !== "reused-context" || !inadmissible.includes(issue4.eventId) : issue4.code !== "wrong-review-round")) {
36796
36886
  return refuse2("inconsistent-review", "Resolve inconsistent source, contract or context evidence before recovery");
36797
36887
  }
36798
36888
  const review = reduceReviewLoop({ ...reviewInput, events: projected });
@@ -36802,8 +36892,8 @@ function admitStoppedMission(input2, projectedHistory = input2.stream.events) {
36802
36892
  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
36893
  return refuse2("incomplete-required-panel", "Every required preparation specialist must have its original matching PASS triplet before recovery");
36804
36894
  }
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)
36895
+ 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"))));
36896
+ if (!replacement && disposition.kind !== "review-provenance" && consumedRounds >= observation2.maxRounds)
36807
36897
  return refuse2("review-budget-exhausted", "The real review budget is exhausted; recovery cannot reset it");
36808
36898
  const consumedCorrectionBatches = projected.filter((event) => event.kind === "lead-writer.completed" && field4(event, "actionKind") === "run-correction").length;
36809
36899
  if (disposition.kind === "review-provenance" && consumedCorrectionBatches > 2) {
@@ -36826,11 +36916,11 @@ function admitStoppedMission(input2, projectedHistory = input2.stream.events) {
36826
36916
  roundCorrections,
36827
36917
  consumedRounds,
36828
36918
  remainingRounds: Math.max(0, observation2.maxRounds - consumedRounds),
36829
- ...disposition.kind !== "review-provenance" ? {} : {
36919
+ ...!replacement && disposition.kind !== "review-provenance" ? {} : {
36830
36920
  consumedCorrectionBatches,
36831
36921
  remainingCorrectionBatches: 2 - consumedCorrectionBatches
36832
36922
  },
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"
36923
+ 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
36924
  };
36835
36925
  if (new TextEncoder().encode(canonicalJson(receipt2)).length > 16384) {
36836
36926
  return refuse2("recovery-receipt-too-large", "Narrow the recovery scope to the supported bounded incident");
@@ -36847,6 +36937,9 @@ function recoveryRequest(value) {
36847
36937
  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
36938
  return false;
36849
36939
  const disposition = value["disposition"];
36940
+ if (disposition["kind"] === "preparation-invocation") {
36941
+ 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;
36942
+ }
36850
36943
  if (disposition["kind"] === "command-correction") {
36851
36944
  return exactKeys2(disposition, ["kind", "pairs", "resolutionArtifact"]) && isCommandEvidenceCorrections(disposition["pairs"]) && artifact(disposition["resolutionArtifact"]);
36852
36945
  }
@@ -38725,10 +38818,13 @@ function recoveredPreparationTargets(events) {
38725
38818
  const request = record15(payload?.["request"] ?? null);
38726
38819
  const disposition = record15(request?.["disposition"] ?? null);
38727
38820
  const ids = disposition?.["completionEventIds"];
38728
- if (observation2?.["stage"] !== "pre-implementation" || disposition?.["kind"] !== "review-blocker" || !Array.isArray(ids))
38821
+ if (observation2?.["stage"] !== "pre-implementation" || !["review-blocker", "preparation-invocation"].includes(String(disposition?.["kind"])) || !Array.isArray(ids))
38729
38822
  return void 0;
38730
38823
  return {
38731
38824
  recoverySeq: recovery.seq,
38825
+ replacement: disposition?.["kind"] === "preparation-invocation",
38826
+ inputHashes: record15(observation2["currentInputHashes"] ?? {}) ?? {},
38827
+ contractVersions: record15(observation2["contractVersions"] ?? {}) ?? {},
38732
38828
  specialistIds: events.filter((item) => item.kind === "specialist.completed" && ids.includes(item.eventId)).map((item) => item.subject)
38733
38829
  };
38734
38830
  }
@@ -38800,7 +38896,7 @@ function orchestrateMissionTeam(originalInput) {
38800
38896
  const start = missionStart(input2);
38801
38897
  const recovered = validatedRecoveredReviewEvents(input2.stream.events);
38802
38898
  const reviewEvents = recovered.ok ? recovered.events : input2.stream.events;
38803
- const preparationRecovery = recovered.ok ? recoveredPreparationTargets(reviewEvents) : void 0;
38899
+ const preparationRecovery = recovered.ok ? recoveredPreparationTargets(input2.stream.events) : void 0;
38804
38900
  const writerEvents = writerCompletions(input2);
38805
38901
  const preparationCorrections = writerEvents.filter((event) => lifecycleField(event, "actionKind") === "run-preparation-correction");
38806
38902
  const completions2 = writerEvents.filter((event) => lifecycleField(event, "actionKind") !== "run-preparation-correction");
@@ -38885,6 +38981,9 @@ function orchestrateMissionTeam(originalInput) {
38885
38981
  }
38886
38982
  if (!migrated.ok)
38887
38983
  return stopped("degraded", preReview, baseVerdict, migrated.reasons);
38984
+ 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])) {
38985
+ return stopped("blocked", preReview, baseVerdict, ["Preparation replacement inputs or contracts changed; reconcile the admitted subject before dispatch"]);
38986
+ }
38888
38987
  const pendingEvidence = obligationStop(obligations, preReview, baseVerdict, firstImplementationSeq === void 0);
38889
38988
  const migration = migrated.migration;
38890
38989
  if (migration !== void 0) {
@@ -38916,7 +39015,7 @@ function orchestrateMissionTeam(originalInput) {
38916
39015
  if (pendingEvidence !== void 0 && !correctiveContinuation) {
38917
39016
  return applyRuntimeCertification(pendingEvidence, input2.specialistRuntime);
38918
39017
  }
38919
- if (preparationRecovery !== void 0 && (lastPreparationSeq === void 0 || lastPreparationSeq < preparationRecovery.recoverySeq)) {
39018
+ if (preparationRecovery !== void 0 && !preparationRecovery.replacement && (lastPreparationSeq === void 0 || lastPreparationSeq < preparationRecovery.recoverySeq)) {
38920
39019
  if (preReview.issues.length > 0) {
38921
39020
  return decideReviewPhase(start, preReview, baseVerdict, "pre-implementation");
38922
39021
  }
@@ -67040,6 +67139,10 @@ function parseMissionRecoveryRequest(value) {
67040
67139
  }
67041
67140
  const commandCorrection = disposition["kind"] === "command-correction";
67042
67141
  const ids = disposition["completionEventIds"];
67142
+ if (disposition["kind"] === "preparation-invocation") {
67143
+ if (!exact2(disposition, ["kind", "completionEventIds"]) || !Array.isArray(ids) || ids.length < 1 || ids.length > 64 || !ids.every(eventId) || new Set(ids).size !== ids.length) invalid11();
67144
+ return { ...base, disposition: { kind: "preparation-invocation", completionEventIds: ids } };
67145
+ }
67043
67146
  const artifact2 = disposition["resolutionArtifact"];
67044
67147
  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
67148
  if (commandCorrection) {
@@ -67817,7 +67920,7 @@ async function recordSpecialistRequests(root, missionId, envelopes, planHash) {
67817
67920
  init_esm_shims();
67818
67921
 
67819
67922
  // package.json
67820
- var version2 = "5.0.1";
67923
+ var version2 = "5.0.3";
67821
67924
 
67822
67925
  // src/lib/runs/verify.ts
67823
67926
  var MAX_CAPTURE_BYTES = 64 * 1024;
@@ -68425,7 +68528,7 @@ async function recoverStoppedMission(roots, missionId, request) {
68425
68528
  const resolutionArtifact = provenance4?.artifact ?? (request.disposition.kind === "review-blocker" || request.disposition.kind === "command-correction" ? await recoveryResolutionArtifact(workRoot, request.disposition.resolutionArtifact.path) : void 0);
68426
68529
  const committedSubject = provenance4 === void 0 ? void 0 : await captureMissionReviewSubject(workRoot, stored.baseCommit, true);
68427
68530
  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;
68531
+ 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
68532
  const observation2 = {
68430
68533
  ...provenance4 === void 0 || committedSubject?.baseCommit === void 0 || committedSubject.reviewedCommit === void 0 ? {} : {
68431
68534
  reviewBindings: provenance4.bindings,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "voidmachine",
3
- "version": "5.0.1",
3
+ "version": "5.0.3",
4
4
  "description": "void-machine CLI — install an opinionated engineering doctrine on any project; render deterministic project health. Run via `npx voidmachine`; command: void-machine (alias vm).",
5
5
  "license": "MIT",
6
6
  "author": "Folpe @ VoidCorp",
@@ -58,10 +58,10 @@
58
58
  "ws": "8.21.0",
59
59
  "yaml": "^2.5.0",
60
60
  "zod": "^4.6.5",
61
- "@voidcorp/harness-graph": "5.0.1",
62
- "@voidcorp/void-machine": "0.0.0",
63
61
  "@voidcorp/hook-runner": "0.0.0",
64
- "@voidcorp/mission-engine": "0.0.0"
62
+ "@voidcorp/harness-graph": "5.0.3",
63
+ "@voidcorp/mission-engine": "0.0.0",
64
+ "@voidcorp/void-machine": "0.0.0"
65
65
  },
66
66
  "scripts": {
67
67
  "build": "tsup",