Repository navigation
Saved observation sets are trusted as written: an aggregate that contradicts its own inventory builds a bundle that verifies #38
Description
Found by the review of 2026-09-30. It is about the offline input path (devostasis build and evaluate over a saved observation set, and the vector runner), not about the live collection, which derives everything from what it collected.
1. An aggregate that contradicts its own inventory is trusted, and the bundle verifies
normalize.derive computes each aggregate from its inventory, but returns early when the aggregate is already present (if observation_id in obs: return), and every saved set that observe writes already carries all of them. So on build an aggregate is never checked against the inventory it claims to be derived from.
Reproduced on the example bundle's own observations (examples/sample-bundle/observations.json): the issue inventory shows one stale open issue and forge.issues.stale_open_count_30d says 1. Changing only the aggregate to 30:
after derive(), forged aggregate: 30 (recomputed from the inventory would be the honest value)
clutter honest: LIGHT | clutter forged: HEAVY
forged build: bundle written; verify problems: none (verified)
snapshot clutter band: ['HEAVY']
The bundle carries both facts in observations.json, the inventory that says one and the aggregate that says thirty, and devostasis verify accepts it: verification binds snapshot.json to the digest of observations.json (OBSERVATIONS_DIGEST_MISMATCH) but never asks whether the aggregates inside are the ones their inventories produce. A verified bundle says HEAVY while its own evidence says LIGHT.
2. The evaluators accept values the observation contract admits but no collector writes
Reproduced at the direct evaluator boundary (saved sets and vectors reach it):
- counts are coerced by
as_int: a Clutterstalecount of-5,0.9or"0"is read as an integer, so a vector expectingCLEAN / AVAILABLE / EXACTpasses over them; - a revision record whose
historical_contributionisVERIFY_FAILwhile itshistory_stateisPASS_ONLY_OBSERVEDwas counted as a pass. The review PR now treats that as a defect (REVISION_RECORD_INCONSISTENT), and a current verdict outside the canonical vocabulary asUNKNOWN; the count coercion is still open.
3. The receipt/observation coherence audit, and a caveat for its repair
PV-AUDIT-RECEIPT-OBS-CONSISTENCY-001 (research run 404, REPAIR REQUIRED, RCPT-OBS-01..08, Drive only until now) asks that a saved set's receipt and observations agree before evaluation: every observation requested and matching per_key status and freshness, returned_keys equal to the value-bearing envelopes, no requested key vanishing.
As stated, that invariant would reject every saved set this implementation writes. The collector finalizes the receipt in GitHubAdapter.collect (obs.finalize_receipt(receipt)), and normalize.derive adds the aggregates afterwards. In the example bundle, 27 of the 36 observations are derived or configuration envelopes the receipt does not list, by construction:
observations 36 per_key 9 requested 9
observations not in per_key: 27
of which derived/config: 27
So the repair has to decide which envelopes the receipt speaks for. The coherent reading is: the receipt binds the collected envelopes (the nine inventories), and the derived ones are bound by recomputation from those inventories, which is finding 1. Finalizing the receipt after derivation instead would change every receipt, which is identity-bearing (#19), so it is the more expensive of the two.
Proposed repair
- On loading a saved set (
build,evaluate), recompute every aggregatenormalize.deriveknows from the inventories present and fail closed on a stored aggregate that differs in status, value or coverage, before any evaluation or write; an aggregate whose inventory is absent is kept and marked as not recomputable. - The same recomputation as a verification step over
observations.jsonwhen the member is present. The 308 stored bundles are honestobserveoutputs, so this should move none of them; measure that before adding the step. - Admit counts as non-negative integers (not booleans, floats or strings) at the observation boundary, so
as_intnever has to guess. - Implement run 404's invariant over the collected envelopes, and write down in
docs/spec/observations.mdwhich envelopes the receipt speaks for.
It belongs to the admission package R020-W01/W04 of the 0.2.0 candidate. No threshold, band or identity change.
🤖 Generated with Claude Code
Activity
andy-zen-dev commentedon Oct 24, 2026
Exact-head admission finding: malformed CI completeness flags are treated as complete (2026-10-24)
Repository/source reviewed: PR #81 / release candidate #75 HEAD
a4761daa9fa87026ea106a3d722e7299b3de3b8b,src/devostasis/revision_history.pyblobe7c871965c2f783ae6991d6d2c6d20596e81daa7,_series_records(); also_evaluate_revisions()insrc/devostasis/vitals/integrity.pyandObservation.__post_init__()insrc/devostasis/observations.py. I am adding this to existing #38 (saved-input admission) rather than filing a duplicate Issue. This is independent of #83's carried-array problem.The candidate current-inventory repair only calls the series incomplete if a known coverage field is identical to
False:An explicit
{"complete": 0},{"complete": "false"},{"complete": null},{"attempts_complete": []}or even non-objectcoverage: []is not diagnosed.Observation.__post_init__checks envelope status/value type but not coverage-flag types;ObservationSet.add()does not strengthen that validation. Thus theAVAILABLEseries can returninventory_complete=Truewith malformed completeness claims.reconcile()then treats a carried revision missing from the current inventory as branch-departed;_evaluate_revisions()can proceed without thereconciled.problemsfail-closed gate. A previous failure plus an apparently complete inventory of four passing revisions is the important false-favorable regression shape to test, not an assertion that a full end-to-end reproduction has already passed.Executed narrow oracle (Python 3.13): 13 cases around the literal exact-source predicate: valid omitted/empty coverage, all-true flags, and Boolean-false flags behaved as currently intended; 8/8 malformed examples were treated as COMPLETE by the existing predicate while a type-aware candidate rejected them. This is a source-faithful isolated test, not the actual Devostasis pytest, historical replay, or upstream CI.
Scoped implementation/acceptance: For supplied known completeness flags, require
type(value) is bool(not truthiness/isinstance(value, bool)on integer0); non-Boolean supplied values and non-object coverage should generate an explicit malformed-coverage diagnostic preventing a completeness claim. Preserve absent/empty coverage's existing compatibility pending any separately accepted contract decision; preserve genuineFalseas INCOMPLETE, genuineTrueas true; avoid touching thresholds, history lineage, or band rules. Add parameterized_series_records -> reconcile -> integrity.evaluatetests for these values and a carriedVERIFY_FAILabsent from four currentVERIFY_PASSrevisions; requireUNKNOWN/no favorable exact band for malformed input, and run full pytest + four-generation historical bundle replay on the fixing HEAD.GitHub effect: finding only; no patch/PR/merge or CI pass claimed. Current connector permissions for
andy-zen-dev:pull=true,push=false,triage=false,maintain=false,admin=false.Prepared implementation + chain regression handoff (2026-10-24)
Exact target: PR #81 HEAD
a4761daa9fa87026ea106a3d722e7299b3de3b8b;src/devostasis/revision_history.pyblobe7c871965c2f783ae6991d6d2c6d20596e81daa7;tests/test_revision_history.pyblobca112cedb6b2544c286406fb3bd42bed56c4b7a3.Prepared a focused two-file patch for the existing issue. No policy threshold changes and no new research-case IDs. It replaces only the
AVAILABLEseries coverage admission check with:Integration regression (13 parametrized scenarios) appended in the prepared patch to
tests/test_revision_history.py: use_chain(store)to persist the precedingVERIFY_FAILfor revisionr; construct the next savedAVAILABLErevision series with_passing([1,2,3,5])(r absent) and overwrite onlycoverage. For the eight malformed variants ({"complete":0},{"complete":"false"},{"complete":null},{"attempts_complete":[]},{"runs_complete":1},{"suites_complete":"true"},[],"invalid"), assert the carriedrremainsFAILURE_OBSERVED, the Integrity band isNone, evaluation status isUNKNOWN, and an explicitREVISION_SERIES_COVERAGE_INVALIDdiagnostic exists. Four literalFalseflags must retain the prior failed revision and emitREVISION_SERIES_COVERAGE_INCOMPLETE. Positive control: literal{"complete":true}may proverdeparted and omit it. No branch/source behavior change is intended for absent/empty coverage.Verification performed:
git apply --checkandgit applyPASS against a synthetic workspace containing the exact fetched hunk contexts at the expected file lines; appended regression Python syntax compiled; 12/12 isolated tests of the exact replacement condition PASS. This is notgit applyagainst an actual checkout, and no real Devostasis pytest or historical replay ran. Two upstream exact-head GitHub Actions runs remainaction_required, not PASS. Candidate patch SHA-256:d036bc761b71808753dff89b1110a1fd933daf0b2214639343dffbcf87cc4f1c(4,830 bytes, held outside GitHub for integration).Next acceptance: apply this scoped change on a focused feature branch targeting
release/0.6.0, execute the new tests plus full offline pytest/history replay, and independently review the changed HEAD before merge. This update records a prepared handoff only; no commit/PR/merge is claimed.andy-zen-dev commentedon Oct 24, 2026
2026-10-24 — executable implementation handoff for malformed revision-series coverage (#38)
Scope: one fail-closed input-admission repair, not a Vital threshold/contract reinterpretation. Verified upstream source context: PR #81 head
a4761daa9fa87026ea106a3d722e7299b3de3b8b;src/devostasis/revision_history.pyblobe7c871965c2f783ae6991d6d2c6d20596e81daa7;_series_records()lines 310–343. The previously filed #38 finding remains open. This is a concrete follow-up to comment #6379736684, not a duplicate Issue.Current code admits an AVAILABLE revision inventory as complete unless a known coverage flag is identically
False; malformed explicit values like{"complete":0},{"complete":null},{"attempts_complete":[]}and non-objectcoverage:[]slip through. An absent carried failed revision may then be treated as departed.Ready replacement for the three-line coverage predicate at lines 340–342:
The type check is intentionally
type(value) is bool:0and1cannot masquerade as boolean proof. LegacyNone/ empty coverage remains accepted, genuineFalseremains incomplete, and validTrueremains acceptable. A malformed field plusFalsestill fails closed as MALFORMED. This is not authority to change the accepted completeness contract.Prepared regression shape (20 parameterized pytest instances):
[],"false",0,{"complete":null},{"complete":0},{"runs_complete":"false"},{"attempts_complete":[]},{"suites_complete":{}}; actual_series_records()must emitREVISION_SERIES_COVERAGE_MALFORMEDandinventory_complete=False.None,{},{"complete":true}, and bothruns_complete/attempts_complete:true.REVISION_SERIES_COVERAGE_INCOMPLETE.rwithVERIFY_FAIL; B2 presents four passing revisions withoutrand explicit malformed coverage. Assert B2 retainsr: FAILURE_OBSERVED, Integrity staysUNKNOWNwith the malformed-coverage diagnostic, and committed B2verify_dirsucceeds without contradicting its own evidence.Verification boundary: an isolated predicate oracle identified 8/8 malformed cases currently escaping the existing check; the proposed guard rejects those 8/8, and seven valid/Boolean-false controls match intended behavior. The test module (86 lines) passes Python 3.13 syntax compilation; a generated unified diff containing this replacement and the test module passes
git apply --checkand compilation on an exact-context fragment mirror only, not a real Devostasis checkout. Real package pytest, historical replay, exact-HEAD hosted CI and independent later-head review are NOT_RUN / NOT_PASS. No GitHub code mutation or merge occurred because the connected account haspull=true, push=false.Before integration, document the new diagnostic in
docs/spec/integrity-ci.md, run full offline suite and historical bundle checks on the fixing branch, and preserve distinct accepted research semantics.