from pathlib import Path
import csv,json,shutil,hashlib,math
from reportlab.pdfgen import canvas
from reportlab.lib.colors import HexColor,white
from reportlab.lib.utils import ImageReader
from reportlab.platypus import Paragraph,Table,TableStyle
from reportlab.lib.styles import ParagraphStyle
ROOT=Path(__file__).resolve().parents[1]
BASE=ROOT/'inputs/final27'
DOC=ROOT/'documents';DOC.mkdir(exist_ok=True)
sha=lambda p:hashlib.sha256(p.read_bytes()).hexdigest()
def writecsv(name,headers,rows):
 with (DOC/name).open('w',newline='') as f:
  w=csv.writer(f);w.writerow(headers);w.writerows(rows)
old=list(csv.DictReader((BASE/'docs/Concept_27_R2_Material_Process_BOM.csv').open()))
geometry=json.loads((ROOT/'audit/independent_geometry_review.json').read_text())
native=json.loads((ROOT/'audit/native_preservation_review.json').read_text())
assert not native['unchanged_assembly_occurrences']['mismatches']
assert all(abs(x['volume_mm3'])<1e-6 for x in native['front_shell_below_z_minus_2_21_mm']['directional_differences'])
assert not geometry['validity_failures']
bounds=geometry['assemblies']['CASE']['bbox_mm'];overall=[round(bounds[i+1]-bounds[i],4) for i in (0,2,4)]
overall_text=' x '.join(f'{v:g}' for v in overall)+' mm'
parts=sorted(p.stem for p in (ROOT/'cad/parts').glob('*.step')if '_HW_' not in p.stem)
replace={1:'Chalk cast rigid urethane; RPS selects tough ABS-like grade',3:'PA12 internal carrier; SLS/MJF target',4:'Optical PMMA; machined/polished, frosted visible face',10:'304 stainless steel; fine circular brush, deburred edge',11:'Qualified adhesive film, 0.10 mm installed',16:'Orange elastomeric urethane; Shore A 80-85 evaluation target'}
rows=[]
for name in parts:
 oldname=name
 n=int(name.split('_')[2])if name.split('_')[2].isdigit()else 0
 prior=next((r for r in old if r['part_id']==name or (name.startswith('C28') and n in replace and r['part_id'].startswith(f'C27_R2_{n:02d}_'))),None)
 if prior:
  material=replace.get(n,prior['material']+'; '+prior['process']) if name.startswith('C28') else prior['material']+'; '+prior['process']
  if n==2:material='Chalk cast rigid urethane; RPS selects tough ABS-like grade'
  if n==9:material='Cast elastomeric urethane; Shore A 80-85 evaluation target; matte warm grey'
  if n in [12,14]:material='6061 aluminium cap; fine brush and clear protective finish, natural silver'
  role=prior['function'] if not name.startswith('C28') else {1:'Revised face only; original internal support geometry and screw bores retained',3:'Round upper face, unchanged lower retention tabs and switch contact',4:'Circular visible optic lowered 3 mm; original lower collector and internal coupler',10:'27 mm circular play cap with shallow laser outline',11:'Round cap-to-carrier adhesive',16:'Smooth capsule outer grip; original concealed engagement retained'}[n]
  mount='Visible center (0,2); original collector and coupler center (0,5), mm' if n==4 else prior['attachment']
  if n==2:
   role='Final R2 battery/PCB/LTE retention and USB support; local casting boss-release tapers'
   mount='Final R2 hardware axes; LTE boss tips Z=-20.33 mm'
 else:
  spec={57:('304 stainless steel; machined bezel for prototype','48 x 50 mm outer frame; 44 x 46 mm visible opening','Bond to shallow front-shell pocket'),58:('Qualified adhesive film; 0.20 mm installed','Die-cut perimeter bond; resin/metal adhesion to qualify','Shell pocket floor z=-0.30 to bezel rear z=-0.10'),59:('Qualified adhesive; 0.09 mm installed allowance','Bond mesh cut edge behind front bezel lip','z=0.26 to 0.35'),60:('Black acoustic nonwoven; 0.10 mm design allowance','44.8 x 46.8 mm acoustic scrim; permeability and shedding to qualify','z=-0.25 to -0.15; perimeter retained'),61:('304 stainless woven mesh; graphite finish','45 x 47 mm blank R10; 1.0 mm pitch, 0.18 mm wire, 0.36 mm nominal thickness','Purchased weave, 92 CAD rods are reference geometry only'),62:('Qualified adhesive film; 0.05 mm installed','Scrim perimeter retention','z=-0.30 to -0.25')}
  material,role,mount=spec[n]
 rows.append([name,1,material,role,mount,'Updated/new 28'if name.startswith('C28')else('Final 27 R2 with native casting boss tapers' if n==2 else 'Preserved final 27 R2 geometry')])
