advanced_facts_collected infers "advanced DWARF extraction ran" from its output rather than recording it¶
Index: Known gaps
Status (2026-10-29): FIXED. The in-memory half landed 2026-10-12; the persisted half landed with schema v68 (ADR-080, accepted 2026-10-29).
Landed (2026-10-12). AdvancedDwarfMetadata.extraction (AdvancedExtractionStatus: not_run, completed, failed, and unrecorded for an object that never recorded one) is set by the extraction itself: dwarf_unified.parse_dwarf records completed after a walk, failed when the file cannot be opened or parsed, and completed with has_dwarf=False when the ELF carries no DWARF. The presence-only paths (dwarf_presence) record not_run. advanced_facts_collected reads the status: completed is collected when DWARF was found, not_run and failed never are, and only unrecorded falls back to the payload inference. The advanced_dwarf detector's support gate names the state in its not-evaluated reason, and analysis_assurance._dwarf_context_status reports a failed side as incomplete coverage. Regression tests: tests/test_advanced_extraction_status.py.
Persisted (schema v68, ADR-080). The status is written as dwarf_advanced.extraction (not_run, completed or failed) whenever it is recorded. A DWARF dump always records completed or failed; a presence-only dump records not_run. unrecorded writes no key, so BTF, CTF, PDB and hand-built objects encode as before. A pre-v68 document, or a v68 document without the key, decodes to unrecorded and keeps the payload inference, so a stored snapshot is never read as completed without a recorded status. A stored snapshot compared against a live one with a different status is named by a mixed-provenance note in the assurance output (ADR-080 D4); the note is not a gate.
Verified. tests/unit/storage/test_snapshot_field_roundtrip.py has no KNOWN_LOSSY entries left (ceiling 0): every status round-trips, and Declarations.debug_advanced round-trips with one. tests/test_advanced_extraction_status.py pins the pre-v68 reading, the garbled-value refusal and the digest behaviour. tests/test_live_stored_advanced_dwarf_parity.py compares a live gcc -g pair with its stored snapshots: both report completed, and the verdict and findings agree.
Historical note (2026-10-09, 456989f): the paragraphs below describe the state before the in-memory fix.
The predicate answers by checking
whether any field dwarf_advanced.diff_advanced_dwarf consumes is
non-empty, plus target_arch as a discriminator for a parse that completed
but established nothing (dwarf_advanced sets it from the ELF header;
the presence-only helpers leave it ""). That is sound for every shape
reachable today, and it is mutation-checked per consumed family in
tests/test_debug_evidence_presence.py. But it is still an inference: the
honest signal is a status, not a reconstruction from findings.
The reason it matters is asymmetric. checker.py requires the predicate on
both sides, so any shape the inference gets wrong does not merely mislabel
coverage — it disables the advanced_dwarf detector wholesale and the run
silently misses real drift. That is a false negative, the worse direction,
and two such shapes were already found by review during one PR (the three
toolchain flag sets, then the successful-but-empty parse).
The durable fix is an explicit "advanced extraction completed" field on
AdvancedDwarfMetadata, set where the parse succeeds and persisted, with
the predicate reading it instead of inferring. Not folded into the fix PR
because it is a persisted-model change: a new field means a
SCHEMA_VERSION bump and a decision about how a pre-bump snapshot reads
(almost certainly "unknown", resolved conservatively), which this file's own
contract says gets its own ADR and migration rather than riding along with a
behavior fix. Until then the inference stands, and any new consumer of
AdvancedDwarfMetadata must be added to _CONSUMED_ADVANCED_FIELDS in that
test or it will silently disable the detector again.