Skip to content

Document adversarial implementation workflow WIP - #181

Draft
taras wants to merge 9 commits into
mainfrom
agent/adversarial-implementation-workflow-wip
Draft

Document adversarial implementation workflow WIP#181
taras wants to merge 9 commits into
mainfrom
agent/adversarial-implementation-workflow-wip

Conversation

@taras

@taras taras commented Jul 28, 2026

Copy link
Copy Markdown
Owner

Why

#181 is the end-goal target for the planner → implementor → human-decider
adversarial implementation loop. It only earns that role while it describes the
architecture the project is actually building, and the path underneath it moved:
#291 and #365 shipped, #425 named what the journal witness proves, #218 became
the authoritative dependency map, and #298's <Stage> was rejected outright
rather than deferred. #292 tracks keeping this target synchronized.

What changes

Before:

The target described a <Workflow> / <Sandbox> / <Stage> spine over an
artifact ledger in sidecar Git history at refs/xmd/runs, one implicit
worktree, an implementor agent that edits files directly, a single <Commit>,
and a <PullRequest> handle carrying reviews, comments and checks. It marked
retention and atomic effects as unbuilt, and described the props asymmetry and
the <Content /> nesting bug as current behavior.

After:

The command selects the environment. xmd workflow start creates the workflow
run and its one retained Workspace (#366); the root document is the workflow,
because #298 rejected stage subdivision. Named <Repository> and <Worktree>
compose the checkouts from ordinary root props, so no locator resolves through a
hidden alias and no single worktree is implied (#293). Agents are read-only
under a host ceiling a document cannot raise, so the implementor returns
constrained XMD that <Expand> preflights and expands as ordinary durable
effects (#302, #369), and <Git.Add>, <Git.Commit>, an explicit <Git.Push>
and <PullRequest> follow in that order (#294, #370, #295). <Issue> still
sits inside the approved branch (#296). Lexical <Dir> and <Agent.AddDir> are
separate operations, and the two stages that give an agent a checkout say so.

Waiting for the user is a durable suspension that releases the executor and
xmd workflow resume continues — which is what <Stage> was reaching for.

Retention is no longer speculative. #291 and #365 are described as shipped
foundation: the run retains its filtered journal, versioned Workspace roots,
Repository/Worktree metadata and Agent-session mappings, addressed by public run
ID, and one expansion publishes its mutation, logical Workspace root and journal
result in one transaction. JournalProvenance (#425) is named where the
documents discuss retained evidence — it is what makes history this run's
history rather than merely storage. refs/xmd/runs is gone.

Props are namespaced everywhere (#305), <Content /> projects at any depth
(#328), and #203's lifetime rule stays. Every unbuilt capability is a table row
naming its issue.

Two gaps are now stated instead of assumed away:

  • Add a deterministic PullRequest workflow effect #295 moved reviews, comments and checks out of <PullRequest>'s creation
    result
    , and no open issue owns the forge read that returns them to a
    network-denied reviewer. The requirement is preserved verbatim; the mechanism
    is marked unowned.
  • The journal records which run and expansion produced a decision, not which
    person answered it.
    No open issue owns that either.

How it works

xmd workflow start → retained Workspace → named Repository/Worktree
  → read-only agents propose → <Expand> performs → Add/Commit/Push → PullRequest
  → review → user gate → accept, defer, or revise

The workflow still works outside in: it establishes observable, independently
reviewable boundaries, then implements smaller PRs within them. Review findings
that would derail the active chain become explicit follow-up issues when
deferral is safe and the user approved it.

Review guide

Start with: workflows/adversarial-implementation/start.md

Then review:

  1. workflows/adversarial-implementation/Implementation.md — the largest change:
    read-only agents, generated XMD, and the Git/forge effect order.
  2. workflows/adversarial-implementation/primitives.md — the inventory, now
    organized as Implement retained Workflow Workspace restoration #218's four-phase dependency map.
  3. workflows/adversarial-implementation/artifacts.md — retained run state and
    JournalProvenance replacing the artifact ledger.
  4. workflows/adversarial-implementation/runtime.md — the host ceiling replacing
    <Sandbox>, and suspension/interruption/cancellation.
  5. specs/adversarial-implementation-workflow.md — the same reconciliation at
    contract level, including the rewritten open-questions list.
  6. Planning.md, Discovery.md, UserCheckpoint.md, InstructionFiles.md
    namespaced props and <Agent.AddDir>.

Look carefully at:

  • whether any claim about shipped behavior is still ahead of main;
  • whether the user remains the final authority at every material transition,
    including decisions a stage resolves internally and returns;
  • whether any durable or external effect can execute before the approval that
    authorizes it;
  • whether the commit/push/pull-request ordering is stated without one implying
    another;
  • whether the two stated gaps are the right ones to leave open, and whether they
    should become issues before this merges;
  • whether the terminology matches architecture.md — "document execution" and
    "workflow run" are now distinguished where the old text said "run".

What must stay true

  • The planner and implementor are equally capable analysts with different
    responsibilities: the planner proposes a theory of implementation and the
    implementor validates it.
  • Material product, architecture, scope, and risk decisions remain with the user,
    and a stage returns its decision and verdict as data rather than prose.
  • Agents inspect; XMD mutates. No document prop grants an agent write access.
  • Git.Push is explicit and separate from both Git.Commit and PullRequest.
  • External effects reconcile provider state and never claim atomicity with
    SQLite.
  • Large changes split into observable, independently validatable PRs, and
    deferred findings stay visible without silently expanding the active chain.

How to verify it

Documentation-only, so verification is inspection through current main rather
than a runtime suite:

  • inspectDocument parses every frontmatter block in the nine workflow documents
    and compiles its declared props and returns schemas through main;
    compileParseSchema compiles all five embedded draft-07 schemas. 9
    documents, 5 embedded schemas, 0 failures.
  • inspectComponent resolves every component name the documents write, through
    the same selectComponent path execution uses. 21 resolveAgent,
    Break, Capture, Discovery, Each, Elicit, Else, File, Glob,
    If, Implementation, InstructionFiles, Loop, Output, Parse,
    Planning, Prompt, Return, SafeParse, Session, UserCheckpoint
    and 9 do not: Agent.AddDir, Expand, Git.Add, Git.Commit,
    Git.Push, Issue, PullRequest, Repository, Worktree. That set is
    exactly what the "what runs today" tables claim, so a table that drifts from
    main fails this check.
  • git diff --check origin/main...HEAD — clean.
  • deno task lint covers packages scripts .reviews/components and does not
    reach specs/ or workflows/, so it was not run; no source or test file
    changed.

The workflow still does not run end to end, and this change does not claim it
does.

Scope

Included

  • Reconciliation of the workflow contract, the entry document, the five stage
    documents, and the runtime, artifact and primitive documents.
  • The Implement retained Workflow Workspace restoration #218 dependency map replacing ad-hoc dependency prose.
  • JournalProvenance terminology where the documents discuss retained evidence.

Intentionally unchanged

New abstractions

  • No new component is proposed. Every name the documents write now belongs to an
    open issue or to shipped syntax, and <Expand> is used with the workflow
    Workspace specification's own placeholder caveat that Evaluate Agent-generated XMD through a constrained allowlist #369 settles the name.
  • No runtime functionality is claimed by this documentation-only WIP.

Risks and limitations

Scope confirmation

  • Every changed file supports the purpose described above.
  • The branch is rebased onto main, not merged.
  • No generated or mechanical changes are included.
  • The description matches the current diff and validation results.

@github-actions

github-actions Bot commented Jul 28, 2026

Copy link
Copy Markdown

PR #181: Document adversarial implementation workflow WIP

11 files, +3337 / -0

Scope

🔴 PR has 3337 lines changed. Split into focused PRs.

🟡 3337 lines changed. PRs under 400 receive more thorough review.

Structural

✅ No structural bloat detected.

Slop

✅ Slop indicators look low.

Static Analysis

✅ Oxlint found no issues.

Correctness

No extraneous code patterns detected.

@taras

taras commented Aug 2, 2026

Copy link
Copy Markdown
Owner Author

End-goal implementation audit — 2026-08-02

Reviewed PR head 28f764e94b9bcaa9f7db0dcc689c31dc06466dac against current main at de4f7757f216063b5b48e431561d141bcbf40097. This audit treats #181 as the target workflow we are building toward, not as a conventional merge candidate. It is invalid after either head changes.

The target remains coherent: the user owns material decisions; planner and implementor converge through evidence; workflow state and environmental effects are explicit; agents do not own Git, GitHub, or workspace effects; and every live resource is scope-owned.

Settled contracts to fold into the target documents

These are documentation updates, not missing product features.

  • Replace inputs with props in start.md, runtime.md, InstructionFiles.md, Discovery.md, Planning.md, UserCheckpoint.md, and Implementation.md. props is the settled declaration vocabulary; inputs is ordinary metadata and does not declare component or root props.
  • Replace the remaining future-facing Support schema-validated component returns #176 language in artifacts.md and primitives.md with the shipped return contract: Markdown value components declare returns and one direct <Return>; registered function returns bind by reference by default; returns opts into JSON validation and requires as; uncaptured strings render and uncaptured non-strings render nothing.
  • Reclassify <If>/<Else>, <Loop>/<Break>, <Answers>/<Answer>, and <Return> as shipped reserved structural syntax. Repository files and registrations cannot claim these names.
  • Reclassify <TempDir>, <File>, <Glob>, <Parse>, <SafeParse>, and <Elicit> as shipped core defaults. A repository component may override each ordinary default.
  • Update the parsing description to the shipped contracts: schemas compile before content, <Parse> binds the validated JSON value, and <SafeParse> binds { ok: true, value } or { ok: false, input, errors } without swallowing child or schema-compilation failures.
  • Update the filesystem description to the shipped contracts: contextual cwd is implemented; <File> reads or atomically replaces UTF-8 text and returns no write handle; <Glob> returns a sorted, deduplicated string[]; both are observationally confined but are not a security sandbox.
  • Update the elicitation description to the shipped architecture: <Elicit> is provider-neutral, validates and durably fingerprints the question and answer, xmd run supplies WebForm as the current host provider, and <Answers> supplies document-owned answers without choosing a transport. Cross-stage stop and resume remains separate work.
  • Update loop durability language: <Loop> records entered iterations and terminal break, exhausted, or error outcomes and refuses stale replay. Workflow-level cancellation and stage-stop records remain future behavior.
  • Record that dynamic agent and session selection through expression props is implemented, and that Agent, Session, Prompt, Elicit, and the other function components resolve through scope-local registration with repository override precedence.
  • Update the PR review guide to the actual target files: start.md, Discovery.md, Planning.md, UserCheckpoint.md, and Implementation.md.

Shipped foundation available to the end goal

The document-level logic in InstructionFiles, Discovery, Planning, and UserCheckpoint is therefore no longer speculative once its declarations are updated to the settled contracts. The remaining gap is workflow orchestration and ownership, not conditional logic, parsing, file discovery, or elicitation.

Missing feature checklist for the complete workflow

Workflow identity, artifacts, and resumption

  • Implement <Workflow> as the owner of one internal run identity without exposing a required runId prop.
  • Resolve base once to a pinned source revision and publish the run and revision through a contextual Run API.
  • Define immutable artifact versions for handoffs, plans, verdicts, implementation results, user decisions, and environmental effects, keyed by stable component and loop-iteration identity.
  • Persist run snapshots in Git objects reachable from refs/xmd/runs, including explicit push/fetch behavior for the custom ref.
  • Restore named stage inputs from the run record and render their exact content into later prompts without transfer files.
  • Record completed stages, completed loop iterations, success, failure, cancellation, and stop reasons without inventing a successful terminal record for interrupted work.
  • Reconcile durable effects with the run identity so resumption cannot duplicate or silently adopt an effect from another run.
  • Resolve replay across replaced ephemeral environments (Implement retained Workflow Workspace restoration #218).

Stage execution and user continuation

  • Implement <Stage> to select one manual stage, restore its declared inputs, publish its outputs, and stop cleanly at the stage boundary.
  • Define how a later invocation selects and resumes the same workflow run and stage.
  • Define in-band runtime input that can resume a stopped workflow. <Elicit> solves an in-run question but not cross-process stage continuation.
  • Implement the automated stop arbitration from the target: iteration completion, configured file change, or user input, with deterministic priority and cancellation behavior.
  • Preserve the current user-authority contract across every resumed transition; resumption must not turn an unanswered material choice into implicit approval.

Workspace ownership

  • Implement <Worktree> to create or reconcile one workspace from the pinned revision and reuse it across discovery, planning, implementation, and review.
  • Publish contextual cwd for all child file, process, agent, and Git operations.
  • Define deterministic worktree identity, branch naming, existing-state reconciliation, and behavior when the base branch moves.
  • Clean up a clean workspace on success; retain dirty, unpushed, failed, or cancelled work with its path, branch, state, and recovery reason.
  • Ensure projected content resources stop before the owning workspace cleans up (Bind projected content resources to the component invocation scope #203).
  • Keep worktree filesystem isolation distinct from the security boundary.

Enforceable sandbox and permissions

  • Implement <Sandbox> as an enforceable capability boundary for filesystem roots, environment variables, processes, network access, secrets, and durable effects.
  • Give planner stages repository read/search capability without source mutation.
  • Give implementor stages write access only to the workflow-owned worktree, never shared Git metadata.
  • Give deterministic components narrow Git and GitHub authority rather than exposing that authority through an agent prompt.
  • Own and halt every process, agent session, stream, and watcher before the enclosing stage or workflow scope closes.
  • Resolve containment that remains safe under concurrent filesystem mutation, or explicitly bind unattended execution to a platform sandbox that provides it (Contain filesystem access at the provider boundary #227).
  • Install default-on secret rejection before journal events and sidecar Git snapshots become durable (Reject secrets before journal persistence by default #199).

Deterministic Git and GitHub effects

  • Implement <Commit> to validate the exact allowed path set, refuse unrelated changes, write Git metadata outside agent authority, and return a structured commit identity.
  • Define commit reconciliation after interruption, including the case where the commit may have succeeded before the process lost its result.
  • Implement <PullRequest> to create or resolve the PR for the workflow branch idempotently and return its number, URL, head, base, state, and review/check state.
  • Implement <Issue> to create or resolve provenance-linked deferred findings idempotently.
  • Record the inputs, observed pre-state, applied effect, and returned state of every Git and GitHub operation in the workflow run.
  • Ensure replay never creates duplicate commits, pull requests, or issues and never trusts a moved PR head without a fresh review.

End-to-end workflow contract

  • Make start.md execute discovery → handoff checkpoint → plan convergence → authorization → implementation/review loop → final user acceptance in the same workflow-owned workspace.
  • Prove malformed agent JSON receives only the bounded correction turns shown in the document and cannot reach control flow or durable effects.
  • Prove a failed planner verdict returns its prescriptive revision prompt to the same implementor session and preserves all prior versions.
  • Prove material choices stop at <UserCheckpoint> and only the user response authorizes the next transition.
  • Prove deferred findings create provenance-linked issues without silently expanding the active PR chain.
  • Prove cancellation and failure halt live resources, preserve recoverable work, and leave enough state for an explicit resume.
  • Prove the complete run can resume after process exit without hidden transcript state or user copy/paste.
  • Prove agents cannot directly perform the workflow-owned Git, GitHub, sandbox, or retention effects.

Not blockers for this workflow

  • External JSON Schema references (Resolve external JSON Schema refs through XMD filesystem and fetch capabilities #192): the target already captures self-contained schemas.
  • Structured <File> handles: the current target passes relative paths and does not consume a write handle.
  • xmd play: it remains the layer built after this implementation loop works; it is not required to make the loop executable.
  • Unattended runtime inspector control: ordinary decisions use the in-band user protocol; inspector support remains operational meta-control.

This checklist should shrink as features land. A settled contract updates the target documents and moves to the shipped foundation; only capabilities absent from the runtime remain unchecked.

@taras

taras commented Aug 2, 2026

Copy link
Copy Markdown
Owner Author

Current delivery map

The root document is the workflow. A durable workflow run may continue through multiple document executions.

Each issue remains an independently reviewable stop point.

Living target and shipped document logic

Workflow identity and environment foundations

#199 and #227 can proceed independently. #218 is designed and stacks on PR #341 until #289 merges.

Persistence and workspace composition

Workspace state is retained across completion, failure, cancellation, and interruption; scope teardown releases only ephemeral provider attachments. Point-in-time snapshots, rollback, and training export are not prerequisites for normal resumption.

Deterministic Git and GitHub effects

After #291 and #293:

Authority, composition, and certification

Dependency spine

#181/#292 → #305 → #290

#289 / PR #341 → #218 ─┐
                        ├→ #293 → #294
#199 + #289 / PR #341 → #291 ─┘

#291 → #297
#294 + #297 → #295 → #296
#227 + #293 → #302

#290 + #291 + #293 + #294 + #295 + #296 + #302
  → #301 → #300 → #299

#298 is superseded by #291, which owns durable lookup, xmd workflow run/continue, restoration of declared values, cross-process continuation, and durable outcomes.

Implementors validate authorized slices. Taras settles #227, #290 exhaustion, and #302's term and installation architecture before those stories are delegated. #218's product decisions are recorded in the issue; its implementor validates that design rather than choosing a replay or provider model.

@taras

taras commented Aug 2, 2026

Copy link
Copy Markdown
Owner Author

Parallel delivery map

Current at PR head 28f764e94b9bcaa9f7db0dcc689c31dc06466dac. Boxes on the same horizontal tier may proceed in parallel. Arrows are merge dependencies, not merely preferred ordering.

                                      START
                                        |
      +---------------------------------+----------------------------------+
      |                                 |                                  |
      v                                 v                                  v
+----------------------+      +----------------------+          +----------------------+
| A. Synchronize #181  |      | B. #203 projected   |          | C. #199 persistence  |
| to settled contracts |      | resource ownership  |          | safety stack         |
+----------+-----------+      +----------+-----------+          +----------+-----------+
           |                             |                                 |
           v                             |                                 |
+----------------------+                 |                                 |
| Prove current        |                 |                                 |
| document logic       |                 |                                 |
+----------+-----------+                 |                                 |
           |                             |                                 |
           |                  +----------v-----------+                     |
           |                  | Run identity +       |                     |
           |                  | pinned base revision |                     |
           |                  +----+-------------+---+                     |
           |                       |             |                         |
           |       +---------------+             +--------------------+    |
           |       |                                                    |    |
           |       |        PRODUCT DECISION TRACKS                     |    |
           |       |                                                    |    |
           |       |   +----------------------+   +------------------+  |    |
           |       +<--| #218 environment     |   | #227 containment |  |    |
           |           | replay ruling + impl |   | / sandbox ruling |  |    |
           |           +----------+-----------+   +---------+--------+  |    |
           |                      |                         |           |    |
           |                      v                         |           |    |
           |           +----------------------+            |           |    |
           |           | Worktree lifecycle   |<-----------+-----------+    |
           |           | and contextual cwd   |            |                |
           |           +----------+-----------+            |                |
           |                      |                        |                |
           |                      |            +-----------v-----------+    |
           |                      |            | Artifact ledger +     |<---+
           |                      |            | refs/xmd/runs history |
           |                      |            +-----------+-----------+
           |                      |                        |
           |                      +------------+-----------+
           |                                   |
           |                                   v
           |                       +------------------------+
           |                       | Stage + manual resume  |
           |                       +-----------+------------+
           |                                   |
           |        +--------------------------+--------------------------+
           |        |                          |                          |
           |        v                          v                          v
           |  +-------------+       +--------------------+      +--------------------+
           |  | Commit      |       | GitHub effect      |      | Sandbox            |
           |  | effect      |       | reconciliation API |      | implementation     |
           |  +------+------+       +---------+----------+      +---------+----------+
           |         |                        |                           |
           |         |              +---------+---------+                 |
           |         |              |                   |                 |
           |         |              v                   v                 |
           |         |       +-------------+     +-------------+          |
           |         |       | PullRequest |     | Issue       |          |
           |         |       | effect      |     | effect      |          |
           |         |       +------+------+     +------+------+          |
           |         |              |                   |                 |
           +---------+--------------+---------+---------+-----------------+
                                            |
                                            v
                              +-----------------------------+
                              | Supervised complete workflow|
                              +--------------+--------------+
                                             |
                                             v
                              +-----------------------------+
                              | Automated continuation      |
                              | file/input/iteration race   |
                              +--------------+--------------+
                                             |
                                             v
                              +-----------------------------+
                              | End-to-end certification    |
                              +-----------------------------+

Parallel waves

Wave 1
  A  Target synchronization -> document-logic proof
  B  #203 projected-resource ownership
  C  #199 scanner and persistence-safety stack
  D  #218 and #227 investigation; Taras resolves the product choices

Wave 2
  Run identity/base pinning
  #218 implementation after the ruling
  remaining #199 slices
  #227 mechanism prototyping after the ruling

Wave 3
  Worktree             requires #203 + Run identity + #218
  Artifact ledger      requires Run identity + #199

Wave 4
  Stage/resume         requires Worktree + artifact ledger
  Commit               requires Worktree + artifact ledger
  GitHub effect core   requires artifact ledger
  Sandbox              requires Worktree interface + #227 ruling

Wave 5
  PullRequest and Issue may proceed in parallel after the shared
  GitHub reconciliation contract lands.

Wave 6
  Supervised workflow joins document logic, Stage/resume, Commit,
  PullRequest, Issue, and Sandbox.

Wave 7
  Automated continuation -> certification

Shared-code collision rules

Execution / durability:
  Run identity, #199, and #218 may be investigated concurrently.
  Their integration commits merge serially because they share execution setup,
  durable context, and replay boundaries.

Expansion / projection:
  #203 owns this lane until its lifecycle contract lands.

Workspace / Git:
  Worktree lands before Commit; both use the same repository ownership boundary.

GitHub:
  PullRequest and Issue split only after one shared idempotent reconciliation
  contract is merged. Neither invents its own replay or uncertain-result rule.

Product decisions:
  Implementors do not choose #218 durability semantics or #227 sandbox guarantees.

Maximum useful initial concurrency is three implementation lanes (A, B, C) plus planner/user investigation of #218 and #227. More implementation lanes would mostly create integration conflicts at the execution and durability boundary.

@taras

taras commented Aug 2, 2026

Copy link
Copy Markdown
Owner Author

Milestone story map

Created the Adversarial implementation workflow milestone. Every task in the approved delivery sequence now has a canonical story:

PR #181 itself is also attached to the milestone as the living end-goal artifact. Each new story records scope, observable acceptance criteria, dependencies, and its sequence position. Existing stories #199, #203, #218, and #227 remain canonical rather than being duplicated.

@taras
taras force-pushed the agent/adversarial-implementation-workflow-wip branch from 1a01e58 to 014447b Compare August 4, 2026 19:49
@taras

taras commented Aug 4, 2026

Copy link
Copy Markdown
Owner Author

Fresh head on current main — #292

Replaced the stale head 1a01e58 (based on e0b37ea, seven commits behind) with 014447b, re-derived from 7d7bdf2 — the #325 merge. No commit from the old head was cherry-picked, merged, or reapplied; the 11 files were re-authored. git merge-base with origin/main is exactly 7d7bdf2.

The markup did not run

Every stage passed props through expression props as agent={props.planner}. On current main that fails with props is not defined: an expression prop reads the bare binding, while text and content interpolation read the namespace. Reproduced at the root and inside a component body; the bare form works in both.

This is #305, still open — "Expression-valued component props can read props.name" is one of its acceptance criteria, so the target was written against a language change that has not landed. 22 expression-prop sites are corrected to the spelling main supports; the 16 text-interpolation sites keep {props.X}. The asymmetry is documented with #305 named as what removes it.

The error model reaches the stages

A stage component is split by its <Output> boundary: the region inside runs under the output error mode, everything outside is documentation and runs under throw, which no <PrintErrors> region replaces. A stage therefore returns a complete validated result or it fails, keeping only what it had already rendered. That is what makes each repair loop's final <Parse> a gate.

throwOnError is load-bearing for the same reason, and not for the reason I first assumed: without it a failed prompt records its failure and returns its text, raising nothing for the mode to decide (agent/function-components.ts:210-221).

One claim I did not repeat: architecture.md says an outer <PrintErrors> can print a failure an <Output> region decided, but expand.ts:2292 consults decidedByOutput only on the projected-content path, and a probe showed an outer boundary not printing a nested component's <Output> failure. The target states only what was observed.

Stale claims removed

<CollectFailures><PrintErrors> in the structural set · "the unresolved diagnostic" → "the unresolved printed error" · "replays recorded results" → replay restores a recorded outcome without re-executing, and a failed run is still a complete record. Replay is described as reaching the state execution resumes from, never as the continuation itself.

Vocabulary

Collapsed onto the concepts #289, #291 and #298 authorize — artifact ledger, artifact version, run identity, pinned source revision, stop reason, terminal record, stage boundary, declared inputs, cross-process continuation — replacing the four names these files used for a ledger and the three for a run. Engine state is described as scoped to the operation that owns it, with no module-scoped registry. Missing capabilities cite the issue that supplies them (#289, #291, #293, #294, #295, #296, #297, #298, #300, #302) rather than saying only "not implemented".

Classification

Shipped: InstructionFiles, Discovery, UserCheckpoint, Planning. Missing: the <Workflow>/<Sandbox>/<Worktree> spine, <Stage>, the artifact ledger, and — inside Implementation<Commit>, <PullRequest>, <Issue>, which is why that stage cannot expand rather than merely lacking a wrapper. Blocked on a product decision: #218, #227, and planning-loop exhaustion under #290, which stays explicitly unresolved — the output reports verdict.passed and does not call an exhausted loop converged.

Evidence

Check Result
inspectDocument on all 9 frontmatter-bearing files parse and compile; every one returnMode=text
compileParseSchema on all 5 embedded draft-07 schemas compile
inspectComponent — 21 shipped names 12 structural, 9 registered
inspectComponent — 5 repository components markdown
inspectComponent — 9 missing names unresolved
InstructionFiles executed against this repo's AGENTS.md renders exact path and content

Gates: deno task fmt, lint, check, test (349 passed, 0 failed), check:jsr (Success Dry run complete), and pnpm exec tsc --project tsconfig.node.json --noEmit.

Outstanding before merge

#203 is still open and is an input to this target, not something this PR closes. Before merge this branch rebases onto the origin/main that carries it, and the projected-resource and component-lifetime language is realigned with the behavior actually merged.

@taras

taras commented Aug 4, 2026

Copy link
Copy Markdown
Owner Author

Rebased onto 511776e — fresh review head 68733d7

014447b68733d7, rebased onto origin/main at 511776e (the #326 merge). Lease was pinned to 014447b. git merge-base with origin/main is exactly 511776e; two commits on the branch, both signed.

#203 as merged

#326 is test-and-spec-only: it adds L8 (a projected persist resource stops ahead of one the component retained after projecting) and Q14 (a projected daemon is gone after the invocation, signalled while the <TempDir> still exists). Those were precisely the two acceptance criteria this target had the weakest evidence for — I had cited O23/O24 and CW3, which are adjacent but not the same claim. #203 is now closed.

The target states the merged behavior and why it matters here: projected content keeps its caller's bindings while its live effects belong to the component invocation and stop before it cleans up its own. That ordering is what <Worktree> (#293) is built on — a process a stage starts stops before the workspace it ran in is removed, so cleanup cannot pull the ground out from under a running effect. Recorded in primitives.md (execution foundation, and the <Worktree> entry) and in the specification's cleanup-and-recovery section.

<PrintErrors> — contract restored, discrepancy filed

architecture.md is authoritative, so the output row reads as the registry states it:

| output | fails the run; <PrintErrors> can print instead | every <Output> region |

My earlier head under-stated that row to match observed behavior. That was the wrong call — the target does not get to redefine a settled contract from an engine observation. The engine discrepancy is now classified as missing and filed as #327, reproduced on 511776e in both arrangements: the failure arising in the callee's own <Output> region, and the failure projected into one. A control case (the same failure directly inside <PrintErrors> at the root) prints and continues, so the mechanism is not broken in general.

The distinction the target still draws is the registry's own: throw is the one mode a boundary cannot replace. Every stage's parsing sits in documentation, so each stage's final <Parse> is a gate for that reason — not because printing is unavailable. No workflow document writes <PrintErrors>, so nothing here depends on #327.

Revalidation on the rebased head

All probes rerun: inspectDocument parses all 9 frontmatters; compileParseSchema compiles all 5 embedded draft-07 schemas; inspectComponent resolves 21 shipped and 5 repository names and confirms 9 missing ones unresolved; InstructionFiles still runs end to end against this repo's AGENTS.md. Vocabulary sweep clean.

Gates rerun: deno task fmt, lint (0 errors), check, test (349 passed, 0 failed), check:jsr (Success Dry run complete), pnpm exec tsc --project tsconfig.node.json --noEmit (exit 0).

Everything from the previous head's summary that is not amended above still stands — the #305 expression-prop correction, the error-mode split, the vocabulary collapse onto #289/#291/#298, and planning-loop exhaustion left open under #290.

@taras

taras commented Aug 4, 2026

Copy link
Copy Markdown
Owner Author

User authority now gates execution — head 545fd93a484828689f70bd1239ca3e5af600ebd0

Both findings were correct. Fixed at 545fd93, on top of 511776e.

1. The decision controls execution

<UserCheckpoint> now declares returns and binds a schema-validated decision — proceed plus the assessment fields a later prompt quotes — instead of returning prose a caller could only read. One decisionSchema serves both paths: <Elicit> binds it when the assessment reports a material choice, and an explicit <Parse> binds "proceed": true with its reason when there is none. Continuation is represented, never inferred from absent elicitation data, which is what keeps #290's "cannot become implicit approval" intact.

Every affected transition is gated: a declined handoff does not start Planning; a declined authorization does not start Implementation; a declined plan-review checkpoint neither revises nor accepts the plan; a declined PR-review checkpoint neither revises nor accepts the implementation; a declined acceptance finishes as rejected rather than falling into the accepted branch. In both loops the checkpoint is read before the verdict, so the user's decision outranks the planner's.

Nesting is not stopping, and the target says so rather than overclaiming. The run still expands to <Output> and completes; there is no clean halt at a stage boundary a later invocation resumes from, and no stop reason recorded for one. Classified as missing under #298 over #289.

2. Two engine limitations found while proving it

#328<Content /> is not substituted when nested. It resolves only at a body's top level or directly inside <Output>. Discovery and UserCheckpoint both wrote <Content /> inside a <Prompt>, so neither could expand at all. Cause read out of expand.ts:2668: substituteSegmentList returns non-Content component segments unchanged and never recurses into their children. Reproduced with a Markdown wrapper, a core function component, and a structural <Capture> — the wrapper's kind does not matter. Both components now take the material as a prop, which interpolates anywhere.

A projection asymmetry worth knowing. A binding made inside a Markdown component's projected content does not escape to its caller; the same binding inside a registered function component does. My first harness stubbed <Agent>/<Session> as Markdown components and produced a failure that looked like a defect in UserCheckpoint but was an artifact of the stub. Rebuilt with TypeScript stubs before drawing any conclusion.

3. artifacts.md inventory corrected

The claim that every listed result is JSON declared inline is gone. Three kinds now, and the difference is stated as load-bearing — only parsed results can gate a transition:

  • Prose, no schema: PlannerHandoff, ImplementationPlan. Planning branches on the separately parsed verdict, not on plan text.
  • Parsed JSON, each described using only fields its inline schema declares — PlannerVerdict is passed/review/revisionPrompt (evidence and user questions live inside review, they are not fields); ImplementationResult is changedFiles/commitMessage/report; PullRequestVerdict adds findings with disposition/title/description/evidence; UserInvolvementAssessment is requiresUser/assessment/question/options/recommendation.
  • A declared return: UserDecision, from the checkpoint. The actor and timestamp that would make it auditable are marked missing under Store WorkflowRuns and filtered journals in SQLite #291 — nothing in the returned value identifies who answered.

4. Executable discrimination over the shipped subset

Real UserCheckpoint, TypeScript stub agent recording every turn, <Answers> supplying the decision:

Scenario Agent turns proceed Stages that ran
Material choice, user declines 1 false none — both bindings stayed unresolved
Material choice, user authorizes 2 true PLANNING-RAN, IMPLEMENTATION-RAN
No material choice 2 true (explicit <Parse> branch) PLANNING-RAN, IMPLEMENTATION-RAN

The declining path records no subsequent agent turn. In the third scenario a declining <Answer> was in scope and never consulted, because <Elicit> never ran — the continuation came from the explicit branch. All four <Output> outcome branches were exercised separately and each renders its own outcome with no unbound-binding error, including rejected-at-acceptance.

5. Verification

Probes rerun: 9 frontmatters parse (UserCheckpoint now returnMode=value, the rest text), 5 embedded schemas compile, 21 shipped + 5 repository names resolve, 9 missing names unresolved. Vocabulary sweep clean.

Local gates: fmt, lint (0 errors), check, test (349 passed, 0 failed), check:jsr, tsc — all green.

All ten PR checks green: composability, deploy, jsr, lint, review, site, smoke, test-bun, test-deno, test-node.

@taras

taras commented Aug 4, 2026

Copy link
Copy Markdown
Owner Author

Authority now survives the component boundary — head 173e96aac33388b715ab9b4e1fff7e3cb50e4f13

All three findings were correct, and the <Issue> one was the serious one: a durable GitHub object created from the planner's proposed disposition before anyone approved it. Fixed at 173e96a, still based on 511776e.

Structured stage boundaries

Planning and Implementation are value components now. Each returns its prose (plan / report), the parsed verdict's fields, the complete UserDecision it resolved internally, and two derived control fields:

  • authorizedproceed && verdict.passed. A stage cannot approve its own advancement, and neither an approving decision over a failing verdict nor a passing verdict under a decline is enough.
  • terminalconverged, declined, or exhausted.

start.md gates on those: authorization is requested only after a passing plan verdict and an approving plan-review decision; acceptance only after a passing pull-request verdict and an approving review decision. It renders the human-readable reports from the returned fields rather than receiving them pre-flattened. An exhausted loop reports itself distinctly and fails closed — that is not an answer to what exhaustion should do, which stays unresolved under #290.

InstructionFiles and Discovery remain text components. The rule is stated where it matters: a controller that resolves a decision and returns a rendering of it has discarded the thing its caller needs.

Approval precedes durable effects

Deferred <Issue> creation moved inside the approved branch, after the checkpoint. proceed: true authorizes the exact transition and effects the checkpoint assessed and nothing more; the free-text response and rationale record the user's reasoning and nothing reads them to change which effects run, because an effect that has already executed cannot be amended by prose. proceed: false performs none of them.

Discrimination — real documents

Real Planning, Implementation, and UserCheckpoint; stubbed only the agent transport and the three deterministic components that do not exist. Targeting is by requiresUser, so exactly one checkpoint per scenario reaches the <Answer> and the rest take the explicit no-material-choice continuation.

Scenario Agent turns commit PR issues Result
Plan review declined 3 0 0 0 terminal=declined, authorized=false; no authorization question, no implementation turn
All approved, verdicts pass 8 1 1 1 accepted
PR review declined 7 1 1 0 implementation.terminal=declined; no acceptance question
Failing verdict, approved 12 1 1 1 revision turn runs; reaches implementation only after the later passing verdict
Exhaustion 20 0 0 0 terminal=exhausted, authorized=false; reaches neither

Mutations, each changing an observed result:

Mutation Effect
<Issue> moved ahead of its approval declined PR review goes issues 0 → 1 — the issue is created despite the decline
Caller gate bypassed (planning.authorizedtrue) declined plan review goes prompts 3 → 6 — advances to the authorization question
Planning's return reduced to text authorized / terminal / verdictPassed render as unresolved literals; the caller cannot gate at all

Correction to my previous report

I described the earlier probe as discriminating the gating. It stubbed the outer stages, so it never exercised any internal-decision path — the harness was built not to see exactly what you found. The scenarios above run the real documents.

Verification

Probes rerun: 9 frontmatters parse (UserCheckpoint, Planning, Implementation now returnMode=value), 5 embedded schemas compile, 21 shipped + 5 repository names resolve, 9 missing names unresolved. Vocabulary sweep clean. #328's missing-capability classification kept, and #327's.

Local gates: fmt, lint (0 errors), check, test (349 passed, 0 failed), check:jsr, tsc.

Docs updated for the new boundaries: start.md (flow, gate section, data-flow table), artifacts.md (StageResult added; the three-kind split now says only parsed results can gate), the specification, and the PR description.

All ten checks green: composability, deploy, jsr, lint, review, site, smoke, test-bun, test-deno, test-node.

@taras

taras commented Aug 4, 2026

Copy link
Copy Markdown
Owner Author

Sources returned, derived state removed — head 5b434db6f5da3576937d95fdd1c749ece9d6cee0

Both problems were real. Fixed at 5b434db, still based on 511776e.

1. The pull-request handle

Confirmed before correcting, not after. With <PullRequest> stubbed at #295's shape — number, url, headSha, baseSha, state, reviews, comments, checks — the head-173e96a Implementation failed:

Return validation failed for <Implementation />:
  - "/pullRequest" must be string

The mutation rerun makes the cost explicit: that failure lands after commit and ISSUE-CREATED have already executed. A conforming implementation would perform its durable effects and only then fail the stage.

pullRequest is removed from the declared return. start.md consumed none of it, and the artifact ledger records the effect and its handle independently (#291). report renders the named fields instead of interpolating the object:

#{pullRequest.number} ({pullRequest.state}) {pullRequest.url}
head {pullRequest.headSha} onto base {pullRequest.baseSha}

If a later caller genuinely needs the handle it is declared with #295's object schema — never a placeholder. The harness <PullRequest> stub now returns that object, and <Commit> returns a {sha, message} structure rather than a string, so a future string placeholder cannot pass again.

2. Duplicated control state

authorized, terminal, and StageResult are removed. Both stages return their prose, the parsed verdict's fields, and the complete UserDecision — the sources, nothing derived. start.md computes each gate where it uses it:

planning.decision.proceed && planning.verdictPassed
implementation.decision.proceed && implementation.verdictPassed

The mutation shows why the duplicate was unsafe rather than merely redundant: a record pairing decision.proceed: false with authorized: true validates — no return schema can hold a derived flag to agreement with its sources — and gating on it advances a declined plan review from 3 turns to 6.

The same two fields carry what terminal was labelling. After a loop, decision.proceed false is a decline; decision.proceed true with verdictPassed false is a review that reached its bound still failing. Neither passes the gate, <Output> tells them apart, and the eventual policy for the second stays unresolved under #290.

On StageResult: I coined it without asking. architecture.md's registry requires permission first. It is removed and not proposed.

<Issue> keeps its corrected position — after the checkpoint, inside the approved path.

Discrimination — real documents, effects stubbed at their specified shapes

Scenario Agent turns commit PR issues Result
Plan review declined 3 0 0 0 no authorization question, no implementation turn
All approved 8 1 1 1 accepted
PR review declined 7 1 1 0 no deferred issue, no acceptance question
Failing verdict, approved 12 1 1 1 revision turn; reaches implementation only after the later passing verdict
Planning exhaustion 20 0 0 0 proceed=true passed=false; reaches neither
PR-review exhaustion 24 5 5 5 proceed=true passed=false; acceptance never reached

Mutations, each changing an observed result:

Mutation Effect
Gate on a duplicated authorized field declined plan review advances, prompts 3 → 6
Declare the handle as string Return validation failed — after commit and issue effects have run
<Issue> moved ahead of its approval declined PR review goes issues 0 → 1

Verification

Probes rerun: 9 frontmatters parse, 5 embedded schemas compile, 21 shipped + 5 repository names resolve, 9 missing unresolved. Sweep clean, including StageResult. #327 and #328 classifications retained.

Local gates: fmt, lint (0 errors), check, test (349 passed, 0 failed), check:jsr, tsc. Docs updated: start.md, artifacts.md, the specification, the data-flow table, and the PR description.

All ten checks green: composability, deploy, jsr, lint, review, site, smoke, test-bun, test-deno, test-node.

@taras

taras commented Aug 6, 2026

Copy link
Copy Markdown
Owner Author

Adversarial Implementation dependency-map delta

The Workspace topology decision now has two evidence paths:

#347 bundled workerd POC ----+
                              +-> #346 topology decision -> #218 -> #293
#349 Deno SQLite/DOFS POC ---+

#349 tests whether Deno can own the persistent SQLite Workspace directly while reusing Cloudflare's DOFS and FUSE layers. It compares real FUSE and the userspace shim independently, and compares its portability, durability, security, and maintenance boundary against PR #348's bundled-workerd result.

@taras

taras commented Aug 7, 2026

Copy link
Copy Markdown
Owner Author

Adversarial Implementation dependency map — Workspace design revision

PR #358 captures the design decisions produced by #346 and the Workspace interview. It changes the implementation path materially: xmd workflow owns one implicit retained Workspace; Deno owns the run's SQLite database and DOFS state; local effects and journal results share a transaction; workflow Agents are read-only and propose constrained XMD.

Evidence and decisions

#347 / #348  bundled workerd evidence ─┐
#349 / #350  Deno + DOFS evidence ─────┼→ #346 / #358 topology decision
#351 / #353  Worker boundaries ────────┘              │
                                                     ├→ #218 Workspace implementation
#357 Worker Shell transaction proof ─────────────────┘  (optional Shell gate)

Current implementation path

#305 props namespace → #290 shipped planning logic

#341 run + expansion identity
        + #358 contract
        + #350 Deno/DOFS foundation
                ↓
              #218 implicit Workspace, lifecycle, replay and local transactions
                ├→ revised #293 Repository + named Worktree lifecycle
                ├→ revised #291 SQLite journal/history/checkpoint/fork storage
                ├→ revised #302 read-only Agent + generated-XMD authority
                └→ revised #294 Git.Add + Git.Commit local effects

#297 external reconciliation → revised #295 PullRequest + #296 Issue

all document/runtime effects → #292 synchronize this living target → #301 compose → #299 certify

Relevance audit

No implementation issue should independently re-decide Workspace explicitness, filesystem restoration, topology, Agent write authority or transaction granularity. Those changes now require an architecture/spec revision first.

@taras

taras commented Aug 7, 2026

Copy link
Copy Markdown
Owner Author

Worker Shell topology delta — INCLUDE

#357 / PR #362 resolves the final optional topology gate positively. One Worker Shell invocation satisfies one expansion → one effect → one SQLite transaction using an immediate outer transaction and shell_mutations savepoint. Success publishes mutations with the filtered result; every known failure path rolls mutations back and retains one failed result; a real host crash publishes neither. Effect identity plus a per-invocation token fences missing, foreign, completed, cancelled and stale Worker messages.

The initial local capability set therefore includes Workspace-scoped Worker Shell through just-bash and a Deno Worker. It still excludes Worker JavaScript, native subprocesses, writable FUSE and bundled workerd.

Production implementation moves to #363 with four constraints that are no longer open design questions:

  1. One host-owned DOFS connection is authoritative per workflow database, and Workspace-local effect transactions execute serially on it.
  2. Cancellation forcefully terminates CPU-bound Worker execution before rollback and failed-result publication; graceful-only shutdown is insufficient.
  3. Every filesystem RPC remains fenced by effect identity and invocation token.
  4. The existing journal security policy filters results before they enter the shared transaction boundary.

Updated path:

#350 Deno/DOFS foundation
  → #353 contained Worker Shell
  → #362 transactional proof
  → #363 production contextual process provider
  → #218 retained Workspace integration
  → #301 composition
  → #299 certification

PR #358 records the accepted architecture and observable contract. #357 closes when its evidence PR is accepted.

@taras

taras commented Aug 7, 2026

Copy link
Copy Markdown
Owner Author

Correction: spike evidence remains outside production main

PRs #350 and #353 were accidentally merged while their stack was being collapsed. PR #364 reverts both squash commits, restoring main exactly to its pre-spike tree. PR #362 remains an unmerged 20-file proof stacked on the #351 evidence branch.

The disposition is:

Do not merge the spike source trees as prerequisites for #363. Production work consumes their measured contracts and may selectively adapt proven code under the repository's normal architecture and dependency rules.

@taras

taras commented Aug 7, 2026

Copy link
Copy Markdown
Owner Author

Adversarial Implementation issue reconciliation after #358

The authoritative production dependency map now lives in #218.

The retained Workspace foundation is sequenced as:

#291 WorkflowRun SQLite + filtered journal
  → #365 atomic Workspace mutation/root/journal transaction
  → #366 foreground start/resume + File vertical slice
  → #367 lifecycle/inspection/ownership
  → #368 versioned history forks

The missing production stories are now explicit:

Stale contracts were reconciled in #199, #227, #290#295, #297, #299#302. In particular, the plan no longer uses refs/xmd/runs, a single implicit worktree, writable Agents, a hidden push in PullRequest, or file-watcher arbitration as the initial continuation model.

#357 is closed with an INCLUDE verdict. PR #362 remains unmerged experimental evidence; #363 owns production Worker Shell after #365/#366. PRs #350 and #353 likewise remain unmerged evidence.

taras added 9 commits August 10, 2026 09:36
The adversarial implementation workflow target was written against a main
that predates the error-model rules (#315), the error vocabulary rename
(#317), error-model semantics (#319), and operation-scoped state (#325).
It asserted `<CollectFailures>` as structural syntax, "the unresolved
diagnostic", and a durable layer that "replays recorded results" — none
of which describe main. This re-derives it on 7d7bdf2.

The error model reaches the documents. A stage component is split by its
`<Output>` boundary: the region inside runs under the `output` error mode,
everything outside is documentation and runs under `throw`, which no
`<PrintErrors>` region replaces. So a stage returns a complete validated
result or it fails, keeping only what it had already rendered — the final
`<Parse>` in each repair loop is a real gate. `throwOnError` is
load-bearing for the same reason: without it a failed prompt records its
failure and returns its text, raising nothing to decide.

The markup did not run. Every stage passed props through expression props
as `agent={props.planner}`, which fails on main with `props is not
defined` — an expression prop reads the bare binding while text
interpolation reads the namespace. Unifying them is #305, whose
acceptance includes expression props reading `props.name`. 22 sites are
corrected to the spelling main supports, and the asymmetry is recorded
with the issue that removes it.

Vocabulary is collapsed onto the concepts #289, #291, and #298 authorize:
artifact ledger, artifact version, run identity, pinned source revision,
stop reason, terminal record, stage boundary, declared inputs, and
cross-process continuation, in place of the four names these files used
for a ledger and the three for a run. Missing capabilities now cite the
issue that supplies them rather than saying only "not implemented", and
replay is described as reaching the state execution resumes from, never
as the continuation itself.

Planning-loop exhaustion stays open. It is recorded against #290, which
pins the behavior; this change reports `verdict.passed` and does not call
an exhausted loop converged.

Evidence: `inspectDocument` parses all 9 frontmatters and compiles both
schema kinds; `compileParseSchema` compiles all 5 embedded draft-07
schemas; `inspectComponent` resolves 21 shipped and 5 repository names
and confirms 9 missing ones unresolved; `InstructionFiles` runs end to
end against the repository's own AGENTS.md.
Rebased onto 511776e. #326 closed #203 by proving the two projection
lifetimes with real modifiers — L8 for a projected `persist` resource and
Q14 for a projected daemon — which were the acceptance criteria this
target had the weakest evidence for. Projected content keeping its
caller's bindings while its live effects belong to the component
invocation is now stated as shipped, along with why it matters: a process
a stage starts stops before the workspace it ran in is removed, which is
the ordering `<Worktree>` (#293) is built on.

`architecture.md` is authoritative on the error model, so the `output`
row reads "fails the run; `<PrintErrors>` can print instead" as the
registry states it. The engine does not do that yet — an outer boundary
ends the run instead, whether the failure arose in the region itself or
in content projected into it — so the discrepancy is classified as
missing and filed as #327 rather than allowed to redefine the settled
contract. No stage writes `<PrintErrors>`, so nothing here depends on it.

The distinction the target does keep is the one the registry makes: a
`throw` decision is the mode a boundary cannot replace. Every stage's
parsing sits in documentation, so the final `<Parse>` is a gate for that
reason and not because printing is unavailable.
…entory

`<UserCheckpoint>` captured `elicitation.proceed` and then returned only
rendered prose, so a caller had nothing to branch on. `start.md` invoked
`Planning` and `Implementation` unconditionally and the two stages
branched on the planner verdict alone: a user answering `proceed: false`
could not stop anything. That contradicts the central user-authority
contract and #290's acceptance.

`<UserCheckpoint>` now declares `returns` and binds a schema-validated
decision — `proceed` plus the assessment fields a later prompt quotes.
One `decisionSchema` serves both paths: `<Elicit>` binds it when the
assessment reports a material choice, and an explicit `<Parse>` binds
`"proceed": true` with its reason when there is none, so continuation is
represented rather than inferred from absent elicitation data. Every
affected transition is gated — a declined handoff does not start
Planning, a declined authorization does not start Implementation, a
declined review neither revises nor accepts, and a declined acceptance
finishes as rejected rather than falling into the accepted branch.

Nesting is what the language supports; it is not stopping. The run still
expands to `<Output>` and completes, with no clean halt at a stage
boundary and no stop reason recorded for one. That is classified as
missing under #298 over #289 rather than described as enforcement.

Two engine limitations surfaced while proving this and are filed rather
than worked around silently. `<Content />` is substituted only at a body's
top level or directly inside `<Output>`, never nested inside a `<Prompt>`
(#328) — `Discovery` and `UserCheckpoint` used exactly that shape and
could not expand, so both now take the material as a prop. And a binding
made inside a Markdown component's projected content does not escape to
its caller, while the same binding inside a registered function component
does; the harness had to account for that to test the real components.

artifacts.md claimed every listed result was JSON declared inline. It is
corrected into three kinds: `PlannerHandoff` and `ImplementationPlan` are
prose with no schema and cannot gate anything; the four parsed results are
described using only fields their inline schemas declare; and
`UserDecision` is the checkpoint's declared return, with the actor and
timestamp that would make it auditable marked missing under #291.

Discrimination over the shipped subset, with a turn-recording stub agent:
a declined checkpoint records 1 agent turn and neither stage runs; the
authorized path records 2 and both run; a no-material-choice assessment
records 2 and proceeds on its explicit `<Parse>` branch while a declining
answer in scope is never consulted.
`Planning` and `Implementation` consumed their internal checkpoint
decisions and returned only prose, so authority leaked at the component
boundary. A declined plan review broke the planning loop, but `start.md`
still asked the authorization question and could reach `Implementation`;
a declined pull-request review still let the change be reported accepted.
`Implementation` also created deferred `<Issue>` effects before its
review checkpoint ran, so the planner's proposed disposition became a
durable GitHub object before the user approved it. The earlier probe
stubbed the outer stages, so it never exercised those paths.

Both stages are now value components. Each returns its prose, the parsed
verdict's fields, the complete `UserDecision` it resolved, and two derived
control fields the caller gates on: `authorized`, which is
`proceed && verdict.passed`, and `terminal`, which distinguishes
`converged` from `declined` and `exhausted`. A stage cannot approve its
own advancement, and an exhausted loop reports itself distinctly and fails
closed — which is not a decision about what exhaustion should do, still
unresolved under #290.

`start.md` gates on those returns: authorization is requested only after a
passing plan verdict and an approving plan-review decision, acceptance
only after a passing pull-request verdict and an approving review
decision. It renders the human-readable reports from the returned fields.

Deferred `<Issue>` creation moved inside the approved branch, after the
checkpoint. `proceed: true` authorizes the exact proposed transition and
effects; the free-text response records reasoning and never amends effects,
because an effect that has already executed cannot be amended by prose.
`proceed: false` performs none of them.

Discrimination against the real `Planning`, `Implementation`, and
`UserCheckpoint`, stubbing only the agent transport and the three
deterministic components that do not exist. A declined plan review: 3
agent turns, no authorization question, no implementation turn, no
effects. A declined pull-request review: no deferred issue, no acceptance
question. A failing verdict with approval performs the revision turn and
reaches the next stage only after a later passing verdict. Exhaustion
reaches neither. Moving `<Issue>` ahead of approval creates the issue
despite a decline; bypassing a caller gate advances past a declined
review; reducing either return to text leaves the gate fields unresolved.
Each mutation changes an observed result.
Two contract problems in the replacement for the authority leak.

`Implementation` declared `pullRequest: { type: string }` and returned the
raw binding. #295 specifies a structured handle — number, URL, head and
base identities, state, reviews, comments, checks — so a conforming
`<PullRequest>` would perform its durable effects and only then fail this
component's return validation. The previous harness stubbed the handle as
a string, which is exactly why the probe stayed green. `start.md` consumes
none of it and the artifact ledger records the effect and handle
independently (#291), so the field is gone and `report` renders the named
fields a reader needs. If a later caller needs the handle it gets #295's
object schema, never a placeholder.

Both stages also returned `authorized` and `terminal`, duplicating
`decision.proceed && verdictPassed` and a second reading of the same two
fields. A return schema can require both sources to be present but cannot
require a derived flag to agree with them, so a record pairing
`proceed: false` with `authorized: true` validated — and `authorized` read
confusingly next to the separate authorization checkpoint. Both are gone,
along with the `StageResult` name, which was coined without the permission
architecture.md's terminology registry requires; it is not being added
there.

`start.md` now computes each gate where it uses it, from the authoritative
pair. After a loop, `decision.proceed` false is a decline and
`decision.proceed` true with `verdictPassed` false is exhaustion; the gate
refuses both and the output tells them apart, while the terminal policy
stays unresolved under #290. Deferred `<Issue>` creation keeps its
corrected position after the checkpoint, inside the approved path.

Discrimination reruns against the real documents with effects stubbed at
their specified shapes. Declined plan review: 3 turns, no authorization
question, no effects. Declined pull-request review: no deferred issue, no
acceptance question. Fail-then-pass reaches implementation only after the
passing verdict. Planning exhaustion and pull-request-review exhaustion
each reach neither. Mutations: gating on a duplicated `authorized` field
advances a declined review (3 turns becomes 6); declaring the handle as a
string fails return validation after commit and issue effects have already
run; moving `<Issue>` ahead of approval creates it despite the decline.
Two inconsistencies left by the return-contract fix.

The migration to value components was described in some places and not
others. The specification still said `Planning` and `Implementation`
return derived `authorized` and `terminal` fields, which they stopped
doing. And the specification, `start.md`, and `primitives.md` all still
described every component body as split by `<Output>` into documentation
under `throw` and a region under `output`. That is true only of the text
components: a value component declares `returns`, renders nothing, cannot
contain `<Output>` at all, and runs its entire body fail-fast, binding
nothing when it fails. Each document now says which kind it is talking
about, and `Planning`, `Implementation`, and `UserCheckpoint` describe
their own bodies as value bodies.

The pull-request reviewer could not see what it was reviewing. #295
resolves reviews, comments, and checks alongside the identities, and the
prompt rendered only number, state, URL, head, and base — while
`runtime.md` denies agent network access, so the planner had no way to
recover the rest. An adversarial review that cannot see a failing check or
an existing objection is uninformed rather than adversarial. Every
category is now rendered explicitly into the review prompt and into the
checkpoint material the user reads, each collection iterated with `<Each>`
rather than stringified, and the prompt names the revision under review:
the diff at `headSha` against `baseSha`, with a verdict describing that
head alone.

The member field names inside reviews, comments, and checks are #295's to
settle; these documents depend on that schema rather than defining a
competing one. What is settled here is that the planner receives the
complete snapshot. The handle stays internal — `start.md` gates on the
verdict and decision — so the earlier claim that nothing consumes it was
wrong, and the PR description is corrected too.

Discrimination adds a structured `<PullRequest>` stub carrying non-empty
reviews, comments, and checks with distinct markers. It captures the
actual rendered planner prompt and the checkpoint material and asserts
every category, both head identities, and the diff instruction reach them.
Omitting any one category reddens exactly its own assertions and leaves
the others green. Nothing in the test uses agent network access. The six
gate scenarios and the three earlier mutations still hold.
…on text

Three claims did not match what the documents do.

`artifacts.md` still said nothing consumes the pull-request handle. The
boundary is now stated exactly: `Implementation` consumes all of it
internally, `start.md` never receives it — what crosses the stage boundary
is the verdict and the decision — and the artifact ledger records the
effect independently (#291).

The specification said both text components do their work in
documentation. Only `Discovery` does. `InstructionFiles` puts its `<Each>`
and `<File>` reads inside `<Output>`, and probing that case corrected a
second assumption in the same sentence: `<File>` prints its own failures,
so an unreadable instruction file is decided as a printed error before the
region's `output` mode sees it. The run continues; what stops the caller
is the binding rule, since `as` refuses a body holding a printed error and
`instructions` stays unbound. `start.md` gains the same qualifier, because
"an undecided error fails the run" is only true of undecided ones.

The user checkpoint did not carry what the PR claimed it did. The planner
prompt rendered each review's body; `checkpointMaterial` rendered only the
author, state, and head. A user approving a change has to read the original
objection, not the planner's summary of it, so the body is now in both. The
earlier probe missed this because it asserted the review *author* on the
checkpoint material and the *body* only on the prompt — an assertion too
weak to see the omission it was meant to cover.

Discrimination now asserts the body on both surfaces. Dropping any category
reddens both symmetrically, and dropping the body from the checkpoint alone
reddens the checkpoint while the prompt stays green — the exact shape of
the defect.
`checkpointMaterial` presented the pull request and the verdict but not
the two things approval actually sets in motion. When a verdict fails,
approval sends `verdict.revisionPrompt` to the implementor, and the
checkpoint never showed it. A `defer` disposition sends the complete
finding to `<Issue>`, including `finding.evidence`, and the checkpoint
showed only the title, disposition, and description.

That contradicts the document's own rule. `proceed: true` authorizes the
exact transition and the exact effects presented for assessment, which
means nothing if the material omits them: a user could approve revision
instructions and issue evidence they had never read. `Planning` already
showed its revision prompt; `Implementation` did not.

Both are now in the material, unchanged and unsummarized — the literal
`verdict.revisionPrompt`, and each finding's evidence rendered beneath it
with a nested `<Each>`. The explanatory text in the component and the
specification says why, rather than asserting that approval covers effects
it never displayed.

Discrimination gains distinct markers for both. The baseline asserts they
reach the checkpoint, that the revision prompt the implementor receives
carries the same value, and that `<Issue>` receives the same complete
finding — the stub now records what it was passed. Removing either field
from the checkpoint reddens exactly its own assertion while the effect
assertions stay green, which is the shape of the leak: the effect still
fires, the user just never saw it.
The target described a `<Workflow>`/`<Sandbox>`/`<Stage>` spine over a sidecar
Git ledger at `refs/xmd/runs`, an implicit worktree, an implementor that edits
files, and a `<PullRequest>` handle carrying reviews, comments and checks. None
of that is the architecture any more, and three of those constructs were
rejected rather than deferred.

The command selects the environment: `xmd workflow start` creates the run and
its one retained Workspace, and the root document is the workflow. Named
`<Repository>` and `<Worktree>` compose the checkouts from ordinary root props,
so nothing resolves through a hidden alias and no single worktree is implied.
Agents are read-only under that host ceiling, so the implementor returns
constrained XMD that `<Expand>` admits and expands as ordinary durable effects,
and `<Git.Add>`, `<Git.Commit>`, an explicit `<Git.Push>` and `<PullRequest>`
follow in that order. Waiting for the user is a durable suspension that `resume`
continues, which is what `<Stage>` was reaching for.

Retention is no longer speculative. #291 and #365 are shipped foundation: the
run retains its filtered journal, Workspace roots, and metadata, and one
expansion publishes its mutation, logical root and journal result in one
transaction. `JournalProvenance` (#425) is what makes that history evidence
rather than storage, and it is named where the documents discuss retained
evidence. Every remaining capability is marked as target behavior against
#218's dependency order.

Two gaps are now stated rather than assumed away. #295 moved reviews, comments
and checks out of the creation result, and no issue owns the forge read that
returns them to a network-denied reviewer; and the journal records which run
and expansion produced a decision but not which person answered.

Props are namespaced throughout (#305), `<Content />` projects at any depth
(#328), and the obsolete asymmetry notes are gone.
@taras
taras force-pushed the agent/adversarial-implementation-workflow-wip branch from 382d115 to 16ac13e Compare August 10, 2026 14:00
@taras

taras commented Aug 10, 2026

Copy link
Copy Markdown
Owner Author

#292 synchronization handoff

Head and base

Base main at 443a591 (🔒 Name what the journal witness proves, #425)
Previous head 382d115, whose merge-base with main was 511776e — 273 commits behind
New head 16ac13e

The branch was rebased, not merged. It had to be: specs/workflow-workspace-spec.md and specs/workflow-spec.md did not exist on the old base, and architecture.md there was 227 lines against main's 1028, so any diff taken from the old head would have read as deleting the settled contracts. The rebase was clean — the eight commits are documentation-only additions plus one edit to specs/markdown-agents-vision.md. Force-pushed with --force-with-lease against 382d115. PR stays draft.

What changed

One commit, eleven files, docs only. Nothing outside specs/ and workflows/.

Retired constructs. <Workflow>, <Stage>, <Sandbox> and <Commit> are gone from the target, and each removal is stated once so a reader who knew the old shape does not read it as an oversight:

Restructured stages. Implementation is the largest change. The implementor no longer edits files: it returns an XMD fragment, <Expand> preflights and expands it under an allowlist of Dir/File/DeleteFile, and the document stages, commits, pushes and opens the pull request itself. Git.Add deliberately stays out of the allowlist — what gets staged is the document's decision, not the proposal's. The proposal schema lost changedFiles for the same reason the stages return no authorized flag: the fragment already says what it writes, and <Git.Commit>'s journaled evidence is the authoritative staged set.

Discovery, Planning and Implementation now take a worktree prop and register it with <Agent.AddDir> inside the session that reads it. UserCheckpoint registers nothing — it assesses supplied material.

Markup migrated. Every expression prop reads props.* (#305). Authored bindings stay bare, which is how as="worktree" flows down as worktree={worktree}.

Settled contracts incorporated

Contract Where
#291 retained WorkflowRun + filtered journal — shipped artifacts.md "What the run retains", spec "Retained run state"
#365 one expansion → one effect → one transaction — shipped artifacts.md, Implementation.md "Every mutation is one effect"
#425 JournalProvenance witness, preserved through trusted filtering artifacts.md "The journal is evidence, and the evidence is witnessed", spec
#218 dependency map, four phases in order primitives.md "What the workflow still needs"
#293 named Repository/Worktree, no alias resolution, native-Git-first provider, cache is not identity start.md, runtime.md, primitives.md, spec
#294 Git.Switch/Add/Commit, journal holds reconciliation evidence not Git objects Implementation.md, primitives.md, spec
#370 Git.Push explicit and external; #295 PullRequest over a pushed head Implementation.md, spec
#302 read-only Agents, Agent.AddDir distinct from lexical Dir every stage document, runtime.md, spec
#369 constrained generated XMD; allowlist is authority Implementation.md, primitives.md, spec
#366/#367 start/resume, suspension, history, cancellation, deletion start.md, runtime.md, artifacts.md
#305 namespaced props, #328 <Content /> at any depth, #203 invocation-owned lifetimes all stage documents
#412/#416 deliberately off the critical path primitives.md

What remains unimplemented

Nine names the documents write do not resolve on main, verified rather than asserted: Agent.AddDir (#302), Expand (#369), Git.Add and Git.Commit (#294), Git.Push (#370), Issue (#296), PullRequest (#295), Repository and Worktree (#293). Neither xmd workflow start nor resume exists (#366), and inspection/lifecycle is #367. Proving the shipped subset is #290; composing the whole loop is #301; certifying it is #299.

Two gaps with no owner

Both are stated in the documents rather than papered over, and both probably want issues:

  1. The forge read for reviews, comments and checks. Add a deterministic PullRequest workflow effect #295 deliberately narrowed <PullRequest>'s creation result to stable identity, number, URL, state, head SHA and base SHA, and moved the rest to "separate reads/effects" — but no issue defines that read. The reviewer has no network access, so without it an objection raised by anyone other than the planner reaches neither the review prompt nor the user's checkpoint. The requirement is preserved verbatim in Implementation.md and the spec; the mechanism is marked unowned.
  2. Elicitation actor identity. The journal records the validated decision, the question fingerprint, and the document execution — but not who answered. A decision is attributable to a run and an expansion, not to a person. The old text blamed this on the unbuilt ledger; Store WorkflowRuns and filtered journals in SQLite #291 shipped and it is still true.

Three smaller questions are raised against their owning issues rather than answered here: <Agent.AddDir>'s placement relative to <Session> and whether re-registering a held path is idempotent (#302); and how a revision iteration reaches the same pull request under a new expansion identity, which needs #297's natural key and needs #295 to tell a deliberately advanced head from a conflicting one.

One documentation discrepancy left alone: specs/workflow-workspace-spec.md §7.5 still says <PullRequest> "returns the request URL through as", which is narrower than #295's settled result. These documents follow #295 and say so; reconciling that sentence is a separate change to a main-owned spec.

Verification

Documentation-only, so this is inspection through current main, not a runtime suite.

  • Frontmatter and schemasinspectDocument on all nine workflow documents, then compilePropsSchema / compileReturnsSchema on what each declares, and compileParseSchema on every embedded draft-07 schema. 9 documents, 5 embedded schemas, 0 failures. returnMode came back value for exactly UserCheckpoint, Planning and Implementation.
  • Name resolutioninspectComponent through the same selectComponent path execution uses. 21 resolve, 9 do not, and the nine are exactly the set the "what runs today" tables name. A table that drifts from main fails this check.
  • git diff --check origin/main...HEAD — clean.
  • deno task lint covers packages scripts .reviews/components and does not reach specs/ or workflows/; no source or test file changed, so the runtime battery was not run.

The workflow still does not run end to end, and nothing here claims it does.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant