# Phase 3A.7 — End-to-End Service Workflow Audit & Freeze

## 1. Executive summary

This audit treats intake, assignment, diagnosis, repair, independent QC, release,
physical custody transfer and closure as one system. It adds integration, transition,
rollback, two-session Admin and adversarial PostgreSQL tests. No new workflow,
state, production module, schema or authorization abstraction is introduced.

The final complete regression passed **1,298 tests, 0 failed, 0 skipped** after the
last test implementation change. No unresolved CRITICAL/HIGH/MEDIUM finding remains
in this bounded audit. Phase 3A is ready for the user's manual freeze commit;
existing LOW deployment warnings and INFO limitations remain documented below.

## 2. Baseline commit

Verified clean `master` at **a58093e47e5b734f1072fe5d713d0202ff7c663d**,
`feat: add service handover and closure workflow`, using `git status` and
`git log --oneline -10`. Baseline: **1,233 tests**.

The previously approved Phase 3A.6 change from `status="CLOSED"` to
`status="INVALID"` is already part of this baseline; its IntegrityError assertion
is unchanged. This audit changes no existing baseline test. No commits are rewritten.

## 3. Scope and evidence

Reviewed `apps/service` models, services, locks, all six query modules, Admin
workflows, templates, migrations 0001–0006, existing tests and phase documentation;
also reviewed the relevant frozen authorization, organization, taxonomy, catalog,
Customer/Device, ownership and production-setting dependencies.

New evidence resides in:

- `tests/test_phase3a_audit.py`: real-state transition matrix, integrated histories,
  rollback, isolation, identity/warranty/ownership and query budgets.
- `tests/test_phase3a_admin_audit.py`: two-session stale forms, terminal gates,
  authentication/CSRF, GET mutation attempts and forged UUIDs.
- `tests/test_phase3a_concurrency.py`: additional cross-phase competing transactions
  using the existing actual PostgreSQL lock-wait methodology.

The 1,233-test baseline supplies detailed per-field validation, scope matrices,
taxonomy applicability and individual constraint coverage. New tests complement
these instead of duplicating every baseline assertion. This is a bounded source
and executable integration audit, not penetration testing or formal verification.

## 4. Architecture and frozen boundaries

ServiceCase remains the stable Customer/Device/Company/Center intake record.
Assignment periods, diagnostic assessments/findings, repair attempts/actions,
QC attempts/checks, release, handover/accessory acknowledgements and closure are
separate protected evidence. No ownership fields or transfer operations are added
to handover. UUID Device identity survives identifier corrections.

`git diff c40e100..a58093e --name-only` restricted to `apps/access`, `accounts`,
`organization`, `catalog`, `service_catalog`, `customers`, and `devices` returned
no changes. Thus the committed Phase 3A series did not modify those frozen Phase
1/2 source trees. This audit likewise changes none of them.

RootCause remains nullable unknown/unconfirmed. No fabricated master is created.
QC independence and the distinct technical-duty versus administrative-superuser
semantics remain unchanged. All work uses the existing default PostgreSQL database.

## 5. Lifecycle transition matrix

Each row lists **all permitted state-changing service operations** at that state.
Every omitted transition is rejected. Conditions such as eligibility, completeness,
fresh revision and exact case/assignment membership still apply to permitted cells.

| Current state | Permitted transition operations → result |
| --- | --- |
| RECEIVED | assign → ASSIGNED; cancel → CANCELLED |
| ASSIGNED | reassign → ASSIGNED (new period); unassign → RECEIVED; begin diagnosis → DIAGNOSING; cancel → CANCELLED |
| DIAGNOSING | complete diagnosis → DIAGNOSED; abandon diagnosis → ASSIGNED; cancel → CANCELLED |
| DIAGNOSED | begin repair → REPAIRING; cancel → CANCELLED |
| REPAIRING | complete REPAIRED → REPAIRED; complete NOT_REPAIRED → DIAGNOSED; abandon repair → DIAGNOSED; cancel → CANCELLED |
| REPAIRED | submit QC → QC_PENDING |
| QC_PENDING | begin QC → QC_IN_PROGRESS |
| QC_IN_PROGRESS | PASS → QC_PASSED; FAIL → DIAGNOSED; abandon QC → QC_PENDING |
| QC_PASSED | release → READY_FOR_DELIVERY |
| READY_FOR_DELIVERY | physical handover → DELIVERED |
| DELIVERED | close → CLOSED |
| CLOSED | None |
| CANCELLED | Repeated cancellation is an idempotent no-op; no transition out |

