Decision Log: Connect Item.Supply to Business Affiliate References
Purpose
Section titled “Purpose”Tracks the design decisions for connecting ItemSupply to a real supplier in
the BusinessAffiliate module at the API/backend layer — the reference target and
form, the reaction to supplier removal, the service-boundary and URL-routing
refactorings, and the cross-Universe resolution and migration questions that
follow from them.
Decision Table
Section titled “Decision Table”| # | Question | Status | Decision | Round |
|---|---|---|---|---|
| DQ-001 | Reference target: BusinessAffiliate vs BusinessRole(VENDOR) | Decided | BusinessRole(VENDOR) | R1 |
| DQ-002 | Reference form: canonical Reference value object vs plain UUID+name | Decided | Canonical SupplierReference.Value | R1 |
| DQ-003 | Effect of supplier removal on an ItemSupply | Decided | Stale marker (PDEV-808 pattern), no delete | R1 |
| DQ-004 | Extract a dedicated ItemSupplyService? | Decided | Yes | R1 |
| DQ-005 | Adopt canonical reference-data URL routes? | Decided | Yes | R1 |
| DQ-006 | Resolving a child BusinessRole across the Universe boundary | Decided | Carry affiliateEId in the reference | R1 |
| DQ-007 | Event source for supplier removal | Decided | BusinessRole DeleteEntity observer notification (in-memory) | R3 |
| DQ-008 | Migration/backfill of existing supplierEId (BA eId → VENDOR role) | Decided | Lazy re-link — no backfill | R1 |
| DQ-009 | Backward compatibility of legacy routes + api-test path migration | Decided | Keep legacy routes as aliases | R1 |
| DQ-010 | Floating-vs-pinned semantics on retirement | Decided | Mirror Kanban (floating; pin on retire) | R1 |
| DQ-011 | Supply mutation qualifier set for ItemSupply creation | Decided | STRICT + create-on-the-fly only; drop LAX | R1 |
| DQ-012 | Creating a supply that points to a retired supplier | Decided | Disallowed — reject at creation | R1 |
| DQ-013 | Representing an unlinked/legacy vendor name (mandatory reference eId) | Superseded | by DQ-014 | R2 |
| DQ-014 | Eliminating the redundant supplier name (supplier vs supplierRef.name) | Decided | Supplier descriptor: name on the reference, drop supplier | R2 |
| DQ-015 | Must a supplied supplier roleEId be the affiliate’s actual VENDOR role? | Decided | Yes — verify against businessRolesFor; reject a mismatch | R3 |
| DQ-016 | How do embedded primary/secondary supplies resolve on item create/update? | Decided | Create-on-the-fly (PROPAGATE-style) regardless of item qualifier, incl. name propagation | R3 |
Round 1: Initial Design Questions
Section titled “Round 1: Initial Design Questions”DQ-001: Reference target — BusinessAffiliate or BusinessRole(VENDOR)?
Section titled “DQ-001: Reference target — BusinessAffiliate or BusinessRole(VENDOR)?”Context: Today ItemSupply.supplierEId holds a BusinessAffiliate eId,
while the domain docs say a supply references the BusinessRole(VENDOR). The
two must be reconciled before the reference type is designed.
| Option | Description | Trade-offs |
|---|---|---|
| A | Reference the BusinessAffiliate eId (match current code) | Simpler; a supplier is “the company”. But loses the “acting as vendor” precision and contradicts docs. |
| B | Reference the BusinessRole(VENDOR) eId (match docs) | Precise about the vendor capability; aligns docs+model. Requires resolving a child entity (see DQ-006) and a backfill (DQ-008). |
Recommendation: Option B — it matches the documented model and the Reference domain intent.
Decision: Option B — SupplierReference.eId is the VENDOR BusinessRole
eId. (Confirmed in design session 2026-06-15.)
Applied to:
- Design Document § Overview, § Class Diagram, § Key Classes (
SupplierReference)
DQ-002: Reference form — canonical Reference value object or plain UUID + name?
Section titled “DQ-002: Reference form — canonical Reference value object or plain UUID + name?”Context: The supply link can stay a bare UUID + denormalized name, or adopt
the canonical reference value-object pattern used by ItemReference /
KanbanCard (eId, rId, cached name, floating/pinned).
| Option | Description | Trade-offs |
|---|---|---|
| A | Keep plain supplierEId: UUID? + supplier: String | Least churn; already cross-Universe compliant. No room for retired/rId/provenance, so the stale-marker (DQ-003) has nowhere to live. |
| B | Adopt canonical SupplierReference.Value (eId, rId, name, retired, provenance) | Consistent with KanbanCard/OrderLine; carries the fields needed for staleness and tombstone reads. Requires a persistence migration. |
Recommendation: Option B — required to support DQ-003 cleanly and consistent with the platform’s reference pattern.
Decision: Option B — introduce SupplierReference.Value mirroring
ItemReference.Value. (Confirmed 2026-06-15.)
Applied to:
- Design Document § Class Diagram, § Key Classes, § Implementation Scope
DQ-003: Effect of supplier removal on an ItemSupply
Section titled “DQ-003: Effect of supplier removal on an ItemSupply”Context: UC 5 requires the Item module to react to supplier removal. The supply may be referenced by pending business workflows already committed to its values, so destructive cleanup is risky.
| Option | Description | Trade-offs |
|---|---|---|
| A | Delete/retire the affected ItemSupply | Clean state, but breaks in-flight workflows referencing the supply. |
| B | Unlink the supplier but keep the supply unmarked | Preserves data but gives no signal that the supplier is gone. |
| C | Mark the supplier reference stale (retired=true + pinned tombstone), keep the supply | Preserves data and signals staleness; identical to the proven Kanban↔Item (PDEV-808) pattern. More machinery (migration columns, resolution path). |
Recommendation: Option C — matches the existing, proven pattern and the stated requirement to protect committed workflows.
Decision: Option C — stale-marker reaction mirroring PDEV-808; the ItemSupply is never deleted by supplier removal. (Confirmed 2026-06-15.)
Applied to:
- Design Document § Overview, § Sequence: Supplier removed, § Testing Strategy
DQ-004: Extract a dedicated ItemSupplyService?
Section titled “DQ-004: Extract a dedicated ItemSupplyService?”Context: Supply logic is a ~400-line private inner SupplyService inside
ItemService. Refactoring item #3.1 of the ticket asks whether to extract it.
| Option | Description | Trade-offs |
|---|---|---|
| A | Keep the inner SupplyService | No refactor risk; but the class stays large and the new event-subscription responsibility is buried. |
| B | Extract a dedicated ItemSupplyService owning the child universe and BA subscription | Clear ownership and a natural home for the stale-marker subscriber; small risk of churn in ItemService wiring. |
Recommendation: Option B — gives the new reaction logic a clean owner.
Decision: Option B — extract ItemSupplyService. (Confirmed 2026-06-15.)
Applied to:
- Design Document § Class Diagram, § Key Classes (
ItemSupplyService), § Implementation Scope
DQ-005: Adopt canonical reference-data URL routes?
Section titled “DQ-005: Adopt canonical reference-data URL routes?”Context: Refactoring item #3.2. No reference-data segment exists today;
Item is /v1/{module}/item, BA is /v1/business-affiliate/.... The url-naming
convention does not yet define reference-data.
| Option | Description | Trade-offs |
|---|---|---|
| A | Leave routes as-is | No work; but the modules remain inconsistent with the intended domain grouping. |
| B | Introduce canonical {version}/{domain}/{module}/{service}/{endpoint} routes (five explicit, all-singular segments) with domain = reference-data; ItemSupply gets its own item-supply/supply endpoint (e.g. /v1/reference-data/item/item/item/{id}/..., /v1/reference-data/item/item-supply/supply/{item-eId}/..., /v1/reference-data/business-affiliate/business-affiliate/business-affiliate/...). Kotlin/Ktor routes only for now — no Helm/Cfn changes. | Consistent domain-scoped routing; requires url-naming.md to add the {domain} segment and api-test path migration (see DQ-009). |
Recommendation: Option B — establishes the canonical convention the ticket asks for.
Decision: Option B — adopt reference-data routes; document the
convention in url-naming.md. (Confirmed 2026-06-15.)
Applied to:
- Design Document § API Contract, § Implementation Scope
DQ-006: How is a child BusinessRole resolved across the Universe boundary?
Section titled “DQ-006: How is a child BusinessRole resolved across the Universe boundary?”Context: A BusinessRole lives in a child universe parametrized by its
parent BA eId, so a reference holding only the role eId cannot be resolved the
way a top-level Item reference can (the Kanban pattern never faced this).
| Option | Description | Trade-offs |
|---|---|---|
| A | SupplierReference carries both the role eId and the parent affiliateEId | Self-sufficient resolution via existing BusinessRoleUniverse(parentEId). Slightly larger reference; must keep affiliateEId correct. |
| B | Add a BusinessAffiliateService.resolveVendorRole(roleEId, asOf) that searches across affiliates | Reference stays minimal (role eId only); new cross-affiliate query capability and its cost. |
| C | Reference the BA eId for resolution but tag the role type | Reintroduces the BA-vs-role ambiguity DQ-001 resolved; not recommended. |
Recommendation: Option A — cheapest resolution, no new query surface;
affiliateEId is known at link time.
Decision: Option A — SupplierReference carries a (required)
affiliateEId alongside the role eId; resolution uses the existing
BusinessRoleUniverse(parentEId). (Confirmed 2026-06-15.)
Applied to:
- Design Document § Class Diagram (
affiliateEIdnow required), § Key Classes (SupplierReference)
DQ-007: Event source for supplier removal
Section titled “DQ-007: Event source for supplier removal”Context: The stale-marker reaction needs a reliable event. Today the Item
module subscribes only to BusinessRole notifications and ignores deletes; it is
unclear whether deleting a whole BusinessAffiliate emits per-VENDOR-role
DeleteEntity events.
| Option | Description | Trade-offs |
|---|---|---|
| A | Rely on cascade: BA deletion emits DeleteEntity for each child VENDOR role; ItemSupplyService subscribes to role deletes only | One subscription; depends on BA delete actually cascading role-delete events (must verify/implement). |
| B | ItemSupplyService subscribes to both BusinessRole and BusinessAffiliate DeleteEntity | Robust to either deletion path; two handlers and dedup logic. |
Recommendation: Option A if BA-delete cascade emits role events; otherwise B. Verify cascade behavior during Phase 1 implementation.
Decision: Deferred to implementation — verify in code whether deleting a
BusinessAffiliate emits per-VENDOR-role DeleteEntity events. If yes, take
Option A (subscribe to role deletes only); if not, take Option B (subscribe to
both). Record the resolved choice here before Phase 3 (T-08).
Applied to: pending (recorded at T-08)
DQ-008: Migration/backfill of existing supplierEId
Section titled “DQ-008: Migration/backfill of existing supplierEId”Context: Existing rows hold a BA eId in supplier_eid; the new model
wants the VENDOR role eId. The migration must convert or re-link.
| Option | Description | Trade-offs |
|---|---|---|
| A | Data migration: for each row, look up the BA’s VENDOR role and write its eId into SUPPLIER_REFERENCE_entity_id | Preserves links; needs a deterministic “the VENDOR role” per BA (what if 0 or >1?). |
| B | Leave legacy rows unlinked (retired/floating by name) and re-link lazily on next edit | Simplest migration; temporary inconsistency until rows are touched. |
| C | Default columns + backfill in a follow-up data task | Decouples schema change from data conversion; two steps. |
Recommendation: Option A where exactly one VENDOR role exists; fall back to B for ambiguous rows. Confirm the data shape in the target environments first.
Decision: Option B — lazy re-link, no data backfill. The migration adds
the new SUPPLIER_REFERENCE_* columns and drops the legacy supplier_eid /
supplier columns; existing supplies become unlinked (floating by cached name)
and are re-linked to a VENDOR role on their next edit. This avoids a brittle
one-time BA→VENDOR-role conversion and the ambiguous 0-or-many-roles cases.
(Confirmed 2026-06-15.)
Applied to:
- Project Plan § Overview, § Phase 1 (T-04)
- Design Document § Decision Summary, § Testing Strategy
DQ-009: Backward compatibility of legacy routes + api-test migration
Section titled “DQ-009: Backward compatibility of legacy routes + api-test migration”Context: Introducing reference-data routes (DQ-005) affects existing API
consumers and the Bruno suite, which uses /v1/item/item/... and
/v1/business-affiliate/....
| Option | Description | Trade-offs |
|---|---|---|
| A | Keep legacy routes as permanent aliases alongside canonical routes | No consumer breakage; two route sets to maintain. |
| B | Add canonical routes, deprecate legacy with a removal window, migrate api-test now | Clean end state; coordination with FE tickets (PDEV-764) and a deprecation period. |
| C | Replace legacy routes outright | Smallest surface; breaks current consumers immediately. |
Recommendation: Option A for this project (non-breaking), with a separate deprecation ticket — given FE work (PDEV-764) is in flight.
Decision: Option A — keep legacy routes as permanent aliases for this project; file a separate deprecation ticket. (Confirmed 2026-06-15.)
Applied to:
- Design Document § API Contract
- Project Plan § Phase 4, T-12
DQ-010: Floating-vs-pinned semantics on retirement
Section titled “DQ-010: Floating-vs-pinned semantics on retirement”Context: The Kanban pattern keeps references floating normally and pins
rId to the tombstone at retirement so the reference still resolves. Confirm the
same for SupplierReference.
| Option | Description | Trade-offs |
|---|---|---|
| A | Mirror Kanban: floating while live; pin rId + set retired on supplier removal; resolve retired refs via getRecord(rId) | Proven; consistent platform behavior. |
| B | Always floating; detect retirement purely at read time | Simpler write path; loses the frozen last-known snapshot and depends on the role record still being queryable. |
Recommendation: Option A — consistency with PDEV-808 and reliable tombstone reads.
Decision: Option A — mirror Kanban: floating while live; pin rId and
set retired on supplier removal; resolve retired refs via getRecord(rId).
(Confirmed 2026-06-15.)
Applied to:
- Design Document § Sequence: Supplier removed, § Behavioral Design (resolution note)
DQ-011: Supply mutation qualifier set for ItemSupply creation
Section titled “DQ-011: Supply mutation qualifier set for ItemSupply creation”Context: The existing system offers three supply-mutation qualifiers —
STRICT, LAX, PROPAGATE. For this project the supply semantics are uniform:
the caller is expected to reference a real, resolvable supplier, with one
sanctioned alternative — create the supplier on-the-fly. The permissive LAX
mode (accept an unlinked supply, silently tolerate mismatches) is not wanted.
| Option | Description | Trade-offs |
|---|---|---|
| A | Keep all three qualifiers (STRICT, LAX, PROPAGATE) | Backward compatible; but retains the permissive LAX path that this project does not want and that weakens the reference guarantee. |
| B | Offer only STRICT (default) and create-on-the-fly; remove LAX | Uniform, strong reference semantics; one clear escape hatch. LAX callers (if any) must move to STRICT or on-the-fly; default flips to STRICT. |
Recommendation: Option B — uniform strict semantics with a single, explicit alternative is simpler to reason about and matches the project intent.
Decision: Option B — ItemSupply creation accepts only STRICT (default; the referenced VENDOR role must resolve) and create-on-the-fly (create the BusinessAffiliate + VENDOR role when the supplier is not found, then link). The on-the-fly mode applies strict validation otherwise — it does not silently tolerate mismatched data. (Confirmed 2026-06-15.)
Implementation note (R2, 2026-06-15): ItemMutationQualifier is a single
enum shared between item-level mutations (bulk add() legitimately uses LAX)
and supply resolution, so LAX cannot be removed outright. Accepted refinement:
DQ-011 removes the LAX name-lookup upsert for supplies — under LAX a supply
is left unlinked (null supplierRef, name-only), with no name-based lookup
or auto-creation. STRICT (require a live ref) and PROPAGATE
(create-on-the-fly) are unchanged. So the three supply behaviors are: STRICT =
require a live VENDOR role; PROPAGATE = find-or-create; LAX = leave unlinked.
The endpoint default qualifier remains PROPAGATE — the DQ-011-envisioned
flip to a STRICT default was not applied in Phase 1. Open follow-up
(PDEV-864): revisit whether the
supply default should become STRICT.
Applied to:
- Design Document § Goal, § API Contract, § Scenarios, § Testing Strategy
- Project Plan § Phase 2, T-06
operations—ItemVendorResolver.resolveVendorRef
DQ-012: Creating a supply that points to a retired supplier
Section titled “DQ-012: Creating a supply that points to a retired supplier”Context: A supplier (its VENDOR BusinessRole, or the parent
BusinessAffiliate) can be retired (deleted). Existing supplies that referenced it
are marked stale per DQ-003. This question is about new supplies: may a newly
created (or newly linked) ItemSupply target an already-retired supplier?
| Option | Description | Trade-offs |
|---|---|---|
| A | Allow linking to a retired supplier (immediately stale) | Permissive; but lets callers create dead links on purpose, contradicting strict semantics. |
| B | Disallow — STRICT resolution rejects a retired VENDOR role/BA; creation fails with a validation error | New supplies always point at live suppliers; consistent with the strong reference guarantee (DQ-011). Create-on-the-fly is unaffected (it creates a live supplier). |
Recommendation: Option B — a freshly created link should never start dead.
Decision: Option B — when resolving a supplier for ItemSupply creation,
a retired VENDOR role (or retired parent BusinessAffiliate) is rejected:
creation returns a validation AppError. Staleness applies only to supplies that
linked the supplier before it was retired (DQ-003); it is never a valid
starting state for a new supply. Create-on-the-fly always yields a live
supplier and is therefore unaffected. (Confirmed 2026-06-15.)
Implementation note (R2, 2026-06-15): Enforcement leans on bitemporal
retired-filtering. BusinessRole is a bitemporal child entity, and
BusinessAffiliateService.detailsFor / businessRolesFor return only the latest
non-retired records (… and (baTable.retired eq false)). So a retired VENDOR
role / affiliate is simply absent from the active query → STRICT and LAX
resolution fail naturally (resolved as “not a VENDOR” / NotFound). The one path
that needed explicit handling is PROPAGATE: because the retired role is
filtered out, PROPAGATE would otherwise re-create (resurrect) a VENDOR role with
the same eId. Per the R2 ruling, PROPAGATE now checks for a retired role /
affiliate (retired-inclusive read) and fails rather than resurrects.
Applied to:
- Design Document § Scenarios (STRICT error path), § API Contract (400), § Testing Strategy
operations—ItemVendorResolver.resolveWithExistingRef,ItemVendorResolverTest
Round 2: Questions Surfaced During Implementation
Section titled “Round 2: Questions Surfaced During Implementation”DQ-013: Representing an unlinked/legacy vendor name
Section titled “DQ-013: Representing an unlinked/legacy vendor name”Context: SupplierReference.eId (the VENDOR BusinessRole id) is mandatory,
mirroring ItemReference. But two cases have a vendor name with no resolved
role: legacy rows under lazy re-link (DQ-008), and the general need to round-trip
a supply whose role link is absent. A single non-null supplier: SupplierReference.Value field (as first sketched) cannot represent
“name, not yet linked.”
| Option | Description | Trade-offs |
|---|---|---|
| A | Keep ItemSupply.supplier: String (vendor name, always present) and add supplierRef: SupplierReference.Value? (nullable canonical link) | Preserves names for legacy/lazy re-link; closest to today’s shape; smallest blast radius (.supplier usages unchanged, only .supplierEId → .supplierRef?.eId). Two fields instead of one. |
| B | supplier: SupplierReference.Value? (nullable); name only inside the reference | One field, but a null reference loses the legacy name → breaks re-link-by-name. |
| C | Make SupplierReference.eId nullable (name required, eId optional) | One field, keeps name, but breaks the canonical-reference contract (ItemReference keys on a non-null eId). |
Recommendation: Option A — the only option that preserves vendor names for
lazy re-link while keeping SupplierReference faithful to the canonical pattern.
Decision: Option A — ItemSupply (and ItemSupplyReference) keep
supplier: String and replace supplierEId: UUID? with supplierRef: SupplierReference.Value?. A null supplierRef means unlinked (name-only); a
non-null supplierRef is the canonical link, which may be retired.
(Confirmed 2026-06-15.)
Applied to:
- Design Document § Class Diagram, § Key Classes (
ItemSupply), § Functional Modules operations—ItemSupply.kt,ItemSupplyReference.kt,SupplierReferenceComponent, migration
DQ-014: Eliminating the redundant supplier name
Section titled “DQ-014: Eliminating the redundant supplier name”Context (surfaced in PR review of #193): DQ-013 kept ItemSupply.supplier: String (the vendor name) and added a nullable supplierRef: SupplierReference.Value whose name cached the same vendor name — two fields
holding the same string, with an out-of-sync risk. The reviewer asked to
consolidate to a single source of truth.
| Option | Description | Trade-offs |
|---|---|---|
| A | Keep supplier: String; drop SupplierReference.name. Reference stays a strict canonical reference (non-null eId/affiliateEId); name is an intrinsic supply field. | Keeps DQ-002 (canonical reference). Name lives on the supply; the reference is a pure link. |
| B | Drop supplier: String; name lives in the reference. Make SupplierReference a supplier descriptor: name required, eId/affiliateEId nullable (null = unlinked/legacy). | Single field, no duplication; name always travels with the descriptor. Relaxes DQ-002 — the reference is no longer a strict EntityPayload reference (nullable identity); the persistence existence-check moves from eId to name; rId/retired/affiliateEId/provenance are meaningful only when linked. |
Recommendation: noted both; the reviewer chose B.
Decision: Option B — SupplierReference becomes a supplier descriptor:
name: String (required) is the single home for the vendor name; eId and
affiliateEId are nullable (null = unlinked/legacy, name-only; non-null =
linked to a VENDOR BusinessRole). ItemSupply.supplier: String and
ItemSupplyReference.supplier: String are removed; the descriptor field is
required on both. This supersedes DQ-013 and relaxes DQ-002: the supplier
link is no longer a strict EntityPayload reference but a descriptor whose
identity is established lazily. The V018 migration moves the legacy supplier
name into supplier_ref_name (no name loss) and drops the legacy columns; the
component’s existence check is keyed on name. (Confirmed 2026-06-15.)
Transitional framing (design intent): the relaxation of DQ-002 is
temporary. The nullable eId/affiliateEId exist only to carry legacy
unlinked supplies through the lazy re-link migration (DQ-008). As those supplies
are edited they re-link and acquire a real VENDOR-role identity; once no unlinked
supplies remain, eId/affiliateEId can be tightened back to non-null and
SupplierReference regains its canonical reference shape (DQ-002). Treat the
nullable identity as a migration-window state, not the permanent model.
Future-convergence follow-up: when the count of supplies with a null
supplier_ref_entity_id reaches zero (across partitions), make the fields
non-null (a schema + type tightening) and restore the strict EntityPayload
reference. Tracked as PDEV-860.
Applied to:
- Design Document § Goal (Key Insight), § Decisions, § Class Diagram, § Key Classes
operations—SupplierReference,SupplierReferenceComponent,ItemSupply,ItemSupplyReference, V018 migration, resolver, stale/propagation logic,Model.kt
Round 3: Resolutions Confirmed During Implementation & PR Review
Section titled “Round 3: Resolutions Confirmed During Implementation & PR Review”These close the one deferred question and record two decisions surfaced while reviewing the implementation in operations PR #193.
DQ-007: Event source for supplier removal — resolved
Section titled “DQ-007: Event source for supplier removal — resolved”Context: R1 deferred the choice between (A) a BusinessAffiliate-deletion cascade and (B) a subscription to BusinessRole removal, pending verification of the in-code cascade.
Resolution: Option B — the Item module subscribes to the
BusinessAffiliate module’s in-memory role observer and reacts to a
DataAuthorityNotification.DeleteEntity for a BusinessRole of type VENDOR.
ItemSupplyService.setParentService registers an ItemSupplyRoleListener via
BusinessAffiliateService.addRoleObserver; on a VENDOR DeleteEntity the
reaction marks referencing supplies stale (DQ-003). No new event infrastructure
and no cross-Universe cascade was introduced — it reuses the existing in-process
Observer pattern. (Confirmed in code 2026-06-16.)
DQ-015: Must a supplied supplier roleEId be the affiliate’s actual VENDOR role?
Section titled “DQ-015: Must a supplied supplier roleEId be the affiliate’s actual VENDOR role?”Context: when a caller supplies a linked SupplierReference (eId +
affiliateEId), resolution originally checked only that the affiliate had a
VENDOR role, then persisted the client-supplied eId unverified.
Decision: Verify the role identity. Resolution now resolves the
affiliate’s actual VENDOR role (via businessRolesFor) and rejects the
request when the supplied eId is not that role — otherwise
supplier_ref_entity_id could point at a role that never receives the vendor
rename/retire reactions. Applies in STRICT, LAX, and PROPAGATE. (PR #193 review.)
DQ-016: How do embedded primary/secondary supplies resolve on item create/update?
Section titled “DQ-016: How do embedded primary/secondary supplies resolve on item create/update?”Context: the embedded primary/secondary supplies carried on an Item
create/update were written straight to the supply universe without vendor
resolution, so a name-only embedded supply was persisted unlinked (no VENDOR
role created/attached) and later supplier rename/retire reactions could not find
it.
Decision: Resolve embedded supplies create-on-the-fly (PROPAGATE-style), regardless of the item mutation qualifier — a name-only embedded supply finds-or-creates its BusinessAffiliate + VENDOR role rather than persisting unlinked, and a name change on a linked embedded supply is propagated to the BusinessAffiliate (explicitly approved). Rationale: an embedded supply’s supplier cannot be pre-created in a separate call, so STRICT/LAX item operations still create/link the supplier on the fly; STRICT’s “verify, no side-effects” character therefore applies to the supply-field consistency check, not to the embedded supplier link. (PR #193 review.) See the design’s Supplier resolution semantics framing.
Applied to: operations — ItemVendorResolver.resolveWithExistingRef
(DQ-015), ItemSupplyCrudService.addMultipleToParent (DQ-016), with tests in
ItemVendorResolverTest, CrossItemSupplyUniverseTest, and the item
create/update suites.
Copyright: (c) Arda Systems 2025-2026, All rights reserved
Copyright: © Arda Systems 2025-2026, All rights reserved