writecsv('Parts_Schedule_BOM.csv',['Part','Qty','Material and process target','Role','Mount / datum','Provenance'],rows)
colours=[['Shells','E3E0D6','9081 C','Pastels & Neons Coated','Fine matte chalk urethane; inherited proposed reference'],['Soft rim','7D786E','Warm Gray 9 C','Solid Coated','Fine matte warm grey elastomer; inherited proposed reference'],['PTT grip','CC4118','173 C','Solid Coated','Smooth ember-orange elastomer; inherited proposed reference'],['Play cap / bezel','Natural silver','Not applicable','Metal finish sample','304 stainless; fine brush on play cap, satin bezel'],['Volume caps','Natural silver','Not applicable','Metal finish sample','6061 aluminium; fine brush and clear protective finish'],['Woven grille','Graphite','Not assigned','Supplier finish sample','Dark graphite finish; qualify coating on cut woven stainless'],['Status lens','Diffusing clear / milky','Not applicable','Optical sample','Warm LED illumination is not a pigment specification']]
writecsv('Colours_and_Finishes.csv',['Component','Display reference','Proposed Pantone','Reference library','Finish target'],colours)
opens=[['Before mating approval','Elian + RPS','Conservative USB gauge overlaps receiver reference by about 2.484 mm3 at assumed full seating. Obtain actual plug CAD and insertion datum; verify physically before release.'],['Before prototype','RPS + Elian','Select resin grades, hardness, shrink compensation, mold splits, gates/vents and surface master finish.'],['Before prototype','RPS','Review inherited thin retention walls (rear divider about 0.8 mm; microphone cradle about 0.75 mm) and 0.8 mm front material above lower speaker pilot ends after the grille rebate.'],['Before prototype','RPS + Elian','Confirm bezel manufacture and bond stack, mesh wire/pitch availability, edge containment, scrim permeability and adhesion without bleed into the sound path.'],['Before assembly','Elian','Approve the retained nominal lens-flange interference (about 0.592 mm3, also present in 27); measure fit in selected optical and shell materials.'],['First article','Elian + RPS','Measure control clearances, return/travel, cap alignment, adhesion, fastener torque and repeated-service durability with actual switches.'],['First article','Elian','Qualify audio response/rattle, offset light-output brightness/uniformity and color, microphone response, RF, harness routing, USB access and drop durability.'],['Before color release','Jacob + RPS','Approve physical Pantone chips and finished material coupons; screen renders and proposed Pantone matches do not establish an exact match.']]
writecsv('Open_Items.csv',['Stage','Owner','Open qualification'],opens)
# Schedules come from the reviewed final trace, with fresh 28 access results.
fast=json.loads((ROOT/'audit/Concept_28_R1_fastener_access.json').read_text())
writecsv('Fastener_Schedule.csv',['Fastener','Standard','Size','Length mm','XY mm','Axial engagement mm','Blind-floor clearance mm','Access stage','Tool diameter mm','Fresh tool hits'],[[r['fastener'],r['standard'],r['size'],r['length_mm'],r['axis_xy'],r['nominal_axial_thread_engagement_mm'],r['tip_to_blind_floor_mm'],r['access_stage'],r['tool_shaft_diameter_mm'],json.dumps(r['tool_hits'])] for r in fast])
shutil.copy2(BASE/'docs/Concept_27_R2_Compliant_Pad_Schedule.csv',DOC/'Soft_Stock_Schedule.csv')
writecsv('Hardware_Reference_BOM.csv',['Part','Qty','Material','Role','Reference only'],[[r['part_id'],r['quantity'],r['material'],r['function'],'OEM geometry unchanged; use actual supplier hardware'] for r in old if r['group']=='bought-in core hardware reference'])
bosses=json.loads((ROOT/'audit/final27_casting_adaptation.json').read_text())['bossTapers']
writecsv('Boss_Release_Features.csv',['Part','XY mm','Z range mm','Draft degrees','Root land mm','Removed mm3','Tip radius mm','Tip end'],[[r[k] for k in ['part','centerXY','zRange','draftDegrees','rootLandMm','removedMm3','tipRadiusMm','tipEnd']]for r in bosses])
notes='''# Concept 28 R1 - Chalk Ember / Fusion handoff

Status: supplier-review prototype. Not released tooling or a production sign-off.

## File authority
Open `cad/Walkie_One_28_R1_Chalk_Ember.f3d` in Autodesk Fusion. This file was edited in Fusion from the completed final Concept 27 R2 STEP assembly, with the UC1 local casting-release approach adapted to its revised boss geometry. Imported baseline bodies do not acquire a reconstructed historical sketch timeline. New native fillet/engraving features and cut-outline sketches are included. No Adam MCP generation was used for 28.

`REFERENCE_ASSEMBLY.step` includes the unchanged OEM electronics. `CASE.step` contains manufactured/custom stock parts plus 18 fasteners. Individual STEP/STL exports are normalized to assembly coordinates in Fusion. The 92 rods in part 61 are one purchased mesh component, not 92 fabrication jobs. The DXF cut outlines and stock specification govern that purchase. F3D and assembly STEP retain the source occurrence organization.

The rigid body remains 78 x 150 x 24 mm. Overall nominal bounds remain OVERALL_DYNAMIC including rim and controls. Front z=0; X across, Y up. Play center (0,-47), visible light (0,2), original collector/LED optical datum (0,5), microphone (0,-14), speaker (0,42), all in mm.

## Changes from the final 27 R2 functional baseline
A separate graphite mesh, stainless bezel, black scrim and adhesive stack replace the molded hole pattern. The acoustic opening is 35 mm diameter, inside the final two-ring gasket stack's 38.0 mm inner diameter. The speaker and gasket do not move. The visible grille is larger than the underlying speaker. Bezel is 48 x 50 mm with R11.5 corners; visible opening 44 x 46 mm R9.5. The skin rebate is 48.4 x 50.4 mm, 0.30 mm deep. Original speaker pilot bores are retained.

The 27 mm solid brushed-metal play cap sits over the revised round upper carrier. Original lower retention wings, actuation contact and clamp remain. The shell bore is 27.9 mm; the upper carrier is 27.3 mm. The cap is 1.10 mm thick plus a 0.10 mm bond film. Its 0.04 mm laser outline is cosmetic.

The light has a 4.7 mm circular visible optic and 4.9 mm shell aperture, moved 3 mm down to (0,2). The original rear collector and internal LED/coupler stay at their original positions. The single-piece optic has an offset output; qualify brightness and uniformity physically. A 0.592 mm3 nominal interference at the collector flange is inherited from 27 and remains subject to fit qualification. The PTT uses a smooth capsule skin and 0.6 mm exposed edge radius; concealed carrier engagement is unchanged.

## Casting route
Cast front and back shells in tough rigid urethane; cast the rim and PTT separately in elastomeric urethane. Shore A 80-85 is an evaluation target. RPS selects grades, compensation and release construction. The four files in `cad/casting_masters` are nominal master-pattern candidates, not mold halves. No shrink scale or finish stock is applied. The front now has a single 35 mm acoustic opening. The old 121-hole blank-master/drilling schedule is obsolete for 28 and is intentionally not included.

The UC1 local 1-degree release approach is applied to 16 actual final R2 bosses. Speaker mounts use Y=18 and 66 mm; LTE boss tips use Z=-20.33 mm. A 0.10 mm root land is retained. This is not a globally drafted injection-molding design. Review thin features, pilot durability and all undercuts in the selected silicone-tool strategy. Metal caps/bezel, mesh, optics, PA12 internal carriers, stock pads and adhesives use separate processes; do not cast every STL.

The 0.30 mm grille rebate leaves nominally 1.90 mm of the original 2.20 mm face skin outside the acoustic opening, and 0.80 mm above the lower speaker pilot ends. Supplier review is required before committing to tooling. Do not add unselected threaded inserts to the inherited bosses.

## Assembly
1. Inspect and finish the cast shells. Check pilot bores, closure interfaces, openings and rim fit before bonding parts.
2. Bond black scrim at the perimeter, with its separate 0.05 mm film. Keep the 35 mm acoustic opening clear of adhesive.
3. Bond the cut woven mesh into the bezel rebate using the 0.09 mm edge bond allowance. Fully contain sharp cut edges. Bond the bezel into the shell using the 0.20 mm perimeter film.
4. Install the circular lens with its visible center at (0,2), 3 mm below the former center, using the inherited collector seat. Retain the original internal right-angle optical coupler and LED mount. Verify brightness and uniformity across the offset output before permanent bonding.
5. Bond the circular metal cap to its carrier. Install the inherited clamp, then check free return and travel. Install smooth PTT grip and unchanged volume carriers/caps.
6. Use the final 27 R2 electronics, pads, keepers and countersunk fasteners in their reviewed locations. The two LTE service frames lift separately. Fit four hidden rim pads to the front shell only and attach the flexible rim after rigid closure; no pad bridges the service seam. Check harness, USB, RF and acoustic performance with actual hardware.

## Verification and limitations
Fusion measured zero material difference in the front shell below z=-2.21 mm relative to the final R2 casting-adapted baseline. All 436 unchanged assembly-occurrence bodies retain their native face counts, volumes, world bounds and transforms versus final R2. Independent STEP validity, full static fit, 60 directional retention checks, four sampled control sweeps, cover insertion and fastener/service access evidence are supplied. These are nominal geometry checks, not force or overtravel certification. See Trace_Reconciliation.md for the fresh results and remaining holds.

Cross-kernel coincident-shell subtraction in OpenCascade was numerically unstable on the inherited toroidal shell surfaces, including the unmodified back shell. Native Fusion differences establish preservation; independent non-coincident overlap checks establish the changed interfaces. The only detected changed-part overlap is the unchanged lens-flange interference. Acoustics, mesh resonance, coating adhesion, drop strength, sealing, resin behavior, optics and RF remain unqualified.

The drawings are nominal prototype dimensions, not approved production tolerances. Suggested acceptance values require supplier agreement. No water-ingress rating is claimed.

RPS describes silicone-tool urethane casting, rigid/rubber-like materials, pigmentation and secondary finishes: https://www.rapid-products.com/service/urethane-castings/ (reviewed 2026-09-10). This is process context, not supplier acceptance of this design.
'''
notes=notes.replace('OVERALL_DYNAMIC',overall_text)
(DOC/'Casting_Shop_Notes.md').write_text(notes)
(DOC/'Assembly_Sequence.md').write_text(notes[notes.index('## Assembly'):notes.index('## Verification')])
writecsv('First_Article_Inspection.csv',['Item','Nominal / requirement','Acceptance responsibility'],[['Rigid shell envelope','78 x 150 x 24 mm','RPS dimensional report; agree tolerance'],['Overall assembled envelope',overall_text,'RPS + Elian'],['Play/carrier radial clearances','0.45 mm cap; 0.30 mm upper carrier','Measure finished parts incl. coating/shrink'],['Light center / clearance','Visible center (0,2), lowered 3 mm; 0.10 mm radial clearance','Verify flange fit and offset output uniformity'],['Grille bezel edge gap','0.20 mm nominal each side','RPS'],['Speaker bore / gasket','35.0 mm opening, 38.0 mm gasket ID','Confirm uninterrupted acoustic seal'],['Control travel','Four 0.05 mm sampled sweeps; front 0.70 mm, side 0.65 mm','Actual switch overtravel/force not certified'],['Mesh assembly','No exposed cut wire, lifting, adhesive bleed or rattle','Visual, pull/peel and acoustic tests'],['Color/finish','Approve physical coupons, then lot sample','Jacob + RPS']])
# Nominal casting patterns are identical to the finished part for this revision.
for directory in ['cad/casting_masters','meshes/casting_masters']:(ROOT/directory).mkdir(exist_ok=True)
for num in [1,2,9,16]:
 name=next(n for n in parts if n.startswith(f'C28_R1_{num:02d}_')or n.startswith(f'C27_R2_{num:02d}_'))
 for sub,ext in [('cad','step'),('meshes','stl')]:shutil.copy2(ROOT/sub/'parts'/f'{name}.{ext}',ROOT/sub/'casting_masters'/f'C28_R1_MASTER_{num:02d}_{name.split("_",3)[-1]}.{ext}')
