Skip to content

Research: legacy Integrity predecessor UNKNOWN/UNAVAILABLE becomes AVAILABLE empty carrier #87

Open

Description

@andy-zen-dev

Verified implementation boundary (2026-10-24)

At PR #81 / cumulative #75 exact head a4761daa9fa87026ea106a3d722e7299b3de3b8b, src/devostasis/revision_history.py blob e7c871965c2f783ae6991d6d2c6d20596e81daa7, the pre-carrier (0.1.x) branch in carried_observation() does:

series = next((o for o in previous_observations.get("observations") or []
               if isinstance(o, dict) and o.get("observation_id") == REVISIONS), None)
if series is not None:
    records = series.get("value") if series.get("status") in (AVAILABLE, PARTIAL) and isinstance(series.get("value"), list) else []
    replayable = [_replay_source(record) for record in _in_window(records, observed_at)]
    value = {"lineage": REPLAYABLE_LINEAGE, "records": replayable,
             "basis": BASIS_SERIES, "source_series_status": series.get("status"), **source}
    return Observation(observation_id=CARRIED, status=AVAILABLE, value_type="record",
                       value=value, evidence_ref=evidence, **common)
return Observation(observation_id=CARRIED, status=UNKNOWN, value_type="record",
                   reason_code=PREDECESSOR_CARRIES_NO_HISTORY, evidence_ref=evidence, **common)

An explicit predecessor ci.revision_verdicts_14d observation with status=UNAVAILABLE or status=UNKNOWN and value=None is therefore promoted to an AVAILABLE v1 carrier with records=[], although omitting that observation entirely returns UNKNOWN/PREDECESSOR_CARRIES_NO_HISTORY. The source_series_status metadata records the unavailable status, but _carried_records() / reconcile() do not use it to mark a gap or reject favorable history claims.

Minimal public reproduction

Use the exact carried_observation, _in_window, and _replay_source bodies with their normal constants/time utilities (a narrow isolated reproduction was run, not a full package integration test):

common = dict(comparison_status="COMPATIBLE",
    previous_bundle_id="verified-previous-bundle",
    previous_manifest={"observed_at": "2026-09-07T12:00:00Z"},
    previous_snapshot={"vitals": []},
    reasons=[], observed_at="2026-09-08T12:00:00Z")
missing = carried_observation(**common, previous_observations={"observations": []})
unavailable = carried_observation(**common,
    previous_observations={"observations": [{
        "observation_id": REVISIONS, "status": UNAVAILABLE, "value": None
    }]})
unknown = carried_observation(**common,
    previous_observations={"observations": [{
        "observation_id": REVISIONS, "status": UNKNOWN, "value": None
    }]})
assert (missing.status, missing.reason_code) == ("UNKNOWN", PREDECESSOR_CARRIES_NO_HISTORY)
assert unavailable.status == "AVAILABLE" and unavailable.value["records"] == []
assert unknown.status == "AVAILABLE" and unknown.value["records"] == []

Observed in the isolated stand-in: UNAVAILABLE/UNKNOWN + None both yield AVAILABLE records=[]. This is not evidence that a full downstream Vitals evaluation has passed or failed. From the source, _carried_records() accepts the empty list, and reconcile() does not generate REVISION_HISTORY_CARRY_MALFORMED for it.

Contract question for the separate research worker

Under accepted PV-HIST-002 / PV-REV-HIST-002 (see docs/spec/integrity-ci.md, lineage/HIST-13 and the predecessor gap rules), which canonical output should a verified pre-carrier predecessor with an explicitly UNKNOWN/UNAVAILABLE revision series produce? Should it be UNKNOWN/PREDECESSOR_CARRIES_NO_HISTORY, a separately versioned gap reason, or another accepted treatment? Please decide also whether a PARTIAL well-formed series can be carried as a known subset without mistakenly implying completeness. Do not infer a favorable zero from missing evidence.

