Skip to content

Add governed PO approvals and ERP CSV exchange - #4

Merged
falltwo merged 5 commits into
mainfrom
codex/atomic-hitl-po-approval
Jul 20, 2026
Merged

Add governed PO approvals and ERP CSV exchange#4
falltwo merged 5 commits into
mainfrom
codex/atomic-hitl-po-approval

Conversation

@falltwo

@falltwo falltwo commented Jul 20, 2026

Copy link
Copy Markdown
Owner

Scope

This PR establishes the SQLite correctness boundary for governed purchase-order writes and adds an L3 V1 ERP CSV batch-exchange prototype on top of it. It does not claim that all ERP writes are governed, that external delivery is exactly-once, that the audit chain is immutable, or that the system is production-ready.

L3 V1 is intentionally narrow: one CSV row represents one purchase order with one item. It is not a generic ETL system, a real-time ERP API connector, or a promise of compatibility with every ERP.

What changed

Governed PO execution

  • Binds protected requests to a stable operation ID, canonical payload digest, resource version, and policy version.
  • Uses conditional approval transitions and unique execution receipts so replay returns the original result instead of repeating the PO effect.
  • Writes the PO header, item, execution receipt, action log, and final approval state in one BEGIN IMMEDIATE SQLite transaction.
  • Revalidates the current approver role, supplier eligibility, business inputs, and resource state at execution time.
  • Preserves the operation ID across Streamlit reruns and shows database-backed approval state.

L3 ERP CSV exchange

  • Strict UTF-8 fixed-schema import with file, row-count, type, date, identifier, supplier, and product validation.
  • Separate staging keyed by source system plus external ID; identical re-imports are idempotent and changed content creates a new revision.
  • Supplier country, region, and risk preview before submission.
  • Operation-bound human approval before insert or update of the local purchase order.
  • Immutable approved-action export from the persisted execution snapshot, not mutable staging.
  • External receipt reconciliation with unique attempt IDs, live RBAC, HMAC-SHA256 verification, retryable error/rejected states, and accepted-state non-downgrade.
  • Legacy unsigned accepted receipts are quarantined as unverified_legacy and can be recovered only by a new valid signed receipt.
  • Export, receipt-template, and reconciliation access events record the actor and a minimized operation-set digest in the hash-chained audit log.
  • Streamlit page for import, risk preview, staging, approval submission, action export, receipt template, reconciliation, and receipt history.
  • Connector-side signing helper: scripts/sign_erp_receipt.py.

Feature and deployment notes: docs/erp_csv_exchange.md

Safety properties covered

  • No protected PO effect occurs before approval.
  • Duplicate submissions reuse one operation; concurrent approval races produce one terminal decision and at most one PO effect.
  • Payload, operation identity, policy, resource version, supplier eligibility, staging digest, and immutable effect snapshot mismatches fail closed.
  • Failure inside the protected transaction rolls back the PO effect, receipt, log, and approval terminal state together.
  • Unsigned, wrong-key, wrong-digest, stale, tampered, or unauthorized external receipts do not produce an acknowledged state.
  • Previously approved revisions remain exportable and delayed valid receipts remain reconcilable after a newer revision is staged.

Verification

  • Focused approval and L3 suite: 78 passed
  • Full regression: 141 passed
  • Python compileall: passed
  • git diff --check: passed
  • Independent code review: PASS, no remaining Critical or Important findings
  • Security/governance review: PASS, no remaining Critical or Important findings
  • Final committed-change credential and private-data scan: clean; only environment reads, a documentation placeholder, and explicit test-only HMAC literals matched secret-related terms

Trust boundary and known limitations

  • The HMAC signer and secret must reside at the controlled ERP side or a controlled integration service. The secret must not be exposed to ordinary Web or warehouse operators, committed to the repository, placed in CSV files, or entered through the UI.
  • V1 supports one active key. A keyring, old-key verification window, and safe rotation workflow are not implemented.
  • If the Web host, SQLite administrator boundary, or HMAC secret is fully compromised, the receipt-source assurance can also be defeated.
  • Atomicity covers effects in the same SQLite database. External-system delivery is not claimed to be exactly-once.
  • The audit chain is traceable but not immutable against an attacker with full database and application-code control.
  • Other ERP write tools and the separate multi-item direct-SQL inventory path remain outside this PR.

Follow-ups

Demo repair verification (2026-07-20)

Live L1/L2/L3 preview uncovered and fixed two reproducibility defects: fresh databases did not encode every schema field required by the bundled demo seeder, and Pandas null values could crash risk-map hover rendering. The ERP export caption now also matches the immutable approved-snapshot behavior.

Migration evidence: a regression test constructs the prior purchase_orders and customers schemas with existing rows, runs init_db(), verifies the original data is unchanged, and confirms only the required columns/table are added.

Verification:

  • 146 passed
  • Python compile check passed
  • git diff --check passed
  • Isolated browser preview passed for L1 overview, L2 impact/What-if, and all L3 ERP exchange tabs
  • OpenCode Go completed a real What-if analysis over the isolated demo ERP data

Files in this follow-up commit:

  • .gitignore
  • backend/database.py
  • frontend/components/supply_map.py
  • frontend/page_erp_csv_exchange.py
  • scripts/seed_e_day1_demo_data.py
  • tests/test_erp_exchange_ui.py
  • tests/test_demo_seed_schema.py
  • tests/test_supply_map.py

@falltwo falltwo left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

check 1

@falltwo falltwo left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ALL CHECK

@falltwo falltwo changed the title Add atomic, idempotent purchase-order approvals Add governed PO approvals and ERP CSV exchange Jul 20, 2026
@falltwo

falltwo commented Jul 20, 2026

Copy link
Copy Markdown
Owner Author

Owner-bypass audit note

PR #4 is being considered for repository-owner PR-mode bypass because the only unsatisfied ruleset condition is one approving review, and the PR author cannot provide an independent self-review.

Evidence checked immediately before merge:

  • PR head: 701409fbb630ff847ce726d6715719e4e6ba7bf1
  • GitHub pytest check: SUCCESS on the same head
  • Fresh local full suite: 146 passed
  • Worktree: clean and synchronized with the remote head
  • Review threads: none open

Independent pre-publication review summary: the atomic approval, idempotency, ERP CSV exchange, secret-handling, and demo-consistency changes received separate code and security-governance review; identified release blockers were corrected before the current head, with no unresolved critical or important finding recorded. This summary is supplemental evidence and does not represent a formal GitHub approval.

The bypass is explicitly limited to this already-reviewed PR. The L1/L2/L3 entitlement and role-capability work will start from updated main on a new branch and will be submitted as a separate PR without inheriting this bypass. The merge will preserve all five commits and will not force-push, rewrite history, direct-push to main, or delete the source branch.

@falltwo
falltwo merged commit db3db44 into main Jul 20, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant