From e7c73458267dde0328c850574edf75ccb99f6d4d Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 29 Jul 2026 22:18:06 +0000 Subject: [PATCH] =?UTF-8?q?docs:=20session=20wrap=20=E2=80=94=20HANDOFF=20?= =?UTF-8?q?entry=20and=20four=20DECISIONS=20for=20the=20enrichment=20arc?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit HANDOFF: records the 2026-07-29 cost-side / production-deploy / period-explicit canonical arc merged to main at 0ea3961, with state and post-CEO-window next steps. DECISIONS: promotes four durable choices — cy2025 as the default canonical period; the five-margin-line "name the basis" rule; contract-to-cash's uncollected-receivables copy is wrong ($0 by construction); and retirement of the invented 22-55% SKU-spread target in favor of "width >= 30pt, position inherited." Docs only. Nothing wired to costing.*; no live app touched. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01Pn556c7bmnhPDqerWYYw2B --- DECISIONS.md | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++ HANDOFF.md | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 121 insertions(+) diff --git a/DECISIONS.md b/DECISIONS.md index 4ed75eb..cbfad95 100644 --- a/DECISIONS.md +++ b/DECISIONS.md @@ -17,6 +17,67 @@ Each entry: --- +## Canonical & Data Model + +### 2026-07-29 — Default period for any unqualified "annual" figure is cy2025 +- **Decision:** When canonical states a figure without a period, it means + cy2025 (2025-01-01 … 2025-12-31). Every other period is a named variant, + not a discrepancy. +- **Why:** Tools kept reading as "failing" against canonical when they were + measuring a different window, not a different number — every prior headline + figure was silently trailing-36-months (e.g. DIO 127.3=t36m, cy2025=134.6). + cy2025 is chosen over other defaults because scan data ends 2025-12-27, so + trailing-12-months resolves to the identical window — it collapses two + candidate defaults into one definition instead of leaving rival readings. +- **Scope:** global — `reference/CINDERHAVEN_CANONICAL.md`, + `reference/canonical_values.yml`, every downstream tool citing canonical. +- **Do not:** cite a canonical figure without its period; treat a + named-variant period as drift. + +### 2026-07-29 — There are five margin lines; always name the basis +- **Decision:** Cinderhaven has five distinct, all-real margin figures — + gross-at-standard (51.98%), contribution after commercial costs (49.01%), + gross-at-landed (~43.5%, legacy), loaded-at-standard (42.5%), and + loaded-at-actual (42.3% blended). Cite the basis with the number, always. +- **Why:** They differ because a CFO expects them to (COGS-narrow vs + fully-loaded contribution are different P&L lines). Presenting one without + its basis reads as the can't-keep-numbers-straight defect this warehouse's + canonical exists to kill. Loaded-at-standard is flat by construction (frozen + standard); loaded-at-actual carries the PPV compression. +- **Scope:** global — anything quoting Cinderhaven margin. +- **Do not:** compute margin from `manufactured_cost_per_unit` and call it the + loaded margin (that is loaded-at-actual, not -at-standard); modify + `raw.sku_costs` wholesale/cogs to hit a spread target (moves every published + margin). + +### 2026-07-29 — contract-to-cash's uncollected-receivables copy is wrong +- **Decision:** The narrative attributing part of the invoiced-vs-collected + gap to uncollected receivables must be rewritten. Uncollected receivables + are **$0** by construction. +- **Why:** `invoiced == gross_payments` to the cent because + `generate_remittances()` partitions every order into exactly one + retailer-month remittance and `net = gross − total_deductions`; the schema + has no aging bucket, bad-debt, or unpaid-invoice concept. The entire gap is + trade allowances, deductions, chargebacks, and a timing residual. +- **Scope:** contract-to-cash hero copy; any tool implying AR. +- **Do not:** present AR as a number; it is absent-structural, not zero. + +### 2026-07-29 — The 22–55% SKU-margin-spread target was invented; retire it +- **Decision:** The "roughly 22–55%" SKU loaded-margin spread target is + retired as unsourced. The criterion is **width ≥ 30 points, position + inherited from `raw.sku_costs`**. Achieved and canonical: 25.81–60.94% + (35.1-point width). +- **Why:** The target was an invented illustration of "wide spread," same + class as the trade-spend trajectory and best-seller-worst-margin claims + already retracted. What mattered was width, and the build exceeds it. The + position is inherited from frozen wholesale/cogs; the only way to move it is + to modify protected pricing data, which moves every published margin. +- **Scope:** cost-side SKU margin; `fct_product_costs`. +- **Do not:** treat a red check against the old 22–55% as a real failure — the + check is wrong; this decision is the fix. + +--- + ## Infrastructure & Ops ### 2026-07-02 — Stop guessing at cinderhaven-db's flypgadmin credential; rebuild or escalate instead diff --git a/HANDOFF.md b/HANDOFF.md index 0b5f00b..ca88d37 100644 --- a/HANDOFF.md +++ b/HANDOFF.md @@ -9,6 +9,66 @@ For things that didn't work, see FAILURES.md. --- +## 2026-07-29 (wrap) — cost-side data model, production deploy, period-explicit canonical; all merged to main + +**Started from:** Phase 1 complete (entry below). User directed the full +enrichment arc across several turns. + +**Did (four arcs, all merged to main at `0ea3961` via squashed PR #2):** +- **Cost side.** New isolated `costing` schema — `fct_product_costs`, + `fct_inventory_snapshot`, `dim_suppliers`, `fct_supplier_invoices`, plus + production runs, inventory lots, lot balances, and a lot→shipment→store + bridge. Five named margin lines (gross-at-standard 51.98%, contribution + 49.01%, gross-at-landed ~43.5%, loaded-at-standard 42.5% flat, + loaded-at-actual 42.3% blended). PPV carries the compression (standard + frozen at launch; actual walks 45.0→42.4→39.6). CCC 119.7 (t36m, + production). Additive-only: nine protected tables byte-identical before/after. + No cross-schema FKs (DROP SCHEMA raw CASCADE would silently drop them); + integrity in the generator + `tests/test_costing_integrity.sql`. Stored + totals are GENERATED STORED. +- **Production deploy.** Dispatch-only workflow `deploy-costing.yml` with a + pre-flight guard (halts if `costing` holds rows unless force_recreate). + First install — `costing` did not previously exist. Every acceptance figure + matched the replica; integrity clean. One-cent divergence on + `fct_retailer_payments` + `mart_channel_contribution` diagnosed as a + different seed run, not tampering (it foots, raw=mart, only float-rounded + currency columns differ). +- **Period-explicit canonical.** Rebuilt `CINDERHAVEN_CANONICAL.md` → + `reference/` so every value carries a basis AND a period; added + machine-readable `reference/canonical_values.yml` keyed + `metric.basis.period`; root pointer left behind. Default period **cy2025** + (≡ trailing_12m). Headline: prior canonical figures were silently + trailing-36m, which is why cy2025 tools read as failing (DIO 127.3=t36m, + cy2025=134.6). Guards hard-fail if the file is missing; + `verify_canonical.py` reads the YAML. Three findings recorded not smoothed: + 2024 revenue is a velocity peak on a shrinking door base; authorizations + 9,943/0/49 is an initial-load artifact; promo spend + deauths are zero in + cy2025 (windows ended 2024). Values VERIFIED-AGAINST-PRODUCTION via + read-only workflow. +- **CI bug fixed.** `canonical-drift.yml` had hardcoded the literal string + `REDACTED` as the Postgres password since `a4cebc4` — the drift check had + **never** authenticated. `f97abbf` interpolates `$POSTGRES_PASSWORD`; drift + now green against production. + +**State:** main `0ea3961`, clean. PR #1 (Phase 1 + cost side) and PR #2 +(period-explicit canonical) both merged. Designated branch recreated from main +for this wrap. `costing.*` live in production, nine protected tables intact, +**nothing wired to `costing.*`** — no tool, no dbt model, no live app. +Local replica is ephemeral to the container. flyctl/Fly creds are NOT in the +session; all production work went through dispatch-only GitHub Actions +(FLY_API_TOKEN + POSTGRES_PASSWORD secrets). Remote branch deletion is blocked +from the session env (git proxy + REST both refuse); user deletes branches. + +**Next (post-CEO-window, separate work):** wire tools to `costing.*` one at a +time (recall-blast-radius, the four margin tools, Spin Rate migration, etc.). +The four UNSOURCED hypotheses (trade-spend trajectory, best-seller-worst-margin, +master-data degradation, deduction learning curve) still need SPINS/Nielsen +checks before becoming demo numbers. `reference/COST-SIDE-DATA-SPEC.md` was +referenced by the user but never existed in the repo — schemas were designed +from the prompt. + +--- + ## 2026-07-29 — Phase 1: canonical verified against Postgres, both contradictions resolved, pre-Phase-2 baseline recorded **Started from:** Two-phase instruction from user. Phase 1 (measure,