Fail closed when the repository plan is stale or incomplete #903

Open
opened 2026-08-05 18:57:41 +00:00 by coilyco-ops · 2 comments
Member

What to build

Make native AOS launch enforce consistency between the human-readable repository plan and the policy sources that produced it.

AOS fetches policy-source repositories, verifies the revision and policy digest sealed into the YAML plan, and regenerates the plan through Agent Compose once when they disagree. AOS reloads and strictly validates the regenerated plan before it creates any worktree.

A stale, invalid, or incomplete plan is never authoritative for workspace projection or unexpected-checkout cleanup.

Acceptance criteria

  • AOS reads ~/.agent-compose/repository-plan.yaml format agent-compose.repositories.v2 with strict unknown-field, duplicate-key, path, identity, ordering, and provenance validation.
  • Native launch fetches policy sources before final plan validation.
  • A source revision or policy-digest mismatch triggers exactly one Agent Compose regeneration attempt and a full plan reload.
  • AOS stops before creating worktrees when regeneration is unavailable, fails, or still produces mismatched provenance.
  • Every required residency entry must resolve to an existing checkout. Missing required repositories produce a precise diagnostic rather than being silently omitted.
  • Unexpected-checkout cleanup and its candidate-state writes do not run while the plan is stale, invalid, incomplete, or unverified.
  • Policy-source worktrees use the exact revision sealed into the validated plan, so session policy cannot be newer than repository selection.
  • aos repositories --format lines|json projects the validated YAML contract.
  • Any temporary JSON compatibility reader emits a clear deprecation warning and has an explicit removal boundary. YAML is the only steady-state format.
  • Tests cover a stale policy checkout, changed policy content at the same path, failed regeneration, a missing required checkout, cleanup gating, and a successful regenerated launch that includes a newly selected repository.
  • Product documentation and docs/FEATURES.md describe the fail-closed launch invariant.
  • Repository validation passes through declared Ward verbs.

Blocked by

## What to build Make native AOS launch enforce consistency between the human-readable repository plan and the policy sources that produced it. AOS fetches policy-source repositories, verifies the revision and policy digest sealed into the YAML plan, and regenerates the plan through Agent Compose once when they disagree. AOS reloads and strictly validates the regenerated plan before it creates any worktree. A stale, invalid, or incomplete plan is never authoritative for workspace projection or unexpected-checkout cleanup. ## Acceptance criteria - [ ] AOS reads `~/.agent-compose/repository-plan.yaml` format `agent-compose.repositories.v2` with strict unknown-field, duplicate-key, path, identity, ordering, and provenance validation. - [ ] Native launch fetches policy sources before final plan validation. - [ ] A source revision or policy-digest mismatch triggers exactly one Agent Compose regeneration attempt and a full plan reload. - [ ] AOS stops before creating worktrees when regeneration is unavailable, fails, or still produces mismatched provenance. - [ ] Every required residency entry must resolve to an existing checkout. Missing required repositories produce a precise diagnostic rather than being silently omitted. - [ ] Unexpected-checkout cleanup and its candidate-state writes do not run while the plan is stale, invalid, incomplete, or unverified. - [ ] Policy-source worktrees use the exact revision sealed into the validated plan, so session policy cannot be newer than repository selection. - [ ] `aos repositories --format lines|json` projects the validated YAML contract. - [ ] Any temporary JSON compatibility reader emits a clear deprecation warning and has an explicit removal boundary. YAML is the only steady-state format. - [ ] Tests cover a stale policy checkout, changed policy content at the same path, failed regeneration, a missing required checkout, cleanup gating, and a successful regenerated launch that includes a newly selected repository. - [ ] Product documentation and `docs/FEATURES.md` describe the fail-closed launch invariant. - [ ] Repository validation passes through declared Ward verbs. ## Blocked by - Blocked by https://forgejo.coilysiren.me/coilyco-flight-deck/agent-compose/issues/203
Author
Member

The Blocked by at the bottom of this issue is stale. coilyco-flight-deck/agent-compose#203 ("Emit a human-readable YAML repository plan with sealed provenance") closed on 2026-08-05, so the YAML contract with sealed provenance that every acceptance criterion here reads against already exists.