The executable `TRANSITIONS` matrix exercises **26 operations across 13 states**
(338 subtests within 13 state tests). It includes all 19 transition operations and
seven representative non-transition writes: intake edit, intake condition/accessory,
complaint removal, diagnostic note, repair note and QC summary. The first four are
RECEIVED-only; the latter three require their respective open technical states.
Per-finding/action/check validation is additionally covered by the baseline.

States are constructed through actual services, not by writing the status column.
Valid operations assert resulting state/current records; invalid operations assert
controlled failure and unchanged database snapshots. Successful probes roll back
before testing the next cell. This catches all specified mandatory-stage skips,
including direct delivery from QC_PASSED and closure from READY_FOR_DELIVERY.

## 6. Cancellation matrix

| State | Cancel | Atomic effects |
| --- | --- | --- |
| RECEIVED | Yes | Timestamp/reason; no technical records |
| ASSIGNED | Yes | Ends current engineer period |
| DIAGNOSING | Yes | Abandons assessment with reason and ends assignment |
| DIAGNOSED | Yes | Retains completed diagnosis and ends assignment |
| REPAIRING | Yes | Abandons open repair and ends assignment; retains actions |
| REPAIRED | No | No mutation |
| QC_PENDING | No | No mutation |
| QC_IN_PROGRESS | No | No mutation |
| QC_PASSED | No | No mutation |
| READY_FOR_DELIVERY | No | No mutation |
| DELIVERED | No | No mutation |
| CLOSED | No | No mutation |
| CANCELLED | Idempotent | Existing facts retained |

Cancellation after QC FAIL is allowed because the case has returned to DIAGNOSED.
There is no exception permitting cancellation after QC PASS or custody transfer.
Assignment, diagnosis, repair and QC open-record counts are checked against state.

## 7. Authorization results

Engineer work requires `service.handle_servicecase` through an active same-path
posting/Role/permission. Company, Region, exact Center and Center+Department qualify
under the established rules; Department-only and Region+Department without Center
do not. Wrong Company/Region/Center and inactive User/posting/organization/Role fail.
Permission cannot be borrowed from a different scope path. Revocation prevents
subsequent technical writes while preserving completed evidence.

QC independently requires `service.perform_quality_control`, a valid same-path
posting, and an inspector different from the engineer on the exact repair period.
Only the responsible inspector may change an open attempt. Staff, Groups, direct
permissions and superuser status alone do not confer engineer/QC duty. Existing
scope and independence tests are retained and included in the full regression.

Release/delivery and closure use the frozen `require_permission` against the case
ServiceCenter with `service.handover_servicecase` and `service.close_servicecase`.
Here the established active-superuser bypass applies, without bypassing domain
lifecycle/prerequisites. Native `has_perm()` and backend behavior are unchanged.

## 8. Company/Center isolation and trusted boundaries

New fixtures contain two independent Company/Region/Center trees and a sibling
Center. Mixed Customer/Center/Device-affinity intake inputs reject. Actors with only
foreign-Company or sibling-Center granting paths cannot diagnose, update QC or
release the target case; engineer/QC/delivery operational queries exclude it.
Existing tests cover foreign complaint/finding/action/QC child references.

An unowned/unaffiliated Device is a global registry record, not implicitly owned
by the current Company. Intake rejects foreign OWNER history; it does not invent
affinity when no ownership exists. Presenting Customer need not be Device owner.

**Trusted APIs are not end-user authorization endpoints.** Intake, assignment
administration, recovery/cancellation and raw historical queries have documented
caller-authorization responsibilities. Earlier native Admin pages are trusted
administration and are not universally business-Company-scoped. QC and delivery
pages add their explicit scoped gates. This intentional distinction is preserved,
not silently replaced with a new architecture. Future handlers must authorize
before exposing trusted raw histories or accepting foreign UUIDs.

