# Phase 3C — Commercial integrity audit and freeze

## Scope and baseline

Read-first audit of quotation, approval, technical/inventory gates, invoice
reconciliation/finalization, payment, allocation, receipt, settlement, due-release
and handover. Baseline: clean `master` at `66c15cb`, 1,943 passing tests, zero
failures/skips. Preflight status/log, Django check, migration drift and migration
inventory matched the required baseline; commercial migrations 0001–0006 were
applied. The prior CUSTOMER-to-WARRANTY fixture adjustment is frozen and unchanged.
No Phase 3D work, staging, commit or push is part of this audit.

## Architecture and authoritative evidence

Reviewed commercial models, services, gates, queries, Admin and all six migrations;
repair, inventory request/usage and handover integrations; actor/path locks; customer
lifecycle; and the SQL authorization engine. Existing feature tests were mapped to
the requirements before adding dedicated adversarial audit tests.

| Boundary | Authority and entry points |
| --- | --- |
| Commercial proposal | QuotationFamily, numbered ServiceQuotation revisions and QuotationLine snapshots; `commercial.services` create/update/set-lines/submit/revise |
| Customer decision | Immutable QuotationDecision for the exact submitted revision; `record_quotation_decision` |
| Work authorization | Persistent family approval obligation; current APPROVED revision and scope snapshot; `gating.require_commercial_authorization` records PERFORM/CONSUME/COMPLETE evidence |
| Physical consumption | PartsDisposition CONSUMED → StockMovement → reservation/issue and serialized unit links; inventory services remain authoritative |
| Billing | ServiceInvoice with retained InvoiceLine generations and explicit InvoiceAllocation; `invoice_services` prepare/reconcile/finalize |
| Money received | POSTED ServicePayment, one full PaymentAllocation and one original ServicePaymentReceipt, committed together |
| Correction | Immutable full PaymentReversal and POSTED→VOIDED transition; original receipt/allocation retained |
| Settlement | Finalized CUSTOMER liability minus POSTED allocations; SQL-derived state in `payment_queries` |
| Delivery exception | Immutable ServiceFinancialRelease amount/actor/time/reason; authorizes due, never settles it |
| Handover | Existing technical release plus fresh financial clearance under ServiceCase lock; no invoice requirement added to frozen invoice-free workflows |

Public query families: `commercial.queries`, `invoice_queries`, `payment_queries`.
Admin writes delegate to services through signed quotation/invoice/settlement
workflows; handover uses its existing signed confirmation form and the final gate.

## State machine and operation matrix

The ordinary commercial chain is DRAFT quotation → SUBMITTED → APPROVED → approved
performance/consumption → DRAFT invoice → reconciled invoice → FINALIZED → derived
settlement → financial clearance → DELIVERED → CLOSED. Draft invoice preparation
can precede QC, but finalization cannot. Planning is not performance.

| Commercial/service state | Allowed operations | Rejected operations / qualifications |
| --- | --- | --- |
| No quotation; eligible technical case | Frozen technical planning/performance/consumption; quotation creation while DIAGNOSED/REPAIRING | Invoice preparation without a current approved quotation; payments without finalization |
| DRAFT without established customer obligation | Metadata/lines/submit; frozen technical flow | Direct approval; invoice preparation; payment |
| DRAFT with customer obligation | Planning and draft edits | PERFORM, CONSUME, successful COMPLETE until current approval |
| SUBMITTED customer obligation | Record approval/rejection; create replacement | Submitted financial edits; unapproved performance/consumption/completion |
| Current APPROVED | Work within snapshotted scope; parts within approved quantity; invoice preparation/reconciliation | New/materially changed scope borrowing old approval; quantities above approved capacity |
| REJECTED or replacement DRAFT/SUBMITTED | Explicit revision/edit/submit/decision; planning | Old approval authorizing new work; removing CUSTOMER lines to clear established obligation |
| Warranty/company-only without customer obligation | Frozen technical work; approved proposal supports invoice | Warranty intake evidence alone creating a financial classification |
| DRAFT invoice; eligible undelivered case | Rebuild/reconcile retained generations | Payments; finalization before successful repair/QC or with unresolved consumed quantities |
| DRAFT invoice referencing obsolete quotation | Rebuild against current approval | Reconcile/finalize against obsolete terms |
| FINALIZED, UNPAID/PARTIALLY_PAID | Positive payments up to remaining due; authorized release after QC; permitted reversal | Invoice/line edits; overpayment; ordinary handover |
| FINALIZED, PAID | Handover; permitted correction reversal | Extra payment, fake release, invoice amendment |
| FINALIZED, NO_CUSTOMER_DUE | Handover with no payment | Artificial zero payments/receipts; collection of WARRANTY/COMPANY value |
| Adequate due-release, still unpaid | Handover; later collection already supported by frozen services | Treating release as payment or removing debt from outstanding reports |
| Payment VOIDED | Read payment, allocation, receipt and reversal history | Repeated reversal; counting voided allocations; reuse of reserved external reference |
| DELIVERED/CLOSED | Historical reads and frozen debt collection; reversal only with adequate prior release coverage | Retroactive invoice amendment; reversal creating an uncovered delivered balance |
| No FINALIZED invoice, including draft-only | Existing permitted handover behavior | Inferring that absent classification means free/warranty/company coverage |

