Skip to main content

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), contract contracts/v1/agent-product-manifest.schema.json, OPA package eai.industrie_supply_chain (deploy/policies/opa/industrie_supply_chain.rego), contracts contracts/v1/industrie-supply-chain-copilot-event.schema.json and contracts/v1/industrie-supply-chain-action-request.schema.json, Manager template navin-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-agent template stays published: false until explicit validation.