## 9. End-to-end scenarios

The golden path checks each state, current assignment/open children, actors,
ordered timestamps and exact evidence references from actual intake through CLOSED.
It uses FaultDiagnosis with NULL RootCause throughout, verifies zero RootCause
masters, reconciles two accessory types/quantities, and ends assignment exactly
at delivery time with the handover actor.

Rework retains the first REPAIRED execution and FAILED QC byte-for-field unchanged,
creates distinct second repair/QC attempts, then reaches delivery/closure. Ordering
and passed-QC release linkage remain deterministic. A separate integrated scenario
abandons diagnosis, abandons repair, completes NOT_REPAIRED, abandons QC, retries
each stage and ultimately closes. None of those attempts is deleted.

Warranty coverage added after intake does not alter the original uncovered
snapshot. A separately covered case retains its snapshot after clearing coverage,
replacing dates/reference and adding purchase evidence. Ownership assignment and
transfer do not change the case's presenting Customer/Device/creator or trigger
another ownership change during delivery.

Identifier replacement before release retains the same Device UUID and technical
chain; release captures the then-current identity digest. Another correction after
release blocks handover, including with a freshly computed digest, because the
immutable release no longer matches. Recovery is explicitly out of scope.

## 10. Historical integrity and deletion

Ordinary `.save()`/`.delete()` are rejected for service evidence. Finalized parent
and child validation protects historical facts; referenced Customer, Device,
Center, actors, taxonomy, diagnosis, repair, QC and handover are PROTECT-linked.
The audit attempts ORM saves/deletes across the closed chain and Django deletion
collection across protected references. QuerySet deletion is guarded separately
by existing tests. The internal job-number sequence is mutable coordination data,
not immutable customer history.

Three distinct guarantees apply:

1. Supported services/Admin enforce lifecycle, eligibility, revisions and immutable
   finalized evidence.
2. Model validation and database constraints protect specified fields, references,
   cardinalities, enums, outcomes and local timestamps.
3. Privileged raw SQL, bulk/update operations, private persistence and database
   owners can bypass some application contracts. A rollback-contained audit test
   demonstrates that QuerySet.update can alter a closure note. This is not a
   tamper-proof ledger, and private methods are not supported mutation APIs.

Historical taxonomy uses protected references, not universal name snapshots;
later activity changes do not rewrite evidence or require historical taxonomy to
remain active. QC checklist labels/policy are versioned snapshots. Completed NULL
RootCause cannot be enriched through ordinary editing.

## 11. Transaction and rollback results

Late injected failure at final ServiceCase persistence verifies rollback of child
records and state for assignment, diagnosis start/completion, repair start/completion,
QC submit/start/PASS, release, handover/assignment ending and closure. Separate
probes cover QC FAIL, cancellation, and intake warranty failure after job allocation.
Whole-service-table snapshots detect partial evidence, counters and timestamps.
For the QC FAIL probe, the separately recorded failed check is enclosed in the
test's outer transaction; the service itself only atomically finalizes the attempt.

Cancellation/rework invariants and baseline failure-injection tests remain in the
full regression. No application rollback behavior was changed by this audit.

## 12. Additional PostgreSQL concurrency

New transaction tests use separate connections and the existing harness that
observes `pg_blocking_pids`, with bounded waits and explicit expected domain failure
or success. They do not simply call the old concurrency tests.

| Cross-phase race | Verified serialization outcomes |
| --- | --- |
| Assign / cancel | Assign-first then cancellation ends its period; cancel-first denies assignment |
| Diagnosis completion / engineer-role revocation | Completion-first retained; revocation-first denies completion |
| Repair completion / cancel | Successful completion prevents later cancellation; cancellation prevents completion |
| Repair completion / RepairAction deactivation | Completion-first remains evidence; deactivation-first rejects completion |
| QC start / assignment mutation | Assignment change is forbidden at QC_PENDING; QC start remains valid |
| QC PASS / FAIL | First finalized result survives; contender cannot overwrite |
| QC PASS / Device lifecycle | PASS-first remains history; inactive-Device-first rejects PASS |
| Release / cancellation attempt | Cancellation remains forbidden before and after release |
| Delivery / stale release edit | Immutable release edit rejects; delivery remains coherent |
| Delivery / assignment mutation | Assignment mutation rejects; delivery ends its period atomically |
| Closure / duplicate closure | Exactly one closure |
| Closure / stale handover edit | Immutable handover edit rejects; closure remains coherent |

