Inventory Pilot Operations
Approved opening counts, read-only reconciliation, write-stop controls, and delivery evidence.
Delivery Boundary
Inventory U1-U6 provide the reusable source ledger. Hospital U10 connects case-stock commands and UI locally. Deployment and pilot acceptance remain open. Use the release acceptance record. The source has no separate MFA app, procurement, retail pharmacy, valuation, or automatic patient charge. Local automated evidence is not deployment, inventory-lead approval, or operator acceptance. Keep the integration PR as draft until its CI and review gates pass. Keep the tracked issue open for QA.
Approved Opening Counts
An authorized backend operator records the actual facility lead's approved counts. Do not invent an approval or copy a demo quantity into a live facility. The authenticated approver needs View, Manage, and adjustments, plus facility access. The importer needs View, Manage, and facility access. Shell manages these grants.
Record the count date, an opaque import reference, a reason code, and explicit rows. Each row needs its source-line identity, scoped item/location, exact decimal quantity, and unit. Include required lot/serial identities or descriptors and an explicit conversion when applicable. Do not put patient/case data in a manifest, source reference, or stock audit. An approval accepts at most 1,000 rows and unique line identities. The facility can have one opening manifest. Use later receipt or count-adjustment commands, not a reset import. An incorrect approved manifest requires operator review; this delivery has no approval replacement route.
Run the following inside an authorized Rails runner or console with the selected tenant, user, and facility. The operator must obtain those records from the approved change request, not browser-provided authority.
Shared::Tenancy::RlsContext.with(tenant.id) do
result = Inventory::CommandContext.call(
user: approver, facility: facility, kind: 'approve_opening_import',
operation_key: approval_key,
input: {
source_reference: count_reference, count_date: count_date,
reason_code: 'approved_count', rows: approved_rows
}
)
raise result.error_code unless result.success?
approval_id = result.operation.id
imported = Inventory::OpeningImport.call(user: importer, facility: facility, approval_id: approval_id)
raise "#{imported.error_code}: #{imported.outcome}" unless imported.success?
endThe approval is an immutable, audited operation. A caller cannot edit its rows later.
Approval creation is an operator-only command, not a public HTTP operation kind.
POST operations with kind: opening_balance must include opening_approval_id and exactly match an approved row.
The import service derives stable keys from the approval ID and source line.
It uses one caller transaction for the batch. One failed row rolls back all new effects.
A retry returns existing authorized rows without duplicating them.
After an unknown outcome, retain the approval and row keys. Do not approve a new manifest.
Reconciliation
Shared::Tenancy::RlsContext.with(tenant.id) do
report = Inventory::Reconcile.call(user: reviewer, facility: facility)
puts JSON.pretty_generate(report.to_h.merge(success: report.success?))
endThe reviewer needs View and facility access. The source uses the stock lock for a consistent comparison. It compares movement totals with physical balances, allocations with held balances, and allocation/custody event history with remaining projections. It checks terminal reservations, custody quantity limits, and one audit record per operation. The report has opaque stock IDs, check counts, and mismatches. It has no Clinical links. Checks use batches of 250. The report returns at most 200 issue details and the full issue count. Reconciliation does not fix stock, release holds, rewrite events, or create an adjustment. Investigate each mismatch. Make an authorized, reasoned correction only after physical verification.
Expiry revisions have no quantity effect. Reconcile before and after an approved correction. Eligibility still uses the current validated cutoff under lock, not a reconciliation result or sweep schedule. Elapsed holds remain held until an audited release/expiry command records the release.
Write Stop
INVENTORY_WRITES_ENABLED=false stops new Inventory effects in every facility for that process.
Only the exact value true enables writes. An omitted value retains normal operation.
INVENTORY_DISABLED_FACILITY_IDS is a comma-separated deny list for a scoped stop.
Apply the setting to every web and worker process. Restart those processes when deployment configuration changes.
This is an operator emergency control, not a new feature-flag or RBAC UI.
Admin continues to own product feature flags. Shell continues to own role permissions.
The command checks the control after current authorization and under the stock lock.
New commands return STOCK_WRITES_DISABLED with a rolled-back outcome; HTTP returns 503.
Reads and reconciliation remain available. Authorized retries of confirmed operations return their original result.
The stop also blocks configuration changes, approval creation, and service expiry writes.
No background repair runs while writes are stopped. Re-enable deliberately and rerun the expiry sweep.
Transactions already in progress are not cancelled by an environment change.
Do not drop populated Inventory tables or reverse migrations as a rollback strategy.
Pilot Evidence
Record this evidence in the existing integration PR and issue. Do not mark unperformed checks as passed.
- Deployment commit, migration versions, runtime grants, queue and schedule checks.
- Tenant and facility IDs; no patient data or credentials.
- Facility lead approval, count date, opaque count reference, and opening approval ID.
- Imported operation IDs, source-row count, and identical retry result.
- Reconciliation output before activation and after the stock workflow exercise.
- Two-user shortage race, expiry handling, quarantine return, and compensation results.
- Grant revocation, same-tenant cross-facility denial, and non-bypass RLS proof.
- Write-stop test, preserved reads, and controlled re-enable result.
- QA owner acceptance and unresolved discrepancies.
- Separate Hospital U10 API/UI integration and clinical rollback evidence.
Use the U6 QA guide. Source completion can unblock Hospital U10. It cannot close Hospital inventory or the whole product.