# Open Questions: Single Supply Chain

**Date:** 2026-05-27
**Author:** Michael Rojas
**Status:** Tracking — none of these block engineering work

---

## How to read this file

Questions and risks that surfaced during design + implementation planning. Each entry includes the resolution path (data fix, code change, or decision needed) and impact if unresolved. Resolved entries are kept for historical context; questions that get fully answered should be moved to `DECISION_LOG.md` and removed here.

---

## Sequencing Risks

### Q1: `sync_contract_sap` `Prctr` NULL window during dual-path rollout

**Risk:** If the lambda is upgraded to the FF-gated dual-path code *before* the backfill of `contract.reference_sap_profit_center_id` completes, and the FF is flipped ON, the lambda will read NULL `Prctr` for un-backfilled contracts.
**Mitigation:**
1. Deploy FF-gated lambda code with FF OFF (M1.11).
2. Run full backfill (M1.15) and verify zero NULLs (M1.17).
3. Only then flip FF ON in prod (M1.19).
This sequence is enforced by M1 ticket dependencies in [ROADMAP.md](ROADMAP.md).
**Status:** Mitigated by sequencing

### Q2: Snowflake view switch may show stale `display_name` if Fivetran hasn't replicated yet

**Risk:** The view update in M1.20 references `reference_sap_profit_center.display_name`. If Snowflake replication lags, the view may briefly show NULL `display_name` for newly-set rows.
**Mitigation:** Run `display_name` backfill (M1.13) well in advance of the view switch (M1.20). Monitor Fivetran sync lag before switching the view. If lag exceeds 15 minutes, delay the switch.
**Status:** Mitigated by ordering

### Q3: `after_contract_update` trigger update timing

**Risk:** If the trigger is recreated (M1.5) *before* the `contract_history` column is added (M1.4), the trigger will fail with "column not found." Conversely, if updates happen between M1.4 and M1.5, history rows will be missing the PC column.
**Mitigation:** Bundle M1.4 and M1.5 into a single Liquibase migration (same changeset file). Apply atomically.
**Status:** Mitigated by bundling

---

## Behavior Questions

### Q4: Soft-delete + UNIQUE collision on the junction

**Question:** If a mapping is soft-deleted and the business later wants to re-create the same `(SE, PC)` pair, the composite UNIQUE blocks the insert.
**Current behavior (per TRD §5.1):** Restore by clearing `deleted_at` on the existing row, not by inserting a duplicate.
**Alternative:** Functional UNIQUE filtered on `deleted_at IS NULL`.
**Resolution path:** Stick with simple UNIQUE for M1. Revisit only if business hits this scenario. If revisited, the change is a single ALTER + index swap — no application code changes.
**Status:** Deferred — no business case yet

### Q5: Can contracts exist without a PC assignment?

**Question:** Today every contract has exactly one PC (1:1 SE→PC). After this change, contracts must still have one (NOT NULL on `contract.reference_sap_profit_center_id` enforced in M1.18). But what if an SE has zero active mappings (e.g., all soft-deleted)? Contract creation must reject this.
**Resolution path:** Application-layer validation on contract create (M1 ticket scope under ows-abacus-contract). Add a test case in M2.
**Status:** Engineering enforces; no business decision needed

### Q6: Can a mapping ever move between signing entities?

**Question:** If Santa Anna's mapping to "US7219" needs to be reassigned to a different legal entity, is that an `UPDATE` to the existing junction row, or a soft-delete + new row?
**Recommendation:** Soft-delete + new row. Updates would silently change the meaning of historical contract data. New row keeps the audit trail clean.
**Resolution path:** Document in M2 admin UX. If business wants `UPDATE` semantics, raise it during M2 implementation.
**Status:** Pending M2 UX decision

### Q7: External documents — display name only, or display name + SAP code?

**Source:** PRD says "Profit Center Name is what is surfaced in external docs"; D18 confirmed both in the Abacus UI.
**Open:** Are external docs (external-facing contract docs, settlement statements) different from the Abacus UI?
**Resolution path:** Confirm with Danielle Vu. If external docs show display_name only, placeholder names become more visible to clients — adds urgency to D20 (business provides real names).
**Status:** Pending product clarification

### Q8: Soft-delete a mapping that has active contracts