Meaningful reverse orders are included. Evidence-edit probes deliberately attempt
private persistence under case coordination to test immutable history against
finalization; they are not new public editing workflows. Rejected-first probes hold
the existing case lock after rejection to observe serialization of the contender.
Tests assert current/open-record coherence after each race. No formal deadlock
freedom or exhaustive scheduling guarantee is claimed.

## 13. Lock-order review

`S` means PostgreSQL SHARE; `U` means UPDATE. UUID sets are locked in stable order.

| Workflow | Effective lock order |
| --- | --- |
| Intake | acting User S → Company S → Center U → Customer S → catalog Brand/Category/Model/optional Variant S → Device U → job sequence U → new case/snapshot |
| Assignment/reassignment | actor/candidate Users S sorted → Company S → candidate posting paths S → Roles S → case U → current assignment U |
| Unassignment | actor User S → case U → current assignment U |
| Diagnosis | actor S → Company/posting/Role S → catalog S → Device S → FaultDiagnosis/optional RootCause S → case U → assignment U → assessment U → finding rows |
| Repair | actor S → Company/posting/Role S → catalog S → Device S → RepairAction S → case U → assignment U → diagnosis U → execution U → actions U |
| QC | inspector S → Company/posting/Role S → catalog S → Device S → case U → assignment U → diagnosis U → repair U → QC U → checks U |
| Release/delivery | actor S → Company/posting/Role S → Customer S → catalog S → Device S → case U → assignment U → diagnosis U → repair U → QC U → release/evidence → accessories U |
| Closure | actor S → Company/posting/Role S → case U → current-assignment check → diagnosis U → repair U → QC U → release U → handover U → accessories/acknowledgements U → closure |
| Cancellation/recovery | active actor S where required → case U → assignment U → diagnosis/repair/QC in existing parent order; no late catalog/taxonomy locks |

Company coordination excludes supported Center/Region movement and lifecycle
changes. Technical writers acquire taxonomy before case; recovery does not acquire
taxonomy behind case. Delivery does not acquire a late engineer-User UPDATE when
ending the assignment. Closure uses historical evidence without Customer/catalog/
Device locks after physical custody has already transferred.

Compared against supported organization/User/role, taxonomy and Device writers;
no credible new inversion was identified in the reviewed paths. This is bounded
review plus exercised races, not proof against arbitrary surrounding transactions,
raw writers or all future lock combinations.

## 14. Admin security and revisions

Two authenticated sessions capture the same workflow page; one advances the domain
state, and the other's stale assignment, diagnosis, repair, QC, release, handover or
closure submission is rejected without changing newer evidence. Existing tests
also cover aggregate child edits, signature tampering and authorization revocation.

All workflow endpoints require native authenticated Admin access and POST/CSRF for
mutation. Native permissions and technical/business checks remain separate. GET
parameters do not mutate; nonexistent forged case UUIDs return 404. CLOSED and
CANCELLED reject every workflow POST and raw ServiceCase change POST while permitted
historical GETs remain readable. No generic status editor or evidence deletion is
introduced. Forms use explicit whitelists and request-user/server actor/time values.

## 15. Query isolation and performance

Reviewed all public helpers in `queries`, `engineer_queries`, `diagnostic_queries`,
`repair_queries`, `quality_control_queries` and `handover_queries`.

