ADR-0191: Navin Enterprise Supply Chain and Procurement Agent, industrial product layer above the Control Plane
- Status: proposed (2026-11-04)
- Deciders: Navin Enterprise AI platform team, mission UC-09 (
agent_uses_cases/09_Industrie_Supply_Chain_Approvisionnement.md) - References: decision of 2026-11-04 "Identities of the Industry agents UC-06 to UC-10" (
.navin/continuity/DECISIONS.md), ADR-0176 (Banking Back-Office, copied generic modules pattern), ADR-0181 and ADR-0183 (sibling insurance agents), contractcontracts/v1/agent-product-manifest.schema.json, OPA packageeai.industrie_supply_chain(deploy/policies/opa/industrie_supply_chain.rego), contractscontracts/v1/industrie-supply-chain-copilot-event.schema.jsonandcontracts/v1/industrie-supply-chain-action-request.schema.json, Manager templatenavin-industrie-supply-chain-agent(published: false).
Context
An industrial site wants to see its multi-site stock positions, consolidate its requirements (production, maintenance, orders, safety), follow supplier commitments, prepare explained replenishment proposals, have a purchase or transfer request approved, then follow confirmations, transport and receipts, without ever letting a language model order, commit spend, select a supplier or cancel a delivery. The specification imposes eight modules (inventory visibility, requirements, supplier commitments, proposals, exceptions, purchase execution, inbound receipts, supplier improvement), an explicit server-side state machine (409 on any forbidden transition), decimal strings carrying unit and currency that are never summed across units or currencies, and six numeric acceptance scenarios (temporary shortage 20, proposal 80 for a net need of 60 under MOQ 80, quarantine 30 not covering, ERP/MES deduplication, partial receipt 60 with 10 rejected, non-approved supplier not executable).
The platform already provides identity, OpenFGA, OPA, the Action Gateway with maker-checker, durable jobs, the document pipeline (ClamAV, YARA-X, Docling behind the Control Plane), RAG, memory and observability (ADR-0176). No real ERP, WMS, MES or EDI is connected in the repository: connectors run in a deterministic sandbox.
Decision
1. The model proposes, a human decides, the ERP confirms
The coverage projection (coverage_projections) is a versioned deterministic engine (engine_version,
ruleset_version, input_snapshot_hash, as_of): projected stock(t) = initial usable stock + cumulative eligible
receipts - cumulative allocated requirements, with usable quantities only (quality-blocked or quarantined stock is never
counted). The replenishment proposal (replenishment_proposals) applies net need, MOQ and multiple and explains every
rounding (explanation, surplus_qty). It remains a suggestion: the purchase request is a Gateway action plan,
approved by a human other than its preparer, transmitted to the ERP by a connector, and supply_order_links.status
stays unknown_pending_confirmation until the source has answered; no local "ordered" status is ever written.
2. Generic modules copied, business modules written
As in ADR-0181: the generic modules (config, errors, i18n, authz, audit, jobs, worker, controlplane,
db/session, Action Gateway, connectors, observability, document pipeline, copilot, ops, api/common, app) are
copied into navin_supply with no change other than the package name, the schema (supply), the prefix
(/api/v1/industrie-supply-chain), the ports (3482, 8481, 6402) and the OPA package. The business tables of section
18.1 (inventory_snapshots, supply_requirements, supplier_commitments, coverage_projections,
replenishment_proposals, supply_order_links, inbound_shipments, receipt_allocations) plus suppliers,
supply_exceptions and supplier_scorecards are written in migration 0001_foundation with tenant then project RLS,
composite foreign keys (tenant_id, parent_id) and CHECK constraints on statuses, units and currencies.
3. Supplier indicators, never decisions
Supplier performance (supplier_scorecards) is an indicator computed on accepted commitments (OTIF, delays measured
against the initial promise, which a new promised date never erases), displaying volume, period and missing data.
Approval (suppliers.approval_status) is a fact of the source referential; a not_approved supplier makes a scenario
not_executable, and a database constraint forbids any order link towards it.
4. Delegation matrix and segregation of duties in OPA
The eai.industrie_supply_chain package follows the fail-closed pattern: typed operations, preparation and approval
roles as data (eai.config.industrie_supply_chain), mandatory second human for purchase_submit, transfer_submit,
expedite_paid, substitution, supplier_change, order_amend, budget_override and rule_change, rail always
none (the application moves no money), applies true only for supply.* and document.* actions. Obligations
announce proposal_not_order and unknown_pending_confirmation.
5. Units, currencies and deduplication
Every quantity carries unit (source UoM) and every value currency; KPIs are grouped per unit and per currency and
never summed across them. A requirement received from the ERP and the MES with the same business reference is
deduplicated by (tenant_id, project_id, dedup_key): a single row is kept, the sources are preserved in source_refs.
Consequences
- Positive: no external effect without an approved plan and a source confirmation; reproducible, explained computations; RLS isolation tested; the same generic frontend renders the product through the manifest.
- Negative: real ERP/WMS/MES systems are not connected; acceptance scenarios run on the deterministic sandbox and do not count as production integration.
- The
navin-industrie-supply-chain-agenttemplate stayspublished: falseuntil explicit validation.