Audit scenarios explicitly retain consumption movement and approved-line provenance,
not just terminal case status. They cover customer-paid parts repair, warranty value,
mixed payer allocation, partial/final-cent settlement, due-release through closure,
and reversal before delivery. Frozen tests additionally cover company-only value,
serialized units, replacement scope and invoice-free histories.

## Financial invariants and enforcement boundaries

- Submitted quotation content is immutable; decisions identify one revision. The
  family approval obligation is monotonic. Approval does not reserve or consume stock.
- Current approval, unchanged action scope and approved part quantities are checked
  under the case lock at performance, consumption and successful completion.
- Invoice PART quantity is supported by actual CONSUMED evidence, bounded by both
  source quantity and approved line quantity. Ambiguity requires manual allocation
  with reason. LABOR/SERVICE require explicit confirmation. Current approved terms
  determine payer, price, discount and tax; all consumed quantity must be resolved
  before finalization. Unused RETURNED custody is not reversal of consumed parts.
- Payer totals sum exactly to grand total. Only CUSTOMER value is collectible.
  Existing money utilities use exact Decimal, cent precision and per-line rounding.
  Partial billing proportionately rounds approved discounts upward. Tests cover
  0.01, final-cent settlement, discounts/tax, maximum values and invalid floats.
- Each received payment is invoice-specific and fully allocated once. Positive
  amount cannot exceed remaining debt. Currency/center/customer/company derive
  from the immutable invoice chain; independent browser payer/allocation inputs
  cannot substitute other evidence. There is no credit wallet or overpayment balance.
- `liability - sum(POSTED allocations) = balance`. NO_CUSTOMER_DUE, UNPAID,
  PARTIALLY_PAID and PAID are derived, never independently editable. Separate SQL
  aggregates prevent join multiplication when reversals and releases coexist.
- Full correction reversal preserves payment, allocation and original receipt.
  Nonblank center/method/reference uniqueness remains reserved after reversal.
- Due-release is amount-bounded authority, not money. It neither changes invoice
  liability nor reduces reported debt, including after delivery and closure.
- Handover checks fresh evidence after the case lock. Payment event revisions
  remain changed even when a payment plus reversal returns the balance to its
  original amount; stale requests cannot exploit that apparent equality.

Database enforcement includes positive/local values, monetary identities, numbering
and one-to-one uniqueness, history guards, submitted/finalized immutability,
deferred quotation/invoice totals, invoice source coherence, and coherent committed
payment/allocation/receipt/reversal records. Direct ORM adversarial tests exercise
these protections. Case-level capacity, complete consumption coverage, eligibility,
scope authorization and payment aggregate over-allocation are service invariants.
Private integration helpers assume a trusted caller holding the documented lock.
Privileged raw SQL is not claimed to enforce every cross-table business rule.

## Authorization, isolation and lifecycle review

Distinct manage-quotation, record-decision, manage-invoice, finalize-invoice,
receive-payment, reverse-payment and authorize-due-release permissions are checked
against the authoritative ServiceCenter. Public reads require their respective view
permission and SQL scope filtering. Permission and organizational scope must come
from one valid assignment/role path. Tests combine a company-wide view-only path
with another center's financial capabilities and verify all financial mutations fail.