**Question:** If admin soft-deletes a junction row that has contracts pointing to its PC, what happens? The `ON DELETE RESTRICT` is on the FK, but a soft-delete is just `UPDATE deleted_at = NOW()` — the FK is still satisfied.
**Resolution path:** Application-layer guard: reject soft-delete if any non-deleted contract has `(SE, PC)` matching this junction row's keys. Show a warning with the count of affected contracts. Captured in test T18.6.
**Status:** Engineering enforces; UX decision in M2

---

## Data Provenance Questions

### Q9: Future SAP feed must supply `display_name`

**Context:** Per D6, SAP creates new profit centers and Abacus maps them in. After M1, `reference_sap_profit_center.display_name` is NOT NULL.
**Risk:** If SAP doesn't provide a `display_name` in the future feed, the ingest will fail.
**Resolution path:** The ingest process (currently manual per D6) must always supply `display_name`. M2 admin UI lets admins set it. If automated SAP feed is added later, the feed must include the column or default to a placeholder. Add to M2.10 Looker report: alert on any PC with placeholder `display_name` older than X days.
**Status:** Documented; revisit if SAP integration becomes automated

### Q10: `display_name` for ~100 existing PCs

**Status (per D20):** Placeholder `<legal_name> -- <profit_center>` shown in UI; business updates via SQL UPDATE.
**No action required from engineering.**

---

## Coordination Questions

### Q11: SE dedup (M3.13) coordination with Humda

**Context:** Humda's parallel signing entity cleanup is in progress (D21). M3.13 reparents contracts from duplicate SE IDs to canonical — that needs to align with whatever canonical IDs Humda picks.
**Resolution path:** Sync with Humda before scheduling M3.13. Confirm canonical SE IDs before running reparent SQL.
**Status:** Pending M3 kickoff

### Q12: ows-coda glossary update timing

**Context:** ows-coda's `snowflake-glossary.json`, golden queries, and `contracts-write` tool reference the old SE→PC path.
**Scope:** Out of scope for this initiative (per user direction). Will be handled in a separate COD ticket after M1 lands.
**Resolution path:** No coordination required from this project. ows-coda team picks up after M1 release.
**Status:** Out of scope — tracked separately

---

## Bulk Operations

### Q13: Bulk endpoints — deferred pending demand

**Context:** Three plausible bulk operations surfaced during planning. Single-row endpoints (M2.2/M2.3/M2.4 for mappings/names, M3.1 for contracts) cover everyday admin workflows. Bulk endpoints add value only when volumes justify them or when there's a concrete migration in flight. Decision: defer all three; revisit when business or a project surfaces the need.

| Bulk Operation | Use Cases | Why Deferred | Cheap Fallback (today) |
|----------------|-----------|--------------|------------------------|
| Bulk contract reassignment (SE and/or PC) | Foundation Media full catalog migration; M3.13 SE dedup; PC reorgs | Highest-value of the three. Foundation Media's migration scale isn't known yet — if it's a few hundred contracts, a one-shot SQL script (transactional, run by engineering) is fine. Revisit if scale grows or if business wants a self-service UI. | One-shot SQL migration script, gated by code review. Audit trail captured via the `after_contract_update` trigger (M1.5). |
| Bulk SE↔PC mapping management (create/update/soft-delete) | New SE onboarding with many PCs; mass-revoke | M2.9 Foundation Media data load is ~5 rows — single-row admin UI covers it. Mass-revoke is rare. | Sequence of single-row admin operations, or direct SQL for one-time loads. |
| Bulk `display_name` update (CSV upload) | Business provides spreadsheet of real names to replace placeholders (D20); periodic refresh | ~100 rows is trivial as `UPDATE reference_sap_profit_center SET display_name = ... WHERE ...`. UI convenience doesn't justify the build cost. | Engineering runs SQL UPDATE on request. |

**Revisit triggers:**
- Foundation Media catalog migration crosses ~500 contracts → reconsider bulk reassignment endpoint.
- Business asks for self-service display_name management beyond the per-row admin UI.
- A new SE onboarding requires >20 mappings → reconsider bulk mapping creation.

**Status:** Deferred — capture the option, ship single-row endpoints first, escalate if demand materializes.
