From bf0d63b807458d690ca75a530854c11682767379 Mon Sep 17 00:00:00 2001 From: rocky Date: Thu, 12 Nov 2026 15:35:52 +0900 Subject: [PATCH 1/6] docs(interactive): record current baseline and local CI fallback policy --- ...0-current-baseline-ci-fallback-20261112.md | 158 ++++++++++++++++++ 1 file changed, 158 insertions(+) create mode 100644 docs/interactive-phase0-current-baseline-ci-fallback-20261112.md diff --git a/docs/interactive-phase0-current-baseline-ci-fallback-20261112.md b/docs/interactive-phase0-current-baseline-ci-fallback-20261112.md new file mode 100644 index 0000000..73b3c2d --- /dev/null +++ b/docs/interactive-phase0-current-baseline-ci-fallback-20261112.md @@ -0,0 +1,158 @@ +# FlowKit Phase 0 — Current Baseline & CI Fallback + +**Snapshot:** 2026-11-12 (UTC+8) +**Repository:** \`devcodex-labs/flowkit\` +**Snapshot base:** \`606d055d5f02451fea0b30294889d740ef370d49\` +**Purpose:** Establish one current status record and a reproducible local verification path while GitHub Actions behavior is investigated. This document does not modify the approved V0.3/V0.6-R5 contract, P0-A implementation plan, Program ABI, Store schema, or product semantics. + +## 1. Authority and status vocabulary + +Authority order remains: + +1. Requirements V0.3 (confirmed; T01–T34). +2. Technical Design V0.6-R5 (confirmed; §§1–18). +3. P0-A Implementation Plan V0.1 (confirmed 2026-11-10; M1–M6, 31 file-level tasks). +4. Trusted Host V2 (PR #14; security design supplement, not a replacement for V0.3/V0.6-R5). +5. Current \`main\` and reproducible tests. +6. Roadmaps, audit reports and local verification reports as evidence indexes, never as substitutes for the confirmed source documents. + +Use only: \`PASS\`, \`FAIL\`, \`PARTIAL\`, \`BLOCKED\`, \`NOT-EXECUTED\`, \`NOT-IN-SCOPE\`, \`DEFERRED\`. A local PASS is not a GitHub Actions PASS; a scripted host fixture is not a native-host PASS. + +## 2. Current repository and PR baseline + +### 2.1 Main + +- Current main at snapshot: \`606d055d5f02451fea0b30294889d740ef370d49\`. +- M1–M5 implementation surfaces are present on main. Their presence is not a blanket completion claim for every task or security gate. +- PR #16 (R1/R2 audit docs), PR #19 (local verification evidence) and PR #18 (R04 fix + regression tests) are merged. +- PR #17 is closed without merge; its two deliberately failing R04 regression tests are included in #18. +- PR #7 is closed without merge; its M6 work was superseded by #13. +- PR #11 and #12 remain open Draft and must be reviewed on their own merits. + +### 2.2 Remaining open PRs + +| PR | Branch | HEAD | Base recorded by PR | Current diff against main | Decision | +|---|---|---|---|---|---| +| [#11 ChatGPT tool bridge](https://github.com/devcodex-labs/flowkit/pull/11) | \`test/s13-chatgpt-tool-bridge\` | \`eac72c66a33e8a6411aa8748240abe9146d0c4c0\` | historical \`ea2bb108\` | 5 commits ahead / 6 behind; 4 unique files | Rebase/update, review actual tool-turn evidence and security boundary; do not equate with native Grok S13 | +| [#12 C01–C24 acceptance](https://github.com/devcodex-labs/flowkit/pull/12) | \`test/interactive-complex-c01-c12-acceptance\` | \`c6b42a36050d885a37831cbdf0839428b2052c85\` | historical \`ea2bb108\` | 15 commits ahead / 6 behind; 8 unique files | Rebase/update, review scripts, matrices and evidence; merging scripts does not pass C12/S13 | + +No PR #11/#12 content is to be discarded merely to make branch cleanup easier. Extract/merge only reviewed assets; explicitly mark native-host gaps BLOCKED. + +## 3. Verified local evidence already available + +PR #19 records the following local Windows evidence: + +- Windows NT 10.0.26200.0. +- Node v24.22.2: \`npm run verify\` — 371/371 tests PASS; type, package check and package consumer steps exit 0. +- Node v22.22.2: \`npm run verify\` — 371/371 tests PASS. +- Documentation examples, docs check (after LF normalization), docs build and selected impact/security probes PASS. +- Before the fix, the two R04 tests failed reproducibly on Node 22.22.2 and 24.22.2; after #18, both passed. +- CF-08 was separately reproduced as a non-deterministic compile-options rejection and remains unfixed. + +Limits: these Node versions are not the exact CI pins (22.13.0 and 24.22.1); Ubuntu was not run; Windows ACL / separate OS identities, native Grok tool events, C12/S13/T27 and complete Host Outbox recovery were not proven. Do not upgrade these items to cross-platform or native-host PASS. + +## 4. GitHub Actions diagnosis at this snapshot + +### 4.1 Workflow shape + +\`.github/workflows/ci.yml\` currently has seven jobs: + +- 4 \`verify\` matrix jobs: Ubuntu 24.04 / Windows 2025 × Node 22.13.0 / 24.22.1. +- 2 Linux Host OS-user isolation + M6 integration jobs: Node 22.13.0 / 24.22.1. +- 1 website build/check job. + +The workflow uses: + +\`\`\`yaml +concurrency: + group: ci-\${{ github.workflow }}-\${{ github.ref }} + cancel-in-progress: true +\`\`\` + +New pushes to the same ref can cancel older runs. This is intentional stale-run suppression, but multiple rapid pushes to \`main\` can cancel earlier main runs before their seven jobs finish. + +### 4.2 Observed run facts + +- Latest successful main run before the three PR merges: [43146363166](https://github.com/devcodex-labs/flowkit/actions/runs/43146363166), commit \`13d573c5ddc4a0ed3502401589c581799c96c5d2\`, 7/7 jobs successful. It is **not** the current \`606d055\` HEAD. +- The three rapid main pushes from merges #16/#19/#18 created runs [43161068943](https://github.com/devcodex-labs/flowkit/actions/runs/43161068943), [43161142187](https://github.com/devcodex-labs/flowkit/actions/runs/43161142187) and [43161214780](https://github.com/devcodex-labs/flowkit/actions/runs/43161214780). All now report \`completed/cancelled\`; the first two were superseded in the same-ref concurrency window. +- Run 43161214780 is attempt 2; all seven jobs currently report cancelled. Accessible run metadata does not establish why its final attempt was cancelled. Do not label it queued or failed. +- Five older runs (43095884874, 43095901291, 43095937558, 43096034832, 43096045021) remain \`queued\` on the old \`design/trusted-host-security-v2-20261111\` branch. Each currently has zero jobs and no associated open PR in the run metadata. Treat them as stale queued events, not as evidence that the current main workflow has active jobs waiting for a runner. +- At the time of this snapshot, there are 5 queued runs, 0 in-progress runs. The latest main run is cancelled, not queued. + +GitHub Status currently reports all systems operational. The Nov 11 incident affecting Actions/Pages/Copilot was marked resolved at 21:21 UTC, with GitHub stating that the Actions backlog had been fully processed. Therefore, do **not** assert a current global GitHub outage without new evidence. A fresh isolated workflow run is required to test current scheduling on this repository. + +Official status: https://www.githubstatus.com/ +Official Actions billing/usage: https://docs.github.com/en/actions/concepts/billing-and-usage + +The repository is now public. GitHub documents standard GitHub-hosted runner usage as free for public repositories. This makes private-repository included-minute exhaustion an unlikely explanation for current standard hosted-runner scheduling; repository/org policy and stale events still require evidence. Do not infer a billing cause. + +## 5. CI outage / queue fallback policy + +### 5.1 Continue development without pretending CI passed + +When Actions is unavailable or a run is cancelled/queued: + +1. Continue source review, requirement mapping, implementation and unit-level work in a scoped branch. +2. Run the same repository scripts locally on the exact PR HEAD. +3. Save raw logs and a machine-readable evidence summary. +4. Have a separate reviewer inspect the exact diff and evidence. +5. Keep the GitHub Actions state explicitly \`BLOCKED\` or \`NOT-EXECUTED\`; never relabel local results as CI PASS. +6. Do not repeatedly create meaningless commits to chase a runner. Trigger one clean isolated run after the branch is ready, then inspect its run/job metadata. + +### 5.2 Standard local verification commands + +Run from a clean worktree at the exact PR HEAD: + +\`\`\`bash +node --version +npm --version +git rev-parse HEAD +git status --short +npm ci --ignore-scripts --no-audit --no-fund +npm run verify +npm run docs:examples +npm --prefix website ci --ignore-scripts --no-audit --no-fund +npm run docs:check +npm run docs:build +\`\`\` + +Use the exact CI Node pins where possible: 22.13.0 and 24.22.1. Record the actual versions; do not claim exact-matrix coverage if using 22.22.2/24.22.2. + +### 5.3 OS coverage + +- Windows tests must run on Windows for Windows-specific path, process, ACL, token and handle behavior. +- Linux tests may run locally in Ubuntu 24.04 / WSL2 with distinct OS users for early verification. Label this \`LOCAL-LINUX\`, not GitHub-hosted Ubuntu CI. If the test depends on a hosted-runner-specific behavior, keep it BLOCKED until tested there. +- Do not use a same-UID shell or same-user child process as proof of cross-principal isolation. +- For each OS/Node combination, record: exact commit SHA, OS build, Node/npm version, install command, test command, exit code, TAP summary, log path/hash, and reviewer. + +### 5.4 Merge and release gates + +- Docs-only PRs can be reviewed and merged using local docs/test evidence if the diff is isolated and no repository rules require a successful Actions check. This does not pass product M6. +- Core/runtime/security PRs require local Windows + Linux evidence appropriate to the changed behavior, raw logs, independent diff review and explicit residual-risk record before any interim merge decision. +- Missing online CI remains \`CI-BLOCKED\`; missing OS profile or native-host proof remains \`BLOCKED\`. Neither can be silently waived to declare P0-A complete. +- P0-A/M6 final closure and release still require the approved four-matrix CI and all applicable security/native-host evidence. Do not bypass branch protection or required checks. + +## 6. Current technical findings carried forward + +| Finding | Current status | Next action | +|---|---|---| +| CF-01 \`adminTerminate\` | GAP / high-confidence P0-A implementation gap | Reconcile exact V0.6-R5 + approved M5 task, then implement trusted admin controller/tombstone/CAS/audit and race tests | +| CF-02 SDK API shape | OPEN / contract decision required | Compare V0.6-R5 §4 and approval record; do not add public exports based only on illustrative V0.3 examples | +| CF-05 terminal State projection | OPEN / source-confirmed discrepancy | Separate public model projection from trusted result read; test actual model-facing adapter | +| CF-06 Store sync vs async contract | OPEN / source-confirmed discrepancy | Compare V0.6-R5 §5/§8 and approved M3 design; preserve atomic CAS/receipt semantics | +| CF-07 start input snapshot | FIXED in merged #18 | Retain regression tests; local Windows Node 22/24 PASS; Linux/CI matrix still outstanding | +| CF-08 compile options snapshot | REPRODUCED / not fixed | Add isolated regression, then minimal fix and re-run compiler/feature-gate tests | +| F-02 native Grok tool binding | PARTIAL/BLOCKED | H3-02 capability probe before adapter implementation | +| F-04 cross-principal handle isolation | PARTIAL/BLOCKED | H3-05 Windows/Linux OS negative tests | +| F-07 formal contract provenance | Source recovery CLOSED; conformance review PENDING | Complete T01–T34 / §§1–18 traceability; do not mark overall conformance PASS yet | + +## 7. Phase 0 work order + +1. Use this document as the current snapshot; keep historical audit reports immutable. +2. Build the 31-row A-M1-01 through A-M6-06 task crosswalk against current source files, tests, package exports, workflow and raw evidence. Distinguish implementation presence from acceptance PASS. +3. Update the roadmap, formal source register and conformance plan to the current main SHA, preserving their historical baseline notes. +4. Rebase/review PR #11 and #12; extract only validated test assets and evidence. +5. Continue formal V0.3/V0.6-R5 contract conformance and CF-01/02/05/06/08 closure. +6. Only after Phase 0 inventory is complete, proceed through the corrected Phase 1/2 sequence; H3-01 and H3-05 may proceed independently of Grok tool PoC, while H3-02/03/04 and Phase 4 retain their stated dependencies. + +**No production semantics, ABI, Store schema, confirmed requirements, npm publication or deployment is changed by this baseline record.** From 6de7ceb7ba5cc2851a6cb9fc46257ffc10d4285f Mon Sep 17 00:00:00 2001 From: rocky Date: Thu, 12 Nov 2026 15:40:36 +0900 Subject: [PATCH 2/6] docs(interactive): map approved P0-A tasks to current main evidence --- ...eractive-p0a-31-task-crosswalk-20261112.md | 101 ++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 docs/interactive-p0a-31-task-crosswalk-20261112.md diff --git a/docs/interactive-p0a-31-task-crosswalk-20261112.md b/docs/interactive-p0a-31-task-crosswalk-20261112.md new file mode 100644 index 0000000..4b2b874 --- /dev/null +++ b/docs/interactive-p0a-31-task-crosswalk-20261112.md @@ -0,0 +1,101 @@ +# FlowKit P0-A V0.1 — 31 Task Current-Main Crosswalk + +**Snapshot main:** \`606d055d5f02451fea0b30294889d740ef370d49\` +**Approved plan:** \`01-P0A-IMPLEMENTATION-PLAN-V0.1-CONFIRMED.md\`, confirmed 2026-11-10. +**Purpose:** Map all 31 approved file-level tasks to current source, tests and evidence. This is a source-presence and gap inventory, **not** the final acceptance report. A source file/test existing does not automatically mean its full task is PASS. + +## 1. Status meanings + +- **CODE-PRESENT** — implementation/test surface exists and maps to the task; acceptance still requires exact contract and runtime evidence. +- **PARTIAL** — some behavior exists, but a named part of the approved task or its evidence remains open. +- **GAP** — required implementation surface/behavior is not present on current main. +- **CI-BLOCKED** — local evidence exists but current exact-main GitHub Actions run has not completed. +- **NOT-IN-SCOPE** — excluded by confirmed P0-A plan; not counted as a defect. + +No item in this table is a final P0-A acceptance PASS. + +## 2. M1 — Standard compiler reuse / Feature Gate / Resumable IR + +| Task | Current main implementation | Tests/evidence | Status and remaining closure | +|---|---|---|---| +| A-M1-01 Standard analyzer reuse | \`src/interactive/compile.mjs\` calls \`analyzeSource\`; original analyzer remains in \`src/compiler/analyze.mjs\` | \`tests/interactive/compiler-front.test.mjs\`: real Standard analyzer for JS/TS and diagnostic preservation; \`ir.test.mjs\` compares original Graph/Dataflow/when AST | **CODE-PRESENT**. Finish T01–T34 mapping and exact CI matrix. | +| A-M1-02 P0-A feature gate | \`src/compiler/interactive/feature-gate.mjs\` | \`compiler-front.test.mjs\`: unsupported Action/Verification, Agent verify, featureStage and pure Condition/Terminal | **CODE-PRESENT**. Keep negative cases in full release matrix. | +| A-M1-03 Resumable IR lowering | \`src/compiler/interactive/lower.mjs\` | \`ir.test.mjs\`: stable IR, source identity, original when AST semantics | **CODE-PRESENT**. Complete independent comparison against V0.6 §2/§5 and edge-case ledger. | +| A-M1-04 IR validation | \`src/compiler/interactive/validate-ir.mjs\` | \`ir.test.mjs\`: injected edges/events, duplicate blocks, missing phases | **CODE-PRESENT**. Verify all T/R/S negative cases, not only current unit fixtures. | +| A-M1-05 M1 tests | \`tests/interactive/compiler-front.test.mjs\`, \`ir.test.mjs\` | 6 + 5 named tests; PR #19 records Windows full verify at Node 22.22.2 / 24.22.2 | **CODE-PRESENT / CI-BLOCKED** for exact Ubuntu/Windows × pinned Node matrix on current main. | + +## 3. M2 — Executable Program / ABI / loader + +| Task | Current main implementation | Tests/evidence | Status and remaining closure | +|---|---|---|---| +| A-M2-01 JS emitter | \`src/compiler/interactive/emit.mjs\` emits executable \`advance()\`, ProgramTable and identity | \`tests/interactive/emitter.test.mjs\`: deterministic bytes/hash, zero imports, Condition/Terminal and Agent frame/Pending/retry decisions | **CODE-PRESENT**. Complete V0.6 §5/§10 contract crosswalk. | +| A-M2-02 compile API / diagnostics | \`src/interactive/compile.mjs\` returns diagnostics and compiled bytes/identity | \`compiler-front.test.mjs\`, \`emitter.test.mjs\` | **CODE-PRESENT; module layout consolidated**. Approved plan named \`diagnostics.mjs\`, but separate file is not itself a semantic requirement; verify diagnostic fields and stable codes. | +| A-M2-03 same-byte loader | \`src/interactive/load.mjs\` exports \`loadInteractiveProgram\` | \`emitter.test.mjs\`: wrong digest, dynamic import and ABI mismatch rejection; \`stage2-program-cache.test.mjs\`: re-read exact Store bytes/identity/policy | **CODE-PRESENT** under \`load.mjs\` rather than planned \`loader.mjs\`. Finish exact corrupted-byte and same-byte load audit. | +| A-M2-04 Checkpoint / proposal runtime validation | Relevant checks are distributed across \`validate-ir.mjs\`, \`coordinator.mjs\` and \`sqlite-store.mjs\`; no standalone \`src/interactive/checkpoint.mjs\` | \`ir.test.mjs\`, \`coordinator.test.mjs\`, \`store.test.mjs\` | **PARTIAL**. Build an explicit requirement-to-function-to-negative-test map for every CheckpointView, event, proposal, stack effect and immutable identity invariant. | +| A-M2-05 emitter/loader/ABI tests | \`emitter.test.mjs\`, \`ir.test.mjs\`, \`compiler-front.test.mjs\` | Emitter suite includes deterministic standalone output, exact hash, zero imports, routing and loader rejects | **CODE-PRESENT**. Dedicated test file names differ from plan; verify the complete required golden/ABI vector coverage. | + +## 4. M3 — Canonical JSON / Registry / SQLite Store / Journal + +| Task | Current main implementation | Tests/evidence | Status and remaining closure | +|---|---|---|---| +| A-M3-01 canonical JSON and identity | \`src/interactive/canonical.mjs\`: bounded canonical bytes, snapshot, hash and decoding; Store implements artifact identity | \`store.test.mjs\`: key order, prototype-as-data, accessors, Proxy, cycle, \`-0\`, non-finite and limits | **PARTIAL**. Confirm the exact V0.6 canonicalization requirement and add/verify full RFC 8785/JCS golden vectors (POC-F04); current tests show a constrained canonical JSON contract, not by themselves complete JCS conformance. | +| A-M3-02 SQLite CheckpointStore | \`src/interactive/sqlite-store.mjs\` implements WAL/FULL, Genesis, transactions, CAS, Journal and receipt index | \`store.test.mjs\`: atomic CAS/Journal, duplicate transition rollback, connection restart and two OS processes | **PARTIAL**. Current public Store interface is synchronous while R1/R2 CF-06 records an async five-operation V0.6 contract discrepancy. Resolve against exact V0.6 §5/§8 and approval record; preserve atomic semantics. | +| A-M3-03 Program Registry / Run retain | Artifact bytes and identity live in \`fk_i_artifacts\`; Run rows reference artifacts; deletion is refused while historical Runs reference bytes | \`store.test.mjs\`: immutable bytes, tenant namespace and deletion refusal; \`m6-e2e.test.mjs\`: Program retained and tamper rejected | **PARTIAL**. The coordinator calls \`putArtifact\` then \`createRun\`; Run+Genesis Journal are transactional, but artifact registration is a preceding Store operation. Explicitly reconcile orphan-artifact and Genesis/Retain atomicity with V0.6 §6.2 and the approved M3 task before calling the full retain contract closed. | +| A-M3-04 Store/Journal/Receipt tests | \`tests/interactive/store.test.mjs\`, \`s07-capacity.test.mjs\`, \`coordinator.test.mjs\` | Tests include CAS, Journal chain, receipt history, duplicate transition rollback, tenant isolation and cross-process competition | **CODE-PRESENT / PARTIAL**. Finish full historical Ack, unknown-CAS-response and all approved failure-matrix cases with raw evidence. | +| A-M3-05 crash workers | \`tests/interactive/crash.test.mjs\`, \`tests/integration/m6-worker.mjs\`, \`m6-host.mjs\` | Real SIGKILL before/after Agent publish, receipt acceptance, validation and State commit; two-process receipt race | **PARTIAL**. Current tests cover representative cut points, not proof that all F01–F20 and all applicable Windows/Linux equivalents have passed. | + +## 5. M4 — Coordinator / Agent / API + +| Task | Current main implementation | Tests/evidence | Status and remaining closure | +|---|---|---|---| +| A-M4-01 Coordinator | \`src/interactive/coordinator.mjs\` | \`coordinator.test.mjs\`: Condition/Terminal, Pending, retry, commit, resume, budget and concurrency | **CODE-PRESENT**. Full T01–T14 and S01–S07 closure remains part of M6. | +| A-M4-02 policy preflight | Policy snapshot/hash and runtime-binding checks are integrated in \`coordinator.mjs\`; no separate \`policy.mjs\` | \`coordinator.test.mjs\`: unsupported checkStep and missing bindings reject before Store writes; \`stage2-integration.test.mjs\`: binding-version drift | **CODE-PRESENT; module consolidated**. Verify all approved policy/skill/program identity drift cases. | +| A-M4-03 Agent execution semantics | Agent frame, Skill resolution, retries, validation and candidate commit are integrated in \`coordinator.mjs\`; no separate \`agent.mjs\` | \`coordinator.test.mjs\`: retries+1, FK_R004, pure validator contract, State isolation and candidate commit | **CODE-PRESENT; module consolidated**. Verify complete Standard parity and every T02/T04/T13/T14 case. | +| A-M4-04 receipt lifecycle | Receipt acceptance, duplicate identity, conflict, CAS and durable index are integrated in Coordinator/Store; no separate \`receipts.mjs\` | \`coordinator.test.mjs\`, \`store.test.mjs\`, \`crash.test.mjs\` | **CODE-PRESENT; module consolidated**. Finish full receipt replay and lost-response matrix. | +| A-M4-05 public SDK entry | \`src/interactive/index.mjs\` is exported as package subpath \`./interactive\`; there is no standalone \`src/interactive.mjs\` facade | \`tests/package/consumer.mjs\` imports \`@devcodex-labs/flowkit/interactive\` and checks its exports/real run | **CODE-PRESENT; file layout/API shape differs from plan**. CF-02 still requires V0.6 §4 and approval-record review before changing public exports. | +| A-M4-06 Coordinator/Agent/recovery tests | \`coordinator.test.mjs\`, \`crash.test.mjs\`, \`store.test.mjs\` | 23 Coordinator tests (including two R04 tests), 3 crash tests and 10 Store tests | **CODE-PRESENT / PARTIAL**. Test files are consolidated; map each T01–T14/T29 acceptance case to exact assertions and raw execution evidence. | + +## 6. M5 — Trusted Host / projections / admin / bridge + +| Task | Current main implementation | Tests/evidence | Status and remaining closure | +|---|---|---|---| +| A-M5-01 PublicTask / trusted result | \`src/interactive/trusted-host.mjs\` provides allowlisted \`getPublicAgentTask()\`; \`coordinator.mjs\` public frame currently includes terminal State; no separate \`readTrustedTerminalResult\` capability is exposed | \`trusted-host.test.mjs\`: public task excludes State/Host secrets and enforces disclosure; CF-05 source discrepancy remains | **PARTIAL**. Need an explicit public-vs-trusted result API/permission boundary and model-facing adapter test; do not infer a real leak without showing the model receives the Host \`load()\` result. | +| A-M5-02 admin controller / adminTerminate | No \`admin-controller.mjs\`, \`adminTerminate\` export or corresponding trusted admin facade found in current source/types | R2 CF-01; current coordinator/trusted-host exports list only start/complete/resume/load/accept/task | **GAP — P0-A blocker**. Design the independent Host Admin principal, tombstone, audit, CAS race, Program-missing escape path and stale-receipt rejection against frozen V0.6/approved M5 plan before implementation. | +| A-M5-03 reference Host bridge CLI | No \`examples/interactive/bridge.mjs\` or \`examples/interactive/\` directory on current main | Current examples are Standard workflows; M6 integration Host fixtures are under \`tests/integration/\` | **GAP / NOT PROVIDED AS A CONSUMABLE EXAMPLE**. Build the minimal short-lived trusted Host bridge after M5 security boundary is resolved; no new npm bin. | +| A-M5-04 tenant/auth/projection/admin tests | \`tests/interactive/trusted-host.test.mjs\`, \`tests/security/host-isolation.mjs\`, \`tests/integration/m6-e2e.test.mjs\` | 16 Trusted Host tests; Linux separate-UID negative test; M6 worker integration | **PARTIAL**. Admin tests cannot pass before A-M5-02; Windows separate-account/ACL/handle-inheritance negatives remain BLOCKED. | + +## 7. M6 — CI / package / types / crash / docs / performance + +| Task | Current main implementation | Tests/evidence | Status and remaining closure | +|---|---|---|---| +| A-M6-01 package exports/manifest | \`package.json\`, \`scripts/package-files.mjs\`, \`check-package.mjs\`, \`test-package.mjs\`; exports include \`./interactive\`, no extra npm bin | \`tests/package/package.test.mjs\`; local PR #19 \`npm run verify\` evidence | **CODE-PRESENT / LOCAL PASS; CI-BLOCKED** at latest main SHA. | +| A-M6-02 TS declarations/consumer | \`types/interactive.d.ts\`, \`tests/types/interactive.ts\`; package consumer imports Interactive runtime subpath | \`scripts/test-types.mjs\`, \`scripts/test-package.mjs\`, \`tests/package/consumer.mjs\` | **CODE-PRESENT / LOCAL PASS; CI-BLOCKED**. Verify exact TS 5.0.4 minimum and exact pinned Node matrix. | +| A-M6-03 CI integration | \`package.json\` test/verify includes Interactive and integration tests; \`.github/workflows/ci.yml\` has 4 OS/Node verify jobs + 2 Linux Host jobs + website | Main run 43146363166 succeeded 7/7 on prior \`13d573c\`; latest main \`606d055\` run was cancelled; isolated PR #20 run 43169266030 has 7 queued jobs | **CODE-PRESENT / CURRENT EXACT-HEAD CI-BLOCKED**. Do not call current main M6 complete. | +| A-M6-04 fault/concurrency matrix | \`crash.test.mjs\`, \`m6-e2e.test.mjs\`, \`m6-ledger-boundary.test.mjs\`, \`store.test.mjs\` | Representative process kills, two-process races, M6 host restart and capacity tests | **PARTIAL**. Map full F01–F20 and platform-equivalent cuts; current coverage is not a full matrix PASS. | +| A-M6-05 docs/examples | Standard README/website docs exist; \`docs/interactive-host-security.md\` documents M5 boundary; no \`examples/interactive/README.md\` or dedicated Interactive quick-start example directory found | \`docs:examples\` verifies existing docs examples, but these are primarily Standard | **PARTIAL**. Need an Interactive-specific quick start, trusted Host example, supported-node/security limits and M6 evidence guide. | +| A-M6-06 budget/performance | \`scripts/bench-interactive-load.mjs\` is explicitly diagnostic-only; S07 capacity tests cover checkpoint/receipt limits | \`s07-capacity.test.mjs\` 13 tests; benchmark records load/cache timings and Journal revisions | **PARTIAL**. No dedicated \`budget-perf.test.mjs\` or full write-amplification/concurrency/WAL/FULL benchmark evidence; add bounded metrics without inventing SLA. | + +## 8. Cross-cutting findings and corrected interpretation + +| Finding | Current conclusion | +|---|---| +| CF-01 | P0-A admin termination is absent; this is a real implementation gap. | +| CF-02 | Factory API is present; whether top-level signatures are required is a formal V0.6 §4/approval decision, not a simple missing capability. | +| CF-05 | Terminal State is present in Coordinator/Host load frame; PublicTask itself is allowlisted. The separate trusted result-read permission and model-facing adapter boundary remain unresolved. Do not claim a proven model leak without a path showing the model receives Host load output. | +| CF-06 | Current Store interface is synchronous; compare exact frozen async Store contract and approved implementation decisions before changing it. | +| CF-07 | Fixed in merged #18; keep both R04 tests. Local Windows Node 22.22.2/24.22.2 passed; current main exact-HEAD CI not completed. | +| CF-08 | Reproduced in local probe; not fixed and not shown to bypass P0-A feature gate. Add an isolated regression and minimal fix. | +| F-02 | Grok native MCP/tool_call start-input binding and truncation behavior remain PARTIAL/BLOCKED. | +| F-04 | Cross-principal Windows inherited-handle / service-token tests remain BLOCKED; Linux UID test alone is insufficient. | +| F-07 | Formal source recovery is closed; full T01–T34 and V0.6 §§1–18 conformance decision remains pending. | + +## 9. Phase 0 conclusion and next actions + +1. The 31-task inventory shows M1/M2/M4 have broad implementation surfaces, but source presence is not final acceptance. M3 has Store contract/atomicity items to reconcile. M5 has material P0-A gaps (admin termination and reference bridge) plus result-projection closure. M6 still lacks complete cross-platform/native-host/performance/docs evidence. +2. Do not repeat M1–M5 wholesale. Work only on proven gaps and incomplete evidence. +3. Complete the formal V0.3/V0.6-R5 conformance matrix before changing CF-02/05/06 public contracts. +4. Resolve CF-01 and the M5 result projection boundary before declaring P0-A complete. +5. Run H3-01 and H3-05 under their approved independent security scope; H3-02 requires its tool-capability probe; H3-03 follows H3-02; H3-04 follows H3-03 + H3-05. +6. Keep local verification and GitHub Actions statuses separate. The current isolated PR run is queued; it is a scheduling observation, not a product test failure. + +**This crosswalk does not modify the approved plan or authorize changing frozen semantics. All task statuses remain subject to independent review and raw evidence.** From 8555d10484e01a02815fdcb2af29e07abd5cffc5 Mon Sep 17 00:00:00 2001 From: rocky Date: Thu, 12 Nov 2026 15:44:00 +0900 Subject: [PATCH 3/6] docs(interactive): refresh roadmap and formal audit baseline to 606d055 --- ...active-full-delivery-roadmap-2026-11-11.md | 28 +++++++++++-------- ...teractive-phase2-formal-source-register.md | 12 +++++++- ...eractive-v03-v06-conformance-audit-plan.md | 19 +++++++++++-- 3 files changed, 44 insertions(+), 15 deletions(-) diff --git a/docs/interactive-full-delivery-roadmap-2026-11-11.md b/docs/interactive-full-delivery-roadmap-2026-11-11.md index 20de9e3..e6db637 100644 --- a/docs/interactive-full-delivery-roadmap-2026-11-11.md +++ b/docs/interactive-full-delivery-roadmap-2026-11-11.md @@ -1,9 +1,11 @@ # FlowKit Interactive — Full Delivery Roadmap & Closure Ledger -**Baseline date:** 2026-11-11 (UTC+8) +**Baseline date:** 2026-11-12 (UTC+8) **Repository:** `devcodex-labs/flowkit` **Historical Phase 0 baseline:** `ea2bb10893a9be2e5de3561fc9a660a6977ae15c` -**Current main HEAD after PR #14:** `ae5fc5a42c67eb6e2c229d72ff4d9ac8e3aab3cd` +**Historical main HEAD after PR #14:** `ae5fc5a42c67eb6e2c229d72ff4d9ac8e3aab3cd` +**Current main snapshot:** `606d055d5f02451fea0b30294889d740ef370d49` +**Phase 0 refresh:** Draft PR [#20](https://github.com/devcodex-labs/flowkit/pull/20) records the current baseline and 31-task crosswalk. **Phase 2 design record:** merged via PR #14 (docs-only; formal contract conformance remains conditional) > This document records the approved end-to-end route from the current M6/P0-A state through P0-B, P1, P2 and production delivery. It is a roadmap and traceability ledger, not evidence that deferred features have been implemented or passed. @@ -12,14 +14,18 @@ ### 1.1 Main and CI -- Current main HEAD after PR #14: `ae5fc5a42c67eb6e2c229d72ff4d9ac8e3aab3cd`. -- Post-merge main CI: [43132513659](https://github.com/devcodex-labs/flowkit/actions/runs/43132513659), **7/7 jobs successful** (Ubuntu/Windows × Node 22/24, Linux Host OS-user isolation × Node 22/24, website). +- Current main snapshot: `606d055d5f02451fea0b30294889d740ef370d49`. +- Historical main CI [43146363166](https://github.com/devcodex-labs/flowkit/actions/runs/43146363166) passed 7/7 on `13d573c5ddc4a0ed3502401589c581799c96c5d2`; it is **not** the current main SHA. +- The three rapid main pushes after PR #16/#19/#18 produced runs 43161068943, 43161142187 and 43161214780; all now show `completed/cancelled`. The workflow has `cancel-in-progress: true`, so earlier same-ref runs are superseded. The latest run's final cancellation cause is not established by accessible metadata. +- Fresh isolated PR #20 run [43169806113](https://github.com/devcodex-labs/flowkit/actions/runs/43169806113) has 7/7 jobs `queued` with no runner/start timestamp. Five older queued runs remain on the merged Trusted Host design branch, with zero jobs and no associated open PR. +- GitHub Status currently reports all systems operational; the Nov 11 incident is resolved. Do not label this a proven global outage; current evidence shows a repository/run-specific scheduling anomaly. Local verification is a fallback, not CI PASS. - PR #14 merge commit: `ae5fc5a42c67eb6e2c229d72ff4d9ac8e3aab3cd`; the merge adds only the reviewed Trusted Host V2 design/acceptance/review documentation. - M1–M5 implementation surfaces and S07 capacity work exist on main. Their presence is not a blanket claim that every M6/native-host gate is passed. - PR #8, #9 and #10 are merged. - PR #7 is **closed without merge** as superseded. PR #13 is **merged** into main with current-main M6 tests, correct project-root discovery and successful exact-HEAD CI. -- PR #12 remains open Draft, head `c6b42a36050d885a37831cbdf0839428b2052c85`, based on `ea2bb10893a9be2e5de3561fc9a660a6977ae15c`. Its scripted C13–C20 tests and documentation CI passed; this does not pass C12/S13 native-host gates. +- PR #11 (ChatGPT tool bridge) and PR #12 (C01–C24 acceptance) remain open Draft; both are based on the older `ea2bb108` baseline and are 6 commits behind current main. Update/review their independent changes before merging. Their scripted evidence does not pass native Grok C12/S13 gates. - PR #14 is **merged** as a docs-only conditional security design record. Merge does not authorize Phase 3 or claim Windows/Linux Secure Host, Grok native provenance, C12/S13 or M6 acceptance. +- PR #16 (formal audit R1/R2), #18 (R04 input snapshot fix) and #19 (local verification report/evidence) are merged. PR #17 is closed without merge because its two regression tests are included in #18. ### 1.2 Evidence classes @@ -34,7 +40,7 @@ Never count P evidence as M or N. Never count a CI replay of recorded model turn | Phase | Scope | Required exit condition | Current state | |---|---|---|---| -| 0 | Baseline freeze and traceability | Immutable baseline, full requirement/Finding/test ledger and evidence index | **Complete** — established in merged PR #13 | +| 0 | Baseline freeze and traceability | Immutable baseline, full requirement/Finding/test ledger and evidence index | **Historical freeze complete** — PR #13; current-main re-baseline and 31-task crosswalk are being updated in PR #20 | | 1 | M6 current-main test compatibility | PR #7 tests run against frozen current main; no Core semantic change hidden in test repair | **PASS, merged** — PR #13; main CI 7/7; four matrix cells 369/369, Linux isolation/M6 e2e 11/11 on Node 22/24; no production Core change | | 2 | Trusted Host security design and formal contract conformance | Approved threat model, OS identity, IPC, key custody, Store ownership, provenance and confirmed V0.3/V0.6-R5 conformance | **设计记录已合并**(PR #14;main CI 43132513659 7/7 PASS);F-01/F-R2-01 **CLOSED**;F-02/F-04 仍 PARTIAL。V0.3 Requirements 与 V0.6-R5 Technical Design 均已恢复并完成完整 SHA-256/包内清单校验;V0.6 Confirmed Handoff 9/9、Core POC Evidence 28/28 文件条目 PASS。现有核心 PoC 为 **22/22 测试 PASS、9/9 进程级崩溃点恢复**,但仅为 Linux/Node 22.16 独立原型;POC-01/05/06/09 PARTIAL,POC-07 Human BLOCKED,POC-08 完整矩阵 BLOCKED。F-07 的原件缺失问题已关闭,正式契约符合性审查进入 **IN-PROGRESS**;在完成 T01–T34、R01–R22、S01–S14 及当前实现映射前,Phase 2 不宣称 conformance PASS。参见 [正式契约原件登记](./interactive-phase2-formal-source-register.md) 和 [V0.3/V0.6 符合性审查计划](./interactive-v03-v06-conformance-audit-plan.md) | | 3 | Trusted Host security implementation | Windows and Linux isolation, access-denial tests and secure Host operations pass | Pending | @@ -96,7 +102,7 @@ Freeze a Host threat model before implementation: - Provider-signed evidence may be used if genuinely available, but is not assumed to be the only possible design. Any alternative Host-owned transport must state its exact assurance level and limits. - Human approval remains unavailable/blocked unless a model-unwritable trusted human decision channel is independently verified. -Deliverables: threat model, trust topology, candidate-ingress security contract (with optional authenticated listening IPC only when needed), key custody, provider/session evidence design, Windows/Linux profiles, attack matrix and acceptance gates. Independent review must close all **applicable design-blocking** findings before Phase 3. Missing formal V0.3/V0.6-R5 originals remain an explicit conformance BLOCKED item, not evidence that they never existed; OS capability PoCs can be performed separately, but no final conformance claim can be made without them. +Deliverables: threat model, trust topology, candidate-ingress security contract (with optional authenticated listening IPC only when needed), key custody, provider/session evidence design, Windows/Linux profiles, attack matrix and acceptance gates. Independent review must close all **applicable design-blocking** findings before Phase 3. The V0.3/V0.6-R5 originals have been recovered and their full SHA-256/archive manifests verified (see source register). The source-provenance portion of F-07 is CLOSED; clause-by-clause conformance remains IN-PROGRESS until T01–T34, §§1–18, R01–R22 and S01–S14 are mapped and independently reviewed. ## 6. Phase 3 — Trusted Host security implementation @@ -369,10 +375,10 @@ A phase cannot pass by deleting a test, weakening an assertion, changing the evi 1. Phase 0/1 **complete**: PR #13 merged to main `9bac8f86347a405efe068f96423ae3e501005061`; old PR #7 closed unmerged. 2. Main CI [42998521531](https://github.com/devcodex-labs/flowkit/actions/runs/42998521531): 7/7 successful; Ubuntu/Windows × Node 22/24 each 369/369; Linux OS isolation + M6 11/11 on both Node versions. -3. Phase 2 security design record (still Draft/Conditional): [Trusted Host V2](./interactive-trusted-host-security-v2-design.md), [threat model](./interactive-trusted-host-security-v2-threat-model.md), [acceptance matrix](./interactive-trusted-host-security-v2-acceptance.md), [review ledger](./interactive-trusted-host-security-v2-review.md). Third-round Grok review closed F-01/F-R2-01; F-02/F-04 remain PARTIAL and F-07 remains BLOCKED. -4. Three rounds of Grok Build independent review have been completed, including the final targeted review of F-01/F-R2-01. Phase 2 is **not yet frozen**: F-02 native tool binding, F-04 cross-principal handle isolation and F-07 formal contract provenance remain open/BLOCKED. Draft/CI success is not a substitute for native Host security acceptance or a professional third-party security certification. -5. Then implement OS isolation, trusted bridge, direct Grok Build tool loop, real-model edge cases and Phase 6 M6 closure. PR #12 remains Draft until its own scoped review. +3. Phase 2 security design record (still Draft/Conditional): [Trusted Host V2](./interactive-trusted-host-security-v2-design.md), [threat model](./interactive-trusted-host-security-v2-threat-model.md), [acceptance matrix](./interactive-trusted-host-security-v2-acceptance.md), [review ledger](./interactive-trusted-host-security-v2-review.md). Third-round Grok review closed F-01/F-R2-01; F-02/F-04 remain PARTIAL. F-07 source recovery is CLOSED; formal clause-by-clause conformance remains PENDING REVIEW. +4. Three rounds of Grok Build independent review have been completed, including the final targeted review of F-01/F-R2-01. Phase 2 is **not yet frozen**: F-02 native tool binding and F-04 cross-principal handle isolation remain PARTIAL/BLOCKED; formal conformance is still pending. Draft/CI success is not a substitute for native Host security acceptance or a professional third-party security certification. +5. Current Phase 0 re-baseline is tracked in [PR #20](https://github.com/devcodex-labs/flowkit/pull/20): current snapshot, CI fallback and the approved 31-task P0-A crosswalk. Then continue the exact dependency order: formal contract review and P0-A gap closure; H3-01/H3-05 OS-only work may proceed independently under the approved security design; H3-02 requires its capability probe; H3-03 follows H3-02; H3-04 follows H3-03 + H3-05; Phase 4 native Grok remains gated by Phase 3. -**Formal contract source caveat:** Historical FlowKit requirement V0.3 and technical design V0.6-R5 are cited in previous handoffs, but their full immutable bodies/SHA-256 are not presently available to this PR's independent reviewer. Conformance to those documents remains **BLOCKED** until the exact originals can be independently read and hashed; roadmap IDs cannot replace official text. +**Formal contract source status:** Requirements V0.3 and Technical Design V0.6-R5 originals are recovered and hash-verified (see [formal source register](./interactive-phase2-formal-source-register.md)). Do not mark overall conformance PASS until the complete clause-by-clause matrix and independent review are finished. **No direct main modification or release is authorized. Merge only through a reviewed PR after exact-HEAD CI. This test/roadmap PR does not authorize production semantic changes or declare M6 complete.** diff --git a/docs/interactive-phase2-formal-source-register.md b/docs/interactive-phase2-formal-source-register.md index b41f1e7..329126c 100644 --- a/docs/interactive-phase2-formal-source-register.md +++ b/docs/interactive-phase2-formal-source-register.md @@ -2,7 +2,9 @@ **状态:SRC-01 / V0.3 与 SRC-02 / V0.6-R5 均已找回并完成 SHA-256/包内清单验证;SRC-03、SRC-04 也已在资料空间目录中定位。** **登记日期:2026-11-12(UTC+8)** -**当前 main:** `ae5fc5a42c67eb6e2c229d72ff4d9ac8e3aab3cd` +**历史源码核验基线:** `ae5fc5a42c67eb6e2c229d72ff4d9ac8e3aab3cd` +**当前 main 快照:** `606d055d5f02451fea0b30294889d740ef370d49`(2026-11-12) +**关联当前状态:** [Phase 0 基线/CI 回退记录](./interactive-phase0-current-baseline-ci-fallback-20261112.md) · [P0-A 31 项交叉核对](./interactive-p0a-31-task-crosswalk-20261112.md) **关联设计:** [Trusted Host V2](./interactive-trusted-host-security-v2-design.md) · [完整路线图](./interactive-full-delivery-roadmap-2026-11-11.md) ## 1. 目标原件 @@ -73,6 +75,14 @@ SRC-01 和 SRC-02 的原件字节、SHA-256 与包内清单已验证;SRC-03 - SRC-04 `FlowKit-Interactive-Final-Convergence-Review-V0.6-R5.zip` 已在 Library `/FlowKit/` 定位,大小 171,006 bytes;本轮任务不依赖该 ZIP 才能开始符合性审查。若后续需要逐条核对历史 R5 复审过程,再单独读取该归档。 - 不能将 V0.3-R2 Draft 或任何摘要当作 V0.6-R5 正式设计;本登记引用的 V0.6-R5 正式文件 SHA-256 为 `09f3a5698e238d10b80efb8e26d1c41e51b663ca620efa70815dd7b52f2106ba`。 + +## 6. Current main and PR snapshot (2026-11-12) + +- Current main: `606d055d5f02451fea0b30294889d740ef370d49`. The original recovery/source-hash evidence above is unchanged; `ae5fc5a` remains a historical source-review baseline only. +- PR #16/#18/#19 merged; PR #17 closed without merge; PR #11/#12 remain open Draft and are six commits behind current main. +- PR #20 carries the current baseline and 31-task crosswalk; its latest exact-head Actions run is queued (7 jobs, no runner start). Local verification must remain separately labelled from CI. +- Formal source recovery is complete; formal conformance review remains pending. + --- **当前结论:** SRC-01(V0.3)与 SRC-02(V0.6-R5)正式原件均已找回并完成 SHA-256/清单验证;SRC-02 位于本轮上传的 Confirmed Handoff ZIP,9/9 条目通过。SRC-03 在资料空间已定位且有已验证内容副本;SRC-04 在资料空间已定位,但其 ZIP 原始字节尚未读取。原件恢复门禁已解除,下一步应直接开展 V0.3/V0.6-R5 逐条符合性核验,不再要求用户重新上传这两份文件;H3-01/H3-05 的独立 OS 安全工作可以继续,但不得越界修改冻结功能契约。 diff --git a/docs/interactive-v03-v06-conformance-audit-plan.md b/docs/interactive-v03-v06-conformance-audit-plan.md index 2c4e221..e5d8887 100644 --- a/docs/interactive-v03-v06-conformance-audit-plan.md +++ b/docs/interactive-v03-v06-conformance-audit-plan.md @@ -2,7 +2,9 @@ **状态:已批准进入审查;尚未形成符合性结论。** **基线日期:2026-11-12(UTC+8)** -**当前 main:** `ae5fc5a42c67eb6e2c229d72ff4d9ac8e3aab3cd` +**历史源码核验基线:** `ae5fc5a42c67eb6e2c229d72ff4d9ac8e3aab3cd` +**当前 main 快照:** `606d055d5f02451fea0b30294889d740ef370d49`(2026-11-12) +**当前基线证据:** [Phase 0 current baseline](./interactive-phase0-current-baseline-ci-fallback-20261112.md) · [P0-A 31-task crosswalk](./interactive-p0a-31-task-crosswalk-20261112.md) **需求基线:** Requirements V0.3(已确认) **技术基线:** Technical Design V0.6-R5(已确认) **安全补充:** PR #14 Trusted Host V2(已合并的安全设计记录,不覆盖 V0.3/V0.6-R5) @@ -37,7 +39,8 @@ | Core POC Evidence ZIP | SHA-256 `a6b5201e8327463b57700174297bf986fbc4902c6ef6493710e8cac021f178` | 内部 manifest 28/28 文件条目 PASS;最终 TAP 22/22;9 个 SIGKILL 断点 | | V0.3 Grok Development Handoff ZIP | SHA-256 `8a2f679a796234383b5108d58db16c1016a35c6110301bc4eb7e091ee2ed5826` | 仅含 V0.3-R2 technical draft,不是 V0.6 Confirmed Handoff | | PR #14 | Merge commit `ae5fc5a42c67eb6e2c229d72ff4d9ac8e3aab3cd` | Trusted Host V2 安全设计记录已合并;不等于安全实施通过 | -| 当前 main | `ae5fc5a42c67eb6e2c229d72ff4d9ac8e3aab3cd` | 本次代码符合性核验的当前基线 | +| 历史 main(原 R1/R2 代码基线) | `ae5fc5a42c67eb6e2c229d72ff4d9ac8e3aab3cd` | 保留为历史审查基线,不覆盖 | +| 当前 main(2026-11-12) | `606d055d5f02451fea0b30294889d740ef370d49` | 本轮实现符合性核验对象 | POC 报告的限定结论: - POC-01 PARTIAL:使用受限 JSON Fixture,未接入真实 FlowKit AST/Fields/Graph/Dataflow。 @@ -74,7 +77,8 @@ POC 报告的限定结论: - [x] V0.6 Confirmed Handoff 内部 9/9 SHA256SUMS 校验。 - [x] Core POC Evidence 内部 28/28 文件条目校验。 - [x] 两个独立归档中的 V0.3/V0.6 基线文件哈希一致。 -- [x] 当前 main、PR #14 merge commit 和 CI 记录已登记。 +- [x] 原 R1/R2 历史 main、PR #14 merge commit 和当时 CI 记录已登记。 +- [x] 2026-11-12 当前 main `606d055`、PR #16/#18/#19 合并、PR #17 关闭、PR #11/#12 开放状态已登记在 Phase 0 current baseline;最新 PR #20 exact-head CI 仍 queued,不能标 PASS。 - [ ] 将原始文件字节、归档哈希、当前 main SHA 和工具版本写入最终审查报告的不可变 Evidence Index。 ### Step 2 — V0.3 需求逐条提取与验收语义锁定 @@ -243,6 +247,15 @@ T25 的赢家选择、未完成分支、迟到副作用、下游状态可见性 - C12/S13 必须有真实原生工具、来源绑定和 Host 安全证据。 - 发布/部署另行授权,不因 P0-A/P0-B 完成自动进行。 +## 3.1 Current-main re-baseline update (2026-11-12) + +- Keep `ae5fc5a` as the historical R1/R2 source-code comparison point; do not rewrite historical evidence. +- Current implementation target is `606d055d5f02451fea0b30294889d740ef370d49`. +- PR #18 fixes CF-07; PR #19 preserves local Windows verification evidence; PR #16 archives the R1/R2 audit. PR #17 is closed as superseded. +- CF-08 is locally reproduced but not fixed. CF-01/02/05/06 remain open with the boundaries recorded in the 31-task crosswalk. +- PR #11/#12 require current-main update and independent review before merge. Their scripted test assets must not be confused with native Grok C12/S13 acceptance. +- GitHub Actions is not currently a proven global outage: official Status reports operational, but the latest isolated PR #20 run has seven queued jobs and no runner start. Use the local verification policy in the current-baseline document; keep CI state BLOCKED. + ## 4. 统一状态和停机规则 每条矩阵只能使用: From c6bff96de2d666dd483499bd4f09009392cd40c3 Mon Sep 17 00:00:00 2001 From: rocky Date: Thu, 12 Nov 2026 16:16:33 +0900 Subject: [PATCH 4/6] docs(interactive): refine retain semantics and review PR11/PR12 evidence --- ...eractive-p0a-31-task-crosswalk-20261112.md | 34 ++++++++++++++++--- ...0-current-baseline-ci-fallback-20261112.md | 22 ++++++++++-- 2 files changed, 48 insertions(+), 8 deletions(-) diff --git a/docs/interactive-p0a-31-task-crosswalk-20261112.md b/docs/interactive-p0a-31-task-crosswalk-20261112.md index 4b2b874..457bfab 100644 --- a/docs/interactive-p0a-31-task-crosswalk-20261112.md +++ b/docs/interactive-p0a-31-task-crosswalk-20261112.md @@ -40,7 +40,7 @@ No item in this table is a final P0-A acceptance PASS. |---|---|---|---| | A-M3-01 canonical JSON and identity | \`src/interactive/canonical.mjs\`: bounded canonical bytes, snapshot, hash and decoding; Store implements artifact identity | \`store.test.mjs\`: key order, prototype-as-data, accessors, Proxy, cycle, \`-0\`, non-finite and limits | **PARTIAL**. Confirm the exact V0.6 canonicalization requirement and add/verify full RFC 8785/JCS golden vectors (POC-F04); current tests show a constrained canonical JSON contract, not by themselves complete JCS conformance. | | A-M3-02 SQLite CheckpointStore | \`src/interactive/sqlite-store.mjs\` implements WAL/FULL, Genesis, transactions, CAS, Journal and receipt index | \`store.test.mjs\`: atomic CAS/Journal, duplicate transition rollback, connection restart and two OS processes | **PARTIAL**. Current public Store interface is synchronous while R1/R2 CF-06 records an async five-operation V0.6 contract discrepancy. Resolve against exact V0.6 §5/§8 and approval record; preserve atomic semantics. | -| A-M3-03 Program Registry / Run retain | Artifact bytes and identity live in \`fk_i_artifacts\`; Run rows reference artifacts; deletion is refused while historical Runs reference bytes | \`store.test.mjs\`: immutable bytes, tenant namespace and deletion refusal; \`m6-e2e.test.mjs\`: Program retained and tamper rejected | **PARTIAL**. The coordinator calls \`putArtifact\` then \`createRun\`; Run+Genesis Journal are transactional, but artifact registration is a preceding Store operation. Explicitly reconcile orphan-artifact and Genesis/Retain atomicity with V0.6 §6.2 and the approved M3 task before calling the full retain contract closed. | +| A-M3-03 Program Registry / Run retain | fk_i_artifacts stores immutable Program bytes/identity; fk_i_runs(namespace, artifact_hash) has a composite FK to the artifact row. createRun() inserts the Run reference and Genesis Journal in one write transaction; deleteArtifact() refuses while any Run references the artifact. | store.test.mjs: immutable bytes, tenant namespace, deletion refusal, atomic Run/Journal; m6-e2e.test.mjs: retained Program and tamper rejection | **CODE-PRESENT for atomic Run-retain + Genesis**. Important distinction: putArtifact() pre-registers immutable bytes in a preceding transaction, but the durable Run→artifact retain association is the FK-bearing Run row committed atomically with Genesis. A crash before createRun() can leave an unreferenced artifact row, not a Run without its Program retain. Finish the exact V0.6 §6.2 lifecycle/cleanup crosswalk; do not call this an established atomic-retain defect. | | A-M3-04 Store/Journal/Receipt tests | \`tests/interactive/store.test.mjs\`, \`s07-capacity.test.mjs\`, \`coordinator.test.mjs\` | Tests include CAS, Journal chain, receipt history, duplicate transition rollback, tenant isolation and cross-process competition | **CODE-PRESENT / PARTIAL**. Finish full historical Ack, unknown-CAS-response and all approved failure-matrix cases with raw evidence. | | A-M3-05 crash workers | \`tests/interactive/crash.test.mjs\`, \`tests/integration/m6-worker.mjs\`, \`m6-host.mjs\` | Real SIGKILL before/after Agent publish, receipt acceptance, validation and State commit; two-process receipt race | **PARTIAL**. Current tests cover representative cut points, not proof that all F01–F20 and all applicable Windows/Linux equivalents have passed. | @@ -70,11 +70,35 @@ No item in this table is a final P0-A acceptance PASS. |---|---|---|---| | A-M6-01 package exports/manifest | \`package.json\`, \`scripts/package-files.mjs\`, \`check-package.mjs\`, \`test-package.mjs\`; exports include \`./interactive\`, no extra npm bin | \`tests/package/package.test.mjs\`; local PR #19 \`npm run verify\` evidence | **CODE-PRESENT / LOCAL PASS; CI-BLOCKED** at latest main SHA. | | A-M6-02 TS declarations/consumer | \`types/interactive.d.ts\`, \`tests/types/interactive.ts\`; package consumer imports Interactive runtime subpath | \`scripts/test-types.mjs\`, \`scripts/test-package.mjs\`, \`tests/package/consumer.mjs\` | **CODE-PRESENT / LOCAL PASS; CI-BLOCKED**. Verify exact TS 5.0.4 minimum and exact pinned Node matrix. | -| A-M6-03 CI integration | \`package.json\` test/verify includes Interactive and integration tests; \`.github/workflows/ci.yml\` has 4 OS/Node verify jobs + 2 Linux Host jobs + website | Main run 43146363166 succeeded 7/7 on prior \`13d573c\`; latest main \`606d055\` run was cancelled; isolated PR #20 run 43169266030 has 7 queued jobs | **CODE-PRESENT / CURRENT EXACT-HEAD CI-BLOCKED**. Do not call current main M6 complete. | +| A-M6-03 CI integration | package.json test/verify includes Interactive and integration tests; .github/workflows/ci.yml has 4 OS/Node verify jobs + 2 Linux Host jobs + website | Main run 43146363166 passed 7/7 on prior 13d573c; latest main 606d055 run 43161214780 is cancelled. PR #20 runs 43169266030 and 43169806113 were superseded/cancelled after subsequent documentation commits; latest exact-head run 43170215982 has all 7 jobs queued with no runner start. | **CODE-PRESENT / CURRENT EXACT-HEAD CI-BLOCKED**. Do not call current main M6 complete. | | A-M6-04 fault/concurrency matrix | \`crash.test.mjs\`, \`m6-e2e.test.mjs\`, \`m6-ledger-boundary.test.mjs\`, \`store.test.mjs\` | Representative process kills, two-process races, M6 host restart and capacity tests | **PARTIAL**. Map full F01–F20 and platform-equivalent cuts; current coverage is not a full matrix PASS. | -| A-M6-05 docs/examples | Standard README/website docs exist; \`docs/interactive-host-security.md\` documents M5 boundary; no \`examples/interactive/README.md\` or dedicated Interactive quick-start example directory found | \`docs:examples\` verifies existing docs examples, but these are primarily Standard | **PARTIAL**. Need an Interactive-specific quick start, trusted Host example, supported-node/security limits and M6 evidence guide. | +| A-M6-05 docs/examples | Interactive maintainer docs already exist: docs/interactive.md (Host-only SDK example and P0-A boundaries), docs/interactive-stage2-contract.md, docs/interactive-host-security.md and docs/interactive-s07-capacity.md. No examples/interactive/README.md or dedicated runnable Trusted Host example directory exists on main. | docs:examples verifies existing Standard documentation examples; Interactive docs include code guidance but are not a complete packaged consumer example suite. | **PARTIAL**. Do not describe Interactive documentation as absent. Remaining work is a runnable, maintained Interactive example/README, consumer-facing documentation integration, supported Node/OS/security limits and a consolidated M6 evidence guide. | | A-M6-06 budget/performance | \`scripts/bench-interactive-load.mjs\` is explicitly diagnostic-only; S07 capacity tests cover checkpoint/receipt limits | \`s07-capacity.test.mjs\` 13 tests; benchmark records load/cache timings and Journal revisions | **PARTIAL**. No dedicated \`budget-perf.test.mjs\` or full write-amplification/concurrency/WAL/FULL benchmark evidence; add bounded metrics without inventing SLA. | +## 7.1 PR #11 / #12 independent evidence review + +These PRs are useful evidence assets, but their evidence tiers and cross-run persistence limits must remain explicit. Both branches are based on the older ea2bb108 baseline and are six commits behind current main 606d055; both must be updated and re-run before merge consideration. Neither changes production Core source. + +### PR #11 — ChatGPT tool-using bridge (M-level, not native S13) + +- Scope: four added files (workflow, public Skill, model-response fixture, one bridge test); no production source or ABI changes. +- Phase 1 evidence: run 42956481857 has a cancelled overall conclusion because later pushes superseded it, but its successful Ubuntu 24.04 / Node 24.22.1 job log contains S13_CHATGPT_PUBLIC_TASK and S13_CHATGPT_PHASE1_WAITING. The exact Pending was requestId=req:6bed7ea39b96e81b99100ffe69bb174ba38533d42f3bbdbefad6239cee0ac829, taskDigest=sha256:96733a8e513b08020acc42ef5dabd93413d52b452d8b982d40afcf3b81ac2876, revision=5, six Journal entries. +- Phase 2 evidence: run 42956698215 was also superseded/cancelled overall; its successful Ubuntu 24.04 / Node 22.13.0 job log contains S13_CHATGPT_TOOL_BRIDGE_COMPLETED: terminal succeeded, acceptedRevision=6, 12 Journal revisions, duplicate Ack and SQLite close/reopen recovery. The model reply digest is recorded in the log. Final PR-head run 42957070193 completed 7/7 jobs successfully. +- Evidence classification: **M / actual ChatGPT tool-using response recorded and bound to the exact Pending requestId/taskDigest; no independent provider/session attestation.** It is not Grok Build, Codex native tools or N-level S13. +- Persistence limit: Phase 1 and Phase 2 are separate Actions runs with separate temporary directories. Phase 2 recreates the deterministic Program/Pending and verifies the recorded model response against the same requestId/taskDigest, then closes/reopens its own SQLite DB before acceptance. This proves the response is bound to the exact deterministic Pending and proves same-run SQLite restart, but does not prove one physical SQLite database survived across the two Actions runs. + +### PR #12 — C01–C24 complex acceptance assets (P + M, not native S13) + +- Scope: eight added files (matrices/results, workflow, fixture, two test suites); no production Core source or ABI changes. +- Scripted protocol layer: complex-c01-c12.test.mjs contains 14 test functions covering C01–C04, C10–C11 and C13–C20. The eight C13–C20 extension cases are scripted Trusted Host tests with zero model calls. Run 42968295106 completed all seven jobs successfully; each of the four Ubuntu/Windows × Node 22/24 matrix cells reported 372/372 tests. Final PR-head run 42968816210 also completed 7/7 jobs successfully. +- Live-model layer: c01-live-chatgpt.test.mjs replays five recorded ChatGPT responses against five exact Pending identities (four dependent Agent nodes plus a deliberate invalid-schema review response and corrected retry). Run 42963110678 job logs record execution=REAL_CHATGPT_GITHUB_BRIDGE, realModelTurns=5, five request IDs, Program hash, final State hash, terminal success and 39 Journal revisions. This is M-level real-model participation, not native provider/session attestation. +- Persistence limit: the live-model test explicitly creates a fresh temporary SQLite DB for each Actions run, replays the recorded responses, and tests close/reopen within that run. It does not preserve one physical DB across the five external model turns/Actions runs. +- C21 is recorded PARTIAL; C22 is protocol/OS-UID evidence with native Host still BLOCKED; C23 is M/N BLOCKED; C24 is CI/compatibility partial with N BLOCKED. C12/S13 remains BLOCKED until Grok Build native tool/session provenance and model-process isolation are independently proven. +- Coverage note: the C04 fixture uses retries=1 (two attempts), not the default retries=2 (three attempts). Default retry exhaustion is covered separately by main's Coordinator tests; do not count the C04 fixture alone as default-retry evidence. +- Historical wording correction: PR #12's 2026-11-11 results refer to PR #7 as still Draft. PR #7 is now closed without merge; its applicable M6 drift coverage was superseded by PR #13/main, including tests/integration/m6-e2e.test.mjs S06. Re-review the exact current-main assertions after branch update. + +**Decision:** Preserve both PRs and all unique assets. Update each branch onto current main, inspect the rebased diff, rerun exact-head CI, and only then decide merge readiness. Even after successful rebase CI, these PRs do not close native Grok C12/S13/T27 or P0-A overall acceptance. + ## 8. Cross-cutting findings and corrected interpretation | Finding | Current conclusion | @@ -91,11 +115,11 @@ No item in this table is a final P0-A acceptance PASS. ## 9. Phase 0 conclusion and next actions -1. The 31-task inventory shows M1/M2/M4 have broad implementation surfaces, but source presence is not final acceptance. M3 has Store contract/atomicity items to reconcile. M5 has material P0-A gaps (admin termination and reference bridge) plus result-projection closure. M6 still lacks complete cross-platform/native-host/performance/docs evidence. +1. The 31-task inventory shows M1/M2/M4 have broad implementation surfaces, but source presence is not final acceptance. M3's Run→Program retain and Genesis association is atomic through the Run FK + Genesis transaction; the async Store contract discrepancy remains open. M5 has material P0-A gaps (admin termination and reference bridge) plus result-projection closure. M6 still lacks exact-current-main CI, complete fault/performance evidence and native-host acceptance. 2. Do not repeat M1–M5 wholesale. Work only on proven gaps and incomplete evidence. 3. Complete the formal V0.3/V0.6-R5 conformance matrix before changing CF-02/05/06 public contracts. 4. Resolve CF-01 and the M5 result projection boundary before declaring P0-A complete. 5. Run H3-01 and H3-05 under their approved independent security scope; H3-02 requires its tool-capability probe; H3-03 follows H3-02; H3-04 follows H3-03 + H3-05. -6. Keep local verification and GitHub Actions statuses separate. The current isolated PR run is queued; it is a scheduling observation, not a product test failure. +6. Keep local verification and GitHub Actions statuses separate. Latest PR #20 exact-head run 43170215982 is queued (7 jobs, no runner start); previous PR #20 runs 43169266030/43169806113 were cancelled after later commits. This is a scheduling observation, not a product test failure. **This crosswalk does not modify the approved plan or authorize changing frozen semantics. All task statuses remain subject to independent review and raw evidence.** diff --git a/docs/interactive-phase0-current-baseline-ci-fallback-20261112.md b/docs/interactive-phase0-current-baseline-ci-fallback-20261112.md index 73b3c2d..86dc1a5 100644 --- a/docs/interactive-phase0-current-baseline-ci-fallback-20261112.md +++ b/docs/interactive-phase0-current-baseline-ci-fallback-20261112.md @@ -27,7 +27,7 @@ Use only: \`PASS\`, \`FAIL\`, \`PARTIAL\`, \`BLOCKED\`, \`NOT-EXECUTED\`, \`NOT- - PR #16 (R1/R2 audit docs), PR #19 (local verification evidence) and PR #18 (R04 fix + regression tests) are merged. - PR #17 is closed without merge; its two deliberately failing R04 regression tests are included in #18. - PR #7 is closed without merge; its M6 work was superseded by #13. -- PR #11 and #12 remain open Draft and must be reviewed on their own merits. +- PR #11 and #12 remain open Draft, based on ea2bb108 and six commits behind current main. Their unique evidence assets have now been reviewed at source/log level; see §4.3. Both must be updated to current main and exact-head CI rerun before merge consideration. ### 2.2 Remaining open PRs @@ -76,8 +76,9 @@ New pushes to the same ref can cancel older runs. This is intentional stale-run - Latest successful main run before the three PR merges: [43146363166](https://github.com/devcodex-labs/flowkit/actions/runs/43146363166), commit \`13d573c5ddc4a0ed3502401589c581799c96c5d2\`, 7/7 jobs successful. It is **not** the current \`606d055\` HEAD. - The three rapid main pushes from merges #16/#19/#18 created runs [43161068943](https://github.com/devcodex-labs/flowkit/actions/runs/43161068943), [43161142187](https://github.com/devcodex-labs/flowkit/actions/runs/43161142187) and [43161214780](https://github.com/devcodex-labs/flowkit/actions/runs/43161214780). All now report \`completed/cancelled\`; the first two were superseded in the same-ref concurrency window. - Run 43161214780 is attempt 2; all seven jobs currently report cancelled. Accessible run metadata does not establish why its final attempt was cancelled. Do not label it queued or failed. -- Five older runs (43095884874, 43095901291, 43095937558, 43096034832, 43096045021) remain \`queued\` on the old \`design/trusted-host-security-v2-20261111\` branch. Each currently has zero jobs and no associated open PR in the run metadata. Treat them as stale queued events, not as evidence that the current main workflow has active jobs waiting for a runner. -- At the time of this snapshot, there are 5 queued runs, 0 in-progress runs. The latest main run is cancelled, not queued. +- Five older runs (43095884874, 43095901291, 43095937558, 43096034832, 43096045021) remain queued on the old design/trusted-host-security-v2-20261111 branch. Each currently has zero jobs and no associated open PR in the run metadata. Treat them as stale queued events, not as evidence that the current main workflow has active jobs waiting for a runner. +- PR #20 run 43169266030 (head bf0d63b) and 43169806113 (head 6de7ceb) were cancelled after subsequent commits superseded those exact heads. Latest PR #20 head is 8555d10484e01a02815fdcb2af29e07abd5cffc5; run 43170215982 has all seven jobs queued, no runner name and no start timestamp. +- At the time of this snapshot, there are 6 queued runs (one current PR #20 run plus five stale design-branch runs), 0 in-progress runs. The latest main run is cancelled, not queued. GitHub Status currently reports all systems operational. The Nov 11 incident affecting Actions/Pages/Copilot was marked resolved at 21:21 UTC, with GitHub stating that the Actions backlog had been fully processed. Therefore, do **not** assert a current global GitHub outage without new evidence. A fresh isolated workflow run is required to test current scheduling on this repository. @@ -86,6 +87,21 @@ Official Actions billing/usage: https://docs.github.com/en/actions/concepts/bill The repository is now public. GitHub documents standard GitHub-hosted runner usage as free for public repositories. This makes private-repository included-minute exhaustion an unlikely explanation for current standard hosted-runner scheduling; repository/org policy and stale events still require evidence. Do not infer a billing cause. +### 4.3 PR #11 / #12 evidence review + +**PR #11 (ChatGPT bridge):** +- The Phase 1 Ubuntu 24.04 / Node 24.22.1 job log from run 42956481857 contains the actual public Pending and exact requestId/taskDigest; that run's overall conclusion is cancelled because later commits superseded it. +- The Phase 2 Ubuntu 24.04 / Node 22.13.0 job log from run 42956698215 records S13_CHATGPT_TOOL_BRIDGE_COMPLETED, terminal success, acceptedRevision 6, Journal revisions 12, duplicate Ack and SQLite close/reopen; that run's overall conclusion is also cancelled. The final PR-head run 42957070193 passed 7/7 jobs. +- This is M-level evidence of a ChatGPT tool-using response bound to the exact Pending digest. It does not attest native provider/session origin or Grok/Codex tools. The two phases use separate temporary CI databases; Phase 2 reconstructs the deterministic Pending and reopens its own DB. It does not prove one physical DB persisted between the model's two phases. + +**PR #12 (complex acceptance):** +- The final PR-head run 42968816210 passed 7/7 jobs. C13–C20 scripted protocol tests passed in run 42968295106, with 372/372 tests in each of the four OS/Node matrix cells. +- The C01/C03 live-model job log from run 42963110678 records five real ChatGPT turns, five request IDs, a Program hash, final State hash, successful terminal and 39 Journal revisions. This is M-level real-model evidence, not N-level native-host provenance. The fixture is replayed through a new temporary SQLite DB per CI run; the test does not share a physical DB across separate model turns/Actions runs. +- C21 partial, C22 protocol/UID evidence only with native Host blocked, C23 blocked, C24 CI partial/native blocked. C12/S13 remains blocked. +- C04's dedicated fixture uses retries=1/two attempts; default retries=2/three attempts remains covered separately by main Coordinator tests. + +Both PRs contain only docs/tests/fixtures/example workflows, not production Core changes. Both are six commits behind current main and require an update/rebase plus exact-head CI before merge review. Do not merge either PR or promote M evidence to native-host PASS. + ## 5. CI outage / queue fallback policy ### 5.1 Continue development without pretending CI passed From 8ccb53055f640539fd86c524f079867fbdb12713 Mon Sep 17 00:00:00 2001 From: rocky Date: Thu, 12 Nov 2026 17:23:28 +0900 Subject: [PATCH 5/6] test(interactive): add C01-C24 complex acceptance evidence MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * test(interactive): freeze C01-C12 scenario matrix and scripted/live/native evidence separation * test(interactive): C01-C04,C10,C11 scripted complex runs with real Program signed Host and SQLite * test(interactive): C01/C03 live multi-Agent two-Condition workflow definition * test(interactive): real ChatGPT multi-Agent 5-turn replay bridge with schema rejection and SQLite reopen * test(c01-live): actual ChatGPT requirements analysis bound to published Pending #1 * test(c01-live): ChatGPT architecture response to real dependent Pending #2 * test(c01-live): actual ChatGPT implementation plan from real Pending #3 * test(c03-live): ChatGPT deliberately submits invalid reviewApproved type to test real retry Pending * test(c01-live): genuine ChatGPT corrected review after real attempt-2 Pending #5 * docs(interactive): record C01-C12 detailed scripted and five-turn real ChatGPT evidence with open native gates * test(interactive): extend complex P0-A acceptance with C13-C20 interleavings * docs(interactive): extend risk-mapped C13-C24 acceptance and native-host gates * test(interactive): inspect durable Store state while Pending frame intentionally redacts State * test(interactive): verify C16 durable Checkpoint while Pending frame hides private State * docs(interactive): record independently checked 7/7 CI and C13-C24 layered verdict * test(interactive): rebase M6 Host integration on current main Add current-main M6 scripted Host integration coverage, root-discovery fixtures, Linux cross-UID CI, and the full Interactive delivery roadmap. This is test/CI/documentation only and does not complete native-host C12/S13 or M6 final acceptance. * docs(interactive): add Trusted Host V2 conditional security design Add the reviewed Trusted Host V2 threat model, deployment profiles, security acceptance matrix, and explicit Phase 2 limitations. This is documentation-only: it does not implement Host isolation, Grok native provenance, Windows ACL enforcement, or Phase 3/4 runtime changes. F-02 and F-04 remain pending real validation; F-07 formal V0.3/V0.6-R5 conformance remains blocked. Merge does not authorize Phase 3 or claim C12/S13/M6 acceptance. * docs(interactive): recover frozen baselines and establish evidence audit plan Record independently validated Requirements V0.3 and Technical Design V0.6-R5 originals, limited Core PoC results and Phase 2 traceability roadmap. Reconcile the previously confirmed M1–M6 P0-A plan and existing M1–M5 implementation. Documentation only: no Core/API/Program ABI/Store schema changes, no Phase 3 authorization, no C12/S13 or full conformance PASS claim. * docs(interactive): archive Phase 2 formal conformance R1/R2 audit * docs(interactive): add source-backed T/R/S crosswalk and initial P0-A gap findings * docs(interactive): document Host/Public terminal State projection contract difference * docs(interactive): record async Store contract divergence from confirmed V0.6-R5 * docs(interactive): add Phase 2 R2 code-evidence review and R04 mutation findings * docs(interactive): link R04 independent regression PR and retrigger Phase 2 CI * docs(interactive): archive local R04 reproduction and verification evidence * docs(interactive): record local verification of PR 16 and 17 The report keeps the PR heads, commands, R04 failure output, the snapshot fix result, and the merge recommendation. Raw decisive logs are stored beside it. No product code changes. * docs(interactive): record that Actions for PR 16-19 are still queued The 13:15 +08 reconfirm keeps all four draft PRs unmerged. Run status is queued with an empty conclusion. That is not a matrix pass and not a proven Actions outage. * fix(interactive): snapshot start inputs before first await (R04) start() copied caller-owned State and startIntent only after loadInteractiveProgram resolved. That await yields even when the loader is already settled, so a caller could change both objects before the Checkpoint and startIntentHash were created. Copy both with the existing bounded canonical snapshot first, and preserve the initial-State capacity error. Later Store writes use those copies. Includes the R04 regression tests from PR #17. * test(interactive): require complete recorded ChatGPT responses in normal CI * docs(interactive): clarify recorded model-response evidence tier --- .../interactive-complex-acceptance-c01-c12.md | 51 ++ ...x-acceptance-c13-c24-results-2026-11-11.md | 58 ++ ...ve-complex-acceptance-extension-c13-c24.md | 51 ++ ...e-complex-acceptance-results-2026-11-11.md | 86 +++ .../interactive/c01-live-chatgpt.workflow.js | 62 ++ tests/fixtures/c01-live-chatgpt-turns.json | 49 ++ tests/interactive/c01-live-chatgpt.test.mjs | 218 +++++++ tests/interactive/complex-c01-c12.test.mjs | 605 ++++++++++++++++++ 8 files changed, 1180 insertions(+) create mode 100644 docs/interactive-complex-acceptance-c01-c12.md create mode 100644 docs/interactive-complex-acceptance-c13-c24-results-2026-11-11.md create mode 100644 docs/interactive-complex-acceptance-extension-c13-c24.md create mode 100644 docs/interactive-complex-acceptance-results-2026-11-11.md create mode 100644 examples/interactive/c01-live-chatgpt.workflow.js create mode 100644 tests/fixtures/c01-live-chatgpt-turns.json create mode 100644 tests/interactive/c01-live-chatgpt.test.mjs create mode 100644 tests/interactive/complex-c01-c12.test.mjs diff --git a/docs/interactive-complex-acceptance-c01-c12.md b/docs/interactive-complex-acceptance-c01-c12.md new file mode 100644 index 0000000..f2375d2 --- /dev/null +++ b/docs/interactive-complex-acceptance-c01-c12.md @@ -0,0 +1,51 @@ +# FlowKit Interactive P0-A — 复杂验收矩阵 C01–C12(冻结版) + +**范围与判断标准**:此矩阵只测试 P0-A 的 `Condition / Agent / Terminal` 和可信 Host 的 CAS、回执、恢复、安全。不得把 Standard 的 Human/Action/Verification/Loop/Parallel 实现或脚本 Worker 的结果当作 Interactive 已支持或真实模型验证。不得把 GitHub CI 的测试数量当成真实模型会话次数。 + +**证据必须分层**: +- **Protocol / Scripted(自动化)**:实际 FlowKit Compiler → JavaScript Program → SQLite Store / Trusted Host 执行,但 Agent 结果由脚本提供。证实协议,不证实模型遵循指令。 +- **Live Model(真实模型)**:真实 ChatGPT/Grok 逐次读取已生成的 Pending 后生成答案;每次的 requestId、taskDigest、输出、工具操作必须有独立证据。ChatGPT → GitHub Actions 桥接只能证明真实参与和受控处理,不代表原生宿主/会话来源认证。 +- **Native Host(S13)**:单个受控 Grok Build / Codex 原生会话模型→JS 工具→Host→回执,原生工具日志及 Host 独立验证的会话/来源证据;不能用脚本模拟、GitHub 上传身份替代。 + +## 场景、可观测预期和证据 + +| ID | 场景 | 冻结验收要求 | 自动化证据范围 | 真实模型门禁 | +|---|---|---|---|---| +| C01 | 4 个串行 Agent + 2 个 Condition | 原生 Program 顺序、后续节点只接收合法上游状态,未跳过/重复执行;最终 State 包含各节点输出 | 新增复杂链+Host 签名测试 | **待实测**:至少四次真实模型回合 | +| C02 | 动态路线与异常条件 | ready=true/false、审查通过/拒绝、缺失 when 输入分别进入正确路径;未选 Agent 不调度 | 新增多路径正反测试 | **待实测**:至少两条真实分支 | +| C03 | Schema 拒绝与修复 | 第一次输出无效不污染 State;下一 Pending requestId/attempt 更新,合法结果可以成功 | 新增接纳/重试负例 | **待实测**:真实模型两次输出 | +| C04 | 失败/重试耗尽 | retries+1 限制,最后 `FK_R004`,State 不含未认可结果 | 新增失败序列 | 至少一个可信 Host 失败路径(真实模型待实测) | +| C05 | Host 崩溃恢复 | Pending 发布、接纳前、校验及提交各切点 SIGKILL;请求 identity/State/Journal 一致 | 已有 `tests/interactive/crash.test.mjs` 三项真子进程测试;当前 main 的 tests/integration/m6-e2e.test.mjs 另有 Host+脚本 Worker(原 PR #7 的相关工作由 PR #13 纳入) | 与真实模型耦合的 kill/resume **待实测** | +| C06 | 双进程竞争、丢响应、重复回执 | CAS 只接纳一次;后续始终返回原始 `acceptedRevision`;不声明外部 Provider 恰好执行一次 | 已有 `crash.test.mjs` + `coordinator.test.mjs` | 原生模型多会话竞争待实测 | +| C07 | Program / Skill / Policy 漂移 | 变更后未发生额外调度/CAS;旧依赖恢复不误放行 | main M5 policy 测试;当前 main 的 tests/integration/m6-e2e.test.mjs S06 覆盖脚本 Host 的 source/Skill/Program drift(由 PR #13 纳入) | 原生 Host/模型待实测 | +| C08 | 权限、签名与泄漏 | 错租户/伪签/敏感字段/UID 隔离 fail closed;模型不能直接操作私有 Store | main M5 `trusted-host` + Linux 2 项 OS 用户隔离任务 | 原生 Grok Build 私钥/SQLite 不可达待实测 | +| C09 | 容量与超限 | 2MiB hard,1.75MiB active 预留;有界结果可成功;错误原子退出;未认证超大回执不能杀 Run | main S07 `s07-capacity` + `host-oversize` | 真实模型大输出路径待实测 | +| C10 | 长链与账本 | 至少 30 个串行 Agent,Checkpoint 近期摘要 ≤16,SQLite 全量历史回执可查;Journal 连续,恢复历史 Ack | 新增长链与 SQLite 回执索引测试(现有 21 节点基础) | 不要求 30 次模型计费;脚本覆盖为准 | +| C11 | 阶段预算一致性 | `maxStagesPerCall=1` 与 128 在相同 Program/结果序列下最终 State **字节相等**,Journal 合法;不要求 revision 一致 | 新增复杂链跨预算用例,当前 main 的 tests/integration/m6-e2e.test.mjs 还有脚本 Worker 验收 | 模型侧不同调度路径待实测 | +| C12 | 原生真实模型宿主 | Grok Build 等原生 JS 工具调用原始日志、真实会话身份、Host 独立来源认证、隔离、终态 | **不能用脚本或 GitHub ChatGPT 桥接替代** | **BLOCKED**:需 Dot/Grok Build 实际宿主权限与真实日志 | + +## 每个可执行测试的最小证据格式 + +```json +{ + "scenarioId": "C01", + "execution": "SCRIPTED_HOST", + "programHash": "sha256:...", + "runId": "...", + "nodeTrace": ["requirements", "design", "plan", "review"], + "checkpointStatus": "succeeded", + "journalRevisions": 0, + "assertions": ["..."], + "result": "PASS" +} +``` + +测试完成后补充**精确提交/CI URL、各环境完成状态、实际模型回合次数、失败/未覆盖限制**。即使自动化 7/7 通过,C01–C05 只应在「协议层」标记 PASS;真实模型层未取得证据必须为 PARTIAL/BLOCKED。 + +## 阶段门禁 + +1. 只开发测试与验证报告,发现真实缺陷才另外起小范围修复 PR;不擅自重构 FlowKit Core。 +2. PR #7 已关闭且未合并,其适用 M6 测试工作由 PR #13 纳入 main;不得把历史 PR #7 当作仍可合并的分支,也不得因绿灯宣称 Grok/Codex 原生模型来源验收通过。 +3. 在复杂矩阵中允许使用脚本结果注入来做 30 Agent、并发、容量、安全负例,但必须标明执行类型和模型调用次数(脚本为零)。 +4. M6 所需的冻结需求 V0.3 / 技术 V0.6-R5 合规审查仍独立存在,不能被此矩阵替代。 +5. 本轮不引入 P0-B、P1、P2、Context、通用业务产物存储或 GC。 diff --git a/docs/interactive-complex-acceptance-c13-c24-results-2026-11-11.md b/docs/interactive-complex-acceptance-c13-c24-results-2026-11-11.md new file mode 100644 index 0000000..15bca73 --- /dev/null +++ b/docs/interactive-complex-acceptance-c13-c24-results-2026-11-11.md @@ -0,0 +1,58 @@ +# FlowKit Interactive — C13–C24 补充复杂验收结果(2026-11-11) + +## 结论 + +**P0-A 复杂协议补充用例 C13–C20:8/8 PASS(脚本可信 Host);原 C01–C12 测试继续通过。原生模型宿主 C12/S13 仍 BLOCKED,不能据此合并 M6 / 发布。** + +- 仓库:devcodex-labs/flowkit(private) +- PR:[Draft #12](https://github.com/devcodex-labs/flowkit/pull/12),基于 main,不修改生产 Core +- 验证测试提交:**09e14e82b72277ef58b656bf129c9c4bc0b4b779** +- 完成的 CI:[42968295106 — 7/7 SUCCESS](https://github.com/devcodex-labs/flowkit/actions/runs/42968295106) +- 关联矩阵:[C01–C12 原矩阵](./interactive-complex-acceptance-c01-c12.md)、[C13–C24 增量矩阵](./interactive-complex-acceptance-extension-c13-c24.md) +- 执行类型:**SCRIPTED_TRUSTED_HOST**,本次新增用例模型调用次数 **0**;不能计入真实模型调用次数 + +### 精确跨平台测试清单 + +| GitHub Actions Job | Test | Pass | Fail | Skip | Job | +|---|---:|---:|---:|---:|---| +| Ubuntu 24.04 / Node 22.13.0 | 372 | 372 | 0 | 0 | SUCCESS | +| Ubuntu 24.04 / Node 24.22.1 | 372 | 372 | 0 | 0 | SUCCESS | +| Windows 2025 / Node 22.13.0 | 372 | 372 | 0 | 0 | SUCCESS | +| Windows 2025 / Node 24.22.1 | 372 | 372 | 0 | 0 | SUCCESS | +| Host OS-user isolation / Node 22.13.0 | — | — | — | — | SUCCESS | +| Host OS-user isolation / Node 24.22.1 | — | — | — | — | SUCCESS | +| Website/docs | — | — | — | — | SUCCESS | + +以上从 GitHub Actions 的实际 job 日志/结论核验,非 PR 描述中的主观声称。372 是每一个环境内的全部测试数量,包含现有回归;新增复杂测试函数为 8 个,不能解释成 372 个真实 Agent 回合。 + +## C13–C24 逐项裁决 + +| ID | 协议层 P | 真实模型 M / 原生宿主 N | 可观测证据 / 缺口 | +|---|---|---|---| +| C13 分支×阶段预算 | **PASS** | M 未单独测 | 预算 1/128 下四个分支结果相同,已核对两个终态 State Hash | +| C14 链中伪造/超限回执 | **PASS** | N 模型对抗攻击待测 | 5 个不同类型的未认证/错误回执被拒且 Checkpoint 和 Journal 字节保持一致 | +| C15 Host 重建后旧 Ack | **PASS** | N 未测 | 下游等待态及 Terminal 后重放历史 receipt,不额外提交 State,Ack 原 acceptedRevision | +| C16 Provider 可信失败回执 | **PASS** | N 真 Provider 失败待测 | signed agent-call-failed 使末端 Agent 重试一次,旧回执重复 Ack,合法第二回合成功 | +| C17 链中 Host policy drift | **PASS** | N 实际宿主升级待测 | 3 条不同入口拒绝政策漂移并证明无 CAS 写入,旧 Host 继续成功 | +| C18 多 Run 交错、重复启动 | **PASS** | N 多模型 Session 未测 | 两 Run 状态隔离;重复 startKey 幂等,同 key 不同 State 冲突 | +| C19 36 Agent 中段失败 | **PASS** | 不要求 36 次模型计费 | 第 18 个脚本结果无效,终态 FK_R004,余下 18 个未分发,State 无非法字段 | +| C20 双有效签名并发竞争 | **PASS(同进程 Host 对象)** | N 真进程/多模型竞争待测 | 两个不同签名内容仅一个 CAS 成功、另一个 FK_I_RECEIPT_CONFLICT;真正双进程测试已在 C06/M4 另验 | +| C21 崩溃/跨版本恢复 | **PARTIAL** | N 未测 | M4 有真 SIGKILL 与同环境恢复;同一物理 DB 跨 OS/Node 迁移未执行,是增强项不是原 P0-A 硬门禁 | +| C22 Prompt 注入/宿主权限 | **PASS(既有 M5 + OS UID)** | **N BLOCKED** | 白名单、拒签、跨 UID 隔离已有证据;Grok Build 原生模型权限分离无证据 | +| C23 真实模型异常组合 | 不可用脚本替代 | **M/N BLOCKED** | 真实 false 分支、持续错误、与 SIGKILL 耦合恢复及多模型竞争未完成 | +| C24 兼容/发行/原生来源门禁 | **PASS(CI 部分)** | **N BLOCKED** | 7 job 全绿不意味着 C12/S13 原生认证已通过 | + +## 首轮失败与复审记录 + +新增 C13–C20 首次提交 5be1abb(CI 42967554504)曾 370 PASS / 2 FAIL,失败集中在 **C16 和 C20 的测试断言**:在状态为 waiting 时,测试错误地读取了公开 Frame 中被隐藏的 State。FlowKit 此时不公开私有 State 是预期安全设计。第二次提交 ac49e3e(CI 42968021802)修复了 C20,留下 C16 一处相同的测试问题(371 PASS / 1 FAIL)。最终测试提交 09e14e8 将 C16 内部断言改为从受信 SQLite Store 读取,四环境 372/372 PASS。 + +这两轮失败**不是 FlowKit Core 缺陷的证据**;本轮修复未修改生产源码、签名器、Coordinator、SQLite Schema 或 Program ABI。PR #12 changed-files 范围仅 docs、tests、fixtures、示例工作流。 + +## 仍不得放行的明确缺口 + +1. **C12/S13:原生 Grok Build/Codex 工具调用、原生 Session/Provider 来源认证、Host 独立可信证明和模型进程权限隔离**。GitHub Actions + ChatGPT 五回合桥接不满足该条件。 +2. **真实模型负例**:C02 的 false 分支、C04 持续错误、C05 实际模型执行中 SIGKILL/恢复、C06 多原生会话竞争、C08/C09 原生输出与权限攻击。 +3. **C07 综合漂移**:原 Draft PR #7 已关闭且未合并;其适用的 source/Program/Skill drift 测试已由 PR #13 纳入当前 main 的 tests/integration/m6-e2e.test.mjs S06。该证据仍是脚本 Host 协议层,不是实时模型或原生 Host 漂移验收。 +4. 未证明的 Provider exactly-once、模型遵循任意 Skill 指令、同 UID 混合进程隔离不能假定成立;这些必须通过宿主信任设计而非脚本测试补足。 + +**裁决:C13–C20 协议 PASS,C01–C12 原先已验证结果继续有效;整体 M6 最终验收仍 BLOCKED。PR #12 保持 Draft 待更新/复审;PR #7 已关闭且未合并。当前阶段不修改 main、不发布新版本。** diff --git a/docs/interactive-complex-acceptance-extension-c13-c24.md b/docs/interactive-complex-acceptance-extension-c13-c24.md new file mode 100644 index 0000000..35940d9 --- /dev/null +++ b/docs/interactive-complex-acceptance-extension-c13-c24.md @@ -0,0 +1,51 @@ +# FlowKit Interactive P0-A — 复杂验收补充 C13–C24 + +> 2026-11-11。追加于[冻结 C01–C12](./interactive-complex-acceptance-c01-c12.md),不修改原冻结用例和通过条件。只针对 P0-A 的 Condition / Agent / Terminal、JavaScript Program / SQLite / Trusted Host。C12/S13 原生模型宿主门禁独立有效。 + +## 0. 范围与证据等级 + +- **P — protocol/scripted**:真实编译器、生成 JS Program、SQLite WAL/FULL、Host 回执/签名/CAS、脚本 Agent 回答;证实程序约束,不证实模型行为。 +- **M — live model**:实际模型读取真实 Pending 后生成回答,有独立 requestId + taskDigest + tool trace;不等于原生宿主来源认证。 +- **N — native host**:Grok Build/Codex 等原生受控宿主,会话/工具原始日志、受信传输的独立来源证明和模型进程隔离。只有这一级可放行 C12/S13。 +- **X — out of scope**:Human、Action、Verification、Loop、Parallel、P0-B/P1/P2、Context、通用产物存储、Provider 恰好执行一次。不得用本矩阵引入未批准的功能。 + +## 1. 追加用例和可观察不变式 + +| ID | 组合场景 | 正反例和核心断言 | 执行入口 | 验收层 | +|---|---|---|---|---| +| **C13** | 分支真值表 × 阶段预算 | ready=false 不分发 Agent;ready 缺失 FK_R002;reviewApproved=false 去 declined;true 去 done。预算 1/128 的终态 State Hash 一致、Journal 合法 | complex-c01-c12.test.mjs C13 | P | +| **C14** | 第 2 个 Agent 等待时恶意回执 | 错 body、attempt、requestId、伪签、超过 2MiB 的未认证大回执全部拒绝;Checkpoint 字节、Journal、Ack 无变化;合法回执后继续成功 | 同文件 C14 | P | +| **C15** | 下游运行时旧回执重传 | Host 对象重建与终态后重传均返回原始 acceptedRevision,无额外 Journal、无状态重写 | 同文件 C15,交叉 C06/C10 | P | +| **C16** | 最后 Agent 可信 Provider 报错 | 只有签名的 Host call-failed 能触发重试;新 requestId,原状态不污染;旧失败回执仅返回旧 Ack;合法第二次响应路由成功 | 同文件 C16 | P | +| **C17** | 多 Agent 链中途策略漂移 | 修改绑定版本后 load/resume/getPublicAgentTask 均拒绝;Checkpoint/Journal 字节不变;旧 Host 可续接 | 同文件 C17 | P | +| **C18** | 两个 Run 交错与重复启动 | 同 startKey+intent 幂等,变更 State 报冲突;不同 Run 的分支、State、Journal 不串 | 同文件 C18 | P | +| **C19** | 36 Agent 链第 18 步失败 | 无效结果触发 FK_R004;余下 18 个 Agent 不再调度,State 不出现未验证字段,终态 resume 幂等 | 同文件 C19 | P | +| **C20** | 两个独立有效签名但冲突的结果 | 同一 Pending 同时提交两个不同结果,恰好一个 CAS 成功,另一个 FK_I_RECEIPT_CONFLICT;后续仍可正常完成 | 同文件 C20;真 OS 多进程由 crash.test.mjs 另验 | P | +| **C21** | SIGKILL 与跨版本恢复 | Pending、校验、接纳、Commit 切点的真正杀进程恢复;同物理 SQLite 文件在不同 Node 版本/OS 重新打开仍能保留身份、账本 | main crash.test.mjs 已有同环境 SIGKILL;跨 Node/OS 文件转移未验证 | P:部分;跨版本增强项 | +| **C22** | Prompt injection / 模型声称拥有权限 | 未签名的模型输出绝不成为 Host 命令;公开 Task 只包含白名单输入;模型无法获取私钥/私有 SQLite;真实模型中仍需攻击实测 | M5 trusted-host 与 Linux 跨 UID;原生模型进程未验证 | P PASS;N BLOCKED | +| **C23** | 真实模型异常组合 | 真实拒绝分支、真实重试耗尽、实际中途 SIGKILL+恢复、两个真实模型会话竞争都有独立原生执行记录;不能复用脚本 fixture | 原 C02/C04/C05/C06 的 M/N 缺口 | M/N BLOCKED | +| **C24** | 安装兼容、证据与发布门禁 | Program ABI、SDK exports/types、CLI、Node 22/24 × Windows/Linux、docs/site/package、宿主原始工具调用来源;只有全部适用硬门禁通过才可宣称 M6 成功 | CI 7 jobs + C12/S13 | CI P 已历史通过;N BLOCKED | + +**裁决**:C13–C20 全部通过只代表复杂协议层 PASS,不等于 24 个真实模型场景全部通过。C21 跨版本迁移是增强项,不擅自升格为 P0-A 原硬门禁;C22–C24 的 N 缺口仍属于原 M6 S13 门禁。 + +## 2. 端到端风险族覆盖索引 + +| 风险族 | 关键验收 | 测试位置 | 判定要点 | +|---|---|---|---| +| 编译/SDK | 真正 Analyzer、TS/JS、固定 Stage/Graph、Program ABI、hash、打包/types/docs | compiler-front, ir, emitter, stage2-integration, stage2-program-cache, test:package, test:types, docs:examples | 不得将非法图降级通过,不能以模型代码冒充受信 Program | +| 条件与数据流 | 公开字段、Condition 真/假/缺失、串行 Agent、长链早停、预算等价 | C01/C02/C10/C11/C13/C19 + coordinator | 比较 State/Trace,不只比较 terminal status | +| 失败/重试 | Schema 错误、validator throw、Provider failure、retries+1、容量失败退出 | C03/C04/C09/C16/C19 + coordinator, host-oversize, s07-capacity | 无假 Ack、无无限 waiting、无错误数据合并 | +| 身份/幂等 | runId/requestId/attempt/startKey、重复/冲突回执、并发 | C06/C10/C15/C18/C20 + crash, store | State commit 至多一次,不保证外部模型执行恰好一次 | +| 原子性/恢复 | WAL/FULL、真 SIGKILL、Journal hash 链、回执索引、2 MiB hard、active 余量 | C05/C09/C10/C19/C21 + store, crash, s07-capacity | 崩溃可恢复、损坏 fail-closed | +| 安全/漂移 | Program/Skill/Policy hash、签名与租户、秘密披露、跨 UID | C07/C08/C14/C17/C22 + trusted-host, stage2, host-isolation | Host-only 密钥/DB、不可泄漏、不可被 Prompt 自报权限 | +| 模型/宿主 | 多回合、真实异常路径、原生来源及会话日志 | C01–C06/C12/C22/C23/C24 | P/M/N 分层,禁止用 CI 重放充当模型调用 | + +## 3. 判停和证据 + +每个测试必须记录场景编号、执行类别、模型调用次数、实际 Program 身份、Run/Request 身份(有时)、终态、Revision、Journal/Checkpoint 不变式和断言。敏感值、Host 私钥、数据库内容不得写入公开任务或日志。 + +测试通过标准:Ubuntu 24.04 / Windows 2025 × Node 22.13.0 / 24.22.1 的精确 HEAD 回归,另有 Ubuntu Node 22/24 OS 用户隔离、网站、打包、类型与 docs 消费。新提交取消的旧 CI 不得作为新 HEAD 证据。 + +阻断(不得合并 M6):伪造或越权 Ack、双 CAS 成功、State/Journal 不一致、未披露字段泄漏、合法输入无限 waiting、真实宿主来源证明缺失。故障属于 Core 时另开最小修复 PR,不得在验收分支悄然改动生产逻辑。 + +历史 C01–C12 结果:[2026-11-11 原报告](./interactive-complex-acceptance-results-2026-11-11.md)。M6 独立整体门禁继续按当前主线路线图与验收台账执行;历史 PR #7 已关闭且未合并,其适用测试由 PR #13 纳入 main。C13–C20 精确结果以本分支最新 GitHub Actions 为准,不继承 364/364 的历史测试计数。 diff --git a/docs/interactive-complex-acceptance-results-2026-11-11.md b/docs/interactive-complex-acceptance-results-2026-11-11.md new file mode 100644 index 0000000..5f64b4c --- /dev/null +++ b/docs/interactive-complex-acceptance-results-2026-11-11.md @@ -0,0 +1,86 @@ +# FlowKit Interactive P0-A 复杂验收 C01–C12 — 实测结果与缺口 + +**日期:2026-11-11。仓库:devcodex-labs/flowkit。** +**被测试分支:test/interactive-complex-c01-c12-acceptance。** +**历史测试基线 main:ea2bb10893a9be2e5de3561fc9a660a6977ae15c。** +**代码+真实 ChatGPT 结果 HEAD:abe592e888a4ea77357e31bd5d26ab14b4dac1dd。** + +**结论:复杂 P0-A 自动化回归通过,真实 ChatGPT 4 Agent / 5 回合的非原生工具桥接通过,Grok Build 等原生宿主 C12/S13 仍 BLOCKED。不是“C01–C12 全部完成”。** + +## 1. 精确提交 / CI 证据 + +- [GitHub Actions 42963110678](https://github.com/devcodex-labs/flowkit/actions/runs/42963110678):7/7 jobs completed / success,Windows 2025 与 Ubuntu 24.04 × Node 22.13.0 / 24.22.1 四组合各 **364 tests / 364 pass / 0 fail / 0 skip**,并且四个组合均输出了 C01_CHATGPT_RECORDED_RESPONSES_ACCEPTED 及 C01/C02/C03/C04/C10/C11 的 FLOWKIT_COMPLEX_ACCEPTANCE 结构化记录。 +- CI 同时覆盖打包、类型、Standard Regression、文档消费、网站构建以及两项 Linux Host 跨 UID 权限隔离。 +- 完成前的多轮 GitHub Actions 因 PR 新提交被取消,**不能**把它们作为精确最终 HEAD 的 7/7 通过证据;每个模型回合的原始 Pending / SHA 仍可在对应 Job 日志核查。 +- Program 代码来源:真正的 FlowKit Analyzer/Interactive Lowerer/Emitter,运行时使用实际生成的 JavaScript Program、默认 SQLite Store 与 Ed25519 Trusted Host;除真实模型桥接外,Agent 回答由脚本确定性提供,**模型调用数为零**。 + +## 2. 每项单独裁决 + +| ID | 协议/脚本验收 | 当前 ChatGPT 桥接 | 原生 Grok Build/Codex Host | 主要证据与限制 | +|---|---|---|---|---| +| C01 串行 4 Agent + 2 Conditions | **PASS** | **PASS(5 次真实模型输出)** | BLOCKED | 脚本 4 个签名回执、35 Journal;真实桥接 4 个不同 Agent / 5 回合,39 Journal,正常 succeeded | +| C02 动态条件与缺失值 | **PASS** | **PARTIAL** | BLOCKED | 脚本分别覆盖 ready=false 直接 declined、ready 缺失 FK_R002、reviewApproved=false 走 declined;真实桥接只覆盖 ready=true + reviewApproved=true | +| C03 Schema 拒绝与修复 | **PASS** | **PASS(受控故障注入)** | BLOCKED | 第一次 reviewApproved 为字符串,被校验拒绝;新 requestId、attempt=2、reasons 中出现类型错误;第二次真正布尔 true 成功,未污染已确认 State | +| C04 重试耗尽 | **PASS** | BLOCKED | BLOCKED | 两次错误结构导致 FK_R004;真实模型只执行了一次拒绝然后修正,没有执行真实持续失败 | +| C05 Host SIGKILL 恢复 | **PASS(既有真子进程)** | PARTIAL | BLOCKED | main tests/interactive/crash.test.mjs 覆盖 Pending 发布、接纳、校验、State 提交前后 SIGKILL;真实 ChatGPT 只在单次 CI 内重新打开 SQLite,并非模型执行中途 SIGKILL | +| C06 并发与重复回执 | **PASS(既有真子进程)** | PARTIAL | BLOCKED | main crash.test.mjs 双进程 CAS 竞争及 coordinator.test.mjs 丢响应恢复;真实 ChatGPT 连续提交不是并发模型会话 | +| C07 Program/Skill/Policy 漂移 | **PASS(脚本协议范围)** | PARTIAL | BLOCKED | main Stage2 policyHash 版本漂移、M5 Program 字节/策略篡改拒绝已测试;PR #13 已将 M6 S06 source/Program/Skill drift 脚本 Host 用例纳入 main。真实模型升级漂移与原生 Host 认证仍未测试 | +| C08 签名、隔离与泄漏 | **PASS(已有指定边界)** | PARTIAL | BLOCKED | main TrustedHost 错签、错租户、输入披露白名单与 Linux 跨 UID 密钥/SQLite 读取拒绝;未证明 Windows ACL 或原生 Grok Build 模型进程隔离 | +| C09 Checkpoint 容量 | **PASS(脚本)** | BLOCKED | BLOCKED | main s07-capacity / host-oversize:2 MiB hard、1.75 MiB active、可接受的 256 KiB 结果、不可接纳的合法回执原子退出;未认证 >2 MiB 拒绝;无真实模型大输出事件 | +| C10 36 Agent 长链 | **PASS(脚本)** | 非必需 | BLOCKED | SQLite Journal 255 条,近期回执缓存 16,全部 36 个 acceptedRevision 可恢复查询,最早回执重放 Ack 不变 | +| C11 budget=1 与 128 | **PASS(脚本)** | 非必需 | BLOCKED | 最终 State 哈希 sha256:e69d3bc210a864cab2801e1c479c5cbc6db7bf492e65256078bafc53be1f7c25,两个预算 Journal 分别 85 与 35 条,符合阶段预算造成不同迁移记录的预期 | +| C12 原生真实模型宿主 | **不适合脚本替代** | ChatGPT GitHub 桥接 PASS,但不满足此项 | **BLOCKED** | 缺 Grok Build / Codex 原生单会话模型→JS 工具→Pending→真实模型→Host 原生工具日志、独立来源认证与宿主隔离证据 | + +**判定用语说明**:PASS 只适用于该列所声明的执行类型,PARTIAL 为只覆盖部分冻结预期,BLOCKED 为缺真实环境或证据。不存在“364/364 = 364 个复杂真实模型用例”的推断。 + +## 3. 真实 ChatGPT 多节点工具桥接的确切边界 + +使用 [C01 真实工作流定义](../examples/interactive/c01-live-chatgpt.workflow.js),生成的不可变 Program 哈希: + +sha256:339425694337fdd24ff005b2d8eab3109d4026ce6bc176f7a8c130421a7cabb5 + +本次当前 ChatGPT 模型**按顺序**从 GitHub Actions 的 C01_LIVE_CHATGPT_PENDING 日志读取公开任务,提交到 tests/fixtures/c01-live-chatgpt-turns.json 的五次模型结果: + +| 回合 | 模型实际操作 | 提交 SHA | 条件/结果 | +|---|---|---|---| +| 1 | Requirements Analysis,写 requirementSummary | 1d515fe0fe9530e1a866a566e0bc122e6b834690 | 真实 Pending #1;成功 | +| 2 | Architecture Design,使用公开 requirementSummary 写 designSummary | 031eb4337a292eebcacafcf3cef27e48c2757e12 | 真实 Pending #2;成功 | +| 3 | Implementation Plan,使用公开 designSummary 写 executionPlan | f0fd5700d1856e05d437e54184b324f5c9d89286 | 真实 Pending #3;成功 | +| 4 | Independent Review,故意给错误类型的 reviewApproved | 7363bd1742fc94a99e05d7140d2e545d57145e04 | **受控错误注入**;校验拒绝,仅接纳回执身份,不写入业务 State,产生 attempt=2 | +| 5 | Independent Review,根据新的 reasons 修正 reviewApproved 布尔值 | abe592e888a4ea77357e31bd5d26ab14b4dac1dd | 新 requestId,成功,Condition 决定 succeeded/done | + +最终结构化日志字段:C01_LIVE_CHATGPT_COMPLETED,recordedModelResponses=5,status=succeeded,journalRevisions=39,retriesObserved=1,terminal node=done,模型公开任务未泄露 Host 私有 canary。每个 CI Job 在各回执间确实关闭/重开了自己的 SQLite 数据库,证明同一 Job 内物理数据库恢复及 Host 重建。 + +**必须防止三种误称:** + +1. 首轮 Actions 发布公开任务 → ChatGPT 通过 GitHub 工具提交 → 下一轮 CI **重新创建相同逻辑 Run**。两个 Actions 运行**没有**共用一个数据库,也不是单个原生模型 Agent Runtime 自主调用下一次模型。该模型输出只是从真实公开 Pending 派生,GH 提交身份不能代替模型原生会话证明。 +2. 第 4 回合是为了验证校验/重试特意注入错误类型,**不是**证明模型在自然任务中会稳定自行纠错。 +3. 四个 OS/Node 组合都运行同一份已保存的模型回答,不等于真实模型发起了 20 次独立调用。模型真实回答数是 **5**,CI 重放总次数另行统计。 + +## 4. 原有复用的代码证据 + +- C05:main [tests/interactive/crash.test.mjs](https://github.com/devcodex-labs/flowkit/blob/ea2bb10893a9be2e5de3561fc9a660a6977ae15c/tests/interactive/crash.test.mjs)。 +- C06:同一 crash.test.mjs 与 [coordinator.test.mjs](https://github.com/devcodex-labs/flowkit/blob/ea2bb10893a9be2e5de3561fc9a660a6977ae15c/tests/interactive/coordinator.test.mjs)。 +- C07:main Stage2 / M5 tests,以及 PR #13 纳入 main 的 tests/integration/m6-e2e.test.mjs S06 综合 source/Program/Skill drift 脚本测试。 +- C08:main trusted-host.test.mjs + .github/workflows/ci.yml Linux Host OS-user isolation。 +- C09:main s07-capacity.test.mjs 与 host-oversize.test.mjs。 +- C01–C04/C10/C11:本 PR 的 [complex-c01-c12.test.mjs](../tests/interactive/complex-c01-c12.test.mjs) 与 CI JSON 事件。 + +## 5. 独立验收裁决与下一步 + +**代码结果:** 尚未发现新的 P0-A Core 语义故障。C01–C04/C10/C11 新增协议脚本测试和真实 ChatGPT 五回合完整通过,且未提前实现未授权的 P0-B/P1/P2。 + +**不足:** C07 的脚本 Host 综合漂移已在 main,但真实模型 false 分支、C04 真实持续失败、C05 中途实际 SIGKILL + 模型、C06 并发模型会话以及 C08–C09 原生模型场景尚未覆盖。**C12/S13 必须继续 BLOCKED。** + +**建议:**将此验收分支继续保持 Draft 作为历史证据,不把固定五回合 fixture 作为可永久依赖的生产回归测试。下一步使用用户可授权的 Dot/Grok Build 原生宿主,在真实模型会话和明确 OS 可信边界下优先复验 C01/C03/C05/C08/C12(尤其原生模型来源证明);不因本次 CI 绿灯宣称 M6 已收口、发布软件或转入 P0-B。 + +完整的冻结验收目标详见 [C01–C12 矩阵](./interactive-complex-acceptance-c01-c12.md)。 + + +## Current-main follow-up — 2026-11-12 + +- Current main is 606d055d5f02451fea0b30294889d740ef370d49. The 2026-11-11 C01–C12 live-model and C13–C20 protocol evidence above remains historical evidence on the old baseline; it is not exact-current-main CI. +- PR #7 is closed without merge. Its applicable M6 source/Program/Skill drift coverage is present on current main through PR #13, including tests/integration/m6-e2e.test.mjs S06. +- PR #12 remains Draft and is six commits behind current main. After this branch is updated, rerun all seven CI jobs on the exact new PR HEAD before any merge decision. +- Current exact-main GitHub Actions is still blocked at scheduling: main run 43161214780 was cancelled; PR #20 exact-head run 43170215982 has seven queued jobs with no runner start. This is not a test failure and does not change the historical PASS results above. +- C12/S13 native Grok Build source/session attestation and model-process isolation remain BLOCKED. diff --git a/examples/interactive/c01-live-chatgpt.workflow.js b/examples/interactive/c01-live-chatgpt.workflow.js new file mode 100644 index 0000000..fdfe6b2 --- /dev/null +++ b/examples/interactive/c01-live-chatgpt.workflow.js @@ -0,0 +1,62 @@ +import {defineWorkflow,condition,node,terminal} from '@devcodex-labs/flowkit/dsl'; + +// P0-A only. Actual ChatGPT turn outputs come from successive published +// Pending tasks, not prerecorded answers from a simulated LLM. +export default defineWorkflow({ + id:'c01-live-chatgpt-complex', + version:'1.0.0', + name:'C01/C03 live complex model acceptance', + nodes:[ + condition('gate',{ + name:'Verify start permission', + branches:[ + {when:'ready',next:'requirements'}, + {when:'true',next:'declined'}, + ], + }), + node('requirements',{ + name:'Requirements analysis', + agent:'requirements', + inputs:['request'], + output:{type:'object',properties:{requirementSummary:{type:'string'}}}, + retries:0,next:'architecture', + }), + node('architecture',{ + name:'Architecture design', + agent:'architecture', + inputs:['requirementSummary'], + output:{type:'object',properties:{designSummary:{type:'string'}}}, + retries:0,next:'implementation', + }), + node('implementation',{ + name:'Implementation plan', + agent:'implementation', + inputs:['designSummary'], + output:{type:'object',properties:{executionPlan:{type:'string'}}}, + retries:0,next:'review', + }), + node('review',{ + name:'Independent review', + agent:'review', + inputs:['executionPlan'], + output:{ + type:'object', + properties:{ + reviewApproved:{type:'boolean'}, + reviewNotes:{type:'string'}, + }, + }, + retries:1, + next:'decision', + }), + condition('decision',{ + name:'Review decision', + branches:[ + {when:'reviewApproved',next:'done'}, + {when:'true',next:'declined'}, + ], + }), + terminal('done',{name:'Accepted',status:'succeeded'}), + terminal('declined',{name:'Declined',status:'failed'}), + ], +}); diff --git a/tests/fixtures/c01-live-chatgpt-turns.json b/tests/fixtures/c01-live-chatgpt-turns.json new file mode 100644 index 0000000..4615004 --- /dev/null +++ b/tests/fixtures/c01-live-chatgpt-turns.json @@ -0,0 +1,49 @@ +[ + { + "index": 0, + "nodeId": "requirements", + "requestId": "req:21438c34374576a97626dca57822f8818b330b5390251afebac979fe45ee6373", + "taskDigest": "sha256:b48e9fe5d58be4db39b122704761d396e38c0c8859aad010aecf5aa8a57bb138", + "result": { + "requirementSummary": "目标是在不扩大 FlowKit 职责的前提下,对 Interactive P0-A 建立可审计的复杂验收。必须覆盖四个以上串行 Agent、两个以上条件路由、上下游结构化数据传递、Schema 校验失败后的有界重试、Host 崩溃恢复、SQLite CAS 幂等、签名安全隔离、容量边界与三十个以上节点的长链。每个场景分别记录 Program 哈希、真实节点顺序、请求身份、原始回执版本、Journal 连续性和预期终态。脚本协议测试与真实模型测试必须独立标注,未获得 Grok Build 原生会话来源认证时不能宣称 S13 验收通过;业务文件存储及复杂上下文关联仍属于用户配置的 Host 或可选 Context。" + } + }, + { + "index": 1, + "nodeId": "architecture", + "requestId": "req:360b12eb62cdc3e6df997415de82522505a96b36a2cf7ab73b4d118007beb5e3", + "taskDigest": "sha256:2889244e0714d3fc2f845a74733a6c81523fce5a5eb44e8f13ee127aaae5bdac", + "result": { + "designSummary": "验收架构采用控制、执行与上下文三条明确边界:FlowKit 编译现有 DSL 为不可变的 JavaScript Program,以条件路由、Agent Pending、重试次数、Checkpoint 与 SQLite 原子 CAS 控制状态迁移;可信 Host 负责实际模型或工具调用、Ed25519 回执签名、私有凭证隔离、结果校验与业务产物的用户自定义存储;可选 Context 仅按需提供已有资料和关联引用,不参与控制下一节点。测试层划分为可复现的脚本协议回归、真实 ChatGPT 逐节点回复,以及 Grok Build 原生会话和来源认证三类证据。所有场景分别检查执行顺序、输入最小披露、错误终态、可恢复性和 Journal,不以测试数量或脚本执行成功冒充真实模型 S13 门禁。" + } + }, + { + "index": 2, + "nodeId": "implementation", + "requestId": "req:78258c27df23723def94c945aaab4d0dc2854f2fe3280c5f3fb3a4c6af131084", + "taskDigest": "sha256:341c06092fa85738c9f4295be450932ec48d530e758a80cd4e043b04f945d900", + "result": { + "executionPlan": "实施分为三组证据。第一组使用真正编译的 P0-A JavaScript Program、SQLite 和可信 Host,构造四个串行 Agent 与两个条件节点,逐项断言输入只来自前序已确认的 State,分别执行通过、拒绝和缺失条件三条路由;向审查节点注入错误 Schema,确认不写入 State、生成新的 requestId 后再次提交合法回执,重试耗尽须持久化 FK_R004。第二组运行三十六 Agent 的脚本长链,检查每条 Journal、CAS 版本和历史回执查询;分别注入 SIGKILL、双进程竞争、Program 或 Skill 漂移、签名伪造和容量超限,验证恢复与失败封闭。第三组让真实 ChatGPT 逐次读取公开 Pending、独立产出五个模型回合,并留存原始任务摘要、提交记录和终态证据。真正的 Grok Build 模型会话及独立来源认证另行验证,无法提供原生日志时持续标记 BLOCKED,不因 CI 全绿宣称完成。" + } + }, + { + "index": 3, + "nodeId": "review", + "requestId": "req:43585b79c64e2980f1d8b0de4e1fc12b1925dc6aaca4b3a936c4548754d90a55", + "taskDigest": "sha256:da7a90e4b6e758dc2c73587f4760af28135ef53685aea7af35f6476d5b28ace5", + "result": { + "reviewApproved": "true", + "reviewNotes": "独立评审认为方案具备可执行的分层证据路线,但还应要求 C05/C06 直接引用真实 SIGKILL 与双进程 CAS 日志,不能只凭文字宣称恢复成功;C07 要明确 Skill 字节漂移与 Host 绑定版本的区别,C12 必须保留 Grok Build 原生会话来源认证门禁。本轮为受控负面测试,故意把 Schema 要求的布尔型 reviewApproved 写成字符串,预期 FlowKit 只能接纳回执身份、拒绝结果写入 State,并发布新的 review Pending,不能错误进入成功终态。" + } + }, + { + "index": 4, + "nodeId": "review", + "requestId": "req:5005e5df646511a14b1c70b87bc3416ff2399c8cc70d39b2f04bba812f24c092", + "taskDigest": "sha256:decd43a929d6d758aaaa629cc1efdf832f6020cf0662728d278ad35284191490", + "result": { + "reviewApproved": true, + "reviewNotes": "针对本次实际发布的第二次审查 Pending,前一轮失败原因明确是 reviewApproved 类型错误,必须改为布尔值而不是字符串。复审认为上游计划可以作为 FlowKit P0-A 复杂验收的执行基线:它区分了四 Agent 串行与两次条件路由、Schema 失败重试、36 Agent 长链、SQLite CAS 与 Journal、一致性预算、SIGKILL 和多进程竞争,并要求保存 Program 哈希与请求身份。建议先将脚本协议结果和当前五次真实 ChatGPT 模型回合分别列为不同证据层,再补验真实 Grok Build 原生 JS 工具、模型会话来源及独立权限隔离。这里批准的是测试方案可继续实施,不代表 C12 或整个 M6 S13 已经验收通过,也不能因此合并 M6。" + } + } +] diff --git a/tests/interactive/c01-live-chatgpt.test.mjs b/tests/interactive/c01-live-chatgpt.test.mjs new file mode 100644 index 0000000..ce457e5 --- /dev/null +++ b/tests/interactive/c01-live-chatgpt.test.mjs @@ -0,0 +1,218 @@ +/** + * Recorded ChatGPT-response evidence: four Agent nodes + deliberate schema retry, + * two Conditions. Responses are authored externally after inspecting the exact + * Pending in prior Actions logs, then replayed through FlowKit Program/SQLite/ + * Trusted Host. This test does not call a model API or native FlowKit JS tool. + * + * Normal CI requires all five recorded responses. Only explicit preparation + * mode (FLOWKIT_C01_PREPARE=1) may stop at a missing Pending for the next turn. + * SQLite is reopened within each CI run; separate Actions runs do NOT share a + * physical DB. GitHub tool identity is NOT provider-native session attestation. + */ +import test from 'node:test'; +import assert from 'node:assert/strict'; +import {readFile,mkdtemp,rm} from 'node:fs/promises'; +import {fileURLToPath} from 'node:url'; +import {tmpdir} from 'node:os'; +import path from 'node:path'; +import {generateKeyPairSync,randomBytes,sign} from 'node:crypto'; +import {compileInteractive} from '../../src/interactive/compile.mjs'; +import {createSqliteCheckpointStore} from '../../src/interactive/sqlite-store.mjs'; +import {createTrustedInteractiveHost} from '../../src/interactive/trusted-host.mjs'; +import {createAgentReceiptStatement,encodeAgentReceiptStatement} + from '../../src/interactive/host-attestation.mjs'; +import {canonicalBytes,sha256Bytes} from '../../src/interactive/canonical.mjs'; + +const workflowFile=fileURLToPath(new URL( + '../../examples/interactive/c01-live-chatgpt.workflow.js',import.meta.url)); +const repliesFile=fileURLToPath(new URL( + '../fixtures/c01-live-chatgpt-turns.json',import.meta.url)); +const NOW=1794400000000; +const runId='c01-live-multi-agent-20261111'; +const namespace='complex-live-chatgpt'; +const expectedPath=['requirements','architecture','implementation','review','review']; +const instructions={ + requirements:"分析用户的 FlowKit 复杂验收要求,给出严谨、可操作的需求说明。只能回答一个 JSON 对象 {requirementSummary:string},不少于 60 个汉字,不包含未授权的内部信息。", + architecture:"基于公开的 requirementSummary 设计精简的 FlowKit 复杂验收架构,分清 FlowKit JS Program、Host、Context 的职责。只能回答 JSON {designSummary:string},不少于 60 个汉字。", + implementation:"基于上个节点公开的 designSummary,提出可复现的 C01-C12 复杂测试实施步骤,包含真实模型场景和故障/恢复验证。只能回答 JSON {executionPlan:string},不少于 60 个汉字。", + review:"独立评审公开的 executionPlan 的可执行性、证据质量和宿主安全边界。只回答 JSON {reviewApproved:boolean,reviewNotes:string},reviewNotes 不少于 60 个汉字;必须依据实际上游数据,不得凭空宣称 Grok Build 已执行或 S13 已通过。", +}; +const outputShape={ + requirements:{requirementSummary:'string'}, + architecture:{designSummary:'string'}, + implementation:{executionPlan:'string'}, + review:{reviewApproved:'boolean',reviewNotes:'string'}, +}; +function validate(schema,output){ + if(!output||typeof output!=='object'||Array.isArray(output))return ['Agent result must be object']; + const allowed=Object.keys(schema.properties??{}).sort(); + if(allowed.join('|')!==Object.keys(output).sort().join('|'))return ['Agent output keys differ from Schema']; + for(const field of allowed){ + if(typeof output[field]!==schema.properties[field].type)return [field+' must be '+schema.properties[field].type]; + if(typeof output[field]==='string'&&output[field].length<70){ + return [field+' must be at least 70 characters']; + } + } + return []; +} +const originalRequest='建立 FlowKit Interactive P0-A 的 C01–C12 复杂验收矩阵,验证多 Agent 顺序、条件路由、Schema 重试、SQLite 恢复、签名、安全与长链;不得越界实现 Context 或通用产物存储。'; + +test('C01/C03 recorded ChatGPT responses bind to exact Pending and replay through Program/Host',async()=>{ + const root=await mkdtemp(path.join(tmpdir(),'fk-c01-live-')); + const file=path.join(root,'run.sqlite'); + let store; + try{ + const compiled=await compileInteractive(workflowFile,{ + output:'memory',featureStage:'P0-A',skillCheck:false, + }); + assert.equal(compiled.diagnostics.some(x=>x.severity==='error'),false, + JSON.stringify(compiled.diagnostics)); + assert.ok(compiled.code&&compiled.programIdentity); + const keys=generateKeyPairSync('ed25519'); + const privateCanary=randomBytes(24).toString('hex'); + const runtime={ + skillResolver:async d=>{ + assert.equal(typeof instructions[d.nodeId],'string'); + return instructions[d.nodeId]; + }, + validateResult:validate, + }; + const hostFor=s=>createTrustedInteractiveHost({ + store:s,runtime,policy:{deploymentId:'c01-live-20261111', + bindingVersions:{skill:'live-c01-v1',validator:'live-c01-v1'}}, + trustedPublicKeys:{'complex-live-host':keys.publicKey}, + trustedArtifacts:[compiled.programIdentity.artifactHash], + allowedInputKeys:['request','requirementSummary','designSummary','executionPlan'], + disclosurePolicyId:'allow-public-c01-inputs', + authorizeDisclosure:async({task})=> + task?.runId===runId&&expectedPath.includes(task?.nodeId), + now:()=>NOW, + }); + store=createSqliteCheckpointStore(file,{namespace}); + let host=hostFor(store); + let frame=await host.start({ + programBytes:Buffer.from(compiled.code,'utf8'), + programIdentity:compiled.programIdentity, + runId,startKey:'complex-live-c01-start', + state:{ready:true,request:originalRequest,hostSecret:privateCanary}, + }); + assert.equal(frame.status,'waiting'); + let replies=[]; + try{ + replies=JSON.parse(await readFile(repliesFile,'utf8')); + }catch(error){ + if(error?.code!=='ENOENT')throw error; + } + const prepareMode=process.env.FLOWKIT_C01_PREPARE==='1'; + assert.ok(Array.isArray(replies)&&replies.length<=expectedPath.length); + assert.ok(prepareMode||replies.length===expectedPath.length, + 'Normal CI requires all five recorded ChatGPT responses; use FLOWKIT_C01_PREPARE=1 only for explicit Pending preparation'); + const resultDigests=[]; + const requestIds=[]; + let rejectedReviewAttempts=0; + for(let index=0;index0); + console.log('C01_CHATGPT_RECORDED_RESPONSES_ACCEPTED '+JSON.stringify({ + scenarioIds:['C01','C03'],execution:'CHATGPT_AUTHORED_FIXTURE_REPLAY', + nativeHostAttested:false,recordedModelResponses:replies.length, + resultDigests,requestIds, + programHash:compiled.programIdentity.artifactHash, + finalStateHash:sha256Bytes(canonicalBytes(frame.state)), + terminal:frame.status,nodeId:frame.terminal.nodeId, + journalRevisions:journal.length,restartedSQLiteWithinEachCI:true, + retriesObserved:rejectedReviewAttempts, + outputLength:last.result.reviewNotes.length, + note:'Five ChatGPT-authored responses replayed against exact Pending identities; GitHub tool identity is not native session attestation and each CI run recreates its DB', + })); + }finally{ + try{store?.close()}finally{await rm(root,{recursive:true,force:true})} + } +}); diff --git a/tests/interactive/complex-c01-c12.test.mjs b/tests/interactive/complex-c01-c12.test.mjs new file mode 100644 index 0000000..807e64e --- /dev/null +++ b/tests/interactive/complex-c01-c12.test.mjs @@ -0,0 +1,605 @@ +/** + * C01/C02/C03/C04/C10/C11: actual FlowKit Program, trusted Host and SQLite, + * but Agent results are SCRIPTED, never claim a real model session here. + */ +import test,{after} from 'node:test'; +import assert from 'node:assert/strict'; +import {mkdtemp,rm} from 'node:fs/promises'; +import {tmpdir} from 'node:os'; +import path from 'node:path'; +import {generateKeyPairSync,sign} from 'node:crypto'; +import {analyzeSource} from '../../src/compiler/analyze.mjs'; +import {lowerInteractive} from '../../src/compiler/interactive/lower.mjs'; +import {emitInteractive} from '../../src/compiler/interactive/emit.mjs'; +import {createSqliteCheckpointStore} from '../../src/interactive/sqlite-store.mjs'; +import {createTrustedInteractiveHost} from '../../src/interactive/trusted-host.mjs'; +import {createAgentReceiptStatement,encodeAgentReceiptStatement} + from '../../src/interactive/host-attestation.mjs'; +import {canonicalBytes,sha256Bytes} from '../../src/interactive/canonical.mjs'; + +const roots=[]; +after(async()=>{for(const dir of roots) await rm(dir,{recursive:true,force:true})}); +const NOW=1794400000000; +const DSL="import {defineWorkflow,condition,node,terminal} from '@devcodex-labs/flowkit/dsl';\n"; +const schema=(field,type='string')=> + "{type:'object',properties:{"+field+":{type:'"+type+"'}}}"; +function complexSource(retries=1) { + return DSL+"export default defineWorkflow({id:'c01-complex',version:'1.0.0',name:'C01 Complex',nodes:["+ + "condition('gate',{name:'Gate',branches:[{when:'ready',next:'requirements'},{when:'true',next:'declined'}]}),"+ + "node('requirements',{name:'Requirements',agent:'analyst',inputs:['request'],output:"+ + schema('requirementId')+",retries:0,next:'design'}),"+ + "node('design',{name:'Design',agent:'designer',inputs:['requirementId'],output:"+ + schema('designId')+",retries:0,next:'plan'}),"+ + "node('plan',{name:'Plan',agent:'planner',inputs:['designId'],output:"+ + schema('planId')+",retries:0,next:'review'}),"+ + "node('review',{name:'Review',agent:'reviewer',inputs:['planId'],output:"+ + schema('reviewApproved','boolean')+",retries:"+retries+",next:'decision'}),"+ + "condition('decision',{name:'Decision',branches:[{when:'reviewApproved',next:'done'},{when:'true',next:'declined'}]}),"+ + "terminal('done',{name:'Done',status:'succeeded'}),"+ + "terminal('declined',{name:'Declined',status:'failed'})]});"; +} +function longSource(count=36){ + const nodes=[]; + for(let i=0;ix.severity==='error'),false, + JSON.stringify(a.diagnostics)); + const ir=lowerInteractive(a); + assert.ok(ir.ir,JSON.stringify(ir.diagnostics)); + const e=emitInteractive(ir.ir); + assert.ok(e.code,JSON.stringify(e.diagnostics)); + return {programBytes:Buffer.from(e.code,'utf8'),programIdentity:e.programIdentity}; +} +function validator(schema,output){ + if(!output||typeof output!=='object'||Array.isArray(output))return ['not an object']; + const properties=schema.properties??{}; + const keys=Object.keys(properties).sort(); + if(Object.keys(output).sort().join('|')!==keys.join('|'))return ['wrong fields']; + for(const k of keys)if(typeof output[k]!==properties[k].type)return ['wrong type: '+k]; + return []; +} +async function fixture(t,{ + source=complexSource(), + maxStagesPerCall=128, + allowedInputKeys=['request','requirementId','designId','planId'], +}={}){ + const root=await mkdtemp(path.join(tmpdir(),'fk-complex-')); + roots.push(root); + const store=createSqliteCheckpointStore(path.join(root,'run.sqlite'),{ + namespace:'complex-acceptance', + }); + t.after(()=>store.close()); + const compiled=await compile(source); + const keys=generateKeyPairSync('ed25519'); + const runtime={ + skillResolver:async({nodeId})=>'Perform declared step '+nodeId, + validateResult:validator, + }; + const makeHost=()=>createTrustedInteractiveHost({ + store,runtime,policy:{deploymentId:'complex-c01-c12',bindingVersions:{ + resolver:'v1',validator:'v1', + }}, + trustedPublicKeys:{'trusted-host':keys.publicKey}, + trustedArtifacts:[compiled.programIdentity.artifactHash], + allowedInputKeys, + disclosurePolicyId:'complex-test-public', + authorizeDisclosure:async()=>true,now:()=>NOW,maxStagesPerCall, + }); + return {root,store,keys,compiled,makeHost,host:makeHost()}; +} +function audit(f,runId){ + const cp=f.store.load(runId),journal=f.store.listJournal(runId); + assert.equal(journal.length,cp.revision+1); + for(let i=0;i{ + const f=await fixture(t); + const first=await start(f,{runId:'C01-four',state:{ + ready:true,request:'software task',secret:'HOST-PRIVATE-DO-NOT-SHARE', + }}); + const {frame,trace}=await fourSteps(f,first); + assert.equal(frame.status,'succeeded'); + assert.equal(frame.terminal.nodeId,'done'); + assert.deepEqual(frame.state,{ + ready:true,request:'software task',secret:'HOST-PRIVATE-DO-NOT-SHARE', + requirementId:'REQ-001',designId:'DES-001',planId:'PLAN-001',reviewApproved:true, + }); + assert.equal(new Set(trace.map(x=>x.requestId)).size,4); + evidence('C01',f,frame,{nodes:trace.map(x=>x.nodeId),signedReceipts:4}); +}); + +test('C02 false/default/unknown Condition routes do not dispatch unreachable Agent',async t=>{ + const f=await fixture(t); + const early=await start(f,{runId:'C02-early',state:{ + ready:false,request:'software task', + }}); + assert.equal(early.status,'failed'); + assert.equal(early.terminal.nodeId,'declined'); + assert.equal(f.store.load('C02-early').receipts.length,0); + audit(f,'C02-early'); + const missing=await start(f,{runId:'C02-missing',state:{ + request:'software task', + }}); + assert.equal(missing.status,'errored'); + assert.equal(missing.terminal.causeCode,'FK_R002'); + assert.equal(f.store.load('C02-missing').receipts.length,0); + audit(f,'C02-missing'); + const pending=await start(f,{runId:'C02-late'}); + const {frame,trace}=await fourSteps(f,pending,{ + reviewResult:{reviewApproved:false}, + }); + assert.equal(frame.status,'failed'); + assert.equal(frame.terminal.nodeId,'declined'); + assert.equal(trace.length,4); + evidence('C02',f,frame,{ + routes:['ready:false -> declined','ready:missing -> FK_R002', + 'reviewApproved:false -> declined'], + earlyDispatches:0, + }); +}); + +test('C03 invalid review schema does not mutate State, retries with new requestId',async t=>{ + const f=await fixture(t); + let frame=await start(f,{runId:'C03-retry'}); + for(const id of ['requirements','design','plan']){ + frame=(await respond(f,frame,answers[id])).frame; + } + const prior=await task(f,frame); + const first=await respond(f,frame,{reviewApproved:'wrong-type'}); + frame=first.frame; + assert.equal(frame.status,'waiting'); + assert.equal(frame.pending.nodeId,'review'); + assert.equal(frame.pending.attempt,2); + assert.notEqual(frame.pending.requestId,prior.requestId); + assert.equal(Object.hasOwn(f.store.load(frame.runId).state,'reviewApproved'),false); + const dup=await f.host.accept({ + receipt:first.receipt,attestation:first.attestation, + }); + assert.equal(dup.duplicate,true); + assert.equal(dup.acceptedRevision,first.acceptedRevision); + assert.equal(dup.pending.requestId,frame.pending.requestId); + const second=await respond(f,frame,{reviewApproved:true}); + assert.equal(second.frame.status,'succeeded'); + assert.equal(second.frame.state.reviewApproved,true); + evidence('C03',f,second.frame,{attempts:[1,2],invalidStateMerged:false, + firstAck:first.acceptedRevision,secondAck:second.acceptedRevision}); +}); + +test('C04 repeated invalid review schema consumes exactly retries+1 and FK_R004',async t=>{ + const f=await fixture(t); + let frame=await start(f,{runId:'C04-error'}); + for(const id of ['requirements','design','plan']){ + frame=(await respond(f,frame,answers[id])).frame; + } + const attempts=[]; + for(let n=0;n<2;n++){ + const p=await task(f,frame); + assert.equal(p.nodeId,'review'); + attempts.push(p.attempt); + frame=(await respond(f,frame,{invalid:true})).frame; + } + assert.deepEqual(attempts,[1,2]); + assert.equal(frame.status,'errored'); + assert.equal(frame.terminal.causeCode,'FK_R004'); + assert.equal(Object.hasOwn(frame.state,'reviewApproved'),false); + evidence('C04',f,frame,{attempts,causeCode:'FK_R004'}); +}); + +test('C10 36 Agent chain keeps 16 recent receipt cache but all 36 Ack identities',async t=>{ + const count=36; + const f=await fixture(t,{ + source:longSource(count), + allowedInputKeys:['request',...Array.from({length:count},(_,i)=>'step'+i)], + }); + let frame=await start(f,{runId:'C10-long'}); + const accepted=[]; + for(let i=0;i{ + const compared=[]; + for(const budget of [1,128]){ + const f=await fixture(t,{maxStagesPerCall:budget}); + const first=await start(f,{runId:'C11-budget-'+budget}); + const trace=[]; + const {frame}=await fourSteps(f,first,{trace}); + assert.equal(frame.status,'succeeded'); + const {journal}=audit(f,frame.runId); + compared.push({ + budget,programHash:f.compiled.programIdentity.artifactHash, + state:frame.state,stateHash:sha256Bytes(canonicalBytes(frame.state)), + trace:trace.map(x=>({id:x.nodeId,attempt:x.attempt})), + revision:frame.revision,journalRevisions:journal.length, + }); + } + assert.equal(compared[0].programHash,compared[1].programHash); + assert.equal(compared[0].stateHash,compared[1].stateHash); + assert.deepEqual(compared[0].trace,compared[1].trace); + assert.ok(compared[0].revision>compared[1].revision); + console.log('FLOWKIT_COMPLEX_ACCEPTANCE '+JSON.stringify({ + scenarioId:'C11',execution:'SCRIPTED_TRUSTED_HOST',modelCalls:0, + programHash:compared[0].programHash, + stateHash:compared[0].stateHash, + runs:compared.map(x=>({budget:x.budget,revision:x.revision, + journalRevisions:x.journalRevisions})), + result:'PASS', + })); +}); + + +// C13-C20 extend the FROZEN C01-C12 set with compound failure/interleaving +// conditions. All model outputs below are SCRIPTED; zero real model calls. +test('C13 cross-budget branch product: true/false/missing and late rejection',async t=>{ + const observations=[]; + for(const budget of [1,128]){ + const f=await fixture(t,{maxStagesPerCall:budget}); + const declined=await start(f,{runId:'C13-early-'+budget, + state:{ready:false,request:'software task'}}); + assert.equal(declined.status,'failed'); + assert.equal(declined.terminal.nodeId,'declined'); + assert.equal(f.store.load(declined.runId).receipts.length,0); + + const missing=await start(f,{runId:'C13-missing-'+budget, + state:{request:'software task'}}); + assert.equal(missing.status,'errored'); + assert.equal(missing.terminal.causeCode,'FK_R002'); + assert.equal(f.store.load(missing.runId).receipts.length,0); + + const falseFirst=await start(f,{runId:'C13-late-false-'+budget}); + const rejected=await fourSteps(f,falseFirst,{ + reviewResult:{reviewApproved:false}}); + assert.equal(rejected.frame.status,'failed'); + assert.equal(rejected.frame.terminal.nodeId,'declined'); + assert.equal(rejected.trace.length,4); + + const trueFirst=await start(f,{runId:'C13-late-true-'+budget}); + const approved=await fourSteps(f,trueFirst); + assert.equal(approved.frame.status,'succeeded'); + assert.equal(approved.frame.terminal.nodeId,'done'); + const stateHash=sha256Bytes(canonicalBytes(approved.frame.state)); + const rejectedStateHash=sha256Bytes(canonicalBytes(rejected.frame.state)); + for(const runId of [declined.runId,missing.runId, + rejected.frame.runId,approved.frame.runId])audit(f,runId); + observations.push({budget,stateHash,rejectedStateHash, + statuses:[declined.status,missing.status,rejected.frame.status, + approved.frame.status]}); + } + assert.equal(observations[0].stateHash,observations[1].stateHash); + assert.equal(observations[0].rejectedStateHash, + observations[1].rejectedStateHash); + assert.deepEqual(observations.map(x=>x.statuses),[ + ['failed','errored','failed','succeeded'], + ['failed','errored','failed','succeeded']]); + console.log('FLOWKIT_COMPLEX_ACCEPTANCE '+JSON.stringify({ + scenarioId:'C13',execution:'SCRIPTED_TRUSTED_HOST',modelCalls:0, + branchCases:4,stageBudgets:[1,128],observations,result:'PASS', + })); +}); + +test('C14 tampered/oversized signed-looking replies halfway through chain are no-ops',async t=>{ + const f=await fixture(t); + let frame=await start(f,{runId:'C14-forged'}); + frame=(await respond(f,frame,answers.requirements)).frame; + const pending=await task(f,frame); + assert.equal(pending.nodeId,'design'); + const valid=receiptFor(pending,{designId:'DES-001'}); + const attestation=attest(f,valid); + const cp=canonicalBytes(f.store.load(frame.runId)); + const journal=f.store.listJournal(frame.runId); + const rejected=[ + {receipt:{...valid,result:{designId:'swapped'}},attestation}, + {receipt:{...valid,attempt:pending.attempt+1},attestation}, + {receipt:{...valid,requestId:'forged-request'},attestation}, + {receipt:{...valid,result:{designId:'x'.repeat(2_100_000)}}, + attestation}, + {receipt:valid,attestation:{...attestation, + signature:'A'.repeat(86)}}, + ]; + for(const entry of rejected){ + await assert.rejects(f.host.accept(entry), + {code:'FK_I_PROVENANCE_REJECTED'}); + assert.deepEqual(canonicalBytes(f.store.load(frame.runId)),cp); + assert.deepEqual(f.store.listJournal(frame.runId),journal); + } + const accepted=await f.host.accept({receipt:valid,attestation}); + frame=await settle(f.host,accepted); + assert.equal(frame.pending.nodeId,'plan'); + frame=(await respond(f,frame,answers.plan)).frame; + frame=(await respond(f,frame,answers.review)).frame; + assert.equal(frame.status,'succeeded'); + assert.equal(frame.state.designId,'DES-001'); + evidence('C14',f,frame,{rejectedBodies:rejected.length, + noMutationBeforeValidReceipt:true}); +}); + +test('C15 lost Ack replay after Host rebuild and after downstream Terminal is immutable',async t=>{ + const f=await fixture(t); + let frame=await start(f,{runId:'C15-lost-ack'}); + const first=await respond(f,frame,answers.requirements); + frame=first.frame; + assert.equal(frame.pending.nodeId,'design'); + const cp=canonicalBytes(f.store.load(frame.runId)); + const before=f.store.listJournal(frame.runId); + const rebuilt=f.makeHost(); + const duplicate=await rebuilt.accept({ + receipt:first.receipt,attestation:first.attestation}); + assert.equal(duplicate.duplicate,true); + assert.equal(duplicate.acceptedRevision,first.acceptedRevision); + assert.deepEqual(canonicalBytes(f.store.load(frame.runId)),cp); + assert.deepEqual(f.store.listJournal(frame.runId),before); + for(const id of ['design','plan','review']){ + frame=(await respond(f,frame,answers[id])).frame; + } + assert.equal(frame.status,'succeeded'); + const terminalRevision=f.store.load(frame.runId).revision; + const after=await f.makeHost().accept({ + receipt:first.receipt,attestation:first.attestation}); + assert.equal(after.duplicate,true); + assert.equal(after.acceptedRevision,first.acceptedRevision); + assert.equal(f.store.load(frame.runId).revision,terminalRevision); + evidence('C15',f,frame,{lostAckRecovered:true, + replayAfterTerminal:true}); +}); + +test('C16 signed Host call-failed in late Agent retries safely and does not skip route',async t=>{ + const f=await fixture(t); + let frame=await start(f,{runId:'C16-provider-failure'}); + for(const id of ['requirements','design','plan']){ + frame=(await respond(f,frame,answers[id])).frame; + } + const p=await task(f,frame); + const failure={runId:p.runId,requestId:p.requestId,nodeId:p.nodeId, + attempt:p.attempt,kind:'agent-call-failed', + failure:{message:'provider unavailable'}}; + const proof=attest(f,failure); + const failed=await f.host.accept({receipt:failure,attestation:proof}); + frame=await settle(f.host,failed); + assert.equal(frame.status,'waiting'); + assert.equal(frame.pending.nodeId,'review'); + assert.equal(frame.pending.attempt,2); + assert.notEqual(frame.pending.requestId,p.requestId); + assert.equal(Object.hasOwn(f.store.load(frame.runId).state,'reviewApproved'),false); + const duplicate=await f.host.accept({receipt:failure,attestation:proof}); + assert.equal(duplicate.duplicate,true); + assert.equal(duplicate.acceptedRevision,failed.acceptedRevision); + frame=(await respond(f,frame,answers.review)).frame; + assert.equal(frame.status,'succeeded'); + evidence('C16',f,frame,{failureReceiptAccepted:true, + attempt2:true,staleAckImmutable:true}); +}); + +test('C17 Host policy drift at intermediate Pending rejects before mutation; old Host completes',async t=>{ + const f=await fixture(t); + let frame=await start(f,{runId:'C17-policy'}); + for(const id of ['requirements','design']){ + frame=(await respond(f,frame,answers[id])).frame; + } + assert.equal(frame.pending.nodeId,'plan'); + const before=canonicalBytes(f.store.load(frame.runId)); + const history=f.store.listJournal(frame.runId); + const drifted=createTrustedInteractiveHost({ + store:f.store,runtime:{skillResolver:async({nodeId})=>'Perform declared step '+nodeId, + validateResult:validator}, + policy:{deploymentId:'complex-c01-c12', + bindingVersions:{resolver:'v2',validator:'v1'}}, + trustedPublicKeys:{'trusted-host':f.keys.publicKey}, + trustedArtifacts:[f.compiled.programIdentity.artifactHash], + allowedInputKeys:['request','requirementId','designId','planId'], + disclosurePolicyId:'complex-test-public', + authorizeDisclosure:async()=>true,now:()=>NOW, + }); + for(const action of [ + ()=>drifted.load({runId:frame.runId}), + ()=>drifted.resume({runId:frame.runId}), + ()=>drifted.getPublicAgentTask({runId:frame.runId}), + ]){ + await assert.rejects(action(),{code:'FK_I_HOST_DENIED'}); + assert.deepEqual(canonicalBytes(f.store.load(frame.runId)),before); + assert.deepEqual(f.store.listJournal(frame.runId),history); + } + frame=(await respond(f,frame,answers.plan)).frame; + frame=(await respond(f,frame,answers.review)).frame; + assert.equal(frame.status,'succeeded'); + evidence('C17',f,frame,{policyChangedResolver:'v1 -> v2', + driftRejectedWithoutCAS:true}); +}); + +test('C18 two interleaved Runs isolate branching, start identity and Journal',async t=>{ + const f=await fixture(t); + let a=await start(f,{runId:'C18-run-A'}); + const b=await start(f,{runId:'C18-run-B',state:{ + ready:false,request:'software task'}}); + assert.equal(a.status,'waiting'); + assert.equal(b.status,'failed'); + assert.equal(f.store.load(b.runId).receipts.length,0); + const replay=await f.host.start({...f.compiled,runId:'C18-shadow', + startKey:'C18-run-A',state:{ready:true,request:'software task'}}); + assert.equal(replay.runId,a.runId); + assert.equal(replay.pending.requestId,a.pending.requestId); + await assert.rejects(f.host.start({...f.compiled,runId:'C18-conflict', + startKey:'C18-run-A',state:{ready:false,request:'software task'}}), + {code:'FK_I_START_CONFLICT'}); + a=(await fourSteps(f,a)).frame; + assert.equal(a.status,'succeeded'); + assert.equal(f.store.load(b.runId).status,'failed'); + assert.equal(f.store.load(b.runId).receipts.length,0); + audit(f,a.runId);audit(f,b.runId); + evidence('C18',f,a,{parallelRuns:2, + duplicateStartIdempotent:true,conflictingStartRejected:true}); +}); + +test('C19 36-node chain with invalid output at step 18 has no ghost dispatch',async t=>{ + const count=36; + const f=await fixture(t,{source:longSource(count), + allowedInputKeys:['request',...Array.from({length:count},(_,i)=>'step'+i)]}); + let frame=await start(f,{runId:'C19-fail-midchain'}); + const receipts=[]; + for(let i=0;i<18;i++){ + const p=await task(f,frame); + assert.equal(p.nodeId,'agent'+i); + receipts.push(p.requestId); + const value=i===17?{invalid:'bad'}:{['step'+i]:'value-'+i}; + frame=(await respond(f,frame,value)).frame; + } + assert.equal(frame.status,'errored'); + assert.equal(frame.terminal.causeCode,'FK_R004'); + assert.equal(Object.hasOwn(frame.state,'step17'),false); + assert.equal(Object.hasOwn(frame.state,'step18'),false); + assert.equal(new Set(receipts).size,18); + const previous=canonicalBytes(f.store.load(frame.runId)); + const resumed=await f.host.resume({runId:frame.runId}); + assert.equal(resumed.status,'errored'); + assert.deepEqual(canonicalBytes(f.store.load(frame.runId)),previous); + evidence('C19',f,frame,{declaredAgents:36,dispatched:18, + remainingNotDispatched:18,causeCode:'FK_R004'}); +}); + +test('C20 conflicting independently signed late-Agent answers accept only one CAS',async t=>{ + const f=await fixture(t); + let frame=await start(f,{runId:'C20-equivocation'}); + frame=(await respond(f,frame,answers.requirements)).frame; + const p=await task(f,frame); + assert.equal(p.nodeId,'design'); + const left=receiptFor(p,{designId:'DES-A'}); + const right=receiptFor(p,{designId:'DES-B'}); + const [one,two]=await Promise.allSettled([ + f.host.accept({receipt:left,attestation:attest(f,left)}), + f.makeHost().accept({receipt:right,attestation:attest(f,right)}), + ]); + const settled=[one,two]; + assert.equal(settled.filter(x=>x.status==='fulfilled').length,1); + assert.equal(settled.filter(x=>x.status==='rejected').length,1); + assert.equal(settled.find(x=>x.status==='rejected').reason.code, + 'FK_I_RECEIPT_CONFLICT'); + const winning=settled.find(x=>x.status==='fulfilled').value; + frame=await settle(f.host,winning); + assert.equal(frame.pending.nodeId,'plan'); + assert.ok(['DES-A','DES-B'].includes(f.store.load(frame.runId).state.designId)); + const journal=f.store.listJournal(frame.runId); + assert.equal(journal.length,frame.revision+1); + frame=(await respond(f,frame,answers.plan)).frame; + frame=(await respond(f,frame,answers.review)).frame; + assert.equal(frame.status,'succeeded'); + evidence('C20',f,frame,{twoValidCompetingHostReceipts:true, + exactlyOneCAS:true,winningDesign:frame.state.designId}); +}); From 81c7839e9f0abe6f4db20d0fc242253b0baff0ea Mon Sep 17 00:00:00 2001 From: rocky Date: Thu, 12 Nov 2026 17:29:07 +0900 Subject: [PATCH 6/6] test(interactive): add ChatGPT Pending response evidence MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * test(interactive): define executable S13 ChatGPT tool-bridge acceptance workflow * test(interactive): add auditable public Agent instruction for S13 bridge * test(interactive): 2-stage public Pending bridge for real ChatGPT tool-using response and Host resume * test(s13): bind actual ChatGPT model-generated response to published public Pending digest * test(s13): generate Host-only private canary inside CI, never commit even a synthetic secret * test(interactive): rebase M6 Host integration on current main Add current-main M6 scripted Host integration coverage, root-discovery fixtures, Linux cross-UID CI, and the full Interactive delivery roadmap. This is test/CI/documentation only and does not complete native-host C12/S13 or M6 final acceptance. * docs(interactive): add Trusted Host V2 conditional security design Add the reviewed Trusted Host V2 threat model, deployment profiles, security acceptance matrix, and explicit Phase 2 limitations. This is documentation-only: it does not implement Host isolation, Grok native provenance, Windows ACL enforcement, or Phase 3/4 runtime changes. F-02 and F-04 remain pending real validation; F-07 formal V0.3/V0.6-R5 conformance remains blocked. Merge does not authorize Phase 3 or claim C12/S13/M6 acceptance. * docs(interactive): recover frozen baselines and establish evidence audit plan Record independently validated Requirements V0.3 and Technical Design V0.6-R5 originals, limited Core PoC results and Phase 2 traceability roadmap. Reconcile the previously confirmed M1–M6 P0-A plan and existing M1–M5 implementation. Documentation only: no Core/API/Program ABI/Store schema changes, no Phase 3 authorization, no C12/S13 or full conformance PASS claim. * docs(interactive): archive Phase 2 formal conformance R1/R2 audit * docs(interactive): add source-backed T/R/S crosswalk and initial P0-A gap findings * docs(interactive): document Host/Public terminal State projection contract difference * docs(interactive): record async Store contract divergence from confirmed V0.6-R5 * docs(interactive): add Phase 2 R2 code-evidence review and R04 mutation findings * docs(interactive): link R04 independent regression PR and retrigger Phase 2 CI * docs(interactive): archive local R04 reproduction and verification evidence * docs(interactive): record local verification of PR 16 and 17 The report keeps the PR heads, commands, R04 failure output, the snapshot fix result, and the merge recommendation. Raw decisive logs are stored beside it. No product code changes. * docs(interactive): record that Actions for PR 16-19 are still queued The 13:15 +08 reconfirm keeps all four draft PRs unmerged. Run status is queued with an empty conclusion. That is not a matrix pass and not a proven Actions outage. * fix(interactive): snapshot start inputs before first await (R04) start() copied caller-owned State and startIntent only after loadInteractiveProgram resolved. That await yields even when the loader is already settled, so a caller could change both objects before the Checkpoint and startIntentHash were created. Copy both with the existing bounded canonical snapshot first, and preserve the initial-State capacity error. Later Store writes use those copies. Includes the R04 regression tests from PR #17. * test(interactive): require explicit preparation mode for ChatGPT response fixture * docs(interactive): label ChatGPT response experiment as M-level * test(interactive): preserve original workflow identity for recorded Pending fixture * docs(interactive): clarify ChatGPT response evidence tier and S13 limits * test(interactive): add C01-C24 complex acceptance evidence * test(interactive): freeze C01-C12 scenario matrix and scripted/live/native evidence separation * test(interactive): C01-C04,C10,C11 scripted complex runs with real Program signed Host and SQLite * test(interactive): C01/C03 live multi-Agent two-Condition workflow definition * test(interactive): real ChatGPT multi-Agent 5-turn replay bridge with schema rejection and SQLite reopen * test(c01-live): actual ChatGPT requirements analysis bound to published Pending #1 * test(c01-live): ChatGPT architecture response to real dependent Pending #2 * test(c01-live): actual ChatGPT implementation plan from real Pending #3 * test(c03-live): ChatGPT deliberately submits invalid reviewApproved type to test real retry Pending * test(c01-live): genuine ChatGPT corrected review after real attempt-2 Pending #5 * docs(interactive): record C01-C12 detailed scripted and five-turn real ChatGPT evidence with open native gates * test(interactive): extend complex P0-A acceptance with C13-C20 interleavings * docs(interactive): extend risk-mapped C13-C24 acceptance and native-host gates * test(interactive): inspect durable Store state while Pending frame intentionally redacts State * test(interactive): verify C16 durable Checkpoint while Pending frame hides private State * docs(interactive): record independently checked 7/7 CI and C13-C24 layered verdict * test(interactive): rebase M6 Host integration on current main Add current-main M6 scripted Host integration coverage, root-discovery fixtures, Linux cross-UID CI, and the full Interactive delivery roadmap. This is test/CI/documentation only and does not complete native-host C12/S13 or M6 final acceptance. * docs(interactive): add Trusted Host V2 conditional security design Add the reviewed Trusted Host V2 threat model, deployment profiles, security acceptance matrix, and explicit Phase 2 limitations. This is documentation-only: it does not implement Host isolation, Grok native provenance, Windows ACL enforcement, or Phase 3/4 runtime changes. F-02 and F-04 remain pending real validation; F-07 formal V0.3/V0.6-R5 conformance remains blocked. Merge does not authorize Phase 3 or claim C12/S13/M6 acceptance. * docs(interactive): recover frozen baselines and establish evidence audit plan Record independently validated Requirements V0.3 and Technical Design V0.6-R5 originals, limited Core PoC results and Phase 2 traceability roadmap. Reconcile the previously confirmed M1–M6 P0-A plan and existing M1–M5 implementation. Documentation only: no Core/API/Program ABI/Store schema changes, no Phase 3 authorization, no C12/S13 or full conformance PASS claim. * docs(interactive): archive Phase 2 formal conformance R1/R2 audit * docs(interactive): add source-backed T/R/S crosswalk and initial P0-A gap findings * docs(interactive): document Host/Public terminal State projection contract difference * docs(interactive): record async Store contract divergence from confirmed V0.6-R5 * docs(interactive): add Phase 2 R2 code-evidence review and R04 mutation findings * docs(interactive): link R04 independent regression PR and retrigger Phase 2 CI * docs(interactive): archive local R04 reproduction and verification evidence * docs(interactive): record local verification of PR 16 and 17 The report keeps the PR heads, commands, R04 failure output, the snapshot fix result, and the merge recommendation. Raw decisive logs are stored beside it. No product code changes. * docs(interactive): record that Actions for PR 16-19 are still queued The 13:15 +08 reconfirm keeps all four draft PRs unmerged. Run status is queued with an empty conclusion. That is not a matrix pass and not a proven Actions outage. * fix(interactive): snapshot start inputs before first await (R04) start() copied caller-owned State and startIntent only after loadInteractiveProgram resolved. That await yields even when the loader is already settled, so a caller could change both objects before the Checkpoint and startIntentHash were created. Copy both with the existing bounded canonical snapshot first, and preserve the initial-State capacity error. Later Store writes use those copies. Includes the R04 regression tests from PR #17. * test(interactive): require complete recorded ChatGPT responses in normal CI * docs(interactive): clarify recorded model-response evidence tier --- docs/interactive-chatgpt-response-evidence.md | 41 ++++ examples/interactive/s13-chatgpt.workflow.js | 33 +++ examples/interactive/skills/reviewer.md | 11 + tests/fixtures/s13-chatgpt-reply.json | 10 + .../s13-chatgpt-tool-bridge.test.mjs | 229 ++++++++++++++++++ 5 files changed, 324 insertions(+) create mode 100644 docs/interactive-chatgpt-response-evidence.md create mode 100644 examples/interactive/s13-chatgpt.workflow.js create mode 100644 examples/interactive/skills/reviewer.md create mode 100644 tests/fixtures/s13-chatgpt-reply.json create mode 100644 tests/interactive/s13-chatgpt-tool-bridge.test.mjs diff --git a/docs/interactive-chatgpt-response-evidence.md b/docs/interactive-chatgpt-response-evidence.md new file mode 100644 index 0000000..e6f884a --- /dev/null +++ b/docs/interactive-chatgpt-response-evidence.md @@ -0,0 +1,41 @@ +# ChatGPT-authored response evidence for FlowKit Interactive + +**Evidence tier: M-level recorded model response. This is not native S13.** + +## What the experiment does + +1. FlowKit compiles the Interactive workflow and durably creates a public Agent Pending in SQLite. +2. The test emits the exact `runId`, `requestId`, `taskDigest`, Program artifact hash and allowlisted task input. +3. A ChatGPT model reads that Pending evidence in the conversation and authors a structured response. +4. The response is returned through an authenticated GitHub tool action and stored as a fixture. +5. A later test run deterministically reconstructs the same Pending and rejects the fixture unless all identity fields match exactly. +6. The trusted Host validates the result, signs its own Host receipt, commits through CAS, verifies duplicate Ack and resumes the Run. + +## What it proves + +- A ChatGPT-authored response was produced after inspection of a real FlowKit Pending. +- The response is bound to the exact deterministic Pending by `runId/requestId/taskDigest`. +- FlowKit's actual Program, SQLite Store and Trusted Host process that recorded response. +- Host signature/CAS, duplicate receipt and same-phase SQLite close/reopen behavior. + +## What it does not prove + +- The ChatGPT model invoked a FlowKit-native JavaScript tool. The response is returned through a GitHub tool action, not a native FlowKit JS-tool call. +- Independent cryptographic attestation of the ChatGPT provider/session identity. +- Grok Build or Codex native tool-call provenance. +- Cross-UID / OS-level model-process isolation. +- One physical SQLite database surviving across the separate Pending-preparation and response-acceptance Actions runs. The second run reconstructs the deterministic Pending and uses its own database. + +Therefore this evidence is useful for M-level real-model participation and response-binding tests, but **must not be counted as native Host S13 / C12 PASS**. + +## Test execution modes + +Normal CI must consume the complete committed response fixture and reach Terminal. If the fixture is absent, the test fails. + +Only an explicit preparation invocation may stop at Pending: + +```bash +FLOWKIT_S13_PREPARE=1 node --test tests/interactive/s13-chatgpt-tool-bridge.test.mjs +``` + +The preparation mode is not used by the normal CI workflow. diff --git a/examples/interactive/s13-chatgpt.workflow.js b/examples/interactive/s13-chatgpt.workflow.js new file mode 100644 index 0000000..bb56ba5 --- /dev/null +++ b/examples/interactive/s13-chatgpt.workflow.js @@ -0,0 +1,33 @@ +import {defineWorkflow,condition,node,terminal} from '@devcodex-labs/flowkit/dsl'; + +export default defineWorkflow({ + id:'s13-chatgpt-tool-bridge', + version:'0.1.0', + name:'ChatGPT 实际工具链 S13 验证', + nodes:[ + condition('gate',{ + name:'确定进入审核节点', + branches:[ + {when:'ready',next:'review'}, + {when:'true',next:'rejected'}, + ], + }), + node('review',{ + name:'分析 FlowKit 运行边界', + agent:'reviewer', + inputs:['request','constraints'], + output:{ + type:'object', + properties:{ + summary:{type:'string'}, + nextAction:{type:'string'}, + flowkitBoundary:{type:'string'}, + }, + }, + retries:0, + next:'done', + }), + terminal('done',{name:'工作流成功',status:'succeeded'}), + terminal('rejected',{name:'未满足进入条件',status:'failed'}), + ], +}); diff --git a/examples/interactive/skills/reviewer.md b/examples/interactive/skills/reviewer.md new file mode 100644 index 0000000..a9e01a8 --- /dev/null +++ b/examples/interactive/skills/reviewer.md @@ -0,0 +1,11 @@ +# FlowKit Host 公开 Agent 任务 + +你是本次 FlowKit S13 验证中实际参与执行的 ChatGPT 模型。 + +请根据公开的 `request` 和 `constraints`,返回一个 JSON 对象: +- `summary`:简短说明为什么 FlowKit 的工作流应该由 JavaScript Program 约束执行。 +- `nextAction`:一项可以直接验证的下一步动作。 +- `flowkitBoundary`:说明 FlowKit 与 Host/Context 的职责边界。 + +禁止请求或输出 Host 的私钥、SQLite 数据库、完整 State 或未公开内容。 +这份说明只是公开任务指令,不构成 Host 对模型来源的独立认证。 diff --git a/tests/fixtures/s13-chatgpt-reply.json b/tests/fixtures/s13-chatgpt-reply.json new file mode 100644 index 0000000..0800cbe --- /dev/null +++ b/tests/fixtures/s13-chatgpt-reply.json @@ -0,0 +1,10 @@ +{ + "runId": "s13-chatgpt-bridge-run-20261111", + "requestId": "req:6bed7ea39b96e81b99100ffe69bb174ba38533d42f3bbdbefad6239cee0ac829", + "taskDigest": "sha256:96733a8e513b08020acc42ef5dabd93413d52b452d8b982d40afcf3b81ac2876", + "result": { + "summary": "FlowKit 将执行顺序、条件分支、失败路径和终态编译为可执行的 JavaScript Program,由代码而不是模型临时决定下一节点;Agent 只提交当前节点的结果,可信 Host 依据 Program、CAS 与 Journal 验证每次推进。", + "nextAction": "在可信 Host 运行本次 Condition→Agent→Terminal 工作流,核对已持久化 Pending 的 requestId 与任务摘要;接纳模型结构化输出后核验签名回执、最终 SQLite State、Journal 连续性、宿主重启恢复及重复回执的原始 Ack。", + "flowkitBoundary": "FlowKit 负责工作流编译、程序化路由、Checkpoint、回执幂等和恢复;Host 负责模型与 JS 工具调用、来源认证、安全隔离以及用户配置的产物存储;可选 Context 模块负责上下文引用和复杂数据关联,不能替代 Program 决定流程。" + } +} diff --git a/tests/interactive/s13-chatgpt-tool-bridge.test.mjs b/tests/interactive/s13-chatgpt-tool-bridge.test.mjs new file mode 100644 index 0000000..912fd24 --- /dev/null +++ b/tests/interactive/s13-chatgpt-tool-bridge.test.mjs @@ -0,0 +1,229 @@ +/** + * ChatGPT-authored response -> exact FlowKit Pending -> trusted Host acceptance. + * + * Explicit preparation mode (FLOWKIT_S13_PREPARE=1) publishes the actual + * Pending and prints its exact requestId/taskDigest for an external ChatGPT + * turn. ChatGPT returns its authored response through an authenticated GitHub + * tool action. That is NOT a FlowKit native JS-tool invocation or S13 Host bridge. + * + * Normal CI mode requires the complete response fixture. It deterministically + * recreates the same Pending, checks runId/requestId/taskDigest, then performs + * Host signing/CAS and SQLite close/reopen within Phase 2. The two phases use + * separate Actions invocations and do NOT share one physical SQLite database. + * + * Evidence is M-level ChatGPT participation only. It does NOT independently + * attest provider/session origin, native Grok/Codex tools or cross-UID isolation. + * Native Host S13 remains BLOCKED. + */ +import test from 'node:test'; +import assert from 'node:assert/strict'; +import {readFile,mkdtemp,rm} from 'node:fs/promises'; +import {fileURLToPath} from 'node:url'; +import path from 'node:path'; +import {tmpdir} from 'node:os'; +import {generateKeyPairSync,randomBytes,sign} from 'node:crypto'; +import {compileInteractive} from '../../src/interactive/compile.mjs'; +import {createSqliteCheckpointStore} from '../../src/interactive/sqlite-store.mjs'; +import {createTrustedInteractiveHost} from '../../src/interactive/trusted-host.mjs'; +import {createAgentReceiptStatement,encodeAgentReceiptStatement} + from '../../src/interactive/host-attestation.mjs'; +import {canonicalBytes,sha256Bytes} from '../../src/interactive/canonical.mjs'; + +const workflowFile=fileURLToPath( + new URL('../../examples/interactive/s13-chatgpt.workflow.js',import.meta.url)); +const skillFile=fileURLToPath( + new URL('../../examples/interactive/skills/reviewer.md',import.meta.url)); +const replyFile=fileURLToPath( + new URL('../fixtures/s13-chatgpt-reply.json',import.meta.url)); +const runId='s13-chatgpt-bridge-run-20261111'; +const startKey='s13-chatgpt-bridge-20261111'; +const namespace='s13-chatgpt-bridge-tenant'; +const privateCanary='HOST_PRIVATE_'+randomBytes(24).toString('hex'); + +const initialState={ + ready:true, + request:'请审查 FlowKit 如何通过可执行 JavaScript Program 约束 Agent 工作流,并给出一项可验证的下一步。', + constraints:[ + 'State 只保留当前工作流所需的轻量状态和少量值。', + '业务文件/产物由用户配置的 Host 存储处理,Context 可以负责复杂关联。', + '流程推进及路由必须由 FlowKit Program 决定,模型不能绕开可信 Host。', + ], + hostOnlySecret:privateCanary, +}; +const policy={ + deploymentId:'s13-chatgpt-tool-bridge', + bindingVersions:{ + 'runtime.skillResolver':'reviewer-skill-test-v1', + 'runtime.validateResult':'reviewer-schema-test-v1', + }, +}; +const resultFields=['flowkitBoundary','nextAction','summary']; + +test('ChatGPT-authored response is bound to exact Pending and accepted by trusted Host',async()=>{ + const dir=await mkdtemp(path.join(tmpdir(),'flowkit-s13-chatgpt-')); + const file=path.join(dir,'run.sqlite'); + let store; + try{ + const compiled=await compileInteractive(workflowFile,{ + output:'memory', + featureStage:'P0-A', + skillsRoot:'examples/interactive/skills', + skillCheck:true, + }); + assert.equal(compiled.diagnostics.some(x=>x.severity==='error'),false, + JSON.stringify(compiled.diagnostics)); + assert.ok(compiled.programIdentity?.artifactHash); + const skill=await readFile(skillFile,'utf8'); + const skillHash=sha256Bytes(Buffer.from(skill,'utf8')); + const keys=generateKeyPairSync('ed25519'); + const runtime={ + skillResolver:async({agent,skill:declared})=>{ + assert.equal(agent,'reviewer'); + assert.equal(declared,null); + return skill; + }, + validateResult:(_schema,output)=>{ + if(!output||typeof output!=='object'||Array.isArray(output)) { + return ['result must be object']; + } + const keys=Object.keys(output).sort(); + if(keys.join(',')!==resultFields.join(','))return ['result field set does not match']; + return resultFields.every(k=>typeof output[k]==='string' + && output[k].length>=15 && output[k].length<=1000)?[]:['result field lengths invalid']; + }, + }; + const hostFor=s=>createTrustedInteractiveHost({ + store:s, + runtime,policy, + trustedPublicKeys:{'s13-test-transport':keys.publicKey}, + trustedArtifacts:[compiled.programIdentity.artifactHash], + allowedInputKeys:['request','constraints'], + disclosurePolicyId:'s13-public-only-v1', + authorizeDisclosure:async({task})=> + task?.kind==='agent' && task?.nodeId==='review' + && task?.runId===runId, + }); + store=createSqliteCheckpointStore(file,{namespace}); + const firstHost=hostFor(store); + const frame=await firstHost.start({ + programBytes:Buffer.from(compiled.code,'utf8'), + programIdentity:compiled.programIdentity, + runId,startKey,state:initialState, + }); + assert.equal(frame.status,'waiting'); + const pending=await firstHost.getPublicAgentTask({runId}); + assert.equal(pending.kind,'agent'); + assert.equal(pending.nodeId,'review'); + assert.equal(pending.runId,runId); + assert.deepEqual(pending.input,{ + request:initialState.request,constraints:initialState.constraints, + }); + assert.equal(JSON.stringify(pending).includes(privateCanary),false); + assert.equal(JSON.stringify(pending).includes('hostOnlySecret'),false); + const taskDigest=sha256Bytes(canonicalBytes(pending)); + const firstJournal=store.listJournal(runId); + assert.ok(firstJournal.length>=3); + assert.equal(store.load(runId).pending.requestId,pending.requestId); + + // Actual public Agent task, published only after durable SQLite Pending. + // No Host secrets, Store path, full State or private signing key are printed. + console.log('S13_CHATGPT_PUBLIC_TASK '+JSON.stringify({ + taskDigest,task:pending, + skillSha256:skillHash, + artifactHash:compiled.programIdentity.artifactHash, + })); + let modelReply; + try{ + modelReply=JSON.parse(await readFile(replyFile,'utf8')); + }catch(error){ + if(error?.code!=='ENOENT')throw error; + } + if(!modelReply){ + assert.equal(process.env.FLOWKIT_S13_PREPARE,'1', + 'Complete ChatGPT response fixture is required for normal CI; set FLOWKIT_S13_PREPARE=1 only for explicit Pending preparation'); + assert.equal((await firstHost.load({runId})).status,'waiting'); + console.log('CHATGPT_PENDING_PREPARED '+JSON.stringify({ + runId,requestId:pending.requestId,revision:frame.revision, + journalRevisions:firstJournal.length, + result:'Real public task printed for next ChatGPT tool turn', + })); + return; + } + assert.equal(modelReply.runId,runId); + assert.equal(modelReply.requestId,pending.requestId); + assert.equal(modelReply.taskDigest,taskDigest); + assert.ok(modelReply.result); + assert.equal(runtime.validateResult(null,modelReply.result).length,0); + + // Host lifecycle: close actual SQLite Store after durable Pending, then + // reopen and continue without recompiling at the resume boundary. + store.close(); + store=createSqliteCheckpointStore(file,{namespace}); + const resumedHost=hostFor(store); + const recovered=await resumedHost.load({runId}); + assert.equal(recovered.status,'waiting'); + const afterRestartTask=await resumedHost.getPublicAgentTask({runId}); + assert.equal(afterRestartTask.requestId,pending.requestId); + assert.equal(sha256Bytes(canonicalBytes(afterRestartTask)),taskDigest); + const receipt={ + runId, + requestId:pending.requestId, + nodeId:pending.nodeId, + attempt:pending.attempt, + kind:'agent-result', + result:modelReply.result, + }; + // Local Host signer is separate from the public model task, but this + // fixture has NO independent native ChatGPT session attestation. + const now=Date.now(); + const statement=createAgentReceiptStatement({ + run:store.load(runId),receipt,keyId:'s13-test-transport', + proofId:'chatgpt-github-bridge-result-001', + issuedAt:now-1000,expiresAt:now+60000, + }); + const attestation={ + statement, + signature:sign(null,encodeAgentReceiptStatement(statement),keys.privateKey) + .toString('base64url'), + }; + const before=store.load(runId); + assert.equal(before.status,'waiting'); + // Signed, but bogus signature must not mutate Run. + await assert.rejects(resumedHost.accept({ + receipt,attestation:{statement,signature:'forged'}, + }),{code:'FK_I_PROVENANCE_REJECTED'}); + assert.equal(store.load(runId).revision,before.revision); + const completed=await resumedHost.accept({receipt,attestation}); + assert.equal(completed.status,'succeeded'); + assert.equal(completed.terminal.nodeId,'done'); + assert.equal(completed.state.hostOnlySecret,privateCanary); + assert.equal(completed.state.summary,modelReply.result.summary); + assert.equal(completed.state.nextAction,modelReply.result.nextAction); + assert.equal(completed.state.flowkitBoundary,modelReply.result.flowkitBoundary); + const receiptIndex=store.getReceipt(runId,receipt.requestId); + assert.equal(receiptIndex.acceptedRevision,completed.acceptedRevision); + assert.equal(store.listJournal(runId).length,completed.revision+1); + const duplicate=await resumedHost.accept({receipt,attestation}); + assert.equal(duplicate.duplicate,true); + assert.equal(duplicate.acceptedRevision,completed.acceptedRevision); + assert.equal(duplicate.revision,completed.revision); + assert.equal((await resumedHost.resume({runId})).status,'succeeded'); + console.log('CHATGPT_RESPONSE_FIXTURE_ACCEPTED '+JSON.stringify({ + runId,requestId:receipt.requestId, + modelReplyDigest:sha256Bytes(canonicalBytes(modelReply.result)), + artifactHash:compiled.programIdentity.artifactHash, + taskDigest,skillHash, + status:completed.status, + terminal:completed.terminal.nodeId, + acceptedRevision:completed.acceptedRevision, + journalRevisions:completed.revision+1, + duplicateAck:true,restoredFromSQLite:true, + phase2DatabaseReconstructed:true,crossRunDatabaseContinuation:false, + policyPinned:true, + secretNotExposedToPublicTask:true, + warning:'ChatGPT-authored response delivered through GitHub tool; not a FlowKit native JS-tool call; no independent native session attestation; S13 remains BLOCKED', + })); + }finally{ + try{store?.close()}finally{await rm(dir,{recursive:true,force:true})} + } +});