Skip to content

feat: the Gate C vertical — the product installs, runs, and proves its own claims - #4

Merged
darklordVirtual merged 7 commits into
mainfrom
feat/gate-c-vertical
Aug 6, 2026
Merged

darklordVirtual merged 7 commits into
mainfrom
feat/gate-c-vertical

Conversation

@darklordVirtual

Copy link
Copy Markdown
Owner
python run.py up && python run.py scenarios
6/6 scenarios behaved as documented

126 tests pass: 71 pinned-core contract, 55 end-to-end against a running stack.

What now runs

[PASS] ACCEPT    assess → accept (grounded_read_accept)
                 execute_accepted → execute
                 replay refused → ReplayRefusedError
[PASS] VERIFY    assess → verify · agent token refused approval (correct)
                 domain_expert approved · execute
                 EFFECT_VERIFIED — the system of record shows the approved delta
                 record_effect → EFFECT_VERIFIED in the chain
[PASS] ABSTAIN   assess → abstain · stopped, and offered nothing to execute
[PASS] ESCALATE  assess → escalate · required_role=senior_authority
[PASS] BINDING   binding_refused (tool-call hash differs from the approved payload)
[PASS] ROLES     reviewer approved · reviewer token refused execution

The VERIFY trace is the whole product in six lines: a production write was held; the agent that proposed it was refused the right to approve it; the identity the decision named released it; the operator executed; and a separate process holding a SELECT-only credential went and looked at the database.

The two P0 findings from the review

Licensing. LICENSING.md was linked from the README and did not exist; GitHub reported license: null on a repository asserting BUSL-1.1. Now present and adapted for AAE, stating explicitly that the pinned REMORA core is a separate Licensed Work — an AAE license grants nothing in REMORA and vice versa.

Manifest drift. core-release-manifest.json had been stale for two pin bumps — commit f3e58db, 28 SDK symbols — while the lock had moved to 4c85937 and 36. verify_core_pin.py never looked at it. Fixed in three places: the file is now the one the release published, its digest is pinned and verified including the in-tree copy, and test_pin_manifest_agreement.py compares the hand-written lock to the release-generated manifest field by field.

Upstream

Three core candidates, every one with the SDK contract byte-identical — only the wheel moved each time.

  • .2 — deployment-declared tool classification, GROUNDED_READ_ACCEPT, per-surface production prerequisites. Without the first, ACCEPT was structurally unreachable for any tool a product names itself. Without the second, classification alone changed nothing: the policy-only kernel has no oracle, so the probabilistic ACCEPT could not fire there at all.
  • .3 — the risk profile resolved against the working directory, so a wheel install refused to start in production mode while the file sat in site-packages. Found by installing the wheel in a container, which is what any deployment does.

Also fixed upstream along the way: a pinned target_environment could lower risk; enabling an opt-in ACCEPT path moved no policy hash; and conftest.py silently skipped two tests asserting that an unknown risk tier in a production environment can never ACCEPT.

What running it found

Every one of these was invisible to unit tests.

  • The approver token was admin. This compose file and REMORA's OT pilot both claimed "the approver token cannot execute" while configuring a role holding every capability including execute. The e2e test caught it by trying. Now reviewer / domain_expert / senior_authority, and the product reads required_role off each decision rather than holding one credential that can approve anything.
  • A refusal is an outcome, not an exception. The binding scenario wrapped execute() in try/except and reported "a payload the approver never saw was executed". It had not been — the system of record was untouched and outcome said binding_refused. Anything integrating with the SDK must read the field.
  • The CLI's execute passed a dict where the SDK wants a ToolCall — found by writing the onboarding walkthrough and then running it.
  • A CRLF entrypoint.sh fails in a container as "no such file or directory". The Windows console crashed scenarios after every decision was recorded. psql -v cannot take a dotted variable name. The runner named aae.py shadowed the aae package. AAE_API_PORT=8080 was already taken.

