Skip to content

[loop-v2-hardening-v1] 4 — Each Developer launch's schema lists the finding ids of the handoff that turn answers #1740

Closed

Description

@daniboomerang

[loop-v2-hardening-v1] 4 — Each Developer launch's output schema lists the finding ids of the handoff that turn answers

Tier: 1
Project: cli, vinaya
Type: fix

Objectives

O1. The output schema an Engine Developer launch is given lists, as the finding ids addressedFindingIds may name, exactly the ids of the revision handoff that turn answers: round 2's ids for the turn answering round 2, round 3's for the turn answering round 3; a test drives three review rounds with distinct finding ids through the Engine's actions and asserts the schema built at each Developer launch names that round's ids and no earlier round's.
O2. A Developer turn that answers no review handoff (a CI, conflict, ready-push or gate send-back) is launched with a schema that admits no finding id, the same set its validation accepts; a test asserts the schema and the validation agree for such a turn.

Documentation

  • processes/vinaya/executing/actions.ts — handedOverIds, validateDeveloperOutput and the vinaya.build-revision-handoff action, which together decide the ids a turn may name (O1, O2)
  • apps/cli/src/lib/developer-turn-result.ts — developerTurnResultJsonSchema, which turns the ids into an enum bounded by their count (O1, O2)

Planner's rationale

Boundary — The Engine rebuilds the Developer's output schema at every launch from task.developerContext (withTurnSchema in the runner), but developerContext.knownFindingIds is written only inside validateDeveloperOutput, after a turn ends, from that turn's handoff. The launch answering round N's findings therefore gets round N−1's ids in its schema, while its validation reads round N's (handedOverIds); a provider that enforces the schema cannot name a new finding, which is what one run hit in round 3. This task sets the ids from the handoff the next turn will answer, before that turn launches. Pinned files: processes/vinaya/executing/actions.ts, processes/vinaya/tests/round-decisions.test.ts, processes/vinaya/process.yaml, .changeset/developer-schema-current-findings.md. Out: the schema builder in apps/cli, which is correct and stays unchanged; the runner's withTurnSchema; the standalone loop's dispatch, which builds its schema per turn from its own handoff; every importer of a pinned file, which calls it unchanged and is in the Surface only because the importer gate requires it.

Sizing — One verification story: the schema at launch and the validation after the turn accept the same ids. Four pinned files; one failure mode. Size S.

Project(s) + blast radius — Project: cli, vinaya. processes/vinaya/executing/actions.ts runs both Engine Flows, which are re-verified by the test; apps/cli owns the schema builder and the tests that read it, re-verification only.

Dependency rationale — Conflicts-with: #1711 — the harness-kernel move also pins processes/vinaya/executing/actions.ts, processes/vinaya/tests/round-decisions.test.ts and processes/vinaya/process.yaml; three shared files, so they run one after the other. The other tasks of this tranche share only processes/vinaya/process.yaml with this one. No Depends-on: everything this task changes is on the default branch.

Traps to avoid — Do NOT widen the schema to any string to make the ids fit; the enum is what lets the provider refuse an invented id. Do NOT read the ids from the round number; read them from the handoff the turn answers, as validation does. A correction turn keeps the ids of the turn it corrects, as today. Bump the patch version in processes/vinaya/process.yaml. Keep new comments free of Issue and pull-request numbers and tranche slugs.

Suggested agent-class — mid: one state write moved earlier in the Engine's actions, with a multi-round fake test.

Stop-and-escalate — Stop if the ids of the handoff a turn answers cannot be known before that turn launches without a new Flow step; name the step.

Docs to keep coherent — no-doc-surface — the loop specification already says the provider's reply must match the schema it was given and that the controller accepts only the handoff's ids; this task makes the code match that text and adds none.

Check decisions

  • atta-labs/process-version-bump: bump the patch version in processes/vinaya/process.yaml.
  • changeset-coverage: add the pinned changeset.
  • reader-resolvable-prose: new comments carry no Issue or pull-request numbers and no tranche slugs.

Premises

  • processes/vinaya/executing/actions.ts contains task.developerContext = { ...task.developerContext, knownFindingIds }
  • processes/vinaya/executing/actions.ts contains const stdout = stdoutOf(results['build-revision-handoff'])
  • processes/vinaya/bin/run-engine.ts contains developerTurnResultJsonSchema(options.taskInput.developerContext)
  • apps/cli/src/lib/developer-turn-result.ts contains .max(context.knownFindingIds.length)

Surface

