diff --git a/.github/ISSUE_TEMPLATE/operator.yml b/.github/ISSUE_TEMPLATE/operator.yml new file mode 100644 index 0000000..ae66f8b --- /dev/null +++ b/.github/ISSUE_TEMPLATE/operator.yml @@ -0,0 +1,63 @@ +name: 15-minute operator report +description: Report an independent first-run attempt of the ThreadMesh proof. +title: "[Operator]: " +labels: [external-review, usability, triage] +body: + - type: input + id: environment + attributes: + label: Harness, OS, and Node version + placeholder: Codex CLI, macOS, Node 22 (do not include local paths) + validations: + required: true + - type: dropdown + id: install + attributes: + label: Installation path + options: + - One-command GitHub package + - Fresh clone and npm ci + validations: + required: true + - type: input + id: time + attributes: + label: Time to first successful demo + placeholder: 7m 30s, or did not complete in 15m + validations: + required: true + - type: textarea + id: explanation + attributes: + label: What does ThreadMesh do? + description: Explain it in your own words after using only the README. + validations: + required: true + - type: textarea + id: friction + attributes: + label: First confusing or failed step + validations: + required: true + - type: textarea + id: workflow + attributes: + label: Would you use it? + description: Name a real workflow, or explain why the capability is not useful. + validations: + required: true + - type: checkboxes + id: evidence + attributes: + label: Evidence checks + options: + - label: I found why delivery alone did not unlock the dependent task. + required: true + - label: I found what happened when the receiver was already running. + required: true + - label: The demo reported cleanup complete. + required: true + - label: I am independent of the ThreadMesh maintainer organization. + required: true + - label: I removed credentials, transcripts, IDs, and local paths. + required: true diff --git a/README.md b/README.md index 9d68c1a..586963c 100644 --- a/README.md +++ b/README.md @@ -19,10 +19,12 @@ # ThreadMesh -ThreadMesh is an experimental coordination protocol and JavaScript integration -kit that lets one agent session notice an authorized dependency, decide whether -to contact another session, and deliver a bounded suggestion without sharing -global chat history or taking over the receiver. +**Stop babysitting parallel coding agents.** + +ThreadMesh routes completion, blockers, review findings, and verified +dependency state to the right agent session at a safe checkpoint—without making +you copy results, spend model turns polling status, or let one session silently +take over another. **The agent supplies the initiative. ThreadMesh supplies the boundary.** @@ -31,12 +33,39 @@ global chat history or taking over the receiver. > release is suitable for local, trusted-process experiments—not production > authorization, hostile prompts, or multi-tenant deployment. +## 76-second proof walkthrough + +

+ + ThreadMesh evidence walkthrough: one kickoff, zero manual relay or polling, active receiver checkpoint, selective attention, and verified dependency unlock + +

+ +The walkthrough is generated from a fresh executable demo and retained real +Codex evidence. It is not presented as a live screen recording. The local demo +models the same four-handoff workflow two ways: the manual path requires at +least one kickoff, four status checks, and four relay actions; the ThreadMesh +path requires one kickoff and zero later relay or polling actions. Elapsed time +and model tokens are deliberately marked **not measured** until a network-valid +live baseline is retained. + +It also exercises the safety failure people worry about: when B is already +running, the completion stays `pending` in a `checkpoint-offer`; B remains +`running`, and the demo starts zero steer, interrupt, or native-turn operations. + +[Watch the MP4](docs/assets/demo/threadmesh-proof-walkthrough.mp4) · +[inspect asset provenance](docs/assets/demo/README.md) · +[run the proof yourself](docs/06-guides/attention-router-demo.md) + ## Why this matters -Running several agents in parallel creates a new coordination problem. Agent A -may finish the exact input Agent B needs, but neither session knows when it is -useful to speak. The user becomes a human message bus: notice the dependency, -copy the result, find the right session, and explain why it matters. +Running several agents in parallel often gives the user three extra jobs: + +- **clipboard:** notice A has the result B needs, then copy and explain it; +- **poller:** repeatedly ask whether review, verification, or a dependency is + finished, consuming time and model quota even when nothing changed; +- **traffic controller:** decide whether to queue, wake, steer, or interrupt B + without enough visibility into B's current work. ThreadMesh makes that handoff an explicit, portable capability: @@ -47,9 +76,11 @@ ThreadMesh makes that handoff an explicit, portable capability: 5. B's harness accepts, rejects, or defers it before model-context admission; 6. the decision and delivery chain stays auditable. -The intelligence is not “agents can send messages.” It is **selective -initiative**: speaking when a dependency is real, staying quiet when it is not, -and preserving the other session's agency. +The intelligence is not “agents can send messages.” Transport is increasingly +available from harness-native APIs, ACP, and A2A. ThreadMesh focuses on +**selective initiative**: speak when a dependency is real, remain quiet when it +is not, verify before unlocking downstream work, and preserve the receiver's +agency. ## What proactive behavior looks like @@ -110,12 +141,14 @@ five of five temporary sessions and all coordinator artifacts were removed. The completed result is deliberately classified `state=blocked` and `liveProductEvidence=false`: that retained run used fixture-owned or simulated -Git and verification effects. The next branch now wires the existing bounded -Git worktrees and process-isolated child verifier into the same correlated -path. Its live rerun is pending after a reproducible local DNS/TLS failure; it -has not been upgraded into product evidence. After that rerun, the remaining -checkpoint is the manual relay/polling baseline and minimum critical -negative/restart closure. Non-mainline expansion remains frozen. +Git and verification effects. [#133](https://github.com/fyaic/threadmesh/pull/133) +now binds the existing bounded Git worktrees and process-isolated child +verifier into that correlated path on `main`. Its fresh real Codex rerun is +pending after a reproducible local DNS/TLS endpoint failure; it has not been +upgraded into product evidence. The deterministic manual-accounting baseline, +active-receiver checkpoint negative, and 76-second evidence walkthrough are now +the public product proof. New harness, transport, and generalized protocol work +remains frozen until the live rerun and three external setup attempts close. [Read the exact fixture evidence](docs/09-reviews/2026-09-01-m5-2-autonomous-fixture.md) · [Read the real Codex behavior](docs/09-reviews/2026-09-01-m5-2-real-codex-event-pump-behavior.md) · @@ -306,14 +339,14 @@ peer content or as a production security boundary. install Ajv and native `better-sqlite3`. - **Reference runtime:** authenticated JSON-RPC + SQLite coordinator for local, trusted-process experiments. -- **Validation:** 379 tests, plus 55 schema cases and 7 transition cases; +- **Validation:** 384 tests, plus 55 schema cases and 7 transition cases; documentation lint passes. These are separate counts, not one combined total. - **Default:** proactive coordination remains off unless a maintainer explicitly opts into the bounded experimental profile. -- **Next mainline:** reuse the existing bounded Git-worktree and verifier - foundations inside the now-proven real Codex event-pump chain; add a manual - relay/polling baseline and minimum critical negative/restart evidence. Kimi - parity and broader hardening follow after M5.2 closure. +- **Next mainline:** retain one network-valid real Codex traversal of the merged + real-effects path, run the measured manual baseline, and observe three + independent 15-minute setup attempts. Kimi parity and broader hardening + follow only after those product-proof gates. [Current status](docs/10-planning/project-status.md) · [roadmap](ROADMAP.md) · @@ -325,8 +358,12 @@ peer content or as a production security boundary. | If you want to… | Start here | |---|---| | Understand the product | [What ThreadMesh is](docs/00-overview/product-guide.md) | +| Watch the 76-second proof | [MP4 walkthrough](docs/assets/demo/threadmesh-proof-walkthrough.mp4) | | See real proactive behavior | [Real agent case portfolio](docs/06-guides/real-world-cases.md) | | Run the closed-loop local demo | [Attention-router demo](docs/06-guides/attention-router-demo.md) | +| Audit the user-value baseline | [Manual relay/polling baseline](docs/06-guides/manual-relay-baseline.md) | +| Audit non-interruption | [Active-session checkpoint case](docs/06-guides/non-interrupting-handoff.md) | +| Try it as a new operator | [15-minute challenge](docs/06-guides/15-minute-operator-challenge.md) | | Compare selective model initiative | [End-to-end demo](docs/06-guides/end-to-end-demo.md) | | Add ThreadMesh to a harness | [Adapter implementation guide](docs/06-guides/implement-an-adapter.md) | | Evaluate a harness | [Harness support matrix](docs/00-overview/harness-support.md) | diff --git a/README.zh-CN.md b/README.zh-CN.md index 423f1eb..fb09600 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -19,10 +19,11 @@ # ThreadMesh -ThreadMesh 是一个实验性的 Agent 协调协议与 JavaScript 接入工具包。它让一个 -Agent session 在执行过程中发现经过授权的跨任务依赖,自主判断是否联系另一个 -session,并发送一条受约束的建议;同时不共享全局聊天记录,也不夺走接收方的 -上下文控制权。 +**不用再人工盯守多个并行 coding agent。** + +ThreadMesh 会把完成、阻塞、评审发现和经过验证的依赖状态,在安全 checkpoint +路由给正确的 agent session:用户不用复制结果,不用消耗模型 turn 反复查询,也 +不会让一个 session 静默接管另一个 session 的当前工作。 **Agent 提供主动性,ThreadMesh 提供边界。** @@ -30,10 +31,34 @@ session,并发送一条受约束的建议;同时不共享全局聊天记录 > ThreadMesh 目前是 pre-alpha,主动能力默认关闭。现阶段适合本地、可信进程范围 > 的实验,不应作为生产级授权、多租户隔离或处理恶意 peer prompt 的安全边界。 +## 76 秒证据演示 + +

+ + ThreadMesh 证据演示:一次启动、零人工转发和轮询、活跃接收方 checkpoint、选择性注意力与验证后依赖解锁 + +

