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. |
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 |
|
Fixed at exact head |
* feat: opt-in content-addressed cross-run reuse - run-level reuseAcrossRuns flag (default false, part of requestHash) - agent() consults prior succeeded nodes from other runs in the same workspace store when context (workspace/input/executor/fingerprints) and spec hash match; newest first, schema revalidated per candidate - reused results carry reusedFrom provenance (crossRun marker, original producer preserved) and consume no call budget - store.findCrossRunReuse joins steps x runs with json_extract filters - README documents the semantics and the honest boundary: reuse proves context identity and storage fidelity, not first-run correctness * fix: address review — lineage, schema, model gate, LIMIT pushdown, provenance - reuseAcrossRuns added to workflow_start/workflow_update MCP schemas (additionalProperties:false previously made the flag undiscoverable) - lineageHash per step (requestHash + dependency lineage closure); cross-run lookup requires lineage equality — a changed/rerun upstream now invalidates downstream reuse (maintainer's reproduced R1/R2 case, regression-tested) - mcode nodes without an explicit spec.model are never cross-run candidates (resolved CLI default model/config is not part of any cache key) - contextHash persisted on steps and filtered in SQL; LIMIT 20 can no longer hide older valid candidates behind newer other-context rows - adoption always writes immediate-source reusedFrom (crossRun:true) plus originalProducer (first producer), matching the emitted event - checkpoints carry lineageHash so value changes break downstream lineage * fix: strip ledger contamination, bind upstream output into lineage, add MCP contract test - store.mjs rebuilt from main: findCrossRunReuse only, no integrity-ledger code (the ledger belongs to #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) * chore: drop local CI helper scripts accidentally committed These are contributor-local gate runners (local mirror + remote Ubuntu box), not part of the plugin or the repository contract. They slipped in via a broad 'git add -A' during the r2 fix round. * fix: restamp planId on cross-run adoption The adopted step spread the source run's planId, so a reused node kept the old topology's plan anchor while the current run's topology carried its own planId for the same agent — the dashboard then rendered two nodes (one planned-not-run, one live). Adoption now restamps the current dispatch's planId exactly like the repair path; regression asserts the adopted step maps onto the current topology's single node (maintainer's workflowGraph reproduction). * fix: fresh-execution gate for adoption; originalProducer across repair chains - cross-run adoption now requires every agent dependency to be itself adopted/reused: a freshly executed upstream has unproven execution identity — spec and output hashes cannot see changed filesystem effects (same return value, different written content). Checkpoints recompute deterministically and stay eligible via their value hash in lineage. Regression mirrors the maintainer's same-output/changed-tracked-file repro end-to-end with real file I/O (a re-executes returning 'done', b re-executes and reads the new content). - repair adoption now carries originalProducer (first producer relayed through R2/R3 repairs, not reset to the immediate repair source), so a later cross-run adoption resolves originalProducer.runId to the run that actually executed the node (multi-repair chain regression) --------- Co-authored-by: moc <moc@sgmov.com>
hetaoBackend
left a comment
There was a problem hiding this comment.
Request changes for exact current head 51c71506a71bf2bdd4d597f4b80401176b2eeba1.
The core integrity logic and the previous Ubuntu CI regression are fixed, but two public-contract gaps remain:
-
Document the trust boundary.
src/store.mjs:22-30stores the source data,integrity_rows, and the integrity head/settings in the same SQLite database. The README nearREADME.md:57and the publicworkflow_statusdescription insrc/tools.mjs:16still present this as tamper evidence without stating that it is in-database tamper evidence, not an independent trust anchor. A party able to rewrite the whole SQLite database can also recompute the ledger/head;verified:truemust not be documented or interpreted as proof against that attacker. Add this limitation to the public README/tool contract. -
Complete deletion regressions on both surfaces. The implementation at
src/store.mjs:77-89appears to fail closed for missing covered rows, butchecks/integrity.check.mjs:86-95only deletes the first of two event rows. Add distinct tail-deletion and middle-deletion cases, and cover botheventsandrepair_cache, so later refactors cannot silently weaken the intended semantics.
Exact-head validate (ubuntu-latest), source/package, Windows lifecycle, and CodeQL checks are green. [code]smith is skipped and was not used as evidence. Once the trust-model disclaimer and deletion regressions are present on a new head, this should be ready for another review.
- 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).
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.
51c7150 to
27d7b12
Compare
- README and the workflow_status description now state the trust boundary: the ledger lives in the same SQLite database as the data it covers — it is in-database tamper evidence, not an independent trust anchor; a party able to rewrite the whole database can also recompute the ledger and heads, and verified:true must not be read as proof against that attacker - four distinct deletion regressions (tail and middle, on both events and repair_cache) with row-identity keys, null actual heads, and heal-on- restore assertions, so later refactors cannot silently weaken the fail-closed semantics
27d7b12 to
d248bfa
Compare
|
Both findings addressed at exact head
Validation at this head: plugin suite 117/117, packaged MCP smoke 1/1, byte-reproducible rebuild, and the full 345-test repository gate on a local Ubuntu box (345/345, 0 failures). Ready for another review. |
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.