Deliberately left standing

  • A fully grounded medium-risk mutation falls through every rule to default_safe_abstain — no review item, no ResolutionPlan, no path an approver could take, for an action a signed work order authorizes. Declaring a risk tier leaves a tool worse off than leaving it unknown. Recorded in the code where the scenario had to be retargeted, and in README "Known gaps".
  • callable_digest is signed and true but not enforced: verify_callable exists upstream and nothing calls it at dispatch.
  • HMAC signing is symmetric, so the verifier holds the signing key.
  • Tools run inside the control-plane process; the credential separation is at the database, not at a process boundary.

Docs

docs/ARCHITECTURE.md names the test that checks each claim at the end of its section. docs/ONBOARDING.md is 30 minutes and half of it is trying to get past the controls. docs/OPERATIONS.md covers signing, what rotation does to evidence already signed, and how to verify an evidence archive without this product.

The review found both, and both were the same failure: a claim nobody
checked.

1. LICENSING.md was linked from the README and did not exist. GitHub
   reported license: null on a repository whose README asserts BUSL-1.1
   and "commercial production use requires separate written terms".
   That is unenforceable. LICENSE, LICENSING.md, COMMERCIAL_LICENSE.md
   and NOTICE now exist, adapted for AAE rather than copied from REMORA:
   they name Assured Agent Execution as the Licensed Work and state
   explicitly that the pinned REMORA core is a SEPARATE Licensed Work,
   so an AAE license grants nothing in REMORA and vice versa. A
   deployment runs both and needs to be permitted under both.

2. product/core-release-manifest.json had been stale for two pin bumps
   — commit f3e58db, 28 SDK symbols, old digests — while the lock had
   moved to 4c85937 and 36. verify_core_pin.py downloaded five contract
   assets and the wheel, and never looked at the manifest at all.

   Fixed in three places, because one would have been decoration:
   - the file is now the manifest the pinned release actually published;
   - its digest is pinned in the lock and verified (7 artifacts, not 6),
     including the copy checked into this tree — verifying only the
     download would leave the in-tree file free to rot again;
   - test_pin_manifest_agreement.py compares the hand-written lock to
     the release-generated manifest field by field: commit, version,
     every artifact digest, the symbol count three ways, and the
     consumer contract. That last one matters most — if core widened
     its internal namespace set and the lock kept the old list, the
     import-boundary test would keep passing while no longer covering
     the boundary.

   These read JSON only, so they fail before anything is downloaded or
   built.

58 compatibility tests pass (was 46).
… Order ToolPack

## The pin

Moves to the core built from master 4d7b62a, which closes the three
things that kept this product to three of its four decisions:
deployment-declared tool classification, the deterministic
GROUNDED_READ_ACCEPT path, and per-surface production prerequisites.

Every frozen contract artifact is byte-identical to the previous
candidate — public_api_v1.json, openapi.json, and all three schemas.
Only the wheel moved. That is worth stating precisely, and it is only
checkable because the contracts are pinned separately from the code:
the SDK surface AAE depends on did not change, so nothing in
tests/compatibility needed to.

## The ToolPack

Five tools over a Postgres work-order system of record, chosen so each
of the four decisions is reachable by a real action rather than a
contrived one — read (ACCEPT when grounded), priority and create
(VERIFY), close (VERIFY, then effect verification), purge (ESCALATE).

Three separations that are the actual product content:

- Classification is DATA, not code. tool_metadata.json declares the risk
  tiers; registry.py holds only callables. Code that could classify
  itself would be a tool granting itself a risk tier. The file's
  resolved content is hashed into REMORA's policy identity, so editing
  a tier invalidates every outstanding lease.

- Authority is resolved SERVER-SIDE. work_orders.json says what each
  work-order id authorizes; the agent names an id and can never assert
  what it means. That asymmetry is what an ACCEPT rests on.

- Credentials are split at the database. aae_worker reads and writes;
  aae_reader is SELECT only and is what the postcondition reader will
  hold. A verifier that could write would be reporting on itself, and
  store.py refuses to fall back from one DSN to the other — that
  substitution would delete the property silently.

