diff --git a/examples/adversarial-implementation/README.md b/examples/adversarial-implementation/README.md index 19dfac715..b1a91efc7 100644 --- a/examples/adversarial-implementation/README.md +++ b/examples/adversarial-implementation/README.md @@ -361,13 +361,32 @@ from claiming readiness or merging independently. ## Prepare requests without metadata repair turns -These rules apply to separate phase requests and Ticket role calls. -`Phase.Request` renders the complete prompt before entering an Agent, including -initial repository instructions, role instructions, assignment, selected text and -response schema. A missing selected component or input fails there; a packet -above 256000 characters refuses before provider dispatch. The selected evidence -keeps its separate 64000-character bound; the complete-prompt ceiling also accommodates -mandatory initialization instructions and the response schema. Nothing is truncated. +These rules apply to separate phase requests and Ticket role calls. Codex authors +prose committed to workflow documents, including guides, component instructions +and prompt templates. Claude roles may write internal runtime handoffs, hold +prompts and summaries. +`Phase.Run` freezes the submission guide in its reserved attempt directory. +`Phase.Request` checks that guide and prepares the phase prompt before entering +an Agent. The prompt includes initial repository and role instructions, +the assignment, selected text and an absolute reference to `submission-guide.md` +in the attempt directory. The guide contains the complete submission instructions +and the current role- and phase-specific JSON contract. Read it before returning +any result, including an early blocker, source conflict or unanswered decision. +The same retained native call reads the file and returns the result; staging the +guide adds no model call. + +The guide and its hash receipt are runner-owned. Preparation refuses occupied +paths and confirms that the published text is readable under current File +permissions and protection. After saving each raw reply, the workflow verifies +the guide and receipt against the expected submission instructions before it +accepts a result or starts a correction. Missing, unreadable or changed files +hold the attempt with its raw reply preserved. Corrections retain their existing +inline repair packet, original session and allowance. + +A missing selected component or input fails before provider dispatch. A prompt +above 256000 characters refuses without truncation. The guide has its own +256000-character and UTF-8-byte bounds. Selected evidence keeps its separate +64000-character allowance; moving submission instructions does not enlarge it. Provider configuration and client compatibility retain their existing checks before a turn starts. No paid prompt probes installation or repairs launch metadata. diff --git a/examples/adversarial-implementation/components/Phase/Correct.md b/examples/adversarial-implementation/components/Phase/Correct.md index 61734ee93..cd69431ab 100644 --- a/examples/adversarial-implementation/components/Phase/Correct.md +++ b/examples/adversarial-implementation/components/Phase/Correct.md @@ -80,6 +80,7 @@ shasum -a 256 -- {quoted}/request.json {quoted}/diagnostic.json {quoted}/origina {raw} + diff --git a/examples/adversarial-implementation/components/Phase/Instructions.md b/examples/adversarial-implementation/components/Phase/Instructions.md index f763ce210..6cfdded6f 100644 --- a/examples/adversarial-implementation/components/Phase/Instructions.md +++ b/examples/adversarial-implementation/components/Phase/Instructions.md @@ -16,12 +16,15 @@ props: default: [] assignment: type: object + submission: + type: object initialize: type: boolean default: false required: - role - assignment + - submission additionalProperties: false --- @@ -44,7 +47,9 @@ You remain the retained repository {props.role}. The previous owner's request is Do not draft, create or edit PR or issue titles or descriptions. The Sidekick running Codex owns that metadata and publication. Return technical decisions, code and evidence only; API documentation stays within the design assignment. Describe user-directed amendments separately from implementation defects, cite the recorded approval evidence and keep the existing correction allowances. This restriction also applies when a general role guide mentions opening a draft PR. -Execute the assigned phase through its stated deliverables. An assigned test or artifact that has not yet been written is remaining work. Continue it within this call. Use blocked only for a concrete external condition you cannot resolve within the assignment: quota, permission, provider failure, unavailable external dependency or genuinely missing input. Supply blocker.kind, reason, unblockCondition and evidence references. A source or design conflict returns needs_discovery; an unanswered human choice returns needs_decision. Use the supplied handoff, artifact paths and evidence first. Store every new plan, handoff, report, candidate and command receipt under assignment.artifactDirectory, the phase directory in this ticket workspace. Keep the source checkout and native cwd unchanged. Historical/source references retain their original locations; do not move or rewrite them. Return absolute references to new artifacts. Leave the runner-owned assignment.json, raw.txt, result.json, status.json and event files unchanged. Tie additional reads to a missing fact or an affected invariant. Reopen earlier conclusions when a named change invalidates them. State the missing fact when the assignment is insufficient. Retain mandatory repository and role requirements. +Codex authors prose committed to workflow documents, including guides, component instructions and prompt templates. Claude roles may write internal runtime handoffs, hold prompts and summaries. If your selected provider is Claude and the assignment needs workflow-document prose that Codex has not supplied, return needs_discovery with the required authoring work. + +Execute the assigned phase through its stated deliverables. An assigned test or artifact that has not yet been written is remaining work. Continue it within this call. Use blocked only for a concrete external condition you cannot resolve within the assignment: quota, permission, provider failure, unavailable external dependency or genuinely missing input. Supply blocker.kind, reason, unblockCondition and evidence references. A source or design conflict returns needs_discovery; an unanswered human choice returns needs_decision. Use the supplied handoff, artifact paths and evidence first. Store every new plan, handoff, report, candidate and command receipt under assignment.artifactDirectory, the phase directory in this ticket workspace. Keep the source checkout and native cwd unchanged. Preserve first failures, command receipts and the exact source inputs actually tested. An uncommitted candidate needs its own retained identity; a base HEAD is not its tested revision. Historical/source references retain their original locations; do not move or rewrite them. Return absolute references to new artifacts. Leave the runner-owned assignment.json, raw.txt, result.json, status.json, submission-guide.md, submission-guide.json and event files unchanged. Tie additional reads to a missing fact or an affected invariant. Reopen earlier conclusions when a named change invalidates them. State the missing fact when the assignment is insufficient. Retain mandatory repository and role requirements. Resolve the assigned design or planning question. Return the bounded proposal or accepted plan and the next owner's exact request. Return needs_decision for an unanswered human decision. Existing design and plan approval gates still apply. @@ -95,26 +100,10 @@ Recorded inputs: Prepared assignment: -Return assessment on completed implementation, changes_required, missing_evidence and escalate. For changes_required or missing_evidence, assess only the finite correction being requested, not the original feature. Keep already settled responsibilities closed; a missing test witness does not by itself reopen the production architecture. Completed implementation likewise reports the actual correction rather than inheriting the whole feature scope. Assess actual impact: mechanical, architecture and acceptance booleans; one short impact reason and individual evidence references, plus risk:null unless a concrete consequential uncertainty or risk needs additional reasoning. For high effort, risk contains its own short reason and supporting evidence. Merely touching concurrency, cancellation, durable state, replay or a public boundary is not that reason. Test-only changes can affect acceptance. A mechanical assessment has no architecture, acceptance or complexity impact. New non-mechanical feature work includes Planner acceptance; correction work requires only affected responsibilities. Keep evidence references in artifacts or already recorded documents. Do not request a reviewer or reasoning effort in prose to override this assessment. - -Return escalate only from medium Discovery or Review when a concrete newly discovered risk or uncertainty prevents completing this assignment. Keep the same revision and impact flags, supply risk with the specific reason and supporting evidence, and leave the checkout clean. The workflow resumes the same original role/session at high. High cannot escalate again. Implementation uses its assigned provider/effort and returns needs_discovery for a scope conflict. - -The workflow supplies omitted phase and work, the assigned revision for read-only phases, and the accepted continuation for complete/pass. Explicit conflicting metadata is refused. Implementation must report the actual resulting revision; evidence must name the inputs actually tested. - -Return next.phase and next.role explicitly when the outcome changes the prepared route. For complete/pass, copy assignment.continuation exactly; completed implementation routing is derived from the returned assessment and replaces that predicted continuation. For escalate, copy the current phase and role; the workflow derives and checks that same-owner continuation. For changes_required or missing_evidence, select implementation/implementor. For needs_discovery with apiConflict, select discovery/planner; otherwise select discovery/architect. For blocked or needs_decision, select hold/null. The program verifies this gate before another role can run; ready is a phase-loop result, not delivery approval. - -Keep summary to 1200 characters. Address handoff to next.role, or ROOT when next.phase is hold/ready. Write only that owner's next bounded action and necessary artifact references in at most 250 words and 1800 characters. Put command receipts in evidence and detailed reports in artifact files. Select only the short documents the next owner needs in handoffInputs. Each selected handoffInputs path must appear in your returned artifacts or the already recorded documents. A file existing on disk alone does not make it a recorded document. Keep full test logs, patches and historical ledgers in artifacts; listing an artifact does not send its contents. The selected-input limit is 64000 UTF-16 units for the recipient's entire owed packet, including undelivered accepted inputs and role guides. Use the recipient's recorded remaining allowance for new handoff material. Keep binding clauses, their conditions, exceptions, commands, identities and unresolved findings exact; reference full supporting artifacts. Ticket.Prepare checks the actual packet before dispatch and retains its receipt. This selected-input allowance is separate from the 256000-character complete-prompt ceiling. Use a new reference for changed contents. The workflow supplies accepted inputs once per retained role; do not request their repetition without a named change. Do not repeat the summary, command list, prior prompts, full plan, contract packet or narrative history in handoff. Omit blocker outside blocked outcomes. - -Reference individual UTF-8 text or JSON files in artifacts, evidence and handoffInputs. Do not return a directory or binary path as a document reference: the workflow reads each reference as a text file. For a group of files, save a text index naming the individual files and return that index. - -Before returning, check the required fields, assigned work/phase, actual revision, next role and phase, and character limits against the contract below. Omit optional metadata you cannot establish instead of guessing. - -Return exactly one JSON object conforming to this contract, without Markdown fences or surrounding prose. The handoff field is the complete ready-to-send request for the next owner; only that field becomes the next request. Artifacts and evidence travel as structured references. For a command on an uncommitted candidate, use evidence.revision=null and candidate=the retained candidate/command metadata path; a base HEAD is not its tested revision. Use a commit SHA only when the tested inputs correspond to that commit. Report observations as observations; schema validation does not establish test results, approvals or delivery readiness. - - - - - !["phase","work",...(props.assignment.phase === "implementation" ? [] : ["revision"])].includes(name)),"discoveryRequests","discoveryGaps"],additionalProperties:false,properties:{...schemas.result.properties,discoveryRequests:{...schemas.result.properties.discoveryRequests,items:authorRequest},discoveryGaps:{...schemas.result.properties.discoveryGaps,items:authorGap},phase:{const:props.assignment.phase},work:{const:props.assignment.work},outcome:phaseOutcome,contract:props.role === "architect" && props.assignment.phase === "discovery" ? schemas.result.properties.contract : undefined},$defs:schemas.result.$defs}} /> - -{resultContract} +Submission guide: +Read the frozen UTF-8 file at {props.submission.path} before returning any result, +including an early blocker, source conflict or unanswered decision. Use the same +native call to read it and return the result; no separate formatting turn is +scheduled. It contains the complete submission instructions and the exact JSON +contract for this role and phase. Leave the guide and its receipt unchanged. diff --git a/examples/adversarial-implementation/components/Phase/Request.md b/examples/adversarial-implementation/components/Phase/Request.md index c4de4c76d..613cd7d3e 100644 --- a/examples/adversarial-implementation/components/Phase/Request.md +++ b/examples/adversarial-implementation/components/Phase/Request.md @@ -13,6 +13,7 @@ props: returns: {type: string} --- - + + 256000}> input.path + " (" + input.content.length + ")").join(", ") + ". Preserve the prepared assignment and reduce the request before dispatch; nothing was truncated or sent. No provider prompt began."} /> diff --git a/examples/adversarial-implementation/components/Phase/Run.md b/examples/adversarial-implementation/components/Phase/Run.md index c076b3c98..946e45632 100644 --- a/examples/adversarial-implementation/components/Phase/Run.md +++ b/examples/adversarial-implementation/components/Phase/Run.md @@ -128,12 +128,14 @@ mkdir -- {quotedAttempt} + {raw} + diff --git a/examples/adversarial-implementation/components/Phase/SubmissionGuide.ts b/examples/adversarial-implementation/components/Phase/SubmissionGuide.ts new file mode 100644 index 000000000..a6bac6e80 --- /dev/null +++ b/examples/adversarial-implementation/components/Phase/SubmissionGuide.ts @@ -0,0 +1,52 @@ +import { Component } from "@executablemd/core/api"; +import { z } from "zod"; +import { clear, describe, descriptor, read, same, unused, write } from "../Ticket/text-storage.ts"; + +export const props = { + type: "object", + properties: { + repository: { type: "string" }, + directory: { type: "string" }, + mode: { enum: ["prepare", "check"], default: "prepare" }, + }, + required: ["repository", "directory"], + additionalProperties: false, +}; +const input = z + .object({ + repository: z.string(), + directory: z.string().startsWith("/"), + mode: z.enum(["prepare", "check"]).default("prepare"), + }) + .strict(); +const limit = 256_000; + +export default function* SubmissionGuide(value: unknown) { + const { repository, directory, mode } = input.parse(value); + const acquired = yield* Component.operations.tryContent(); + if (acquired.failure !== undefined) { + throw acquired.failure; + } + const text = acquired.text; + const expected = describe(directory + "/submission-guide.md", text); + if (text.length > limit || expected.utf8Bytes > limit) { + throw new Error("The submission guide exceeds 256000 characters or UTF-8 bytes."); + } + yield* clear(text); + const receipt = directory + "/submission-guide.json"; + if (mode === "prepare") { + if (!(yield* unused(repository, expected.path)) || !(yield* unused(repository, receipt))) { + throw new Error("The submission guide is occupied or unavailable; preserve this attempt."); + } + yield* write(repository, expected.path, text); + yield* write(repository, receipt, JSON.stringify(expected)); + } + const recorded = descriptor.parse(JSON.parse(yield* read(repository, receipt, limit))); + const retained = yield* read(repository, expected.path, limit); + if (!same(expected, recorded) || !same(expected, describe(expected.path, retained))) { + throw new Error( + "The frozen submission guide changed; preserve the raw reply. No successor is admitted.", + ); + } + return expected; +} diff --git a/examples/adversarial-implementation/components/Phase/SubmissionInstructions.md b/examples/adversarial-implementation/components/Phase/SubmissionInstructions.md new file mode 100644 index 000000000..5a5f2ffe0 --- /dev/null +++ b/examples/adversarial-implementation/components/Phase/SubmissionInstructions.md @@ -0,0 +1,40 @@ +--- +props: + type: object + properties: + role: {enum: [architect, planner, implementor]} + assignment: {type: object} + required: [role, assignment] + additionalProperties: false +--- + + +# Submit a phase result + +Read this guide before returning from this assignment, including an early blocker, +source conflict or unanswered decision. It applies to this role's current native +agent call. Return the existing phase result in that call. + +Return assessment on completed implementation, changes_required, missing_evidence and escalate. For changes_required or missing_evidence, assess only the finite correction being requested, not the original feature. Keep already settled responsibilities closed; a missing test witness does not by itself reopen the production architecture. Completed implementation likewise reports the actual correction rather than inheriting the whole feature scope. Assess actual impact: mechanical, architecture and acceptance booleans; one short impact reason and individual evidence references, plus risk:null unless a concrete consequential uncertainty or risk needs additional reasoning. For high effort, risk contains its own short reason and supporting evidence. Merely touching concurrency, cancellation, durable state, replay or a public boundary is not that reason. Test-only changes can affect acceptance. A mechanical assessment has no architecture, acceptance or complexity impact. New non-mechanical feature work includes Planner acceptance; correction work requires only affected responsibilities. Keep evidence references in artifacts or already recorded documents. Do not request a reviewer or reasoning effort in prose to override this assessment. + +Return escalate only from medium Discovery or Review when a concrete newly discovered risk or uncertainty prevents completing this assignment. Keep the same revision and impact flags, supply risk with the specific reason and supporting evidence, and leave the checkout clean. The workflow resumes the same original role/session at high. High cannot escalate again. Implementation uses its assigned provider/effort and returns needs_discovery for a scope conflict. + +The workflow supplies omitted phase and work, the assigned revision for read-only phases, and the accepted continuation for complete/pass. Explicit conflicting metadata is refused. Implementation must report the actual resulting revision; evidence must name the inputs actually tested. + +Return next.phase and next.role explicitly when the outcome changes the prepared route. For complete/pass, copy assignment.continuation exactly; completed implementation routing is derived from the returned assessment and replaces that predicted continuation. For escalate, copy the current phase and role; the workflow derives and checks that same-owner continuation. For changes_required or missing_evidence, select implementation/implementor. For needs_discovery with apiConflict, select discovery/planner; otherwise select discovery/architect. For blocked or needs_decision, select hold/null. The program verifies this gate before another role can run; ready is a phase-loop result, not delivery approval. + +Keep summary to 1200 characters. Address handoff to next.role, or ROOT when next.phase is hold/ready. Write only that owner's next bounded action and necessary artifact references in at most 250 words and 1800 characters. Put command receipts in evidence and detailed reports in artifact files. Select only the short documents the next owner needs in handoffInputs. Each selected handoffInputs path must appear in your returned artifacts or the already recorded documents. A file existing on disk alone does not make it a recorded document. Keep full test logs, patches and historical ledgers in artifacts; listing an artifact does not send its contents. The selected-input limit is 64000 UTF-16 units for the recipient's entire owed packet, including undelivered accepted inputs and role guides. Use the recipient's recorded remaining allowance for new handoff material. Keep binding clauses, their conditions, exceptions, commands, identities and unresolved findings exact; reference full supporting artifacts. Ticket.Prepare checks the actual packet before dispatch and retains its receipt. This selected-input allowance is separate from the 256000-character complete-prompt ceiling. Use a new reference for changed contents. The workflow supplies accepted inputs once per retained role; do not request their repetition without a named change. Do not repeat the summary, command list, prior prompts, full plan, contract packet or narrative history in handoff. Omit blocker outside blocked outcomes. + +Reference individual UTF-8 text or JSON files in artifacts, evidence and handoffInputs. Do not return a directory or binary path as a document reference: the workflow reads each reference as a text file. For a group of files, save a text index naming the individual files and return that index. + +Before returning, check the required fields, assigned work/phase, actual revision, next role and phase, and character limits against the contract below. Omit optional metadata you cannot establish instead of guessing. + +Return exactly one JSON object conforming to this contract, without Markdown fences or surrounding prose. The handoff field is the complete ready-to-send request for the next owner; only that field becomes the next request. Artifacts and evidence travel as structured references. For a command on an uncommitted candidate, use evidence.revision=null and candidate=the retained candidate/command metadata path; a base HEAD is not its tested revision. Use a commit SHA only when the tested inputs correspond to that commit. Report observations as observations; schema validation does not establish test results, approvals or delivery readiness. + + + + + !["phase","work",...(props.assignment.phase === "implementation" ? [] : ["revision"])].includes(name)),"discoveryRequests","discoveryGaps"],additionalProperties:false,properties:{...schemas.result.properties,discoveryRequests:{...schemas.result.properties.discoveryRequests,items:authorRequest},discoveryGaps:{...schemas.result.properties.discoveryGaps,items:authorGap},phase:{const:props.assignment.phase},work:{const:props.assignment.work},outcome:phaseOutcome,contract:props.role === "architect" && props.assignment.phase === "discovery" ? schemas.result.properties.contract : undefined},$defs:schemas.result.$defs}} /> + +{resultContract} + diff --git a/examples/adversarial-implementation/tests/Delivery.test.md b/examples/adversarial-implementation/tests/Delivery.test.md index 42e209302..1b6a881c4 100644 --- a/examples/adversarial-implementation/tests/Delivery.test.md +++ b/examples/adversarial-implementation/tests/Delivery.test.md @@ -87,7 +87,9 @@ printf '%s' "$XMD_EXAMPLE_COMMAND" - + + + diff --git a/examples/adversarial-implementation/tests/Friction.test.md b/examples/adversarial-implementation/tests/Friction.test.md index 7fefbd9a1..f0caff020 100644 --- a/examples/adversarial-implementation/tests/Friction.test.md +++ b/examples/adversarial-implementation/tests/Friction.test.md @@ -128,10 +128,11 @@ git rev-parse HEAD - + {raw} + {correction.output} diff --git a/examples/adversarial-implementation/tests/ProductionRole.test.md b/examples/adversarial-implementation/tests/ProductionRole.test.md index 987e3756c..32a87e446 100644 --- a/examples/adversarial-implementation/tests/ProductionRole.test.md +++ b/examples/adversarial-implementation/tests/ProductionRole.test.md @@ -18,9 +18,13 @@ pwd -P - + + + - + + + @@ -37,13 +41,21 @@ pwd -P - + + + - + + + - + + + - + + + @@ -70,9 +82,10 @@ pwd -P ``` - + {raw} + @@ -155,10 +168,11 @@ false - + - + + {schemaText} diff --git a/examples/adversarial-implementation/tests/Submission.test.md b/examples/adversarial-implementation/tests/Submission.test.md new file mode 100644 index 000000000..39c0e6571 --- /dev/null +++ b/examples/adversarial-implementation/tests/Submission.test.md @@ -0,0 +1,79 @@ +```bash exec as="location" +pwd -P +``` + + + + + + + + + + + + + +{schemaText} + + + + + + + + + + + + + + + + +```bash exec as="head" +git -C {quoted} rev-parse HEAD +``` + + + + + + + + + + + + + 0} expected={true} /> + +{deliveryText} + + + + + 0} expected={true} /> + +{execution.output} + + + + + + + + + + + + + + +Changed before dispatch. +A directory cannot supply the guide. + + + + + diff --git a/examples/adversarial-implementation/tests/agents/api-conflict-correction.md b/examples/adversarial-implementation/tests/agents/api-conflict-correction.md index d1c3949a4..5fa7dc813 100644 --- a/examples/adversarial-implementation/tests/agents/api-conflict-correction.md +++ b/examples/adversarial-implementation/tests/agents/api-conflict-correction.md @@ -1,5 +1,5 @@ - + {text} {assignment.request} diff --git a/examples/adversarial-implementation/tests/agents/decision-planner-held.md b/examples/adversarial-implementation/tests/agents/decision-planner-held.md index b7197ad34..76796ff15 100644 --- a/examples/adversarial-implementation/tests/agents/decision-planner-held.md +++ b/examples/adversarial-implementation/tests/agents/decision-planner-held.md @@ -1,4 +1,4 @@ - + {text} diff --git a/examples/adversarial-implementation/tests/agents/decision-planner.md b/examples/adversarial-implementation/tests/agents/decision-planner.md index 38527ce4b..f01778c98 100644 --- a/examples/adversarial-implementation/tests/agents/decision-planner.md +++ b/examples/adversarial-implementation/tests/agents/decision-planner.md @@ -1,9 +1,9 @@ - + {text} - + {text} diff --git a/examples/adversarial-implementation/tests/agents/initialized-role.md b/examples/adversarial-implementation/tests/agents/initialized-role.md index a5d4e2e00..6ed6e1f74 100644 --- a/examples/adversarial-implementation/tests/agents/initialized-role.md +++ b/examples/adversarial-implementation/tests/agents/initialized-role.md @@ -1,3 +1,4 @@ - request.instructions.includes(text))}> + request.instructions.includes(text))}> + initialization received diff --git a/examples/adversarial-implementation/tests/agents/preparation-architect.md b/examples/adversarial-implementation/tests/agents/preparation-architect.md index 25c928fa3..cc908ce88 100644 --- a/examples/adversarial-implementation/tests/agents/preparation-architect.md +++ b/examples/adversarial-implementation/tests/agents/preparation-architect.md @@ -1,5 +1,5 @@ - + {text} {assignment.request} diff --git a/examples/adversarial-implementation/tests/agents/preparation-implementor.md b/examples/adversarial-implementation/tests/agents/preparation-implementor.md index 15dc51713..5f2c976bd 100644 --- a/examples/adversarial-implementation/tests/agents/preparation-implementor.md +++ b/examples/adversarial-implementation/tests/agents/preparation-implementor.md @@ -3,7 +3,7 @@ - + {text} {assignment.request} diff --git a/examples/adversarial-implementation/tests/agents/preparation-planner.md b/examples/adversarial-implementation/tests/agents/preparation-planner.md index 00e1712d6..d00f8754e 100644 --- a/examples/adversarial-implementation/tests/agents/preparation-planner.md +++ b/examples/adversarial-implementation/tests/agents/preparation-planner.md @@ -1,10 +1,10 @@ - + {text} {assignment.request} - + {text} {assignment.request} diff --git a/examples/adversarial-implementation/tests/agents/submission-result.md b/examples/adversarial-implementation/tests/agents/submission-result.md new file mode 100644 index 000000000..03441b9c6 --- /dev/null +++ b/examples/adversarial-implementation/tests/agents/submission-result.md @@ -0,0 +1,15 @@ + + + +{text} + +not a phase result + + + + + + +{packetText} + + diff --git a/examples/adversarial-implementation/tests/production-components/NativeGuide.ts b/examples/adversarial-implementation/tests/production-components/NativeGuide.ts new file mode 100644 index 000000000..abee5d125 --- /dev/null +++ b/examples/adversarial-implementation/tests/production-components/NativeGuide.ts @@ -0,0 +1,53 @@ +import { Agent, Component } from "@executablemd/core/api"; +import { ensureDir, rm } from "@effectionx/fs"; +import { z } from "zod"; +import { read, write } from "../../components/Ticket/text-storage.ts"; + +export const props = { + type: "object", + properties: { variant: { type: "string" } }, + required: ["variant"], + additionalProperties: false, +}; + +export default function* NativeGuide(input: unknown) { + const { variant } = z.object({ variant: z.string() }).parse(input); + let calls = 0; + let path: string | undefined; + yield* Agent.around({ + *prompt(args, next) { + calls++; + const text = args[0]; + path ??= text.split("Read the frozen UTF-8 file at ")[1]?.split(" before returning")[0]; + if (path === undefined || (calls === 1 && text.includes('"$defs"'))) { + throw new Error("The native request did not stage its submission guide."); + } + const guide = yield* read("/", path); + if ( + ![ + '"$defs"', + "including an early blocker", + "Test-only changes can affect acceptance.", + "A mechanical assessment has no architecture, acceptance or complexity impact.", + "a public boundary is not that reason", + ].every((rule) => guide.includes(rule)) + ) { + throw new Error("The staged guide is unreadable or incomplete."); + } + if (variant === "changed" || (variant === "correction-changed" && calls === 2)) { + yield* write("/", path, "Changed during the native turn."); + } + if (variant === "missing" || variant === "unreadable") { + yield* rm(path); + } + if (variant === "unreadable") { + yield* ensureDir(path); + } + return yield* next(...args); + }, + }); + yield* Component.operations.content(); + if (calls !== (variant === "correction-changed" ? 2 : 1)) { + throw new Error("The staged submission used an additional native call."); + } +} diff --git a/packages/cli/tests/adversarial-submission.test.ts b/packages/cli/tests/adversarial-submission.test.ts new file mode 100644 index 000000000..85aca680e --- /dev/null +++ b/packages/cli/tests/adversarial-submission.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 Submission Markdown journeys without native models", () => + runAdversarialJourney("Submission")); +}); diff --git a/packages/cli/tests/support/adversarial-journey.ts b/packages/cli/tests/support/adversarial-journey.ts index c4a97f469..575698c1d 100644 --- a/packages/cli/tests/support/adversarial-journey.ts +++ b/packages/cli/tests/support/adversarial-journey.ts @@ -3,7 +3,7 @@ import { fileURLToPath } from "node:url"; import { env } from "@executablemd/runtime"; import { readTextFile } from "@effectionx/fs"; -const testedSuites = ["ProductionRole", "Preparation"]; +const testedSuites = ["ProductionRole", "Preparation", "Submission"]; export function* runAdversarialJourney(suite: string) { const retainedEvidence = suite.startsWith("ArtifactReturn") @@ -48,6 +48,9 @@ export function* runAdversarialJourney(suite: string) { testedSuites.includes(suite) ? "examples/adversarial-implementation/components" : "examples/adversarial-implementation/tests/components", + ...(suite === "Submission" + ? ["--include", "examples/adversarial-implementation/tests/production-components"] + : []), "--include", "examples/adversarial-implementation/components", ], diff --git a/scripts/tests/runtime-exclusions.test.ts b/scripts/tests/runtime-exclusions.test.ts index 06eadfb62..0b812d97d 100644 --- a/scripts/tests/runtime-exclusions.test.ts +++ b/scripts/tests/runtime-exclusions.test.ts @@ -163,6 +163,7 @@ describe("the applicable corpus", () => { "adversarial-preparation", "adversarial-production-role", "adversarial-session-continuity", + "adversarial-submission", "adversarial-workflow", ].map((name) => `packages/cli/tests/${name}.test.ts`); expect(