# PDF layout helpers: explicit page breaks keep manufacturing tables legible.
PDF=DOC/'Walkie_One_28_R1_Fusion_Handoff.pdf';W,H=595.28,841.89
notes=notes.replace('OVERALL_DYNAMIC',overall_text)
c=canvas.Canvas(str(PDF),pagesize=(W,H));c.setTitle('Walkie One 28 R1 - Chalk Ember / Fusion handoff')
body=ParagraphStyle('body',fontName='Helvetica',fontSize=9,leading=13,textColor=HexColor('#30352f'))
small=ParagraphStyle('small',parent=body,fontSize=8,leading=11)
page=0
def start(title,kicker='CHALK EMBER / CONCEPT 28 R1'):
 global page
 page+=1;c.setFillColor(HexColor('#F4F3ED'));c.rect(0,0,W,H,fill=1,stroke=0)
 c.setFillColor(HexColor('#707668'));c.setFont('Helvetica',9);c.drawString(38,H-37,kicker)
 c.setFillColor(HexColor('#273126'));c.setFont('Helvetica-Bold',24);c.drawString(38,H-75,title)
 c.setStrokeColor(HexColor('#C9CCBF'));c.line(38,43,W-38,43);c.setFont('Helvetica',8);c.drawString(38,28,'SUPPLIER REVIEW / NOMINAL MM / 2026-09-10');c.drawRightString(W-38,28,f'{page} / 7')