The worker holds no DELETE grant anywhere. purge_work_order_history is
declared and deliberately unimplemented, so the ESCALATE scenario runs
against a tool the deployment genuinely declares rather than an unknown
name, which would test the fail-closed floor instead.

## The dependency I am not hiding

bundle.py imports nine types from remora.toolcall.* to declare tool
semantics. That namespace is not remora.sdk, is not in
public_api_v1.json, and is not forbidden either — it is undeclared
territory, and no equivalent exists in the SDK, so a deployment cannot
author its own semantics without it.

test_toolpack_authoring_surface.py pins the exact symbols AND the
constructor keywords, so an upstream rename fails in CI on a pin bump
rather than in a container as "every proposal abstains". Its last test
asserts remora.sdk does NOT yet offer this surface — when that fails,
it is the signal to move the imports and delete the file.

## Also

docker/control-plane.Dockerfile installs the hash-verified wheel and
re-verifies the digest inside the image against the lock it copies in.
Twice is not redundant: the first check gates the download, the second
makes the image self-describing, so an image built from an unverified
wheel fails its own build.

71 compatibility tests pass (was 58).
    make up && aae scenarios
    6/6 scenarios behaved as documented

One command brings up a control plane built from the hash-verified core
wheel, two Postgres instances, and a migrated system of record. The four
decisions are then exercised against it for real:

  ACCEPT    a grounded read under signed WO-1201 executes with no human;
            the token is refused on replay (ReplayRefusedError)
  VERIFY    close WO-1202 is held; the agent token is refused approval;
            the DOMAIN_EXPERT identity — the role that decision asked for
            — approves; the operator executes; the effect is read back on
            a SELECT-only credential and attested in the chain as
            EFFECT_VERIFIED
  ABSTAIN   the same read under an authority that does not resolve stops,
            and offers nothing to execute
  ESCALATE  the destructive tool is refused and routed to senior_authority

