From a15b75e38a285b84601c8fc516f93a6a9e24c537 Mon Sep 17 00:00:00 2001 From: gsinghpal Date: Tue, 21 Apr 2026 19:53:40 -0400 Subject: [PATCH] docs(plating): fine-tuning initiative roadmap + Sub 2 design spec MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Captures the current state of the system-wide fine-tuning initiative so a fresh Claude Code session can resume without context loss. CLAUDE.md additions (fusion_plating/CLAUDE.md): * Sub-project roadmap (Sub 1 through 8 + two deferred items) * Sub 2 locked decisions (Q1–Q6 answers) * Sub 2 defensive measures that prevent rework when later subs land * Sub 6 / 7 / 8 previews from the client transcript * Client-confirmed operational thresholds (tank polling, active tanks) * How to resume in a fresh session Sub 2 design spec (docs/superpowers/specs/): * Part Data Model Overhaul — covers gaps 2b, 2c, 2d, 4 * 12 sections: scope, data model, migration, UI, cert resolution, reports, testing, defensive measures, files touched, rollout, success criteria, open questions * All clarifying questions answered; zero placeholders * Ready for writing-plans skill to generate implementation plan Co-Authored-By: Claude Opus 4.7 (1M context) --- .../2026-04-21-sub2-part-data-model-design.md | 381 ++++++++++++++++++ fusion_plating/CLAUDE.md | 79 ++++ 2 files changed, 460 insertions(+) create mode 100644 docs/superpowers/specs/2026-04-21-sub2-part-data-model-design.md diff --git a/docs/superpowers/specs/2026-04-21-sub2-part-data-model-design.md b/docs/superpowers/specs/2026-04-21-sub2-part-data-model-design.md new file mode 100644 index 00000000..e0df3bd7 --- /dev/null +++ b/docs/superpowers/specs/2026-04-21-sub2-part-data-model-design.md @@ -0,0 +1,381 @@ +# Sub 2 — Part Data Model Overhaul + +**Date:** 2026-04-21 +**Module scope:** `fusion_plating_configurator`, `fusion_plating_reports`, `fusion_plating_bridge_mrp` (cert-resolution wiring) +**Status:** Design approved; ready for implementation plan +**Predecessor context:** Fine-Tuning Initiative, entry in `fusion_plating/CLAUDE.md` + +--- + +## 1. Scope + +Four gaps from the Fine-Tuning running plan: + +| Gap | Summary | +|---|---| +| **2b** | Part Number + Revision become required; Part Name becomes optional | +| **2c** | Dual descriptions (internal + customer-facing) on every description-template row, flowing to SO line | +| **2d** | Per-part `certificate_requirement` with `inherit` fallback to the partner's existing flags | +| **4** | "SKU" relabel to "Part Number" in UI; customer-facing reports print `part_number`, not `default_code` | + +### Out of scope (moved to later sub-projects) + +- Part's default process / Process Composer → **Sub 3** +- Contract Review workflow → **Sub 4** +- Order-line additions (serial, job#, thickness dropdown, revision picker) → **Sub 5** +- Contact Profiles and per-location notifications → **Sub 6** + +--- + +## 2. Data Model Changes + +### 2.1 `fp.part.catalog` (customer parts library) + +``` +part_number : Char, required=True # was optional +revision : Char, required=True, default='A' # was optional +name : Char, required=False # was required + ++ certificate_requirement : Selection( + ('inherit', 'Inherit from Customer'), + ('none', 'No Certificate'), + ('coc', 'CoC Only'), + ('coc_thickness', 'CoC + Thickness Report'), + ), default='inherit', tracking=True +``` + +### 2.2 `fp.sale.description.template` (Descriptions tab repeater) + +``` +description : REMOVED (migrated out and dropped) + ++ internal_description : Text, required=True ++ customer_facing_description : Text, required=True +``` + +### 2.3 `sale.order.line` (Odoo standard, extended) + +``` +name : (Odoo native, already required. Clarified + semantically as THE customer-facing + description — no repurpose, just formal + naming.) + ++ x_fc_internal_description : Text, required=True ++ x_fc_description_template_id : Many2one('fp.sale.description.template') + (which template row the estimator picked) +``` + +### 2.4 Explicitly NOT changing + +- `product.product` / `product.template.default_code` — untouched. The generic service products (EN Plating, Chrome, etc.) keep their SKUs. +- Revision chain (`parent_part_id`, `is_latest_revision`, `revision_ids`) — kept as-is (Sub 5 consumes it for the revision picker). +- `fp.part.catalog.notes` Html — kept as freeform drawer notes, not part of the description system. +- Partner-level cert flags (`res.partner.x_fc_send_coc`, `x_fc_send_thickness_report`) — kept as the fallback layer for `certificate_requirement = 'inherit'`. + +--- + +## 3. Migration Strategy + +Runs once via `post_init_hook` on the module upgrade. All steps idempotent (NULL/empty guards). Safe to re-run. + +### Step 1 — Backfill `fp.part.catalog.part_number` + +```sql +UPDATE fp_part_catalog +SET part_number = name +WHERE part_number IS NULL OR part_number = ''; +``` + +Defensible: before this change, `name` was the part identifier. Copy over so `required=True` doesn't reject existing records on upgrade. + +### Step 2 — Backfill `fp.part.catalog.revision` + +```sql +UPDATE fp_part_catalog +SET revision = 'A' +WHERE revision IS NULL OR revision = ''; +``` + +### Step 3 — Split `fp.sale.description.template.description` + +For every template row with non-empty `description`: + +``` +internal_description := (original description value) +customer_facing_description := (original description value) +``` + +Both fields start with the same text. Estimators separate internal workflow text from customer text over time. The old `description` column is dropped in the same migration. + +### Step 4 — Backfill `sale.order.line.x_fc_internal_description` + +For every SO line in any state: + +``` +x_fc_internal_description := name (starter, copy from the existing line description) +``` + +The `required=True` constraint applies to **new lines only** — migration flag skips enforcement on historical records so upgrades don't fail on old orders. + +### Step 5 — Default cert requirement + +Every existing `fp.part.catalog` record gets `certificate_requirement = 'inherit'`. Zero behaviour change for in-flight jobs: the cert cascade still reads partner toggles until a shop admin explicitly sets a part to something other than `inherit`. + +--- + +## 4. UI Changes + +### 4.1 Part form (`fp.part.catalog`) + +Top identity block: + +``` +Part Number* [required] │ Revision* [required, default 'A'] +Part Name [optional] │ Customer [required] +``` + +New "Quality & Delivery" group: + +``` +Certificate Requirement: [Inherit from Customer ▾] + options: Inherit / None / CoC / CoC + Thickness +Help tooltip: "Inherit reads the customer's default + (Partner → Plating Documents tab)." +``` + +Descriptions tab — the existing repeater gains two columns: + +| Template Name | Category | Internal Description | Customer-Facing Description | Used | Active | +|---|---|---|---|---|---| + +Both description columns required to save a row. Hint above the table: + +> "Internal = what the shop floor sees on the WO / traveler. Customer-Facing = what prints on SO, invoice, packing slip." + +### 4.2 Direct-Order Wizard + SO Line form + +Per line: + +- Part picker (unchanged) +- **Description Template** dropdown — lists active templates where `part_catalog_id == the chosen part`. Partner-wide and coating-wide templates (which the data model allows) are **not** shown at order entry; the dropdown is narrowed to per-part templates to match the shop's mental model ("canned descriptions for this part"). +- **Customer-Facing Description** text box — prefilled from template, editable +- **Internal Description** text box — prefilled from template, editable + +If the part has zero templates, both boxes start blank and the estimator types them. Both required before save. + +### 4.3 Universal SKU → Part Number relabel + +- Fusion Plating form / list / search views: `string="SKU"` → `string="Part Number"` on fields referencing `fp.part.catalog.part_number`. +- Customer-facing reports: line rendering flows through the new QWeb macro (§6.1) — prints `part_number + revision + name` (customer-facing desc), no `[default_code]`, no product display name. +- Internal reports: show everything — part number, revision, customer-facing description, internal description, service product name, service SKU. +- Odoo-native screens (inventory, warehouse, product selector): untouched. Keep showing `default_code` as "SKU". Customer never sees these. + +--- + +## 5. Certificate-Requirement Resolution (Runtime) + +### 5.1 Single-source resolver (Defensive Measure 1) + +All cert-related decisions route through one method on `mrp.production`: + +``` +def _fp_resolve_cert_requirement(self): + """Returns (want_coc: bool, want_thickness: bool) for this MO. + + Walks SO lines to collect each part's certificate_requirement. + Part-level wins; 'inherit' falls back to partner toggles. + Multi-line MO: strictest wins. + """ +``` + +### 5.2 Resolution order + +``` +1. Walk MO → origin (SO name) → sale.order → sale.order.lines → x_fc_part_catalog_id. +2. For each line's part: + if part.certificate_requirement != 'inherit': + want_coc_line = part.certificate_requirement in ('coc', 'coc_thickness') + want_thickness_line = part.certificate_requirement == 'coc_thickness' + else: + # Fallback to partner-level flags + want_coc_line = partner.x_fc_send_coc + want_thickness_line = partner.x_fc_send_thickness_report + +3. Multi-line MO — strictest wins: + want_coc = any(want_coc_line across lines) + want_thickness = any(want_thickness_line across lines) +``` + +### 5.3 Callers (must use the resolver) + +- `_fp_generate_cert_pdf` in `fusion_plating_bridge_mrp/models/mrp_production.py` (cert cascade on MO done) +- QC gate's thickness-required check (if/when it reads partner flags today — audit during implementation) +- Notification routing for auto-email (future Sub 6 will hook here) + +### 5.4 Multi-line and fallback cases + +- **Multi-line MO** — strictest wins so a customer never gets less paperwork than promised for any part in the batch. +- **MO with no SO link** (manual MO) — falls back to `mo.partner_id` if set, else `want_coc=True, want_thickness=False` as safe default. + +### 5.5 Backward compatibility + +Every existing part has `certificate_requirement = 'inherit'` after migration. The resolver falls through to partner toggles exactly as today. No behaviour change for any shipping job until a shop admin explicitly changes a part's cert requirement. + +--- + +## 6. Report Impact + +### 6.1 Shared QWeb line-header macro (Defensive Measure 2) + +New template in `fusion_plating_reports`: + +```xml + +``` + +All four customer-facing report line renderers call ``. When Sub 5 adds the revision picker (and with it the revision snapshot on the SO line), the macro is updated once and all reports follow. + +### 6.2 Per-report changes + +| Report | Audience | Change | +|---|---|---| +| `report_fp_sale.xml` | Customer | Line header via macro: `part_number + revision + name`. Skip `[default_code]`, skip product display name. | +| `report_fp_invoice.xml` | Customer | Same (via macro) | +| `report_fp_packing_slip.xml` | Customer | Same (via macro) | +| `report_fp_bol.xml` | Customer | Same (via macro) | +| `report_fp_work_order.xml` | Internal (operator) | Keep product/service name + `default_code`. Add `part_number`, `revision`, `name` (customer-facing desc), `x_fc_internal_description` (ops workflow). | +| `report_fp_job_traveller.xml` | Internal | Same as work order. | +| `report_coc.xml` | Customer | Audit — reads `doc.part_number` on `fp.certificate`. Spot-check that the cert model populates `part_number` from `sale_order_line.x_fc_part_catalog_id.part_number`. No change expected. | +| `report_fp_receipt.xml` | Customer | Customer macro treatment. | + +### 6.3 Fallback for non-part lines + +The macro's fallback branch renders the generic product name for lines without `x_fc_part_catalog_id` (rush fees, freight, expedite). Those lines were never meant to show a part number. + +--- + +## 7. Testing Strategy + +### 7.1 Migration tests (one-shot, runs on upgrade) + +- `fp.part.catalog` with empty `part_number` → `part_number = name` after migration +- `fp.part.catalog` with empty `revision` → `revision = 'A'` after migration +- `fp.sale.description.template` rows with text in `description` → both `internal_description` AND `customer_facing_description` hold that same text; old column gone +- Confirmed/done SO lines get `x_fc_internal_description = name` backfilled +- Every existing part ends with `certificate_requirement = 'inherit'` +- Running the migration a second time is a no-op (idempotency) + +### 7.2 Unit tests + +- New part without `part_number` → save rejected (UserError / validation) +- New part without `revision` → save rejected +- New part without `name` → saves fine (optional) +- Description template row: both descriptions must be non-empty +- SO line: both `name` AND `x_fc_internal_description` must be non-empty +- Cert resolution: part `coc_thickness` + partner `send_coc=False` → result `(True, True)` — part wins +- Cert resolution: part `inherit` + partner `send_coc=True, send_thickness=False` → result `(True, False)` — falls through +- Cert resolution: multi-line MO with parts `none` + `coc_thickness` → result `(True, True)` — strictest wins +- Cert resolution: MO with no SO link → safe fallback + +### 7.3 End-to-end smoke (odoo-shell scripts, pattern from QC suite) + +- Direct order → SO confirm → MO confirm → MO done → CoC generated with customer part number on page 1, no `[default_code]` +- Same flow with `certificate_requirement = 'none'` on the part → no CoC generated even if partner has `send_coc=True` +- Order entry: pick a description template row → both fields populate on the SO line → save → reopen → both fields persist → customer SO PDF shows only the customer-facing description +- Two customers both add a part numbered `WIDGET-001` at different revisions → no collision (different fp.part.catalog records; default_code on the service product is unchanged) + +### 7.4 Regression on Phase 1–3 (QC work) + +After the Sub 2 migration, re-run: + +- `fp_qc_smoke.py` (9-step smoke) +- `fp_qc_e2e.py` (8-case edge suite) +- `fp_full_workflow.py` (full lifecycle) + +All must stay green. Sub 2 only wires cert resolution through a new helper — QC checklist logic is untouched. + +--- + +## 8. Defensive Measures (Prevent Rework When Later Subs Land) + +1. **Single-source cert resolution** (§5.1) — `_fp_resolve_cert_requirement` is the only place partner-level fallback is read. When Sub 6 restructures partner flags into per-location or per-contact permissions, one function updates — no call-site hunt. +2. **Shared QWeb macro** (§6.1) — all four customer-facing reports render the line header through one template. Sub 5's revision picker updates the macro, all reports follow. +3. **Idempotent migration** (§3) — safe to re-run; doesn't fight future sub-project migrations. +4. **Additive SO line fields** — `x_fc_internal_description`, `x_fc_description_template_id` sit alongside future Sub 5 fields (`x_fc_serial_number`, `x_fc_job_number`, `x_fc_thickness`, `x_fc_revision_snapshot`) with zero touchpoints. +5. **Clean removal of old `description` column** — migrated then dropped in the same migration. No deprecated-field confusion later. + +--- + +## 9. Files Touched (Anticipated) + +### Models +- `fusion_plating_configurator/models/fp_part_catalog.py` — field changes (part_number / revision required, name optional, + certificate_requirement) +- `fusion_plating_configurator/models/fp_sale_description_template.py` — field split +- `fusion_plating_configurator/models/sale_order_line.py` — add `x_fc_internal_description`, `x_fc_description_template_id` +- `fusion_plating_bridge_mrp/models/mrp_production.py` — add `_fp_resolve_cert_requirement`; rewire `_fp_generate_cert_pdf` to call it + +### Views +- `fusion_plating_configurator/views/fp_part_catalog_views.xml` — required markers, cert requirement field, relabels +- `fusion_plating_configurator/views/fp_part_catalog_views.xml` (Descriptions tab) — two-column repeater +- `fusion_plating_configurator/views/sale_order_views.xml` — SO line internal-description field +- `fusion_plating_configurator/wizard/fp_direct_order_wizard_views.xml` — description-template picker + dual-description inputs +- Wherever "SKU" appears in views → relabel to "Part Number" + +### Reports +- `fusion_plating_reports/report/report_fp_sale.xml` — use macro +- `fusion_plating_reports/report/report_fp_invoice.xml` — use macro +- `fusion_plating_reports/report/report_fp_packing_slip.xml` — use macro +- `fusion_plating_reports/report/report_fp_bol.xml` — use macro +- `fusion_plating_reports/report/report_fp_work_order.xml` — add internal description, keep product/default_code +- `fusion_plating_reports/report/report_fp_job_traveller.xml` — same as WO +- `fusion_plating_reports/report/customer_line_header.xml` — NEW macro + +### Migration +- `fusion_plating_configurator/migrations/19.0.X.X.X/post-migration.py` — all five migration steps +- `fusion_plating_configurator/hooks.py` — register `post_init_hook` if not already present + +### Security +- No new models, so no new ACL rows needed. Existing `fp.part.catalog` and `fp.sale.description.template` ACLs already cover the new fields. + +### Manifest +- `fusion_plating_configurator/__manifest__.py` — bump version; register new view / wizard changes +- `fusion_plating_reports/__manifest__.py` — register new macro file +- `fusion_plating_bridge_mrp/__manifest__.py` — bump version + +--- + +## 10. Rollout + +1. Bump version on all three affected modules. +2. Push to entech via standard deploy: `systemctl stop odoo` → `odoo -d admin -u fusion_plating_configurator,fusion_plating_reports,fusion_plating_bridge_mrp --stop-after-init` → clear asset cache → `systemctl start odoo`. +3. Verify migrations ran: count backfilled records against expected. +4. Run the smoke + E2E + regression suites. +5. Commit + push when green. + +--- + +## 11. Success Criteria + +- Every part on the system has a non-empty `part_number` and `revision`. +- The Descriptions tab on every part shows the two-column repeater; old single-column layout is gone. +- Creating a sale order without filling both descriptions on each line is rejected. +- Customer-facing CoC / SO / invoice / packing slip / BoL never print Odoo's internal SKU. +- Setting a part's `certificate_requirement` to `none` suppresses CoC generation on MO done, even if the partner has `x_fc_send_coc=True`. +- Phase 1–3 QC regression suite stays fully green. + +--- + +## 12. Open Questions (None Blocking) + +All clarifying questions from the brainstorm (Q1–Q6) are answered. No blocking open questions. Possible implementation-time discoveries (flagged for the plan, not for the spec): + +- Exact list of QWeb reports that currently print `default_code` as a line-prefix (grep during implementation; the macro swap might touch one or two more than listed in §6.2). +- Whether any third-party portal template also renders line headers (unlikely; portal jobs show job-level data not line-level, but worth a sanity grep). + +These are discovery items, not design decisions. diff --git a/fusion_plating/CLAUDE.md b/fusion_plating/CLAUDE.md index 03ec644b..029037e6 100644 --- a/fusion_plating/CLAUDE.md +++ b/fusion_plating/CLAUDE.md @@ -356,3 +356,82 @@ See `K:\Github\RePackaged-Odoo\CLAUDE.md` for full details. Key points: - Phone-home/telemetry gutted - `web_enterprise` and `mail_enterprise` are installed on odoo-entech - Addons path includes: `_dependencies`, `accounting`, `inventory_manufacturing`, `hr`, `sales`, `ai`, `fusion_backend`, `custom`, `website` + +## Fine-Tuning Initiative (Started 2026-04-21) + +System-wide UX gap closure. Running PLAN → SPEC → IMPLEMENT per sub-project so we don't +rewrite code as new requirements surface. Each sub-project has its own design doc in +`docs/superpowers/specs/` and its own implementation plan before any code lands. + +### Sub-Project Roadmap +| # | Sub-project | Status | Gaps | +|---|---|---|---| +| 1 | Direct Order Wizard fix (no auto-confirm/auto-email) | Pending | Gap 1 | +| 2 | Part Data Model Overhaul (part#/rev required, dual descriptions, per-part cert requirement, SKU→Part Number on customer docs) | Design approved 2026-04-21 | 2b, 2c, 2d, 4 | +| 3 | Default Process + Composer per part (reuse recipe tree) | Pending | 2e, 2f | +| 4 | Contract Review two-portion workflow (QA Assistant + QA Manager; pre-production gate) | Pending | 2i | +| 5 | Order-line fields (serial, job#, thickness dropdown, revision picker) | Pending | 5, 6, Q2 | +| 6 | Contact Profiles & Communication Routing (sub-contacts + per-location notification lists + global contacts) | Pending | client transcript A/B/C | +| 7 | IoT tuning (configurable polling interval 15–30 min, seed 6–10 tank sensors) | Pending | client transcript D | +| 8 | Receiving / Inspection / QC flow restructure (split receiving vs inspection; racking crew inspects, not receiver) | Pending | client transcript E | +| ∞ | First-off / last-off QC | Deferred | client transcript F | +| ∞ | VEC machine auto-ingest (Word-format thickness report from network-connected XRF; different machine from Fischerscope) | Deferred | client transcript G | + +### Sub 2 Locked Decisions (2026-04-21) + +| Q | Decision | +|---|---| +| Q1 — Cert requirement precedence | Part wins; partner is fallback. New selection `certificate_requirement` on `fp.part.catalog`: `inherit` / `none` / `coc` / `coc_thickness`. Default `inherit` preserves current behaviour for existing records. | +| Q2 — Revision handling | Keep existing chain (`parent_part_id`, `is_latest_revision`, `revision_ids`). Out-of-scope for Sub 2. The "revision picker at order entry" moves to Sub 5. | +| Q3 — Required-field flip | Strict + backfill. On upgrade: `part_number = name` if empty; `revision = 'A'` if empty. Then `required=True` for both. `name` becomes optional. | +| Q4 — Descriptions shape | Split `fp.sale.description.template.description` into `internal_description` + `customer_facing_description`. Repeater on the part's Descriptions tab gains two columns. Old `description` column dropped in migration. | +| Q5 — SKU vs Part Number | Use `fp.part.catalog.part_number` directly as the source of truth. Don't sync to `default_code`. Customer-facing reports print `part_number`; internal reports keep showing `default_code` (service code). Odoo-native screens untouched. | +| Q6 — Description required at order entry | **Both required.** SO line carries `name` (customer-facing, already Odoo standard) + new `x_fc_internal_description` (ops workflow). Both required before save. | + +### Sub 2 Defensive Measures (Prevent Rework When Later Subs Land) + +1. **Single-source cert resolution function** — `mrp.production._fp_resolve_cert_requirement(self)` returns `(want_coc, want_thickness)`. Every caller (cert cascade, QC gate, notification routing) goes through this. When Sub 6 restructures partner-level flags into location / contact permissions, one function updates — no call-site hunt. +2. **Shared QWeb line-header macro** — `fusion_plating_reports.customer_line_header` renders `part_number + revision + customer-facing description` with fallback to product name for non-part lines. All 4 customer-facing reports (SO, invoice, packing slip, BoL) call the macro. Sub 5's revision picker updates the macro once, all reports follow. +3. **Isolated migration** — Sub 2's `post_init_hook` is idempotent (NULL/empty checks). Safe to re-run. Doesn't fight Sub 3/4/5/6 migrations. +4. **Additive SO line fields** — `x_fc_internal_description`, `x_fc_description_template_id` sit alongside future Sub 5 fields (`x_fc_serial_number`, `x_fc_job_number`, `x_fc_thickness`, `x_fc_revision_snapshot`) with zero touchpoints. +5. **Clean removal of old `description` column** — migrated then dropped. Not kept as deprecated. One clean break now beats two migrations later. + +### Sub 6 Preview — Contact Profiles & Communication Routing (client transcript A/B/C) +- Sub-contacts under `res.partner` with per-contact permissions: certs / QC / quotes+SO / invoices. +- Multiple delivery locations per customer; each location has its own notification list. +- Global contact (company-level + location-level) gets all communications. +- Will restructure or augment the partner-level `x_fc_send_coc` / `x_fc_send_thickness_report` flags that Sub 2 currently falls back to. Sub 2's `_fp_resolve_cert_requirement` is the update point. + +### Sub 7 Preview — IoT Tuning (client transcript D) +- 6–10 active tanks (of ~20–25 total) need continuous monitoring. +- Polling interval: **30 minutes acceptable, 15 minutes ideal.** Configurable per tank. +- Temperature, pH, nickel concentration — all on automated controller (existing `fusion_plating_iot` module). +- Work scope: ensure per-sensor interval field exists + defaults + seed 6–10 tank.sensor records. + +### Sub 8 Preview — Receiving / Inspection / QC Restructure (client transcript E) +**Current flow (wrong):** Direct order → receiving entry → receiver inspects on arrival. +**Correct flow:** +1. Customer ships parts in boxes. Receiver counts boxes (does NOT inspect individual parts). +2. Boxes sit in staging until racking. +3. Racking crew opens boxes, inspects each part as they load racks (inspection ≠ receiving). +4. Parts go through plating process. +5. Post-plate QC on machine (thickness / depth / coating thickness) — existing QC gate (Phase 1–3 work). +6. Pack back into the SAME boxes they arrived in. Same qty out as in. + +**Implication:** The current `fusion_plating_receiving` module conflates receiving + inspection. Sub 8 splits them. Racking-time inspection becomes its own record, linked to WOs not to receiving. + +### Deferred Items (Future) +- **First-off / last-off QC** — first and last part of each batch get full QC inspection; middle parts sampled. Not priority. +- **VEC machine auto-ingest** — different from Fischerscope. Exports a Word doc (picture + data) named `workorder_PO.docx` to a network share. Plan: auto-scan the share, parse, attach to QC as thickness_report. Defer until core flow is solid. + +### Client-Confirmed Operational Thresholds +- Tank polling: 15–30 min, half-hour acceptable +- Active tanks: 6–10 (not all 20–25) +- Boxes round-trip: parts ship back in the same boxes they arrived in, same quantity per box + +### How to Resume This Work in a Fresh Session +1. Read this section (Fine-Tuning Initiative). +2. Check the sub-project status table — which sub is in flight. +3. Read the corresponding spec in `docs/superpowers/specs/YYYY-MM-DD-sub-*-design.md`. +4. Read the implementation plan if one exists. +5. Continue from the next un-checked step.