feat(plating): per-step compliance gates + backfill — 0 CRITICAL gaps

Per-step audit caught real enforcement bugs across all 9 WO kinds in
the recipe (Masking, Racking, Plating, De-Masking, Oven baking, etc.).
Five gates added or fixed; 0 CRITICAL gaps remain after a verification
run on a fresh MO.

**1. Bake-WO finish gate** (`_fp_check_required_fields_before_finish`)
button_finish on a bake WO now blocks unless:
  • x_fc_bake_temp set (Nadcap req — actual setpoint, not just oven)
  • x_fc_bake_duration_hours set (actual run time at temp)
  • x_fc_oven_id.chart_recorder_ref set (so the chart for THIS run
    can be retrieved by an auditor — required for AS9100/Nadcap)

Run-time data lives at FINISH, not START — operators don't know
temp/duration until the bake is done.

**2. Rack-WO start gate** added to the existing button_start gate.
Per-rack life tracking + which physical fixture handled the parts.

**3. Classifier priority fix** (`_fp_classify_kind`)
"Post-plate Inspection" was matching the `plat` wet keyword and
getting kind=wet (then required to have bath/tank). Reordered:
  1. Explicit equipment links (bath_id/oven_id)
  2. Specific keywords (inspect → mask → bake → rack)
     — bake before rack so "Oven bake (Post de-rack)" → bake
  3. Workcenter wet families
  4. Wet name keywords as last fallback

**4. Auto-populate target_thickness + dwell_time** at recipe→WO
generation. Plating WOs inherit:
  • thickness_target from coating_config.thickness_max
  • thickness_uom from coating_config.thickness_uom
  • dwell_time_minutes from recipe node's estimated_duration

So aerospace QC has the spec target on every WO without paper.

**5. Mask-WO start gate + masking_material field**
New x_fc_masking_material Selection (tape/plug/paint/silicone/wax/
mixed/other). Required to start a mask WO. Needed later when
stripping or replating because each material requires a different
removal process.

**View** (`mrp_workorder_views.xml`)
Process Details tab now branches by kind:
  wet  → Bath/Tank/Rack/Thickness/Dwell
  bake → Oven/Temp/Duration
  rack → Rack/Fixture
  mask → Masking Material
  inspect/other → informational alerts only
WO Kind shows as colour-coded badge in header.

**Backfill** (`scripts/fp_backfill.py`)
Idempotent script that catches up existing data:
  • chart_recorder_ref on every oven
  • rack_id on existing rack/de-rack WOs (91 backfilled)
  • bake_temp + bake_duration_hours on existing bake WOs (33)
  • masking_material on existing mask WOs (62)
  • thickness/dwell on existing plating WOs (38)
  • Cleared 7 legacy bath/tank from inspection WOs that had been
    misclassified by the OLD wet-keyword classifier.

**Per-step audit** (`scripts/fp_per_step_audit.py`)
Walks every WO of the most recent done MO and reports per-kind
which compliance fields are filled vs missing. Re-runnable to
catch regressions.

**Final state on freshly-run MO 00049:**
  • 0 CRITICAL gaps
  • 2 IMPORTANT gaps (dwell_time + rack_id on E-Nickel Plating —
    both inherited from recipe node data, not enforcement bugs)

Negative tests still passing (12 total).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
gsinghpal
2026-04-19 11:40:01 -04:00
parent 5020129c45
commit 4ffbdc596d
7 changed files with 607 additions and 27 deletions

View File

@@ -96,7 +96,12 @@
required="1"
options="{'no_create': True}"/>
<field name="x_fc_work_role_id" readonly="1"/>
<field name="x_fc_wo_kind" widget="badge" readonly="1"
decoration-info="x_fc_wo_kind == 'wet'"
decoration-warning="x_fc_wo_kind == 'bake'"
decoration-muted="x_fc_wo_kind in ('mask', 'rack', 'inspect', 'other')"/>
<field name="x_fc_requires_bath" invisible="1"/>
<field name="x_fc_requires_oven" invisible="1"/>
</xpath>
<!-- ============================================================
@@ -162,12 +167,18 @@
</group>
</xpath>
<!-- 5b. Plating Details tab (insert AFTER Time & Cost) -->
<!-- 5b. Process Details tab — content adapts to WO kind so
operators see only the equipment fields that matter. -->
<xpath expr="//notebook/page[@name='time_tracking']" position="after">
<page string="Plating Details" name="plating_details">
<page string="Process Details" name="plating_details">
<group>
<group string="Bath &amp; Tank">
<group string="Where">
<field name="x_fc_facility_id"/>
</group>
</group>
<!-- Wet / bath WOs -->
<group invisible="x_fc_wo_kind != 'wet'">
<group string="Bath &amp; Tank">
<field name="x_fc_bath_id"
required="x_fc_requires_bath"/>
<field name="x_fc_tank_id"
@@ -181,6 +192,44 @@
<field name="x_fc_dwell_time_minutes"/>
</group>
</group>
<!-- Bake / cure WOs -->
<group invisible="x_fc_wo_kind != 'bake'">
<group string="Oven">
<field name="x_fc_oven_id"
required="x_fc_requires_oven"/>
</group>
<group string="Bake Parameters (required at finish)">
<field name="x_fc_bake_temp"/>
<field name="x_fc_bake_duration_hours"/>
</group>
</group>
<!-- Rack / de-rack WOs -->
<group invisible="x_fc_wo_kind != 'rack'">
<group string="Rack">
<field name="x_fc_rack_id" required="1"/>
<field name="x_fc_rack_ref"/>
</group>
</group>
<!-- Mask / De-mask WOs -->
<group invisible="x_fc_wo_kind != 'mask'">
<group string="Masking">
<field name="x_fc_masking_material" required="1"/>
</group>
</group>
<!-- Inspection -->
<group invisible="x_fc_wo_kind != 'inspect'">
<div class="alert alert-info" role="alert">
Inspection — record Fischerscope readings via
the Tablet Station. Cal-std + n measurements
per part. Readings auto-link to the CoC.
</div>
</group>
<group invisible="x_fc_wo_kind != 'other'">
<div class="alert alert-light text-muted" role="alert">
Generic operation — equipment is identified
by the work centre.
</div>
</group>
</page>
</xpath>