diff --git a/examples/adversarial-implementation/README.md b/examples/adversarial-implementation/README.md
index 80c727298..19dfac715 100644
--- a/examples/adversarial-implementation/README.md
+++ b/examples/adversarial-implementation/README.md
@@ -535,6 +535,85 @@ custom/workflow provider storage contract or migration of old inline records.
External reviewer models and publication use their existing workflows. The
phase entry retains the implementation workflow's role and model policy.
+### Resolve a decision hold
+
+A Planner or Architect that returns `needs_decision`, and an Implementor that
+returns `needs_discovery` naming the Architect, hold the ticket for an accepted
+decision. When the hold is at the clean launch revision before implementation
+feedback, its envelope names the supported operation:
+
+```json
+{"entry": "resolve-decision.md", "gate": "planning", "action": "resolve_decision",
+ "result": "/absolute/path/to/work/attempts/0000/result.json", "input": "ticket-decision.v1"}
+```
+
+Save the decision and its provenance as text files, then save one request that
+binds them to this exact hold. Every field is required and no other field is
+accepted:
+
+```json
+{
+ "schema": "ticket-decision.v1",
+ "work": "selected-task",
+ "continuation": {"path": "/absolute/path/to/work/continuations/HASH.json", "utf8Bytes": 13240, "sha256": "HASH"},
+ "heldResult": {"path": "/absolute/path/to/work/attempts/0000/result.json", "utf8Bytes": 2210, "sha256": "RESULT_HASH"},
+ "disposition": "accept",
+ "decision": {"path": "/absolute/path/to/decision.md", "utf8Bytes": 412, "sha256": "DECISION_HASH"},
+ "provenance": {"path": "/absolute/path/to/provenance.md", "utf8Bytes": 96, "sha256": "PROVENANCE_HASH"},
+ "acceptedInputs": []
+}
+```
+
+`continuation` copies the held envelope's descriptor and `heldResult` the
+retained descriptor of its final call's result. Each artifact descriptor names an
+absolute path and its exact UTF-8 byte length and SHA-256. The decision and
+provenance are always selected for the routed owner, followed by
+`acceptedInputs` in order. A recorded reference keeps its first text; give changed
+text a fresh path. Provenance states the actual authority, such as standing
+coordinator authority. It is evidence for the routed owner; it neither overrides
+a permission nor records a new human answer.
+
+```bash
+deno task xmd run --allow-absolute examples/adversarial-implementation/resolve-decision.md \
+ --props-record /absolute/path/to/held-record.json \
+ --props-decision /absolute/path/to/decision.json \
+ --include examples/adversarial-implementation/components --raw
+```
+
+Resolution calls no role. It validates the held result, records the decision under
+the hold's continuation digest, prepares the original owner and publishes the
+successor. Continue the returned envelope with `continue.md --props-steps 1`; that
+ordinary step dispatches the owner through the existing source, identity, input
+and publication checks:
+
+| Held result | Disposition | Next owner | Then |
+| --- | --- | --- | --- |
+| discovery Planner `needs_decision` | `accept` | original Planner | original Implementor |
+| discovery Planner `needs_decision` | `amend` | original Architect | retained Planner, then original Implementor |
+| discovery Architect `needs_decision` | `accept` | same Architect | retained Planner, then original Implementor |
+| implementation Implementor `needs_discovery` naming the Architect | either | original Architect | retained Planner, then original Implementor |
+
+The original task, sessions, calls, results, delivered inputs, source anchor and
+correction count are unchanged; resolution grants no further corrections. Every
+other hold refuses, including an Architect amendment, an API conflict routed to
+the Planner, execution failure, uncertain native work, changed input, source
+mismatch, an exhausted correction bound and publication failure. A held result
+whose phase execution failed after the result was saved also refuses; resolution
+requires the call's execution record to show completion. A dirty or moved
+checkout, prior implementation feedback, a stale or foreign binding and a changed
+input also refuse. A refusal returns a held envelope carrying the failure and
+leaves the managed ticket unchanged; keep the original envelope.
+
+Repeating the same request against the same hold returns its recorded successor
+without publishing again. The repeat checks the evidence the successor retained,
+under current File permission and protection; it does not reread the decision's
+original files, so they may later change or disappear. A different decision for a resolved hold refuses. If
+reservation, publication or the receipt is interrupted, the hold stays held and
+its reservation directory preserves the first failure for operator disposition. A
+matching successor file alone does not confirm the interrupted write. Repeated
+continuation of an older envelope reuses the existing call reservation and resends
+no role effect.
+
## Supervise a live REPL phase
Keep the original ACP call pending, or reconnect passively with the existing
diff --git a/examples/adversarial-implementation/components/Entry/ResolveDecision.md b/examples/adversarial-implementation/components/Entry/ResolveDecision.md
new file mode 100644
index 000000000..8b09a79d8
--- /dev/null
+++ b/examples/adversarial-implementation/components/Entry/ResolveDecision.md
@@ -0,0 +1,19 @@
+---
+props:
+ type: object
+ properties:
+ record: {type: string}
+ decision: {type: string}
+ required: [record, decision]
+ additionalProperties: false
+returns: {type: object}
+---
+
+{text}
+
+
+
+{resolved.output}
+
+ !/^\s+at /.test(line)).join("\n").slice(0,1024),data:null}}} as="bounded" />
+
diff --git a/examples/adversarial-implementation/components/Ticket/Advance.md b/examples/adversarial-implementation/components/Ticket/Advance.md
index 892ec4ce4..e2d63ab2c 100644
--- a/examples/adversarial-implementation/components/Ticket/Advance.md
+++ b/examples/adversarial-implementation/components/Ticket/Advance.md
@@ -14,6 +14,8 @@ returns: {type: object}
---
A decision or contract conflict holds the ticket for its existing approval gate.
+An implementation discovery hold keeps its validated next owner as a routing fact;
+a hold whose phase execution failed after saving its result records that failure.
A correction clears prior verdicts. Readiness requires every selected reviewer to
PASS the same signed implementation SHA; it does not authorize delivery or merge.
Selected feedback documents remain available across reviews and corrections.
@@ -32,7 +34,7 @@ Selected feedback documents remain available across reviews and corrections.
-
+
@@ -49,6 +51,6 @@ Selected feedback documents remain available across reviews and corrections.
- 0 ? [{role:call.role,revision:result.revision,result:props.pending.resultPath,requests:result.discoveryRequests ?? [],gaps:result.discoveryGaps ?? []}] : [])],feedback:result.outcome === "complete" && call.role === "implementor" ? [props.pending.resultPath,props.observation.path] : state.feedback,hold:held ? {kind:correction ? "correction_bound" : result.outcome,reason:result.handoff} : null}} />
+ 0 ? [{role:call.role,revision:result.revision,result:props.pending.resultPath,requests:result.discoveryRequests ?? [],gaps:result.discoveryGaps ?? []}] : [])],feedback:result.outcome === "complete" && call.role === "implementor" ? [props.pending.resultPath,props.observation.path] : state.feedback,hold:held ? {kind:correction ? "correction_bound" : result.outcome,reason:result.handoff,...(result.outcome === "needs_discovery" ? {next:result.next} : {}),...(props.pending.execution.status === "failed" ? {execution:"failed"} : {})} : null}} />
diff --git a/examples/adversarial-implementation/components/Ticket/Decision.ts b/examples/adversarial-implementation/components/Ticket/Decision.ts
new file mode 100644
index 000000000..708db6c26
--- /dev/null
+++ b/examples/adversarial-implementation/components/Ticket/Decision.ts
@@ -0,0 +1,71 @@
+import { z } from "zod";
+import { envelope, state } from "./control.ts";
+import { describe, descriptor, readBounded, same, stateLimit, textLimit } from "./text-storage.ts";
+
+export const props = {
+ type: "object",
+ properties: {
+ path: { type: "string", pattern: "^/" },
+ record: { type: "object" },
+ saved: { type: "object" },
+ },
+ required: ["path", "record", "saved"],
+ additionalProperties: false,
+};
+const reference = descriptor.extend({ path: z.string().startsWith("/") }).strict();
+const text = reference.extend({ utf8Bytes: z.number().int().min(1).max(textLimit) }).strict();
+const request = z
+ .object({
+ schema: z.literal("ticket-decision.v1"),
+ work: z.string().min(1),
+ continuation: reference,
+ heldResult: reference,
+ disposition: z.enum(["accept", "amend"]),
+ decision: text,
+ provenance: text,
+ acceptedInputs: z.array(reference),
+ })
+ .strict();
+type Reference = z.infer;
+
+export default function* Decision(value: unknown) {
+ const input = z
+ .object({ path: z.string().startsWith("/"), record: envelope, saved: state })
+ .strict()
+ .parse(value);
+ const source = yield* readBounded(input.path, stateLimit);
+ const selected = request.parse(JSON.parse(source));
+ const { saved } = input;
+ if (selected.work !== saved.manifest.work) {
+ throw new Error("The decision names another work item; no resolution was recorded.");
+ }
+ if (
+ input.record.continuation === null ||
+ !same(selected.continuation, input.record.continuation)
+ ) {
+ throw new Error(
+ "The decision is bound to another or stale continuation; bind it to this exact confirmed hold.",
+ );
+ }
+ const call = saved.calls.at(-1);
+ const result = typeof call?.result === "string" ? saved.documents[call.result] : undefined;
+ if (result === undefined || !same(selected.heldResult, result)) {
+ throw new Error(
+ "The decision names another held result; bind it to the retained result of the final call.",
+ );
+ }
+ const references = new Map();
+ for (const entry of [selected.decision, selected.provenance, ...selected.acceptedInputs]) {
+ const prior = references.get(entry.path);
+ if (prior !== undefined && !same(prior, entry)) {
+ throw new Error("One decision reference names different contents: " + entry.path);
+ }
+ references.set(entry.path, entry);
+ }
+ return {
+ request: selected,
+ file: describe(input.path, source),
+ references: [...references.keys()],
+ descriptors: Object.fromEntries(references),
+ };
+}
diff --git a/examples/adversarial-implementation/components/Ticket/DecisionInputs.ts b/examples/adversarial-implementation/components/Ticket/DecisionInputs.ts
new file mode 100644
index 000000000..32e006299
--- /dev/null
+++ b/examples/adversarial-implementation/components/Ticket/DecisionInputs.ts
@@ -0,0 +1,34 @@
+import { z } from "zod";
+import { describe, descriptor, readBounded, same, snapshot, textLimit } from "./text-storage.ts";
+
+export const props = {
+ type: "object",
+ properties: { descriptors: { type: "object" }, documents: { type: "object" } },
+ required: ["descriptors", "documents"],
+ additionalProperties: false,
+};
+
+// A first resolution observes each decision input once: a recorded reference keeps
+// its retained text, and a new reference must match its origin's current bytes.
+export default function* DecisionInputs(value: unknown) {
+ const { descriptors, documents } = z
+ .object({
+ descriptors: z.record(z.string(), descriptor),
+ documents: z.record(z.string(), snapshot),
+ })
+ .strict()
+ .parse(value);
+ for (const entry of Object.values(descriptors)) {
+ const retained = documents[entry.path];
+ const current = retained ?? describe(entry.path, yield* readBounded(entry.path, textLimit));
+ if (!same(entry, current)) {
+ throw new Error(
+ (retained === undefined
+ ? "Decision input differs from its descriptor: "
+ : "A recorded reference keeps its first text; give changed text a fresh reference: ") +
+ entry.path,
+ );
+ }
+ }
+ return Object.keys(descriptors);
+}
diff --git a/examples/adversarial-implementation/components/Ticket/Publish.ts b/examples/adversarial-implementation/components/Ticket/Publish.ts
index 018c67791..f72409c56 100644
--- a/examples/adversarial-implementation/components/Ticket/Publish.ts
+++ b/examples/adversarial-implementation/components/Ticket/Publish.ts
@@ -86,14 +86,41 @@ export default function* Publish(value: unknown) {
remainingRequiredDeliveryWork: ["independent-review", "required-ci", "main-health"],
}
: {};
+ const last = record.calls.at(-1);
+ const hold = record.checkpoint.hold;
+ const decision =
+ !record.checkpoint.dispatchable &&
+ record.checkpoint.status === "hold" &&
+ record.checkpoint.revision === record.manifest.assignment.revision &&
+ record.checkpoint.feedback.length === 0 &&
+ hold?.execution === undefined &&
+ last?.status === "accepted" &&
+ typeof last.result === "string" &&
+ ((hold?.kind === "needs_decision" &&
+ last.assignment.phase === "discovery" &&
+ last.role !== "implementor") ||
+ (hold?.kind === "needs_discovery" &&
+ last.role === "implementor" &&
+ hold.next?.phase === "discovery" &&
+ hold.next.role === "architect"))
+ ? last.result
+ : null;
const nextAction =
record.checkpoint.status === "feedback_ready" && typeof deliveryDirectory === "string"
? { entry: "delivery.md", record: deliveryDirectory + "/requirements.json", action: "review" }
- : {
- entry: "continue.md",
- gate: record.checkpoint.gate,
- action: record.checkpoint.dispatchable ? "continue_feedback" : "resolve_feedback_hold",
- };
+ : decision !== null
+ ? {
+ entry: "resolve-decision.md",
+ gate: record.checkpoint.gate,
+ action: "resolve_decision",
+ result: decision,
+ input: "ticket-decision.v1",
+ }
+ : {
+ entry: "continue.md",
+ gate: record.checkpoint.gate,
+ action: record.checkpoint.dispatchable ? "continue_feedback" : "resolve_feedback_hold",
+ };
return {
...presentation,
nextAction,
diff --git a/examples/adversarial-implementation/components/Ticket/ResolveDecision.md b/examples/adversarial-implementation/components/Ticket/ResolveDecision.md
new file mode 100644
index 000000000..01682012b
--- /dev/null
+++ b/examples/adversarial-implementation/components/Ticket/ResolveDecision.md
@@ -0,0 +1,114 @@
+---
+description: >-
+ Record an accepted decision for one exact retained hold and publish the prepared
+ original owner without calling a role. Use , then continue the returned
+ envelope normally.
+props:
+ type: object
+ properties:
+ record: {type: object}
+ decision: {type: string, pattern: '^/'}
+ required: [record, decision]
+ additionalProperties: false
+returns: {type: object}
+---
+
+Resolution covers a decision or discovery hold at the clean unchanged launch
+revision, before implementation feedback. The held result selects the original
+owner: an accepted Planner decision returns to that Planner, an amended Planner
+decision or an accepted Architect decision returns to the Architect, and an
+Implementor's discovery hold returns to the Architect it named. The decision and
+its evidence enter that owner's selected inputs; the original sessions, calls,
+delivered inputs, source anchor and correction count stay unchanged.
+
+The reservation under the hold's continuation digest admits one resolution. A
+confirmed repeat returns the recorded successor, and a different decision for that
+hold refuses. A reservation without its confirmed receipt stays held: matching
+files do not establish an unknown earlier write. The repeat uses the evidence the
+successor retained, so later changes to the decision's original files do not
+affect it. A held call whose execution
+record is failed, missing or uncertain refuses, even when its result was saved.
+
+
+
+
+
+
+
+
+
+
+
+```bash exec as="existing"
+if test -e {quoted}/receipt.json; then printf confirmed; elif test -e {quoted} || test -L {quoted}; then printf reserved; else printf none; fi
+```
+
+
+
+
+
+
+{receiptText}
+
+
+
+ [path,recorded.documents[path]]))} as="retained" />
+
+
+
+
+
+
+
+
+{executionRead.output}{executionJson}
+
+
+
+
+ saved.manifest.maxCorrections}>
+
+
+
+
+
+
+
+
+
+
+
+ "'" + (saved.manifest.directory + part + id).replaceAll("'","'\"'\"'") + "'").join(" ")} />
+```bash exec as="unstarted"
+for path in {unstartedPaths}; do if test -e "$path" || test -L "$path"; then exit 1; fi; done
+```
+
+
+```bash exec as="reserved"
+mkdir -p -- {parent} && mkdir -- {quoted}
+```
+
+
+
+
+
+
+
+
+ documents[path].utf8Bytes !== bound.descriptors[path].utf8Bytes || documents[path].sha256 !== bound.descriptors[path].sha256)}>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/adversarial-implementation/components/Ticket/control.ts b/examples/adversarial-implementation/components/Ticket/control.ts
index 15a5331b7..efc4a2f0a 100644
--- a/examples/adversarial-implementation/components/Ticket/control.ts
+++ b/examples/adversarial-implementation/components/Ticket/control.ts
@@ -43,6 +43,8 @@ export const envelope = z
record: z.string().optional(),
gate: z.string().nullable().optional(),
action: z.string(),
+ result: z.string().optional(),
+ input: z.literal("ticket-decision.v1").optional(),
})
.strict()
.optional(),
@@ -97,7 +99,13 @@ export const state = z
.object({ architect: z.boolean(), planner: z.boolean(), implementor: z.boolean() })
.strict(),
hold: z
- .object({ kind: z.string(), reason: z.string(), receipt: z.string().optional() })
+ .object({
+ kind: z.string(),
+ reason: z.string(),
+ receipt: z.string().optional(),
+ next: z.object({ phase: z.string(), role: role.nullable() }).strict().optional(),
+ execution: z.literal("failed").optional(),
+ })
.strict()
.nullable(),
plannerCall: z.string().startsWith("/").nullable().optional(),
@@ -105,6 +113,7 @@ export const state = z
discovery: z.array(jsonObject).optional(),
exactApproval: z.json().optional(),
exactReview: z.json().optional(),
+ decisions: z.array(z.string()).optional(),
})
.strict(),
calls: z.array(
@@ -196,6 +205,15 @@ export function confirmLinks(saved: z.infer, selected: z.infer {
return !result.ok && parseFilesFailure(result.error)?.reason === "missing";
});
}
+
+export function same(
+ left: { path: string; utf8Bytes: number; sha256: string },
+ right: { path: string; utf8Bytes: number; sha256: string },
+) {
+ return (
+ left.path === right.path && left.utf8Bytes === right.utf8Bytes && left.sha256 === right.sha256
+ );
+}
+
+export function* readBounded(path: string, limit: number): Operation {
+ try {
+ return yield* read("/", path, limit);
+ } catch (error) {
+ const failure = parseFilesFailure(error);
+ if (failure === undefined) {
+ throw error;
+ }
+ throw new Error(
+ "Cannot read " +
+ path +
+ " within " +
+ limit +
+ " UTF-8 bytes under current File permission: " +
+ failure.reason +
+ ". No resolution was recorded.",
+ );
+ }
+}
diff --git a/examples/adversarial-implementation/resolve-decision.md b/examples/adversarial-implementation/resolve-decision.md
new file mode 100644
index 000000000..8c71583f7
--- /dev/null
+++ b/examples/adversarial-implementation/resolve-decision.md
@@ -0,0 +1,11 @@
+---
+props:
+ type: object
+ properties:
+ record: {type: string, minLength: 1}
+ decision: {type: string, minLength: 1}
+ required: [record, decision]
+ additionalProperties: false
+---
+
+
diff --git a/examples/adversarial-implementation/tests/DecisionResolution.test.md b/examples/adversarial-implementation/tests/DecisionResolution.test.md
new file mode 100644
index 000000000..86066e9d7
--- /dev/null
+++ b/examples/adversarial-implementation/tests/DecisionResolution.test.md
@@ -0,0 +1,41 @@
+```bash exec as="location"
+pwd -P
+```
+
+```bash exec as="commandSetting"
+printf '%s' "$XMD_EXAMPLE_COMMAND"
+```
+
+'},
+ {name:"DR2 A2 amending a Planner decision routes original Architect, retained Planner, then Implementor",fixture:''},
+ {name:"DR3 A2 accepting an Architect decision returns to that Architect before the retained Planner",fixture:''},
+ {name:"DR4 A3 an Implementor discovery hold at clean source routes Architect, retained Planner, original Implementor",fixture:''},
+ {name:"DR5 A4 A6 stale, foreign, unsupported and excluded resolutions refuse without dispatch or managed change",fixture:''},
+ {name:"DR5 A4 a saved decision result whose phase execution then failed refuses before reservation",fixture:''},
+ {name:"DR6 A5 repeats, contenders and interrupted publication never duplicate or adopt effects",fixture:''},
+ {name:"DR7 A6 decision inputs keep snapshot, descriptor, protection, permission and capacity boundaries",fixture:''}
+]} />
+
+
+
+' + selected.fixture.replaceAll("ROOT",JSON.stringify(root)) + ''} />
+ "'" + value.replaceAll("'","'\"'\"'") + "'").join(" ")} />
+```bash exec as="ran"
+{runner} {caseArguments}
+```
+
+
+
+
+
+```bash exec as="testCommandSetting"
+printf '%s' "$XMD_EXAMPLE_TEST_COMMAND"
+```
+
+ "'" + value.replaceAll("'","'\"'\"'") + "'").join(" ")} />
+```bash exec as="native"
+{testRunner} {nativeArguments}
+```
+
+
diff --git a/examples/adversarial-implementation/tests/agents/decision-planner-held.md b/examples/adversarial-implementation/tests/agents/decision-planner-held.md
new file mode 100644
index 000000000..b7197ad34
--- /dev/null
+++ b/examples/adversarial-implementation/tests/agents/decision-planner-held.md
@@ -0,0 +1,4 @@
+
+
+{text}
+
diff --git a/examples/adversarial-implementation/tests/agents/decision-planner.md b/examples/adversarial-implementation/tests/agents/decision-planner.md
new file mode 100644
index 000000000..38527ce4b
--- /dev/null
+++ b/examples/adversarial-implementation/tests/agents/decision-planner.md
@@ -0,0 +1,9 @@
+
+
+{text}
+
+
+
+
+{text}
+
diff --git a/examples/adversarial-implementation/tests/components/Fixture/DecisionBoundary.md b/examples/adversarial-implementation/tests/components/Fixture/DecisionBoundary.md
new file mode 100644
index 000000000..587ce78a7
--- /dev/null
+++ b/examples/adversarial-implementation/tests/components/Fixture/DecisionBoundary.md
@@ -0,0 +1,95 @@
+---
+description: >-
+ Keep the inherited snapshot, descriptor, protection, permission and capacity refusals
+ for decision inputs. Use .
+props:
+ type: object
+ properties:
+ root: {type: string}
+ required: [root]
+ additionalProperties: false
+---
+
+
+
+
+
+
+
+
+
+```bash exec as="altered"
+cp -- {snapshotPath} {snapshotPath}.original
+printf 'altered retained result' > {snapshotPath}
+```
+
+
+```bash exec as="removed"
+rm -- {snapshotPath}
+```
+
+
+```bash exec as="restored"
+mv -- {snapshotPath}.original {snapshotPath}
+```
+
+
+Rewritten after the request was bound.
+
+
+
+
+
+
+```bash exec as="described"
+set -e
+printf '%s%s%s' ghp _ abcdefghijklmnopqrstuvwxyz0123456789 > {secretQuoted}
+printf 'Readable only before its permission was withdrawn.' > {deniedQuoted}
+digest() { if command -v sha256sum >/dev/null 2>&1; then sha256sum "$1"; else shasum -a 256 "$1"; fi | cut -d' ' -f1; }
+printf '{"secret":{"utf8Bytes":%s,"sha256":"%s"},"denied":{"utf8Bytes":%s,"sha256":"%s"}}' "$(wc -c < {secretQuoted} | tr -d ' ')" "$(digest {secretQuoted})" "$(wc -c < {deniedQuoted} | tr -d ' ')" "$(digest {deniedQuoted})"
+chmod 000 {deniedQuoted}
+```
+
+{described.stdout}
+
+
+
+
+
+
+
+
+
+{oversizedText}
+
+
+```bash exec as="permitted"
+chmod 644 {deniedQuoted}
+```
+
+
+
+Accepted scope rewritten after launch.Accepted scope rewritten after launch.
+
+
+
+
+
+{child.stdout}
+
+
+
+
+
+{child.stdout}
+
+
+
+{calledText}
+ input.path === held.evidence)?.content,called.inputs.find(input => input.path === revised.path)?.content]} expected={["architect",originalEvidence,"Accepted scope rewritten after launch."]} />
+
diff --git a/examples/adversarial-implementation/tests/components/Fixture/DecisionFailedExecution.md b/examples/adversarial-implementation/tests/components/Fixture/DecisionFailedExecution.md
new file mode 100644
index 000000000..4180fb09d
--- /dev/null
+++ b/examples/adversarial-implementation/tests/components/Fixture/DecisionFailedExecution.md
@@ -0,0 +1,54 @@
+---
+description: >-
+ Refuse a decision for an accepted needs_decision result whose phase execution failed
+ after saving it. Use .
+props:
+ type: object
+ properties:
+ root: {type: string}
+ required: [root]
+ additionalProperties: false
+---
+
+
+
+
+
+
+
+
+{executionText}
+
+
+{resultText}
+
+
+
+
+
+
+
+
+
+
+```bash exec as="hidden"
+mv -- {executionPath} {executionPath}.retained
+```
+
+
+```bash exec as="restored"
+mv -- {executionPath}.retained {executionPath}
+```
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/adversarial-implementation/tests/components/Fixture/DecisionHold.md b/examples/adversarial-implementation/tests/components/Fixture/DecisionHold.md
new file mode 100644
index 000000000..65f7f4b93
--- /dev/null
+++ b/examples/adversarial-implementation/tests/components/Fixture/DecisionHold.md
@@ -0,0 +1,52 @@
+---
+description: >-
+ Launch a deterministic ordinary ticket until its first hold. Use inside a TempDir.
+props:
+ type: object
+ properties:
+ root: {type: string}
+ scenario: {type: string}
+ ready: {type: boolean, default: false}
+ cut: {type: [object, 'null'], default: null}
+ required: [root, scenario]
+ additionalProperties: false
+returns: {type: object}
+---
+
+
+
+format() { printf '%s' "$1"; }
+
+```bash exec as="base"
+git add api.sh
+git -c commit.gpgsign=false commit -qm 'ordinary unsigned planning base'
+git rev-parse HEAD
+```
+
+
+
+Accepted ordinary planning scope and frozen checks.
+
+
+
+
+
+```bash exec as="commandSetting"
+printf '%s' "$XMD_EXAMPLE_COMMAND"
+```
+
+
+ "'" + value.replaceAll("'","'\"'\"'") + "'").join(" ")} />
+
+```bash exec as="child"
+XMD_DECISION_CUT_MODE={props.cut.mode} XMD_DECISION_CUT_MATCH={props.cut.match} {runner} {runArguments}
+```
+
+
+
+
+{child.stdout}
+
+
+
diff --git a/examples/adversarial-implementation/tests/components/Fixture/DecisionInterruption.md b/examples/adversarial-implementation/tests/components/Fixture/DecisionInterruption.md
new file mode 100644
index 000000000..bd98cf57b
--- /dev/null
+++ b/examples/adversarial-implementation/tests/components/Fixture/DecisionInterruption.md
@@ -0,0 +1,183 @@
+---
+description: >-
+ Repeat, contend for and interrupt decision resolution, publication and continuation.
+ Use .
+props:
+ type: object
+ properties:
+ root: {type: string}
+ required: [root]
+ additionalProperties: false
+---
+
+```bash exec as="commandSetting"
+printf '%s' "$XMD_EXAMPLE_COMMAND"
+```
+
+
+
+
+
+
+
+
+
+
+```bash exec as="uncertain"
+mkdir attempts/0001
+```
+
+
+
+
+```bash exec as="cleared"
+rmdir attempts/0001
+test ! -e decisions
+```
+
+
+
+
+ quote + value.replaceAll(quote,quote + '"' + quote + '"' + quote) + quote).join(" ")} />
+
+
+```bash exec as="contended"
+{runner} {entry} > {output}/first.json 2> {output}/first.err &
+first=$!
+{runner} {entry} > {output}/second.json 2> {output}/second.err &
+second=$!
+wait "$first"; firstStatus=$?
+wait "$second"; secondStatus=$?
+printf '%s %s' "$firstStatus" "$secondStatus"
+```
+
+
+
+
+{firstText}
+{secondText}
+
+
+
+
+ entry.publication === "confirmed")} />
+= 1 && winners.every(entry => JSON.stringify(entry.continuation) === JSON.stringify(winners[0].continuation)))}>
+ entry.publication !== "confirmed").every(entry => entry.status === "hold" && JSON.stringify(entry.continuation) === JSON.stringify(held.work.continuation) && entry.hold.includes(reservation))}>
+
+
+
+
+
+{child.stdout}
+
+
+
+
+
+
+```bash exec as="origins"
+set -e
+printf 'The original pathname was reused after the confirmed resolution.' > {decisionOrigin}
+rm -- {provenanceOrigin}
+```
+
+{child.stdout}
+
+```bash exec as="corrupted"
+cp -- {retainedDecision} {retainedDecision}.retained
+printf 'altered retained decision' > {retainedDecision}
+```
+
+
+```bash exec as="retainedRestored"
+mv -- {retainedDecision}.retained {retainedDecision}
+```
+
+
+
+
+
+
+
+
+
+
+
+
+{child.stdout}
+
+
+{child.stdout}
+
+
+
+{child.stdout}
+
+
+{child.stdout}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ quote + value.replaceAll(quote,quote + '"' + quote + '"' + quote) + quote).join(" ")} />
+
+```bash exec as="child"
+XMD_DECISION_CUT_MODE={cut.mode} XMD_DECISION_CUT_MATCH={cut.match} {runner} {cutArguments}
+```
+
+
+{child.stdout}
+
+
+{interrupted.output}
+
+
+
+
+
+
+
+
+
+{repeat.stdout}
+
+
+
+
+
+
+
+
+
+
+{child.stdout}
+
+
+```bash exec as="uncertain"
+mkdir calls/0001
+```
+
+
+{child.stdout}
+
+
+
+
diff --git a/examples/adversarial-implementation/tests/components/Fixture/DecisionJourney.md b/examples/adversarial-implementation/tests/components/Fixture/DecisionJourney.md
new file mode 100644
index 000000000..cda68bd83
--- /dev/null
+++ b/examples/adversarial-implementation/tests/components/Fixture/DecisionJourney.md
@@ -0,0 +1,108 @@
+---
+description: >-
+ Resolve one prospective managed hold and continue it through its original owners.
+ Use .
+props:
+ type: object
+ properties:
+ root: {type: string}
+ scenario: {type: string}
+ disposition: {enum: [accept, amend]}
+ route: {type: array, items: {enum: [architect, planner, implementor]}}
+ required: [root, scenario, disposition, route]
+ additionalProperties: false
+---
+
+
+
+
+
+
+
+
+```bash exec as="checkout"
+git rev-parse HEAD
+git status --porcelain --untracked-files=no
+```
+
+
+
+
+{heldResultText}
+
+
+
+
+
+Selected accepted input for the routed owner.
+
+
+
+
+
+
+{refusedChild.stdout}
+
+
+
+
+
+{child.stdout}
+
+
+
+
+
+
+
+
+
+ 0} expected={true} />
+
+
+
+
+ [resolved.documents[path].utf8Bytes,resolved.documents[path].sha256,resolved.documents[path].observation])} expected={[[decision.request.decision.utf8Bytes,decision.request.decision.sha256,"file"],[decision.request.provenance.utf8Bytes,decision.request.provenance.sha256,"file"],[selected.utf8Bytes,selected.sha256,"file"]]} />
+
+
+
+{receiptText}
+
+
+
+
+
+
+
+
+
+{continuation.stdout}
+
+
+
+
+
+ call.role)} expected={props.route} />
+ call.session === saved.manifest.roles[call.role].session && call.provider === saved.manifest.roles[call.role].provider)} expected={true} />
+ call.initialize)} expected={props.route.map((role,index) => !saved.checkpoint.initialized[role] && props.route.indexOf(role) === index)} />
+ call.assignment.phase)} expected={props.route.map(role => role === "implementor" ? "implementation" : "discovery")} />
+ call.status)} expected={props.route.map(() => "accepted")} />
+
+
+ input.path === held.evidence)} expected={!(saved.deliveredInputs[first.session] ?? []).includes(held.evidence)} />
+ first.inputs.some(input => input.path === path))} expected={true} />
+
+{calledText}
+ input.path)]} />
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/adversarial-implementation/tests/components/Fixture/DecisionRefusal.md b/examples/adversarial-implementation/tests/components/Fixture/DecisionRefusal.md
new file mode 100644
index 000000000..6dfd1dfb5
--- /dev/null
+++ b/examples/adversarial-implementation/tests/components/Fixture/DecisionRefusal.md
@@ -0,0 +1,97 @@
+---
+description: >-
+ Refuse stale, conflicting, foreign and excluded decision resolutions without a role
+ call or managed change. Use .
+props:
+ type: object
+ properties:
+ root: {type: string}
+ required: [root]
+ additionalProperties: false
+---
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```bash exec as="dirty"
+printf 'edited during the hold\n' > legacy.fixture
+```
+
+
+
+
+```bash exec as="moved"
+set -e
+git checkout -q -- legacy.fixture
+git -c commit.gpgsign=false commit -q --allow-empty -m 'moved during the hold'
+```
+
+
+
+
+
+```bash exec as="restored"
+git reset -q --hard {held.task.revision}
+```
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/adversarial-implementation/tests/components/Fixture/DecisionRequest.md b/examples/adversarial-implementation/tests/components/Fixture/DecisionRequest.md
new file mode 100644
index 000000000..c8c2139e7
--- /dev/null
+++ b/examples/adversarial-implementation/tests/components/Fixture/DecisionRequest.md
@@ -0,0 +1,30 @@
+---
+description: >-
+ Save decision texts and one ticket-decision.v1 request bound to a held ticket. Use
+ .
+props:
+ type: object
+ properties:
+ held: {type: object}
+ name: {type: string}
+ disposition: {type: string, default: accept}
+ acceptedInputs: {type: array, default: []}
+ override: {type: object, default: {}}
+ required: [held, name]
+ additionalProperties: false
+returns: {type: object}
+---
+
+
+
+
+{decisionText}
+Standing coordinator authority recorded in the accepted contract; no new human answer is recorded.
+
+
+
+
+
+
+
+
diff --git a/examples/adversarial-implementation/tests/components/Fixture/Execution.md b/examples/adversarial-implementation/tests/components/Fixture/Execution.md
index 4b957fd37..c8508bfec 100644
--- a/examples/adversarial-implementation/tests/components/Fixture/Execution.md
+++ b/examples/adversarial-implementation/tests/components/Fixture/Execution.md
@@ -2,11 +2,12 @@
props:
type: object
properties:
- entry: {enum: [run, continue]}
+ entry: {enum: [run, continue, resolve-decision]}
value: {type: object}
repository: {type: string}
root: {type: string}
steps: {type: integer, minimum: 1}
+ decision: {type: string}
required: [entry, value, repository, root]
additionalProperties: false
returns: {type: object}
@@ -19,7 +20,7 @@ pwd -P
-
+
diff --git a/examples/adversarial-implementation/tests/components/Fixture/InitialPlanning.md b/examples/adversarial-implementation/tests/components/Fixture/InitialPlanning.md
index 03cd2b795..b90525516 100644
--- a/examples/adversarial-implementation/tests/components/Fixture/InitialPlanning.md
+++ b/examples/adversarial-implementation/tests/components/Fixture/InitialPlanning.md
@@ -80,7 +80,7 @@ git rev-parse HEAD
-
+
{text}
diff --git a/examples/adversarial-implementation/tests/components/Fixture/Refused.md b/examples/adversarial-implementation/tests/components/Fixture/Refused.md
new file mode 100644
index 000000000..070af96d9
--- /dev/null
+++ b/examples/adversarial-implementation/tests/components/Fixture/Refused.md
@@ -0,0 +1,20 @@
+---
+description: >-
+ Require a refused decision envelope that keeps the prior continuation. Use
+ .
+props:
+ type: object
+ properties:
+ output: {type: string}
+ continuation: {type: object}
+ expected: {type: string}
+ required: [output, continuation, expected]
+ additionalProperties: false
+returns: {type: object}
+---
+{props.output}
+
+
+
+
diff --git a/examples/adversarial-implementation/tests/components/Phase/Role.md b/examples/adversarial-implementation/tests/components/Phase/Role.md
index fc6d64bcb..18fb4cb72 100644
--- a/examples/adversarial-implementation/tests/components/Phase/Role.md
+++ b/examples/adversarial-implementation/tests/components/Phase/Role.md
@@ -41,7 +41,7 @@ printf '%s' 'Evidence B: mutable original after planning.' > {evidencePath}
Changed during read-only discovery.
-
+
@@ -56,6 +56,9 @@ git rev-parse HEAD^
+
+
+
```bash exec as="check"
@@ -117,3 +120,5 @@ git rev-parse HEAD
+
+
diff --git a/examples/adversarial-implementation/tests/decision-cut.md b/examples/adversarial-implementation/tests/decision-cut.md
new file mode 100644
index 000000000..1dfc7e048
--- /dev/null
+++ b/examples/adversarial-implementation/tests/decision-cut.md
@@ -0,0 +1,13 @@
+---
+props:
+ type: object
+ properties:
+ record: {type: string}
+ decision: {type: string}
+ required: [record, decision]
+ additionalProperties: false
+---
+
+{text}
+
+
diff --git a/examples/adversarial-implementation/tests/decision-native-cases.md b/examples/adversarial-implementation/tests/decision-native-cases.md
new file mode 100644
index 000000000..1b11092ba
--- /dev/null
+++ b/examples/adversarial-implementation/tests/decision-native-cases.md
@@ -0,0 +1,67 @@
+```bash exec as="location"
+pwd -P
+```
+
+
+
+
+
+```bash exec as="repositoryPrepared"
+set -eu
+mkdir repository
+git -C repository init -q
+git -C repository config user.name Fixture
+git -C repository config user.email fixture@example.invalid
+git -C repository config commit.gpgsign false
+pwd -P
+```
+
+
+Follow the accepted fixture assignment.
+Prepare the accepted fixture plan.
+Preserve the accepted fixture architecture.
+Implement the accepted fixture plan.
+```bash exec as="base"
+git add AGENTS.md .agents
+git commit -qm 'fixture instructions'
+git rev-parse HEAD
+```
+
+Accepted decision-resolution fixture scope.
+
+
+
+
+
+
+
+
+
+
+{stdout}
+
+
+
+{journeyText}
+{journey.identityBefore}
+
+
+
+
+
+
+
+
+
+{deliveryText}
+ input.path)]} expected={["decision-planner",[fixture.root + "/decision.md",fixture.root + "/provenance.md"]]} />
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/adversarial-implementation/tests/decision-native-journey.md b/examples/adversarial-implementation/tests/decision-native-journey.md
new file mode 100644
index 000000000..9268bf8d7
--- /dev/null
+++ b/examples/adversarial-implementation/tests/decision-native-journey.md
@@ -0,0 +1,32 @@
+---
+props:
+ type: object
+ properties:
+ manifest: {type: string}
+ root: {type: string}
+ variant: {enum: [continued, missing]}
+ required: [manifest, root, variant]
+---
+
+{text}
+
+
+
+
+Decision native: accept the held proposal.Standing coordinator authority; no new human answer is recorded.
+
+
+ [path,{path,utf8Bytes:document.utf8Bytes,sha256:document.sha256}]))} />
+
+
+
+
+
+```bash exec as="removed"
+rm -- {quoted}
+```
+
+
+
+
+
diff --git a/packages/cli/tests/adversarial-decision-resolution.test.ts b/packages/cli/tests/adversarial-decision-resolution.test.ts
new file mode 100644
index 000000000..922181a4a
--- /dev/null
+++ b/packages/cli/tests/adversarial-decision-resolution.test.ts
@@ -0,0 +1,7 @@
+import { describe, it } from "@executablemd/test-support/bdd";
+import { runAdversarialJourney } from "./support/adversarial-journey.ts";
+
+describe("adversarial implementation example", () => {
+ it("runs the DecisionResolution Markdown journeys without native models", () =>
+ runAdversarialJourney("DecisionResolution"));
+});
diff --git a/packages/cli/tests/fixtures/decision-cut.mjs b/packages/cli/tests/fixtures/decision-cut.mjs
new file mode 100644
index 000000000..5f1743a72
--- /dev/null
+++ b/packages/cli/tests/fixtures/decision-cut.mjs
@@ -0,0 +1,28 @@
+import { Plugin } from "@executablemd/core/api";
+import { API, env } from "@executablemd/runtime";
+
+// Fail the first host commit whose target contains XMD_DECISION_CUT_MATCH, either before
+// its bytes exist or after the rename completed without acknowledging it to the writer.
+export default Plugin({
+ name: "decision-cut",
+ *install() {
+ const mode = yield* env("XMD_DECISION_CUT_MODE");
+ const match = yield* env("XMD_DECISION_CUT_MATCH");
+ if (mode === undefined || match === undefined) {
+ return;
+ }
+ let cut = false;
+ yield* API.Fs.around({
+ *rename([from, to], next) {
+ if (!cut && String(to).includes(match)) {
+ cut = true;
+ if (mode === "after") {
+ yield* next(from, to);
+ }
+ throw new Error("synthetic " + mode + " cut at " + String(to));
+ }
+ return yield* next(from, to);
+ },
+ });
+ },
+});
diff --git a/packages/cli/tests/support/adversarial-journey.ts b/packages/cli/tests/support/adversarial-journey.ts
index 14d1a9467..c4a97f469 100644
--- a/packages/cli/tests/support/adversarial-journey.ts
+++ b/packages/cli/tests/support/adversarial-journey.ts
@@ -57,7 +57,7 @@ export function* runAdversarialJourney(suite: string) {
? preparationTimeout
: suite === "Friction" || suite === "Implementation"
? 180_000
- : suite === "Delivery"
+ : suite === "Delivery" || suite === "DecisionResolution"
? 300_000
: 120_000,
env: {
diff --git a/scripts/tests/runtime-exclusions.test.ts b/scripts/tests/runtime-exclusions.test.ts
index 700af2514..06eadfb62 100644
--- a/scripts/tests/runtime-exclusions.test.ts
+++ b/scripts/tests/runtime-exclusions.test.ts
@@ -155,6 +155,7 @@ describe("the applicable corpus", () => {
const wrappers = [
"adversarial-artifact-return-recovery",
"adversarial-artifact-return",
+ "adversarial-decision-resolution",
"adversarial-delivery",
"adversarial-friction",
"adversarial-implementation",