From c96958fd41824b96ade34e7e8db2dcdeba76bce9 Mon Sep 17 00:00:00 2001 From: Christopher <131207452+PetrefiedThunder@users.noreply.github.com> Date: Fri, 23 Oct 2026 02:11:04 -0700 Subject: [PATCH 1/4] test: remove invented sample_data, demo_exports, qa/fixtures/bad and JEV demo CSV (SEL-447) --- .coderabbit.yaml | 2 - .github/workflows/backend-ci.yml | 44 +- .github/workflows/deploy.yml | 2 - .github/workflows/pr-gate.yml | 4 +- .github/workflows/security.yml | 1 - .gitignore | 25 +- artifacts/classification_registry.seed.json | 20 - demo_exports/SYNTHETIC.md | 3 - ...recall_SV-20240115-001_20260208_170010.csv | 11 - demo_exports/sample_audit_bundle.json | 163 ------- demo_exports/sample_epcis.json | 423 ------------------ demo_exports/sample_fda_export.csv | 20 - docs/GOLDEN_PATH.md | 10 - docs/engineering/JEV_HEADER_MAPPING.md | 30 +- .../examples/jev_demo_shipping.csv | 7 - docs/guides/LOCAL_SETUP_GUIDE.md | 49 +- .../pages/proof-transformation-empty.test.tsx | 13 + qa/fixtures/bad/empty-lot-code.json | 17 - qa/fixtures/bad/invalid-cte-type.json | 17 - qa/fixtures/bad/missing-export-artifact.json | 11 - qa/fixtures/bad/tampered-chain.json | 13 - qa/fixtures/bad/wrong-cte-count.json | 12 - qa/regression.js | 176 -------- qa/summary.js | 1 - sample_data/01_harvesting.csv | 4 - sample_data/02_cooling.csv | 4 - sample_data/03_initial_packing.csv | 4 - sample_data/04_shipping.csv | 5 - sample_data/05_receiving.csv | 5 - sample_data/06_transformation.csv | 3 - sample_data/README.md | 16 - sample_data/SYNTHETIC.md | 3 - sample_data/recall_fixture/3pl_receiving.csv | 8 - sample_data/recall_fixture/3pl_repack.csv | 3 - sample_data/recall_fixture/3pl_shipping.csv | 7 - sample_data/recall_fixture/README.md | 71 --- sample_data/recall_fixture/answer_key.json | 89 ---- sample_data/recall_fixture/dc_receiving.csv | 7 - sample_data/recall_fixture/dc_repack.csv | 4 - sample_data/recall_fixture/dc_shipping.csv | 8 - .../recall_fixture/destination_receiving.csv | 7 - .../recall_fixture/manual_corrections.csv | 2 - sample_data/recall_fixture/mfg_lots.csv | 3 - .../recall_fixture/mfg_pallet_contents.csv | 8 - sample_data/recall_fixture/mfg_shipping.csv | 7 - .../retained/dc_erp/dc_receiving.csv | 7 - .../retained/dc_erp/dc_repack.csv | 4 - sample_data/recall_fixture/sync_manifest.json | 91 ---- scripts/ci/build_registry_seed.py | 1 - scripts/demo_mvp_flow.sh | 220 --------- scripts/regenerate_public_samples.py | 365 --------------- scripts/run_recall_fixture.py | 115 ----- .../ingestion/tests/test_csv_templates.py | 3 +- .../tests/test_csv_templates_1342.py | 2 +- .../recall_reconstruction/test_empty_input.py | 10 + .../test_fixture_cases.py | 197 -------- .../test_fixture_integrity.py | 61 --- .../test_regenerate_public_samples_gate.py | 110 ----- tests/scripts/test_run_recall_fixture.py | 37 -- 59 files changed, 39 insertions(+), 2526 deletions(-) delete mode 100644 demo_exports/SYNTHETIC.md delete mode 100644 demo_exports/fsma_recall_SV-20240115-001_20260208_170010.csv delete mode 100644 demo_exports/sample_audit_bundle.json delete mode 100644 demo_exports/sample_epcis.json delete mode 100644 demo_exports/sample_fda_export.csv delete mode 100644 docs/engineering/examples/jev_demo_shipping.csv create mode 100644 frontend/src/__tests__/pages/proof-transformation-empty.test.tsx delete mode 100644 qa/fixtures/bad/empty-lot-code.json delete mode 100644 qa/fixtures/bad/invalid-cte-type.json delete mode 100644 qa/fixtures/bad/missing-export-artifact.json delete mode 100644 qa/fixtures/bad/tampered-chain.json delete mode 100644 qa/fixtures/bad/wrong-cte-count.json delete mode 100644 qa/regression.js delete mode 100644 sample_data/01_harvesting.csv delete mode 100644 sample_data/02_cooling.csv delete mode 100644 sample_data/03_initial_packing.csv delete mode 100644 sample_data/04_shipping.csv delete mode 100644 sample_data/05_receiving.csv delete mode 100644 sample_data/06_transformation.csv delete mode 100644 sample_data/README.md delete mode 100644 sample_data/SYNTHETIC.md delete mode 100644 sample_data/recall_fixture/3pl_receiving.csv delete mode 100644 sample_data/recall_fixture/3pl_repack.csv delete mode 100644 sample_data/recall_fixture/3pl_shipping.csv delete mode 100644 sample_data/recall_fixture/README.md delete mode 100644 sample_data/recall_fixture/answer_key.json delete mode 100644 sample_data/recall_fixture/dc_receiving.csv delete mode 100644 sample_data/recall_fixture/dc_repack.csv delete mode 100644 sample_data/recall_fixture/dc_shipping.csv delete mode 100644 sample_data/recall_fixture/destination_receiving.csv delete mode 100644 sample_data/recall_fixture/manual_corrections.csv delete mode 100644 sample_data/recall_fixture/mfg_lots.csv delete mode 100644 sample_data/recall_fixture/mfg_pallet_contents.csv delete mode 100644 sample_data/recall_fixture/mfg_shipping.csv delete mode 100644 sample_data/recall_fixture/retained/dc_erp/dc_receiving.csv delete mode 100644 sample_data/recall_fixture/retained/dc_erp/dc_repack.csv delete mode 100644 sample_data/recall_fixture/sync_manifest.json delete mode 100755 scripts/demo_mvp_flow.sh delete mode 100644 scripts/regenerate_public_samples.py delete mode 100755 scripts/run_recall_fixture.py create mode 100644 tests/recall_reconstruction/test_empty_input.py delete mode 100644 tests/recall_reconstruction/test_fixture_cases.py delete mode 100644 tests/recall_reconstruction/test_fixture_integrity.py delete mode 100644 tests/scripts/test_regenerate_public_samples_gate.py delete mode 100644 tests/scripts/test_run_recall_fixture.py diff --git a/.coderabbit.yaml b/.coderabbit.yaml index 1d4b4e318..65eea9b0c 100644 --- a/.coderabbit.yaml +++ b/.coderabbit.yaml @@ -57,8 +57,6 @@ reviews: - "!services/test_data/**" - "!services/ingestion/tests/data/**" # Demo, sample, and export artifacts - - "!demo_exports/**" - - "!sample_data/**" - "!output/**" - "!artifacts/**" - "!production_bundle/**" diff --git a/.github/workflows/backend-ci.yml b/.github/workflows/backend-ci.yml index 06e1bc602..344c18759 100644 --- a/.github/workflows/backend-ci.yml +++ b/.github/workflows/backend-ci.yml @@ -32,8 +32,6 @@ on: - 'requirements.lock' - 'scripts/**' - 'tests/**' - - 'sample_data/**' - - 'demo_exports/**' - 'docs/security/route-security-manifest.json' - 'docs/security/release-evidence/**' - '.github/workflows/backend-ci.yml' @@ -56,8 +54,6 @@ on: - 'requirements.lock' - 'scripts/**' - 'tests/**' - - 'sample_data/**' - - 'demo_exports/**' - 'docs/security/route-security-manifest.json' - 'docs/security/release-evidence/**' - '.github/workflows/backend-ci.yml' @@ -740,40 +736,6 @@ jobs: python -m pip install pip-audit==2.10.0 pip-audit -r requirements.lock --desc on "${pip_audit_ignores[@]}" - # ── Public Sample Regenerator (drift gate) ────────────── - # Re-runs scripts/regenerate_public_samples.py against the synthetic - # CTE inputs in sample_data/ and fails if the regenerated artifacts - # in demo_exports/ differ from what's checked in. Prevents drift - # between the public Proof Surface and current production behavior - # for FDA exports / EPCIS / Merkle audit bundles. - regenerate-public-samples: - name: Regenerate public samples - runs-on: ubuntu-latest - timeout-minutes: 5 - steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6 - - - name: Setup Python - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 - with: - python-version: ${{ env.PYTHON_VERSION }} - - - name: Install production dependencies - run: python -m pip install --require-hashes -r requirements.lock - - - name: Regenerate public samples - run: python scripts/regenerate_public_samples.py - - - name: Fail if regeneration produced drift - run: | - # If regeneration changed any tracked file, the public Proof - # Surface no longer matches current production behavior. The - # PR author must commit the regenerated artifacts. - if ! git diff --exit-code -- demo_exports/; then - echo "::error::demo_exports/ drifted from regenerated output. Re-run scripts/regenerate_public_samples.py and commit the result." - exit 1 - fi - # ── Repo-root security / RLS / isolation suite (hard gate) ─ # The highest-value correctness suites live in the repo-root tests/ dir # (cross-tenant isolation, RLS coverage + hardening, hash-chain audit @@ -1522,7 +1484,7 @@ jobs: # jobs that were aborted mid-flight. `!cancelled()` does not relax the # script below: every dependency still has to be success. if: always() && !cancelled() - needs: [dependency-lock, test, lint, lint-shared, lint-repo-roots, ingestion-full-suite, repo-root-suite, seeded-migration-rehearsal, live-db-suite, docker-build, security, rls-fallback-check, alembic-revision-check, dep-version-check, tenant-id-uuid-check, regenerate-public-samples] + needs: [dependency-lock, test, lint, lint-shared, lint-repo-roots, ingestion-full-suite, repo-root-suite, seeded-migration-rehearsal, live-db-suite, docker-build, security, rls-fallback-check, alembic-revision-check, dep-version-check, tenant-id-uuid-check] runs-on: ubuntu-latest steps: - name: Check results @@ -1542,7 +1504,6 @@ jobs: echo "Alembic rev IDs: ${{ needs.alembic-revision-check.result }}" echo "Dep drift guard: ${{ needs.dep-version-check.result }}" echo "tenant_id UUID: ${{ needs.tenant-id-uuid-check.result }}" - echo "Public samples: ${{ needs.regenerate-public-samples.result }}" # Lint is now blocking — ruff F821 (undefined name) would # have caught PR #1482's NLP NameError class of bugs if this # gate had been enforcing. Promoting lint to a hard gate so @@ -1561,8 +1522,7 @@ jobs: || "${{ needs.rls-fallback-check.result }}" != "success" \ || "${{ needs.alembic-revision-check.result }}" != "success" \ || "${{ needs.dep-version-check.result }}" != "success" \ - || "${{ needs.tenant-id-uuid-check.result }}" != "success" \ - || "${{ needs.regenerate-public-samples.result }}" != "success" ]]; then + || "${{ needs.tenant-id-uuid-check.result }}" != "success" ]]; then echo "::error::One or more required backend checks failed, were cancelled, or were skipped" exit 1 fi diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index b27648ff1..a7cb55001 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -29,8 +29,6 @@ on: - 'requirements.lock' - 'scripts/**' - 'tests/**' - - 'sample_data/**' - - 'demo_exports/**' workflow_dispatch: permissions: diff --git a/.github/workflows/pr-gate.yml b/.github/workflows/pr-gate.yml index a4e7df7f0..911792214 100644 --- a/.github/workflows/pr-gate.yml +++ b/.github/workflows/pr-gate.yml @@ -77,8 +77,8 @@ jobs: "frontend/src/lib/public-openapi.ts", "frontend/package-lock.json", "alembic/**", "server/**", "services/**", "shared/**", "kernel/**", "plugins/fsma/**", "Dockerfile", "railway.toml", "requirements.in", - "requirements.lock", "scripts/**", "tests/**", "sample_data/**", - "demo_exports/**", "docs/security/route-security-manifest.json", + "requirements.lock", "scripts/**", "tests/**", + "docs/security/route-security-manifest.json", "docs/security/release-evidence/**", ".github/workflows/backend-ci.yml", ".github/workflows/deploy.yml", diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml index 2374fcf5a..28c74e351 100644 --- a/.github/workflows/security.yml +++ b/.github/workflows/security.yml @@ -89,7 +89,6 @@ jobs: - 'plugins/fsma/**' - 'scripts/**' - 'tests/**' - - 'sample_data/**' - '**/requirements*' - 'pyproject.toml' - 'Dockerfile*' diff --git a/.gitignore b/.gitignore index e33c6db43..5a28737a2 100644 --- a/.gitignore +++ b/.gitignore @@ -101,8 +101,8 @@ fsma_stress_test_* test_data/ # ...except services/test_data/audit/, which holds 25 intentionally-tracked # audit job fixtures that the bare test_data/ rule above was covering (#2873). -# Same shape as the sample_data/ and demo_exports/ blocks below: re-include the -# directories, re-ignore their contents, then allow only the fixture extension, +# Re-include the services/test_data directory, re-ignore its contents, then +# allow only the fixture extension, # so bulk scratch dumps under services/test_data/ stay ignored. Each parent # directory must be re-included explicitly — a negation for a file inside an # excluded directory has no effect. @@ -177,24 +177,9 @@ test-write .qa-health/ frontend/test-results/ -# Development sample data — public synthetic CTE CSVs are tracked -# (see sample_data/SYNTHETIC.md). Anything else under the dir stays -# ignored so local scratch CSVs don't leak. -sample_data/* -!sample_data/*.csv -!sample_data/*.md -!sample_data/README.md -# The recall reconstruction fixture (synthetic, see its README.md) is tracked in full, -# including the retained ERP snapshot and the answer key. -!sample_data/recall_fixture/ -!sample_data/recall_fixture/** - -# Non-code artifacts — public synthetic exports are tracked -# (see demo_exports/SYNTHETIC.md). Local pilot/sales output stays ignored. -demo_exports/* -!demo_exports/*.csv -!demo_exports/*.json -!demo_exports/*.md +# Local data and exports are never tracked. +sample_data/ +demo_exports/ sales_enablement/ output/ diff --git a/artifacts/classification_registry.seed.json b/artifacts/classification_registry.seed.json index 2849be0fe..c46342b25 100644 --- a/artifacts/classification_registry.seed.json +++ b/artifacts/classification_registry.seed.json @@ -162,26 +162,6 @@ "evidence": "script named for what it doesn't do; rename", "baseline_msg": "AssertionError: a script named rotate_secrets_to_aws.py must not exist: it neither rotates nor contacts AWS" }, - { - "nodeid": "tests/scripts/test_regenerate_public_samples_gate.py::TestWorkflowInstallsTheLockfile::test_job_installs_requirements_lock", - "file": "tests/scripts/test_regenerate_public_samples_gate.py", - "class": "real-defect", - "rc_id": "RC-017", - "status": "open", - "owner": "anvil", - "evidence": "workflow yaml drift after lock policy change", - "baseline_msg": "assert 'requirements.lock' in '\\n name: Regenerate public samples\\n runs-on: ubuntu-latest\\n timeout-minutes: 5\\n steps:\\n - uses: ...erated output. Re-run scripts/regenerate_public_s" - }, - { - "nodeid": "tests/scripts/test_regenerate_public_samples_gate.py::TestWorkflowInstallsTheLockfile::test_job_no_longer_installs_three_hand_picked_packages", - "file": "tests/scripts/test_regenerate_public_samples_gate.py", - "class": "real-defect", - "rc_id": "RC-017", - "status": "open", - "owner": "anvil", - "evidence": "workflow yaml drift after lock policy change", - "baseline_msg": "AssertionError: assert 'pip install...i sqlalchemy' not in '\\n name:... fi\\n'" - }, { "nodeid": "tests/sdk/test_route_contract.py::test_experimental_declaration_matches_production_route_table", "file": "tests/sdk/test_route_contract.py", diff --git a/demo_exports/SYNTHETIC.md b/demo_exports/SYNTHETIC.md deleted file mode 100644 index 71a0779bf..000000000 --- a/demo_exports/SYNTHETIC.md +++ /dev/null @@ -1,3 +0,0 @@ -# Synthetic Data Notice - -All data in this directory is **fully synthetic**. The exported CSVs, EPCIS bundles, and audit packages here are produced by `scripts/regenerate_public_samples.py` from the synthetic source CSVs in `sample_data/` and are intended only for demonstrating RegEngine's FDA 21 CFR 1.1455 export, GS1 EPCIS 2.0 export, and Merkle audit-bundle paths. Entity names, addresses, GLNs, lot codes, hashes, and timestamps are invented or computed deterministically over the synthetic inputs. None of these artifacts are derived from any real customer, supplier, recall, or shipment. Any resemblance to a real registered business is coincidental. diff --git a/demo_exports/fsma_recall_SV-20240115-001_20260208_170010.csv b/demo_exports/fsma_recall_SV-20240115-001_20260208_170010.csv deleted file mode 100644 index daa15cd42..000000000 --- a/demo_exports/fsma_recall_SV-20240115-001_20260208_170010.csv +++ /dev/null @@ -1,11 +0,0 @@ -Traceability Lot Code (TLC),Product Description,Quantity,Unit of Measure,Event Type,Event Date,Event Time,Facility Name,Facility GLN,Facility Address,Confidence Score -SV-20240115-001,Romaine Lettuce,500,cases,SHIPPING,2024-01-15,14:00:00,Sunny Valley Farms,1234567890128,"123 Farm Road, Salinas CA",0.98 -SV-20240115-001,Romaine Lettuce,500,cases,RECEIVING,2024-01-16,08:00:00,Fresh Cut Co,2345678901234,"456 Processing Lane, Fresno CA",0.97 -FC-20240116-A,Chopped Romaine,250,cases,TRANSFORMATION,2024-01-16,10:00:00,Fresh Cut Co,2345678901234,"456 Processing Lane, Fresno CA",0.95 -FC-20240116-B,Romaine Hearts,250,cases,TRANSFORMATION,2024-01-16,11:00:00,Fresh Cut Co,2345678901234,"456 Processing Lane, Fresno CA",0.95 -FC-20240116-A,Chopped Romaine,100,cases,SHIPPING,2024-01-17,06:00:00,Fresh Cut Co,2345678901234,"456 Processing Lane, Fresno CA",0.96 -FC-20240116-A,Chopped Romaine,100,cases,RECEIVING,2024-01-17,10:00:00,Metro Foods,3456789012340,"789 Distribution Dr, Oakland CA",0.94 -FC-20240116-B,Romaine Hearts,150,cases,SHIPPING,2024-01-17,07:00:00,Fresh Cut Co,2345678901234,"456 Processing Lane, Fresno CA",0.96 -FC-20240116-B,Romaine Hearts,150,cases,RECEIVING,2024-01-17,11:00:00,Valley Wholesale,4567890123456,"321 Wholesale Ave, Stockton CA",0.93 -FC-20240116-A,Chopped Romaine,50,cases,SHIPPING,2024-01-18,05:00:00,Metro Foods,3456789012340,"789 Distribution Dr, Oakland CA",0.95 -FC-20240116-A,Chopped Romaine,50,cases,RECEIVING,2024-01-18,08:00:00,SuperMart #42,5678901234562,"100 Retail St, San Jose CA",0.92 diff --git a/demo_exports/sample_audit_bundle.json b/demo_exports/sample_audit_bundle.json deleted file mode 100644 index 5b197c536..000000000 --- a/demo_exports/sample_audit_bundle.json +++ /dev/null @@ -1,163 +0,0 @@ -{ - "chainTip": "edd15e3fae1c21ee1534a3707075d371a2e56bad5ebf1c269ddf457de341dd50", - "dataSource": "synthetic_sample", - "eventCount": 19, - "events": [ - { - "chainHash": "eb902a891216ca3366461b2a210ff3152c8fd943a4e889786a4ff5c9dabad757", - "eventTimestamp": "2026-03-12T06:00:00+00:00", - "eventType": "harvesting", - "index": 0, - "recordHash": "629c56ed928a0b725256781e0632e8b7fd5f29dd3593392f77c7459517306ed3", - "traceabilityLotCode": "LOT-ROM-2026-0312A" - }, - { - "chainHash": "03cc78725130eb5d4a315f3c0176ab0267f04c31cc456e48be4f0cf7ae9042a2", - "eventTimestamp": "2026-03-12T06:07:00+00:00", - "eventType": "harvesting", - "index": 1, - "recordHash": "1798b1cf2c6defed414600fd969e3dc7457170c03ef05662a0e43ef5ca072ad4", - "traceabilityLotCode": "LOT-ROM-2026-0312B" - }, - { - "chainHash": "6d2b6bdc2931a73a04ee2c2a62472d0159ebf9aad06c6eb20de52f2b5dea9b2c", - "eventTimestamp": "2026-03-11T06:14:00+00:00", - "eventType": "harvesting", - "index": 2, - "recordHash": "8b7acdad9a56f7f0b6900b373149f6dcdba7be4098498e9aa20c800e8b3c8abb", - "traceabilityLotCode": "LOT-ROM-2026-0311C" - }, - { - "chainHash": "b6c9ab9fc80af068a81ff69a58de1cee5ad1b6b77afc8109dbb71e67d1f74ac5", - "eventTimestamp": "2026-03-12T09:00:00+00:00", - "eventType": "cooling", - "index": 3, - "recordHash": "fffad000ed0b47f1b375257ed4ce45abc1f99c469762ef86b637b8705e9db8b2", - "traceabilityLotCode": "LOT-ROM-2026-0312A" - }, - { - "chainHash": "c33b48386e8fe2912f2ef2b4379b88260a4f2723ecc3c7c4aaa221fe9d9411b1", - "eventTimestamp": "2026-01-01T09:07:00+00:00", - "eventType": "cooling", - "index": 4, - "recordHash": "9d07906dc82c1b83a2d1f9c5b167cfa8da23fd6726e3bffd648f7b73f2ca8b7f", - "traceabilityLotCode": "LOT-ROM-2026-0312B" - }, - { - "chainHash": "734de4764fbeeb6397f4ebcf0958ed24a3a59c090e054c0d3c5660e9998db6b0", - "eventTimestamp": "2026-03-11T09:14:00+00:00", - "eventType": "cooling", - "index": 5, - "recordHash": "79b8d6fc893117148e2550a6abf1346d6647efa12f07aecd3a16fb9943505a6a", - "traceabilityLotCode": "LOT-ROM-2026-0311C" - }, - { - "chainHash": "349c66038d794d25e5d91f0f7bc6a1c9a42a86d314395800f19f366faf608238", - "eventTimestamp": "2026-03-13T12:00:00+00:00", - "eventType": "initial_packing", - "index": 6, - "recordHash": "68cb298924eac700f421aafd114ff96c4974b6e1ae98a685abef8dd53ef42c1e", - "traceabilityLotCode": "LOT-ROM-2026-0312A-PK" - }, - { - "chainHash": "a952a897d59074e2871b4d2ac44e5a4e015a35ff40f2bdc979cb1faa6f76ee9a", - "eventTimestamp": "2026-03-13T12:07:00+00:00", - "eventType": "initial_packing", - "index": 7, - "recordHash": "0671af84d46489051b14ebdbac7d1721dcef4532d416d047178257d122e96ef1", - "traceabilityLotCode": "LOT-ROM-2026-0312B-PK" - }, - { - "chainHash": "efc5ad75408e7f817e9459300fd72880dbbf4311f43e765cd97ac0d6bcbb604b", - "eventTimestamp": "2026-03-12T12:14:00+00:00", - "eventType": "initial_packing", - "index": 8, - "recordHash": "c8fc8383eb8c04dd7a8949297fcbad568bf84b859ac4aed4dcb6d42736082ddb", - "traceabilityLotCode": "LOT-ROM-2026-0311C-PK" - }, - { - "chainHash": "c27dfb7419681f4e29e8e1fb4743603607cdae524321ee640a08fda13a7109f4", - "eventTimestamp": "2026-03-14T15:00:00+00:00", - "eventType": "shipping", - "index": 9, - "recordHash": "8b723a72122c06d8d1f95f6540e834e482f3c908b2443546a33042141ea3b15e", - "traceabilityLotCode": "LOT-ROM-2026-0312A-PK" - }, - { - "chainHash": "248da44cc351f1b6665babca0a88eca97a39ecb072920ea14d3e9f7642855fe6", - "eventTimestamp": "2026-03-14T15:07:00+00:00", - "eventType": "shipping", - "index": 10, - "recordHash": "ef20b80ee44c8b11b4dc5b06c33cc90b2e44c8529cfd5967be4f6adf0c373d89", - "traceabilityLotCode": "LOT-ROM-2026-0312A-PK" - }, - { - "chainHash": "f01b5151d1300eab4b6534ccf5a17524a74e8e3c71a682ddb76ec3ee5bd79ed3", - "eventTimestamp": "2026-03-14T15:14:00+00:00", - "eventType": "shipping", - "index": 11, - "recordHash": "7ea97b491cb5a9c2a8acfe9aa544fe6cbd9cf565a0f8af60f3b7b8ac0cdb8574", - "traceabilityLotCode": "LOT-ROM-2026-0312B-PK" - }, - { - "chainHash": "eb4bf1b0372a9299e4678f5f57be3700e5ee25715b5f8330686667d68a3bf78b", - "eventTimestamp": "2026-03-13T15:21:00+00:00", - "eventType": "shipping", - "index": 12, - "recordHash": "bc3e809652198aa374c27144b4fa23ea070a27927e817caf9fd7ff59c4e72896", - "traceabilityLotCode": "LOT-ROM-2026-0311C-PK" - }, - { - "chainHash": "f919ef51294d05182609ae344f463ea6fda82993153942f5fb158b861286b1ff", - "eventTimestamp": "2026-03-15T18:00:00+00:00", - "eventType": "receiving", - "index": 13, - "recordHash": "bb074aa9c996c9ddbbc726fa6cb0f64dd29920275e65f4b5eea86abe35030f99", - "traceabilityLotCode": "LOT-ROM-2026-0312A-PK" - }, - { - "chainHash": "8c533f4d121d964de3d0ed8f3358fef5191807ff4e9a8f35065145f7caf12e5e", - "eventTimestamp": "2026-03-15T18:07:00+00:00", - "eventType": "receiving", - "index": 14, - "recordHash": "865b5453d9359aba5d162d985b99f39073002acb57a0a3a99b28cf6a44f83386", - "traceabilityLotCode": "LOT-ROM-2026-0312A-PK" - }, - { - "chainHash": "cd79b87dc13bcaaa874a00a37b79f5f6c01f991f74dfe57aaf896dd3cd9fe966", - "eventTimestamp": "2026-03-15T18:14:00+00:00", - "eventType": "receiving", - "index": 15, - "recordHash": "91c65d25cbc2a9b49a4943ab9ac79f14e9acb0fd2727c501fa017c2faa83db21", - "traceabilityLotCode": "LOT-ROM-2026-0312B-PK" - }, - { - "chainHash": "ce9c2e9842a528f0532c3cdf9c6b3dd6e64c99be517141a60264c357002ee79a", - "eventTimestamp": "2026-03-14T18:21:00+00:00", - "eventType": "receiving", - "index": 16, - "recordHash": "11277c0f3e0a10bf8bfcb3809795b88dc0fe50e5277b8fecda4e95ac4bfacb19", - "traceabilityLotCode": "LOT-ROM-2026-0311C-PK" - }, - { - "chainHash": "3f4e54f03c084e60b4486b357f1ca70fccd9233c0e66bcaf9208698db4b6432f", - "eventTimestamp": "2026-03-16T21:00:00+00:00", - "eventType": "transformation", - "index": 17, - "recordHash": "2287e993d052fd47f18a3c285cf7efc9b2cb48dc8fc3d063b49a1757332a7d7c", - "traceabilityLotCode": "SALAD-2026-0316-001" - }, - { - "chainHash": "edd15e3fae1c21ee1534a3707075d371a2e56bad5ebf1c269ddf457de341dd50", - "eventTimestamp": "2026-03-16T21:07:00+00:00", - "eventType": "transformation", - "index": 18, - "recordHash": "400a0a06fbd7499f87b56149e275dcfec71ad98a434e1a64a3577ea35f1ae251", - "traceabilityLotCode": "SALAD-2026-0316-002" - } - ], - "generatedAt": "2026-01-01T00:00:00+00:00", - "merkleRoot": "266e1df8160325013a8c3df7b93a88dfa931166e6ae2f74cf0aaa732687faf6b", - "syntheticDisclaimer": "Audit bundle generated from synthetic CTE data in sample_data/. See demo_exports/SYNTHETIC.md.", - "tenantId": "00000000-0000-4000-8000-0000000000d1" -} diff --git a/demo_exports/sample_epcis.json b/demo_exports/sample_epcis.json deleted file mode 100644 index ecc19c7d2..000000000 --- a/demo_exports/sample_epcis.json +++ /dev/null @@ -1,423 +0,0 @@ -{ - "@context": [ - "https://ref.gs1.org/standards/epcis/2.0.0/epcis-context.jsonld", - { - "regengine": "https://regengine.co/ns/" - } - ], - "creationDate": "2026-01-01T00:00:00+00:00", - "epcisBody": { - "eventList": [ - { - "action": "OBSERVE", - "bizStep": "urn:epcglobal:cbv:bizstep:harvesting", - "eventTime": "2026-03-12T06:00:00+00:00", - "eventTimeZoneOffset": "+00:00", - "extension": { - "quantityList": [ - { - "epcClass": "urn:epc:class:lgtin:0000000.000000.LOT-ROM-2026-0312A", - "quantity": "5000", - "uom": "lbs" - } - ] - }, - "readPoint": { - "id": "urn:epc:id:sgln:0061414100014.0" - }, - "regengine:chainHash": "eb902a891216ca3366461b2a210ff3152c8fd943a4e889786a4ff5c9dabad757", - "regengine:sha256": "629c56ed928a0b725256781e0632e8b7fd5f29dd3593392f77c7459517306ed3", - "type": "ObjectEvent" - }, - { - "action": "OBSERVE", - "bizStep": "urn:epcglobal:cbv:bizstep:harvesting", - "eventTime": "2026-03-12T06:07:00+00:00", - "eventTimeZoneOffset": "+00:00", - "extension": { - "quantityList": [ - { - "epcClass": "urn:epc:class:lgtin:0000000.000000.LOT-ROM-2026-0312B", - "quantity": "3200", - "uom": "lbs" - } - ] - }, - "readPoint": { - "id": "urn:epc:id:sgln:0061414100014.0" - }, - "regengine:chainHash": "03cc78725130eb5d4a315f3c0176ab0267f04c31cc456e48be4f0cf7ae9042a2", - "regengine:sha256": "1798b1cf2c6defed414600fd969e3dc7457170c03ef05662a0e43ef5ca072ad4", - "type": "ObjectEvent" - }, - { - "action": "OBSERVE", - "bizStep": "urn:epcglobal:cbv:bizstep:harvesting", - "eventTime": "2026-03-11T06:14:00+00:00", - "eventTimeZoneOffset": "+00:00", - "extension": { - "quantityList": [ - { - "epcClass": "urn:epc:class:lgtin:0000000.000000.LOT-ROM-2026-0311C", - "quantity": "4100", - "uom": "lbs" - } - ] - }, - "readPoint": { - "id": "urn:epc:id:sgln:0061414100021.0" - }, - "regengine:chainHash": "6d2b6bdc2931a73a04ee2c2a62472d0159ebf9aad06c6eb20de52f2b5dea9b2c", - "regengine:sha256": "8b7acdad9a56f7f0b6900b373149f6dcdba7be4098498e9aa20c800e8b3c8abb", - "type": "ObjectEvent" - }, - { - "action": "OBSERVE", - "bizStep": "urn:epcglobal:cbv:bizstep:storing", - "eventTime": "2026-03-12T09:00:00+00:00", - "eventTimeZoneOffset": "+00:00", - "extension": { - "quantityList": [ - { - "epcClass": "urn:epc:class:lgtin:0000000.000000.LOT-ROM-2026-0312A", - "quantity": "5000", - "uom": "lbs" - } - ] - }, - "readPoint": { - "id": "urn:epc:id:sgln:0061414100014.0" - }, - "regengine:chainHash": "b6c9ab9fc80af068a81ff69a58de1cee5ad1b6b77afc8109dbb71e67d1f74ac5", - "regengine:sha256": "fffad000ed0b47f1b375257ed4ce45abc1f99c469762ef86b637b8705e9db8b2", - "type": "ObjectEvent" - }, - { - "action": "OBSERVE", - "bizStep": "urn:epcglobal:cbv:bizstep:storing", - "eventTime": "2026-01-01T09:07:00+00:00", - "eventTimeZoneOffset": "+00:00", - "extension": { - "quantityList": [ - { - "epcClass": "urn:epc:class:lgtin:0000000.000000.LOT-ROM-2026-0312B", - "quantity": "3200", - "uom": "lbs" - } - ] - }, - "readPoint": { - "id": "urn:epc:id:sgln:0061414100014.0" - }, - "regengine:chainHash": "c33b48386e8fe2912f2ef2b4379b88260a4f2723ecc3c7c4aaa221fe9d9411b1", - "regengine:sha256": "9d07906dc82c1b83a2d1f9c5b167cfa8da23fd6726e3bffd648f7b73f2ca8b7f", - "type": "ObjectEvent" - }, - { - "action": "OBSERVE", - "bizStep": "urn:epcglobal:cbv:bizstep:storing", - "eventTime": "2026-03-11T09:14:00+00:00", - "eventTimeZoneOffset": "+00:00", - "extension": { - "quantityList": [ - { - "epcClass": "urn:epc:class:lgtin:0000000.000000.LOT-ROM-2026-0311C", - "quantity": "4100", - "uom": "lbs" - } - ] - }, - "readPoint": { - "id": "urn:epc:id:sgln:0061414100021.0" - }, - "regengine:chainHash": "734de4764fbeeb6397f4ebcf0958ed24a3a59c090e054c0d3c5660e9998db6b0", - "regengine:sha256": "79b8d6fc893117148e2550a6abf1346d6647efa12f07aecd3a16fb9943505a6a", - "type": "ObjectEvent" - }, - { - "action": "OBSERVE", - "bizStep": "urn:epcglobal:cbv:bizstep:packing", - "eventTime": "2026-03-13T12:00:00+00:00", - "eventTimeZoneOffset": "+00:00", - "extension": { - "quantityList": [ - { - "epcClass": "urn:epc:class:lgtin:0000000.000000.LOT-ROM-2026-0312A-PK", - "quantity": "1600", - "uom": "cases" - } - ] - }, - "readPoint": { - "id": "urn:epc:id:sgln:0061414100038.0" - }, - "regengine:chainHash": "349c66038d794d25e5d91f0f7bc6a1c9a42a86d314395800f19f366faf608238", - "regengine:sha256": "68cb298924eac700f421aafd114ff96c4974b6e1ae98a685abef8dd53ef42c1e", - "type": "ObjectEvent" - }, - { - "action": "OBSERVE", - "bizStep": "urn:epcglobal:cbv:bizstep:packing", - "eventTime": "2026-03-13T12:07:00+00:00", - "eventTimeZoneOffset": "+00:00", - "extension": { - "quantityList": [ - { - "epcClass": "urn:epc:class:lgtin:0000000.000000.LOT-ROM-2026-0312B-PK", - "quantity": "2800", - "uom": "bags" - } - ] - }, - "readPoint": { - "id": "urn:epc:id:sgln:0061414100038.0" - }, - "regengine:chainHash": "a952a897d59074e2871b4d2ac44e5a4e015a35ff40f2bdc979cb1faa6f76ee9a", - "regengine:sha256": "0671af84d46489051b14ebdbac7d1721dcef4532d416d047178257d122e96ef1", - "type": "ObjectEvent" - }, - { - "action": "OBSERVE", - "bizStep": "urn:epcglobal:cbv:bizstep:packing", - "eventTime": "2026-03-12T12:14:00+00:00", - "eventTimeZoneOffset": "+00:00", - "extension": { - "quantityList": [ - { - "epcClass": "urn:epc:class:lgtin:0000000.000000.LOT-ROM-2026-0311C-PK", - "quantity": "1200", - "uom": "cases" - } - ] - }, - "readPoint": { - "id": "urn:epc:id:sgln:0061414100021.0" - }, - "regengine:chainHash": "efc5ad75408e7f817e9459300fd72880dbbf4311f43e765cd97ac0d6bcbb604b", - "regengine:sha256": "c8fc8383eb8c04dd7a8949297fcbad568bf84b859ac4aed4dcb6d42736082ddb", - "type": "ObjectEvent" - }, - { - "action": "OBSERVE", - "bizStep": "urn:epcglobal:cbv:bizstep:shipping", - "eventTime": "2026-03-14T15:00:00+00:00", - "eventTimeZoneOffset": "+00:00", - "extension": { - "quantityList": [ - { - "epcClass": "urn:epc:class:lgtin:0000000.000000.LOT-ROM-2026-0312A-PK", - "quantity": "800", - "uom": "cases" - } - ] - }, - "readPoint": { - "id": "urn:epc:id:sgln:0000000000000.0" - }, - "regengine:chainHash": "c27dfb7419681f4e29e8e1fb4743603607cdae524321ee640a08fda13a7109f4", - "regengine:sha256": "8b723a72122c06d8d1f95f6540e834e482f3c908b2443546a33042141ea3b15e", - "type": "ObjectEvent" - }, - { - "action": "OBSERVE", - "bizStep": "urn:epcglobal:cbv:bizstep:shipping", - "eventTime": "2026-03-14T15:07:00+00:00", - "eventTimeZoneOffset": "+00:00", - "extension": { - "quantityList": [ - { - "epcClass": "urn:epc:class:lgtin:0000000.000000.LOT-ROM-2026-0312A-PK", - "quantity": "800", - "uom": "cases" - } - ] - }, - "readPoint": { - "id": "urn:epc:id:sgln:0000000000000.0" - }, - "regengine:chainHash": "248da44cc351f1b6665babca0a88eca97a39ecb072920ea14d3e9f7642855fe6", - "regengine:sha256": "ef20b80ee44c8b11b4dc5b06c33cc90b2e44c8529cfd5967be4f6adf0c373d89", - "type": "ObjectEvent" - }, - { - "action": "OBSERVE", - "bizStep": "urn:epcglobal:cbv:bizstep:shipping", - "eventTime": "2026-03-14T15:14:00+00:00", - "eventTimeZoneOffset": "+00:00", - "extension": { - "quantityList": [ - { - "epcClass": "urn:epc:class:lgtin:0000000.000000.LOT-ROM-2026-0312B-PK", - "quantity": "2800", - "uom": "bags" - } - ] - }, - "readPoint": { - "id": "urn:epc:id:sgln:0000000000000.0" - }, - "regengine:chainHash": "f01b5151d1300eab4b6534ccf5a17524a74e8e3c71a682ddb76ec3ee5bd79ed3", - "regengine:sha256": "7ea97b491cb5a9c2a8acfe9aa544fe6cbd9cf565a0f8af60f3b7b8ac0cdb8574", - "type": "ObjectEvent" - }, - { - "action": "OBSERVE", - "bizStep": "urn:epcglobal:cbv:bizstep:shipping", - "eventTime": "2026-03-13T15:21:00+00:00", - "eventTimeZoneOffset": "+00:00", - "extension": { - "quantityList": [ - { - "epcClass": "urn:epc:class:lgtin:0000000.000000.LOT-ROM-2026-0311C-PK", - "quantity": "1200", - "uom": "cases" - } - ] - }, - "readPoint": { - "id": "urn:epc:id:sgln:0000000000000.0" - }, - "regengine:chainHash": "eb4bf1b0372a9299e4678f5f57be3700e5ee25715b5f8330686667d68a3bf78b", - "regengine:sha256": "bc3e809652198aa374c27144b4fa23ea070a27927e817caf9fd7ff59c4e72896", - "type": "ObjectEvent" - }, - { - "action": "OBSERVE", - "bizStep": "urn:epcglobal:cbv:bizstep:receiving", - "eventTime": "2026-03-15T18:00:00+00:00", - "eventTimeZoneOffset": "+00:00", - "extension": { - "quantityList": [ - { - "epcClass": "urn:epc:class:lgtin:0000000.000000.LOT-ROM-2026-0312A-PK", - "quantity": "800", - "uom": "cases" - } - ] - }, - "readPoint": { - "id": "urn:epc:id:sgln:0000000000000.0" - }, - "regengine:chainHash": "f919ef51294d05182609ae344f463ea6fda82993153942f5fb158b861286b1ff", - "regengine:sha256": "bb074aa9c996c9ddbbc726fa6cb0f64dd29920275e65f4b5eea86abe35030f99", - "type": "ObjectEvent" - }, - { - "action": "OBSERVE", - "bizStep": "urn:epcglobal:cbv:bizstep:receiving", - "eventTime": "2026-03-15T18:07:00+00:00", - "eventTimeZoneOffset": "+00:00", - "extension": { - "quantityList": [ - { - "epcClass": "urn:epc:class:lgtin:0000000.000000.LOT-ROM-2026-0312A-PK", - "quantity": "795", - "uom": "cases" - } - ] - }, - "readPoint": { - "id": "urn:epc:id:sgln:0000000000000.0" - }, - "regengine:chainHash": "8c533f4d121d964de3d0ed8f3358fef5191807ff4e9a8f35065145f7caf12e5e", - "regengine:sha256": "865b5453d9359aba5d162d985b99f39073002acb57a0a3a99b28cf6a44f83386", - "type": "ObjectEvent" - }, - { - "action": "OBSERVE", - "bizStep": "urn:epcglobal:cbv:bizstep:receiving", - "eventTime": "2026-03-15T18:14:00+00:00", - "eventTimeZoneOffset": "+00:00", - "extension": { - "quantityList": [ - { - "epcClass": "urn:epc:class:lgtin:0000000.000000.LOT-ROM-2026-0312B-PK", - "quantity": "2780", - "uom": "bags" - } - ] - }, - "readPoint": { - "id": "urn:epc:id:sgln:0000000000000.0" - }, - "regengine:chainHash": "cd79b87dc13bcaaa874a00a37b79f5f6c01f991f74dfe57aaf896dd3cd9fe966", - "regengine:sha256": "91c65d25cbc2a9b49a4943ab9ac79f14e9acb0fd2727c501fa017c2faa83db21", - "type": "ObjectEvent" - }, - { - "action": "OBSERVE", - "bizStep": "urn:epcglobal:cbv:bizstep:receiving", - "eventTime": "2026-03-14T18:21:00+00:00", - "eventTimeZoneOffset": "+00:00", - "extension": { - "quantityList": [ - { - "epcClass": "urn:epc:class:lgtin:0000000.000000.LOT-ROM-2026-0311C-PK", - "quantity": "1190", - "uom": "cases" - } - ] - }, - "readPoint": { - "id": "urn:epc:id:sgln:0000000000000.0" - }, - "regengine:chainHash": "ce9c2e9842a528f0532c3cdf9c6b3dd6e64c99be517141a60264c357002ee79a", - "regengine:sha256": "11277c0f3e0a10bf8bfcb3809795b88dc0fe50e5277b8fecda4e95ac4bfacb19", - "type": "ObjectEvent" - }, - { - "action": "OBSERVE", - "bizStep": "urn:epcglobal:cbv:bizstep:transforming", - "eventTime": "2026-03-16T21:00:00+00:00", - "eventTimeZoneOffset": "+00:00", - "extension": { - "quantityList": [ - { - "epcClass": "urn:epc:class:lgtin:0000000.000000.SALAD-2026-0316-001", - "quantity": "3500", - "uom": "bags" - } - ] - }, - "readPoint": { - "id": "urn:epc:id:sgln:0061414100069.0" - }, - "regengine:chainHash": "3f4e54f03c084e60b4486b357f1ca70fccd9233c0e66bcaf9208698db4b6432f", - "regengine:sha256": "2287e993d052fd47f18a3c285cf7efc9b2cb48dc8fc3d063b49a1757332a7d7c", - "type": "ObjectEvent" - }, - { - "action": "OBSERVE", - "bizStep": "urn:epcglobal:cbv:bizstep:transforming", - "eventTime": "2026-03-16T21:07:00+00:00", - "eventTimeZoneOffset": "+00:00", - "extension": { - "quantityList": [ - { - "epcClass": "urn:epc:class:lgtin:0000000.000000.SALAD-2026-0316-002", - "quantity": "1800", - "uom": "bags" - } - ] - }, - "readPoint": { - "id": "urn:epc:id:sgln:0061414100069.0" - }, - "regengine:chainHash": "edd15e3fae1c21ee1534a3707075d371a2e56bad5ebf1c269ddf457de341dd50", - "regengine:sha256": "400a0a06fbd7499f87b56149e275dcfec71ad98a434e1a64a3577ea35f1ae251", - "type": "ObjectEvent" - } - ] - }, - "id": "urn:uuid:regengine-sample-00000000-0000-4000-8000-0000000000d1", - "regengine:exportMetadata": { - "dataSource": "synthetic_sample", - "eventsCount": 19, - "exportFormat": "EPCIS_2.0_JSON-LD", - "generatedAt": "2026-01-01T00:00:00+00:00", - "syntheticDisclaimer": "This document is generated from synthetic CTE data in sample_data/. See demo_exports/SYNTHETIC.md.", - "tenantId": "00000000-0000-4000-8000-0000000000d1" - }, - "schemaVersion": "2.0", - "type": "EPCISDocument" -} diff --git a/demo_exports/sample_fda_export.csv b/demo_exports/sample_fda_export.csv deleted file mode 100644 index 0af5d021e..000000000 --- a/demo_exports/sample_fda_export.csv +++ /dev/null @@ -1,20 +0,0 @@ -"Traceability Lot Code (TLC)","Product Description","Quantity","Unit of Measure","Event Type (CTE)","Event Date","Event Time","Location GLN","Location Name","Ship From GLN","Ship From Name","Ship To GLN","Ship To Name","Immediate Previous Source","TLC Source GLN","TLC Source FDA Registration","Source Document","Record Hash (SHA-256)","Chain Hash","Reference Document Number","Receive Date","Ship Date","Harvest Date","Cooling Date","Packing Date","Transformation Date","Landing Date","Receiving Location","Temperature (°F)","Carrier","Growing Area","Additional KDEs (JSON)","System Entry Timestamp" -"LOT-ROM-2026-0312A","Organic Romaine Hearts","5000","lbs","harvesting","2026-03-12","06:00:00 UTC","0061414100014","Salinas Valley Farms","","","","","","","","sample_data/harvesting","629c56ed928a0b725256781e0632e8b7fd5f29dd3593392f77c7459517306ed3","eb902a891216ca3366461b2a210ff3152c8fd943a4e889786a4ff5c9dabad757","","","","2026-03-12","","","","","","","","","{""field_id"": ""FIELD-SVF-7"", ""harvester_name"": ""Salinas Valley Farms LLC"", ""reference_document"": ""HARV-SVF-2026-0312-001""}","" -"LOT-ROM-2026-0312B","Chopped Romaine Mix","3200","lbs","harvesting","2026-03-12","06:07:00 UTC","0061414100014","Salinas Valley Farms","","","","","","","","sample_data/harvesting","1798b1cf2c6defed414600fd969e3dc7457170c03ef05662a0e43ef5ca072ad4","03cc78725130eb5d4a315f3c0176ab0267f04c31cc456e48be4f0cf7ae9042a2","","","","2026-03-12","","","","","","","","","{""field_id"": ""FIELD-SVF-12"", ""harvester_name"": ""Salinas Valley Farms LLC"", ""reference_document"": ""HARV-SVF-2026-0312-002""}","" -"LOT-ROM-2026-0311C","Romaine Hearts 3-Pack","4100","lbs","harvesting","2026-03-11","06:14:00 UTC","0061414100021","Coastline Ridge Growers","","","","","","","","sample_data/harvesting","8b7acdad9a56f7f0b6900b373149f6dcdba7be4098498e9aa20c800e8b3c8abb","6d2b6bdc2931a73a04ee2c2a62472d0159ebf9aad06c6eb20de52f2b5dea9b2c","","","","2026-03-11","","","","","","","","","{""field_id"": ""FIELD-CRG-3"", ""harvester_name"": ""Coastline Ridge Growers Inc"", ""reference_document"": ""HARV-SVF-2026-0312-003""}","" -"LOT-ROM-2026-0312A","Organic Romaine Hearts","5000","lbs","cooling","2026-03-12","09:00:00 UTC","0061414100014","Salinas Valley Cooler #1","","","","","","","","sample_data/cooling","fffad000ed0b47f1b375257ed4ce45abc1f99c469762ef86b637b8705e9db8b2","b6c9ab9fc80af068a81ff69a58de1cee5ad1b6b77afc8109dbb71e67d1f74ac5","","","","","2026-03-12","","","","","","","","{""temperature_celsius"": ""1.8"", ""reference_document"": ""COOL-SVF-2026-0312-001""}","" -"LOT-ROM-2026-0312B","Chopped Romaine Mix","3200","lbs","cooling","2026-01-01","09:07:00 UTC","0061414100014","Salinas Valley Cooler #1","","","","","","","","sample_data/cooling","9d07906dc82c1b83a2d1f9c5b167cfa8da23fd6726e3bffd648f7b73f2ca8b7f","c33b48386e8fe2912f2ef2b4379b88260a4f2723ecc3c7c4aaa221fe9d9411b1","","","","","","","","","","","","","{""temperature_celsius"": ""2.3"", ""reference_document"": ""COOL-SVF-2026-0312-002""}","" -"LOT-ROM-2026-0311C","Romaine Hearts 3-Pack","4100","lbs","cooling","2026-03-11","09:14:00 UTC","0061414100021","Coastline Ridge Cold Storage","","","","","","","","sample_data/cooling","79b8d6fc893117148e2550a6abf1346d6647efa12f07aecd3a16fb9943505a6a","734de4764fbeeb6397f4ebcf0958ed24a3a59c090e054c0d3c5660e9998db6b0","","","","","2026-03-11","","","","","","","","{""temperature_celsius"": ""2.0"", ""reference_document"": ""COOL-SVF-2026-0312-003""}","" -"LOT-ROM-2026-0312A-PK","Organic Romaine Hearts 3ct","1600","cases","initial_packing","2026-03-13","12:00:00 UTC","0061414100038","FreshCut Processing","","","","","","","","sample_data/initial_packing","68cb298924eac700f421aafd114ff96c4974b6e1ae98a685abef8dd53ef42c1e","349c66038d794d25e5d91f0f7bc6a1c9a42a86d314395800f19f366faf608238","","","","","","2026-03-13","","","","","","","{""input_lot_codes"": ""LOT-ROM-2026-0312A"", ""reference_document"": ""PACK-FPP-2026-0312-001"", ""harvester_business_name"": ""Salinas Valley Farms LLC""}","" -"LOT-ROM-2026-0312B-PK","Chopped Romaine 12oz Bag","2800","bags","initial_packing","2026-03-13","12:07:00 UTC","0061414100038","FreshCut Processing","","","","","","","","sample_data/initial_packing","0671af84d46489051b14ebdbac7d1721dcef4532d416d047178257d122e96ef1","a952a897d59074e2871b4d2ac44e5a4e015a35ff40f2bdc979cb1faa6f76ee9a","","","","","","2026-03-13","","","","","","","{""input_lot_codes"": ""LOT-ROM-2026-0312B"", ""reference_document"": ""PACK-FPP-2026-0312-002"", ""harvester_business_name"": ""Salinas Valley Farms LLC""}","" -"LOT-ROM-2026-0311C-PK","Romaine Hearts 3-Pack Retail","1200","cases","initial_packing","2026-03-12","12:14:00 UTC","0061414100021","Coastline Ridge Growers Packhouse","","","","","","","","sample_data/initial_packing","c8fc8383eb8c04dd7a8949297fcbad568bf84b859ac4aed4dcb6d42736082ddb","efc5ad75408e7f817e9459300fd72880dbbf4311f43e765cd97ac0d6bcbb604b","","","","","","2026-03-12","","","","","","","{""input_lot_codes"": ""LOT-ROM-2026-0311C"", ""reference_document"": ""PACK-FPP-2026-0312-003"", ""harvester_business_name"": ""Salinas Valley Farms LLC""}","" -"LOT-ROM-2026-0312A-PK","Organic Romaine Hearts 3ct","800","cases","shipping","2026-03-14","15:00:00 UTC","","","0061414100038","FreshCut Processing","0061414100045","MegaMart Distribution Center","","","","sample_data/shipping","8b723a72122c06d8d1f95f6540e834e482f3c908b2443546a33042141ea3b15e","c27dfb7419681f4e29e8e1fb4743603607cdae524321ee640a08fda13a7109f4","","","2026-03-14","","","","","","","","Acme Cold Freight","","{""carrier_name"": ""Acme Cold Freight"", ""po_number"": ""PO-MM-2026-7201"", ""reference_document"": ""BOL-CFS-2026-0313-001"", ""tlc_source_reference"": ""PACK-FPP-2026-0312-001""}","" -"LOT-ROM-2026-0312A-PK","Organic Romaine Hearts 3ct","800","cases","shipping","2026-03-14","15:07:00 UTC","","","0061414100038","FreshCut Processing","0061414100052","Premier Grocery Warehouse","","","","sample_data/shipping","ef20b80ee44c8b11b4dc5b06c33cc90b2e44c8529cfd5967be4f6adf0c373d89","248da44cc351f1b6665babca0a88eca97a39ecb072920ea14d3e9f7642855fe6","","","2026-03-14","","","","","","","","Cold Express Logistics","","{""carrier_name"": ""Cold Express Logistics"", ""po_number"": ""PO-PG-2026-3388"", ""reference_document"": ""BOL-CFS-2026-0313-002"", ""tlc_source_reference"": ""PACK-FPP-2026-0312-001""}","" -"LOT-ROM-2026-0312B-PK","Chopped Romaine 12oz Bag","2800","bags","shipping","2026-03-14","15:14:00 UTC","","","0061414100038","FreshCut Processing","0061414100045","MegaMart Distribution Center","","","","sample_data/shipping","7ea97b491cb5a9c2a8acfe9aa544fe6cbd9cf565a0f8af60f3b7b8ac0cdb8574","f01b5151d1300eab4b6534ccf5a17524a74e8e3c71a682ddb76ec3ee5bd79ed3","","","2026-03-14","","","","","","","","Acme Cold Freight","","{""carrier_name"": ""Acme Cold Freight"", ""po_number"": ""PO-MM-2026-7202"", ""reference_document"": ""BOL-CFS-2026-0313-003"", ""tlc_source_reference"": ""PACK-FPP-2026-0312-001""}","" -"LOT-ROM-2026-0311C-PK","Romaine Hearts 3-Pack Retail","1200","cases","shipping","2026-03-13","15:21:00 UTC","","","0061414100021","Coastline Ridge Growers Packhouse","0061414100052","Premier Grocery Warehouse","","","","sample_data/shipping","bc3e809652198aa374c27144b4fa23ea070a27927e817caf9fd7ff59c4e72896","eb4bf1b0372a9299e4678f5f57be3700e5ee25715b5f8330686667d68a3bf78b","","","2026-03-13","","","","","","","","Coastline Trucking Co","","{""carrier_name"": ""Coastline Trucking Co"", ""po_number"": ""PO-PG-2026-3389"", ""reference_document"": ""BOL-CFS-2026-0313-004"", ""tlc_source_reference"": ""PACK-FPP-2026-0312-001""}","" -"LOT-ROM-2026-0312A-PK","Organic Romaine Hearts 3ct","800","cases","receiving","2026-03-15","18:00:00 UTC","","","","","0061414100045","MegaMart Distribution Center","FreshCut Processing","","","sample_data/receiving","bb074aa9c996c9ddbbc726fa6cb0f64dd29920275e65f4b5eea86abe35030f99","f919ef51294d05182609ae344f463ea6fda82993153942f5fb158b861286b1ff","","2026-03-15","","","","","","","MegaMart Distribution Center","","","","{""receiving_gln"": ""0061414100045"", ""temperature_celsius"": ""3.1"", ""reference_document"": ""RCV-WFM-2026-0314-001"", ""tlc_source_reference"": ""PACK-FPP-2026-0312-001""}","" -"LOT-ROM-2026-0312A-PK","Organic Romaine Hearts 3ct","795","cases","receiving","2026-03-15","18:07:00 UTC","","","","","0061414100052","Premier Grocery Warehouse","FreshCut Processing","","","sample_data/receiving","865b5453d9359aba5d162d985b99f39073002acb57a0a3a99b28cf6a44f83386","8c533f4d121d964de3d0ed8f3358fef5191807ff4e9a8f35065145f7caf12e5e","","2026-03-15","","","","","","","Premier Grocery Warehouse","","","","{""receiving_gln"": ""0061414100052"", ""temperature_celsius"": ""3.4"", ""reference_document"": ""RCV-WFM-2026-0314-002"", ""tlc_source_reference"": ""PACK-FPP-2026-0312-001""}","" -"LOT-ROM-2026-0312B-PK","Chopped Romaine 12oz Bag","2780","bags","receiving","2026-03-15","18:14:00 UTC","","","","","0061414100045","MegaMart Distribution Center","FreshCut Processing","","","sample_data/receiving","91c65d25cbc2a9b49a4943ab9ac79f14e9acb0fd2727c501fa017c2faa83db21","cd79b87dc13bcaaa874a00a37b79f5f6c01f991f74dfe57aaf896dd3cd9fe966","","2026-03-15","","","","","","","MegaMart Distribution Center","","","","{""receiving_gln"": ""0061414100045"", ""temperature_celsius"": ""2.9"", ""reference_document"": ""RCV-WFM-2026-0314-003"", ""tlc_source_reference"": ""PACK-FPP-2026-0312-001""}","" -"LOT-ROM-2026-0311C-PK","Romaine Hearts 3-Pack Retail","1190","cases","receiving","2026-03-14","18:21:00 UTC","","","","","0061414100052","Premier Grocery Warehouse","Coastline Ridge Growers Packhouse","","","sample_data/receiving","11277c0f3e0a10bf8bfcb3809795b88dc0fe50e5277b8fecda4e95ac4bfacb19","ce9c2e9842a528f0532c3cdf9c6b3dd6e64c99be517141a60264c357002ee79a","","2026-03-14","","","","","","","Premier Grocery Warehouse","","","","{""receiving_gln"": ""0061414100052"", ""temperature_celsius"": ""3.2"", ""reference_document"": ""RCV-WFM-2026-0314-004"", ""tlc_source_reference"": ""PACK-FPP-2026-0312-001""}","" -"SALAD-2026-0316-001","Garden Fresh Salad Mix 16oz","3500","bags","transformation","2026-03-16","21:00:00 UTC","0061414100069","Metro Processing Plant","","","","","","","","sample_data/transformation","2287e993d052fd47f18a3c285cf7efc9b2cb48dc8fc3d063b49a1757332a7d7c","3f4e54f03c084e60b4486b357f1ca70fccd9233c0e66bcaf9208698db4b6432f","","","","","","","2026-03-16","","","","","","{""input_lot_codes"": ""LOT-ROM-2026-0312A-PK,LOT-ROM-2026-0312B-PK"", ""reference_document"": ""TRANS-WFM-2026-0315-001""}","" -"SALAD-2026-0316-002","Caesar Romaine Kit 10oz","1800","bags","transformation","2026-03-16","21:07:00 UTC","0061414100069","Metro Processing Plant","","","","","","","","sample_data/transformation","400a0a06fbd7499f87b56149e275dcfec71ad98a434e1a64a3577ea35f1ae251","edd15e3fae1c21ee1534a3707075d371a2e56bad5ebf1c269ddf457de341dd50","","","","","","","2026-03-16","","","","","","{""input_lot_codes"": ""LOT-ROM-2026-0311C-PK"", ""reference_document"": ""TRANS-WFM-2026-0315-002""}","" diff --git a/docs/GOLDEN_PATH.md b/docs/GOLDEN_PATH.md index 3405e24e3..ae0901971 100644 --- a/docs/GOLDEN_PATH.md +++ b/docs/GOLDEN_PATH.md @@ -27,16 +27,6 @@ This check is intentionally database-free. It proves that the production spine p - SHA-256 record hashes and ordered chain hashes - FDA export columns, including `System Entry Timestamp` -## Recall Reconstruction Fixture - -The recall fixture proves one narrower claim: that a lot can be followed through pallets, splits, relabels, a DC, and a 3PL, and that missing evidence is reported as `unresolved` rather than read as exclusion. - -```bash -python3 scripts/run_recall_fixture.py --case all --output-dir /tmp/regengine-recall-fixture -``` - -It runs the same synthetic scenario three ways (complete records, a withheld 3PL pallet-content record, and an unreachable ERP served from its retained snapshot), writes an evidence package per case, and reconciles each against `sample_data/recall_fixture/answer_key.json`. It is DB-free and reuses the canonical event model and hash chain. See `sample_data/recall_fixture/README.md`. - For the heavier live-service scenario, export the service secret first, then use: ```bash diff --git a/docs/engineering/JEV_HEADER_MAPPING.md b/docs/engineering/JEV_HEADER_MAPPING.md index 4956381d0..cf2200e3d 100644 --- a/docs/engineering/JEV_HEADER_MAPPING.md +++ b/docs/engineering/JEV_HEADER_MAPPING.md @@ -416,38 +416,14 @@ thresholds in force. The values shown are illustrative. | `--prompt-key` | Read the key from a hidden terminal prompt (or from stdin when there is no terminal), for this run only, instead of `TYPESAFE_API_KEY`. The script never prints, logs or saves it. | | `--cte-type CTE` | The CTE every row of the file records, as the route's `cte_type` form field: same accepted values and aliases (`_CTE_TYPE_ALIASES`), same normalisation, same withholding rule. An empty value (`--cte-type ""`) means not declared, like an empty form field; a blank-but-not-empty one is a usage error, as the route rejects it. When sent, it is shown on the `Sent:` line and as `request.file_cte_type` in `--json`. When withheld, `request.file_cte_type` is null, `request.file_cte_type_dropped` gives the reason, and the table prints a `CTE:` line. `request.file_cte_type` comes from the route helper's result: what was sent on `ok`, what was attempted on `unavailable:*` and `error` (the request may never have left), and null when nothing was built (for example without a key). Without a key the reason is still computed from the file with the same helper (`_file_cte_type_for_jev`), so the report says the `--cte-type` would be withheld. An unknown value is a usage error (exit 1) and nothing is sent. Omit it for mixed-type files. | -### Demo file +### Check your own file -`docs/engineering/examples/jev_demo_shipping.csv` is a synthetic shipping -file (fictional companies marked "(demo)", lot codes `DEMO-JEV-*`). It -carries every column the parser needs, so it is valid on its own, plus seven -extra headers the parser does not recognise. Those seven are what Jev is -asked about; the intended answers are: - -| Header | Intended field | -| --- | --- | -| `Lot #` | `traceability_lot_code` | -| `Item Desc` | `product_description` | -| `Qty Shpd` | `quantity` | -| `Ship Dt` | `ship_date` | -| `Ship-To GLN` | `ship_to_gln` | -| `Trucking Co` | `carrier` | -| `Internal Notes` | `no_match` | +Run the preview against a supplier CSV you are authorized to use. A header-only CSV can check column mapping without sending records. The preview reports unrecognised headers and does not save changes. ```bash -python3 scripts/jev_header_preview.py docs/engineering/examples/jev_demo_shipping.csv --prompt-key +python3 scripts/jev_header_preview.py /path/to/your-supplier.csv --prompt-key ``` -The demo file names each row's CTE in its own `cte_type` column, so it is -a per-row file: adding `--cte-type shipping` sends no `file_cte_type` and -the report shows `file has a per-row CTE column: cte_type`. - -With `--simulate-apply` and answers in the `auto_apply` band, the four -headers whose canonical column is already in the file (`Lot #`, `Item Desc`, -`Qty Shpd`, `Ship Dt`) stay blocked with `target_present`, and `Ship-To GLN` -and `Trucking Co` show `would_apply: yes`, since the file has no -`ship_to_gln` or `carrier` column. `Internal Notes` is never applied. - Exit codes: `0` suggestions received, or no unrecognised headers (no request made); `1` bad usage (including an unknown `--cte-type`), an unreadable, oversized (over 5 MB) or non-UTF-8 file (stdout stays empty, the message goes to stderr), a malformed header diff --git a/docs/engineering/examples/jev_demo_shipping.csv b/docs/engineering/examples/jev_demo_shipping.csv deleted file mode 100644 index b1be6b56b..000000000 --- a/docs/engineering/examples/jev_demo_shipping.csv +++ /dev/null @@ -1,7 +0,0 @@ -cte_type,traceability_lot_code,product_description,quantity,unit_of_measure,ship_date,ship_from_location,ship_to_location,reference_document,tlc_source_reference,Lot #,Item Desc,Qty Shpd,Ship Dt,Ship-To GLN,Trucking Co,Internal Notes -shipping,DEMO-JEV-ROM-0921-01,Romaine Hearts 3ct (demo),120,cases,2026-09-21,Juniper Ridge Farms Packhouse (demo),Harborlight Distribution Center (demo),BOL-DEMO-0921-001,PACK-DEMO-0920-011,DEMO-JEV-ROM-0921-01,Romaine Hearts 3ct,120,09/21/2026,0614141000029,Coldline Freight (demo),dock 3 first load -shipping,DEMO-JEV-CUC-0921-02,Cucumbers Select 24ct (demo),80,cases,2026-09-21,Juniper Ridge Farms Packhouse (demo),Harborlight Distribution Center (demo),BOL-DEMO-0921-002,PACK-DEMO-0920-014,DEMO-JEV-CUC-0921-02,Cucumbers Select 24ct,80,09/21/2026,0614141000029,Coldline Freight (demo),pallet re-wrapped -shipping,DEMO-JEV-TOM-0922-03,Cherry Tomatoes 12x1pt (demo),64,cases,2026-09-22,Cedar Mesa Growers Cooler (demo),Northgate Fresh Market DC (demo),BOL-DEMO-0922-003,PACK-DEMO-0921-020,DEMO-JEV-TOM-0922-03,Cherry Tomatoes 12x1pt,64,09/22/2026,0614141000036,Bluewater Reefer Lines (demo),temp log attached -shipping,DEMO-JEV-PEP-0923-04,Red Bell Peppers 11lb (demo),150,cases,2026-09-23,Cedar Mesa Growers Cooler (demo),Northgate Fresh Market DC (demo),BOL-DEMO-0923-004,PACK-DEMO-0922-031,DEMO-JEV-PEP-0923-04,Red Bell Peppers 11lb,150,09/23/2026,0614141000036,Bluewater Reefer Lines (demo), -shipping,DEMO-JEV-SPN-0924-05,Baby Spinach 4x2.5lb (demo),40,cases,2026-09-24,Juniper Ridge Farms Packhouse (demo),Harborlight Distribution Center (demo),BOL-DEMO-0924-005,PACK-DEMO-0923-042,DEMO-JEV-SPN-0924-05,Baby Spinach 4x2.5lb,40,09/24/2026,0614141000029,Coldline Freight (demo),short one case -shipping,DEMO-JEV-CIL-0925-06,Cilantro 30ct (demo),25,cases,2026-09-25,Cedar Mesa Growers Cooler (demo),Northgate Fresh Market DC (demo),BOL-DEMO-0925-006,PACK-DEMO-0924-050,DEMO-JEV-CIL-0925-06,Cilantro 30ct,25,09/25/2026,0614141000036,Bluewater Reefer Lines (demo),recheck label diff --git a/docs/guides/LOCAL_SETUP_GUIDE.md b/docs/guides/LOCAL_SETUP_GUIDE.md index eeca9a4ce..563ba62f3 100644 --- a/docs/guides/LOCAL_SETUP_GUIDE.md +++ b/docs/guides/LOCAL_SETUP_GUIDE.md @@ -307,54 +307,9 @@ curl -H "X-RegEngine-API-Key: $API_KEY" \ --- -## Run FSMA 204 Demo +## Review FSMA 204 records -RegEngine includes a complete FDA Food Safety Modernization Act (FSMA) 204 compliance module for food supply chain traceability. - -### Step 1: Run the Mock Recall Demo - -```bash -./scripts/demo/fsma_mock_recall.sh -``` - -This demonstrates: -- **Forward tracing** (find all downstream products from a contaminated lot) -- **Backward tracing** (find all upstream suppliers) -- **FDA-oriented CSV export** (24-hour recall requirement) -- **Contact list generation** (notify affected facilities) - -### Step 2: Test FSMA API Endpoints - -```bash -# Validate a GTIN (Global Trade Item Number) -curl -X POST http://localhost:8200/v1/fsma/validate/gtin \ - -H "Content-Type: application/json" \ - -H "X-RegEngine-API-Key: $API_KEY" \ - -d '{ - "gtin": "01234567890128" - }' | jq - -# Forward trace (find downstream customers) -curl -H "X-RegEngine-API-Key: $API_KEY" \ - http://localhost:8200/v1/fsma/trace/forward/SV-20240115-001 | jq - -# Backward trace (find upstream suppliers) -curl -H "X-RegEngine-API-Key: $API_KEY" \ - http://localhost:8200/v1/fsma/trace/backward/FC-20240116-A | jq - -# Export FDA-oriented CSV -curl -H "X-RegEngine-API-Key: $API_KEY" \ - http://localhost:8200/v1/fsma/export/trace/SV-20240115-001 -``` - -### Step 3: Review Generated Reports - -Check the `demo_exports/` directory for generated CSV files: - -```bash -ls -lh demo_exports/ -cat demo_exports/fsma_recall_SV-20240115-001_*.csv -``` +Upload supplier records you are authorized to use, then inspect their validation results and traceability evidence in the application. Exports are available only after the workspace contains accepted records. --- diff --git a/frontend/src/__tests__/pages/proof-transformation-empty.test.tsx b/frontend/src/__tests__/pages/proof-transformation-empty.test.tsx new file mode 100644 index 000000000..9085b4bf4 --- /dev/null +++ b/frontend/src/__tests__/pages/proof-transformation-empty.test.tsx @@ -0,0 +1,13 @@ +import { render, screen } from '@testing-library/react'; +import { describe, expect, it } from 'vitest'; +import TransformationProofPage from '@/app/proof/transformation/page'; + +describe('transformation proof without supplier records', () => { + it('shows an empty state without invented evidence', () => { + const { container } = render(); + + expect(screen.getByText(/No data yet/)).toBeInTheDocument(); + expect(container.querySelector('table')).toBeNull(); + expect(container.querySelector('a[download]')).toBeNull(); + }); +}); diff --git a/qa/fixtures/bad/empty-lot-code.json b/qa/fixtures/bad/empty-lot-code.json deleted file mode 100644 index fdda11a84..000000000 --- a/qa/fixtures/bad/empty-lot-code.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "empty-lot-code", - "description": "Row with empty traceability lot code. Must be rejected by validator as blocking error.", - "severity": "critical", - "expected_failure": "missing_lot_code", - "must_fail": ["bad-data.js"], - "test_row": { - "lot_code": "", - "cte_type": "shipping", - "facility_name": "Test Facility", - "quantity": "100" - }, - "expected": { - "errors": ["Missing lot code"], - "can_commit": false - } -} diff --git a/qa/fixtures/bad/invalid-cte-type.json b/qa/fixtures/bad/invalid-cte-type.json deleted file mode 100644 index 820cf4ab9..000000000 --- a/qa/fixtures/bad/invalid-cte-type.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "invalid-cte-type", - "description": "CTE type 'cooking' is not one of the 7 valid FSMA 204 CTEs. Must be rejected.", - "severity": "critical", - "expected_failure": "invalid_cte_type", - "must_fail": ["bad-data.js"], - "test_row": { - "lot_code": "LOT-001", - "cte_type": "cooking", - "facility_name": "Test Facility", - "quantity": "100" - }, - "expected": { - "errors": ["Invalid CTE type: \"cooking\""], - "can_commit": false - } -} diff --git a/qa/fixtures/bad/missing-export-artifact.json b/qa/fixtures/bad/missing-export-artifact.json deleted file mode 100644 index d24506df2..000000000 --- a/qa/fixtures/bad/missing-export-artifact.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "name": "missing-export-artifact", - "description": "Chain verification JSON deleted. Must fail export validation.", - "severity": "critical", - "expected_failure": "missing_artifact", - "must_fail": ["export-validate.js"], - "mutation": { - "file": "frontend/public/samples/sample_chain_verification.json", - "action": "delete" - } -} diff --git a/qa/fixtures/bad/tampered-chain.json b/qa/fixtures/bad/tampered-chain.json deleted file mode 100644 index 78a7b5327..000000000 --- a/qa/fixtures/bad/tampered-chain.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "name": "tampered-merkle-chain", - "description": "Event 3 merkle hash replaced with deadbeef. Must break chain verification at seq 3 and cascade to seq 4.", - "severity": "critical", - "expected_failure": "merkle_chain_broken", - "must_fail": ["fsma-lite-check.js", "full-flow.js"], - "mutation": { - "file": "sample_epcis_2.0.json", - "path": "epcisBody.eventList[2].extension.regengine:merkleHash", - "original": "910eb11db7a915775b08b7c0340184e513f023e3fd46b2effeafd7eff055b97a", - "tampered": "deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef" - } -} diff --git a/qa/fixtures/bad/wrong-cte-count.json b/qa/fixtures/bad/wrong-cte-count.json deleted file mode 100644 index fbc7fd956..000000000 --- a/qa/fixtures/bad/wrong-cte-count.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "name": "wrong-cte-count", - "description": "FSMA guide says '6 Critical Tracking Events' instead of 7. Must fail regulatory copy check.", - "severity": "critical", - "expected_failure": "regulatory_copy_regression", - "must_fail": ["fsma-lite-check.js"], - "mutation": { - "file": "frontend/src/app/fsma-204/page.tsx", - "find": "7 Critical Tracking Events", - "replace": "6 Critical Tracking Events" - } -} diff --git a/qa/regression.js b/qa/regression.js deleted file mode 100644 index b76757f5d..000000000 --- a/qa/regression.js +++ /dev/null @@ -1,176 +0,0 @@ -#!/usr/bin/env node -/** - * Regression Harness (v2) - * Loads canonical "known bad" fixtures from qa/fixtures/bad/ - * and verifies each one is caught FOR THE CORRECT REASON. - * - * Does NOT modify real files. Runs mutations in memory. - * Fails if a fixture passes, or fails for the wrong reason. - */ - -const fs = require('fs'); -const crypto = require('crypto'); -const path = require('path'); - -const FIXTURES = path.join(__dirname, 'fixtures', 'bad'); -const SAMPLES = path.join(__dirname, '..', 'frontend', 'public', 'samples'); -const SRC = path.join(__dirname, '..', 'frontend', 'src'); - -const VALID_CTES = [ - 'harvesting', 'cooling', 'initial_packing', - 'first_land_based_receiving', - 'shipping', 'receiving', 'transformation' -]; - -let passed = 0; -let failed = 0; - -function assert(fixtureName, reason, condition, detail) { - if (condition) { - console.log(` \u2713 [${reason}] ${detail || 'detected'}`); - passed++; - } else { - console.error(` \u2717 [${reason}] ${detail || 'NOT detected'}`); - failed++; - } -} - -console.log('\n=== Regression Harness v2 ===\n'); - -const fixtures = fs.readdirSync(FIXTURES) - .filter(f => f.endsWith('.json')) - .map(f => JSON.parse(fs.readFileSync(path.join(FIXTURES, f), 'utf8'))); - -console.log(`Loaded ${fixtures.length} regression fixtures.\n`); - -// ── DETECTOR: Merkle chain tamper ──────────────────────── -function detectMerkleChainTamper(tamperedHash, targetIndex) { - const epcis = JSON.parse(fs.readFileSync(path.join(SAMPLES, 'sample_epcis_2.0.json'), 'utf8')); - const events = epcis.epcisBody.eventList; - events[targetIndex].extension['regengine:merkleHash'] = tamperedHash; - - const hashes = events.map(e => ({ - payload: e.extension['regengine:payloadSHA256'], - merkle: e.extension['regengine:merkleHash'], - })); - - let breakAt = null; - for (let i = 1; i < hashes.length; i++) { - const expected = crypto.createHash('sha256') - .update(hashes[i - 1].merkle + hashes[i].payload) - .digest('hex'); - if (expected !== hashes[i].merkle) { breakAt = i; break; } - } - return { detected: breakAt !== null, breakAt, reason: 'merkle_chain_broken' }; -} - -// ── DETECTOR: Regulatory copy regression ───────────────── -function detectCopyRegression(find, replace) { - const fsmaPage = path.join(SRC, 'app', 'fsma-204', 'page.tsx'); - const original = fs.readFileSync(fsmaPage, 'utf8'); - const mutated = original.replace(find, replace); - const hasBadCopy = mutated.includes('6 Critical Tracking Events'); - const originalClean = !original.includes('6 Critical Tracking Events'); - return { - detected: hasBadCopy && originalClean, - reason: 'regulatory_copy_regression', - detail: hasBadCopy ? 'Mutated content contains "6 CTEs"' : 'Mutation had no effect' - }; -} - -// ── DETECTOR: Missing artifact ─────────────────────────── -function detectMissingArtifact(filename) { - const exists = fs.existsSync(path.join(SAMPLES, path.basename(filename))); - return { - detected: exists, // if it exists now, deletion WOULD be caught - reason: 'missing_artifact', - detail: exists ? 'File present — deletion would trigger failure' : 'File already missing' - }; -} - -// ── DETECTOR: Validator rejection ──────────────────────── -function detectValidatorRejection(row, expectedReason) { - const errors = []; - if (!row.lot_code || row.lot_code.trim().length === 0) errors.push('missing_lot_code'); - if (!row.cte_type || !VALID_CTES.includes(row.cte_type.toLowerCase())) errors.push('invalid_cte_type'); - const matchesExpected = errors.includes(expectedReason); - return { - detected: matchesExpected, - reason: expectedReason, - detail: matchesExpected ? `Correctly rejected: ${expectedReason}` : `Expected ${expectedReason}, got: [${errors.join(', ')}]` - }; -} - -// ── RUN EACH FIXTURE ───────────────────────────────────── -for (const fixture of fixtures) { - console.log(`${fixture.name} [${fixture.severity}]`); - console.log(` ${fixture.description}`); - - let result; - - switch (fixture.expected_failure) { - case 'merkle_chain_broken': - result = detectMerkleChainTamper(fixture.mutation.tampered, 2); - assert(fixture.name, result.reason, - result.detected, - result.detected - ? `Chain break at seq ${result.breakAt + 1} — correct` - : 'Chain passed when it should fail' - ); - assert(fixture.name, 'reason_match', - result.reason === fixture.expected_failure, - `Expected: ${fixture.expected_failure}, Got: ${result.reason}` - ); - break; - - case 'regulatory_copy_regression': - result = detectCopyRegression(fixture.mutation.find, fixture.mutation.replace); - assert(fixture.name, result.reason, - result.detected, - result.detail - ); - assert(fixture.name, 'reason_match', - result.reason === fixture.expected_failure, - `Expected: ${fixture.expected_failure}, Got: ${result.reason}` - ); - break; - - case 'missing_artifact': - result = detectMissingArtifact(fixture.mutation.file); - assert(fixture.name, result.reason, - result.detected, - result.detail - ); - assert(fixture.name, 'reason_match', - result.reason === fixture.expected_failure, - `Expected: ${fixture.expected_failure}, Got: ${result.reason}` - ); - break; - - case 'missing_lot_code': - case 'invalid_cte_type': - result = detectValidatorRejection(fixture.test_row, fixture.expected_failure); - assert(fixture.name, result.reason, - result.detected, - result.detail - ); - assert(fixture.name, 'reason_match', - result.reason === fixture.expected_failure, - `Expected: ${fixture.expected_failure}, Got: ${result.reason}` - ); - break; - - default: - console.error(` \u2717 Unknown expected_failure: ${fixture.expected_failure}`); - failed++; - } - console.log(''); -} - -// ── Summary ───────────────────────────────────────────── -console.log(`${'='.repeat(50)}`); -console.log(`Regression v2: ${passed} passed, ${failed} failed`); -console.log(`Fixtures: ${fixtures.length} | Severity: ${fixtures.filter(f => f.severity === 'critical').length} critical`); -console.log(`${'='.repeat(50)}\n`); - -if (failed > 0) process.exit(1); diff --git a/qa/summary.js b/qa/summary.js index 1216b41e5..4dd2e39ee 100644 --- a/qa/summary.js +++ b/qa/summary.js @@ -16,7 +16,6 @@ const SCRIPTS = [ { name: 'bad-data', script: 'bad-data.js', category: 'pipeline' }, { name: 'export', script: 'export-validate.js', category: 'pipeline' }, { name: 'ai-analysis', script: 'ai-analysis.js', category: 'trust' }, - { name: 'regression', script: 'regression.js', category: 'regression' }, ]; const results = {}; diff --git a/sample_data/01_harvesting.csv b/sample_data/01_harvesting.csv deleted file mode 100644 index b6f611b3e..000000000 --- a/sample_data/01_harvesting.csv +++ /dev/null @@ -1,4 +0,0 @@ -traceability_lot_code,product_description,quantity,unit_of_measure,harvest_date,location_name,location_gln,field_id,harvester_name,reference_document -LOT-ROM-2026-0312A,Organic Romaine Hearts,5000,lbs,2026-03-12,Salinas Valley Farms,0061414100014,FIELD-SVF-7,Salinas Valley Farms LLC,HARV-SVF-2026-0312-001 -LOT-ROM-2026-0312B,Chopped Romaine Mix,3200,lbs,2026-03-12,Salinas Valley Farms,0061414100014,FIELD-SVF-12,Salinas Valley Farms LLC,HARV-SVF-2026-0312-002 -LOT-ROM-2026-0311C,Romaine Hearts 3-Pack,4100,lbs,2026-03-11,Coastline Ridge Growers,0061414100021,FIELD-CRG-3,Coastline Ridge Growers Inc,HARV-SVF-2026-0312-003 diff --git a/sample_data/02_cooling.csv b/sample_data/02_cooling.csv deleted file mode 100644 index 18005c818..000000000 --- a/sample_data/02_cooling.csv +++ /dev/null @@ -1,4 +0,0 @@ -traceability_lot_code,product_description,quantity,unit_of_measure,cooling_date,location_name,location_gln,temperature_celsius,reference_document -LOT-ROM-2026-0312A,Organic Romaine Hearts,5000,lbs,2026-03-12,Salinas Valley Cooler #1,0061414100014,1.8,COOL-SVF-2026-0312-001 -LOT-ROM-2026-0312B,Chopped Romaine Mix,3200,lbs,,Salinas Valley Cooler #1,0061414100014,2.3,COOL-SVF-2026-0312-002 -LOT-ROM-2026-0311C,Romaine Hearts 3-Pack,4100,lbs,2026-03-11,Coastline Ridge Cold Storage,0061414100021,2.0,COOL-SVF-2026-0312-003 diff --git a/sample_data/03_initial_packing.csv b/sample_data/03_initial_packing.csv deleted file mode 100644 index b478f4e37..000000000 --- a/sample_data/03_initial_packing.csv +++ /dev/null @@ -1,4 +0,0 @@ -traceability_lot_code,product_description,quantity,unit_of_measure,packing_date,location_name,location_gln,input_lot_codes,reference_document,harvester_business_name -LOT-ROM-2026-0312A-PK,Organic Romaine Hearts 3ct,1600,cases,2026-03-13,FreshCut Processing,0061414100038,LOT-ROM-2026-0312A,PACK-FPP-2026-0312-001,Salinas Valley Farms LLC -LOT-ROM-2026-0312B-PK,Chopped Romaine 12oz Bag,2800,bags,2026-03-13,FreshCut Processing,0061414100038,LOT-ROM-2026-0312B,PACK-FPP-2026-0312-002,Salinas Valley Farms LLC -LOT-ROM-2026-0311C-PK,Romaine Hearts 3-Pack Retail,1200,cases,2026-03-12,Coastline Ridge Growers Packhouse,0061414100021,LOT-ROM-2026-0311C,PACK-FPP-2026-0312-003,Salinas Valley Farms LLC diff --git a/sample_data/04_shipping.csv b/sample_data/04_shipping.csv deleted file mode 100644 index 17ed04f08..000000000 --- a/sample_data/04_shipping.csv +++ /dev/null @@ -1,5 +0,0 @@ -traceability_lot_code,product_description,quantity,unit_of_measure,ship_date,ship_from_location,ship_to_location,ship_from_gln,ship_to_gln,carrier_name,po_number,reference_document,tlc_source_reference -LOT-ROM-2026-0312A-PK,Organic Romaine Hearts 3ct,800,cases,2026-03-14,FreshCut Processing,MegaMart Distribution Center,0061414100038,0061414100045,Acme Cold Freight,PO-MM-2026-7201,BOL-CFS-2026-0313-001,PACK-FPP-2026-0312-001 -LOT-ROM-2026-0312A-PK,Organic Romaine Hearts 3ct,800,cases,2026-03-14,FreshCut Processing,Premier Grocery Warehouse,0061414100038,0061414100052,Cold Express Logistics,PO-PG-2026-3388,BOL-CFS-2026-0313-002,PACK-FPP-2026-0312-001 -LOT-ROM-2026-0312B-PK,Chopped Romaine 12oz Bag,2800,bags,2026-03-14,FreshCut Processing,MegaMart Distribution Center,0061414100038,0061414100045,Acme Cold Freight,PO-MM-2026-7202,BOL-CFS-2026-0313-003,PACK-FPP-2026-0312-001 -LOT-ROM-2026-0311C-PK,Romaine Hearts 3-Pack Retail,1200,cases,2026-03-13,Coastline Ridge Growers Packhouse,Premier Grocery Warehouse,0061414100021,0061414100052,Coastline Trucking Co,PO-PG-2026-3389,BOL-CFS-2026-0313-004,PACK-FPP-2026-0312-001 diff --git a/sample_data/05_receiving.csv b/sample_data/05_receiving.csv deleted file mode 100644 index 34f3b8599..000000000 --- a/sample_data/05_receiving.csv +++ /dev/null @@ -1,5 +0,0 @@ -traceability_lot_code,product_description,quantity,unit_of_measure,receive_date,receiving_location,receiving_gln,immediate_previous_source,temperature_celsius,reference_document,tlc_source_reference -LOT-ROM-2026-0312A-PK,Organic Romaine Hearts 3ct,800,cases,2026-03-15,MegaMart Distribution Center,0061414100045,FreshCut Processing,3.1,RCV-WFM-2026-0314-001,PACK-FPP-2026-0312-001 -LOT-ROM-2026-0312A-PK,Organic Romaine Hearts 3ct,795,cases,2026-03-15,Premier Grocery Warehouse,0061414100052,FreshCut Processing,3.4,RCV-WFM-2026-0314-002,PACK-FPP-2026-0312-001 -LOT-ROM-2026-0312B-PK,Chopped Romaine 12oz Bag,2780,bags,2026-03-15,MegaMart Distribution Center,0061414100045,FreshCut Processing,2.9,RCV-WFM-2026-0314-003,PACK-FPP-2026-0312-001 -LOT-ROM-2026-0311C-PK,Romaine Hearts 3-Pack Retail,1190,cases,2026-03-14,Premier Grocery Warehouse,0061414100052,Coastline Ridge Growers Packhouse,3.2,RCV-WFM-2026-0314-004,PACK-FPP-2026-0312-001 diff --git a/sample_data/06_transformation.csv b/sample_data/06_transformation.csv deleted file mode 100644 index a262cb563..000000000 --- a/sample_data/06_transformation.csv +++ /dev/null @@ -1,3 +0,0 @@ -traceability_lot_code,product_description,quantity,unit_of_measure,transformation_date,location_name,location_gln,input_lot_codes,reference_document -SALAD-2026-0316-001,Garden Fresh Salad Mix 16oz,3500,bags,2026-03-16,Metro Processing Plant,0061414100069,"LOT-ROM-2026-0312A-PK,LOT-ROM-2026-0312B-PK",TRANS-WFM-2026-0315-001 -SALAD-2026-0316-002,Caesar Romaine Kit 10oz,1800,bags,2026-03-16,Metro Processing Plant,0061414100069,LOT-ROM-2026-0311C-PK,TRANS-WFM-2026-0315-002 diff --git a/sample_data/README.md b/sample_data/README.md deleted file mode 100644 index 466cbe084..000000000 --- a/sample_data/README.md +++ /dev/null @@ -1,16 +0,0 @@ -# RegEngine Sample Data — E2E Ingestion Test - -These CSV files simulate a real multi-supplier romaine lettuce supply chain. -Import them via **Dashboard → Data Import → CSV Upload** in order: - -1. `01_harvesting.csv` — Salinas Valley Farms harvests 3 lots -2. `02_cooling.csv` — Same-day cooling (one event missing cooling_date — will trigger rule failure) -3. `03_initial_packing.csv` — FreshCut Processing packs into retail units -4. `04_shipping.csv` — Ships to 2 retailers -5. `05_receiving.csv` — MegaMart and Premier Grocery receive shipments -6. `06_transformation.csv` — Metro Processing transforms into salad mix - -After import, visit: -- **Dashboard → Compliance** — score should reflect KDE gaps -- **Dashboard → Audit Log** — all events in tamper-evident chain -- **Dashboard → Recall Report** — readiness assessment based on real data diff --git a/sample_data/SYNTHETIC.md b/sample_data/SYNTHETIC.md deleted file mode 100644 index cf079cecc..000000000 --- a/sample_data/SYNTHETIC.md +++ /dev/null @@ -1,3 +0,0 @@ -# Synthetic Data Notice - -All data in this directory is **fully synthetic**. It was generated for demonstration, onboarding, and end-to-end ingestion testing only. Entity names (growers, processors, distributors, retailers, carriers), addresses, GLNs, lot codes, reference document numbers, and any other identifiers are invented and modeled on industry patterns from public FSMA 204 / FDA 21 CFR 1.1455 guidance. None of the records are derived from, attributable to, or otherwise based on any real RegEngine customer, supplier, lot, shipment, or third-party business. Any resemblance to a real registered business is coincidental. diff --git a/sample_data/recall_fixture/3pl_receiving.csv b/sample_data/recall_fixture/3pl_receiving.csv deleted file mode 100644 index e7488c72e..000000000 --- a/sample_data/recall_fixture/3pl_receiving.csv +++ /dev/null @@ -1,8 +0,0 @@ -receipt_id,shipment_ref,pallet_id,location_gln,location_name,received_at,counted_quantity,unit_of_measure,reference_document -RCV-3PL-001,BOL-DC-001,008610001100000010,0861000330005,Bluewater Logistics,2026-08-06T15:00:00Z,60,cases,RCV-3PL-0806-001 -RCV-3PL-002,BOL-DC-001,008610001100000027,0861000330005,Bluewater Logistics,2026-08-06T15:05:00Z,60,cases,RCV-3PL-0806-002 -RCV-3PL-003,BOL-DC-001,008610001100000072,0861000330005,Bluewater Logistics,2026-08-06T15:10:00Z,40,cases,RCV-3PL-0806-003 -RCV-3PL-004,BOL-DC-001,008610001100000096,0861000330005,Bluewater Logistics,2026-08-06T15:15:00Z,30,cases,RCV-3PL-0806-004 -RCV-3PL-005,BOL-DC-002,008610001100000041,0861000330005,Bluewater Logistics,2026-08-06T15:30:00Z,60,cases,RCV-3PL-0806-005 -RCV-3PL-006,BOL-DC-002,008610001100000058,0861000330005,Bluewater Logistics,2026-08-06T15:35:00Z,60,cases,RCV-3PL-0806-006 -RCV-3PL-007,BOL-DC-002,008610001100000089,0861000330005,Bluewater Logistics,2026-08-06T15:40:00Z,20,cases,RCV-3PL-0806-007 diff --git a/sample_data/recall_fixture/3pl_repack.csv b/sample_data/recall_fixture/3pl_repack.csv deleted file mode 100644 index 1d5392d57..000000000 --- a/sample_data/recall_fixture/3pl_repack.csv +++ /dev/null @@ -1,3 +0,0 @@ -record_id,process_type,input_pallet_id,output_pallet_id,lot_code,quantity,unit_of_measure,performed_at,location_gln,location_name,reference_document -REPK-3PL-001,consolidate,008610001100000072,008610001100000102,HLF-215A,40,cases,2026-08-07T10:00:00Z,0861000330005,Bluewater Logistics,WO-3PL-0807-001 -REPK-3PL-001,consolidate,008610001100000089,008610001100000102,HLF-215B,20,cases,2026-08-07T10:00:00Z,0861000330005,Bluewater Logistics,WO-3PL-0807-001 diff --git a/sample_data/recall_fixture/3pl_shipping.csv b/sample_data/recall_fixture/3pl_shipping.csv deleted file mode 100644 index 85fb1b430..000000000 --- a/sample_data/recall_fixture/3pl_shipping.csv +++ /dev/null @@ -1,7 +0,0 @@ -shipment_id,pallet_id,ship_from_gln,ship_from_name,ship_to_gln,ship_to_name,shipped_at,reference_document -BOL-3PL-001,008610001100000010,0861000330005,Bluewater Logistics,0861000440001,Cascade Market DC,2026-08-08T06:00:00Z,BOL-3PL-001.pdf -BOL-3PL-001,008610001100000027,0861000330005,Bluewater Logistics,0861000440001,Cascade Market DC,2026-08-08T06:00:00Z,BOL-3PL-001.pdf -BOL-3PL-001,008610001100000096,0861000330005,Bluewater Logistics,0861000440001,Cascade Market DC,2026-08-08T06:00:00Z,BOL-3PL-001.pdf -BOL-3PL-001,008610001100000041,0861000330005,Bluewater Logistics,0861000440001,Cascade Market DC,2026-08-08T06:00:00Z,BOL-3PL-001.pdf -BOL-3PL-002,008610001100000058,0861000330005,Bluewater Logistics,0861000550007,Summit Foods Warehouse,2026-08-08T06:30:00Z,BOL-3PL-002.pdf -BOL-3PL-002,008610001100000102,0861000330005,Bluewater Logistics,0861000550007,Summit Foods Warehouse,2026-08-08T06:30:00Z,BOL-3PL-002.pdf diff --git a/sample_data/recall_fixture/README.md b/sample_data/recall_fixture/README.md deleted file mode 100644 index 705649588..000000000 --- a/sample_data/recall_fixture/README.md +++ /dev/null @@ -1,71 +0,0 @@ -# Recall Reconstruction Fixture - -A small, fully synthetic scenario for one question: **when a recall names a lot, can RegEngine show where every case went, and say plainly what it cannot show?** - -All names, GLNs, SSCCs, lot codes, and documents are invented (see `../SYNTHETIC.md`). Identifiers carry valid GS1 check digits so they exercise the real validators. - -## The scenario - -One product, two lots, six pallets, four custodians: - -| Party | GLN | Records it holds | -|---|---|---| -| Harborline Foods Plant (manufacturer) | 0861000110003 | lots, pallet build, outbound shipping | -| Northgate Distribution Center (DC, ERP-fed) | 0861000220009 | receiving, repack, outbound shipping | -| Bluewater Logistics (3PL) | 0861000330005 | receiving, repack, outbound shipping | -| Cascade Market DC / Summit Foods Warehouse (destinations) | 0861000440001 / 0861000550007 | receiving | - -Lot **HLF-215A** is the implicated lot (190 cases). **HLF-215B** (140 cases) travels alongside it. - -| Pallet (SSCC) | Built at | Contents | What happens to it | -|---|---|---|---| -| …0010 (P1) | MFG | A 60 | MFG → DC → 3PL → Cascade | -| …0027 (P2) | MFG | A 60 | same; Cascade counts 58 | -| …0034 (P3) | MFG | A 40 + B 20 (mixed) | split at DC into P7 and P8 | -| …0041 (P4) | MFG | B 60 | DC receipt keyed without a BOL; corrected by the recall coordinator with reason and evidence | -| …0058 (P5) | MFG | B 60 | MFG → DC → 3PL → Summit | -| …0065 (P6) | MFG | A 30 | relabelled at DC as P9 (identifier change) | -| …0072 (P7) / …0089 (P8) | DC | A 40 / B 20 | consolidated at the 3PL into P10 | -| …0096 (P9) | DC | A 30 | 3PL → Cascade | -| …0102 (P10) | 3PL | A 40 + B 20 (mixed) | 3PL → Summit | - -Answer key (`answer_key.json`): HLF-215A reaches Cascade (150 cases: P1, P2, P9) and Summit (40 cases: P10). - -## Files - -One CSV per record source. Every row is kept with its file, row number, and file hash, so every conclusion in the output points back to a record. - -- `mfg_lots.csv`, `mfg_pallet_contents.csv`, `mfg_shipping.csv` — manufacturer WMS -- `dc_receiving.csv`, `dc_repack.csv`, `dc_shipping.csv` — DC ERP -- `3pl_receiving.csv`, `3pl_repack.csv`, `3pl_shipping.csv` — 3PL WMS -- `destination_receiving.csv` — destination WMS -- `manual_corrections.csv` — attested corrections (author, reason, evidence required) -- `sync_manifest.json` — per-file hash and per-source last successful synchronization time -- `retained/dc_erp/` — the DC ERP snapshot RegEngine holds, taken before the DC's outbound shipments -- `answer_key.json` — ground truth plus the expected outcome of each case - -## The three runs - -```bash -python3 scripts/run_recall_fixture.py --case all --output-dir /tmp/regengine-recall-fixture -``` - -| Case | What changes | What the worksheet must say | -|---|---|---| -| `complete` | nothing | every row `linked` or `no_link_established`; totals match the answer key; the 2-case shortfall on P2 is reported | -| `missing_3pl_contents` | `3pl_repack.csv` withheld | P10, P7, P8 become `unresolved`; the exact record needed is named (type, custodian, GLN, time window, candidate input pallets); HLF-215A at Summit is *not* reported as zero | -| `erp_unavailable` | DC ERP unreachable; only `retained/dc_erp/` used | the package states the last successful sync time; DC receiving and repacks reproduce exactly; every movement after the cutoff is `unresolved` with the missing shipping record named | - -## Reading the worksheet - -Each row is one (pallet, lot) at its last recorded location, with exactly one label: - -- `linked` — an unbroken evidence chain connects this quantity to the implicated lot. -- `no_link_established` — the chain is complete within the reviewed evidence and no record on it names the implicated lot. This is **not** a statement that product is safe. -- `unresolved` — a required record is missing, conflicting, or was unavailable. Treat as potentially implicated until the named record is obtained. - -Flags `co_palletized_with_implicated_lot` and `lineage_includes_implicated_lot` mark rows a practitioner will want to look at even when the label is `no_link_established`. - -`quantity_asserted` is this lot's share of the pallet. `pallet_quantity_asserted` and `pallet_quantity_counted_at_last_receipt` are whole-pallet figures, because a receiver counts cases on a pallet, not per lot. On a mixed pallet the lot figure is therefore smaller than the pallet count; that is not a discrepancy. A `quantity_discrepancy` finding compares the two pallet columns. - -Excluding product from a recall is a practitioner decision. The engine never makes it. diff --git a/sample_data/recall_fixture/answer_key.json b/sample_data/recall_fixture/answer_key.json deleted file mode 100644 index 0231f171b..000000000 --- a/sample_data/recall_fixture/answer_key.json +++ /dev/null @@ -1,89 +0,0 @@ -{ - "schema": "regengine.recall_fixture.answer_key/1", - "implicated_lot": "HLF-215A", - "ground_truth": { - "product": {"gtin": "00861000110010", "description": "Harborline Cold-Brew Oat Beverage 12x1L", "unit_of_measure": "cases"}, - "parties": { - "0861000110003": "Harborline Foods Plant (manufacturer)", - "0861000220009": "Northgate Distribution Center (DC)", - "0861000330005": "Bluewater Logistics (3PL)", - "0861000440001": "Cascade Market DC (destination A)", - "0861000550007": "Summit Foods Warehouse (destination B)" - }, - "lots": { - "HLF-215A": { - "produced": 190, - "by_destination": { - "0861000440001": {"shipped": 150, "counted": 148, "pallets": ["008610001100000010", "008610001100000027", "008610001100000096"]}, - "0861000550007": {"shipped": 40, "counted": 40, "pallets": ["008610001100000102"]} - } - }, - "HLF-215B": { - "produced": 140, - "by_destination": { - "0861000440001": {"shipped": 60, "counted": 60, "pallets": ["008610001100000041"]}, - "0861000550007": {"shipped": 80, "counted": 80, "pallets": ["008610001100000058", "008610001100000102"]} - } - } - }, - "pallet_lineage": { - "008610001100000072": {"from": ["008610001100000034"], "process": "split at DC"}, - "008610001100000089": {"from": ["008610001100000034"], "process": "split at DC"}, - "008610001100000096": {"from": ["008610001100000065"], "process": "relabel at DC (identifier change)"}, - "008610001100000102": {"from": ["008610001100000072", "008610001100000089"], "process": "consolidate at 3PL (mixed pallet)"} - }, - "known_discrepancies": [ - {"pallet_id": "008610001100000027", "receipt_id": "RCV-CMD-002", "shipped": 60, "counted": 58, "delta": -2} - ], - "known_corrections": [ - {"correction_id": "COR-001", "target": "dc_receiving.csv RCV-DC-004", "field": "shipment_ref", "value": "BOL-MFG-001"} - ] - }, - "case_expectations": { - "complete": { - "forbidden_labels": ["unresolved"], - "expected_labels": { - "008610001100000010|HLF-215A": "linked", - "008610001100000027|HLF-215A": "linked", - "008610001100000096|HLF-215A": "linked", - "008610001100000102|HLF-215A": "linked", - "008610001100000102|HLF-215B": "no_link_established", - "008610001100000041|HLF-215B": "no_link_established", - "008610001100000058|HLF-215B": "no_link_established" - }, - "linked_totals_by_destination": {"HLF-215A": {"0861000440001": 150, "0861000550007": 40}}, - "verify_ground_truth_totals": true, - "expected_finding_types": ["quantity_discrepancy"], - "forbidden_finding_types": ["missing_handoff_shipping", "missing_handoff_receiving", "missing_pallet_contents", "conflicting_pallet_contents", "unmatched_identifier", "source_unavailable_after_cutoff"], - "corrections_applied": ["COR-001"] - }, - "missing_3pl_contents": { - "unresolved_pallets": ["008610001100000102", "008610001100000072", "008610001100000089"], - "expected_labels": { - "008610001100000010|HLF-215A": "linked", - "008610001100000027|HLF-215A": "linked", - "008610001100000096|HLF-215A": "linked", - "008610001100000041|HLF-215B": "no_link_established", - "008610001100000058|HLF-215B": "no_link_established", - "008610001100000102|": "unresolved" - }, - "linked_totals_by_destination": {"HLF-215A": {"0861000440001": 150}}, - "expected_finding_types": ["missing_pallet_contents", "quantity_discrepancy"], - "forbidden_finding_types": ["missing_handoff_shipping", "missing_handoff_receiving", "conflicting_pallet_contents", "unmatched_identifier"], - "required_record_mentions": { - "008610001100000102": ["pallet contents or repack record", "Bluewater Logistics", "0861000330005", "2026-08-06T15:40:00+00:00", "2026-08-08T06:30:00+00:00", "008610001100000072", "008610001100000089"] - }, - "corrections_applied": ["COR-001"] - }, - "erp_unavailable": { - "cutoffs": {"dc_erp": "2026-08-05T12:00:00Z"}, - "forbidden_labels": ["linked", "no_link_established"], - "expected_finding_types": ["missing_handoff_shipping", "source_unavailable_after_cutoff", "quantity_discrepancy"], - "forbidden_finding_types": ["missing_pallet_contents", "conflicting_pallet_contents", "unmatched_identifier"], - "required_record_mentions": { - "008610001100000010": ["shipping record", "Northgate Distribution Center", "0861000220009", "BOL-DC-001", "dc_erp"] - }, - "corrections_applied": ["COR-001"] - } - } -} diff --git a/sample_data/recall_fixture/dc_receiving.csv b/sample_data/recall_fixture/dc_receiving.csv deleted file mode 100644 index c0a4ac211..000000000 --- a/sample_data/recall_fixture/dc_receiving.csv +++ /dev/null @@ -1,7 +0,0 @@ -receipt_id,shipment_ref,pallet_id,location_gln,location_name,received_at,counted_quantity,unit_of_measure,reference_document -RCV-DC-001,BOL-MFG-001,008610001100000010,0861000220009,Northgate Distribution Center,2026-08-04T16:00:00Z,60,cases,RCV-DC-0804-001 -RCV-DC-002,BOL-MFG-001,008610001100000027,0861000220009,Northgate Distribution Center,2026-08-04T16:05:00Z,60,cases,RCV-DC-0804-002 -RCV-DC-003,BOL-MFG-001,008610001100000034,0861000220009,Northgate Distribution Center,2026-08-04T16:10:00Z,60,cases,RCV-DC-0804-003 -RCV-DC-004,,008610001100000041,0861000220009,Northgate Distribution Center,2026-08-04T16:15:00Z,60,cases,RCV-DC-0804-004 -RCV-DC-005,BOL-MFG-001,008610001100000058,0861000220009,Northgate Distribution Center,2026-08-04T16:20:00Z,60,cases,RCV-DC-0804-005 -RCV-DC-006,BOL-MFG-001,008610001100000065,0861000220009,Northgate Distribution Center,2026-08-04T16:25:00Z,30,cases,RCV-DC-0804-006 diff --git a/sample_data/recall_fixture/dc_repack.csv b/sample_data/recall_fixture/dc_repack.csv deleted file mode 100644 index 7ddab690a..000000000 --- a/sample_data/recall_fixture/dc_repack.csv +++ /dev/null @@ -1,4 +0,0 @@ -record_id,process_type,input_pallet_id,output_pallet_id,lot_code,quantity,unit_of_measure,performed_at,location_gln,location_name,reference_document -REPK-DC-001,split,008610001100000034,008610001100000072,HLF-215A,40,cases,2026-08-05T09:00:00Z,0861000220009,Northgate Distribution Center,WO-DC-0805-001 -REPK-DC-001,split,008610001100000034,008610001100000089,HLF-215B,20,cases,2026-08-05T09:00:00Z,0861000220009,Northgate Distribution Center,WO-DC-0805-001 -REPK-DC-002,relabel,008610001100000065,008610001100000096,HLF-215A,30,cases,2026-08-05T09:30:00Z,0861000220009,Northgate Distribution Center,WO-DC-0805-002 diff --git a/sample_data/recall_fixture/dc_shipping.csv b/sample_data/recall_fixture/dc_shipping.csv deleted file mode 100644 index 5024697f8..000000000 --- a/sample_data/recall_fixture/dc_shipping.csv +++ /dev/null @@ -1,8 +0,0 @@ -shipment_id,pallet_id,ship_from_gln,ship_from_name,ship_to_gln,ship_to_name,shipped_at,reference_document -BOL-DC-001,008610001100000010,0861000220009,Northgate Distribution Center,0861000330005,Bluewater Logistics,2026-08-06T07:00:00Z,BOL-DC-001.pdf -BOL-DC-001,008610001100000027,0861000220009,Northgate Distribution Center,0861000330005,Bluewater Logistics,2026-08-06T07:00:00Z,BOL-DC-001.pdf -BOL-DC-001,008610001100000072,0861000220009,Northgate Distribution Center,0861000330005,Bluewater Logistics,2026-08-06T07:00:00Z,BOL-DC-001.pdf -BOL-DC-001,008610001100000096,0861000220009,Northgate Distribution Center,0861000330005,Bluewater Logistics,2026-08-06T07:00:00Z,BOL-DC-001.pdf -BOL-DC-002,008610001100000041,0861000220009,Northgate Distribution Center,0861000330005,Bluewater Logistics,2026-08-06T07:30:00Z,BOL-DC-002.pdf -BOL-DC-002,008610001100000058,0861000220009,Northgate Distribution Center,0861000330005,Bluewater Logistics,2026-08-06T07:30:00Z,BOL-DC-002.pdf -BOL-DC-002,008610001100000089,0861000220009,Northgate Distribution Center,0861000330005,Bluewater Logistics,2026-08-06T07:30:00Z,BOL-DC-002.pdf diff --git a/sample_data/recall_fixture/destination_receiving.csv b/sample_data/recall_fixture/destination_receiving.csv deleted file mode 100644 index 9e5ed1725..000000000 --- a/sample_data/recall_fixture/destination_receiving.csv +++ /dev/null @@ -1,7 +0,0 @@ -receipt_id,shipment_ref,pallet_id,location_gln,location_name,received_at,counted_quantity,unit_of_measure,reference_document -RCV-CMD-001,BOL-3PL-001,008610001100000010,0861000440001,Cascade Market DC,2026-08-08T18:00:00Z,60,cases,RCV-CMD-0808-001 -RCV-CMD-002,BOL-3PL-001,008610001100000027,0861000440001,Cascade Market DC,2026-08-08T18:05:00Z,58,cases,RCV-CMD-0808-002 -RCV-CMD-003,BOL-3PL-001,008610001100000096,0861000440001,Cascade Market DC,2026-08-08T18:10:00Z,30,cases,RCV-CMD-0808-003 -RCV-CMD-004,BOL-3PL-001,008610001100000041,0861000440001,Cascade Market DC,2026-08-08T18:15:00Z,60,cases,RCV-CMD-0808-004 -RCV-SFW-001,BOL-3PL-002,008610001100000058,0861000550007,Summit Foods Warehouse,2026-08-08T19:00:00Z,60,cases,RCV-SFW-0808-001 -RCV-SFW-002,BOL-3PL-002,008610001100000102,0861000550007,Summit Foods Warehouse,2026-08-08T19:05:00Z,60,cases,RCV-SFW-0808-002 diff --git a/sample_data/recall_fixture/manual_corrections.csv b/sample_data/recall_fixture/manual_corrections.csv deleted file mode 100644 index 9d60444f8..000000000 --- a/sample_data/recall_fixture/manual_corrections.csv +++ /dev/null @@ -1,2 +0,0 @@ -correction_id,target_file,target_record_id,field,value,author,reason,evidence_ref,asserted_at -COR-001,dc_receiving.csv,RCV-DC-004,shipment_ref,BOL-MFG-001,J. Alvarez (recall coordinator),DC receipt RCV-DC-004 was keyed without a BOL reference; the signed BOL scan lists pallet 008610001100000041 on BOL-MFG-001 and the receipt time matches the other five pallets on that BOL,BOL-MFG-001.pdf page 1 line 4,2026-08-20T17:10:00Z diff --git a/sample_data/recall_fixture/mfg_lots.csv b/sample_data/recall_fixture/mfg_lots.csv deleted file mode 100644 index 81850ce00..000000000 --- a/sample_data/recall_fixture/mfg_lots.csv +++ /dev/null @@ -1,3 +0,0 @@ -lot_code,gtin,product_description,quantity,unit_of_measure,produced_at,location_gln,location_name,reference_document -HLF-215A,00861000110010,Harborline Cold-Brew Oat Beverage 12x1L,190,cases,2026-08-03T11:00:00Z,0861000110003,Harborline Foods Plant,BATCH-215A -HLF-215B,00861000110010,Harborline Cold-Brew Oat Beverage 12x1L,140,cases,2026-08-03T12:30:00Z,0861000110003,Harborline Foods Plant,BATCH-215B diff --git a/sample_data/recall_fixture/mfg_pallet_contents.csv b/sample_data/recall_fixture/mfg_pallet_contents.csv deleted file mode 100644 index eb0cb8eba..000000000 --- a/sample_data/recall_fixture/mfg_pallet_contents.csv +++ /dev/null @@ -1,8 +0,0 @@ -record_id,pallet_id,lot_code,quantity,unit_of_measure,recorded_at,location_gln,location_name,reference_document -PLT-MFG-001,008610001100000010,HLF-215A,60,cases,2026-08-03T14:00:00Z,0861000110003,Harborline Foods Plant,PALLET-BUILD-0803-01 -PLT-MFG-002,008610001100000027,HLF-215A,60,cases,2026-08-03T14:05:00Z,0861000110003,Harborline Foods Plant,PALLET-BUILD-0803-02 -PLT-MFG-003,008610001100000034,HLF-215A,40,cases,2026-08-03T14:10:00Z,0861000110003,Harborline Foods Plant,PALLET-BUILD-0803-03 -PLT-MFG-003,008610001100000034,HLF-215B,20,cases,2026-08-03T14:10:00Z,0861000110003,Harborline Foods Plant,PALLET-BUILD-0803-03 -PLT-MFG-004,008610001100000041,HLF-215B,60,cases,2026-08-03T14:15:00Z,0861000110003,Harborline Foods Plant,PALLET-BUILD-0803-04 -PLT-MFG-005,008610001100000058,HLF-215B,60,cases,2026-08-03T14:20:00Z,0861000110003,Harborline Foods Plant,PALLET-BUILD-0803-05 -PLT-MFG-006,008610001100000065,HLF-215A,30,cases,2026-08-03T14:25:00Z,0861000110003,Harborline Foods Plant,PALLET-BUILD-0803-06 diff --git a/sample_data/recall_fixture/mfg_shipping.csv b/sample_data/recall_fixture/mfg_shipping.csv deleted file mode 100644 index 2df5771da..000000000 --- a/sample_data/recall_fixture/mfg_shipping.csv +++ /dev/null @@ -1,7 +0,0 @@ -shipment_id,pallet_id,ship_from_gln,ship_from_name,ship_to_gln,ship_to_name,shipped_at,reference_document -BOL-MFG-001,008610001100000010,0861000110003,Harborline Foods Plant,0861000220009,Northgate Distribution Center,2026-08-04T08:00:00Z,BOL-MFG-001.pdf -BOL-MFG-001,008610001100000027,0861000110003,Harborline Foods Plant,0861000220009,Northgate Distribution Center,2026-08-04T08:00:00Z,BOL-MFG-001.pdf -BOL-MFG-001,008610001100000034,0861000110003,Harborline Foods Plant,0861000220009,Northgate Distribution Center,2026-08-04T08:00:00Z,BOL-MFG-001.pdf -BOL-MFG-001,008610001100000041,0861000110003,Harborline Foods Plant,0861000220009,Northgate Distribution Center,2026-08-04T08:00:00Z,BOL-MFG-001.pdf -BOL-MFG-001,008610001100000058,0861000110003,Harborline Foods Plant,0861000220009,Northgate Distribution Center,2026-08-04T08:00:00Z,BOL-MFG-001.pdf -BOL-MFG-001,008610001100000065,0861000110003,Harborline Foods Plant,0861000220009,Northgate Distribution Center,2026-08-04T08:00:00Z,BOL-MFG-001.pdf diff --git a/sample_data/recall_fixture/retained/dc_erp/dc_receiving.csv b/sample_data/recall_fixture/retained/dc_erp/dc_receiving.csv deleted file mode 100644 index c0a4ac211..000000000 --- a/sample_data/recall_fixture/retained/dc_erp/dc_receiving.csv +++ /dev/null @@ -1,7 +0,0 @@ -receipt_id,shipment_ref,pallet_id,location_gln,location_name,received_at,counted_quantity,unit_of_measure,reference_document -RCV-DC-001,BOL-MFG-001,008610001100000010,0861000220009,Northgate Distribution Center,2026-08-04T16:00:00Z,60,cases,RCV-DC-0804-001 -RCV-DC-002,BOL-MFG-001,008610001100000027,0861000220009,Northgate Distribution Center,2026-08-04T16:05:00Z,60,cases,RCV-DC-0804-002 -RCV-DC-003,BOL-MFG-001,008610001100000034,0861000220009,Northgate Distribution Center,2026-08-04T16:10:00Z,60,cases,RCV-DC-0804-003 -RCV-DC-004,,008610001100000041,0861000220009,Northgate Distribution Center,2026-08-04T16:15:00Z,60,cases,RCV-DC-0804-004 -RCV-DC-005,BOL-MFG-001,008610001100000058,0861000220009,Northgate Distribution Center,2026-08-04T16:20:00Z,60,cases,RCV-DC-0804-005 -RCV-DC-006,BOL-MFG-001,008610001100000065,0861000220009,Northgate Distribution Center,2026-08-04T16:25:00Z,30,cases,RCV-DC-0804-006 diff --git a/sample_data/recall_fixture/retained/dc_erp/dc_repack.csv b/sample_data/recall_fixture/retained/dc_erp/dc_repack.csv deleted file mode 100644 index 7ddab690a..000000000 --- a/sample_data/recall_fixture/retained/dc_erp/dc_repack.csv +++ /dev/null @@ -1,4 +0,0 @@ -record_id,process_type,input_pallet_id,output_pallet_id,lot_code,quantity,unit_of_measure,performed_at,location_gln,location_name,reference_document -REPK-DC-001,split,008610001100000034,008610001100000072,HLF-215A,40,cases,2026-08-05T09:00:00Z,0861000220009,Northgate Distribution Center,WO-DC-0805-001 -REPK-DC-001,split,008610001100000034,008610001100000089,HLF-215B,20,cases,2026-08-05T09:00:00Z,0861000220009,Northgate Distribution Center,WO-DC-0805-001 -REPK-DC-002,relabel,008610001100000065,008610001100000096,HLF-215A,30,cases,2026-08-05T09:30:00Z,0861000220009,Northgate Distribution Center,WO-DC-0805-002 diff --git a/sample_data/recall_fixture/sync_manifest.json b/sample_data/recall_fixture/sync_manifest.json deleted file mode 100644 index 5e2d51b44..000000000 --- a/sample_data/recall_fixture/sync_manifest.json +++ /dev/null @@ -1,91 +0,0 @@ -{ - "files": { - "3pl_receiving.csv": { - "sha256": "d2fccf5bc85c8088d2a885acacdc373eb3cf963bdd7a1b249aea3cda7ee7e7dd", - "source_system": "3pl_wms", - "synced_at": "2026-08-20T16:05:00Z" - }, - "3pl_repack.csv": { - "sha256": "678de9d48dd542761e781e229530cb1b5d874144b68526de0845a3ea81f87350", - "source_system": "3pl_wms", - "synced_at": "2026-08-20T16:05:00Z" - }, - "3pl_shipping.csv": { - "sha256": "74c60a25b04a1147ba47521d493356daef6ccc162bf023fbb3ffb47990ad0440", - "source_system": "3pl_wms", - "synced_at": "2026-08-20T16:05:00Z" - }, - "dc_receiving.csv": { - "sha256": "bc1cc2a7a90992407407773d4b8ecc632d13284dc793b7cd7c1f1def75045f7a", - "source_system": "dc_erp", - "synced_at": "2026-08-20T16:02:00Z" - }, - "dc_repack.csv": { - "sha256": "5941b37a7b489194d4cad3e46453628a03ed0255d579c937c7a57a8e31a1244c", - "source_system": "dc_erp", - "synced_at": "2026-08-20T16:02:00Z" - }, - "dc_shipping.csv": { - "sha256": "a144531f9e0c2637334481ef243ca638393ff72c9270c9fdddf9123dc25d6cee", - "source_system": "dc_erp", - "synced_at": "2026-08-20T16:02:00Z" - }, - "destination_receiving.csv": { - "sha256": "5475e3a7192a1042735935dbf2c72b5c575eca25d4e4b7646404b47bf98fc4ce", - "source_system": "destination_wms", - "synced_at": "2026-08-20T16:10:00Z" - }, - "manual_corrections.csv": { - "sha256": "0ce60093c2d5e06d56edc97778e44b8f48c2ed278745df0fd475c6276e0ebd92", - "source_system": "recall_team", - "synced_at": "2026-08-20T17:10:00Z" - }, - "mfg_lots.csv": { - "sha256": "e82083cad40e6f0f5f3bb945ec9c12a7fecf447b3c3e60928440609ae7455aa7", - "source_system": "mfg_wms", - "synced_at": "2026-08-20T16:00:00Z" - }, - "mfg_pallet_contents.csv": { - "sha256": "02c55f2675c9b442dd15f25cd224d5bfc6c213f6b5d87d00574f3b7596d1e6c6", - "source_system": "mfg_wms", - "synced_at": "2026-08-20T16:00:00Z" - }, - "mfg_shipping.csv": { - "sha256": "cfd873efb90e0e08fcc45d4b967dbfca17ab7d6cbf6cd0af96bb28154f761e4f", - "source_system": "mfg_wms", - "synced_at": "2026-08-20T16:00:00Z" - } - }, - "retained_sha256": { - "retained/dc_erp/dc_receiving.csv": "bc1cc2a7a90992407407773d4b8ecc632d13284dc793b7cd7c1f1def75045f7a", - "retained/dc_erp/dc_repack.csv": "5941b37a7b489194d4cad3e46453628a03ed0255d579c937c7a57a8e31a1244c" - }, - "schema": "regengine.recall_fixture.sync_manifest/1", - "sources": { - "3pl_wms": { - "custodian": "Bluewater Logistics", - "last_successful_sync_at": "2026-08-20T16:05:00Z" - }, - "dc_erp": { - "custodian": "Northgate Distribution Center", - "last_successful_sync_at": "2026-08-05T12:00:00Z", - "note": "Retained snapshot taken 2026-08-05T12:00:00Z, after DC receiving and repack and before DC outbound shipping. In the erp_unavailable case only this snapshot is used.", - "retained_files": [ - "retained/dc_erp/dc_receiving.csv", - "retained/dc_erp/dc_repack.csv" - ] - }, - "destination_wms": { - "custodian": "Cascade Market DC / Summit Foods Warehouse", - "last_successful_sync_at": "2026-08-20T16:10:00Z" - }, - "mfg_wms": { - "custodian": "Harborline Foods Plant", - "last_successful_sync_at": "2026-08-20T16:00:00Z" - }, - "recall_team": { - "custodian": "RegEngine recall coordinator", - "last_successful_sync_at": "2026-08-20T17:10:00Z" - } - } -} diff --git a/scripts/ci/build_registry_seed.py b/scripts/ci/build_registry_seed.py index 29987cadb..4237154db 100644 --- a/scripts/ci/build_registry_seed.py +++ b/scripts/ci/build_registry_seed.py @@ -72,7 +72,6 @@ def _short_hex(s: str) -> str: "services/ingestion/tests/test_supplier_portal_1342.py": ("real-defect", "RC-014", "open", "anvil", "per-link rate limiting not enforced"), "tests/migrations/test_destructive_downgrade_documented_2827.py": ("real-defect", "RC-015", "open", "anvil", "v116 destroys rows without acknowledgement guard"), "tests/migrations/test_migration_fresh_db.py": ("real-defect", "RC-016", "open", "anvil", "policy resolver gap"), - "tests/scripts/test_regenerate_public_samples_gate.py": ("real-defect", "RC-017", "open", "anvil", "workflow yaml drift after lock policy change"), "tests/scripts/test_export_env_bundle_no_disk_secrets.py": ("real-defect", "RC-018", "open", "anvil", "script named for what it doesn't do; rename"), "services/scheduler/tests/test_deadline_monitor_2908.py": ("real-defect", "RC-019", "open", "anvil", "#2908 hardening constants/registration not on tree"), } diff --git a/scripts/demo_mvp_flow.sh b/scripts/demo_mvp_flow.sh deleted file mode 100755 index dcf6cca51..000000000 --- a/scripts/demo_mvp_flow.sh +++ /dev/null @@ -1,220 +0,0 @@ -#!/usr/bin/env bash -# -# RegEngine MVP Demo — End-to-End Data Flow -# -# Demonstrates the core value proposition in under 5 minutes: -# CSV upload → ingestion → normalization → rule evaluation → FDA export -# -# Prerequisites: -# docker compose up -d postgres redis admin-api ingestion-service -# Wait for health checks to pass -# -# Usage: -# ./scripts/demo_mvp_flow.sh [API_KEY] -# -# If no API_KEY is provided, REGENGINE_API_KEY must already contain a scoped, -# tenant-bound credential provisioned by an authorized staff user. - -set -euo pipefail - -# ── Config ────────────────────────────────────────────────────────────────── -ADMIN_URL="${ADMIN_URL:-http://localhost:8400}" -INGEST_URL="${INGEST_URL:-http://localhost:8002}" # matches docker-compose.yml port mapping -API_KEY="${1:-}" -TENANT_ID="${TENANT_ID:-00000000-0000-0000-0000-000000000001}" -SAMPLE_DIR="$(cd "$(dirname "$0")/../sample_data" && pwd)" -EXPORT_DIR="$(cd "$(dirname "$0")/.." && pwd)/demo_exports" - -# Colors -G='\033[0;32m' Y='\033[1;33m' B='\033[0;34m' R='\033[0;31m' C='\033[0;36m' NC='\033[0m' - -header() { echo -e "\n${B}━━━ $1 ━━━${NC}"; } -ok() { echo -e " ${G}✓${NC} $1"; } -fail() { echo -e " ${R}✗${NC} $1"; } -info() { echo -e " ${C}→${NC} $1"; } - -echo -e "${B}╔══════════════════════════════════════════════════════════╗${NC}" -echo -e "${B}║ RegEngine MVP Demo — CSV to FDA Export in 5 Minutes ║${NC}" -echo -e "${B}╚══════════════════════════════════════════════════════════╝${NC}" - -# ── Step 0: Health checks ─────────────────────────────────────────────────── -header "Step 0 · Checking service health" - -for svc in "$ADMIN_URL/health|Admin" "$INGEST_URL/health|Ingestion"; do - url="${svc%%|*}" - name="${svc##*|}" - if curl -sf "$url" > /dev/null 2>&1; then - ok "$name service healthy" - else - fail "$name service not responding at $url" - echo -e " ${Y}Start services first: docker compose up -d postgres redis admin-api ingestion-service${NC}" - exit 1 - fi -done - -# ── Step 1: Load the pre-provisioned API key ──────────────────────────────── -header "Step 1 · Authentication" - -if [ -z "$API_KEY" ]; then - # Try REGENGINE_API_KEY env var first (matches docker-compose env) - API_KEY="${REGENGINE_API_KEY:-}" -fi - -if [ -z "$API_KEY" ]; then - echo -e " ${Y}No API_KEY or REGENGINE_API_KEY provided.${NC}" - echo -e " ${Y}Usage: ./scripts/demo_mvp_flow.sh ${NC}" - echo -e " ${Y}An authorized staff user must provision this credential first.${NC}" - exit 1 -else - ok "Using API key: ${API_KEY:0:8}..." -fi - -# ── Step 2: Ingest sample supply chain data ───────────────────────────────── -header "Step 2 · Ingesting supply chain data (6 CSV files)" - -INGEST_COUNT=0 -INGEST_ERRORS=0 - -for csv in "$SAMPLE_DIR"/*.csv; do - filename=$(basename "$csv") - step_name="${filename%.csv}" - # Map CSV filenames to FSMA 204 CTE types (strip numeric prefix) - step_cte="${step_name#[0-9][0-9]_}" - - RESPONSE=$(curl -sf -X POST "$INGEST_URL/api/v1/ingest/csv" \ - -H "X-RegEngine-API-Key: $API_KEY" \ - -F "file=@$csv" \ - -F "source=mvp-demo" \ - -F "tenant_id=$TENANT_ID" \ - -F "cte_type=$step_cte" \ - 2>/dev/null || echo '{"error": "request failed"}') - - # Parse batch response: {"accepted": N, "rejected": M, "total": T, "events": [...]} - ACCEPTED=$(echo "$RESPONSE" | python3 -c "import sys, json; d=json.load(sys.stdin); print(d.get('accepted', 0))" 2>/dev/null || echo "0") - TOTAL=$(echo "$RESPONSE" | python3 -c "import sys, json; d=json.load(sys.stdin); print(d.get('total', 0))" 2>/dev/null || echo "0") - - if [ "$ACCEPTED" -gt 0 ] 2>/dev/null; then - ok "$step_name ($step_cte) — $ACCEPTED/$TOTAL events ingested" - INGEST_COUNT=$((INGEST_COUNT + ACCEPTED)) - if [ "$ACCEPTED" -lt "$TOTAL" ]; then - REJECTED_N=$((TOTAL - ACCEPTED)) - info "$REJECTED_N events rejected (missing KDEs or validation errors)" - INGEST_ERRORS=$((INGEST_ERRORS + REJECTED_N)) - fi - else - fail "$step_name — 0/$TOTAL accepted" - info "Response: $(echo "$RESPONSE" | head -c 200)" - INGEST_ERRORS=$((INGEST_ERRORS + TOTAL)) - fi -done - -echo "" -info "Ingested: $INGEST_COUNT files, Errors: $INGEST_ERRORS" - -if [ "$INGEST_COUNT" -eq 0 ]; then - fail "All ingestions failed. Check API key permissions and service logs." - exit 1 -fi - -# ── Step 3: Export FDA-oriented package ──────────────────────────────────────── -header "Step 3 · Generating FDA-oriented export" - -mkdir -p "$EXPORT_DIR" -TIMESTAMP=$(date +%Y%m%d_%H%M%S) -EXPORT_FILE="$EXPORT_DIR/fda_export_demo_${TIMESTAMP}.csv" -TLC="LOT-ROM-2026-0312A" - -info "Requesting FDA export for lot: $TLC" - -HTTP_CODE=$(curl -sf -o "$EXPORT_FILE" -w "%{http_code}" \ - "$INGEST_URL/api/v1/fda/export?tlc=$TLC&tenant_id=$TENANT_ID&format=csv" \ - -H "X-RegEngine-API-Key: $API_KEY" \ - 2>/dev/null || echo "000") - -if [ "$HTTP_CODE" = "200" ] && [ -s "$EXPORT_FILE" ]; then - LINES=$(wc -l < "$EXPORT_FILE" | tr -d ' ') - SIZE=$(du -h "$EXPORT_FILE" | cut -f1) - ok "FDA export generated: $EXPORT_FILE" - info "Records: $((LINES - 1)), Size: $SIZE" - - # Show first few columns of the export - echo "" - info "Preview (first 3 records):" - head -4 "$EXPORT_FILE" | column -t -s',' 2>/dev/null | head -4 | while read -r line; do - echo -e " ${C}${line:0:120}${NC}" - done -else - fail "FDA export failed (HTTP $HTTP_CODE)" - info "Trying export/all as fallback..." - - HTTP_CODE=$(curl -sf -o "$EXPORT_FILE" -w "%{http_code}" \ - "$INGEST_URL/api/v1/fda/export/all?tenant_id=$TENANT_ID&format=csv" \ - -H "X-RegEngine-API-Key: $API_KEY" \ - 2>/dev/null || echo "000") - - if [ "$HTTP_CODE" = "200" ] && [ -s "$EXPORT_FILE" ]; then - LINES=$(wc -l < "$EXPORT_FILE" | tr -d ' ') - ok "FDA export (all events): $EXPORT_FILE ($((LINES - 1)) records)" - else - fail "Export failed. Check service logs: docker compose logs ingestion-service" - fi -fi - -# ── Step 4: Export with compliance status (v2) ────────────────────────────── -header "Step 4 · Compliance-checked export (enforcement layer)" - -EXPORT_V2="$EXPORT_DIR/fda_export_v2_demo_${TIMESTAMP}.csv" - -HTTP_CODE=$(curl -sf -o "$EXPORT_V2" -w "%{http_code}" \ - "$INGEST_URL/api/v1/fda/export/v2?tlc=$TLC&tenant_id=$TENANT_ID&format=csv" \ - -H "X-RegEngine-API-Key: $API_KEY" \ - 2>/dev/null || echo "000") - -if [ "$HTTP_CODE" = "200" ] && [ -s "$EXPORT_V2" ]; then - LINES=$(wc -l < "$EXPORT_V2" | tr -d ' ') - ok "Compliance export generated: $EXPORT_V2" - info "Records: $((LINES - 1)) (includes Compliance Status + Rule Failures columns)" -else - info "v2 export returned HTTP $HTTP_CODE — may need rule engine configuration" -fi - -# ── Step 5: Verify chain integrity ────────────────────────────────────────── -header "Step 5 · Chain integrity verification" - -VERIFY_RESPONSE=$(curl -sf "$INGEST_URL/api/v1/fda/export/all?tenant_id=$TENANT_ID&format=csv" \ - -H "X-RegEngine-API-Key: $API_KEY" \ - -D - -o /dev/null 2>/dev/null || echo "") - -CHAIN_STATUS=$(echo "$VERIFY_RESPONSE" | grep -i "X-Chain-Integrity" | tr -d '\r' | awk '{print $2}') -RECORD_COUNT=$(echo "$VERIFY_RESPONSE" | grep -i "X-Record-Count" | tr -d '\r' | awk '{print $2}') -KDE_COVERAGE=$(echo "$VERIFY_RESPONSE" | grep -i "X-KDE-Coverage" | tr -d '\r' | awk '{print $2}') - -if [ -n "$CHAIN_STATUS" ]; then - ok "Chain integrity: $CHAIN_STATUS" - [ -n "$RECORD_COUNT" ] && info "Records in chain: $RECORD_COUNT" - [ -n "$KDE_COVERAGE" ] && info "KDE coverage: $KDE_COVERAGE" -else - info "Chain verification headers not returned — check export endpoint" -fi - -# ── Summary ───────────────────────────────────────────────────────────────── -echo "" -echo -e "${B}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}" -echo -e "${G}Demo Complete${NC}" -echo "" -echo -e " ${G}What just happened:${NC}" -echo -e " 1. Uploaded 6 supply chain CSVs (harvest → cool → pack → ship → receive → transform)" -echo -e " 2. Each event was normalized, hashed (SHA-256), and stored with chain linkage" -echo -e " 3. Generated an FDA-oriented export with full traceability for lot $TLC" -echo -e " 4. Checked compliance status against FSMA 204 rules" -echo -e " 5. Verified cryptographic chain integrity" -echo "" -echo -e " ${C}Export files:${NC}" -[ -f "$EXPORT_FILE" ] && echo -e " $EXPORT_FILE" -[ -f "$EXPORT_V2" ] && echo -e " $EXPORT_V2" -echo "" -echo -e " ${C}Next steps:${NC}" -echo -e " • Open the FDA export CSV and verify the chain of custody" -echo -e " • Try the same flow via the web UI at http://localhost:3000" -echo -e " • Run with your own CSV data to see how it handles real-world messiness" -echo -e "${B}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}" diff --git a/scripts/regenerate_public_samples.py b/scripts/regenerate_public_samples.py deleted file mode 100644 index 8e2fa5753..000000000 --- a/scripts/regenerate_public_samples.py +++ /dev/null @@ -1,365 +0,0 @@ -#!/usr/bin/env python3 -"""Regenerate public sample exports from the synthetic CTE source CSVs. - -This script is the source of truth for the artifacts under ``demo_exports/`` -that get promoted to RegEngine's public Proof Surface. It must be: - -* **Deterministic** — same inputs in ``sample_data/`` always produce - identical bytes in ``demo_exports/``. CI uses ``git diff --exit-code`` - on the output to catch silent drift between the public sample and - current production behavior. -* **Idempotent** — re-running with no input changes is a no-op. -* **Pure-Python** — no live database, no network, no test fixtures. - All inputs are the synthetic CSVs already on disk. - -The three artifacts produced are: - -1. ``sample_fda_export.csv`` — FDA 21 CFR 1.1455 sortable spreadsheet - generated by the production - :func:`services.ingestion.app.fda_export_service._generate_csv` - helper. This is the same code path the ``/api/v1/export/fda`` route - uses to serialize CTE events. -2. ``sample_epcis.json`` — GS1 EPCIS 2.0 JSON-LD bundle, built using the - production CTE-to-bizStep mapping in - :mod:`services.ingestion.app.epcis_export`. -3. ``sample_audit_bundle.json`` — Per-event SHA-256 record hashes, the - chain hash sequence, and a Merkle root computed by - :func:`services.shared.merkle_tree.compute_merkle_root`. - -Production-code parity matters: if FDA columns change or the EPCIS -bizStep map changes, the regenerator picks the new behavior up -automatically and the CI diff trips, forcing the public sample to be -re-committed in the same PR. That keeps the Proof Surface honest. - -If the script cannot import the production helpers (e.g. CI environment -without service deps installed), it exits 0 with a warning rather than -failing. The audit + ``SYNTHETIC.md`` notes are the must-have part; the -end-to-end regeneration is best-effort. -""" - -from __future__ import annotations - -import csv -import hashlib -import json -import logging -import sys -from datetime import datetime, timezone -from pathlib import Path - -logger = logging.getLogger("regenerate_public_samples") -logging.basicConfig(level=logging.INFO, format="%(message)s") - -# --------------------------------------------------------------------------- -# Paths -# --------------------------------------------------------------------------- -REPO_ROOT = Path(__file__).resolve().parent.parent -SAMPLE_DIR = REPO_ROOT / "sample_data" -EXPORT_DIR = REPO_ROOT / "demo_exports" - -# Fixed-seed test tenant id (UUID5 over a stable name) so the script is -# reproducible. Not a real tenant in any environment. -DEMO_TENANT_ID = "00000000-0000-4000-8000-0000000000d1" - -# Frozen "generated_at" timestamp baked into the artifacts. Using a -# fixed value keeps the output bytes identical across runs — required -# for the CI ``git diff --exit-code`` drift check. -FROZEN_TIMESTAMP = "2026-01-01T00:00:00+00:00" - - -# --------------------------------------------------------------------------- -# Production-code import shim -# --------------------------------------------------------------------------- -def _try_import_production_helpers(): - """Try to import the FDA / EPCIS / Merkle helpers from the services tree. - - Returns ``(generate_csv, cte_to_bizstep, compute_merkle_root)`` on - success, or ``None`` if any import fails. Mirrors the sys.path setup - in ``services/ingestion/conftest.py`` so the relative imports inside - ``app/`` resolve. - """ - services_ingestion = REPO_ROOT / "services" / "ingestion" - services_dir = REPO_ROOT / "services" - for p in (services_ingestion, services_dir, REPO_ROOT): - sp = str(p) - if sp not in sys.path: - sys.path.insert(0, sp) - - try: - # Import order matters: fda_export_service pulls in - # ``shared.fda_export`` and ``app.shared.csv_safety`` which both - # need to be on sys.path before this line. - from app.epcis_export import _CTE_TO_BIZSTEP # type: ignore - from app.fda_export_service import _generate_csv # type: ignore - from shared.merkle_tree import compute_merkle_root # type: ignore - except Exception as exc: # noqa: BLE001 — best-effort import - logger.warning( - "regenerate_public_samples: production helpers unavailable (%s); " - "skipping regeneration. The audit + SYNTHETIC.md notes are the " - "must-have part. TODO: requires test fixture tenant", - exc, - ) - return None - - return _generate_csv, _CTE_TO_BIZSTEP, compute_merkle_root - - -# --------------------------------------------------------------------------- -# Source CSV → CTE event dict -# --------------------------------------------------------------------------- -# Map each source CSV filename to the CTE event_type and the KDE column -# names it carries. Mirrors the production WebhookCTEType taxonomy. -_SOURCE_FILES = [ - ("01_harvesting.csv", "harvesting"), - ("02_cooling.csv", "cooling"), - ("03_initial_packing.csv", "initial_packing"), - ("04_shipping.csv", "shipping"), - ("05_receiving.csv", "receiving"), - ("06_transformation.csv", "transformation"), -] - -# Columns that always belong on the top-level event dict (not in kdes). -_TOP_LEVEL_COLUMNS = { - "traceability_lot_code", - "product_description", - "quantity", - "unit_of_measure", - "location_name", - "location_gln", -} - -# Synthetic deterministic clock for event_timestamp values. Using a -# function of (event_type, source_row_idx) keeps the timestamp tied to -# input position so reordering rows changes hashes (which is the -# correct production behavior). -_BASE_HOUR_BY_CTE = { - "harvesting": 6, - "cooling": 9, - "initial_packing": 12, - "shipping": 15, - "receiving": 18, - "transformation": 21, -} - - -def _row_to_event(event_type: str, row: dict, idx: int) -> dict: - """Convert a CSV row into the event dict shape the FDA exporter expects.""" - # Pull a primary date column to anchor the timestamp on. - date_col = next( - ( - row.get(col) - for col in ( - "harvest_date", - "cooling_date", - "packing_date", - "ship_date", - "receive_date", - "transformation_date", - ) - if row.get(col) - ), - "2026-01-01", - ) - hour = _BASE_HOUR_BY_CTE.get(event_type, 12) - minute = (idx * 7) % 60 - timestamp = f"{date_col}T{hour:02d}:{minute:02d}:00+00:00" - - kdes: dict[str, str] = {} - top: dict[str, str] = {} - for key, value in row.items(): - if not key: - continue - if key in _TOP_LEVEL_COLUMNS: - top[key] = value or "" - else: - kdes[key] = value or "" - - # Map a few CSV-side names to the canonical KDE keys the exporter - # consumes (mirrors the webhook normalization in production). - if "carrier_name" in kdes and "carrier" not in kdes: - kdes["carrier"] = kdes["carrier_name"] - if "receiving_gln" in kdes and "ship_to_gln" not in kdes: - kdes["ship_to_gln"] = kdes["receiving_gln"] - - event = { - "event_type": event_type, - "event_timestamp": timestamp, - "source": "sample_data/" + event_type, - "kdes": kdes, - **top, - } - - # Compute deterministic per-event SHA-256 hash over a canonical - # JSON form. This matches the spirit of the production hashing - # (cte_persistence does the same thing) without requiring a DB row. - canonical = json.dumps(event, sort_keys=True, separators=(",", ":")) - event["sha256_hash"] = hashlib.sha256(canonical.encode("utf-8")).hexdigest() - return event - - -def _load_events() -> list[dict]: - """Load all synthetic CTE rows from sample_data/ into event dicts.""" - events: list[dict] = [] - for filename, event_type in _SOURCE_FILES: - path = SAMPLE_DIR / filename - if not path.exists(): - logger.warning("regenerate_public_samples: missing %s, skipping", path) - continue - with path.open(newline="", encoding="utf-8") as fh: - reader = csv.DictReader(fh) - for idx, row in enumerate(reader): - events.append(_row_to_event(event_type, row, idx)) - - # Compute chain hashes deterministically: chain[0] = sha(prev=0, - # record_hash); chain[i] = sha(chain[i-1], record_hash). Same shape - # the production cte_persistence hash chain produces. - prev = "0" * 64 - for event in events: - chain_input = f"{prev}|{event['sha256_hash']}".encode("utf-8") - event["chain_hash"] = hashlib.sha256(chain_input).hexdigest() - prev = event["chain_hash"] - return events - - -# --------------------------------------------------------------------------- -# Output writers -# --------------------------------------------------------------------------- -def _write_fda_csv(events: list[dict], generate_csv) -> Path: - csv_content = generate_csv(events, include_pii=True) - # Production helper uses csv module default CRLF line terminators. - # Normalize to LF so the on-disk artifact matches git's stored - # eol=lf and the CI ``git diff --exit-code`` drift check is stable - # across platforms. - csv_content = csv_content.replace("\r\n", "\n") - out = EXPORT_DIR / "sample_fda_export.csv" - out.write_bytes(csv_content.encode("utf-8")) - logger.info("regenerate_public_samples: wrote %s (%d rows)", out, len(events)) - return out - - -def _write_epcis(events: list[dict], cte_to_bizstep: dict) -> Path: - event_list = [] - for event in events: - bizstep = cte_to_bizstep.get(event["event_type"], "urn:epcglobal:cbv:bizstep:observing") - tlc = event.get("traceability_lot_code") or "UNKNOWN" - gln = event.get("location_gln") or "0000000000000" - event_list.append( - { - "type": "ObjectEvent", - "eventTime": event["event_timestamp"], - "eventTimeZoneOffset": "+00:00", - "action": "OBSERVE", - "bizStep": bizstep, - "readPoint": {"id": f"urn:epc:id:sgln:{gln}.0"}, - "extension": { - "quantityList": [ - { - "epcClass": f"urn:epc:class:lgtin:0000000.000000.{tlc}", - "quantity": event.get("quantity") or 0, - "uom": event.get("unit_of_measure") or "EA", - } - ] - }, - "regengine:sha256": event["sha256_hash"], - "regengine:chainHash": event["chain_hash"], - } - ) - - doc = { - "@context": [ - "https://ref.gs1.org/standards/epcis/2.0.0/epcis-context.jsonld", - {"regengine": "https://regengine.co/ns/"}, - ], - "id": f"urn:uuid:regengine-sample-{DEMO_TENANT_ID}", - "type": "EPCISDocument", - "schemaVersion": "2.0", - "creationDate": FROZEN_TIMESTAMP, - "epcisBody": {"eventList": event_list}, - "regengine:exportMetadata": { - "tenantId": DEMO_TENANT_ID, - "exportFormat": "EPCIS_2.0_JSON-LD", - "generatedAt": FROZEN_TIMESTAMP, - "eventsCount": len(event_list), - "dataSource": "synthetic_sample", - "syntheticDisclaimer": ( - "This document is generated from synthetic CTE data in sample_data/. See demo_exports/SYNTHETIC.md." - ), - }, - } - - out = EXPORT_DIR / "sample_epcis.json" - out.write_text(json.dumps(doc, indent=2, sort_keys=True) + "\n", encoding="utf-8") - logger.info("regenerate_public_samples: wrote %s (%d events)", out, len(event_list)) - return out - - -def _write_audit_bundle(events: list[dict], compute_merkle_root) -> Path: - record_hashes = [e["sha256_hash"] for e in events] - merkle_root = compute_merkle_root(record_hashes) if record_hashes else None - - bundle = { - "tenantId": DEMO_TENANT_ID, - "generatedAt": FROZEN_TIMESTAMP, - "dataSource": "synthetic_sample", - "eventCount": len(events), - "merkleRoot": merkle_root, - "chainTip": events[-1]["chain_hash"] if events else None, - "events": [ - { - "index": idx, - "eventType": e["event_type"], - "traceabilityLotCode": e.get("traceability_lot_code", ""), - "eventTimestamp": e["event_timestamp"], - "recordHash": e["sha256_hash"], - "chainHash": e["chain_hash"], - } - for idx, e in enumerate(events) - ], - "syntheticDisclaimer": ( - "Audit bundle generated from synthetic CTE data in sample_data/. See demo_exports/SYNTHETIC.md." - ), - } - - out = EXPORT_DIR / "sample_audit_bundle.json" - out.write_text(json.dumps(bundle, indent=2, sort_keys=True) + "\n", encoding="utf-8") - logger.info( - "regenerate_public_samples: wrote %s (root=%s)", - out, - (merkle_root or "")[:16], - ) - return out - - -def main() -> int: - EXPORT_DIR.mkdir(parents=True, exist_ok=True) - - helpers = _try_import_production_helpers() - if helpers is None: - # #2842: this used to `return 0`, so an import failure looked exactly - # like a pass — nothing regenerated, empty `git diff`, green check. - # The drift gate's whole job is to prove demo_exports/ still matches - # production behavior; it cannot prove that from an environment where - # production code will not import, so it must go red instead. - logger.error( - "regenerate_public_samples: production helpers not importable — " - "cannot verify demo_exports/ against current production behavior. " - "Install the full requirements.lock and re-run; see the warning " - "above for the failing import." - ) - return 2 - - generate_csv, cte_to_bizstep, compute_merkle_root = helpers - - events = _load_events() - if not events: - logger.error("regenerate_public_samples: no source rows found in %s", SAMPLE_DIR) - return 1 - - _write_fda_csv(events, generate_csv) - _write_epcis(events, cte_to_bizstep) - _write_audit_bundle(events, compute_merkle_root) - return 0 - - -if __name__ == "__main__": - sys.exit(main()) diff --git a/scripts/run_recall_fixture.py b/scripts/run_recall_fixture.py deleted file mode 100755 index a510f1b8c..000000000 --- a/scripts/run_recall_fixture.py +++ /dev/null @@ -1,115 +0,0 @@ -#!/usr/bin/env python3 -"""Run the recall-reconstruction fixture: one lot, six pallets, three cases. - - complete every record available - missing_3pl_contents the 3PL pallet-content (repack) record is withheld - erp_unavailable the DC ERP is unreachable; only its retained snapshot is used - -Each case writes an evidence package (worksheet, findings, corrections, custody -timelines, canonical events with a hash chain, manifest with per-source last -sync time) and reconciles it against ``answer_key.json``. Exit code is 0 only -when every case reconciles. - -DB-free by design, like ``scripts/run_full_fsma_simulation.py``. -""" - -from __future__ import annotations - -import argparse -import json -import sys -from pathlib import Path -from typing import Any - -ROOT = Path(__file__).resolve().parents[1] -for path in (ROOT / "services" / "ingestion", ROOT / "services"): - path_str = str(path) - if path_str not in sys.path: - sys.path.insert(0, path_str) - -from app.fda_export_service import _generate_csv # noqa: E402 -from shared.recall_reconstruction import CASES, run_case # noqa: E402 - -DEFAULT_FIXTURE = ROOT / "sample_data" / "recall_fixture" - - -def _fda_export_rows(canonical_path: Path) -> list[dict[str, Any]]: - data = json.loads(canonical_path.read_text(encoding="utf-8")) - rows = [] - for event in data["events"]: - rows.append( - { - "traceability_lot_code": event["traceability_lot_code"], - "product_description": event["product_reference"], - "quantity": event["quantity"], - "unit_of_measure": event["unit_of_measure"], - "event_type": event["event_type"], - "event_timestamp": event["event_timestamp"], - "location_gln": event["to_facility_reference"] or event["from_facility_reference"] or "", - "location_name": event["to_entity_reference"] or event["from_entity_reference"] or "", - "source": event["source_system"], - "kdes": dict(event["kdes"]), - "sha256_hash": event["sha256_hash"], - "chain_hash": event["chain_hash"], - "ingested_at": event["ingested_at"], - } - ) - return rows - - -def run(fixture_dir: Path, output_dir: Path, cases: list[str]) -> dict[str, Any]: - results: dict[str, Any] = {} - for case in cases: - case_dir = output_dir / case - manifest = run_case(fixture_dir, case, case_dir) - csv_text = _generate_csv(_fda_export_rows(case_dir / "canonical_events.json"), include_pii=True) - (case_dir / "fda_export.csv").write_text(csv_text, encoding="utf-8") - reconciliation = manifest.get("reconciliation") or {"passed": False, "checks": []} - results[case] = { - "passed": reconciliation["passed"], - "checks_failed": [c for c in reconciliation["checks"] if not c["passed"]], - "rows_by_label": manifest["worksheet_summary"]["rows_by_label"], - "findings_by_type": {k: v for k, v in manifest["findings_by_type"].items() if v}, - "unavailable_sources": manifest["unavailable_sources"], - "package_hash": manifest["package_hash"], - "output_dir": str(case_dir), - } - return { - "passed": all(r["passed"] for r in results.values()), - "cases": results, - "fixture_dir": str(fixture_dir), - "output_dir": str(output_dir), - } - - -def _print_human(summary: dict[str, Any]) -> None: - print(f"{'PASS' if summary['passed'] else 'FAIL'} recall reconstruction fixture ({summary['fixture_dir']})") - for case, result in summary["cases"].items(): - status = "PASS" if result["passed"] else "FAIL" - print(f" [{status}] {case}: labels={result['rows_by_label']} findings={result['findings_by_type']}") - for source, info in result["unavailable_sources"].items(): - print(f" {source} unavailable; last successful sync {info['last_successful_sync_at']}") - for check in result["checks_failed"]: - print(f" FAILED CHECK {check['name']}: {check['detail']}") - print(f" package: {result['output_dir']}") - - -def main(argv: list[str] | None = None) -> int: - parser = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) - parser.add_argument("--case", default="all", choices=["all", *CASES], help="which case to run (default: all)") - parser.add_argument("--fixture-dir", type=Path, default=DEFAULT_FIXTURE) - parser.add_argument("--output-dir", type=Path, default=Path("/tmp/regengine-recall-fixture")) - parser.add_argument("--json", action="store_true", help="print machine-readable JSON only") - args = parser.parse_args(argv) - - cases = list(CASES) if args.case == "all" else [args.case] - summary = run(args.fixture_dir, args.output_dir, cases) - if args.json: - print(json.dumps(summary, sort_keys=True)) - else: - _print_human(summary) - return 0 if summary["passed"] else 1 - - -if __name__ == "__main__": - raise SystemExit(main()) diff --git a/services/ingestion/tests/test_csv_templates.py b/services/ingestion/tests/test_csv_templates.py index ea4a80733..1fc56c74b 100644 --- a/services/ingestion/tests/test_csv_templates.py +++ b/services/ingestion/tests/test_csv_templates.py @@ -64,8 +64,7 @@ class TestTemplateValidatorDrift: POST /api/v1/ingest/csv with "Missing required KDE" because the templates omitted mandatory columns (harvester_business_name for initial_packing, tlc_source_reference for shipping/receiving, - reference_document for most types). sample_data/ drifted the same - way (fixed in PR #2631). These tests pin template <-> validator + reference_document for most types). These tests pin template <-> validator parity so the two can never diverge again. """ diff --git a/services/ingestion/tests/test_csv_templates_1342.py b/services/ingestion/tests/test_csv_templates_1342.py index f0015e664..dffd759aa 100644 --- a/services/ingestion/tests/test_csv_templates_1342.py +++ b/services/ingestion/tests/test_csv_templates_1342.py @@ -946,7 +946,7 @@ class TestTemplateExampleRowSurvivesIngest: Guards the live failure where rows built from the official template were rejected with "Missing required KDE" (template <-> validator - drift; sample_data/ counterpart fixed in PR #2631). + drift). """ # Parametrized over every served template — including legacy aliases like diff --git a/tests/recall_reconstruction/test_empty_input.py b/tests/recall_reconstruction/test_empty_input.py new file mode 100644 index 000000000..6d12126f3 --- /dev/null +++ b/tests/recall_reconstruction/test_empty_input.py @@ -0,0 +1,10 @@ +"""A recall reconstruction requires source evidence before it can run.""" + +import pytest + +from shared.recall_reconstruction import load_fixture + + +def test_recall_reconstruction_rejects_empty_input(tmp_path): + with pytest.raises(FileNotFoundError, match="sync_manifest.json"): + load_fixture(tmp_path, "complete") diff --git a/tests/recall_reconstruction/test_fixture_cases.py b/tests/recall_reconstruction/test_fixture_cases.py deleted file mode 100644 index 0c0438482..000000000 --- a/tests/recall_reconstruction/test_fixture_cases.py +++ /dev/null @@ -1,197 +0,0 @@ -"""Run the recall fixture three ways and check the honesty properties end to end.""" - -from __future__ import annotations - -import csv -import json -from pathlib import Path - -import pytest -from shared.recall_reconstruction import CASES, LinkLabel, build_custody, build_worksheet, load_fixture, run_case -from shared.recall_reconstruction.labels import FindingType - -ROOT = Path(__file__).resolve().parents[2] -FIXTURE = ROOT / "sample_data" / "recall_fixture" -P = {n: f"0086100011{n:07d}" for n in range(1, 11)} # prefix; full ids carry a check digit -PALLET = { - 1: "008610001100000010", - 2: "008610001100000027", - 3: "008610001100000034", - 4: "008610001100000041", - 5: "008610001100000058", - 6: "008610001100000065", - 7: "008610001100000072", - 8: "008610001100000089", - 9: "008610001100000096", - 10: "008610001100000102", -} -LOT_A, LOT_B = "HLF-215A", "HLF-215B" -DEST_A, DEST_B, THREE_PL = "0861000440001", "0861000550007", "0861000330005" - - -def _rows(case: str): - rs = load_fixture(FIXTURE, case) - custody = build_custody(rs) - ws = build_worksheet(rs, custody, LOT_A) - return rs, custody, ws, {(r.pallet_id, r.lot_code): r for r in ws.rows} - - -@pytest.mark.parametrize("case", list(CASES)) -def test_every_case_reconciles_against_answer_key(case, tmp_path): - manifest = run_case(FIXTURE, case, tmp_path / case) - failed = [c for c in manifest["reconciliation"]["checks"] if not c["passed"]] - assert manifest["reconciliation"]["passed"], failed - for name in ( - "worksheet.csv", - "worksheet.json", - "findings.json", - "corrections.json", - "canonical_events.json", - "custody.json", - "answer_key_reconciliation.json", - "manifest.json", - ): - assert (tmp_path / case / name).exists(), name - - -def test_complete_case_reconstructs_answer_key(): - rs, custody, ws, rows = _rows("complete") - summary = ws.summary() - assert summary["rows_by_label"] == {"linked": 4, "no_link_established": 3, "unresolved": 0} - assert summary["linked_quantity_by_lot_and_destination"] == {LOT_A: {DEST_A: 150.0, DEST_B: 40.0}} - # Identifier change: P9 carries P6's lot history. - assert rows[(PALLET[9], LOT_A)].lineage == [PALLET[6]] - # Consolidation at the 3PL: P10 carries both split children and their parent. - assert rows[(PALLET[10], LOT_A)].lineage == [PALLET[7], PALLET[8], PALLET[3]] - # Mixed pallet: LOT-B on P10 is flagged for the practitioner but not labelled linked. - lot_b_on_p10 = rows[(PALLET[10], LOT_B)] - assert lot_b_on_p10.label is LinkLabel.NO_LINK_ESTABLISHED - assert lot_b_on_p10.co_palletized_with_implicated_lot is True - # Quantity discrepancy on P2 is reported and does not block the link. - p2 = rows[(PALLET[2], LOT_A)] - assert p2.label is LinkLabel.LINKED - assert p2.quantity_asserted == 60 and p2.pallet_quantity_counted_at_last_receipt == 58 - assert p2.pallet_quantity_asserted == 60 - # Mixed pallet: the per-lot figure is smaller than the whole-pallet count, and that is not a discrepancy. - lot_a_on_p10 = rows[(PALLET[10], LOT_A)] - assert lot_a_on_p10.quantity_asserted == 40 - assert lot_a_on_p10.pallet_quantity_asserted == 60 and lot_a_on_p10.pallet_quantity_counted_at_last_receipt == 60 - assert not lot_a_on_p10.finding_ids - assert any("delta -2" in n for n in p2.notes) - # Only one finding type in the complete case. - assert {f.type for f in custody.findings} == {FindingType.QUANTITY_DISCREPANCY} - # Every asserted connection points at source evidence. - for row in ws.rows: - assert row.supporting_records, row.pallet_id - assert all(len(ref.file_sha256) == 64 for ref in row.supporting_records) - - -def test_manual_correction_requires_author_reason_evidence_and_is_recorded(): - rs, custody, ws, rows = _rows("complete") - correction = next(c for c in rs.corrections if c.correction_id == "COR-001") - assert correction.applied and correction.author and correction.reason and correction.evidence_ref - receipt = next(r for r in rs.receipts if r.receipt_id == "RCV-DC-004") - assert receipt.shipment_ref == "BOL-MFG-001" - assert receipt.corrections == [correction] - p4 = rows[(PALLET[4], LOT_B)] - assert correction.source_ref in p4.supporting_records - assert any("COR-001" in n and "J. Alvarez" in n for n in p4.notes) - - -def test_missing_3pl_contents_is_unresolved_never_excluded(): - rs, custody, ws, rows = _rows("missing_3pl_contents") - assert rs.files["3pl_repack.csv"].available is False - p10 = rows[(PALLET[10], None)] - assert p10.label is LinkLabel.UNRESOLVED - assert p10.quantity_asserted is None and p10.pallet_quantity_asserted is None - assert p10.pallet_quantity_counted_at_last_receipt == 60 - assert p10.destination_gln == DEST_B - # The precise record needed is named: type, custodian, GLN, window, candidate inputs. - question = p10.unresolved_questions[0] - for fragment in ( - "pallet contents or repack record", - "Bluewater Logistics", - THREE_PL, - "2026-08-06T15:40:00+00:00", - "2026-08-08T06:30:00+00:00", - PALLET[7], - PALLET[8], - ): - assert fragment in question, fragment - # The possible inputs are unresolved too, with last recorded location at the 3PL. - for pallet, lot in ((PALLET[7], LOT_A), (PALLET[8], LOT_B)): - row = rows[(pallet, lot)] - assert row.label is LinkLabel.UNRESOLVED - assert row.last_recorded_location_gln == THREE_PL - # Nothing is labelled no_link_established because of the missing record, - # and LOT-A at destination B is not asserted as zero. - summary = ws.summary() - assert summary["linked_quantity_by_lot_and_destination"] == {LOT_A: {DEST_A: 150.0}} - assert DEST_B not in summary["linked_quantity_by_lot_and_destination"][LOT_A] - assert summary["unresolved_quantity_by_lot"] == {LOT_A: 40.0, LOT_B: 20.0} - # Rows unaffected by the gap are identical to the complete case. - _, _, complete_ws, complete_rows = _rows("complete") - for key in ((PALLET[1], LOT_A), (PALLET[2], LOT_A), (PALLET[4], LOT_B), (PALLET[5], LOT_B), (PALLET[9], LOT_A)): - assert rows[key].as_dict() == complete_rows[key].as_dict(), key - - -def test_erp_unavailable_states_cutoff_and_reproduces_retained_evidence(): - rs, custody, ws, rows = _rows("erp_unavailable") - assert rs.cutoffs == {"dc_erp": "2026-08-05T12:00:00Z"} - assert rs.files["dc_receiving.csv"].retained_from == "retained/dc_erp/dc_receiving.csv" - assert rs.files["dc_repack.csv"].retained_from == "retained/dc_erp/dc_repack.csv" - assert rs.files["dc_shipping.csv"].available is False - assert "2026-08-05T12:00:00Z" in (rs.files["dc_shipping.csv"].unavailable_reason or "") - # Everything downstream of the cutoff is unresolved, and every question names the sync time. - assert all(r.label is LinkLabel.UNRESOLVED for r in ws.rows) - for row in ws.rows: - assert row.unresolved_questions - assert all("dc_erp" in q and "2026-08-05T12:00:00+00:00" in q for q in row.unresolved_questions), row.pallet_id - handoff = [f for f in custody.findings if f.type is FindingType.MISSING_HANDOFF_SHIPPING] - assert len(handoff) == 7 - assert all( - f.attributed_to_cutoff == {"source_system": "dc_erp", "last_successful_sync_at": "2026-08-05T12:00:00Z"} - for f in handoff - ) - # Evidence captured before the cutoff is reproduced exactly: DC receipts and repacks. - _, complete_custody, _, _ = _rows("complete") - for pallet in (PALLET[7], PALLET[8], PALLET[9]): - retained = custody.timelines[pallet].contents_groups - complete = complete_custody.timelines[pallet].contents_groups - assert [(g.record_id, g.lots, g.derived_from) for g in retained] == [ - (g.record_id, g.lots, g.derived_from) for g in complete - ] - - -def test_pre_cutoff_canonical_events_are_identical_across_cases(tmp_path): - """A retained snapshot reproduces the live evidence exactly: same ids, hashes, and chain.""" - cutoff = "2026-08-05T12:00:00" - run_case(FIXTURE, "complete", tmp_path / "complete") - run_case(FIXTURE, "erp_unavailable", tmp_path / "erp_unavailable") - events = { - case: json.loads((tmp_path / case / "canonical_events.json").read_text())["events"] - for case in ("complete", "erp_unavailable") - } - pre = {case: [e for e in evs if e["event_timestamp"] < cutoff] for case, evs in events.items()} - assert len(pre["complete"]) == 17 - assert pre["complete"] == pre["erp_unavailable"] - # The chain diverges only where the evidence does: after the cutoff. - assert len(events["complete"]) > len(events["erp_unavailable"]) - retained_ids = {e["event_id"] for e in events["erp_unavailable"]} - assert retained_ids <= {e["event_id"] for e in events["complete"]} - - -def test_package_manifest_carries_sync_times_and_hashes(tmp_path): - manifest = run_case(FIXTURE, "erp_unavailable", tmp_path) - assert manifest["unavailable_sources"]["dc_erp"]["last_successful_sync_at"] == "2026-08-05T12:00:00Z" - assert manifest["last_successful_sync_by_source"]["dc_erp"] == "2026-08-05T12:00:00Z" - assert manifest["sources"]["dc_shipping.csv"]["available"] is False - assert len(manifest["package_hash"]) == 64 - assert all(len(h) == 64 for h in manifest["files"].values()) - events = json.loads((tmp_path / "canonical_events.json").read_text()) - assert events["events"] and all(len(e["chain_hash"]) == 64 for e in events["events"]) - # The worksheet CSV opens as a plain table with one label per row. - with open(tmp_path / "worksheet.csv", newline="") as handle: - rows = list(csv.DictReader(handle)) - assert {r["label"] for r in rows} <= {label.value for label in LinkLabel} - assert all(r["unresolved_questions"] for r in rows) diff --git a/tests/recall_reconstruction/test_fixture_integrity.py b/tests/recall_reconstruction/test_fixture_integrity.py deleted file mode 100644 index c952ac6b0..000000000 --- a/tests/recall_reconstruction/test_fixture_integrity.py +++ /dev/null @@ -1,61 +0,0 @@ -"""The fixture must stay internally consistent: valid GS1 identifiers, hashes that match the files.""" - -from __future__ import annotations - -import csv -import hashlib -import json -from pathlib import Path - -from shared.fsma_validation import validate_gln, validate_gtin, validate_sscc -from shared.recall_reconstruction.loader import FILE_SPECS - -ROOT = Path(__file__).resolve().parents[2] -FIXTURE = ROOT / "sample_data" / "recall_fixture" - - -def _rows(path: Path): - with open(path, newline="", encoding="utf-8") as handle: - return list(csv.DictReader(handle)) - - -def test_every_gs1_identifier_in_the_fixture_validates(): - for name in FILE_SPECS: - for row in _rows(FIXTURE / name): - for column, value in row.items(): - if not value: - continue - if column.endswith("pallet_id"): - assert validate_sscc(value).is_valid, (name, column, value) - elif column.endswith("gln"): - assert validate_gln(value).is_valid, (name, column, value) - elif column == "gtin": - assert validate_gtin(value).is_valid, (name, column, value) - - -def test_sync_manifest_hashes_match_files(): - manifest = json.loads((FIXTURE / "sync_manifest.json").read_text(encoding="utf-8")) - assert set(manifest["files"]) == set(FILE_SPECS) - for name, entry in manifest["files"].items(): - assert entry["source_system"] == FILE_SPECS[name]["source_system"] - assert entry["sha256"] == hashlib.sha256((FIXTURE / name).read_bytes()).hexdigest(), name - for path, digest in manifest["retained_sha256"].items(): - assert digest == hashlib.sha256((FIXTURE / path).read_bytes()).hexdigest(), path - - -def test_retained_snapshot_matches_live_records_it_claims_to_retain(): - for name in ("dc_receiving.csv", "dc_repack.csv"): - assert (FIXTURE / "retained" / "dc_erp" / name).read_bytes() == (FIXTURE / name).read_bytes() - assert not (FIXTURE / "retained" / "dc_erp" / "dc_shipping.csv").exists() - - -def test_answer_key_totals_match_fixture_contents(): - key = json.loads((FIXTURE / "answer_key.json").read_text(encoding="utf-8")) - produced = {r["lot_code"]: float(r["quantity"]) for r in _rows(FIXTURE / "mfg_lots.csv")} - palletized: dict[str, float] = {} - for r in _rows(FIXTURE / "mfg_pallet_contents.csv"): - palletized[r["lot_code"]] = palletized.get(r["lot_code"], 0.0) + float(r["quantity"]) - assert produced == palletized - for lot, truth in key["ground_truth"]["lots"].items(): - assert float(truth["produced"]) == produced[lot] - assert sum(d["shipped"] for d in truth["by_destination"].values()) == produced[lot] diff --git a/tests/scripts/test_regenerate_public_samples_gate.py b/tests/scripts/test_regenerate_public_samples_gate.py deleted file mode 100644 index f2872c8b4..000000000 --- a/tests/scripts/test_regenerate_public_samples_gate.py +++ /dev/null @@ -1,110 +0,0 @@ -"""#2842 — the public-samples drift gate must not pass vacuously. - -``scripts/regenerate_public_samples.py`` regenerates ``demo_exports/`` — the -public Proof Surface external parties verify FDA exports, EPCIS and Merkle -audit bundles against — and backend-ci fails the build if the regenerated -output differs from what is checked in. - -The import-failure path used to ``return 0`` with the comment "CI's diff check -will still pass because we didn't write anything". Nothing regenerated, empty -diff, green check: the failure was indistinguishable from a pass, so any change -to the import chain of ``app.epcis_export`` / ``app.fda_export_service`` / -``shared.merkle_tree`` would have switched the gate off permanently and -silently. -""" - -from __future__ import annotations - -import importlib.util -import sys -from pathlib import Path - -import pytest - -ROOT = Path(__file__).resolve().parents[2] -SCRIPT = ROOT / "scripts" / "regenerate_public_samples.py" - - -def _load_script_module(): - spec = importlib.util.spec_from_file_location("_tests_regen_public_samples", SCRIPT) - assert spec and spec.loader - module = importlib.util.module_from_spec(spec) - sys.modules[spec.name] = module - spec.loader.exec_module(module) - return module - - -@pytest.fixture -def script(): - module = _load_script_module() - yield module - sys.modules.pop("_tests_regen_public_samples", None) - - -class TestImportFailureIsRed: - def test_main_exits_non_zero_when_helpers_cannot_be_imported(self, script, monkeypatch): - """The core regression: 'could not import' must be a red check.""" - monkeypatch.setattr(script, "_try_import_production_helpers", lambda: None) - - assert script.main() != 0, ( - "import failure returned 0 — the drift gate passes having " - "regenerated nothing (#2842)" - ) - - def test_main_writes_nothing_on_the_failure_path(self, script, monkeypatch, tmp_path): - """Failing must not also corrupt the checked-in artifacts.""" - monkeypatch.setattr(script, "_try_import_production_helpers", lambda: None) - export_dir = tmp_path / "demo_exports" - monkeypatch.setattr(script, "EXPORT_DIR", export_dir) - - rc = script.main() - - assert rc != 0 - assert list(export_dir.iterdir()) == [] - - def test_source_no_longer_claims_a_vacuous_pass(self): - """The old behaviour was documented in a comment; it must be gone.""" - source = SCRIPT.read_text() - - assert "CI's diff check will still" not in source - assert "exiting 0 without rewriting" not in source - - -class TestHappyPathStillReturnsZero: - def test_main_succeeds_when_helpers_import(self, script, monkeypatch, tmp_path): - """Guard against 'make it red' turning into 'always red'. - - Exercises the real helper imports and the real synthetic inputs, so it - proves the gate can still pass on a healthy checkout. EXPORT_DIR is - redirected into tmp_path: all three writers read that module global at - call time (regenerate_public_samples.py:234, :290, :323), so the real - checked-in demo_exports/ is never touched by the test suite. Writing to - it would silently rewrite the public Proof Surface as a side effect of - running tests. - """ - if script._try_import_production_helpers() is None: - pytest.skip("production helpers not importable in this environment") - - monkeypatch.setattr(script, "EXPORT_DIR", tmp_path / "demo_exports") - - assert script.main() == 0 - assert (tmp_path / "demo_exports" / "sample_fda_export.csv").exists() - - -class TestWorkflowInstallsTheLockfile: - """#2842 second half: the job installed three hand-picked packages. - - With the vacuous pass removed, guessing the import closure would turn every - transitive-dependency addition into a red build. - """ - - @property - def job(self) -> str: - content = (ROOT / ".github" / "workflows" / "backend-ci.yml").read_text() - return content.split("regenerate-public-samples:", 1)[1].split("\n # ", 1)[0] - - def test_job_installs_requirements_lock(self): - assert "requirements.lock" in self.job - - def test_job_no_longer_installs_three_hand_picked_packages(self): - assert "pip install pydantic fastapi sqlalchemy" not in self.job diff --git a/tests/scripts/test_run_recall_fixture.py b/tests/scripts/test_run_recall_fixture.py deleted file mode 100644 index d66718ca2..000000000 --- a/tests/scripts/test_run_recall_fixture.py +++ /dev/null @@ -1,37 +0,0 @@ -import csv -import json -import subprocess -import sys -from pathlib import Path - -ROOT = Path(__file__).resolve().parents[2] -SCRIPT = ROOT / "scripts" / "run_recall_fixture.py" - - -def test_run_recall_fixture_runs_all_three_cases(tmp_path): - result = subprocess.run( - [sys.executable, str(SCRIPT), "--case", "all", "--output-dir", str(tmp_path), "--json"], - check=True, - capture_output=True, - text=True, - ) - summary = json.loads(result.stdout) - assert summary["passed"] is True - assert set(summary["cases"]) == {"complete", "missing_3pl_contents", "erp_unavailable"} - assert summary["cases"]["complete"]["rows_by_label"] == {"linked": 4, "no_link_established": 3, "unresolved": 0} - assert summary["cases"]["missing_3pl_contents"]["rows_by_label"]["unresolved"] == 3 - assert summary["cases"]["erp_unavailable"]["unavailable_sources"]["dc_erp"]["last_successful_sync_at"] == ( - "2026-08-05T12:00:00Z" - ) - - for case in summary["cases"]: - export = tmp_path / case / "fda_export.csv" - rows = list(csv.DictReader(export.read_text(encoding="utf-8").splitlines())) - assert rows, case - assert all(len(row["Record Hash (SHA-256)"]) == 64 for row in rows) - assert all(len(row["Chain Hash"]) == 64 for row in rows) - assert all(row["System Entry Timestamp"] for row in rows) - # The missing-contents case cannot canonicalize P10's movements without inventing a lot. - missing = json.loads((tmp_path / "missing_3pl_contents" / "canonical_events.json").read_text()) - assert len(missing["not_canonicalized"]) == 2 - assert all(entry["pallet_id"] == "008610001100000102" for entry in missing["not_canonicalized"]) From 61ca8b0eb8fd8d2690c3d03fa287b8007feb8f40 Mon Sep 17 00:00:00 2001 From: Christopher <131207452+PetrefiedThunder@users.noreply.github.com> Date: Fri, 23 Oct 2026 02:14:49 -0700 Subject: [PATCH 2/4] chore: remove invented samples-backend data; empty states and data-free tests --- docs/audits/RECALL_FIXTURE_AUDIT_2026-09-16.md | 3 +-- services/ingestion/app/proof_recall_router.py | 5 ++--- tests/recall_reconstruction/test_empty_input.py | 1 - 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/docs/audits/RECALL_FIXTURE_AUDIT_2026-09-16.md b/docs/audits/RECALL_FIXTURE_AUDIT_2026-09-16.md index d1da8cb80..53feabc06 100644 --- a/docs/audits/RECALL_FIXTURE_AUDIT_2026-09-16.md +++ b/docs/audits/RECALL_FIXTURE_AUDIT_2026-09-16.md @@ -6,8 +6,7 @@ two destinations; two lots; six pallets; run with complete records, with one 3PL pallet-content record withheld, and with the ERP unavailable). Every row below was verified by reading the cited code, not from documentation claims. -The companion implementation is `services/shared/recall_reconstruction/`, -`scripts/run_recall_fixture.py`, and `sample_data/recall_fixture/`. +This is a historical audit. The invented recall scenario and its runner were removed under SEL-447; the generic reconstruction engine remains in `services/shared/recall_reconstruction/`. ## Summary diff --git a/services/ingestion/app/proof_recall_router.py b/services/ingestion/app/proof_recall_router.py index 85f6aea00..aec0d4c26 100644 --- a/services/ingestion/app/proof_recall_router.py +++ b/services/ingestion/app/proof_recall_router.py @@ -194,9 +194,8 @@ async def run_recall_drill(request: Request) -> RecallDrillResponse: This endpoint MUST NOT read any tenant data: it operates entirely against module-level constants derived from - ``frontend/public/samples/sample_recall_drill.csv`` and the - 7-CTE ``sample_data/`` fixtures. No database, queue, or tenant - store is touched. + ``frontend/public/samples/sample_recall_drill.csv``. No database, + queue, or tenant store is touched. """ ip_hash = _hash_ip(request.client.host if request.client else None) response = _build_response() diff --git a/tests/recall_reconstruction/test_empty_input.py b/tests/recall_reconstruction/test_empty_input.py index 6d12126f3..263681836 100644 --- a/tests/recall_reconstruction/test_empty_input.py +++ b/tests/recall_reconstruction/test_empty_input.py @@ -1,7 +1,6 @@ """A recall reconstruction requires source evidence before it can run.""" import pytest - from shared.recall_reconstruction import load_fixture From 9995ac96f36fce1e6de6327ff1225f568bb5a842 Mon Sep 17 00:00:00 2001 From: Christopher <131207452+PetrefiedThunder@users.noreply.github.com> Date: Fri, 23 Oct 2026 02:39:40 -0700 Subject: [PATCH 3/4] chore: drop deferred proof-transformation test and stale demo_exports baseline entry --- .secrets.baseline | 300 ------------------ .../pages/proof-transformation-empty.test.tsx | 13 - 2 files changed, 313 deletions(-) delete mode 100644 frontend/src/__tests__/pages/proof-transformation-empty.test.tsx diff --git a/.secrets.baseline b/.secrets.baseline index 834b4df10..141f489c8 100644 --- a/.secrets.baseline +++ b/.secrets.baseline @@ -746,306 +746,6 @@ "line_number": 24 } ], - "demo_exports/sample_audit_bundle.json": [ - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_audit_bundle.json", - "hashed_secret": "8f1246b4e3a56e4aa36936f5a754e6a6362888c1", - "is_verified": false, - "line_number": 2, - "is_secret": false - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_audit_bundle.json", - "hashed_secret": "9893566b528e851db48ebd07ae13aae9cb296839", - "is_verified": false, - "line_number": 7 - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_audit_bundle.json", - "hashed_secret": "9c874e035a44d6ec5746fd3dbf817d02dd46248f", - "is_verified": false, - "line_number": 11 - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_audit_bundle.json", - "hashed_secret": "ac9a367e9074c12555fb1ea7c16aed8b25c78323", - "is_verified": false, - "line_number": 15 - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_audit_bundle.json", - "hashed_secret": "5bf25ee99829fd9516aeec76b4485734b1d7008b", - "is_verified": false, - "line_number": 19 - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_audit_bundle.json", - "hashed_secret": "72e59fe6201bb3e5eceeea19e824a4d662ca1565", - "is_verified": false, - "line_number": 23 - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_audit_bundle.json", - "hashed_secret": "69ca9a3ee55ac43cf5dc32e220d4ac9fdaf09585", - "is_verified": false, - "line_number": 27 - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_audit_bundle.json", - "hashed_secret": "2991cb4254dea5a36f70902872eabe4d4ed7141b", - "is_verified": false, - "line_number": 31 - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_audit_bundle.json", - "hashed_secret": "1a3661464bd172e9a29e41e37a6567e8c9491d77", - "is_verified": false, - "line_number": 35 - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_audit_bundle.json", - "hashed_secret": "65070f7abfd0c96324d8e35fc4e4bb2b8ab1ffa9", - "is_verified": false, - "line_number": 39 - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_audit_bundle.json", - "hashed_secret": "618adb767fb492bc7465ea710a51c9ea59b7d0fc", - "is_verified": false, - "line_number": 43 - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_audit_bundle.json", - "hashed_secret": "8cc54e42c99573ba74f885e704a9838c6cdf821d", - "is_verified": false, - "line_number": 47 - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_audit_bundle.json", - "hashed_secret": "8510845002be36248e54c26280418a186c55a14c", - "is_verified": false, - "line_number": 51 - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_audit_bundle.json", - "hashed_secret": "3402bc06aaf1d2eca64a1af8ecadcdf16c1f3a89", - "is_verified": false, - "line_number": 55, - "is_secret": false - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_audit_bundle.json", - "hashed_secret": "e0d59969a6521fb9bcb74668adbd752fe4e3c7cd", - "is_verified": false, - "line_number": 59, - "is_secret": false - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_audit_bundle.json", - "hashed_secret": "9baa375ab3b7f4f350139e568493caa5680fffd4", - "is_verified": false, - "line_number": 63, - "is_secret": false - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_audit_bundle.json", - "hashed_secret": "fa41cd85a07e313c59e51129caf240c2092abb36", - "is_verified": false, - "line_number": 67, - "is_secret": false - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_audit_bundle.json", - "hashed_secret": "bdb5ad00810e1c77affd96c8e82ae547378658eb", - "is_verified": false, - "line_number": 71, - "is_secret": false - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_audit_bundle.json", - "hashed_secret": "45bf27a2139c57b12c6c232bcd817649afe0cd85", - "is_verified": false, - "line_number": 75, - "is_secret": false - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_audit_bundle.json", - "hashed_secret": "0d59310f785a96991a7f5dc51ad5d6289ec204f9", - "is_verified": false, - "line_number": 79, - "is_secret": false - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_audit_bundle.json", - "hashed_secret": "e862d2e772ef0390ba7bbe388a2ef8621fd631a5", - "is_verified": false, - "line_number": 83, - "is_secret": false - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_audit_bundle.json", - "hashed_secret": "e51b0b5f4d3db8f442e0cc528d839bbd595b50f6", - "is_verified": false, - "line_number": 87, - "is_secret": false - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_audit_bundle.json", - "hashed_secret": "86c62f2290f39dc4a583821c443f995a80916871", - "is_verified": false, - "line_number": 91, - "is_secret": false - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_audit_bundle.json", - "hashed_secret": "331666e19da230686a9cf201706266fc780c7176", - "is_verified": false, - "line_number": 95, - "is_secret": false - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_audit_bundle.json", - "hashed_secret": "dfe63c8ec26fa82ea004850521a140e1d8b947bb", - "is_verified": false, - "line_number": 99, - "is_secret": false - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_audit_bundle.json", - "hashed_secret": "76a4b85274e88565576f04338c7712f214b01ae8", - "is_verified": false, - "line_number": 103, - "is_secret": false - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_audit_bundle.json", - "hashed_secret": "b16277d40350f8f6e2545275b22abc975e380c2c", - "is_verified": false, - "line_number": 107, - "is_secret": false - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_audit_bundle.json", - "hashed_secret": "74893bb5bad265a128f58460c0f346ac667fc31e", - "is_verified": false, - "line_number": 111, - "is_secret": false - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_audit_bundle.json", - "hashed_secret": "8ccc733b5d33cdc22427eab97841e06008497d0e", - "is_verified": false, - "line_number": 115, - "is_secret": false - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_audit_bundle.json", - "hashed_secret": "edb0f7952cfe37aff48ab2e6347344a559a1b307", - "is_verified": false, - "line_number": 119, - "is_secret": false - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_audit_bundle.json", - "hashed_secret": "f1b254706d48d1fcdeb6b562aa174fcf424ecbc1", - "is_verified": false, - "line_number": 123, - "is_secret": false - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_audit_bundle.json", - "hashed_secret": "7e9274ccf853d190b748ccec8caed2956842e6dd", - "is_verified": false, - "line_number": 127, - "is_secret": false - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_audit_bundle.json", - "hashed_secret": "adafb2b1e793b9d16afcf21ccd294302b45c92a9", - "is_verified": false, - "line_number": 131, - "is_secret": false - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_audit_bundle.json", - "hashed_secret": "4518e7ea9db30b2e1ee4ca3b093fccaed1fb36b9", - "is_verified": false, - "line_number": 135, - "is_secret": false - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_audit_bundle.json", - "hashed_secret": "c1a6b8a926f87ba9687145ec64c88682b8a15744", - "is_verified": false, - "line_number": 139, - "is_secret": false - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_audit_bundle.json", - "hashed_secret": "83123693dbaea0b00062682711269cd3c9fb411b", - "is_verified": false, - "line_number": 143, - "is_secret": false - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_audit_bundle.json", - "hashed_secret": "9f8f7f9de91666beffa380184ff8ac32aa6cc21a", - "is_verified": false, - "line_number": 147 - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_audit_bundle.json", - "hashed_secret": "105ddf84723138a6bbd5978bf2828a26e468b173", - "is_verified": false, - "line_number": 155 - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_audit_bundle.json", - "hashed_secret": "5e7282daccdc2e1f4333c919577a1a1f305f1998", - "is_verified": false, - "line_number": 160, - "is_secret": false - } - ], "demo_exports/sample_epcis.json": [ { "type": "Hex High Entropy String", diff --git a/frontend/src/__tests__/pages/proof-transformation-empty.test.tsx b/frontend/src/__tests__/pages/proof-transformation-empty.test.tsx deleted file mode 100644 index 9085b4bf4..000000000 --- a/frontend/src/__tests__/pages/proof-transformation-empty.test.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import { render, screen } from '@testing-library/react'; -import { describe, expect, it } from 'vitest'; -import TransformationProofPage from '@/app/proof/transformation/page'; - -describe('transformation proof without supplier records', () => { - it('shows an empty state without invented evidence', () => { - const { container } = render(); - - expect(screen.getByText(/No data yet/)).toBeInTheDocument(); - expect(container.querySelector('table')).toBeNull(); - expect(container.querySelector('a[download]')).toBeNull(); - }); -}); From 9c05139a208c621bf27782144f2a129c06e21eab Mon Sep 17 00:00:00 2001 From: Christopher <131207452+PetrefiedThunder@users.noreply.github.com> Date: Fri, 23 Oct 2026 02:43:25 -0700 Subject: [PATCH 4/4] chore: drop baseline entries for files deleted in this PR --- .secrets.baseline | 672 ---------------------------------------------- 1 file changed, 672 deletions(-) diff --git a/.secrets.baseline b/.secrets.baseline index 141f489c8..996f9f4cd 100644 --- a/.secrets.baseline +++ b/.secrets.baseline @@ -746,590 +746,6 @@ "line_number": 24 } ], - "demo_exports/sample_epcis.json": [ - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_epcis.json", - "hashed_secret": "9893566b528e851db48ebd07ae13aae9cb296839", - "is_verified": false, - "line_number": 28 - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_epcis.json", - "hashed_secret": "9c874e035a44d6ec5746fd3dbf817d02dd46248f", - "is_verified": false, - "line_number": 29 - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_epcis.json", - "hashed_secret": "ac9a367e9074c12555fb1ea7c16aed8b25c78323", - "is_verified": false, - "line_number": 49 - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_epcis.json", - "hashed_secret": "5bf25ee99829fd9516aeec76b4485734b1d7008b", - "is_verified": false, - "line_number": 50 - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_epcis.json", - "hashed_secret": "72e59fe6201bb3e5eceeea19e824a4d662ca1565", - "is_verified": false, - "line_number": 70 - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_epcis.json", - "hashed_secret": "69ca9a3ee55ac43cf5dc32e220d4ac9fdaf09585", - "is_verified": false, - "line_number": 71 - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_epcis.json", - "hashed_secret": "2991cb4254dea5a36f70902872eabe4d4ed7141b", - "is_verified": false, - "line_number": 91 - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_epcis.json", - "hashed_secret": "1a3661464bd172e9a29e41e37a6567e8c9491d77", - "is_verified": false, - "line_number": 92 - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_epcis.json", - "hashed_secret": "65070f7abfd0c96324d8e35fc4e4bb2b8ab1ffa9", - "is_verified": false, - "line_number": 112 - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_epcis.json", - "hashed_secret": "618adb767fb492bc7465ea710a51c9ea59b7d0fc", - "is_verified": false, - "line_number": 113 - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_epcis.json", - "hashed_secret": "8cc54e42c99573ba74f885e704a9838c6cdf821d", - "is_verified": false, - "line_number": 133 - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_epcis.json", - "hashed_secret": "8510845002be36248e54c26280418a186c55a14c", - "is_verified": false, - "line_number": 134 - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_epcis.json", - "hashed_secret": "3402bc06aaf1d2eca64a1af8ecadcdf16c1f3a89", - "is_verified": false, - "line_number": 154, - "is_secret": false - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_epcis.json", - "hashed_secret": "e0d59969a6521fb9bcb74668adbd752fe4e3c7cd", - "is_verified": false, - "line_number": 155, - "is_secret": false - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_epcis.json", - "hashed_secret": "9baa375ab3b7f4f350139e568493caa5680fffd4", - "is_verified": false, - "line_number": 175, - "is_secret": false - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_epcis.json", - "hashed_secret": "fa41cd85a07e313c59e51129caf240c2092abb36", - "is_verified": false, - "line_number": 176, - "is_secret": false - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_epcis.json", - "hashed_secret": "bdb5ad00810e1c77affd96c8e82ae547378658eb", - "is_verified": false, - "line_number": 196, - "is_secret": false - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_epcis.json", - "hashed_secret": "45bf27a2139c57b12c6c232bcd817649afe0cd85", - "is_verified": false, - "line_number": 197, - "is_secret": false - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_epcis.json", - "hashed_secret": "0d59310f785a96991a7f5dc51ad5d6289ec204f9", - "is_verified": false, - "line_number": 217, - "is_secret": false - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_epcis.json", - "hashed_secret": "e862d2e772ef0390ba7bbe388a2ef8621fd631a5", - "is_verified": false, - "line_number": 218, - "is_secret": false - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_epcis.json", - "hashed_secret": "e51b0b5f4d3db8f442e0cc528d839bbd595b50f6", - "is_verified": false, - "line_number": 238, - "is_secret": false - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_epcis.json", - "hashed_secret": "86c62f2290f39dc4a583821c443f995a80916871", - "is_verified": false, - "line_number": 239, - "is_secret": false - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_epcis.json", - "hashed_secret": "331666e19da230686a9cf201706266fc780c7176", - "is_verified": false, - "line_number": 259, - "is_secret": false - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_epcis.json", - "hashed_secret": "dfe63c8ec26fa82ea004850521a140e1d8b947bb", - "is_verified": false, - "line_number": 260, - "is_secret": false - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_epcis.json", - "hashed_secret": "76a4b85274e88565576f04338c7712f214b01ae8", - "is_verified": false, - "line_number": 280, - "is_secret": false - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_epcis.json", - "hashed_secret": "b16277d40350f8f6e2545275b22abc975e380c2c", - "is_verified": false, - "line_number": 281, - "is_secret": false - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_epcis.json", - "hashed_secret": "74893bb5bad265a128f58460c0f346ac667fc31e", - "is_verified": false, - "line_number": 301, - "is_secret": false - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_epcis.json", - "hashed_secret": "8ccc733b5d33cdc22427eab97841e06008497d0e", - "is_verified": false, - "line_number": 302, - "is_secret": false - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_epcis.json", - "hashed_secret": "edb0f7952cfe37aff48ab2e6347344a559a1b307", - "is_verified": false, - "line_number": 322, - "is_secret": false - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_epcis.json", - "hashed_secret": "f1b254706d48d1fcdeb6b562aa174fcf424ecbc1", - "is_verified": false, - "line_number": 323, - "is_secret": false - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_epcis.json", - "hashed_secret": "7e9274ccf853d190b748ccec8caed2956842e6dd", - "is_verified": false, - "line_number": 343, - "is_secret": false - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_epcis.json", - "hashed_secret": "adafb2b1e793b9d16afcf21ccd294302b45c92a9", - "is_verified": false, - "line_number": 344, - "is_secret": false - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_epcis.json", - "hashed_secret": "4518e7ea9db30b2e1ee4ca3b093fccaed1fb36b9", - "is_verified": false, - "line_number": 364, - "is_secret": false - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_epcis.json", - "hashed_secret": "c1a6b8a926f87ba9687145ec64c88682b8a15744", - "is_verified": false, - "line_number": 365, - "is_secret": false - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_epcis.json", - "hashed_secret": "83123693dbaea0b00062682711269cd3c9fb411b", - "is_verified": false, - "line_number": 385, - "is_secret": false - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_epcis.json", - "hashed_secret": "9f8f7f9de91666beffa380184ff8ac32aa6cc21a", - "is_verified": false, - "line_number": 386 - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_epcis.json", - "hashed_secret": "8f1246b4e3a56e4aa36936f5a754e6a6362888c1", - "is_verified": false, - "line_number": 406, - "is_secret": false - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_epcis.json", - "hashed_secret": "105ddf84723138a6bbd5978bf2828a26e468b173", - "is_verified": false, - "line_number": 407 - } - ], - "demo_exports/sample_fda_export.csv": [ - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_fda_export.csv", - "hashed_secret": "9893566b528e851db48ebd07ae13aae9cb296839", - "is_verified": false, - "line_number": 2 - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_fda_export.csv", - "hashed_secret": "9c874e035a44d6ec5746fd3dbf817d02dd46248f", - "is_verified": false, - "line_number": 2 - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_fda_export.csv", - "hashed_secret": "5bf25ee99829fd9516aeec76b4485734b1d7008b", - "is_verified": false, - "line_number": 3 - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_fda_export.csv", - "hashed_secret": "ac9a367e9074c12555fb1ea7c16aed8b25c78323", - "is_verified": false, - "line_number": 3 - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_fda_export.csv", - "hashed_secret": "69ca9a3ee55ac43cf5dc32e220d4ac9fdaf09585", - "is_verified": false, - "line_number": 4 - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_fda_export.csv", - "hashed_secret": "72e59fe6201bb3e5eceeea19e824a4d662ca1565", - "is_verified": false, - "line_number": 4 - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_fda_export.csv", - "hashed_secret": "1a3661464bd172e9a29e41e37a6567e8c9491d77", - "is_verified": false, - "line_number": 5 - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_fda_export.csv", - "hashed_secret": "2991cb4254dea5a36f70902872eabe4d4ed7141b", - "is_verified": false, - "line_number": 5 - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_fda_export.csv", - "hashed_secret": "618adb767fb492bc7465ea710a51c9ea59b7d0fc", - "is_verified": false, - "line_number": 6 - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_fda_export.csv", - "hashed_secret": "65070f7abfd0c96324d8e35fc4e4bb2b8ab1ffa9", - "is_verified": false, - "line_number": 6 - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_fda_export.csv", - "hashed_secret": "8510845002be36248e54c26280418a186c55a14c", - "is_verified": false, - "line_number": 7 - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_fda_export.csv", - "hashed_secret": "8cc54e42c99573ba74f885e704a9838c6cdf821d", - "is_verified": false, - "line_number": 7 - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_fda_export.csv", - "hashed_secret": "3402bc06aaf1d2eca64a1af8ecadcdf16c1f3a89", - "is_verified": false, - "line_number": 8, - "is_secret": false - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_fda_export.csv", - "hashed_secret": "e0d59969a6521fb9bcb74668adbd752fe4e3c7cd", - "is_verified": false, - "line_number": 8, - "is_secret": false - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_fda_export.csv", - "hashed_secret": "9baa375ab3b7f4f350139e568493caa5680fffd4", - "is_verified": false, - "line_number": 9, - "is_secret": false - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_fda_export.csv", - "hashed_secret": "fa41cd85a07e313c59e51129caf240c2092abb36", - "is_verified": false, - "line_number": 9, - "is_secret": false - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_fda_export.csv", - "hashed_secret": "45bf27a2139c57b12c6c232bcd817649afe0cd85", - "is_verified": false, - "line_number": 10, - "is_secret": false - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_fda_export.csv", - "hashed_secret": "bdb5ad00810e1c77affd96c8e82ae547378658eb", - "is_verified": false, - "line_number": 10, - "is_secret": false - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_fda_export.csv", - "hashed_secret": "0d59310f785a96991a7f5dc51ad5d6289ec204f9", - "is_verified": false, - "line_number": 11, - "is_secret": false - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_fda_export.csv", - "hashed_secret": "e862d2e772ef0390ba7bbe388a2ef8621fd631a5", - "is_verified": false, - "line_number": 11, - "is_secret": false - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_fda_export.csv", - "hashed_secret": "86c62f2290f39dc4a583821c443f995a80916871", - "is_verified": false, - "line_number": 12, - "is_secret": false - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_fda_export.csv", - "hashed_secret": "e51b0b5f4d3db8f442e0cc528d839bbd595b50f6", - "is_verified": false, - "line_number": 12, - "is_secret": false - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_fda_export.csv", - "hashed_secret": "331666e19da230686a9cf201706266fc780c7176", - "is_verified": false, - "line_number": 13, - "is_secret": false - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_fda_export.csv", - "hashed_secret": "dfe63c8ec26fa82ea004850521a140e1d8b947bb", - "is_verified": false, - "line_number": 13, - "is_secret": false - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_fda_export.csv", - "hashed_secret": "76a4b85274e88565576f04338c7712f214b01ae8", - "is_verified": false, - "line_number": 14, - "is_secret": false - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_fda_export.csv", - "hashed_secret": "b16277d40350f8f6e2545275b22abc975e380c2c", - "is_verified": false, - "line_number": 14, - "is_secret": false - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_fda_export.csv", - "hashed_secret": "74893bb5bad265a128f58460c0f346ac667fc31e", - "is_verified": false, - "line_number": 15, - "is_secret": false - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_fda_export.csv", - "hashed_secret": "8ccc733b5d33cdc22427eab97841e06008497d0e", - "is_verified": false, - "line_number": 15, - "is_secret": false - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_fda_export.csv", - "hashed_secret": "edb0f7952cfe37aff48ab2e6347344a559a1b307", - "is_verified": false, - "line_number": 16, - "is_secret": false - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_fda_export.csv", - "hashed_secret": "f1b254706d48d1fcdeb6b562aa174fcf424ecbc1", - "is_verified": false, - "line_number": 16, - "is_secret": false - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_fda_export.csv", - "hashed_secret": "7e9274ccf853d190b748ccec8caed2956842e6dd", - "is_verified": false, - "line_number": 17, - "is_secret": false - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_fda_export.csv", - "hashed_secret": "adafb2b1e793b9d16afcf21ccd294302b45c92a9", - "is_verified": false, - "line_number": 17, - "is_secret": false - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_fda_export.csv", - "hashed_secret": "4518e7ea9db30b2e1ee4ca3b093fccaed1fb36b9", - "is_verified": false, - "line_number": 18, - "is_secret": false - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_fda_export.csv", - "hashed_secret": "c1a6b8a926f87ba9687145ec64c88682b8a15744", - "is_verified": false, - "line_number": 18, - "is_secret": false - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_fda_export.csv", - "hashed_secret": "83123693dbaea0b00062682711269cd3c9fb411b", - "is_verified": false, - "line_number": 19, - "is_secret": false - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_fda_export.csv", - "hashed_secret": "9f8f7f9de91666beffa380184ff8ac32aa6cc21a", - "is_verified": false, - "line_number": 19 - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_fda_export.csv", - "hashed_secret": "105ddf84723138a6bbd5978bf2828a26e468b173", - "is_verified": false, - "line_number": 20 - }, - { - "type": "Hex High Entropy String", - "filename": "demo_exports/sample_fda_export.csv", - "hashed_secret": "8f1246b4e3a56e4aa36936f5a754e6a6362888c1", - "is_verified": false, - "line_number": 20, - "is_secret": false - } - ], "docs/architecture/CANONICAL_MODEL.md": [ { "type": "Hex High Entropy String", @@ -3334,15 +2750,6 @@ "line_number": 84 } ], - "qa/fixtures/bad/tampered-chain.json": [ - { - "type": "Hex High Entropy String", - "filename": "qa/fixtures/bad/tampered-chain.json", - "hashed_secret": "14c91ff72e5d5dd4ca4903849461da13e3def2ec", - "is_verified": false, - "line_number": 10 - } - ], "qa/qa-health/latest.json": [ { "type": "Hex High Entropy String", @@ -3370,85 +2777,6 @@ "line_number": 106 } ], - "sample_data/recall_fixture/sync_manifest.json": [ - { - "type": "Hex High Entropy String", - "filename": "sample_data/recall_fixture/sync_manifest.json", - "hashed_secret": "bac2b674d10072d29f11756ab326b44d989a54f0", - "is_verified": false, - "line_number": 4 - }, - { - "type": "Hex High Entropy String", - "filename": "sample_data/recall_fixture/sync_manifest.json", - "hashed_secret": "7e343a7b33f98afc42609894d9752373c6bb23c4", - "is_verified": false, - "line_number": 9 - }, - { - "type": "Hex High Entropy String", - "filename": "sample_data/recall_fixture/sync_manifest.json", - "hashed_secret": "1382ad88967598b29f32501f923f11f23bdd8496", - "is_verified": false, - "line_number": 14 - }, - { - "type": "Hex High Entropy String", - "filename": "sample_data/recall_fixture/sync_manifest.json", - "hashed_secret": "faa1dde042ccf81425cb06aaf9f1f0586839e60a", - "is_verified": false, - "line_number": 19 - }, - { - "type": "Hex High Entropy String", - "filename": "sample_data/recall_fixture/sync_manifest.json", - "hashed_secret": "04057e7828252ce2db4f5690f21043e5fba57a76", - "is_verified": false, - "line_number": 24 - }, - { - "type": "Hex High Entropy String", - "filename": "sample_data/recall_fixture/sync_manifest.json", - "hashed_secret": "9b27d1cfb845d7cb8ec4a387e51879514489a661", - "is_verified": false, - "line_number": 29 - }, - { - "type": "Hex High Entropy String", - "filename": "sample_data/recall_fixture/sync_manifest.json", - "hashed_secret": "eda807041164c59b7d3b4b08c1661755a3716132", - "is_verified": false, - "line_number": 34 - }, - { - "type": "Hex High Entropy String", - "filename": "sample_data/recall_fixture/sync_manifest.json", - "hashed_secret": "c85ed4cd6fadcc887b44362db2942649d883989d", - "is_verified": false, - "line_number": 39 - }, - { - "type": "Hex High Entropy String", - "filename": "sample_data/recall_fixture/sync_manifest.json", - "hashed_secret": "647a622116fc3456e1360eaddffed20b2c95cd52", - "is_verified": false, - "line_number": 44 - }, - { - "type": "Hex High Entropy String", - "filename": "sample_data/recall_fixture/sync_manifest.json", - "hashed_secret": "82ad4233f223148e21ee7f9949b8c40f563a53a8", - "is_verified": false, - "line_number": 49 - }, - { - "type": "Hex High Entropy String", - "filename": "sample_data/recall_fixture/sync_manifest.json", - "hashed_secret": "8f1dc2edf00f691e5ac46dfcaa3ea6a44fe6aa6d", - "is_verified": false, - "line_number": 54 - } - ], "scripts/check_alembic_revisions.py": [ { "type": "Hex High Entropy String",