negative control: promote must delete pack pointers absent from rollback target RUN v3.1.3 ❯ tests/promote.test.ts (10 tests | 1 failed | 9 skipped) 50ms ↓ promote > refuses an absent dev pointer with RFC 9457 exit 2 ↓ promote > refuses a malformed --to digest with RFC 9457 exit 2 ↓ promote > refuses an absent --to manifest with RFC 9457 exit 2 ↓ promote > refuses an incomplete closure with RFC 9457 exit 2 ↓ promote > reports corrupt store bytes with RFC 9457 exit 4 ↓ promote > reports a malformed dev pointer as pointer-shape exit 4 ↓ promote > verifies, writes prod pack pointers then manifest, and copies no bytes ↓ promote > rolls prod back with --to after verifying the earlier manifest × promote > reconciles a two-pack prod pointer set when rolling back to one pack 50ms → expected { …(3) } to be null ↓ promote > ships CLI JSON success and RFC 9457 refusal output ⎯⎯⎯⎯⎯⎯⎯ Failed Tests 1 ⎯⎯⎯⎯⎯⎯⎯ FAIL tests/promote.test.ts > promote > reconciles a two-pack prod pointer set when rolling back to one pack AssertionError: expected { …(3) } to be null - Expected: null + Received: { "by": { "model": "test-model", "role": "builder", "run": "test-run", }, "manifest": "e1f7ba820a3076c29f2d3bf74a596172d917782016408b54903156facb301107", "published_at": "2026-09-02T17:35:38.884Z", } ❯ tests/promote.test.ts:163:67 161| await promote(options({ to: first.report.assetManifest })); 162| 163| expect(await readPackPointer(store, "prod", secondPack.name)).toBe… | ^ 164| expect(await readPackPointer(store, "prod", first.pack.name)).not.… 165| expect(await verify({ store, reader: store, env: "prod" })).toMatc… ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[1/1]⎯ Test Files 1 failed (1) Tests 1 failed | 9 skipped (10) Start at 13:35:37 Duration 986ms (transform 54ms, setup 0ms, collect 64ms, tests 50ms, environment 0ms, prepare 28ms) negative control: verify must report a pack pointer absent from the current manifest RUN v3.1.3 ❯ tests/verify.test.ts (9 tests | 1 failed | 8 skipped) 30ms ↓ verify > walks the pointer's closure and reports every object present, re-hashed ↓ verify > names exactly the blob removed from a closure ↓ verify > reports a child missing from an octet-stream-labelled JSON record ↓ verify > reports bytes declared JSON that do not parse as JSON ↓ verify > names a blob whose bytes no longer hash to its key as mismatched ↓ verify > reports a pack pointer that names another manifest than the Asset Manifest as drift × verify > reports an extraneous prod pack pointer absent from the current Asset Manifest 30ms → expected true to be false // Object.is equality ↓ verify > reports a missing pointer for an environment never published ↓ verify > re-hashes into a temp dir it removes, and writes nothing under ~/.aa2/cache ⎯⎯⎯⎯⎯⎯⎯ Failed Tests 1 ⎯⎯⎯⎯⎯⎯⎯ FAIL tests/verify.test.ts > verify > reports an extraneous prod pack pointer absent from the current Asset Manifest AssertionError: expected true to be false // Object.is equality - Expected + Received - false + true ❯ tests/verify.test.ts:148:23 146| const report = await verify({ store, reader: store, env: "prod" }); 147| 148| expect(report.ok).toBe(false); | ^ 149| expect(report.extraneous).toEqual([key]); 150| expect(report.drift).toEqual([]); ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[1/1]⎯ Test Files 1 failed (1) Tests 1 failed | 8 skipped (9) Start at 13:35:54 Duration 932ms (transform 49ms, setup 0ms, collect 56ms, tests 30ms, environment 0ms, prepare 26ms) negative control: deletePointer must refuse immutable keys outside env/ RUN v3.1.3 ❯ tests/fs-store.test.ts (10 tests | 1 failed | 9 skipped) 4ms ↓ fs store > defaults to the one store root and takes bucket and prefix as a test seam ↓ fs store > head is null for an absent key and get is null for an absent key ↓ fs store > putIfAbsent creates, then reports exists for identical bytes (idempotent) ↓ fs store > putIfAbsent takes a file path and uploads it as one object ↓ fs store > refuses a second put with different bytes under the same key ↓ fs store > refuses a put whose bytes do not hash to the declared sha256 × fs store > refuses putIfAbsent under env/ and putPointer outside env/ 4ms → promise resolved "undefined" instead of rejecting ↓ fs store > deletes pointers idempotently and no other kind of key ↓ fs store > putPointer overwrites, the only kind of key that may ↓ fs store > lists keys under a prefix, relative to the store prefix, without metadata files ⎯⎯⎯⎯⎯⎯⎯ Failed Tests 1 ⎯⎯⎯⎯⎯⎯⎯ FAIL tests/fs-store.test.ts > fs store > refuses putIfAbsent under env/ and putPointer outside env/ AssertionError: promise resolved "undefined" instead of rejecting - Expected: Error { "message": "rejected promise", } + Received: undefined ❯ tests/fs-store.test.ts:108:50 106| ).rejects.toThrow(Problem); 107| await expect(store.putPointer(blobKey(dA), { manifest: dA })).reje… 108| await expect(store.deletePointer(blobKey(dA))).rejects.toThrow(Pro… | ^ 109| }); 110| ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[1/1]⎯ Test Files 1 failed (1) Tests 1 failed | 9 skipped (10) Start at 13:36:11 Duration 1.37s (transform 32ms, setup 0ms, collect 30ms, tests 4ms, environment 0ms, prepare 35ms) negative control: extraneous pack pointers need their own RFC 9457 problem code RUN v3.1.3 ❯ tests/cli.test.ts (11 tests | 1 failed | 10 skipped) 166ms ↓ aa-asset CLI > ships as dist/cli/aa-asset.js, the package bin ↓ aa-asset CLI > defaults to the prod read URL and AA_ENV=dev selects the dev read URL ↓ aa-asset CLI > requires all four scoped R2 variables by name ↓ aa-asset CLI > exits 2 on usage with an RFC 9457 problem on stderr ↓ aa-asset CLI > publishes to the fs store with exit 0 and a JSON report on stdout ↓ aa-asset CLI > verifies dev from a separate process with exit 0 and touches no cache ↓ aa-asset CLI > exits 4 with pointer-shape when the fs store holds a malformed pointer ↓ aa-asset CLI > exits 2 with code digest-mismatch when a closure member lies about its digest ↓ aa-asset CLI > exits 4 with code verify-gap naming the removed blob × aa-asset CLI > exits 4 with code verify-extraneous for an unreferenced pack pointer 160ms → expected 'verify-gap' to be 'verify-extraneous' // Object.is equality ↓ aa-asset CLI > refuses the R2 store when the credentials are absent, naming them, never their values ⎯⎯⎯⎯⎯⎯⎯ Failed Tests 1 ⎯⎯⎯⎯⎯⎯⎯ FAIL tests/cli.test.ts > aa-asset CLI > exits 4 with code verify-extraneous for an unreferenced pack pointer AssertionError: expected 'verify-gap' to be 'verify-extraneous' // Object.is equality Expected: "verify-extraneous" Received: "verify-gap" ❯ tests/cli.test.ts:205:36 203| 204| expect(r.code).toBe(4); 205| expect(problem(r.stderr).code).toBe("verify-extraneous"); | ^ 206| expect(JSON.parse(r.stdout.trim().split("\n").at(-1) ?? "").extran… 207| }); ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[1/1]⎯ Test Files 1 failed (1) Tests 1 failed | 10 skipped (11) Start at 13:36:29 Duration 1.10s (transform 36ms, setup 0ms, collect 87ms, tests 166ms, environment 0ms, prepare 33ms) negative control: documented emergency rollback must remove extraneous prod pack pointers RUN v3.1.3 ❯ tests/runbook.test.ts (1 test | 1 failed) 223ms × store runbook > executes the documented --fs emergency rollback without pointer drift 223ms → {"type":"https://agentarmies.io/problems/verify-extraneous","title":"The prod pointer set contains pack pointers absent from its Asset Manifest","detail":"1 gap(s): extraneous env/prod/pack/materials-austin-barton-hills.json","code":"verify-extraneous","hint":"Re-run `aa-asset verify` to confirm, then follow docs/runbooks/store.md (a verify gap): re-publish the pack that carries the object, or move the pointer back.","exit":4,"instance":"env/prod/manifest.json"} : expected 4 to be +0 // Object.is equality ⎯⎯⎯⎯⎯⎯⎯ Failed Tests 1 ⎯⎯⎯⎯⎯⎯⎯ FAIL tests/runbook.test.ts > store runbook > executes the documented --fs emergency rollback without pointer drift AssertionError: {"type":"https://agentarmies.io/problems/verify-extraneous","title":"The prod pointer set contains pack pointers absent from its Asset Manifest","detail":"1 gap(s): extraneous env/prod/pack/materials-austin-barton-hills.json","code":"verify-extraneous","hint":"Re-run `aa-asset verify` to confirm, then follow docs/runbooks/store.md (a verify gap): re-publish the pack that carries the object, or move the pointer back.","exit":4,"instance":"env/prod/manifest.json"} : expected 4 to be +0 // Object.is equality - Expected + Received - 0 + 4 ❯ tests/runbook.test.ts:82:36 80| }); 81| 82| expect(run.status, run.stderr).toBe(0); | ^ 83| expect((await readPointer(store, "prod"))?.manifest).toBe(first.as… 84| expect(await readPackPointer(store, "prod", secondPack.name)).toBe… ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[1/1]⎯ Test Files 1 failed (1) Tests 1 failed (1) Start at 13:38:44 Duration 1.10s (transform 43ms, setup 0ms, collect 49ms, tests 223ms, environment 0ms, prepare 23ms) negative control: manifest pointer must remain last after pack-pointer deletion RUN v3.1.3 ❯ tests/promote.test.ts (10 tests | 1 failed | 9 skipped) 52ms ↓ promote > refuses an absent dev pointer with RFC 9457 exit 2 ↓ promote > refuses a malformed --to digest with RFC 9457 exit 2 ↓ promote > refuses an absent --to manifest with RFC 9457 exit 2 ↓ promote > refuses an incomplete closure with RFC 9457 exit 2 ↓ promote > reports corrupt store bytes with RFC 9457 exit 4 ↓ promote > reports a malformed dev pointer as pointer-shape exit 4 ↓ promote > verifies, writes prod pack pointers then manifest, and copies no bytes ↓ promote > rolls prod back with --to after verifying the earlier manifest × promote > reconciles a two-pack prod pointer set when rolling back to one pack 52ms → expected [ …(3) ] to deeply equal [ …(3) ] ↓ promote > ships CLI JSON success and RFC 9457 refusal output ⎯⎯⎯⎯⎯⎯⎯ Failed Tests 1 ⎯⎯⎯⎯⎯⎯⎯ FAIL tests/promote.test.ts > promote > reconciles a two-pack prod pointer set when rolling back to one pack AssertionError: expected [ …(3) ] to deeply equal [ …(3) ] - Expected + Received [ "put env/prod/pack/veg-austin-barton-hills.json", - "delete env/prod/pack/materials-austin-barton-hills.json", "put env/prod/manifest.json", + "delete env/prod/pack/materials-austin-barton-hills.json", ] ❯ tests/promote.test.ts:188:24 186| extraneous: [], 187| }); 188| expect(operations).toEqual([ | ^ 189| `put env/prod/pack/${first.pack.name}.json`, 190| `delete env/prod/pack/${secondPack.name}.json`, ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[1/1]⎯ Test Files 1 failed (1) Tests 1 failed | 9 skipped (10) Start at 13:39:20 Duration 927ms (transform 49ms, setup 0ms, collect 61ms, tests 52ms, environment 0ms, prepare 25ms)