This is workable now. Flagging it because an engineer scanning the lane sees a blocker line and moves on, which is what nearly happened when I read it.

Director note on where it sits: this is the only member of phase 3 that is a subsystem rather than a defect, twelve acceptance criteria against a launch path. I have suggested on #1177 that it goes last within the phase, after #1047, #810, #1032, and #1034, all of which are contained and one of which (#1047) is actively costing another repo's agents today.

**The `Blocked by` at the bottom of this issue is stale.** `coilyco-flight-deck/agent-compose#203` ("Emit a human-readable YAML repository plan with sealed provenance") closed on 2026-08-05, so the YAML contract with sealed provenance that every acceptance criterion here reads against already exists. This is workable now. Flagging it because an engineer scanning the lane sees a blocker line and moves on, which is what nearly happened when I read it. Director note on where it sits: this is the only member of phase 3 that is a subsystem rather than a defect, twelve acceptance criteria against a launch path. I have suggested on #1177 that it goes last within the phase, after #1047, #810, #1032, and #1034, all of which are contained and one of which (#1047) is actively costing another repo's agents today.
Author
Member

Director input before this gets built, because one acceptance bullet as written would fire on almost every commit to this repo. Measured on kais-macbook-pro today.

Two things first, both good news: the Blocked by line is stale (agent-compose#203 closed 2026-08-05, noted above), and the plan this issue reads already exists in the shape the acceptance assumes.

$ head -3 ~/.agent-compose/repository-plan.yaml
format: agent-compose.repositories.v2
projects_root: /Users/kai/projects
inputs:
  - identity: coilyco-bridge/agentic-os-kai
    revision: 31c61d83...
    policy: {path: .agents/roles.kdl, sha256: sha256:3a015ac7...}

474 lines, sealed provenance per input, roles: keyed by role with required: flags. Nothing to build a fixture for. The live file is the fixture.

The bullet that will misfire

A source revision or policy-digest mismatch triggers exactly one Agent Compose regeneration attempt and a full plan reload.

Right now, on this host:

sealed revision  d44f9b7508d67dc89aa66f3e13f77232289810dc
current main     fefcf7bfb6d90988d829ba5f44db39b6a16d18dc     <- mismatch

roles.kdl at sealed rev   sha256:c910c59c2601288440bf10baf8cff5c650a5ea2968fd4f654a8ea631afff4343
roles.kdl at current main sha256:c910c59c2601288440bf10baf8cff5c650a5ea2968fd4f654a8ea631afff4343
plan seals                sha256:c910c59c2601288440bf10baf8cff5c650a5ea2968fd4f654a8ea631afff4343   <- match

The revision moved eight times today and the policy never changed once. Every one of those merges was ordinary lane work in a repo that happens to also be a policy source. Under the bullet as written, each would force a regeneration and a full plan reload at the next native launch, for a plan that was already correct.

That is not a small tax. agentic-os takes many commits a day, and the regeneration sits in the launch path ahead of worktree creation, which is the thing the rest of this issue is trying to make trustworthy. A fail-closed gate that fires constantly gets routed around, and then it protects nothing.

Suggested change to the acceptance

  • Trigger regeneration on the policy digest, not on the revision. The digest changes exactly when the thing that determines the plan changes. That is the definition of the right signal.
  • Keep sealing the revision, and treat drift in it as provenance to refresh rather than as invalidation. It answers "which commit produced this plan", which is worth having and is not the same question as "is this plan still correct".
  • The bullet about policy-source worktrees using the exact sealed revision still works: it stops session policy being newer than repository selection, and a revision whose roles.kdl is byte-identical is not newer in any way that matters.
  • Everything fail-closed stays as written. A digest mismatch that regeneration cannot resolve should still stop before any worktree exists.

This is a recommendation on the specification rather than a finding about code, so overturn it here if you think revision drift genuinely needs to invalidate. My case is only that today's eight regenerations would all have been for nothing, and that is the steady state rather than a bad day.

One implementation detail worth knowing up front

~ is not the same path inside a native session. This session's HOME is /tmp/aos/native/dx65/home, and the plan is at both:

/Users/kai/.agent-compose/repository-plan.yaml            20404 bytes
/tmp/aos/native/dx65/home/.agent-compose/repository-plan.yaml  20404 bytes, identical today

They are identical right now, which is exactly the condition under which a path bug stays invisible. Whichever one AOS reads, the choice should be deliberate and stated, because a shadow that regenerates into its own HOME while the canonical plan goes stale is a failure this issue would otherwise be understood to have prevented.

**Director input before this gets built, because one acceptance bullet as written would fire on almost every commit to this repo. Measured on `kais-macbook-pro` today.** Two things first, both good news: the `Blocked by` line is stale (agent-compose#203 closed 2026-08-05, noted above), and the plan this issue reads already exists in the shape the acceptance assumes. ``` $ head -3 ~/.agent-compose/repository-plan.yaml format: agent-compose.repositories.v2 projects_root: /Users/kai/projects inputs: - identity: coilyco-bridge/agentic-os-kai revision: 31c61d83... policy: {path: .agents/roles.kdl, sha256: sha256:3a015ac7...} ``` 474 lines, sealed provenance per input, `roles:` keyed by role with `required:` flags. Nothing to build a fixture for. The live file is the fixture. ## The bullet that will misfire > A source revision **or** policy-digest mismatch triggers exactly one Agent Compose regeneration attempt and a full plan reload. Right now, on this host: ``` sealed revision d44f9b7508d67dc89aa66f3e13f77232289810dc current main fefcf7bfb6d90988d829ba5f44db39b6a16d18dc <- mismatch roles.kdl at sealed rev sha256:c910c59c2601288440bf10baf8cff5c650a5ea2968fd4f654a8ea631afff4343 roles.kdl at current main sha256:c910c59c2601288440bf10baf8cff5c650a5ea2968fd4f654a8ea631afff4343 plan seals sha256:c910c59c2601288440bf10baf8cff5c650a5ea2968fd4f654a8ea631afff4343 <- match ``` **The revision moved eight times today and the policy never changed once.** Every one of those merges was ordinary lane work in a repo that happens to also be a policy source. Under the bullet as written, each would force a regeneration and a full plan reload at the next native launch, for a plan that was already correct. That is not a small tax. agentic-os takes many commits a day, and the regeneration sits in the launch path ahead of worktree creation, which is the thing the rest of this issue is trying to make trustworthy. A fail-closed gate that fires constantly gets routed around, and then it protects nothing. ## Suggested change to the acceptance * **Trigger regeneration on the policy digest, not on the revision.** The digest changes exactly when the thing that determines the plan changes. That is the definition of the right signal. * **Keep sealing the revision, and treat drift in it as provenance to refresh rather than as invalidation.** It answers "which commit produced this plan", which is worth having and is not the same question as "is this plan still correct". * The bullet about policy-source worktrees using the exact sealed revision still works: it stops session policy being newer than repository selection, and a revision whose `roles.kdl` is byte-identical is not newer in any way that matters. * Everything fail-closed stays as written. A digest mismatch that regeneration cannot resolve should still stop before any worktree exists. This is a recommendation on the specification rather than a finding about code, so overturn it here if you think revision drift genuinely needs to invalidate. My case is only that today's eight regenerations would all have been for nothing, and that is the steady state rather than a bad day. ## One implementation detail worth knowing up front `~` is not the same path inside a native session. This session's `HOME` is `/tmp/aos/native/dx65/home`, and the plan is at both: ``` /Users/kai/.agent-compose/repository-plan.yaml 20404 bytes /tmp/aos/native/dx65/home/.agent-compose/repository-plan.yaml 20404 bytes, identical today ``` They are identical right now, which is exactly the condition under which a path bug stays invisible. Whichever one AOS reads, the choice should be deliberate and stated, because a shadow that regenerates into its own `HOME` while the canonical plan goes stale is a failure this issue would otherwise be understood to have prevented.
Sign in to join this conversation.
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
coilyco-flight-deck/agentic-os#903
No description provided.