Release report: live and stored operands render different documents¶
Index: Known gaps
Status (2026-10-26): CLOSED by #1814 (release schema 2.5, ADR-068's
2026-10-26 amendment). A stored BundleFacts comparison now renders the live
release document: release_schema_version, libraries as a list, exit,
the receipt (marked effective_config_source:
"reconstructed_from_stored_facts") and explicit unavailable markers for
fields a stored comparison cannot compute. The flat mode: "bundle_facts"
shape is retired, and every format comes from one ReleaseEvaluation.
Still different by nature, not by shape: the stored operand has no old-side
inventory, so its JUnit omits the passing testcase per unchanged symbol, and
it has no HTML or output.view show= projection.
The record below is the gap as it stood before the fix.
Status (updated 2026-10-24): PARTIAL. Both operands now go through one
builder, report.release_document.build_release_report, but each still
yields its own document shape. They agree on every semantic field both carry
(pinned by tests/unit/report/test_release_document.py); the shapes differ.
A directory/package compare (live operand) and compare
OLD.bundle-facts.json NEW (stored operand) describe the same kind of
release comparison, but:
- JSON. The live document carries
release_schema_version,librariesas a list of flattened per-member entries,changed_libraries,unmatched_old/unmatched_new,warnings,exit,change_inventory,severity,effective_config_digest/effective_config_fields,disposition_audit, the matrix fields andshow_only_filter. The stored document carriesmode: "bundle_facts",old_bundle_facts,new_is_stored,per_library_verdict,librariesas an object keyed by member holding each member's full scalarcompareJSON, andanalysis_errors(always present). The live one names the same fieldbundle_analysis_errorsand emits it only when non-empty. Only the storedbundle_findingscarrydemangled_symbol. The stored document has norelease_schema_version,exitblock, receipt digest ordisposition_audit. - Markdown. The two headings differ ("ABI Release Comparison" and "Bundle-facts comparison"), and so do the sections. The stored Markdown is always demangled; the live one follows the demangle setting.
- Formats. The stored operand renders JSON, Markdown, JUnit and
oneline. JUnit andonelinego through the live release renderer, fed the stored comparison's own per-library entries (frontends/cli/commands/compare_bundle_facts_release.py); pinned against the live operand bytests/test_cli_compare_stored_release_parity.py. It still has no HTML oroutput.viewshow=projection: HTML is rendered from the JSON document, which needs an effective-config receipt the stored path does not resolve, andoutput.viewis rejected for a stored OLD_INPUT. - JUnit detail. The live JUnit emits a passing testcase for every unchanged symbol, because the live operand has the old-side inventory. The stored operand has none, so its JUnit omits those cases and its test counts differ. Verdict, exit code, members and findings agree.
Converging them changes a published JSON shape on one side, so it needs a
release-schema decision. It is not a byte-preserving refactor. When they
converge, test_stored_and_live_documents_still_differ_in_shape fails;
close this entry then.