8000 Mission artifact gate: second, third and fourth review fixes (M9.9, M9.42) by adeelahmad · Pull Request #114 · adeelahmad/aloop · GitHub
[go: up one dir, main page]

Skip to content

Mission artifact gate: second, third and fourth review fixes (M9.9, M9.42) - #114

Merged
adeelahmad merged 10 commits into
masterfrom
claude/m9-roles-9u038t
Oct 20, 2026
Merged

adeelahmad merged 10 commits into
masterfrom
claude/m9-roles-9u038t

Conversation

@adeelahmad
@adeelahmad adeelahmad commented Oct 20, 2026 •
Copy link
Copy Markdown
Owner

Requested by Adeel · project thread

Before: three adversarial reviews of the mission artifact gate (gate-mission-artifact, M9.9) confirmed findings it judged wrong. Some let a role's bad write through:

  • the Mission Planner rewriting the human's intent, or its own invalid intent, hidden by a git commit -am made during its run;
  • a ledger row edited in place and hashed again, passed as the supervisor's restore;
  • a new zz-request.json in docs/agents/intents/ (which aladdin run picks up) exempt because no intent id names it;
  • a source: mission intent flipped to prompt to pose as the human.

Others blocked a role for something it did not do:

  • a human's confirm, restore or veto-window apply during the run;
  • a supervisor's git merge or git pull bringing in an intent;
  • intake's fill turning an intent's source from prompt to mixed;
  • an Evaluator or Scout run that wrote nothing on a ledger broken before it started, blocked every round until the stuck release;
  • the Product Tester's own report in research/, blocked as the Scout's (M9.42).

After: every confirmed finding is a check in mission-roles.test.py that failed before its fix, with its allow-control. That makes 69 checks; master has 34.

