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
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ tag in lockstep. Tag releases as `vMAJOR.MINOR.PATCH`.
- A mission's stop at a spend cap holds on a fresh checkout (ROADMAP §4.12, M9.24): the first `STOP_BUDGET` tick records a `mission.budget_exhausted` ledger row for the mission's content (once per content), and `mission tick` stops on it whatever the checkout's token ledger says, until a raised cap changes the content.
- Lifting a mission block is the human's own words (ROADMAP §4.12, M9.51): `aloop mission tick --force --by` now asks (exit 3) for the human's typed `lift <mission> <code>` line, the code bound to this occurrence of that block, and records a `mission.lifted` ledger row, so `--by` alone, a lift only the run log has (or a replayed one), an old line or a line typed for an earlier block lift nothing, a lift of 3 failed goals reaches only those goals whatever `--now` says, and a fresh checkout keeps a lifted block lifted. `/aloop:mission` counts a lift among the typed grants it relays. A lift recorded before this (run data only) no longer counts.
- The mission layer's six fixed roles (ROADMAP §4.12, M9.9): `market-researcher`, `product-tester`, `state-assessor`, `evaluator`, `mission-planner` and `ethics-reviewer`, each a persona with a four-case eval suite, a model route (the four that judge on the planning route, the two that measure on the worker route), hook matchers on Claude Code, Codex, OpenCode and dsh, and Codex/OpenCode agents and dsh presets from `aloop install` (which also renders the mission skill for OpenCode as `aloop-mission` once it ships). `plugin/mission/roles.json` names the paths each role writes. `gate-mission-scope` (PreToolUse) is the role path guard: a mission role never writes source, mission.json or another role's dir, never commits and never runs a human's approval; a builder never writes `docs/agents/mission/` or runs a writing `mission` command; the supervisor never hand-writes a role's artifact. No one hand-writes `docs/agents/mission/ledger.jsonl` or the captured prompts a grant reads (`<run data>/transcripts/`), runs a hook's `transcripts prompt|record|…`, or starts a host session (`claude -p`, `codex exec`, `opencode run`, `dsh <profile>`) from a tool call (in every aloop project since M0.9; its prompt would count as the human's words, M9.17), and no dispatched agent runs `mission baseline restore`, `events authority` or an `events emit` of a human event. `gate-mission-artifact` records what exists when a role starts and, at its stop, requires an artifact in its own paths that passes the core contract and its area's check, refuses a deleted artifact, a change to another role's or a ledger that no longer verifies, and records `artifact.created|updated` as provenance. A mission write never arms the sprint lock. The scope gate reads a Bash command as the shell would (`_shellread.py`: quotes, comments, line continuations, heredocs, wrappers such as `timeout` and `env`, `bash -c`, `eval`, a script run by an interpreter, variables and `$(mktemp)`). Each area's check runs once per artifact with its id or subject, an ethics hard line is the reviewer's finding, not a defect, and a derived goal whose only blocks are its pending ethics review waits on the Ethics Reviewer, not on the planner. Test: `mission-roles.test.py` (33 checks, with each role run through the real journeys, baseline, assess, evaluate and ethics, goal, research and judge areas), `mission-scope-bash.test.py` (718 commands), `opencode-plugin.test.mjs`.
- Its gates after a second adversarial review (each finding now a test) and M9.42: 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 no role's write and never blocks it, while a status no record explains still does. An overlapping run excuses only what it answers for as the file is now, and a run counts as open while it is active (its last tool call). The ledger is append-only during a run, with or without the run log. No role rewrites the human's or intake's intent, and a `source: mission` intent is the Mission Planner's. A research report belongs to the role its `role` field names, so the Product Tester files its own (`research new --role product-tester`); a judge run log and a usage report are the writing role's work, checked by their area; a draft in a role's own dir may be removed. The telemetry check's instrumentation problems and ledger problems that predate the run are notes, not the role's block; a malformed intent field and a timed-out check are ordinary blocks the stuck release can end; an OpenCode child continued for a new task starts a new run. Test: `mission-roles.test.py` (47 checks), `opencode-plugin.test.mjs`.
- Its gates after a third review (each finding now a test with its allow-control): 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 a deleted one theirs, while one no event names still blocks; the supervisor's restore of the ledger (HEAD's committed copy, or its rows before the first bad line) is no rewrite; a run counts as active by its last tool call in the transcript store, not by a file a role can touch; a judge run log or usage report counts only with its command's event of the run (`judge.run`, `telemetry.report`); a research snapshot belongs to the roles whose reports cite it; deleting an artifact another run's pass accepted during this run blocks; a run that wrote nothing on a ledger broken before it started gets a note. The Product Tester's eval suite names `baseline new --supersedes`, and every persona and eval verb is checked against `mission <area> --help`. Test: `mission-roles.test.py` (57 checks).
- The mission loop end to end, offline (ROADMAP §4.12, M9.13): `mission-e2e.test.py` drives `mission tick` from a new mission through research, a journey, a confirmed baseline, a gap list, a goal, its intents and one Aladdin sprint per intent to GOAL MET and the next raise of the bar, with zero tokens and each step done through the CLI the way its role or the human does it. A fresh clone hands out the same action. Ethics reviews and hard lines are now ledger rows (M9.24), so a clone no longer asks for every review again or forgets a hard line; the ledger row wins over its run-log copy, and a broken ledger makes every ethics verdict `broken`. Tests: `mission-e2e.test.py`, `mission-ethics.test.py`.
- A mission baseline binds the mission's direction (ROADMAP §4.12, M9.25): `direction_sha256` covers the mission id, statement, mode and constraints, so raising a budget cap or changing the cadence (and approving it) keeps the confirmed baseline, while a new direction still asks for a new version. Reason: M9.8's budget test, a raised cap asked for a new baseline though "best" had not changed. Test: `mission-baseline.test.py`.
- Mission approvals are the human's own words (ROADMAP §4.12, M9.17): `mission approve`, `baseline confirm|restore`, `journeys approve`, `mission ethics consent` and `mission telemetry consent` record only when a prompt the `UserPromptSubmit` hook captured has a line such as `approve msn_… 3f2a9c1b` (the verb and the first 8 hex of the content's sha256); until then they ask (exit 3) with that line. `--by` alone, a negated line, another code, a line older than a later decision about the subject (for a baseline, any version's confirmation) and a hand-appended ledger row without such a line grant nothing. Reason: an approval was only as strong as `--by`, so a role could approve its own mission change. Tests: `mission-core.test.py`, `mission-baseline.test.py`.
Expand Down Expand Up @@ -88,6 +90,8 @@ tag in lockstep. Tag releases as `vMAJOR.MINOR.PATCH`.
- `make conformance` now covers ROADMAP §6.1 and §6.10–6.20 (except 6.15) by running the focused test of the tool that holds each item. Before this, its report said those items "do not exist yet", though they shipped in v0.12.0. It now reports 74 checks across 19 of the 20 items. §6.15 (re-decomposition) stays explicit: it is measured by live runs. CI's rust job sets up Node 22 for the OpenCode test.

### Fixed
- The mission artifact gate (`gate-mission-artifact`, ROADMAP §4.12, M9.9) after a fourth review (each finding now a test in `mission-roles.test.py`, with its allow-control): a ledger restore during a role's run is the supervisor's repair only when every row after HEAD's committed copy (or after the good rows of a ledger the run started broken) is one the run started with, byte for byte, or a command's append, so a row edited in place with its event_id kept and the chain hashed again blocks again; a run that wrote nothing on a ledger broken before it is a note only for a role whose own commands decide from the ledger (`ledger_bound` in roles.json, each checked to refuse); every file in `docs/agents/intents/` counts, so the human's words `aladdin` keeps beside an intent (`raw-*.txt`) and a new `*.json` no intent id names (which `aladdin run` would pick) are no role's to write; an event names an intent only by its own `refs.intent` or `intent_id`, never by a ref its caller picks (`intent new --raw-ref`); the planner can no longer flip a `source: mission` intent to another source to pose it as the human's; and an intent a supervisor's `git merge` or `git pull` brings in or removes during a role's run no longer blocks the role, while one the role then changes still does.
- The mission artifact gate after the fourth review's second round (each finding a test in `mission-roles.test.py`, with its allow-control): only a `git merge` or `git pull` during a role's run brings a file into `docs/agents/intents/` (the HEAD reflog entries since the run started say so, and for a merge it made the file is the other side's blob), so a commit of the working tree (the human's `git commit -am`, or one made on a branch and merged) no longer hides the Mission Planner's rewrite of the human's intent or its own invalid intent from `intent check`; the Evaluator's `evaluate` and `goal close` decide from the ledger (`ledger_bound`), so an Evaluator run that wrote nothing on a ledger broken before it is a note again, not a block every round until the stuck release, and `mission evaluate` refuses on a broken ledger before it writes a gap list (it used to leave one no `eval.completed` record backs); and intake's fill may change an intent's source to another of the human's (`prompt` to `mixed` after a screenshot, with a question still open), so `aladdin "<text>"` during a role's run no longer tells the role to delete the human's request, while a change to or from `source: mission` still blocks. Its over-block check and review found more: every command a role's persona, eval suite or handout names that refuses on a broken ledger is now in its `ledger_bound` (the Scout's `journeys retire`, the Product Tester's `baseline measure` and both measuring roles' `baseline apply`, and the planner's `goal retire` from M9.50), and the test checks the list is complete, so a run of any role that wrote nothing on a ledger broken before it is a note, as before these reviews. The note needs every ledger problem to be one the run started with, so a ledger event a role appends to the run log from a program, with no row, is no excuse. The words `aladdin` keeps beside an intent still count in every role's run: a program's write (`python3 -c`) is invisible to the scope gate, and `aladdin run` reads them back as the request.
- **OpenCode judges the supervisor's and roles' shell commands with `gate-supervisor-scope`, as every other host does.** The OpenCode plugin ran the gate only for write, edit and apply_patch, so on OpenCode alone the supervisor could commit on main or append an agent's `output.md` block during a sprint, and a role could rewrite its task contract with `sed -i`. `bash` now runs it, with the payload's `cwd` taken from the command's `workdir` (a commit in a task worktree is a worker's). Tests: opencode-plugin (three refusals and the worktree pass), failing before the fix.
- **A NEEDS-HUMAN release can no longer be forged, carries no text in the gate's voice, and is told once on every host.** `intent release` needs the intake's SubagentStop and a contract `intent new` issued (its `intent.received`) in `docs/agents/intents/`; a role's own file or another role's stop records nothing. Each question is one quoted line in the notice and in `ASK[intent]` lines, so an intake's text cannot start a `[aloop gate]` line. `intent hook` reports a record only to its own session and only while its contract is still the newest. dsh and OpenCode read a release from the gate's own marker line (the last one at a line start) and accept NEEDS-HUMAN only at the intake's stop (a question quoting `STUCK … NOT verified` read as STUCK before); they tell the supervisor through `intent hook`, which claims the record, so a later Claude Code or Codex session is not told again. Tests: intent-contract, dsh-plugin, opencode-plugin, all failing before the fix.
- **A gate with no doc named judges the project's planning doc, never a host's agent definition.** `gate-intake`, `gate-standards-cited` and the gate matrix lookup (`standards_file`) found `intake.md` / `standards.md` with `find | head -1` (or a locale-dependent `sort | tail -1`), so in an OpenCode project they could judge `.opencode/agents/intake.md` instead of `docs/agents/sprintN/intake.md`: on CI's file order the intake's Intent Contract was never checked and an open ask passed, and a worker's RED could run a matrix read from the standards agent file. The new `agentic_find_doc` (`bin/_finddoc.sh`) skips hidden dirs (every host's own config), linked worktrees, `node_modules` and `target`, and takes the newest match. Tests: intent-contract (decoys in `.opencode`, `.claude`, `.codex`, `.dsh`, a worktree; the newest sprint wins) and any-language (a decoy matrix the RED would pass), both failing before the fix.
Expand Down
Loading
Loading
0