voidmachine 5.0.6 → 5.0.7
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/core-assets/.claude-plugin/plugin.json +1 -1
- package/core-assets/data/catalog.v3.json +3 -3
- package/core-assets/data/certification.json +1 -1
- package/core-assets/data/model.json +2 -2
- package/core-assets/skills/void-implement/SKILL.md +7 -6
- package/dist/main.js +79 -40
- package/package.json +4 -4
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "harness",
|
|
3
|
-
"version": "5.0.
|
|
3
|
+
"version": "5.0.7",
|
|
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",
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
"source": {
|
|
6
6
|
"kind": "adapter",
|
|
7
7
|
"version": "3.0.0-alpha.1",
|
|
8
|
-
"rootHash": "sha256:
|
|
8
|
+
"rootHash": "sha256:7a824dcd695bae061ba5ee2b9e797032682dd8ace6a2957015c8a1949248d5d7"
|
|
9
9
|
},
|
|
10
10
|
"nodes": [
|
|
11
11
|
{
|
|
@@ -4331,7 +4331,7 @@
|
|
|
4331
4331
|
}
|
|
4332
4332
|
],
|
|
4333
4333
|
"id": "skill:void-implement",
|
|
4334
|
-
"lines":
|
|
4334
|
+
"lines": 193,
|
|
4335
4335
|
"name": "void-implement",
|
|
4336
4336
|
"owner": "folpe",
|
|
4337
4337
|
"pack": null,
|
|
@@ -4340,7 +4340,7 @@
|
|
|
4340
4340
|
"codex"
|
|
4341
4341
|
],
|
|
4342
4342
|
"source": "packages/core/skills/void-implement/SKILL.md",
|
|
4343
|
-
"staticTokens":
|
|
4343
|
+
"staticTokens": 5864,
|
|
4344
4344
|
"type": "skill"
|
|
4345
4345
|
}
|
|
4346
4346
|
},
|
|
@@ -2195,7 +2195,7 @@
|
|
|
2195
2195
|
}
|
|
2196
2196
|
],
|
|
2197
2197
|
"id": "skill:void-implement",
|
|
2198
|
-
"lines":
|
|
2198
|
+
"lines": 193,
|
|
2199
2199
|
"name": "void-implement",
|
|
2200
2200
|
"owner": "folpe",
|
|
2201
2201
|
"pack": null,
|
|
@@ -2204,7 +2204,7 @@
|
|
|
2204
2204
|
"codex"
|
|
2205
2205
|
],
|
|
2206
2206
|
"source": "packages/core/skills/void-implement/SKILL.md",
|
|
2207
|
-
"staticTokens":
|
|
2207
|
+
"staticTokens": 5864,
|
|
2208
2208
|
"type": "skill"
|
|
2209
2209
|
},
|
|
2210
2210
|
{
|
|
@@ -36,11 +36,12 @@ materializes its runtime-neutral specialist envelopes from the current plan.
|
|
|
36
36
|
1. Keep one `leadWriterId` for implementation and every correction. The implementer owns
|
|
37
37
|
the worktree and code; specialists and the independent reviewer never edit.
|
|
38
38
|
2. Start with `mission start --ticket <ticket>` and follow `mission dispatch --id <mission>
|
|
39
|
-
--json`. The frozen task and controller own routing, state and correction budget.
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
39
|
+
--json`. The frozen task and controller own routing, state and correction budget. Normal
|
|
40
|
+
dispatch starts the writer without a compulsory preparation panel. Consult a targeted native
|
|
41
|
+
specialist only when a concrete risk or unresolved question warrants advice (pass 5).
|
|
42
|
+
For canonical `invoke-specialists` actions, pass each envelope unchanged through
|
|
43
|
+
`void-orchestrate` and record actual starts/results with `mission specialist-event --id <mission>`.
|
|
44
|
+
Reconcile any existing invocation; a missing response resumes its run, never another cycle.
|
|
44
45
|
3. The implementer implements and verifies, then commits the candidate. Record the pending
|
|
45
46
|
writer receipt with `mission writer-event --id <mission>`. Review must bind an exact
|
|
46
47
|
`reviewedCommit`, `baseCommit` and `acceptanceCriteriaHash`; a mutable worktree is insufficient.
|
|
@@ -101,7 +102,7 @@ Run in order. Each pass names the skill it composes and the predicate that fires
|
|
|
101
102
|
2. **Architecture pass** (IF it touches structure, a module boundary, the data model, or public types). Compose `void-hexagonal-architecture`, `void-domain-driven-design`, agents `type-design-analyzer` + `doctrine-critic`. Confirm the applicable ADR is honored.
|
|
102
103
|
3. **Source grounding** (ALWAYS; the source depends on what the change touches). Read the relevant sources before the first line, per the Anti-rustine section of `PHILOSOPHY.md`. For a third-party configuration, schema or call signature, compose `void-source-driven-development`: official documentation **of the installed version**, never an upgrade by default. For internal code, read the owning contract, types, source and project docs of what you are about to change. Assumed semantics produce bugs that cost hours to find, and the assumption is invisible in the diff — which is why this runs before the writing rather than at review. Cite a source briefly when it helps understand or record a choice; a missing citation never blocks on its own.
|
|
103
104
|
4. **Migration safety** (IF it changes a DB schema or ships a migration). Compose `void-migrations` (and `void-drizzle-migration-safe` on a Drizzle/Postgres stack): zero-downtime, two-phase, batched backfill, locking analysis. **Once the migration is generated and safety-reviewed, apply it to the dev/local database before the TDD and E2E passes run** — otherwise those tests execute against a stale schema and prove nothing about the new shape. **This cycle only ever applies to dev/local; production migrations run through CI / GitHub Actions on merge, never from a worker or this session** (see the `void-migrations` anti-rule). A schema change must never reach the rest of the cycle without this pass.
|
|
104
|
-
5. **
|
|
105
|
+
5. **Targeted preparation advice** (IF a concrete risk or unresolved question warrants a specialist). Use the existing professional passes and `void-orchestrate` to consult only the relevant native specialist. Bind the question to the actual brief, cited artifacts, boundary or risk being examined; revisit only the affected advice when those materially change. Baseline/profile applicability alone does not require a panel, and advice is not an automatic canonical gate. With `panel.provider: orchestrator`, consume its supplied advice without launching a duplicate. For canonical `invoke-specialists` actions, preserve runtime, agentName, missionId, contextPack, reviewSubject and reviewScope; record actual starts/results, never invented receipts. Reconcile uncertain invocations before launching, keep at most four simultaneous agents, and never fail one on a wait timeout. Preserve real unresolved findings and author-owned evidence obligations. Already-started preparation may finish as advice after writer admission; it cannot satisfy final code review or authorize a new preparation invocation after implementation starts.
|
|
105
106
|
6. **TDD implementation** (ALWAYS). During development, the coordinator may create or reuse a draft pull request for the branch. Keep work-in-progress PRs in draft and run focused local checks; do not wait for full remote CI per iteration. `void-verify` owns the transition to complete integration checks and its portable CI template. The single lead writer composes `void-tdd` + `void-testing`. Red, green, refactor. Unit tests for the behavior, green before moving on. Review specialists remain read-only.
|
|
106
107
|
7. **Async + idempotency** (IF it sends email, calls an external side-effecting API, enqueues a job, or mints a single-use token). Compose `void-async-safety`: idempotency keys, replay/dedup window, bounded retries, single-use enforcement.
|
|
107
108
|
8. **End-to-end tests** (IF it touches a user-facing flow). Write/extend the E2E suite (Playwright). The path a user actually walks, not just the unit.
|
package/dist/main.js
CHANGED
|
@@ -35813,7 +35813,19 @@ function collectCompletions(events, stage, expectedSource, stageStartSeqExclusiv
|
|
|
35813
35813
|
const contextIds = /* @__PURE__ */ new Set();
|
|
35814
35814
|
const currentFailedRounds = [];
|
|
35815
35815
|
let historicalHighestRound = 0;
|
|
35816
|
-
const inStageWindow = (event) =>
|
|
35816
|
+
const inStageWindow = (event) => {
|
|
35817
|
+
let seq = event.seq;
|
|
35818
|
+
if (stage === "pre-implementation" && event.kind === "specialist.completed") {
|
|
35819
|
+
const payload = record7(event.payload);
|
|
35820
|
+
const mission2 = events.find((candidate) => candidate.kind === "mission.started" && candidate.missionId === event.missionId && candidate.seq < event.seq);
|
|
35821
|
+
const planHash = record7(mission2?.payload)?.["planHash"];
|
|
35822
|
+
const matches = (candidate) => candidate.missionId === event.missionId && candidate.subject === event.subject && ["stage", "reviewRound", "inputHash", "contractVersion"].every((key) => record7(candidate.payload)?.[key] === payload?.[key]);
|
|
35823
|
+
const invocation = events.find((candidate) => candidate.seq < event.seq && candidate.kind === "specialist.started" && candidate.source === expectedSource && matches(candidate) && typeof payload?.contextId === "string" && record7(candidate.payload)?.contextId === payload.contextId);
|
|
35824
|
+
if (invocation !== void 0 && events.some((candidate) => candidate.seq < invocation.seq && candidate.kind === "specialist.requested" && candidate.source === "void-harness:mission.dispatch" && typeof planHash === "string" && SHA256.test(planHash) && record7(candidate.payload)?.["planHash"] === planHash && `runtime:${record7(candidate.payload)?.["runtime"]}` === expectedSource && matches(candidate)))
|
|
35825
|
+
seq = invocation.seq;
|
|
35826
|
+
}
|
|
35827
|
+
return (afterSeqExclusive === void 0 || seq > afterSeqExclusive) && (beforeSeqExclusive === void 0 || seq < beforeSeqExclusive);
|
|
35828
|
+
};
|
|
35817
35829
|
for (const event of events) {
|
|
35818
35830
|
const payload = record7(event.payload);
|
|
35819
35831
|
if (event.kind === "specialist.failed") {
|
|
@@ -38739,10 +38751,10 @@ function lifecycleField(event, key) {
|
|
|
38739
38751
|
function sameSpecialistDispatch(left, right) {
|
|
38740
38752
|
return left.missionId === right.missionId && left.subject === right.subject && lifecycleField(left, "contractVersion") === lifecycleField(right, "contractVersion") && lifecycleField(left, "stage") === lifecycleField(right, "stage") && lifecycleField(left, "reviewRound") === lifecycleField(right, "reviewRound") && lifecycleField(left, "inputHash") === lifecycleField(right, "inputHash");
|
|
38741
38753
|
}
|
|
38742
|
-
function unboundCompletionReasons(input2, runtime2) {
|
|
38754
|
+
function unboundCompletionReasons(input2, runtime2, completions2 = input2.stream.events.filter((event) => event.kind === "specialist.completed"), invocationBeforeSeq) {
|
|
38743
38755
|
const reasons = [];
|
|
38744
|
-
for (const completion of
|
|
38745
|
-
const started = input2.stream.events.find((event) => event.seq < completion.seq && event.kind === "specialist.started" && event.source === `runtime:${runtime2 ?? "invalid"}` && sameSpecialistDispatch(event, completion) && (lifecycleField(completion, "reviewInvocationEventId") === void 0 ? lifecycleField(event, "contextId") === lifecycleField(completion, "contextId") : event.eventId === lifecycleField(completion, "reviewInvocationEventId") && lifecycleField(event, "reviewerId") === parseSpecialistCompletionValue(lifecycleField(completion, "completion"))?.review?.reviewerId));
|
|
38756
|
+
for (const completion of completions2) {
|
|
38757
|
+
const started = input2.stream.events.find((event) => event.seq < completion.seq && (invocationBeforeSeq === void 0 || event.seq < invocationBeforeSeq) && event.kind === "specialist.started" && event.source === `runtime:${runtime2 ?? "invalid"}` && sameSpecialistDispatch(event, completion) && (lifecycleField(completion, "reviewInvocationEventId") === void 0 ? lifecycleField(event, "contextId") === lifecycleField(completion, "contextId") : event.eventId === lifecycleField(completion, "reviewInvocationEventId") && lifecycleField(event, "reviewerId") === parseSpecialistCompletionValue(lifecycleField(completion, "completion"))?.review?.reviewerId));
|
|
38746
38758
|
const requested = started === void 0 ? void 0 : input2.stream.events.find((event) => event.seq < started.seq && event.kind === "specialist.requested" && event.source === "void-harness:mission.dispatch" && sameSpecialistDispatch(event, completion) && lifecycleField(event, "planHash") === input2.plan.planHash && lifecycleField(event, "runtime") === runtime2);
|
|
38747
38759
|
if (requested === void 0 || started === void 0) {
|
|
38748
38760
|
reasons.push(`specialist lifecycle is unbound: ${completion.subject}`);
|
|
@@ -38816,7 +38828,7 @@ function decideReviewPhase(start, review, baseVerdict, stage) {
|
|
|
38816
38828
|
action: stage === "pre-implementation" ? {
|
|
38817
38829
|
kind: "run-preparation-correction",
|
|
38818
38830
|
writerId: start.leadWriterId,
|
|
38819
|
-
findingIds: review.findings.filter((finding) =>
|
|
38831
|
+
findingIds: review.findings.filter((finding) => finding.classification !== "advisory").map((finding) => finding.findingId)
|
|
38820
38832
|
} : {
|
|
38821
38833
|
kind: "run-correction",
|
|
38822
38834
|
writerId: start.leadWriterId,
|
|
@@ -38897,15 +38909,6 @@ function retainedPreparationSpecialists(input2, events, boundary, targets) {
|
|
|
38897
38909
|
return result?.["verdict"] === "pass" && result["contractVersion"] === contractVersions(input2.plan)[id3] && lifecycleField(latest, "inputHash") === input2.currentInputHashesByStage["pre-implementation"][id3];
|
|
38898
38910
|
});
|
|
38899
38911
|
}
|
|
38900
|
-
function preparationHasMissingOrStaleReviews(input2, events, boundary) {
|
|
38901
|
-
return requiredSpecialists(input2.plan, "pre-implementation").some((id3) => {
|
|
38902
|
-
const latest = events.filter((item) => item.kind === "specialist.completed" && item.subject === id3 && item.seq < boundary && lifecycleField(item, "stage") === "pre-implementation").at(-1);
|
|
38903
|
-
if (latest === void 0)
|
|
38904
|
-
return true;
|
|
38905
|
-
const result = record15(lifecycleField(latest, "completion") ?? null);
|
|
38906
|
-
return result?.["contractVersion"] !== contractVersions(input2.plan)[id3] || lifecycleField(latest, "inputHash") !== input2.currentInputHashesByStage["pre-implementation"][id3];
|
|
38907
|
-
});
|
|
38908
|
-
}
|
|
38909
38912
|
function pendingRecoveredCorrectionFindingIds(events) {
|
|
38910
38913
|
const recovery = events.filter((event) => event.kind === "mission.recovered").at(-1);
|
|
38911
38914
|
if (recovery === void 0 || events.some((event) => event.seq > recovery.seq && event.kind === "lead-writer.completed"))
|
|
@@ -38962,14 +38965,18 @@ function orchestrateMissionTeam(originalInput) {
|
|
|
38962
38965
|
const firstWriterSeq = completions2.length === 0 ? void 0 : Math.min(...completions2.map((event) => event.seq));
|
|
38963
38966
|
const implementationCompletions = completions2.filter((event) => leadWriterActionKind(event) !== "run-preparation-correction");
|
|
38964
38967
|
const firstImplementationSeq = implementationCompletions.length === 0 ? void 0 : Math.min(...implementationCompletions.map((event) => event.seq));
|
|
38965
|
-
const
|
|
38966
|
-
const preparationFollowupRequired = preparationRecovery !== void 0 || lastPreparationSeq !== void 0 && preparationHasMissingOrStaleReviews(input2, reviewEvents, lastPreparationSeq);
|
|
38967
|
-
const latePreparationCompletion = lastPreparationSeq !== void 0 && input2.stream.events.some((event) => event.seq > lastPreparationSeq && event.kind === "specialist.completed" && lifecycleField(event, "stage") === "pre-implementation");
|
|
38968
|
+
const preparationFollowupRequired = preparationRecovery !== void 0;
|
|
38968
38969
|
const lastWriterSeq = completions2.length === 0 ? void 0 : Math.max(...completions2.map((event) => event.seq));
|
|
38969
38970
|
const missionStartSeq = input2.stream.events.find((event) => event.kind === "mission.started")?.seq;
|
|
38970
38971
|
const expectedSource = start.runtime === "claude" ? "runtime:claude" : "runtime:codex";
|
|
38971
38972
|
const obligations = evidenceObligations(input2, expectedSource, firstImplementationSeq === void 0 ? "pre-implementation" : "post-implementation");
|
|
38972
38973
|
const preparationObligationIds = new Set(obligations.obligations.filter((obligation) => input2.stream.events.some((event) => event.eventId === obligation.completionEventId && lifecycleField(event, "stage") === "pre-implementation")).map((obligation) => obligation.obligationId));
|
|
38974
|
+
const preparationBoundary = Math.max(lastPreparationSeq ?? 0, ...completions2.filter((event) => leadWriterActionKind(event) === "run-correction").map((event) => event.seq));
|
|
38975
|
+
const observedPreparation = reviewEvents.filter((event) => event.kind === "specialist.completed" && lifecycleField(event, "stage") === "pre-implementation");
|
|
38976
|
+
const unresolvedPreparation = [...new Map(observedPreparation.filter((event) => event.seq > preparationBoundary).map((event) => [event.subject, event])).values()].filter((event) => {
|
|
38977
|
+
const completion = parseSpecialistCompletionValue(lifecycleField(event, "completion"));
|
|
38978
|
+
return completion !== void 0 && completion.verdict !== "pass" && (completion.verdict !== "changes-requested" || completion.findings.length === 0 || completion.findings.some((finding) => finding.classification !== "advisory"));
|
|
38979
|
+
});
|
|
38973
38980
|
const preReview = reduceReviewLoop({
|
|
38974
38981
|
stage: "pre-implementation",
|
|
38975
38982
|
expectedSource,
|
|
@@ -38977,9 +38984,10 @@ function orchestrateMissionTeam(originalInput) {
|
|
|
38977
38984
|
stageStartSeqExclusive: missionStartSeq,
|
|
38978
38985
|
afterSeqExclusive: lastPreparationSeq
|
|
38979
38986
|
},
|
|
38980
|
-
...firstWriterSeq === void 0 ? {} : { beforeSeqExclusive: firstWriterSeq },
|
|
38981
38987
|
events: reviewEvents,
|
|
38982
|
-
|
|
38988
|
+
// Historical advice is inspected, but the frozen plan is no longer a
|
|
38989
|
+
// compulsory preparation quorum. Explicit admitted recoveries retain theirs.
|
|
38990
|
+
requiredSpecialists: requiredSpecialists(input2.plan, "pre-implementation").filter((id3) => preparationRecovery !== void 0 || (unresolvedPreparation.length > 0 ? unresolvedPreparation : observedPreparation).some((event) => event.subject === id3)),
|
|
38983
38991
|
contractVersions: contractVersions(input2.plan),
|
|
38984
38992
|
currentInputHashes: input2.currentInputHashesByStage["pre-implementation"],
|
|
38985
38993
|
maxRounds: input2.maxReviewRounds,
|
|
@@ -38987,11 +38995,17 @@ function orchestrateMissionTeam(originalInput) {
|
|
|
38987
38995
|
...obligations,
|
|
38988
38996
|
blockingObligationIds: obligations.blockingObligationIds.filter((id3) => preparationObligationIds.has(id3))
|
|
38989
38997
|
},
|
|
38998
|
+
...preparationRecovery === void 0 && lastPreparationSeq !== void 0 && missionStartSeq !== void 0 ? {
|
|
38999
|
+
retainedSpecialists: requiredSpecialists(input2.plan, "pre-implementation").filter((id3) => unresolvedPreparation.some((event) => event.subject === id3))
|
|
39000
|
+
} : {},
|
|
38990
39001
|
...!preparationFollowupRequired || lastPreparationSeq === void 0 || preparationRecovery !== void 0 && lastPreparationSeq <= preparationRecovery.recoverySeq ? {} : {
|
|
38991
39002
|
retainedSpecialists: retainedPreparationSpecialists(input2, reviewEvents, lastPreparationSeq, preparationRecovery?.specialistIds ?? [])
|
|
38992
39003
|
}
|
|
38993
39004
|
});
|
|
38994
39005
|
const baseVerdict = deriveMissionVerdict(input2.stream, input2.evidenceContext);
|
|
39006
|
+
if (baseVerdict.status === "degraded") {
|
|
39007
|
+
return stopped("degraded", preReview, baseVerdict, baseVerdict.reasons);
|
|
39008
|
+
}
|
|
38995
39009
|
const invalidRuntime = input2.specialistRuntime === void 0 || !Array.isArray(input2.specialistRuntime.limitations) || input2.specialistRuntime.limitations.some((item) => typeof item !== "string" || item.trim() === "") || !["available", "degraded", "unavailable"].includes(input2.specialistRuntime.status);
|
|
38996
39010
|
if (invalidRuntime) {
|
|
38997
39011
|
return stopped("degraded", preReview, baseVerdict, [
|
|
@@ -39042,8 +39056,17 @@ function orchestrateMissionTeam(originalInput) {
|
|
|
39042
39056
|
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])) {
|
|
39043
39057
|
return stopped("blocked", preReview, baseVerdict, ["Preparation replacement inputs or contracts changed; reconcile the admitted subject before dispatch"]);
|
|
39044
39058
|
}
|
|
39045
|
-
|
|
39046
|
-
|
|
39059
|
+
const implementationBoundary = input2.stream.events.find((event) => event.kind === "lead-writer.requested" && leadWriterActionKind(event) === "run-lead-writer")?.seq ?? firstImplementationSeq;
|
|
39060
|
+
if (implementationBoundary !== void 0) {
|
|
39061
|
+
const latePreparation = observedPreparation.filter((event) => event.seq > implementationBoundary);
|
|
39062
|
+
const lifecycleReasons = unboundCompletionReasons(input2, start.runtime, latePreparation, implementationBoundary);
|
|
39063
|
+
const replayed = input2.stream.events.some((event) => event.seq > implementationBoundary && event.kind === "specialist.started" && lifecycleField(event, "stage") === "pre-implementation");
|
|
39064
|
+
if (replayed || lifecycleReasons.length > 0) {
|
|
39065
|
+
return stopped("blocked", preReview, baseVerdict, ["pre-implementation review was replayed after implementation", ...lifecycleReasons]);
|
|
39066
|
+
}
|
|
39067
|
+
}
|
|
39068
|
+
if (preReview.issues.length > 0) {
|
|
39069
|
+
return decideReviewPhase(start, preReview, baseVerdict, "pre-implementation");
|
|
39047
39070
|
}
|
|
39048
39071
|
const pendingEvidence = obligationStop(obligations, preReview, baseVerdict);
|
|
39049
39072
|
const migration = migrated.migration;
|
|
@@ -39054,7 +39077,7 @@ function orchestrateMissionTeam(originalInput) {
|
|
|
39054
39077
|
}
|
|
39055
39078
|
const terminal = input2.stream.events.some((event) => event.seq > migration.seq && event.subject === receipt2.specialistId && ["specialist.completed", "specialist.failed"].includes(event.kind));
|
|
39056
39079
|
const onlyAuthorObligations = obligations.issues.length === 0 && obligations.blockingObligationIds.every((id3) => receipt2.pendingAuthorObligationIds.includes(id3));
|
|
39057
|
-
const preparationAdmitted =
|
|
39080
|
+
const preparationAdmitted = firstImplementationSeq !== void 0;
|
|
39058
39081
|
if (!terminal && onlyAuthorObligations && preparationAdmitted) {
|
|
39059
39082
|
const reasons = ["Explicit contract migration requires one fresh visual assessment; historical evidence obligations remain due"];
|
|
39060
39083
|
return applyRuntimeCertification({
|
|
@@ -39120,22 +39143,30 @@ function orchestrateMissionTeam(originalInput) {
|
|
|
39120
39143
|
reasons
|
|
39121
39144
|
}, input2.specialistRuntime);
|
|
39122
39145
|
}
|
|
39123
|
-
if (
|
|
39124
|
-
return applyRuntimeCertification(
|
|
39146
|
+
if (preparationFollowupRequired && !preReview.readyForVerdict) {
|
|
39147
|
+
return applyRuntimeCertification(decideReviewPhase(start, preReview, baseVerdict, "pre-implementation"), input2.specialistRuntime);
|
|
39125
39148
|
}
|
|
39126
|
-
if (
|
|
39127
|
-
const reasons =
|
|
39149
|
+
if (unresolvedPreparation.length > 0) {
|
|
39150
|
+
const reasons = unresolvedPreparation.flatMap((event) => {
|
|
39151
|
+
const completion = parseSpecialistCompletionValue(lifecycleField(event, "completion"));
|
|
39152
|
+
return completion === void 0 ? [] : [
|
|
39153
|
+
...completion.findings.map((finding) => finding.summary),
|
|
39154
|
+
...completion.limitations
|
|
39155
|
+
];
|
|
39156
|
+
});
|
|
39157
|
+
if (preReview.staleSpecialists.some((id3) => unresolvedPreparation.some((event) => event.subject === id3))) {
|
|
39158
|
+
return stopped("blocked", preReview, baseVerdict, ["Existing preparation findings require reconciliation against changed inputs.", ...reasons]);
|
|
39159
|
+
}
|
|
39160
|
+
const decision = decideReviewPhase(start, preReview, baseVerdict, "pre-implementation");
|
|
39161
|
+
if (decision.action.kind === "run-preparation-correction" && decision.action.findingIds.length === 0) {
|
|
39162
|
+
return stopped("blocked", preReview, baseVerdict, ["Preparation requested changes without an actionable finding.", ...reasons]);
|
|
39163
|
+
}
|
|
39128
39164
|
return applyRuntimeCertification({
|
|
39129
|
-
|
|
39130
|
-
|
|
39131
|
-
|
|
39132
|
-
verdict: overrideVerdict(baseVerdict, "unverified", reasons),
|
|
39133
|
-
reasons
|
|
39165
|
+
...decision,
|
|
39166
|
+
reasons: [...decision.reasons, ...reasons],
|
|
39167
|
+
...firstImplementationSeq !== void 0 && decision.action.kind === "run-preparation-correction" ? { action: { ...decision.action, kind: "run-correction" } } : {}
|
|
39134
39168
|
}, input2.specialistRuntime);
|
|
39135
39169
|
}
|
|
39136
|
-
if (!preReview.readyForVerdict && (!preparationCorrectionCompleted || preparationFollowupRequired)) {
|
|
39137
|
-
return applyRuntimeCertification(decideReviewPhase(start, preReview, baseVerdict, "pre-implementation"), input2.specialistRuntime);
|
|
39138
|
-
}
|
|
39139
39170
|
if (completions2.length === 0) {
|
|
39140
39171
|
const reasons = ["lead writer implementation is incomplete"];
|
|
39141
39172
|
return applyRuntimeCertification({
|
|
@@ -56469,7 +56500,7 @@ async function missionReviewBase(root) {
|
|
|
56469
56500
|
throw new Error("MISSION_REVIEW_BASE_INVALID: a committed Git baseline is required");
|
|
56470
56501
|
}
|
|
56471
56502
|
}
|
|
56472
|
-
async function
|
|
56503
|
+
async function validateMissionReviewBase(root, baseCommit) {
|
|
56473
56504
|
if (baseCommit === void 0) {
|
|
56474
56505
|
throw new Error(
|
|
56475
56506
|
"MISSION_REVIEW_BASE_MISSING: legacy mission has no review baseline; preserve its history and start a new mission"
|
|
@@ -56479,8 +56510,13 @@ async function captureMissionReviewSubject(root, baseCommit, committed = false,
|
|
|
56479
56510
|
try {
|
|
56480
56511
|
await execFile2("git", ["merge-base", "--is-ancestor", baseCommit, "HEAD"], options2);
|
|
56481
56512
|
} catch {
|
|
56482
|
-
throw new Error("MISSION_REVIEW_BASE_INVALID: baseline is missing or is not an ancestor of HEAD");
|
|
56513
|
+
throw new Error("MISSION_REVIEW_BASE_INVALID: baseline is missing or is not an ancestor of HEAD; return to the mission worktree with a checkout descended from its bound base; preserve the journal");
|
|
56483
56514
|
}
|
|
56515
|
+
return baseCommit;
|
|
56516
|
+
}
|
|
56517
|
+
async function captureMissionReviewSubject(root, baseCommit, committed = false, hashFormat = committed ? "committed" : "legacy") {
|
|
56518
|
+
const validatedBase = await validateMissionReviewBase(root, baseCommit);
|
|
56519
|
+
const options2 = { cwd: root, encoding: "utf8", timeout: 1e4, maxBuffer: 4e6 };
|
|
56484
56520
|
try {
|
|
56485
56521
|
const paths = ["--", ".", ":(exclude).void/machine/**"];
|
|
56486
56522
|
const reviewedCommit = committed ? await missionReviewBase(root) : void 0;
|
|
@@ -56497,7 +56533,7 @@ async function captureMissionReviewSubject(root, baseCommit, committed = false,
|
|
|
56497
56533
|
throw new Error("MISSION_REVIEW_UNCOMMITTED: commit the implementation before independent review");
|
|
56498
56534
|
}
|
|
56499
56535
|
}
|
|
56500
|
-
const range = reviewedCommit === void 0 ? [
|
|
56536
|
+
const range = reviewedCommit === void 0 ? [validatedBase] : [validatedBase, reviewedCommit];
|
|
56501
56537
|
const [patch, names, untracked] = await Promise.all([
|
|
56502
56538
|
execFile2("git", [
|
|
56503
56539
|
"diff",
|
|
@@ -56547,11 +56583,11 @@ async function captureMissionReviewSubject(root, baseCommit, committed = false,
|
|
|
56547
56583
|
throw new Error("MISSION_REVIEW_CHANGED: HEAD changed while capturing the review subject");
|
|
56548
56584
|
}
|
|
56549
56585
|
return Object.freeze({
|
|
56550
|
-
...reviewedCommit === void 0 ? {} : { baseCommit, reviewedCommit },
|
|
56586
|
+
...reviewedCommit === void 0 ? {} : { baseCommit: validatedBase, reviewedCommit },
|
|
56551
56587
|
diff: patch.stdout,
|
|
56552
56588
|
files,
|
|
56553
56589
|
hash: canonicalJsonHash({
|
|
56554
|
-
baseCommit,
|
|
56590
|
+
baseCommit: validatedBase,
|
|
56555
56591
|
...hashFormat === "legacy" ? {} : { reviewedCommit },
|
|
56556
56592
|
diff: patch.stdout,
|
|
56557
56593
|
files: files.files
|
|
@@ -68026,7 +68062,7 @@ async function recordSpecialistRequests(root, missionId, envelopes, planHash) {
|
|
|
68026
68062
|
init_esm_shims();
|
|
68027
68063
|
|
|
68028
68064
|
// package.json
|
|
68029
|
-
var version2 = "5.0.
|
|
68065
|
+
var version2 = "5.0.7";
|
|
68030
68066
|
|
|
68031
68067
|
// src/lib/runs/verify.ts
|
|
68032
68068
|
var MAX_CAPTURE_BYTES = 64 * 1024;
|
|
@@ -68725,6 +68761,9 @@ async function dispatchMissionSpecialists(roots, input2, generatedAt = (/* @__PU
|
|
|
68725
68761
|
const inspected = current?.inspected ?? initialInspection;
|
|
68726
68762
|
requireOpenMission(inspected.stream.events);
|
|
68727
68763
|
const implemented = inspected.stream.events.some((event) => event.kind === "lead-writer.completed" && isUnknownRecord(event.payload) && event.payload.actionKind !== "run-preparation-correction");
|
|
68764
|
+
if (!implemented && stored.baseCommit !== void 0) {
|
|
68765
|
+
await validateMissionReviewBase(workRoot, stored.baseCommit);
|
|
68766
|
+
}
|
|
68728
68767
|
const reviewSubject = implemented ? await captureControllerReviewSubject(workRoot, stored.baseCommit, inspected.stream.events) : void 0;
|
|
68729
68768
|
const live = await planBoundMission(
|
|
68730
68769
|
workRoot,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "voidmachine",
|
|
3
|
-
"version": "5.0.
|
|
3
|
+
"version": "5.0.7",
|
|
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/hook-runner": "0.0.0",
|
|
61
62
|
"@voidcorp/mission-engine": "0.0.0",
|
|
62
|
-
"@voidcorp/
|
|
63
|
-
"@voidcorp/
|
|
64
|
-
"@voidcorp/hook-runner": "0.0.0"
|
|
63
|
+
"@voidcorp/harness-graph": "5.0.7",
|
|
64
|
+
"@voidcorp/void-machine": "0.0.0"
|
|
65
65
|
},
|
|
66
66
|
"scripts": {
|
|
67
67
|
"build": "tsup",
|