How:

  • Ownership (_mission_roles.py, roles.json):
    • A file whose role field names a role is that role's.
    • A research snapshot belongs to the roles whose reports cite it.
    • A judge run log or usage report is its role's work only with its command's event of the run (judge.run, telemetry.report).
  • The human's steps:
    • A confirm, restore or veto-window apply, and what its command changed (journeys frozen, a version superseded), is never the role's write.
    • A status that no record explains still blocks.
  • Overlapping runs:
    • Another run excuses a file only when it answers for the file as it is now.
    • A run counts as open while its last tool call in the transcript store is recent.
    • A released run owns nothing.
  • Ledger:
    • The ledger is append-only during a run.
    • A restore is the supervisor's repair only when it is HEAD's copy (or the good rows of a ledger the run started broken), followed byte for byte by rows the run started with, plus its commands' appends.
    • A run that wrote nothing on a ledger broken before it is a note when the role's own commands refuse there (ledger_bound). The test checks that each listed command refuses, and that the list holds every refusing command the role's persona, eval suite or handout names. The list includes the Scout's journeys retire and the planner's goal retire from M9.50.
    • That note needs every ledger problem to be one the run started with, so a ledger event a role appends to the run log, with no row, is no excuse.
    • mission evaluate now refuses before it writes a gap list.
  • docs/agents/intents/:
    • Every file there counts.
    • A source: mission intent is the Mission Planner's, and no role flips it to another source.
    • The human's or intake's intent changes only with a human event or intake's own record of the run naming it by refs.intent or intent_id (never --raw-ref).
    • A file arrives through a commit only when HEAD's reflog since the start shows a git merge or git pull brought it in.
    • The words beside an intent (raw-*.txt) count in every role's run. A program's write (python3 -c) is invisible to the scope gate, and aladdin run reads the words back as the request.
  • OpenCode: a mission child that the parent continues for a new task starts a new run.
  • Personas: they name baseline new --supersedes, and the test checks each persona and eval verb against mission <area> --help.
  • Merge of master (A goal its sprints did not meet is retired, and the loop moves on (M9.50) #103, dsh follow-ups: per-project models, cost, capabilities, mission roles on the runtime; intake NEEDS-HUMAN, JSON payloads and a gate pipe race on every host #104, aloop stop: one stop for the whole project (M10.4) #109, aloop stop --clear: refuse every host's agent shell (M10.4) #110, Run 52: slugify (Python) under the new gates, 12/12 for $0.56 #112): the OpenCode stop keeps both the new run per task and master's NEEDS-HUMAN release.

Not in this PR (ROADMAP M9.41 and M9.48, each with its reason):

  • Findings that need per-file authorship from the area command:
    • an artifact another open run created;
    • the human's rm of an older intent, or their own edit of its words;
    • a squash merge, rebase or git reset --hard to the upstream;
    • a git gc that drops the run's reflog start;
    • a pull of another clone's artifacts.
  • The 8 MiB liveness line cap.
  • The ledger-recovery advice.

Evidence:

  • mission-roles.test.py: 69 checks (34 on master).
  • The final over-block check compared base and fix on 35 scenarios (git merges, pulls, rebases, stashes, gc, parallel runs, daily flows). It found two over-blocks. The Scout's journeys retire on a broken ledger is fixed and tested here. The human editing their own words during another role's run still blocks, because the gate cannot tell that edit from a role's write made by a program (M9.41).
  • A last adversarial review (3 lenses, each finding re-verified) checked the master merge and those fixes. It confirmed five findings, all fixed here: the words rule above, goal retire missing from the list, and three stale doc lines. It refuted two.
  • macOS: a ledger path in the test now goes through realpath (/var is /private/var). The test passes with a symlinked TMPDIR.
  • make ci passes locally on 7adf6a4 (conformance 82/82).

🤖 Generated with Claude Code

https://claude.ai/code/session_0197nSutKR1QAAqgJhFZ8fPj

claude added 10 commits October 20, 2026 08:39
…ership

The artifact gate (gate-mission-artifact, _mission_roles.py, roles.json) after
the second adversarial review, each finding a test in mission-roles.test.py:

- A human's confirm, restore or veto-window apply during a role's run, and
  what its command changed (journeys frozen, a version superseded), is never
  the role's write and never blocks it; a status no record explains still
  blocks (effects() reads the records, with the status they set).
- An overlapping run excuses a path only when it answers for it as it is now:
  an open run that will see the change at its stop, or a passed run whose
  `judged` holds those bytes; a released run owns nothing. A run is open
  while it is active (its newest tool call, from budget's per-agent state).
- The ledger is append-only during a run: the start record keeps its byte
  length and sha256, and the stop requires that prefix.
- Intents: no role rewrites an intent of the human's or intake's that
  existed at its start (intake's own `intent check` of it excuses its fill);
  a `source: mission` intent is the Mission Planner's.
- Records (roles.json `records`): a judge run log and a usage report are the
  writing role's work, checked by their own contract and their area.
- M9.42: the Product Tester writes research/, and a report belongs to the role
  its `role` field names.
- A draft no harness id names may be removed; telemetry instrumentation is a
  `foreign` note; an area check blocking only on ledger problems that predate
  the run is a note; a timed-out check has a constant reason; a malformed
  intent field is an ordinary block.
- OpenCode: a mission child continued for a new task starts a new run.
- Personas name `baseline new --supersedes` (no `baseline propose`).

ROADMAP: M9.42 done, M9.9 calls and counts, M9.41 note, M9.43 for the parts
that need other tracks' files. CHANGELOG line under M9.9.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0197nSutKR1QAAqgJhFZ8fPj
…tifact-gate fixes

Conflicts: CHANGELOG (master's lines, this track's M9.9 sub-bullet kept),
ROADMAP (master's rows; this track's M9.41/M9.42; its follow-up row moves
from M9.43, which master took, to M9.48). The track's new checks now get
the human's typed line for an approval (grant(), and the OpenCode test
types it through the UserPromptSubmit hook), and the ledger row that came
through git cites the human's words, as M9.17 requires.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0197nSutKR1QAAqgJhFZ8fPj
…eir event

- Intents: a human event, or intake's own intent.received/intent.normalized, of
  the run that names an intent makes its change, a new intent or its deletion
  theirs; a harness-named intent no event names (posed or deleted) blocks, and
  the source the run found decides whose an intent is.
- Ledger: the supervisor's restore (HEAD's committed copy, or the rows before
  the first bad line of a ledger the run started broken) is a note, not a
  rewrite; a run that wrote nothing on a ledger broken before it started gets
  a note instead of "no artifact".
- Liveness: an open run's last tool call is read from the transcript store
  (written by PostToolUse on every host, refused to roles), not from a budget
  file a role can touch; the backward read keeps a capped partial line, so it
  stays linear (a 200 MiB line: 30.7 s before, 0.95 s after).
- Records: a judge run log or usage report counts only with its command's
  event of the run (judge.run, telemetry.report).
- Snapshots belong to the roles whose reports cite them; deleting an artifact
  another run's pass accepted during this run blocks.
- The Product Tester's eval suite names `baseline new --supersedes`; persona
  and eval verbs are checked against `mission <area> --help`.
- mission-roles.test.py: 47 -> 57 checks; docs, ROADMAP M9.9/M9.41/M9.42/M9.48,
  TRACKING and CHANGELOG updated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0197nSutKR1QAAqgJhFZ8fPj
…-4 scope gate

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0197nSutKR1QAAqgJhFZ8fPj
…ir, merges)

