You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Browse filesBrowse the repository at this point in the historyBrowse files
moc
committed
fix: bind record identity into digests; restore default list shape
- event digests now cover events.runId (sha256(prev:event:runId:seq:body))
and verification re-derives the key from the CURRENT row's identity columns,
never trusting the ledger's stored key — migrating events.runId or
repair_cache.runId/id with bodies and heads intact now fails verification
(maintainer's reproduced ownership-mutation case, regression-tested both
surfaces incl. restore-to-valid)
- workflow_status list form returns the original bare array by default;
the extended {runs, integrityHeads, integrity} object is opt-in via
verifyIntegrity:true; workspace-router consumer assertion restored to the
upstream default shape
- verification covers the anchored prefix and fails closed on any unanchored
row (unchained>0 => verified:false), documented in README and the tool
description alongside the trust-boundary statement
Copy file name to clipboardExpand all lines: plugins/hetaoBackend/mcode-dynamic-workflows/README.md
+1Lines changed: 1 addition & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -54,6 +54,7 @@ The repaired script runs from its beginning; checkpoints are recomputed and unre
54
54
- Real agents run through the user's MCode CLI with its configured provider, tools and smart permissions. Project materials and prompts may be sent to that provider; agents may access other destinations and modify files as the task permits. These destinations depend on the user's configuration and task. Credentials remain managed by the CLI; the plugin does not ask for or store credentials, but prompts/outputs/logs can contain sensitive information supplied by users or tools.
55
55
- QuickJS isolates the orchestration script from direct Node/file/network access. **The spawned MCode agents are not an OS sandbox** and do not inherit the full parent conversation. Review prompts, budgets, side effects and permissions before execution or retries.
56
56
- A lifetime SQLite lock enforces one state owner even if a discovery lockfile is lost. The run list prioritizes active runs and recovery attention within its 100-entry window; crash recovery inspects every unfinished run.
57
+
- Tamper evidence: the append-only `events` and `repair_cache` surfaces each carry a SHA-256 hash chain whose per-row links are written in the same transaction as the insert. Digests bind each row's identity (`runId` plus `seq`/`id`) as well as its body, so moving a row to another run is detected like any body edit. `workflow_status` with `verifyIntegrity: true` recomputes both chains and returns heads, per-face verdicts and the first divergence. Verification covers the anchored prefix; any unanchored row fails closed (`unchained > 0` → `verified: false`). The default run list stays a plain JSON array; the object form with `integrityHeads` is only returned for `verifyIntegrity: true`.
57
58
- The project service and approved workflows survive a chat disconnect. No OS autostart is installed; machine shutdown interrupts execution. After abnormal termination, verify old agents have stopped before recovery.
// Independent recomputation of the contracted digest formulas over raw stored rows.
18
-
functionrecomputeEvents(store){letprev=GENESIS;for(constrofstore.db.prepare('SELECT seq,body FROM events ORDER BY seq').all())prev=createHash('sha256').update(`${prev}:event:${r.seq}:${r.body}`).digest('hex');returnprev;}
18
+
// r3 contract: digests bind row identity (events runId+seq, repair runId/id) as well as body.
19
+
functionrecomputeEvents(store){letprev=GENESIS;for(constrofstore.db.prepare('SELECT seq,runId,body FROM events ORDER BY seq').all())prev=createHash('sha256').update(`${prev}:event:${r.runId}:${r.seq}:${r.body}`).digest('hex');returnprev;}
19
20
functionrecomputeRepair(store){letprev=GENESIS;for(constrofstore.db.prepare('SELECT rowid,runId,id,body FROM repair_cache ORDER BY rowid').all())prev=createHash('sha256').update(`${prev}:repair:${r.runId}/${r.id}:${r.body}`).digest('hex');returnprev;}
@@ -53,15 +54,44 @@ test('single-byte repair_cache tamper is detected at its row key and restoring t
53
54
}finally{awaitf.cleanup();}
54
55
});
55
56
56
-
test('deleting the smaller of two event rows reports the first divergence at key 1',async()=>{
57
+
test('re-attributing events.runId and repair_cache runId/id without touching bodies, chains or heads is caught on both faces; restoring attribution heals',async()=>{
const seq = Number(this.db.prepare("INSERT INTO events(runId,body) VALUES(?,?)").run(runId, JSON.stringify(event)).lastInsertRowid);
7843
-
this.chainAdvance("event", "events", "SELECT seq AS pos,body FROM events WHERE seq>? AND seq<=? ORDER BY seq", seq, (r) => String(r.pos));
7843
+
this.chainAdvance("event", "events", "SELECT seq AS pos,runId,body FROM events WHERE seq>? AND seq<=? ORDER BY seq", seq, (r) => `${r.runId}:${r.pos}`);
return { head: rec.head, upto: rec.upto, verified, checked: rows.length, unchained: Number(this.db.prepare(`SELECT COUNT(*) AS n FROM ${table} WHERE ${posCol}>?`).get(rec.upto).n), firstDivergence };
0 commit comments