MRP refactor & tech-team work streams · Tech Team Weekly · v1 (curated, May 28 2026)
14
Audit findings logged
2
Findings closed
Phase 1
Active — central inventory svc
952
Prod drift keys (F-014, open)
Jun 12
Brian's last day
Where it actually stands · source of truth: MRP repo — docs/audit-findings.md + plans/phase-*.md
The live refactor is an inventory-integrity track — make the running stock balance always reconcile with the movement ledger (findings F-001–F-014). This panel mirrors that register; the bullseye and engine below are the method.
✓
Phase 0 — reconciliation invariant
Runtime check + property tests + Slack drift alerts shipped (closed F-002, F-013). Runs in reporting mode until F-001's clamp drift is fixed.
Done
▸
Phase 1 — central inventory service
One disciplined write path for the ~20 sites that mutate stock today (closes F-001 clamp drift, F-010, and several others). The active build.
Building
▢
Stage 2 — write-site classification
Per-site audit of the ~22 stock-movement call sites. Not started.
Queued
▢
Stage 3 — cross-system coherence + UoM audit
End-to-end units of measure (schema → API → integrations), sales/return symmetry, FBA vs Amazon counts. Not started.
Queued
!
F-014 — 952 drifted keys in production
The new check found 952 (product, location, lot) keys where ledger and balance disagree — one off by 562M units. Mix of old bulk-import corruption + ongoing clamp drift. Doc recommendation: stop new drift now, write off old history later. Needs Dan's decision.
Decide
The Bullseye — what "correct" means, core outward
Core: BOM → finished goods, decrement raw materials, yields
Ring 1: State & sequencing — perpetual ledger, order/timing of MOs, concurrency
Ring 2: Scheduling & lateness (the 49% late-MO problem)
Outer: Nice-to-haves — reports, decorations
Correctness is stateful and temporal — not a pure snapshot function. Sequencing belongs inside the bullseye.
The Engine — order of operations
1 · Write test (inherits best-practice lattice)→2 · User-verify oracle (by hand)→3 · Segment + weight (fundamentals vs nice-to-have)→4 · Run prod & dev (snapshots)→5 · Diff-classify: fix / regression / neutral→6 · Merge on dominance
Loop until the precision threshold (depth × breadth vs the test) is met → then advance one ring out. The test defines the core; the bug ledger keeps the test honest.
The method — test-first engine, step by step
This is the approach, not the live tracker — current build status is in "Where it actually stands" above. Step 0 is done; "Harvest Brian" stays urgent (he leaves Jun 12).
0
Safe workspace — the precondition
Before touching code: a frozen prod snapshot plus the ability to run dev against a copy of the data. Tests run against snapshots and fixtures, never the live instance — the "don't flood the real bathroom" rule. This is also where you confirm data changes are reversible, because rolling back code doesn't roll back migrated data. In old-school terms: branch isolation plus a restorable data fixture.
Done
1
Harvest Brian — do this this week
Out of logical order on purpose. The oracle and the test both depend on knowing why the bugs happen, and 136 tickets of that knowledge walk out on the 12th. Sit Brian down against the ticket ledger and extract the failure patterns and the gnarly real BOMs. The single most time-sensitive step — it can't be redone later.
This week
2
Define the bullseye precisely
Name the one transform in plain words: BOM → finished goods, decrement raw materials, with yields and sequencing. Write what "correct" means before writing any test. Critically, include the temporal/state dimension — order and timing of MOs, concurrency — because the late-MO pain lives there, not in the snapshot math.
Next
3
Build the oracle from the hardest real cases
Hand-compute expected outputs for multi-level, partial-yield, sequenced BOMs sourced from step 1 — not clean toy examples. This is your user-validated truth, and its coverage is what the whole strategy rides on. The easy cases are exactly the ones that don't matter.
Next
4
Anchor the test to the bug ledger
Resolved tickets become regression cases; open tickets become target cases. This makes "the test defines the core" measurable instead of circular — the ledger is your external completeness check. Segment the suite (fundamentals vs nice-to-haves) and weight by severity, so a high average can't hide a critical regression.
Planned
5
Make it deterministic
Exact-decimal arithmetic for units of measure, frozen inputs, canonical units defined once. If the same test scores differently twice, the merge gate is noise. UoM normalization is both a correctness fix and the thing that makes the gate trustworthy.
Planned
6
Run the parallel harness, then refactor green-to-green
Score the prod snapshot and dev on the weighted suite; classify every divergence as fix / regression / neutral. Then change code — smallest pieces first, starting at the center of the bullseye (UoM is the likely first real refactor), always with the test as guardrail: characterize, then refactor under its protection.
Planned
7
Merge on dominance
Promote dev → prod only when there are zero regressions on the weighted segments, strict improvement, and a reversible / cutover-safe data migration. Communicate the breaking changes when UoM behavior flips — the cutover-window reliability dip is the one real residue.
Planned
8
Loop or advance
A precision threshold — depth × breadth against the test — decides the next move: close enough, advance one ring out on the bullseye; not close enough, improve the test or the code and re-run. The test defines done.
Planned
Engine findings — grounded in the code, ready as oracle cases
1 · Planning nets against on-hand, not available.mrp_engine._load_stock_levels sums StockItem.quantity_on_hand and nets against it, but stock also carries quantity_reserved. Can double-allocate reserved stock.
2 · UoM conversion happens outside the planning explosion.BOMLine says conversion is "applied at MO creation," but _plan_manufacturing explodes with no unit conversion. Planning in one basis, executing in another — classic silent corruption.
3 · Scrap is on inputs; output yield is not obvious.effective_quantity inflates component use by scrap %, but there's no visible yield-loss on the manufactured output — exactly Brian's "post-yield manufacturing" concern.
User-reported feedback log · source: curated (verbal — run export_bug_stats.py to go live)
Resolved136
Open~34
Weekly inflow7–12
Live from MRP feedback_submissions (user-reported bugs) — distinct from the engineering findings register (F-001–F-014) above, and from Brian's own ticket count. Confirm which is the canonical bug ledger before using it as the test's completeness check.
Architecture reference — MRP vs Data Hub, the 9 layers
Verdict: a Civic and a Tacoma, not two Corollas. Same nine layer names, opposite shapes. Data Hub is an OLAP reporting system; MRP is an OLTP system of record. Keep both; run them on a bus with explicit contracts. Consolidate only where layers truly coincide — identity/SSO (L9) and one cloud-storage story (L1) — and integrate at the seam (L5–6), don't merge cores.
#
Layer
Data Hub
MRP
Same?
1
Storage
Parquet files (→ R2)
Postgres / Cloud SQL
Diff
2
Format
Columnar Parquet
Row-oriented Postgres
Diff
3
Catalog
schema.sql + parquet_db
ORM + 97 Alembic migrations
~
4
Compute
DuckDB, ephemeral
Postgres, always-on
Diff
5
Ingestion
Batch pulls (Windsor)
Webhooks + Pub/Sub, event-driven
Diff
6
Logic
Thin (formulas in md)
Thick (mrp_engine — the mass)
Diff
7
Serving
Static baked JSON
Live FastAPI, 29 routers
Diff
8
App
Vanilla HTML + Chart.js
React/TS SPA
~
9
Auth
Cloudflare Zero Trust
JWT + RBAC + multi-tenant
Diff
Plus two layers the analytics stack has no row for and MRP lives on: transaction/state integrity (perpetual ledger) and schema evolution (Alembic).
Trustworthy meeting transcripts you can prompt against — "pull every problem and proposed solution," prioritize, and get to work. Infrastructure that pays back across every meeting.
Key engineering decision — diarization
Diarization is an audio-signal problem, not a reasoning one. Claude receives text, never the waveform, so it can't pull "who's speaking" from raw audio — that's pyannote / Deepgram / Gemini acoustic-model territory.
The decomposition: convert one n>1 problem into n parallel n=1 problems plus a text merge. With per-speaker capture (separate mics/streams), you never diarize at all — each speaker is a pristine stream transcribed at high integrity.
Trade-off: everyone runs local capture software (more logistics). The Gemini "watch the screen" workaround is clever but fragile and leans entirely on Gemini.
Next steps
·
Get this week's cleaned transcript out sooner
Usefulness scales with how much time the team has with it.
In progress
·
Research idiomatic agent-driven test development
Feeds the MRP "target" best-practice lattice.
Offered
·
Evaluate per-speaker capture vs single-stream cleanup
Decide whether local-software logistics are worth the integrity gain.
Open
Active
Infrastructure & Architecture Rationalization
Decide how MRP and Data Hub relate, then standardize the shared ground. The layer map (see MRP Refactor tab) is the input; this is the decision.
The verdict & topology
Civic & Tacoma — keep both. OLAP reporting vs OLTP system of record; different jobs, different correct architectures. Welding them would break both.
Bus with explicit contracts, not a merged monolith. Paths keep their value even on a bus — the two are genuinely different bounded contexts.
Canonical-ownership rule (already in MRP's CLAUDE.md): Data Hub is canonical for finance; MRP is canonical for inventory. Cross-references are links, never copies.
Consolidate vs integrate
Consolidate (layers coincide)
· Identity / SSO (L9) — one Google-account login across both, not Zero-Trust-here / JWT-there. · One cloud / object-storage story (L1) — pick R2 or GCS, stop straddling.
Integrate, don't merge (the seam, L5–6)
· MRP inventory / production facts → Data Hub for analytics. · Data Hub finance & Dave's forecast → MRP to drive the production-planning module.
First contract on the bus — live now
Live
MRP bug log → Data Hub
The bug burndown on the MRP Refactor tab is the first real cross-system link — a working prototype of the bus-with-contracts pattern, at the smallest possible stakes.
Direction: MRP (canonical owner of the bug log) → Data Hub (read-only snapshot). Data Hub never owns the data; it displays a refreshed copy. Links, not copies — exactly the canonical-ownership rule.
Mechanism:scripts/export_bug_stats.py reads feedback_submissions (read-only) → writes tech_program_data.json → the dashboard fetches it. Refresh:scripts/refresh_bug_stats.sh on a daily cron (runs where Cloud SQL is reachable, then deploys).
Why start here: it validates the integration shape — direction, ownership, refresh cadence, failure mode (stale snapshot, not a broken page) — before the heavier flows (inventory → Data Hub, forecast → MRP) ride the same bus.
The AI-layers (Factorio) model
Model processes as networks visually, talk to Claude against the binary, get ~60–80% accurate process models, then translate to code. The meta-move: load the 9-layer map into both systems, have each self-represent per layer, then run the translation analysis from inside Data Hub.
Gated on one undefined qualifier: is the model rigorous enough to arbitrate architecture, or only to build shared understanding? Keep it as ideation until that bar is set.
Open flag
R64 conflict: the logged decision was to migrate to AWS RDS Postgres, but MRP actually runs on GCP Cloud SQL Postgres. Needs Dan's resolution — did the plan change, or is this an unfinished migration? (Flagged in MRP_CLAUDE_MD.md audit checklist.)