plus payload binding (binding_refused: "tool-call hash differs from the
approved payload") and role separation.

110 tests pass: 71 compatibility, 39 end-to-end.

## What running it actually found

Six defects, none of which any unit test would have reached:

1. The approver token was `admin`. Both this compose file and the OT
   pilot's claimed "the approver token cannot execute" while configuring
   a role holding every capability including execute — so the approver
   approved its own proposal and then executed it. The e2e test caught it
   by trying. Now `reviewer`/`domain_expert`/`senior_authority`, none of
   which can act.

2. One approver identity is not enough. REMORA's escalation contract
   decides per decision which role may release it: a priority change
   takes a reviewer, a production close takes a domain expert, a purge
   takes senior authority. The product now reads `required_role` off the
   decision and presents the matching identity, and refuses loudly when
   it holds none — approving with a weaker identity than the decision
   asked for is exactly what the escalation existed to prevent.

3. A refusal arrives as an OUTCOME, not an exception. The binding
   scenario wrapped execute() in try/except, saw nothing raised, and
   reported "a payload the approver never saw was executed". It had not
   been — the system of record was untouched, and `outcome` said
   `binding_refused`. A consumer that only catches exceptions treats a
   refusal as success. Both the scenario and the tests now read the field.

4. `psql -v` cannot take a dotted variable name, and psql does not
   substitute variables inside dollar-quoted strings — so the first
   migration's DO blocks reading current_setting('aae.worker_password')
   could never have worked. Rewritten with \gexec.

5. A CRLF entrypoint.sh fails in a container as "no such file or
   directory", naming the interpreter rather than the script. .gitattributes
   forces LF.

6. The Windows console cannot encode the report's arrows, so `aae
   scenarios` crashed with UnicodeEncodeError AFTER running every
   scenario — governance decisions recorded, operator shown a traceback.
   The CLI now forces UTF-8 with errors="replace".

## Two findings left standing, deliberately

- A fully grounded MEDIUM-risk mutation falls through every rule to
  default_safe_abstain: no review item, no ResolutionPlan, no path an
  approver could take, for an action a signed work order authorizes. High
  risk hits evidence_insufficient and ungrounded arguments hit their own
  rule; medium-and-grounded matches neither, so declaring a risk tier
  leaves a tool worse off than leaving it unknown. The role-separation
  scenario is retargeted with that reason recorded in the code rather
  than papered over.

- REMORA's evidence bundle is not byte-stable across exports. Exactly one
  field moves — manifest.exported_at — which is correct, and means an
  outer file digest identifies THAT export rather than the evidence. The
  test now asserts nothing ELSE moves, and names any field that starts to.

## Structure

  toolpacks/work_order/   registry (callables + credentials), bundle
                          (semantics + server-side authority resolution),
                          tool_metadata.json (risk classification as DATA,
                          hashed into REMORA's policy identity),
                          work_orders.json (signed authorities)
  db/workorders/          the product's own schema, applied by a one-shot
                          migration under an admin role; the worker and
                          reader roles it creates hold no DDL
  src/aae/                config (identity per decision), postcondition
                          (the read-only verifier), scenarios, evidence,
                          cli
  docker/                 control plane from the verified wheel, with a
                          preflight that refuses on an unresolvable
                          toolpack rather than letting every dispatch
                          report unknown_tool
outsider verifies it with

Closes the four remaining items. 126 tests pass, 6/6 scenarios.

## Signed ToolSpec bundle

`make sign` computes each callable_digest from the SOURCE of the function
actually registered, signs with the deployment's key, and pins the digest
into .env. It refuses to sign in both directions: a declared tool with no
callable, or a registered callable with no spec. A registered tool without
a spec runs unattested; a spec without a tool is an authority nobody can
exercise, which rots quietly until someone adds a function to match it.

tests/e2e/test_toolspec.py takes the bundle this deployment actually runs
and attacks it six ways — widening allowed_targets, rewriting the
description an agent reads, escalating credential_scope, reclassifying a
destructive tool as routine, removing the postcondition reader, loosening
the argument schema — plus a revoked signer, an untrusted signer, the
wrong key, and the subtle one: a correctly-signed OLDER bundle. Every
signature check passes on that last one, because it really was signed by
this deployment. Only the pinned digest refuses it.

Three things this surfaced:

- The runtime compares REMORA_TOOLSPEC_PINNED_DIGEST against a BARE hex
  digest. Everything else in the codebase uses the "sha256:" form, so the
  first version emitted one and the control plane refused the bundle as
  toolspec_bundle_stale — which reads exactly like a real staleness
  attack rather than a formatting mistake.

- A refused bundle surfaces as a 500 on every request rather than a
  startup refusal. Strict mode with an unusable bundle should fail closed
  where an operator sees it.

- callable_digest is recorded but never checked: verify_callable exists
  upstream and nothing calls it at dispatch. Computing the true digest is
  still worth it — it is signed, and it becomes enforced the moment core
  wires the check — and a test asserts it matches the deployed source, so
  the field is not decoration in the meantime.

## Operator console

A separate image that imports no REMORA module and holds no policy. It
shells out to the product CLI for the scenarios rather than keeping its
own copy: a console that could show green while the CLI showed red would
leave nobody able to say which one described the product.

The posture panel is the reason it exists. A console that only showed
activity would let a deployment look healthy while running unpinned,
unenforced, or with a chain that no longer verifies.

Running it found a real config bug: Config.from_env demanded
AAE_READER_PASSWORD even when the full reader DSN was supplied, so the
console's scenario run failed on a credential it does not need.

## The CLI's execute was broken, and the docs caught it

cmd_execute passed a dict where the SDK wants a ToolCall — the same
mistake the scenarios made, left behind in the CLI. Writing the onboarding
walkthrough and then RUNNING it is what found it.

It now takes the review item id, the tool name, the arguments, the intent
and the environment, because the approval is bound to a hash over all of
them. Restating the whole call is what lets the server detect that you are
executing something other than what was approved.

It also exits 1 on a refusal. binding_refused arrives as an OUTCOME, not
an exception, so a script that only checked for a raised error would treat
it as success — exactly the mistake this product's own scenario made.

## Documentation

README rewritten for a product that runs, with a Known gaps section naming
five, two of them upstream and open.

docs/ARCHITECTURE.md — what runs where and why each boundary is where it
is, with the test that checks each claim named at the end of its section.

docs/ONBOARDING.md — 30 minutes, no research repo required, and half of it
is trying to get past the controls rather than watching them work. Every
command in it was executed against the running stack before it was
written down; the CLI bug above is what that caught.

docs/OPERATIONS.md — signing, rotation (and what rotation does to evidence
already signed), evidence export including how to verify an archive
WITHOUT this product, and what each non-terminal effect status means for
an incident.
…achine

Wiped .venv, dist, .env and every volume, then followed the onboarding
guide as written. It failed three times, and all three were real.

1. `make` is not installed on a default Windows machine. The install
   instruction for a product whose pitch is "one command" cannot be
   "first install make". Every target now delegates to run.py, so there
   is one implementation and the Makefile cannot drift from the docs.

2. The runner was named aae.py, which SHADOWS the aae package in src/ —
   `from aae.config import ...` inside a script resolved to the runner
   instead. Renamed to run.py. A latent trap for anything else importing
   aae from the repository root, and only a from-scratch run finds it.

3. bootstrap_env.py hardcoded AAE_API_PORT=8080, which was already taken
   on this machine, so `up` died on "port is already allocated". It now
   probes for a free port and prints the URLs it chose. A fixed default
   is wrong for everyone already running something on 8080, and that is
   a poor first experience.

Verified from a genuinely clean slate afterwards:

    python run.py up          → one command, ends with the two URLs
    python run.py scenarios   → 6/6
    python run.py verify      → 71 compatibility + 55 end-to-end
    python run.py doctor      → pinned core, execution surface only
    console /api/posture      → toolspec signed + pinned, chain valid

Docs now use the commands that exist, and say the venv note the `aae`
console script needs. Every command in ONBOARDING.md was executed against
the running stack before it was written down — which is how the CLI's
broken `execute` was found in the previous commit, and these three here.
Two jobs. The contract job needs no Docker and fails in seconds if the pin,
the manifest agreement or the import boundary is wrong.

The vertical job runs `python run.py up` — the same command the README gives
a new developer — then the four decisions, the end-to-end suite and the
ToolSpec verification. If that step breaks, the install instructions are
broken, which is exactly what we want CI to notice.

Running it is what found everything interesting this product got wrong: an
approver token that could also execute, a refusal that arrives as an outcome
rather than an exception, a CRLF entrypoint failing as "no such file or
directory", a hardcoded port, and a runner module shadowing the package it
was meant to run. None of those were reachable by unit tests.
@darklordVirtual
darklordVirtual merged commit 6cdf5f2 into main Aug 6, 2026
2 checks passed
darklordVirtual added a commit that referenced this pull request Aug 6, 2026
PR #4 was squash-merged while this branch kept moving, so main holds the
early work as one commit and this branch holds it as its originals plus
everything since. Every file main has that this branch lacks is a deliberate
removal here:

  Makefile                  run.py became the single implementation
  docs/ARCHITECTURE.md      replaced by docs/architecture.md
  docs/ONBOARDING.md        folded into the README and the attack tutorial
  docs/OPERATIONS.md        replaced by docs/operations.md
  tool_specs.signed.json    generated per install, now gitignored

Checked with `git diff --diff-filter=A feat/gate-c-vertical origin/main`
before merging: that list is exhaustive, so `-s ours` drops nothing
unintentional. The doc renames are lowercase-only changes that a
case-insensitive filesystem hides — verified against `git ls-tree`, not the
working directory.
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