| Query family | Scope and activity semantics |
| --- | --- |
| Intake Customer/Device/Center/job/search | Trusted historical filters; search explicitly requires Company; active intake means RECEIVED only |
| Engineer eligibility/queues | Fresh valid duty path and active hierarchy; assigned engineer and operational states; no superuser duty bypass |
| Diagnosis/repair histories and child sets | Trusted case/parent reference filters; completed/inactive historical evidence retained |
| Diagnosis/repair operational queues | Reuse engineer-scoped SQL and appropriate state |
| QC eligibility/queues | Inspector posting, permission and independence; state/repair constraints |
| QC visible cases | Scoped history independent of workflow state; current granting path still required |
| QC history/checks/latest/failed | Trusted parent/case filters, joined relations and deterministic ordering |
| Delivery authorized cases/actor queues | Frozen SQL ServiceCenter authorization; readiness versus closure capability as documented |
| Delivery detail/history and actor-less queues | Trusted internal filters, including representative collection under presenting Customer |

Historical helpers intentionally do not hide evidence merely because upstream
records become inactive. They must not be exposed as unauthenticated ID lookups.
Native trusted Admin disclosure is not misrepresented as an end-user scoped API.

Measured audit budgets (evaluation plus representative related display):

| Evaluation | SQL queries |
| --- | ---: |
| Center RECEIVED intake queue | 1 |
| Engineer assigned queue | 1 |
| Diagnosis history | 1 |
| Repair history | 1 |
| Scoped QC pending queue | 1 |
| QC attempt history/detail | 1 |
| Scoped ready/delivered/closed queues | 1 each |
| Single completed-case reconstruction including original complaints, conditions, intake accessories, identifiers, assignment, diagnosis/findings, repair/actions, QC/checks/complaints, handover/acknowledgements and closure | 16 |

The 16-query reconstruction composes existing helpers; it is not a new reporting
API and is measured for one complete case, not claimed as constant for arbitrary
multi-case/rework reporting. Baseline tests additionally measure joined findings,
actions, QC checks/complaints, recipient/actor and closure display. Admin histories
use existing prefetches for child collections. No measured defect justified a
production query change, so there is no before/after optimization claim.

## 16. Database and migration integrity

Reviewed enum/status constraints, unique current assignment/open assessment/open
repair/open QC, assignment and outcome timestamp coherence, NULL-aware active
finding uniqueness, active action uniqueness, checklist/complaint uniqueness,
controlled recipient/verification coherence, unique release/handover/closure and
accessory acknowledgements, positive intake/nonnegative returned quantities.

Direct unsupported status updates (`INVALID`, `REOPENED`, lowercase `closed`, empty)
must fail at the database boundary. Cross-table stage prerequisites, applicability,
same-path authorization, returned ≤ received and complete closure evidence remain
transactional service guarantees; PostgreSQL accepting a valid enum does not imply
that raw status updates are a supported lifecycle API.

No migration is created or edited. Required applied service graph:
0001_initial → 0002_engineer_assignment → 0003_diagnostic_assessment →
0004_repair_execution → 0005_quality_control → 0006_handover_closure.
Final verification applies the entire graph to a fresh PostgreSQL test database.

## 17. Bounded security review

Reviewed IDOR/mixed-object handling, scope/privilege separation, CSRF, signed
revisions, mass assignment, arbitrary status writes, deletion, isolation, SQL
construction, rendering and secret disclosure. ORM predicates parameterize user
values. The small raw lock helpers quote metadata-derived table names and bind IDs;
no user-controlled SQL identifiers are accepted. Templates retain autoescape and
format_html/format_html_join for constructed markup; no unsafe-rendering or CSRF
exemption was found in the reviewed service paths.

Normal operations attribute actors from trusted caller/session and timestamps from
the server. Recipient data is minimal bounded free text with privacy instructions;
this does not automatically detect every possible credential. No external identity
authentication, OTP, document uploads or production penetration testing is claimed.

## 18. Secret and artifact hygiene

Initial bounded scan covered **197 tracked text files** without printing values.
No high-confidence credential-pattern candidates or tracked `.env`, database dump,
cache/debug/log artifact candidates were found. `.env` is ignored. New fixtures use
synthetic names/references only. Final changed-file and status review checks that
only the intended audit tests/report remain; no generated runtime report is tracked.
This does not claim an exhaustive scan of Git history or every possible secret.