Each finding is now a check in scripts/test/mission-roles.test.py that failed
before the fix, with its allow-control (58 -> 64 checks).

Regressions of the third round, fixed:
- Ledger restore: the start record now keeps each ledger row's bytes by
  event_id. A restore counts as the supervisor's repair only when it is HEAD's
  committed copy, or the good rows of a ledger the run started broken,
  followed only by rows the run started with (byte for byte) and rows a
  command of the run appended (its ledger event). A row edited in place, with
  its event_id kept and the chain hashed again, blocks again (after HEAD and
  after the bad line).
- Wrote nothing on a ledger broken before the run: this is a note only for a
  role whose own commands decide from the ledger (roles.json `ledger_bound`:
  baseline new, assess, baseline measure, goal derive, ethics record). The
  test checks that each listed command refuses. The Scout and the Evaluator
  are blocked with "you wrote no artifact", as on the base.
- docs/agents/intents/: every file there counts, not only *.json, so a
  rewrite of the human's raw-*.txt words blocks.
- explained(): an event names an intent only through refs.intent or
  data.intent_id, never through refs.raw, which `intent new --raw-ref` lets
  the caller choose.

Over-block fixed: an intent that a commit made during the run brought in or
removed is the supervisor's (a `git merge` or `git pull`; mission roles
cannot write git). The start record keeps HEAD, and the file must be HEAD's
blob. The role is still blocked when it changes or deletes the file itself.

Narrow items closed: a new file in intents/ whose name is not an intent id
is no longer exempt (`aladdin run` picks the last *.json there). No role can
flip a `source: mission` intent to another source to pose as the human,
whether the intent existed before the run or intake's intent.received of
the run recorded it as mission.

Two existing intents checks (mp1, ev12) wrote the human's files with no
event naming them. They now first assert the new block, then pass once
the human's record 
8000
is emitted.

Deferred to ROADMAP M9.41 and M9.48, each with a reason: deleting an artifact
that another open run created, the python channel into the transcript store
(and a commit made from inside a program), merges into docs/agents/mission/,
the 8 MiB liveness line cap, and the ledger-recovery advice over-block.
M9.48 records the ALOOP_JUDGE_CMD part as done.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0197nSutKR1QAAqgJhFZ8fPj
…aluator ledger, intake source)

Each finding is a check in scripts/test/mission-roles.test.py that failed
before its fix, with its allow-control (64 -> 67 checks). Each fix was also
reverted alone in a copy of the tree, and the test then fails at its check.