New scope tests exercise Company, Region and Center+Department postings through real
receive/read/reverse/release services. Frozen authorization tests cover the full
containment matrix, invalid paths, company/center isolation, inactive actors,
staff/Groups/direct permissions and active-superuser semantics. Engineer eligibility
does not grant commercial authority. Native Admin permission is additionally required.

Actor, Company, assignment and Role locks serialize supported revocations. New races
deactivate the actor before approval, finalization, receipt, reversal and due-release
and verify no forbidden evidence commits. Existing races cover role-permission
revocation and organizational lifecycle. Inactive Customer/Device do not erase
financial history or prevent frozen debt collection; operational handover still
requires eligibility. Inactive organizational paths block operational financial
writes; immutable database history remains. Active superusers retain the frozen
historical scope bypass, while ordinary scoped reads reflect current valid paths.

## Concurrency and lock review

Shared dependencies precede the ServiceCase write lock. Technical/inventory writers
then lock their case children and stock resources. Commercial gates run inside those
transactions without reacquiring earlier dependencies. Quotation writes take actor,
Company/path/Role, catalog/Device and referenced part locks, then Case, family,
revision and children. Invoice writes take actor/path dependencies, Case, invoice
and reconciliation evidence; finalization also locks existing technical history.
Payment writes take actor/path dependencies, Customer SHARE, Case, invoice, then
payment or center receipt counter. Handover takes Customer/catalog/Device before
Case and evaluates settlement without acquiring earlier dependency locks.

One real lock-upgrade defect was reproduced and fixed (C3-01 below). The invoice
case query already uses `FOR UPDATE OF self`; quotation now follows that discipline.
Customer edits use Company coordination; Device dependencies retain their explicit
shared locks. Joined display rows therefore need no new exclusive lock at Case.

New independent-connection schedules cover overlapping quotation edits; replacement
removing CUSTOMER lines versus repair; approval versus performance and consumption;
new consumption versus old invoice reconciliation; finalization versus reconciliation
and payment; competing payment methods; posting versus reversal; last-cent payment,
reversal and release versus handover; and five actor-revocation boundaries. They
assert committed statuses, amounts, provenance and evidence counts. Ordered races
use the frozen harness's PostgreSQL blocking-PID checks. The deadlock regression uses
a barrier after both Device SHARE locks, exposing overlap before either case write.

Existing quotation/invoice/payment concurrency modules cover complementary orderings,
finalization versus consumption, same/different-center counters, duplicate references,
stale Admin submissions, reversal-first schedules and rollback with waiting writers.
Passing these schedules is not a formal proof of deadlock freedom for every possible
transaction, caller or privileged SQL operation.

## Rollback and numbering

Quotation EST, invoice INV and receipt RCT counters are center-scoped locked rows,
not MAX()+1. Unique constraints protect committed numbers. Creation failures roll
back counters; committed receipt numbers survive reversal without reuse. Existing
tests exercise concurrent same/different-center allocation and rollback.

New fault injection after replacement revision creation proves the old approval
remains current when copying fails. Failure after invoice allocation creation proves
the invoice, lines, allocations and counter all roll back. Frozen tests inject
failures at quotation submission/approval, invoice finalization, payment/allocation/
receipt creation, reversal and release, including waiting concurrent transactions.

## Admin and query review

Mutations require POST and native permission plus service authorization. Signed tokens
bind actor/revision where the frozen workflow specifies; financial tokens cannot be
transferred between actors. Forged IDs, posted receipt edits and CSRF-free reversal/
release requests are rejected. Audit tests verify stale submit/approval, invoice
reconciliation after quotation replacement, due-release after payment, and a handover
form loaded while PAID then submitted after reversal. The last case is rejected by
the fresh service gate even if technical form facts did not change.

Queries are lazy where expected, ordered deterministically and filtered by SQL scope.
New query budgets measure quotation history/list (one query), quotation detail with
lines (two), invoice list/allocation list (one), nonserialized invoice detail with
provenance (four), settlement and receipt lists (one). Existing tests measure
serialized detail and populated Admin displays, including row-growth budgets. No
financial caching or query-related production change was introduced. Free text uses
the existing escaped templates; no payment authentication fields were added.

## Findings by severity

### C3-01 — MEDIUM — Quotation dependency lock upgrade deadlock (fixed)

- **Invariant:** dependency-first locks must not upgrade joined dependency rows after
  both transactions have taken compatible shared locks.
