test(e2e,docs)!: the suites, the CI leg and the public docs speak records - #1402
test(e2e,docs)!: the suites, the CI leg and the public docs speak records#1402yousefh409 wants to merge 1 commit into
Conversation
…ords
## What
The top of the OSS stack, re-pointed at the automation RECORD.
**Suites.** The `automations-e2e` fixture harness composes the engine the way the
umbrella now does — the four-verb `automations` seam into `createApps`, the
runner map, the one internal create op — and its 19 suites assert records rather
than apps-with-triggers. Three suites are new, one per flow that had no cover:
`agent-on` (code authoring, boot reconcile, kill-switch survival),
`vendo-automate` (chat authoring, every `when` shape, cross-owner refusal), and
`missing-agent` (duplicate name throws at boot; an unregistered name is a FAILED
run row and no fallback brain ever runs).
`fixtures/integration` moves off `/apps/import`-with-triggers onto one shared
`createAutomation` harness helper, and gains the leg nothing covered: Vendo
Cloud's **signed** heartbeat knock on `POST /api/vendo/tick` — 202 `{fired:1}`,
idempotent on a retry with a fresh delivery id, 401 for an unsigned stranger and
for a wrong key. It signs with the base64url-decoded secret, so it agrees with
the door's own `verifySignature` rather than with a restatement of the scheme.
That leg needs the deployment to HOLD a tick secret — the key every credential is
verified against — which the test now asserts as an explicit precondition rather
than assuming.
**CI.** The automations leg gets `ANTHROPIC_API_KEY`, on pushes to `main` only:
ANTHROPIC_API_KEY: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' && matrix.name == 'automations' && secrets.ANTHROPIC_API_KEY || '' }}
`pull_request` and `merge_group` both evaluate to `''`, so nothing a contributor
or a fork can trigger reaches the key, and `live-agentic`'s own `describe.skipIf`
makes the empty string a clean no-op everywhere else.
**Docs.** `capabilities/automations` is rewritten around the record and the two
authoring doors; `backend/automate` is a new page for `.on()` (every shape, the
declaration-time refusal, what a redeploy does), slotted into "In your backend"
after `run`. `production/vendo-cloud`, `production/deploying`,
`reference/http-routes` and one stale sentence in `reference/cli` stop saying
automations run in Cloud — they run in your process, and Cloud only knocks. The
dead `deploy/scheduler-and-webhooks` link in `packages/automations/README.md` now
points at the live page.
**Demo-bank.** The seeded automations and their run history are records, in
Maple's own consumer voice. Two real defects came out of running it:
- a seeded run row carried no `owner`, so the engine's own reader rejected every
one of them (`invalid run row …: Required`) and the console's Automations tab
would have shown an empty history. Every owner-scoped read filters on that
field.
- `away-drill`'s dev server used `MAPLE_DIST_DIR=.next/away-drill`, NESTED inside
the distDir `next build` wipes. It is now the sibling `.next-away-drill`, the
rule `fixtures/context-e2e` already follows for this same app, with the
matching `.gitignore` entry.
## Why the docs changed more than the rename
Three claims in them were wrong in a way that costs a reader real time:
- `VENDO_TICK_SECRET` was described as the BYO-cron credential. Both credentials
the door accepts are verified against it (`tickAuthorized`), so with it unset
even Cloud's signed heartbeat is refused. `capabilities/automations`,
`production/vendo-cloud` and `production/deploying` now say so.
- `GET /automations` was documented as carrying `pendingGrants`/`grantSetId`.
`list` returns plain redacted `AutomationRecord[]`.
- `.on()`'s validation error was paraphrased. It is now the message
`validateCron` actually throws, and the `budget` default is the real 50.
Server-side snippets show the `RunContext` every verb takes last, because
`vendo.automations` is the engine itself — there is no ctx-injecting facade.
## Gate
Rebased onto `automations/s2c-vendo` @ af8f2d0, then: `pnpm build` 21/21,
`dependency-guard` OK (30 packages), `portability-gate` all legs green, and
`fixtures/{automations-e2e,redteam,integration}` + `examples/demo-bank` typecheck
clean.
- `fixtures/integration` — 47 pass, 1 skipped, 1 fail (BUG C below, proven
pre-existing at the base). The Cloud-heartbeat leg passes.
- `automations-e2e` — 66 pass, 1 skipped, 3 fail (BUGs A and B below). Identical
to the pre-rebase run, so the rebase changed nothing.
- `redteam-e2e` — 6 files, 23 pass, 1 skipped, 0 fail.
- `demo-bank` — 25 files, 119 pass, 0 fail. `away-drill` boots and passes in 24s
now that its dist dir is a sibling; it had been timing out at 240s.
Three PRODUCT bugs these suites caught live in code this change does not touch.
The assertions are correct and should not be weakened to go green:
1. `runs.list({ owner })` / `({ agent })` throw `Unknown vendo_runs ref key:
subject`. `runs-surface.ts:49-50` filters on refs `vendo_runs` does not
declare (`routing.ts:583` has only `automation_id`, `status`). Both are
documented public filters and both are mapped from `?owner` / `?agent` on
`GET /runs`, so this is a 500 on a public route.
2. A `vendo.json` manifest schedule can never be armed. `manifest-triggers.ts`
states that "`fn:` steps capture an EMPTY consent surface", but
`consentSurface` passes every step tool through verbatim, so capture rejects
the app's own function with `unknown tool in automation: fn:chase` and the
fold-in creates nothing.
3. `fixtures/integration/tests/machine-skin` — a guarded app read that HOLDS a
live standing grant returns `pending-approval` instead of `ok`. Reproduced at
`origin/automations/s2c-vendo` with this lane's files reverted, so it is not
this change; my only edit there is the rename `importAutomation` → `importApp`.
Greptile SummaryThis PR moves fixtures, demo data, CI coverage, and documentation to standalone automation records. End-to-end checks found three failures that prevent expected automation workflows: public run filtering by owner or agent returns validation errors, manifest schedules that invoke app-local functions fail after being armed, and machine callbacks request approval again despite a matching active standing grant. These paths should be corrected before merge. Confidence Score: 2/5Not safe to merge until the verified automation execution, run filtering, and standing-grant regressions are fixed. Each reported failure was reproduced through a composed runtime path with persisted state and captured output, covering public HTTP requests, manifest fold-in and ticking, and guarded machine callbacks. Files Needing Attention: packages/vendo/src/wire/automations.ts, packages/automations/src/consent.ts, packages/vendo/src/wire/box.ts, and the corresponding store routing and guard matching implementations.
What T-Rex did
|
What
The top of the OSS stack, re-pointed at the automation RECORD.
Suites. The
automations-e2efixture harness composes the engine the way theumbrella now does — the four-verb
automationsseam intocreateApps, therunner map, the one internal create op — and its 19 suites assert records rather
than apps-with-triggers. Three suites are new, one per flow that had no cover:
agent-on(code authoring, boot reconcile, kill-switch survival),vendo-automate(chat authoring, everywhenshape, cross-owner refusal), andmissing-agent(duplicate name throws at boot; an unregistered name is a FAILEDrun row and no fallback brain ever runs).
fixtures/integrationmoves off/apps/import-with-triggers onto one sharedcreateAutomationharness helper, and gains the leg nothing covered: VendoCloud's signed heartbeat knock on
POST /api/vendo/tick— 202{fired:1},idempotent on a retry with a fresh delivery id, 401 for an unsigned stranger and
for a wrong key. It signs with the base64url-decoded secret, so it agrees with
the door's own
verifySignaturerather than with a restatement of the scheme.That leg needs the deployment to HOLD a tick secret — the key every credential is
verified against — which the test now asserts as an explicit precondition rather
than assuming.
CI. The automations leg gets
ANTHROPIC_API_KEY, on pushes tomainonly:pull_requestandmerge_groupboth evaluate to'', so nothing a contributoror a fork can trigger reaches the key, and
live-agentic's owndescribe.skipIfmakes the empty string a clean no-op everywhere else.
Docs.
capabilities/automationsis rewritten around the record and the twoauthoring doors;
backend/automateis a new page for.on()(every shape, thedeclaration-time refusal, what a redeploy does), slotted into "In your backend"
after
run.production/vendo-cloud,production/deploying,reference/http-routesand one stale sentence inreference/clistop sayingautomations run in Cloud — they run in your process, and Cloud only knocks. The
dead
deploy/scheduler-and-webhookslink inpackages/automations/README.mdnowpoints at the live page.
Demo-bank. The seeded automations and their run history are records, in
Maple's own consumer voice. Two real defects came out of running it:
owner, so the engine's own reader rejected everyone of them (
invalid run row …: Required) and the console's Automations tabwould have shown an empty history. Every owner-scoped read filters on that
field.
away-drill's dev server usedMAPLE_DIST_DIR=.next/away-drill, NESTED insidethe distDir
next buildwipes. It is now the sibling.next-away-drill, therule
fixtures/context-e2ealready follows for this same app, with thematching
.gitignoreentry.Why the docs changed more than the rename
Three claims in them were wrong in a way that costs a reader real time:
VENDO_TICK_SECRETwas described as the BYO-cron credential. Both credentialsthe door accepts are verified against it (
tickAuthorized), so with it unseteven Cloud's signed heartbeat is refused.
capabilities/automations,production/vendo-cloudandproduction/deployingnow say so.GET /automationswas documented as carryingpendingGrants/grantSetId.listreturns plain redactedAutomationRecord[]..on()'s validation error was paraphrased. It is now the messagevalidateCronactually throws, and thebudgetdefault is the real 50.Server-side snippets show the
RunContextevery verb takes last, becausevendo.automationsis the engine itself — there is no ctx-injecting facade.Gate
Rebased onto
automations/s2c-vendo@ af8f2d0, then:pnpm build21/21,dependency-guardOK (30 packages),portability-gateall legs green, andfixtures/{automations-e2e,redteam,integration}+examples/demo-banktypecheckclean.
fixtures/integration— 47 pass, 1 skipped, 1 fail (BUG C below, provenpre-existing at the base). The Cloud-heartbeat leg passes.
automations-e2e— 66 pass, 1 skipped, 3 fail (BUGs A and B below). Identicalto the pre-rebase run, so the rebase changed nothing.
redteam-e2e— 6 files, 23 pass, 1 skipped, 0 fail.demo-bank— 25 files, 119 pass, 0 fail.away-drillboots and passes in 24snow that its dist dir is a sibling; it had been timing out at 240s.
Three PRODUCT bugs these suites caught live in code this change does not touch.
The assertions are correct and should not be weakened to go green:
runs.list({ owner })/({ agent })throwUnknown vendo_runs ref key: subject.runs-surface.ts:49-50filters on refsvendo_runsdoes notdeclare (
routing.ts:583has onlyautomation_id,status). Both aredocumented public filters and both are mapped from
?owner/?agentonGET /runs, so this is a 500 on a public route.vendo.jsonmanifest schedule can never be armed.manifest-triggers.tsstates that "
fn:steps capture an EMPTY consent surface", butconsentSurfacepasses every step tool through verbatim, so capture rejectsthe app's own function with
unknown tool in automation: fn:chaseand thefold-in creates nothing.
fixtures/integration/tests/machine-skin— a guarded app read that HOLDS alive standing grant returns
pending-approvalinstead ofok. Reproduced atorigin/automations/s2c-vendowith this lane's files reverted, so it is notthis change; my only edit there is the rename
importAutomation→importApp.Base
Stacked on
automations/s2c-vendo(@ af8f2d0), so this diff is only the S3 lane— e2e suites, the CI leg, the public docs, demo-bank. Do not merge ahead of the
lanes below it.
A note on the docs conflict ahead
mainmoved during this build (a507b92 → af2d337) and retiredE-SCHED-001. I reverted this lane's edits to that page so main's tombstoneapplies cleanly. One correction still needs folding into it by whoever owns it:
the tick door verifies BOTH credentials against
VENDO_TICK_SECRET, so aCloud-only deployment needs the secret too. That correction does ship, in the
three automations pages this lane owns.
Summary by cubic
Repoints automations from app-with-triggers to first‑class automation records across tests, docs, and demo, and gates the live‑agentic CI leg. Old: automations were triggers on apps and ran in Cloud. New: automations are records that run in your process; Cloud only wakes via
POST /api/vendo/tick. Side effects: per‑record HMAC for webhooks, enable/capture and run ledger bind to record IDs, and docs reflect the new model.ANTHROPIC_API_KEYto the automations CI leg only on pushes tomain(skipped for PRs/merge groups)./backend/automatefor.on(), rewrites automations and Cloud pages around records, fixesGET /automationsshape, and updates links.automations-e2e,integration, andredteamharnesses and suites now create, enable, and run records; three new suites cover code authoring (agent.on), chat authoring (vendo_automate), and missing/duplicate runners; external webhooks verify per record with redacted keys.owneron seeded runs and movesaway-drilldist dir to a sibling to avoid build wipes.Rollout and migration
VENDO_TICK_SECRETin all deployments. Cloud’s signed heartbeat and any bearer credential are verified against it; without it, ticks are refused.GET /automations: it returns redactedAutomationRecord[](nopendingGrantsorgrantSetId).list/getredact them.Known product issues not changed by this PR (tests document them):
runs.list({ owner|agent })500s on unknown ref keys.vendo.jsonmanifest schedules cannot be armed due to consent-surface mismatch.pending-approvalinstead ofok.Written for commit ee87fdd. Summary will update on new commits.