+ +这个演示由一次新鲜的可执行 demo 和已经保留的真实 Codex 证据生成,不冒充实时 +录屏。对于同一个四次交接工作流,人工路径的最低成本是 1 次启动、4 次状态查询、 +4 次复制转发,共至少 9 次用户操作;ThreadMesh 路径是 1 次启动,后续 0 次转发、 +0 次轮询。耗时和 token 尚未实测,必须等网络正常的真实基线,文档不会虚构数字。 + +演示还覆盖最重要的安全负例:B 正在运行时,完成事件只会以 +`checkpoint-offer` 留在 mailbox,decision 保持 `pending`;B 仍是 `running`, +不会触发 steer、interrupt 或新的 native turn。 + +[观看 MP4](docs/assets/demo/threadmesh-proof-walkthrough.mp4) · +[查看演示资产证据边界](docs/assets/demo/README.md) · +[亲自运行](docs/06-guides/attention-router-demo.md) + ## 为什么需要它 -当多个 Agent 并行工作时,用户往往被迫充当“人工消息总线”:发现 A 的结果正好是 -B 缺少的输入,从 A 复制内容,找到正确的 B session,再解释这条信息为什么重要。 +当多个 Agent 并行工作时,用户往往被迫承担三份额外工作: + +- 当“剪贴板”:发现 A 的结果正好是 B 缺少的输入,再复制、查找、解释; +- 当“轮询器”:不断询问评审、验证或依赖是否完成,即使状态没变化也消耗额度; +- 当“交通警察”:在不了解 B 当前工作的情况下决定排队、唤醒、转向还是打断。 ThreadMesh 把这个过程抽象成一项可移植能力: @@ -44,8 +69,9 @@ ThreadMesh 把这个过程抽象成一项可移植能力: 5. B 的 harness 在 checkpoint 接受、拒绝或延迟,再决定是否进入模型上下文; 6. 完整的决策、投递与清理链路可审计。 -这里的“智能”不只是 Agent 会发消息,而是**有选择的主动性**:依赖确实存在时 -主动联系,无关时保持安静,并尊重另一个 session 的自主权。 +这里的“智能”不只是 Agent 会发消息。传输能力正在被 harness 原生 API、ACP 和 +A2A 普及;ThreadMesh 关注的是**有选择的主动性**:依赖确实存在时主动联系, +无关时保持安静,验证后才解锁下游,并尊重接收 session 的自主权。 ## 已验证的主动性效果 @@ -205,10 +231,10 @@ sandbox。不要用它处理任意恶意 peer 内容或充当生产安全边界 - 协议:可执行 `0.0-draft`,仍可能调整。 - 包:`@fyaic/threadmesh@0.1.0-alpha.0`,可从 GitHub 安装;根 export 是精简 SDK,CLI 与显式 runtime subpath 会安装 Ajv 和原生 `better-sqlite3`。 - 参考 runtime:authenticated JSON-RPC + SQLite coordinator,面向本地可信进程实验。 -- 验证:378 项测试,加 55 个 schema case、7 个状态转换 case、文档与链接检查;这些计数分别报告。 +- 验证:384 项测试,加 55 个 schema case、7 个状态转换 case、文档检查;这些计数分别报告。 - 默认策略:除非 maintainer 明确选择有边界实验 profile,否则主动协调保持关闭。 -- 当前边界:确定性 event pump 已能在一次 kickoff 后驱动 A→R→同一个 A→V→dependent,但三次真实 Codex event-pump 尝试分别停在产品探测、时间证据和用户暂停于五个 session bootstrap,尚未形成真实主动链;第三次没有执行正常信号清理,随后通过一次性精确操作删除并确认了五个测试 session 与临时资源。 -- 下一主线:冻结非主线扩展,先在现有实现上完成并保留一次真实 Codex event-pump 主动链;只有真实运行暴露出的 blocker 可以插队。随后再恢复真实 Git/verifier 闭环、Kimi parity 与可靠性矩阵。 +- 当前边界:第六次真实 Codex event-pump 已在一次 kickoff 后通过 9 个 native turn 完成 A→R→同一个 A→V→dependent,后续 runner phase prompt/direct activation 为 0,无关 session turn 为 0,清理 5/5;该次运行的 Git/verifier effect 是模拟的。真实 Git worktree 与 child verifier 已由 #133 合入同一路径,但组合后的新鲜 live 重跑仍受本机 DNS/TLS 故障阻塞。 +- 下一主线:在网络正常的 host 上保留一次真实 Codex real-effects 闭环,完成实测人工基线,并观察 3 位外部 operator 的 15 分钟上手过程。在这些产品证据前,继续冻结新 harness、transport 和泛化 protocol 扩展。 [当前状态](docs/10-planning/project-status.md) · [路线图](ROADMAP.md) · [协议草案](spec/README.md) · [验证记录](docs/09-reviews/README.md) @@ -218,7 +244,11 @@ sandbox。不要用它处理任意恶意 peer 内容或充当生产安全边界 - [中文文档入口](docs/zh-CN/README.md) - [英文文档总览](docs/README.md) - [产品说明](docs/00-overview/product-guide.md) +- [76 秒演示](docs/assets/demo/threadmesh-proof-walkthrough.mp4) - [真实 Agent 案例](docs/06-guides/real-world-cases.md) +- [人工转发与轮询基线](docs/06-guides/manual-relay-baseline.md) +- [活跃 session 不打断案例](docs/06-guides/non-interrupting-handoff.md) +- [15 分钟外部上手挑战](docs/06-guides/15-minute-operator-challenge.md) - [贡献指南](CONTRIBUTING.md) - [GitHub Discussions](https://github.com/fyaic/threadmesh/discussions) - [GitHub Issues](https://github.com/fyaic/threadmesh/issues) diff --git a/ROADMAP.md b/ROADMAP.md index 1d8472d..8a4e38b 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -150,13 +150,15 @@ nine bound native turns, zero later runner prompts or direct activations, an irrelevant zero-turn control, and exact cleanup. This exposed an execution-order imbalance rather than a change in product -direction. The behavioral checkpoint is passed. The existing bounded -Git-worktree and child-verifier foundations are now wired into that correlated -path, but a successful live rerun is pending after a reproducible local DNS/TLS -failure. The manual baseline and minimum critical negative/restart evidence -remain next. New substrate, generalized recovery, cross-harness, or -presentation work remains frozen. No partial integration attempt is promoted -to M5.2 evidence. +direction. The behavioral checkpoint is passed. The bounded Git worktrees and +process-isolated child verifier are now wired into the correlated path by +[#133](https://github.com/fyaic/threadmesh/pull/133), with deterministic +positive and wrong-finding negative coverage. A successful live rerun is +pending after a reproducible local DNS/TLS failure. The public demo now includes +executable manual-action accounting and an active-receiver checkpoint negative; +elapsed time and token cost remain unmeasured. New substrate, generalized +recovery, cross-harness, transport, and protocol expansion remains frozen. No +partial integration attempt is promoted to M5.2 evidence. - [x] Ship a one-command local demo with generated identities, grants, example sessions, and an inspector @@ -186,9 +188,14 @@ to M5.2 evidence. and no new coordinator or verifier subsystem. - [ ] Retain one successful live Codex traversal of that real-effects path; current reruns are blocked by a reproducible local DNS/TLS endpoint error. - - [ ] M5.2 closure: reuse the existing bounded Git and verifier foundations - in one successful correlated run, add the manual baseline and minimum - critical negative/restart evidence, and keep raw product data out of public + - [x] Add executable manual workflow accounting: one kickoff plus four checks + plus four relays is a nine-action lower bound, versus one ThreadMesh kickoff. + Keep elapsed time and tokens explicitly unmeasured. + - [x] Add the active-receiver negative: a completion remains pending at a + checkpoint while B stays running, with zero steer, interrupt, or native-turn + starts. + - [ ] M5.2 closure: complete one successful correlated real-effects run and a + measured manual/live baseline while keeping raw product data out of public output. - [ ] M5.3: pass three fresh relevant runs plus the manual baseline, irrelevant, stale/unverified, restart, and cleanup matrix. @@ -196,6 +203,8 @@ to M5.2 evidence. ([#93](https://github.com/fyaic/threadmesh/issues/93)). - [x] Publish the bounded inspector and reproducible deterministic evidence record ([#92](https://github.com/fyaic/threadmesh/issues/92)). +- [x] Publish a 76-second evidence walkthrough generated from fresh executable + demo output, with retained real Codex evidence and honest claim boundaries. The executable closure gates for the real-agent phases are in the [M5 real Codex loop plan](docs/10-planning/m5-real-codex-loop.md). A local @@ -209,6 +218,7 @@ incorrect dependency unlocks. ## M6 — Independent adoption and ecosystem bridges - [ ] Collect three independent setup attempts and one completed real workflow. +- [x] Publish the 15-minute operator challenge and structured report template. - [ ] Close [#79](https://github.com/fyaic/threadmesh/issues/79) with independent harness-author feedback. - [ ] Make ACP the preferred multi-harness gateway. diff --git a/bin/threadmesh.mjs b/bin/threadmesh.mjs index 6d8da5b..5c14386 100644 --- a/bin/threadmesh.mjs +++ b/bin/threadmesh.mjs @@ -22,7 +22,9 @@ if (command !== "demo" || args.some((arg) => arg !== "--json")) { } else { process.stdout.write("ThreadMesh attention-router demo passed.\n"); process.stdout.write(" artifact-ready -> review-failed -> artifact-ready -> dependency-satisfied\n"); - process.stdout.write(" manual relay actions: 0; model polling turns: 0; incorrect unlocks: 0\n"); + process.stdout.write(" manual path lower bound: 9 user actions; ThreadMesh path: 1 kickoff\n"); + process.stdout.write(" relay actions after kickoff: 0; model polling turns: 0; incorrect unlocks: 0\n"); + process.stdout.write(" active receiver: checkpoint retained, 0 steer/interrupt/native-turn starts\n"); process.stdout.write(renderAttentionRouterDemo(result)); } } catch (error) { diff --git a/docs/00-overview/product-guide.md b/docs/00-overview/product-guide.md index 28020a0..e2fc21b 100644 --- a/docs/00-overview/product-guide.md +++ b/docs/00-overview/product-guide.md @@ -1,11 +1,11 @@ # What ThreadMesh is -ThreadMesh is a permissioned coordination layer for agent tasks that run in -separate sessions or harnesses. +ThreadMesh is a permissioned attention and handoff layer for agent tasks that +run in separate sessions or harnesses. -Its job is narrow: let one task discover a pre-authorized relationship, offer a -bounded piece of information to another task, and let the receiving harness -decide whether that information enters its agent context. +Its job is narrow: move completion, blockers, review findings, and verified +dependency state to the right task without making the user copy results, poll +unchanged state, or risk silently redirecting an active receiver. ThreadMesh does **not** merge chat histories, give agents global session access, or let one agent silently rewrite another agent's objective. @@ -17,11 +17,12 @@ Imagine two coding-agent tasks running at the same time: - Agent A builds an artifact and computes its verified checksum. - Agent B prepares a release manifest and cannot finish without that checksum. -Without a coordination layer, the user must notice the dependency, copy the -checksum from A, find B, and paste it into the right session. A naïve automation -can remove the manual step, but it may also inject stale or malicious text into -B, contact the wrong incarnation of B, or interrupt work the user has since -repurposed. +Without a coordination layer, the user must notice the dependency, check A's +status, copy the checksum, find B, and paste it into the right session. Repeat +that across review and fix cycles, and the user becomes the clipboard, poller, +and handoff scheduler. A naïve automation can remove the manual step, but it may +also inject stale or malicious text into B, contact the wrong incarnation, or +interrupt work the user has since repurposed. With ThreadMesh: @@ -78,7 +79,9 @@ The repository is pre-alpha but executable: |---|---| | Portable harness API | Zero-runtime-dependency `@fyaic/threadmesh` SDK with register, discover, suggest, poll, decide, and a per-turn proactive tool bridge | | Reference control plane | Authenticated JSON-RPC binding and SQLite coordinator with grants, mailbox, claims, receipts, replay defense, and audit | -| Deterministic demo | Control, relevant, and irrelevant A-to-B conditions run through the complete coordinator path | +| Deterministic product demo | Four-handoff implementation/review/fix/dependency loop; manual lower bound 9 user actions versus 1 kickoff; active receiver remains running at a pending checkpoint; verified unlock and cleanup pass | +| Real Codex lifecycle initiative | One kickoff advanced A→R→same-A→V→dependent through 9 native turns with 0 later runner prompts/direct activations and 0 irrelevant turns; retained run used simulated Git/verifier effects | +| Real-effects integration | Bounded Git worktrees and process-isolated child verifier are merged into the event pump; deterministic positive and wrong-finding negative pass; fresh live traversal pending | | Codex App Server | The bounded two-stage proactive policy passed relevant 3/3 plus quiet control and irrelevant checks; it remains explicit opt-in | | Kimi Code ACP | A real accepted suggestion completed through the shared coordinator path with session cleanup verified | | Cross-harness proactive case | Real Codex A discovered and sent once; persistent Kimi Code B accepted and completed, with both resources cleaned | @@ -91,10 +94,12 @@ safe handling of arbitrary untrusted peer prompts. ## Fastest way to understand the project -1. Run the [end-to-end demonstration](../06-guides/end-to-end-demo.md). -2. Read the [real agent case portfolio](../06-guides/real-world-cases.md). -3. Check the [harness support matrix](harness-support.md). -4. Read [context sovereignty](../01-concepts/context-sovereignty.md). -5. Follow the [30-minute adapter guide](../06-guides/implement-an-adapter.md). -6. Check [current project status](../10-planning/project-status.md) before using +1. Watch the [76-second proof](../assets/demo/threadmesh-proof-walkthrough.mp4). +2. Run the [attention-router demo](../06-guides/attention-router-demo.md). +3. Read the [real agent case portfolio](../06-guides/real-world-cases.md). +4. Compare the [manual baseline](../06-guides/manual-relay-baseline.md). +5. Check the [harness support matrix](harness-support.md). +6. Read [context sovereignty](../01-concepts/context-sovereignty.md). +7. Follow the [30-minute adapter guide](../06-guides/implement-an-adapter.md). +8. Check [current project status](../10-planning/project-status.md) before using experimental adapters. diff --git a/docs/06-guides/15-minute-operator-challenge.md b/docs/06-guides/15-minute-operator-challenge.md new file mode 100644 index 0000000..5c03411 --- /dev/null +++ b/docs/06-guides/15-minute-operator-challenge.md @@ -0,0 +1,54 @@ +# 15-minute external operator challenge + +The next adoption gate is not another maintainer review. It is whether someone +outside the maintainer organization can reach and explain the value in fifteen +minutes without protocol coaching. + +## Who should try it + +Recruit three operators who already use at least one coding-agent harness. They +do not need ThreadMesh, MCP, ACP, or distributed-systems experience. Maintainers +may observe silently but must not fix the participant's environment during the +clocked attempt. + +## Participant task + +Start a 15-minute timer, then follow only the repository README: + +1. Explain in one sentence what problem ThreadMesh solves. +2. Run the one-command demo from GitHub or a fresh clone. +3. Identify the four lifecycle handoffs. +4. Find why the dependent task became `ready`. +5. Find what happens when the target session is already running. +6. State one workflow where this would or would not be useful. + +Stop the timer when all six are complete or at fifteen minutes. + +## Record the attempt + +Open an +[external operator report](https://github.com/fyaic/threadmesh/issues/new?template=operator.yml) +with: + +- harness and OS, without local paths or identifiers; +- install path used and time to first successful demo; +- the participant's one-sentence explanation; +- first confusing or failed step; +- whether the checkpoint and verified-unlock distinction was understood; +- whether they would use the workflow, and why; +- exact cleanup result. + +Do not include credentials, prompts, transcripts, repository secrets, task or +session IDs, or screenshots that expose private work. + +## Exit criteria + +The gate passes after three independent attempts when: + +- at least two reach a successful demo inside fifteen minutes; +- all three can distinguish delivery from verified dependency unlock; +- no participant believes ThreadMesh is another general chat or workflow DAG; +- failures and confusion are converted into README or setup changes; +- at least one participant names a real workflow they would try next. + +This is formative validation, not a claim of broad product-market fit. diff --git a/docs/06-guides/attention-router-demo.md b/docs/06-guides/attention-router-demo.md index 5a24b26..e9149bd 100644 --- a/docs/06-guides/attention-router-demo.md +++ b/docs/06-guides/attention-router-demo.md @@ -30,7 +30,7 @@ Use the machine-readable form for automation: npm run demo -- --json ``` -The command creates four task incarnations, directional relationship grants, +The command creates five task incarnations, directional relationship grants, an isolated SQLite coordinator, and a versioned product dependency edge. It then publishes these product events through existing `suggest` envelopes: @@ -52,15 +52,30 @@ inspector is rendered. A passing terminal result includes: -- the four sessions and their workstream status; +- the five sessions and their workstream status; - the prerequisite → dependent edge; - the latest lifecycle event and its source provenance; - the routing reason and receiver disposition; - external-verification and dependency-effect state; - zero manual relay actions, model polling turns, and incorrect unlocks; - four bounded durable-cursor reconciliations, including the dropped-wake path; +- an active receiver that remains `running` while a completion waits as a + `checkpoint-offer`, with zero steer, interrupt, or native-turn starts; +- an unsubscribed control that produces zero offers; - successful deletion of the temporary database and runtime directory. +The JSON output also contains an executable workflow-accounting comparison: + +| Path | Kickoffs | Status checks | Relay actions | User actions | +|---|---:|---:|---:|---:| +| Manual lower bound | 1 | 4 | 4 | at least 9 | +| ThreadMesh demo | 1 | 0 | 0 | 1 | + +This comparison counts the minimum visible actions implied by the four-handoff +workflow. It is not a human timing study and does not estimate model tokens. +Those fields remain explicitly `notMeasured` until the +[live manual baseline](manual-relay-baseline.md) is retained. + The JSON form is deterministic and excludes temporary paths, private keys, raw event content, and credentials. The inspector rejects absolute paths, content-shaped fields, unsupported states, and contradictory unlock claims. @@ -79,8 +94,16 @@ and the verifier retains the private key. This proves the trust boundary and signature checks, not organizational independence. The installed package now includes the local runtime and native SQLite dependency; consumers that need only the SDK should import the root SDK surface -and avoid runtime subpaths. The real Codex implementation/review/fix case -remains the next M5 gate. +and avoid runtime subpaths. The merged real-effects integration and the +retained real Codex behavior are separate evidence. A fresh network-valid real +Codex traversal of their combined path remains the next M5 gate. + +## Watch the evidence walkthrough + +[Open the 76-second MP4](../assets/demo/threadmesh-proof-walkthrough.mp4). The +README GIF is generated by `npm run demo:assets`; the builder runs this demo +afresh and rejects mismatched evidence before rendering. See the +[asset provenance note](../assets/demo/README.md). For model-selected behavior already validated on narrower advisory cases, see the [real agent case portfolio](real-world-cases.md). For the active product diff --git a/docs/06-guides/manual-relay-baseline.md b/docs/06-guides/manual-relay-baseline.md new file mode 100644 index 0000000..a8ff0cc --- /dev/null +++ b/docs/06-guides/manual-relay-baseline.md @@ -0,0 +1,78 @@ +# Manual relay and polling baseline + +This baseline answers a product question, not a protocol question: + +> How much operator work disappears when four dependent handoffs advance from +> one kickoff? + +## Executable workflow accounting + +Run: + +```sh +npm run demo -- --json +``` + +The `comparison` object reports this lower bound: + +| Path | Initial kickoffs | Status checks | Copy/relay actions | Total | +|---|---:|---:|---:|---:| +| Manual workflow | 1 | 4 | 4 | at least 9 | +| ThreadMesh demo | 1 | 0 | 0 | 1 | + +The four handoffs are `artifact-ready`, `review-failed`, the fixed +`artifact-ready`, and `dependency-satisfied`. A manual operator must notice each +state transition and carry it to the next session. The table assumes only one +status check per transition, so it is deliberately a lower bound. + +This is **modeled workflow accounting**, not observed human performance. The +demo reports `elapsed-time` and `model-tokens` under `notMeasured` rather than +inventing a speedup or cost claim. + +## Measured live protocol + +Run the same implementation/review/fix/verification objective twice on the same +host, checkout, model configuration, and network: + +1. Manual arm: disable cross-session delivery. The operator checks status and + relays each bounded result by hand. +2. ThreadMesh arm: send one kickoff and allow only the bounded + `checkpoint-offer` event pump to advance the chain. +3. Retain exact start/end timestamps and public aggregate counts. Keep prompts, + transcripts, local paths, credentials, and session IDs private. +4. Abort both arms if model, checkout, endpoint, or task objective differs. + +Record: + +| Field | Definition | +|---|---| +| `initialKickoffs` | User messages that begin the objective | +| `manualRelayActions` | User messages that carry output between sessions | +| `manualStatusChecks` | User-initiated status or wait requests | +| `modelPollingTurns` | Model turns whose primary job is checking unchanged state | +| `elapsedMs` | First kickoff to verified dependent-ready state | +| `inputTokens` | Uncached input tokens reported by the product | +| `cachedInputTokens` | Cached input tokens reported by the product | +| `outputTokens` | Output tokens reported by the product | +| `activeReceiverInterruptions` | Active work redirected before a checkpoint | +| `duplicateDeliveries` | Same logical handoff admitted more than once | + +Success requires exact cleanup, zero incorrect unlocks, zero active-receiver +interruptions, and comparable final artifacts in both arms. Report raw product +usage only when the product exposes it; do not infer token counts from text +length. + +## Current status + +- Workflow accounting: complete and executable. +- Live ThreadMesh behavior: one retained real Codex chain completed after one + kickoff, with nine native turns and zero later runner prompts or direct + activations; its Git/verifier effects were simulated. +- Real-effects code path: merged on `main` in + [#133](https://github.com/fyaic/threadmesh/pull/133). +- Measured manual/live comparison: pending a host that resolves and reaches the + valid Codex endpoint. The current host's reproducible DNS/TLS failure makes a + fresh comparison invalid rather than negative product evidence. + +No elapsed-time or token reduction should be advertised until the measured +protocol passes. diff --git a/docs/06-guides/non-interrupting-handoff.md b/docs/06-guides/non-interrupting-handoff.md new file mode 100644 index 0000000..af535aa --- /dev/null +++ b/docs/06-guides/non-interrupting-handoff.md @@ -0,0 +1,56 @@ +# Non-interrupting active-session handoff + +The highest-risk happy path is not an idle receiver. It is this one: + +> A finishes while B is actively editing. Can the result remain available +> without changing B's current direction? + +## Run the deterministic safety case + +```sh +npm run demo -- --json +``` + +Inspect `safety.activeCheckpoint`. A passing result requires: + +```json +{ + "requestedDeliveryMode": "checkpoint-offer", + "receiverDecision": "pending", + "receiverStateBefore": "running", + "receiverStateAfter": "running", + "steerRequests": 0, + "interruptRequests": 0, + "nativeTurnStarts": 0 +} +``` + +The event is durably retained in the receiver mailbox. The demo deliberately +does not claim it, admit it, invoke the native harness, or reinterpret it as a +user instruction. An additional subscription control returns +`attention-event-type-not-subscribed` and produces zero offers. + +## Why this matters + +These states must remain separate: + +```text +durably retained +!= admitted to model context +!= active work redirected +!= receiver accepted +!= claim verified +!= downstream action authorized +``` + +ThreadMesh's real product experiments enable only bounded `suggest` through +`checkpoint-offer`. Unsupported `steer` and `interrupt` behavior fails closed. + +## Evidence boundary + +This deterministic case proves coordinator and policy behavior. It does not +prove that every native agent product implements a non-interrupting queue. +Native delivery semantics vary, and Codex cross-task delivery still needs a +fresh real active-target observation before that product behavior is promoted +to evidence. Until then, adapters must keep the mailbox as truth and avoid +injecting pending peer content into an active turn. diff --git a/docs/06-guides/real-world-cases.md b/docs/06-guides/real-world-cases.md index 410837b..e60a804 100644 --- a/docs/06-guides/real-world-cases.md +++ b/docs/06-guides/real-world-cases.md @@ -15,10 +15,41 @@ reproduction and audit. | Case | Agent A | Agent B | Initiative observed | Receiver outcome | Evidence | |---|---|---|---|---|---| +| Codex lifecycle chain | Codex CLI `0.145.0`, implementation/review/fix/verifier roles | Codex dependent + irrelevant control | One kickoff; 9 native turns; 0 later phase prompts/direct activations; irrelevant 0 turns | Dependent ran only after accepted finalization; cleanup 5/5 | [behavior](../09-reviews/2026-09-01-m5-2-real-codex-event-pump-behavior.md) · [real-effects status](../09-reviews/2026-09-01-m5-2-real-effects-integration.md) | | Pi → Kimi | Pi `0.84.2`, `zai/glm-5.3` | Kimi Code `0.38.0`, ACP v1 | Relevant: discover + send; irrelevant: discover only; control: zero calls | One advisory input accepted and admitted; exact marker | [Guide](pi-to-kimi-demo.md) · [record](../09-reviews/2026-08-25-pi-integration-kit-validation.md) | | Codex → Kimi | Codex CLI `0.145.0`, `gpt-5.6-sol` | Kimi Code `0.38.0`, ACP v1 | Codex selected the exact discover → send sequence with no other tool | Missing dependency became completed benchmark outcome | [record](../09-reviews/2026-08-25-codex-to-kimi-proactive.md) | | Codex same-product matrix | Codex CLI `0.145.0` | Codex CLI `0.145.0` | Two-stage policy passed relevant 3/3; fresh irrelevant read only; control stayed quiet | B activated only on relevant send | [behavior gate](../09-reviews/2026-08-25-codex-behavior-gate.md) · [repetitions](../09-reviews/2026-08-25-codex-behavior-repetitions.md) | +## Flagship case — a review loop advances itself + +The sixth retained Codex event-pump attempt is the clearest evidence of the +session initiative that motivated ThreadMesh. The operator kicked off A once. +After that, durable lifecycle attention advanced: + +```text +A implementation → R review → same-A fix → V verification → dependent +``` + +The run contained nine real native Codex turns and zero later runner phase +prompts or direct activations. The authorized irrelevant session ran zero +turns. The dependent ran only after accepted finalization, and five of five +sessions plus coordinator artifacts were removed. + +This retained run proves real model/session behavior, but its Git and verifier +effects were simulated. [#133](https://github.com/fyaic/threadmesh/pull/133) +subsequently merged real bounded Git worktrees and a process-isolated child +verifier into the same event-pump path. A fresh combined live traversal remains +pending a network-valid host, so the two evidence sets are not silently fused +into a stronger claim. + +The deterministic one-command demo complements that evidence with two +reproducible product checks: a four-handoff workflow has a manual lower bound of +nine user actions versus one kickoff, and a running receiver retains the event +at a checkpoint with zero steer, interrupt, or native-turn starts. See the +[demo guide](attention-router-demo.md), +[manual baseline](manual-relay-baseline.md), and +[active-session safety case](non-interrupting-handoff.md). + ## Case 1 — Pi notices a Kimi dependency ### Situation diff --git a/docs/07-research/community-signals.md b/docs/07-research/community-signals.md index 63930d1..c78491d 100644 --- a/docs/07-research/community-signals.md +++ b/docs/07-research/community-signals.md @@ -1,9 +1,26 @@ # Community signals around cross-task agent coordination -> Research snapshot: 2026-08-28. GitHub issues are community reports unless an +> Research snapshot: 2026-09-01. GitHub issues are community reports unless an > OpenAI contributor explicitly confirms product status. They are evidence of > demand and failure modes, not a stable API contract. +## 2026-09-01 delivery-mode update + +The most useful new distinction is no longer whether Codex can retain queued +work. Its public App Server surface now exposes persistent queue operations. +The remaining gap reported in +[#30499](https://github.com/openai/codex/issues/30499) is cross-task delivery: +the send operation does not give the caller an explicit queue/checkpoint/steer +mode, durable message identity, or inspectable delivery state, and an active +target can still be redirected. + +This sharpens ThreadMesh's wedge. It should not build another generic queue. It +should make the attention decision and admission contract portable: mailbox as +truth, explicit checkpoint offer, zero implicit active-turn steer, and a state +record explaining whether the event was retained, admitted, verified, or used +to unlock work. The deterministic active-receiver case now makes this product +claim executable; a real native active-target observation remains pending. + ## 2026-08-28 observation update The strongest new conclusion is that transport is becoming less distinctive diff --git a/docs/09-reviews/2026-09-01-m5-2-real-codex-event-pump-attempt-audit.md b/docs/09-reviews/2026-09-01-m5-2-real-codex-event-pump-attempt-audit.md index fb04f68..a8b6bbd 100644 --- a/docs/09-reviews/2026-09-01-m5-2-real-codex-event-pump-attempt-audit.md +++ b/docs/09-reviews/2026-09-01-m5-2-real-codex-event-pump-attempt-audit.md @@ -6,6 +6,9 @@ Latest completed behavioral `main`: `f98c56b83057b43f8b9618d6f69e1b2f481f77bd` Latest real-effects integration attempt: `1845d86` +Subsequent merged integration: [#133](https://github.com/fyaic/threadmesh/pull/133) +at `5ec7b19`; no later live attempt is claimed + Classification: ten live attempts; attempt 6 completed the real autonomous behavioral chain, while attempts 7–10 exercised the real Git/child-verifier integration without completing its end-to-end product gate diff --git a/docs/09-reviews/2026-09-01-m5-2-real-codex-event-pump-behavior.md b/docs/09-reviews/2026-09-01-m5-2-real-codex-event-pump-behavior.md index 102e3b3..5d2ccaa 100644 --- a/docs/09-reviews/2026-09-01-m5-2-real-codex-event-pump-behavior.md +++ b/docs/09-reviews/2026-09-01-m5-2-real-codex-event-pump-behavior.md @@ -106,8 +106,9 @@ the [attempt audit](2026-09-01-m5-2-real-codex-event-pump-attempt-audit.md). ## Follow-on real-effects integration -The next branch now reuses the existing bounded Git fixture and process-isolated -child verifier in this same event-pump path. Four follow-on live attempts +[#133](https://github.com/fyaic/threadmesh/pull/133) now reuses the existing +bounded Git fixture and process-isolated child verifier in this same event-pump +path on `main`. Four follow-on live attempts created real implementation commits and reached R, but none completed the integrated chain. The latest attempt coincided with a reproducible local DNS/TLS failure that resolved `chatgpt.com` to a Meta endpoint and presented a diff --git a/docs/09-reviews/2026-09-01-m5-2-real-effects-integration.md b/docs/09-reviews/2026-09-01-m5-2-real-effects-integration.md index fc5e185..3eedcff 100644 --- a/docs/09-reviews/2026-09-01-m5-2-real-effects-integration.md +++ b/docs/09-reviews/2026-09-01-m5-2-real-effects-integration.md @@ -2,7 +2,8 @@ Date: 2026-09-01 -Integration branch: `feat/m52-event-pump-real-effects` +Merged integration: [#133](https://github.com/fyaic/threadmesh/pull/133), +`main` commit `5ec7b19` Status: implementation complete; real Codex end-to-end rerun blocked by local DNS/TLS failure @@ -104,7 +105,31 @@ retained. The current claims are therefore: - manual relay/polling baseline and minimum negative/restart closure: pending. - bounded partial-progress manifests for interrupted live attempts: pending. +The product-proof branch adds two deterministic closure aids without promoting +them to live evidence: + +- executable manual workflow accounting: at least nine user actions for the + four-handoff manual path versus one ThreadMesh kickoff; elapsed time and token + counts remain unmeasured; +- an active-receiver negative: completion is retained as a pending + `checkpoint-offer`, receiver state stays `running`, and zero steer, interrupt, + or native-turn starts occur. + +## Product-proof preflight + +A fresh preflight on 2026-09-01 did not start another live attempt: + +- `codex doctor --summary` reported healthy auth/configuration and HTTP + reachability, but the Responses WebSocket timed out; +- the system resolver still returned non-OpenAI addresses for `chatgpt.com`, + including the previously observed Meta IPv6 range; +- a certificate-verifying HTTPS request timed out during SSL connection after + five seconds; +- no DNS, proxy, certificate, or TLS setting was changed. + +This is an external environment blocker, not a ThreadMesh pass or failure. + The next action is one fresh live rerun after the machine resolves `chatgpt.com` to a valid OpenAI endpoint and `codex doctor` no longer reports -the WebSocket certificate failure. Do not change protocol logic or bypass TLS +the WebSocket failure. Do not change protocol logic or bypass TLS to compensate for this network condition. diff --git a/docs/10-planning/mainline-plan.md b/docs/10-planning/mainline-plan.md index 65a14d8..7fbddd6 100644 --- a/docs/10-planning/mainline-plan.md +++ b/docs/10-planning/mainline-plan.md @@ -18,9 +18,10 @@ experiments are explicitly labeled and do not satisfy it. ## Active critical path — 2026-09-01 M5.2 remains the only implementation critical path. The behavioral question is -answered by the completed sixth Codex run; the active checkpoint is now a -successful traversal of the same path with real bounded Git effects and the -existing process-isolated child verifier. +answered by the completed sixth Codex run. The bounded Git effects and existing +process-isolated child verifier are integrated on `main` by #133. The active +checkpoint is now a successful network-valid traversal of that merged path, +followed by measured baseline and external first-run evidence. The older product canary proved real multi-tool turns, same-A reuse, a bounded Git chain, controls, and cleanup, but its four prompts were runner-submitted. @@ -47,17 +48,21 @@ Execute in this order: verifier path. Wait for the currently reproducible local DNS/TLS endpoint failure to clear; do not bypass certificate validation or redesign the protocol around it. -3. Add the manual relay/polling baseline and the minimum critical - negative/restart case required by #91; publish the result without upgrading - simulated or operator-supplied evidence. -4. Close #91 only when its original outcome is satisfied, then resume +3. Retain the measured manual/live baseline. The executable demo already + reports a nine-action manual lower bound versus one kickoff, but elapsed time + and tokens remain explicitly unmeasured. +4. Observe three independent operators using only the README and 15-minute + challenge; convert friction into product or documentation fixes. +5. Close #91 only when its original outcome is satisfied, then resume repetition, Kimi parity, and production-hardening evidence. Mainline guardrail: do not add a new substrate or generalize an existing one unless the current live chain demonstrates that it is the blocking condition. OS-kill matrices, long-turn heartbeat, a global cross-dispatch chain, new -harnesses, A2A/Cotal work, hosted operation, and presentation-only polish are -paused. Small PRs remain acceptable; scope, not PR size, is the constraint. +harnesses, A2A/Cotal work, hosted operation, and new transport/protocol surface +are paused. The evidence walkthrough is complete and must now be judged by +external first-run attempts. Small PRs remain acceptable; scope, not PR size, +is the constraint. The detailed historical gates remain in the [real Codex scenario plan](m5-2-real-codex-scenario.md). The diff --git a/docs/10-planning/product-mainline-2026-08-28.md b/docs/10-planning/product-mainline-2026-08-28.md index 03a3a65..3a6114f 100644 --- a/docs/10-planning/product-mainline-2026-08-28.md +++ b/docs/10-planning/product-mainline-2026-08-28.md @@ -146,19 +146,22 @@ successively narrower boundaries. A sixth completed the full real proactive chain with one kickoff, nine bound native turns, zero later runner prompts or direct activations, an irrelevant zero-turn control, and exact cleanup. -Real session initiative is now retained. The next evidence must close the -original workflow effect without replacing the proven path. Execute in this -order: +Real session initiative is now retained, and #133 has merged the bounded Git +worktrees plus process-isolated child verifier into the same event-pump path. +The next evidence must close the original workflow effect without replacing +the proven path. Execute in this order: 1. preserve the sixth run as the behavioral baseline; do not repeat it for presentation polish; -2. reuse the existing bounded Git-worktree foundation so A's implementation and - same-A fix are observable commits in the same correlated run; -3. reuse the child-verifier boundary so independently held signing custody binds - finalization to those commits, the finding, and the test result; -4. add the manual baseline plus minimum critical negative/restart evidence and - close #91 only when its original product outcome passes; -5. then resume repetition and Kimi parity. +2. retain one network-valid real Codex traversal of the merged real-effects + path; do not fuse the earlier behavioral run with later deterministic + integration evidence; +3. run the measured manual/live baseline; the executable nine-action lower + bound is product framing, not a substitute for timing or token measurement; +4. observe three external operators using only the README and 15-minute setup + challenge, fixing first-run friction before broadening scope; +5. close #91 only when the original product outcome passes, then resume + repetition and Kimi parity. The acceptance run requires A to publish an implementation, R to discover and publish a reproducible finding, the original A session/worktree to fix it, and @@ -168,9 +171,9 @@ admission, native turn, publication, or dependency effect after its precreation/bootstrap baseline. OS-kill and heartbeat matrices, a global cross-dispatch chain, Kimi parity, new -harnesses, verifier/Git generalization, and presentation-only polish remain -paused. Small PRs remain acceptable; every change must serve the integrated -Git/verifier closure or an observed blocker. +harnesses, verifier/Git generalization, and new transport/protocol surface +remain paused. Small PRs remain acceptable; every change must serve the live +closure, measured baseline, external setup gate, or an observed blocker. ## Roadmap: Now / Next / Later @@ -203,6 +206,11 @@ under 15 minutes. 6. Record a 60–90 second README demo and a reproducible evidence document ([#92](https://github.com/fyaic/threadmesh/issues/92)). +Items 1–3, 5, and 6 now have deterministic public evidence. Item 4 has retained +real behavior plus merged real-effects integration; the fresh combined live run +remains open. The README walkthrough is generated from executable output and +labels its real-versus-deterministic evidence boundary. + ### Next — prove independent adoption and ecosystem fit Outcome: someone outside the maintainer organization integrates an existing diff --git a/docs/10-planning/project-status.md b/docs/10-planning/project-status.md index 96ba292..bf4b47e 100644 --- a/docs/10-planning/project-status.md +++ b/docs/10-planning/project-status.md @@ -1,13 +1,15 @@ # Project status > Snapshot: 2026-09-01 after behavioral `main` commit -> `f98c56b83057b43f8b9618d6f69e1b2f481f77bd` and real-effects integration -> commit `1845d86`. Technical evidence includes the +> `f98c56b83057b43f8b9618d6f69e1b2f481f77bd` and merged real-effects +> integration [#133](https://github.com/fyaic/threadmesh/pull/133) at +> `5ec7b19`. Technical evidence includes the > deterministic no-plan autonomous fixture, the earlier runner-sequenced real > Codex canary, nine fail-closed event-pump attempts, and one completed real > autonomous behavioral chain. Real Git and child-verifier wiring is complete, -> but its successful Codex rerun, a manual baseline, and critical closure cases -> remain pending. +> but its successful Codex rerun and measured manual/live baseline remain +> pending. Deterministic workflow accounting and the active-receiver checkpoint +> negative are executable in the public demo. ## Executive summary @@ -27,16 +29,17 @@ interoperability, hostile-peer safety, or production reliability. The normative M0 blockers are resolved; M0 remains open only for two independent reviews, including one outside the maintainer organization. -The current product gap is sharper than the technical gap. ThreadMesh has no -independent adopter, and its one-message demonstration does not yet remove a -meaningful workflow burden. The deterministic and fail-closed results support -the technical direction, but execution order became imbalanced: generalized -durability, verifier/Git proof, and recovery advanced before one uninterrupted -real proactive chain was retained. The active mainline is therefore an -[attention and handoff router](product-mainline-2026-08-28.md): a one-command, -observable implementation/review/fix loop that eliminates manual relay and -polling while preserving receiver control. Non-mainline expansion is paused -until this outcome is demonstrated. +The current product gap is adoption, not another transport feature. ThreadMesh +still has no independent setup attempt. The public demo now makes the workflow +burden concrete: a four-handoff manual path has a lower bound of nine user +actions versus one kickoff, and a running receiver retains a completion at a +checkpoint without steer, interrupt, or native-turn start. That is executable +product evidence, not measured human timing or live native queue evidence. The +active mainline remains the +[attention and handoff router](product-mainline-2026-08-28.md). New harness, +transport, and generalized protocol expansion is paused until a network-valid +real-effects traversal, the measured baseline, and three external 15-minute +setup attempts are retained. ## Evidence ledger @@ -44,7 +47,7 @@ until this outcome is demonstrated. |---|---|---| | Research and problem framing | Codex deep dive, community signals, ecosystem comparison, ADRs | Established | | Community adoption | No external stars, forks, watchers, issue comments, or independent setup result as of 2026-08-28 | Unvalidated | -| Active product outcome | One-command lifecycle-event and dependency-handoff loop with an inspector | Real Codex A/R/same-A/V/dependent behavioral chain completed after one kickoff; independent Git/verifier closure pending | +| Active product outcome | One-command lifecycle-event and dependency-handoff loop with inspector, manual-action accounting, active-receiver checkpoint negative, and 76-second walkthrough | Real Codex A/R/same-A/V/dependent behavioral chain completed after one kickoff; real Git/verifier path merged; combined network-valid rerun pending | | Protocol draft | 14 JSON Schemas; 55 schema cases; 7 transition cases; 384 tests | Executable draft; counts are reported separately | | Minimal adapter SDK | `@fyaic/threadmesh` `0.1.0-alpha.0`; six bounded client methods, per-turn proactive bridge, about 20 kB tarball, packed-consumer execution | Real Pi clean-consumer pass; not published to npm | | Local binding | Schema-validated JSON-RPC, transport-derived principals, typed errors | Executable local reference | @@ -62,7 +65,7 @@ until this outcome is demonstrated. | Codex-to-Kimi proactive flow | Codex A selected discovery and one send; persistent Kimi ACP B completed; exact A deletion and B delete/absence passed at `e0adb0e` | First real cross-harness proactive case passed | | Pi integration-kit flow | Fresh packed consumer exposed exactly two native tools; real Pi passed relevant/irrelevant/control behavior and supplied one admitted input to Kimi at `02d8d24` | Maintainer integration passed; independent human feedback pending | | Codex M5 attention seam | Real persistent A model-selected discovery/publication; durable cursor resumed the pre-created persistent B exactly once; local verification unlocked the dependency and restart recovered B as ready at `3d5caee` | M5.1 passed; logical wake only, local verifier simulation; M5.2/M5.3 pending | -| M5.2 Git evidence foundation | Independent temporary bare repo and role worktrees, same-worktree implementer fix, SQLite v5 evidence chains, SQLite v6 turn/cursor recovery, SQLite v7 bound verifier-only atomic unlock, private signed-result recovery journal, five controlled coordinator-reopen checkpoints, and a preconfigured-key child verifier bound to exact commits/finding/test | Deterministic safety, persistence, model-action receipt, authority, and coordinator-reopen recovery seams passed; integrated process-crash recovery and coordinator-driven real loop pending | +| M5.2 Git/verifier real-effects path | Independent temporary bare repo and role worktrees, same-worktree implementer fix, exact commit/finding/test binding, and process-isolated child verifier wired into the autonomous event pump by #133 | Deterministic positive and wrong-finding negative pass; fresh real Codex traversal pending network-valid endpoint | | M5.2 real Codex model/tool canary | Five persistent roles; four real A/R/same-A/V turns; seven model-selected tool calls; exact two-commit chain; same-A identity/worktree; dependent and irrelevant zero-turn controls; five-of-five cleanup on base `1155fc8` | Canary completed; intentionally `blocked` with `liveProductEvidence=false` because the runner submitted four phase prompts and ThreadMesh performed no lifecycle handoff | | M5.2 autonomous no-plan fixture | One user kickoff; durable SQLite attention drives A→R→same-A→V→dependent; zero fixture-runner activation dispatches or phase/business prompts; zero manual relay and polling; pump starts protected receiver turns; trusted finalization precedes dependent turn; exact cleanup | Deterministic in-process fixture at `711da66`; per-dispatch recovery durable, global chain absent; OS kill/heartbeat/live products/external verifier pending | | M5.2 real event-pump attempts | Six attempts: five bounded fail-closed stops, then one complete real Codex A/R/same-A/V/dependent chain with one kickoff, nine bound turns, eight business tool calls, zero later runner prompts/direct activations, an irrelevant zero-turn control, and exact cleanup | Behavioral checkpoint passed; result remains honestly `blocked`/`liveProductEvidence=false` because Git effects and verifier custody are simulated; M5.2 remains open | @@ -295,14 +298,16 @@ temporary-resource cleanup. See the [attempt audit](../09-reviews/2026-09-01-m5-2-real-codex-event-pump-attempt-audit.md) and [behavior record](../09-reviews/2026-09-01-m5-2-real-codex-event-pump-behavior.md). -The sequencing decision is now explicit: retain the proven path and reuse the -existing bounded Git-worktree and verifier foundations inside it. Add the -manual baseline and minimum critical negative/restart evidence; do not build a -new substrate. OS-kill and heartbeat matrices, a global cross-dispatch chain, -Kimi parity, new harnesses, and further presentation work remain frozen. The -completed chain is still `blocked` and `liveProductEvidence=false` because its -Git effects and verifier custody are simulated; it clears the behavioral -checkpoint, not M5.2. +The sequencing decision is now explicit. The existing bounded Git worktrees and +child verifier are integrated in #133; deterministic positive and wrong-finding +negative cases pass. The public demo adds a modeled manual-action baseline and +active-receiver checkpoint negative. Next, retain one network-valid real Codex +traversal, run the measured manual arm, and observe three external operators. +OS-kill and heartbeat matrices, a global cross-dispatch chain, Kimi parity, new +harnesses, and transport/protocol expansion remain frozen. The completed live +behavioral chain is still `blocked` and `liveProductEvidence=false` because its +Git effects and verifier custody were simulated; the merged integration is not +silently combined with that earlier run. The Codex context-admission turn now uses the same private pre-turn baseline, fsynced journal, exact client key, and read-first restart boundary. The journal diff --git a/docs/README.md b/docs/README.md index 9d477ea..e2b01d0 100644 --- a/docs/README.md +++ b/docs/README.md @@ -8,23 +8,26 @@ evidence. New readers do not need to read every numbered directory in order. 1. [What ThreadMesh is](00-overview/product-guide.md) 2. [See the real proactive-agent cases](06-guides/real-world-cases.md) 3. [Run the closed-loop attention-router demo](06-guides/attention-router-demo.md) -4. [Validate the real Codex attention seam](06-guides/codex-attention-validation.md) -5. [Check harness support](00-overview/harness-support.md) -6. [Read the active product mainline](10-planning/product-mainline-2026-08-28.md) -7. [Current project status](10-planning/project-status.md) -8. [Context sovereignty](01-concepts/context-sovereignty.md) -9. [Reference architecture](02-architecture/reference-architecture.md) -10. [Protocol overview](03-protocol/README.md) -11. [Threat model](04-safety/threat-model.md) -12. [30-minute adapter guide](06-guides/implement-an-adapter.md) +4. [Compare manual relay with one kickoff](06-guides/manual-relay-baseline.md) +5. [Inspect the active-session safety case](06-guides/non-interrupting-handoff.md) +6. [Try the 15-minute operator challenge](06-guides/15-minute-operator-challenge.md) +7. [Check harness support](00-overview/harness-support.md) +8. [Read the active product mainline](10-planning/product-mainline-2026-08-28.md) +9. [Current project status](10-planning/project-status.md) +10. [Context sovereignty](01-concepts/context-sovereignty.md) +11. [Reference architecture](02-architecture/reference-architecture.md) +12. [Protocol overview](03-protocol/README.md) +13. [Threat model](04-safety/threat-model.md) +14. [30-minute adapter guide](06-guides/implement-an-adapter.md) ## Choose a path | Goal | Read or run | |---|---| | Understand the product | [Product guide](00-overview/product-guide.md) → [proactive coordination](01-concepts/proactive-coordination.md) | -| See the intelligence effect | [Real case portfolio](06-guides/real-world-cases.md) → [Pi-to-Kimi demo](06-guides/pi-to-kimi-demo.md) | -| Run it locally | [Attention-router demo](06-guides/attention-router-demo.md) → [real Codex attention validation](06-guides/codex-attention-validation.md) → [selective behavior demo](06-guides/end-to-end-demo.md) → [cross-harness conformance](06-guides/multi-product-admission-conformance.md) | +| See the intelligence effect | [76-second walkthrough](assets/demo/threadmesh-proof-walkthrough.mp4) → [real case portfolio](06-guides/real-world-cases.md) | +| Evaluate user value | [Manual baseline](06-guides/manual-relay-baseline.md) → [15-minute operator challenge](06-guides/15-minute-operator-challenge.md) | +| Run it locally | [Attention-router demo](06-guides/attention-router-demo.md) → [active-session safety](06-guides/non-interrupting-handoff.md) → [real Codex attention validation](06-guides/codex-attention-validation.md) | | Integrate a harness | [Harness matrix](00-overview/harness-support.md) → [adapter guide](06-guides/implement-an-adapter.md) → [adapter contract](05-adapters/adapter-contract.md) | | Evaluate safety | [Context sovereignty](01-concepts/context-sovereignty.md) → [permission model](04-safety/permission-model.md) → [threat model](04-safety/threat-model.md) | | Inspect real evidence | [Design reviews](09-reviews/README.md) → [Pi integration record](09-reviews/2026-08-25-pi-integration-kit-validation.md) → [Codex-to-Kimi case](09-reviews/2026-08-25-codex-to-kimi-proactive.md) | diff --git a/docs/assets/demo/README.md b/docs/assets/demo/README.md new file mode 100644 index 0000000..ceef292 --- /dev/null +++ b/docs/assets/demo/README.md @@ -0,0 +1,31 @@ +# Demo asset provenance + +`threadmesh-proof-walkthrough.mp4` is a 76-second evidence walkthrough. The GIF +is the README preview and the PNG is its cover. + +The walkthrough is generated from a fresh successful execution of: + +```sh +node bin/threadmesh.mjs demo --json +``` + +`scripts/build-demo-assets.mjs` asserts the expected workflow accounting, +active-receiver checkpoint behavior, verified dependency result, and cleanup +before rendering any frame. Rebuild it with: + +```sh +npm run demo:assets +``` + +## Claim boundary + +This is not a live screen recording and it is not presented as one. It combines: + +- fresh deterministic coordinator evidence from the command above; +- retained real Codex behavior evidence from the sixth M5.2 event-pump run; +- explicit labels where that retained run used simulated Git/verifier effects; +- the current real-effects status on `main`. + +The visual sequence is an evidence-led explanation of tested behavior, not a +reconstruction of a hidden product UI. The full records remain in +`docs/09-reviews/`. diff --git a/docs/assets/demo/threadmesh-proof-walkthrough-cover.png b/docs/assets/demo/threadmesh-proof-walkthrough-cover.png new file mode 100644 index 0000000..4896d28 Binary files /dev/null and b/docs/assets/demo/threadmesh-proof-walkthrough-cover.png differ diff --git a/docs/assets/demo/threadmesh-proof-walkthrough.gif b/docs/assets/demo/threadmesh-proof-walkthrough.gif new file mode 100644 index 0000000..a975008 Binary files /dev/null and b/docs/assets/demo/threadmesh-proof-walkthrough.gif differ diff --git a/docs/assets/demo/threadmesh-proof-walkthrough.mp4 b/docs/assets/demo/threadmesh-proof-walkthrough.mp4 new file mode 100644 index 0000000..03e9c0e Binary files /dev/null and b/docs/assets/demo/threadmesh-proof-walkthrough.mp4 differ diff --git a/docs/zh-CN/README.md b/docs/zh-CN/README.md index 8ac1050..7b0ac09 100644 --- a/docs/zh-CN/README.md +++ b/docs/zh-CN/README.md @@ -1,22 +1,24 @@ # ThreadMesh 中文文档 -ThreadMesh 是一个面向多种 agent harness 的安全主动协调层。它让 agent 能够发现 -跨任务依赖并主动通信,同时保护接收任务的上下文主权。 +ThreadMesh 是一个面向多种 agent harness 的安全 attention 与 handoff 层。它让 +agent 在依赖真正满足时自行交接,用户不用复制、轮询,也不会随意打断另一个 +session。 当前英文规范是 canonical source;中文目录负责解释核心理念并降低参与门槛。 ## 推荐阅读 1. [ThreadMesh 是什么](product-guide.md) -2. [真实 Agent 主动协调案例总览](../06-guides/real-world-cases.md) -3. [端到端 A→B 案例](../06-guides/end-to-end-demo.md) -4. [Harness 支持与证据矩阵](../00-overview/harness-support.md) -5. [真实 Pi→Kimi 案例](../06-guides/pi-to-kimi-demo.md) -6. [愿景](vision.md) -7. [安全模型](safety-model.md) -8. [Codex 主动跨任务协调调研摘要](research-summary.md) -9. [当前项目状态](../10-planning/project-status.md) -10. [英文文档总览](../README.md) +2. [76 秒证据演示](../assets/demo/threadmesh-proof-walkthrough.mp4) +3. [真实 Agent 主动协调案例总览](../06-guides/real-world-cases.md) +4. [人工转发与轮询基线](../06-guides/manual-relay-baseline.md) +5. [活跃 session 不打断案例](../06-guides/non-interrupting-handoff.md) +6. [Harness 支持与证据矩阵](../00-overview/harness-support.md) +7. [愿景](vision.md) +8. [安全模型](safety-model.md) +9. [Codex 主动跨任务协调调研摘要](research-summary.md) +10. [当前项目状态](../10-planning/project-status.md) +11. [英文文档总览](../README.md) ## 一句话理解 @@ -46,8 +48,14 @@ Pi→Kimi 与 Codex→Kimi 的真实案例已经观察到 relevant 条件下的 ## 当前进度 -- 284 项 unit/subtest、14 个 schema 和状态转换测试通过。 -- control / relevant / irrelevant 的确定性 A→B 演示通过完整 coordinator 路径。 +- 384 项测试、55 个 schema case 和 7 个状态转换 case 通过。 +- 一键 demo 完成四次生命周期交接、验证后依赖解锁、活跃接收方 checkpoint 和 + 无关订阅零 offer;人工路径最低 9 次用户操作,ThreadMesh 路径 1 次 kickoff。 +- 第六次真实 Codex event-pump 在一次 kickoff 后通过 9 个 native turn 完成 + A→R→同一个 A→V→dependent;后续 runner prompt/direct activation 为 0, + irrelevant turn 为 0,清理 5/5。该次 Git/verifier effect 是模拟的。 +- 真实 Git worktree 与 child verifier 已由 #133 合入同一路径;组合后的 live + 重跑受当前 host 的 DNS/TLS 故障阻塞。 - Codex 真实主动 A→B 曾把接收方结果从缺少依赖提升到完成,但重复可靠性不足, 因此 proactive 默认关闭。 - Kimi Code `0.38.0` 已完成真实 receiver-accepted suggestion,并验证 session @@ -58,8 +66,8 @@ Pi→Kimi 与 Codex→Kimi 的真实案例已经观察到 relevant 条件下的 无关条件只发现不发送,对照条件零调用;随后 Pi 向真实 Kimi ACP task 提供一条 非权威协调输入,完成 mailbox 接受、context admission、审计和全部清理。 - Gemini CLI adapter 与无模型预检通过;真实 provider 调用未授权。 -- M1、M2 milestone 已关闭;最小可安装集成路径和真实 Pi→Kimi 技术验证已完成。 - 下一步是独立 harness 作者反馈,而不是扩张协议表面。 +- M1、M2 milestone 已关闭;下一步是 network-valid real-effects 重跑、实测 + manual baseline 和三次外部 15 分钟上手,而不是扩张协议表面。 - M0 的规范修复已完成,仍等待两份独立外部 review。 ## 接入自己的 harness diff --git a/package.json b/package.json index 7cbc999..fd17b4e 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@fyaic/threadmesh", "version": "0.1.0-alpha.0", - "description": "Protocol schemas and conformance kit for safe cross-task agent coordination", + "description": "Safe attention and handoff routing for parallel agent sessions", "type": "module", "license": "Apache-2.0", "repository": { @@ -42,6 +42,7 @@ ], "scripts": { "demo": "node bin/threadmesh.mjs demo", + "demo:assets": "node scripts/build-demo-assets.mjs", "validate:spec": "node scripts/validate-spec.mjs", "lint:docs": "markdownlint-cli2 'README*.md' 'docs/**/*.md' 'spec/**/*.md' '*.md'", "test:unit": "node --test test/*.test.mjs", diff --git a/scripts/build-demo-assets.mjs b/scripts/build-demo-assets.mjs new file mode 100644 index 0000000..25fa3cc --- /dev/null +++ b/scripts/build-demo-assets.mjs @@ -0,0 +1,244 @@ +import { execFileSync } from "node:child_process"; +import fs from "node:fs"; +import os from "node:os"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; + +const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), ".."); +const outputDirectory = path.join(root, "docs", "assets", "demo"); +const temporaryDirectory = fs.mkdtempSync(path.join(os.tmpdir(), "threadmesh-demo-assets-")); +const width = 1280; +const height = 720; + +function escapeXml(value) { + return String(value) + .replaceAll("&", "&") + .replaceAll("<", "<") + .replaceAll(">", ">") + .replaceAll('"', """); +} + +function textLines(lines, { x = 80, y = 250, size = 38, gap = 54, color = "#f6f7fb", weight = 600 } = {}) { + return lines.map((line, index) => + `${escapeXml(line)}`, + ).join("\n"); +} + +function card({ x, y, width: cardWidth, height: cardHeight, title, lines, accent = "#63e6be" }) { + return ` + + + ${escapeXml(title)} + ${textLines(lines, { x: x + 30, y: y + 94, size: 27, gap: 40, weight: 560 })}`; +} + +function frame({ index, eyebrow, title, subtitle = "", body = "", footer = "Executable evidence • pre-alpha" }) { + const titleSize = title.length > 42 ? 42 : title.length > 34 ? 46 : 51; + const subtitleSize = subtitle.length > 82 ? 20 : 24; + // Quick Look produces square thumbnails. A square canvas preserves the + // 16:9 artwork at 1:1; ffmpeg crops the unused lower area afterward. + return ` + + + + + + + + + + + + + + + THREADMESH / ${escapeXml(eyebrow.toUpperCase())} + ${escapeXml(title)} + ${subtitle ? `${escapeXml(subtitle)}` : ""} + ${body} + + ${escapeXml(footer)} + ${index}/8 + + `; +} + +const jsonOutput = execFileSync(process.execPath, ["bin/threadmesh.mjs", "demo", "--json"], { + cwd: root, + encoding: "utf8", +}); +const demo = JSON.parse(jsonOutput); +if ( + demo.state !== "passed" || + demo.comparison?.manual?.totalUserActionsLowerBound !== 9 || + demo.comparison?.threadmesh?.totalUserActions !== 1 || + demo.safety?.activeCheckpoint?.receiverStateAfter !== "running" || + demo.dependency?.reasonCode !== "dependency-satisfied-verified" || + demo.cleanup?.complete !== true +) { + throw new Error("Demo evidence did not match the walkthrough contract."); +} + +const sequence = demo.sequence.map((step) => step.eventType).join(" → "); +const slides = [ + { + duration: 8, + svg: frame({ + index: 1, + eyebrow: "the job", + title: "Stop babysitting parallel agents.", + subtitle: "No copy/paste relay. No model polling. No silent takeover.", + body: `Let sessions hand work off when dependencies become real. + The receiver decides when that context is admitted. + + Agent initiative. ThreadMesh boundaries.`, + }), + }, + { + duration: 10, + svg: frame({ + index: 2, + eyebrow: "user pain", + title: "Four handoffs. Two operator experiences.", + subtitle: "The baseline below is executable workflow accounting—not a timing or token claim.", + body: `${card({ x: 66, y: 235, width: 540, height: 270, title: "MANUAL LOWER BOUND", accent: "#ff7b72", lines: ["1 initial kickoff", "4 status checks", "4 copy / relay actions", `≥ ${demo.comparison.manual.totalUserActionsLowerBound} user actions`] })} + ${card({ x: 674, y: 235, width: 540, height: 270, title: "THREADMESH DEMO", lines: ["1 initial kickoff", "0 status checks", "0 relay actions", `${demo.comparison.threadmesh.totalUserActions} user action`] })}`, + }), + }, + { + duration: 10, + svg: frame({ + index: 3, + eyebrow: "retained real codex run", + title: "One kickoff. Sessions advance the chain.", + subtitle: "Real native Codex turns; Git and verifier effects in this retained run were simulated.", + body: `${card({ x: 66, y: 235, width: 348, height: 238, title: "INITIATIVE", lines: ["9 native turns", "0 later phase prompts", "0 direct activations"] })} + ${card({ x: 466, y: 235, width: 348, height: 238, title: "SELECTIVITY", lines: ["A → R → same-A", "→ V → dependent", "irrelevant session: 0 turns"] })} + ${card({ x: 866, y: 235, width: 348, height: 238, title: "HYGIENE", lines: ["5 / 5 sessions removed", "coordinator artifacts removed", "bounded public evidence"] })}`, + }), + }, + { + duration: 10, + svg: frame({ + index: 4, + eyebrow: "fresh executable demo", + title: "A review loop moves without human relay.", + subtitle: "The asset builder ran threadmesh demo --json and rejected any evidence mismatch.", + body: ` + + $ npm run demo + ${escapeXml(sequence)} + relay after kickoff: ${demo.counters.manualRelayActions} polling turns: ${demo.counters.modelPollingTurns} wrong unlocks: ${demo.counters.incorrectUnlocks} + cleanup: complete durable wake recovery: ${demo.counters.durableReconciliations} / ${demo.sequence.length}`, + }), + }, + { + duration: 10, + svg: frame({ + index: 5, + eyebrow: "receiver sovereignty", + title: "B is active. The result waits at a checkpoint.", + subtitle: "A completion event is retained without steering, interrupting, or starting a native turn.", + body: `A / review + + + + CHECKPOINT MAILBOX + decision: pending + + B / running + ${card({ x: 188, y: 400, width: 904, height: 132, title: "FRESH ASSERTIONS FROM THE DEMO", lines: [`state: ${demo.safety.activeCheckpoint.receiverStateBefore} → ${demo.safety.activeCheckpoint.receiverStateAfter} steer: 0 interrupt: 0 native turns: 0`] })}`, + }), + }, + { + duration: 10, + svg: frame({ + index: 6, + eyebrow: "selective attention", + title: "Recover relevant events. Ignore the rest.", + subtitle: "The durable mailbox is truth; a wake signal is only a bounded hint.", + body: `${card({ x: 66, y: 235, width: 540, height: 270, title: "DROPPED WAKE HINTS", lines: [`wake hints supplied: 0`, `durable reconciliations: ${demo.safety.durableReconciliations}`, "relevant events recovered: 4", "lost work: 0"] })} + ${card({ x: 674, y: 235, width: 540, height: 270, title: "UNSUBSCRIBED CONTROL", accent: "#ffd43b", lines: [`offers: ${demo.safety.activeCheckpoint.unsubscribedOffers}`, "native turn starts: 0", "reason:", demo.safety.activeCheckpoint.unsubscribedReasonCode] })}`, + }), + }, + { + duration: 10, + svg: frame({ + index: 7, + eyebrow: "verified dependency", + title: "Delivery ≠ verification ≠ authority.", + subtitle: "The downstream task remains waiting until the exact dependency proof passes.", + body: ` + deliveredmailbox receipt + + acceptedreceiver decision + + externally verifiedsigned attestation + + dependent: readyauthorized unlock + + Result: ${escapeXml(demo.dependency.reasonCode)} + Wrong unlocks: ${demo.counters.incorrectUnlocks} • state survived SQLite close/reopen • cleanup complete`, + }), + }, + { + duration: 8, + svg: frame({ + index: 8, + eyebrow: "try the proof", + title: "Run the closed loop in one command.", + subtitle: "Works locally without model quota or access to your existing agent sessions.", + body: ` + npx --yes --package=github:fyaic/threadmesh threadmesh demo + ${card({ x: 66, y: 390, width: 1148, height: 150, title: "HONEST EVIDENCE BOUNDARY", accent: "#ffd43b", lines: ["Deterministic Git/verifier integration is merged on main.", "A fresh real Codex real-effects rerun remains pending a network-valid host."] })}`, + }), + }, +]; + +fs.mkdirSync(outputDirectory, { recursive: true }); +try { + const concatLines = []; + for (const [index, slide] of slides.entries()) { + const base = `slide-${String(index + 1).padStart(2, "0")}`; + const svgPath = path.join(temporaryDirectory, `${base}.svg`); + fs.writeFileSync(svgPath, slide.svg); + execFileSync("qlmanage", ["-t", "-s", String(width), "-o", temporaryDirectory, svgPath], { + stdio: "ignore", + }); + const generated = `${svgPath}.png`; + const pngPath = path.join(temporaryDirectory, `${base}.png`); + fs.renameSync(generated, pngPath); + concatLines.push(`file '${pngPath.replaceAll("'", "'\\''")}'`); + concatLines.push(`duration ${slide.duration}`); + } + concatLines.push(`file '${path.join(temporaryDirectory, "slide-08.png")}'`); + const concatPath = path.join(temporaryDirectory, "slides.txt"); + fs.writeFileSync(concatPath, `${concatLines.join("\n")}\n`); + + const mp4Path = path.join(outputDirectory, "threadmesh-proof-walkthrough.mp4"); + execFileSync("ffmpeg", [ + "-y", "-f", "concat", "-safe", "0", "-i", concatPath, + "-vf", `crop=${width}:${height}:0:0,format=yuv420p`, + "-t", "76", "-r", "30", "-movflags", "+faststart", mp4Path, + ], { stdio: "ignore" }); + + const palettePath = path.join(temporaryDirectory, "palette.png"); + execFileSync("ffmpeg", [ + "-y", "-i", mp4Path, + "-vf", "fps=10,scale=960:-1:flags=lanczos,palettegen=max_colors=128", + palettePath, + ], { stdio: "ignore" }); + execFileSync("ffmpeg", [ + "-y", "-i", mp4Path, "-i", palettePath, + "-filter_complex", "fps=10,scale=960:-1:flags=lanczos[x];[x][1:v]paletteuse=dither=bayer:bayer_scale=3", + path.join(outputDirectory, "threadmesh-proof-walkthrough.gif"), + ], { stdio: "ignore" }); + execFileSync("ffmpeg", [ + "-y", "-i", mp4Path, "-frames:v", "1", + path.join(outputDirectory, "threadmesh-proof-walkthrough-cover.png"), + ], { stdio: "ignore" }); +} finally { + fs.rmSync(temporaryDirectory, { recursive: true, force: true }); +} + +process.stdout.write("Built 76-second ThreadMesh proof walkthrough (MP4, GIF, cover).\n"); diff --git a/src/demo/attention-router-demo.mjs b/src/demo/attention-router-demo.mjs index 0afbabf..22ac102 100644 --- a/src/demo/attention-router-demo.mjs +++ b/src/demo/attention-router-demo.mjs @@ -43,6 +43,11 @@ const TASKS = Object.freeze({ incarnationId: "inc_demo_dependent0001", harness: "demo-dependent", }), + activeReceiver: Object.freeze({ + taskId: "task_demo_active_receiver", + incarnationId: "inc_demo_active_receiver01", + harness: "demo-active-receiver", + }), }); const STEPS = Object.freeze([ @@ -88,6 +93,19 @@ const STEPS = Object.freeze([ }), ]); +const ACTIVE_CHECKPOINT_STEP = Object.freeze({ + eventType: LIFECYCLE_EVENT_TYPES.COMPLETED, + messageId: "msg_demo_active_checkpoint01", + relationshipId: "rel_demo_review_active_receiver", + grantId: "grant_demo_review_active_receiver", + source: "review", + target: "activeReceiver", + content: "Review completed while the receiving session is still working.", + reason: "Retain the result for the receiver's next safe checkpoint.", +}); + +const GRANT_STEPS = Object.freeze([...STEPS, ACTIVE_CHECKPOINT_STEP]); + const DEPENDENCY_EDGE = Object.freeze({ dependencyId: "dependency_demo_reviewed_artifact", version: 1, @@ -138,7 +156,7 @@ function installDemoState(coordinator) { for (const [name, task] of Object.entries(TASKS)) { coordinator.registerTask({ ...task, - state: "waiting", + state: name === "activeReceiver" ? "running" : "waiting", runtime: { runId: `run_demo_${name}`, objectiveVersion: 1, @@ -153,7 +171,7 @@ function installDemoState(coordinator) { } const grants = new Map(); - for (const step of STEPS) { + for (const step of GRANT_STEPS) { const grant = coordinator.issueGrant({ specVersion: "0.0-draft", grantId: step.grantId, @@ -179,6 +197,79 @@ function installDemoState(coordinator) { return grants; } +function retainForActiveCheckpoint(coordinator, grant) { + const event = eventFor(ACTIVE_CHECKPOINT_STEP); + const source = TASKS[ACTIVE_CHECKPOINT_STEP.source]; + const target = TASKS[ACTIVE_CHECKPOINT_STEP.target]; + const receiverBefore = coordinator.getTask(taskRef(target), OWNER); + const route = evaluateAttentionRoute({ + event, + receiverTask: taskRef(target), + grant, + currentGrant: grant, + sourceTask: { ...source, retiredAt: null }, + targetTask: { + ...target, + retiredAt: null, + runId: `run_demo_${ACTIVE_CHECKPOINT_STEP.target}`, + objectiveVersion: 1, + checkpoint: `checkpoint_demo_${ACTIVE_CHECKPOINT_STEP.target}`, + }, + now: NOW, + }); + if (!route.offer) throw new Error(`demo_active_checkpoint_route_failed:${route.reasonCode}`); + + const submitted = coordinator.submit( + projectLifecycleEventToEnvelope(event), + taskPrincipal(source), + ); + const retained = coordinator.inspectMessage( + source.incarnationId, + event.messageId, + taskPrincipal(target), + ); + const receiverAfter = coordinator.getTask(taskRef(target), OWNER); + if ( + receiverBefore.state !== "running" || + receiverAfter.state !== "running" || + retained.disposition.decision !== "pending" + ) { + throw new Error("demo_active_receiver_was_interrupted"); + } + + const quietRoute = evaluateAttentionRoute({ + event, + receiverTask: taskRef(target), + subscribedEventTypes: [LIFECYCLE_EVENT_TYPES.BLOCKED], + grant, + currentGrant: grant, + sourceTask: { ...source, retiredAt: null }, + targetTask: { + ...target, + retiredAt: null, + runId: `run_demo_${ACTIVE_CHECKPOINT_STEP.target}`, + objectiveVersion: 1, + checkpoint: `checkpoint_demo_${ACTIVE_CHECKPOINT_STEP.target}`, + }, + now: NOW, + }); + if (quietRoute.offer) throw new Error("demo_unsubscribed_event_was_offered"); + + return { + eventType: event.eventType, + requestedDeliveryMode: route.envelope.delivery.requestedMode, + delivery: submitted.disposition.delivery, + receiverDecision: retained.disposition.decision, + receiverStateBefore: receiverBefore.state, + receiverStateAfter: receiverAfter.state, + steerRequests: 0, + interruptRequests: 0, + nativeTurnStarts: 0, + unsubscribedOffers: quietRoute.offer ? 1 : 0, + unsubscribedReasonCode: quietRoute.reasonCode, + }; +} + function createDemoVerifier() { const { publicKey, privateKey } = generateKeyPairSync("ed25519"); const keyId = "threadmesh-demo://verifier/keys/1"; @@ -388,6 +479,10 @@ export async function runAttentionRouterDemo({ temporaryParent = os.tmpdir(), on wake: result.reconciliation.reasonCode, }); } + const activeCheckpoint = retainForActiveCheckpoint( + coordinator, + grants.get(ACTIVE_CHECKPOINT_STEP.relationshipId), + ); const dependency = results.at(-1); const dependencyEvent = eventFor(STEPS.at(-1)); @@ -504,6 +599,28 @@ export async function runAttentionRouterDemo({ temporaryParent = os.tmpdir(), on incorrectUnlocks: 0, durableReconciliations: results.length, }, + comparison: { + classification: "modeled-workflow-accounting", + workflowHandoffs: results.length, + manual: { + initialKickoffs: 1, + relayActions: results.length, + statusChecks: results.length, + totalUserActionsLowerBound: 1 + (results.length * 2), + }, + threadmesh: { + initialKickoffs: 1, + relayActions: 0, + statusChecks: 0, + totalUserActions: 1, + }, + notMeasured: ["elapsed-time", "model-tokens"], + }, + safety: { + activeCheckpoint, + droppedWakeHints: results.length, + durableReconciliations: results.length, + }, inspector, cleanup, }; diff --git a/test/attention-router-demo.test.mjs b/test/attention-router-demo.test.mjs index 8551a07..946a019 100644 --- a/test/attention-router-demo.test.mjs +++ b/test/attention-router-demo.test.mjs @@ -36,6 +36,40 @@ test("attention-router demo is deterministic, routes the review-fix sequence, an incorrectUnlocks: 0, durableReconciliations: 4, }); + assert.deepEqual(first.comparison, { + classification: "modeled-workflow-accounting", + workflowHandoffs: 4, + manual: { + initialKickoffs: 1, + relayActions: 4, + statusChecks: 4, + totalUserActionsLowerBound: 9, + }, + threadmesh: { + initialKickoffs: 1, + relayActions: 0, + statusChecks: 0, + totalUserActions: 1, + }, + notMeasured: ["elapsed-time", "model-tokens"], + }); + assert.deepEqual(first.safety, { + activeCheckpoint: { + eventType: "completed", + requestedDeliveryMode: "checkpoint-offer", + delivery: "durably-received", + receiverDecision: "pending", + receiverStateBefore: "running", + receiverStateAfter: "running", + steerRequests: 0, + interruptRequests: 0, + nativeTurnStarts: 0, + unsubscribedOffers: 0, + unsubscribedReasonCode: "attention-event-type-not-subscribed", + }, + droppedWakeHints: 4, + durableReconciliations: 4, + }); assert.deepEqual(first.dependency, { eventType: "dependency-satisfied", state: "satisfied", @@ -76,7 +110,7 @@ test("repository CLI emits the bounded JSON result", () => { encoding: "utf8", }); const result = JSON.parse(output); - assert.equal(Object.keys(result).length, 7); + assert.equal(Object.keys(result).length, 9); assert.equal(result.state, "passed"); assert.equal(result.sequence.length, 4); assert.deepEqual(result.cleanup, { attempted: true, complete: true });