Fixed:
- A commit of the working tree during a role's run no longer hides the
  role's writes to docs/agents/intents/. Before, the human's `git commit -am`
  (or the supervisor's commit) made the Mission Planner's rewrite of the
  human's intent, and its own invalid `source: mission` intent, look like
  files a merge brought in. A file now counts as arrived only when a
  `git merge` or `git pull` brought it in. The start record keeps the size
  of HEAD's reflog. The reflog entries since then must chain from the start
  commit to HEAD, and the last entry that changed the file must be a merge
  or a pull. For a merge made here, the file must be the other side's blob,
  never a result merged with a local change. No commit made here during the
  run may have made the file as it is now, so a commit on a branch that is
  then merged is still a local commit.
- Evaluator on a ledger broken before its run: `evaluate` and `goal close`
  decide from the ledger and refuse, so roles.json lists them as the
  Evaluator's `ledger_bound` commands. A run of it that wrote nothing is a
  note again, not a block every round until the stuck release.
  `mission evaluate` now refuses on a broken ledger before it writes a gap
  list. Before, it left a sealed gap list that no eval.completed record
  backs. The test now also shows that the Scout's commands (`research
  new|archive|claim`, `journeys new`) do not refuse on that ledger.
- Intake's fill may change an intent's source to another of the human's
  kinds (`prompt` to `mixed` after a screenshot, with an `ask` question still
  open). Its intent.received of the run still names the intent. Before, the
  role was told to delete the human's request. A change to or from
  `source: mission` still blocks.

Deferred, each to ROADMAP M9.41 or M9.48 with its reason:
- A pull of another clone's mission artifacts, or of the human's
  `baseline confirm` made there.
- The human's `rm` of an older request during a run, which leaves no event.
- A squash merge, a conflicted merge concluded by `git commit`, or a plain
  `git rebase` during a run, which HEAD's reflog cannot tell from a local
  commit.
- Still open from before: the 8 MiB liveness line cap, the ledger-recovery
  advice, eventless edits of an older intent (OB1/OB2), and the python
  channel. M9.41 now says that a branch made and merged from inside a
  program still passes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0197nSutKR1QAAqgJhFZ8fPj
…ledger note, the human's words)

The Scout's `journeys retire` refuses on a broken ledger, so roles.json gives
market-researcher `ledger_bound` and a Scout run that wrote nothing there is a
note again. The words `aladdin` keeps beside an intent are judged only in the
Mission Planner's run, the one role the scope gate lets write the dir, so the
human editing or removing them while another role runs no longer blocks it.
ROADMAP M9.41 records the over-blocks that are the same on master.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0197nSutKR1QAAqgJhFZ8fPj
… into the artifact gate fixes

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0197nSutKR1QAAqgJhFZ8fPj
…complete ledger_bound, no self-made excuse)

- The words `aladdin` keeps beside an intent count in every role's run again:
  a program's write (`python3 -c`) is invisible to the scope gate, so
  af437a1's planner-only rule let an evaluator rewrite the human's request
  that `aladdin run` reads back. The test now writes them through a program.
- l
8000
edger_bound is checked complete: every command a role's persona, eval
  suite or handout (the mission skill) names that refuses on a broken ledger
  is listed. It adds the planner's `goal retire` (M9.50), the Product
  Tester's `baseline measure`, and both measuring roles' `baseline apply`.
- The wrote-nothing ledger note needs every ledger problem to be one the run
  started with: a ledger event a role appends to the run log with no row is
  no excuse.
- macOS: the ledger path in the restore check is taken through realpath
  (/var is /private/var), which failed the macOS job.
- Docs: the stale Scout claims in ROADMAP M9.9 and CHANGELOG, the gate
  docstring's ledger_bound list, M9.41's note on the human's own edits.

mission-roles.test.py: 68 -> 69 checks.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0197nSutKR1QAAqgJhFZ8fPj
@adeelahmad
adeelahmad marked this pull request as ready for review October 20, 2026 18:26
@adeelahmad
adeelahmad merged commit 566d806 into master Oct 20, 2026
5 checks passed
adeelahmad pushed a commit that referenced this pull request Oct 20, 2026
…oop stop) into the M9.31 branch

Conflicts: both sides' plugin constants and helpers kept (the door gate's
timeout and read-only set beside master's NEEDS-HUMAN release), the dsh
test's question helper renamed (master added a child named `ask`). This
branch's open items move to M9.56–M9.65: master took M9.55 and #114 claims
M9.48.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012rsDo9GYzNx8tXucywZHnA
adeelahmad pushed a commit that referenced this pull request Oct 20, 2026
…sh-clone stop) into the M9.31 branch

ROADMAP: the M9 row keeps this branch's done/open lists and adds M9.42
(done in #114) and M9.48 (open); the M10 row takes master's fresh-clone
stop and says the OpenCode plugin exports ALOOP_AGENT_SHELL since M9.31.
aloop.js: the SubagentStart comment names both the core principles and
the artifact gate's per-task start.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012rsDo9GYzNx8tXucywZHnA
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.

2 participants

0