Persona 03 — Tier 4 Fibre Producer
Confidence markers and citation shorthand per README.md.
Who they are
The company at the physical start of the traced chain: a cotton gin (demo: Sundown Gin, Australia) or a recycled-polyester plant (demo: ACME rPET). They apply the FibreTrace pigment to raw fibre and create the production volume every downstream claim is ultimately metered against. FibreTrace deliberately enters the chain at the gin, not the farm. STATED (BL:2026-07-08-malcolm-walkthrough-demo.md:32-33).
A good day: the SDU line runs without faults, bale records flow in (SDU feed, EWR eCotton import, or manual entry), scan counts accrue, and the programme’s Activated volume climbs toward — never over — their ceiling.
What makes them this persona
A company is a Fibre Producer if and only if it has at least one programme_producers registration. VERIFIED (L:src/hooks/usePersonaContext.ts:36). The QC script canonises this: “A company is a Fibre Producer only if registered as a producer on a programme. An SDU or EWR assignment alone is a feature gate, not a persona.” STATED (QC:8). The older hook usePersona also counted an enabled sdu company module as producer — the QC rule effectively declares that clause retired; the newer hook already matches the rule. VERIFIED (L:src/hooks/usePersona.ts:34 vs usePersonaContext.ts:36). Caveat the QC expectation overreaches the current code in one spot: the “SDU Device Status” nav item is gated on the company having SDU device rows, not on producer registration, so an SDU-only company today still sees that one item — QC P-01’s expected result (“does NOT see Production or SDU Device Status”) would fail as written. VERIFIED (AppSidebar: hasSduDevices from sliver_delivery_units count gates the SDU item; fibreCreationEnabled from programme-producer rows gates Fibre Creation — agent-verified at origin/main, AppSidebar.tsx:114-137).
Their registration carries the programme economics
Each programme_producers row holds: ceiling_mt (their production cap), scans_per_mt (how many scans one tonne should produce), pigment_supplied_kg, scans_completed, produced_mt, and a production window (start/end). VERIFIED (SQL: programme_producers). Derived: total scan volume = ceil(ceiling_mt x scans_per_mt). VERIFIED (calc_scan_volume_total trigger, SQL 20260420114208:81-88). Their facilities are attached via programme_producer_facilities, with a DB trigger forbidding one facility from serving two active programmes with the same pigment in overlapping dates. VERIFIED (check_facility_pigment_uniqueness, SQL 20260420114208:96-133).
How their work raises Activated
When a scan session lands at one of their programme facilities inside the programme window, the auto_associate_session_to_programme trigger records it in programme_facility_scans (one programme association per session, UNIQUE session_id) and recomputes produced_mt = LEAST(ceiling_mt, scans_completed / scans_per_mt) — production is capped at the ceiling. VERIFIED (SQL 20260420114208:140-183). Separately, production_records (weight_kg) drive the programme-level Activated aggregate in the UI. VERIFIED (L:src/hooks/useProgrammes.ts producedByProgramme). Manual production records require roughly one scan per 5 percent of quantity (scans_required = GREATEST(1, CEIL(quantity * 0.05))), while SDU/EWR-sourced records need only 1. VERIFIED (generate_production_short_code trigger, SQL 20260414200926:8-46). Production record short codes are the company code plus a 6-digit sequence. VERIFIED (same).
Every screen they touch
| Route | What they see / do |
|---|---|
| / (HomeProducer) | Producer dashboard: production/volume KPIs, next-actions inbox; empty state = “You’re all caught up” card. VERIFIED (L:src/pages/HomeProducer.tsx:354-364) |
| /fibre-creation | The production ledger: order pigment (pigment_orders), log manual production (date, facility, weight, programme), EWR eCotton demo import, SDU-fed records; rows lock ~30 days after creation (client-derived). VERIFIED (L:src/pages/FibreCreation.tsx:441; memory reference_fibre_production_sundown; DemoEWRModal) |
| /sdu | SDU Device Status: per-device status from the sdu_status enum (feeding, ended, idle, starting, paused, blocked, fault), facility, telemetry (bale counters, dose g/kg, sliver remaining, speed bph), activity logs, CSV import/export, API-key CTA. VERIFIED (SQL 20260409114812:3; L:src/pages/SDU.tsx). QC P-02 names only four states (feeding, idle, paused, fault) — the enum has seven. STATED vs VERIFIED divergence (QC:130) |
| /claim-position and programme pages | Producers see their programmes’ capacity funnels (the matrix records /programs -> /claim-position redirects). VERIFIED routes (L:src/App.tsx ProgramsRedirect) |
| /verifications, /collections, /facilities, /scanners, /team, /partners, /settings/* | Shared operational surfaces, same as any company. VERIFIED routes |
CRUD abilities and gates
Create: production records (manual/EWR/SDU-demo), pigment orders, facilities (licence-gated), scans (via SAT/scanners), partner invites, team invites. Update: own production records until the 30-day lock; own facilities. Cannot: create programmes, set their own ceiling or scans_per_mt (admin does), register themselves as producer (admin does), create SDU devices (admin does — and the real backend has no SDU write endpoints at all). VERIFIED (persona-01 file; .local/backend-specs/claude-sdu-api-spec.md:3).
Business rules binding specifically to them
- Production cannot raise
produced_mtpast the ceiling (LEAST cap in the trigger). VERIFIED. QC P-06 additionally expects a clear blocking error when an entry exceeds allocation — no client-side guard was found in FibreCreation at HEAD; the cap is a silent server-side clamp on the scan-derived figure, so P-06 as written will likely fail. VERIFIED absence of client guard (.local/qc-test-script/analysis.mde7). - One facility cannot serve two same-pigment overlapping programmes. VERIFIED (SQL trigger).
- Manual entries carry the 1-per-5-percent scans_required rule; source is labelled (manual vs sdu vs ewr_demo). VERIFIED (SQL 20260414200926; DemoEWRModal source “ewr_demo”).
- Their scans retire only when a Tier 1 uses them on a confirmed claim — sub-tier scans never retire (see
02-lifecycles.md). STATED (BL:wt2:28-29).
Dependencies
Upstream: FT Admin (programme, producer registration with ceiling, pigment assignment, SDU devices, facility licences). Downstream: the entire claim economy — Activated volume is the pool claims draw on; a producer that stops scanning starves every participant’s available-to-claim figure (available_to_claim = min(my reserved - my claimed, total produced - total claimed)). VERIFIED (L:src/hooks/useProgrammes.ts).
First-login / empty state
A producer registered but with no production sees HomeProducer’s all-clear card and an empty Fibre Creation list; the Production nav group appears immediately on registration (that is the gate). VERIFIED (HomeProducer.tsx:354-364; AppSidebar fibreCreationEnabled).
Likely failure modes and confusions
- EWR looks like a live integration but is simulator-only: “Dummy connection — production records will sync once live integration is enabled”. VERIFIED (L:src/components/AddFacilityFlow.tsx:226; DemoEWRModal:83).
- The Tier 4 home tiles reading 0 while Production Records showed 274 MT was observed live in July — possibly a data-scope bug, never re-verified. STATED (BL:
ux-findings-for-malcolm.mdfinding; status UNKNOWN). - The rPET hybrid (producer sidebar, owner home) confuses anyone testing “the producer experience” on that seed. VERIFIED observation (BL:gui-walkthrough README).
- Believing an SDU assignment makes them a producer — it only lights up device status; Production/Fibre Creation stays hidden without registration. VERIFIED (AppSidebar gating).
Implementation state
Lovable: fully working against Supabase, including the SDU page’s Aug polish. Monet: /fibre-creation and /sdu are routed but are empty shells (production_records, pigment_orders, sliver_delivery_units all no-op stubs); the real backend offers 4 read-only SDU GET endpoints (devices, detail, run-events, bale-ranges) that monet’s sduApi already consumes for reads, plus nothing for production records. VERIFIED (M:src/lib/apiAdapter.ts:228,234,236; .local/backend-specs/claude-sdu-api-spec.md; integration-audit: sliver_delivery_units GAP write-side).