- **Reproduction:** two independent transactions edit the same DRAFT quotation with
  its original revision token. A barrier holds both after acquiring Device SHARE.
  The unqualified joined Case `SELECT FOR UPDATE` upgrades Device to an exclusive
  lock while the other transaction retains SHARE. PostgreSQL reported an actual
  `DeadlockDetected` error in the new regression before the fix.
- **Impact:** a legitimate overlapping quotation operation aborts unexpectedly;
  transactions roll back, so no financial corruption was observed. Classified as
  availability/operational integrity, not data theft or silent monetary corruption.
- **Fix:** restrict the Case query to `select_for_update(of=("self",))`. Keep all
  earlier dependency locks and existing stale-revision/authorization validation.
- **Regression:** `CommercialLockAudit.test_overlapping_quotation_edits_do_not_upgrade_dependency_locks`.
  After the fix exactly one edit commits, the other receives the expected stale
  ValidationError, and the persisted quotation and totals remain valid.
- **Residual limitation:** this schedule is evidence for this defect, not a proof
  of universal deadlock freedom. No migration or baseline-test change is needed.

No other production fix is included. C3-01 is resolved. No unresolved CRITICAL,
HIGH or MEDIUM finding remains within the audited scope and stated limitations.

## Accepted boundaries (INFO)

No general ledger/chart of accounts, external gateway/processor refund, bank
reconciliation, wallet, deposits/advances, retrospective invoice correction or
finalized-invoice amendment exists. Full payment reversal is a recorded correction,
not an external transfer. There is no consumed-part reversal in the frozen usage
model; unused returns cannot be treated as such. Due-release is an immutable
amount-bounded exception without expiry/revocation in this phase. Invoice-free and
draft-only compatibility remains intentional, not evidence of zero liability.
Existing post-delivery collection is preserved; no new collection feature was added.
Currency labels retain the frozen two-decimal contract; no FX engine was introduced.
Privileged raw writes and untested lock schedules retain the limits described above.

## Migration, security scan and final verification

No schema change is needed and no migration is added. Historical migration contents
and all 1,943 baseline tests must remain byte-for-byte unchanged. Final verification
includes complete migration of a fresh PostgreSQL test database, migration drift,
all applied migrations, Django checks and Git whitespace checks.

The bounded scan covers every changed/new file for private-key/token/credential-URL
patterns and unexpected artifacts, with explicit `.env` ignored/untracked checks.
This is a bounded source scan, not a promise that arbitrary future user free text
can never contain sensitive data. Financial forms retain their credential warnings.

Final verification on 2026-09-28:

- One complete `python manage.py test --noinput` command after the last production
  or test change passed **1,986 tests** in **3,975.176 seconds** (66 minutes 15 seconds).
- **1,943 baseline tests unchanged; 43 audit tests added; 0 failures/errors; 0 skips.**
- **17 additional PostgreSQL concurrency tests** passed, including the reproduced
  lock-upgrade regression. The final run contains all feature and audit tests.
- An earlier full run was interrupted without a completion result and is not counted.
  The successful replacement run recreated the leftover test database, applied the
  complete migration chain from zero and destroyed the test database on completion.
- Final Django checks and migration-drift checks pass. Commercial migrations through
  0006 are applied. No historical migration or baseline test was changed.
- The bounded scan of all five changed/new files found zero secret-pattern matches
  and zero suspicious artifact paths. `.env` remains ignored and untracked.
- Git whitespace checks pass. Tracked diff: one file, three insertions and one
  deletion. Four new audit files are listed below and excluded from that diff stat.
  All changes remain unstaged; HEAD remains `66c15cb` on `master`.

Full-run output is retained outside the repository in the system temporary file
`c-care-phase3c4-full-suite.log`. No staging, commit, push or Phase 3D work occurred.

## Exact changed-file inventory

Modified:

- `apps/commercial/services.py` — Case-only quotation write lock; no business rule change.

New (excluded from ordinary `git diff --stat` until staged):

- `tests/test_phase3c_audit.py` — end-to-end, money, evidence, rollback, queries and scope tests.
- `tests/test_phase3c_admin_audit.py` — forged/stale cross-domain Admin requests.
- `tests/test_phase3c_concurrency.py` — overlapping dependency-lock regression and cross-module races.
- `docs/PHASE_3C_AUDIT.md` — this audit record.
