From 5d968197a58e9f1c4b5357791b833b057aac2ebb Mon Sep 17 00:00:00 2001 From: Enrico Piovesan Date: Wed, 22 Jul 2026 21:51:54 -0600 Subject: [PATCH] feat: pin Traverse-published starter agents for embedded smoke Replace App-Refs hand-built WASI stand-ins with digest-pinned copies of Traverse example agents so embedded E2E proves real product output shapes. Co-authored-by: Cursor --- AGENTS.md | 2 +- docs/getting-started-embedded.md | 2 +- docs/production-playbook.md | 2 +- docs/production-reference-plan.md | 4 +- docs/quality-standards.md | 2 +- scripts/ci/embedded_smoke.sh | 3 +- .../fixtures/build_starter_smoke_agents.mjs | 70 ---------------- .../traverse-starter-smoke-agents/README.md | 21 +++-- .../digests.json | 20 +++-- .../process-agent.wasm | Bin 265 -> 727 bytes .../summarize-agent.wasm | Bin 184 -> 686 bytes .../validate-agent.wasm | Bin 154 -> 588 bytes .../ci/pin_traverse_starter_smoke_agents.sh | 76 ++++++++++++++++++ scripts/ci/prepare_embedded_smoke_bundle.sh | 42 +++++++--- scripts/ci/repository_checks.sh | 7 +- 15 files changed, 152 insertions(+), 99 deletions(-) delete mode 100644 scripts/ci/fixtures/build_starter_smoke_agents.mjs create mode 100755 scripts/ci/pin_traverse_starter_smoke_agents.sh diff --git a/AGENTS.md b/AGENTS.md index 36d1fe0..6c0715c 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -21,7 +21,7 @@ gh project item-list 2 --owner traverse-framework --format json --limit 300 \ | `phase2-sidecar-nightly` | Future | Defer — low demo value | | `embed-trace-explorer` | **In Progress** (Cursor) | Unblocked — Traverse `embedded-trace-api` Done (#802) | | `registry-ref-starter-process` | **Done** (#224) | Process component uses `registry_ref` | -| `consume-product-wasm-agents` | **Ready** | Unblocked — Traverse `real-wasm-agent-execute` Done (#795/#809) | +| `consume-product-wasm-agents` | **In Progress** (Cursor, #226) | Digest-pin Traverse-published starter agents | Full gap table + wave notes: [`docs/production-reference-plan.md`](docs/production-reference-plan.md). diff --git a/docs/getting-started-embedded.md b/docs/getting-started-embedded.md index 8514fd4..43fe82a 100644 --- a/docs/getting-started-embedded.md +++ b/docs/getting-started-embedded.md @@ -137,7 +137,7 @@ bash scripts/ci/embedded_smoke.sh - **Web:** sync bundle → `BundleEmbedder` + `NodeFsBundleLoader` → init + workflow invoke - **CLI:** `phase2_link_traverse.sh` → `cargo run -p traverse-starter-cli -- health --json` → `Embedded` / `Ready` - **Android / Swift / Windows:** digest-check committed `runtime/runtime.wasm`; full SDK tests when tools exist -- Hard-fails unless validate/process/summarize runtime-owned fields are present (smoke WASI fixtures under `scripts/ci/fixtures/traverse-starter-smoke-agents/`) +- Hard-fails unless validate/process/summarize runtime-owned fields are present (digest-pinned Traverse-published agents under `scripts/ci/fixtures/traverse-starter-smoke-agents/`; see `digests.json` provenance) CI runs this with `EMBEDDED_SMOKE_EXPECT=linux` on every PR (see `.github/workflows/ci.yml`). diff --git a/docs/production-playbook.md b/docs/production-playbook.md index 44cdaa7..aa433c5 100644 --- a/docs/production-playbook.md +++ b/docs/production-playbook.md @@ -99,7 +99,7 @@ bash scripts/ci/embedded_smoke.sh ``` - Merge-blocking on PR CI for **Web + CLI** with **runtime-owned pipeline output** required -- Smoke overlays deterministic WASI fixtures (`scripts/ci/fixtures/traverse-starter-smoke-agents/`) until Traverse example agents ship non-stub WASM +- Smoke overlays digest-pinned Traverse-published agents (`scripts/ci/fixtures/traverse-starter-smoke-agents/`; see `digests.json` provenance) - Other platforms: skip-with-reason when SDK missing; digest-check always --- diff --git a/docs/production-reference-plan.md b/docs/production-reference-plan.md index 0dbb80b..2d70516 100644 --- a/docs/production-reference-plan.md +++ b/docs/production-reference-plan.md @@ -36,7 +36,7 @@ Related: | Repo front door | Embedded-first README + playbook; sidecar appendix-only | Decision B | | Digest sync | **Shared core + thin per-platform wrappers** — see [`runtime-bundle-sync.md`](runtime-bundle-sync.md) | Decision B | | Showcase rollout | **Wave 1:** Web + Linux/CLI (+ Android if stable); **Wave 2:** Windows + Apple | Decision C | -| Product agents | Smoke fixtures today; adopt Traverse agents via `consume-product-wasm-agents` | Gap capture | +| Product agents | Digest-pinned Traverse-published starter agents (`consume-product-wasm-agents`) | Gap capture | ### Primary vs secondary (locked) @@ -58,7 +58,7 @@ Live status is always on [Project 2](https://github.com/orgs/traverse-framework/ | Trace Explorer embed | `embed-trace-explorer` | **In Progress** | Traverse embedded-trace-api Done (#802); migrate web Trace Explorer | Finish PR | | Delete sidecar client code | `remove-sidecar-paths` | **Done** (#206) | Dead HTTP paths removed from starter/doc-approval | Shipped | | Nightly Apple/Windows + Android/GTK | `native-ci-android-gtk-required` | **Done** (#209); nightly green via `fix-nightly-native-required` | Required nightly jobs | Shipped | -| Product WASM agents (Traverse) | `consume-product-wasm-agents` | **Ready** | Traverse real-wasm-agent-execute Done (#795/#809) | Replace App-Refs smoke fixtures | +| Product WASM agents (Traverse) | `consume-product-wasm-agents` | **In Progress** (#226) | Traverse real-wasm-agent-execute Done (#795/#809) | Digest-pin Traverse-published starter agents | | `registry_ref` adoption | `registry-ref-starter-process` | **In Progress** | Process component uses `registry_ref`; sync materializes for embedders | Finish smoke evidence | | Phase 2 sidecar nightly | `phase2-sidecar-nightly` | **Future** (defer) | Legacy path; low demo value | Optional; low priority | diff --git a/docs/quality-standards.md b/docs/quality-standards.md index 3e88534..616df21 100644 --- a/docs/quality-standards.md +++ b/docs/quality-standards.md @@ -123,7 +123,7 @@ A change must not merge when any of the following are true: Every PR runs `scripts/ci/embedded_smoke.sh` with `EMBEDDED_SMOKE_EXPECT=linux` (`.github/workflows/ci.yml` job `embedded-smoke`): - Requires Web (`BundleEmbedder` init + full pipeline → validate/process/summarize fields) and Rust CLI (`health` + `run` with the same output shape) -- Uses smoke WASI fixtures when Traverse example agents are stubs; still public embedder path only +- Uses digest-pinned Traverse-published starter agents for pipeline output; still public embedder path only - Skips Apple / Windows / Android SDK slices with reason when tools are absent; still digest-checks committed `runtime.wasm` - Does **not** start `traverse-cli serve` - Coverage gate for `host/embeddedHost.ts` + `client/traverseOutput.ts` is **100%** line coverage diff --git a/scripts/ci/embedded_smoke.sh b/scripts/ci/embedded_smoke.sh index a45dff7..9c4a998 100755 --- a/scripts/ci/embedded_smoke.sh +++ b/scripts/ci/embedded_smoke.sh @@ -13,7 +13,8 @@ # EMBEDDED_SMOKE_SKIP= force-skip slices (web,cli,gtk,android,swift,windows) # # Web + CLI always require runtime-owned pipeline output (validate/process/summarize) -# via scripts/ci/fixtures/traverse-starter-smoke-agents/ (WASI fixtures). +# via digest-pinned Traverse-published agents under +# scripts/ci/fixtures/traverse-starter-smoke-agents/ (see digests.json provenance). # # Exit 0 on pass (skips allowed). Exit 1 on any required-slice failure. set -euo pipefail diff --git a/scripts/ci/fixtures/build_starter_smoke_agents.mjs b/scripts/ci/fixtures/build_starter_smoke_agents.mjs deleted file mode 100644 index 8af144a..0000000 --- a/scripts/ci/fixtures/build_starter_smoke_agents.mjs +++ /dev/null @@ -1,70 +0,0 @@ -#!/usr/bin/env node -/** - * Build deterministic WASI smoke agents for traverse-starter.pipeline. - * Each agent writes fixed contract-shaped JSON to stdout (no UI business logic). - * - * Usage: node scripts/ci/fixtures/build_starter_smoke_agents.mjs - */ -import initWabt from 'wabt' -import { writeFileSync, mkdirSync } from 'node:fs' -import { createHash } from 'node:crypto' -import { dirname, join } from 'node:path' -import { fileURLToPath } from 'node:url' - -const here = dirname(fileURLToPath(import.meta.url)) -const outDir = join(here, 'traverse-starter-smoke-agents') - -function watFixedJson(json) { - const bytes = Buffer.from(json, 'utf8') - const escaped = [...bytes].map((b) => `\\${b.toString(16).padStart(2, '0')}`).join('') - return ` - (module - (import "wasi_snapshot_preview1" "fd_write" - (func $fd_write (param i32 i32 i32 i32) (result i32))) - (memory (export "memory") 1) - (data (i32.const 16) "${escaped}") - (func (export "_start") - (i32.store (i32.const 0) (i32.const 16)) - (i32.store (i32.const 4) (i32.const ${bytes.length})) - (drop (call $fd_write (i32.const 1) (i32.const 0) (i32.const 1) (i32.const 8))) - ) - )` -} - -const agents = { - validate: '{"valid":true,"issues":[]}', - process: - '{"title":"Meeting notes","tags":["meeting","design"],"noteType":"meeting","suggestedNextAction":"Schedule follow-up","status":"ready"}', - summarize: '{"summary":"Design onboarding discussion","wordCount":3}', -} - -const wabt = await initWabt() -mkdirSync(outDir, { recursive: true }) - -const digests = {} -for (const [name, json] of Object.entries(agents)) { - const module = wabt.parseWat(`${name}.wat`, watFixedJson(json)) - const { buffer } = module.toBinary({}) - const wasm = Buffer.from(buffer) - const file = `${name}-agent.wasm` - writeFileSync(join(outDir, file), wasm) - const digest = `sha256:${createHash('sha256').update(wasm).digest('hex')}` - digests[name] = { file, digest, bytes: wasm.length } - console.log(`OK: ${file} ${digest} (${wasm.length} bytes)`) -} - -writeFileSync(join(outDir, 'digests.json'), `${JSON.stringify(digests, null, 2)}\n`) -writeFileSync( - join(outDir, 'README.md'), - `# traverse-starter smoke agents - -Deterministic WASI command modules used only by \`scripts/ci/embedded_smoke.sh\`. -Each writes fixed JSON matching the public capability contracts (validate / process / summarize). - -Rebuild: \`node scripts/ci/fixtures/build_starter_smoke_agents.mjs\` (requires \`wabt\`). - -These are **not** UI business logic — they stand in for Traverse example agents until -those ship non-stub WASM. Digests are applied to the smoke bundle at prepare time. -`, -) -console.log(`OK: wrote digests → ${join(outDir, 'digests.json')}`) diff --git a/scripts/ci/fixtures/traverse-starter-smoke-agents/README.md b/scripts/ci/fixtures/traverse-starter-smoke-agents/README.md index ef2efb5..40ebfbe 100644 --- a/scripts/ci/fixtures/traverse-starter-smoke-agents/README.md +++ b/scripts/ci/fixtures/traverse-starter-smoke-agents/README.md @@ -1,9 +1,20 @@ # traverse-starter smoke agents -Deterministic WASI command modules used only by `scripts/ci/embedded_smoke.sh`. -Each writes fixed JSON matching the public capability contracts (validate / process / summarize). +Digest-pinned **Traverse-published** example agents used by +`scripts/ci/prepare_embedded_smoke_bundle.sh` / `scripts/ci/embedded_smoke.sh`. -Rebuild: `node scripts/ci/fixtures/build_starter_smoke_agents.mjs` (requires `wabt`). +Provenance is recorded in `digests.json` (`provenance.ref` + per-agent +`traverse_source`). These binaries are copies of Traverse +`examples/traverse-starter/{validate,process,summarize}-agent` artifacts — not +App-Refs hand-built WASI stand-ins. -These are **not** UI business logic — they stand in for Traverse example agents until -those ship non-stub WASM. Digests are applied to the smoke bundle at prepare time. +Refresh from a Traverse checkout that contains the real stdout-only agents: + +```bash +export TRAVERSE_REPO=/path/to/Traverse # main (post #795/#803/#805/#809) +bash scripts/ci/pin_traverse_starter_smoke_agents.sh +``` + +Prepare overlays these pinned digests onto `$TRAVERSE_REPO` and the synced web +bundle so CI can stay on an older Traverse tag while still exercising product +agent output shapes. diff --git a/scripts/ci/fixtures/traverse-starter-smoke-agents/digests.json b/scripts/ci/fixtures/traverse-starter-smoke-agents/digests.json index 8caf57d..4f6f0f8 100644 --- a/scripts/ci/fixtures/traverse-starter-smoke-agents/digests.json +++ b/scripts/ci/fixtures/traverse-starter-smoke-agents/digests.json @@ -1,17 +1,25 @@ { + "provenance": { + "source": "traverse-framework/Traverse", + "ref": "b00a5c4fb8f93503932afd52eadda5e2fe8d04d0", + "note": "Digest-pinned copies of Traverse-published traverse-starter example agents (stdout-only WASM). Not App-Refs hand-built WASI stand-ins. Refresh with: bash scripts/ci/pin_traverse_starter_smoke_agents.sh" + }, "validate": { "file": "validate-agent.wasm", - "digest": "sha256:ecc46ac478334adb1dacc2bb36841edf2617fcbfab26e6fecfb3d73440805ce9", - "bytes": 154 + "digest": "sha256:6cf96349ff6af05cb7417561384dccd63b6f92f4bfc197bcc53838f2ae5b8016", + "bytes": 588, + "traverse_source": "examples/traverse-starter/validate-agent/artifacts/validate-agent.wasm" }, "process": { "file": "process-agent.wasm", - "digest": "sha256:15ae4a7431bb45fca2a4d253d4e24fec4962ce067b012c5d1bfc7b86350c79dd", - "bytes": 265 + "digest": "sha256:2c6690fd00432f8bff4366d4852395af22a3c766517020532590bab1fba1ab34", + "bytes": 727, + "traverse_source": "examples/traverse-starter/process-agent/artifacts/process-agent.wasm" }, "summarize": { "file": "summarize-agent.wasm", - "digest": "sha256:a2e916443233b3346c6ba9211a341f961def495870b77350d2824bba3667440f", - "bytes": 184 + "digest": "sha256:fa5d90f9cbdddc7d81daff0f965650cd34c3fc311d8a312cf79637a1bb2c0b7d", + "bytes": 686, + "traverse_source": "examples/traverse-starter/summarize-agent/artifacts/summarize-agent.wasm" } } diff --git a/scripts/ci/fixtures/traverse-starter-smoke-agents/process-agent.wasm b/scripts/ci/fixtures/traverse-starter-smoke-agents/process-agent.wasm index 40f5bd6a741488d65e9e6497862d9cb44024e7af..3750d6857f59c76d9d2bc7ac8c586801d143e8da 100644 GIT binary patch literal 727 zcmYjOU2EGg6qTH`O_M;n777~-j5@}K>yXrGwiNb|hrM=e^l4+LihbiawIv~4_k%H# z{fGU7J`eU2_R}Ui8B8zd>PqKa=^P?#K?xzW>s>cjZqd~>A>Ii+z7sa%Rtjww3b{6L zo59_%HBb1R$q)!>c$DrmD0#B`w6UVo_4*I#tjP57#|D2_xYuv)7Embj;E`Q!Q5Yn& z&3PhFaF9uZb~s;v(0nE=G`#jl`hn8b$=WS4J-A`yMP2$%myW%bLpNtl#$MBv4!Tq7 zisrJ0?((3%{miuvmK$cL^NZ4&MLLi48^a89U>EFD{U86zh+8lg{Q7NRe4({(Ak8cq zftix*l%Ys1yZFL37F3Nb$(36g`+CZxLb!U+mAE!)2{BgZWtxITNG{6Dh2Xx-_1$N*ttNv+mVojvj@6k zN{jLHVSh5}5BygnF@pJM5`lj)%JcBO delta 186 zcmcc4+Q~G*xt@_-n29YnH8;Pgl8J#WzPKc@sDy!$OO8>7!I8mHz>JB(k;So%5kxZr z1sEMU1Q?{axqBHIfwJ6fjMYjdnI$=?N>)m~si`HIdFcvy`6a2vN;*msNM%8)5~meResV0Mq-t<-MrulFPO3s$eojt)xo&9zP#e%q QC8a>4l!{UlQ!15e0q$`$HUIzs diff --git a/scripts/ci/fixtures/traverse-starter-smoke-agents/summarize-agent.wasm b/scripts/ci/fixtures/traverse-starter-smoke-agents/summarize-agent.wasm index d543297103160604e0dd7347a8c3be21aebceb34..9e8bb8c57cc114f7d1a7fdd26c2222dfd63846bb 100644 GIT binary patch literal 686 zcmYk3U5^qm6o%V@WmzBrzc$gtq?t8lH?t+M!=hlkAjVsb#w%~SW#%vpJJU982NsP1 z{SE#g|CV=_flWL&?|YilkM}9!CdUXN-12U!8&`O9gOGQIPgmTe%m}W`Tw10yEK^wZ z>$8}xbZP;iiih!01)~SGrv8=9W5({my3d7sll-)Leh}O_AqZul=$AxeP?UXubq(fRv8|O}J9zTxq$0$X*ai zEKkgs?Bib&dlEqY;GRU>Npz7{A8{ipLKzYO@{D=$0v& z3JdzAfzfeS%N<#t}f7T+;*RpfMqk_w$NbeL33JUw{-uVLHoakN@au7h-Vp1MVx9!j!H*0lOhQk zd6C(4$+H52c3xOM&44DEobt>BkAxHssZyy(=uFvNkf5z$1{y>J)UFknpl;GcP>1;+ Dg)7sD delta 124 zcmZ3-x`T0ob15UcFcVvDYHof}B@+W%d~r!)Q3(Shmn@?+gCm2ZfEg2mBa5R2h++it z867zU7^Jwl?HGY_+!obJ#ihBqiA9x4R!T0Z#hK}O3i)|S`H4j-nR)37DVfE|rNzaW W`FTn@O6B=QDbD$&c_m6##1-%MsQ`Tv3Ii~s=XIQR9VEpogEa7N^M&$VD$@cYW zCJww}pYLv}(ffY^Ox~>*L3|S~FbHPzV9bN)BYE`Ld`h6p&VIu!D{>(Xs>?Qkrmym| zb@*^uSSmwQnsh9Ns5M4(bs!h2)Fyl}@fS0HJa|3hGmK}800-0YbWX{D+%X3#{x}^_cd)@yUnis~q4tbhVAtRwMG&J9#N^_Zb?W|0Vu&zt=x>;%X sDn**4`HH97yOOyyiWh~D35^SLHsW;^#;8z+NX?-@?X|Q>B*ky$FI6