in: processes/vinaya/executing, processes/vinaya/tests, processes/vinaya/bin, processes/vinaya/loops/dev-review/v2, processes/vinaya, apps/cli/src/lib, apps/cli/tests, .changeset
out: harness, aeg-root, .github, apps/log-server, apps/vinaya-portal

Parts

Part 1 (O1) — The Engine's actions set the Developer context's finding ids from the revision handoff before the turn that answers it launches.
Part 2 (O2) — A send-back that is not a review handoff launches with no finding ids, matching its validation.

Test plan

cd processes/vinaya && bun test tests/round-decisions.test.ts → 0 fail; each launch's schema names the ids of the handoff it answers; a non-review send-back admits none

Stop conditions

  • The ids of the handoff a turn answers cannot be known before that turn launches without a new Flow step.

Origin

Principal-directed, 2026-10-29: on the first night of version-2 Engine loops, a round-3 Developer turn could not name a round-2 finding because its schema still listed round 1's ids.

Activity

  1. daniboomerang commented on Oct 29, 2026

    @daniboomerang
    MemberAuthor

    Brief hash: 855383a67623db8f369a7701c052ae51a56fc2e2bd326e63584d20c36ae82e90
    For: [model] (coding-agent CLI on a dev machine, dispatched locally, unattended)
    Reason: Suggested agent-class — mid: one state write moved earlier in the Engine's actions, with a multi-round fake test.
    Owner: the Principal
    Goal: Each Developer launch's schema lists the finding ids of the handoff that turn answers
    Project: cli, vinaya
    Tier: 1

    Closes #1740

    You are the AEG Developer. Run bun apps/cli/src/index.ts doctrine --role developer --print and read its output first. Mandatory.

    Objectives

    O1. The output schema an Engine Developer launch is given lists, as the finding ids addressedFindingIds may name, exactly the ids of the revision handoff that turn answers: round 2's ids for the turn answering round 2, round 3's for the turn answering round 3; a test drives three review rounds with distinct finding ids through the Engine's actions and asserts the schema built at each Developer launch names that round's ids and no earlier round's.
    O2. A Developer turn that answers no review handoff (a CI, conflict, ready-push or gate send-back) is launched with a schema that admits no finding id, the same set its validation accepts; a test asserts the schema and the validation agree for such a turn.

    Documentation

    • processes/vinaya/executing/actions.ts — handedOverIds, validateDeveloperOutput and the vinaya.build-revision-handoff action, which together decide the ids a turn may name (O1, O2)
    • apps/cli/src/lib/developer-turn-result.ts — developerTurnResultJsonSchema, which turns the ids into an enum bounded by their count (O1, O2)

    Premises

    Checked against the code when this task Issue was cut, and again against the default branch at dispatch — facts, not claims.

    • processes/vinaya/executing/actions.ts contains task.developerContext = { ...task.developerContext, knownFindingIds }
    • processes/vinaya/executing/actions.ts contains const stdout = stdoutOf(results['build-revision-handoff'])
    • processes/vinaya/bin/run-engine.ts contains developerTurnResultJsonSchema(options.taskInput.developerContext)
    • apps/cli/src/lib/developer-turn-result.ts contains .max(context.knownFindingIds.length)

    2. Context — read before doing anything

    • Tranche: loop-v2-hardening-v1, task 4, Issue [loop-v2-hardening-v1] 4 — Each Developer launch's schema lists the finding ids of the handoff that turn answers #1740. Branch task/loop-v2-hardening-v1/4. Depends-on: —, Conflicts-with: #1711.
    • Read Issue [loop-v2-hardening-v1] 4 — Each Developer launch's schema lists the finding ids of the handoff that turn answers #1740 in full for the complete rationale — do not re-derive it.
    • Revision: rendered at ca981c2858bd54f2f6136ef5cc11ee05532089fd — the checkout's HEAD equaled the remote default branch, and no pinned file below carried an uncommitted change, when these facts were read.
    • Boundary — The Engine rebuilds the Developer's output schema at every launch from task.developerContext (withTurnSchema in the runner), but developerContext.knownFindingIds is written only inside validateDeveloperOutput, after a turn ends, from that turn's handoff. The launch answering round N's findings therefore gets round N−1's ids in its schema, while its validation reads round N's (handedOverIds); a provider that enforces the schema cannot name a new finding, which is what one run hit in round 3. This task sets the ids from the handoff the next turn will answer, before that turn launches. Pinned files: processes/vinaya/executing/actions.ts, processes/vinaya/tests/round-decisions.test.ts, processes/vinaya/process.yaml, .changeset/developer-schema-current-findings.md. Out: the schema builder in apps/cli, which is correct and stays unchanged; the runner's withTurnSchema; the standalone loop's dispatch, which builds its schema per turn from its own handoff; every importer of a pinned file, which calls it unchanged and is in the Surface only because the importer gate requires it.
    • Traps to avoid — Do NOT widen the schema to any string to make the ids fit; the enum is what lets the provider refuse an invented id. Do NOT read the ids from the round number; read them from the handoff the turn answers, as validation does. A correction turn keeps the ids of the turn it corrects, as today. Bump the patch version in processes/vinaya/process.yaml. Keep new comments free of Issue and pull-request numbers and tranche slugs.

    3. Technical dependencies

    Dependency rationale — Conflicts-with: #1711 — the harness-kernel move also pins processes/vinaya/executing/actions.ts, processes/vinaya/tests/round-decisions.test.ts and processes/vinaya/process.yaml; three shared files, so they run one after the other. The other tasks of this tranche share only processes/vinaya/process.yaml with this one. No Depends-on: everything this task changes is on the default branch.

    4. Technical surface map

    Create:

    • (none — every surface file already exists)

    Modify:

    • processes/vinaya/executing
    • processes/vinaya/tests
    • processes/vinaya/bin
    • processes/vinaya/loops/dev-review/v2
    • processes/vinaya
    • apps/cli/src/lib
    • apps/cli/tests
    • .changeset

    Out of surface: harness, aeg-root, .github, apps/log-server, apps/vinaya-portal — a change there, or to any path no Surface in: glob covers, is still published: the review-loop driver records each such path in the pull request body's beyond-Surface block, and the reviewers judge it like any change.

    Premise pins

    Premise:

    • processes/vinaya/executing/actions.ts sha256: 7a7cf53558ad152506ddb80234ff9ec661820388a5858239146f93db125ea706
    • processes/vinaya/process.yaml sha256: ad0698b377651016e52d76e898c94dbd0367ad68393ebab1d716f72826b915bf
    • processes/vinaya/tests/round-decisions.test.ts sha256: a7b83cb0679771dbbfed05eda6f7f80749f9b0d9326532750907bd8f7b695de1

    5. Pre-flight checks

    Step 0 (mandatory, verbatim):

    bun install --frozen-lockfile --silent
    
    1. Clean status; parent origin/main; branch suffix literal-matches the task id.
    2. Under the review loop (bun apps/cli/src/index.ts task run), the driver has already run the dispatch-readiness gate plus, on this repository toolchain, its own fuller derivation from its own unsandboxed process before dispatching you (re-derived at render time: it was ready), and dispatches you only when that verdict is READY — a NOT READY verdict refuses the turn before it starts, so being dispatched is the verdict: look for no file and run neither script, whose own gh call fails inside your sandbox. Working manually, with no driver behind you, fall back to roles/developer.md's own items 3/5/7 prose — each a complete, hand-run forge check in its own right.

    On any failure: STOP and report.

    6. Numbered parts — publish once with publish_changes when every Part is done, then open_pull_request

    1. Part 1 (O1): The Engine's actions set the Developer context's finding ids from the revision handoff before the turn that answers it launches.

      Files (touches the repo root):

      • processes/vinaya/executing/actions.ts
      • processes/vinaya/process.yaml
      • processes/vinaya/tests/round-decisions.test.ts

      The pre-push hook runs the affected suite on your one push and refuses it on failure — do not run it yourself per Part.

    2. Part 2 (O2): A send-back that is not a review handoff launches with no finding ids, matching its validation.

    7. Documentation-update list

    .vinaya/doc-owners derivation matched zero bindings against this task's surface — no mechanically-derived doc updates. Confirm no additional doc artifact applies before treating this list as final.

    8. Verification before claiming done

    • Under the review loop, the controller runs the static gates: the commit hook applies safe format and lint fixes to staged files, typechecks affected packages, and runs the Vinaya checks; the pre-push hook runs the affected suite; run_checks and CI provide the authoritative results. Do not hand-run or paste static-gate commands. Working manually, run this repository's declared typecheck, lint/format, build, and documentation-gate commands yourself.
    • The pre-push hook runs the affected suite once, on your one push, and refuses it on failure; CI runs the full suite.
    • Every blast-radius consumer named in §4, re-verified by name.
    • The tier checklist in bun apps/cli/src/index.ts doctrine --role developer --print genuinely satisfied; use the controller's run_checks result, hooks, and CI as gate evidence.

    9. Test Plan

    cd processes/vinaya && bun test tests/round-decisions.test.ts → 0 fail; each launch's schema names the ids of the handoff it answers; a non-review send-back admits none
    

    10. Stop conditions

    • The ids of the handoff a turn answers cannot be known before that turn launches without a new Flow step.

    Stop-and-escalate — Stop if the ids of the handoff a turn answers cannot be known before that turn launches without a new Flow step; name the step.

    11. Constraints

    Autonomy: Do not stop to ask clarifying questions. For any ambiguity not covered by a Section 10 stop condition, choose the most reasonable option consistent with this brief, record the choice in the PR body at open, or in a PR comment after open, and continue. Halt only for the explicit Section 10 stop conditions — and when you halt, record the blocker in a PR comment or an Issue comment rather than waiting interactively for input.

    12. Deliverable

    • PR title (exact): [loop-v2-hardening-v1] 4 — Each Developer launch's schema lists the finding ids of the handoff that turn answers
    • Open the PR only via the open_pull_request tool (title and body); publish your commits with publish_changes and update the body with update_pull_request_body/refresh_evidence — you hold no gh/git push credential.
    • Publish once, with publish_changes, when every Part is done; then open the pull request with open_pull_request. Publish again only to answer review findings or a red gate — a refused hook, a failing check, a merge conflict.
    • PR body = the Developer's PR report (print it with bun apps/cli/src/index.ts doctrine --template pr-report --print), with Closes #1740 at the top of the header block. This brief stays frozen on the task Issue and never rides in the body.
    • Pre-open: tier checklist satisfied. The documentation gate is the controller's — run_checks and CI run it.
    • Include git diff origin/main...HEAD --stat as context only; Surface is judged by the driver's surface-scope check, never by this hand-run diff. Token use needs no report — the Vinaya log records it.
    • Then STOP. Review and Verification are separate invocations.
  2. daniboomerang commented on Oct 29, 2026

    @daniboomerang
    MemberAuthor

    The dev-review-loop paused: escalation — the Developer reported the task blocked (preflight_failed): The brief names .changeset/developer-schema-current-findings.md as an existing pinned file, but reading it failed with “No such file or directory”. — Stopped before implementation because a pinned reference file is missing..

    No pull request exists yet for this task, so the pause is recorded on this Issue instead.
    A Principal ruling is needed before this can continue. Post it as a comment on this Issue whose FIRST line is exactly this marker — the second number is the ordinal, and it must exceed the one this pause recorded:

    <!-- aeg:principal:ruling:1740-1 -->
    Your ruling text here.
    

    Then continue with:

    vinaya task run loop-v2-hardening-v1 4 --agent codex --model gpt-6.1-sol --runner atta-engine
    

    The Operator's own task_resume clears this pause too, reading that same ruling from this Issue; task_cancel ends it instead.

  3. daniboomerang commented on Oct 29, 2026

    @daniboomerang
    MemberAuthor

    Decision: proceed as briefed.

    Pinned files list every file the task touches, including files it creates. .changeset/developer-schema-current-findings.md does not exist yet because this task adds it: create it with the changeset this change needs. No objective, Surface or scope change.

  4. daniboomerang commented on Oct 29, 2026

    @daniboomerang
    MemberAuthor

    The dev-review-loop paused: infrastructure — an uncaught error ended round 1's own processing: ready gate storage cleanup failed: [{"dir":"~/.vinaya/test-tmp/ready-gates/4691b771-1353-4c07-a792-8678ea2cefaa","error":"ownership marker missing; refusing removal"}].

    No pull request exists yet for this task, so the pause is recorded on this Issue instead.
    A Principal ruling is needed before this can continue. Post it as a comment on this Issue whose FIRST line is exactly this marker — the second number is the ordinal, and it must exceed the one this pause recorded:

    <!-- aeg:principal:ruling:1740-2 -->
    Your ruling text here.
    

    Then continue with:

    vinaya task run loop-v2-hardening-v1 4 --agent codex --model gpt-6.1-sol --runner atta-engine
    

    The Operator's own task_resume clears this pause too, reading that same ruling from this Issue; task_cancel ends it instead.

  5. daniboomerang commented on Oct 29, 2026

    @daniboomerang
    MemberAuthor

    Decision: proceed as briefed.

    The pause was infrastructure: the ready push's temporary storage lost its ownership marker while other test runs on the same machine swept abandoned fixture folders, so its cleanup refused. Continue the run; the ready push's failing test files are the send-back to answer. No objective, Surface or scope change.

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

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions