fix: packet-only hosted default + no live-provenance claims on synthetic data - #4
Merged
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Two defects, both live on https://reconradar.streamlit.app right now.
1. The hosted case ledger was shared across all visitors
bd_page.pycached a singleCaseRepositoryvia@st.cache_resourcebound to one on-disk SQLite path, with no per-session key and no tenant column — every query filters onWHERE case_id=?only. On a shared URL, any two visitors read and mutate the same rows. The public app ships Cases / New Case / Scan & Evidence tabs, so this is reachable, not theoretical.The README already documented this and already prescribed the remedy ("host only the packet-only surface"). This implements it.
Fail-safe default: the ledger is now opt-in via
TENS_HQ_ENABLE_CASE_LEDGER=1. A deployment with no configuration is packet-only. It is deliberately not "hide it when a PUBLIC flag is set" — that leaves the app exposed whenever someone forgets to set the flag, which is the failure being closed.case_ledger_enabled()sits beside the existingpilot_mode_enabled()inroles.pyand follows its shape.When disabled, the guard returns before
_repository()is ever called, so no SQLite file is opened or created. There is a test asserting exactly that.2. Synthetic data claimed live API provenance in eight places
incumbent_leads.pystampedAPI_RETRIEVEDon bundled synthetic records. The repo's own example packet showedSource: bundled SYNTHETIC exampleandProvenance assurance: API_RETRIEVEDthree lines apart.The repo had disclosed four such sites. Fixing them and adding a sweep surfaced four more: a general Origin provenance sentence, the prospective ACS-pull placeholder, the conditional handoff-manifest note, and a bundled-null gate that said "USAspending returned" over an offline fixture.
All now branch on
contract_facts.synthetic_example, the signal that was already in scope — this was an unused-signal bug, not a missing-signal one. Informational content is preserved; only the false provenance claim changed.An initial narrower fix gated on an exact
(source_url, retrieved_at)match. That was an under-fix:_subaward_leads()copies its source tuple fromSubawardsResult, which can differ, leaving a group still labeledAPI_RETRIEVED. Now gated onsynthetic_examplealone, with a regression test using two differing source groups.The durable part
tests/test_synthetic_provenance_sweep.pysweeps the whole rendered export forAPI_RETRIEVEDand non-negated live-claim language, and carries a coverage guard (_MIN_RENDERED_LINE_COUNT = 169, headers ≥ 8, ledger ≥ 11) so deleting a section cannot make it vacuously pass.Mutation-tested: reverting one fix fails it with
ADR-025 extended to cover these modules.
docs/examples/example-packet.mdregenerated by script, not hand-edited. Historical disclosure kept and updated to describe present state.Gate
Baseline was 585.
Restart the Streamlit deployment so the packet-only default takes effect — until then the live app still commingles visitor cases. The repo
homepagefield was deliberately left unset for this repo; set it to the app URL once the redeploy is confirmed.