def para(text,x,y,w=W-76,style=body):
 p=Paragraph(text,style);_,h=p.wrap(w,1000);p.drawOn(c,x,y-h);return y-h-12
def table(headers,rows,y,widths):
 data=[[Paragraph(str(t),small)for t in r]for r in [headers]+rows]
 t=Table(data,colWidths=widths,repeatRows=1,hAlign='LEFT')
 t.setStyle(TableStyle([('BACKGROUND',(0,0),(-1,0),HexColor('#DCE0D4')),('VALIGN',(0,0),(-1,-1),'TOP'),('LINEBELOW',(0,0),(-1,-1),.35,HexColor('#CED1C7')),('LEFTPADDING',(0,0),(-1,-1),7),('RIGHTPADDING',(0,0),(-1,-1),7),('TOPPADDING',(0,0),(-1,-1),6),('BOTTOMPADDING',(0,0),(-1,-1),6)]))
 _,h=t.wrap(W-76,1000);t.drawOn(c,38,y-h);return y-h-14
def pic(path,x,y,w,h):c.drawImage(str(path),x,y,w,h,preserveAspectRatio=True,anchor='c',mask='auto')
start('A familiar build. A new face.')
para('Edited directly in Autodesk Fusion from the completed final Concept 27 R2, with local casting-release tapers. The approved Chalk Ember direction adds a separate graphite grille, round light and brushed circular play button, with a smooth orange talk grip.',38,H-98)
pic(ROOT/'renders/studio/front-left.png',115,258,365,430)
y=248;y=table(['Kept from 27','Changed for 28'],[['78 x 150 x 24 mm rigid body; existing internals','Mesh / bezel / scrim assembly; circular light and play face'],['Soft rim, microphone, volume controls and hardware positions','Smooth PTT surface; revised front seats and upper play carrier']],y,[259,260])
para('<b>Build status:</b> supplier-review prototype. Fusion source, STEP/STL, cut outlines, nominal casting masters and verification are supplied. Physical first-article qualification remains open.',38,y)
c.showPage()
start('Dimensions and interfaces')
y=H-104
y=table(['Feature','Nominal dimensions / datum'],[['Rigid body / overall','78 x 150 x 24 / '+overall_text],['Coordinate system','X width; Y up; front face Z=0; rear Z=-24'],['Control centers','Speaker (0,42); mic (0,-14); play (0,-47); visible light (0,2)'],['Grille / pocket','Bezel 48 x 50 R11.5; pocket 48.4 x 50.4 R11.7, depth 0.30'],['Visible mesh / cut blank','Opening 44 x 46 R9.5; blank 45 x 47 R10'],['Acoustic path','35.0 mm shell opening within inherited gasket ID 38.0 mm'],['Round controls','Play cap dia.27.0; carrier dia.27.3; shell bore dia.27.9'],['Light','Optic dia.4.7; bore dia.4.9; lowered 3 mm; original collector retained'],['PTT','Original installed envelope and concealed engagement; R0.6 exposed edge']],y,[132,387])
y=para('The front-shell interior below Z=-2.21 mm has zero difference in Fusion. The new 0.30 mm grille rebate preserves the final R2 mounting features; speaker pilots are restored at X +/-9.1, Y 18 and 66 mm.',38,y)
y=para('Clearance values are nominal CAD values before resin shrink and finishing. Agree dimensional tolerances with RPS before tooling. The light collector retains the pre-existing nominal interference and needs a measured fit trial.',38,y)
c.showPage()
start('Grille stack and metal controls')
y=H-104
y=table(['Part','Installed Z / build instruction'],[['Front skin rebate','Floor -0.30 mm. 1.90 mm skin remains outside opening. About 0.80 mm remains above lower speaker pilot ends.'],['Scrim film / scrim','0.05 mm perimeter film (-0.30 to -0.25); 0.10 mm black acoustic scrim (-0.25 to -0.15).'],['Mesh','0.36 mm envelope (-0.10 to +0.26). Nominal 0.18 mm wire / 1.0 mm pitch; about 67% projected open area before finish.'],['Mesh edge bond','0.09 mm allowance (+0.26 to +0.35), captured under bezel lip; qualify bond method.'],['Bezel / perimeter bond','304 bezel -0.10 to +0.55; 0.20 mm shell-to-bezel film (-0.30 to -0.10).'],['Play cap','304 stainless, dia.27.0 x 1.10 mm; fine circular brush; 0.04 mm laser-outline play mark. 0.10 mm carrier bond film.']],y,[132,387])
y=para('<b>Mesh procurement:</b> the CAD uses 92 crossing rods to depict one purchased woven panel. This is an envelope approximation, not literal weave tooling. DXF defines the blank. Supplier confirms available weave, formed thickness, cut-edge capture, graphite finish and acoustic loss.',38,y)
y=para('The larger rectangular grille is cosmetic around the unchanged speaker. It does not enlarge the speaker, move it, or claim improved audio. Prototype the entire mesh/scrim/bond stack and test response, rattle and adhesion.',38,y)
c.showPage()
start('Materials and colour targets')
y=H-104
y=table(['Component','Material / finish','Colour reference'],[['Shells','Tough ABS-like cast urethane; fine matte','Pantone 9081 C* / E3E0D6'],['Rim','Elastomeric urethane; matte','Warm Gray 9 C* / 7D786E'],['PTT','Elastomeric urethane; smooth; Shore A 80-85 evaluation','173 C* / CC4118'],['Play / bezel','304 stainless; brushed play face / satin bezel','Natural metal sample'],['Volume faces','6061 aluminium; fine brush / clear protection','Natural silver sample'],['Speaker mesh','Stainless woven stock; graphite finish','Supplier coating sample'],['Optics / internals','PMMA circular lens; inherited coupler, PA12 supports, pads and OEM hardware','See complete BOM']],y,[97,257,165])
y=para('*Inherited <b>proposed</b> Pantone references from Concept 27. Shell uses the Pastels &amp; Neons Coated library; rim/PTT use Solid Coated. These are not verified exact matches in urethane. Approve physical chips and finished coupons before production. Natural metallic finishes are specified by material and sample, not a simulated Pantone swatch.',38,y)
y=para('RPS must select resin grades, shrink allowance, cure and tooling. Do not substitute injection-molded PC-ABS for the specified casting route without a separate review. The metal grille and cap also require acoustic, RF, durability and adhesive evaluation.',38,y)
c.showPage()
start('Casting and assembly')
y=H-104
steps=[('1 / Make and inspect patterns','Four nominal casting masters: front shell, rear shell, rim and smooth PTT. No mold halves, gates, vents, shrink scaling or finish stock are modeled. RPS approves these choices.'),('2 / Preserve the internal build','Use the final R2 PCB pads, battery locators, split LTE frames, hidden rim pads, lead routes and countersunk fasteners. The UC1 one-degree approach is adapted to the revised bosses. Review the inherited thin walls and screw durability.'),('3 / Assemble the grille','Bond scrim to its perimeter land; bond cut mesh under bezel lip; fully contain cut wire edges. Bond the bezel to its pocket. Keep adhesive out of the acoustic opening.'),('4 / Assemble controls and optics','Fit lowered lens and original coupler; check output uniformity. Bond metal play cap to its round carrier; fit unchanged clamp and check return. Fit smooth PTT and inherited volume interfaces.'),('5 / Fit and test hardware','Use actual electronics and retained stock parts. Fit the hidden grip pads to the front shell only, then attach the rim after closure. Test switches, light, microphone, speaker, USB, RF and drop behavior.')]
for title,txt in steps:y=para('<b>'+title+'</b><br/>'+txt,38,y)
y=para('<b>Obsolete for 28:</b> the 121-hole grille drill schedule and blank drilled front master from 27. The 28 front has a single acoustic opening with a separate purchased grille assembly.',38,y)
y=para('RPS confirms silicone-tool urethane casting and rigid/rubber-like materials on its service page. This package requests supplier review; it does not represent RPS acceptance.<br/><link href="https://www.rapid-products.com/service/urethane-castings/">rapid-products.com/service/urethane-castings</link>',38,y)
c.showPage()
start('Verification and first article')
y=H-104
checks=[['Geometry preservation','436 unchanged assembly bodies retain native faces, volume, world bounds and placement versus final R2. The front interior below Z=-2.21 is preserved versus the casting-adapted baseline.'],['Export checks','91 individual STEP files (73 custom/material parts plus 18 fasteners), valid solids. Case: 182 solids. Full reference: 540 solids, including 356 OEM solids and 2 lead-route references.'],['Envelope / controls','Rigid body remains 78 x 150 x 24 mm. Four controls are sampled at 0.05 mm increments: front to 0.70 mm and sides to 0.65 mm. Actual force and permissible overtravel remain unqualified.'],['Interference','No new detected changed-part/OEM hardware overlap. The 0.592 mm3 lens-flange overlap is unchanged from 27 and remains an open fit qualification.'],['Independent check limit','OpenCascade coincident-shell subtraction was unstable on inherited trimmed toroidal surfaces. Native Fusion differences establish preservation; independent STEP checks cover validity and targeted interfaces.']]
y=table(['Check','Evidence / limit'],checks,y,[111,408])
y=para('<b>Before a run:</b> RPS and Elian must agree resin/tooling, thin-wall release, critical tolerances, adhesion, mesh stock, lens fit, screw torque and first-article acceptance. Jacob approves physical colour and finish samples. Test actual acoustics, optics, RF, harness, USB, control return and durability.',38,y)
y=para('Open the native Fusion file to edit. Use the full STEP for fit review and individual files/DXFs with the BOM for fabrication planning. Read Open_Items.csv and First_Article_Inspection.csv before ordering. No sealing, drop or production-quality certification is claimed.',38,y)
c.showPage()
start('Final trace carried into 28')
y=H-104
y=table(['Functional area','Final design incorporated'],[['PCB / battery','Four paired PCB supports on bare FR4; extended battery rails/liners and a central lead-service gate.'],['Speaker / optics','38 mm-ID split gasket stack; original speaker and collector retained. New front scrim, mesh and lowered round light need physical acoustic/optical trials.'],['Antenna / rim','Separate upper/lower LTE service frames, four soft edge stops, and four hidden front-shell rim grip pads.'],['Hardware / service','Countersunk closure and internal fasteners, actual side-switch plungers, full-length lead-route references and reviewed USB reaction support.']],y,[111,408])
y=para('<b>Fresh verification:</b> read Trace_Reconciliation.md and the audit JSON files for geometry results on this exact 28 export. Prior PASS labels are not release approval. All source inputs are checksum listed.',38,y)
y=para('<b>USB mating hold:</b> the supplied conservative plug gauge clears the case approach, but has approximately 2.484 mm3 overlap with the actual receiver reference at assumed full seating. Obtain the real mating plug and confirmed insertion datum; qualify on actual hardware. The PCB was not cut or altered to conceal this hold.',38,y)
y=para('<b>Physical qualification:</b> resin shrink/release, threaded pilot durability, soft-pad compression forces, switch return/overtravel, mesh adhesion and rattle, optics, RF, lead routing, sealing and drop endurance remain open. This is a supplier-review prototype package.',38,y)
c.showPage();c.save()
(ROOT/'audit/handoff_build.json').write_text(json.dumps({'pdf':str(PDF.name),'pages':7,'parts':len(rows),'source':'Autodesk Fusion exports','fabricationRelease':False},indent=2))
print(PDF)