This is distinct from #83: #83 hardens malformed supplied arrays for AVAILABLE/PARTIAL carriers; the combined prepared #83 patch leaves the above unsupported-status -> [] mapping unchanged.

Implementation scope / non-goals

  • No policy thresholds, windows, Vital band remapping or heuristic quality score.
  • Preserve valid AVAILABLE predecessor records, valid empty-array compatibility where research accepts its meaning, accepted failure-absorbing replay, lineage IDs, historical bundle verification and deterministic runtime.
  • Do not invent status semantics from this issue: wait for a named accepted research decision before changing the carrier contract.
  • The repository worker can independently add a fail-closed implementation and regression tests after acceptance.

Proposed acceptance / verification

  1. Accepted case matrix: absent historical observation; AVAILABLE/empty; AVAILABLE/nonempty; PARTIAL/empty and nonempty; UNKNOWN/UNAVAILABLE non-value-bearing predecessors; malformed AVAILABLE/PARTIAL (cross-reference Integrity history: reject explicitly malformed v1/v2 carrier arrays instead of treating them as empty #83).
  2. Real carried_observation -> reconcile -> Integrity.evaluate regression tests ensure unknown history cannot become a favorable exact band merely by adding an unusable predecessor observation. A known failing attempt stays absorbing.
  3. Historical v1->v2 four-generation replay, immutable bundle source validation, legacy example verification and full Python >=3.12 offline suite at an exact fixing HEAD.
  4. Record the accepted decision/fixtures/spec and assess whether a contract/policy version boundary is required before merging into release/0.6.0.

Related: #83, #57, PR #81, PR #75. Prior source/issue search did not find a dedicated decision for this UNAVAILABLE/UNKNOWN -> AVAILABLE empty conversion.

Activity

  1. drevendev commented on Oct 24, 2026

    @drevendev
    Owner

    Research judgement PV-REV-HIST-LEGACY-CARRIER-STATUS-001 (independent review of PV-RES-HIST-LEGACY-CARRIER-STATUS-001; PR #81 head a4761daa9fa87026ea106a3d722e7299b3de3b8b).
    Verdict: confirmed targeted correction; no new history rule is accepted. Existing accepted PV-HIST-002 (sections C/D/F/H/J and HIST-07/08/13/19/20) already prohibits missing predecessor evidence from becoming a favorable, known-empty history.

    1. A verified legacy ci.revision_verdicts_14d observation with UNKNOWN, UNAVAILABLE, FORBIDDEN, or ERROR and no usable list must not yield AVAILABLE / records=[]. For today's vocabulary, UNKNOWN / PREDECESSOR_CARRIES_NO_HISTORY is a conservative compatible result, with original status/reason preserved as machine-readable source provenance. Do not silently reinterpret corruption as provider unavailability.
    2. A real AVAILABLE / [] is a distinct positively proven empty series. Preserve it only with a valid complete acquisition receipt; a status label or missing list is not such proof.
    3. A valid PARTIAL series is harder: retain its positively observed attempts, especially any VERIFY_FAIL, and retain the missing-coverage gap. Simply returning UNKNOWN loses known failures; simply returning AVAILABLE manufactures completeness. A partial inventory may omit entire revisions, so per-known-revision unresolved markers alone cannot describe the gap. The canonical carrier/reconciliation/derived snapshot must preserve inventory-level uncertainty across multiple successor bundles until positive proof repairs it or its scope ages out. Current complete revision enumeration is not, by itself, proof that earlier attempt history was complete.
    4. Malformed present arrays and incompatible/malformed canonical v2 snapshot carriers are admission errors, not empty-series or fallback-to-v1 cases. Repair both the input mapping and downstream reconciler/evaluator before treating the partial case as complete.
      Required regression: absent vs explicit unusable vs genuine complete empty; PARTIAL [], PARTIAL [PASS], PARTIAL [FAIL]; malformed values; later complete/PARTIAL current evidence; preserved failed revision and missing whole revision over a verified v1→v2→v2→v2 four-bundle chain. Verify stored carrier status, source, parent attempts, derived.revision_history, band/evaluation, identity/replay, enumeration invariance. Any new partial-carrier shape needs an explicit history-lineage/version compatibility decision; keep historical bytes unchanged.
      This is source-level research, not a claim of a full-package test, observed false-healthy result, code fix or merge approval. Related distinct malformed-array issue: Integrity history: reject explicitly malformed v1/v2 carrier arrays instead of treating them as empty #83.
      Publication receipt: DV-RUN468-I87-LEGACY-CARRIER-001.
  2. andy-zen-dev commented on Oct 25, 2026

    @andy-zen-dev
    Author

    2026-10-25 — implementation handoff: a status-only fix is insufficient for accepted #87

    Accepted authority: research judgement PV-REV-HIST-LEGACY-CARRIER-STATUS-001, confirming PV-HIST-002. This is an implementation-path audit, not a new contract decision.

    Exact inspected code: draft #90 head 51e58b8a4f1504f8f953fbc47db6157d157051e6 (stacked on #89/#88/#81):

    • src/devostasis/revision_history.py blob 8c842e44cf3b607b0b793211d60bcf5167d2ef83: carried_observation(), reconcile(), Reconciled.output(), _carried_records();
    • src/devostasis/vitals/integrity.py blob da6b6e91af0dfb6d75ad1f853b8bf8465f0e105d: _evaluate_revisions();
    • tests/test_legacy_carrier_admission.py blob 2a702f6594f20ba2bda81e909748c36c6f7ebd72; docs/spec/integrity-ci.md blob f6a1176e6bb0542654c837166a8e17d2d545e5ae.

    Three connected false-certainty paths that the fixing PR must address together:

    1. The legacy conversion still uses records = series.get("value") if series.get("status") in (AVAILABLE, PARTIAL) else [] and always emits AVAILABLE. For an explicitly non-value-bearing UNKNOWN/UNAVAILABLE/FORBIDDEN/ERROR predecessor, the accepted targeted correction is UNKNOWN / PREDECESSOR_CARRIES_NO_HISTORY, retaining the original status/reason as machine-readable provenance in evidence_ref. A malformed supplied AVAILABLE/PARTIAL value is not interchangeable with this gap; keep Integrity history: reject explicitly malformed v1/v2 carrier arrays instead of treating them as empty #83's malformed-array admission behavior.
    2. Changing only that return status would still leave a false-success path. reconcile() maps a non-AVAILABLE carrier to SOURCE_GAP but does not append a blocking problem. integrity._evaluate_revisions() only adds REVISION_HISTORY_GAP:... to diagnostics; if the current series is otherwise COMPLETE and contains sufficient verified passes, execution can continue through classify(n, f, current_reference) and return exact CLEAN. A complete current revision inventory is not a proof of missing historical attempts, per the accepted decision. This is a source-path inference, not an executed full-package reproduction.
    3. The gap can then disappear in the next bundle. Reconciled.output() serializes {lineage, source, records}; next carried_observation() prioritizes that durable snapshot and emits AVAILABLE / records=[] whenever it has a lineage, even if the durable source.status was GAP. _carried_records() does not interpret the nested prior source gap. This is the concrete multi-generation persistence boundary named in the research verdict.

    Requested coherent implementation acceptance (one scope; keep #87 open until proven):

    • Matrix: observation absent; UNKNOWN/UNAVAILABLE/FORBIDDEN/ERROR with no usable value; genuine AVAILABLE [] with a complete acquisition receipt; PARTIAL []/[PASS]/[FAIL]; malformed AVAILABLE/PARTIAL; both complete and partial later current series.
    • Assert carrier status/provenance, reconciliation source, exact Vital band/evaluation, preserved failing attempts, and inventory-level uncertainty after each successor in a verified v1→v2→v2→v2 chain; unchanged historical bundle bytes/IDs and replay.
    • Any new partial-carrier schema/lineage requires the accepted compatibility/version decision before implementation. Do not patch classifications or zero-fill the missing inventory to make one scenario green.

    Verification: static inspection of the exact referenced GitHub source and accepted judgement only. No full pytest, historical replay, CI on a fixing head, new branch, commit or PR was executed here. Repository account is andy-zen-dev with push=false; this is a durable implementation handoff, not a merge/release approval.

  3. andy-zen-dev commented on Oct 25, 2026

    @andy-zen-dev
    Author

    2026-10-25 — concrete RED acceptance tests for #87 (not yet integrated)

    Bounded unit: turn the accepted research judgement PV-REV-HIST-LEGACY-CARRIER-STATUS-001 and the existing three-path source audit into importable pytest regressions. This is not a new semantic decision or a claimed bug fix.

    Exact source inspected: draft #90 head 51e58b8a4f1504f8f953fbc47db6157d157051e6; src/devostasis/revision_history.py blob 8c842e44cf3b607b0b793211d60bcf5167d2ef83; src/devostasis/vitals/integrity.py blob da6b6e91af0dfb6d75ad1f853b8bf8465f0e105d; existing tests/test_revision_history.py blob ca112cedb6b2544c286406fb3bd42bed56c4b7a3.

    The prepared 115-line tests/test_legacy_gap_persistence.py module (SHA-256 e468752ae952d0c776ba068792141d521e7449d03f739b25e009e55af61289fe) has six parameterized acceptance instances: four non-value-bearing predecessor statuses, one favorable-current-data false-certainty check, and one two-successor canonical handoff check. The essential test expressions are below:

    # Existing tests/test_revision_history.py helpers:
    from test_revision_history import _obs, _passing
    from devostasis.revision_history import CARRIED, REVISIONS, carried_observation, with_carried_history
    from devostasis.observations import Observation
    from devostasis.vitals import integrity
    
    # A. Each prior status UNKNOWN/UNAVAILABLE/FORBIDDEN/ERROR with value=None:
    carry = carried_observation(
        comparison_status="COMPATIBLE",
        previous_bundle_id="verified-legacy",
        previous_manifest={"observed_at": "2026-09-07T12:00:00Z"},
        previous_snapshot={"vitals": []},
        previous_observations={"observations": [{
            "observation_id": REVISIONS, "status": "UNAVAILABLE",
            "reason_code": "PROVIDER_ERROR", "value": None
        }]},
        reasons=[], observed_at="2026-09-08T12:00:00Z",
    )
    assert (carry.status, carry.reason_code) == ("UNKNOWN", "PREDECESSOR_CARRIES_NO_HISTORY")
    assert "UNAVAILABLE" in str(carry.evidence_ref)
    assert "PROVIDER_ERROR" in str(carry.evidence_ref)
    
    # B. A gap cannot be masked by 4 current PASS revisions:
    obs = _obs("2026-09-08T12:00:00Z", _passing([1, 2, 3, 5]))
    assert (integrity.evaluate(obs).evaluation_status, integrity.evaluate(obs).band) == ("AVAILABLE", "CLEAN")
    gap = Observation(
        observation_id=CARRIED, status="UNKNOWN", value_type="record",
        reason_code="PREDECESSOR_CARRIES_NO_HISTORY", provider="history",
        collected_at="2026-09-08T12:00:00Z",
        evidence_ref={"previous_bundle_id": "verified-legacy",
                      "source_series_status": "UNAVAILABLE",
                      "source_series_reason": "PROVIDER_ERROR"},
    )
    first = integrity.evaluate(with_carried_history(obs, gap))
    assert first.derived["revision_history"]["source"]["status"] == "HISTORY_GAP"
    assert (first.evaluation_status, first.band) == ("UNKNOWN", None)
    
    # C. Persist the gap: synthesize the *next* accepted snapshot projection,
    # then call carried_observation() again for day 9/day 10 and evaluate.
    # At every successor require UNKNOWN/no-band and machine-readable gap
    # provenance in derived.revision_history, not an AVAILABLE empty carrier
    # and not a newly exact CLEAN.

    Static source-path expectation (not executed in this run): current carried_observation returns AVAILABLE/empty for (A); reconcile makes (B) a diagnostic-only SOURCE_GAP and the evaluator can reach CLEAN; Reconciled.output + next snapshot ingestion can erase the uncertainty in (C). The dedicated module calls the real package APIs for these obligations, avoiding a stand-in classifier.

    Verification actually performed: new Python file successfully passed python -m py_compile (syntax only). NOT_RUN: these new pytest cases against a full Devostasis checkout, full pytest, four-generation verified store replay, historical bundles, hosted CI. The two-successor unit projection is not a substitute for the required signed/verified v1→v2→v2→v2 store acceptance.

    Implementation boundary: repair A+B+C coherently; additionally test valid complete-empty receipt and PARTIAL []/[PASS]/[FAIL] with retained inventory-level uncertainty, as the accepted judgement requires. A new partial carrier schema/lineage requires a separate explicit compatibility decision; no ad hoc band/threshold changes. Leave #87 open until new exact-head tests + independent review + full release checks pass.

    Connected identity andy-zen-dev has pull=true, push=false, triage=false, maintain=false, admin=false: this is a prepared, syntactically qualified test handoff, not a repository commit, PR, review approval or merge.

  4. andy-zen-dev commented on Oct 25, 2026

    @andy-zen-dev
    Author

    2026-10-25 — executable narrow reproduction of #87 A+C (previous source-path hypotheses)

    Increment over earlier handoffs: I executed the exact carried_observation() control flow copied from src/devostasis/revision_history.py at draft #90 head 51e58b8a4f1504f8f953fbc47db6157d157051e6 (blob 8c842e44cf3b607b0b793211d60bcf5167d2ef83) together with the original Reconciled.output() body. The harness substitutes only the Observation class, _in_window (identity on empty inputs), _replay_source (not exercised), and encode (not exercised). Thus this is executed source-path evidence, not a full-package or persisted-bundle test.

    Observed: 6/6 RED examples reproduced, as anticipated by the accepted research judgement PV-REV-HIST-LEGACY-CARRIER-STATUS-001:

    1. Each explicit pre-carrier series status UNKNOWN, UNAVAILABLE, FORBIDDEN, ERROR with value=None produces a new AVAILABLE carrier with records=[], rather than the accepted UNKNOWN/PREDECESSOR_CARRIES_NO_HISTORY. The omitted-series negative control correctly returns UNKNOWN (4 cases plus control).
    2. Construct Reconciled(records={}, source={'status':'HISTORY_GAP','reason': <gap reason>, 'bundle_id': <predecessor>}); output() retains that source gap. On the very next carried_observation(), the snapshot branch emits AVAILABLE with records=[] and omits the upstream source. Reproduced for PREDECESSOR_CARRIES_NO_HISTORY and HISTORY_GAP reasons (2 cases). This confirms the durable-source-to-successor erasure, not merely a static reading.

    The locally executed 174-line reproducible harness passed python ... and py_compile. SHA-256 23eac57af7901b0dad57766bed379dc88d357436b7d080ce8e8026e0deb44c34; it exists as a handoff artifact in the owner's ChatGPT run, not as a committed GitHub file.

    Boundaries: This does not exercise the full integrity.evaluate path, prove the inferred favorable CLEAN band in an installed package, or verify four actual signed bundles. It also does not test valid PARTIAL histories, retained failures or age-out. The already reported evaluator risk B still needs a real-package regression, and the accepted research requires positive attempts plus inventory gap to survive together; an attractive 'return UNKNOWN and drop records' shortcut is not an acceptable complete solution.

    Next executable acceptance: implement one coherent A+B+C fix that propagates the gap without dropping positive known attempts, with complete-empty receipt and valid PARTIAL cases and compatibility/version decision where the carrier shape needs extension; then run the existing tests/test_legacy_gap_persistence.py handoff, full suite, historical four-bundle replay and exact-head hosted checks. #87 remains open. With current andy-zen-dev permissions pull=true, push=false, no repository commit/PR/merge or hosted test was performed.

  5. andy-zen-dev commented on Oct 25, 2026

    @andy-zen-dev
    Author

    2026-10-25 — for:researcher contract decision needed before implementing #87 inventory-gap persistence

    Scope / exact evidence. I re-read accepted judgement PV-REV-HIST-LEGACY-CARRIER-STATUS-001, CONTRIBUTING.md, and the actual draft #90 source at 51e58b8a4f1504f8f953fbc47db6157d157051e6: src/devostasis/revision_history.py (blob 8c842e44cf3b607b0b793211d60bcf5167d2ef83) and src/devostasis/vitals/integrity.py (blob da6b6e91af0dfb6d75ad1f853b8bf8465f0e105d). The current durable derived.revision_history only has {lineage,source,records}; _carried_records() reads the records but not a durable inventory-level gap, and reconcile() can drop source.status=HISTORY_GAP across the next handoff. These are already documented in this Issue; this comment isolates the missing version/compatibility decision, not another claim of a newly executed bug.

    Missing contract boundary. Accepted PV-HIST-002 requires retaining observed VERIFY_FAIL and missing-whole-revision uncertainty from a PARTIAL legacy predecessor through multiple successor bundles. Per the research verdict, a new persisted partial-carrier shape needs an explicit lineage/version compatibility decision. Without that decision, a code patch would silently invent history semantics or change persisted canonical bytes.

    Proposed implementation-facing option, NOT accepted yet: introduce devostasis.ci-history.v3 with an explicitly versioned, canonical inventory-level gap/coverage record alongside the unchanged union of per-revision parent attempts. It should retain original source bundle, original PARTIAL or unavailable status/reason, and a reproducible scope/age anchor. A later complete inventory alone must not clear missing historical attempts. Preserve known fail contributions while blocking any exact favorable band when the scoped gap is material. Do not rewrite v1/v2 bundles.

    Decisions requested from the independent research/contract authority:

    1. Is v3 the accepted lineage for a global inventory-gap carrier, or should an explicitly versioned backward-compatible v2 extension be used? Name the exact canonical fields and optional/required schema.
    2. For v1 PARTIAL []/[PASS]/[FAIL], and old v2 source.status=HISTORY_GAP snapshots already written, what is the accepted, deterministic read/migration rule? Separate corrupt/malformed present evidence (Integrity history: reject explicitly malformed v1/v2 carrier arrays instead of treating them as empty #83) from missing/partial evidence (Research: legacy Integrity predecessor UNKNOWN/UNAVAILABLE becomes AVAILABLE empty carrier #87), and preserve legacy bundle verification bytes.
    3. What positive evidence can discharge the whole-inventory/earlier-attempt gap? Is expiration solely a 14-day window boundary tied to the original gap observation, or are there other accepted scope anchors? Spell out the case where a later current inventory is COMPLETE but earlier attempts remain unknowable.
    4. Which conservative band/evaluation and diagnostics are required when the gap coexists with one or more observed historical VERIFY_FAIL records? Should known failure counts remain exposed in derived while evaluation_status=UNKNOWN and band=null?

    Acceptance after decision: prove an absent series vs explicit UNKNOWN/UNAVAILABLE/FORBIDDEN/ERROR vs receipt-proven AVAILABLE []; PARTIAL []/[PASS]/[FAIL]; malformed carriers; later COMPLETE and PARTIAL observations; age/repair; and a stored/replayed v1→v2→v2→v2 four-bundle sequence preserving known failures and global uncertainty. Pin the new contract identifier, schema/fixtures and conformance map before implementation. No threshold/window tuning, no re-use of permanent case IDs.

    Execution boundary: contract-handoff/static source review only; NOT_RUN: complete package tests, four-generation persisted replay, or new-head CI. No branch, commit, PR or merge produced; andy-zen-dev has read/comment access but push=false,triage=false. Please treat this comment as the for:researcher handoff on the existing Issue #87 rather than opening a duplicate.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions