Conversation
2c9cad5 to
edc36cf
Compare
|
Heads-up on the failing |
hetaoBackend
left a comment
There was a problem hiding this comment.
Request changes for exact current head edc36cf.
Blocking CI regression:
- The required
validate (ubuntu-latest)check is failing on the current head. The single failing test isplugins/Hylouis233/cli-agent-bridge/tests/server.test.mjs:4404: “a fetch in another repository does not disable target attribution”. It returnsok:falsewithorphanedProcesses:true,treeTerminated:false,terminationError:"process tree still appears alive after forceful termination", andquarantinePath=...quarantine; the assertion expected success. This is an actual repository test failure, not the skipped [code]smith check.
Do not merge while validate is red. Reproduce and fix the interaction between the new integrity/store changes and the cli-agent-bridge test/runtime, or demonstrate a correctly isolated flaky-test fix without weakening the fail-closed process-tree cleanup contract. Then rerun the exact-head Ubuntu validation and retain fresh green evidence.
Additional integrity semantics to clarify before approval:
Store.verifyIntegrity()returnsverified:truewhile reportingunchained > 0for rows inserted after the ledger head (store.mjs:61-71, covered bychecks/integrity.check.mjs:80-88). For a tamper-evident audit API, either make any unchained data fail closed or expose an explicit partial/unverified status that callers cannot mistake for a complete verification. Add tests for append-after-head, forged settings, and tail/middle deletion with the intended security semantics.- The hash-chain record binds the row body and a derived key, but the public API must document that this is an in-database tamper-evidence signal, not an independent trust anchor. Do not present
verified:trueas proof against an attacker who can modify both SQLite data and integrity settings.
[code]smith is SKIPPED and is not evidence of correctness.
edc36cf to
6df2db2
Compare
|
Follow-up review of current head
Validation: the new integrity suite passes 8/8 locally, but does not cover the ownership/key mutation above. Current GitHub checks are green, so the older review's red-CI observation is no longer the current state. I am not treating |
…dd MCP contract test - store.mjs rebuilt from main: findCrossRunReuse only, no integrity-ledger code (the ledger belongs to MiniMax-AI#48; the previous round accidentally carried it) - lineageHash now includes each succeeded dependency's output hash, so an upstream that re-executes with different output (mcode node without an explicit model, tracked-file change during execution) invalidates downstream adoption — regression covers the maintainer's divergence shape - checks/cross-reuse-mcp.check.mjs: packaged MCP advertises reuseAcrossRuns on workflow_start/workflow_update and accepts/rejects it through the public tool surface (additionalProperties:false contract)
|
Thank you — both blockers are addressed at exact head
On the prefix semantics: we kept the stricter fail-closed behavior ( Validation at this head: full plugin suite 82/82, packaged MCP smoke 1/1, byte-reproducible rebuild. The earlier red validate run predates #43's merge; current head is green, and we additionally ran the complete 493-test repository gate on a local Ubuntu 24.04 box (Node 24) — 482 pass / 0 fail / 11 platform skips, including the cli-agent-bridge Linux paths. Re-requesting review. |
|
Re-reviewed at One remaining issue before merging: unanchored records inserted into an older sequence gap are silently excluded from verification ( I reproduced this independently for both
This contradicts the documented guarantee that any unanchored row fails closed. Please check coverage across the entire source table against ledger entries for the corresponding surface, rather than only counting the tail, and add regression cases for gap insertion on both surfaces. Latest-head CI is green; this finding comes from the additional reproduction, not a failing existing test. No real model calls were involved. |
174b344 to
0572ac5
Compare
|
Fixed at exact head Process note: head |
|
Re-reviewed exact head Ordinary writes silently anchor externally inserted tail recordsIn Independently reproduced on both
Thus a record that was correctly rejected by verification becomes accepted solely because unrelated normal activity appends another record. The documented legacy behavior permits implicit adoption on the first anchoring write; it should not silently repeat after an anchor already exists. Please restrict legacy bulk anchoring to initial chain creation. For subsequent writes, detect unexpected unanchored records and preserve the failure (or require an explicit recovery/re-anchoring operation), rather than automatically incorporating them. Add regressions for both surfaces covering raw tail insertion followed by a normal API write, alongside the existing immediate-verification test. Validation at this exact head: plugin checks 83/83, packaged MCP smoke 1/1, byte-identical rebuild, and clean-tree repository validator pass. Current GitHub checks are 5 passed / 0 failed / 1 skipped. The finding comes from an additional independent Store/SQLite reproduction, not a failing existing test; no real model calls were involved. |
- two per-database hash chains over the append-only surfaces (events by
seq, repair_cache by rowid), digests chained sha256(prev:kind:key:body)
- per-row ledger table integrity_rows records each link in the same
transaction as the insert, so the first divergent row is precisely
locable; heads live in settings as {head,upto}
- store transaction is reentrant (engine.start already wraps both
append points in one outer transaction)
- workflow_status list form carries integrityHeads and accepts
verifyIntegrity for full recomputation; response becomes an object
since a bare JSON array cannot carry the added fields
- zero migration: CREATE TABLE IF NOT EXISTS, lazy first-anchoring
commits pre-existing rows
- 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
Coverage check: every source row inside the anchored range (pos <= upto) must carry a ledger link. A row imported/restored into an earlier gap was previously invisible to both the link walk and the unchained tail count — verification returned true with checked < rows. Gap rows now report firstDivergence with the row's derived identity and verified:false; regression covers both surfaces plus heal-on-restore (maintainer's independent repro shape).
0572ac5 to
adc0f19
Compare
…dd MCP contract test - store.mjs rebuilt from main: findCrossRunReuse only, no integrity-ledger code (the ledger belongs to MiniMax-AI#48; the previous round accidentally carried it) - lineageHash now includes each succeeded dependency's output hash, so an upstream that re-executes with different output (mcode node without an explicit model, tracked-file change during execution) invalidates downstream adoption — regression covers the maintainer's divergence shape - checks/cross-reuse-mcp.check.mjs: packaged MCP advertises reuseAcrossRuns on workflow_start/workflow_update and accepts/rejects it through the public tool surface (additionalProperties:false contract)
|
Rebased onto main after #50 (and #45's merge); exact head is now |
chainAdvance bulk-adopts pre-existing rows only when the chain is first created. Once a head exists, each write anchors exactly its own new position; rows injected between the head and a later write are never linked — verification keeps failing closed on them (reported as an in-range gap with the injected row's identity) instead of silently legitimizing them (maintainer's independent repro on both surfaces). Regression: raw tail insert rejected, stays rejected across a normal write, heals on removal.
|
Fixed at exact head |
What changes
Implements the integrity ledger proposed in #46: tamper-evident hash chains over the append-only surfaces (
repair_cacheinserts andevents), so "the results reuse is about to trust are the ones earlier runs actually produced" becomes mechanically checkable. Closes #46.Design constraints honored from the issue discussion: threat model is accidental mutation (agent mistakes), not adversaries; only append-only surfaces are chained; zero schema migration for existing databases; no new MCP tool; no change to any existing behavior or response shape except additive fields.
Design
events(seq order) andrepair_cache(rowid order). Row digest:sha256(prev:kind:key:body)over the exact stored JSON bytes; genesis prev is 64 zeros. Chain heads live in the existingsettingstable (integrity_events/integrity_repairas{head, upto}).integrity_rows(surface,pos,key,hash)table records each link, appended in the same transaction as the insert — this is what makes the first divergent row precisely locable (a single end-anchor alone cannot localize mid-chain tampering; we tried that design first and the test suite rejected it).event()/saveRepairCandidate()wrap INSERT + chain advance in a transaction (the store transaction is now reentrant —engine.start()already wraps both calls in one). The first anchoring write implicitly commits pre-existing rows; later tampering with them is detected.workflow_status(list form) always carries a lightintegrityHeadsfield; passingverifyIntegrity: truetriggers a full recomputation and returns anintegrityreport per surface:{head,upto,verified,checked,unchained,firstDivergence}.verifiedis three-valued:true/false/null(nothing anchored yet). Rows beyonduptoare reported asunchained— an honest window, not a false tamper verdict.CREATE TABLE IF NOT EXISTS; existing databases upgrade lazily on first write, old rows are implicitly committed by the first anchoring write.Note: the list form of
workflow_statuschanges from a bare array to{runs, integrityHeads, ...}— a bare JSON array cannot carry the added fields. The tool description documents the shape.Test evidence
checks/integrity.check.mjs: 8 tests covering chain anchoring, byte-level tamper detection + healing, deleted-row detection, forged-head detection, honestunchainedwindow, implicit commit of pre-existing rows, tool-layer schema/fields, and end-to-end repair flow.72 + 8 new; the one intermittent failure is the pre-existing race from fix(dynamic-workflow): deterministic wait polling and checkpoint lineage in repair reuse #44's description, never an integrity test), packaged MCP smoke passes,npm run buildbyte-reproducible, repository validator green. One existing assertion migrated for the new list-form shape (workflow_statusconsumer inchecks/workspace-router.check.mjs).sih/state/plan/integrity-ledger-parallel.md).Need help on this PR? Tag
@codesmith-botwith what you need. Autofix is disabled.