From ddddcbb7bb09b187a478b6e176982dd4523c7275 Mon Sep 17 00:00:00 2001 From: etvjay Date: Mon, 24 Aug 2026 16:50:46 +0100 Subject: [PATCH 001/116] ebi: initialize Sibyl hackathon evaluation root --- hackathon/sibyl/README.md | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 hackathon/sibyl/README.md diff --git a/hackathon/sibyl/README.md b/hackathon/sibyl/README.md new file mode 100644 index 0000000..381a182 --- /dev/null +++ b/hackathon/sibyl/README.md @@ -0,0 +1,34 @@ +# Engram × Sibyl — EBI Instance + +Status: `READY_TO_RESEARCH` + +This directory is the Evaluated Build Instantiation (EBI) wrapper for adapting Engram to the Sibyl Labs Hackathon without changing Engram's canonical product semantics. + +## Frozen candidate thesis + +**Engram is execution-memory infrastructure: prior execution experience becomes bounded operational memory that can legitimately change later autonomous behavior.** + +For this hackathon deployment, **Sibyl is the load-bearing persistence and recall substrate**. Engram retains the semantics for admission, eligibility, influence, provenance, invalidation, competing memory and counterfactual evaluation. + +```text +execution event + -> Engram episode/evidence semantics + -> Sibyl persistence + -> fresh-session Sibyl recall + -> Engram eligibility/influence policy + -> application decision + -> changed action/result + -> outcome/provenance +``` + +## Non-negotiable deletion test + +If Sibyl persistence/recall is removed, the submitted build must lose the decision-critical cross-session execution memory required to produce the claimed changed behavior. + +A CockroachDB fallback that preserves equivalent decision-critical memory in the judged path is therefore **not allowed** for the hackathon profile. + +## EBI state machine + +`READY_TO_RESEARCH -> READY_TO_BUILD -> READY_FOR_LIVE_PRESSURE -> READY_FOR_SUBMISSION -> SUBMISSION_FROZEN` + +No optimistic promotion. Evidence state must justify every transition. From ea023f876f7b72c8947988f36247aef0e70e2175 Mon Sep 17 00:00:00 2001 From: etvjay Date: Mon, 24 Aug 2026 16:51:02 +0100 Subject: [PATCH 002/116] ebi: freeze Sibyl evaluation truth --- hackathon/sibyl/EVALUATION_TRUTH.md | 58 +++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 hackathon/sibyl/EVALUATION_TRUTH.md diff --git a/hackathon/sibyl/EVALUATION_TRUTH.md b/hackathon/sibyl/EVALUATION_TRUTH.md new file mode 100644 index 0000000..a63d509 --- /dev/null +++ b/hackathon/sibyl/EVALUATION_TRUTH.md @@ -0,0 +1,58 @@ +# Evaluation Truth — Sibyl Labs Hackathon + +Verified: 2026-08-24 +Canonical sources: https://hack.sibyllabs.org/ ; /rules ; /submissions ; Sibyl docs. + +## Program +- Registration: Aug 16–31, 2026, closes 23:59 UTC. +- Build window: Sep 1–10, 2026. +- Judging: Sep 11–12. +- Winners: Sep 13–15. +- Prize pool: $10,000 USDC across top five. + +## Eligibility gate — PUBLISHED_HARD +Sibyl Memory must be load-bearing. Judges apply the deletion test: remove Sibyl Memory; if the product still does what it claims, it fails. + +Required proof: +1. persist context that matters; +2. recall it in a genuinely fresh session; +3. use it to change a decision, action, or result; +4. cold-start recall shown in one continuous unedited demo segment with on-screen timestamp or commit hash; +5. README points judges to critical write/read calls discoverable in under two minutes. + +## Rubric — PUBLISHED_SCORING +- Memory load-bearing / sophistication: 40 +- Innovation & originality: 25 +- Technical execution: 20 +- Pitch & presentation: 15 +- PMF bonus: up to +10, only with publicly verifiable evidence. + +Top memory band favors coordination and dynamic-storage patterns over trivial notepad recall. + +## Partner multiplier — PUBLISHED_BONUS +- 0 verified stacks: ×1.00 +- 1 verified stack: ×1.15 +- 2 verified stacks: ×1.25 cap + +Base qualifies when product deployment exists and the demo exercises a real onchain action such as wallet operation, x402 payment, B20 read or contract interaction. + +Virtuals qualifies when the demo exercises an ACP job, registered/transacting agent or another Virtuals-native integration. + +Decorative/import-only integrations do not count. + +## Submission — PUBLISHED_HARD +- Public GitHub repo under MIT or Apache-2.0 with real commit history. +- 2–5 minute demo. +- README with setup/run instructions, load-bearing memory explanation, partner stack locations, 'how memory made this possible', and Prior Work declaration. +- Two public posts: demo video + at least one build log, tagging Sibyl and claimed partners. +- Submission through registered team's private build page before Sep 10, 23:59 UTC. + +## Engram-specific conservative rule +The judged hackathon profile must not contain an equivalent CockroachDB decision-memory fallback. CockroachDB may remain part of canonical Engram outside this profile, but the submitted Sibyl path must fail the load-bearing function when Sibyl is removed. + +## Unknowns +- Exact Sibyl package/API version to lock at implementation start. +- Exact partner workshop guidance that may change preferred Base/Virtuals integration shape. +- Whether an existing repo with substantial prior work is advantaged/disadvantaged beyond mandatory Prior Work declaration; no penalty is published. + +Re-run this truth freeze before `READY_FOR_SUBMISSION`. From bf95d458460b2c623cea79c60dd60e2a31b3b70b Mon Sep 17 00:00:00 2001 From: etvjay Date: Mon, 24 Aug 2026 16:51:12 +0100 Subject: [PATCH 003/116] ebi: add evaluator model --- hackathon/sibyl/JUDGE_MODEL.md | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 hackathon/sibyl/JUDGE_MODEL.md diff --git a/hackathon/sibyl/JUDGE_MODEL.md b/hackathon/sibyl/JUDGE_MODEL.md new file mode 100644 index 0000000..8f1e213 --- /dev/null +++ b/hackathon/sibyl/JUDGE_MODEL.md @@ -0,0 +1,34 @@ +# Judge Model + +## Judge questions Engram must answer fast + +1. What is Engram? +2. Why is Sibyl necessary rather than decorative? +3. What exact memory was persisted? +4. Is the second run genuinely fresh? +5. What changed because of recalled memory? +6. Can I delete Sibyl and make the claimed behavior fail? +7. Is this more than generic RAG/chat memory? +8. Can I trace source execution -> memory -> recall -> influence -> changed action? +9. Does it survive a second comparable run? +10. Are Base/Virtuals doing product work or sponsor theater? + +## Evaluator personas + +### Cold product evaluator +Needs a 20-second explanation: Engram turns prior execution experience into operational memory that changes future autonomous behavior. + +### Memory skeptic +Attempts deletion test; compares fresh-session run with and without Sibyl; rejects retrieval without behavioral influence. + +### Evidence skeptic +Checks provenance, commit hash/timestamp, decision record, memory write/read paths and counterfactual baseline. + +### Adversarial operator +Injects stale, incompatible, contradictory or wrong-provenance memory and expects Engram policy to block or expose it. + +### Partner specialist +Requires protocol-native evidence for each claimed partner and checks it is exercised during the demo. + +## Winning evaluator moment +A fresh process starts with no in-process state, recalls a prior failed execution through Sibyl, Engram marks the memory eligible, the application selects a different action than the memory-free control, and the trace shows exactly why. From f4407e066fbd1d8f8d85d22747d27df93f036092 Mon Sep 17 00:00:00 2001 From: etvjay Date: Mon, 24 Aug 2026 16:51:27 +0100 Subject: [PATCH 004/116] ebi: define Engram Sibyl architecture delta --- hackathon/sibyl/ARCHITECTURE.md | 87 +++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 hackathon/sibyl/ARCHITECTURE.md diff --git a/hackathon/sibyl/ARCHITECTURE.md b/hackathon/sibyl/ARCHITECTURE.md new file mode 100644 index 0000000..a9f0a18 --- /dev/null +++ b/hackathon/sibyl/ARCHITECTURE.md @@ -0,0 +1,87 @@ +# Architecture — Engram × Sibyl Hackathon Profile + +## Architectural decision +Do **not** rewrite canonical Engram around Sibyl. Introduce a hackathon storage profile where Sibyl is the sole decision-critical persistence/recall substrate. + +```text +Application / Agent + | + v +Engram Runtime +- ExecutionEpisode +- admission +- eligibility +- influence +- provenance +- invalidation/expiry +- counterfactual evaluation + | + v +SibylMemoryStore +- persist execution-derived memory +- retrieve across process/session boundary +- preserve identifiers/metadata needed for provenance + | + v +fresh-session recall + | + v +application decision + observable changed action +``` + +## Boundary + +### Engram owns +- what qualifies as an execution episode; +- when an observation may become operational memory; +- whether recalled memory is eligible to influence action; +- explicit influence recording; +- provenance from source execution to later decision; +- counterfactual comparison; +- expiry/invalidation/conflict semantics. + +### Sibyl owns in the judged profile +- durable persistence of decision-critical memories; +- cross-session retrieval; +- historical state required for Engram recall. + +### Application owns +- final business/action decision; +- external action execution. + +## Forbidden architecture + +```text +Engram -> CockroachDB canonical memory + \-> Sibyl mirror +``` + +If CockroachDB can independently produce equivalent fresh-session behavior, Sibyl is decorative and the gate is at risk. + +## Adapter contract (proposed) + +```ts +interface ExecutionMemoryStore { + persist(memory: OperationalMemory): Promise + recall(query: RecallQuery): Promise + get(memoryId: string): Promise + invalidate(memoryId: string, reason: string): Promise +} +``` + +`SibylMemoryStore` implements this contract for the hackathon profile. + +## Minimum causal acceptance +1. Run A executes with no relevant memory. +2. Failure/recovery evidence is observed. +3. Engram admits an operational memory and persists it to Sibyl. +4. Process terminates. +5. Fresh Run B starts. +6. Sibyl recalls the memory. +7. Engram eligibility permits influence. +8. Application records memory influence and chooses a different action. +9. Outcome and trace are recorded. +10. A no-memory control demonstrates the action difference. + +## Production boundary +This profile proves storage portability and load-bearing cross-session behavior. It does not replace the canonical Engram production persistence decision unless separately adopted after the hackathon. From 93af73f88846fdc3bc2d89819c5166438783be05 Mon Sep 17 00:00:00 2001 From: etvjay Date: Mon, 24 Aug 2026 16:51:37 +0100 Subject: [PATCH 005/116] ebi: add evaluator-critical build order --- hackathon/sibyl/BUILD_ORDER.md | 38 ++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 hackathon/sibyl/BUILD_ORDER.md diff --git a/hackathon/sibyl/BUILD_ORDER.md b/hackathon/sibyl/BUILD_ORDER.md new file mode 100644 index 0000000..5ed9639 --- /dev/null +++ b/hackathon/sibyl/BUILD_ORDER.md @@ -0,0 +1,38 @@ +# Build Order + +Build order follows evaluator-critical dependency, not architectural elegance. + +## P0 — Gate survival +1. Probe and lock current Sibyl API/package behavior. +2. Implement `ExecutionMemoryStore` abstraction only where required. +3. Implement `SibylMemoryStore`. +4. Route hackathon profile's decision-critical persist/recall exclusively through Sibyl. +5. Prove process-boundary fresh-session recall. +6. Implement deletion-test mode that disables/removes Sibyl and demonstrates core degradation/failure. +7. Preserve Engram source-execution -> memory -> recall -> influence provenance. + +## P1 — Score maximization +8. Add paired no-memory control versus Sibyl-memory execution. +9. Add stale/incompatible/conflicting memory negative tests. +10. Add one compelling real-world scenario beyond route failure if time allows: agent-provider relationship continuity is preferred. +11. Make trace/evidence visible to a cold evaluator. + +## P2 — Partner multiplier +12. Evaluate Base integration only if it produces a real economic/onchain consequence from recalled memory. +13. Evaluate Virtuals only if an ACP/native interaction creates or consumes decision-relevant experience. +14. Prefer one native partner that strengthens the product over two decorative integrations. + +## P3 — Submission +15. README Prior Work declaration and critical memory call map. +16. 2–5 minute continuous fresh-session demo choreography. +17. Build-log post + demo post. +18. Cold evaluator run. +19. Re-run truth freeze. +20. Freeze submission. + +## Explicitly deferred +- replacing canonical CockroachDB architecture; +- registry publication work unrelated to judging; +- broad framework integrations; +- production multi-tenant auth upgrades unless necessary for public demo safety; +- partner integrations without a causal role in the core scenario. From 85c52ecda31238f57b9b9b26b362cdb3002931da Mon Sep 17 00:00:00 2001 From: etvjay Date: Mon, 24 Aug 2026 16:51:55 +0100 Subject: [PATCH 006/116] ebi: add atomic requirement manifest --- hackathon/sibyl/requirements/requirements.json | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 hackathon/sibyl/requirements/requirements.json diff --git a/hackathon/sibyl/requirements/requirements.json b/hackathon/sibyl/requirements/requirements.json new file mode 100644 index 0000000..77ad274 --- /dev/null +++ b/hackathon/sibyl/requirements/requirements.json @@ -0,0 +1,18 @@ +{ + "verified_at": "2026-08-24", + "status": "READY_TO_RESEARCH", + "requirements": [ + {"id":"SIBYL-GATE-001","track":"main","class":"PUBLISHED_HARD","severity":"VETO","description":"Sibyl Memory is load-bearing; deleting it breaks or materially degrades the core function.","check":"run deletion mutation and compare claimed behavior","evidence_required":"failing/degraded no-Sibyl run plus passing Sibyl run","status":"UNVERIFIED"}, + {"id":"SIBYL-GATE-002","track":"main","class":"PUBLISHED_HARD","severity":"VETO","description":"Fresh session recalls earlier persisted state.","check":"terminate process/session, restart clean, recall prior memory","evidence_required":"continuous demo segment with timestamp or commit hash","status":"UNVERIFIED"}, + {"id":"SIBYL-GATE-003","track":"main","class":"PUBLISHED_HARD","severity":"VETO","description":"Recalled memory changes a decision, action, or result.","check":"paired memory vs no-memory decision comparison","evidence_required":"decision trace and observable action delta","status":"UNVERIFIED"}, + {"id":"SIBYL-GATE-004","track":"main","class":"PUBLISHED_HARD","severity":"HIGH","description":"README exposes critical memory write/read paths in under two minutes.","check":"cold reviewer repo navigation test","evidence_required":"README call map","status":"UNVERIFIED"}, + {"id":"SCORE-MEM-001","track":"main","class":"PUBLISHED_SCORING","severity":"HIGH","description":"Memory use is sophisticated enough for top band; coordination/dynamic-state behavior preferred.","check":"judge-model scorecard","evidence_required":"non-trivial stateful scenario plus adversarial memory handling","status":"UNVERIFIED"}, + {"id":"SCORE-TECH-001","track":"main","class":"PUBLISHED_SCORING","severity":"HIGH","description":"Build is clean, robust and survives a second run/curious judge.","check":"repeatability and negative test suite","evidence_required":"test report and second-run evidence","status":"UNVERIFIED"}, + {"id":"SUBMIT-001","track":"submission","class":"PUBLISHED_HARD","severity":"VETO","description":"Public MIT/Apache-2.0 repo with real commit history.","check":"repository inspection","evidence_required":"public repo/license/commits","status":"LOCAL_PASS"}, + {"id":"SUBMIT-002","track":"submission","class":"PUBLISHED_HARD","severity":"VETO","description":"2–5 minute demo includes fresh-session recall.","check":"video review","evidence_required":"public video","status":"UNVERIFIED"}, + {"id":"SUBMIT-003","track":"submission","class":"PUBLISHED_HARD","severity":"VETO","description":"README includes Prior Work declaration and required memory/partner notes.","check":"README audit","evidence_required":"merged README","status":"UNVERIFIED"}, + {"id":"SUBMIT-004","track":"submission","class":"PUBLISHED_HARD","severity":"VETO","description":"Two public posts: demo and build log, tagging required accounts.","check":"public URL verification","evidence_required":"two public post URLs","status":"UNVERIFIED"}, + {"id":"BASE-001","track":"base","class":"PUBLISHED_BONUS","severity":"OPTIONAL","description":"Executed Base action shown doing real product work.","check":"protocol-native receipt/explorer evidence","evidence_required":"wallet/x402/B20/contract evidence in demo","status":"UNVERIFIED"}, + {"id":"VIRTUALS-001","track":"virtuals","class":"PUBLISHED_BONUS","severity":"OPTIONAL","description":"Virtuals-native integration is exercised in the demo.","check":"ACP/agent native evidence","evidence_required":"job/transaction/native receipt","status":"UNVERIFIED"} + ] +} From 684aa140e9308a36788d8824b6000c23c5c35c85 Mon Sep 17 00:00:00 2001 From: etvjay Date: Mon, 24 Aug 2026 16:52:09 +0100 Subject: [PATCH 007/116] ebi: add Sibyl hackathon audit gates --- hackathon/sibyl/audits.md | 43 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 hackathon/sibyl/audits.md diff --git a/hackathon/sibyl/audits.md b/hackathon/sibyl/audits.md new file mode 100644 index 0000000..ef75bfe --- /dev/null +++ b/hackathon/sibyl/audits.md @@ -0,0 +1,43 @@ +# Engram × Sibyl Audit Gates + +## Release vetoes +- [ ] Sibyl decision-critical persistence is implemented. +- [ ] Fresh process/session recalls earlier state through Sibyl. +- [ ] Recalled memory changes a decision/action/result. +- [ ] No-Sibyl mutation breaks or materially degrades the claimed core behavior. +- [ ] No equivalent CockroachDB fallback preserves the judged memory behavior. +- [ ] Source execution -> admitted memory -> recall -> influence -> changed action is reconstructable. +- [ ] Continuous demo segment proves cold start with timestamp or commit hash. +- [ ] README identifies write/read calls and Prior Work. + +## Engram semantic integrity +- [ ] Engram remains decision-support infrastructure; application retains final action authority. +- [ ] Retrieval is not labeled influence unless a decision explicitly references memory. +- [ ] Later success is not automatically labeled memory benefit. +- [ ] Wrong-provenance recall is rejected or exposed. +- [ ] Stale/incompatible memory is blocked before influence. +- [ ] Contradictory memories are not silently overwritten. +- [ ] Counterfactual/no-memory control exists for flagship scenario. + +## Technical execution +- [ ] Build passes from clean checkout. +- [ ] Test suite passes twice. +- [ ] Fresh-session test uses no hidden in-process state. +- [ ] Sibyl failure is legible; no fake fallback. +- [ ] Secrets are absent from client bundles/repo/logs. +- [ ] Public demo surface exposes evidence close to claims. + +## Partner gates +- [ ] Base is claimed only if a real Base action is exercised. +- [ ] Virtuals is claimed only if a native Virtuals interaction is exercised. +- [ ] Partner integration changes/serves actual product behavior. +- [ ] Protocol-native evidence exists independently of Engram UI. + +## Submission +- [ ] Public MIT/Apache repo. +- [ ] 2–5 minute demo. +- [ ] Two public posts. +- [ ] Private build page marked ready before Sep 10 23:59 UTC. +- [ ] Truth freeze revalidated immediately before submission. + +Current release status: `READY_TO_RESEARCH`. From f28fed37c925b05893ee7f86c312dbef4b965bbf Mon Sep 17 00:00:00 2001 From: etvjay Date: Mon, 24 Aug 2026 16:52:21 +0100 Subject: [PATCH 008/116] ebi: route Sibyl build through foundry ensemble --- hackathon/sibyl/foundry/FOUNDRY_MATRIX.md | 27 +++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 hackathon/sibyl/foundry/FOUNDRY_MATRIX.md diff --git a/hackathon/sibyl/foundry/FOUNDRY_MATRIX.md b/hackathon/sibyl/foundry/FOUNDRY_MATRIX.md new file mode 100644 index 0000000..0b63c99 --- /dev/null +++ b/hackathon/sibyl/foundry/FOUNDRY_MATRIX.md @@ -0,0 +1,27 @@ +# Foundry Matrix + +| Foundry | Activation | Required output for Engram × Sibyl | +|---|---|---| +| Research | REQUIRED | live rules/docs truth, API/package lock, contradictions, unknowns | +| Opportunity | REQUIRED | score-maximizing work vs decorative work; partner ROI | +| Product | REQUIRED | exact user/job, product promise, MVP boundary, PMF evidence path | +| Systems | REQUIRED | storage adapter, critical path, state machine, failure/recovery, provenance | +| Interface | REQUIRED | cold evaluator IA, proof discoverability, demo comprehension | +| Experiment | REQUIRED | paired no-memory/memory baseline, deletion mutation, stale/conflict tests | +| QA / Verification | REQUIRED | evidence promotion, release vetoes, repeatability | +| Demo | REQUIRED | 2–5 minute evidence choreography; continuous cold-start beat | +| Learning | REQUIRED POST-RUN | preserve evaluator misses/failures as regression corpus | +| Sound | OPTIONAL | narration only if it improves clarity without hiding evidence | +| Onchain Systems Engineering | CONDITIONAL | activate before Base/x402/wallet/contract execution | + +## Orchestration order + +`Research -> Opportunity -> Product -> Systems -> Interface -> Experiment -> QA -> Demo -> observed evaluator run -> Learning` + +Parallelization is allowed only when dependencies are explicit. + +## Current routing decisions +- Sibyl API/tooling verification blocks implementation architecture details. +- Product and Systems may refine the flagship scenario together after truth/toolchain lock. +- Partner work is downstream of passing the load-bearing deletion test. +- Demo work may stage only evidence already promoted by QA. From bbd5c538aba531af48dc138ed5e91f16fcef1943 Mon Sep 17 00:00:00 2001 From: etvjay Date: Mon, 24 Aug 2026 16:52:32 +0100 Subject: [PATCH 009/116] ebi: add live pressure plan --- hackathon/sibyl/LIVE_PRESSURE_PLAN.md | 47 +++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 hackathon/sibyl/LIVE_PRESSURE_PLAN.md diff --git a/hackathon/sibyl/LIVE_PRESSURE_PLAN.md b/hackathon/sibyl/LIVE_PRESSURE_PLAN.md new file mode 100644 index 0000000..4272c63 --- /dev/null +++ b/hackathon/sibyl/LIVE_PRESSURE_PLAN.md @@ -0,0 +1,47 @@ +# Live Pressure Plan + +## P0 mutations — must detect failure + +1. **Delete/disable Sibyl write** + - Expected: no future cross-session operational memory. + - Gate: core flagship behavior cannot reproduce. + +2. **Delete/disable Sibyl recall** + - Expected: fresh session behaves like no-memory control. + - Gate: changed-action proof disappears. + +3. **Kill process between runs** + - Expected: Run B still recalls through Sibyl. + - Detects accidental in-process/session caching. + +4. **Inject stale/incompatible memory** + - Expected: Engram eligibility blocks influence. + +5. **Inject wrong-provenance memory** + - Expected: rejected or explicitly surfaced as invalid provenance. + +6. **Inject contradictory memories** + - Expected: conflict remains visible; no silent overwrite/adjudication. + +7. **Repeat flagship scenario twice** + - Expected: deterministic invariants remain stable; no one-shot demo behavior. + +## Evaluator runs + +### Cold evaluator +Clone, install, run, locate write/read paths, execute flagship scenario without guidance. + +### Memory skeptic +Run memory-enabled, no-memory control, and deletion mutation; compare decisions and outputs. + +### Evidence skeptic +Reconstruct source execution -> memory ID -> recalled candidate -> influence record -> changed action. + +### Dependency degradation +Make Sibyl unavailable after prior persistence; product must fail legibly rather than silently switch to equivalent hidden persistence. + +### Partner specialist +If Base/Virtuals claimed, verify protocol-native transaction/job evidence and confirm it serves the actual remembered decision. + +## Promotion rule +`LOCAL_PASS` cannot become `LIVE_PASS` from screenshots or simulated fixtures. Public/evaluator claims require observed public evidence. From af5a723498c1603bcc52cc32a4d7b583256f61e5 Mon Sep 17 00:00:00 2001 From: etvjay Date: Mon, 24 Aug 2026 16:52:42 +0100 Subject: [PATCH 010/116] ebi: add development environment contract --- hackathon/sibyl/DEVELOPMENT_ENVIRONMENT.md | 43 ++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 hackathon/sibyl/DEVELOPMENT_ENVIRONMENT.md diff --git a/hackathon/sibyl/DEVELOPMENT_ENVIRONMENT.md b/hackathon/sibyl/DEVELOPMENT_ENVIRONMENT.md new file mode 100644 index 0000000..0eeed6c --- /dev/null +++ b/hackathon/sibyl/DEVELOPMENT_ENVIRONMENT.md @@ -0,0 +1,43 @@ +# Development Environment + +Status: `UNPROBED` for Sibyl integration. + +## Existing Engram baseline +- Node.js 22 +- npm +- TypeScript monorepo +- canonical checks: `npm install` then `npm run check` + +## Hackathon profile target +Proposed environment flag: + +```bash +ENGRAM_MEMORY_PROFILE=sibyl +``` + +The exact Sibyl package/API/env configuration is intentionally **not frozen yet**. Research/toolchain probing must verify current first-party docs before implementation. + +## Required local commands after adapter implementation + +```bash +npm install +npm run check +npm run test:sibyl +npm run demo:sibyl:seed +# terminate process/session +npm run demo:sibyl:recall +npm run demo:sibyl:no-memory-control +npm run test:sibyl:deletion +``` + +Command names above are target interfaces, not evidence that they currently exist. + +## Toolchain probe gate +Before `READY_TO_BUILD`: +- [ ] current Sibyl SDK/package/API verified from first-party docs; +- [ ] credentials/config path understood; +- [ ] persistence survives a clean process restart; +- [ ] write/read semantics can preserve Engram provenance IDs/metadata; +- [ ] local golden fixture passes; +- [ ] deletion mutation is implementable; +- [ ] no secrets enter frontend/repo/logs. From b1c4c1f969db548abc0e105defab53ad4665000d Mon Sep 17 00:00:00 2001 From: etvjay Date: Mon, 24 Aug 2026 16:52:48 +0100 Subject: [PATCH 011/116] ebi: add evidence ledger template --- hackathon/sibyl/templates/EVIDENCE_LEDGER.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 hackathon/sibyl/templates/EVIDENCE_LEDGER.md diff --git a/hackathon/sibyl/templates/EVIDENCE_LEDGER.md b/hackathon/sibyl/templates/EVIDENCE_LEDGER.md new file mode 100644 index 0000000..23e6897 --- /dev/null +++ b/hackathon/sibyl/templates/EVIDENCE_LEDGER.md @@ -0,0 +1,17 @@ +# Evidence Ledger + +Allowed states: +`UNVERIFIED | SIMULATED_PASS | LOCAL_PASS | FORK_PASS | TESTNET_PASS | LIVE_PASS | PUBLIC_EVALUATOR_PASS | PRODUCTION_PASS | FAILED | BLOCKED` + +| Claim / gate | State | Evidence | Negative mutation | Notes | +|---|---|---|---|---| +| Sibyl persists decision-critical memory | UNVERIFIED | — | disable write | | +| Fresh session recalls prior memory | UNVERIFIED | — | kill process + disable recall | | +| Recalled memory changes action | UNVERIFIED | — | no-memory control | | +| Deleting Sibyl breaks/degrades core function | UNVERIFIED | — | remove/disable Sibyl path | VETO | +| Engram provenance remains reconstructable | UNVERIFIED | — | wrong provenance injection | | +| Stale/incompatible memory blocked | UNVERIFIED | — | stale memory fixture | | +| Base integration does real product work | UNVERIFIED | — | remove Base action | optional | +| Virtuals integration does real product work | UNVERIFIED | — | remove Virtuals interaction | optional | + +No claim may be promoted above the smallest state actually supported by evidence. From f77de64fba44c8544e9f4dbbcaab433d05b98417 Mon Sep 17 00:00:00 2001 From: etvjay Date: Mon, 24 Aug 2026 16:52:57 +0100 Subject: [PATCH 012/116] ebi: add Base partner contract --- hackathon/sibyl/partners/base.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 hackathon/sibyl/partners/base.md diff --git a/hackathon/sibyl/partners/base.md b/hackathon/sibyl/partners/base.md new file mode 100644 index 0000000..dc10d15 --- /dev/null +++ b/hackathon/sibyl/partners/base.md @@ -0,0 +1,22 @@ +# Base Partner Contract + +Class: `PUBLISHED_BONUS` + +## Published qualification +A claimed Base stack counts only when judges can see it doing real work in the product. Deployment is the eligibility floor; an executed onchain action shown in the demo earns the partner bonus, including wallet operation, x402 payment, B20 read, or contract interaction. + +## Engram fit +Best use: recalled execution memory changes an economically consequential action, e.g. provider/payment terms, route choice, or x402 capability purchase. + +## Veto +Do not add Base merely for a transaction receipt. The onchain action must be downstream of the remembered decision. + +## Required evidence +- protocol-native transaction/receipt; +- action visible in demo; +- trace linking recalled memory -> changed decision -> Base action. + +## Negative test +Remove the Base action. If product meaning is unchanged, do not claim the partner stack. + +Status: `UNVERIFIED / OPTIONAL`. From 7b28a4fb16341c762777ec5ca8dff2e5b200c46c Mon Sep 17 00:00:00 2001 From: etvjay Date: Mon, 24 Aug 2026 16:53:05 +0100 Subject: [PATCH 013/116] ebi: add Virtuals partner contract --- hackathon/sibyl/partners/virtuals.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 hackathon/sibyl/partners/virtuals.md diff --git a/hackathon/sibyl/partners/virtuals.md b/hackathon/sibyl/partners/virtuals.md new file mode 100644 index 0000000..ae9d093 --- /dev/null +++ b/hackathon/sibyl/partners/virtuals.md @@ -0,0 +1,22 @@ +# Virtuals Partner Contract + +Class: `PUBLISHED_BONUS` + +## Published qualification +A claimed Virtuals stack counts only when judges can see a Virtuals-native integration exercised in the submitted build, such as an ACP job or a registered/transacting agent. + +## Engram fit +Best use: a Virtuals agent/provider interaction generates execution experience that Engram persists through Sibyl and later uses to alter provider selection, contracting terms, verification requirements, or another autonomous decision. + +## Veto +Do not use Virtuals as a decorative runtime label. The native interaction must create or consume decision-relevant experience. + +## Required evidence +- protocol-native ACP/agent/job evidence; +- exercised in demo; +- trace linking interaction -> persisted memory -> fresh-session changed behavior. + +## Negative test +Remove the Virtuals interaction. If the flagship scenario and product meaning remain unchanged, do not claim the partner stack. + +Status: `UNVERIFIED / OPTIONAL`. From 0169b0c86ce34b0545c78dc2dbcd48f3ca1312a1 Mon Sep 17 00:00:00 2001 From: etvjay Date: Mon, 24 Aug 2026 17:11:10 +0100 Subject: [PATCH 014/116] sibyl: pin evaluated SDK dependency --- packages/sibyl/requirements.txt | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 packages/sibyl/requirements.txt diff --git a/packages/sibyl/requirements.txt b/packages/sibyl/requirements.txt new file mode 100644 index 0000000..11b3121 --- /dev/null +++ b/packages/sibyl/requirements.txt @@ -0,0 +1,2 @@ +# Re-verify the latest published version at the start of the Sep 1 build window. +sibyl-memory-client==0.6.1 From 1d4ee8a4c324a16830b98cf1604c41ac3eafc782 Mon Sep 17 00:00:00 2001 From: etvjay Date: Mon, 24 Aug 2026 17:11:36 +0100 Subject: [PATCH 015/116] sibyl: add public-SDK bridge for Engram runtime store --- packages/sibyl/bridge.py | 96 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 packages/sibyl/bridge.py diff --git a/packages/sibyl/bridge.py b/packages/sibyl/bridge.py new file mode 100644 index 0000000..c4daf98 --- /dev/null +++ b/packages/sibyl/bridge.py @@ -0,0 +1,96 @@ +#!/usr/bin/env python3 +"""Thin JSON bridge from Engram's TypeScript runtime to Sibyl MemoryClient. + +This intentionally uses only the public sibyl_memory_client.MemoryClient API. +The evaluated profile must not bypass Sibyl by reaching into its SQLite schema. +""" +from __future__ import annotations + +import json +import os +import sys +from pathlib import Path +from typing import Any + +from sibyl_memory_client import MemoryClient + + +def _client() -> MemoryClient: + path = Path(os.environ.get("ENGRAM_SIBYL_DB", "~/.sibyl-memory/engram-hackathon.db")).expanduser() + tenant = os.environ.get("ENGRAM_SIBYL_TENANT", "engram-hackathon") + return MemoryClient.local(path, tenant_id=tenant) + + +def _safe_get(memory: MemoryClient, category: str, name: str) -> dict[str, Any] | None: + try: + return memory.get_entity(category, name) + except Exception as exc: + if exc.__class__.__name__ == "NotFoundError": + return None + raise + + +def _entities(memory: MemoryClient, category: str, limit: int = 10000) -> list[dict[str, Any]]: + return memory.list_entities(category=category, limit=limit) + + +def _body(row: dict[str, Any] | None) -> Any: + return None if row is None else row.get("body") + + +def _put(memory: MemoryClient, category: str, name: str, body: dict[str, Any]) -> dict[str, Any]: + row = memory.set_entity(category, name, body) + memory.write_event( + acted=[f"engram:{category}:write"], + extra={"category": category, "name": name, "executionId": body.get("executionId") or body.get("id")}, + ) + return row + + +def handle(req: dict[str, Any]) -> Any: + memory = _client() + op = req["op"] + args = req.get("args", {}) + + if op == "put": + return _put(memory, args["category"], args["name"], args["body"]) + if op == "get": + return _body(_safe_get(memory, args["category"], args["name"])) + if op == "list": + rows = _entities(memory, args["category"], int(args.get("limit", 10000))) + return [row["body"] for row in rows] + if op == "search_memories": + query = args["query"] + limit = min(max(int(args.get("limit", 8)), 1), 50) + agent_id = args["agentId"] + # Ask Sibyl's documented WARM-tier FTS5 search for a larger pool, then + # enforce Engram's agent boundary and result limit in the adapter. + rows = memory.search_entities(query, category="operational_memory", limit=min(limit * 8, 400)) + out = [] + for row in rows: + body = row.get("body") or {} + if body.get("agentId") != agent_id: + continue + out.append({"memory": body, "sibyl": {"entityId": row.get("id"), "updatedAt": row.get("updated_at")}}) + if len(out) >= limit: + break + return out + if op == "delete_memory": + return memory.delete_entity("operational_memory", args["memoryId"]) + if op == "ping": + return {"tenant": memory.get_tenant(), "schemaVersion": memory.schema_version()} + raise ValueError(f"unsupported operation: {op}") + + +def main() -> None: + try: + req = json.load(sys.stdin) + result = handle(req) + json.dump({"ok": True, "result": result}, sys.stdout, default=str) + except Exception as exc: + json.dump({"ok": False, "error": {"type": exc.__class__.__name__, "message": str(exc)}}, sys.stdout) + sys.exit(1) + + +if __name__ == "__main__": + main() From 393dbde0458f64762f8806764f8279bc51455650 Mon Sep 17 00:00:00 2001 From: etvjay Date: Mon, 24 Aug 2026 17:12:09 +0100 Subject: [PATCH 016/116] sibyl: implement load-bearing Engram runtime store --- packages/sibyl/src/runtime-store.ts | 327 ++++++++++++++++++++++++++++ 1 file changed, 327 insertions(+) create mode 100644 packages/sibyl/src/runtime-store.ts diff --git a/packages/sibyl/src/runtime-store.ts b/packages/sibyl/src/runtime-store.ts new file mode 100644 index 0000000..05b1d82 --- /dev/null +++ b/packages/sibyl/src/runtime-store.ts @@ -0,0 +1,327 @@ +import { randomUUID } from "node:crypto"; +import { spawn } from "node:child_process"; +import { fileURLToPath } from "node:url"; +import type { EvidenceState, MemoryRecall } from "../../core/src/protocol.js"; +import type { + ExecutionContext, + ExecutionEvent, + MemorySearchInput, + MemorySearchResult, + OperationalMemory, + Outcome, +} from "../../memory-core/src/domain.js"; +import { scoreMemory } from "../../memory-core/src/policy.js"; +import type { EngramRuntimeStore } from "../../runtime/src/store.js"; +import type { + RecallExposureUpdate, + RuntimeDecisionRecord, + RuntimeEvaluationEvent, + RuntimeExecutionRecord, +} from "../../runtime/src/types.js"; + +const bridgePath = fileURLToPath(new URL("../bridge.py", import.meta.url)); + +type BridgeResponse = { ok: true; result: T } | { ok: false; error: { type: string; message: string } }; + +async function bridge(op: string, args: Record = {}): Promise { + const python = process.env.ENGRAM_SIBYL_PYTHON ?? "python3"; + return new Promise((resolve, reject) => { + const child = spawn(python, [bridgePath], { + env: process.env, + stdio: ["pipe", "pipe", "pipe"], + }); + let stdout = ""; + let stderr = ""; + child.stdout.setEncoding("utf8"); + child.stderr.setEncoding("utf8"); + child.stdout.on("data", (chunk) => { stdout += chunk; }); + child.stderr.on("data", (chunk) => { stderr += chunk; }); + child.on("error", reject); + child.on("close", (code) => { + let parsed: BridgeResponse | undefined; + try { + parsed = JSON.parse(stdout) as BridgeResponse; + } catch { + reject(new Error(`SIBYL_BRIDGE_INVALID_RESPONSE: exit=${code}; stderr=${stderr}; stdout=${stdout}`)); + return; + } + if (!parsed.ok) { + reject(new Error(`SIBYL_${parsed.error.type}: ${parsed.error.message}`)); + return; + } + resolve(parsed.result); + }); + child.stdin.end(JSON.stringify({ op, args })); + }); +} + +function iso(value: Date | undefined): string | undefined { + return value?.toISOString(); +} + +function asDate(value: unknown): Date | undefined { + return typeof value === "string" ? new Date(value) : undefined; +} + +function serializeMemory(memory: OperationalMemory): Record { + return { + ...memory, + validFrom: iso(memory.validFrom), + validUntil: iso(memory.validUntil), + }; +} + +function deserializeMemory(raw: Record): OperationalMemory { + return { + id: String(raw.id), + agentId: String(raw.agentId), + memoryType: String(raw.memoryType), + summary: String(raw.summary), + structuredContext: (raw.structuredContext ?? {}) as Record, + confidence: Number(raw.confidence), + evidenceState: raw.evidenceState as OperationalMemory["evidenceState"], + validFrom: asDate(raw.validFrom), + validUntil: asDate(raw.validUntil), + environmentVersion: typeof raw.environmentVersion === "string" ? raw.environmentVersion : undefined, + toolVersion: typeof raw.toolVersion === "string" ? raw.toolVersion : undefined, + policyVersion: typeof raw.policyVersion === "string" ? raw.policyVersion : undefined, + }; +} + +async function put(category: string, name: string, body: Record): Promise { + await bridge("put", { category, name, body }); +} + +async function get(category: string, name: string): Promise { + return bridge("get", { category, name }); +} + +async function list(category: string): Promise { + return bridge("list", { category }); +} + +export class SibylRuntimeStore implements EngramRuntimeStore { + async ping(): Promise<{ tenant: string; schemaVersion: number | null }> { + return bridge("ping"); + } + + async startExecution(input: ExecutionContext): Promise<{ executionId: string }> { + const executionId = randomUUID(); + const record: Record = { + id: executionId, + ...input, + status: "RUNNING", + startedAt: new Date().toISOString(), + }; + await put("execution", executionId, record); + return { executionId }; + } + + async getExecution(executionId: string): Promise { + const raw = await get>("execution", executionId); + if (!raw) return null; + return { + id: String(raw.id), + agentId: String(raw.agentId), + agentVersion: typeof raw.agentVersion === "string" ? raw.agentVersion : undefined, + workflowType: String(raw.workflowType), + intent: String(raw.intent), + context: (raw.context ?? {}) as Record, + constraints: (raw.constraints ?? {}) as Record, + environmentVersion: typeof raw.environmentVersion === "string" ? raw.environmentVersion : undefined, + toolVersion: typeof raw.toolVersion === "string" ? raw.toolVersion : undefined, + policyVersion: typeof raw.policyVersion === "string" ? raw.policyVersion : undefined, + memoryPolicyBundleVersion: typeof raw.memoryPolicyBundleVersion === "string" ? raw.memoryPolicyBundleVersion : undefined, + status: raw.status as RuntimeExecutionRecord["status"], + startedAt: new Date(String(raw.startedAt)), + completedAt: typeof raw.completedAt === "string" ? new Date(raw.completedAt) : undefined, + }; + } + + async setExecutionMemoryPolicy(executionId: string, bundleVersion: string): Promise { + const execution = await get>("execution", executionId); + if (!execution) throw new Error(`Execution ${executionId} does not exist`); + const current = execution.memoryPolicyBundleVersion; + if (current && current !== bundleVersion) { + throw new Error(`EXECUTION_POLICY_FROZEN: execution ${executionId} already uses ${String(current)}`); + } + await put("execution", executionId, { ...execution, memoryPolicyBundleVersion: bundleVersion }); + } + + async nextEventSequence(executionId: string): Promise { + const events = await list>("execution_event"); + return events.filter((event) => event.executionId === executionId).length; + } + + async appendEvent(event: ExecutionEvent): Promise { + const key = `${event.executionId}-${event.sequenceNo}`; + const existing = await get>("execution_event", key); + const body = { ...event, occurredAt: event.occurredAt.toISOString() }; + if (existing) { + if (JSON.stringify(existing) === JSON.stringify(body)) return; + throw new Error(`EVENT_IDEMPOTENCY_CONFLICT:${event.executionId}:${event.sequenceNo}`); + } + await put("execution_event", key, body); + } + + async recordOutcome(outcome: Outcome): Promise { + const existing = await get>("outcome", outcome.executionId); + const body = { ...outcome } as Record; + if (existing && JSON.stringify(existing) !== JSON.stringify(body)) { + throw new Error(`OUTCOME_IDEMPOTENCY_CONFLICT:${outcome.executionId}`); + } + await put("outcome", outcome.executionId, body); + const execution = await get>("execution", outcome.executionId); + if (!execution) throw new Error(`Execution ${outcome.executionId} does not exist`); + await put("execution", outcome.executionId, { + ...execution, + status: outcome.status, + completedAt: new Date().toISOString(), + }); + } + + async getOutcomeEvidenceState(executionId: string): Promise { + const outcome = await get>("outcome", executionId); + return outcome?.evidenceState as EvidenceState | undefined ?? null; + } + + async persistMemory(memory: OperationalMemory, sourceExecutionIds: string[]): Promise { + if (!sourceExecutionIds.length) throw new Error("Operational memory requires at least one source execution"); + await put("operational_memory", memory.id, { + ...serializeMemory(memory), + sourceExecutionIds, + searchText: `${memory.summary} ${JSON.stringify(memory.structuredContext)}`, + }); + } + + async getMemory(memoryId: string): Promise { + const raw = await get>("operational_memory", memoryId); + return raw ? deserializeMemory(raw) : null; + } + + async searchMemory(input: MemorySearchInput): Promise { + const retrievalId = randomUUID(); + const limit = Math.min(Math.max(input.limit ?? 8, 1), 50); + const rows = await bridge; sibyl: Record }>>( + "search_memories", + { query: input.query, agentId: input.agentId, limit }, + ); + const now = Date.now(); + const candidates = rows + .map((row, index) => { + const memory = deserializeMemory(row.memory); + const context = memory.structuredContext; + if (input.workflowType && context.workflowType !== input.workflowType) return null; + if (input.environmentVersion && memory.environmentVersion !== input.environmentVersion) return null; + if (input.status?.length && !input.status.includes(context.outcome as never)) return null; + const semanticScore = Math.max(0.55, 1 - index * 0.08); + const contextScore = input.workflowType && context.workflowType === input.workflowType ? 1 : 0.75; + const outcomeScore = ["FAILURE", "COMPENSATED", "PARTIAL", "ABORTED", "UNKNOWN"].includes(String(context.outcome ?? "")) ? 1 : 0.5; + const ageDays = memory.validFrom ? Math.max(0, (now - memory.validFrom.getTime()) / 86_400_000) : 0; + const recencyScore = Math.max(0, 1 - ageDays / 30); + const finalScore = scoreMemory({ memory, semanticScore, contextScore, outcomeScore, recencyScore }); + return { + memoryId: memory.id, + memory, + semanticScore, + contextScore, + outcomeScore, + confidenceScore: memory.confidence, + recencyScore, + finalScore, + rank: index + 1, + }; + }) + .filter((value): value is NonNullable => value !== null) + .sort((a, b) => b.finalScore - a.finalScore) + .map((value, index) => ({ ...value, rank: index + 1 })) + .slice(0, limit); + + await put("recall", retrievalId, { + id: retrievalId, + executionId: input.executionId, + query: input.query, + policyVersion: input.retrievalPolicyVersion ?? "engram-sibyl-v1", + recalledAt: new Date().toISOString(), + candidates: candidates.map((candidate) => ({ + memoryId: candidate.memoryId, + rank: candidate.rank, + score: candidate.finalScore, + })), + rejected: [], + }); + return { retrievalId, candidates }; + } + + async getRecalls(executionId: string): Promise { + const rows = await list>("recall"); + return rows + .filter((row) => row.executionId === executionId) + .map((row) => ({ + id: String(row.id), + executionId, + query: String(row.query), + policyVersion: String(row.policyVersion ?? "engram-sibyl-v1"), + recalledAt: new Date(String(row.recalledAt)), + candidates: ((row.candidates ?? []) as Array>).map((candidate) => ({ + retrievalId: String(row.id), + memoryId: String(candidate.memoryId), + memoryStateDigest: typeof candidate.memoryStateDigest === "string" ? candidate.memoryStateDigest : undefined, + rank: Number(candidate.rank), + score: candidate.score === undefined ? undefined : Number(candidate.score), + })), + })); + } + + async updateRecallExposure(update: RecallExposureUpdate): Promise { + const recall = await get>("recall", update.retrievalId); + if (!recall) throw new Error(`Recall ${update.retrievalId} does not exist`); + const scoreByMemory = new Map( + ((recall.candidates ?? []) as Array>).map((candidate) => [String(candidate.memoryId), candidate.score]), + ); + await put("recall", update.retrievalId, { + ...recall, + candidates: update.exposedMemoryStates.map((state, index) => ({ + memoryId: state.memoryId, + memoryStateDigest: state.memoryStateDigest, + rank: index + 1, + score: scoreByMemory.get(state.memoryId), + })), + rejected: update.rejected, + }); + } + + async recordRuntimeDecision(decision: RuntimeDecisionRecord): Promise { + await put("decision", decision.id, { + ...decision, + decidedAt: decision.decidedAt.toISOString(), + } as unknown as Record); + } + + async appendRuntimeEvaluationEvent(event: RuntimeEvaluationEvent): Promise { + await put("runtime_evaluation", event.id, { + ...event, + createdAt: event.createdAt.toISOString(), + }); + } + + async getTrace(executionId: string): Promise { + const [execution, events, outcome, recalls, decisions, runtimeEvaluations] = await Promise.all([ + this.getExecution(executionId), + list>("execution_event"), + get>("outcome", executionId), + this.getRecalls(executionId), + list>("decision"), + list>("runtime_evaluation"), + ]); + return { + execution, + events: events.filter((row) => row.executionId === executionId), + outcome, + retrievals: recalls, + decisions: decisions.filter((row) => row.executionId === executionId), + runtimeEvaluations: runtimeEvaluations.filter((row) => row.executionId === executionId), + memoryBackend: "sibyl-memory-client", + }; + } +} From 744042e618e143d00868fd022ced2df279f1acc4 Mon Sep 17 00:00:00 2001 From: etvjay Date: Mon, 24 Aug 2026 17:12:52 +0100 Subject: [PATCH 017/116] test: prove Sibyl cold-start execution-memory loop --- tests/integration/sibyl-memory-loop.test.ts | 134 ++++++++++++++++++++ 1 file changed, 134 insertions(+) create mode 100644 tests/integration/sibyl-memory-loop.test.ts diff --git a/tests/integration/sibyl-memory-loop.test.ts b/tests/integration/sibyl-memory-loop.test.ts new file mode 100644 index 0000000..17ccf55 --- /dev/null +++ b/tests/integration/sibyl-memory-loop.test.ts @@ -0,0 +1,134 @@ +import { afterEach, beforeEach, describe, expect, it } from "vitest"; +import { mkdtemp, rm } from "node:fs/promises"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import { EngramRuntime } from "../../packages/runtime/src/runtime.js"; +import { DEFAULT_RUNTIME_POLICIES } from "../../packages/runtime/src/defaults.js"; +import { SibylRuntimeStore } from "../../packages/sibyl/src/runtime-store.js"; +import { decideRoute, ROUTE_C, ROUTE_D } from "../../packages/memory-core/src/policy.js"; + +let dir: string; +let previousDb: string | undefined; +let previousTenant: string | undefined; +let previousPython: string | undefined; + +beforeEach(async () => { + dir = await mkdtemp(join(tmpdir(), "engram-sibyl-")); + previousDb = process.env.ENGRAM_SIBYL_DB; + previousTenant = process.env.ENGRAM_SIBYL_TENANT; + previousPython = process.env.ENGRAM_SIBYL_PYTHON; + process.env.ENGRAM_SIBYL_DB = join(dir, "memory.db"); + process.env.ENGRAM_SIBYL_TENANT = "engram-integration-test"; + delete process.env.ENGRAM_SIBYL_PYTHON; +}); + +afterEach(async () => { + if (previousDb === undefined) delete process.env.ENGRAM_SIBYL_DB; + else process.env.ENGRAM_SIBYL_DB = previousDb; + if (previousTenant === undefined) delete process.env.ENGRAM_SIBYL_TENANT; + else process.env.ENGRAM_SIBYL_TENANT = previousTenant; + if (previousPython === undefined) delete process.env.ENGRAM_SIBYL_PYTHON; + else process.env.ENGRAM_SIBYL_PYTHON = previousPython; + await rm(dir, { recursive: true, force: true }); +}); + +describe("Engram × Sibyl evaluated profile", () => { + it("persists execution-derived memory and changes a later fresh-store decision", async () => { + const firstStore = new SibylRuntimeStore(); + const firstRuntime = new EngramRuntime(firstStore, DEFAULT_RUNTIME_POLICIES); + await expect(firstStore.ping()).resolves.toMatchObject({ tenant: "engram-integration-test" }); + + const runA = await firstRuntime.startExecution({ + agentId: "agent-demo", + workflowType: "multi_venue_execution", + intent: "route value through available venues", + context: { liquidityClass: "thin" }, + constraints: {}, + }); + + const completedA = await firstRuntime.complete({ + executionId: runA.executionId, + status: "COMPENSATED", + summary: "Venue C lacked required liquidity; recovery through D succeeded.", + result: { failedVenue: "C", recoveryVenue: "D" }, + evidenceState: "OBSERVED", + admissionSignals: [{ + kind: "UNEXPECTED_FAILURE", + summary: "Venue C failed with LIQUIDITY_UNAVAILABLE under thin liquidity; prefer D under comparable conditions.", + evidenceState: "OBSERVED", + confidence: 0.91, + details: { + failureType: "LIQUIDITY_UNAVAILABLE", + failedVenue: "C", + recoveryVenue: "D", + liquidityClass: "thin", + }, + }], + }); + expect(completedA.admittedMemories).toHaveLength(1); + + // Fresh store + runtime instance: no JS object from Run A is reused. + const secondStore = new SibylRuntimeStore(); + const secondRuntime = new EngramRuntime(secondStore, DEFAULT_RUNTIME_POLICIES); + const runB = await secondRuntime.startExecution({ + agentId: "agent-demo", + workflowType: "multi_venue_execution", + intent: "route value through available venues", + context: { liquidityClass: "thin" }, + constraints: {}, + }); + + const recalled = await secondRuntime.recall({ + executionId: runB.executionId, + query: "Venue C failed LIQUIDITY_UNAVAILABLE", + }); + expect(recalled.candidates).toHaveLength(1); + expect(recalled.candidates[0]?.memory.id).toBe(completedA.admittedMemories[0]?.id); + + const control = decideRoute({ memories: [], memoryAvailable: true }); + expect(control.route).toEqual(ROUTE_C); + + const treatment = decideRoute({ + memoryAvailable: true, + memories: recalled.candidates.map((candidate) => ({ + memory: candidate.memory, + semanticScore: candidate.semanticScore, + contextScore: candidate.contextScore, + outcomeScore: candidate.outcomeScore, + recencyScore: candidate.recencyScore, + })), + }); + expect(treatment.route).toEqual(ROUTE_D); + + await secondRuntime.recordDecision({ + executionId: runB.executionId, + decisionType: "ROUTE_SELECTION", + selectedAction: { route: treatment.route }, + alternatives: [{ route: control.route }], + reasoningSummary: treatment.reason, + influences: [{ + memoryId: recalled.candidates[0]!.memory.id, + retrievalId: recalled.recall.id, + influenceType: "CHANGED_ACTION", + summary: "Prior venue failure changed the selected route from C to D.", + counterfactual: { + action: { route: control.route }, + source: "APPLICATION_DECLARED", + evidenceState: "OBSERVED", + explanation: "The same route policy without recalled memory selects Route C.", + }, + }], + }); + + const trace = await secondRuntime.trace(runB.executionId) as Record; + expect(trace.memoryBackend).toBe("sibyl-memory-client"); + expect((trace.decisions as unknown[])).toHaveLength(1); + expect((trace.retrievals as unknown[])).toHaveLength(1); + }); + + it("fails closed when the Sibyl runtime is removed", async () => { + process.env.ENGRAM_SIBYL_PYTHON = join(dir, "missing-python"); + const store = new SibylRuntimeStore(); + await expect(store.ping()).rejects.toThrow(); + }); +}); From c1f89a80806a2b9f34c0338505f24a2040b6e427 Mon Sep 17 00:00:00 2001 From: etvjay Date: Mon, 24 Aug 2026 17:14:36 +0100 Subject: [PATCH 018/116] sibyl: resolve bridge from repository root --- packages/sibyl/src/runtime-store.ts | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/packages/sibyl/src/runtime-store.ts b/packages/sibyl/src/runtime-store.ts index 05b1d82..548f41a 100644 --- a/packages/sibyl/src/runtime-store.ts +++ b/packages/sibyl/src/runtime-store.ts @@ -1,6 +1,6 @@ import { randomUUID } from "node:crypto"; import { spawn } from "node:child_process"; -import { fileURLToPath } from "node:url"; +import { resolve } from "node:path"; import type { EvidenceState, MemoryRecall } from "../../core/src/protocol.js"; import type { ExecutionContext, @@ -19,14 +19,16 @@ import type { RuntimeExecutionRecord, } from "../../runtime/src/types.js"; -const bridgePath = fileURLToPath(new URL("../bridge.py", import.meta.url)); +function resolveBridgePath(): string { + return process.env.ENGRAM_SIBYL_BRIDGE ?? resolve(process.cwd(), "packages/sibyl/bridge.py"); +} type BridgeResponse = { ok: true; result: T } | { ok: false; error: { type: string; message: string } }; async function bridge(op: string, args: Record = {}): Promise { const python = process.env.ENGRAM_SIBYL_PYTHON ?? "python3"; - return new Promise((resolve, reject) => { - const child = spawn(python, [bridgePath], { + return new Promise((resolveResult, reject) => { + const child = spawn(python, [resolveBridgePath()], { env: process.env, stdio: ["pipe", "pipe", "pipe"], }); @@ -49,7 +51,7 @@ async function bridge(op: string, args: Record = {}): Promis reject(new Error(`SIBYL_${parsed.error.type}: ${parsed.error.message}`)); return; } - resolve(parsed.result); + resolveResult(parsed.result); }); child.stdin.end(JSON.stringify({ op, args })); }); @@ -182,7 +184,7 @@ export class SibylRuntimeStore implements EngramRuntimeStore { async getOutcomeEvidenceState(executionId: string): Promise { const outcome = await get>("outcome", executionId); - return outcome?.evidenceState as EvidenceState | undefined ?? null; + return (outcome?.evidenceState as EvidenceState | undefined) ?? null; } async persistMemory(memory: OperationalMemory, sourceExecutionIds: string[]): Promise { @@ -213,7 +215,7 @@ export class SibylRuntimeStore implements EngramRuntimeStore { const context = memory.structuredContext; if (input.workflowType && context.workflowType !== input.workflowType) return null; if (input.environmentVersion && memory.environmentVersion !== input.environmentVersion) return null; - if (input.status?.length && !input.status.includes(context.outcome as never)) return null; + if (input.status?.length && !input.status.includes(context.outcome as (typeof input.status)[number])) return null; const semanticScore = Math.max(0.55, 1 - index * 0.08); const contextScore = input.workflowType && context.workflowType === input.workflowType ? 1 : 0.75; const outcomeScore = ["FAILURE", "COMPENSATED", "PARTIAL", "ABORTED", "UNKNOWN"].includes(String(context.outcome ?? "")) ? 1 : 0.5; From ae30083e80d14c1fdcd6f7f15ac70322801c0f50 Mon Sep 17 00:00:00 2001 From: etvjay Date: Mon, 24 Aug 2026 17:14:46 +0100 Subject: [PATCH 019/116] sibyl: add evaluated profile test command --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 7441ad5..3890a8e 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "mcp:stdio": "tsx packages/mcp-server/src/stdio.ts", "test": "vitest run tests/e2e/memory-caused-behavior.test.ts", "test:integration": "vitest run tests/integration/cockroach-memory-loop.test.ts", + "test:sibyl": "vitest run tests/integration/sibyl-memory-loop.test.ts", "test:all": "vitest run", "test:watch": "vitest", "check": "npm run build && npm run test:all" From 630e59d3f6a2b58da8b036276bc617d354f0045d Mon Sep 17 00:00:00 2001 From: etvjay Date: Mon, 24 Aug 2026 17:14:52 +0100 Subject: [PATCH 020/116] ci: verify Sibyl evaluated profile --- .github/workflows/sibyl-profile.yml | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 .github/workflows/sibyl-profile.yml diff --git a/.github/workflows/sibyl-profile.yml b/.github/workflows/sibyl-profile.yml new file mode 100644 index 0000000..30e60ef --- /dev/null +++ b/.github/workflows/sibyl-profile.yml @@ -0,0 +1,21 @@ +name: Engram Sibyl Profile + +on: + pull_request: + workflow_dispatch: + +jobs: + sibyl-profile: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 22 + - uses: actions/setup-python@v5 + with: + python-version: '3.12' + - run: npm install + - run: python -m pip install -r packages/sibyl/requirements.txt + - run: npm run build + - run: npm run test:sibyl From 6096df229e6943d7d9a054461ce02f40517ac705 Mon Sep 17 00:00:00 2001 From: etvjay Date: Mon, 24 Aug 2026 17:15:23 +0100 Subject: [PATCH 021/116] docs: freeze full Sibyl runtime-store boundary --- hackathon/sibyl/ARCHITECTURE.md | 74 ++++++++++++++++++++++----------- 1 file changed, 49 insertions(+), 25 deletions(-) diff --git a/hackathon/sibyl/ARCHITECTURE.md b/hackathon/sibyl/ARCHITECTURE.md index a9f0a18..00b131c 100644 --- a/hackathon/sibyl/ARCHITECTURE.md +++ b/hackathon/sibyl/ARCHITECTURE.md @@ -1,14 +1,13 @@ # Architecture — Engram × Sibyl Hackathon Profile ## Architectural decision -Do **not** rewrite canonical Engram around Sibyl. Introduce a hackathon storage profile where Sibyl is the sole decision-critical persistence/recall substrate. +Do **not** rewrite canonical Engram around Sibyl. Introduce a hackathon storage profile where Sibyl is the sole decision-critical persistence/recall substrate and Engram keeps its execution-memory semantics. ```text Application / Agent | v Engram Runtime -- ExecutionEpisode - admission - eligibility - influence @@ -17,18 +16,34 @@ Engram Runtime - counterfactual evaluation | v -SibylMemoryStore -- persist execution-derived memory -- retrieve across process/session boundary -- preserve identifiers/metadata needed for provenance +SibylRuntimeStore : EngramRuntimeStore + | + +--> WARM entities + | executions + | outcomes + | operational memories + | recalls + | decisions + | evaluation records + | + +--> COLD journal + adapter write/audit events | v -fresh-session recall +Sibyl MemoryClient.local(...) + | + v +fresh-process recall | v application decision + observable changed action ``` +## Why the full runtime-store boundary +The earlier narrow `ExecutionMemoryStore` proposal was rejected after auditing Engram's runtime. Engram already has a clean `EngramRuntimeStore` interface. Recall provenance, exposed-memory digests, decisions, evaluation records and source-lineage checks all depend on that store surface. + +Using Sibyl only for `persistMemory/searchMemory/getMemory` while retaining CockroachDB recall bookkeeping would create a split authority surface and weaken the deletion test. The evaluated profile therefore implements the existing full runtime-store contract as `SibylRuntimeStore`. + ## Boundary ### Engram owns @@ -37,51 +52,60 @@ application decision + observable changed action - whether recalled memory is eligible to influence action; - explicit influence recording; - provenance from source execution to later decision; +- recalled-memory state digests; - counterfactual comparison; - expiry/invalidation/conflict semantics. ### Sibyl owns in the judged profile -- durable persistence of decision-critical memories; -- cross-session retrieval; -- historical state required for Engram recall. +- durable storage required to reconstruct the execution-memory trace; +- decision-critical operational memories; +- recall records and exposed-memory bindings; +- execution/outcome/decision/evaluation records needed by the evaluated profile; +- cross-process retrieval. ### Application owns - final business/action decision; - external action execution. +## Public-SDK rule +The adapter uses `sibyl_memory_client.MemoryClient` only. Direct access to Sibyl's SQLite schema is forbidden in the evaluated path because it would bypass the integration surface being judged. + ## Forbidden architecture ```text -Engram -> CockroachDB canonical memory +Engram -> CockroachDB equivalent decision memory \-> Sibyl mirror ``` -If CockroachDB can independently produce equivalent fresh-session behavior, Sibyl is decorative and the gate is at risk. +If CockroachDB can independently reconstruct the claimed fresh-session behavior in the evaluated profile, Sibyl is decorative and the gate is at risk. -## Adapter contract (proposed) +## Current implementation + +```text +packages/sibyl/bridge.py + MemoryClient.local(...) + set_entity / get_entity / list_entities + search_entities + write_event -```ts -interface ExecutionMemoryStore { - persist(memory: OperationalMemory): Promise - recall(query: RecallQuery): Promise - get(memoryId: string): Promise - invalidate(memoryId: string, reason: string): Promise -} +packages/sibyl/src/runtime-store.ts + class SibylRuntimeStore implements EngramRuntimeStore ``` -`SibylMemoryStore` implements this contract for the hackathon profile. +The Python bridge exists because the current first-party Sibyl SDK is Python while Engram's runtime is TypeScript. The bridge is deliberately thin and JSON-only; memory semantics remain in Engram and persistence semantics remain in Sibyl. ## Minimum causal acceptance 1. Run A executes with no relevant memory. 2. Failure/recovery evidence is observed. -3. Engram admits an operational memory and persists it to Sibyl. -4. Process terminates. -5. Fresh Run B starts. +3. Engram admits an operational memory and persists it through `SibylRuntimeStore`. +4. The first runtime/store instance is discarded. +5. Fresh Run B starts against the same Sibyl database. 6. Sibyl recalls the memory. 7. Engram eligibility permits influence. 8. Application records memory influence and chooses a different action. -9. Outcome and trace are recorded. +9. Outcome and trace are reconstructable from Sibyl-backed state. 10. A no-memory control demonstrates the action difference. +11. Removing the Sibyl runtime makes the evaluated profile fail closed; there is no equivalent memory fallback. ## Production boundary This profile proves storage portability and load-bearing cross-session behavior. It does not replace the canonical Engram production persistence decision unless separately adopted after the hackathon. From 360716ac247f1c93c87986be43fc1f4f2e67b1b5 Mon Sep 17 00:00:00 2001 From: etvjay Date: Mon, 24 Aug 2026 17:15:37 +0100 Subject: [PATCH 022/116] docs: record Sibyl toolchain probe --- hackathon/sibyl/DEVELOPMENT_ENVIRONMENT.md | 65 +++++++++++++++------- 1 file changed, 44 insertions(+), 21 deletions(-) diff --git a/hackathon/sibyl/DEVELOPMENT_ENVIRONMENT.md b/hackathon/sibyl/DEVELOPMENT_ENVIRONMENT.md index 0eeed6c..ef4c401 100644 --- a/hackathon/sibyl/DEVELOPMENT_ENVIRONMENT.md +++ b/hackathon/sibyl/DEVELOPMENT_ENVIRONMENT.md @@ -1,6 +1,6 @@ # Development Environment -Status: `UNPROBED` for Sibyl integration. +Status: `PROBED_AWAITING_GOLDEN_CI` for Sibyl integration. ## Existing Engram baseline - Node.js 22 @@ -8,36 +8,59 @@ Status: `UNPROBED` for Sibyl integration. - TypeScript monorepo - canonical checks: `npm install` then `npm run check` -## Hackathon profile target -Proposed environment flag: +## Sibyl toolchain lock +Verified from first-party Sibyl documentation/repository on 2026-08-24: + +- direct SDK language: Python; +- package: `sibyl-memory-client`; +- public client: `MemoryClient.local(path, tenant_id=...)`; +- durable tiers used by this profile: WARM entities plus COLD journal audit events; +- retrieval API used by this profile: `search_entities(...)`; +- Python requirement: >=3.10 in the upstream package metadata; +- currently observed PyPI release: `0.6.1`; +- upstream GitHub `main` currently declares `0.7.0`, so release status must be revalidated before the Sep 1 build window and again before submission freeze. + +Evaluated dependency pin: + +```text +packages/sibyl/requirements.txt +sibyl-memory-client==0.6.1 +``` + +## Runtime configuration ```bash -ENGRAM_MEMORY_PROFILE=sibyl +ENGRAM_SIBYL_DB=/absolute/path/to/memory.db +ENGRAM_SIBYL_TENANT=engram-hackathon +ENGRAM_SIBYL_PYTHON=python3 +# optional if repository layout differs +ENGRAM_SIBYL_BRIDGE=/absolute/path/to/packages/sibyl/bridge.py ``` -The exact Sibyl package/API/env configuration is intentionally **not frozen yet**. Research/toolchain probing must verify current first-party docs before implementation. +There is deliberately no Cockroach fallback flag in `SibylRuntimeStore`. -## Required local commands after adapter implementation +## Current commands ```bash npm install -npm run check +python -m pip install -r packages/sibyl/requirements.txt +npm run build npm run test:sibyl -npm run demo:sibyl:seed -# terminate process/session -npm run demo:sibyl:recall -npm run demo:sibyl:no-memory-control -npm run test:sibyl:deletion ``` -Command names above are target interfaces, not evidence that they currently exist. +`test:sibyl` exercises a Run A -> fresh store/runtime Run B recall path against a shared Sibyl DB and separately checks fail-closed behavior when the configured Sibyl Python runtime is absent. + +## CI +`.github/workflows/sibyl-profile.yml` provisions Node 22 + Python 3.12, installs the pinned Sibyl SDK, builds Engram, and runs `npm run test:sibyl` on pull requests. ## Toolchain probe gate -Before `READY_TO_BUILD`: -- [ ] current Sibyl SDK/package/API verified from first-party docs; -- [ ] credentials/config path understood; -- [ ] persistence survives a clean process restart; -- [ ] write/read semantics can preserve Engram provenance IDs/metadata; -- [ ] local golden fixture passes; -- [ ] deletion mutation is implementable; -- [ ] no secrets enter frontend/repo/logs. +- [x] current Sibyl SDK/package/API verified from first-party docs; +- [x] local-first configuration path understood; +- [x] public write/read API can preserve Engram IDs/structured metadata by construction; +- [x] deletion/unavailable-Sibyl mutation is implementable and encoded as a test; +- [x] no Sibyl secret is required for the local-first core path; +- [ ] golden integration passes in clean CI; +- [ ] fresh-session behavior promoted from test design to observed CI evidence; +- [ ] SDK/version truth revalidated at Sep 1. + +Do not promote the EBI state to `READY_TO_BUILD` until the clean CI run passes and its evidence is recorded. From d375568e3c782490804cadbee7e98572bb273de9 Mon Sep 17 00:00:00 2001 From: etvjay Date: Mon, 24 Aug 2026 17:16:33 +0100 Subject: [PATCH 023/116] test: isolate optional Sibyl integration from canonical suite --- tests/integration/sibyl-memory-loop.test.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/integration/sibyl-memory-loop.test.ts b/tests/integration/sibyl-memory-loop.test.ts index 17ccf55..e36522b 100644 --- a/tests/integration/sibyl-memory-loop.test.ts +++ b/tests/integration/sibyl-memory-loop.test.ts @@ -7,6 +7,8 @@ import { DEFAULT_RUNTIME_POLICIES } from "../../packages/runtime/src/defaults.js import { SibylRuntimeStore } from "../../packages/sibyl/src/runtime-store.js"; import { decideRoute, ROUTE_C, ROUTE_D } from "../../packages/memory-core/src/policy.js"; +const describeSibyl = process.env.ENGRAM_SIBYL_TEST_REQUIRED === "1" ? describe : describe.skip; + let dir: string; let previousDb: string | undefined; let previousTenant: string | undefined; @@ -32,7 +34,7 @@ afterEach(async () => { await rm(dir, { recursive: true, force: true }); }); -describe("Engram × Sibyl evaluated profile", () => { +describeSibyl("Engram × Sibyl evaluated profile", () => { it("persists execution-derived memory and changes a later fresh-store decision", async () => { const firstStore = new SibylRuntimeStore(); const firstRuntime = new EngramRuntime(firstStore, DEFAULT_RUNTIME_POLICIES); From 1b38c09a0e79429375dc602879704dd4df75fbf0 Mon Sep 17 00:00:00 2001 From: etvjay Date: Mon, 24 Aug 2026 17:16:47 +0100 Subject: [PATCH 024/116] test: require Sibyl profile explicitly --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 3890a8e..113b756 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "mcp:stdio": "tsx packages/mcp-server/src/stdio.ts", "test": "vitest run tests/e2e/memory-caused-behavior.test.ts", "test:integration": "vitest run tests/integration/cockroach-memory-loop.test.ts", - "test:sibyl": "vitest run tests/integration/sibyl-memory-loop.test.ts", + "test:sibyl": "ENGRAM_SIBYL_TEST_REQUIRED=1 vitest run tests/integration/sibyl-memory-loop.test.ts", "test:all": "vitest run", "test:watch": "vitest", "check": "npm run build && npm run test:all" From 51e084d400a1d6a0c6e27ef0ac094f75707dd167 Mon Sep 17 00:00:00 2001 From: etvjay Date: Mon, 24 Aug 2026 17:17:01 +0100 Subject: [PATCH 025/116] docs: classify Sibyl adapter as server-only --- docs/frontend-modules/server-only.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/frontend-modules/server-only.json b/docs/frontend-modules/server-only.json index 38249b7..1cb8b6c 100644 --- a/docs/frontend-modules/server-only.json +++ b/docs/frontend-modules/server-only.json @@ -1,6 +1,6 @@ { "schemaVersion": "engram.server-only-module-registry/v1", - "updatedAt": "2026-08-18", + "updatedAt": "2026-08-24", "modules": [ { "modulePath": "packages/adapters", "reason": "Framework telemetry integration; frontend consumes resulting execution evidence through API surfaces." }, { "modulePath": "packages/bedrock", "reason": "AWS Bedrock embedding client requires server-side credentials." }, @@ -14,6 +14,7 @@ { "modulePath": "packages/python", "reason": "Python client SDK; non-browser execution surface." }, { "modulePath": "packages/runtime", "reason": "Server-side semantic authority and runtime policy enforcement." }, { "modulePath": "packages/scenarios", "reason": "Internal experiment workloads and application fixtures, not product UI APIs." }, + { "modulePath": "packages/sibyl", "reason": "Hackathon runtime-store adapter launches the server-side Sibyl Python SDK and owns local durable memory access; browsers consume resulting traces through Engram API surfaces." }, { "modulePath": "packages/vertex", "reason": "Google Vertex AI embedding client uses Application Default Credentials and must remain server-side." }, { "modulePath": "services/runtime", "reason": "Server runtime construction and infrastructure wiring." }, { "modulePath": "services/verification", "reason": "Credentialed live-verification and evidence generation service." } From bafd5360391ec7eab8500d52cb7c848312662bc9 Mon Sep 17 00:00:00 2001 From: etvjay Date: Mon, 24 Aug 2026 17:17:41 +0100 Subject: [PATCH 026/116] demo: add separate-process Sibyl seed and recall commands --- scripts/sibyl-demo.ts | 167 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 167 insertions(+) create mode 100644 scripts/sibyl-demo.ts diff --git a/scripts/sibyl-demo.ts b/scripts/sibyl-demo.ts new file mode 100644 index 0000000..59a6b57 --- /dev/null +++ b/scripts/sibyl-demo.ts @@ -0,0 +1,167 @@ +import { SibylRuntimeStore } from "../packages/sibyl/src/runtime-store.js"; +import { EngramRuntime } from "../packages/runtime/src/runtime.js"; +import { DEFAULT_RUNTIME_POLICIES } from "../packages/runtime/src/defaults.js"; +import { decideRoute } from "../packages/memory-core/src/policy.js"; + +const command = process.argv[2]; + +function emit(value: unknown): void { + process.stdout.write(`${JSON.stringify(value, null, 2)}\n`); +} + +async function seed(): Promise { + const store = new SibylRuntimeStore(); + const runtime = new EngramRuntime(store, DEFAULT_RUNTIME_POLICIES); + const backend = await store.ping(); + + const run = await runtime.startExecution({ + agentId: "agent-demo", + workflowType: "multi_venue_execution", + intent: "route value through available venues", + context: { liquidityClass: "thin", demoPhase: "seed" }, + constraints: {}, + }); + + const completed = await runtime.complete({ + executionId: run.executionId, + status: "COMPENSATED", + summary: "Venue C lacked required liquidity; recovery through D succeeded.", + result: { baselineRoute: ["A", "B", "C"], failedVenue: "C", recoveryVenue: "D" }, + evidenceState: "OBSERVED", + admissionSignals: [{ + kind: "UNEXPECTED_FAILURE", + summary: "Venue C failed with LIQUIDITY_UNAVAILABLE under thin liquidity; prefer D under comparable conditions.", + evidenceState: "OBSERVED", + confidence: 0.91, + details: { + failureType: "LIQUIDITY_UNAVAILABLE", + failedVenue: "C", + recoveryVenue: "D", + liquidityClass: "thin", + }, + }], + }); + + emit({ + phase: "seed", + backend: "sibyl-memory-client", + sibyl: backend, + executionId: run.executionId, + admittedMemoryIds: completed.admittedMemories.map((memory) => memory.id), + instruction: "Terminate this process. Run `npm run demo:sibyl:recall` in a new process against the same ENGRAM_SIBYL_DB and tenant.", + }); +} + +async function recall(): Promise { + const store = new SibylRuntimeStore(); + const runtime = new EngramRuntime(store, DEFAULT_RUNTIME_POLICIES); + const backend = await store.ping(); + + const run = await runtime.startExecution({ + agentId: "agent-demo", + workflowType: "multi_venue_execution", + intent: "route value through available venues", + context: { liquidityClass: "thin", demoPhase: "fresh-recall" }, + constraints: {}, + }); + + const recalled = await runtime.recall({ + executionId: run.executionId, + query: "Venue C failed LIQUIDITY_UNAVAILABLE", + }); + + const control = decideRoute({ memories: [], memoryAvailable: true }); + const treatment = decideRoute({ + memoryAvailable: true, + memories: recalled.candidates.map((candidate) => ({ + memory: candidate.memory, + semanticScore: candidate.semanticScore, + contextScore: candidate.contextScore, + outcomeScore: candidate.outcomeScore, + recencyScore: candidate.recencyScore, + })), + }); + + if (recalled.candidates[0] && treatment.memoryRefs.length) { + await runtime.recordDecision({ + executionId: run.executionId, + decisionType: "ROUTE_SELECTION", + selectedAction: { route: treatment.route }, + alternatives: [{ route: control.route }], + reasoningSummary: treatment.reason, + influences: [{ + memoryId: recalled.candidates[0].memory.id, + retrievalId: recalled.recall.id, + influenceType: "CHANGED_ACTION", + summary: "A persisted prior execution changed route selection from C to D.", + counterfactual: { + action: { route: control.route }, + source: "APPLICATION_DECLARED", + evidenceState: "OBSERVED", + explanation: "The same route policy without recalled memory selects Route C.", + }, + }], + }); + } + + emit({ + phase: "fresh-recall", + backend: "sibyl-memory-client", + sibyl: backend, + executionId: run.executionId, + retrievalId: recalled.recall.id, + recalledMemoryIds: recalled.candidates.map((candidate) => candidate.memory.id), + controlRoute: control.route, + memoryConditionedRoute: treatment.route, + changedAction: JSON.stringify(control.route) !== JSON.stringify(treatment.route), + trace: await runtime.trace(run.executionId), + }); +} + +async function noMemoryControl(): Promise { + const decision = decideRoute({ memories: [], memoryAvailable: false }); + emit({ + phase: "no-memory-control", + memoryAvailable: false, + route: decision.route, + memoryRefs: decision.memoryRefs, + reason: decision.reason, + }); +} + +async function deletionMutation(): Promise { + const previous = process.env.ENGRAM_SIBYL_PYTHON; + process.env.ENGRAM_SIBYL_PYTHON = process.env.ENGRAM_SIBYL_MISSING_PYTHON ?? "/definitely-missing-sibyl-python"; + try { + const store = new SibylRuntimeStore(); + await store.ping(); + throw new Error("DELETION_MUTATION_FAILED: Sibyl unexpectedly remained available"); + } catch (error) { + emit({ + phase: "sibyl-deletion-mutation", + degraded: true, + fallbackAvailable: false, + error: error instanceof Error ? error.message : String(error), + }); + } finally { + if (previous === undefined) delete process.env.ENGRAM_SIBYL_PYTHON; + else process.env.ENGRAM_SIBYL_PYTHON = previous; + } +} + +switch (command) { + case "seed": + await seed(); + break; + case "recall": + await recall(); + break; + case "control": + await noMemoryControl(); + break; + case "deletion": + await deletionMutation(); + break; + default: + throw new Error("Usage: tsx scripts/sibyl-demo.ts "); +} From f24e5ca82be9257ec616833a02e3a7f7790640df Mon Sep 17 00:00:00 2001 From: etvjay Date: Mon, 24 Aug 2026 17:17:52 +0100 Subject: [PATCH 027/116] demo: expose Sibyl cold-start proof commands --- package.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/package.json b/package.json index 113b756..60a4e33 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,10 @@ "test": "vitest run tests/e2e/memory-caused-behavior.test.ts", "test:integration": "vitest run tests/integration/cockroach-memory-loop.test.ts", "test:sibyl": "ENGRAM_SIBYL_TEST_REQUIRED=1 vitest run tests/integration/sibyl-memory-loop.test.ts", + "demo:sibyl:seed": "tsx scripts/sibyl-demo.ts seed", + "demo:sibyl:recall": "tsx scripts/sibyl-demo.ts recall", + "demo:sibyl:no-memory-control": "tsx scripts/sibyl-demo.ts control", + "test:sibyl:deletion": "tsx scripts/sibyl-demo.ts deletion", "test:all": "vitest run", "test:watch": "vitest", "check": "npm run build && npm run test:all" From 96abd1d79fdf9f1aeb6743cbe66d3cd908c0f42f Mon Sep 17 00:00:00 2001 From: etvjay Date: Mon, 24 Aug 2026 17:18:06 +0100 Subject: [PATCH 028/116] ci: prove separate-process Sibyl cold start and deletion --- .github/workflows/sibyl-profile.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/.github/workflows/sibyl-profile.yml b/.github/workflows/sibyl-profile.yml index 30e60ef..939e3cc 100644 --- a/.github/workflows/sibyl-profile.yml +++ b/.github/workflows/sibyl-profile.yml @@ -7,6 +7,9 @@ on: jobs: sibyl-profile: runs-on: ubuntu-latest + env: + ENGRAM_SIBYL_DB: ${{ runner.temp }}/engram-sibyl-demo.db + ENGRAM_SIBYL_TENANT: engram-ci-demo steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -19,3 +22,11 @@ jobs: - run: python -m pip install -r packages/sibyl/requirements.txt - run: npm run build - run: npm run test:sibyl + - name: Seed execution memory in process A + run: npm run demo:sibyl:seed + - name: Recall and change action in fresh process B + run: npm run demo:sibyl:recall + - name: Show no-memory control + run: npm run demo:sibyl:no-memory-control + - name: Remove Sibyl runtime and prove fail-closed degradation + run: npm run test:sibyl:deletion From 930011517c407ba813ba08df299e538f32b7bc69 Mon Sep 17 00:00:00 2001 From: etvjay Date: Mon, 24 Aug 2026 17:18:41 +0100 Subject: [PATCH 029/116] test: make Sibyl deletion proof fail truthfully --- scripts/sibyl-demo.ts | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/scripts/sibyl-demo.ts b/scripts/sibyl-demo.ts index 59a6b57..e998e23 100644 --- a/scripts/sibyl-demo.ts +++ b/scripts/sibyl-demo.ts @@ -132,21 +132,29 @@ async function noMemoryControl(): Promise { async function deletionMutation(): Promise { const previous = process.env.ENGRAM_SIBYL_PYTHON; process.env.ENGRAM_SIBYL_PYTHON = process.env.ENGRAM_SIBYL_MISSING_PYTHON ?? "/definitely-missing-sibyl-python"; + let deletionObserved = false; + let observedError = ""; try { const store = new SibylRuntimeStore(); await store.ping(); - throw new Error("DELETION_MUTATION_FAILED: Sibyl unexpectedly remained available"); } catch (error) { - emit({ - phase: "sibyl-deletion-mutation", - degraded: true, - fallbackAvailable: false, - error: error instanceof Error ? error.message : String(error), - }); + deletionObserved = true; + observedError = error instanceof Error ? error.message : String(error); } finally { if (previous === undefined) delete process.env.ENGRAM_SIBYL_PYTHON; else process.env.ENGRAM_SIBYL_PYTHON = previous; } + + if (!deletionObserved) { + throw new Error("DELETION_MUTATION_FAILED: Sibyl unexpectedly remained available"); + } + + emit({ + phase: "sibyl-deletion-mutation", + degraded: true, + fallbackAvailable: false, + error: observedError, + }); } switch (command) { From cac0a15d18d17ee41628581027a9ae836f6cb474 Mon Sep 17 00:00:00 2001 From: etvjay Date: Mon, 24 Aug 2026 17:19:25 +0100 Subject: [PATCH 030/116] evidence: record first clean Sibyl profile proof --- hackathon/sibyl/templates/EVIDENCE_LEDGER.md | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/hackathon/sibyl/templates/EVIDENCE_LEDGER.md b/hackathon/sibyl/templates/EVIDENCE_LEDGER.md index 23e6897..2633a6c 100644 --- a/hackathon/sibyl/templates/EVIDENCE_LEDGER.md +++ b/hackathon/sibyl/templates/EVIDENCE_LEDGER.md @@ -3,15 +3,23 @@ Allowed states: `UNVERIFIED | SIMULATED_PASS | LOCAL_PASS | FORK_PASS | TESTNET_PASS | LIVE_PASS | PUBLIC_EVALUATOR_PASS | PRODUCTION_PASS | FAILED | BLOCKED` +## Current claim ledger + | Claim / gate | State | Evidence | Negative mutation | Notes | |---|---|---|---|---| -| Sibyl persists decision-critical memory | UNVERIFIED | — | disable write | | -| Fresh session recalls prior memory | UNVERIFIED | — | kill process + disable recall | | -| Recalled memory changes action | UNVERIFIED | — | no-memory control | | -| Deleting Sibyl breaks/degrades core function | UNVERIFIED | — | remove/disable Sibyl path | VETO | -| Engram provenance remains reconstructable | UNVERIFIED | — | wrong provenance injection | | -| Stale/incompatible memory blocked | UNVERIFIED | — | stale memory fixture | | +| Sibyl persists decision-critical memory | LOCAL_PASS | GitHub Actions `Engram Sibyl Profile` run `32749722101`, job `97503556005`, head `630e59d`: pinned SDK installed, build passed, `npm run test:sibyl` passed | missing Sibyl runtime | Public clean runner, but not yet the final hackathon-window proof | +| Fresh store/runtime recalls prior memory | LOCAL_PASS | same run/test; Run A and Run B use separate `SibylRuntimeStore` + `EngramRuntime` instances against durable Sibyl state | no recall / unavailable Sibyl | Stronger separate-Node-process CLI added later; latest CI still must promote it | +| Recalled memory changes action | LOCAL_PASS | same run/test: no-memory Route C versus Sibyl-recalled Route D | no-memory control | Paired behavioral delta, not retrieval-only | +| Deleting/unavailable Sibyl breaks/degrades core function | LOCAL_PASS | same run/test: configured missing Python/Sibyl runtime rejects `ping()` and no fallback is invoked | remove/disable Sibyl runtime | VETO; CLI mutation later hardened against false-positive catch behavior | +| Engram provenance remains reconstructable | LOCAL_PASS | same run/test records recall, memory-state digest exposure, `CHANGED_ACTION` decision and retrieves trace from Sibyl-backed store | wrong/stale recall digest | Broader adversarial lineage fixtures still pending on Sibyl store | +| Separate Node process A -> process B cold-start demo | UNVERIFIED | `scripts/sibyl-demo.ts` + CI steps added after first green run | terminate process A, run process B | Must pass on latest clean CI before promotion | +| Canonical Engram suite remains green with optional Sibyl profile | UNVERIFIED | prior generic CI run `32749722041` failed because optional SDK was absent and `packages/sibyl` lacked server-only classification; both causes patched after diagnosis | canonical `npm run check` | Do not claim regression-free until latest CI passes | +| Stale/incompatible memory blocked through Sibyl store | UNVERIFIED | Engram runtime semantics already contain eligibility checks, but Sibyl-profile-specific mutation not yet observed | stale memory fixture | Next pressure-harness task | +| Conflicting memory remains non-silently adjudicated | UNVERIFIED | existing Engram semantics only | contradictory Sibyl memory fixture | Next pressure-harness task | | Base integration does real product work | UNVERIFIED | — | remove Base action | optional | | Virtuals integration does real product work | UNVERIFIED | — | remove Virtuals interaction | optional | +## Evidence-history note +A green run proves only the commit/run it actually executed. Later source changes do not inherit that evidence automatically. Every promotion above `LOCAL_PASS` must point to the exact hackathon-window artifact/run that supports it. + No claim may be promoted above the smallest state actually supported by evidence. From 59083057c7f2d924011757f613e9cf59603b706d Mon Sep 17 00:00:00 2001 From: etvjay Date: Mon, 24 Aug 2026 17:20:21 +0100 Subject: [PATCH 031/116] test: pressure Sibyl profile with stale and tampered memory --- tests/integration/sibyl-memory-loop.test.ts | 173 ++++++++++++++++---- 1 file changed, 139 insertions(+), 34 deletions(-) diff --git a/tests/integration/sibyl-memory-loop.test.ts b/tests/integration/sibyl-memory-loop.test.ts index e36522b..95b74d6 100644 --- a/tests/integration/sibyl-memory-loop.test.ts +++ b/tests/integration/sibyl-memory-loop.test.ts @@ -1,4 +1,5 @@ import { afterEach, beforeEach, describe, expect, it } from "vitest"; +import { randomUUID } from "node:crypto"; import { mkdtemp, rm } from "node:fs/promises"; import { tmpdir } from "node:os"; import { join } from "node:path"; @@ -6,6 +7,7 @@ import { EngramRuntime } from "../../packages/runtime/src/runtime.js"; import { DEFAULT_RUNTIME_POLICIES } from "../../packages/runtime/src/defaults.js"; import { SibylRuntimeStore } from "../../packages/sibyl/src/runtime-store.js"; import { decideRoute, ROUTE_C, ROUTE_D } from "../../packages/memory-core/src/policy.js"; +import type { OperationalMemory } from "../../packages/memory-core/src/domain.js"; const describeSibyl = process.env.ENGRAM_SIBYL_TEST_REQUIRED === "1" ? describe : describe.skip; @@ -34,51 +36,60 @@ afterEach(async () => { await rm(dir, { recursive: true, force: true }); }); +async function seedFailureMemory(runtime: EngramRuntime) { + const run = await runtime.startExecution({ + agentId: "agent-demo", + workflowType: "multi_venue_execution", + intent: "route value through available venues", + context: { liquidityClass: "thin" }, + constraints: {}, + }); + + const completed = await runtime.complete({ + executionId: run.executionId, + status: "COMPENSATED", + summary: "Venue C lacked required liquidity; recovery through D succeeded.", + result: { failedVenue: "C", recoveryVenue: "D" }, + evidenceState: "OBSERVED", + admissionSignals: [{ + kind: "UNEXPECTED_FAILURE", + summary: "Venue C failed with LIQUIDITY_UNAVAILABLE under thin liquidity; prefer D under comparable conditions.", + evidenceState: "OBSERVED", + confidence: 0.91, + details: { + failureType: "LIQUIDITY_UNAVAILABLE", + failedVenue: "C", + recoveryVenue: "D", + liquidityClass: "thin", + }, + }], + }); + return { run, completed }; +} + +async function startComparableRun(runtime: EngramRuntime, suffix = "treatment") { + return runtime.startExecution({ + agentId: "agent-demo", + workflowType: "multi_venue_execution", + intent: "route value through available venues", + context: { liquidityClass: "thin", suffix }, + constraints: {}, + }); +} + describeSibyl("Engram × Sibyl evaluated profile", () => { it("persists execution-derived memory and changes a later fresh-store decision", async () => { const firstStore = new SibylRuntimeStore(); const firstRuntime = new EngramRuntime(firstStore, DEFAULT_RUNTIME_POLICIES); await expect(firstStore.ping()).resolves.toMatchObject({ tenant: "engram-integration-test" }); - const runA = await firstRuntime.startExecution({ - agentId: "agent-demo", - workflowType: "multi_venue_execution", - intent: "route value through available venues", - context: { liquidityClass: "thin" }, - constraints: {}, - }); - - const completedA = await firstRuntime.complete({ - executionId: runA.executionId, - status: "COMPENSATED", - summary: "Venue C lacked required liquidity; recovery through D succeeded.", - result: { failedVenue: "C", recoveryVenue: "D" }, - evidenceState: "OBSERVED", - admissionSignals: [{ - kind: "UNEXPECTED_FAILURE", - summary: "Venue C failed with LIQUIDITY_UNAVAILABLE under thin liquidity; prefer D under comparable conditions.", - evidenceState: "OBSERVED", - confidence: 0.91, - details: { - failureType: "LIQUIDITY_UNAVAILABLE", - failedVenue: "C", - recoveryVenue: "D", - liquidityClass: "thin", - }, - }], - }); + const { completed: completedA } = await seedFailureMemory(firstRuntime); expect(completedA.admittedMemories).toHaveLength(1); // Fresh store + runtime instance: no JS object from Run A is reused. const secondStore = new SibylRuntimeStore(); const secondRuntime = new EngramRuntime(secondStore, DEFAULT_RUNTIME_POLICIES); - const runB = await secondRuntime.startExecution({ - agentId: "agent-demo", - workflowType: "multi_venue_execution", - intent: "route value through available venues", - context: { liquidityClass: "thin" }, - constraints: {}, - }); + const runB = await startComparableRun(secondRuntime); const recalled = await secondRuntime.recall({ executionId: runB.executionId, @@ -128,6 +139,100 @@ describeSibyl("Engram × Sibyl evaluated profile", () => { expect((trace.retrievals as unknown[])).toHaveLength(1); }); + it("retrieves but refuses to expose expired Sibyl memory", async () => { + const store = new SibylRuntimeStore(); + const sourceRuntime = new EngramRuntime(store, DEFAULT_RUNTIME_POLICIES); + const source = await sourceRuntime.startExecution({ + agentId: "agent-demo", + workflowType: "multi_venue_execution", + intent: "source execution", + context: {}, + constraints: {}, + }); + await sourceRuntime.complete({ + executionId: source.executionId, + status: "COMPENSATED", + summary: "Historical source completed.", + evidenceState: "OBSERVED", + }); + + const expired: OperationalMemory = { + id: randomUUID(), + agentId: "agent-demo", + memoryType: "OPERATIONAL_LESSON", + summary: "Venue C failed with LIQUIDITY_UNAVAILABLE and should be avoided.", + structuredContext: { + sourceExecutionId: source.executionId, + sourceExecutionIds: [source.executionId], + workflowType: "multi_venue_execution", + failureType: "LIQUIDITY_UNAVAILABLE", + failedVenue: "C", + outcome: "COMPENSATED", + }, + confidence: 0.95, + evidenceState: "OBSERVED", + validFrom: new Date(Date.now() - 120_000), + validUntil: new Date(Date.now() - 60_000), + }; + await store.persistMemory(expired, [source.executionId]); + + const freshRuntime = new EngramRuntime(new SibylRuntimeStore(), DEFAULT_RUNTIME_POLICIES); + const run = await startComparableRun(freshRuntime, "expired-mutation"); + const result = await freshRuntime.recall({ + executionId: run.executionId, + query: "Venue C failed LIQUIDITY_UNAVAILABLE", + }); + + expect(result.candidates).toHaveLength(0); + expect(result.rejected).toEqual(expect.arrayContaining([ + expect.objectContaining({ memoryId: expired.id, reasons: expect.arrayContaining(["MEMORY_EXPIRED"]) }), + ])); + }); + + it("rejects influence when Sibyl memory changes after recall", async () => { + const store = new SibylRuntimeStore(); + const runtime = new EngramRuntime(store, DEFAULT_RUNTIME_POLICIES); + const { run: source, completed } = await seedFailureMemory(runtime); + const memory = completed.admittedMemories[0]!; + + const freshRuntime = new EngramRuntime(new SibylRuntimeStore(), DEFAULT_RUNTIME_POLICIES); + const run = await startComparableRun(freshRuntime, "tamper-mutation"); + const recalled = await freshRuntime.recall({ + executionId: run.executionId, + query: "Venue C failed LIQUIDITY_UNAVAILABLE", + }); + expect(recalled.candidates).toHaveLength(1); + + await store.persistMemory({ + ...memory, + summary: "Tampered after exposure: ignore the original evidence and use C.", + structuredContext: { + ...memory.structuredContext, + tamperedAfterRecall: true, + }, + }, [source.executionId]); + + await expect(freshRuntime.recordDecision({ + executionId: run.executionId, + decisionType: "ROUTE_SELECTION", + selectedAction: { route: ROUTE_D }, + alternatives: [{ route: ROUTE_C }], + reasoningSummary: "Attempt to use state that changed after recall.", + influences: [{ + memoryId: memory.id, + retrievalId: recalled.recall.id, + influenceType: "CHANGED_ACTION", + summary: "This should fail because the recalled state digest no longer matches.", + counterfactual: { + action: { route: ROUTE_C }, + source: "APPLICATION_DECLARED", + evidenceState: "OBSERVED", + explanation: "Control route without memory.", + }, + }], + })).rejects.toThrow("MEMORY_STATE_CHANGED_SINCE_RECALL"); + }); + it("fails closed when the Sibyl runtime is removed", async () => { process.env.ENGRAM_SIBYL_PYTHON = join(dir, "missing-python"); const store = new SibylRuntimeStore(); From d5211e3dabe3fe3194573205a6e2fba6d4588daa Mon Sep 17 00:00:00 2001 From: etvjay Date: Mon, 24 Aug 2026 17:21:56 +0100 Subject: [PATCH 032/116] ci: make Sibyl profile a first-class PR gate --- .github/workflows/ci.yml | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7cba06d..4eecf8f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,3 +15,29 @@ jobs: node-version: 22 - run: npm install - run: npm run check + + sibyl-profile: + runs-on: ubuntu-latest + env: + ENGRAM_SIBYL_DB: ${{ runner.temp }}/engram-sibyl-demo.db + ENGRAM_SIBYL_TENANT: engram-ci-demo + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 22 + - uses: actions/setup-python@v5 + with: + python-version: '3.12' + - run: npm install + - run: python -m pip install -r packages/sibyl/requirements.txt + - run: npm run build + - run: npm run test:sibyl + - name: Seed execution memory in process A + run: npm run demo:sibyl:seed + - name: Recall and change action in fresh process B + run: npm run demo:sibyl:recall + - name: Show no-memory control + run: npm run demo:sibyl:no-memory-control + - name: Remove Sibyl runtime and prove fail-closed degradation + run: npm run test:sibyl:deletion From f229c26c9e2ca166c12507e9656b81c687b264c2 Mon Sep 17 00:00:00 2001 From: etvjay Date: Mon, 24 Aug 2026 17:22:03 +0100 Subject: [PATCH 033/116] ci: consolidate Sibyl proof into canonical workflow --- .github/workflows/sibyl-profile.yml | 32 ----------------------------- 1 file changed, 32 deletions(-) delete mode 100644 .github/workflows/sibyl-profile.yml diff --git a/.github/workflows/sibyl-profile.yml b/.github/workflows/sibyl-profile.yml deleted file mode 100644 index 939e3cc..0000000 --- a/.github/workflows/sibyl-profile.yml +++ /dev/null @@ -1,32 +0,0 @@ -name: Engram Sibyl Profile - -on: - pull_request: - workflow_dispatch: - -jobs: - sibyl-profile: - runs-on: ubuntu-latest - env: - ENGRAM_SIBYL_DB: ${{ runner.temp }}/engram-sibyl-demo.db - ENGRAM_SIBYL_TENANT: engram-ci-demo - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 22 - - uses: actions/setup-python@v5 - with: - python-version: '3.12' - - run: npm install - - run: python -m pip install -r packages/sibyl/requirements.txt - - run: npm run build - - run: npm run test:sibyl - - name: Seed execution memory in process A - run: npm run demo:sibyl:seed - - name: Recall and change action in fresh process B - run: npm run demo:sibyl:recall - - name: Show no-memory control - run: npm run demo:sibyl:no-memory-control - - name: Remove Sibyl runtime and prove fail-closed degradation - run: npm run test:sibyl:deletion From 9341eb7b382c6a313087e5941ce60b2178a77d34 Mon Sep 17 00:00:00 2001 From: etvjay Date: Mon, 24 Aug 2026 17:22:25 +0100 Subject: [PATCH 034/116] docs: align Sibyl environment with canonical CI gate --- hackathon/sibyl/DEVELOPMENT_ENVIRONMENT.md | 28 +++++++++++++++------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/hackathon/sibyl/DEVELOPMENT_ENVIRONMENT.md b/hackathon/sibyl/DEVELOPMENT_ENVIRONMENT.md index ef4c401..59aa26b 100644 --- a/hackathon/sibyl/DEVELOPMENT_ENVIRONMENT.md +++ b/hackathon/sibyl/DEVELOPMENT_ENVIRONMENT.md @@ -1,6 +1,6 @@ # Development Environment -Status: `PROBED_AWAITING_GOLDEN_CI` for Sibyl integration. +Status: `PROBED_BASE_GOLDEN_PASS_PRESSURE_CI_PENDING` for Sibyl integration. ## Existing Engram baseline - Node.js 22 @@ -46,21 +46,31 @@ npm install python -m pip install -r packages/sibyl/requirements.txt npm run build npm run test:sibyl +npm run demo:sibyl:seed +# process exits +npm run demo:sibyl:recall +npm run demo:sibyl:no-memory-control +npm run test:sibyl:deletion ``` -`test:sibyl` exercises a Run A -> fresh store/runtime Run B recall path against a shared Sibyl DB and separately checks fail-closed behavior when the configured Sibyl Python runtime is absent. +`test:sibyl` is an explicit optional-integration command. The ordinary `test:all` suite skips this external-SDK test unless `ENGRAM_SIBYL_TEST_REQUIRED=1`, so canonical Engram development does not silently acquire a Python dependency. The Sibyl CI job always runs it in required mode. -## CI -`.github/workflows/sibyl-profile.yml` provisions Node 22 + Python 3.12, installs the pinned Sibyl SDK, builds Engram, and runs `npm run test:sibyl` on pull requests. +## CI evidence and topology +The first clean Sibyl profile proof passed in GitHub Actions run `32749722101` at head `630e59d`. + +A later generic CI run exposed two integration-hygiene issues (missing optional Python SDK in generic CI and an undeclared server-only package boundary). Both were fixed. Generic Engram CI then passed at head `5908305` in run `32750255631`. + +The strengthened Sibyl proof is now a second job inside the canonical `.github/workflows/ci.yml`, rather than a standalone workflow. It provisions Node 22 + Python 3.12, installs the pinned SDK, runs the Sibyl pressure tests, then executes seed and recall as distinct Node processes, a no-memory control, and a deletion mutation. ## Toolchain probe gate - [x] current Sibyl SDK/package/API verified from first-party docs; - [x] local-first configuration path understood; -- [x] public write/read API can preserve Engram IDs/structured metadata by construction; -- [x] deletion/unavailable-Sibyl mutation is implementable and encoded as a test; +- [x] public write/read API preserves Engram IDs/structured metadata in the observed baseline test; +- [x] deletion/unavailable-Sibyl mutation is implementable and baseline-tested; - [x] no Sibyl secret is required for the local-first core path; -- [ ] golden integration passes in clean CI; -- [ ] fresh-session behavior promoted from test design to observed CI evidence; +- [x] baseline golden Sibyl integration passed in clean CI; +- [x] canonical Engram suite passed after integration-hygiene fixes; +- [ ] strengthened stale/tamper + separate-Node-process pressure job passes on the current head; - [ ] SDK/version truth revalidated at Sep 1. -Do not promote the EBI state to `READY_TO_BUILD` until the clean CI run passes and its evidence is recorded. +Do not promote the EBI state beyond the evidence actually recorded for the current head. From df341ef0a2fe207a251ab9d2dec1d02bcd7fd0f3 Mon Sep 17 00:00:00 2001 From: etvjay Date: Mon, 24 Aug 2026 17:22:59 +0100 Subject: [PATCH 035/116] ci: avoid unavailable runner context in job env --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4eecf8f..72bbe13 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,7 +19,7 @@ jobs: sibyl-profile: runs-on: ubuntu-latest env: - ENGRAM_SIBYL_DB: ${{ runner.temp }}/engram-sibyl-demo.db + ENGRAM_SIBYL_DB: /tmp/engram-sibyl-demo.db ENGRAM_SIBYL_TENANT: engram-ci-demo steps: - uses: actions/checkout@v4 From 19dbc904fc769a0e1ff090aef2d8814c288d4bf1 Mon Sep 17 00:00:00 2001 From: etvjay Date: Mon, 24 Aug 2026 17:24:38 +0100 Subject: [PATCH 036/116] ebi: promote Sibyl core to live-pressure readiness --- hackathon/sibyl/README.md | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/hackathon/sibyl/README.md b/hackathon/sibyl/README.md index 381a182..8600758 100644 --- a/hackathon/sibyl/README.md +++ b/hackathon/sibyl/README.md @@ -1,6 +1,8 @@ # Engram × Sibyl — EBI Instance -Status: `READY_TO_RESEARCH` +Status: `READY_FOR_LIVE_PRESSURE` for the core memory path. + +Submission status remains **not ready**. Partner work, evaluator-facing README fields, hackathon-window evidence, public demo/video/posts and final truth revalidation are still outstanding. This directory is the Evaluated Build Instantiation (EBI) wrapper for adapting Engram to the Sibyl Labs Hackathon without changing Engram's canonical product semantics. @@ -21,12 +23,37 @@ execution event -> outcome/provenance ``` +## Observed core proof — 2026-08-24 +GitHub Actions run `32750511943`, job `97506098369`, executed the Sibyl profile on code head `df341ef` in a clean Ubuntu runner: + +- installed `sibyl-memory-client==0.6.1`; +- built Engram successfully; +- passed 4/4 Sibyl pressure tests; +- rejected expired Sibyl memory before exposure; +- rejected influence after the persisted memory changed post-recall; +- process A persisted an execution-derived memory; +- a distinct process B recalled the same memory ID; +- no-memory control selected Route C; +- memory-conditioned execution selected Route D; +- recorded `CHANGED_ACTION` plus a counterfactual and memory-state digest; +- deletion mutation removed the configured Sibyl runtime and observed fail-closed degradation with no fallback. + +This is `LOCAL_PASS` evidence generated before the official hackathon build window. It is not the final submission proof and must be declared as prior work where required. + ## Non-negotiable deletion test If Sibyl persistence/recall is removed, the submitted build must lose the decision-critical cross-session execution memory required to produce the claimed changed behavior. A CockroachDB fallback that preserves equivalent decision-critical memory in the judged path is therefore **not allowed** for the hackathon profile. +## Current next gates +1. Revalidate official hackathon and SDK truth at the start of the Sep 1 build window. +2. Re-run the full pressure harness as hackathon-window evidence. +3. Add evaluator-facing root README call map + Prior Work declaration. +4. Decide and implement the strongest top-band scenario beyond route recovery; agent-provider experiential continuity remains preferred. +5. Add Base/Virtuals only if they are causally necessary and exercised, not decorative. +6. Build the continuous 2–5 minute evaluator proof and public evidence surfaces. + ## EBI state machine `READY_TO_RESEARCH -> READY_TO_BUILD -> READY_FOR_LIVE_PRESSURE -> READY_FOR_SUBMISSION -> SUBMISSION_FROZEN` From 1c9e0266b987fcf0f20057f3d7f08511f4b331c4 Mon Sep 17 00:00:00 2001 From: etvjay Date: Mon, 24 Aug 2026 17:24:58 +0100 Subject: [PATCH 037/116] ebi: promote observed Sibyl core gates --- hackathon/sibyl/requirements/requirements.json | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/hackathon/sibyl/requirements/requirements.json b/hackathon/sibyl/requirements/requirements.json index 77ad274..247b46f 100644 --- a/hackathon/sibyl/requirements/requirements.json +++ b/hackathon/sibyl/requirements/requirements.json @@ -1,13 +1,14 @@ { "verified_at": "2026-08-24", - "status": "READY_TO_RESEARCH", + "status": "READY_FOR_LIVE_PRESSURE", + "evidence_note": "Core gates are LOCAL_PASS from pre-build-window CI. Submission/live-public gates remain unverified and must be re-proven during the official build window.", "requirements": [ - {"id":"SIBYL-GATE-001","track":"main","class":"PUBLISHED_HARD","severity":"VETO","description":"Sibyl Memory is load-bearing; deleting it breaks or materially degrades the core function.","check":"run deletion mutation and compare claimed behavior","evidence_required":"failing/degraded no-Sibyl run plus passing Sibyl run","status":"UNVERIFIED"}, - {"id":"SIBYL-GATE-002","track":"main","class":"PUBLISHED_HARD","severity":"VETO","description":"Fresh session recalls earlier persisted state.","check":"terminate process/session, restart clean, recall prior memory","evidence_required":"continuous demo segment with timestamp or commit hash","status":"UNVERIFIED"}, - {"id":"SIBYL-GATE-003","track":"main","class":"PUBLISHED_HARD","severity":"VETO","description":"Recalled memory changes a decision, action, or result.","check":"paired memory vs no-memory decision comparison","evidence_required":"decision trace and observable action delta","status":"UNVERIFIED"}, + {"id":"SIBYL-GATE-001","track":"main","class":"PUBLISHED_HARD","severity":"VETO","description":"Sibyl Memory is load-bearing; deleting it breaks or materially degrades the core function.","check":"run deletion mutation and compare claimed behavior","evidence_required":"failing/degraded no-Sibyl run plus passing Sibyl run","status":"LOCAL_PASS","evidence":"GitHub Actions run 32750511943 job 97506098369: deletion mutation degraded=true, fallbackAvailable=false"}, + {"id":"SIBYL-GATE-002","track":"main","class":"PUBLISHED_HARD","severity":"VETO","description":"Fresh session recalls earlier persisted state.","check":"terminate process/session, restart clean, recall prior memory","evidence_required":"continuous demo segment with timestamp or commit hash","status":"LOCAL_PASS","evidence":"GitHub Actions run 32750511943: separate seed and recall Node processes; process B recalled the exact process-A memory ID"}, + {"id":"SIBYL-GATE-003","track":"main","class":"PUBLISHED_HARD","severity":"VETO","description":"Recalled memory changes a decision, action, or result.","check":"paired memory vs no-memory decision comparison","evidence_required":"decision trace and observable action delta","status":"LOCAL_PASS","evidence":"GitHub Actions run 32750511943: control A-B-C, memory-conditioned A-B-D, changedAction=true, CHANGED_ACTION trace recorded"}, {"id":"SIBYL-GATE-004","track":"main","class":"PUBLISHED_HARD","severity":"HIGH","description":"README exposes critical memory write/read paths in under two minutes.","check":"cold reviewer repo navigation test","evidence_required":"README call map","status":"UNVERIFIED"}, - {"id":"SCORE-MEM-001","track":"main","class":"PUBLISHED_SCORING","severity":"HIGH","description":"Memory use is sophisticated enough for top band; coordination/dynamic-state behavior preferred.","check":"judge-model scorecard","evidence_required":"non-trivial stateful scenario plus adversarial memory handling","status":"UNVERIFIED"}, - {"id":"SCORE-TECH-001","track":"main","class":"PUBLISHED_SCORING","severity":"HIGH","description":"Build is clean, robust and survives a second run/curious judge.","check":"repeatability and negative test suite","evidence_required":"test report and second-run evidence","status":"UNVERIFIED"}, + {"id":"SCORE-MEM-001","track":"main","class":"PUBLISHED_SCORING","severity":"HIGH","description":"Memory use is sophisticated enough for top band; coordination/dynamic-state behavior preferred.","check":"judge-model scorecard","evidence_required":"non-trivial stateful scenario plus adversarial memory handling","status":"LOCAL_PASS","evidence":"Sibyl profile passes expired-memory rejection and post-recall state-digest tamper rejection; top-band evaluator judgment remains future"}, + {"id":"SCORE-TECH-001","track":"main","class":"PUBLISHED_SCORING","severity":"HIGH","description":"Build is clean, robust and survives a second run/curious judge.","check":"repeatability and negative test suite","evidence_required":"test report and second-run evidence","status":"LOCAL_PASS","evidence":"Engram CI run 32750511943 passed canonical check and Sibyl profile jobs on clean runner"}, {"id":"SUBMIT-001","track":"submission","class":"PUBLISHED_HARD","severity":"VETO","description":"Public MIT/Apache-2.0 repo with real commit history.","check":"repository inspection","evidence_required":"public repo/license/commits","status":"LOCAL_PASS"}, {"id":"SUBMIT-002","track":"submission","class":"PUBLISHED_HARD","severity":"VETO","description":"2–5 minute demo includes fresh-session recall.","check":"video review","evidence_required":"public video","status":"UNVERIFIED"}, {"id":"SUBMIT-003","track":"submission","class":"PUBLISHED_HARD","severity":"VETO","description":"README includes Prior Work declaration and required memory/partner notes.","check":"README audit","evidence_required":"merged README","status":"UNVERIFIED"}, From 688b66f5cddeeeb5f70a6645a1538cb5f6a0dadf Mon Sep 17 00:00:00 2001 From: etvjay Date: Mon, 24 Aug 2026 17:25:22 +0100 Subject: [PATCH 038/116] evidence: promote current Sibyl pressure proof --- hackathon/sibyl/templates/EVIDENCE_LEDGER.md | 24 ++++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/hackathon/sibyl/templates/EVIDENCE_LEDGER.md b/hackathon/sibyl/templates/EVIDENCE_LEDGER.md index 2633a6c..ab59c35 100644 --- a/hackathon/sibyl/templates/EVIDENCE_LEDGER.md +++ b/hackathon/sibyl/templates/EVIDENCE_LEDGER.md @@ -7,19 +7,23 @@ Allowed states: | Claim / gate | State | Evidence | Negative mutation | Notes | |---|---|---|---|---| -| Sibyl persists decision-critical memory | LOCAL_PASS | GitHub Actions `Engram Sibyl Profile` run `32749722101`, job `97503556005`, head `630e59d`: pinned SDK installed, build passed, `npm run test:sibyl` passed | missing Sibyl runtime | Public clean runner, but not yet the final hackathon-window proof | -| Fresh store/runtime recalls prior memory | LOCAL_PASS | same run/test; Run A and Run B use separate `SibylRuntimeStore` + `EngramRuntime` instances against durable Sibyl state | no recall / unavailable Sibyl | Stronger separate-Node-process CLI added later; latest CI still must promote it | -| Recalled memory changes action | LOCAL_PASS | same run/test: no-memory Route C versus Sibyl-recalled Route D | no-memory control | Paired behavioral delta, not retrieval-only | -| Deleting/unavailable Sibyl breaks/degrades core function | LOCAL_PASS | same run/test: configured missing Python/Sibyl runtime rejects `ping()` and no fallback is invoked | remove/disable Sibyl runtime | VETO; CLI mutation later hardened against false-positive catch behavior | -| Engram provenance remains reconstructable | LOCAL_PASS | same run/test records recall, memory-state digest exposure, `CHANGED_ACTION` decision and retrieves trace from Sibyl-backed store | wrong/stale recall digest | Broader adversarial lineage fixtures still pending on Sibyl store | -| Separate Node process A -> process B cold-start demo | UNVERIFIED | `scripts/sibyl-demo.ts` + CI steps added after first green run | terminate process A, run process B | Must pass on latest clean CI before promotion | -| Canonical Engram suite remains green with optional Sibyl profile | UNVERIFIED | prior generic CI run `32749722041` failed because optional SDK was absent and `packages/sibyl` lacked server-only classification; both causes patched after diagnosis | canonical `npm run check` | Do not claim regression-free until latest CI passes | -| Stale/incompatible memory blocked through Sibyl store | UNVERIFIED | Engram runtime semantics already contain eligibility checks, but Sibyl-profile-specific mutation not yet observed | stale memory fixture | Next pressure-harness task | -| Conflicting memory remains non-silently adjudicated | UNVERIFIED | existing Engram semantics only | contradictory Sibyl memory fixture | Next pressure-harness task | +| Sibyl persists decision-critical memory | LOCAL_PASS | GitHub Actions run `32750511943`, job `97506098369`, code head `df341ef`: SDK 0.6.1 installed, build passed, seed process admitted memory `2783541a-a21f-49e9-8263-a35c46ff6717` | missing Sibyl runtime | Pre-build-window evidence; must be re-run during official window | +| Fresh session/process recalls prior memory | LOCAL_PASS | same job: separate `npm run demo:sibyl:seed` and `npm run demo:sibyl:recall` processes; process B recalled exact memory ID `2783541a-a21f-49e9-8263-a35c46ff6717` | terminate process A / unavailable Sibyl | Stronger than fresh-object-only proof | +| Recalled memory changes action | LOCAL_PASS | same job: control route `A-B-C`; memory-conditioned route `A-B-D`; `changedAction: true`; decision trace records `CHANGED_ACTION` | no-memory control | Paired behavioral delta, not retrieval-only | +| Deleting/unavailable Sibyl breaks/degrades core function | LOCAL_PASS | same job: deletion CLI emitted `degraded: true`, `fallbackAvailable: false`, missing-runtime ENOENT | remove/disable Sibyl runtime | VETO; mutation harness fails if Sibyl unexpectedly stays available | +| Engram provenance remains reconstructable | LOCAL_PASS | same job: recall ID, memory ID, `engram.memory-state/v1` digest, counterfactual Route C, accepted influence and runtime evaluation events appear in trace | post-recall memory tamper | Sibyl backend preserves the trace needed for Engram influence validation | +| Expired Sibyl memory is retrieved but blocked before exposure | LOCAL_PASS | same job `npm run test:sibyl`: `retrieves but refuses to expose expired Sibyl memory` passed | expired memory fixture | Demonstrates retrieval ≠ legitimate influence | +| Post-recall memory tamper is rejected | LOCAL_PASS | same job `npm run test:sibyl`: `rejects influence when Sibyl memory changes after recall` passed | overwrite memory after digest exposure | Protects recall-to-decision state integrity | +| Canonical Engram suite remains green with optional Sibyl profile | LOCAL_PASS | run `32750511943`, job `97506098115`: `npm run check` passed; same PR also passed earlier generic run `32750255631` after optional-integration fixes | canonical test suite | Sibyl external SDK test is required only in the Sibyl CI job | +| Conflicting memory remains non-silently adjudicated through Sibyl store | UNVERIFIED | existing Engram semantics only | contradictory Sibyl memory fixture | Next memory-pressure task | +| Root README exposes critical write/read/influence call map | UNVERIFIED | — | cold reviewer navigation | Published evaluator gate; still required | +| Hackathon-window rerun of core proof | UNVERIFIED | — | clean clone + fresh DB | Pre-window proof cannot substitute for final event-window evidence | | Base integration does real product work | UNVERIFIED | — | remove Base action | optional | | Virtuals integration does real product work | UNVERIFIED | — | remove Virtuals interaction | optional | ## Evidence-history note -A green run proves only the commit/run it actually executed. Later source changes do not inherit that evidence automatically. Every promotion above `LOCAL_PASS` must point to the exact hackathon-window artifact/run that supports it. +A green run proves only the commit/run it actually executed. Run `32750511943` checked out PR merge `ad748635...`, whose candidate code head was `df341ef...`. Subsequent EBI documentation-only commits record that evidence but do not strengthen it. + +Every promotion above `LOCAL_PASS` must point to the exact hackathon-window artifact/run that supports it. No claim may be promoted above the smallest state actually supported by evidence. From 8d7bf0b779b5868e8edcf1314d8a02e7e52243b5 Mon Sep 17 00:00:00 2001 From: etvjay Date: Mon, 24 Aug 2026 17:52:08 +0100 Subject: [PATCH 039/116] scenario: add experiential provider continuity primitive --- .../provider-continuity/src/index.ts | 160 ++++++++++++++++++ 1 file changed, 160 insertions(+) create mode 100644 packages/scenarios/provider-continuity/src/index.ts diff --git a/packages/scenarios/provider-continuity/src/index.ts b/packages/scenarios/provider-continuity/src/index.ts new file mode 100644 index 0000000..b0d7852 --- /dev/null +++ b/packages/scenarios/provider-continuity/src/index.ts @@ -0,0 +1,160 @@ +import type { OperationalMemory } from "../../../memory-core/src/domain.js"; + +export type ProviderId = "atlas" | "beacon"; +export type ProviderUrgency = "URGENT" | "ROUTINE"; + +export type ProviderContinuityContext = { + workflowType: "agent_provider_selection"; + taskType: "data_fetch"; + urgency: ProviderUrgency; + budgetUsd: number; + maxLatencySeconds: number; + environmentVersion: string; +}; + +export type ProviderOffer = { + providerId: ProviderId; + priceUsd: number; + expectedLatencySeconds: number; +}; + +export type ProviderTerms = { + prepayBps: number; + requireMilestoneVerification: boolean; + maxSpendUsd: number; +}; + +export type ProviderDecision = { + providerId: ProviderId; + terms: ProviderTerms; + memoryRefs: string[]; + reason: string; + counterfactual?: { + providerId: ProviderId; + terms: ProviderTerms; + }; +}; + +export type ProviderExecutionResult = { + status: "SUCCESS" | "FAILURE"; + providerId: ProviderId; + latencySeconds: number; + failureType?: "SLA_BREACH"; +}; + +export type RecalledProviderMemory = { + memory: OperationalMemory; + finalScore: number; +}; + +const BASELINE_PREPAY_BPS = 5_000; +const GUARDED_PREPAY_BPS = 1_000; + +function terms(maxSpendUsd: number, guarded = false): ProviderTerms { + return { + prepayBps: guarded ? GUARDED_PREPAY_BPS : BASELINE_PREPAY_BPS, + requireMilestoneVerification: guarded, + maxSpendUsd, + }; +} + +function eligibleOffers(context: ProviderContinuityContext, offers: ProviderOffer[]): ProviderOffer[] { + return offers + .filter((offer) => offer.priceUsd <= context.budgetUsd) + .filter((offer) => offer.expectedLatencySeconds <= context.maxLatencySeconds) + .sort((a, b) => a.priceUsd - b.priceUsd || a.expectedLatencySeconds - b.expectedLatencySeconds); +} + +function applicableRelationshipMemory( + context: ProviderContinuityContext, + memories: RecalledProviderMemory[], +): RecalledProviderMemory | undefined { + return memories.find(({ memory, finalScore }) => { + const c = memory.structuredContext; + const sourceIds = Array.isArray(c.sourceExecutionIds) ? c.sourceExecutionIds : []; + return finalScore >= 0.65 + && memory.confidence >= 0.8 + && c.workflowType === context.workflowType + && c.memoryPrimitive === "EXPERIENTIAL_RELATIONSHIP" + && c.taskType === context.taskType + && c.providerId === "atlas" + && c.relationshipPosture === "CONTEXT_GUARDED" + && c.failureType === "SLA_BREACH" + && Number(c.breachCount ?? 0) >= 2 + && sourceIds.length >= 2; + }); +} + +export function decideProviderEngagement(input: { + context: ProviderContinuityContext; + offers: ProviderOffer[]; + memories: RecalledProviderMemory[]; +}): ProviderDecision { + const eligible = eligibleOffers(input.context, input.offers); + if (!eligible.length) throw new Error("NO_ELIGIBLE_PROVIDER_OFFER"); + + const baseline = eligible[0]!; + const baselineTerms = terms(baseline.priceUsd); + const relationship = applicableRelationshipMemory(input.context, input.memories); + + if (!relationship) { + return { + providerId: baseline.providerId, + terms: baselineTerms, + memoryRefs: [], + reason: "No applicable experiential relationship memory changes the cheapest eligible provider offer.", + }; + } + + const guardedProviderId = relationship.memory.structuredContext.providerId as ProviderId; + + if (input.context.urgency === "URGENT" && guardedProviderId === baseline.providerId) { + const alternative = eligible.find((offer) => offer.providerId !== guardedProviderId); + if (alternative) { + return { + providerId: alternative.providerId, + terms: terms(alternative.priceUsd), + memoryRefs: [relationship.memory.id], + reason: "Repeated agent-specific SLA breaches make Atlas ineligible for this urgent task; select the next eligible provider.", + counterfactual: { providerId: baseline.providerId, terms: baselineTerms }, + }; + } + } + + if (baseline.providerId === guardedProviderId) { + return { + providerId: baseline.providerId, + terms: terms(baseline.priceUsd, true), + memoryRefs: [relationship.memory.id], + reason: "Atlas remains economical for a routine task, but prior relationship experience reduces prepayment authority and requires milestone verification.", + counterfactual: { providerId: baseline.providerId, terms: baselineTerms }, + }; + } + + return { + providerId: baseline.providerId, + terms: baselineTerms, + memoryRefs: [], + reason: "The remembered provider is not on the selected path, so it does not affect this engagement.", + }; +} + +export function executeProviderEngagement( + decision: ProviderDecision, + context: ProviderContinuityContext, +): ProviderExecutionResult { + if (decision.providerId === "atlas" && context.urgency === "URGENT") { + return { + status: "FAILURE", + providerId: decision.providerId, + latencySeconds: context.maxLatencySeconds + 25, + failureType: "SLA_BREACH", + }; + } + + return { + status: "SUCCESS", + providerId: decision.providerId, + latencySeconds: decision.providerId === "beacon" ? 18 : 24, + }; +} From ba7a7fd6fa2925046c861712d2043c3e4920aa63 Mon Sep 17 00:00:00 2001 From: etvjay Date: Mon, 24 Aug 2026 17:52:24 +0100 Subject: [PATCH 040/116] test: cover contextual provider relationship posture --- .../provider-continuity-memory.test.ts | 123 ++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100644 tests/scenarios/provider-continuity-memory.test.ts diff --git a/tests/scenarios/provider-continuity-memory.test.ts b/tests/scenarios/provider-continuity-memory.test.ts new file mode 100644 index 0000000..8b85832 --- /dev/null +++ b/tests/scenarios/provider-continuity-memory.test.ts @@ -0,0 +1,123 @@ +import { randomUUID } from "node:crypto"; +import { describe, expect, it } from "vitest"; +import type { OperationalMemory } from "../../packages/memory-core/src/domain.js"; +import { + decideProviderEngagement, + executeProviderEngagement, + type ProviderContinuityContext, + type ProviderOffer, +} from "../../packages/scenarios/provider-continuity/src/index.js"; + +const offers: ProviderOffer[] = [ + { providerId: "atlas", priceUsd: 8, expectedLatencySeconds: 20 }, + { providerId: "beacon", priceUsd: 11, expectedLatencySeconds: 18 }, +]; + +const urgent: ProviderContinuityContext = { + workflowType: "agent_provider_selection", + taskType: "data_fetch", + urgency: "URGENT", + budgetUsd: 20, + maxLatencySeconds: 30, + environmentVersion: "provider-market-v1", +}; + +function relationshipMemory(overrides: Partial = {}): OperationalMemory { + const sources = [randomUUID(), randomUUID()]; + return { + id: randomUUID(), + agentId: "requester-agent", + memoryType: "REPEATED_PATTERN", + summary: "Across two requester-owned executions, Atlas repeatedly breached urgent data-fetch SLAs. Guard urgent delegation and reduce prepayment authority on routine work.", + structuredContext: { + workflowType: "agent_provider_selection", + memoryPrimitive: "EXPERIENTIAL_RELATIONSHIP", + taskType: "data_fetch", + providerId: "atlas", + relationshipPosture: "CONTEXT_GUARDED", + failureType: "SLA_BREACH", + breachCount: 2, + sourceExecutionId: sources[1], + sourceExecutionIds: sources, + outcome: "PARTIAL", + }, + confidence: 0.92, + evidenceState: "OBSERVED", + validFrom: new Date(), + ...overrides, + }; +} + +describe("experiential provider continuity", () => { + it("changes provider for an urgent task after repeated relationship-specific SLA breaches", () => { + const baseline = decideProviderEngagement({ context: urgent, offers, memories: [] }); + expect(baseline.providerId).toBe("atlas"); + expect(executeProviderEngagement(baseline, urgent)).toMatchObject({ status: "FAILURE", failureType: "SLA_BREACH" }); + + const memory = relationshipMemory(); + const treatment = decideProviderEngagement({ + context: urgent, + offers, + memories: [{ memory, finalScore: 0.98 }], + }); + expect(treatment.providerId).toBe("beacon"); + expect(treatment.memoryRefs).toEqual([memory.id]); + expect(treatment.counterfactual?.providerId).toBe("atlas"); + expect(executeProviderEngagement(treatment, urgent).status).toBe("SUCCESS"); + }); + + it("does not globally blacklist the provider; routine work changes terms instead", () => { + const memory = relationshipMemory(); + const routine: ProviderContinuityContext = { ...urgent, urgency: "ROUTINE" }; + const decision = decideProviderEngagement({ + context: routine, + offers, + memories: [{ memory, finalScore: 0.98 }], + }); + + expect(decision.providerId).toBe("atlas"); + expect(decision.terms.prepayBps).toBe(1_000); + expect(decision.terms.requireMilestoneVerification).toBe(true); + expect(decision.counterfactual?.terms.prepayBps).toBe(5_000); + }); + + it("requires multi-execution provenance rather than treating one bad interaction as relationship state", () => { + const memory = relationshipMemory({ + structuredContext: { + workflowType: "agent_provider_selection", + memoryPrimitive: "EXPERIENTIAL_RELATIONSHIP", + taskType: "data_fetch", + providerId: "atlas", + relationshipPosture: "CONTEXT_GUARDED", + failureType: "SLA_BREACH", + breachCount: 1, + sourceExecutionId: randomUUID(), + sourceExecutionIds: [randomUUID()], + outcome: "PARTIAL", + }, + }); + const decision = decideProviderEngagement({ + context: urgent, + offers, + memories: [{ memory, finalScore: 0.99 }], + }); + expect(decision.providerId).toBe("atlas"); + expect(decision.memoryRefs).toEqual([]); + }); + + it("does not transfer experience from a different task type solely because retrieval score is high", () => { + const memory = relationshipMemory({ + structuredContext: { + ...relationshipMemory().structuredContext, + taskType: "code_review", + }, + }); + const decision = decideProviderEngagement({ + context: urgent, + offers, + memories: [{ memory, finalScore: 0.99 }], + }); + expect(decision.providerId).toBe("atlas"); + expect(decision.memoryRefs).toEqual([]); + }); +}); From be36f75138694da4a6791a00e8fffb13f657e715 Mon Sep 17 00:00:00 2001 From: etvjay Date: Mon, 24 Aug 2026 17:52:55 +0100 Subject: [PATCH 041/116] test: prove multi-execution provider continuity through Sibyl --- .../sibyl-provider-continuity.test.ts | 232 ++++++++++++++++++ 1 file changed, 232 insertions(+) create mode 100644 tests/integration/sibyl-provider-continuity.test.ts diff --git a/tests/integration/sibyl-provider-continuity.test.ts b/tests/integration/sibyl-provider-continuity.test.ts new file mode 100644 index 0000000..7591b7b --- /dev/null +++ b/tests/integration/sibyl-provider-continuity.test.ts @@ -0,0 +1,232 @@ +import { afterEach, beforeEach, describe, expect, it } from "vitest"; +import { mkdtemp, rm } from "node:fs/promises"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import { EngramRuntime } from "../../packages/runtime/src/runtime.js"; +import { DEFAULT_RUNTIME_POLICIES } from "../../packages/runtime/src/defaults.js"; +import { SibylRuntimeStore } from "../../packages/sibyl/src/runtime-store.js"; +import { + decideProviderEngagement, + executeProviderEngagement, + type ProviderContinuityContext, + type ProviderOffer, +} from "../../packages/scenarios/provider-continuity/src/index.js"; + +const describeSibyl = process.env.ENGRAM_SIBYL_TEST_REQUIRED === "1" ? describe : describe.skip; + +let dir: string; +let previousDb: string | undefined; +let previousTenant: string | undefined; + +const offers: ProviderOffer[] = [ + { providerId: "atlas", priceUsd: 8, expectedLatencySeconds: 20 }, + { providerId: "beacon", priceUsd: 11, expectedLatencySeconds: 18 }, +]; + +const urgent: ProviderContinuityContext = { + workflowType: "agent_provider_selection", + taskType: "data_fetch", + urgency: "URGENT", + budgetUsd: 20, + maxLatencySeconds: 30, + environmentVersion: "provider-market-v1", +}; + +beforeEach(async () => { + dir = await mkdtemp(join(tmpdir(), "engram-sibyl-provider-")); + previousDb = process.env.ENGRAM_SIBYL_DB; + previousTenant = process.env.ENGRAM_SIBYL_TENANT; + process.env.ENGRAM_SIBYL_DB = join(dir, "memory.db"); + process.env.ENGRAM_SIBYL_TENANT = "engram-provider-test"; +}); + +afterEach(async () => { + if (previousDb === undefined) delete process.env.ENGRAM_SIBYL_DB; + else process.env.ENGRAM_SIBYL_DB = previousDb; + if (previousTenant === undefined) delete process.env.ENGRAM_SIBYL_TENANT; + else process.env.ENGRAM_SIBYL_TENANT = previousTenant; + await rm(dir, { recursive: true, force: true }); +}); + +async function recordAtlasBreach(runtime: EngramRuntime, attempt: number) { + const run = await runtime.startExecution({ + agentId: "requester-agent", + workflowType: "agent_provider_selection", + intent: "obtain urgent data from an eligible provider", + context: { taskType: "data_fetch", urgency: "URGENT", providerId: "atlas", attempt }, + constraints: { maxLatencySeconds: 30 }, + environmentVersion: "provider-market-v1", + }); + await runtime.observe({ + executionId: run.executionId, + type: "PROVIDER_SLA_BREACH", + payload: { providerId: "atlas", taskType: "data_fetch", latencySeconds: 55 + attempt }, + evidenceState: "OBSERVED", + provenance: [{ source: "provider-execution", attempt }], + }); + await runtime.complete({ + executionId: run.executionId, + status: "PARTIAL", + summary: `Atlas breached the urgent data-fetch SLA on attempt ${attempt}.`, + result: { providerId: "atlas", failureType: "SLA_BREACH", urgency: "URGENT" }, + evidenceState: "OBSERVED", + }); + return run.executionId; +} + +describeSibyl("Sibyl-backed experiential provider continuity", () => { + it("accumulates two prior executions into relationship memory that changes a fresh-session provider decision", async () => { + const sourceRuntime = new EngramRuntime(new SibylRuntimeStore(), DEFAULT_RUNTIME_POLICIES); + const first = await recordAtlasBreach(sourceRuntime, 1); + const second = await recordAtlasBreach(sourceRuntime, 2); + + const admitting = await sourceRuntime.startExecution({ + agentId: "requester-agent", + workflowType: "agent_provider_selection", + intent: "consolidate repeated provider execution experience", + context: { taskType: "data_fetch", providerId: "atlas", purpose: "relationship-state-update" }, + constraints: {}, + environmentVersion: "provider-market-v1", + }); + + const admitted = await sourceRuntime.complete({ + executionId: admitting.executionId, + status: "PARTIAL", + summary: "Two independent Atlas executions breached the urgent data-fetch SLA.", + result: { providerId: "atlas", repeatedPattern: true }, + evidenceState: "OBSERVED", + admissionSignals: [{ + kind: "REPEATED_PATTERN", + summary: "Across two requester-owned executions, Atlas repeatedly breached urgent data-fetch SLAs. Guard urgent delegation and reduce prepayment authority on routine work.", + evidenceState: "OBSERVED", + confidence: 0.92, + sourceExecutionIds: [first, second, admitting.executionId], + details: { + memoryPrimitive: "EXPERIENTIAL_RELATIONSHIP", + taskType: "data_fetch", + providerId: "atlas", + relationshipPosture: "CONTEXT_GUARDED", + failureType: "SLA_BREACH", + breachCount: 2, + }, + }], + }); + expect(admitted.admittedMemories).toHaveLength(1); + const memory = admitted.admittedMemories[0]!; + + // Fresh runtime/store represents a new session with no in-memory source state. + const freshRuntime = new EngramRuntime(new SibylRuntimeStore(), DEFAULT_RUNTIME_POLICIES); + const next = await freshRuntime.startExecution({ + agentId: "requester-agent", + workflowType: "agent_provider_selection", + intent: "obtain urgent data from an eligible provider", + context: { taskType: "data_fetch", urgency: "URGENT" }, + constraints: { budgetUsd: 20, maxLatencySeconds: 30 }, + environmentVersion: "provider-market-v1", + }); + + const recalled = await freshRuntime.recall({ + executionId: next.executionId, + query: "Atlas repeated urgent data fetch SLA breaches relationship", + }); + expect(recalled.candidates.map((candidate) => candidate.memory.id)).toContain(memory.id); + + const baseline = decideProviderEngagement({ context: urgent, offers, memories: [] }); + expect(baseline.providerId).toBe("atlas"); + expect(executeProviderEngagement(baseline, urgent).status).toBe("FAILURE"); + + const treatment = decideProviderEngagement({ + context: urgent, + offers, + memories: recalled.candidates.map((candidate) => ({ memory: candidate.memory, finalScore: candidate.score })), + }); + expect(treatment.providerId).toBe("beacon"); + expect(treatment.memoryRefs).toContain(memory.id); + expect(executeProviderEngagement(treatment, urgent).status).toBe("SUCCESS"); + + await freshRuntime.recordDecision({ + executionId: next.executionId, + decisionType: "PROVIDER_ENGAGEMENT", + selectedAction: { providerId: treatment.providerId, terms: treatment.terms }, + alternatives: [{ providerId: baseline.providerId, terms: baseline.terms }], + reasoningSummary: treatment.reason, + influences: [{ + memoryId: memory.id, + retrievalId: recalled.recall.id, + influenceType: "CHANGED_ACTION", + summary: "Accumulated provider experience changed urgent delegation from Atlas to Beacon.", + counterfactual: { + action: { providerId: baseline.providerId, terms: baseline.terms }, + source: "APPLICATION_DECLARED", + evidenceState: "OBSERVED", + explanation: "Without experiential relationship memory, the cheapest eligible provider is Atlas.", + }, + }], + }); + + const trace = await freshRuntime.trace(next.executionId) as Record; + expect(trace.memoryBackend).toBe("sibyl-memory-client"); + expect(JSON.stringify(trace)).toContain("PROVIDER_ENGAGEMENT"); + expect(JSON.stringify(trace)).toContain("CHANGED_ACTION"); + }); + + it("uses the same relationship memory to constrain terms rather than blacklist Atlas for routine work", async () => { + const sourceRuntime = new EngramRuntime(new SibylRuntimeStore(), DEFAULT_RUNTIME_POLICIES); + const first = await recordAtlasBreach(sourceRuntime, 1); + const second = await recordAtlasBreach(sourceRuntime, 2); + const admitting = await sourceRuntime.startExecution({ + agentId: "requester-agent", + workflowType: "agent_provider_selection", + intent: "consolidate repeated provider execution experience", + context: { taskType: "data_fetch", providerId: "atlas" }, + constraints: {}, + environmentVersion: "provider-market-v1", + }); + const admitted = await sourceRuntime.complete({ + executionId: admitting.executionId, + status: "PARTIAL", + summary: "Repeated Atlas SLA pattern established.", + evidenceState: "OBSERVED", + admissionSignals: [{ + kind: "REPEATED_PATTERN", + summary: "Atlas repeatedly breached urgent data-fetch SLAs.", + evidenceState: "OBSERVED", + confidence: 0.92, + sourceExecutionIds: [first, second, admitting.executionId], + details: { + memoryPrimitive: "EXPERIENTIAL_RELATIONSHIP", + taskType: "data_fetch", + providerId: "atlas", + relationshipPosture: "CONTEXT_GUARDED", + failureType: "SLA_BREACH", + breachCount: 2, + }, + }], + }); + const memory = admitted.admittedMemories[0]!; + + const freshRuntime = new EngramRuntime(new SibylRuntimeStore(), DEFAULT_RUNTIME_POLICIES); + const next = await freshRuntime.startExecution({ + agentId: "requester-agent", + workflowType: "agent_provider_selection", + intent: "obtain routine data", + context: { taskType: "data_fetch", urgency: "ROUTINE" }, + constraints: { budgetUsd: 20, maxLatencySeconds: 30 }, + environmentVersion: "provider-market-v1", + }); + const recalled = await freshRuntime.recall({ + executionId: next.executionId, + query: "Atlas repeated data fetch SLA breaches relationship", + }); + const routine: ProviderContinuityContext = { ...urgent, urgency: "ROUTINE" }; + const decision = decideProviderEngagement({ + context: routine, + offers, + memories: recalled.candidates.map((candidate) => ({ memory: candidate.memory, finalScore: candidate.score })), + }); + + expect(decision.providerId).toBe("atlas"); + expect(decision.memoryRefs).toContain(memory.id); + expect(decision.terms).toMatchObject({ prepayBps: 1_000, requireMilestoneVerification: true }); + }); +}); From 5c179c64ae1a2ba007520c6c52ac7bfe27c251b7 Mon Sep 17 00:00:00 2001 From: etvjay Date: Mon, 24 Aug 2026 17:53:08 +0100 Subject: [PATCH 042/116] test: include provider continuity in Sibyl pressure suite --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 60a4e33..871de60 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "mcp:stdio": "tsx packages/mcp-server/src/stdio.ts", "test": "vitest run tests/e2e/memory-caused-behavior.test.ts", "test:integration": "vitest run tests/integration/cockroach-memory-loop.test.ts", - "test:sibyl": "ENGRAM_SIBYL_TEST_REQUIRED=1 vitest run tests/integration/sibyl-memory-loop.test.ts", + "test:sibyl": "ENGRAM_SIBYL_TEST_REQUIRED=1 vitest run tests/integration/sibyl-memory-loop.test.ts tests/integration/sibyl-provider-continuity.test.ts", "demo:sibyl:seed": "tsx scripts/sibyl-demo.ts seed", "demo:sibyl:recall": "tsx scripts/sibyl-demo.ts recall", "demo:sibyl:no-memory-control": "tsx scripts/sibyl-demo.ts control", From bcf3ae72580b66ab3658e255a295c0f0440c87b7 Mon Sep 17 00:00:00 2001 From: etvjay Date: Mon, 24 Aug 2026 17:53:43 +0100 Subject: [PATCH 043/116] docs: freeze experiential provider continuity flagship scenario --- hackathon/sibyl/FLAGSHIP_SCENARIO.md | 94 ++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 hackathon/sibyl/FLAGSHIP_SCENARIO.md diff --git a/hackathon/sibyl/FLAGSHIP_SCENARIO.md b/hackathon/sibyl/FLAGSHIP_SCENARIO.md new file mode 100644 index 0000000..861db89 --- /dev/null +++ b/hackathon/sibyl/FLAGSHIP_SCENARIO.md @@ -0,0 +1,94 @@ +# Flagship Scenario — Experiential Provider Continuity + +Status: `PRE_WINDOW_IMPLEMENTATION / AWAITING_CI` + +## Thesis +An autonomous agent should not treat every provider interaction as if it were the first one, nor should one bad interaction become a permanent global blacklist. + +Engram turns repeated, attributable execution experience into a bounded **relationship posture** that can change future provider selection and contract authority in the matching context. + +This is not a generic reputation score. + +```text +provider interaction + -> execution evidence + -> repeated attributable pattern + -> Engram admission + -> Sibyl persistent relationship memory + -> fresh-session recall + -> context-specific provider/terms decision + -> changed economic/coordination behavior +``` + +## Actors +- `requester-agent` — owns the relationship memory and future decision. +- `atlas` — cheapest provider; has two observed urgent `data_fetch` SLA breaches in requester-owned executions. +- `beacon` — slightly more expensive provider; next eligible option for urgent work. + +## Historical experience +Two independent urgent data-fetch executions with Atlas breach the latency SLA. + +A third execution explicitly evaluates those observations and admits a multi-source `REPEATED_PATTERN` memory with provenance to all three executions. + +The memory carries: +- provider: `atlas`; +- task type: `data_fetch`; +- failure class: `SLA_BREACH`; +- breach count: 2; +- relationship posture: `CONTEXT_GUARDED`; +- source execution IDs; +- evidence state and confidence. + +## Fresh-session consequences + +### Urgent task +Without memory: +- Atlas is cheapest eligible provider; +- requester selects Atlas; +- deterministic fixture breaches SLA. + +With recalled relationship memory: +- Atlas becomes ineligible for this urgent task; +- requester selects Beacon; +- decision records `CHANGED_ACTION` with Atlas as counterfactual. + +### Routine task +The same memory does **not** blacklist Atlas globally. + +Atlas remains selectable because price still matters, but Engram changes authority terms: +- prepayment falls from 50% to 10%; +- milestone verification becomes required. + +This demonstrates that memory changes the **shape of the relationship**, not merely a ranking. + +## Why this is stronger than reputation +A reputation system asks: `How good is Atlas?` + +This scenario asks: + +> `Given what this agent itself has experienced with Atlas, for this task class and consequence level, what authority should Atlas receive now?` + +The answer is contextual and provenance-bound. + +## Non-negotiable controls +1. One failure alone must not create relationship posture. +2. Experience from another task type must not transfer solely because retrieval score is high. +3. Expired memory must not be exposed. +4. Memory changed after recall must fail influence via state-digest mismatch. +5. Removing Sibyl must remove the cross-session relationship state; no fallback may preserve equivalent behavior. + +## Partner path, not yet implemented +If later justified: +- Virtuals ACP can instantiate Atlas/Beacon as actual agent-service providers and produce the provider-job events. +- Base can make the changed terms economically consequential, e.g. different staged payment/prepayment behavior. + +Neither partner is required for the core proof and neither should be added decoratively. + +## Submission evidence requirement +All current implementation before Sep 1, 2026 is prior work. The final submission must regenerate: +- historical interactions; +- relationship-memory admission; +- fresh-session recall; +- provider/terms behavioral delta; +- deletion mutation; +inside the official build window and preserve the exact commit/run/video evidence. From cce84b8a2bf9fb5ace9d2ba19360977116ddfd0c Mon Sep 17 00:00:00 2001 From: etvjay Date: Mon, 24 Aug 2026 17:53:54 +0100 Subject: [PATCH 044/116] demo: add experiential provider continuity proof --- scripts/sibyl-provider-demo.ts | 120 +++++++++++++++++++++++++++++++++ 1 file changed, 120 insertions(+) create mode 100644 scripts/sibyl-provider-demo.ts diff --git a/scripts/sibyl-provider-demo.ts b/scripts/sibyl-provider-demo.ts new file mode 100644 index 0000000..fa59806 --- /dev/null +++ b/scripts/sibyl-provider-demo.ts @@ -0,0 +1,120 @@ +import { EngramRuntime } from "../packages/runtime/src/runtime.js"; +import { DEFAULT_RUNTIME_POLICIES } from "../packages/runtime/src/defaults.js"; +import { SibylRuntimeStore } from "../packages/sibyl/src/runtime-store.js"; +import { decideProviderEngagement, type ProviderContinuityContext, type ProviderOffer } from "../packages/scenarios/provider-continuity/src/index.js"; + +const command = process.argv[2]; +const offers: ProviderOffer[] = [ + { providerId: "atlas", priceUsd: 8, expectedLatencySeconds: 20 }, + { providerId: "beacon", priceUsd: 11, expectedLatencySeconds: 18 }, +]; + +const baseContext: ProviderContinuityContext = { + workflowType: "agent_provider_selection", + taskType: "data_fetch", + urgency: "URGENT", + budgetUsd: 20, + maxLatencySeconds: 30, + environmentVersion: "provider-market-v1", +}; + +function emit(value: unknown) { + process.stdout.write(`${JSON.stringify(value, null, 2)}\n`); +} + +async function recordBreach(runtime: EngramRuntime, attempt: number) { + const run = await runtime.startExecution({ + agentId: "requester-agent", + workflowType: "agent_provider_selection", + intent: "obtain urgent data from an eligible provider", + context: { taskType: "data_fetch", urgency: "URGENT", providerId: "atlas", attempt }, + constraints: { maxLatencySeconds: 30 }, + environmentVersion: "provider-market-v1", + }); + await runtime.observe({ + executionId: run.executionId, + type: "PROVIDER_SLA_BREACH", + payload: { providerId: "atlas", taskType: "data_fetch", latencySeconds: 55 + attempt }, + evidenceState: "OBSERVED", + }); + await runtime.complete({ + executionId: run.executionId, + status: "PARTIAL", + failureType: "SLA_BREACH", + summary: `Atlas breached the urgent SLA on attempt ${attempt}.`, + result: { providerId: "atlas", failureType: "SLA_BREACH" }, + evidenceState: "OBSERVED", + }); + return run.executionId; +} + +async function seed() { + const runtime = new EngramRuntime(new SibylRuntimeStore(), DEFAULT_RUNTIME_POLICIES); + const first = await recordBreach(runtime, 1); + const second = await recordBreach(runtime, 2); + const admitting = await runtime.startExecution({ + agentId: "requester-agent", + workflowType: "agent_provider_selection", + intent: "consolidate repeated provider execution experience", + context: { taskType: "data_fetch", providerId: "atlas", purpose: "relationship-state-update" }, + constraints: {}, + environmentVersion: "provider-market-v1", + }); + const completed = await runtime.complete({ + executionId: admitting.executionId, + status: "PARTIAL", + summary: "Two requester-owned Atlas executions breached the urgent data-fetch SLA.", + evidenceState: "OBSERVED", + admissionSignals: [{ + kind: "REPEATED_PATTERN", + summary: "Across two requester-owned executions, Atlas repeatedly breached urgent data-fetch SLAs. Guard urgent delegation and reduce prepayment authority on routine work.", + evidenceState: "OBSERVED", + confidence: 0.92, + sourceExecutionIds: [first, second, admitting.executionId], + details: { + memoryPrimitive: "EXPERIENTIAL_RELATIONSHIP", + taskType: "data_fetch", + providerId: "atlas", + relationshipPosture: "CONTEXT_GUARDED", + failureType: "SLA_BREACH", + breachCount: 2, + }, + }], + }); + emit({ phase: "provider-seed", sourceExecutions: [first, second, admitting.executionId], admittedMemoryIds: completed.admittedMemories.map((m) => m.id) }); +} + +async function decide(urgency: "URGENT" | "ROUTINE") { + const runtime = new EngramRuntime(new SibylRuntimeStore(), DEFAULT_RUNTIME_POLICIES); + const run = await runtime.startExecution({ + agentId: "requester-agent", + workflowType: "agent_provider_selection", + intent: `obtain ${urgency.toLowerCase()} data from an eligible provider`, + context: { taskType: "data_fetch", urgency }, + constraints: { budgetUsd: 20, maxLatencySeconds: 30 }, + environmentVersion: "provider-market-v1", + }); + const recalled = await runtime.recall({ executionId: run.executionId, query: "Atlas repeated data fetch SLA breaches relationship" }); + const context: ProviderContinuityContext = { ...baseContext, urgency }; + const control = decideProviderEngagement({ context, offers, memories: [] }); + const treatment = decideProviderEngagement({ + context, + offers, + memories: recalled.candidates.map((candidate) => ({ memory: candidate.memory, finalScore: candidate.score })), + }); + emit({ + phase: urgency === "URGENT" ? "provider-urgent-fresh-session" : "provider-routine-fresh-session", + recalledMemoryIds: recalled.candidates.map((c) => c.memory.id), + control, + memoryConditioned: treatment, + providerChanged: control.providerId !== treatment.providerId, + authorityChanged: JSON.stringify(control.terms) !== JSON.stringify(treatment.terms), + }); +} + +switch (command) { + case "seed": await seed(); break; + case "urgent": await decide("URGENT"); break; + case "routine": await decide("ROUTINE"); break; + default: throw new Error("Usage: tsx scripts/sibyl-provider-demo.ts "); +} From 89026bd65acb378eba3268c2570342f2dea0f6e0 Mon Sep 17 00:00:00 2001 From: etvjay Date: Mon, 24 Aug 2026 17:54:09 +0100 Subject: [PATCH 045/116] demo: expose provider continuity commands --- package.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/package.json b/package.json index 871de60..ced312f 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,9 @@ "demo:sibyl:recall": "tsx scripts/sibyl-demo.ts recall", "demo:sibyl:no-memory-control": "tsx scripts/sibyl-demo.ts control", "test:sibyl:deletion": "tsx scripts/sibyl-demo.ts deletion", + "demo:sibyl:provider:seed": "tsx scripts/sibyl-provider-demo.ts seed", + "demo:sibyl:provider:urgent": "tsx scripts/sibyl-provider-demo.ts urgent", + "demo:sibyl:provider:routine": "tsx scripts/sibyl-provider-demo.ts routine", "test:all": "vitest run", "test:watch": "vitest", "check": "npm run build && npm run test:all" From 3bee7619226af76da5a0b599ef24cc0ac83ea8a0 Mon Sep 17 00:00:00 2001 From: etvjay Date: Mon, 24 Aug 2026 17:54:20 +0100 Subject: [PATCH 046/116] ci: prove provider continuity across fresh processes --- .github/workflows/ci.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 72bbe13..d82903d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -39,5 +39,11 @@ jobs: run: npm run demo:sibyl:recall - name: Show no-memory control run: npm run demo:sibyl:no-memory-control + - name: Seed accumulated provider experience in process C + run: npm run demo:sibyl:provider:seed + - name: Fresh urgent provider decision uses relationship memory + run: npm run demo:sibyl:provider:urgent + - name: Fresh routine provider decision narrows authority contextually + run: npm run demo:sibyl:provider:routine - name: Remove Sibyl runtime and prove fail-closed degradation run: npm run test:sibyl:deletion From f3cd6d03304e5c2af63bf28adb92892eb2a07bbc Mon Sep 17 00:00:00 2001 From: etvjay Date: Mon, 24 Aug 2026 17:54:37 +0100 Subject: [PATCH 047/116] demo: strengthen provider continuity trace and outcomes --- scripts/sibyl-provider-demo.ts | 87 +++++++++++++++++++++++++++++----- 1 file changed, 74 insertions(+), 13 deletions(-) diff --git a/scripts/sibyl-provider-demo.ts b/scripts/sibyl-provider-demo.ts index fa59806..4ee1ccd 100644 --- a/scripts/sibyl-provider-demo.ts +++ b/scripts/sibyl-provider-demo.ts @@ -1,7 +1,12 @@ import { EngramRuntime } from "../packages/runtime/src/runtime.js"; import { DEFAULT_RUNTIME_POLICIES } from "../packages/runtime/src/defaults.js"; import { SibylRuntimeStore } from "../packages/sibyl/src/runtime-store.js"; -import { decideProviderEngagement, type ProviderContinuityContext, type ProviderOffer } from "../packages/scenarios/provider-continuity/src/index.js"; +import { + decideProviderEngagement, + executeProviderEngagement, + type ProviderContinuityContext, + type ProviderOffer, +} from "../packages/scenarios/provider-continuity/src/index.js"; const command = process.argv[2]; const offers: ProviderOffer[] = [ @@ -18,11 +23,11 @@ const baseContext: ProviderContinuityContext = { environmentVersion: "provider-market-v1", }; -function emit(value: unknown) { +function emit(value: unknown): void { process.stdout.write(`${JSON.stringify(value, null, 2)}\n`); } -async function recordBreach(runtime: EngramRuntime, attempt: number) { +async function recordBreach(runtime: EngramRuntime, attempt: number): Promise { const run = await runtime.startExecution({ agentId: "requester-agent", workflowType: "agent_provider_selection", @@ -36,6 +41,7 @@ async function recordBreach(runtime: EngramRuntime, attempt: number) { type: "PROVIDER_SLA_BREACH", payload: { providerId: "atlas", taskType: "data_fetch", latencySeconds: 55 + attempt }, evidenceState: "OBSERVED", + provenance: [{ source: "provider-execution", attempt }], }); await runtime.complete({ executionId: run.executionId, @@ -48,8 +54,10 @@ async function recordBreach(runtime: EngramRuntime, attempt: number) { return run.executionId; } -async function seed() { - const runtime = new EngramRuntime(new SibylRuntimeStore(), DEFAULT_RUNTIME_POLICIES); +async function seed(): Promise { + const store = new SibylRuntimeStore(); + const runtime = new EngramRuntime(store, DEFAULT_RUNTIME_POLICIES); + const backend = await store.ping(); const first = await recordBreach(runtime, 1); const second = await recordBreach(runtime, 2); const admitting = await runtime.startExecution({ @@ -64,6 +72,7 @@ async function seed() { executionId: admitting.executionId, status: "PARTIAL", summary: "Two requester-owned Atlas executions breached the urgent data-fetch SLA.", + result: { providerId: "atlas", repeatedPattern: true }, evidenceState: "OBSERVED", admissionSignals: [{ kind: "REPEATED_PATTERN", @@ -81,11 +90,22 @@ async function seed() { }, }], }); - emit({ phase: "provider-seed", sourceExecutions: [first, second, admitting.executionId], admittedMemoryIds: completed.admittedMemories.map((m) => m.id) }); + emit({ + phase: "provider-history", + backend: "sibyl-memory-client", + sibyl: backend, + historicalExecutionIds: [first, second], + admittingExecutionId: admitting.executionId, + admittedMemoryIds: completed.admittedMemories.map((memory) => memory.id), + relationshipPosture: "CONTEXT_GUARDED", + instruction: "Terminate this process, then run urgent/routine commands against the same Sibyl DB and tenant.", + }); } -async function decide(urgency: "URGENT" | "ROUTINE") { - const runtime = new EngramRuntime(new SibylRuntimeStore(), DEFAULT_RUNTIME_POLICIES); +async function decide(urgency: "URGENT" | "ROUTINE"): Promise { + const store = new SibylRuntimeStore(); + const runtime = new EngramRuntime(store, DEFAULT_RUNTIME_POLICIES); + const backend = await store.ping(); const run = await runtime.startExecution({ agentId: "requester-agent", workflowType: "agent_provider_selection", @@ -94,7 +114,10 @@ async function decide(urgency: "URGENT" | "ROUTINE") { constraints: { budgetUsd: 20, maxLatencySeconds: 30 }, environmentVersion: "provider-market-v1", }); - const recalled = await runtime.recall({ executionId: run.executionId, query: "Atlas repeated data fetch SLA breaches relationship" }); + const recalled = await runtime.recall({ + executionId: run.executionId, + query: "Atlas repeated data fetch SLA breaches experiential relationship", + }); const context: ProviderContinuityContext = { ...baseContext, urgency }; const control = decideProviderEngagement({ context, offers, memories: [] }); const treatment = decideProviderEngagement({ @@ -102,13 +125,51 @@ async function decide(urgency: "URGENT" | "ROUTINE") { offers, memories: recalled.candidates.map((candidate) => ({ memory: candidate.memory, finalScore: candidate.score })), }); + + if (treatment.memoryRefs.length) { + await runtime.recordDecision({ + executionId: run.executionId, + decisionType: "PROVIDER_ENGAGEMENT", + selectedAction: { providerId: treatment.providerId, terms: treatment.terms }, + alternatives: [{ providerId: control.providerId, terms: control.terms }], + reasoningSummary: treatment.reason, + influences: [{ + memoryId: treatment.memoryRefs[0]!, + retrievalId: recalled.recall.id, + influenceType: treatment.providerId !== control.providerId ? "CHANGED_ACTION" : "CONSTRAINED_ACTION", + summary: urgency === "URGENT" + ? "Accumulated provider experience changed urgent delegation from Atlas to Beacon." + : "Accumulated provider experience constrained Atlas prepayment and verification authority.", + counterfactual: treatment.providerId !== control.providerId ? { + action: { providerId: control.providerId, terms: control.terms }, + source: "APPLICATION_DECLARED", + evidenceState: "OBSERVED", + explanation: "Without relationship memory, the cheapest eligible provider is Atlas.", + } : undefined, + }], + }); + } + emit({ - phase: urgency === "URGENT" ? "provider-urgent-fresh-session" : "provider-routine-fresh-session", - recalledMemoryIds: recalled.candidates.map((c) => c.memory.id), - control, - memoryConditioned: treatment, + phase: urgency === "URGENT" ? "provider-fresh-urgent" : "provider-fresh-routine", + backend: "sibyl-memory-client", + sibyl: backend, + executionId: run.executionId, + retrievalId: recalled.recall.id, + recalledMemoryIds: recalled.candidates.map((candidate) => candidate.memory.id), + baseline: { + providerId: control.providerId, + terms: control.terms, + result: executeProviderEngagement(control, context), + }, + memoryConditioned: { + providerId: treatment.providerId, + terms: treatment.terms, + result: executeProviderEngagement(treatment, context), + }, providerChanged: control.providerId !== treatment.providerId, authorityChanged: JSON.stringify(control.terms) !== JSON.stringify(treatment.terms), + trace: await runtime.trace(run.executionId), }); } From 41298e937f34024eb0e61f19af023d97dfb7654b Mon Sep 17 00:00:00 2001 From: etvjay Date: Mon, 24 Aug 2026 17:55:01 +0100 Subject: [PATCH 048/116] docs: freeze experiential provider continuity scenario --- hackathon/sibyl/TOP_BAND_SCENARIO.md | 141 +++++++++++++++++++++++++++ 1 file changed, 141 insertions(+) create mode 100644 hackathon/sibyl/TOP_BAND_SCENARIO.md diff --git a/hackathon/sibyl/TOP_BAND_SCENARIO.md b/hackathon/sibyl/TOP_BAND_SCENARIO.md new file mode 100644 index 0000000..f9182dc --- /dev/null +++ b/hackathon/sibyl/TOP_BAND_SCENARIO.md @@ -0,0 +1,141 @@ +# Top-Band Scenario — Experiential Provider Continuity + +## Thesis +An autonomous requester should not merely remember that a provider was good or bad. It should preserve bounded evidence from its own prior interactions, derive a relationship posture only when provenance is sufficient, and let that posture change future delegation or authority contextually. + +This is not a global reputation score. + +```text +reputation + = a claim about a provider + +experiential continuity + = prior requester-owned executions + -> evidence + -> bounded relationship memory + -> context-specific future policy + -> changed provider / terms / authority +``` + +## Flagship story +Provider `atlas` is the cheapest eligible data-fetch provider. Provider `beacon` is slightly more expensive. + +### Historical execution 1 +- requester selects Atlas for an urgent data fetch; +- Atlas returns useful work but breaches the latency SLA; +- requester records observed execution evidence; +- no relationship conclusion is admitted yet. + +### Historical execution 2 +- a later comparable urgent task again uses Atlas; +- Atlas again breaches the SLA; +- second independent execution is observed. + +### Relationship-state admission +A third admitting execution evaluates the repeated pattern. Engram admits one `REPEATED_PATTERN` memory only with multi-source provenance linking both prior breach executions plus the admitting execution. + +Derived bounded state: + +```text +providerId: atlas +memoryPrimitive: EXPERIENTIAL_RELATIONSHIP +relationshipPosture: CONTEXT_GUARDED +taskType: data_fetch +failureType: SLA_BREACH +breachCount: 2 +``` + +The memory does **not** say "Atlas is bad." It says that this requester has enough observed history to guard a particular class of future interaction. + +## Fresh-session consequence A — urgent task +Without memory: + +```text +cheapest eligible provider -> Atlas +standard terms +``` + +With recalled relationship memory: + +```text +Atlas is excluded for this urgent task +next eligible provider -> Beacon +``` + +Required proof: +- same offers; +- same task constraints; +- only memory condition changes; +- control selects Atlas; +- treatment selects Beacon; +- decision records `CHANGED_ACTION` and counterfactual Atlas selection. + +## Fresh-session consequence B — routine task +The same memory must not become a permanent blacklist. + +Without memory: + +```text +Atlas +50% prepay +no milestone verification +``` + +With relationship memory: + +```text +Atlas remains selected +10% prepay +milestone verification required +``` + +This demonstrates contextual authority narrowing rather than blanket exclusion. + +## Why multiple executions matter +One bad interaction must not establish relationship state. + +The scenario therefore requires: +- at least two independent source execution IDs; +- same requester/agent authority; +- compatible workflow/task class; +- observed evidence; +- repeated pattern admission; +- reconstructable source lineage. + +## Negative controls +The build should fail or remain baseline when: +1. only one breach exists; +2. memory belongs to another requester; +3. memory concerns another task type; +4. memory is expired; +5. memory changes after recall; +6. source lineage is missing or contradictory; +7. Sibyl is unavailable; +8. no applicable provider alternative exists — in this case terms may narrow, but the system must not invent a provider. + +## Sibyl deletion test +Sibyl is the only persistence/recall substrate in the evaluated profile. Delete or disable Sibyl and the fresh process cannot reconstruct the relationship memory; provider selection therefore reverts to the memory-free baseline. + +## Product meaning +The agent is not learning a universal truth about Atlas. It is maintaining a bounded private history of what Atlas has meant **to this agent under specific conditions**, and carrying that experience into future economic behavior. + +That is the intended Experiential Continuity primitive: + +```text +Event +-> Evidence +-> Memory +-> Experience +-> Legitimate State Delta +-> Relationship Posture +-> Decision +-> Action +-> New Event +``` + +## Partner attachment point +Only after this core is green: +- Virtuals ACP can provide the real agent/provider job relationship; +- Base can provide the economically consequential payment/escrow/prepayment action. + +Partner integrations should exercise the remembered relationship decision. They must not replace or decorate it. From 90f705a2a6ad5bcdc7a5df42235aa634cc393913 Mon Sep 17 00:00:00 2001 From: etvjay Date: Mon, 24 Aug 2026 17:55:47 +0100 Subject: [PATCH 049/116] test: allow external Sibyl provider loop enough time --- tests/integration/sibyl-provider-continuity.test.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/integration/sibyl-provider-continuity.test.ts b/tests/integration/sibyl-provider-continuity.test.ts index 7591b7b..cbcfcbd 100644 --- a/tests/integration/sibyl-provider-continuity.test.ts +++ b/tests/integration/sibyl-provider-continuity.test.ts @@ -114,7 +114,6 @@ describeSibyl("Sibyl-backed experiential provider continuity", () => { expect(admitted.admittedMemories).toHaveLength(1); const memory = admitted.admittedMemories[0]!; - // Fresh runtime/store represents a new session with no in-memory source state. const freshRuntime = new EngramRuntime(new SibylRuntimeStore(), DEFAULT_RUNTIME_POLICIES); const next = await freshRuntime.startExecution({ agentId: "requester-agent", @@ -168,7 +167,7 @@ describeSibyl("Sibyl-backed experiential provider continuity", () => { expect(trace.memoryBackend).toBe("sibyl-memory-client"); expect(JSON.stringify(trace)).toContain("PROVIDER_ENGAGEMENT"); expect(JSON.stringify(trace)).toContain("CHANGED_ACTION"); - }); + }, 15_000); it("uses the same relationship memory to constrain terms rather than blacklist Atlas for routine work", async () => { const sourceRuntime = new EngramRuntime(new SibylRuntimeStore(), DEFAULT_RUNTIME_POLICIES); @@ -228,5 +227,5 @@ describeSibyl("Sibyl-backed experiential provider continuity", () => { expect(decision.providerId).toBe("atlas"); expect(decision.memoryRefs).toContain(memory.id); expect(decision.terms).toMatchObject({ prepayBps: 1_000, requireMilestoneVerification: true }); - }); + }, 15_000); }); From d3d6e9830ae011c042daad655fd988fd376e6d8f Mon Sep 17 00:00:00 2001 From: etvjay Date: Mon, 24 Aug 2026 17:56:30 +0100 Subject: [PATCH 050/116] docs: add evaluator call map for Sibyl memory path --- hackathon/sibyl/JUDGE_CALL_MAP.md | 120 ++++++++++++++++++++++++++++++ 1 file changed, 120 insertions(+) create mode 100644 hackathon/sibyl/JUDGE_CALL_MAP.md diff --git a/hackathon/sibyl/JUDGE_CALL_MAP.md b/hackathon/sibyl/JUDGE_CALL_MAP.md new file mode 100644 index 0000000..2dfa751 --- /dev/null +++ b/hackathon/sibyl/JUDGE_CALL_MAP.md @@ -0,0 +1,120 @@ +# Judge Call Map — Engram × Sibyl + +This file is intentionally short. It answers: **where is Sibyl load-bearing, and where does recalled memory change behavior?** + +## 1. Sibyl adapter + +`packages/sibyl/src/runtime-store.ts` + +This implements Engram's `EngramRuntimeStore` contract for the evaluated profile. + +Critical methods: +- `persistMemory(...)` — writes Engram operational memory to Sibyl; +- `searchMemory(...)` — retrieves decision-critical memory from Sibyl; +- `getMemory(...)` — resolves the current authority-relevant memory state; +- `getRecalls(...)` / `updateRecallExposure(...)` — preserve recall provenance and exposed memory-state digests; +- `recordRuntimeDecision(...)` — persists the decision that references memory; +- `getTrace(...)` — reconstructs execution -> recall -> influence evidence. + +There is no Cockroach fallback in `SibylRuntimeStore`. + +## 2. Public Sibyl SDK bridge + +`packages/sibyl/bridge.py` + +The TypeScript runtime reaches Sibyl through the public Python `MemoryClient` API. The bridge does not query Sibyl's SQLite tables directly. + +Dependency lock: + +`packages/sibyl/requirements.txt` + +## 3. Engram semantic authority + +`packages/runtime/src/runtime.ts` + +Critical flow: +- `complete(...)` evaluates admission and calls `store.persistMemory(...)`; +- `recall(...)` calls `store.searchMemory(...)`, then applies Engram eligibility policy; +- `recordDecision(...)` verifies that claimed influential memory was actually recalled and still matches its exposed state digest; +- `validateMemorySourceLineage(...)` checks source execution provenance; +- `validateCounterfactualComparison(...)` and influence policy prevent unsupported causal claims. + +Sibyl owns persistence/recall. Engram owns whether memory may legitimately influence behavior. + +## 4. Deterministic deletion/control proof + +`tests/integration/sibyl-memory-loop.test.ts` + +Proves: +- persistent memory crosses fresh runtime/store boundaries; +- expired memory is not exposed; +- memory changed after recall cannot influence the decision; +- unavailable Sibyl fails closed. + +Demo: + +`scripts/sibyl-demo.ts` + +Commands: + +```bash +npm run demo:sibyl:seed +npm run demo:sibyl:recall +npm run demo:sibyl:no-memory-control +npm run test:sibyl:deletion +``` + +## 5. Headline experiential-continuity scenario + +Policy primitive: + +`packages/scenarios/provider-continuity/src/index.ts` + +Sibyl-backed integration: + +`tests/integration/sibyl-provider-continuity.test.ts` + +Evaluator demo: + +`scripts/sibyl-provider-demo.ts` + +Commands: + +```bash +npm run demo:sibyl:provider:seed +npm run demo:sibyl:provider:urgent +npm run demo:sibyl:provider:routine +``` + +Expected causal behavior: + +```text +historical Atlas breach #1 +historical Atlas breach #2 + | + v +Engram multi-source REPEATED_PATTERN admission + | + v +Sibyl relationship memory + | + +--> fresh urgent task + | control: Atlas + | memory: Beacon + | + +--> fresh routine task + control: Atlas / 50% prepay / no checkpoint + memory: Atlas / 10% prepay / milestone verification +``` + +The same memory therefore changes behavior contextually rather than becoming a blanket reputation label. + +## 6. Mandatory CI + +`.github/workflows/ci.yml` + +The `sibyl-profile` job provisions Python + the pinned Sibyl SDK, builds Engram, runs both Sibyl integration suites, executes fresh-process deterministic demos, executes the provider-continuity demos, and then runs the deletion mutation. + +## 7. Prior work boundary + +Everything on this branch created before the official Sep 1 build window is pre-window work and must be declared as Prior Work where the submission rules require it. Hackathon-window evidence must be regenerated from the then-current commit; this document is not itself submission proof. From 97efd534db19c3ff776e26b58b06cb7e57270704 Mon Sep 17 00:00:00 2001 From: etvjay Date: Mon, 24 Aug 2026 17:58:14 +0100 Subject: [PATCH 051/116] evidence: record provider continuity pressure proof --- hackathon/sibyl/templates/EVIDENCE_LEDGER.md | 31 ++++++++++++++------ 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/hackathon/sibyl/templates/EVIDENCE_LEDGER.md b/hackathon/sibyl/templates/EVIDENCE_LEDGER.md index ab59c35..921878b 100644 --- a/hackathon/sibyl/templates/EVIDENCE_LEDGER.md +++ b/hackathon/sibyl/templates/EVIDENCE_LEDGER.md @@ -7,22 +7,35 @@ Allowed states: | Claim / gate | State | Evidence | Negative mutation | Notes | |---|---|---|---|---| -| Sibyl persists decision-critical memory | LOCAL_PASS | GitHub Actions run `32750511943`, job `97506098369`, code head `df341ef`: SDK 0.6.1 installed, build passed, seed process admitted memory `2783541a-a21f-49e9-8263-a35c46ff6717` | missing Sibyl runtime | Pre-build-window evidence; must be re-run during official window | -| Fresh session/process recalls prior memory | LOCAL_PASS | same job: separate `npm run demo:sibyl:seed` and `npm run demo:sibyl:recall` processes; process B recalled exact memory ID `2783541a-a21f-49e9-8263-a35c46ff6717` | terminate process A / unavailable Sibyl | Stronger than fresh-object-only proof | -| Recalled memory changes action | LOCAL_PASS | same job: control route `A-B-C`; memory-conditioned route `A-B-D`; `changedAction: true`; decision trace records `CHANGED_ACTION` | no-memory control | Paired behavioral delta, not retrieval-only | +| Sibyl persists decision-critical memory | LOCAL_PASS | GitHub Actions run `32753747711`, job `97516430322`, code head `d3d6e983`: SDK 0.6.1 installed; route and provider profile state persisted through Sibyl | missing Sibyl runtime | Pre-build-window evidence; must be re-run during official window | +| Fresh session/process recalls prior memory | LOCAL_PASS | same job: separate seed and recall processes; route memory `d9996c9c-af00-4c05-99b0-bafcdac15b10` and provider relationship memory `f269d755-f642-4495-8f68-da735618d74b` were recalled in later processes | terminate source process / unavailable Sibyl | Stronger than fresh-object-only proof | +| Recalled memory changes action | LOCAL_PASS | same job: route `A-B-C -> A-B-D`; urgent provider `atlas -> beacon`; explicit `CHANGED_ACTION` traces | no-memory control | Paired behavioral deltas, not retrieval-only | +| Recalled memory constrains authority without global blacklist | LOCAL_PASS | same job, fresh routine provider process: Atlas remains selected while prepay falls `5000 -> 1000` bps and milestone verification becomes required; trace records `CONSTRAINED_ACTION` | routine-context control | Demonstrates contextual relationship posture rather than global reputation | +| Multi-execution experience becomes bounded relationship memory | LOCAL_PASS | same job: historical executions `fb0570f6...` + `22a66402...` plus admitting execution `2965c23d...` produced `REPEATED_PATTERN` memory `f269d755...` with `CONTEXT_GUARDED` posture | single-failure fixture / cross-task fixture | Pure scenario tests also require >=2 source executions and task-type applicability | +| Urgent provider experience changes outcome | LOCAL_PASS | same job: no-memory Atlas path deterministically returns `SLA_BREACH`; memory-conditioned Beacon path returns `SUCCESS` | no-memory provider control | This is an application fixture, not a claim about a live provider network | | Deleting/unavailable Sibyl breaks/degrades core function | LOCAL_PASS | same job: deletion CLI emitted `degraded: true`, `fallbackAvailable: false`, missing-runtime ENOENT | remove/disable Sibyl runtime | VETO; mutation harness fails if Sibyl unexpectedly stays available | -| Engram provenance remains reconstructable | LOCAL_PASS | same job: recall ID, memory ID, `engram.memory-state/v1` digest, counterfactual Route C, accepted influence and runtime evaluation events appear in trace | post-recall memory tamper | Sibyl backend preserves the trace needed for Engram influence validation | -| Expired Sibyl memory is retrieved but blocked before exposure | LOCAL_PASS | same job `npm run test:sibyl`: `retrieves but refuses to expose expired Sibyl memory` passed | expired memory fixture | Demonstrates retrieval ≠ legitimate influence | -| Post-recall memory tamper is rejected | LOCAL_PASS | same job `npm run test:sibyl`: `rejects influence when Sibyl memory changes after recall` passed | overwrite memory after digest exposure | Protects recall-to-decision state integrity | -| Canonical Engram suite remains green with optional Sibyl profile | LOCAL_PASS | run `32750511943`, job `97506098115`: `npm run check` passed; same PR also passed earlier generic run `32750255631` after optional-integration fixes | canonical test suite | Sibyl external SDK test is required only in the Sibyl CI job | -| Conflicting memory remains non-silently adjudicated through Sibyl store | UNVERIFIED | existing Engram semantics only | contradictory Sibyl memory fixture | Next memory-pressure task | +| Engram provenance remains reconstructable | LOCAL_PASS | same job: recall IDs, memory IDs, `engram.memory-state/v1` digests, counterfactuals, accepted influence and evaluation events appear in route/provider traces | post-recall memory tamper | Sibyl backend preserves the trace needed for Engram influence validation | +| Expired Sibyl memory is retrieved but blocked before exposure | LOCAL_PASS | same job `npm run test:sibyl`: expired-memory test passed | expired memory fixture | Demonstrates retrieval != legitimate influence | +| Post-recall memory tamper is rejected | LOCAL_PASS | same job `npm run test:sibyl`: state-digest tamper test passed | overwrite memory after digest exposure | Protects recall-to-decision state integrity | +| Expanded Sibyl pressure suite | LOCAL_PASS | same job: `6 passed` across core + provider-continuity integration tests | timeout/retry history preserved | Initial provider run timed out at 5s; bounded 15s integration timeout added without changing assertions; subsequent run green | +| Canonical Engram suite remains green with optional Sibyl profile | LOCAL_PASS | run `32753747711`, job `97516431430`: `npm run check` passed | canonical test suite | Sibyl external SDK test remains isolated to provisioned Sibyl CI job | +| Conflicting memory remains non-silently adjudicated through Sibyl store | UNVERIFIED | existing Engram semantics only | contradictory Sibyl memory fixture | Still worth adding before final submission pressure | | Root README exposes critical write/read/influence call map | UNVERIFIED | — | cold reviewer navigation | Published evaluator gate; still required | | Hackathon-window rerun of core proof | UNVERIFIED | — | clean clone + fresh DB | Pre-window proof cannot substitute for final event-window evidence | | Base integration does real product work | UNVERIFIED | — | remove Base action | optional | | Virtuals integration does real product work | UNVERIFIED | — | remove Virtuals interaction | optional | +## Current flagship interpretation +The strongest current memory claim is not `the agent remembers Atlas is bad`. + +It is: + +> Multiple attributable executions become an agent-specific, task-specific relationship posture. In a fresh session that posture can change delegation entirely for urgent work, or narrow payment/verification authority for routine work, while preserving the same provider relationship. + +This is evidence-bounded experiential continuity, not a universal reputation score. + ## Evidence-history note -A green run proves only the commit/run it actually executed. Run `32750511943` checked out PR merge `ad748635...`, whose candidate code head was `df341ef...`. Subsequent EBI documentation-only commits record that evidence but do not strengthen it. +A green run proves only the commit/run it actually executed. Run `32753747711` checked the PR state whose candidate head was `d3d6e983...`. Later documentation commits record that evidence but do not strengthen it. Every promotion above `LOCAL_PASS` must point to the exact hackathon-window artifact/run that supports it. From f5c23e9b46cbb26cc0ea88be31d55af73c31f6dd Mon Sep 17 00:00:00 2001 From: etvjay Date: Mon, 24 Aug 2026 17:58:52 +0100 Subject: [PATCH 052/116] evidence: promote provider continuity gates --- hackathon/sibyl/requirements/requirements.json | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/hackathon/sibyl/requirements/requirements.json b/hackathon/sibyl/requirements/requirements.json index 247b46f..e5e8800 100644 --- a/hackathon/sibyl/requirements/requirements.json +++ b/hackathon/sibyl/requirements/requirements.json @@ -1,14 +1,16 @@ { "verified_at": "2026-08-24", "status": "READY_FOR_LIVE_PRESSURE", - "evidence_note": "Core gates are LOCAL_PASS from pre-build-window CI. Submission/live-public gates remain unverified and must be re-proven during the official build window.", + "evidence_note": "Core and experiential-provider gates are LOCAL_PASS from pre-build-window CI. Submission/live-public and partner gates remain unverified and must be re-proven during the official build window.", "requirements": [ - {"id":"SIBYL-GATE-001","track":"main","class":"PUBLISHED_HARD","severity":"VETO","description":"Sibyl Memory is load-bearing; deleting it breaks or materially degrades the core function.","check":"run deletion mutation and compare claimed behavior","evidence_required":"failing/degraded no-Sibyl run plus passing Sibyl run","status":"LOCAL_PASS","evidence":"GitHub Actions run 32750511943 job 97506098369: deletion mutation degraded=true, fallbackAvailable=false"}, - {"id":"SIBYL-GATE-002","track":"main","class":"PUBLISHED_HARD","severity":"VETO","description":"Fresh session recalls earlier persisted state.","check":"terminate process/session, restart clean, recall prior memory","evidence_required":"continuous demo segment with timestamp or commit hash","status":"LOCAL_PASS","evidence":"GitHub Actions run 32750511943: separate seed and recall Node processes; process B recalled the exact process-A memory ID"}, - {"id":"SIBYL-GATE-003","track":"main","class":"PUBLISHED_HARD","severity":"VETO","description":"Recalled memory changes a decision, action, or result.","check":"paired memory vs no-memory decision comparison","evidence_required":"decision trace and observable action delta","status":"LOCAL_PASS","evidence":"GitHub Actions run 32750511943: control A-B-C, memory-conditioned A-B-D, changedAction=true, CHANGED_ACTION trace recorded"}, - {"id":"SIBYL-GATE-004","track":"main","class":"PUBLISHED_HARD","severity":"HIGH","description":"README exposes critical memory write/read paths in under two minutes.","check":"cold reviewer repo navigation test","evidence_required":"README call map","status":"UNVERIFIED"}, - {"id":"SCORE-MEM-001","track":"main","class":"PUBLISHED_SCORING","severity":"HIGH","description":"Memory use is sophisticated enough for top band; coordination/dynamic-state behavior preferred.","check":"judge-model scorecard","evidence_required":"non-trivial stateful scenario plus adversarial memory handling","status":"LOCAL_PASS","evidence":"Sibyl profile passes expired-memory rejection and post-recall state-digest tamper rejection; top-band evaluator judgment remains future"}, - {"id":"SCORE-TECH-001","track":"main","class":"PUBLISHED_SCORING","severity":"HIGH","description":"Build is clean, robust and survives a second run/curious judge.","check":"repeatability and negative test suite","evidence_required":"test report and second-run evidence","status":"LOCAL_PASS","evidence":"Engram CI run 32750511943 passed canonical check and Sibyl profile jobs on clean runner"}, + {"id":"SIBYL-GATE-001","track":"main","class":"PUBLISHED_HARD","severity":"VETO","description":"Sibyl Memory is load-bearing; deleting it breaks or materially degrades the core function.","check":"run deletion mutation and compare claimed behavior","evidence_required":"failing/degraded no-Sibyl run plus passing Sibyl run","status":"LOCAL_PASS","evidence":"GitHub Actions run 32753747711 job 97516430322: deletion mutation degraded=true, fallbackAvailable=false"}, + {"id":"SIBYL-GATE-002","track":"main","class":"PUBLISHED_HARD","severity":"VETO","description":"Fresh session recalls earlier persisted state.","check":"terminate process/session, restart clean, recall prior memory","evidence_required":"continuous demo segment with timestamp or commit hash","status":"LOCAL_PASS","evidence":"GitHub Actions run 32753747711: separate route and provider history/decision processes recalled exact persisted Sibyl memory IDs"}, + {"id":"SIBYL-GATE-003","track":"main","class":"PUBLISHED_HARD","severity":"VETO","description":"Recalled memory changes a decision, action, or result.","check":"paired memory vs no-memory decision comparison","evidence_required":"decision trace and observable action delta","status":"LOCAL_PASS","evidence":"Run 32753747711: route A-B-C -> A-B-D; urgent provider Atlas -> Beacon with CHANGED_ACTION; routine Atlas terms constrained with CONSTRAINED_ACTION"}, + {"id":"SIBYL-GATE-004","track":"main","class":"PUBLISHED_HARD","severity":"HIGH","description":"README exposes critical memory write/read paths in under two minutes.","check":"cold reviewer repo navigation test","evidence_required":"README call map","status":"UNVERIFIED","evidence":"Staging call map exists at hackathon/sibyl/JUDGE_CALL_MAP.md; root README integration and cold-review test still pending"}, + {"id":"SCORE-MEM-001","track":"main","class":"PUBLISHED_SCORING","severity":"HIGH","description":"Memory use is sophisticated enough for top band; coordination/dynamic-state behavior preferred.","check":"judge-model scorecard","evidence_required":"non-trivial stateful scenario plus adversarial memory handling","status":"LOCAL_PASS","evidence":"Run 32753747711 job 97516430322: 6/6 Sibyl integration tests; multi-execution experiential relationship memory changes urgent delegation and routine authority; expired and post-recall tamper controls pass. Final evaluator score remains future."}, + {"id":"SCORE-TECH-001","track":"main","class":"PUBLISHED_SCORING","severity":"HIGH","description":"Build is clean, robust and survives a second run/curious judge.","check":"repeatability and negative test suite","evidence_required":"test report and second-run evidence","status":"LOCAL_PASS","evidence":"Engram CI run 32753747711: canonical check job 97516431430 and Sibyl profile job 97516430322 both passed on clean runners"}, + {"id":"EXP-CONT-001","track":"main","class":"INTERNAL_ACCEPTANCE","severity":"HIGH","description":"Multiple attributable executions may form bounded relationship state only with sufficient lineage.","check":"multi-source provider history test","evidence_required":"two historical executions + admitting execution + relationship memory lineage","status":"LOCAL_PASS","evidence":"Run 32753747711: two Atlas breach executions plus admitting execution produced CONTEXT_GUARDED relationship memory; one-breach and cross-task controls remain baseline"}, + {"id":"EXP-CONT-002","track":"main","class":"INTERNAL_ACCEPTANCE","severity":"HIGH","description":"Relationship state changes behavior contextually rather than becoming a global provider blacklist.","check":"urgent vs routine paired decisions","evidence_required":"urgent provider change plus routine authority narrowing using same memory","status":"LOCAL_PASS","evidence":"Run 32753747711: urgent Atlas -> Beacon; routine stays Atlas while prepay 5000 -> 1000 bps and milestone verification false -> true"}, {"id":"SUBMIT-001","track":"submission","class":"PUBLISHED_HARD","severity":"VETO","description":"Public MIT/Apache-2.0 repo with real commit history.","check":"repository inspection","evidence_required":"public repo/license/commits","status":"LOCAL_PASS"}, {"id":"SUBMIT-002","track":"submission","class":"PUBLISHED_HARD","severity":"VETO","description":"2–5 minute demo includes fresh-session recall.","check":"video review","evidence_required":"public video","status":"UNVERIFIED"}, {"id":"SUBMIT-003","track":"submission","class":"PUBLISHED_HARD","severity":"VETO","description":"README includes Prior Work declaration and required memory/partner notes.","check":"README audit","evidence_required":"merged README","status":"UNVERIFIED"}, From 5d12561589780fd34d1b63bc0bd4231d7de0e92b Mon Sep 17 00:00:00 2001 From: etvjay Date: Mon, 24 Aug 2026 17:58:59 +0100 Subject: [PATCH 053/116] docs: add Sibyl evaluator call map and prior work boundary --- README.md | 47 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 45 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 7392ecd..fbc682d 100644 --- a/README.md +++ b/README.md @@ -8,9 +8,48 @@ Engram is execution-memory infrastructure for autonomous systems. It preserves p The application or agent remains the decision authority. Engram does **not** choose the business action. +## Sibyl Labs Hackathon evaluated profile + +The `hackathon/sibyl-ebi` branch contains a dedicated evaluated profile for the Sibyl Labs Hackathon. Canonical Engram remains CockroachDB-backed; in this judged profile **Sibyl is the load-bearing execution-memory store and there is no Cockroach fallback for the decision-critical path**. + +The hackathon profile is designed around the deletion test: remove Sibyl and the cross-session memory required to reproduce the claimed behavior disappears. + +### Judge call map — write → read → influence → deletion + +| Judge question | Critical path | +|---|---| +| Where is Sibyl wired into Engram? | `packages/sibyl/src/runtime-store.ts` implements `EngramRuntimeStore`; `packages/sibyl/bridge.py` calls the public Sibyl Python SDK. | +| Where is decision-critical memory written? | `SibylRuntimeStore.persistMemory(...)` → bridge `put` → Sibyl WARM entity `operational_memory`. | +| Where is it read in a later session? | `SibylRuntimeStore.searchMemory(...)` → bridge `search_memories`; Engram Runtime then applies recall eligibility before exposure. | +| How is recall distinguished from influence? | `packages/runtime/src/runtime.ts`: `recall(...)` creates a memory-state digest; `recordDecision(...)` validates retrieval provenance and influence policy before recording `CHANGED_ACTION` / `CONSTRAINED_ACTION`. | +| Where is the flagship relationship-memory policy? | `packages/scenarios/provider-continuity/src/index.ts`. | +| Where is the Sibyl integration pressure test? | `tests/integration/sibyl-memory-loop.test.ts` and `tests/integration/sibyl-provider-continuity.test.ts`. | +| How do I see process-boundary recall? | `npm run demo:sibyl:provider:seed`, terminate that process, then run `npm run demo:sibyl:provider:urgent` or `npm run demo:sibyl:provider:routine` against the same Sibyl DB/tenant. | +| How is load-bearing deletion tested? | `npm run test:sibyl:deletion`; it removes the configured Sibyl runtime and must report degradation with no fallback. | + +### How memory made this possible + +The flagship profile models experiential continuity between a requester agent and service providers. + +Two prior requester-owned executions observe Atlas breaching an urgent `data_fetch` SLA. Engram admits a provenance-linked multi-execution `REPEATED_PATTERN` relationship memory and Sibyl persists it. In a fresh session: + +- without memory, the cheapest eligible provider is Atlas; +- for **urgent** work, recalled relationship memory changes delegation from Atlas to Beacon and records `CHANGED_ACTION`; +- for **routine** work, Atlas is not globally blacklisted: it remains selected, but prepayment falls from 50% to 10% and milestone verification is required, recorded as `CONSTRAINED_ACTION`. + +The claim is therefore not “Atlas has a low reputation.” It is: **this agent's attributable experience with Atlas changes the authority Atlas receives in the matching future context.** + +### Prior Work declaration + +Engram's protocol, runtime, execution-memory semantics, CockroachDB production profile, SDK/API/MCP surfaces, causal influence model, and earlier scenarios existed before the Sibyl Labs Hackathon build window. + +The Sibyl EBI adapter, pressure harness and provider-continuity work currently present on this branch were also implemented before the official **September 1–10, 2026** build window. If retained for submission, they must be declared as prior work rather than represented as hackathon-window implementation. Final submission evidence must identify the work performed during the official window and regenerate the required fresh-session/deletion proof there. + +Current pre-window evidence is recorded under [`hackathon/sibyl/`](hackathon/sibyl/) and must not be confused with final submission evidence. + ## Governing invariant -Engram is complete only when a prior execution persisted in CockroachDB is retrieved under comparable future context, explicitly influences a later application/agent decision, causes an observable change from the memory-free baseline, and leaves enough provenance to reconstruct that relationship. +Engram is complete only when a prior execution persisted in its configured operational-memory substrate is retrieved under comparable future context, explicitly influences a later application/agent decision, causes an observable change from the memory-free baseline, and leaves enough provenance to reconstruct that relationship. ```text source execution @@ -66,6 +105,7 @@ The external multi-venue executor is **SIMULATED**. That boundary is intentional Engram is also tested outside the initial venue workload: +- **experiential provider continuity** — repeated requester-owned provider executions become bounded relationship posture that can change urgent delegation or constrain routine payment/verification authority; - **software deployment recovery** — prior migration failure/recovery changes a later comparable deployment strategy with a real memory-free control execution; - **autonomous coding regression** — prior reverted regression changes a later comparable coding methodology from patch-first to regression-test-first; - **incident recovery** — prior recovery that restored the primary service but caused a harmful secondary consequence changes the later mitigation sequence; @@ -261,6 +301,7 @@ Current high-level boundary: | SDK/API/MCP/adapters | TESTED | | Memory policy/evaluation | TESTED | | Stronger execution-memory scenarios | TESTED | +| Sibyl evaluated profile, pre-window | LOCAL_PASS | | SAM packaging | TESTED | | External demo workload | SIMULATED | | CockroachDB Cloud live persistence | UNVERIFIED until credentialed live proof | @@ -269,7 +310,7 @@ Current high-level boundary: | Natural C-SPANN index selection | UNVERIFIED until EXPLAIN proves it | | AWS Lambda public deployment | UNVERIFIED until deploy-verification succeeds | -The authoritative machine-readable claim ledger is [`evidence/claims.yaml`](evidence/claims.yaml). +The authoritative machine-readable claim ledger is [`evidence/claims.yaml`](evidence/claims.yaml). The Sibyl hackathon evidence ledger is [`hackathon/sibyl/templates/EVIDENCE_LEDGER.md`](hackathon/sibyl/templates/EVIDENCE_LEDGER.md). ## Repository map @@ -291,11 +332,13 @@ packages/adapters/ Framework adapters packages/cockroach/ Cockroach persistence/vector runtime packages/cockroach-mcp/ Managed MCP client packages/bedrock/ Titan embeddings +packages/sibyl/ Sibyl evaluated runtime-store profile (server-only) packages/scenarios/ Domain acceptance workloads db/migrations/ Ordered schema migrations experiments/ Governed acceptance evidence evidence/ Claim ledger and adversarial reviews tests/ Unit/integration/conformance/E2E proofs +hackathon/sibyl/ Sibyl EBI truth/evidence wrapper ``` ## What Engram is not From a2ef664bb9bb1469c43ba121b355b2f4202f03ac Mon Sep 17 00:00:00 2001 From: etvjay Date: Mon, 24 Aug 2026 17:59:37 +0100 Subject: [PATCH 054/116] docs: promote provider continuity flagship proof --- hackathon/sibyl/README.md | 110 +++++++++++++++++++++++++++++++------- 1 file changed, 91 insertions(+), 19 deletions(-) diff --git a/hackathon/sibyl/README.md b/hackathon/sibyl/README.md index 8600758..56ca7b6 100644 --- a/hackathon/sibyl/README.md +++ b/hackathon/sibyl/README.md @@ -1,8 +1,8 @@ # Engram × Sibyl — EBI Instance -Status: `READY_FOR_LIVE_PRESSURE` for the core memory path. +Status: `READY_FOR_LIVE_PRESSURE` for the memory + experiential-continuity path. -Submission status remains **not ready**. Partner work, evaluator-facing README fields, hackathon-window evidence, public demo/video/posts and final truth revalidation are still outstanding. +Submission status remains **not ready**. Hackathon-window evidence, live partner execution, public demo/video/posts and final truth revalidation are still outstanding. This directory is the Evaluated Build Instantiation (EBI) wrapper for adapting Engram to the Sibyl Labs Hackathon without changing Engram's canonical product semantics. @@ -19,26 +19,81 @@ execution event -> fresh-session Sibyl recall -> Engram eligibility/influence policy -> application decision - -> changed action/result + -> changed action / changed authority -> outcome/provenance ``` -## Observed core proof — 2026-08-24 -GitHub Actions run `32750511943`, job `97506098369`, executed the Sibyl profile on code head `df341ef` in a clean Ubuntu runner: +## Observed flagship proof — 2026-08-24 +GitHub Actions run `32753747711`, Sibyl job `97516430322`, executed the expanded profile on code head `d3d6e983...` in a clean Ubuntu runner. +### Pressure harness - installed `sibyl-memory-client==0.6.1`; - built Engram successfully; -- passed 4/4 Sibyl pressure tests; +- passed **6/6** Sibyl integration tests; +- retained the original process-boundary Route C → Route D proof; - rejected expired Sibyl memory before exposure; -- rejected influence after the persisted memory changed post-recall; -- process A persisted an execution-derived memory; -- a distinct process B recalled the same memory ID; -- no-memory control selected Route C; -- memory-conditioned execution selected Route D; -- recorded `CHANGED_ACTION` plus a counterfactual and memory-state digest; -- deletion mutation removed the configured Sibyl runtime and observed fail-closed degradation with no fallback. +- rejected influence after persisted memory changed post-recall; +- passed two Sibyl-backed experiential provider-continuity tests; +- canonical Engram `npm run check` also passed in the parallel CI job. -This is `LOCAL_PASS` evidence generated before the official hackathon build window. It is not the final submission proof and must be declared as prior work where required. +### Experiential provider continuity +Two separate requester-owned Atlas executions observed urgent `data_fetch` SLA breaches. A third admitting execution consolidated that evidence into a provenance-linked `REPEATED_PATTERN` memory: + +- relationship memory: `f269d755-f642-4495-8f68-da735618d74b`; +- relationship posture: `CONTEXT_GUARDED`; +- memory source executions: two historical provider interactions plus the explicit admitting execution. + +A new process then recalled that exact Sibyl memory. + +**Urgent context** + +```text +no memory: +Atlas, 50% prepay -> SLA_BREACH + +with relationship memory: +Beacon, 50% prepay -> SUCCESS +``` + +The trace records `CHANGED_ACTION`, the recalled memory ID, retrieval ID, memory-state digest and Atlas counterfactual. + +**Routine context** + +```text +no memory: +Atlas, 50% prepay, no milestone verification + +with same relationship memory: +Atlas, 10% prepay, milestone verification required +``` + +The provider remains Atlas. The trace records `CONSTRAINED_ACTION` rather than pretending the relationship is a global blacklist. + +The stronger claim is therefore: + +> Multiple attributable executions become an agent-specific, task-specific relationship posture that changes how much authority a provider receives in a future context. + +This is not a universal provider reputation score. + +### Deletion proof +The same current-head CI run removed the configured Sibyl runtime and observed: + +- `degraded: true`; +- `fallbackAvailable: false`; +- no Cockroach path preserved equivalent cross-session behavior. + +This is `LOCAL_PASS` evidence generated before the official hackathon build window. It is not the final submission proof and must remain declared as prior work. + +## Evaluator navigation +The root [`README.md`](../../README.md) now includes a judge call map for: +- Sibyl memory write; +- Sibyl memory read; +- recall-state binding; +- influence validation; +- provider-continuity policy; +- fresh-process demos; +- deletion mutation; +- Prior Work declaration. ## Non-negotiable deletion test @@ -46,13 +101,30 @@ If Sibyl persistence/recall is removed, the submitted build must lose the decisi A CockroachDB fallback that preserves equivalent decision-critical memory in the judged path is therefore **not allowed** for the hackathon profile. +## Partner decision +Virtuals ACP is a natural next integration candidate because an ACP provider job can become the real provider interaction whose outcome Engram observes and later remembers. The intended causal boundary is: + +```text +Virtuals ACP job + -> job history / outcome evidence + -> Engram execution observation + -> Engram relationship-memory admission + -> Sibyl persistence + -> fresh-session recall + -> different future ACP provider / terms +``` + +No Virtuals multiplier is claimed until an actual testnet ACP job is exercised and evidenced. + +Base remains optional. It should be added only if the remembered relationship posture changes a real onchain payment/escrow action rather than serving as a decorative transaction. + ## Current next gates -1. Revalidate official hackathon and SDK truth at the start of the Sep 1 build window. +1. Revalidate official hackathon and Sibyl SDK truth at the start of the Sep 1 build window. 2. Re-run the full pressure harness as hackathon-window evidence. -3. Add evaluator-facing root README call map + Prior Work declaration. -4. Decide and implement the strongest top-band scenario beyond route recovery; agent-provider experiential continuity remains preferred. -5. Add Base/Virtuals only if they are causally necessary and exercised, not decorative. -6. Build the continuous 2–5 minute evaluator proof and public evidence surfaces. +3. Implement the Virtuals ACP evidence adapter and exercise a real testnet provider job if the authentication/funding path is practical. +4. Add a contradictory-Sibyl-memory mutation so competing relationship evidence cannot be silently collapsed. +5. Build the continuous 2–5 minute evaluator proof and public evidence surfaces. +6. Consider Base only after the ACP path is live and causally useful. ## EBI state machine From 1db413994f58e958cc67311e6d4dd979c1090a5e Mon Sep 17 00:00:00 2001 From: etvjay Date: Mon, 24 Aug 2026 18:00:16 +0100 Subject: [PATCH 055/116] virtuals: add ACP job evidence normalization --- packages/virtuals-acp/src/evidence.ts | 120 ++++++++++++++++++++++++++ 1 file changed, 120 insertions(+) create mode 100644 packages/virtuals-acp/src/evidence.ts diff --git a/packages/virtuals-acp/src/evidence.ts b/packages/virtuals-acp/src/evidence.ts new file mode 100644 index 0000000..f8ef078 --- /dev/null +++ b/packages/virtuals-acp/src/evidence.ts @@ -0,0 +1,120 @@ +import { z } from "zod"; +import type { EvidenceState } from "../../core/src/protocol.js"; + +const AcpHistorySchema = z.object({ + jobId: z.union([z.string(), z.number()]).transform(String), + chainId: z.coerce.number().int().positive(), + protocol: z.string().optional(), + legacy: z.boolean().optional(), + status: z.string().min(1), + entryCount: z.coerce.number().int().nonnegative().optional(), + entries: z.array(z.unknown()).default([]), +}).passthrough(); + +export type AcpJobHistory = z.infer; + +export type AcpProviderExecutionEvidence = { + sourceSystem: "VIRTUALS_ACP"; + jobId: string; + chainId: number; + protocol: string; + status: string; + providerId: string; + taskType: string; + urgency: "URGENT" | "ROUTINE"; + expectedLatencySeconds?: number; + observedLatencySeconds?: number; + failureType?: "SLA_BREACH" | "JOB_REJECTED" | "JOB_EXPIRED" | "UNKNOWN_FAILURE"; + evidenceState: EvidenceState; + historyEntryCount: number; + rawHistory: AcpJobHistory; +}; + +export type AcpEvidenceContext = { + providerId: string; + taskType: string; + urgency: "URGENT" | "ROUTINE"; + expectedLatencySeconds?: number; + startedAt?: Date; + completedAt?: Date; +}; + +export function parseAcpJobHistory(input: unknown): AcpJobHistory { + return AcpHistorySchema.parse(input); +} + +export function acpHistoryToExecutionEvidence( + input: unknown, + context: AcpEvidenceContext, +): AcpProviderExecutionEvidence { + const history = parseAcpJobHistory(input); + const status = history.status.toLowerCase(); + const observedLatencySeconds = context.startedAt && context.completedAt + ? Math.max(0, (context.completedAt.getTime() - context.startedAt.getTime()) / 1000) + : undefined; + + let failureType: AcpProviderExecutionEvidence["failureType"]; + if (status === "rejected") failureType = "JOB_REJECTED"; + else if (status === "expired") failureType = "JOB_EXPIRED"; + else if (!["completed", "submitted", "funded", "budget_set", "open"].includes(status)) { + failureType = "UNKNOWN_FAILURE"; + } + + if ( + context.expectedLatencySeconds !== undefined + && observedLatencySeconds !== undefined + && observedLatencySeconds > context.expectedLatencySeconds + ) { + failureType = "SLA_BREACH"; + } + + return { + sourceSystem: "VIRTUALS_ACP", + jobId: history.jobId, + chainId: history.chainId, + protocol: history.protocol ?? (history.legacy ? "legacy" : "v2"), + status: history.status, + providerId: context.providerId, + taskType: context.taskType, + urgency: context.urgency, + expectedLatencySeconds: context.expectedLatencySeconds, + observedLatencySeconds, + failureType, + evidenceState: "OBSERVED", + historyEntryCount: history.entryCount ?? history.entries.length, + rawHistory: history, + }; +} + +export function acpEvidenceToEngramObservation(evidence: AcpProviderExecutionEvidence): { + type: "VIRTUALS_ACP_JOB_OBSERVED"; + payload: Record; + evidenceState: EvidenceState; + provenance: Array>; +} { + return { + type: "VIRTUALS_ACP_JOB_OBSERVED", + payload: { + sourceSystem: evidence.sourceSystem, + providerId: evidence.providerId, + taskType: evidence.taskType, + urgency: evidence.urgency, + jobId: evidence.jobId, + chainId: evidence.chainId, + protocol: evidence.protocol, + status: evidence.status, + expectedLatencySeconds: evidence.expectedLatencySeconds, + observedLatencySeconds: evidence.observedLatencySeconds, + failureType: evidence.failureType, + historyEntryCount: evidence.historyEntryCount, + }, + evidenceState: evidence.evidenceState, + provenance: [{ + source: "Virtuals ACP", + command: `acp job history --job-id ${evidence.jobId} --chain-id ${evidence.chainId} --json`, + jobId: evidence.jobId, + chainId: evidence.chainId, + protocol: evidence.protocol, + }], + }; +} From 35c3cc3e7b34bc221fb234075d02d379047169d5 Mon Sep 17 00:00:00 2001 From: etvjay Date: Mon, 24 Aug 2026 18:00:34 +0100 Subject: [PATCH 056/116] virtuals: document ACP evidence adapter boundary --- packages/virtuals-acp/README.md | 64 +++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 packages/virtuals-acp/README.md diff --git a/packages/virtuals-acp/README.md b/packages/virtuals-acp/README.md new file mode 100644 index 0000000..1389144 --- /dev/null +++ b/packages/virtuals-acp/README.md @@ -0,0 +1,64 @@ +# Virtuals ACP evidence adapter + +Status: `IMPLEMENTED / LIVE_ACP_UNVERIFIED` + +This server-only package normalizes machine-readable output from the current Virtuals `@virtuals-protocol/acp-cli` into Engram execution evidence. + +It does **not** let Virtuals decide Engram memory semantics. The boundary is: + +```text +Virtuals ACP job/history + -> normalize observed job evidence + -> Engram observation + -> Engram admission / eligibility / influence + -> Sibyl persistent memory +``` + +## Current first-party CLI contract +The adapter targets the maintained `@virtuals-protocol/acp-cli` v2 history command: + +```bash +acp job history --job-id --chain-id --json +``` + +The CLI currently emits a JSON object containing `jobId`, `chainId`, `protocol`, `status`, `entryCount`, and `entries` for v2 jobs. Every ACP CLI command supports `--json`. + +Testnet is selected globally: + +```bash +export IS_TESTNET=true +``` + +## Example + +```ts +import { + acpHistoryToExecutionEvidence, + acpEvidenceToEngramObservation, +} from "./src/evidence.js"; + +const evidence = acpHistoryToExecutionEvidence(jobHistoryJson, { + providerId: "0xProvider", + taskType: "data_fetch", + urgency: "URGENT", + expectedLatencySeconds: 30, + startedAt, + completedAt, +}); + +await runtime.observe({ + executionId, + ...acpEvidenceToEngramObservation(evidence), +}); +``` + +## Evidence boundary +- ACP job history is treated as `OBSERVED` external-system evidence. +- SLA breach classification requires caller-supplied expected latency plus observed start/completion timestamps; the adapter does not invent SLA expectations from provider reputation. +- `rejected` and `expired` jobs are preserved as distinct failure classes. +- Raw parsed history is retained in the normalized evidence object for audit/debugging, but the Engram observation records only bounded fields plus a provenance command reference. + +## Live-proof gate +This package is not evidence that the Virtuals partner multiplier has been earned. + +Promotion requires an actual authenticated ACP testnet flow with a real job/agent interaction, retained job ID/chain ID/history, and a later Engram/Sibyl decision whose behavior changes because of that prior ACP experience. From 8bb06ecabcbd5a2ad6b5707e0ee14278900b0bae Mon Sep 17 00:00:00 2001 From: etvjay Date: Mon, 24 Aug 2026 18:00:48 +0100 Subject: [PATCH 057/116] test: cover Virtuals ACP evidence normalization --- tests/adapters/virtuals-acp-evidence.test.ts | 89 ++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 tests/adapters/virtuals-acp-evidence.test.ts diff --git a/tests/adapters/virtuals-acp-evidence.test.ts b/tests/adapters/virtuals-acp-evidence.test.ts new file mode 100644 index 0000000..d358b0b --- /dev/null +++ b/tests/adapters/virtuals-acp-evidence.test.ts @@ -0,0 +1,89 @@ +import { describe, expect, it } from "vitest"; +import { + acpHistoryToExecutionEvidence, + acpEvidenceToEngramObservation, + parseAcpJobHistory, +} from "../../packages/virtuals-acp/src/evidence.js"; + +describe("Virtuals ACP evidence adapter", () => { + it("parses the maintained ACP v2 job-history JSON shape", () => { + const parsed = parseAcpJobHistory({ + jobId: "42", + chainId: 84532, + protocol: "v2", + status: "completed", + entryCount: 3, + entries: [ + { kind: "system", event: { type: "job.created" } }, + { kind: "message", contentType: "requirement", content: "{}" }, + { kind: "system", event: { type: "job.completed" } }, + ], + }); + + expect(parsed).toMatchObject({ jobId: "42", chainId: 84532, protocol: "v2", status: "completed", entryCount: 3 }); + }); + + it("classifies an over-SLA completed job as observed SLA-breach evidence", () => { + const startedAt = new Date("2026-08-24T10:00:00Z"); + const completedAt = new Date("2026-08-24T10:00:55Z"); + const evidence = acpHistoryToExecutionEvidence({ + jobId: "42", + chainId: 84532, + protocol: "v2", + status: "completed", + entryCount: 4, + entries: [], + }, { + providerId: "0xAtlas", + taskType: "data_fetch", + urgency: "URGENT", + expectedLatencySeconds: 30, + startedAt, + completedAt, + }); + + expect(evidence).toMatchObject({ + sourceSystem: "VIRTUALS_ACP", + failureType: "SLA_BREACH", + observedLatencySeconds: 55, + evidenceState: "OBSERVED", + }); + + const observation = acpEvidenceToEngramObservation(evidence); + expect(observation.type).toBe("VIRTUALS_ACP_JOB_OBSERVED"); + expect(observation.payload).toMatchObject({ jobId: "42", chainId: 84532, failureType: "SLA_BREACH" }); + expect(observation.provenance[0]).toMatchObject({ source: "Virtuals ACP", jobId: "42", chainId: 84532 }); + }); + + it("preserves rejected and expired terminal states without pretending they are SLA failures", () => { + const rejected = acpHistoryToExecutionEvidence({ + jobId: 7, + chainId: 84532, + protocol: "v2", + status: "rejected", + entries: [], + }, { + providerId: "0xAtlas", + taskType: "data_fetch", + urgency: "URGENT", + }); + const expired = acpHistoryToExecutionEvidence({ + jobId: 8, + chainId: 84532, + protocol: "v2", + status: "expired", + entries: [], + }, { + providerId: "0xAtlas", + taskType: "data_fetch", + urgency: "URGENT", + }); + + expect(rejected.failureType).toBe("JOB_REJECTED"); + expect(expired.failureType).toBe("JOB_EXPIRED"); + }); + + it("fails closed on malformed ACP history rather than fabricating evidence", () => { + expect(() => parseAcpJobHistory({ status: "completed", entries: [] })).toThrow(); + }); +}); From 538d2d54f1e52f838f87b6bd9381de3b361932d2 Mon Sep 17 00:00:00 2001 From: etvjay Date: Mon, 24 Aug 2026 18:01:10 +0100 Subject: [PATCH 058/116] docs: classify Virtuals ACP adapter server-only --- docs/frontend-modules/server-only.json | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/frontend-modules/server-only.json b/docs/frontend-modules/server-only.json index 1cb8b6c..d818f81 100644 --- a/docs/frontend-modules/server-only.json +++ b/docs/frontend-modules/server-only.json @@ -16,6 +16,7 @@ { "modulePath": "packages/scenarios", "reason": "Internal experiment workloads and application fixtures, not product UI APIs." }, { "modulePath": "packages/sibyl", "reason": "Hackathon runtime-store adapter launches the server-side Sibyl Python SDK and owns local durable memory access; browsers consume resulting traces through Engram API surfaces." }, { "modulePath": "packages/vertex", "reason": "Google Vertex AI embedding client uses Application Default Credentials and must remain server-side." }, + { "modulePath": "packages/virtuals-acp", "reason": "Virtuals ACP adapter handles agent-commerce job evidence and eventually credentialed CLI/testnet interactions; frontend must consume normalized evidence through Engram API surfaces." }, { "modulePath": "services/runtime", "reason": "Server runtime construction and infrastructure wiring." }, { "modulePath": "services/verification", "reason": "Credentialed live-verification and evidence generation service." } ] From 4edfb7030de2ca0282fbefaa0297db409d8fd195 Mon Sep 17 00:00:00 2001 From: etvjay Date: Mon, 24 Aug 2026 18:01:53 +0100 Subject: [PATCH 059/116] virtuals: add ACP CLI runner for live evidence --- packages/virtuals-acp/src/cli.ts | 72 ++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 packages/virtuals-acp/src/cli.ts diff --git a/packages/virtuals-acp/src/cli.ts b/packages/virtuals-acp/src/cli.ts new file mode 100644 index 0000000..3d9e4d5 --- /dev/null +++ b/packages/virtuals-acp/src/cli.ts @@ -0,0 +1,72 @@ +import { spawn } from "node:child_process"; + +export type AcpCliResult = { + stdout: string; + stderr: string; + json: unknown; +}; + +function commandPrefix(): { command: string; args: string[] } { + const configured = process.env.ENGRAM_ACP_BIN?.trim(); + if (configured) return { command: configured, args: [] }; + return { command: "npx", args: ["--yes", "@virtuals-protocol/acp-cli"] }; +} + +export async function runAcpJson(args: string[], options: { testnet?: boolean } = {}): Promise { + const prefix = commandPrefix(); + const commandArgs = [...prefix.args, ...args, "--json"]; + + return new Promise((resolve, reject) => { + const child = spawn(prefix.command, commandArgs, { + env: { + ...process.env, + ...(options.testnet === undefined ? {} : { IS_TESTNET: options.testnet ? "true" : "false" }), + }, + stdio: ["ignore", "pipe", "pipe"], + }); + + let stdout = ""; + let stderr = ""; + child.stdout.setEncoding("utf8"); + child.stderr.setEncoding("utf8"); + child.stdout.on("data", (chunk) => { stdout += chunk; }); + child.stderr.on("data", (chunk) => { stderr += chunk; }); + child.on("error", reject); + child.on("close", (code) => { + const trimmed = stdout.trim(); + if (code !== 0) { + reject(new Error(`ACP_CLI_FAILED: exit=${code}; stderr=${stderr.trim()}; stdout=${trimmed}`)); + return; + } + if (!trimmed) { + reject(new Error(`ACP_CLI_EMPTY_RESPONSE: stderr=${stderr.trim()}`)); + return; + } + try { + const json = JSON.parse(trimmed); + if (json && typeof json === "object" && "error" in json) { + reject(new Error(`ACP_CLI_ERROR_RESPONSE: ${JSON.stringify(json)}`)); + return; + } + resolve({ stdout, stderr, json }); + } catch (error) { + reject(new Error(`ACP_CLI_INVALID_JSON: ${error instanceof Error ? error.message : String(error)}; stdout=${trimmed}`)); + } + }); + }); +} + +export async function fetchAcpJobHistory(input: { + jobId: string; + chainId: number; + testnet?: boolean; +}): Promise { + return (await runAcpJson([ + "job", + "history", + "--job-id", + input.jobId, + "--chain-id", + String(input.chainId), + ], { testnet: input.testnet })).json; +} From c0180f32d91966b54ffe59bcf20d5ae1d514f5ab Mon Sep 17 00:00:00 2001 From: etvjay Date: Mon, 24 Aug 2026 18:02:07 +0100 Subject: [PATCH 060/116] virtuals: add live ACP job ingest command --- scripts/virtuals-acp-ingest.ts | 72 ++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 scripts/virtuals-acp-ingest.ts diff --git a/scripts/virtuals-acp-ingest.ts b/scripts/virtuals-acp-ingest.ts new file mode 100644 index 0000000..e77228f --- /dev/null +++ b/scripts/virtuals-acp-ingest.ts @@ -0,0 +1,72 @@ +import { EngramRuntime } from "../packages/runtime/src/runtime.js"; +import { DEFAULT_RUNTIME_POLICIES } from "../packages/runtime/src/defaults.js"; +import { SibylRuntimeStore } from "../packages/sibyl/src/runtime-store.js"; +import { fetchAcpJobHistory } from "../packages/virtuals-acp/src/cli.js"; +import { + acpEvidenceToEngramObservation, + acpHistoryToExecutionEvidence, +} from "../packages/virtuals-acp/src/evidence.js"; + +function flag(name: string): string | undefined { + const index = process.argv.indexOf(`--${name}`); + return index >= 0 ? process.argv[index + 1] : undefined; +} + +function required(name: string): string { + const value = flag(name); + if (!value) throw new Error(`Missing --${name}`); + return value; +} + +function parseDate(name: string): Date | undefined { + const value = flag(name); + if (!value) return undefined; + const date = new Date(value); + if (Number.isNaN(date.getTime())) throw new Error(`Invalid --${name}: ${value}`); + return date; +} + +const executionId = required("execution-id"); +const jobId = required("job-id"); +const chainId = Number(required("chain-id")); +const providerId = required("provider-id"); +const taskType = required("task-type"); +const urgency = required("urgency").toUpperCase(); +const expectedLatency = flag("expected-latency-seconds"); +const testnet = process.argv.includes("--testnet"); + +if (!Number.isInteger(chainId) || chainId <= 0) throw new Error("--chain-id must be a positive integer"); +if (urgency !== "URGENT" && urgency !== "ROUTINE") throw new Error("--urgency must be URGENT or ROUTINE"); + +const history = await fetchAcpJobHistory({ jobId, chainId, testnet }); +const evidence = acpHistoryToExecutionEvidence(history, { + providerId, + taskType, + urgency, + expectedLatencySeconds: expectedLatency === undefined ? undefined : Number(expectedLatency), + startedAt: parseDate("started-at"), + completedAt: parseDate("completed-at"), +}); + +const runtime = new EngramRuntime(new SibylRuntimeStore(), DEFAULT_RUNTIME_POLICIES); +await runtime.observe({ + executionId, + ...acpEvidenceToEngramObservation(evidence), +}); + +process.stdout.write(`${JSON.stringify({ + phase: "virtuals-acp-ingest", + executionId, + jobId: evidence.jobId, + chainId: evidence.chainId, + protocol: evidence.protocol, + status: evidence.status, + providerId: evidence.providerId, + taskType: evidence.taskType, + urgency: evidence.urgency, + failureType: evidence.failureType ?? null, + observedLatencySeconds: evidence.observedLatencySeconds ?? null, + evidenceState: evidence.evidenceState, + memoryBackend: "sibyl-memory-client", + partnerClaim: "UNVERIFIED_UNTIL_REAL_ACP_JOB_EVIDENCE_IS_RETAINED", +}, null, 2)}\n`); From 59e0ecb012b837391fa9ff1bc9eb36f1d70fc8fc Mon Sep 17 00:00:00 2001 From: etvjay Date: Mon, 24 Aug 2026 18:02:25 +0100 Subject: [PATCH 061/116] virtuals: expose live ACP ingest command --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index ced312f..4767c58 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ "demo:sibyl:provider:seed": "tsx scripts/sibyl-provider-demo.ts seed", "demo:sibyl:provider:urgent": "tsx scripts/sibyl-provider-demo.ts urgent", "demo:sibyl:provider:routine": "tsx scripts/sibyl-provider-demo.ts routine", + "virtuals:acp:ingest": "tsx scripts/virtuals-acp-ingest.ts", "test:all": "vitest run", "test:watch": "vitest", "check": "npm run build && npm run test:all" From 2d8645298b7c753191b338e698f753327da1a1e9 Mon Sep 17 00:00:00 2001 From: etvjay Date: Mon, 24 Aug 2026 18:02:59 +0100 Subject: [PATCH 062/116] scorecard: record judge map and Virtuals adapter boundary --- hackathon/sibyl/requirements/requirements.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hackathon/sibyl/requirements/requirements.json b/hackathon/sibyl/requirements/requirements.json index e5e8800..6ae3cc0 100644 --- a/hackathon/sibyl/requirements/requirements.json +++ b/hackathon/sibyl/requirements/requirements.json @@ -1,21 +1,21 @@ { "verified_at": "2026-08-24", "status": "READY_FOR_LIVE_PRESSURE", - "evidence_note": "Core and experiential-provider gates are LOCAL_PASS from pre-build-window CI. Submission/live-public and partner gates remain unverified and must be re-proven during the official build window.", + "evidence_note": "Core and experiential-provider gates are LOCAL_PASS from pre-build-window CI. Root judge call map is implemented. Virtuals ACP evidence adapter is implemented but partner bonus remains UNVERIFIED until an actual authenticated testnet job is exercised. Submission/live-public gates must be re-proven during the official build window.", "requirements": [ {"id":"SIBYL-GATE-001","track":"main","class":"PUBLISHED_HARD","severity":"VETO","description":"Sibyl Memory is load-bearing; deleting it breaks or materially degrades the core function.","check":"run deletion mutation and compare claimed behavior","evidence_required":"failing/degraded no-Sibyl run plus passing Sibyl run","status":"LOCAL_PASS","evidence":"GitHub Actions run 32753747711 job 97516430322: deletion mutation degraded=true, fallbackAvailable=false"}, {"id":"SIBYL-GATE-002","track":"main","class":"PUBLISHED_HARD","severity":"VETO","description":"Fresh session recalls earlier persisted state.","check":"terminate process/session, restart clean, recall prior memory","evidence_required":"continuous demo segment with timestamp or commit hash","status":"LOCAL_PASS","evidence":"GitHub Actions run 32753747711: separate route and provider history/decision processes recalled exact persisted Sibyl memory IDs"}, {"id":"SIBYL-GATE-003","track":"main","class":"PUBLISHED_HARD","severity":"VETO","description":"Recalled memory changes a decision, action, or result.","check":"paired memory vs no-memory decision comparison","evidence_required":"decision trace and observable action delta","status":"LOCAL_PASS","evidence":"Run 32753747711: route A-B-C -> A-B-D; urgent provider Atlas -> Beacon with CHANGED_ACTION; routine Atlas terms constrained with CONSTRAINED_ACTION"}, - {"id":"SIBYL-GATE-004","track":"main","class":"PUBLISHED_HARD","severity":"HIGH","description":"README exposes critical memory write/read paths in under two minutes.","check":"cold reviewer repo navigation test","evidence_required":"README call map","status":"UNVERIFIED","evidence":"Staging call map exists at hackathon/sibyl/JUDGE_CALL_MAP.md; root README integration and cold-review test still pending"}, + {"id":"SIBYL-GATE-004","track":"main","class":"PUBLISHED_HARD","severity":"HIGH","description":"README exposes critical memory write/read paths in under two minutes.","check":"cold reviewer repo navigation test","evidence_required":"README call map","status":"LOCAL_PASS","evidence":"Root README on hackathon/sibyl-ebi now opens with a judge call map covering Sibyl store wiring, write, read, recall-state binding, influence, provider scenario, process-boundary demo and deletion path. Human cold-review timing remains to be performed."}, {"id":"SCORE-MEM-001","track":"main","class":"PUBLISHED_SCORING","severity":"HIGH","description":"Memory use is sophisticated enough for top band; coordination/dynamic-state behavior preferred.","check":"judge-model scorecard","evidence_required":"non-trivial stateful scenario plus adversarial memory handling","status":"LOCAL_PASS","evidence":"Run 32753747711 job 97516430322: 6/6 Sibyl integration tests; multi-execution experiential relationship memory changes urgent delegation and routine authority; expired and post-recall tamper controls pass. Final evaluator score remains future."}, {"id":"SCORE-TECH-001","track":"main","class":"PUBLISHED_SCORING","severity":"HIGH","description":"Build is clean, robust and survives a second run/curious judge.","check":"repeatability and negative test suite","evidence_required":"test report and second-run evidence","status":"LOCAL_PASS","evidence":"Engram CI run 32753747711: canonical check job 97516431430 and Sibyl profile job 97516430322 both passed on clean runners"}, {"id":"EXP-CONT-001","track":"main","class":"INTERNAL_ACCEPTANCE","severity":"HIGH","description":"Multiple attributable executions may form bounded relationship state only with sufficient lineage.","check":"multi-source provider history test","evidence_required":"two historical executions + admitting execution + relationship memory lineage","status":"LOCAL_PASS","evidence":"Run 32753747711: two Atlas breach executions plus admitting execution produced CONTEXT_GUARDED relationship memory; one-breach and cross-task controls remain baseline"}, {"id":"EXP-CONT-002","track":"main","class":"INTERNAL_ACCEPTANCE","severity":"HIGH","description":"Relationship state changes behavior contextually rather than becoming a global provider blacklist.","check":"urgent vs routine paired decisions","evidence_required":"urgent provider change plus routine authority narrowing using same memory","status":"LOCAL_PASS","evidence":"Run 32753747711: urgent Atlas -> Beacon; routine stays Atlas while prepay 5000 -> 1000 bps and milestone verification false -> true"}, {"id":"SUBMIT-001","track":"submission","class":"PUBLISHED_HARD","severity":"VETO","description":"Public MIT/Apache-2.0 repo with real commit history.","check":"repository inspection","evidence_required":"public repo/license/commits","status":"LOCAL_PASS"}, {"id":"SUBMIT-002","track":"submission","class":"PUBLISHED_HARD","severity":"VETO","description":"2–5 minute demo includes fresh-session recall.","check":"video review","evidence_required":"public video","status":"UNVERIFIED"}, - {"id":"SUBMIT-003","track":"submission","class":"PUBLISHED_HARD","severity":"VETO","description":"README includes Prior Work declaration and required memory/partner notes.","check":"README audit","evidence_required":"merged README","status":"UNVERIFIED"}, + {"id":"SUBMIT-003","track":"submission","class":"PUBLISHED_HARD","severity":"VETO","description":"README includes Prior Work declaration and required memory/partner notes.","check":"README audit","evidence_required":"merged README","status":"UNVERIFIED","evidence":"Branch README now includes explicit Prior Work and memory-path sections; final partner notes and submission-window truth freeze remain pending."}, {"id":"SUBMIT-004","track":"submission","class":"PUBLISHED_HARD","severity":"VETO","description":"Two public posts: demo and build log, tagging required accounts.","check":"public URL verification","evidence_required":"two public post URLs","status":"UNVERIFIED"}, {"id":"BASE-001","track":"base","class":"PUBLISHED_BONUS","severity":"OPTIONAL","description":"Executed Base action shown doing real product work.","check":"protocol-native receipt/explorer evidence","evidence_required":"wallet/x402/B20/contract evidence in demo","status":"UNVERIFIED"}, - {"id":"VIRTUALS-001","track":"virtuals","class":"PUBLISHED_BONUS","severity":"OPTIONAL","description":"Virtuals-native integration is exercised in the demo.","check":"ACP/agent native evidence","evidence_required":"job/transaction/native receipt","status":"UNVERIFIED"} + {"id":"VIRTUALS-001","track":"virtuals","class":"PUBLISHED_BONUS","severity":"OPTIONAL","description":"Virtuals-native integration is exercised in the demo.","check":"ACP/agent native evidence","evidence_required":"job/transaction/native receipt","status":"UNVERIFIED","evidence":"Server-only adapter now normalizes current acp-cli v2 job-history JSON into Engram observations and `virtuals:acp:ingest` can fetch/ingest a live job. No authenticated ACP job has been executed yet; no multiplier claimed."} ] } From ef605a1616c9644e80ec36d854bcb6edf7709394 Mon Sep 17 00:00:00 2001 From: etvjay Date: Mon, 24 Aug 2026 18:04:03 +0100 Subject: [PATCH 063/116] virtuals: add authenticated ACP testnet proof runbook --- hackathon/sibyl/VIRTUALS_LIVE_RUN.md | 194 +++++++++++++++++++++++++++ 1 file changed, 194 insertions(+) create mode 100644 hackathon/sibyl/VIRTUALS_LIVE_RUN.md diff --git a/hackathon/sibyl/VIRTUALS_LIVE_RUN.md b/hackathon/sibyl/VIRTUALS_LIVE_RUN.md new file mode 100644 index 0000000..7676cdd --- /dev/null +++ b/hackathon/sibyl/VIRTUALS_LIVE_RUN.md @@ -0,0 +1,194 @@ +# Virtuals ACP Live Proof Runbook + +Status: `IMPLEMENTED_ADAPTER / AUTHENTICATED_JOB_NOT_RUN` + +Goal: replace the provider-continuity fixture's external interaction boundary with a real Virtuals ACP testnet job while keeping Engram/Sibyl as the memory and influence authority. + +## Safety / truth boundary +- Use the maintained `@virtuals-protocol/acp-cli`. +- Use `IS_TESTNET=true` until the entire proof is stable. +- Every scripted command uses `--json`. +- Authentication and signer state remain in the ACP config / OS keychain. Never commit them. +- Do not claim the Virtuals partner multiplier until a real ACP job/agent interaction is captured in evidence. + +## 1. Install / select testnet + +```bash +npm i -g @virtuals-protocol/acp-cli +export IS_TESTNET=true +``` + +Optional isolated config for the experiment: + +```bash +export ACP_CONFIG_DIR="$HOME/.config/acp-engram-sibyl" +``` + +## 2. Authenticate — split flow + +For agent/tool-driven terminals, do not use the blocking bare configure command. + +```bash +acp configure start --json +``` + +This returns a sign-in URL and request ID. Open the URL, authenticate, then: + +```bash +acp configure complete --request-id --wait --timeout 300 --json +``` + +Expected terminal state: `authenticated` plus wallet address. + +## 3. Create/select requester agent and signer + +Inspect current state first: + +```bash +acp agent list --json +acp agent whoami --json +``` + +If no suitable testnet requester exists: + +```bash +acp agent create \ + --name "Engram Requester" \ + --description "Requester agent for Sibyl experiential-continuity evaluation" \ + --signer \ + --policy restricted \ + --json +``` + +If an agent already exists, select it and ensure a signer is configured using the current ACP CLI guidance before any job action that signs onchain. + +## 4. Discover a real provider/offering + +Start with a low-cost, deterministic-enough service category: + +```bash +acp browse "data analysis" --top-k 5 --json +``` + +Record: +- provider wallet/address; +- provider/agent name; +- offering name; +- price; +- advertised SLA if available; +- supported testnet chain ID. + +Do not invent `Atlas`/`Beacon` identities for the live proof. The deterministic fixture names are test-only. Live evidence uses the actual ACP provider identity. + +## 5. Start an Engram execution before the ACP job + +The live harness needs an Engram execution ID that will receive the ACP observation. Start it through the existing SDK/API/runtime surface with: +- `agentId`: requester identity; +- `workflowType`: `agent_provider_selection`; +- `taskType`: matching the chosen offering; +- provider identity; +- urgency / SLA constraint; +- environment version including ACP testnet and chain. + +Record the Engram execution ID and start timestamp. + +## 6. Create and execute the ACP job + +Recommended offering flow: + +```bash +acp client create-job \ + --provider \ + --offering-name "" \ + --requirements '' \ + --chain-id \ + --json +``` + +Follow the current ACP state machine rather than assuming the next action: + +```text +open -> budget_set -> funded -> submitted -> completed/rejected +``` + +Inspect/watch the job: + +```bash +acp job watch --job-id --timeout 300 --json +acp job history --job-id --chain-id --json +``` + +Funding/release only when the current job state requires it: + +```bash +acp client fund --job-id --amount --chain-id --json +acp client complete --job-id --chain-id --reason "accepted" --json +``` + +If the deliverable is invalid, use the real rejection path rather than forcing a success: + +```bash +acp client reject --job-id --chain-id --reason "" --json +``` + +## 7. Ingest authoritative ACP history into Engram + +Once terminal/meaningful evidence exists, record completion timestamp and run: + +```bash +npm run virtuals:acp:ingest -- \ + --execution-id \ + --job-id \ + --chain-id \ + --provider-id \ + --task-type \ + --urgency URGENT \ + --expected-latency-seconds \ + --started-at \ + --completed-at \ + --testnet +``` + +The command: +1. calls `acp job history ... --json`; +2. validates the current v2 history shape; +3. derives bounded observed evidence; +4. appends `VIRTUALS_ACP_JOB_OBSERVED` to the specified Sibyl-backed Engram execution; +5. emits a receipt that still labels the partner claim unverified until evidence is retained/audited. + +## 8. Admit only what the evidence supports + +One ACP interaction is an execution episode, not automatically a relationship memory. + +For the flagship `CONTEXT_GUARDED` relationship posture, collect multiple attributable interactions or another justified evidence basis, then use Engram's multi-source admission path. + +The existing acceptance rule intentionally rejects: +- a one-failure relationship posture; +- unrelated task-type transfer; +- expired memory; +- post-recall memory mutation. + +## 9. Fresh-session consequence + +After relationship memory is admitted to Sibyl: +1. terminate the requester process/session; +2. start a fresh comparable provider-selection execution; +3. recall the provider relationship memory; +4. show the memory-free candidate decision; +5. show the memory-conditioned ACP provider/terms decision; +6. execute the changed ACP interaction if practical; +7. retain Engram trace + ACP job IDs/history. + +## 10. Promotion evidence + +`VIRTUALS-001` can move above `UNVERIFIED` only when we have: +- authenticated testnet agent identity; +- real ACP provider/offering; +- real ACP job ID + chain ID; +- job history / terminal state; +- Engram execution observation sourced from that history; +- Sibyl memory derived from attributable ACP experience; +- fresh-session decision trace showing the memory's causal role; +- demo evidence that clearly shows the Virtuals-native interaction. + +Until then, adapter/test code is implementation evidence only — not partner-stack proof. From 2c7317ce76f55a6ec24b096c521fd2a2ef73260e Mon Sep 17 00:00:00 2001 From: etvjay Date: Fri, 28 Aug 2026 18:38:40 +0100 Subject: [PATCH 064/116] test: add Virtuals ACP history conformance fixture --- .../virtuals-acp/completed-job-history.json | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 tests/fixtures/virtuals-acp/completed-job-history.json diff --git a/tests/fixtures/virtuals-acp/completed-job-history.json b/tests/fixtures/virtuals-acp/completed-job-history.json new file mode 100644 index 0000000..32fb189 --- /dev/null +++ b/tests/fixtures/virtuals-acp/completed-job-history.json @@ -0,0 +1,31 @@ +{ + "jobId": "engram-acp-fixture-001", + "chainId": 84532, + "protocol": "v2", + "status": "completed", + "entryCount": 5, + "entries": [ + { + "kind": "system", + "event": { "type": "job_opened" } + }, + { + "kind": "message", + "from": "0xRequesterFixture", + "content": "Fetch the requested dataset within the agreed SLA." + }, + { + "kind": "system", + "event": { "type": "funded" } + }, + { + "kind": "message", + "from": "0xProviderFixture", + "content": "Deliverable submitted." + }, + { + "kind": "system", + "event": { "type": "completed" } + } + ] +} From ce2392ec12df9665a9608af1e55c49dcff20cd5d Mon Sep 17 00:00:00 2001 From: etvjay Date: Fri, 28 Aug 2026 18:38:55 +0100 Subject: [PATCH 065/116] test: pressure Virtuals ACP evidence normalization --- .../integration/virtuals-acp-evidence.test.ts | 110 ++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 tests/integration/virtuals-acp-evidence.test.ts diff --git a/tests/integration/virtuals-acp-evidence.test.ts b/tests/integration/virtuals-acp-evidence.test.ts new file mode 100644 index 0000000..4f4d247 --- /dev/null +++ b/tests/integration/virtuals-acp-evidence.test.ts @@ -0,0 +1,110 @@ +import { readFile } from "node:fs/promises"; +import { resolve } from "node:path"; +import { describe, expect, it } from "vitest"; +import { + acpEvidenceToEngramObservation, + acpHistoryToExecutionEvidence, + parseAcpJobHistory, +} from "../../packages/virtuals-acp/src/evidence.js"; + +async function fixture() { + const raw = await readFile(resolve(process.cwd(), "tests/fixtures/virtuals-acp/completed-job-history.json"), "utf8"); + return JSON.parse(raw) as unknown; +} + +describe("Virtuals ACP evidence adapter", () => { + it("normalizes a current v2 history shape without inventing failure", async () => { + const history = await fixture(); + const parsed = parseAcpJobHistory(history); + expect(parsed).toMatchObject({ + jobId: "engram-acp-fixture-001", + chainId: 84532, + protocol: "v2", + status: "completed", + entryCount: 5, + }); + + const evidence = acpHistoryToExecutionEvidence(history, { + providerId: "0xProviderFixture", + taskType: "data_fetch", + urgency: "ROUTINE", + expectedLatencySeconds: 60, + startedAt: new Date("2026-08-28T12:00:00.000Z"), + completedAt: new Date("2026-08-28T12:00:40.000Z"), + }); + + expect(evidence).toMatchObject({ + sourceSystem: "VIRTUALS_ACP", + chainId: 84532, + protocol: "v2", + status: "completed", + providerId: "0xProviderFixture", + observedLatencySeconds: 40, + evidenceState: "OBSERVED", + historyEntryCount: 5, + }); + expect(evidence.failureType).toBeUndefined(); + + const observation = acpEvidenceToEngramObservation(evidence); + expect(observation).toMatchObject({ + type: "VIRTUALS_ACP_JOB_OBSERVED", + evidenceState: "OBSERVED", + payload: { + jobId: "engram-acp-fixture-001", + chainId: 84532, + providerId: "0xProviderFixture", + }, + }); + expect(observation.provenance[0]).toMatchObject({ + source: "Virtuals ACP", + jobId: "engram-acp-fixture-001", + chainId: 84532, + }); + }); + + it("classifies an SLA breach only from explicit expected and observed timing", async () => { + const evidence = acpHistoryToExecutionEvidence(await fixture(), { + providerId: "0xProviderFixture", + taskType: "data_fetch", + urgency: "URGENT", + expectedLatencySeconds: 30, + startedAt: new Date("2026-08-28T12:00:00.000Z"), + completedAt: new Date("2026-08-28T12:00:55.000Z"), + }); + expect(evidence.failureType).toBe("SLA_BREACH"); + expect(evidence.observedLatencySeconds).toBe(55); + }); + + it("preserves rejected and expired jobs as distinct failure classes", () => { + const rejected = acpHistoryToExecutionEvidence({ + jobId: "job-rejected", + chainId: 84532, + protocol: "v2", + status: "rejected", + entries: [], + }, { + providerId: "0xProviderFixture", + taskType: "data_fetch", + urgency: "ROUTINE", + }); + const expired = acpHistoryToExecutionEvidence({ + jobId: "job-expired", + chainId: 84532, + protocol: "v2", + status: "expired", + entries: [], + }, { + providerId: "0xProviderFixture", + taskType: "data_fetch", + urgency: "ROUTINE", + }); + + expect(rejected.failureType).toBe("JOB_REJECTED"); + expect(expired.failureType).toBe("JOB_EXPIRED"); + }); + + it("fails closed on malformed ACP history", () => { + expect(() => parseAcpJobHistory({ status: "completed", entries: [] })).toThrow(); + expect(() => parseAcpJobHistory({ jobId: "x", chainId: -1, status: "completed", entries: [] })).toThrow(); + }); +}); From e7f38996a8687611e6afa77aed19f978607b0cdb Mon Sep 17 00:00:00 2001 From: etvjay Date: Fri, 28 Aug 2026 18:39:08 +0100 Subject: [PATCH 066/116] test: expose Virtuals ACP adapter verification --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 4767c58..c762671 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ "test": "vitest run tests/e2e/memory-caused-behavior.test.ts", "test:integration": "vitest run tests/integration/cockroach-memory-loop.test.ts", "test:sibyl": "ENGRAM_SIBYL_TEST_REQUIRED=1 vitest run tests/integration/sibyl-memory-loop.test.ts tests/integration/sibyl-provider-continuity.test.ts", + "test:virtuals": "vitest run tests/integration/virtuals-acp-evidence.test.ts", "demo:sibyl:seed": "tsx scripts/sibyl-demo.ts seed", "demo:sibyl:recall": "tsx scripts/sibyl-demo.ts recall", "demo:sibyl:no-memory-control": "tsx scripts/sibyl-demo.ts control", From 93cad4f3d42030abe66644824d60e41a8a444450 Mon Sep 17 00:00:00 2001 From: etvjay Date: Fri, 28 Aug 2026 18:39:23 +0100 Subject: [PATCH 067/116] docs: document Virtuals ACP conformance pressure --- packages/virtuals-acp/README.md | 34 +++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/packages/virtuals-acp/README.md b/packages/virtuals-acp/README.md index 1389144..a8cf455 100644 --- a/packages/virtuals-acp/README.md +++ b/packages/virtuals-acp/README.md @@ -1,6 +1,6 @@ # Virtuals ACP evidence adapter -Status: `IMPLEMENTED / LIVE_ACP_UNVERIFIED` +Status: `IMPLEMENTED / LOCAL_CONFORMANCE_PASS_PENDING_CI / LIVE_ACP_UNVERIFIED` This server-only package normalizes machine-readable output from the current Virtuals `@virtuals-protocol/acp-cli` into Engram execution evidence. @@ -29,6 +29,8 @@ Testnet is selected globally: export IS_TESTNET=true ``` +The deterministic conformance fixture uses Base Sepolia chain ID `84532`, which is exposed by the current Virtuals CLI chain configuration. The fixture is synthetic and can never promote the partner evidence state above local conformance. + ## Example ```ts @@ -52,8 +54,36 @@ await runtime.observe({ }); ``` +## Local conformance pressure + +Run: + +```bash +npm run test:virtuals +``` + +The suite checks: + +- current v2 history shape (`jobId`, `chainId`, `protocol`, `status`, `entryCount`, `entries`); +- no invented failure on an on-time completed job; +- `SLA_BREACH` only when explicit expected latency and observed timestamps justify it; +- `rejected` and `expired` remain distinct failure classes; +- malformed or invalid history fails closed. + +Fixture: + +```text +tests/fixtures/virtuals-acp/completed-job-history.json +``` + +Test: + +```text +tests/integration/virtuals-acp-evidence.test.ts +``` + ## Evidence boundary -- ACP job history is treated as `OBSERVED` external-system evidence. +- ACP job history is treated as `OBSERVED` external-system evidence only when it comes from the live ACP command. A repository fixture is `SIMULATED_PASS`/local conformance evidence, never live partner evidence. - SLA breach classification requires caller-supplied expected latency plus observed start/completion timestamps; the adapter does not invent SLA expectations from provider reputation. - `rejected` and `expired` jobs are preserved as distinct failure classes. - Raw parsed history is retained in the normalized evidence object for audit/debugging, but the Engram observation records only bounded fields plus a provenance command reference. From 51e26d4181f6c923774f1f2b077d41c8efa4f68d Mon Sep 17 00:00:00 2001 From: etvjay Date: Fri, 28 Aug 2026 18:39:48 +0100 Subject: [PATCH 068/116] fix: preserve ACP terminal failure causality --- packages/virtuals-acp/src/evidence.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/virtuals-acp/src/evidence.ts b/packages/virtuals-acp/src/evidence.ts index f8ef078..fb08e08 100644 --- a/packages/virtuals-acp/src/evidence.ts +++ b/packages/virtuals-acp/src/evidence.ts @@ -60,8 +60,12 @@ export function acpHistoryToExecutionEvidence( failureType = "UNKNOWN_FAILURE"; } + // Latency is a secondary classification. It may classify an otherwise + // successful/in-flight job as an SLA breach, but must not erase a stronger + // terminal cause such as ACP rejection or expiry. if ( - context.expectedLatencySeconds !== undefined + failureType === undefined + && context.expectedLatencySeconds !== undefined && observedLatencySeconds !== undefined && observedLatencySeconds > context.expectedLatencySeconds ) { From 510c345351d3b49620a12014dfa8b1c90524c2f1 Mon Sep 17 00:00:00 2001 From: etvjay Date: Fri, 28 Aug 2026 18:40:05 +0100 Subject: [PATCH 069/116] test: preserve ACP terminal failure precedence --- tests/integration/virtuals-acp-evidence.test.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/integration/virtuals-acp-evidence.test.ts b/tests/integration/virtuals-acp-evidence.test.ts index 4f4d247..7fa6ad0 100644 --- a/tests/integration/virtuals-acp-evidence.test.ts +++ b/tests/integration/virtuals-acp-evidence.test.ts @@ -86,6 +86,9 @@ describe("Virtuals ACP evidence adapter", () => { providerId: "0xProviderFixture", taskType: "data_fetch", urgency: "ROUTINE", + expectedLatencySeconds: 30, + startedAt: new Date("2026-08-28T12:00:00.000Z"), + completedAt: new Date("2026-08-28T12:02:00.000Z"), }); const expired = acpHistoryToExecutionEvidence({ jobId: "job-expired", @@ -97,6 +100,9 @@ describe("Virtuals ACP evidence adapter", () => { providerId: "0xProviderFixture", taskType: "data_fetch", urgency: "ROUTINE", + expectedLatencySeconds: 30, + startedAt: new Date("2026-08-28T12:00:00.000Z"), + completedAt: new Date("2026-08-28T12:02:00.000Z"), }); expect(rejected.failureType).toBe("JOB_REJECTED"); From 838c189e1953933fef925fefa8b28de6a81884a3 Mon Sep 17 00:00:00 2001 From: etvjay Date: Sat, 29 Aug 2026 00:52:25 +0100 Subject: [PATCH 070/116] test: prove Sibyl preserves unresolved memory conflict --- .../sibyl-competing-memories.test.ts | 178 ++++++++++++++++++ 1 file changed, 178 insertions(+) create mode 100644 tests/integration/sibyl-competing-memories.test.ts diff --git a/tests/integration/sibyl-competing-memories.test.ts b/tests/integration/sibyl-competing-memories.test.ts new file mode 100644 index 0000000..6cb26a6 --- /dev/null +++ b/tests/integration/sibyl-competing-memories.test.ts @@ -0,0 +1,178 @@ +import { afterEach, beforeEach, describe, expect, it } from "vitest"; +import { randomUUID } from "node:crypto"; +import { mkdtemp, rm } from "node:fs/promises"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import type { MemoryRelationship } from "../../packages/evaluation/src/domain.js"; +import { RelationshipMemoryEligibilityAdvisor } from "../../packages/evaluation/src/eligibility-advisor.js"; +import type { OperationalMemory } from "../../packages/memory-core/src/domain.js"; +import { DEFAULT_RUNTIME_POLICIES } from "../../packages/runtime/src/defaults.js"; +import { EngramRuntime } from "../../packages/runtime/src/runtime.js"; +import { SibylRuntimeStore } from "../../packages/sibyl/src/runtime-store.js"; + +const describeSibyl = process.env.ENGRAM_SIBYL_TEST_REQUIRED === "1" ? describe : describe.skip; + +let dir: string; +let previousDb: string | undefined; +let previousTenant: string | undefined; + +beforeEach(async () => { + dir = await mkdtemp(join(tmpdir(), "engram-sibyl-conflict-")); + previousDb = process.env.ENGRAM_SIBYL_DB; + previousTenant = process.env.ENGRAM_SIBYL_TENANT; + process.env.ENGRAM_SIBYL_DB = join(dir, "memory.db"); + process.env.ENGRAM_SIBYL_TENANT = "engram-conflict-test"; +}); + +afterEach(async () => { + if (previousDb === undefined) delete process.env.ENGRAM_SIBYL_DB; + else process.env.ENGRAM_SIBYL_DB = previousDb; + if (previousTenant === undefined) delete process.env.ENGRAM_SIBYL_TENANT; + else process.env.ENGRAM_SIBYL_TENANT = previousTenant; + await rm(dir, { recursive: true, force: true }); +}); + +class RelationshipStore { + relationships: MemoryRelationship[] = []; + + async listRelationships(memoryId: string): Promise { + return this.relationships.filter((relationship) => + relationship.leftMemoryId === memoryId || relationship.rightMemoryId === memoryId, + ); + } +} + +function relationship( + leftMemoryId: string, + rightMemoryId: string, + relation: MemoryRelationship["relation"], +): MemoryRelationship { + return { + id: randomUUID(), + leftMemoryId, + rightMemoryId, + relation, + rationale: `${relation} is explicit evaluation evidence`, + evidenceState: "OBSERVED", + method: "HUMAN_ASSESSMENT", + assessedAt: new Date(), + }; +} + +function memory(id: string, sourceExecutionId: string, summary: string): OperationalMemory { + return { + id, + agentId: "agent-conflict", + memoryType: "OPERATIONAL_LESSON", + summary, + structuredContext: { + workflowType: "deployment", + sourceExecutionId, + sourceExecutionIds: [sourceExecutionId], + outcome: "COMPENSATED", + }, + confidence: 0.93, + evidenceState: "OBSERVED", + validFrom: new Date(Date.now() - 1_000), + environmentVersion: "prod-v1", + toolVersion: "1.4.0", + }; +} + +async function sourceExecution(store: SibylRuntimeStore) { + const runtime = new EngramRuntime(store, DEFAULT_RUNTIME_POLICIES); + const run = await runtime.startExecution({ + agentId: "agent-conflict", + workflowType: "deployment", + intent: "produce conflict evidence", + context: {}, + constraints: {}, + environmentVersion: "prod-v1", + toolVersion: "1.4.0", + }); + await runtime.complete({ + executionId: run.executionId, + status: "COMPENSATED", + summary: "Source execution retained for provenance.", + evidenceState: "OBSERVED", + }); + return run.executionId; +} + +async function start(runtime: EngramRuntime) { + return runtime.startExecution({ + agentId: "agent-conflict", + workflowType: "deployment", + intent: "Deploy service", + context: {}, + constraints: {}, + environmentVersion: "prod-v1", + toolVersion: "1.4.0", + }); +} + +describeSibyl("Sibyl competing memory semantics", () => { + it("keeps contradictory memories recall-visible but rejects influence until explicit supersession", async () => { + const seedStore = new SibylRuntimeStore(); + const sourceA = await sourceExecution(seedStore); + const sourceB = await sourceExecution(seedStore); + const memoryA = memory(randomUUID(), sourceA, "Use dependency alpha during production deployment."); + const memoryB = memory(randomUUID(), sourceB, "Avoid dependency alpha during production deployment."); + await seedStore.persistMemory(memoryA, [sourceA]); + await seedStore.persistMemory(memoryB, [sourceB]); + + const relationships = new RelationshipStore(); + relationships.relationships = [relationship(memoryA.id, memoryB.id, "CONTRADICTS")]; + const advisor = new RelationshipMemoryEligibilityAdvisor(relationships, { + unresolvedContradictionStages: ["INFLUENCE"], + }); + + // Fresh store/runtime proves the memories themselves are coming back through Sibyl. + const runtime = new EngramRuntime(new SibylRuntimeStore(), DEFAULT_RUNTIME_POLICIES, undefined, advisor); + const run = await start(runtime); + const recalled = await runtime.recall({ + executionId: run.executionId, + query: "dependency alpha production deployment", + }); + + expect(recalled.candidates.map((candidate) => candidate.memory.id).sort()).toEqual( + [memoryA.id, memoryB.id].sort(), + ); + + await expect(runtime.recordDecision({ + executionId: run.executionId, + decisionType: "DEPENDENCY_SELECTION", + selectedAction: { dependency: "alpha" }, + reasoningSummary: "Attempt to act on one side of unresolved contradictory Sibyl memory.", + influences: [{ + memoryId: memoryA.id, + retrievalId: recalled.recall.id, + influenceType: "SUPPORTED_ACTION", + summary: "Memory A supports dependency alpha.", + }], + })).rejects.toThrow("UNRESOLVED_MEMORY_CONTRADICTION"); + + const rejectedTrace = await runtime.trace(run.executionId) as Record; + expect((rejectedTrace.decisions as unknown[])).toHaveLength(0); + + relationships.relationships.push(relationship(memoryB.id, memoryA.id, "SUPERSEDES")); + const resolvedRun = await start(runtime); + const resolvedRecall = await runtime.recall({ + executionId: resolvedRun.executionId, + query: "dependency alpha production deployment", + }); + + await expect(runtime.recordDecision({ + executionId: resolvedRun.executionId, + decisionType: "DEPENDENCY_SELECTION", + selectedAction: { dependency: "beta" }, + reasoningSummary: "Explicit supersession resolves the prior contradiction for Memory B.", + influences: [{ + memoryId: memoryB.id, + retrievalId: resolvedRecall.recall.id, + influenceType: "SUPPORTED_ACTION", + summary: "Memory B is eligible after explicit supersession evidence.", + }], + })).resolves.toMatchObject({ executionId: resolvedRun.executionId }); + }, 20_000); +}); From 8f616545a856bb9ce3ab95b14f06af0306417d4e Mon Sep 17 00:00:00 2001 From: etvjay Date: Sat, 29 Aug 2026 00:52:37 +0100 Subject: [PATCH 071/116] test: include Sibyl conflict pressure in evaluated profile --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c762671..48f5f20 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "mcp:stdio": "tsx packages/mcp-server/src/stdio.ts", "test": "vitest run tests/e2e/memory-caused-behavior.test.ts", "test:integration": "vitest run tests/integration/cockroach-memory-loop.test.ts", - "test:sibyl": "ENGRAM_SIBYL_TEST_REQUIRED=1 vitest run tests/integration/sibyl-memory-loop.test.ts tests/integration/sibyl-provider-continuity.test.ts", + "test:sibyl": "ENGRAM_SIBYL_TEST_REQUIRED=1 vitest run tests/integration/sibyl-memory-loop.test.ts tests/integration/sibyl-provider-continuity.test.ts tests/integration/sibyl-competing-memories.test.ts", "test:virtuals": "vitest run tests/integration/virtuals-acp-evidence.test.ts", "demo:sibyl:seed": "tsx scripts/sibyl-demo.ts seed", "demo:sibyl:recall": "tsx scripts/sibyl-demo.ts recall", From 10ecf1623cd9bdbe5f3e9e57d3c2834d85b841d4 Mon Sep 17 00:00:00 2001 From: etvjay Date: Sat, 29 Aug 2026 00:54:10 +0100 Subject: [PATCH 072/116] docs: promote latest Sibyl pressure baseline --- hackathon/sibyl/templates/EVIDENCE_LEDGER.md | 46 ++++++++++++-------- 1 file changed, 29 insertions(+), 17 deletions(-) diff --git a/hackathon/sibyl/templates/EVIDENCE_LEDGER.md b/hackathon/sibyl/templates/EVIDENCE_LEDGER.md index 921878b..307a560 100644 --- a/hackathon/sibyl/templates/EVIDENCE_LEDGER.md +++ b/hackathon/sibyl/templates/EVIDENCE_LEDGER.md @@ -7,23 +7,23 @@ Allowed states: | Claim / gate | State | Evidence | Negative mutation | Notes | |---|---|---|---|---| -| Sibyl persists decision-critical memory | LOCAL_PASS | GitHub Actions run `32753747711`, job `97516430322`, code head `d3d6e983`: SDK 0.6.1 installed; route and provider profile state persisted through Sibyl | missing Sibyl runtime | Pre-build-window evidence; must be re-run during official window | -| Fresh session/process recalls prior memory | LOCAL_PASS | same job: separate seed and recall processes; route memory `d9996c9c-af00-4c05-99b0-bafcdac15b10` and provider relationship memory `f269d755-f642-4495-8f68-da735618d74b` were recalled in later processes | terminate source process / unavailable Sibyl | Stronger than fresh-object-only proof | -| Recalled memory changes action | LOCAL_PASS | same job: route `A-B-C -> A-B-D`; urgent provider `atlas -> beacon`; explicit `CHANGED_ACTION` traces | no-memory control | Paired behavioral deltas, not retrieval-only | -| Recalled memory constrains authority without global blacklist | LOCAL_PASS | same job, fresh routine provider process: Atlas remains selected while prepay falls `5000 -> 1000` bps and milestone verification becomes required; trace records `CONSTRAINED_ACTION` | routine-context control | Demonstrates contextual relationship posture rather than global reputation | -| Multi-execution experience becomes bounded relationship memory | LOCAL_PASS | same job: historical executions `fb0570f6...` + `22a66402...` plus admitting execution `2965c23d...` produced `REPEATED_PATTERN` memory `f269d755...` with `CONTEXT_GUARDED` posture | single-failure fixture / cross-task fixture | Pure scenario tests also require >=2 source executions and task-type applicability | -| Urgent provider experience changes outcome | LOCAL_PASS | same job: no-memory Atlas path deterministically returns `SLA_BREACH`; memory-conditioned Beacon path returns `SUCCESS` | no-memory provider control | This is an application fixture, not a claim about a live provider network | -| Deleting/unavailable Sibyl breaks/degrades core function | LOCAL_PASS | same job: deletion CLI emitted `degraded: true`, `fallbackAvailable: false`, missing-runtime ENOENT | remove/disable Sibyl runtime | VETO; mutation harness fails if Sibyl unexpectedly stays available | -| Engram provenance remains reconstructable | LOCAL_PASS | same job: recall IDs, memory IDs, `engram.memory-state/v1` digests, counterfactuals, accepted influence and evaluation events appear in route/provider traces | post-recall memory tamper | Sibyl backend preserves the trace needed for Engram influence validation | -| Expired Sibyl memory is retrieved but blocked before exposure | LOCAL_PASS | same job `npm run test:sibyl`: expired-memory test passed | expired memory fixture | Demonstrates retrieval != legitimate influence | -| Post-recall memory tamper is rejected | LOCAL_PASS | same job `npm run test:sibyl`: state-digest tamper test passed | overwrite memory after digest exposure | Protects recall-to-decision state integrity | -| Expanded Sibyl pressure suite | LOCAL_PASS | same job: `6 passed` across core + provider-continuity integration tests | timeout/retry history preserved | Initial provider run timed out at 5s; bounded 15s integration timeout added without changing assertions; subsequent run green | -| Canonical Engram suite remains green with optional Sibyl profile | LOCAL_PASS | run `32753747711`, job `97516431430`: `npm run check` passed | canonical test suite | Sibyl external SDK test remains isolated to provisioned Sibyl CI job | -| Conflicting memory remains non-silently adjudicated through Sibyl store | UNVERIFIED | existing Engram semantics only | contradictory Sibyl memory fixture | Still worth adding before final submission pressure | -| Root README exposes critical write/read/influence call map | UNVERIFIED | — | cold reviewer navigation | Published evaluator gate; still required | +| Sibyl persists decision-critical memory | LOCAL_PASS | GitHub Actions run `33221823993`, job `99017280805`, branch head `8f616545`: SDK 0.6.1 installed; route/provider/conflict memories persisted through Sibyl | missing Sibyl runtime | Pre-build-window evidence; must be re-run during official window | +| Fresh session/process recalls prior memory | LOCAL_PASS | run `33221823993`: separate seed and recall processes; route memory plus provider relationship memory were recalled in later processes; conflict test creates a fresh `SibylRuntimeStore` before retrieving both contradictory memories | terminate source process / unavailable Sibyl | Stronger than fresh-object-only proof | +| Recalled memory changes action | LOCAL_PASS | run `33221823993`: route `A-B-C -> A-B-D`; urgent provider `atlas -> beacon`; explicit `CHANGED_ACTION` traces | no-memory control | Paired behavioral deltas, not retrieval-only | +| Recalled memory constrains authority without global blacklist | LOCAL_PASS | run `33221823993`, fresh routine provider process: Atlas remains selected while prepay falls `5000 -> 1000` bps and milestone verification becomes required; trace records `CONSTRAINED_ACTION` | routine-context control | Demonstrates contextual relationship posture rather than global reputation | +| Multi-execution experience becomes bounded relationship memory | LOCAL_PASS | run `33221823993`: two historical Atlas breach executions plus admitting execution produced `CONTEXT_GUARDED` relationship memory | single-failure fixture / cross-task fixture | Pure scenario tests also require >=2 source executions and task-type applicability | +| Urgent provider experience changes outcome | LOCAL_PASS | run `33221823993`: no-memory Atlas path deterministically returns `SLA_BREACH`; memory-conditioned Beacon path returns `SUCCESS` | no-memory provider control | Application fixture, not a claim about a live provider network | +| Deleting/unavailable Sibyl breaks/degrades core function | LOCAL_PASS | run `33221823993`: deletion CLI emitted `degraded: true`, `fallbackAvailable: false`, missing-runtime ENOENT | remove/disable Sibyl runtime | VETO; mutation harness fails if Sibyl unexpectedly stays available | +| Engram provenance remains reconstructable | LOCAL_PASS | run `33221823993`: recall IDs, memory IDs, `engram.memory-state/v1` digests, counterfactuals, accepted influence and evaluation events appear in route/provider traces | post-recall memory tamper | Sibyl backend preserves trace material needed for influence validation | +| Expired Sibyl memory is retrieved but blocked before exposure | LOCAL_PASS | run `33221823993`, `npm run test:sibyl` | expired memory fixture | Demonstrates retrieval != legitimate influence | +| Post-recall memory tamper is rejected | LOCAL_PASS | run `33221823993`, `npm run test:sibyl` | overwrite memory after digest exposure | Protects recall-to-decision state integrity | +| Conflicting memory remains non-silently adjudicated through Sibyl store | LOCAL_PASS | run `33221823993`, job `99017280805`: `sibyl-competing-memories.test.ts` persisted contradictory memories, retrieved both through a fresh Sibyl-backed runtime, rejected influence with `UNRESOLVED_MEMORY_CONTRADICTION`, then allowed the resolved side only after explicit `SUPERSEDES` evidence | unresolved `CONTRADICTS` pair | Proves Sibyl persistence/retrieval does not silently turn ranking into adjudication | +| Expanded Sibyl pressure suite | LOCAL_PASS | run `33221823993`, job `99017280805`: `3` test files and `7/7` tests passed | expiry, tamper, contradiction, deletion, single-failure/cross-task controls | Provider tests retain bounded 15s timeout; contradiction integration test uses bounded 20s timeout because bridge-backed round trips are multi-process | +| Canonical Engram suite remains green with evaluated Sibyl profile | LOCAL_PASS | run `33221823993`, check job `99017280705`: `npm run check` passed; SAM build run `33221823973` also passed | canonical test suite | Same branch head `8f616545a856bb9ce3ab95b14f06af0306417d4e` | +| Root README exposes critical write/read/influence call map | LOCAL_PASS | root README on `hackathon/sibyl-ebi` opens with judge-facing call map for Sibyl wiring, write/read, influence, provider scenario, process-boundary demo and deletion path | cold reviewer navigation | Human under-two-minute timing remains to be performed; therefore not `PUBLIC_EVALUATOR_PASS` | | Hackathon-window rerun of core proof | UNVERIFIED | — | clean clone + fresh DB | Pre-window proof cannot substitute for final event-window evidence | -| Base integration does real product work | UNVERIFIED | — | remove Base action | optional | -| Virtuals integration does real product work | UNVERIFIED | — | remove Virtuals interaction | optional | +| Base integration does real product work | UNVERIFIED | — | remove Base action | optional; do not add decoratively | +| Virtuals integration does real product work | UNVERIFIED | adapter/conformance/live-ingest path implemented; no authenticated ACP job yet | remove Virtuals interaction | optional; partner multiplier remains unclaimed | ## Current flagship interpretation The strongest current memory claim is not `the agent remembers Atlas is bad`. @@ -34,8 +34,20 @@ It is: This is evidence-bounded experiential continuity, not a universal reputation score. +The adversarial corollary is equally important: + +> Retrieval rank is not adjudication. If two persisted memories explicitly contradict each other, Engram may expose both but refuses to let either silently become authority until relationship evidence resolves the conflict. + ## Evidence-history note -A green run proves only the commit/run it actually executed. Run `32753747711` checked the PR state whose candidate head was `d3d6e983...`. Later documentation commits record that evidence but do not strengthen it. +Run `32753747711` remains an earlier pre-window baseline for the original six-test profile. + +The current stronger pre-window baseline is branch head `8f616545a856bb9ce3ab95b14f06af0306417d4e`: +- Engram CI `33221823993`: SUCCESS +- Sibyl profile job `99017280805`: SUCCESS, 3 files / 7 tests +- canonical check job `99017280705`: SUCCESS +- Engram SAM Build `33221823973`: SUCCESS + +A green run proves only the commit/run it actually executed. Later documentation commits may record that evidence but do not strengthen it. Every promotion above `LOCAL_PASS` must point to the exact hackathon-window artifact/run that supports it. From 073f9cee3e1456e510bd114a915f5cf033c3835e Mon Sep 17 00:00:00 2001 From: etvjay Date: Sat, 29 Aug 2026 00:54:26 +0100 Subject: [PATCH 073/116] docs: add Sibyl conflict adjudication gate --- .../sibyl/requirements/requirements.json | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/hackathon/sibyl/requirements/requirements.json b/hackathon/sibyl/requirements/requirements.json index 6ae3cc0..f642692 100644 --- a/hackathon/sibyl/requirements/requirements.json +++ b/hackathon/sibyl/requirements/requirements.json @@ -1,21 +1,22 @@ { - "verified_at": "2026-08-24", + "verified_at": "2026-08-29", "status": "READY_FOR_LIVE_PRESSURE", - "evidence_note": "Core and experiential-provider gates are LOCAL_PASS from pre-build-window CI. Root judge call map is implemented. Virtuals ACP evidence adapter is implemented but partner bonus remains UNVERIFIED until an actual authenticated testnet job is exercised. Submission/live-public gates must be re-proven during the official build window.", + "evidence_note": "Core and experiential-provider gates are LOCAL_PASS from pre-build-window CI. Current stronger baseline is head 8f616545 with Engram CI 33221823993 and SAM build 33221823973. Sibyl conflict handling is now directly pressure-tested. Root judge call map is implemented. Virtuals ACP evidence adapter is implemented but partner bonus remains UNVERIFIED until an actual authenticated testnet job is exercised. Submission/live-public gates must be re-proven during the official build window.", "requirements": [ - {"id":"SIBYL-GATE-001","track":"main","class":"PUBLISHED_HARD","severity":"VETO","description":"Sibyl Memory is load-bearing; deleting it breaks or materially degrades the core function.","check":"run deletion mutation and compare claimed behavior","evidence_required":"failing/degraded no-Sibyl run plus passing Sibyl run","status":"LOCAL_PASS","evidence":"GitHub Actions run 32753747711 job 97516430322: deletion mutation degraded=true, fallbackAvailable=false"}, - {"id":"SIBYL-GATE-002","track":"main","class":"PUBLISHED_HARD","severity":"VETO","description":"Fresh session recalls earlier persisted state.","check":"terminate process/session, restart clean, recall prior memory","evidence_required":"continuous demo segment with timestamp or commit hash","status":"LOCAL_PASS","evidence":"GitHub Actions run 32753747711: separate route and provider history/decision processes recalled exact persisted Sibyl memory IDs"}, - {"id":"SIBYL-GATE-003","track":"main","class":"PUBLISHED_HARD","severity":"VETO","description":"Recalled memory changes a decision, action, or result.","check":"paired memory vs no-memory decision comparison","evidence_required":"decision trace and observable action delta","status":"LOCAL_PASS","evidence":"Run 32753747711: route A-B-C -> A-B-D; urgent provider Atlas -> Beacon with CHANGED_ACTION; routine Atlas terms constrained with CONSTRAINED_ACTION"}, - {"id":"SIBYL-GATE-004","track":"main","class":"PUBLISHED_HARD","severity":"HIGH","description":"README exposes critical memory write/read paths in under two minutes.","check":"cold reviewer repo navigation test","evidence_required":"README call map","status":"LOCAL_PASS","evidence":"Root README on hackathon/sibyl-ebi now opens with a judge call map covering Sibyl store wiring, write, read, recall-state binding, influence, provider scenario, process-boundary demo and deletion path. Human cold-review timing remains to be performed."}, - {"id":"SCORE-MEM-001","track":"main","class":"PUBLISHED_SCORING","severity":"HIGH","description":"Memory use is sophisticated enough for top band; coordination/dynamic-state behavior preferred.","check":"judge-model scorecard","evidence_required":"non-trivial stateful scenario plus adversarial memory handling","status":"LOCAL_PASS","evidence":"Run 32753747711 job 97516430322: 6/6 Sibyl integration tests; multi-execution experiential relationship memory changes urgent delegation and routine authority; expired and post-recall tamper controls pass. Final evaluator score remains future."}, - {"id":"SCORE-TECH-001","track":"main","class":"PUBLISHED_SCORING","severity":"HIGH","description":"Build is clean, robust and survives a second run/curious judge.","check":"repeatability and negative test suite","evidence_required":"test report and second-run evidence","status":"LOCAL_PASS","evidence":"Engram CI run 32753747711: canonical check job 97516431430 and Sibyl profile job 97516430322 both passed on clean runners"}, - {"id":"EXP-CONT-001","track":"main","class":"INTERNAL_ACCEPTANCE","severity":"HIGH","description":"Multiple attributable executions may form bounded relationship state only with sufficient lineage.","check":"multi-source provider history test","evidence_required":"two historical executions + admitting execution + relationship memory lineage","status":"LOCAL_PASS","evidence":"Run 32753747711: two Atlas breach executions plus admitting execution produced CONTEXT_GUARDED relationship memory; one-breach and cross-task controls remain baseline"}, - {"id":"EXP-CONT-002","track":"main","class":"INTERNAL_ACCEPTANCE","severity":"HIGH","description":"Relationship state changes behavior contextually rather than becoming a global provider blacklist.","check":"urgent vs routine paired decisions","evidence_required":"urgent provider change plus routine authority narrowing using same memory","status":"LOCAL_PASS","evidence":"Run 32753747711: urgent Atlas -> Beacon; routine stays Atlas while prepay 5000 -> 1000 bps and milestone verification false -> true"}, + {"id":"SIBYL-GATE-001","track":"main","class":"PUBLISHED_HARD","severity":"VETO","description":"Sibyl Memory is load-bearing; deleting it breaks or materially degrades the core function.","check":"run deletion mutation and compare claimed behavior","evidence_required":"failing/degraded no-Sibyl run plus passing Sibyl run","status":"LOCAL_PASS","evidence":"GitHub Actions run 33221823993 job 99017280805: deletion mutation degraded=true, fallbackAvailable=false"}, + {"id":"SIBYL-GATE-002","track":"main","class":"PUBLISHED_HARD","severity":"VETO","description":"Fresh session recalls earlier persisted state.","check":"terminate process/session, restart clean, recall prior memory","evidence_required":"continuous demo segment with timestamp or commit hash","status":"LOCAL_PASS","evidence":"GitHub Actions run 33221823993: separate route/provider processes recalled persisted Sibyl memory; conflict test also retrieves both contradictory memories through a fresh SibylRuntimeStore"}, + {"id":"SIBYL-GATE-003","track":"main","class":"PUBLISHED_HARD","severity":"VETO","description":"Recalled memory changes a decision, action, or result.","check":"paired memory vs no-memory decision comparison","evidence_required":"decision trace and observable action delta","status":"LOCAL_PASS","evidence":"Run 33221823993: route A-B-C -> A-B-D; urgent provider Atlas -> Beacon with CHANGED_ACTION; routine Atlas terms constrained with CONSTRAINED_ACTION"}, + {"id":"SIBYL-GATE-004","track":"main","class":"PUBLISHED_HARD","severity":"HIGH","description":"README exposes critical memory write/read paths in under two minutes.","check":"cold reviewer repo navigation test","evidence_required":"README call map","status":"LOCAL_PASS","evidence":"Root README on hackathon/sibyl-ebi opens with a judge call map covering Sibyl store wiring, write, read, recall-state binding, influence, provider scenario, process-boundary demo and deletion path. Human cold-review timing remains to be performed."}, + {"id":"SCORE-MEM-001","track":"main","class":"PUBLISHED_SCORING","severity":"HIGH","description":"Memory use is sophisticated enough for top band; coordination/dynamic-state behavior preferred.","check":"judge-model scorecard","evidence_required":"non-trivial stateful scenario plus adversarial memory handling","status":"LOCAL_PASS","evidence":"Run 33221823993 job 99017280805: 7/7 Sibyl integration tests; multi-execution experiential relationship memory changes urgent delegation and routine authority; expiry, post-recall tamper and unresolved-contradiction controls pass. Final evaluator score remains future."}, + {"id":"SCORE-TECH-001","track":"main","class":"PUBLISHED_SCORING","severity":"HIGH","description":"Build is clean, robust and survives a second run/curious judge.","check":"repeatability and negative test suite","evidence_required":"test report and second-run evidence","status":"LOCAL_PASS","evidence":"Head 8f616545: Engram CI 33221823993 and Engram SAM Build 33221823973 both succeeded on clean runners"}, + {"id":"EXP-CONT-001","track":"main","class":"INTERNAL_ACCEPTANCE","severity":"HIGH","description":"Multiple attributable executions may form bounded relationship state only with sufficient lineage.","check":"multi-source provider history test","evidence_required":"two historical executions + admitting execution + relationship memory lineage","status":"LOCAL_PASS","evidence":"Run 33221823993: two Atlas breach executions plus admitting execution produced CONTEXT_GUARDED relationship memory; one-breach and cross-task controls remain baseline"}, + {"id":"EXP-CONT-002","track":"main","class":"INTERNAL_ACCEPTANCE","severity":"HIGH","description":"Relationship state changes behavior contextually rather than becoming a global provider blacklist.","check":"urgent vs routine paired decisions","evidence_required":"urgent provider change plus routine authority narrowing using same memory","status":"LOCAL_PASS","evidence":"Run 33221823993: urgent Atlas -> Beacon; routine stays Atlas while prepay 5000 -> 1000 bps and milestone verification false -> true"}, + {"id":"EXP-CONT-003","track":"main","class":"INTERNAL_ACCEPTANCE","severity":"HIGH","description":"Retrieval ranking must not silently adjudicate explicit contradictory memories.","check":"persist contradictory memories through Sibyl, fresh-recall both, attempt influence before and after explicit resolution","evidence_required":"both memories recall-visible; unresolved influence rejected; explicit supersession required before resolved influence","status":"LOCAL_PASS","evidence":"Run 33221823993 job 99017280805: sibyl-competing-memories.test.ts rejected unresolved influence with UNRESOLVED_MEMORY_CONTRADICTION and only accepted the resolved side after SUPERSEDES evidence"}, {"id":"SUBMIT-001","track":"submission","class":"PUBLISHED_HARD","severity":"VETO","description":"Public MIT/Apache-2.0 repo with real commit history.","check":"repository inspection","evidence_required":"public repo/license/commits","status":"LOCAL_PASS"}, {"id":"SUBMIT-002","track":"submission","class":"PUBLISHED_HARD","severity":"VETO","description":"2–5 minute demo includes fresh-session recall.","check":"video review","evidence_required":"public video","status":"UNVERIFIED"}, - {"id":"SUBMIT-003","track":"submission","class":"PUBLISHED_HARD","severity":"VETO","description":"README includes Prior Work declaration and required memory/partner notes.","check":"README audit","evidence_required":"merged README","status":"UNVERIFIED","evidence":"Branch README now includes explicit Prior Work and memory-path sections; final partner notes and submission-window truth freeze remain pending."}, + {"id":"SUBMIT-003","track":"submission","class":"PUBLISHED_HARD","severity":"VETO","description":"README includes Prior Work declaration and required memory/partner notes.","check":"README audit","evidence_required":"merged README","status":"UNVERIFIED","evidence":"Branch README includes explicit Prior Work and memory-path sections; final partner notes and submission-window truth freeze remain pending."}, {"id":"SUBMIT-004","track":"submission","class":"PUBLISHED_HARD","severity":"VETO","description":"Two public posts: demo and build log, tagging required accounts.","check":"public URL verification","evidence_required":"two public post URLs","status":"UNVERIFIED"}, {"id":"BASE-001","track":"base","class":"PUBLISHED_BONUS","severity":"OPTIONAL","description":"Executed Base action shown doing real product work.","check":"protocol-native receipt/explorer evidence","evidence_required":"wallet/x402/B20/contract evidence in demo","status":"UNVERIFIED"}, - {"id":"VIRTUALS-001","track":"virtuals","class":"PUBLISHED_BONUS","severity":"OPTIONAL","description":"Virtuals-native integration is exercised in the demo.","check":"ACP/agent native evidence","evidence_required":"job/transaction/native receipt","status":"UNVERIFIED","evidence":"Server-only adapter now normalizes current acp-cli v2 job-history JSON into Engram observations and `virtuals:acp:ingest` can fetch/ingest a live job. No authenticated ACP job has been executed yet; no multiplier claimed."} + {"id":"VIRTUALS-001","track":"virtuals","class":"PUBLISHED_BONUS","severity":"OPTIONAL","description":"Virtuals-native integration is exercised in the demo.","check":"ACP/agent native evidence","evidence_required":"job/transaction/native receipt","status":"UNVERIFIED","evidence":"Server-only adapter normalizes current acp-cli v2 job-history JSON into Engram observations and virtuals:acp:ingest can fetch/ingest a live job. No authenticated ACP job has been executed yet; no multiplier claimed."} ] } From 074e1b07e334fb433a9937e922647dc0164fd697 Mon Sep 17 00:00:00 2001 From: etvjay Date: Sat, 29 Aug 2026 00:55:07 +0100 Subject: [PATCH 074/116] feat: add reproducible Sibyl evidence capture harness --- scripts/sibyl-evidence-capture.ts | 104 ++++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 scripts/sibyl-evidence-capture.ts diff --git a/scripts/sibyl-evidence-capture.ts b/scripts/sibyl-evidence-capture.ts new file mode 100644 index 0000000..af50585 --- /dev/null +++ b/scripts/sibyl-evidence-capture.ts @@ -0,0 +1,104 @@ +import { mkdir, writeFile } from "node:fs/promises"; +import { spawnSync } from "node:child_process"; +import { resolve } from "node:path"; + +function safeStamp(date = new Date()): string { + return date.toISOString().replace(/[:.]/g, "-"); +} + +function gitHead(): string { + const result = spawnSync("git", ["rev-parse", "HEAD"], { encoding: "utf8" }); + if (result.status !== 0) return "unknown"; + return result.stdout.trim(); +} + +type Step = { + id: string; + args: string[]; +}; + +type StepReceipt = { + id: string; + command: string; + exitCode: number | null; + stdoutFile: string; + stderrFile: string; + startedAt: string; + completedAt: string; +}; + +const capturedAt = new Date(); +const head = gitHead(); +const stamp = safeStamp(capturedAt); +const outputDir = resolve( + process.env.ENGRAM_EVIDENCE_DIR ?? `artifacts/sibyl-evidence/${stamp}-${head.slice(0, 12)}`, +); +const dbPath = resolve(outputDir, "sibyl-evidence.db"); +const tenant = process.env.ENGRAM_SIBYL_TENANT ?? `engram-evidence-${stamp}`; + +const steps: Step[] = [ + { id: "sibyl-pressure-suite", args: ["run", "test:sibyl"] }, + { id: "route-seed", args: ["run", "demo:sibyl:seed"] }, + { id: "route-fresh-recall", args: ["run", "demo:sibyl:recall"] }, + { id: "route-no-memory-control", args: ["run", "demo:sibyl:no-memory-control"] }, + { id: "provider-history", args: ["run", "demo:sibyl:provider:seed"] }, + { id: "provider-fresh-urgent", args: ["run", "demo:sibyl:provider:urgent"] }, + { id: "provider-fresh-routine", args: ["run", "demo:sibyl:provider:routine"] }, + { id: "sibyl-deletion-mutation", args: ["run", "test:sibyl:deletion"] }, +]; + +await mkdir(outputDir, { recursive: true }); + +const baseEnv = { + ...process.env, + ENGRAM_SIBYL_DB: dbPath, + ENGRAM_SIBYL_TENANT: tenant, +}; + +const receipts: StepReceipt[] = []; +let failed = false; + +for (const step of steps) { + const startedAt = new Date(); + const result = spawnSync("npm", step.args, { + encoding: "utf8", + env: baseEnv, + cwd: process.cwd(), + }); + const completedAt = new Date(); + const stdoutFile = `${step.id}.stdout.txt`; + const stderrFile = `${step.id}.stderr.txt`; + await writeFile(resolve(outputDir, stdoutFile), result.stdout ?? "", "utf8"); + await writeFile(resolve(outputDir, stderrFile), result.stderr ?? "", "utf8"); + + receipts.push({ + id: step.id, + command: `npm ${step.args.join(" ")}`, + exitCode: result.status, + stdoutFile, + stderrFile, + startedAt: startedAt.toISOString(), + completedAt: completedAt.toISOString(), + }); + + if (result.status !== 0) { + failed = true; + break; + } +} + +const manifest = { + schema: "engram.sibyl-evidence-capture/v1", + capturedAt: capturedAt.toISOString(), + gitHead: head, + tenant, + dbFile: "sibyl-evidence.db", + status: failed ? "FAILED" : "LOCAL_PASS", + evidenceBoundary: "This capture is local/CI evidence unless the surrounding run is itself an eligible public evaluator or live partner execution.", + steps: receipts, +}; + +await writeFile(resolve(outputDir, "manifest.json"), `${JSON.stringify(manifest, null, 2)}\n`, "utf8"); + +process.stdout.write(`${JSON.stringify({ outputDir, ...manifest }, null, 2)}\n`); +if (failed) process.exit(1); From f2673d15e763c005a9ee746cebc13b43fdfb00a5 Mon Sep 17 00:00:00 2001 From: etvjay Date: Sat, 29 Aug 2026 00:55:15 +0100 Subject: [PATCH 075/116] chore: ignore generated Sibyl evidence captures --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index f6d427f..9344b66 100644 --- a/.gitignore +++ b/.gitignore @@ -18,6 +18,7 @@ coverage/ # Generated external evidence (uploaded as workflow artifacts, not committed) evidence/live/ evidence/aws/ +artifacts/sibyl-evidence/ # Logs and editor/OS noise *.log From 1da1871a5665c14994794941c1823cf480bdb00e Mon Sep 17 00:00:00 2001 From: etvjay Date: Sat, 29 Aug 2026 00:55:27 +0100 Subject: [PATCH 076/116] feat: expose Sibyl evidence capture command --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 48f5f20..a37d7c9 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ "demo:sibyl:provider:seed": "tsx scripts/sibyl-provider-demo.ts seed", "demo:sibyl:provider:urgent": "tsx scripts/sibyl-provider-demo.ts urgent", "demo:sibyl:provider:routine": "tsx scripts/sibyl-provider-demo.ts routine", + "evidence:sibyl:capture": "tsx scripts/sibyl-evidence-capture.ts", "virtuals:acp:ingest": "tsx scripts/virtuals-acp-ingest.ts", "test:all": "vitest run", "test:watch": "vitest", From edd9f1a2f5f296623ecfebc819129cca0587b1b5 Mon Sep 17 00:00:00 2001 From: etvjay Date: Sat, 29 Aug 2026 00:55:35 +0100 Subject: [PATCH 077/116] ci: add manual Sibyl evidence artifact workflow --- .github/workflows/sibyl-evidence-capture.yml | 30 ++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 .github/workflows/sibyl-evidence-capture.yml diff --git a/.github/workflows/sibyl-evidence-capture.yml b/.github/workflows/sibyl-evidence-capture.yml new file mode 100644 index 0000000..dae1233 --- /dev/null +++ b/.github/workflows/sibyl-evidence-capture.yml @@ -0,0 +1,30 @@ +name: Sibyl Evidence Capture + +on: + workflow_dispatch: + +jobs: + capture: + runs-on: ubuntu-latest + permissions: + contents: read + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 22 + - uses: actions/setup-python@v5 + with: + python-version: '3.12' + - run: npm install + - run: python -m pip install -r packages/sibyl/requirements.txt + - run: npm run build + - name: Capture fresh Sibyl evidence bundle + run: npm run evidence:sibyl:capture + - name: Upload evidence bundle + uses: actions/upload-artifact@v4 + with: + name: sibyl-evidence-${{ github.sha }} + path: artifacts/sibyl-evidence/ + if-no-files-found: error + retention-days: 30 From 06e1c2dbff40419d9864218ed19ab3cfad3528dd Mon Sep 17 00:00:00 2001 From: etvjay Date: Sat, 29 Aug 2026 04:46:14 +0100 Subject: [PATCH 078/116] feat: make Sibyl evidence bundle self-verifying --- scripts/sibyl-evidence-capture.ts | 70 +++++++++++++++++++++++++++---- 1 file changed, 63 insertions(+), 7 deletions(-) diff --git a/scripts/sibyl-evidence-capture.ts b/scripts/sibyl-evidence-capture.ts index af50585..05f22c6 100644 --- a/scripts/sibyl-evidence-capture.ts +++ b/scripts/sibyl-evidence-capture.ts @@ -1,4 +1,5 @@ -import { mkdir, writeFile } from "node:fs/promises"; +import { createHash } from "node:crypto"; +import { mkdir, readFile, writeFile } from "node:fs/promises"; import { spawnSync } from "node:child_process"; import { resolve } from "node:path"; @@ -6,10 +7,23 @@ function safeStamp(date = new Date()): string { return date.toISOString().replace(/[:.]/g, "-"); } -function gitHead(): string { - const result = spawnSync("git", ["rev-parse", "HEAD"], { encoding: "utf8" }); +function commandOutput(command: string, args: string[]): string { + const result = spawnSync(command, args, { encoding: "utf8", cwd: process.cwd() }); if (result.status !== 0) return "unknown"; - return result.stdout.trim(); + return result.stdout.trim() || result.stderr.trim() || "unknown"; +} + +function gitHead(): string { + return commandOutput("git", ["rev-parse", "HEAD"]); +} + +async function sha256File(path: string): Promise { + try { + const body = await readFile(path); + return createHash("sha256").update(body).digest("hex"); + } catch { + return null; + } } type Step = { @@ -22,7 +36,9 @@ type StepReceipt = { command: string; exitCode: number | null; stdoutFile: string; + stdoutSha256: string | null; stderrFile: string; + stderrSha256: string | null; startedAt: string; completedAt: string; }; @@ -30,11 +46,23 @@ type StepReceipt = { const capturedAt = new Date(); const head = gitHead(); const stamp = safeStamp(capturedAt); +const sourceTreeStatus = commandOutput("git", ["status", "--porcelain"]); +const sourceTreeClean = sourceTreeStatus === "unknown" ? false : sourceTreeStatus.length === 0; +const allowDirty = process.env.ENGRAM_EVIDENCE_ALLOW_DIRTY === "1"; + +if (!sourceTreeClean && !allowDirty) { + throw new Error( + `EVIDENCE_SOURCE_TREE_DIRTY: commit-stamped evidence requires a clean working tree. ` + + `Set ENGRAM_EVIDENCE_ALLOW_DIRTY=1 only for non-submission diagnostics. status=${JSON.stringify(sourceTreeStatus)}`, + ); +} + const outputDir = resolve( process.env.ENGRAM_EVIDENCE_DIR ?? `artifacts/sibyl-evidence/${stamp}-${head.slice(0, 12)}`, ); const dbPath = resolve(outputDir, "sibyl-evidence.db"); const tenant = process.env.ENGRAM_SIBYL_TENANT ?? `engram-evidence-${stamp}`; +const python = process.env.ENGRAM_SIBYL_PYTHON ?? "python3"; const steps: Step[] = [ { id: "sibyl-pressure-suite", args: ["run", "test:sibyl"] }, @@ -68,15 +96,19 @@ for (const step of steps) { const completedAt = new Date(); const stdoutFile = `${step.id}.stdout.txt`; const stderrFile = `${step.id}.stderr.txt`; - await writeFile(resolve(outputDir, stdoutFile), result.stdout ?? "", "utf8"); - await writeFile(resolve(outputDir, stderrFile), result.stderr ?? "", "utf8"); + const stdoutPath = resolve(outputDir, stdoutFile); + const stderrPath = resolve(outputDir, stderrFile); + await writeFile(stdoutPath, result.stdout ?? "", "utf8"); + await writeFile(stderrPath, result.stderr ?? "", "utf8"); receipts.push({ id: step.id, command: `npm ${step.args.join(" ")}`, exitCode: result.status, stdoutFile, + stdoutSha256: await sha256File(stdoutPath), stderrFile, + stderrSha256: await sha256File(stderrPath), startedAt: startedAt.toISOString(), completedAt: completedAt.toISOString(), }); @@ -87,14 +119,38 @@ for (const step of steps) { } } +const packageLockPath = resolve(process.cwd(), "package-lock.json"); +const sibylRequirementsPath = resolve(process.cwd(), "packages/sibyl/requirements.txt"); +const dbSha256 = await sha256File(dbPath); + const manifest = { - schema: "engram.sibyl-evidence-capture/v1", + schema: "engram.sibyl-evidence-capture/v2", capturedAt: capturedAt.toISOString(), + repository: commandOutput("git", ["remote", "get-url", "origin"]), gitHead: head, + sourceTreeClean, + sourceTreeStatus, tenant, + environment: { + platform: process.platform, + arch: process.arch, + node: process.version, + npm: commandOutput("npm", ["--version"]), + python: commandOutput(python, ["--version"]), + sibylMemoryClient: commandOutput(python, [ + "-c", + "import importlib.metadata as m; print(m.version('sibyl-memory-client'))", + ]), + }, + dependencyDigests: { + packageLockSha256: await sha256File(packageLockPath), + sibylRequirementsSha256: await sha256File(sibylRequirementsPath), + }, dbFile: "sibyl-evidence.db", + dbSha256, status: failed ? "FAILED" : "LOCAL_PASS", evidenceBoundary: "This capture is local/CI evidence unless the surrounding run is itself an eligible public evaluator or live partner execution.", + integrityNote: "SHA-256 values bind retained stdout/stderr, dependency manifests, and the final Sibyl database to this manifest. The manifest itself is the root receipt and should be retained with the artifact.", steps: receipts, }; From f074c1a159dc4ee0af51b6d58fd564811308f600 Mon Sep 17 00:00:00 2001 From: etvjay Date: Sat, 29 Aug 2026 04:46:23 +0100 Subject: [PATCH 079/116] ci: smoke Sibyl evidence capture path --- .github/workflows/ci.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d82903d..7033d0d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -47,3 +47,9 @@ jobs: run: npm run demo:sibyl:provider:routine - name: Remove Sibyl runtime and prove fail-closed degradation run: npm run test:sibyl:deletion + - name: Smoke exact evidence capture path + env: + ENGRAM_EVIDENCE_DIR: /tmp/engram-sibyl-evidence-smoke + run: npm run evidence:sibyl:capture + - name: Verify evidence manifest exists + run: test -s /tmp/engram-sibyl-evidence-smoke/manifest.json From 6928ca3461585e92d92a2ffdb3d64e4cdb6166d1 Mon Sep 17 00:00:00 2001 From: etvjay Date: Sat, 29 Aug 2026 04:46:47 +0100 Subject: [PATCH 080/116] docs: promote Virtuals adapter local conformance status --- packages/virtuals-acp/README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/virtuals-acp/README.md b/packages/virtuals-acp/README.md index a8cf455..224769d 100644 --- a/packages/virtuals-acp/README.md +++ b/packages/virtuals-acp/README.md @@ -1,6 +1,6 @@ # Virtuals ACP evidence adapter -Status: `IMPLEMENTED / LOCAL_CONFORMANCE_PASS_PENDING_CI / LIVE_ACP_UNVERIFIED` +Status: `IMPLEMENTED / LOCAL_CONFORMANCE_PASS / LIVE_ACP_UNVERIFIED` This server-only package normalizes machine-readable output from the current Virtuals `@virtuals-protocol/acp-cli` into Engram execution evidence. @@ -82,10 +82,12 @@ Test: tests/integration/virtuals-acp-evidence.test.ts ``` +Current conformance state is `LOCAL_CONFORMANCE_PASS`: the adapter suite is included by the repository's canonical `npm run test:all` / `npm run check` path and has passed in CI. This is code-contract evidence only; it is not evidence of a real ACP interaction. + ## Evidence boundary - ACP job history is treated as `OBSERVED` external-system evidence only when it comes from the live ACP command. A repository fixture is `SIMULATED_PASS`/local conformance evidence, never live partner evidence. - SLA breach classification requires caller-supplied expected latency plus observed start/completion timestamps; the adapter does not invent SLA expectations from provider reputation. -- `rejected` and `expired` jobs are preserved as distinct failure classes. +- `rejected` and `expired` jobs are preserved as distinct failure classes and take causal precedence over a derived latency classification. - Raw parsed history is retained in the normalized evidence object for audit/debugging, but the Engram observation records only bounded fields plus a provenance command reference. ## Live-proof gate From 2beedcc9536d6772921b0055948dde81d3e40ef8 Mon Sep 17 00:00:00 2001 From: etvjay Date: Sat, 29 Aug 2026 04:47:07 +0100 Subject: [PATCH 081/116] docs: expose Sibyl evidence and contradiction paths --- README.md | 200 ++++++++---------------------------------------------- 1 file changed, 28 insertions(+), 172 deletions(-) diff --git a/README.md b/README.md index fbc682d..51f66c5 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ The `hackathon/sibyl-ebi` branch contains a dedicated evaluated profile for the The hackathon profile is designed around the deletion test: remove Sibyl and the cross-session memory required to reproduce the claimed behavior disappears. -### Judge call map — write → read → influence → deletion +### Judge call map — write → read → influence → conflict → deletion | Judge question | Critical path | |---|---| @@ -22,10 +22,36 @@ The hackathon profile is designed around the deletion test: remove Sibyl and the | Where is decision-critical memory written? | `SibylRuntimeStore.persistMemory(...)` → bridge `put` → Sibyl WARM entity `operational_memory`. | | Where is it read in a later session? | `SibylRuntimeStore.searchMemory(...)` → bridge `search_memories`; Engram Runtime then applies recall eligibility before exposure. | | How is recall distinguished from influence? | `packages/runtime/src/runtime.ts`: `recall(...)` creates a memory-state digest; `recordDecision(...)` validates retrieval provenance and influence policy before recording `CHANGED_ACTION` / `CONSTRAINED_ACTION`. | +| What prevents search rank from silently resolving contradictory memories? | `tests/integration/sibyl-competing-memories.test.ts`: both contradictory memories remain recall-visible through Sibyl; unresolved influence is rejected until explicit `SUPERSEDES` evidence resolves the relevant side. | | Where is the flagship relationship-memory policy? | `packages/scenarios/provider-continuity/src/index.ts`. | -| Where is the Sibyl integration pressure test? | `tests/integration/sibyl-memory-loop.test.ts` and `tests/integration/sibyl-provider-continuity.test.ts`. | +| Where is the Sibyl integration pressure suite? | `tests/integration/sibyl-memory-loop.test.ts`, `tests/integration/sibyl-provider-continuity.test.ts`, and `tests/integration/sibyl-competing-memories.test.ts`. | | How do I see process-boundary recall? | `npm run demo:sibyl:provider:seed`, terminate that process, then run `npm run demo:sibyl:provider:urgent` or `npm run demo:sibyl:provider:routine` against the same Sibyl DB/tenant. | | How is load-bearing deletion tested? | `npm run test:sibyl:deletion`; it removes the configured Sibyl runtime and must report degradation with no fallback. | +| How do I reproduce the complete evidence bundle? | After installing the pinned Sibyl dependency, run `npm run evidence:sibyl:capture`. It uses a fresh Sibyl DB/tenant, separate processes for the behavioral phases, and emits a commit/timestamp/version-stamped `manifest.json` with SHA-256 integrity metadata. | + +### One-command evidence capture + +Install the evaluated Sibyl dependency, then capture the full pre-submission proof: + +```bash +python -m pip install -r packages/sibyl/requirements.txt +npm run evidence:sibyl:capture +``` + +The capture fails on a dirty source tree by default so the manifest's git SHA actually identifies the tested source. For non-submission diagnostics only, `ENGRAM_EVIDENCE_ALLOW_DIRTY=1` may override that guard. + +The generated evidence bundle binds: + +- exact UTC capture time and git SHA; +- repository URL and clean-tree state; +- Node, npm, Python and `sibyl-memory-client` versions; +- dependency-manifest SHA-256 digests; +- separate-process route and provider outputs; +- contradiction, expiry, tamper and deletion pressure results; +- the final Sibyl SQLite database digest; +- SHA-256 digests for retained stdout/stderr files. + +The manually dispatched `.github/workflows/sibyl-evidence-capture.yml` runs the same command on a clean GitHub-hosted runner and uploads the bundle as an artifact. A successful CI or local capture is still `LOCAL_PASS` unless the surrounding run qualifies for a stronger evidence state. ### How memory made this possible @@ -178,173 +204,3 @@ DATABASE_URL='postgresql://...' npm run migrate ``` Run the credential-gated integration suite: - -```bash -DATABASE_URL='postgresql://...' npm run test:integration -``` - -CockroachDB is Engram's canonical operational-memory substrate. Application hot-path reads/writes use the PostgreSQL-compatible connection. CockroachDB Cloud Managed MCP is a separate read/introspection/provenance plane. - -Production retrieval is agent-scoped and cosine based. Successful vector ordering does **not** prove C-SPANN index use; the live verifier records the natural `EXPLAIN` plan and promotes that claim only when the optimizer actually selects the expected vector index. - -## TypeScript SDK - -Inside this monorepo, the canonical SDK barrel is `packages/sdk/src/index.ts` and exposes `Engram`, `httpTransport`, `runtimeTransport`, and the transport types: - -```ts -import { Engram, httpTransport } from "./packages/sdk/src/index.js"; - -const engram = new Engram(httpTransport({ - baseUrl: process.env.ENGRAM_API_URL!, - apiToken: process.env.ENGRAM_API_TOKEN, -})); - -const execution = await engram.startExecution({ - agentId: "deployment-agent", - workflowType: "deployment", - intent: "Deploy safely", - context: { service: "api" }, - constraints: {}, -}); - -const recall = await execution.recall({ query: "comparable prior failures" }); - -// The application/agent decides. Engram does not. -const decision = await application.decide({ memories: recall.candidates }); - -await execution.recordDecision({ - decisionType: "DEPLOYMENT_STRATEGY", - selectedAction: decision.action, - reasoningSummary: decision.summary, - influences: decision.memoryInfluences, -}); -``` - -The SDK is currently a monorepo package surface; publication as an installable `@engram/sdk` registry package is not claimed yet. - -## Python SDK - -```python -from engram import Engram - -client = Engram( - "https://YOUR_API", - api_token="SERVER_SIDE_TOKEN", -) - -execution = client.start_execution( - agentId="deployment-agent", - workflowType="deployment", - intent="Deploy safely", - context={"service": "api"}, - constraints={}, -) - -recall = execution.recall("comparable prior failures") -``` - -## HTTP API - -Core runtime routes: - -```text -POST /v1/executions -POST /v1/executions/{id}/recall -POST /v1/executions/{id}/decisions -POST /v1/executions/{id}/observations -POST /v1/executions/{id}/complete -GET /v1/executions/{id}/trace -``` - -Read-focused control-plane routes live under `/v1/control-plane/*`. - -`GET /health` and `POST /v1/demo/run` are intentionally public in the MVP. Every other `/v1/*` route requires `Authorization: Bearer $ENGRAM_API_TOKEN` and fails closed if the server token is not configured. - -The shared bearer token is an initial deployment guard, **not** production multi-tenant RBAC. Do not place it in a public frontend bundle. - -## Engram MCP vs CockroachDB Managed MCP - -These are intentionally different surfaces. - -**Engram MCP** exposes execution-memory semantics such as execution inspection, memory inspection, recall and influence explanation. - -**CockroachDB Cloud Managed MCP** is used as a read/introspection/provenance interface to the underlying CockroachDB data plane. - -Managed MCP is not Engram's transactional application database driver. - -## AWS deployment - -The SAM application packages successfully in CI. Local package proof: - -```bash -npm install -export PATH="$PWD/node_modules/.bin:$PATH" -sam build -``` - -The repository contains two manual external-proof workflows: - -- `.github/workflows/live-verification.yml` — CockroachDB + Bedrock + Managed MCP + natural C-SPANN plan evidence; -- `.github/workflows/aws-deploy-verification.yml` — SAM deploy plus deployed public/authenticated API exercise. - -Neither external workflow should be treated as successful merely because its code exists. See [`docs/deployment.md`](docs/deployment.md) for credentials, promotion rules and evidence artifacts. - -## Evidence status - -Engram keeps implementation/test evidence separate from live-cloud evidence. - -Current high-level boundary: - -| Area | Status | -|---|---| -| Protocol/runtime causal invariants | TESTED | -| SDK/API/MCP/adapters | TESTED | -| Memory policy/evaluation | TESTED | -| Stronger execution-memory scenarios | TESTED | -| Sibyl evaluated profile, pre-window | LOCAL_PASS | -| SAM packaging | TESTED | -| External demo workload | SIMULATED | -| CockroachDB Cloud live persistence | UNVERIFIED until credentialed live proof | -| Bedrock Titan live invocation | UNVERIFIED until credentialed live proof | -| Managed MCP live provenance | UNVERIFIED until credentialed live proof | -| Natural C-SPANN index selection | UNVERIFIED until EXPLAIN proves it | -| AWS Lambda public deployment | UNVERIFIED until deploy-verification succeeds | - -The authoritative machine-readable claim ledger is [`evidence/claims.yaml`](evidence/claims.yaml). The Sibyl hackathon evidence ledger is [`hackathon/sibyl/templates/EVIDENCE_LEDGER.md`](hackathon/sibyl/templates/EVIDENCE_LEDGER.md). - -## Repository map - -```text -apps/web/ Control-plane UI -services/api/ Lambda/HTTP API -services/runtime/ Runtime composition -services/demo/ Deterministic causal demo -services/verification/ Credentialed external verifier -packages/core/ Protocol primitives -packages/episode/ ExecutionEpisode schema -packages/runtime/ Memory runtime -packages/policy/ Policy contracts/registry -packages/evaluation/ Memory evaluation semantics -packages/sdk/ TypeScript SDK -packages/python/ Python SDK -packages/mcp-server/ Engram semantic MCP -packages/adapters/ Framework adapters -packages/cockroach/ Cockroach persistence/vector runtime -packages/cockroach-mcp/ Managed MCP client -packages/bedrock/ Titan embeddings -packages/sibyl/ Sibyl evaluated runtime-store profile (server-only) -packages/scenarios/ Domain acceptance workloads -db/migrations/ Ordered schema migrations -experiments/ Governed acceptance evidence -evidence/ Claim ledger and adversarial reviews -tests/ Unit/integration/conformance/E2E proofs -hackathon/sibyl/ Sibyl EBI truth/evidence wrapper -``` - -## What Engram is not - -Engram is not generic chat memory, a generic RAG wrapper, an autonomous adjudicator, or a replacement for an agent framework. It does not infer that retrieval equals influence and does not turn a later successful outcome into proof that a memory was beneficial. - -## License - -MIT. See [`LICENSE`](LICENSE). From 45806957b4eae16c3a5204de0eff1c5be2c381af Mon Sep 17 00:00:00 2001 From: etvjay Date: Sat, 29 Aug 2026 04:48:10 +0100 Subject: [PATCH 082/116] fix: accept empty clean git status in evidence capture --- scripts/sibyl-evidence-capture.ts | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/scripts/sibyl-evidence-capture.ts b/scripts/sibyl-evidence-capture.ts index 05f22c6..0460880 100644 --- a/scripts/sibyl-evidence-capture.ts +++ b/scripts/sibyl-evidence-capture.ts @@ -13,6 +13,12 @@ function commandOutput(command: string, args: string[]): string { return result.stdout.trim() || result.stderr.trim() || "unknown"; } +function commandStdoutAllowEmpty(command: string, args: string[]): string | null { + const result = spawnSync(command, args, { encoding: "utf8", cwd: process.cwd() }); + if (result.status !== 0) return null; + return result.stdout.trim(); +} + function gitHead(): string { return commandOutput("git", ["rev-parse", "HEAD"]); } @@ -46,8 +52,9 @@ type StepReceipt = { const capturedAt = new Date(); const head = gitHead(); const stamp = safeStamp(capturedAt); -const sourceTreeStatus = commandOutput("git", ["status", "--porcelain"]); -const sourceTreeClean = sourceTreeStatus === "unknown" ? false : sourceTreeStatus.length === 0; +const sourceTreeStatusResult = commandStdoutAllowEmpty("git", ["status", "--porcelain"]); +const sourceTreeStatus = sourceTreeStatusResult ?? "unknown"; +const sourceTreeClean = sourceTreeStatusResult !== null && sourceTreeStatusResult.length === 0; const allowDirty = process.env.ENGRAM_EVIDENCE_ALLOW_DIRTY === "1"; if (!sourceTreeClean && !allowDirty) { From afb3ac3751cd0c9a736266f199d4f87682251913 Mon Sep 17 00:00:00 2001 From: etvjay Date: Sat, 29 Aug 2026 04:50:06 +0100 Subject: [PATCH 083/116] fix: distinguish setup residue from source drift --- scripts/sibyl-evidence-capture.ts | 36 ++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/scripts/sibyl-evidence-capture.ts b/scripts/sibyl-evidence-capture.ts index 0460880..249d0d1 100644 --- a/scripts/sibyl-evidence-capture.ts +++ b/scripts/sibyl-evidence-capture.ts @@ -54,13 +54,25 @@ const head = gitHead(); const stamp = safeStamp(capturedAt); const sourceTreeStatusResult = commandStdoutAllowEmpty("git", ["status", "--porcelain"]); const sourceTreeStatus = sourceTreeStatusResult ?? "unknown"; -const sourceTreeClean = sourceTreeStatusResult !== null && sourceTreeStatusResult.length === 0; +const sourceTreeStatusLines = sourceTreeStatusResult === null || sourceTreeStatusResult.length === 0 + ? [] + : sourceTreeStatusResult.split("\n").map((line) => line.trimEnd()).filter(Boolean); + +// `npm install` currently creates this untracked file because the repository +// does not commit a package lock. It is setup residue, not source drift. It is +// still hashed into the evidence manifest if present. +const allowedGeneratedStatusLines = new Set(["?? package-lock.json"]); +const allowedGeneratedStatus = sourceTreeStatusLines.filter((line) => allowedGeneratedStatusLines.has(line)); +const unexpectedSourceTreeStatus = sourceTreeStatusLines.filter((line) => !allowedGeneratedStatusLines.has(line)); +const submissionSourceClean = sourceTreeStatusResult !== null && unexpectedSourceTreeStatus.length === 0; +const literallyClean = sourceTreeStatusResult !== null && sourceTreeStatusLines.length === 0; const allowDirty = process.env.ENGRAM_EVIDENCE_ALLOW_DIRTY === "1"; -if (!sourceTreeClean && !allowDirty) { +if (!submissionSourceClean && !allowDirty) { throw new Error( - `EVIDENCE_SOURCE_TREE_DIRTY: commit-stamped evidence requires a clean working tree. ` - + `Set ENGRAM_EVIDENCE_ALLOW_DIRTY=1 only for non-submission diagnostics. status=${JSON.stringify(sourceTreeStatus)}`, + `EVIDENCE_SOURCE_TREE_DIRTY: commit-stamped evidence requires no tracked source drift or unexpected untracked files. ` + + `Set ENGRAM_EVIDENCE_ALLOW_DIRTY=1 only for non-submission diagnostics. ` + + `unexpected=${JSON.stringify(unexpectedSourceTreeStatus)}`, ); } @@ -126,6 +138,7 @@ for (const step of steps) { } } +const packageJsonPath = resolve(process.cwd(), "package.json"); const packageLockPath = resolve(process.cwd(), "package-lock.json"); const sibylRequirementsPath = resolve(process.cwd(), "packages/sibyl/requirements.txt"); const dbSha256 = await sha256File(dbPath); @@ -135,8 +148,14 @@ const manifest = { capturedAt: capturedAt.toISOString(), repository: commandOutput("git", ["remote", "get-url", "origin"]), gitHead: head, - sourceTreeClean, - sourceTreeStatus, + sourceTree: { + submissionSourceClean, + literallyClean, + rawStatus: sourceTreeStatus, + allowedGeneratedStatus, + unexpectedStatus: unexpectedSourceTreeStatus, + dirtyOverrideUsed: allowDirty && !submissionSourceClean, + }, tenant, environment: { platform: process.platform, @@ -150,14 +169,15 @@ const manifest = { ]), }, dependencyDigests: { - packageLockSha256: await sha256File(packageLockPath), + packageJsonSha256: await sha256File(packageJsonPath), + generatedPackageLockSha256: await sha256File(packageLockPath), sibylRequirementsSha256: await sha256File(sibylRequirementsPath), }, dbFile: "sibyl-evidence.db", dbSha256, status: failed ? "FAILED" : "LOCAL_PASS", evidenceBoundary: "This capture is local/CI evidence unless the surrounding run is itself an eligible public evaluator or live partner execution.", - integrityNote: "SHA-256 values bind retained stdout/stderr, dependency manifests, and the final Sibyl database to this manifest. The manifest itself is the root receipt and should be retained with the artifact.", + integrityNote: "SHA-256 values bind retained stdout/stderr, dependency manifests/setup lockfile when present, and the final Sibyl database to this manifest. The manifest itself is the root receipt and should be retained with the artifact.", steps: receipts, }; From 5b42e0fe69b065b5b79f2d695f0a3742072b670f Mon Sep 17 00:00:00 2001 From: etvjay Date: Sat, 29 Aug 2026 04:52:07 +0100 Subject: [PATCH 084/116] docs: promote self-verifying Sibyl capture baseline --- hackathon/sibyl/templates/EVIDENCE_LEDGER.md | 47 +++++++++++--------- 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/hackathon/sibyl/templates/EVIDENCE_LEDGER.md b/hackathon/sibyl/templates/EVIDENCE_LEDGER.md index 307a560..3edcf3a 100644 --- a/hackathon/sibyl/templates/EVIDENCE_LEDGER.md +++ b/hackathon/sibyl/templates/EVIDENCE_LEDGER.md @@ -7,23 +7,24 @@ Allowed states: | Claim / gate | State | Evidence | Negative mutation | Notes | |---|---|---|---|---| -| Sibyl persists decision-critical memory | LOCAL_PASS | GitHub Actions run `33221823993`, job `99017280805`, branch head `8f616545`: SDK 0.6.1 installed; route/provider/conflict memories persisted through Sibyl | missing Sibyl runtime | Pre-build-window evidence; must be re-run during official window | -| Fresh session/process recalls prior memory | LOCAL_PASS | run `33221823993`: separate seed and recall processes; route memory plus provider relationship memory were recalled in later processes; conflict test creates a fresh `SibylRuntimeStore` before retrieving both contradictory memories | terminate source process / unavailable Sibyl | Stronger than fresh-object-only proof | -| Recalled memory changes action | LOCAL_PASS | run `33221823993`: route `A-B-C -> A-B-D`; urgent provider `atlas -> beacon`; explicit `CHANGED_ACTION` traces | no-memory control | Paired behavioral deltas, not retrieval-only | -| Recalled memory constrains authority without global blacklist | LOCAL_PASS | run `33221823993`, fresh routine provider process: Atlas remains selected while prepay falls `5000 -> 1000` bps and milestone verification becomes required; trace records `CONSTRAINED_ACTION` | routine-context control | Demonstrates contextual relationship posture rather than global reputation | -| Multi-execution experience becomes bounded relationship memory | LOCAL_PASS | run `33221823993`: two historical Atlas breach executions plus admitting execution produced `CONTEXT_GUARDED` relationship memory | single-failure fixture / cross-task fixture | Pure scenario tests also require >=2 source executions and task-type applicability | -| Urgent provider experience changes outcome | LOCAL_PASS | run `33221823993`: no-memory Atlas path deterministically returns `SLA_BREACH`; memory-conditioned Beacon path returns `SUCCESS` | no-memory provider control | Application fixture, not a claim about a live provider network | -| Deleting/unavailable Sibyl breaks/degrades core function | LOCAL_PASS | run `33221823993`: deletion CLI emitted `degraded: true`, `fallbackAvailable: false`, missing-runtime ENOENT | remove/disable Sibyl runtime | VETO; mutation harness fails if Sibyl unexpectedly stays available | -| Engram provenance remains reconstructable | LOCAL_PASS | run `33221823993`: recall IDs, memory IDs, `engram.memory-state/v1` digests, counterfactuals, accepted influence and evaluation events appear in route/provider traces | post-recall memory tamper | Sibyl backend preserves trace material needed for influence validation | -| Expired Sibyl memory is retrieved but blocked before exposure | LOCAL_PASS | run `33221823993`, `npm run test:sibyl` | expired memory fixture | Demonstrates retrieval != legitimate influence | -| Post-recall memory tamper is rejected | LOCAL_PASS | run `33221823993`, `npm run test:sibyl` | overwrite memory after digest exposure | Protects recall-to-decision state integrity | -| Conflicting memory remains non-silently adjudicated through Sibyl store | LOCAL_PASS | run `33221823993`, job `99017280805`: `sibyl-competing-memories.test.ts` persisted contradictory memories, retrieved both through a fresh Sibyl-backed runtime, rejected influence with `UNRESOLVED_MEMORY_CONTRADICTION`, then allowed the resolved side only after explicit `SUPERSEDES` evidence | unresolved `CONTRADICTS` pair | Proves Sibyl persistence/retrieval does not silently turn ranking into adjudication | -| Expanded Sibyl pressure suite | LOCAL_PASS | run `33221823993`, job `99017280805`: `3` test files and `7/7` tests passed | expiry, tamper, contradiction, deletion, single-failure/cross-task controls | Provider tests retain bounded 15s timeout; contradiction integration test uses bounded 20s timeout because bridge-backed round trips are multi-process | -| Canonical Engram suite remains green with evaluated Sibyl profile | LOCAL_PASS | run `33221823993`, check job `99017280705`: `npm run check` passed; SAM build run `33221823973` also passed | canonical test suite | Same branch head `8f616545a856bb9ce3ab95b14f06af0306417d4e` | -| Root README exposes critical write/read/influence call map | LOCAL_PASS | root README on `hackathon/sibyl-ebi` opens with judge-facing call map for Sibyl wiring, write/read, influence, provider scenario, process-boundary demo and deletion path | cold reviewer navigation | Human under-two-minute timing remains to be performed; therefore not `PUBLIC_EVALUATOR_PASS` | +| Sibyl persists decision-critical memory | LOCAL_PASS | GitHub Actions run `33232373531`, job `99047294445`, branch head `afb3ac3751cd0c9a736266f199d4f87682251913`: SDK 0.6.1 installed; route/provider/conflict memories persisted through Sibyl | missing Sibyl runtime | Pre-build-window evidence; must be re-run during official window | +| Fresh session/process recalls prior memory | LOCAL_PASS | run `33232373531`: separate seed and recall processes; route memory plus provider relationship memory recalled in later processes; conflict test creates a fresh `SibylRuntimeStore` before retrieving both contradictory memories | terminate source process / unavailable Sibyl | Stronger than fresh-object-only proof | +| Recalled memory changes action | LOCAL_PASS | run `33232373531`: route `A-B-C -> A-B-D`; urgent provider `atlas -> beacon`; explicit `CHANGED_ACTION` traces | no-memory control | Paired behavioral deltas, not retrieval-only | +| Recalled memory constrains authority without global blacklist | LOCAL_PASS | run `33232373531`, fresh routine provider process: Atlas remains selected while prepay falls `5000 -> 1000` bps and milestone verification becomes required; trace records `CONSTRAINED_ACTION` | routine-context control | Demonstrates contextual relationship posture rather than global reputation | +| Multi-execution experience becomes bounded relationship memory | LOCAL_PASS | run `33232373531`: two historical Atlas breach executions plus admitting execution produced `CONTEXT_GUARDED` relationship memory | single-failure fixture / cross-task fixture | Pure scenario tests also require >=2 source executions and task-type applicability | +| Urgent provider experience changes outcome | LOCAL_PASS | run `33232373531`: no-memory Atlas path deterministically returns `SLA_BREACH`; memory-conditioned Beacon path returns `SUCCESS` | no-memory provider control | Application fixture, not a claim about a live provider network | +| Deleting/unavailable Sibyl breaks/degrades core function | LOCAL_PASS | run `33232373531`: deletion CLI emitted degradation with no fallback | remove/disable Sibyl runtime | VETO; mutation harness fails if Sibyl unexpectedly stays available | +| Engram provenance remains reconstructable | LOCAL_PASS | run `33232373531`: recall IDs, memory IDs, `engram.memory-state/v1` digests, counterfactuals, accepted influence and evaluation events appear in route/provider traces | post-recall memory tamper | Sibyl backend preserves trace material needed for influence validation | +| Expired Sibyl memory is retrieved but blocked before exposure | LOCAL_PASS | run `33232373531`, `npm run test:sibyl` | expired memory fixture | Demonstrates retrieval != legitimate influence | +| Post-recall memory tamper is rejected | LOCAL_PASS | run `33232373531`, `npm run test:sibyl` | overwrite memory after digest exposure | Protects recall-to-decision state integrity | +| Conflicting memory remains non-silently adjudicated through Sibyl store | LOCAL_PASS | run `33232373531`, job `99047294445`: contradictory memories remain recall-visible, unresolved influence is rejected, explicit `SUPERSEDES` resolves the relevant side | unresolved `CONTRADICTS` pair | Proves Sibyl persistence/retrieval does not silently turn ranking into adjudication | +| Expanded Sibyl pressure suite | LOCAL_PASS | run `33232373531`, job `99047294445`: `3` test files / `7` tests passed, followed by route/provider/deletion process-boundary proof | expiry, tamper, contradiction, deletion, single-failure/cross-task controls | Same evaluated profile remains repeatable on clean hosted runners | +| Self-verifying evidence capture path | LOCAL_PASS | run `33232373531`, job `99047294445`: `Smoke exact evidence capture path` and `Verify evidence manifest exists` both passed on head `afb3ac37` | dirty source / unexpected untracked file; failed precursor run `33232299952` | Capture v2 records git/source state, environment versions, dependency digests, output SHA-256 values and final Sibyl DB digest | +| Canonical Engram suite remains green with evaluated Sibyl profile | LOCAL_PASS | run `33232373531`, check job `99047294544`: `npm run check` passed; SAM build run `33232373540` also passed | canonical test suite | Same branch head `afb3ac3751cd0c9a736266f199d4f87682251913` | +| Root README exposes critical write/read/influence/conflict/deletion/evidence call map | LOCAL_PASS | root README on `hackathon/sibyl-ebi` exposes all critical judged paths plus one-command capture | cold reviewer navigation | Human under-two-minute timing remains to be performed; therefore not `PUBLIC_EVALUATOR_PASS` | | Hackathon-window rerun of core proof | UNVERIFIED | — | clean clone + fresh DB | Pre-window proof cannot substitute for final event-window evidence | | Base integration does real product work | UNVERIFIED | — | remove Base action | optional; do not add decoratively | -| Virtuals integration does real product work | UNVERIFIED | adapter/conformance/live-ingest path implemented; no authenticated ACP job yet | remove Virtuals interaction | optional; partner multiplier remains unclaimed | +| Virtuals integration does real product work | UNVERIFIED | adapter/conformance/live-ingest path implemented; local conformance passed; no authenticated ACP job yet | remove Virtuals interaction | optional; partner multiplier remains unclaimed | ## Current flagship interpretation The strongest current memory claim is not `the agent remembers Atlas is bad`. @@ -41,11 +42,17 @@ The adversarial corollary is equally important: ## Evidence-history note Run `32753747711` remains an earlier pre-window baseline for the original six-test profile. -The current stronger pre-window baseline is branch head `8f616545a856bb9ce3ab95b14f06af0306417d4e`: -- Engram CI `33221823993`: SUCCESS -- Sibyl profile job `99017280805`: SUCCESS, 3 files / 7 tests -- canonical check job `99017280705`: SUCCESS -- Engram SAM Build `33221823973`: SUCCESS +Head `8f616545...` / run `33221823993` added the Sibyl-backed contradiction gate and passed 7/7 Sibyl tests. + +The first exact capture-smoke run on head `45806957...`, CI `33232299952`, intentionally surfaced an evidence-harness failure after every product/Sibyl phase passed: `npm install` generated an untracked `package-lock.json`, which the first strict source-tree guard treated as unexpected dirtiness. That run is retained as a failed harness attempt, not a product failure. + +The current strongest pre-window engineering baseline is branch head `afb3ac3751cd0c9a736266f199d4f87682251913`: +- Engram CI `33232373531`: SUCCESS +- Sibyl profile job `99047294445`: SUCCESS, including exact evidence-capture smoke and manifest check +- canonical check job `99047294544`: SUCCESS +- Engram SAM Build `33232373540`: SUCCESS + +The corrected capture classifies only the known generated untracked `package-lock.json` as setup residue, records and hashes it when present, and continues to veto tracked source drift or unexpected untracked files. A green run proves only the commit/run it actually executed. Later documentation commits may record that evidence but do not strengthen it. From a482148a9bf329241b0a99dda1a94b74aafe5acb Mon Sep 17 00:00:00 2001 From: etvjay Date: Sat, 29 Aug 2026 17:49:57 +0100 Subject: [PATCH 085/116] feat: add Base settlement authority model --- packages/base-settlement/src/index.ts | 113 ++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 packages/base-settlement/src/index.ts diff --git a/packages/base-settlement/src/index.ts b/packages/base-settlement/src/index.ts new file mode 100644 index 0000000..d257645 --- /dev/null +++ b/packages/base-settlement/src/index.ts @@ -0,0 +1,113 @@ +import type { + ProviderDecision, + ProviderId, + ProviderTerms, +} from "../../scenarios/provider-continuity/src/index.js"; + +export const BASE_SEPOLIA_CHAIN_ID = 84_532; +export const BASE_SEPOLIA_NETWORK = "base-sepolia" as const; +export const BASE_SEPOLIA_USDC = "0x036CbD53842c5426634e7929541eC2318f3dCF7e" as const; +export const USDC_DECIMALS = 6; + +const ADDRESS_RE = /^0x[0-9a-fA-F]{40}$/; + +export type ProviderAddressBook = Record; + +export type SettlementProvenance = { + executionId: string; + retrievalId?: string; + decisionId?: string; +}; + +export type BaseSettlementTerms = { + maxSpendUsd: number; + prepayBps: number; + authorizedPrepayAtomic: bigint; + authorizedPrepayUsd: string; + requireMilestoneVerification: boolean; +}; + +export type BaseSettlementCounterfactual = { + providerId: ProviderId; + recipient: string; + terms: BaseSettlementTerms; +}; + +export type BaseSettlementIntent = { + schema: "engram.base-settlement-intent/v1"; + chainId: typeof BASE_SEPOLIA_CHAIN_ID; + network: typeof BASE_SEPOLIA_NETWORK; + token: "USDC"; + tokenAddress: typeof BASE_SEPOLIA_USDC; + providerId: ProviderId; + recipient: string; + terms: BaseSettlementTerms; + memoryRefs: string[]; + provenance: SettlementProvenance; + counterfactual?: BaseSettlementCounterfactual; +}; + +function assertAddress(address: string, label: string): string { + if (!ADDRESS_RE.test(address)) throw new Error(`INVALID_${label.toUpperCase()}_ADDRESS`); + return address; +} + +function usdToUsdcAtomic(value: number): bigint { + if (!Number.isFinite(value) || value < 0) throw new Error("INVALID_USD_AMOUNT"); + const scaled = Math.round(value * 1_000_000); + if (Math.abs((scaled / 1_000_000) - value) > 1e-9) { + throw new Error("USD_AMOUNT_EXCEEDS_USDC_PRECISION"); + } + return BigInt(scaled); +} + +export function usdcAtomicToDecimal(value: bigint): string { + if (value < 0n) throw new Error("NEGATIVE_USDC_AMOUNT"); + const whole = value / 1_000_000n; + const fraction = (value % 1_000_000n).toString().padStart(6, "0"); + return `${whole}.${fraction}`; +} + +function settlementTerms(terms: ProviderTerms): BaseSettlementTerms { + if (!Number.isInteger(terms.prepayBps) || terms.prepayBps < 0 || terms.prepayBps > 10_000) { + throw new Error("INVALID_PREPAY_BPS"); + } + const maxSpendAtomic = usdToUsdcAtomic(terms.maxSpendUsd); + const authorizedPrepayAtomic = (maxSpendAtomic * BigInt(terms.prepayBps)) / 10_000n; + return { + maxSpendUsd: terms.maxSpendUsd, + prepayBps: terms.prepayBps, + authorizedPrepayAtomic, + authorizedPrepayUsd: usdcAtomicToDecimal(authorizedPrepayAtomic), + requireMilestoneVerification: terms.requireMilestoneVerification, + }; +} + +export function deriveBaseSettlementIntent(input: { + decision: ProviderDecision; + addresses: ProviderAddressBook; + provenance: SettlementProvenance; +}): BaseSettlementIntent { + const recipient = assertAddress(input.addresses[input.decision.providerId], "provider"); + const counterfactual = input.decision.counterfactual + ? { + providerId: input.decision.counterfactual.providerId, + recipient: assertAddress(input.addresses[input.decision.counterfactual.providerId], "counterfactual_provider"), + terms: settlementTerms(input.decision.counterfactual.terms), + } + : undefined; + + return { + schema: "engram.base-settlement-intent/v1", + chainId: BASE_SEPOLIA_CHAIN_ID, + network: BASE_SEPOLIA_NETWORK, + token: "USDC", + tokenAddress: BASE_SEPOLIA_USDC, + providerId: input.decision.providerId, + recipient, + terms: settlementTerms(input.decision.terms), + memoryRefs: [...input.decision.memoryRefs], + provenance: input.provenance, + counterfactual, + }; +} From 4aea898bec208ab4e8054ef8e652a36350acd37f Mon Sep 17 00:00:00 2001 From: etvjay Date: Sat, 29 Aug 2026 17:50:13 +0100 Subject: [PATCH 086/116] test: prove memory changes Base settlement authority --- .../base-settlement-authority.test.ts | 136 ++++++++++++++++++ 1 file changed, 136 insertions(+) create mode 100644 tests/integration/base-settlement-authority.test.ts diff --git a/tests/integration/base-settlement-authority.test.ts b/tests/integration/base-settlement-authority.test.ts new file mode 100644 index 0000000..68940eb --- /dev/null +++ b/tests/integration/base-settlement-authority.test.ts @@ -0,0 +1,136 @@ +import { describe, expect, it } from "vitest"; +import { + BASE_SEPOLIA_CHAIN_ID, + BASE_SEPOLIA_USDC, + deriveBaseSettlementIntent, +} from "../../packages/base-settlement/src/index.js"; +import { + decideProviderEngagement, + type ProviderContinuityContext, + type ProviderOffer, + type RecalledProviderMemory, +} from "../../packages/scenarios/provider-continuity/src/index.js"; +import type { OperationalMemory } from "../../packages/memory-core/src/domain.js"; + +const addresses = { + atlas: "0x1111111111111111111111111111111111111111", + beacon: "0x2222222222222222222222222222222222222222", +}; + +const offers: ProviderOffer[] = [ + { providerId: "atlas", priceUsd: 8, expectedLatencySeconds: 20 }, + { providerId: "beacon", priceUsd: 11, expectedLatencySeconds: 18 }, +]; + +function relationshipMemory(): RecalledProviderMemory { + return { + finalScore: 0.99, + memory: { + id: "memory-atlas-guarded", + agentId: "requester-agent", + workflowType: "agent_provider_selection", + memoryType: "REPEATED_PATTERN", + summary: "Repeated Atlas SLA breaches.", + structuredContext: { + workflowType: "agent_provider_selection", + memoryPrimitive: "EXPERIENTIAL_RELATIONSHIP", + taskType: "data_fetch", + providerId: "atlas", + relationshipPosture: "CONTEXT_GUARDED", + failureType: "SLA_BREACH", + breachCount: 2, + sourceExecutionIds: ["exec-1", "exec-2"], + }, + sourceExecutionIds: ["exec-1", "exec-2"], + confidence: 0.92, + evidenceState: "OBSERVED", + status: "ACTIVE", + createdAt: new Date("2026-08-29T00:00:00.000Z"), + updatedAt: new Date("2026-08-29T00:00:00.000Z"), + } as OperationalMemory, + }; +} + +function context(urgency: "URGENT" | "ROUTINE"): ProviderContinuityContext { + return { + workflowType: "agent_provider_selection", + taskType: "data_fetch", + urgency, + budgetUsd: 20, + maxLatencySeconds: 30, + environmentVersion: "provider-market-v1", + }; +} + +describe("Base settlement authority", () => { + it("turns remembered urgent provider experience into a different Base recipient", () => { + const baseline = decideProviderEngagement({ context: context("URGENT"), offers, memories: [] }); + const conditioned = decideProviderEngagement({ + context: context("URGENT"), + offers, + memories: [relationshipMemory()], + }); + + const baselineIntent = deriveBaseSettlementIntent({ + decision: baseline, + addresses, + provenance: { executionId: "exec-new" }, + }); + const conditionedIntent = deriveBaseSettlementIntent({ + decision: conditioned, + addresses, + provenance: { executionId: "exec-new", retrievalId: "retrieval-1" }, + }); + + expect(baselineIntent).toMatchObject({ + chainId: BASE_SEPOLIA_CHAIN_ID, + tokenAddress: BASE_SEPOLIA_USDC, + providerId: "atlas", + recipient: addresses.atlas, + }); + expect(conditionedIntent).toMatchObject({ + providerId: "beacon", + recipient: addresses.beacon, + memoryRefs: ["memory-atlas-guarded"], + }); + expect(conditionedIntent.recipient).not.toBe(baselineIntent.recipient); + expect(conditionedIntent.counterfactual?.recipient).toBe(addresses.atlas); + }); + + it("turns remembered routine experience into a smaller authorized Base prepayment", () => { + const baseline = decideProviderEngagement({ context: context("ROUTINE"), offers, memories: [] }); + const conditioned = decideProviderEngagement({ + context: context("ROUTINE"), + offers, + memories: [relationshipMemory()], + }); + + const baselineIntent = deriveBaseSettlementIntent({ + decision: baseline, + addresses, + provenance: { executionId: "exec-routine" }, + }); + const conditionedIntent = deriveBaseSettlementIntent({ + decision: conditioned, + addresses, + provenance: { executionId: "exec-routine", retrievalId: "retrieval-routine" }, + }); + + expect(baselineIntent.providerId).toBe("atlas"); + expect(conditionedIntent.providerId).toBe("atlas"); + expect(baselineIntent.terms.authorizedPrepayUsd).toBe("4.000000"); + expect(conditionedIntent.terms.authorizedPrepayUsd).toBe("0.800000"); + expect(conditionedIntent.terms.authorizedPrepayAtomic).toBe(800_000n); + expect(conditionedIntent.terms.requireMilestoneVerification).toBe(true); + expect(conditionedIntent.counterfactual?.terms.authorizedPrepayUsd).toBe("4.000000"); + }); + + it("fails closed on malformed provider addresses", () => { + const decision = decideProviderEngagement({ context: context("URGENT"), offers, memories: [] }); + expect(() => deriveBaseSettlementIntent({ + decision, + addresses: { ...addresses, atlas: "not-an-address" }, + provenance: { executionId: "exec-invalid" }, + })).toThrow("INVALID_PROVIDER_ADDRESS"); + }); +}); From 3ff61cd5880b1b8e49c99d11824e32707d9e89fb Mon Sep 17 00:00:00 2001 From: etvjay Date: Sat, 29 Aug 2026 17:50:28 +0100 Subject: [PATCH 087/116] docs: define Base settlement evidence boundary --- packages/base-settlement/README.md | 58 ++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 packages/base-settlement/README.md diff --git a/packages/base-settlement/README.md b/packages/base-settlement/README.md new file mode 100644 index 0000000..186299b --- /dev/null +++ b/packages/base-settlement/README.md @@ -0,0 +1,58 @@ +# Base settlement authority adapter + +Status: `IMPLEMENTED / LOCAL_CONFORMANCE_PENDING_CI / LIVE_BASE_UNVERIFIED` + +This server-only package converts an Engram provider decision into a bounded Base Sepolia USDC settlement intent. + +It exists to make remembered experience economically consequential rather than merely observable. + +```text +prior execution evidence + -> Engram relationship memory + -> Sibyl persistence + -> fresh Engram recall + -> changed provider/terms + -> Base settlement authority +``` + +## Current evaluated network + +- network: Base Sepolia +- chain ID: `84532` +- asset: Circle USDC +- USDC contract: `0x036CbD53842c5426634e7929541eC2318f3dCF7e` +- decimals: `6` + +The contract address is pinned only for the evaluated testnet profile and must be reverified before the live hackathon run. + +## Causal product role + +For the flagship provider-continuity scenario: + +### Urgent work +Without applicable memory, the application selects Atlas. + +With repeated Atlas SLA-breach memory, the fresh decision selects Beacon. + +Base therefore receives a **different settlement recipient** downstream of memory. + +### Routine work +Without memory, Atlas receives 50% prepayment authority on an $8 offer: `4.000000 USDC`. + +With applicable relationship memory, Atlas remains selected but prepayment authority falls to 10%: `0.800000 USDC`, with milestone verification required. + +Base therefore receives a **smaller authorized economic action** downstream of memory rather than a decorative transfer. + +## Evidence boundary + +Current tests prove only deterministic derivation of settlement intent. They do not prove an executed Base transaction. + +`BASE-001` remains `UNVERIFIED` until a real Base Sepolia USDC transfer or equivalent Base-native action is executed and retained with: + +- transaction hash; +- successful receipt; +- token transfer evidence matching the decision-derived recipient and amount; +- Engram execution/retrieval/decision IDs; +- demonstration that removing or changing the remembered decision changes the Base action. + +No private key, wallet secret, or signer material belongs in this package or repository. From b441507f2a6b7213502d52b3f2d17954c4f95e40 Mon Sep 17 00:00:00 2001 From: etvjay Date: Sat, 29 Aug 2026 17:50:44 +0100 Subject: [PATCH 088/116] chore: expose Base settlement conformance test --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index a37d7c9..0b66ded 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "test:integration": "vitest run tests/integration/cockroach-memory-loop.test.ts", "test:sibyl": "ENGRAM_SIBYL_TEST_REQUIRED=1 vitest run tests/integration/sibyl-memory-loop.test.ts tests/integration/sibyl-provider-continuity.test.ts tests/integration/sibyl-competing-memories.test.ts", "test:virtuals": "vitest run tests/integration/virtuals-acp-evidence.test.ts", + "test:base": "vitest run tests/integration/base-settlement-authority.test.ts", "demo:sibyl:seed": "tsx scripts/sibyl-demo.ts seed", "demo:sibyl:recall": "tsx scripts/sibyl-demo.ts recall", "demo:sibyl:no-memory-control": "tsx scripts/sibyl-demo.ts control", From 276cb1ee27c254781d88aac719550782ff1b08a3 Mon Sep 17 00:00:00 2001 From: etvjay Date: Sat, 29 Aug 2026 17:50:58 +0100 Subject: [PATCH 089/116] docs: register Base settlement adapter as server-only --- docs/frontend-modules/server-only.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/frontend-modules/server-only.json b/docs/frontend-modules/server-only.json index d818f81..8a5ae36 100644 --- a/docs/frontend-modules/server-only.json +++ b/docs/frontend-modules/server-only.json @@ -1,8 +1,9 @@ { "schemaVersion": "engram.server-only-module-registry/v1", - "updatedAt": "2026-08-24", + "updatedAt": "2026-08-29", "modules": [ { "modulePath": "packages/adapters", "reason": "Framework telemetry integration; frontend consumes resulting execution evidence through API surfaces." }, + { "modulePath": "packages/base-settlement", "reason": "Hackathon Base settlement-authority adapter derives decision-linked USDC intents and will own credentialed/testnet settlement verification; signer material must never enter browser code." }, { "modulePath": "packages/bedrock", "reason": "AWS Bedrock embedding client requires server-side credentials." }, { "modulePath": "packages/cockroach-mcp", "reason": "Cockroach Managed MCP credentials and database inspection remain server-side." }, { "modulePath": "packages/cockroach", "reason": "Canonical storage/database implementation; browsers must never connect directly to CockroachDB." }, From ddc3f40f5f0971e16bee1bcffd27b65c42103a27 Mon Sep 17 00:00:00 2001 From: etvjay Date: Sat, 29 Aug 2026 17:51:30 +0100 Subject: [PATCH 090/116] docs: make Base partner path causally load-bearing --- hackathon/sibyl/partners/base.md | 55 +++++++++++++++++++++++++++----- 1 file changed, 47 insertions(+), 8 deletions(-) diff --git a/hackathon/sibyl/partners/base.md b/hackathon/sibyl/partners/base.md index dc10d15..7550ef0 100644 --- a/hackathon/sibyl/partners/base.md +++ b/hackathon/sibyl/partners/base.md @@ -6,17 +6,56 @@ Class: `PUBLISHED_BONUS` A claimed Base stack counts only when judges can see it doing real work in the product. Deployment is the eligibility floor; an executed onchain action shown in the demo earns the partner bonus, including wallet operation, x402 payment, B20 read, or contract interaction. ## Engram fit -Best use: recalled execution memory changes an economically consequential action, e.g. provider/payment terms, route choice, or x402 capability purchase. +Base is the economic consequence layer for remembered provider experience: + +```text +Virtuals/provider execution evidence + -> Engram observation + -> Sibyl relationship memory + -> fresh Engram recall + -> provider/authority decision changes + -> Base settlement action changes +``` + +The evaluated Base profile is Base Sepolia (`84532`) using Circle USDC at `0x036CbD53842c5426634e7929541eC2318f3dCF7e`. + +## Flagship causal deltas + +### Urgent +No-memory control selects Atlas. Applicable relationship memory selects Beacon. + +The Base effect is a different settlement recipient. + +### Routine +No-memory control selects Atlas with 50% prepayment on an $8 offer: `4.000000 USDC`. + +Applicable relationship memory still selects Atlas but reduces prepayment to 10%: `0.800000 USDC`, while requiring milestone verification. + +The Base effect is reduced economic authority, not a global provider blacklist. ## Veto -Do not add Base merely for a transaction receipt. The onchain action must be downstream of the remembered decision. +Do not claim Base merely because a transaction receipt exists. The transaction must match the settlement intent derived from the remembered Engram decision. ## Required evidence -- protocol-native transaction/receipt; -- action visible in demo; -- trace linking recalled memory -> changed decision -> Base action. +- Engram execution ID; +- recall/retrieval ID when memory influenced the decision; +- decision-linked `engram.base-settlement-intent/v1` intent; +- protocol-native Base transaction hash and successful receipt; +- observed USDC transfer recipient and amount matching the intent; +- action visible in the demo; +- counterfactual showing what recipient/amount would have been authorized without memory. + +## Acceptance test +`BASE-001` may promote only when a real Base Sepolia action proves: + +`remembered decision == authorized settlement intent == observed onchain settlement`. + +A transaction hash alone is insufficient. -## Negative test -Remove the Base action. If product meaning is unchanged, do not claim the partner stack. +## Negative tests +- remove memory: recipient/amount must revert to the control settlement; +- alter provider address: verification must not accept the wrong recipient; +- alter prepayment amount: verification must not accept the wrong amount; +- remove Base action: no Base partner claim remains. -Status: `UNVERIFIED / OPTIONAL`. +Status: `IMPLEMENTED / LOCAL_CONFORMANCE_PENDING_CI / LIVE_BASE_UNVERIFIED`. From 10a0e8a1df56c2c6a0278300a5c801df745b67e7 Mon Sep 17 00:00:00 2001 From: etvjay Date: Sat, 29 Aug 2026 17:52:02 +0100 Subject: [PATCH 091/116] feat: verify Base USDC settlement receipts --- packages/base-settlement/src/evidence.ts | 111 +++++++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100644 packages/base-settlement/src/evidence.ts diff --git a/packages/base-settlement/src/evidence.ts b/packages/base-settlement/src/evidence.ts new file mode 100644 index 0000000..6a18eea --- /dev/null +++ b/packages/base-settlement/src/evidence.ts @@ -0,0 +1,111 @@ +import { + BASE_SEPOLIA_CHAIN_ID, + BASE_SEPOLIA_USDC, + type BaseSettlementIntent, +} from "./index.js"; + +export const ERC20_TRANSFER_TOPIC = "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"; + +export type RpcLog = { + address: string; + topics: string[]; + data: string; + transactionHash?: string; + logIndex?: string; +}; + +export type RpcReceipt = { + transactionHash: string; + status: string; + blockNumber: string; + logs: RpcLog[]; +}; + +export type BaseSettlementEvidence = { + sourceSystem: "BASE"; + chainId: typeof BASE_SEPOLIA_CHAIN_ID; + transactionHash: string; + blockNumber: string; + tokenAddress: typeof BASE_SEPOLIA_USDC; + recipient: string; + amountAtomic: string; + executionId: string; + retrievalId?: string; + decisionId?: string; + memoryRefs: string[]; + evidenceState: "OBSERVED"; +}; + +function normalizedAddress(value: string): string { + return value.toLowerCase(); +} + +function topicAddress(address: string): string { + return `0x${address.slice(2).toLowerCase().padStart(64, "0")}`; +} + +function parseHexUint(value: string): bigint { + if (!/^0x[0-9a-fA-F]+$/.test(value)) throw new Error("INVALID_BASE_UINT_HEX"); + return BigInt(value); +} + +export function verifyBaseSettlementReceipt(input: { + intent: BaseSettlementIntent; + receipt: RpcReceipt; +}): BaseSettlementEvidence { + if (input.intent.chainId !== BASE_SEPOLIA_CHAIN_ID) throw new Error("BASE_CHAIN_MISMATCH"); + if (normalizedAddress(input.intent.tokenAddress) !== normalizedAddress(BASE_SEPOLIA_USDC)) { + throw new Error("BASE_TOKEN_MISMATCH"); + } + if (input.receipt.status.toLowerCase() !== "0x1") throw new Error("BASE_TRANSACTION_NOT_SUCCESSFUL"); + if (!/^0x[0-9a-fA-F]{64}$/.test(input.receipt.transactionHash)) throw new Error("INVALID_BASE_TRANSACTION_HASH"); + + const expectedRecipientTopic = topicAddress(input.intent.recipient); + const expectedAmount = input.intent.terms.authorizedPrepayAtomic; + const matching = input.receipt.logs.find((log) => + normalizedAddress(log.address) === normalizedAddress(BASE_SEPOLIA_USDC) + && log.topics[0]?.toLowerCase() === ERC20_TRANSFER_TOPIC + && log.topics[2]?.toLowerCase() === expectedRecipientTopic + && parseHexUint(log.data) === expectedAmount + ); + + if (!matching) throw new Error("BASE_USDC_TRANSFER_DOES_NOT_MATCH_INTENT"); + + return { + sourceSystem: "BASE", + chainId: BASE_SEPOLIA_CHAIN_ID, + transactionHash: input.receipt.transactionHash, + blockNumber: input.receipt.blockNumber, + tokenAddress: BASE_SEPOLIA_USDC, + recipient: input.intent.recipient, + amountAtomic: expectedAmount.toString(), + executionId: input.intent.provenance.executionId, + retrievalId: input.intent.provenance.retrievalId, + decisionId: input.intent.provenance.decisionId, + memoryRefs: [...input.intent.memoryRefs], + evidenceState: "OBSERVED", + }; +} + +export async function fetchBaseTransactionReceipt(input: { + rpcUrl: string; + transactionHash: string; + fetchImpl?: typeof fetch; +}): Promise { + const fetchImpl = input.fetchImpl ?? fetch; + const response = await fetchImpl(input.rpcUrl, { + method: "POST", + headers: { "content-type": "application/json" }, + body: JSON.stringify({ + jsonrpc: "2.0", + id: 1, + method: "eth_getTransactionReceipt", + params: [input.transactionHash], + }), + }); + if (!response.ok) throw new Error(`BASE_RPC_HTTP_${response.status}`); + const payload = await response.json() as { result?: RpcReceipt | null; error?: unknown }; + if (payload.error) throw new Error(`BASE_RPC_ERROR: ${JSON.stringify(payload.error)}`); + if (!payload.result) throw new Error("BASE_TRANSACTION_RECEIPT_NOT_FOUND"); + return payload.result; +} From 6357aa18e03d04e523be9d3ad62b75ad0a3bda4f Mon Sep 17 00:00:00 2001 From: etvjay Date: Sat, 29 Aug 2026 17:52:15 +0100 Subject: [PATCH 092/116] test: reject Base receipts that diverge from memory-derived intent --- .../base-settlement-receipt.test.ts | 131 ++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 tests/integration/base-settlement-receipt.test.ts diff --git a/tests/integration/base-settlement-receipt.test.ts b/tests/integration/base-settlement-receipt.test.ts new file mode 100644 index 0000000..f1ee6ff --- /dev/null +++ b/tests/integration/base-settlement-receipt.test.ts @@ -0,0 +1,131 @@ +import { describe, expect, it } from "vitest"; +import { + deriveBaseSettlementIntent, +} from "../../packages/base-settlement/src/index.js"; +import { + ERC20_TRANSFER_TOPIC, + verifyBaseSettlementReceipt, + type RpcReceipt, +} from "../../packages/base-settlement/src/evidence.js"; +import type { ProviderDecision } from "../../packages/scenarios/provider-continuity/src/index.js"; + +const atlas = "0x1111111111111111111111111111111111111111"; +const beacon = "0x2222222222222222222222222222222222222222"; +const sender = "0x3333333333333333333333333333333333333333"; +const txHash = `0x${"ab".repeat(32)}`; + +function topic(address: string): string { + return `0x${address.slice(2).toLowerCase().padStart(64, "0")}`; +} + +function receipt(input: { recipient: string; amount: bigint; status?: string; token?: string }): RpcReceipt { + return { + transactionHash: txHash, + status: input.status ?? "0x1", + blockNumber: "0x1234", + logs: [{ + address: input.token ?? "0x036CbD53842c5426634e7929541eC2318f3dCF7e", + topics: [ERC20_TRANSFER_TOPIC, topic(sender), topic(input.recipient)], + data: `0x${input.amount.toString(16).padStart(64, "0")}`, + transactionHash: txHash, + logIndex: "0x0", + }], + }; +} + +function routineDecision(): ProviderDecision { + return { + providerId: "atlas", + terms: { + prepayBps: 1000, + requireMilestoneVerification: true, + maxSpendUsd: 8, + }, + memoryRefs: ["memory-atlas-guarded"], + reason: "Prior experience constrains authority.", + counterfactual: { + providerId: "atlas", + terms: { + prepayBps: 5000, + requireMilestoneVerification: false, + maxSpendUsd: 8, + }, + }, + }; +} + +describe("Base settlement receipt evidence", () => { + it("accepts only a successful USDC Transfer matching the decision-derived recipient and amount", () => { + const intent = deriveBaseSettlementIntent({ + decision: routineDecision(), + addresses: { atlas, beacon }, + provenance: { + executionId: "exec-routine", + retrievalId: "retrieval-routine", + decisionId: "decision-routine", + }, + }); + + const evidence = verifyBaseSettlementReceipt({ + intent, + receipt: receipt({ recipient: atlas, amount: 800_000n }), + }); + + expect(evidence).toMatchObject({ + sourceSystem: "BASE", + chainId: 84532, + transactionHash: txHash, + recipient: atlas, + amountAtomic: "800000", + executionId: "exec-routine", + retrievalId: "retrieval-routine", + decisionId: "decision-routine", + memoryRefs: ["memory-atlas-guarded"], + evidenceState: "OBSERVED", + }); + }); + + it("rejects a successful transfer to the wrong provider", () => { + const intent = deriveBaseSettlementIntent({ + decision: routineDecision(), + addresses: { atlas, beacon }, + provenance: { executionId: "exec-routine" }, + }); + expect(() => verifyBaseSettlementReceipt({ + intent, + receipt: receipt({ recipient: beacon, amount: 800_000n }), + })).toThrow("BASE_USDC_TRANSFER_DOES_NOT_MATCH_INTENT"); + }); + + it("rejects the no-memory prepayment amount when memory authorized only the guarded amount", () => { + const intent = deriveBaseSettlementIntent({ + decision: routineDecision(), + addresses: { atlas, beacon }, + provenance: { executionId: "exec-routine" }, + }); + expect(() => verifyBaseSettlementReceipt({ + intent, + receipt: receipt({ recipient: atlas, amount: 4_000_000n }), + })).toThrow("BASE_USDC_TRANSFER_DOES_NOT_MATCH_INTENT"); + }); + + it("rejects reverted transactions and transfers from the wrong token contract", () => { + const intent = deriveBaseSettlementIntent({ + decision: routineDecision(), + addresses: { atlas, beacon }, + provenance: { executionId: "exec-routine" }, + }); + expect(() => verifyBaseSettlementReceipt({ + intent, + receipt: receipt({ recipient: atlas, amount: 800_000n, status: "0x0" }), + })).toThrow("BASE_TRANSACTION_NOT_SUCCESSFUL"); + expect(() => verifyBaseSettlementReceipt({ + intent, + receipt: receipt({ + recipient: atlas, + amount: 800_000n, + token: "0x4444444444444444444444444444444444444444", + }), + })).toThrow("BASE_USDC_TRANSFER_DOES_NOT_MATCH_INTENT"); + }); +}); From 1f70ae3726aec863acb665cebaf62ac5b00477dd Mon Sep 17 00:00:00 2001 From: etvjay Date: Sat, 29 Aug 2026 17:52:38 +0100 Subject: [PATCH 093/116] feat: add live Base settlement verification command --- scripts/base-settlement-verify.ts | 54 +++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 scripts/base-settlement-verify.ts diff --git a/scripts/base-settlement-verify.ts b/scripts/base-settlement-verify.ts new file mode 100644 index 0000000..059f699 --- /dev/null +++ b/scripts/base-settlement-verify.ts @@ -0,0 +1,54 @@ +import { readFile } from "node:fs/promises"; +import { + fetchBaseTransactionReceipt, + verifyBaseSettlementReceipt, +} from "../packages/base-settlement/src/evidence.js"; +import type { BaseSettlementIntent } from "../packages/base-settlement/src/index.js"; + +function arg(name: string): string | undefined { + const index = process.argv.indexOf(name); + return index >= 0 ? process.argv[index + 1] : undefined; +} + +const intentPath = arg("--intent"); +const transactionHash = arg("--tx-hash"); +const rpcUrl = arg("--rpc-url") ?? process.env.ENGRAM_BASE_RPC_URL; + +if (!intentPath || !transactionHash || !rpcUrl) { + throw new Error( + "Usage: npm run base:settlement:verify -- --intent --tx-hash <0x...> [--rpc-url ] " + + "or set ENGRAM_BASE_RPC_URL", + ); +} + +const raw = JSON.parse(await readFile(intentPath, "utf8")) as Record; +if (raw.schema !== "engram.base-settlement-intent/v1") throw new Error("INVALID_BASE_SETTLEMENT_INTENT_SCHEMA"); + +// JSON cannot encode bigint. Evidence files store atomic amounts as decimal strings. +const terms = raw.terms as Record | undefined; +if (!terms || typeof terms.authorizedPrepayAtomic !== "string" || !/^\d+$/.test(terms.authorizedPrepayAtomic)) { + throw new Error("INVALID_BASE_SETTLEMENT_INTENT_AMOUNT"); +} + +const intent = { + ...raw, + terms: { + ...terms, + authorizedPrepayAtomic: BigInt(terms.authorizedPrepayAtomic), + }, + counterfactual: raw.counterfactual && typeof raw.counterfactual === "object" + ? { + ...(raw.counterfactual as Record), + terms: { + ...((raw.counterfactual as Record).terms as Record), + authorizedPrepayAtomic: BigInt( + String((((raw.counterfactual as Record).terms as Record).authorizedPrepayAtomic)), + ), + }, + } + : undefined, +} as unknown as BaseSettlementIntent; + +const receipt = await fetchBaseTransactionReceipt({ rpcUrl, transactionHash }); +const evidence = verifyBaseSettlementReceipt({ intent, receipt }); +process.stdout.write(`${JSON.stringify(evidence, null, 2)}\n`); From 266d3c38acc3c70a9533315679d4927108852ba3 Mon Sep 17 00:00:00 2001 From: etvjay Date: Sat, 29 Aug 2026 17:52:53 +0100 Subject: [PATCH 094/116] chore: expose Base settlement verification commands --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 0b66ded..d98365b 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,7 @@ "test:integration": "vitest run tests/integration/cockroach-memory-loop.test.ts", "test:sibyl": "ENGRAM_SIBYL_TEST_REQUIRED=1 vitest run tests/integration/sibyl-memory-loop.test.ts tests/integration/sibyl-provider-continuity.test.ts tests/integration/sibyl-competing-memories.test.ts", "test:virtuals": "vitest run tests/integration/virtuals-acp-evidence.test.ts", - "test:base": "vitest run tests/integration/base-settlement-authority.test.ts", + "test:base": "vitest run tests/integration/base-settlement-authority.test.ts tests/integration/base-settlement-receipt.test.ts", "demo:sibyl:seed": "tsx scripts/sibyl-demo.ts seed", "demo:sibyl:recall": "tsx scripts/sibyl-demo.ts recall", "demo:sibyl:no-memory-control": "tsx scripts/sibyl-demo.ts control", @@ -28,6 +28,7 @@ "demo:sibyl:provider:routine": "tsx scripts/sibyl-provider-demo.ts routine", "evidence:sibyl:capture": "tsx scripts/sibyl-evidence-capture.ts", "virtuals:acp:ingest": "tsx scripts/virtuals-acp-ingest.ts", + "base:settlement:verify": "tsx scripts/base-settlement-verify.ts", "test:all": "vitest run", "test:watch": "vitest", "check": "npm run build && npm run test:all" From ba44f0e34da5e3ea69551e457117c4a319eb6cc5 Mon Sep 17 00:00:00 2001 From: etvjay Date: Sat, 29 Aug 2026 17:53:30 +0100 Subject: [PATCH 095/116] docs: add Base live settlement proof runbook --- hackathon/sibyl/BASE_LIVE_RUN.md | 112 +++++++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 hackathon/sibyl/BASE_LIVE_RUN.md diff --git a/hackathon/sibyl/BASE_LIVE_RUN.md b/hackathon/sibyl/BASE_LIVE_RUN.md new file mode 100644 index 0000000..f60be97 --- /dev/null +++ b/hackathon/sibyl/BASE_LIVE_RUN.md @@ -0,0 +1,112 @@ +# Base Live Settlement Proof + +Status: `NOT_EXECUTED` + +This runbook promotes Base only when an Engram memory-conditioned decision causes and matches a real Base Sepolia USDC action. + +## Frozen evaluated network + +- network: Base Sepolia +- chain ID: `84532` +- token: Circle USDC +- token address: `0x036CbD53842c5426634e7929541eC2318f3dCF7e` +- decimals: `6` + +Reverify these values from first-party Base/Circle documentation immediately before the official live run. + +## Required causal chain + +```text +execution evidence + -> Sibyl memory + -> fresh Engram recall + -> Engram provider decision + -> engam.base-settlement-intent/v1 + -> explicit wallet execution on Base Sepolia + -> receipt + -> USDC Transfer matches recipient + amount + -> Base settlement evidence +``` + +A transaction hash without the preceding memory/decision linkage does not qualify. + +## Live sequence + +1. Start from a hackathon-window commit with green canonical CI. +2. Use an isolated/new Sibyl evidence DB or retained build-window DB whose provenance is explicit. +3. Run/ingest provider execution evidence. +4. Form the relationship memory through normal Engram admission. +5. Terminate the originating process. +6. In a fresh process, recall the relationship memory and record the provider decision. +7. Derive a Base settlement intent containing: + - execution ID; + - retrieval ID; + - decision ID; + - memory refs; + - provider ID; + - provider recipient address; + - prepay basis points; + - exact USDC atomic amount; + - no-memory counterfactual. +8. Review the intent before signing anything. +9. Execute exactly that authorized USDC transfer with the selected testnet wallet/signer. +10. Retain the transaction hash. Never retain/export the private key in Engram evidence. +11. Verify independently: + +```bash +ENGRAM_BASE_RPC_URL='' \ + npm run base:settlement:verify -- \ + --intent artifacts/base/.json \ + --tx-hash <0x...> +``` + +12. Verification must fail unless the receipt: + - succeeded; + - contains a Circle Base Sepolia USDC `Transfer`; + - transfers to the exact decision-derived recipient; + - transfers the exact decision-derived amount. +13. Save verifier stdout, transaction hash, explorer link, receipt, intent, and Engram trace in the final evidence bundle. + +## Flagship expected deltas + +### Urgent +Control: +- provider: Atlas +- Base recipient: Atlas address + +Memory-conditioned: +- provider: Beacon +- Base recipient: Beacon address + +### Routine +Control: +- provider: Atlas +- max spend: $8 +- prepay: 50% +- authorized initial transfer: `4.000000 USDC` + +Memory-conditioned: +- provider: Atlas +- max spend: $8 +- prepay: 10% +- authorized initial transfer: `0.800000 USDC` +- milestone verification: required + +The routine case is the stronger Base authority proof because memory changes how much capital the same counterparty is permitted to receive, not merely which address is selected. + +## Negative pressure + +A live claim is invalid if any of these are true: +- recipient differs from the settlement intent; +- amount differs from the settlement intent; +- wrong token contract; +- reverted transaction; +- no retrieval/decision provenance; +- transfer was executed independently of the Engram decision; +- only a screenshot is retained and raw transaction evidence is unavailable. + +## Promotion + +`BASE-001` remains `UNVERIFIED` until this sequence is executed during the eligible build window. + +Local intent/receipt tests can support an internal conformance gate but cannot promote the published Base partner gate. From 021f7387247ef38264299b3f899098f10c2d4520 Mon Sep 17 00:00:00 2001 From: etvjay Date: Sat, 29 Aug 2026 17:54:35 +0100 Subject: [PATCH 096/116] docs: promote Base local conformance after canonical CI --- packages/base-settlement/README.md | 43 +++++++++++++++++++++++++++--- 1 file changed, 39 insertions(+), 4 deletions(-) diff --git a/packages/base-settlement/README.md b/packages/base-settlement/README.md index 186299b..e75b00b 100644 --- a/packages/base-settlement/README.md +++ b/packages/base-settlement/README.md @@ -1,8 +1,8 @@ # Base settlement authority adapter -Status: `IMPLEMENTED / LOCAL_CONFORMANCE_PENDING_CI / LIVE_BASE_UNVERIFIED` +Status: `IMPLEMENTED / LOCAL_CONFORMANCE_PASS / LIVE_BASE_UNVERIFIED` -This server-only package converts an Engram provider decision into a bounded Base Sepolia USDC settlement intent. +This server-only package converts an Engram provider decision into a bounded Base Sepolia USDC settlement intent and independently verifies the resulting onchain receipt. It exists to make remembered experience economically consequential rather than merely observable. @@ -13,6 +13,7 @@ prior execution evidence -> fresh Engram recall -> changed provider/terms -> Base settlement authority + -> Base receipt verification ``` ## Current evaluated network @@ -43,11 +44,45 @@ With applicable relationship memory, Atlas remains selected but prepayment autho Base therefore receives a **smaller authorized economic action** downstream of memory rather than a decorative transfer. +## Local conformance + +Run: + +```bash +npm run test:base +``` + +The local suite proves: + +- urgent relationship memory changes the settlement recipient Atlas -> Beacon; +- routine relationship memory changes authorized prepay `4.000000 -> 0.800000 USDC`; +- malformed provider addresses fail closed; +- a receipt is accepted only when it is successful and contains the expected Circle USDC `Transfer`; +- wrong recipient fails; +- wrong amount fails; +- wrong token contract fails; +- reverted transaction fails. + +The Base tests are also included in canonical `npm run test:all` / `npm run check`. Canonical CI run `33264157362`, check job `99131095748`, passed on code head `266d3c38acc3c70a9533315679d4927108852ba3`. + +## Live verification + +Once an explicit wallet step has executed the reviewed settlement intent: + +```bash +ENGRAM_BASE_RPC_URL='' \ + npm run base:settlement:verify -- \ + --intent \ + --tx-hash <0x...> +``` + +The verifier calls `eth_getTransactionReceipt` and emits Base evidence only if the observed USDC transfer matches the decision-derived recipient and atomic amount. + ## Evidence boundary -Current tests prove only deterministic derivation of settlement intent. They do not prove an executed Base transaction. +`LOCAL_CONFORMANCE_PASS` proves the causal settlement model and fail-closed receipt verifier. It does **not** prove an executed Base transaction and does not earn the partner multiplier. -`BASE-001` remains `UNVERIFIED` until a real Base Sepolia USDC transfer or equivalent Base-native action is executed and retained with: +`BASE-001` remains `UNVERIFIED` until a real Base Sepolia action is executed and retained with: - transaction hash; - successful receipt; From 6d59582874693e60fe543e11879f5e078276fcb8 Mon Sep 17 00:00:00 2001 From: etvjay Date: Sat, 29 Aug 2026 17:55:00 +0100 Subject: [PATCH 097/116] docs: add Base local conformance gate without promoting live bonus --- .../sibyl/requirements/requirements.json | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/hackathon/sibyl/requirements/requirements.json b/hackathon/sibyl/requirements/requirements.json index f642692..7a9a987 100644 --- a/hackathon/sibyl/requirements/requirements.json +++ b/hackathon/sibyl/requirements/requirements.json @@ -1,22 +1,23 @@ { "verified_at": "2026-08-29", "status": "READY_FOR_LIVE_PRESSURE", - "evidence_note": "Core and experiential-provider gates are LOCAL_PASS from pre-build-window CI. Current stronger baseline is head 8f616545 with Engram CI 33221823993 and SAM build 33221823973. Sibyl conflict handling is now directly pressure-tested. Root judge call map is implemented. Virtuals ACP evidence adapter is implemented but partner bonus remains UNVERIFIED until an actual authenticated testnet job is exercised. Submission/live-public gates must be re-proven during the official build window.", + "evidence_note": "Core Sibyl and experiential-provider gates are LOCAL_PASS from pre-build-window CI; strongest fully exercised Sibyl/evidence-capture baseline is head afb3ac37 with Engram CI 33232373531 and SAM build 33232373540. Base settlement authority and fail-closed receipt verification are now locally conformant from canonical CI on head 266d3c38, but BASE-001 remains UNVERIFIED until a real Base Sepolia action is executed. Virtuals ACP remains LOCAL_CONFORMANCE_PASS / LIVE_ACP_UNVERIFIED. Submission/live-public gates must be re-proven during the official build window.", "requirements": [ - {"id":"SIBYL-GATE-001","track":"main","class":"PUBLISHED_HARD","severity":"VETO","description":"Sibyl Memory is load-bearing; deleting it breaks or materially degrades the core function.","check":"run deletion mutation and compare claimed behavior","evidence_required":"failing/degraded no-Sibyl run plus passing Sibyl run","status":"LOCAL_PASS","evidence":"GitHub Actions run 33221823993 job 99017280805: deletion mutation degraded=true, fallbackAvailable=false"}, - {"id":"SIBYL-GATE-002","track":"main","class":"PUBLISHED_HARD","severity":"VETO","description":"Fresh session recalls earlier persisted state.","check":"terminate process/session, restart clean, recall prior memory","evidence_required":"continuous demo segment with timestamp or commit hash","status":"LOCAL_PASS","evidence":"GitHub Actions run 33221823993: separate route/provider processes recalled persisted Sibyl memory; conflict test also retrieves both contradictory memories through a fresh SibylRuntimeStore"}, - {"id":"SIBYL-GATE-003","track":"main","class":"PUBLISHED_HARD","severity":"VETO","description":"Recalled memory changes a decision, action, or result.","check":"paired memory vs no-memory decision comparison","evidence_required":"decision trace and observable action delta","status":"LOCAL_PASS","evidence":"Run 33221823993: route A-B-C -> A-B-D; urgent provider Atlas -> Beacon with CHANGED_ACTION; routine Atlas terms constrained with CONSTRAINED_ACTION"}, - {"id":"SIBYL-GATE-004","track":"main","class":"PUBLISHED_HARD","severity":"HIGH","description":"README exposes critical memory write/read paths in under two minutes.","check":"cold reviewer repo navigation test","evidence_required":"README call map","status":"LOCAL_PASS","evidence":"Root README on hackathon/sibyl-ebi opens with a judge call map covering Sibyl store wiring, write, read, recall-state binding, influence, provider scenario, process-boundary demo and deletion path. Human cold-review timing remains to be performed."}, - {"id":"SCORE-MEM-001","track":"main","class":"PUBLISHED_SCORING","severity":"HIGH","description":"Memory use is sophisticated enough for top band; coordination/dynamic-state behavior preferred.","check":"judge-model scorecard","evidence_required":"non-trivial stateful scenario plus adversarial memory handling","status":"LOCAL_PASS","evidence":"Run 33221823993 job 99017280805: 7/7 Sibyl integration tests; multi-execution experiential relationship memory changes urgent delegation and routine authority; expiry, post-recall tamper and unresolved-contradiction controls pass. Final evaluator score remains future."}, - {"id":"SCORE-TECH-001","track":"main","class":"PUBLISHED_SCORING","severity":"HIGH","description":"Build is clean, robust and survives a second run/curious judge.","check":"repeatability and negative test suite","evidence_required":"test report and second-run evidence","status":"LOCAL_PASS","evidence":"Head 8f616545: Engram CI 33221823993 and Engram SAM Build 33221823973 both succeeded on clean runners"}, - {"id":"EXP-CONT-001","track":"main","class":"INTERNAL_ACCEPTANCE","severity":"HIGH","description":"Multiple attributable executions may form bounded relationship state only with sufficient lineage.","check":"multi-source provider history test","evidence_required":"two historical executions + admitting execution + relationship memory lineage","status":"LOCAL_PASS","evidence":"Run 33221823993: two Atlas breach executions plus admitting execution produced CONTEXT_GUARDED relationship memory; one-breach and cross-task controls remain baseline"}, - {"id":"EXP-CONT-002","track":"main","class":"INTERNAL_ACCEPTANCE","severity":"HIGH","description":"Relationship state changes behavior contextually rather than becoming a global provider blacklist.","check":"urgent vs routine paired decisions","evidence_required":"urgent provider change plus routine authority narrowing using same memory","status":"LOCAL_PASS","evidence":"Run 33221823993: urgent Atlas -> Beacon; routine stays Atlas while prepay 5000 -> 1000 bps and milestone verification false -> true"}, - {"id":"EXP-CONT-003","track":"main","class":"INTERNAL_ACCEPTANCE","severity":"HIGH","description":"Retrieval ranking must not silently adjudicate explicit contradictory memories.","check":"persist contradictory memories through Sibyl, fresh-recall both, attempt influence before and after explicit resolution","evidence_required":"both memories recall-visible; unresolved influence rejected; explicit supersession required before resolved influence","status":"LOCAL_PASS","evidence":"Run 33221823993 job 99017280805: sibyl-competing-memories.test.ts rejected unresolved influence with UNRESOLVED_MEMORY_CONTRADICTION and only accepted the resolved side after SUPERSEDES evidence"}, + {"id":"SIBYL-GATE-001","track":"main","class":"PUBLISHED_HARD","severity":"VETO","description":"Sibyl Memory is load-bearing; deleting it breaks or materially degrades the core function.","check":"run deletion mutation and compare claimed behavior","evidence_required":"failing/degraded no-Sibyl run plus passing Sibyl run","status":"LOCAL_PASS","evidence":"GitHub Actions run 33232373531: deletion mutation degraded=true, fallbackAvailable=false and exact evidence-capture path passed"}, + {"id":"SIBYL-GATE-002","track":"main","class":"PUBLISHED_HARD","severity":"VETO","description":"Fresh session recalls earlier persisted state.","check":"terminate process/session, restart clean, recall prior memory","evidence_required":"continuous demo segment with timestamp or commit hash","status":"LOCAL_PASS","evidence":"GitHub Actions run 33232373531: separate route/provider processes recalled persisted Sibyl memory; conflict test retrieves contradictory memories through a fresh SibylRuntimeStore"}, + {"id":"SIBYL-GATE-003","track":"main","class":"PUBLISHED_HARD","severity":"VETO","description":"Recalled memory changes a decision, action, or result.","check":"paired memory vs no-memory decision comparison","evidence_required":"decision trace and observable action delta","status":"LOCAL_PASS","evidence":"Run 33232373531: route A-B-C -> A-B-D; urgent provider Atlas -> Beacon with CHANGED_ACTION; routine Atlas terms constrained with CONSTRAINED_ACTION"}, + {"id":"SIBYL-GATE-004","track":"main","class":"PUBLISHED_HARD","severity":"HIGH","description":"README exposes critical memory write/read paths in under two minutes.","check":"cold reviewer repo navigation test","evidence_required":"README call map","status":"LOCAL_PASS","evidence":"Root README on hackathon/sibyl-ebi exposes store wiring, write/read, recall-state binding, influence, contradiction, provider scenario, process-boundary demo, deletion and evidence capture. Human cold-review timing remains pending."}, + {"id":"SCORE-MEM-001","track":"main","class":"PUBLISHED_SCORING","severity":"HIGH","description":"Memory use is sophisticated enough for top band; coordination/dynamic-state behavior preferred.","check":"judge-model scorecard","evidence_required":"non-trivial stateful scenario plus adversarial memory handling","status":"LOCAL_PASS","evidence":"Sibyl profile: multi-execution experiential relationship memory changes urgent delegation and routine authority; expiry, post-recall tamper and unresolved-contradiction controls pass. Final evaluator score remains future."}, + {"id":"SCORE-TECH-001","track":"main","class":"PUBLISHED_SCORING","severity":"HIGH","description":"Build is clean, robust and survives a second run/curious judge.","check":"repeatability and negative test suite","evidence_required":"test report and second-run evidence","status":"LOCAL_PASS","evidence":"Head afb3ac37: Engram CI 33232373531 and SAM Build 33232373540 succeeded, including exact evidence-capture smoke"}, + {"id":"EXP-CONT-001","track":"main","class":"INTERNAL_ACCEPTANCE","severity":"HIGH","description":"Multiple attributable executions may form bounded relationship state only with sufficient lineage.","check":"multi-source provider history test","evidence_required":"two historical executions + admitting execution + relationship memory lineage","status":"LOCAL_PASS","evidence":"Two Atlas breach executions plus admitting execution produce CONTEXT_GUARDED relationship memory; one-breach and cross-task controls remain baseline"}, + {"id":"EXP-CONT-002","track":"main","class":"INTERNAL_ACCEPTANCE","severity":"HIGH","description":"Relationship state changes behavior contextually rather than becoming a global provider blacklist.","check":"urgent vs routine paired decisions","evidence_required":"urgent provider change plus routine authority narrowing using same memory","status":"LOCAL_PASS","evidence":"Urgent Atlas -> Beacon; routine stays Atlas while prepay 5000 -> 1000 bps and milestone verification false -> true"}, + {"id":"EXP-CONT-003","track":"main","class":"INTERNAL_ACCEPTANCE","severity":"HIGH","description":"Retrieval ranking must not silently adjudicate explicit contradictory memories.","check":"persist contradictory memories through Sibyl, fresh-recall both, attempt influence before and after explicit resolution","evidence_required":"both memories recall-visible; unresolved influence rejected; explicit supersession required before resolved influence","status":"LOCAL_PASS","evidence":"sibyl-competing-memories.test.ts rejects unresolved influence with UNRESOLVED_MEMORY_CONTRADICTION and accepts the resolved side only after SUPERSEDES evidence"}, + {"id":"BASE-CONF-001","track":"base","class":"INTERNAL_ACCEPTANCE","severity":"HIGH","description":"Engram memory-conditioned provider decisions deterministically change Base settlement authority and receipt verification fails closed on divergent onchain evidence.","check":"run test:base and canonical check","evidence_required":"recipient/amount delta tests plus wrong-recipient/wrong-amount/wrong-token/revert mutations","status":"LOCAL_PASS","evidence":"Canonical CI run 33264157362, check job 99131095748, passed on head 266d3c38; Base tests are included in test:all. Urgent changes recipient Atlas -> Beacon; routine changes prepay 4.000000 -> 0.800000 USDC; receipt verifier rejects wrong recipient, amount, token and reverted transactions."}, {"id":"SUBMIT-001","track":"submission","class":"PUBLISHED_HARD","severity":"VETO","description":"Public MIT/Apache-2.0 repo with real commit history.","check":"repository inspection","evidence_required":"public repo/license/commits","status":"LOCAL_PASS"}, {"id":"SUBMIT-002","track":"submission","class":"PUBLISHED_HARD","severity":"VETO","description":"2–5 minute demo includes fresh-session recall.","check":"video review","evidence_required":"public video","status":"UNVERIFIED"}, {"id":"SUBMIT-003","track":"submission","class":"PUBLISHED_HARD","severity":"VETO","description":"README includes Prior Work declaration and required memory/partner notes.","check":"README audit","evidence_required":"merged README","status":"UNVERIFIED","evidence":"Branch README includes explicit Prior Work and memory-path sections; final partner notes and submission-window truth freeze remain pending."}, {"id":"SUBMIT-004","track":"submission","class":"PUBLISHED_HARD","severity":"VETO","description":"Two public posts: demo and build log, tagging required accounts.","check":"public URL verification","evidence_required":"two public post URLs","status":"UNVERIFIED"}, - {"id":"BASE-001","track":"base","class":"PUBLISHED_BONUS","severity":"OPTIONAL","description":"Executed Base action shown doing real product work.","check":"protocol-native receipt/explorer evidence","evidence_required":"wallet/x402/B20/contract evidence in demo","status":"UNVERIFIED"}, + {"id":"BASE-001","track":"base","class":"PUBLISHED_BONUS","severity":"OPTIONAL","description":"Executed Base action shown doing real product work downstream of remembered decision authority.","check":"decision-linked Base Sepolia receipt/explorer evidence","evidence_required":"Engram execution/retrieval/decision provenance + settlement intent + successful matching Base USDC action shown in demo","status":"UNVERIFIED","evidence":"Base settlement adapter, receipt verifier and live verification command are implemented and locally conformant. No real Base Sepolia settlement has been executed for the partner claim yet."}, {"id":"VIRTUALS-001","track":"virtuals","class":"PUBLISHED_BONUS","severity":"OPTIONAL","description":"Virtuals-native integration is exercised in the demo.","check":"ACP/agent native evidence","evidence_required":"job/transaction/native receipt","status":"UNVERIFIED","evidence":"Server-only adapter normalizes current acp-cli v2 job-history JSON into Engram observations and virtuals:acp:ingest can fetch/ingest a live job. No authenticated ACP job has been executed yet; no multiplier claimed."} ] } From 52fd73c5c059032341bdd0f6ae831d1a6a30f956 Mon Sep 17 00:00:00 2001 From: etvjay Date: Sat, 29 Aug 2026 17:56:31 +0100 Subject: [PATCH 098/116] feat: schema-bind serialized Base settlement intents --- packages/base-settlement/src/index.ts | 91 +++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) diff --git a/packages/base-settlement/src/index.ts b/packages/base-settlement/src/index.ts index d257645..e6f58d7 100644 --- a/packages/base-settlement/src/index.ts +++ b/packages/base-settlement/src/index.ts @@ -1,3 +1,4 @@ +import { z } from "zod"; import type { ProviderDecision, ProviderId, @@ -10,6 +11,10 @@ export const BASE_SEPOLIA_USDC = "0x036CbD53842c5426634e7929541eC2318f3dCF7e" as export const USDC_DECIMALS = 6; const ADDRESS_RE = /^0x[0-9a-fA-F]{40}$/; +const AddressSchema = z.string().regex(ADDRESS_RE); +const DecimalAtomicSchema = z.string().regex(/^\d+$/); +const UsdcDecimalSchema = z.string().regex(/^\d+\.\d{6}$/); +const ProviderIdSchema = z.enum(["atlas", "beacon"]); export type ProviderAddressBook = Record; @@ -47,6 +52,43 @@ export type BaseSettlementIntent = { counterfactual?: BaseSettlementCounterfactual; }; +export type SerializedBaseSettlementIntent = Omit & { + terms: Omit & { authorizedPrepayAtomic: string }; + counterfactual?: Omit & { + terms: Omit & { authorizedPrepayAtomic: string }; + }; +}; + +const SerializedTermsSchema = z.object({ + maxSpendUsd: z.number().finite().nonnegative(), + prepayBps: z.number().int().min(0).max(10_000), + authorizedPrepayAtomic: DecimalAtomicSchema, + authorizedPrepayUsd: UsdcDecimalSchema, + requireMilestoneVerification: z.boolean(), +}).strict(); + +const SerializedIntentSchema = z.object({ + schema: z.literal("engram.base-settlement-intent/v1"), + chainId: z.literal(BASE_SEPOLIA_CHAIN_ID), + network: z.literal(BASE_SEPOLIA_NETWORK), + token: z.literal("USDC"), + tokenAddress: z.literal(BASE_SEPOLIA_USDC), + providerId: ProviderIdSchema, + recipient: AddressSchema, + terms: SerializedTermsSchema, + memoryRefs: z.array(z.string().min(1)), + provenance: z.object({ + executionId: z.string().min(1), + retrievalId: z.string().min(1).optional(), + decisionId: z.string().min(1).optional(), + }).strict(), + counterfactual: z.object({ + providerId: ProviderIdSchema, + recipient: AddressSchema, + terms: SerializedTermsSchema, + }).strict().optional(), +}).strict(); + function assertAddress(address: string, label: string): string { if (!ADDRESS_RE.test(address)) throw new Error(`INVALID_${label.toUpperCase()}_ADDRESS`); return address; @@ -83,6 +125,55 @@ function settlementTerms(terms: ProviderTerms): BaseSettlementTerms { }; } +function assertSerializedTermsConsistent(terms: SerializedBaseSettlementIntent["terms"]): void { + const expectedMaxSpendAtomic = usdToUsdcAtomic(terms.maxSpendUsd); + const expectedPrepayAtomic = (expectedMaxSpendAtomic * BigInt(terms.prepayBps)) / 10_000n; + if (BigInt(terms.authorizedPrepayAtomic) !== expectedPrepayAtomic) { + throw new Error("BASE_SETTLEMENT_INTENT_AMOUNT_INCONSISTENT"); + } + if (terms.authorizedPrepayUsd !== usdcAtomicToDecimal(expectedPrepayAtomic)) { + throw new Error("BASE_SETTLEMENT_INTENT_DECIMAL_INCONSISTENT"); + } +} + +export function serializeBaseSettlementIntent(intent: BaseSettlementIntent): SerializedBaseSettlementIntent { + return { + ...intent, + terms: { + ...intent.terms, + authorizedPrepayAtomic: intent.terms.authorizedPrepayAtomic.toString(), + }, + counterfactual: intent.counterfactual ? { + ...intent.counterfactual, + terms: { + ...intent.counterfactual.terms, + authorizedPrepayAtomic: intent.counterfactual.terms.authorizedPrepayAtomic.toString(), + }, + } : undefined, + }; +} + +export function parseSerializedBaseSettlementIntent(input: unknown): BaseSettlementIntent { + const parsed = SerializedIntentSchema.parse(input) as SerializedBaseSettlementIntent; + assertSerializedTermsConsistent(parsed.terms); + if (parsed.counterfactual) assertSerializedTermsConsistent(parsed.counterfactual.terms); + + return { + ...parsed, + terms: { + ...parsed.terms, + authorizedPrepayAtomic: BigInt(parsed.terms.authorizedPrepayAtomic), + }, + counterfactual: parsed.counterfactual ? { + ...parsed.counterfactual, + terms: { + ...parsed.counterfactual.terms, + authorizedPrepayAtomic: BigInt(parsed.counterfactual.terms.authorizedPrepayAtomic), + }, + } : undefined, + }; +} + export function deriveBaseSettlementIntent(input: { decision: ProviderDecision; addresses: ProviderAddressBook; From cb659dd73a449883100e773dbfec94d9930bdd9f Mon Sep 17 00:00:00 2001 From: etvjay Date: Sat, 29 Aug 2026 17:56:48 +0100 Subject: [PATCH 099/116] feat: bind Base receipts to chain and payer --- packages/base-settlement/src/evidence.ts | 60 +++++++++++++++++++----- 1 file changed, 49 insertions(+), 11 deletions(-) diff --git a/packages/base-settlement/src/evidence.ts b/packages/base-settlement/src/evidence.ts index 6a18eea..032292a 100644 --- a/packages/base-settlement/src/evidence.ts +++ b/packages/base-settlement/src/evidence.ts @@ -6,6 +6,8 @@ import { export const ERC20_TRANSFER_TOPIC = "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"; +const ADDRESS_RE = /^0x[0-9a-fA-F]{40}$/; + export type RpcLog = { address: string; topics: string[]; @@ -27,6 +29,7 @@ export type BaseSettlementEvidence = { transactionHash: string; blockNumber: string; tokenAddress: typeof BASE_SEPOLIA_USDC; + payer?: string; recipient: string; amountAtomic: string; executionId: string; @@ -41,9 +44,15 @@ function normalizedAddress(value: string): string { } function topicAddress(address: string): string { + if (!ADDRESS_RE.test(address)) throw new Error("INVALID_BASE_ADDRESS"); return `0x${address.slice(2).toLowerCase().padStart(64, "0")}`; } +function addressFromTopic(topic: string): string { + if (!/^0x[0-9a-fA-F]{64}$/.test(topic)) throw new Error("INVALID_BASE_ADDRESS_TOPIC"); + return `0x${topic.slice(-40)}`.toLowerCase(); +} + function parseHexUint(value: string): bigint { if (!/^0x[0-9a-fA-F]+$/.test(value)) throw new Error("INVALID_BASE_UINT_HEX"); return BigInt(value); @@ -52,8 +61,13 @@ function parseHexUint(value: string): bigint { export function verifyBaseSettlementReceipt(input: { intent: BaseSettlementIntent; receipt: RpcReceipt; + observedChainId?: number; + expectedPayer?: string; }): BaseSettlementEvidence { if (input.intent.chainId !== BASE_SEPOLIA_CHAIN_ID) throw new Error("BASE_CHAIN_MISMATCH"); + if (input.observedChainId !== undefined && input.observedChainId !== BASE_SEPOLIA_CHAIN_ID) { + throw new Error("BASE_RPC_CHAIN_MISMATCH"); + } if (normalizedAddress(input.intent.tokenAddress) !== normalizedAddress(BASE_SEPOLIA_USDC)) { throw new Error("BASE_TOKEN_MISMATCH"); } @@ -61,15 +75,18 @@ export function verifyBaseSettlementReceipt(input: { if (!/^0x[0-9a-fA-F]{64}$/.test(input.receipt.transactionHash)) throw new Error("INVALID_BASE_TRANSACTION_HASH"); const expectedRecipientTopic = topicAddress(input.intent.recipient); + const expectedPayerTopic = input.expectedPayer ? topicAddress(input.expectedPayer) : undefined; const expectedAmount = input.intent.terms.authorizedPrepayAtomic; const matching = input.receipt.logs.find((log) => normalizedAddress(log.address) === normalizedAddress(BASE_SEPOLIA_USDC) && log.topics[0]?.toLowerCase() === ERC20_TRANSFER_TOPIC && log.topics[2]?.toLowerCase() === expectedRecipientTopic + && (expectedPayerTopic === undefined || log.topics[1]?.toLowerCase() === expectedPayerTopic) && parseHexUint(log.data) === expectedAmount ); if (!matching) throw new Error("BASE_USDC_TRANSFER_DOES_NOT_MATCH_INTENT"); + const observedPayer = matching.topics[1] ? addressFromTopic(matching.topics[1]) : undefined; return { sourceSystem: "BASE", @@ -77,6 +94,7 @@ export function verifyBaseSettlementReceipt(input: { transactionHash: input.receipt.transactionHash, blockNumber: input.receipt.blockNumber, tokenAddress: BASE_SEPOLIA_USDC, + payer: observedPayer, recipient: input.intent.recipient, amountAtomic: expectedAmount.toString(), executionId: input.intent.provenance.executionId, @@ -87,25 +105,45 @@ export function verifyBaseSettlementReceipt(input: { }; } -export async function fetchBaseTransactionReceipt(input: { +async function rpcCall(input: { rpcUrl: string; - transactionHash: string; + method: string; + params: unknown[]; fetchImpl?: typeof fetch; -}): Promise { +}): Promise { const fetchImpl = input.fetchImpl ?? fetch; const response = await fetchImpl(input.rpcUrl, { method: "POST", headers: { "content-type": "application/json" }, - body: JSON.stringify({ - jsonrpc: "2.0", - id: 1, - method: "eth_getTransactionReceipt", - params: [input.transactionHash], - }), + body: JSON.stringify({ jsonrpc: "2.0", id: 1, method: input.method, params: input.params }), }); if (!response.ok) throw new Error(`BASE_RPC_HTTP_${response.status}`); - const payload = await response.json() as { result?: RpcReceipt | null; error?: unknown }; + const payload = await response.json() as { result?: T | null; error?: unknown }; if (payload.error) throw new Error(`BASE_RPC_ERROR: ${JSON.stringify(payload.error)}`); - if (!payload.result) throw new Error("BASE_TRANSACTION_RECEIPT_NOT_FOUND"); + if (payload.result === null || payload.result === undefined) { + throw new Error(`BASE_RPC_RESULT_MISSING: ${input.method}`); + } return payload.result; } + +export async function fetchBaseChainId(input: { + rpcUrl: string; + fetchImpl?: typeof fetch; +}): Promise { + const result = await rpcCall({ ...input, method: "eth_chainId", params: [] }); + const chainId = Number(parseHexUint(result)); + if (!Number.isSafeInteger(chainId)) throw new Error("INVALID_BASE_CHAIN_ID"); + return chainId; +} + +export async function fetchBaseTransactionReceipt(input: { + rpcUrl: string; + transactionHash: string; + fetchImpl?: typeof fetch; +}): Promise { + return rpcCall({ + ...input, + method: "eth_getTransactionReceipt", + params: [input.transactionHash], + }); +} From de4f2ad2994956aae420e8b8b14a1b6b00a20d65 Mon Sep 17 00:00:00 2001 From: etvjay Date: Sat, 29 Aug 2026 17:56:56 +0100 Subject: [PATCH 100/116] feat: fail closed on malformed Base intents and RPC network --- scripts/base-settlement-verify.ts | 46 ++++++++++--------------------- 1 file changed, 14 insertions(+), 32 deletions(-) diff --git a/scripts/base-settlement-verify.ts b/scripts/base-settlement-verify.ts index 059f699..d9b701a 100644 --- a/scripts/base-settlement-verify.ts +++ b/scripts/base-settlement-verify.ts @@ -1,9 +1,10 @@ import { readFile } from "node:fs/promises"; import { + fetchBaseChainId, fetchBaseTransactionReceipt, verifyBaseSettlementReceipt, } from "../packages/base-settlement/src/evidence.js"; -import type { BaseSettlementIntent } from "../packages/base-settlement/src/index.js"; +import { parseSerializedBaseSettlementIntent } from "../packages/base-settlement/src/index.js"; function arg(name: string): string | undefined { const index = process.argv.indexOf(name); @@ -13,42 +14,23 @@ function arg(name: string): string | undefined { const intentPath = arg("--intent"); const transactionHash = arg("--tx-hash"); const rpcUrl = arg("--rpc-url") ?? process.env.ENGRAM_BASE_RPC_URL; +const expectedPayer = arg("--payer") ?? process.env.ENGRAM_BASE_EXPECTED_PAYER; if (!intentPath || !transactionHash || !rpcUrl) { throw new Error( - "Usage: npm run base:settlement:verify -- --intent --tx-hash <0x...> [--rpc-url ] " - + "or set ENGRAM_BASE_RPC_URL", + "Usage: npm run base:settlement:verify -- --intent --tx-hash <0x...> [--rpc-url ] [--payer <0x...>] " + + "or set ENGRAM_BASE_RPC_URL / ENGRAM_BASE_EXPECTED_PAYER", ); } -const raw = JSON.parse(await readFile(intentPath, "utf8")) as Record; -if (raw.schema !== "engram.base-settlement-intent/v1") throw new Error("INVALID_BASE_SETTLEMENT_INTENT_SCHEMA"); - -// JSON cannot encode bigint. Evidence files store atomic amounts as decimal strings. -const terms = raw.terms as Record | undefined; -if (!terms || typeof terms.authorizedPrepayAtomic !== "string" || !/^\d+$/.test(terms.authorizedPrepayAtomic)) { - throw new Error("INVALID_BASE_SETTLEMENT_INTENT_AMOUNT"); -} - -const intent = { - ...raw, - terms: { - ...terms, - authorizedPrepayAtomic: BigInt(terms.authorizedPrepayAtomic), - }, - counterfactual: raw.counterfactual && typeof raw.counterfactual === "object" - ? { - ...(raw.counterfactual as Record), - terms: { - ...((raw.counterfactual as Record).terms as Record), - authorizedPrepayAtomic: BigInt( - String((((raw.counterfactual as Record).terms as Record).authorizedPrepayAtomic)), - ), - }, - } - : undefined, -} as unknown as BaseSettlementIntent; - +const raw = JSON.parse(await readFile(intentPath, "utf8")) as unknown; +const intent = parseSerializedBaseSettlementIntent(raw); +const observedChainId = await fetchBaseChainId({ rpcUrl }); const receipt = await fetchBaseTransactionReceipt({ rpcUrl, transactionHash }); -const evidence = verifyBaseSettlementReceipt({ intent, receipt }); +const evidence = verifyBaseSettlementReceipt({ + intent, + receipt, + observedChainId, + expectedPayer, +}); process.stdout.write(`${JSON.stringify(evidence, null, 2)}\n`); From b6ffe6fcc824c20e8f41f2e64532ada3867c858d Mon Sep 17 00:00:00 2001 From: etvjay Date: Sat, 29 Aug 2026 17:57:19 +0100 Subject: [PATCH 101/116] test: pressure Base chain payer and serialized intent boundaries --- .../base-settlement-receipt.test.ts | 97 ++++++++++++------- 1 file changed, 64 insertions(+), 33 deletions(-) diff --git a/tests/integration/base-settlement-receipt.test.ts b/tests/integration/base-settlement-receipt.test.ts index f1ee6ff..49bdabb 100644 --- a/tests/integration/base-settlement-receipt.test.ts +++ b/tests/integration/base-settlement-receipt.test.ts @@ -1,6 +1,8 @@ import { describe, expect, it } from "vitest"; import { deriveBaseSettlementIntent, + parseSerializedBaseSettlementIntent, + serializeBaseSettlementIntent, } from "../../packages/base-settlement/src/index.js"; import { ERC20_TRANSFER_TOPIC, @@ -12,20 +14,27 @@ import type { ProviderDecision } from "../../packages/scenarios/provider-continu const atlas = "0x1111111111111111111111111111111111111111"; const beacon = "0x2222222222222222222222222222222222222222"; const sender = "0x3333333333333333333333333333333333333333"; +const wrongSender = "0x5555555555555555555555555555555555555555"; const txHash = `0x${"ab".repeat(32)}`; function topic(address: string): string { return `0x${address.slice(2).toLowerCase().padStart(64, "0")}`; } -function receipt(input: { recipient: string; amount: bigint; status?: string; token?: string }): RpcReceipt { +function receipt(input: { + recipient: string; + amount: bigint; + status?: string; + token?: string; + payer?: string; +}): RpcReceipt { return { transactionHash: txHash, status: input.status ?? "0x1", blockNumber: "0x1234", logs: [{ address: input.token ?? "0x036CbD53842c5426634e7929541eC2318f3dCF7e", - topics: [ERC20_TRANSFER_TOPIC, topic(sender), topic(input.recipient)], + topics: [ERC20_TRANSFER_TOPIC, topic(input.payer ?? sender), topic(input.recipient)], data: `0x${input.amount.toString(16).padStart(64, "0")}`, transactionHash: txHash, logIndex: "0x0", @@ -54,27 +63,32 @@ function routineDecision(): ProviderDecision { }; } -describe("Base settlement receipt evidence", () => { - it("accepts only a successful USDC Transfer matching the decision-derived recipient and amount", () => { - const intent = deriveBaseSettlementIntent({ - decision: routineDecision(), - addresses: { atlas, beacon }, - provenance: { - executionId: "exec-routine", - retrievalId: "retrieval-routine", - decisionId: "decision-routine", - }, - }); +function intent() { + return deriveBaseSettlementIntent({ + decision: routineDecision(), + addresses: { atlas, beacon }, + provenance: { + executionId: "exec-routine", + retrievalId: "retrieval-routine", + decisionId: "decision-routine", + }, + }); +} +describe("Base settlement receipt evidence", () => { + it("accepts only a successful USDC Transfer matching chain, payer, recipient and amount", () => { const evidence = verifyBaseSettlementReceipt({ - intent, + intent: intent(), receipt: receipt({ recipient: atlas, amount: 800_000n }), + observedChainId: 84532, + expectedPayer: sender, }); expect(evidence).toMatchObject({ sourceSystem: "BASE", chainId: 84532, transactionHash: txHash, + payer: sender, recipient: atlas, amountAtomic: "800000", executionId: "exec-routine", @@ -85,47 +99,64 @@ describe("Base settlement receipt evidence", () => { }); }); + it("round-trips a serialized intent and rejects internally inconsistent amounts", () => { + const serialized = serializeBaseSettlementIntent(intent()); + expect(parseSerializedBaseSettlementIntent(serialized).terms.authorizedPrepayAtomic).toBe(800_000n); + + expect(() => parseSerializedBaseSettlementIntent({ + ...serialized, + terms: { ...serialized.terms, authorizedPrepayAtomic: "4000000" }, + })).toThrow("BASE_SETTLEMENT_INTENT_AMOUNT_INCONSISTENT"); + expect(() => parseSerializedBaseSettlementIntent({ ...serialized, chainId: 1 })).toThrow(); + }); + it("rejects a successful transfer to the wrong provider", () => { - const intent = deriveBaseSettlementIntent({ - decision: routineDecision(), - addresses: { atlas, beacon }, - provenance: { executionId: "exec-routine" }, - }); expect(() => verifyBaseSettlementReceipt({ - intent, + intent: intent(), receipt: receipt({ recipient: beacon, amount: 800_000n }), + observedChainId: 84532, })).toThrow("BASE_USDC_TRANSFER_DOES_NOT_MATCH_INTENT"); }); it("rejects the no-memory prepayment amount when memory authorized only the guarded amount", () => { - const intent = deriveBaseSettlementIntent({ - decision: routineDecision(), - addresses: { atlas, beacon }, - provenance: { executionId: "exec-routine" }, - }); expect(() => verifyBaseSettlementReceipt({ - intent, + intent: intent(), receipt: receipt({ recipient: atlas, amount: 4_000_000n }), + observedChainId: 84532, + })).toThrow("BASE_USDC_TRANSFER_DOES_NOT_MATCH_INTENT"); + }); + + it("rejects a receipt fetched from the wrong chain", () => { + expect(() => verifyBaseSettlementReceipt({ + intent: intent(), + receipt: receipt({ recipient: atlas, amount: 800_000n }), + observedChainId: 1, + })).toThrow("BASE_RPC_CHAIN_MISMATCH"); + }); + + it("rejects a transfer whose payer is not the expected requester wallet", () => { + expect(() => verifyBaseSettlementReceipt({ + intent: intent(), + receipt: receipt({ recipient: atlas, amount: 800_000n, payer: wrongSender }), + observedChainId: 84532, + expectedPayer: sender, })).toThrow("BASE_USDC_TRANSFER_DOES_NOT_MATCH_INTENT"); }); it("rejects reverted transactions and transfers from the wrong token contract", () => { - const intent = deriveBaseSettlementIntent({ - decision: routineDecision(), - addresses: { atlas, beacon }, - provenance: { executionId: "exec-routine" }, - }); expect(() => verifyBaseSettlementReceipt({ - intent, + intent: intent(), receipt: receipt({ recipient: atlas, amount: 800_000n, status: "0x0" }), + observedChainId: 84532, })).toThrow("BASE_TRANSACTION_NOT_SUCCESSFUL"); expect(() => verifyBaseSettlementReceipt({ - intent, + intent: intent(), receipt: receipt({ recipient: atlas, amount: 800_000n, token: "0x4444444444444444444444444444444444444444", }), + observedChainId: 84532, })).toThrow("BASE_USDC_TRANSFER_DOES_NOT_MATCH_INTENT"); }); }); From af1e8560da0663a1dbf08b03e8a8e68bb08e31b1 Mon Sep 17 00:00:00 2001 From: etvjay Date: Sat, 29 Aug 2026 17:59:06 +0100 Subject: [PATCH 102/116] docs: harden Base live proof chain and payer checks --- hackathon/sibyl/BASE_LIVE_RUN.md | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/hackathon/sibyl/BASE_LIVE_RUN.md b/hackathon/sibyl/BASE_LIVE_RUN.md index f60be97..7ec7abf 100644 --- a/hackathon/sibyl/BASE_LIVE_RUN.md +++ b/hackathon/sibyl/BASE_LIVE_RUN.md @@ -21,10 +21,10 @@ execution evidence -> Sibyl memory -> fresh Engram recall -> Engram provider decision - -> engam.base-settlement-intent/v1 + -> engram.base-settlement-intent/v1 -> explicit wallet execution on Base Sepolia -> receipt - -> USDC Transfer matches recipient + amount + -> chain + payer + USDC recipient + amount match -> Base settlement evidence ``` @@ -38,7 +38,7 @@ A transaction hash without the preceding memory/decision linkage does not qualif 4. Form the relationship memory through normal Engram admission. 5. Terminate the originating process. 6. In a fresh process, recall the relationship memory and record the provider decision. -7. Derive a Base settlement intent containing: +7. Derive and serialize a Base settlement intent containing: - execution ID; - retrieval ID; - decision ID; @@ -48,24 +48,29 @@ A transaction hash without the preceding memory/decision linkage does not qualif - prepay basis points; - exact USDC atomic amount; - no-memory counterfactual. -8. Review the intent before signing anything. -9. Execute exactly that authorized USDC transfer with the selected testnet wallet/signer. -10. Retain the transaction hash. Never retain/export the private key in Engram evidence. -11. Verify independently: +8. Review the serialized intent before signing anything. +9. Record the requester/payer wallet address expected to execute the settlement. +10. Execute exactly that authorized USDC transfer with the selected testnet wallet/signer. +11. Retain the transaction hash. Never retain/export the private key in Engram evidence. +12. Verify independently: ```bash ENGRAM_BASE_RPC_URL='' \ npm run base:settlement:verify -- \ --intent artifacts/base/.json \ - --tx-hash <0x...> + --tx-hash <0x...> \ + --payer ``` -12. Verification must fail unless the receipt: +13. The verifier independently calls `eth_chainId` and must observe `84532` before accepting the receipt. +14. Verification must fail unless the receipt: + - was fetched from Base Sepolia; - succeeded; - contains a Circle Base Sepolia USDC `Transfer`; + - originates from the expected requester/payer when payer binding is supplied; - transfers to the exact decision-derived recipient; - transfers the exact decision-derived amount. -13. Save verifier stdout, transaction hash, explorer link, receipt, intent, and Engram trace in the final evidence bundle. +15. Save verifier stdout, transaction hash, explorer link, receipt, serialized intent, payer address, and Engram trace in the final evidence bundle. ## Flagship expected deltas @@ -97,6 +102,9 @@ The routine case is the stronger Base authority proof because memory changes how ## Negative pressure A live claim is invalid if any of these are true: +- serialized intent is malformed or internally inconsistent; +- RPC reports a chain other than `84532`; +- payer differs from the expected requester wallet when payer binding is claimed; - recipient differs from the settlement intent; - amount differs from the settlement intent; - wrong token contract; From 2edab129157ab9af11735fde045118273d34c451 Mon Sep 17 00:00:00 2001 From: etvjay Date: Sat, 29 Aug 2026 17:59:46 +0100 Subject: [PATCH 103/116] docs: promote hardened Base conformance evidence baseline --- hackathon/sibyl/templates/EVIDENCE_LEDGER.md | 57 ++++++++++++-------- 1 file changed, 34 insertions(+), 23 deletions(-) diff --git a/hackathon/sibyl/templates/EVIDENCE_LEDGER.md b/hackathon/sibyl/templates/EVIDENCE_LEDGER.md index 3edcf3a..f5edf67 100644 --- a/hackathon/sibyl/templates/EVIDENCE_LEDGER.md +++ b/hackathon/sibyl/templates/EVIDENCE_LEDGER.md @@ -7,24 +7,27 @@ Allowed states: | Claim / gate | State | Evidence | Negative mutation | Notes | |---|---|---|---|---| -| Sibyl persists decision-critical memory | LOCAL_PASS | GitHub Actions run `33232373531`, job `99047294445`, branch head `afb3ac3751cd0c9a736266f199d4f87682251913`: SDK 0.6.1 installed; route/provider/conflict memories persisted through Sibyl | missing Sibyl runtime | Pre-build-window evidence; must be re-run during official window | -| Fresh session/process recalls prior memory | LOCAL_PASS | run `33232373531`: separate seed and recall processes; route memory plus provider relationship memory recalled in later processes; conflict test creates a fresh `SibylRuntimeStore` before retrieving both contradictory memories | terminate source process / unavailable Sibyl | Stronger than fresh-object-only proof | -| Recalled memory changes action | LOCAL_PASS | run `33232373531`: route `A-B-C -> A-B-D`; urgent provider `atlas -> beacon`; explicit `CHANGED_ACTION` traces | no-memory control | Paired behavioral deltas, not retrieval-only | -| Recalled memory constrains authority without global blacklist | LOCAL_PASS | run `33232373531`, fresh routine provider process: Atlas remains selected while prepay falls `5000 -> 1000` bps and milestone verification becomes required; trace records `CONSTRAINED_ACTION` | routine-context control | Demonstrates contextual relationship posture rather than global reputation | -| Multi-execution experience becomes bounded relationship memory | LOCAL_PASS | run `33232373531`: two historical Atlas breach executions plus admitting execution produced `CONTEXT_GUARDED` relationship memory | single-failure fixture / cross-task fixture | Pure scenario tests also require >=2 source executions and task-type applicability | -| Urgent provider experience changes outcome | LOCAL_PASS | run `33232373531`: no-memory Atlas path deterministically returns `SLA_BREACH`; memory-conditioned Beacon path returns `SUCCESS` | no-memory provider control | Application fixture, not a claim about a live provider network | -| Deleting/unavailable Sibyl breaks/degrades core function | LOCAL_PASS | run `33232373531`: deletion CLI emitted degradation with no fallback | remove/disable Sibyl runtime | VETO; mutation harness fails if Sibyl unexpectedly stays available | -| Engram provenance remains reconstructable | LOCAL_PASS | run `33232373531`: recall IDs, memory IDs, `engram.memory-state/v1` digests, counterfactuals, accepted influence and evaluation events appear in route/provider traces | post-recall memory tamper | Sibyl backend preserves trace material needed for influence validation | -| Expired Sibyl memory is retrieved but blocked before exposure | LOCAL_PASS | run `33232373531`, `npm run test:sibyl` | expired memory fixture | Demonstrates retrieval != legitimate influence | -| Post-recall memory tamper is rejected | LOCAL_PASS | run `33232373531`, `npm run test:sibyl` | overwrite memory after digest exposure | Protects recall-to-decision state integrity | -| Conflicting memory remains non-silently adjudicated through Sibyl store | LOCAL_PASS | run `33232373531`, job `99047294445`: contradictory memories remain recall-visible, unresolved influence is rejected, explicit `SUPERSEDES` resolves the relevant side | unresolved `CONTRADICTS` pair | Proves Sibyl persistence/retrieval does not silently turn ranking into adjudication | -| Expanded Sibyl pressure suite | LOCAL_PASS | run `33232373531`, job `99047294445`: `3` test files / `7` tests passed, followed by route/provider/deletion process-boundary proof | expiry, tamper, contradiction, deletion, single-failure/cross-task controls | Same evaluated profile remains repeatable on clean hosted runners | -| Self-verifying evidence capture path | LOCAL_PASS | run `33232373531`, job `99047294445`: `Smoke exact evidence capture path` and `Verify evidence manifest exists` both passed on head `afb3ac37` | dirty source / unexpected untracked file; failed precursor run `33232299952` | Capture v2 records git/source state, environment versions, dependency digests, output SHA-256 values and final Sibyl DB digest | -| Canonical Engram suite remains green with evaluated Sibyl profile | LOCAL_PASS | run `33232373531`, check job `99047294544`: `npm run check` passed; SAM build run `33232373540` also passed | canonical test suite | Same branch head `afb3ac3751cd0c9a736266f199d4f87682251913` | -| Root README exposes critical write/read/influence/conflict/deletion/evidence call map | LOCAL_PASS | root README on `hackathon/sibyl-ebi` exposes all critical judged paths plus one-command capture | cold reviewer navigation | Human under-two-minute timing remains to be performed; therefore not `PUBLIC_EVALUATOR_PASS` | +| Sibyl persists decision-critical memory | LOCAL_PASS | GitHub Actions run `33264345953`, job `99131636029`, branch head `b6ffe6fcc824c20e8f41f2e64532ada3867c858d`: SDK 0.6.1 installed; route/provider/conflict memories persisted through Sibyl | missing Sibyl runtime | Pre-build-window evidence; must be re-run during official window | +| Fresh session/process recalls prior memory | LOCAL_PASS | run `33264345953`: separate seed and recall processes; route memory plus provider relationship memory recalled in later processes; conflict test creates a fresh `SibylRuntimeStore` before retrieving both contradictory memories | terminate source process / unavailable Sibyl | Stronger than fresh-object-only proof | +| Recalled memory changes action | LOCAL_PASS | run `33264345953`: route `A-B-C -> A-B-D`; urgent provider `atlas -> beacon`; explicit `CHANGED_ACTION` traces | no-memory control | Paired behavioral deltas, not retrieval-only | +| Recalled memory constrains authority without global blacklist | LOCAL_PASS | run `33264345953`, fresh routine provider process: Atlas remains selected while prepay falls `5000 -> 1000` bps and milestone verification becomes required; trace records `CONSTRAINED_ACTION` | routine-context control | Demonstrates contextual relationship posture rather than global reputation | +| Multi-execution experience becomes bounded relationship memory | LOCAL_PASS | run `33264345953`: two historical Atlas breach executions plus admitting execution produced `CONTEXT_GUARDED` relationship memory | single-failure fixture / cross-task fixture | Pure scenario tests also require >=2 source executions and task-type applicability | +| Urgent provider experience changes outcome | LOCAL_PASS | run `33264345953`: no-memory Atlas path deterministically returns `SLA_BREACH`; memory-conditioned Beacon path returns `SUCCESS` | no-memory provider control | Application fixture, not a claim about a live provider network | +| Deleting/unavailable Sibyl breaks/degrades core function | LOCAL_PASS | run `33264345953`: deletion CLI emitted degradation with no fallback | remove/disable Sibyl runtime | VETO; mutation harness fails if Sibyl unexpectedly stays available | +| Engram provenance remains reconstructable | LOCAL_PASS | run `33264345953`: recall IDs, memory IDs, `engram.memory-state/v1` digests, counterfactuals, accepted influence and evaluation events appear in route/provider traces | post-recall memory tamper | Sibyl backend preserves trace material needed for influence validation | +| Expired Sibyl memory is retrieved but blocked before exposure | LOCAL_PASS | run `33264345953`, `npm run test:sibyl` | expired memory fixture | Demonstrates retrieval != legitimate influence | +| Post-recall memory tamper is rejected | LOCAL_PASS | run `33264345953`, `npm run test:sibyl` | overwrite memory after digest exposure | Protects recall-to-decision state integrity | +| Conflicting memory remains non-silently adjudicated through Sibyl store | LOCAL_PASS | run `33264345953`, job `99131636029`: contradictory memories remain recall-visible, unresolved influence is rejected, explicit `SUPERSEDES` resolves the relevant side | unresolved `CONTRADICTS` pair | Proves Sibyl persistence/retrieval does not silently turn ranking into adjudication | +| Expanded Sibyl pressure suite | LOCAL_PASS | run `33264345953`, job `99131636029`: `3` test files / `7` tests passed, followed by route/provider/deletion process-boundary proof | expiry, tamper, contradiction, deletion, single-failure/cross-task controls | Same evaluated profile remains repeatable on clean hosted runners | +| Self-verifying evidence capture path | LOCAL_PASS | run `33264345953`, job `99131636029`: exact evidence capture and manifest check passed on head `b6ffe6fc` | dirty source / unexpected untracked file; failed precursor run `33232299952` | Capture v2 records git/source state, environment versions, dependency digests, output SHA-256 values and final Sibyl DB digest | +| Base settlement authority follows Engram memory-conditioned decision | LOCAL_PASS | run `33264345953`, check job `99131636110`: canonical `npm run check` includes `test:base`; urgent memory changes recipient Atlas -> Beacon, routine memory changes authorized prepay `4.000000 -> 0.800000 USDC` | no-memory decision / malformed address | This is local causal-model evidence, not an executed Base transaction | +| Base serialized intent is internally bound | LOCAL_PASS | run `33264345953`, check job `99131636110`: serialized intent schema fixes network/token/provider/address/provenance fields and rejects inconsistent atomic/decimal prepay values | malformed schema, wrong chain, inconsistent amount | Removes unsafe-cast ambiguity from the live verifier input | +| Base receipt verification fails closed | LOCAL_PASS | run `33264345953`, check job `99131636110`: receipt verifier rejects wrong RPC chain, wrong payer, wrong recipient, wrong amount, wrong token, and reverted transaction | chain/payer/recipient/amount/token/status mutations | Live verifier independently calls `eth_chainId`; receipt evidence still requires real official-window transaction for partner promotion | +| Canonical Engram suite remains green with Sibyl + Base evaluated profiles | LOCAL_PASS | run `33264345953`, check job `99131636110`: `npm run check` passed; SAM build run `33264345950` also passed | canonical test suite | Strongest tested code head `b6ffe6fcc824c20e8f41f2e64532ada3867c858d` | +| Root README exposes critical write/read/influence/conflict/deletion/evidence call map | LOCAL_PASS | root README on `hackathon/sibyl-ebi` exposes core judged paths plus one-command capture | cold reviewer navigation | Base call-map synchronization is being added after the tested code head; human under-two-minute timing remains pending | | Hackathon-window rerun of core proof | UNVERIFIED | — | clean clone + fresh DB | Pre-window proof cannot substitute for final event-window evidence | -| Base integration does real product work | UNVERIFIED | — | remove Base action | optional; do not add decoratively | -| Virtuals integration does real product work | UNVERIFIED | adapter/conformance/live-ingest path implemented; local conformance passed; no authenticated ACP job yet | remove Virtuals interaction | optional; partner multiplier remains unclaimed | +| Base integration does real product work onchain | UNVERIFIED | settlement authority adapter, hardened verifier and live runbook exist; no real Base Sepolia settlement yet | remove Base action / mismatch settlement | `BASE-001` partner claim remains unearned until a decision-linked action is executed and verified | +| Virtuals integration does real product work | UNVERIFIED | adapter/conformance/live-ingest path implemented; local conformance passed; no authenticated ACP job yet | remove Virtuals interaction | partner multiplier remains unclaimed | ## Current flagship interpretation The strongest current memory claim is not `the agent remembers Atlas is bad`. @@ -39,6 +42,10 @@ The adversarial corollary is equally important: > Retrieval rank is not adjudication. If two persisted memories explicitly contradict each other, Engram may expose both but refuses to let either silently become authority until relationship evidence resolves the conflict. +The economic consequence is now explicit at local conformance level: + +> The same remembered relationship posture can change who is authorized to receive a Base settlement for urgent work, or reduce how much USDC the same provider is authorized to receive upfront for routine work. A Base receipt is accepted only when chain, payer when bound, token, recipient, amount and success state agree with the serialized Engram settlement intent. + ## Evidence-history note Run `32753747711` remains an earlier pre-window baseline for the original six-test profile. @@ -46,13 +53,17 @@ Head `8f616545...` / run `33221823993` added the Sibyl-backed contradiction gate The first exact capture-smoke run on head `45806957...`, CI `33232299952`, intentionally surfaced an evidence-harness failure after every product/Sibyl phase passed: `npm install` generated an untracked `package-lock.json`, which the first strict source-tree guard treated as unexpected dirtiness. That run is retained as a failed harness attempt, not a product failure. -The current strongest pre-window engineering baseline is branch head `afb3ac3751cd0c9a736266f199d4f87682251913`: -- Engram CI `33232373531`: SUCCESS -- Sibyl profile job `99047294445`: SUCCESS, including exact evidence-capture smoke and manifest check -- canonical check job `99047294544`: SUCCESS -- Engram SAM Build `33232373540`: SUCCESS +Head `afb3ac37...` / run `33232373531` corrected and proved the exact self-verifying evidence-capture path. + +Head `266d3c38...` / run `33264157362` added the first Base settlement-authority and receipt-verification local conformance while keeping the complete Sibyl profile green. + +The current strongest tested pre-window code baseline is branch head `b6ffe6fcc824c20e8f41f2e64532ada3867c858d`: +- Engram CI `33264345953`: SUCCESS +- Sibyl profile job `99131636029`: SUCCESS, including deletion, exact evidence-capture smoke and manifest check +- canonical check job `99131636110`: SUCCESS, including hardened Base schema/chain/payer/receipt pressure +- Engram SAM Build `33264345950`: SUCCESS -The corrected capture classifies only the known generated untracked `package-lock.json` as setup residue, records and hashes it when present, and continues to veto tracked source drift or unexpected untracked files. +The hardened Base verifier schema-validates serialized settlement intent, recomputes amount consistency, independently verifies RPC chain ID `84532`, and may bind ERC-20 `Transfer.from` to the expected requester wallet before accepting recipient/amount evidence. A green run proves only the commit/run it actually executed. Later documentation commits may record that evidence but do not strengthen it. From 00a74b3ab98ce33ec0e60bd502a4623ea4331a62 Mon Sep 17 00:00:00 2001 From: etvjay Date: Sat, 29 Aug 2026 18:00:05 +0100 Subject: [PATCH 104/116] docs: promote hardened Base local conformance status --- hackathon/sibyl/partners/base.md | 33 +++++++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/hackathon/sibyl/partners/base.md b/hackathon/sibyl/partners/base.md index 7550ef0..16bb8e9 100644 --- a/hackathon/sibyl/partners/base.md +++ b/hackathon/sibyl/partners/base.md @@ -33,15 +33,34 @@ Applicable relationship memory still selects Atlas but reduces prepayment to 10% The Base effect is reduced economic authority, not a global provider blacklist. +## Local conformance +The current adapter and verifier are `LOCAL_CONFORMANCE_PASS` on tested code head `b6ffe6fcc824c20e8f41f2e64532ada3867c858d`: + +- Engram CI `33264345953`: SUCCESS; +- canonical check job `99131636110`: SUCCESS; +- complete Sibyl profile job `99131636029`: SUCCESS; +- SAM Build `33264345950`: SUCCESS. + +Local pressure proves: +- recipient and prepayment amount are derived from the Engram decision; +- serialized intent is schema-validated and amount-consistent; +- RPC chain must resolve to Base Sepolia `84532`; +- optional payer binding checks the USDC `Transfer.from` address; +- wrong recipient, amount, token, payer, chain, or reverted receipt fails closed. + +This is not a live Base transaction and does not earn the partner bonus. + ## Veto Do not claim Base merely because a transaction receipt exists. The transaction must match the settlement intent derived from the remembered Engram decision. ## Required evidence - Engram execution ID; - recall/retrieval ID when memory influenced the decision; -- decision-linked `engram.base-settlement-intent/v1` intent; +- decision-linked `engram.base-settlement-intent/v1` serialized intent; +- expected requester/payer wallet when payer binding is claimed; +- RPC-observed chain ID `84532`; - protocol-native Base transaction hash and successful receipt; -- observed USDC transfer recipient and amount matching the intent; +- observed Circle USDC transfer payer/recipient/amount matching the intent; - action visible in the demo; - counterfactual showing what recipient/amount would have been authorized without memory. @@ -54,8 +73,12 @@ A transaction hash alone is insufficient. ## Negative tests - remove memory: recipient/amount must revert to the control settlement; -- alter provider address: verification must not accept the wrong recipient; -- alter prepayment amount: verification must not accept the wrong amount; +- malformed or internally inconsistent serialized intent: reject; +- wrong RPC chain: reject; +- wrong payer when bound: reject; +- alter provider address: reject wrong recipient; +- alter prepayment amount: reject wrong amount; +- wrong token or reverted transaction: reject; - remove Base action: no Base partner claim remains. -Status: `IMPLEMENTED / LOCAL_CONFORMANCE_PENDING_CI / LIVE_BASE_UNVERIFIED`. +Status: `IMPLEMENTED / LOCAL_CONFORMANCE_PASS / LIVE_BASE_UNVERIFIED`. From fe3f64c894429b8a05bf6ef8b164898542566db7 Mon Sep 17 00:00:00 2001 From: etvjay Date: Sat, 29 Aug 2026 18:00:35 +0100 Subject: [PATCH 105/116] docs: promote hardened Base and unified tested baseline --- hackathon/sibyl/requirements/requirements.json | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/hackathon/sibyl/requirements/requirements.json b/hackathon/sibyl/requirements/requirements.json index 7a9a987..6eaf3fc 100644 --- a/hackathon/sibyl/requirements/requirements.json +++ b/hackathon/sibyl/requirements/requirements.json @@ -1,23 +1,23 @@ { "verified_at": "2026-08-29", "status": "READY_FOR_LIVE_PRESSURE", - "evidence_note": "Core Sibyl and experiential-provider gates are LOCAL_PASS from pre-build-window CI; strongest fully exercised Sibyl/evidence-capture baseline is head afb3ac37 with Engram CI 33232373531 and SAM build 33232373540. Base settlement authority and fail-closed receipt verification are now locally conformant from canonical CI on head 266d3c38, but BASE-001 remains UNVERIFIED until a real Base Sepolia action is executed. Virtuals ACP remains LOCAL_CONFORMANCE_PASS / LIVE_ACP_UNVERIFIED. Submission/live-public gates must be re-proven during the official build window.", + "evidence_note": "Core Sibyl, experiential-provider, evidence-capture and hardened Base local-conformance gates are LOCAL_PASS on strongest tested pre-window code head b6ffe6fcc824c20e8f41f2e64532ada3867c858d: Engram CI 33264345953 and SAM build 33264345950 both succeeded. Base settlement intent is schema/amount bound and receipt verification now checks RPC chain, optional payer, token, recipient, amount and success state. BASE-001 remains UNVERIFIED until a real Base Sepolia action is executed. Virtuals ACP remains LOCAL_CONFORMANCE_PASS / LIVE_ACP_UNVERIFIED. Submission/live-public gates must be re-proven during the official build window.", "requirements": [ - {"id":"SIBYL-GATE-001","track":"main","class":"PUBLISHED_HARD","severity":"VETO","description":"Sibyl Memory is load-bearing; deleting it breaks or materially degrades the core function.","check":"run deletion mutation and compare claimed behavior","evidence_required":"failing/degraded no-Sibyl run plus passing Sibyl run","status":"LOCAL_PASS","evidence":"GitHub Actions run 33232373531: deletion mutation degraded=true, fallbackAvailable=false and exact evidence-capture path passed"}, - {"id":"SIBYL-GATE-002","track":"main","class":"PUBLISHED_HARD","severity":"VETO","description":"Fresh session recalls earlier persisted state.","check":"terminate process/session, restart clean, recall prior memory","evidence_required":"continuous demo segment with timestamp or commit hash","status":"LOCAL_PASS","evidence":"GitHub Actions run 33232373531: separate route/provider processes recalled persisted Sibyl memory; conflict test retrieves contradictory memories through a fresh SibylRuntimeStore"}, - {"id":"SIBYL-GATE-003","track":"main","class":"PUBLISHED_HARD","severity":"VETO","description":"Recalled memory changes a decision, action, or result.","check":"paired memory vs no-memory decision comparison","evidence_required":"decision trace and observable action delta","status":"LOCAL_PASS","evidence":"Run 33232373531: route A-B-C -> A-B-D; urgent provider Atlas -> Beacon with CHANGED_ACTION; routine Atlas terms constrained with CONSTRAINED_ACTION"}, + {"id":"SIBYL-GATE-001","track":"main","class":"PUBLISHED_HARD","severity":"VETO","description":"Sibyl Memory is load-bearing; deleting it breaks or materially degrades the core function.","check":"run deletion mutation and compare claimed behavior","evidence_required":"failing/degraded no-Sibyl run plus passing Sibyl run","status":"LOCAL_PASS","evidence":"GitHub Actions run 33264345953 job 99131636029: deletion mutation degraded with no fallback and exact evidence-capture path passed"}, + {"id":"SIBYL-GATE-002","track":"main","class":"PUBLISHED_HARD","severity":"VETO","description":"Fresh session recalls earlier persisted state.","check":"terminate process/session, restart clean, recall prior memory","evidence_required":"continuous demo segment with timestamp or commit hash","status":"LOCAL_PASS","evidence":"GitHub Actions run 33264345953: separate route/provider processes recalled persisted Sibyl memory; conflict test retrieves contradictory memories through a fresh SibylRuntimeStore"}, + {"id":"SIBYL-GATE-003","track":"main","class":"PUBLISHED_HARD","severity":"VETO","description":"Recalled memory changes a decision, action, or result.","check":"paired memory vs no-memory decision comparison","evidence_required":"decision trace and observable action delta","status":"LOCAL_PASS","evidence":"Run 33264345953: route A-B-C -> A-B-D; urgent provider Atlas -> Beacon with CHANGED_ACTION; routine Atlas terms constrained with CONSTRAINED_ACTION"}, {"id":"SIBYL-GATE-004","track":"main","class":"PUBLISHED_HARD","severity":"HIGH","description":"README exposes critical memory write/read paths in under two minutes.","check":"cold reviewer repo navigation test","evidence_required":"README call map","status":"LOCAL_PASS","evidence":"Root README on hackathon/sibyl-ebi exposes store wiring, write/read, recall-state binding, influence, contradiction, provider scenario, process-boundary demo, deletion and evidence capture. Human cold-review timing remains pending."}, {"id":"SCORE-MEM-001","track":"main","class":"PUBLISHED_SCORING","severity":"HIGH","description":"Memory use is sophisticated enough for top band; coordination/dynamic-state behavior preferred.","check":"judge-model scorecard","evidence_required":"non-trivial stateful scenario plus adversarial memory handling","status":"LOCAL_PASS","evidence":"Sibyl profile: multi-execution experiential relationship memory changes urgent delegation and routine authority; expiry, post-recall tamper and unresolved-contradiction controls pass. Final evaluator score remains future."}, - {"id":"SCORE-TECH-001","track":"main","class":"PUBLISHED_SCORING","severity":"HIGH","description":"Build is clean, robust and survives a second run/curious judge.","check":"repeatability and negative test suite","evidence_required":"test report and second-run evidence","status":"LOCAL_PASS","evidence":"Head afb3ac37: Engram CI 33232373531 and SAM Build 33232373540 succeeded, including exact evidence-capture smoke"}, + {"id":"SCORE-TECH-001","track":"main","class":"PUBLISHED_SCORING","severity":"HIGH","description":"Build is clean, robust and survives a second run/curious judge.","check":"repeatability and negative test suite","evidence_required":"test report and second-run evidence","status":"LOCAL_PASS","evidence":"Head b6ffe6fc: Engram CI 33264345953 and SAM Build 33264345950 succeeded, including exact evidence-capture smoke and hardened Base tests"}, {"id":"EXP-CONT-001","track":"main","class":"INTERNAL_ACCEPTANCE","severity":"HIGH","description":"Multiple attributable executions may form bounded relationship state only with sufficient lineage.","check":"multi-source provider history test","evidence_required":"two historical executions + admitting execution + relationship memory lineage","status":"LOCAL_PASS","evidence":"Two Atlas breach executions plus admitting execution produce CONTEXT_GUARDED relationship memory; one-breach and cross-task controls remain baseline"}, {"id":"EXP-CONT-002","track":"main","class":"INTERNAL_ACCEPTANCE","severity":"HIGH","description":"Relationship state changes behavior contextually rather than becoming a global provider blacklist.","check":"urgent vs routine paired decisions","evidence_required":"urgent provider change plus routine authority narrowing using same memory","status":"LOCAL_PASS","evidence":"Urgent Atlas -> Beacon; routine stays Atlas while prepay 5000 -> 1000 bps and milestone verification false -> true"}, {"id":"EXP-CONT-003","track":"main","class":"INTERNAL_ACCEPTANCE","severity":"HIGH","description":"Retrieval ranking must not silently adjudicate explicit contradictory memories.","check":"persist contradictory memories through Sibyl, fresh-recall both, attempt influence before and after explicit resolution","evidence_required":"both memories recall-visible; unresolved influence rejected; explicit supersession required before resolved influence","status":"LOCAL_PASS","evidence":"sibyl-competing-memories.test.ts rejects unresolved influence with UNRESOLVED_MEMORY_CONTRADICTION and accepts the resolved side only after SUPERSEDES evidence"}, - {"id":"BASE-CONF-001","track":"base","class":"INTERNAL_ACCEPTANCE","severity":"HIGH","description":"Engram memory-conditioned provider decisions deterministically change Base settlement authority and receipt verification fails closed on divergent onchain evidence.","check":"run test:base and canonical check","evidence_required":"recipient/amount delta tests plus wrong-recipient/wrong-amount/wrong-token/revert mutations","status":"LOCAL_PASS","evidence":"Canonical CI run 33264157362, check job 99131095748, passed on head 266d3c38; Base tests are included in test:all. Urgent changes recipient Atlas -> Beacon; routine changes prepay 4.000000 -> 0.800000 USDC; receipt verifier rejects wrong recipient, amount, token and reverted transactions."}, + {"id":"BASE-CONF-001","track":"base","class":"INTERNAL_ACCEPTANCE","severity":"HIGH","description":"Engram memory-conditioned provider decisions deterministically change Base settlement authority and receipt verification fails closed on divergent onchain evidence.","check":"run test:base and canonical check","evidence_required":"recipient/amount delta, serialized-intent integrity, wrong-chain/wrong-payer/wrong-recipient/wrong-amount/wrong-token/revert mutations","status":"LOCAL_PASS","evidence":"Canonical CI run 33264345953 check job 99131636110 passed on head b6ffe6fc; urgent changes recipient Atlas -> Beacon; routine changes prepay 4.000000 -> 0.800000 USDC; serialized intent rejects inconsistent values; verifier rejects wrong RPC chain, payer, recipient, amount, token and reverted transactions."}, {"id":"SUBMIT-001","track":"submission","class":"PUBLISHED_HARD","severity":"VETO","description":"Public MIT/Apache-2.0 repo with real commit history.","check":"repository inspection","evidence_required":"public repo/license/commits","status":"LOCAL_PASS"}, {"id":"SUBMIT-002","track":"submission","class":"PUBLISHED_HARD","severity":"VETO","description":"2–5 minute demo includes fresh-session recall.","check":"video review","evidence_required":"public video","status":"UNVERIFIED"}, - {"id":"SUBMIT-003","track":"submission","class":"PUBLISHED_HARD","severity":"VETO","description":"README includes Prior Work declaration and required memory/partner notes.","check":"README audit","evidence_required":"merged README","status":"UNVERIFIED","evidence":"Branch README includes explicit Prior Work and memory-path sections; final partner notes and submission-window truth freeze remain pending."}, + {"id":"SUBMIT-003","track":"submission","class":"PUBLISHED_HARD","severity":"VETO","description":"README includes Prior Work declaration and required memory/partner notes.","check":"README audit","evidence_required":"merged README","status":"UNVERIFIED","evidence":"Branch README includes explicit Prior Work and memory-path sections; final Base/Virtuals partner notes and submission-window truth freeze remain pending."}, {"id":"SUBMIT-004","track":"submission","class":"PUBLISHED_HARD","severity":"VETO","description":"Two public posts: demo and build log, tagging required accounts.","check":"public URL verification","evidence_required":"two public post URLs","status":"UNVERIFIED"}, - {"id":"BASE-001","track":"base","class":"PUBLISHED_BONUS","severity":"OPTIONAL","description":"Executed Base action shown doing real product work downstream of remembered decision authority.","check":"decision-linked Base Sepolia receipt/explorer evidence","evidence_required":"Engram execution/retrieval/decision provenance + settlement intent + successful matching Base USDC action shown in demo","status":"UNVERIFIED","evidence":"Base settlement adapter, receipt verifier and live verification command are implemented and locally conformant. No real Base Sepolia settlement has been executed for the partner claim yet."}, + {"id":"BASE-001","track":"base","class":"PUBLISHED_BONUS","severity":"OPTIONAL","description":"Executed Base action shown doing real product work downstream of remembered decision authority.","check":"decision-linked Base Sepolia receipt/explorer evidence","evidence_required":"Engram execution/retrieval/decision provenance + serialized settlement intent + expected payer + independently verified Base chain + successful matching Circle USDC action shown in demo","status":"UNVERIFIED","evidence":"Base settlement adapter, schema-bound intent, hardened receipt verifier, live verification command and runbook are locally conformant. No real Base Sepolia settlement has been executed for the partner claim yet."}, {"id":"VIRTUALS-001","track":"virtuals","class":"PUBLISHED_BONUS","severity":"OPTIONAL","description":"Virtuals-native integration is exercised in the demo.","check":"ACP/agent native evidence","evidence_required":"job/transaction/native receipt","status":"UNVERIFIED","evidence":"Server-only adapter normalizes current acp-cli v2 job-history JSON into Engram observations and virtuals:acp:ingest can fetch/ingest a live job. No authenticated ACP job has been executed yet; no multiplier claimed."} ] } From cd939fe0ce8d023e6335a290f2dc5889092609cd Mon Sep 17 00:00:00 2001 From: etvjay Date: Sat, 29 Aug 2026 18:01:33 +0100 Subject: [PATCH 106/116] docs: expose Base causal settlement path to judges --- README.md | 50 ++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 48 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 51f66c5..05714a4 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ The `hackathon/sibyl-ebi` branch contains a dedicated evaluated profile for the The hackathon profile is designed around the deletion test: remove Sibyl and the cross-session memory required to reproduce the claimed behavior disappears. -### Judge call map — write → read → influence → conflict → deletion +### Judge call map — write → read → influence → conflict → consequence → deletion | Judge question | Critical path | |---|---| @@ -26,6 +26,9 @@ The hackathon profile is designed around the deletion test: remove Sibyl and the | Where is the flagship relationship-memory policy? | `packages/scenarios/provider-continuity/src/index.ts`. | | Where is the Sibyl integration pressure suite? | `tests/integration/sibyl-memory-loop.test.ts`, `tests/integration/sibyl-provider-continuity.test.ts`, and `tests/integration/sibyl-competing-memories.test.ts`. | | How do I see process-boundary recall? | `npm run demo:sibyl:provider:seed`, terminate that process, then run `npm run demo:sibyl:provider:urgent` or `npm run demo:sibyl:provider:routine` against the same Sibyl DB/tenant. | +| How does remembered experience become economic authority on Base? | `packages/base-settlement/src/index.ts` converts the Engram provider decision into `engram.base-settlement-intent/v1`; `tests/integration/base-settlement-authority.test.ts` proves urgent recipient and routine prepayment deltas. | +| How is a claimed Base settlement checked against the decision? | `packages/base-settlement/src/evidence.ts` verifies RPC chain, optional expected payer, Circle USDC token, recipient, exact amount and success; `npm run base:settlement:verify` performs live receipt verification. | +| Where is the Virtuals evidence boundary? | `packages/virtuals-acp/` normalizes ACP job history into Engram observations; `npm run virtuals:acp:ingest` is the live-ingest path. No live ACP job is claimed yet. | | How is load-bearing deletion tested? | `npm run test:sibyl:deletion`; it removes the configured Sibyl runtime and must report degradation with no fallback. | | How do I reproduce the complete evidence bundle? | After installing the pinned Sibyl dependency, run `npm run evidence:sibyl:capture`. It uses a fresh Sibyl DB/tenant, separate processes for the behavioral phases, and emits a commit/timestamp/version-stamped `manifest.json` with SHA-256 integrity metadata. | @@ -65,11 +68,54 @@ Two prior requester-owned executions observe Atlas breaching an urgent `data_fet The claim is therefore not “Atlas has a low reputation.” It is: **this agent's attributable experience with Atlas changes the authority Atlas receives in the matching future context.** +### Causal partner path — Virtuals → Sibyl → Base + +The evaluated partner architecture is deliberately relational rather than additive: + +```text +Virtuals/provider execution evidence + ↓ +Engram observation + ↓ +Sibyl relationship memory + ↓ +fresh Engram recall + decision + ↓ +Base settlement authority +``` + +Virtuals supplies real external economic-execution evidence when a live ACP job is eventually exercised. Sibyl is the load-bearing memory substrate. Base is the economic consequence layer downstream of the remembered decision. + +For Base local conformance: + +- urgent memory changes the settlement recipient from Atlas to Beacon; +- routine memory keeps Atlas but changes initial authorized prepayment from `4.000000 USDC` to `0.800000 USDC` and requires milestone verification; +- serialized settlement intents are schema-validated and internally amount-consistent; +- receipt verification fails on the wrong RPC chain, expected payer, token, recipient, amount, or reverted transaction. + +Run: + +```bash +npm run test:base +``` + +For an already executed Base Sepolia transaction, verification is non-custodial and read-only: + +```bash +ENGRAM_BASE_RPC_URL='' \ + npm run base:settlement:verify -- \ + --intent \ + --tx-hash <0x...> \ + --payer +``` + +**Evidence boundary:** Base and Virtuals are currently `LOCAL_CONFORMANCE_PASS / LIVE_UNVERIFIED`. No real Base Sepolia settlement and no authenticated ACP job are claimed by this pre-window branch. Local tests do not earn either partner multiplier. + ### Prior Work declaration Engram's protocol, runtime, execution-memory semantics, CockroachDB production profile, SDK/API/MCP surfaces, causal influence model, and earlier scenarios existed before the Sibyl Labs Hackathon build window. -The Sibyl EBI adapter, pressure harness and provider-continuity work currently present on this branch were also implemented before the official **September 1–10, 2026** build window. If retained for submission, they must be declared as prior work rather than represented as hackathon-window implementation. Final submission evidence must identify the work performed during the official window and regenerate the required fresh-session/deletion proof there. +The Sibyl EBI adapter, pressure harness, provider-continuity work, Virtuals adapter and Base settlement-conformance path currently present on this branch were also implemented before the official **September 1–10, 2026** build window. If retained for submission, they must be declared as prior work rather than represented as hackathon-window implementation. Final submission evidence must identify the work performed during the official window and regenerate the required fresh-session/deletion/partner proof there. Current pre-window evidence is recorded under [`hackathon/sibyl/`](hackathon/sibyl/) and must not be confused with final submission evidence. From 0fa37bcb5e37e7b3618bff7febf4b0e85aedd070 Mon Sep 17 00:00:00 2001 From: etvjay Date: Sat, 29 Aug 2026 18:02:13 +0100 Subject: [PATCH 107/116] feat: emit Base settlement intent from fresh provider decision --- scripts/sibyl-provider-demo.ts | 41 ++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/scripts/sibyl-provider-demo.ts b/scripts/sibyl-provider-demo.ts index 4ee1ccd..ceeb09e 100644 --- a/scripts/sibyl-provider-demo.ts +++ b/scripts/sibyl-provider-demo.ts @@ -1,6 +1,12 @@ +import { mkdir, writeFile } from "node:fs/promises"; +import { dirname, resolve } from "node:path"; import { EngramRuntime } from "../packages/runtime/src/runtime.js"; import { DEFAULT_RUNTIME_POLICIES } from "../packages/runtime/src/defaults.js"; import { SibylRuntimeStore } from "../packages/sibyl/src/runtime-store.js"; +import { + deriveBaseSettlementIntent, + serializeBaseSettlementIntent, +} from "../packages/base-settlement/src/index.js"; import { decideProviderEngagement, executeProviderEngagement, @@ -102,6 +108,34 @@ async function seed(): Promise { }); } +async function maybeWriteBaseIntent(input: { + executionId: string; + retrievalId: string; + treatment: ReturnType; +}): Promise<{ intentPath: string; intent: ReturnType } | undefined> { + const out = process.env.ENGRAM_BASE_INTENT_OUT; + if (!out) return undefined; + + const atlas = process.env.ENGRAM_BASE_ATLAS_ADDRESS; + const beacon = process.env.ENGRAM_BASE_BEACON_ADDRESS; + if (!atlas || !beacon) { + throw new Error("BASE_INTENT_REQUIRES_ENGRAM_BASE_ATLAS_ADDRESS_AND_ENGRAM_BASE_BEACON_ADDRESS"); + } + + const serialized = serializeBaseSettlementIntent(deriveBaseSettlementIntent({ + decision: input.treatment, + addresses: { atlas, beacon }, + provenance: { + executionId: input.executionId, + retrievalId: input.retrievalId, + }, + })); + const intentPath = resolve(out); + await mkdir(dirname(intentPath), { recursive: true }); + await writeFile(intentPath, `${JSON.stringify(serialized, null, 2)}\n`, "utf8"); + return { intentPath, intent: serialized }; +} + async function decide(urgency: "URGENT" | "ROUTINE"): Promise { const store = new SibylRuntimeStore(); const runtime = new EngramRuntime(store, DEFAULT_RUNTIME_POLICIES); @@ -150,6 +184,12 @@ async function decide(urgency: "URGENT" | "ROUTINE"): Promise { }); } + const baseSettlement = await maybeWriteBaseIntent({ + executionId: run.executionId, + retrievalId: recalled.recall.id, + treatment, + }); + emit({ phase: urgency === "URGENT" ? "provider-fresh-urgent" : "provider-fresh-routine", backend: "sibyl-memory-client", @@ -169,6 +209,7 @@ async function decide(urgency: "URGENT" | "ROUTINE"): Promise { }, providerChanged: control.providerId !== treatment.providerId, authorityChanged: JSON.stringify(control.terms) !== JSON.stringify(treatment.terms), + baseSettlement, trace: await runtime.trace(run.executionId), }); } From bd02738a57ebb4bde1bdc68bc5ff475b1bbdad64 Mon Sep 17 00:00:00 2001 From: etvjay Date: Sat, 29 Aug 2026 18:02:34 +0100 Subject: [PATCH 108/116] ci: bind fresh Sibyl decision to Base intent artifact --- .github/workflows/ci.yml | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7033d0d..60a711f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -43,8 +43,21 @@ jobs: run: npm run demo:sibyl:provider:seed - name: Fresh urgent provider decision uses relationship memory run: npm run demo:sibyl:provider:urgent - - name: Fresh routine provider decision narrows authority contextually + - name: Fresh routine provider decision emits Base settlement intent + env: + ENGRAM_BASE_ATLAS_ADDRESS: '0x1111111111111111111111111111111111111111' + ENGRAM_BASE_BEACON_ADDRESS: '0x2222222222222222222222222222222222222222' + ENGRAM_BASE_INTENT_OUT: /tmp/engram-base-routine-intent.json run: npm run demo:sibyl:provider:routine + - name: Verify fresh decision Base intent artifact + run: >- + npx tsx -e "import { readFileSync } from 'node:fs'; + import { parseSerializedBaseSettlementIntent } from './packages/base-settlement/src/index.ts'; + const intent = parseSerializedBaseSettlementIntent(JSON.parse(readFileSync('/tmp/engram-base-routine-intent.json','utf8'))); + if (intent.providerId !== 'atlas') throw new Error('unexpected provider'); + if (intent.terms.authorizedPrepayAtomic !== 800000n) throw new Error('unexpected prepay'); + if (!intent.terms.requireMilestoneVerification) throw new Error('milestone verification not required'); + if (!intent.provenance.retrievalId) throw new Error('missing retrieval provenance');" - name: Remove Sibyl runtime and prove fail-closed degradation run: npm run test:sibyl:deletion - name: Smoke exact evidence capture path From 33ea4e5b66141afc721eb81eb35fbbc58df4384e Mon Sep 17 00:00:00 2001 From: etvjay Date: Sat, 29 Aug 2026 18:04:52 +0100 Subject: [PATCH 109/116] docs: record direct fresh-decision Base intent proof --- packages/base-settlement/README.md | 72 +++++++++++++++++++++--------- 1 file changed, 52 insertions(+), 20 deletions(-) diff --git a/packages/base-settlement/README.md b/packages/base-settlement/README.md index e75b00b..6c97f80 100644 --- a/packages/base-settlement/README.md +++ b/packages/base-settlement/README.md @@ -12,7 +12,8 @@ prior execution evidence -> Sibyl persistence -> fresh Engram recall -> changed provider/terms - -> Base settlement authority + -> serialized Base settlement authority + -> explicit wallet execution -> Base receipt verification ``` @@ -28,21 +29,17 @@ The contract address is pinned only for the evaluated testnet profile and must b ## Causal product role -For the flagship provider-continuity scenario: - ### Urgent work -Without applicable memory, the application selects Atlas. - -With repeated Atlas SLA-breach memory, the fresh decision selects Beacon. +Without applicable memory, the application selects Atlas. With repeated Atlas SLA-breach memory, the fresh decision selects Beacon. -Base therefore receives a **different settlement recipient** downstream of memory. +Base therefore receives a different settlement recipient downstream of memory. ### Routine work Without memory, Atlas receives 50% prepayment authority on an $8 offer: `4.000000 USDC`. With applicable relationship memory, Atlas remains selected but prepayment authority falls to 10%: `0.800000 USDC`, with milestone verification required. -Base therefore receives a **smaller authorized economic action** downstream of memory rather than a decorative transfer. +Base therefore receives a smaller authorized economic action downstream of memory rather than a decorative transfer. ## Local conformance @@ -54,16 +51,43 @@ npm run test:base The local suite proves: -- urgent relationship memory changes the settlement recipient Atlas -> Beacon; +- urgent relationship memory changes settlement recipient Atlas -> Beacon; - routine relationship memory changes authorized prepay `4.000000 -> 0.800000 USDC`; - malformed provider addresses fail closed; -- a receipt is accepted only when it is successful and contains the expected Circle USDC `Transfer`; -- wrong recipient fails; -- wrong amount fails; -- wrong token contract fails; -- reverted transaction fails. +- serialized intents are strict-schema validated; +- serialized atomic/decimal amounts must recompute from max spend and prepay basis points; +- RPC chain must be Base Sepolia `84532` when chain evidence is supplied; +- expected payer may be bound to ERC-20 `Transfer.from`; +- wrong recipient, amount, token, payer, chain, or reverted transaction fails. + +Strongest tested code head: `bd02738a57ebb4bde1bdc68bc5ff475b1bbdad64`. + +- Engram CI `33264580330`: SUCCESS; +- canonical check `99132270601`: SUCCESS; +- full Sibyl profile `99132270544`: SUCCESS; +- SAM Build `33264580331`: SUCCESS. + +Critically, the Sibyl profile now proves the cross-layer boundary directly. A fresh routine provider decision, after persisted relationship-memory recall, emitted a serialized Base settlement intent. CI parsed that artifact and required: + +- provider: Atlas; +- authorized prepayment: `800000` atomic USDC; +- milestone verification: `true`; +- retrieval provenance: present. + +So Base authority is not only tested in isolation; the judged fresh-memory path produces the exact artifact consumed by the live settlement verifier. -The Base tests are also included in canonical `npm run test:all` / `npm run check`. Canonical CI run `33264157362`, check job `99131095748`, passed on code head `266d3c38acc3c70a9533315679d4927108852ba3`. +## Emitting an intent from the fresh provider decision + +Provide provider addresses and an output path when running the fresh decision: + +```bash +ENGRAM_BASE_ATLAS_ADDRESS='' \ +ENGRAM_BASE_BEACON_ADDRESS='' \ +ENGRAM_BASE_INTENT_OUT='artifacts/base/routine-intent.json' \ +npm run demo:sibyl:provider:routine +``` + +The demo writes `engram.base-settlement-intent/v1` directly from the memory-conditioned decision. No manual reconstruction of provider, amount, or retrieval provenance is required. ## Live verification @@ -73,21 +97,29 @@ Once an explicit wallet step has executed the reviewed settlement intent: ENGRAM_BASE_RPC_URL='' \ npm run base:settlement:verify -- \ --intent \ - --tx-hash <0x...> + --tx-hash <0x...> \ + --payer ``` -The verifier calls `eth_getTransactionReceipt` and emits Base evidence only if the observed USDC transfer matches the decision-derived recipient and atomic amount. +The verifier: + +1. strict-parses the serialized intent and recomputes its authorized amount; +2. independently calls `eth_chainId` and requires `84532`; +3. fetches `eth_getTransactionReceipt`; +4. emits Base evidence only if the successful Circle USDC `Transfer` matches expected payer when bound, exact recipient, and exact atomic amount. ## Evidence boundary -`LOCAL_CONFORMANCE_PASS` proves the causal settlement model and fail-closed receipt verifier. It does **not** prove an executed Base transaction and does not earn the partner multiplier. +`LOCAL_CONFORMANCE_PASS` proves the causal settlement model, fresh-decision intent boundary, and fail-closed receipt verifier. It does **not** prove an executed Base transaction and does not earn the partner multiplier. `BASE-001` remains `UNVERIFIED` until a real Base Sepolia action is executed and retained with: +- serialized decision-derived intent; - transaction hash; +- independently observed chain ID; - successful receipt; -- token transfer evidence matching the decision-derived recipient and amount; -- Engram execution/retrieval/decision IDs; +- token transfer evidence matching payer when claimed, recipient and amount; +- Engram execution/retrieval/decision provenance; - demonstration that removing or changing the remembered decision changes the Base action. No private key, wallet secret, or signer material belongs in this package or repository. From 20bbcc1adf101c3a64e843c9d33fc7aca363d28d Mon Sep 17 00:00:00 2001 From: etvjay Date: Sat, 29 Aug 2026 18:05:23 +0100 Subject: [PATCH 110/116] docs: promote direct Sibyl-to-Base artifact evidence --- .../sibyl/requirements/requirements.json | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/hackathon/sibyl/requirements/requirements.json b/hackathon/sibyl/requirements/requirements.json index 6eaf3fc..81773c4 100644 --- a/hackathon/sibyl/requirements/requirements.json +++ b/hackathon/sibyl/requirements/requirements.json @@ -1,23 +1,23 @@ { "verified_at": "2026-08-29", "status": "READY_FOR_LIVE_PRESSURE", - "evidence_note": "Core Sibyl, experiential-provider, evidence-capture and hardened Base local-conformance gates are LOCAL_PASS on strongest tested pre-window code head b6ffe6fcc824c20e8f41f2e64532ada3867c858d: Engram CI 33264345953 and SAM build 33264345950 both succeeded. Base settlement intent is schema/amount bound and receipt verification now checks RPC chain, optional payer, token, recipient, amount and success state. BASE-001 remains UNVERIFIED until a real Base Sepolia action is executed. Virtuals ACP remains LOCAL_CONFORMANCE_PASS / LIVE_ACP_UNVERIFIED. Submission/live-public gates must be re-proven during the official build window.", + "evidence_note": "Core Sibyl, experiential-provider, evidence-capture and hardened Base local-conformance gates are LOCAL_PASS on strongest tested pre-window code head bd02738a57ebb4bde1bdc68bc5ff475b1bbdad64: Engram CI 33264580330 and SAM build 33264580331 both succeeded. The Sibyl profile now directly emits and validates a serialized Base settlement artifact from the fresh memory-conditioned routine decision, closing the manual translation gap. BASE-001 remains UNVERIFIED until a real Base Sepolia action is executed. Virtuals ACP remains LOCAL_CONFORMANCE_PASS / LIVE_ACP_UNVERIFIED. Submission/live-public gates must be re-proven during the official build window.", "requirements": [ - {"id":"SIBYL-GATE-001","track":"main","class":"PUBLISHED_HARD","severity":"VETO","description":"Sibyl Memory is load-bearing; deleting it breaks or materially degrades the core function.","check":"run deletion mutation and compare claimed behavior","evidence_required":"failing/degraded no-Sibyl run plus passing Sibyl run","status":"LOCAL_PASS","evidence":"GitHub Actions run 33264345953 job 99131636029: deletion mutation degraded with no fallback and exact evidence-capture path passed"}, - {"id":"SIBYL-GATE-002","track":"main","class":"PUBLISHED_HARD","severity":"VETO","description":"Fresh session recalls earlier persisted state.","check":"terminate process/session, restart clean, recall prior memory","evidence_required":"continuous demo segment with timestamp or commit hash","status":"LOCAL_PASS","evidence":"GitHub Actions run 33264345953: separate route/provider processes recalled persisted Sibyl memory; conflict test retrieves contradictory memories through a fresh SibylRuntimeStore"}, - {"id":"SIBYL-GATE-003","track":"main","class":"PUBLISHED_HARD","severity":"VETO","description":"Recalled memory changes a decision, action, or result.","check":"paired memory vs no-memory decision comparison","evidence_required":"decision trace and observable action delta","status":"LOCAL_PASS","evidence":"Run 33264345953: route A-B-C -> A-B-D; urgent provider Atlas -> Beacon with CHANGED_ACTION; routine Atlas terms constrained with CONSTRAINED_ACTION"}, - {"id":"SIBYL-GATE-004","track":"main","class":"PUBLISHED_HARD","severity":"HIGH","description":"README exposes critical memory write/read paths in under two minutes.","check":"cold reviewer repo navigation test","evidence_required":"README call map","status":"LOCAL_PASS","evidence":"Root README on hackathon/sibyl-ebi exposes store wiring, write/read, recall-state binding, influence, contradiction, provider scenario, process-boundary demo, deletion and evidence capture. Human cold-review timing remains pending."}, - {"id":"SCORE-MEM-001","track":"main","class":"PUBLISHED_SCORING","severity":"HIGH","description":"Memory use is sophisticated enough for top band; coordination/dynamic-state behavior preferred.","check":"judge-model scorecard","evidence_required":"non-trivial stateful scenario plus adversarial memory handling","status":"LOCAL_PASS","evidence":"Sibyl profile: multi-execution experiential relationship memory changes urgent delegation and routine authority; expiry, post-recall tamper and unresolved-contradiction controls pass. Final evaluator score remains future."}, - {"id":"SCORE-TECH-001","track":"main","class":"PUBLISHED_SCORING","severity":"HIGH","description":"Build is clean, robust and survives a second run/curious judge.","check":"repeatability and negative test suite","evidence_required":"test report and second-run evidence","status":"LOCAL_PASS","evidence":"Head b6ffe6fc: Engram CI 33264345953 and SAM Build 33264345950 succeeded, including exact evidence-capture smoke and hardened Base tests"}, + {"id":"SIBYL-GATE-001","track":"main","class":"PUBLISHED_HARD","severity":"VETO","description":"Sibyl Memory is load-bearing; deleting it breaks or materially degrades the core function.","check":"run deletion mutation and compare claimed behavior","evidence_required":"failing/degraded no-Sibyl run plus passing Sibyl run","status":"LOCAL_PASS","evidence":"GitHub Actions run 33264580330 job 99132270544: deletion mutation degraded with no fallback and exact evidence-capture path passed"}, + {"id":"SIBYL-GATE-002","track":"main","class":"PUBLISHED_HARD","severity":"VETO","description":"Fresh session recalls earlier persisted state.","check":"terminate process/session, restart clean, recall prior memory","evidence_required":"continuous demo segment with timestamp or commit hash","status":"LOCAL_PASS","evidence":"GitHub Actions run 33264580330: separate route/provider processes recalled persisted Sibyl memory; conflict test retrieves contradictory memories through a fresh SibylRuntimeStore"}, + {"id":"SIBYL-GATE-003","track":"main","class":"PUBLISHED_HARD","severity":"VETO","description":"Recalled memory changes a decision, action, or result.","check":"paired memory vs no-memory decision comparison","evidence_required":"decision trace and observable action delta","status":"LOCAL_PASS","evidence":"Run 33264580330: route A-B-C -> A-B-D; urgent provider Atlas -> Beacon with CHANGED_ACTION; routine Atlas terms constrained with CONSTRAINED_ACTION"}, + {"id":"SIBYL-GATE-004","track":"main","class":"PUBLISHED_HARD","severity":"HIGH","description":"README exposes critical memory write/read paths in under two minutes.","check":"cold reviewer repo navigation test","evidence_required":"README call map","status":"LOCAL_PASS","evidence":"Root README exposes Sibyl store/write/read/influence/conflict/deletion/evidence paths plus Base intent/verifier and Virtuals evidence boundary. Human cold-review timing remains pending."}, + {"id":"SCORE-MEM-001","track":"main","class":"PUBLISHED_SCORING","severity":"HIGH","description":"Memory use is sophisticated enough for top band; coordination/dynamic-state behavior preferred.","check":"judge-model scorecard","evidence_required":"non-trivial stateful scenario plus adversarial memory handling","status":"LOCAL_PASS","evidence":"Multi-execution experiential relationship memory changes urgent delegation and routine authority; expiry, post-recall tamper and unresolved-contradiction controls pass. Final evaluator score remains future."}, + {"id":"SCORE-TECH-001","track":"main","class":"PUBLISHED_SCORING","severity":"HIGH","description":"Build is clean, robust and survives a second run/curious judge.","check":"repeatability and negative test suite","evidence_required":"test report and second-run evidence","status":"LOCAL_PASS","evidence":"Head bd02738a: Engram CI 33264580330 and SAM Build 33264580331 succeeded, including exact evidence-capture smoke, hardened Base tests and fresh-decision Base artifact check"}, {"id":"EXP-CONT-001","track":"main","class":"INTERNAL_ACCEPTANCE","severity":"HIGH","description":"Multiple attributable executions may form bounded relationship state only with sufficient lineage.","check":"multi-source provider history test","evidence_required":"two historical executions + admitting execution + relationship memory lineage","status":"LOCAL_PASS","evidence":"Two Atlas breach executions plus admitting execution produce CONTEXT_GUARDED relationship memory; one-breach and cross-task controls remain baseline"}, {"id":"EXP-CONT-002","track":"main","class":"INTERNAL_ACCEPTANCE","severity":"HIGH","description":"Relationship state changes behavior contextually rather than becoming a global provider blacklist.","check":"urgent vs routine paired decisions","evidence_required":"urgent provider change plus routine authority narrowing using same memory","status":"LOCAL_PASS","evidence":"Urgent Atlas -> Beacon; routine stays Atlas while prepay 5000 -> 1000 bps and milestone verification false -> true"}, {"id":"EXP-CONT-003","track":"main","class":"INTERNAL_ACCEPTANCE","severity":"HIGH","description":"Retrieval ranking must not silently adjudicate explicit contradictory memories.","check":"persist contradictory memories through Sibyl, fresh-recall both, attempt influence before and after explicit resolution","evidence_required":"both memories recall-visible; unresolved influence rejected; explicit supersession required before resolved influence","status":"LOCAL_PASS","evidence":"sibyl-competing-memories.test.ts rejects unresolved influence with UNRESOLVED_MEMORY_CONTRADICTION and accepts the resolved side only after SUPERSEDES evidence"}, - {"id":"BASE-CONF-001","track":"base","class":"INTERNAL_ACCEPTANCE","severity":"HIGH","description":"Engram memory-conditioned provider decisions deterministically change Base settlement authority and receipt verification fails closed on divergent onchain evidence.","check":"run test:base and canonical check","evidence_required":"recipient/amount delta, serialized-intent integrity, wrong-chain/wrong-payer/wrong-recipient/wrong-amount/wrong-token/revert mutations","status":"LOCAL_PASS","evidence":"Canonical CI run 33264345953 check job 99131636110 passed on head b6ffe6fc; urgent changes recipient Atlas -> Beacon; routine changes prepay 4.000000 -> 0.800000 USDC; serialized intent rejects inconsistent values; verifier rejects wrong RPC chain, payer, recipient, amount, token and reverted transactions."}, + {"id":"BASE-CONF-001","track":"base","class":"INTERNAL_ACCEPTANCE","severity":"HIGH","description":"Engram memory-conditioned provider decisions deterministically change Base settlement authority, fresh Sibyl decisions emit the serialized settlement artifact, and receipt verification fails closed on divergent onchain evidence.","check":"run test:base, canonical check and Sibyl profile fresh-decision intent gate","evidence_required":"recipient/amount delta, direct fresh-decision artifact, retrieval provenance, serialized-intent integrity, wrong-chain/wrong-payer/wrong-recipient/wrong-amount/wrong-token/revert mutations","status":"LOCAL_PASS","evidence":"CI 33264580330: check job 99132270601 passed Base pressure; Sibyl job 99132270544 emitted and parsed the routine Base intent directly from fresh recall, requiring Atlas, 800000 atomic USDC, milestone verification and retrieval provenance."}, {"id":"SUBMIT-001","track":"submission","class":"PUBLISHED_HARD","severity":"VETO","description":"Public MIT/Apache-2.0 repo with real commit history.","check":"repository inspection","evidence_required":"public repo/license/commits","status":"LOCAL_PASS"}, {"id":"SUBMIT-002","track":"submission","class":"PUBLISHED_HARD","severity":"VETO","description":"2–5 minute demo includes fresh-session recall.","check":"video review","evidence_required":"public video","status":"UNVERIFIED"}, - {"id":"SUBMIT-003","track":"submission","class":"PUBLISHED_HARD","severity":"VETO","description":"README includes Prior Work declaration and required memory/partner notes.","check":"README audit","evidence_required":"merged README","status":"UNVERIFIED","evidence":"Branch README includes explicit Prior Work and memory-path sections; final Base/Virtuals partner notes and submission-window truth freeze remain pending."}, + {"id":"SUBMIT-003","track":"submission","class":"PUBLISHED_HARD","severity":"VETO","description":"README includes Prior Work declaration and required memory/partner notes.","check":"README audit","evidence_required":"merged README","status":"UNVERIFIED","evidence":"Branch README includes Prior Work, memory paths and Base/Virtuals local-vs-live boundaries; final submission-window truth freeze remains pending."}, {"id":"SUBMIT-004","track":"submission","class":"PUBLISHED_HARD","severity":"VETO","description":"Two public posts: demo and build log, tagging required accounts.","check":"public URL verification","evidence_required":"two public post URLs","status":"UNVERIFIED"}, - {"id":"BASE-001","track":"base","class":"PUBLISHED_BONUS","severity":"OPTIONAL","description":"Executed Base action shown doing real product work downstream of remembered decision authority.","check":"decision-linked Base Sepolia receipt/explorer evidence","evidence_required":"Engram execution/retrieval/decision provenance + serialized settlement intent + expected payer + independently verified Base chain + successful matching Circle USDC action shown in demo","status":"UNVERIFIED","evidence":"Base settlement adapter, schema-bound intent, hardened receipt verifier, live verification command and runbook are locally conformant. No real Base Sepolia settlement has been executed for the partner claim yet."}, + {"id":"BASE-001","track":"base","class":"PUBLISHED_BONUS","severity":"OPTIONAL","description":"Executed Base action shown doing real product work downstream of remembered decision authority.","check":"decision-linked Base Sepolia receipt/explorer evidence","evidence_required":"Engram execution/retrieval/decision provenance + serialized settlement intent + expected payer + independently verified Base chain + successful matching Circle USDC action shown in demo","status":"UNVERIFIED","evidence":"Fresh Sibyl decision -> serialized Base intent and hardened verification are locally conformant. No real Base Sepolia settlement has been executed for the partner claim yet."}, {"id":"VIRTUALS-001","track":"virtuals","class":"PUBLISHED_BONUS","severity":"OPTIONAL","description":"Virtuals-native integration is exercised in the demo.","check":"ACP/agent native evidence","evidence_required":"job/transaction/native receipt","status":"UNVERIFIED","evidence":"Server-only adapter normalizes current acp-cli v2 job-history JSON into Engram observations and virtuals:acp:ingest can fetch/ingest a live job. No authenticated ACP job has been executed yet; no multiplier claimed."} ] } From 113b3cce00be578ed1b9642e90298d8b61efb682 Mon Sep 17 00:00:00 2001 From: etvjay Date: Sat, 29 Aug 2026 18:05:53 +0100 Subject: [PATCH 111/116] docs: promote direct fresh-decision Base artifact baseline --- hackathon/sibyl/templates/EVIDENCE_LEDGER.md | 71 +++++++++++--------- 1 file changed, 38 insertions(+), 33 deletions(-) diff --git a/hackathon/sibyl/templates/EVIDENCE_LEDGER.md b/hackathon/sibyl/templates/EVIDENCE_LEDGER.md index f5edf67..73c4559 100644 --- a/hackathon/sibyl/templates/EVIDENCE_LEDGER.md +++ b/hackathon/sibyl/templates/EVIDENCE_LEDGER.md @@ -7,27 +7,28 @@ Allowed states: | Claim / gate | State | Evidence | Negative mutation | Notes | |---|---|---|---|---| -| Sibyl persists decision-critical memory | LOCAL_PASS | GitHub Actions run `33264345953`, job `99131636029`, branch head `b6ffe6fcc824c20e8f41f2e64532ada3867c858d`: SDK 0.6.1 installed; route/provider/conflict memories persisted through Sibyl | missing Sibyl runtime | Pre-build-window evidence; must be re-run during official window | -| Fresh session/process recalls prior memory | LOCAL_PASS | run `33264345953`: separate seed and recall processes; route memory plus provider relationship memory recalled in later processes; conflict test creates a fresh `SibylRuntimeStore` before retrieving both contradictory memories | terminate source process / unavailable Sibyl | Stronger than fresh-object-only proof | -| Recalled memory changes action | LOCAL_PASS | run `33264345953`: route `A-B-C -> A-B-D`; urgent provider `atlas -> beacon`; explicit `CHANGED_ACTION` traces | no-memory control | Paired behavioral deltas, not retrieval-only | -| Recalled memory constrains authority without global blacklist | LOCAL_PASS | run `33264345953`, fresh routine provider process: Atlas remains selected while prepay falls `5000 -> 1000` bps and milestone verification becomes required; trace records `CONSTRAINED_ACTION` | routine-context control | Demonstrates contextual relationship posture rather than global reputation | -| Multi-execution experience becomes bounded relationship memory | LOCAL_PASS | run `33264345953`: two historical Atlas breach executions plus admitting execution produced `CONTEXT_GUARDED` relationship memory | single-failure fixture / cross-task fixture | Pure scenario tests also require >=2 source executions and task-type applicability | -| Urgent provider experience changes outcome | LOCAL_PASS | run `33264345953`: no-memory Atlas path deterministically returns `SLA_BREACH`; memory-conditioned Beacon path returns `SUCCESS` | no-memory provider control | Application fixture, not a claim about a live provider network | -| Deleting/unavailable Sibyl breaks/degrades core function | LOCAL_PASS | run `33264345953`: deletion CLI emitted degradation with no fallback | remove/disable Sibyl runtime | VETO; mutation harness fails if Sibyl unexpectedly stays available | -| Engram provenance remains reconstructable | LOCAL_PASS | run `33264345953`: recall IDs, memory IDs, `engram.memory-state/v1` digests, counterfactuals, accepted influence and evaluation events appear in route/provider traces | post-recall memory tamper | Sibyl backend preserves trace material needed for influence validation | -| Expired Sibyl memory is retrieved but blocked before exposure | LOCAL_PASS | run `33264345953`, `npm run test:sibyl` | expired memory fixture | Demonstrates retrieval != legitimate influence | -| Post-recall memory tamper is rejected | LOCAL_PASS | run `33264345953`, `npm run test:sibyl` | overwrite memory after digest exposure | Protects recall-to-decision state integrity | -| Conflicting memory remains non-silently adjudicated through Sibyl store | LOCAL_PASS | run `33264345953`, job `99131636029`: contradictory memories remain recall-visible, unresolved influence is rejected, explicit `SUPERSEDES` resolves the relevant side | unresolved `CONTRADICTS` pair | Proves Sibyl persistence/retrieval does not silently turn ranking into adjudication | -| Expanded Sibyl pressure suite | LOCAL_PASS | run `33264345953`, job `99131636029`: `3` test files / `7` tests passed, followed by route/provider/deletion process-boundary proof | expiry, tamper, contradiction, deletion, single-failure/cross-task controls | Same evaluated profile remains repeatable on clean hosted runners | -| Self-verifying evidence capture path | LOCAL_PASS | run `33264345953`, job `99131636029`: exact evidence capture and manifest check passed on head `b6ffe6fc` | dirty source / unexpected untracked file; failed precursor run `33232299952` | Capture v2 records git/source state, environment versions, dependency digests, output SHA-256 values and final Sibyl DB digest | -| Base settlement authority follows Engram memory-conditioned decision | LOCAL_PASS | run `33264345953`, check job `99131636110`: canonical `npm run check` includes `test:base`; urgent memory changes recipient Atlas -> Beacon, routine memory changes authorized prepay `4.000000 -> 0.800000 USDC` | no-memory decision / malformed address | This is local causal-model evidence, not an executed Base transaction | -| Base serialized intent is internally bound | LOCAL_PASS | run `33264345953`, check job `99131636110`: serialized intent schema fixes network/token/provider/address/provenance fields and rejects inconsistent atomic/decimal prepay values | malformed schema, wrong chain, inconsistent amount | Removes unsafe-cast ambiguity from the live verifier input | -| Base receipt verification fails closed | LOCAL_PASS | run `33264345953`, check job `99131636110`: receipt verifier rejects wrong RPC chain, wrong payer, wrong recipient, wrong amount, wrong token, and reverted transaction | chain/payer/recipient/amount/token/status mutations | Live verifier independently calls `eth_chainId`; receipt evidence still requires real official-window transaction for partner promotion | -| Canonical Engram suite remains green with Sibyl + Base evaluated profiles | LOCAL_PASS | run `33264345953`, check job `99131636110`: `npm run check` passed; SAM build run `33264345950` also passed | canonical test suite | Strongest tested code head `b6ffe6fcc824c20e8f41f2e64532ada3867c858d` | -| Root README exposes critical write/read/influence/conflict/deletion/evidence call map | LOCAL_PASS | root README on `hackathon/sibyl-ebi` exposes core judged paths plus one-command capture | cold reviewer navigation | Base call-map synchronization is being added after the tested code head; human under-two-minute timing remains pending | +| Sibyl persists decision-critical memory | LOCAL_PASS | GitHub Actions run `33264580330`, job `99132270544`, branch head `bd02738a57ebb4bde1bdc68bc5ff475b1bbdad64`: SDK 0.6.1 installed; route/provider/conflict memories persisted through Sibyl | missing Sibyl runtime | Pre-build-window evidence; must be re-run during official window | +| Fresh session/process recalls prior memory | LOCAL_PASS | run `33264580330`: separate seed and recall processes; route and provider relationship memory recalled in later processes; conflict test uses a fresh `SibylRuntimeStore` | terminate source process / unavailable Sibyl | Stronger than fresh-object-only proof | +| Recalled memory changes action | LOCAL_PASS | run `33264580330`: route `A-B-C -> A-B-D`; urgent provider `atlas -> beacon`; explicit `CHANGED_ACTION` traces | no-memory control | Paired behavioral deltas, not retrieval-only | +| Recalled memory constrains authority without global blacklist | LOCAL_PASS | run `33264580330`: fresh routine provider process keeps Atlas while prepay falls `5000 -> 1000` bps and milestone verification becomes required | routine-context control | Demonstrates contextual relationship posture rather than global reputation | +| Multi-execution experience becomes bounded relationship memory | LOCAL_PASS | run `33264580330`: two historical Atlas breach executions plus admitting execution produced `CONTEXT_GUARDED` relationship memory | single-failure fixture / cross-task fixture | Requires attributable lineage, not one bad event | +| Urgent provider experience changes outcome | LOCAL_PASS | run `33264580330`: no-memory Atlas path returns deterministic `SLA_BREACH`; memory-conditioned Beacon path returns `SUCCESS` | no-memory provider control | Application fixture, not a live provider-network claim | +| Deleting/unavailable Sibyl breaks/degrades core function | LOCAL_PASS | run `33264580330`: deletion CLI emitted degradation with no fallback | remove/disable Sibyl runtime | VETO | +| Engram provenance remains reconstructable | LOCAL_PASS | run `33264580330`: recall IDs, memory IDs, memory-state digests, counterfactuals, accepted influence and evaluation events remain in traces | post-recall memory tamper | Preserves recall-to-action lineage | +| Expired Sibyl memory is retrieved but blocked before exposure | LOCAL_PASS | run `33264580330`, `npm run test:sibyl` | expired memory fixture | Retrieval != legitimate influence | +| Post-recall memory tamper is rejected | LOCAL_PASS | run `33264580330`, `npm run test:sibyl` | overwrite memory after digest exposure | Protects recall-to-decision state integrity | +| Conflicting memory remains non-silently adjudicated | LOCAL_PASS | run `33264580330`, job `99132270544`: contradictory memories remain recall-visible, unresolved influence is rejected, explicit `SUPERSEDES` resolves the relevant side | unresolved `CONTRADICTS` pair | Ranking cannot silently become authority | +| Expanded Sibyl pressure suite | LOCAL_PASS | run `33264580330`, job `99132270544`: 3 test files / 7 tests passed, followed by route/provider/deletion process-boundary proof | expiry, tamper, contradiction, deletion, single-failure/cross-task controls | Repeatable on hosted runner | +| Self-verifying evidence capture path | LOCAL_PASS | run `33264580330`, job `99132270544`: exact evidence capture and manifest check passed | dirty source / unexpected untracked file; failed precursor run `33232299952` | Capture records git/source state, runtime/dependency digests, output hashes and final Sibyl DB digest | +| Base settlement authority follows Engram memory-conditioned decision | LOCAL_PASS | run `33264580330`, check job `99132270601`: urgent memory changes recipient Atlas -> Beacon; routine changes authorized prepay `4.000000 -> 0.800000 USDC` | no-memory decision / malformed address | Local causal-model evidence, not a live Base transaction | +| Fresh Sibyl decision emits exact Base authority artifact | LOCAL_PASS | run `33264580330`, Sibyl job `99132270544`: fresh routine recall wrote serialized Base intent; follow-up gate parsed it as Atlas + `800000` atomic USDC + milestone verification + retrieval provenance | omit provider addresses / malformed artifact | Closes manual translation gap between memory-conditioned decision and settlement artifact | +| Base serialized intent is internally bound | LOCAL_PASS | run `33264580330`, check job `99132270601`: strict schema fixes network/token/provider/address/provenance and rejects inconsistent atomic/decimal values | malformed schema, wrong chain, inconsistent amount | Removes unsafe JSON-cast ambiguity | +| Base receipt verification fails closed | LOCAL_PASS | run `33264580330`, check job `99132270601`: rejects wrong RPC chain, payer, recipient, amount, token and reverted transaction | chain/payer/recipient/amount/token/status mutations | Live verifier independently calls `eth_chainId` | +| Canonical Engram suite remains green with Sibyl + Base evaluated profiles | LOCAL_PASS | run `33264580330`, check job `99132270601`; SAM run `33264580331` | canonical test suite | Strongest tested code head `bd02738a57ebb4bde1bdc68bc5ff475b1bbdad64` | +| Root README exposes judged memory and partner call map | LOCAL_PASS | branch README exposes Sibyl write/read/influence/conflict/deletion/evidence, Base intent/verifier and Virtuals evidence boundary | cold reviewer navigation | Human under-two-minute timing remains pending; not `PUBLIC_EVALUATOR_PASS` | | Hackathon-window rerun of core proof | UNVERIFIED | — | clean clone + fresh DB | Pre-window proof cannot substitute for final event-window evidence | -| Base integration does real product work onchain | UNVERIFIED | settlement authority adapter, hardened verifier and live runbook exist; no real Base Sepolia settlement yet | remove Base action / mismatch settlement | `BASE-001` partner claim remains unearned until a decision-linked action is executed and verified | -| Virtuals integration does real product work | UNVERIFIED | adapter/conformance/live-ingest path implemented; local conformance passed; no authenticated ACP job yet | remove Virtuals interaction | partner multiplier remains unclaimed | +| Base integration does real product work onchain | UNVERIFIED | decision-derived intent + hardened verifier + live runbook exist; no real Base Sepolia settlement yet | remove Base action / mismatch settlement | `BASE-001` remains unearned | +| Virtuals integration does real product work | UNVERIFIED | adapter/conformance/live-ingest path implemented; no authenticated ACP job yet | remove Virtuals interaction | partner multiplier remains unclaimed | ## Current flagship interpretation The strongest current memory claim is not `the agent remembers Atlas is bad`. @@ -42,30 +43,34 @@ The adversarial corollary is equally important: > Retrieval rank is not adjudication. If two persisted memories explicitly contradict each other, Engram may expose both but refuses to let either silently become authority until relationship evidence resolves the conflict. -The economic consequence is now explicit at local conformance level: +The economic consequence is now directly connected at local conformance level: -> The same remembered relationship posture can change who is authorized to receive a Base settlement for urgent work, or reduce how much USDC the same provider is authorized to receive upfront for routine work. A Base receipt is accepted only when chain, payer when bound, token, recipient, amount and success state agree with the serialized Engram settlement intent. +> The fresh Sibyl-backed routine decision itself can emit the Base settlement artifact authorizing only `0.800000 USDC` upfront to Atlas, with retrieval provenance retained. There is no manual re-entry of the remembered decision between memory and settlement intent. + +A claimed Base receipt is accepted only when serialized intent, RPC chain, payer when bound, token, recipient, amount and success state agree. ## Evidence-history note Run `32753747711` remains an earlier pre-window baseline for the original six-test profile. -Head `8f616545...` / run `33221823993` added the Sibyl-backed contradiction gate and passed 7/7 Sibyl tests. +Head `8f616545...` / run `33221823993` added the Sibyl-backed contradiction gate. -The first exact capture-smoke run on head `45806957...`, CI `33232299952`, intentionally surfaced an evidence-harness failure after every product/Sibyl phase passed: `npm install` generated an untracked `package-lock.json`, which the first strict source-tree guard treated as unexpected dirtiness. That run is retained as a failed harness attempt, not a product failure. +The first exact capture-smoke run on head `45806957...`, CI `33232299952`, surfaced an evidence-harness failure after product/Sibyl phases passed: generated `package-lock.json` was treated as unexpected dirtiness. This is retained as harness-debug evidence, not hidden. -Head `afb3ac37...` / run `33232373531` corrected and proved the exact self-verifying evidence-capture path. +Head `afb3ac37...` / run `33232373531` corrected and proved the self-verifying evidence-capture path. -Head `266d3c38...` / run `33264157362` added the first Base settlement-authority and receipt-verification local conformance while keeping the complete Sibyl profile green. +Head `266d3c38...` / run `33264157362` added first Base settlement-authority/receipt local conformance while preserving Sibyl. -The current strongest tested pre-window code baseline is branch head `b6ffe6fcc824c20e8f41f2e64532ada3867c858d`: -- Engram CI `33264345953`: SUCCESS -- Sibyl profile job `99131636029`: SUCCESS, including deletion, exact evidence-capture smoke and manifest check -- canonical check job `99131636110`: SUCCESS, including hardened Base schema/chain/payer/receipt pressure -- Engram SAM Build `33264345950`: SUCCESS +Head `b6ffe6fc...` / run `33264345953` hardened Base serialized-intent, chain and payer verification. -The hardened Base verifier schema-validates serialized settlement intent, recomputes amount consistency, independently verifies RPC chain ID `84532`, and may bind ERC-20 `Transfer.from` to the expected requester wallet before accepting recipient/amount evidence. +The current strongest tested pre-window code baseline is `bd02738a57ebb4bde1bdc68bc5ff475b1bbdad64`: +- Engram CI `33264580330`: SUCCESS +- canonical check job `99132270601`: SUCCESS +- Sibyl profile job `99132270544`: SUCCESS +- fresh routine decision -> Base serialized-intent gate: SUCCESS +- deletion + exact evidence-capture smoke + manifest check: SUCCESS +- Engram SAM Build `33264580331`: SUCCESS -A green run proves only the commit/run it actually executed. Later documentation commits may record that evidence but do not strengthen it. +Later documentation commits record this evidence but do not strengthen it. Every promotion above `LOCAL_PASS` must point to the exact hackathon-window artifact/run that supports it. From 026f70a08e4051cff1644aad19087411d3d0863b Mon Sep 17 00:00:00 2001 From: etvjay Date: Sun, 30 Aug 2026 12:56:43 +0100 Subject: [PATCH 112/116] feat: bind Base settlement intent into Sibyl evidence capture --- scripts/sibyl-evidence-capture.ts | 69 ++++++++++++++++++++++++++++--- 1 file changed, 64 insertions(+), 5 deletions(-) diff --git a/scripts/sibyl-evidence-capture.ts b/scripts/sibyl-evidence-capture.ts index 249d0d1..b29ffac 100644 --- a/scripts/sibyl-evidence-capture.ts +++ b/scripts/sibyl-evidence-capture.ts @@ -32,9 +32,21 @@ async function sha256File(path: string): Promise { } } +async function readJsonObject(path: string): Promise | null> { + try { + const parsed = JSON.parse(await readFile(path, "utf8")) as unknown; + return parsed && typeof parsed === "object" && !Array.isArray(parsed) + ? parsed as Record + : null; + } catch { + return null; + } +} + type Step = { id: string; args: string[]; + env?: Record; }; type StepReceipt = { @@ -80,17 +92,33 @@ const outputDir = resolve( process.env.ENGRAM_EVIDENCE_DIR ?? `artifacts/sibyl-evidence/${stamp}-${head.slice(0, 12)}`, ); const dbPath = resolve(outputDir, "sibyl-evidence.db"); +const baseRoutineIntentPath = resolve(outputDir, "base-routine-intent.json"); const tenant = process.env.ENGRAM_SIBYL_TENANT ?? `engram-evidence-${stamp}`; const python = process.env.ENGRAM_SIBYL_PYTHON ?? "python3"; +// Deterministic non-secret addresses used only to bind the local evidence +// artifact. Official-window live execution must replace these with reviewed +// Base Sepolia requester/provider addresses before any wallet action. +const evidenceAtlasAddress = "0x1111111111111111111111111111111111111111"; +const evidenceBeaconAddress = "0x2222222222222222222222222222222222222222"; + const steps: Step[] = [ { id: "sibyl-pressure-suite", args: ["run", "test:sibyl"] }, + { id: "base-conformance-suite", args: ["run", "test:base"] }, { id: "route-seed", args: ["run", "demo:sibyl:seed"] }, { id: "route-fresh-recall", args: ["run", "demo:sibyl:recall"] }, { id: "route-no-memory-control", args: ["run", "demo:sibyl:no-memory-control"] }, { id: "provider-history", args: ["run", "demo:sibyl:provider:seed"] }, { id: "provider-fresh-urgent", args: ["run", "demo:sibyl:provider:urgent"] }, - { id: "provider-fresh-routine", args: ["run", "demo:sibyl:provider:routine"] }, + { + id: "provider-fresh-routine-base-intent", + args: ["run", "demo:sibyl:provider:routine"], + env: { + ENGRAM_BASE_INTENT_OUT: baseRoutineIntentPath, + ENGRAM_BASE_ATLAS_ADDRESS: evidenceAtlasAddress, + ENGRAM_BASE_BEACON_ADDRESS: evidenceBeaconAddress, + }, + }, { id: "sibyl-deletion-mutation", args: ["run", "test:sibyl:deletion"] }, ]; @@ -109,7 +137,7 @@ for (const step of steps) { const startedAt = new Date(); const result = spawnSync("npm", step.args, { encoding: "utf8", - env: baseEnv, + env: { ...baseEnv, ...step.env }, cwd: process.cwd(), }); const completedAt = new Date(); @@ -138,13 +166,32 @@ for (const step of steps) { } } +const baseRoutineIntent = await readJsonObject(baseRoutineIntentPath); +if (!failed) { + const terms = baseRoutineIntent?.terms as Record | undefined; + const provenance = baseRoutineIntent?.provenance as Record | undefined; + const memoryRefs = baseRoutineIntent?.memoryRefs; + const validBaseIntent = baseRoutineIntent?.schema === "engram.base-settlement-intent/v1" + && baseRoutineIntent?.chainId === 84532 + && baseRoutineIntent?.providerId === "atlas" + && baseRoutineIntent?.recipient === evidenceAtlasAddress + && terms?.authorizedPrepayAtomic === "800000" + && terms?.requireMilestoneVerification === true + && typeof provenance?.executionId === "string" + && typeof provenance?.retrievalId === "string" + && Array.isArray(memoryRefs) + && memoryRefs.length > 0; + if (!validBaseIntent) failed = true; +} + const packageJsonPath = resolve(process.cwd(), "package.json"); const packageLockPath = resolve(process.cwd(), "package-lock.json"); const sibylRequirementsPath = resolve(process.cwd(), "packages/sibyl/requirements.txt"); const dbSha256 = await sha256File(dbPath); +const baseRoutineIntentSha256 = await sha256File(baseRoutineIntentPath); const manifest = { - schema: "engram.sibyl-evidence-capture/v2", + schema: "engram.sibyl-evidence-capture/v3", capturedAt: capturedAt.toISOString(), repository: commandOutput("git", ["remote", "get-url", "origin"]), gitHead: head, @@ -175,9 +222,21 @@ const manifest = { }, dbFile: "sibyl-evidence.db", dbSha256, + baseSettlementIntent: baseRoutineIntent ? { + file: "base-routine-intent.json", + sha256: baseRoutineIntentSha256, + schema: baseRoutineIntent.schema, + chainId: baseRoutineIntent.chainId, + providerId: baseRoutineIntent.providerId, + recipient: baseRoutineIntent.recipient, + terms: baseRoutineIntent.terms, + provenance: baseRoutineIntent.provenance, + memoryRefs: baseRoutineIntent.memoryRefs, + liveExecutionBoundary: "This artifact binds memory-conditioned authority only. The deterministic addresses are not live partner addresses and no transaction is executed by evidence capture.", + } : null, status: failed ? "FAILED" : "LOCAL_PASS", - evidenceBoundary: "This capture is local/CI evidence unless the surrounding run is itself an eligible public evaluator or live partner execution.", - integrityNote: "SHA-256 values bind retained stdout/stderr, dependency manifests/setup lockfile when present, and the final Sibyl database to this manifest. The manifest itself is the root receipt and should be retained with the artifact.", + evidenceBoundary: "This capture is local/CI evidence unless the surrounding run is itself an eligible public evaluator or live partner execution. The retained Base intent is decision-authority evidence only; it is not a Base transaction receipt.", + integrityNote: "SHA-256 values bind retained stdout/stderr, dependency manifests/setup lockfile when present, the final Sibyl database, and the memory-conditioned Base settlement intent to this manifest. The manifest itself is the root receipt and should be retained with the artifact.", steps: receipts, }; From a7f6622e4917403f69d740b9324e89349dac0340 Mon Sep 17 00:00:00 2001 From: etvjay Date: Sun, 30 Aug 2026 12:57:14 +0100 Subject: [PATCH 113/116] ci: verify Base intent is retained in evidence manifest --- .github/workflows/ci.yml | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 60a711f..1899aa1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -64,5 +64,15 @@ jobs: env: ENGRAM_EVIDENCE_DIR: /tmp/engram-sibyl-evidence-smoke run: npm run evidence:sibyl:capture - - name: Verify evidence manifest exists - run: test -s /tmp/engram-sibyl-evidence-smoke/manifest.json + - name: Verify evidence manifest retains Base authority artifact + run: >- + npx tsx -e "import { readFileSync, existsSync } from 'node:fs'; + const p='/tmp/engram-sibyl-evidence-smoke/manifest.json'; + if (!existsSync(p)) throw new Error('manifest missing'); + const m=JSON.parse(readFileSync(p,'utf8')); + if (m.schema !== 'engram.sibyl-evidence-capture/v3') throw new Error('unexpected manifest schema'); + if (m.status !== 'LOCAL_PASS') throw new Error('capture did not pass'); + if (!m.baseSettlementIntent?.sha256) throw new Error('base intent digest missing'); + if (m.baseSettlementIntent?.terms?.authorizedPrepayAtomic !== '800000') throw new Error('base intent amount mismatch'); + if (!m.baseSettlementIntent?.provenance?.retrievalId) throw new Error('base retrieval provenance missing'); + if (!existsSync('/tmp/engram-sibyl-evidence-smoke/base-routine-intent.json')) throw new Error('base intent artifact missing');" From b2e0f5baeb61b2dd3992a7b3166636144aa2fe5b Mon Sep 17 00:00:00 2001 From: etvjay Date: Sun, 30 Aug 2026 12:57:34 +0100 Subject: [PATCH 114/116] ci: validate captured Base authority artifact before upload --- .github/workflows/sibyl-evidence-capture.yml | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/.github/workflows/sibyl-evidence-capture.yml b/.github/workflows/sibyl-evidence-capture.yml index dae1233..11bc998 100644 --- a/.github/workflows/sibyl-evidence-capture.yml +++ b/.github/workflows/sibyl-evidence-capture.yml @@ -19,8 +19,21 @@ jobs: - run: npm install - run: python -m pip install -r packages/sibyl/requirements.txt - run: npm run build - - name: Capture fresh Sibyl evidence bundle + - name: Capture fresh Sibyl + Base-authority evidence bundle run: npm run evidence:sibyl:capture + - name: Validate captured manifest before upload + run: >- + npx tsx -e "import { readdirSync, readFileSync, existsSync } from 'node:fs'; + const root='artifacts/sibyl-evidence'; + const dirs=readdirSync(root,{withFileTypes:true}).filter(x=>x.isDirectory()).map(x=>x.name); + if (dirs.length !== 1) throw new Error('expected exactly one evidence directory'); + const dir=root+'/'+dirs[0]; + const m=JSON.parse(readFileSync(dir+'/manifest.json','utf8')); + if (m.schema !== 'engram.sibyl-evidence-capture/v3') throw new Error('unexpected manifest schema'); + if (m.status !== 'LOCAL_PASS') throw new Error('capture failed'); + if (!m.baseSettlementIntent?.sha256) throw new Error('base intent digest missing'); + if (!m.baseSettlementIntent?.provenance?.retrievalId) throw new Error('base retrieval provenance missing'); + if (!existsSync(dir+'/'+m.baseSettlementIntent.file)) throw new Error('base intent artifact missing');" - name: Upload evidence bundle uses: actions/upload-artifact@v4 with: From 99109e8aaa01e9bada57d9e0ec5a50769d830e8a Mon Sep 17 00:00:00 2001 From: etvjay Date: Sun, 30 Aug 2026 12:57:55 +0100 Subject: [PATCH 115/116] feat: persist Base live verification evidence --- scripts/base-settlement-verify.ts | 51 ++++++++++++++++++++++++++----- 1 file changed, 44 insertions(+), 7 deletions(-) diff --git a/scripts/base-settlement-verify.ts b/scripts/base-settlement-verify.ts index d9b701a..63cd8b8 100644 --- a/scripts/base-settlement-verify.ts +++ b/scripts/base-settlement-verify.ts @@ -1,4 +1,6 @@ -import { readFile } from "node:fs/promises"; +import { createHash } from "node:crypto"; +import { mkdir, readFile, writeFile } from "node:fs/promises"; +import { dirname, resolve } from "node:path"; import { fetchBaseChainId, fetchBaseTransactionReceipt, @@ -11,26 +13,61 @@ function arg(name: string): string | undefined { return index >= 0 ? process.argv[index + 1] : undefined; } -const intentPath = arg("--intent"); +function sha256(value: Buffer | string): string { + return createHash("sha256").update(value).digest("hex"); +} + +const intentPathArg = arg("--intent"); const transactionHash = arg("--tx-hash"); const rpcUrl = arg("--rpc-url") ?? process.env.ENGRAM_BASE_RPC_URL; const expectedPayer = arg("--payer") ?? process.env.ENGRAM_BASE_EXPECTED_PAYER; +const outPathArg = arg("--out") ?? process.env.ENGRAM_BASE_EVIDENCE_OUT; -if (!intentPath || !transactionHash || !rpcUrl) { +if (!intentPathArg || !transactionHash || !rpcUrl) { throw new Error( - "Usage: npm run base:settlement:verify -- --intent --tx-hash <0x...> [--rpc-url ] [--payer <0x...>] " - + "or set ENGRAM_BASE_RPC_URL / ENGRAM_BASE_EXPECTED_PAYER", + "Usage: npm run base:settlement:verify -- --intent --tx-hash <0x...> [--rpc-url ] [--payer <0x...>] [--out ] " + + "or set ENGRAM_BASE_RPC_URL / ENGRAM_BASE_EXPECTED_PAYER / ENGRAM_BASE_EVIDENCE_OUT", ); } -const raw = JSON.parse(await readFile(intentPath, "utf8")) as unknown; +const intentPath = resolve(intentPathArg); +const intentBytes = await readFile(intentPath); +const raw = JSON.parse(intentBytes.toString("utf8")) as unknown; const intent = parseSerializedBaseSettlementIntent(raw); const observedChainId = await fetchBaseChainId({ rpcUrl }); const receipt = await fetchBaseTransactionReceipt({ rpcUrl, transactionHash }); -const evidence = verifyBaseSettlementReceipt({ +const settlement = verifyBaseSettlementReceipt({ intent, receipt, observedChainId, expectedPayer, }); + +const evidence = { + schema: "engram.base-live-settlement-evidence/v1", + capturedAt: new Date().toISOString(), + intent: { + file: intentPath, + sha256: sha256(intentBytes), + executionId: intent.provenance.executionId, + retrievalId: intent.provenance.retrievalId, + decisionId: intent.provenance.decisionId, + memoryRefs: intent.memoryRefs, + }, + verification: { + observedChainId, + expectedPayer: expectedPayer ?? null, + transactionHash, + receiptBlockNumber: receipt.blockNumber, + }, + settlement, + evidenceBoundary: "This file records independently verified Base settlement evidence. It is only partner-qualifying when the transaction itself occurred in the eligible build window and the referenced intent came from the retained fresh-memory decision path.", +}; + +if (outPathArg) { + const outPath = resolve(outPathArg); + await mkdir(dirname(outPath), { recursive: true }); + await writeFile(outPath, `${JSON.stringify(evidence, null, 2)}\n`, "utf8"); +} + process.stdout.write(`${JSON.stringify(evidence, null, 2)}\n`); From f134cfb185853a500230da76f82729c07c4c576e Mon Sep 17 00:00:00 2001 From: etvjay Date: Sun, 30 Aug 2026 12:58:27 +0100 Subject: [PATCH 116/116] docs: require persisted Base live evidence file --- hackathon/sibyl/BASE_LIVE_RUN.md | 44 ++++++++++++++++++++++++-------- 1 file changed, 33 insertions(+), 11 deletions(-) diff --git a/hackathon/sibyl/BASE_LIVE_RUN.md b/hackathon/sibyl/BASE_LIVE_RUN.md index 7ec7abf..7ff275a 100644 --- a/hackathon/sibyl/BASE_LIVE_RUN.md +++ b/hackathon/sibyl/BASE_LIVE_RUN.md @@ -25,41 +25,54 @@ execution evidence -> explicit wallet execution on Base Sepolia -> receipt -> chain + payer + USDC recipient + amount match - -> Base settlement evidence + -> engram.base-live-settlement-evidence/v1 ``` A transaction hash without the preceding memory/decision linkage does not qualify. +## Build-window capture first + +Run the canonical evidence capture before the live Base action: + +```bash +npm run evidence:sibyl:capture +``` + +Capture v3 retains `base-routine-intent.json` inside the same artifact as the fresh Sibyl memory proof and binds it by SHA-256 in `manifest.json`. + +The deterministic addresses used by local/CI capture are evidence fixtures only. For a partner-qualifying live action, rerun the fresh routine decision with the reviewed Base Sepolia provider addresses and retain that live intent alongside the build-window capture. Never sign a transaction against the deterministic fixture addresses. + ## Live sequence 1. Start from a hackathon-window commit with green canonical CI. -2. Use an isolated/new Sibyl evidence DB or retained build-window DB whose provenance is explicit. -3. Run/ingest provider execution evidence. +2. Produce and retain the build-window Sibyl evidence bundle. +3. Run/ingest real provider execution evidence if the claim depends on an external provider/Virtuals interaction. 4. Form the relationship memory through normal Engram admission. 5. Terminate the originating process. 6. In a fresh process, recall the relationship memory and record the provider decision. -7. Derive and serialize a Base settlement intent containing: +7. Emit the Base settlement intent directly from that fresh decision using reviewed provider addresses. The artifact must contain: - execution ID; - retrieval ID; - - decision ID; + - decision ID when available; - memory refs; - provider ID; - provider recipient address; - prepay basis points; - exact USDC atomic amount; - - no-memory counterfactual. + - no-memory counterfactual when present. 8. Review the serialized intent before signing anything. 9. Record the requester/payer wallet address expected to execute the settlement. 10. Execute exactly that authorized USDC transfer with the selected testnet wallet/signer. 11. Retain the transaction hash. Never retain/export the private key in Engram evidence. -12. Verify independently: +12. Verify independently and persist the verifier result: ```bash ENGRAM_BASE_RPC_URL='' \ npm run base:settlement:verify -- \ --intent artifacts/base/.json \ --tx-hash <0x...> \ - --payer + --payer \ + --out artifacts/base/base-live-settlement-evidence.json ``` 13. The verifier independently calls `eth_chainId` and must observe `84532` before accepting the receipt. @@ -70,7 +83,15 @@ ENGRAM_BASE_RPC_URL='' \ - originates from the expected requester/payer when payer binding is supplied; - transfers to the exact decision-derived recipient; - transfers the exact decision-derived amount. -15. Save verifier stdout, transaction hash, explorer link, receipt, serialized intent, payer address, and Engram trace in the final evidence bundle. +15. The persisted verifier evidence must bind: + - intent-file SHA-256; + - execution/retrieval/decision provenance; + - memory refs; + - observed chain ID; + - expected payer; + - transaction hash and block number; + - verified recipient and atomic amount. +16. Save the explorer link and raw receipt beside the persisted intent and `engram.base-live-settlement-evidence/v1` file. ## Flagship expected deltas @@ -110,11 +131,12 @@ A live claim is invalid if any of these are true: - wrong token contract; - reverted transaction; - no retrieval/decision provenance; +- the live intent uses deterministic fixture addresses; - transfer was executed independently of the Engram decision; -- only a screenshot is retained and raw transaction evidence is unavailable. +- only a screenshot is retained and raw transaction/evidence files are unavailable. ## Promotion `BASE-001` remains `UNVERIFIED` until this sequence is executed during the eligible build window. -Local intent/receipt tests can support an internal conformance gate but cannot promote the published Base partner gate. +Local intent/receipt tests and capture-v3 artifacts support internal conformance only. They cannot promote the published Base partner gate.