## 19. Findings by severity and fixes

| ID | Severity | Finding / disposition |
| --- | --- | --- |
| A7-01 | LOW, existing | Production HSTS subdomains/preload warnings W005/W021 remain. Deployment-domain policy must be decided by operators; settings unchanged. |
| A7-02 | INFO, existing boundary | Trusted raw queries/native administration are not universal Company authorization. Caller responsibility remains explicit. |
| A7-03 | INFO, existing boundary | Raw/bulk/private writes can bypass some application immutability; not a tamper-proof ledger. Demonstrated in rollback-contained test. |
| A7-04 | INFO, existing limitation | Identifier correction after release blocks delivery; no release recovery, evidence revision or reopening is provided. |

No new production correctness/security defect has been reproduced in the reviewed
paths. No CRITICAL/HIGH/MEDIUM finding is being hidden by a test change. Changes are
additive audit tests and this report; no production fix, scope redesign or schema
change was justified. Existing tests remain unchanged.

## 20. Test counts and final verification

The final full `python manage.py test --noinput` run completed after the last test
implementation change in **1,697.284 seconds**, exited 0, and destroyed its fresh
PostgreSQL test database normally. Counts below are from that one complete run.

| Measure | Result |
| --- | ---: |
| Baseline tests | 1,233 |
| Audit tests added | 65 |
| Final total | 1,298 |
| Passed | 1,298 |
| Failed | 0 |
| Skipped | 0 |

Audit tests comprise 30 transition/integration/query tests (including 13 generated
state-matrix tests), 12 Admin tests and 23 additional PostgreSQL concurrency tests.
All existing baseline tests, including the prior 37 handover concurrency tests,
remain unchanged and passed in the final run.

`check`, `makemigrations --check`, `migrate` and `showmigrations` passed. All project
migrations are applied; service remains at 0006 with no schema changes or conflicts.
The fresh test database migrated the entire graph from zero. Production deploy
checks exited 0 with only the existing W005/W021 warnings. Final `git diff --check`,
`git diff --stat` and status review confirm no tracked-file modifications; the
four intended new audit files remain unstaged. New-file whitespace and bounded
credential/artifact review found no candidates. No baseline test was modified.

## 21. Known limitations

This audit is bounded; it cannot prove absence of every scheduling or security
defect. Recovery callers remain trusted, raw writers remain privileged, and
historical labels are not all immutable snapshots. Custom Admin histories are not
paginated. Single-case query measurements do not certify arbitrary reporting
queries. Physical identity/recipient/QC assertions do not prove external authenticity
or hardware telemetry. No reopening, correction, disposal, shipping, payment,
inventory, notification, SLA or reporting subsystem is added.

## 22. Production and deployment boundaries

Ran `check --deploy --settings=config.settings.production` with a generated
temporary process-only secret and `audit.invalid` host/origin, following previous
audits. It exited 0 with exactly W005/W021; no warning was suppressed. No secret was
printed or saved, and no production infrastructure was configured. TLS/domain/proxy,
application server, database operations, static/media serving and backups remain
deployment responsibilities. Repository checks are not deployment certification.

## 23. Git status

Baseline `master` / `a58093e` was clean and HEAD remains unchanged. Final status has
exactly four untracked files: the three audit test modules and this report. There
are no modified tracked files and no staged changes, so ordinary `git diff --stat`
is empty (untracked additions are listed by `git status`). No existing test,
production source, settings or migration was modified. No stage, commit or push
was performed.
The user owns the freeze commit. Phase 3B and later phases are not started.

## 24. Freeze decision

All repository freeze gates passed: integrated lifecycle and terminal behavior,
authorization/isolation, history, rollback, concurrency, Admin, migrations, full
regression, documentation and artifact review. No unresolved CRITICAL/HIGH/MEDIUM
finding remains within the reviewed scope. No production fix or new abstraction
was required. This is readiness for a manual freeze commit, not a claim that the
user has already committed/frozen Phase 3A or that Phase 3B may begin.

PHASE 3A VERIFIED — READY TO FREEZE
