T
Sign in

QUEUE.md — runner-owned machine ledger (generated)

QUEUE.md — runner-owned machine ledger (generated)

FILE OWNERSHIP: written ONLY by scripts/queue-next.ts --sync (the runner). It is a projection of the owner's docs/CORRECTIONS.md Pending table plus the reopen feed; the owner never edits it. Batching rules: docs/OWNERSHIP.md. Do not hand-edit a block's status to done — the verifier agent does that on proof.

Regenerate/enrich: bun scripts/queue-next.ts --sync Inspect: bun scripts/queue-next.ts --list Plan next batch: bun scripts/queue-next.ts --next

C131

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/masters
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting

C132

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/masters?tab=party
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: Retire the opening-balance field on every authoring/display surface only; keep the party.opening_balance column and legacy values untouched (mirrors C131).

C133

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/masters?tab=party
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: Retire the due-days field on every authoring/display surface only; keep the party.due_days column and legacy values untouched (mirrors C132).

C134

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/masters?tab=party
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: Mobile/email rules already exist (PLANNING 141); C134 is read as: keep them and make the mobile/email inputs actively relevant at the keyboard (mobile strips non-pattern characters as typed; stale errors clear on edit). Nothing else changes.

C135

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/masters?tab=party
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: Godown is a master label added to the party-category vocabulary; no downstream filter (gatepasses trader picker) changes. New value only, reversible; revisit only if the owner wants Godown parties hidden from pickers.

C136

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/masters?tab=party
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: Keep +91 storage byte-identical (bare 10 digits); persist other known codes as ; shared whitelist in src/lib/countryCodes.ts; reversible and additive.

C137

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/masters?tab=party
  • verify: /tmp/opencode/c137-proof.ts
  • acceptance:
    • party tab renders no visible phone input but a hidden round-trip name=phone input
    • a create POST with phone=not-a-phone returns only 'party name required' (no phone-format error)
    • blank name still rejected
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: C137 = drop the visible party Phone input + validation only; preserve existing phone data via a hidden round-trip input; keep the record-detail Phone row.

C138

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/masters?tab=party
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: MSME stored as free-text (trimmed string; blank -> null); label 'MSME (Udyam Aadhar) no.'; shown in the party form and the record detail; no format validation; no list column.

C139

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/masters?tab=party
  • verify: -
  • acceptance:
    • Party form at /masters?tab=party renders no visible Own unit toggle
    • a hidden isOwnUnit round-trip input is present
    • creating an own-unit party stores is_own_unit=1 and editing another field leaves it 1
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: remove only the visible 'Own unit' toggle; keep the is_own_unit column/data and the detail/list rows; hidden round-trip input preserves the value on edit

C140

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/masters?tab=party
  • verify: -
  • acceptance:
    • typing abcde-1234f into PAN normalises to ABCDE1234F as you type
    • typing 27abcde-1234f1z5 into GSTIN normalises to 27ABCDE1234F1Z5 as you type
    • a malformed PAN/GSTIN still shows the existing per-field error on save
    • that error clears as soon as the field is edited
    • a valid PAN/GSTIN saves exactly as before
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: PAN/GSTIN rules predate the correction; the row wants them relevant at the keyboard (mirror C134/A94) - normalise-as-you-type + clear stale error, existing rules/messages unchanged

C141

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/masters?tab=party
  • verify: -
  • acceptance:
    • party record dialog shows Edit fields and no standalone Amend control
    • entering edit shows the Correction remark field among the other fields
    • Cancel sits beside Save and returns to the read-only view
    • saving an edit with a remark writes one amendment whose reason is the remark
    • saving an edit with no remark writes none
    • other master tabs keep their Amend control
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: Party tab only: the edit form carries the correction remark alongside the fields, Cancel + Save sit side by side, and the standalone Amend control is removed (the remark is written to the audit trail as an amendment on save). Other master tabs are unchanged.

C142

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/masters?tab=party
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: C142 = delete the Suggest button from the party Acronym field only; the auto-suggest-from-name behaviour and the acronym field itself are untouched.

C143

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/masters?tab=payment-terms
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting

C144

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/masters?tab=payment-terms
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting

C145

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/masters?tab=payment-terms
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: Target is the design master (/masters?tab=design) — same ?tab=payment-terms batch mislabel as C143/C144 (Q103/Q104). Permissible counts live per row inside the existing warp_rows/weft_rows JSON as permissible:[...]; the grid posts the same warpRowsJson/weftRowsJson names so buildDesignValues/designErrors keep working.

C146

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/masters?tab=payment-terms
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: C146 = remove the raw-JSON warp/weft field presentation (its literal target, already gone with C145); keep the C145 grid, relabel it Warp/Weft, and drop the JSON claim from static/masters-fields.html

C147

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/masters?tab=payment-terms
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: the quality name is derived (server builder + form preview share one helper) in the format width``reed/dentingpick/warpweft-weave; the design-master target is the C143-C150 batch mislabel (Q103-Q107)

C148

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/masters?tab=payment-terms
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: C148 = design master (masters?tab=design, batch mislabel); the removed field is the visible Pick (PPI) input; the derived name writes the literal Pick in the pick slot; stored pick preserved by a hidden carry on edit

C149

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/masters?tab=payment-terms
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: the design-master fields are removed from the UI/client/server validation and from buildDesignValues so an edit never overwrites the stored gsm_target/utl (checking report still reads them); columns stay, no migration

C150

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/masters?tab=payment-terms
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: drop the '— EPI = reed × denting ÷ 2' suffix from the Denting field label in DesignForm.svelte, keep 'Denting (ends per dent)'; ?tab=payment-terms is the C143-C150 batch mislabel so the design master is the surface; no input name, stored value, client rule or server validation moves.

C151

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/masters?tab=party
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting

C152

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/masters?tab=party
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting

C153

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/masters?tab=party
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: Target /tippans/new (sheet) and ?tab=party (queue) are the C143-C152 batch mislabel (Q103-Q111); the only 'L2L (104)' label is on the design master form, so remove '(104)' there and nowhere else.

C154

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/masters?tab=party
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting

C155

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/masters?tab=party
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: Only the /masters page tables (all 7 tabs) are in scope; the 'Open' links on /tippans and /reconciliations are not master tables and stay. rowHref already opened the record on row-tap, so removing the duplicate Open column is the whole change.

C156

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/masters
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting

C157

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/masters
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: Target is the design master (/masters?tab=design): the warp/weft grid with permissible counts exists only in DesignRowsGrid there (same C143-C152 batch mislabel as Q111). The permissible-count picker stays a multi-select checkbox list (C152 stored it as permissible:number[]); the fix is a search input inside the dropdown that filters the yarn-master counts, empty = all, no min length. Transient permQuery is per-row UI state, excluded from the posted JSON and from server validation, so no schema/field/validation change; POST names, JSON shape, distribute and both grid layouts are untouched.

C158

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/masters
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: C158 = design master (/masters?tab=design); remove Mode from every authoring/display surface (DesignForm select + client rule, designErrors server rule, MASTER_FIELDS detail row, SmartTable Mode column) and from buildDesignValues so an edit never overwrites the stored mode_pref; the design.mode_pref column and BOTH default stay (no migration) so the SO mode prefill keeps working (mirrors C149).

C159

  • status: done
  • priority: P1
  • target: -
  • verify: bunx tsc --noEmit = 140 (< 147 baseline); bun run build green on @sveltejs/adapter-bun; built server boots (GET / -> 303, /signin -> 200, cookieless POST /api/events -> 403); bun run check exit 0
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: Safe 80/20: migrate deps/config/aliases/removed-API call sites exactly as the official sv migrate sveltekit-3 did; keep deprecated-but-working API usages (json/text) and proven false-positive review findings (delta identifiers here are qty steps; enhanced forms post to their own page). Official @sveltejs/adapter-bun (community peers Kit 2). No schema/POST/validation change; reversible by restoring the old dep pins + svelte.config.js. | landed: deps @sveltejs/kit@^3.1.0 / svelte@^5.57.1 / zod@^4.6.7 / sveltekit-superforms@^3.0.0; svelte-adapter-bun -> @sveltejs/adapter-bun@^1.0.0; svelte.config.js deleted (config in vite.config.ts); tsconfig extends $app/tsconfig; $lib -> #lib subpath + .js across ~196 files; $app/environment->$app/env, $app/stores->$app/state, ActionResult from $app/forms; src/env.ts feeds $app/env/private; invalidateAll->refreshAll, goto keepFocus->reset:false, replaceState->replace. PLANNING §441, BUILD-LOG.

C160

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/masters
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: 711c8b9
  • live: 711c8b9
  • notes: landed: weave sub-master projected from design rows + pick-or-type datalist + case-insensitive de-dup/validation (WEAVE_RE) — PLANNING §448, BUILD-LOG; code swept into 711c8b9 after a deploy-scheduled queue-watch restart (SIGTERM) killed the C160 session mid-work; row-watch now runs --unstick before picking a row so a restart can no longer strand a doing row

C161

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/orders/new/trading
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: the reported 500 is the order form's post-save read-back GET /api/orders/[id] (order.quality is not a column; the quality is design.qualityName) — fix that one endpoint by joining the design master, keep the response shape and both callers unchanged

C162

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/quote
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: = latest quote for the design_id, newest inputs_json.warpReedSpace/weftReedSpace, carried via adj only when it differs from the master; empty/absent falls back to the master.

C163

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/quote
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: job rate = inputs_json.jobRatePaise of the newest quote for the design_id, falling back to the design master when there is no history; set directly on the wizard's job-rate field (no 'edited' badge, unlike wrs/frs) — no field added, no schema change, reversible.

C164

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/quote
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: warp sizing rate = the yarn master siz_rate for the row's count (first count+system match, then count-only); fills a blank row, re-prefills only a value this prefill wrote when the count moves to another master count, and never overwrites a quote/design/hand-typed rate. No field added, no schema change, reversible.

C165

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/quote
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting

C166

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/quote
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: Remove only the visible sizing-GST field from the new-quote wizard summary (/quote/new): drop the 'Warp n siz GST' tap-row and the sizGst branch of openYarnField. The stored sizGst value stays (yarn-master prefill + the costing path unchanged, blank = follow Fabric GST); RowEd.sizGst is untouched; /quote/edit's own per-warp Siz GST input stays because the row names /quote. No field added, no schema change, reversible.

C167

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/tippans/new
  • verify: -
  • acceptance:
    • /tippans/new serves no mill/ticket field: no yMill hidden input and no mill/ticket summary/wizard row
    • TippanWizard.svelte declares no yMill prop or step
    • the create action derives yarnIssue.mill from the assigned yarn/gatepass and never from a posted yMill
    • existing tippan records and prints still show the mill derived from their source, unchanged
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: Removed only the mill/ticket entry field from /tippans/new (state + hidden input + wizard prop/binding + gatepass ticket carry + PREFILLABLE entry + the create action's raw(fd,'yMill') read); the tippan's stored mill stays, derived from the assigned yarn or its gatepass (r.issue.mill | gpRow.ticket), so record/print/existing rows are unchanged. No schema, POST-name, record or print change — fewest files, reversible.

C168

  • status: done
  • priority: P1
  • target: -
  • verify: -
  • acceptance:
    • masters load exposes mills = distinct rate-board tickets, case-insensitively deduped, first spelling canonical, sorted
    • a new rate ticket appears in mills on the next load with no other action
    • the yarn Add/Edit Ticket/mill input is a pick-or-type datalist fed by mills
    • no schema change/migration and stored yarn tickets unchanged
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: The mill/ticket master is a derived projection of the rate board's ticket column (mirroring C160's weave sub-master), not a new table/tab; it feeds a pick-or-type datalist on the yarn master's Ticket/mill field so any count+type shows all mills. No schema change, stored yarns untouched, reversible.

C169

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/tippans/new
  • verify: -
  • acceptance:
    • masters design tab: focusing or typing in the Weave field shows the filtered weave-master list above the input
    • tapping a row fills the field with the stored spelling
    • typing a weave not in the master stays in the field and is saved (canonicalWeave adds it), appearing in the master and the next dropdown
    • the design tab shows a read-only Weave master panel with the count and every distinct weave (case-insensitive unique)
    • name=weave, WEAVE_RE and designErrors are unchanged and no schema/migration exists
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: C169 surface is the design master (/masters?tab=design) — /tippans/new carries no weave field (weave is derived from the picked design), so the target is the same C143–C157 batch mislabel; the weave master stays a projection of design rows (C160) and is now shown read-only on the design tab, and the Weave field becomes a visible searchable dropdown that still accepts a new weave; no schema change, no POST-name/validation change, reversible.

C170

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/orders/new/trading
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting

C171

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/orders/new/trading
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting

C172

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/orders/new/trading
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: Brokerage slot = 1% across the field's existing 0–100 range, coins exactly 1% and 2%, wheel floors a fractional typed value into its slot; no field added so server readNum(0–100) and the client decimal guard stay unchanged; reversible (restore the single input/subtitle).

C173

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/orders/new/trading
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: Pass-on wheel slot = 0.25% across the existing 0-100 range, coins exactly 0.5% and 2%, wheel keeps a fractional typed value (snaps to nearest 0.25 slot for display); no field added so server readNum(0-100) and the client decimal guard stay unchanged; reversible (restore the plain input/subtitle).

C174

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/orders?operations=1
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: own-key guard only in the target file src/routes/orders/+page.server.ts (Object.hasOwn for rawSort); the identical SORT_COLS[rawSort] idiom on the nine sibling list pages is a separate reversible follow-up, not this row's file

C175

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/orders/new/trading
  • verify: -
  • acceptance:
    • deliver-in popup shows a Start date and an End date, each with Today/+2d/+7d/+15d/+30d/+40d chips and a ±1-day stepper
    • a chip/step rewrites that date and the window resolves to the whole-day span
    • the hidden input still posts name=dueDays as a non-negative integer (blank stays blank)
    • bun helper proof for addDaysIso/deliverSpanDays passes
    • bun run check is 0 errors
    • tsc adds no error in the touched files
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: keep dueDays integer as the one stored value; deliver start/end are UI-only dates over it (addDaysIso/deliverSpanDays), no schema/migration; window resolves to the whole-day span, clamped >=0; summary reads 'N day(s)'

C176

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/masters
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: mill master = board projection (C168) UNION a new insert-only mill table; name required + MILL_RE(1-40) on both surfaces; case-insensitive dedupe across both sources; no rate columns, quote popup untouched

C177

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/masters
  • verify: -
  • acceptance:
    • weave tab shows an Add weave button opening a modal
    • submitting a new weave adds it to the weave master list
    • a case-insensitive duplicate of a design or stored weave is refused 409
    • a non-conforming name is refused 400 on both surfaces
    • buildWeaveValues returns name+active
    • bunx tsc --noEmit adds no error in the touched files
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: weave master = design-weave projection (C160) UNION a new insert-only weave table; name required + WEAVE_RE(1-20) on both surfaces; case-insensitive dedupe across both sources; no construction columns

C178

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/orders?type=SO
  • verify: -
  • acceptance:
    • every list page (hishob, bookings, tippans, gatepasses, lots, beams, samples, drafts) returns non-500 for ?sort=proto / constructor / toString / hasOwnProperty and 200 on its base load
    • every real sort key still sorts and /orders is unchanged (already guarded by C174)
    • bunx tsc --noEmit adds no error in the touched files
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: C178 is the same inherited-property sort 500 C174 fixed on /orders (A130 named the sibling loads as the follow-up); apply the one-line own-key guard to the eight remaining list loads so no list table 500s on a non-own sort value — one line per file, behaviour unchanged for real keys, reversible

C179

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/orders/new/trading
  • verify: -
  • acceptance:
    • the operations/production fields are shown on this order form
    • the sales person may fill or skip them (non-compulsory)
    • OCR of the contract copy prefills the operations fields on this same form
    • skipping them still saves the order and lists it on the operations queue
    • the operations user later completes the same fields as an appendage (before/after, never a silent edit)
    • bunx tsc --noEmit adds no error in the touched files
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting

C180

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/orders/new/job-work
  • verify: -
  • acceptance:
    • the operations/production fields are shown on this order form
    • the sales person may fill or skip them (non-compulsory)
    • OCR of the contract copy prefills the operations fields on this same form
    • skipping them still saves the order and lists it on the operations queue
    • the operations user later completes the same fields as an appendage (before/after, never a silent edit)
    • bunx tsc --noEmit adds no error in the touched files
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: C180 mirrors C179 for the Job Work SO: same four ops fields (lotSizeMtrPerRoll, rolls, dispatchCity, promisedDays) added by kind ['SO','JW'], optional, step-less single-field boxes, server validation unchanged; OCR reachability restored as a JW-only, picker-free source step reading the contract copy; OUTSOURCE/PROD untouched.

C181

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/orders/new/production-order
  • verify: -
  • acceptance:
    • the operations/production fields are shown on this order form
    • the sales person may fill or skip them (non-compulsory)
    • OCR of the contract copy prefills the operations fields on this same form
    • skipping them still saves the order and lists it on the operations queue
    • the operations user later completes the same fields as an appendage (before/after, never a silent edit)
    • bunx tsc --noEmit adds no error in the touched files
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: C181 mirrors C179/C180 for the Stock (Production) order: the same four ops fields (lotSizeMtrPerRoll, rolls, dispatchCity, promisedDays) join ORDER_FIELD_SPEC by kind ['SO','JW','PROD'], all required:false, each a step-less summary row opening its own single-field box; the source step returns for PROD as a contract-copy READ only (picker stays SO-only); client inputs gain the sibling pattern rules (decimal for cut size, whole number for rolls/sales promise), server validation unchanged and already kind-agnostic; OUTSOURCE untouched.

C182

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/orders/new/job-work
  • verify: -
  • acceptance:
    • the job work wizard opens on the 'Loom width and panna?' popup as its first step
    • the job work form's Kind section leads with 'Loom width (from master)' then 'No. of panna (panels together)'
    • both fields keep their existing validation (loom-master widths, panna a whole number >= 1)
    • the Trading SO and Production Order forms have no loom step or fields
    • bunx tsc --noEmit adds no error in the touched files
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: loom width + panna are literally first on the JW wizard (before the contract-read source step) and lead the JW form's kind section; the shared job-work code also applies it to OUTSOURCE; SO/PROD unaffected; C146's fields and their existing validation (loomWidth in the loom master's width set, panna a whole number ≥1) are unchanged

C183

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/quote/new
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting

C184

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/quote/new
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: the payment dhara field = the /quote/new summary form's 'Payment dhara' row; 'in the end' = last section of the full form, after Construction, just above the actions (the wizard's dhara step is already last among steps). One file (NewSummary.svelte), reversible, no behaviour change.

C185

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/quote/new
  • verify: -
  • acceptance:
    • on /quote/new's calc screen, when a side has more than one valid yarn row, each warp and each weft is listed with its own ₹/m cost and g/m weight
    • the existing warp/weft totals are unchanged
    • a side with a single row shows no per-yarn breakdown
    • the per-row figures match the engine's warpRowCosts/weftRowCosts and warpRowKg/weftRowKg
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: second page = the calc/numbers screen (NewCalc.svelte); show per-warp and per-weft cost+weight only when a side has >1 valid rows, using the engine's existing per-row arrays (C.warpRowCosts/weftRowCosts, W.warpRowKg/weftRowKg) filtered by positive count so indices align; totals unchanged; one file; reversible.

C186

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/quote/new
  • verify: -
  • acceptance:
    • on /quote/new the Est qty (mtrs) term popup shows a scroll entry stepping 1000 mtr per slot
    • typing a figure is kept as typed and opening the popup does not rewrite an existing estimate
    • coins list previous sale orders (type='SO') of the same quality, most recent first, up to 4
    • coins fall back to the browser's last-used estimate when there is no order history and no coins row shows when neither exists
    • estQty still posts and validates (junk / <0 / >1000000 fail), no new field
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: coins = previous type='SO' order rows of the same design (positive metre qty, recent-first, dedupe, max 4), browser last-used as fallback; wheel = NumberWheel one slot 1000 mtr, floor one slot, top = server's 1,000,000-mtr estQty cap, typeable keeps a typed figure

C187

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/quote/new
  • verify: -
  • acceptance:
    • on /quote/new the Delivery end term popup shows coins +10d, +20d, +30d, +40d, +50d, +60d
    • tapping a coin fills the date with the chosen Delivery start + that many days, or today + days when no start is set
    • the Delivery start popup still shows its C105 quality-typical coins unchanged
    • deliveryEnd still posts and still validates (a non-date fails), no new field
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: delivery-end coins = +10/+20/+30/+40/+50/+60 days added to dStart when set, else today; suggestions only, dStart coins untouched. Q140/A140

C188

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/orders
  • verify: -
  • acceptance:
    • the orders list shows no fixture order number (order_no glob SO-C-, SO-AIR*, SO-AM-, SO-ML-, SO-E2E*)
    • real orders numbered SO-YYMMDD-XXXX are untouched
    • data.db is backed up before any delete
    • every candidate row is checked first for linked booking/amendment/event children and none referenced is removed
    • the fix is proved by listing order_no values after the purge
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: Fixture-subtree purge (Q141): delete the fixture order and its linked child rows (evt/amendment/order_attachment/roll/dispatch_slip/lot) in one transaction after backing up data.db; the acceptance protection clause means no referenced child is left dangling, not that a referenced fixture stays. Real SO-YYMMDD-XXXX never match the globs.

C189

  • status: done
  • priority: P1
  • target: -
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: Q142/A142: the official DeepSeek key is set in the host .env (never committed) and .env.example documents url+model; the official API only accepts model deepseek-flash (display name DeepSeek-V4.1-Flash), proven by GET /models.

C190

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/samples
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: rate wheel min 0 max 999 step 0.25 typeable, up to 6 distinct recent order rates of the quality as coins; no strict 0.25-multiple validation (a typed fractional rate posts as before) — fewest files, existing rate validation untouched, reversible

C191

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/samples
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting

C192

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/samples
  • verify: -
  • acceptance:
    • [reopen 2026-10-18] never implemented — board marked done (3870b04) but the purpose field is still live in samples/+page.svelte and +page.server.ts; the 'row C192' commit fa08fe5 carried only docs (C206-C218). Reopened per owner 2026-10-18.
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: never implemented — board marked done (3870b04) but the purpose field is still live in samples/+page.svelte and +page.server.ts; the 'row C192' commit fa08fe5 carried only docs (C206-C218). Reopened per owner 2026-10-18. | assumed: Purpose removed from the samples form only: the svelte form/prefill/state and the samples create action stop reading or posting it; the capture-draft confirm still writes the nullable sample_order.purpose from the slip and the column stays (existing data preserved, reversible, two target files). | pre-checked: row-watch: read the row and its target before starting

C193

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/samples
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: The correction does not settle WHICH spot 'top of the form' is nor the displayed value: read it as a new first summary section named 'Sample' holding the existing read-only 'Sample no · Auto' row (value stays 'Auto' like every other doc-number row), moved up from the bottom of 'Charge or waive'. Display-only, one .svelte file, reversible; nothing else about the form or the server changes.

C194

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/hishob
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: remove Hishob (/hishob) and Reports (/reports) from the Orders nav group (both are reports); place both in a new 'Reports' nav group with the same roles. Display-only, one file, reversible by moving the two children back.

C195

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/bookings/new
  • verify: -
  • acceptance:
    • On /bookings/new, selecting an open order shows its warp/weft · count+type · already-assigned-kg grid, each assigned figure expanding to its date + mill ticket
    • selecting more than one production order makes the bags step ask bags per order and blocks save until the shares are positive whole numbers summing to the total
    • a single order or the pending bucket posts exactly as before
    • the split is validated server-side.
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: The grid is read-only context built from the order design's warp/weft rows + open bookings against that order; multi-select is PROD-only (an SO/pending replaces the selection); the primary order keeps the existing cost link, the split is an additive nullable JSON column, and the grid also renders for an SO harmlessly.

C196

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/bookings/new
  • verify: -
  • acceptance:
    • On /bookings/new, picking a yarn whose own master row has no booking history but whose count+system+type+mill matches another master that was booked, prefill cones/bag and bag wt from that last booking untouched-only, with the 'last booking' badge
    • the wizard's cones/bag + bag wt one-tap coins show that same last value
    • supplier/broker/lot/payment term/rate still prefill only from the exact selected master
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: cone/bag + bag wt prefill from the last booking whose yarn matches the selected yarn's count+system+type+mill (not the exact master id); the other history fields keep exact-id matching

C197

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/bookings/new
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting

C198

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/orders/new/trading
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: C198 is reorder-only: apply the owner's sequence to both faces (the shared ORDER_FIELD_SPEC + WIZARD_STEPS); keep the system date read-only at the top (C135) and keep both quote/lead link rows adjacent (the wizard already asks them as one box); protect C182's job-work loom-first step.

C199

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/orders/new/job-work
  • verify: -
  • acceptance:
    • JW form order: buyer's order no > booking date > system date > loom width (from master) > no. of panna > beams whose > broker > buyer > quality > rate > picks > job rate > qty > counted in > send as > deliver-in days > cut size > rolls > payment dhara > cash discount % days > brokerage % > capture draft > remark
    • JW form shows ONE loom width (legacy loomType gone)
    • JW form drops Send to city, Sales promise and Broker/weaver confirmation
    • JW wizard: loom > booking date > source > broker > buyer > quality > rate > picks > job rate > qty
    • trading SO (C198) and legacy OUTSOURCE forms unchanged
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: C199 is a JW-only reorder+removal: (1) retire the duplicate legacy loomType for JW (keep master-driven loomWidth, C146/C182); (2) keep the derived rate field/wizard step (not in the explicit remove list; C142) so the visible buyer/quality/rate/picks/job-rate sequence stands; (3) drop dispatchCity, promisedDays and contractFile on JW only; (4) keep the job-work wizard opening on loom (C182) with booking date next; (5) leave the legacy OUTSOURCE form (loomType, contractFile, city, promise) untouched — fewest files, keep existing behaviour, reversible

C200

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/orders/new/job-work
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: sourceDraftId shows on JW+OUTSOURCE, not tied to contractFile (C199 made contractFile OUTSOURCE-only); the field's upload uses the capture gateway (/api/capture-ocr) so it writes a draft and links it — party/quality prefill from the read's masters, full field-prefill stays the wizard's order-OCR — one file, reversible

C201

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/bookings/new
  • verify: -
  • acceptance:
    • New booking form carries an optional Own firm row whose options are exactly the party-master rows with category OwnUnit
    • legacy blank bookings still save and post firm_name empty
    • a saved booking stores the picked name in booking.firm_name and it appears in the summary/review
    • a POST naming a non-OwnUnit party returns 400 with the firmName error and stores nothing
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: own party type = party.category 'OwnUnit'; field optional + master-validated; stored as nullable text column booking.firm_name; pick-list rendered as the wizard's last step (index 13) to avoid clashing with the pending C207-C210 booking reorder rows; no auto-prefill.

C202

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/quote
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting

C203

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/quote
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | assumed: Prefill L2L from the design's most recent quote (inputs_json.l2l) via the existing lastQuoteRows map, winning over the design master exactly like wrs/frs/job; the L2L popup's suggestion coins lead with that last actual value, then fall back to the common master coins. No new field, no validation change. | pre-checked: row-watch: read the row and its target before starting

C204

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/quote
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting

C205

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/orders
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting

C206

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/orders
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: Create from the picker reuses the real party master form (PartyForm posted to /masters?/createParty) with no page reload; the new row is kept in the order form's local list and auto-selected. Category defaults: Party for a buyer, Weaver for an OUTSOURCE buyer, Broker for a broker. No new order field, so no new validation.

C207

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/bookings/new
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting

C208

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/bookings/new
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting

C209

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/bookings/new
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: Trader's booking no + booking date are optional (booking saves without them); trader no max 60 chars of letters/digits/space and / . _ -, booking date a real calendar day that starts on today's system date, untouched-only.

C210

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/bookings/new
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting

C211

  • status: done
  • priority: P1
  • target: src/routes/users/**, src/routes/+layout.server.ts, src/routes/+layout.svelte
  • verify: -
  • acceptance:
    • owner opens /users and sees the existing logins + a create-login form
    • owner creates a guard login (name/email/password/role) and the new user's role is guard
    • a signed-out or non-owner session cannot reach /users
    • creating a login with a duplicate email is refused with an inline error
    • there is no edit or delete action
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting

C212

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/gatepasses/new?kind=YARN_IN
  • verify: -
  • acceptance:
    • the yarn booking field on /gatepasses/new?kind=YARN_IN opens a table of bookings (not a search drop-down)
    • only bookings not yet fully received (status open or partial) are listed
    • tapping a table row selects that booking and carries its yarn, trader and rate
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: pending = booking.status open | partial (not yet fully received); the table applies to the shared yarn-booking field on both booking-driven kinds (YARN_IN and DIRECT) since it is one list/one field; other kinds keep their prefill picker

C213

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/gatepasses/new?kind=YARN_IN
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting

C214

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/gatepasses/new?kind=YARN_IN
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: reuse /api/capture-ocr for the OCR row (it saves the file and returns validated prefill); apply only the values this form shows/mounts (bags, vehicle, transport) and let the user confirm each; the signed gatepass copy gets its own document upload; dictation is a Web Speech textarea saved with the record and only prefills an explicit bags/plate mention; all three ride the creation event payload (no column, no migration); image stays the GP photo.

C215

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/gatepasses/new?kind=YARN_IN
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: form name = the YARN_IN kind label on /gatepasses/new (badge + list dropdown + FocusEntry title); generic h1 and nav left as-is

C216

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/gatepasses/new?kind=YARN_IN
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting

C217

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/gatepasses/new?kind=YARN_IN
  • verify: -
  • acceptance:
    • On /gatepasses/new?kind=YARN_IN the rows read Booking, Yarn (count + type + mill name), Yarn inward intimation no, System date, Location of pickup, Bags to be received, Remark in that order
    • a picked booking fills the Yarn row
    • Remark accepts 200 chars and rejects 201 server-side and caps the input
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: remarks = a new optional Remark row (max 200, event payload); reorder applies to the six named YARN_IN entry rows, static meta kept, uploads after

C218

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/gatepasses/new?kind=YARN_IN
  • verify: -
  • acceptance:
    • On /gatepasses/new?kind=YARN_IN the Kind row is gone — the rows read Booking, Yarn (count + type + mill name), Yarn inward intimation no, System date, Location of pickup, Bags to be received, Remark
    • every other kind still shows its Kind row
    • the YARN_IN after-save summary no longer lists Kind
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: remove kind = drop the Kind row/chip on the standalone YARN_IN form only (and its after-save summary line); keep the top-right form-name badge (C215), the direction marker, the hidden POST kind/direction markers and the list menu — fewest files, reversible, no other kind touched

C219

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/samples
  • verify: -
  • acceptance:
    • On /samples the new-sample form's Charge or waive section asks only Charge or Waive — picking Waive shows no Waive ₹ amount field (Rate shows only when charging)
    • A waive save writes charge_type=waive, waiver_amt=0, rate=null, and the sample list Charge column shows a green waive badge
    • A charge still requires Rate and writes charge_type=charged with the typed rate
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: waive = complete waive: drop the amount field; store waiverAmt=0, chargeType='waive', rate=null, auto-approved (waiverBy/waiverApprovedBy='user') because the >₹1000 owner gate needs an amount; list badge reads chargeType not the amount; fewest files (samples page + server), reversible

C220

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/samples
  • verify: -
  • acceptance:
    • On /samples the new-sample form shows no Rate source row in Charge or waive (Rate still appears only when Charge is picked)
    • a charge save still stores the typed rate
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting

C221

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/samples
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: remove the complete 'From (context)' section (lead picker, order picker, Capture draft static row) and the lead/order carry plumbing + server leadOptions/orderOptions; keep the hidden draftId POST and prefill so a draft still saves the same

C222

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/bookings/new
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: shared NumberWheel typeable input: while typing do not sync text from value (so backspace clears the last digit) and do not re-canonicalise on emit; canonicalise on blur. Empty/partial text left as typed; wheel range clamp unchanged.

C223

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/orders/new/trading
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: no broker selected (buyer present, non-PROD) is a DIRECT order: store brokerName 'DIRECT', brokeragePct 1, passOnPct 1 on save, accepting an incoming 'DIRECT' as no-broker too; directOrderDefaults treats our own 'DIRECT' as empty so the form effect is stable; a typed value (0 included) always wins; PROD unchanged

C224

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/quote/new?quoteId=aemxzq7f45xw
  • verify: -
  • acceptance:
    • Tap Reuse on a quote row: lands on /quote/new?quoteId=&reuse=1 with fields prefilled and NO 'Editing' banner
    • Calculate/save mints a fresh quote number (Edit still opens the carried 'Editing' form)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: Reuse opens the same prefilled summary form as a new quote (no edit carry, fresh number), keeping Edit as-is — the correction only names Reuse; fewest files, reversible

C225

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/orders/new/trading
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: the two lists are role-scoped on the one Trading SO form (production role -> production set, sales role -> sales set); Buyer stays buyer-or-broker; other roles and kinds unchanged

C226

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/orders/new/trading
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting

C227

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/orders/new/trading
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: Booking no. = the buyer's booking/order no already stored as partyContractNo; add it as a Trading SO-only wizard step right after the source/OCR step, with a standard 60-char reference-format validation on both surfaces; job work/outsource/stock and the yarn cost-basis booking are unchanged.

C228

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/orders/new/trading
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: C228 ships as the owner-approved ± stepper on the trading wizard's rate step: each tap nudges ₹0.25 (rounded to 2 dp), the centre stays typeable for any amount, and typed decimals are kept instead of floored. The desktop Price section rate input and the ops popup wheel are untouched; no server validation change.

C229

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/orders/new/trading
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: rate is money: formatRate() shows/stores 2 dp on /orders/new/trading (wizard + section input + prefills/coins), validateOrderFields rounds rate to 2 dp; ops popup untouched.

C230

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/orders/new/trading
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: C230 = the trading wizard's picks ± now moves 1 per tap (was 100); the C142 same-quality+party suggestion coins already ship and stay as they are; job work's picks input and rate maths untouched.

C231

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/orders/new/trading
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting

C232

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/orders/new/trading
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting

C233

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/orders/new/trading
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: the +/- stepper applies to the wizard brokerage scroll only; the summary popup's plain brokerage input and the 1%/2% coins stay as they are (fewest files, reversible)

C234

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/orders/new/trading
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting

C235

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/orders
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting

C236

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/orders/new/production-order
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: PROD staged: sales set = booking date+buyer+broker+quality+rate+picks+dueDays+payment dhara+CD+brokerage+pass-on; production set = buyer PO no+send as+cut size+rolls; qty already mandatory; quote/lead optional and the picker locks after manual entry; production completion enforces the same four.

C237

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/orders/new/trading
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: C237: fix scoped to the one control the operator sees on /orders/new/trading — the §4b send-as field pop-up; the hidden POST select and the order-detail page's send-as controls are left as-is (fewest files, reversible, invisible either way). No field added, so no validation change.

C238

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/orders/new/trading
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting

C239

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/orders/new/trading
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: C239: suggestion coins are quality-only (designId), newest first, de-duplicated, max 4; the party no longer filters coins though it still drives the C142 prefill; coins also show under the section picks input for non-job-work kinds; load reads a dedicated picksHistory (200, picks not null) so a quality older than the 40-row recent list still gets coins. No field/POST/schema/validation change.

C240

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/orders
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: C240: aliases for both cells in the wide orders table (party acronym/name, quality alias/name), column order unchanged (Party then Quality); record popup keeps full names; reuse existing partyCell/qualityCell helpers.

C241

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/orders
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: C241: "booking date" means the wizard's own booking date (order.orderDate, C135), shown as the first column of the wide /orders table, sorted by that raw date while displaying d MMM yy; the compact Job-work table (C140, four phone columns) and the existing trailing "Booked" system-date column stay exactly as they are. Display-only, one file.

C242

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/orders
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: the table's Status column shows short badge words (Open / In Prod / Delivered / Closed / Pending / Confirmed / Cancelled) and the Progress column shows one abbreviated leading fact (e.g. '3 rl · 1.2k m sent'); the record popup keeps the full status and progress text; display-only, one file (src/routes/orders/+page.svelte)

C243

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/orders
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: C243: the row popup is the only action surface on /orders (C140's rule); the table's trailing actions column is removed for all tabs, including the Reuse/Requote links, because the popup already carries the same destinations. Display-only, one file (src/routes/orders/+page.svelte).

C244

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/orders/new/trading
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: C244: 'open' means what the Leads/Quote list screens show — lost leads (not converted/deleted, no generated quote) and non-terminal quotes (open/approved/draft/sent, no generated SO) even when the printed validity date has passed; the picker and the create action share that set. The wizard's sourceLink picker opens as a modal (popup) with Lead/Quote tabs instead of inline.

C245

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/orders/new/trading
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting

C246

  • status: done
  • priority: P1
  • target: -
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: C246: two separate append-only reference masters (loom_class, loom_type) unioned with built-in values and values already on looms; the loom form reads them and validates against them. Class = 2-3 digit width in cm (optional cm suffix normalised), type = 2-20 letters/digits + space/-/_. C247's combined master is left to C247.

C247

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/masters?tab=loom
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: C247: loom_type gains a width column and is the combined master; Loom class stays as the width source/tab. The loom form has ONE Loom type select whose value is width | type; the loom keeps loom_class/loom_type text (downstream screens untouched) plus a nullable loom_type_id link filled when the picked pair is a stored master row. Blank-width C246 type rows apply to every class width; values already on looms and built-in pairs stay selectable. Recorded reading: keep the class master, no table or data dropped — reversible, fewest files.

C248

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/orders/new/job-work
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: C248: 'loom type' = the job-work loom width (loomWidth); panna prefills from the last order with that quality + width whichever party, and the old quality+party panna is only the fallback while no width is chosen. Blank when that width has no prior panna.

C249

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/orders/new/job-work
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting

C250

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/orders
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: production wizard = SO→/production/trading, OUTSOURCE→/production/job-commercial, PROD→/production/production-order, JW→/orders/#operations (no JW production screen); chip reads 'Details pending' beside Status and as the Ops column on the job-work table; only role 'production' gets Fill details and loses New.

C251

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/orders/new/trading
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | job-work | production-order all compose the same OrderEntryForm component, so one row covers all three. No schema change expected (visibility only). | pre-checked: row-watch: read the row and its target before starting | assumed: Role visibility is spec-level on both faces; buyer/qty/kind/system date/remark are universal; hidden fields post their carried values through hidden inputs; JW production gains the same four compulsory physical fields as SO/PROD production.

C252

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/production/trading
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: C252: role visibility+requiredness is spec-level on the production summary, its popups and the save gate; production's compulsory set is the four physical fields on every side; sales' set is the seven commercial fields; /production access stays owner/planner/production/checker/godown (no access change).

C253

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/orders/new/job-work
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: C253: rate per metre = jobRate × picks ÷ 100, derived; removed from the JW wizard but kept read-only in the background Price section and summary; OUTSOURCE keeps its editable form and explicit-rate-wins rule, only its auto maths follows ÷100.

C254

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/orders/new/job-work
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: C254: 'form' is the background Price section; only the job-rate and rate-per-metre blocks swap, Picks stays between them (rate → picks → job rate), matching the summary's ORDER_FIELD_SPEC order; the shared OrderEntryForm makes OUTSOURCE read the same order too. No wizard change (the JW rate step is already gone per C253).

C255

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/orders/new/job-work
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting

C256

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/orders?type=JW
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: C256: seven requested JW columns in the owner's order (booking date, order no, quality alias, party alias, mtr/beam, job rate, status), then the C250 Ops marker; job rate shown from order.jobRate as ₹/pick; Mtr/beam uses the order qty + qtyUnit.

C257

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/orders?type=JW
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: C257: chat/share stay in the row popup (C140/C153) and are always enabled for job-work rows; with a mobile they deep-link to the party, without one they open WhatsApp's contact picker with the same prefilled text.

C258

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/orders?type=JW
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: Hide Book yarn only on a JW row's actions; SO/Outsource/Stock keep it and the order detail page already omits it for JW

C259

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/orders?type=JW
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: C259: drop New tippan only from the JW row's actions in the orders list popup (the JW detail page already shows beam-out/yarn-inward, not sizing tippan); SO/Outsource/Stock keep it, other popup actions untouched — fewest files, reversible

C260

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/orders/new/job-work
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: job-work picks gets the same ±1 stepper and the same quality's most recent distinct picks (up to 4, from stored picks history, quality-only — no party filter, no fallback) as coins; tapping a coin or the stepper keeps the JW rate = job rate × picks live. No new field, so no new validation; the existing whole-number >0 rule stays on both surfaces.

C261

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/orders?type=JW
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: C261: the Job-work tab (?type=JW) renders only the Job Work SO draft; SO/PROD tabs likewise render only their own; the All tab keeps all three as before. Draft offers filtered client-side by data.fType — no server/DB change, no new field, no validation change.

C262

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/orders?type=JW
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting

C263

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/orders/new/job-work
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting

C264

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/orders?type=OUTSOURCE
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: C264: the four order forms share one draft mechanism keyed order-new-draft[-TYPE]; the generic OUTSOURCE form (null fixedType) keys order-new-draft, so it becomes a fourth draft offer and the existing fType tab filter shows each kind only its own (All keeps all four). Client-side, no server/DB change, no new field so no new validation. | assumed: C264: add the generic OUTSOURCE form's own draft offer (key order-new-draft, type OUTSOURCE, href /orders/new?type=OUTSOURCE) as the fourth entry; the existing filter (!data.fType | data.fType === d.type) then gives each kind tab only its own draft and the All tab keeps all four. No server/DB change, no new field, no validation change.

C265

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/orders/new?type=OUTSOURCE
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: C265 removes the four OUTSOURCE-only fields (tcsEffRate, tcsUncondRate, tcsLiability, deliveryGpId) from the booking form's one spec ORDER_FIELD_SPEC and its hardcoded terms block, records them in ORDER_INTENTIONALLY_HIDDEN, and leaves the server action, DB columns, order-record page and production-ops face untouched — fewest files, reversible, and a past order keeps the values it booked.

C266

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/orders/new?type=OUTSOURCE
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: C266 = C255's shared-form change: 'end of terms' means the last field of the Terms section (after the Outsource terms block), not nested inside that collapse; no further code change, same beamsSource POST/options/validation (no new field, so no new validation).

C267

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/orders/new?type=OUTSOURCE
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: C267: OUTSOURCE is the job-work form with its kind fixed by the URL; wizard/fields/rate/OCR match JW exactly and the only naming change is partyContractNo -> Weaver's order no. The party field keeps its existing buyer/weaver picker because the row names only the order no. Brokerage stays for C268.

C268

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/orders/new?type=OUTSOURCE
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: remove brokerage means the outsource form no longer shows or books brokerage (weaver job rate is the whole price); JW keeps its 1%, past outsource orders keep their booked value, fewest files/reversible

C269

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/orders/new/production-order
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: C269 = the production-order form keeps only yarn allocation (costBookingId) + remark from its Terms section; 'buyer, rate, send to city' and every other term/paper field leave the shared spec for PROD, while SO/JW/OUTSOURCE keep them. Buyer's order no/quote/lead/broker/booking date stay for C270. Fewest files (one spec + one component), reversible, past orders keep their booked values.

C270

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/orders/new/production-order
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: C270 = remove the buyer's order no, quote, lead, broker and booking date from the production-order form only; a value a quote/OCR/history held is not smuggled back as a hidden POST; the contract kinds (SO/JW/OUTSOURCE) and past production orders keep the fields they stored; the production stage still fills the buyer's order no at order-record completion.

C271

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/orders/new/job-work
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: C271 removes panna as a wizard step only: it stays a summary row that opens its own single-field box, required=false, prefilled from history, and saved unchanged.

C272

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/masters?tab=loom
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: C272 removes the Loom class master tab/form/action only: the loom_type master is the single width+type master with its width typed in cm (2-3 digits, cm suffix stripped, validated client+server), and the loom_class table, loom.loomClass column and stored values stay because beams/board/print read them; no data dropped, no schema change.

C273

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/bookings/new
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: C273 adds the OCR + dictation controls to the booking wizard's first popup: both only PREFILL every booking field the read understands (not just the booking no), OCR reuses /api/capture-ocr so the slip is kept as a capture draft, speech/typed text goes to /api/booking-understand, and the existing form validation + confirm sheet remain the only save path.

C274

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/bookings/new
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: C274 mirrors the order form's C141 pattern: the wizard still auto-opens, a header 'Start the wizard' button appears only when it is closed, and it reopens at step 0 (the capture popup); no field, POST name, validation, or save path changes.

C275

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/bookings/new
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: Delivery end is an optional new delivery_end column; all four delivery controls share one wizard popup; interval coins 3/5/7/10 with 1-day and 1-bag steppers; bags-per-interval suggestion = ceil(total bags ÷ inclusive interval count), stopping once the user edits it; end date optional, requires the start and is never before it — existing saves and blanks unchanged.

C276

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/bookings/new
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: Supplier options are the Supplier-category party master plus historic booking names, so old prefills stay selectable; the field remains optional and saves the same text, and a new supplier is created through the same PartyForm with category Supplier, selected in the wizard without a page reload.

C277

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/bookings/new
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: Broker options are the Broker-category party master plus brokers just created in this wizard, deduped and sorted; a new broker is created with the shared PartyForm (category Broker), then selected and the wizard advances; the booking broker stays optional and the existing server rule (Broker must be picked from masters) is unchanged. Fewest files, reversible, no data rewritten.

C278

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/bookings/new
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: reuse the masters YarnForm in a nested popup posting to /masters?/createYarn; on save refresh page data, select the new yarn and advance the wizard (mirrors the broker picker), no new booking field or column

C279

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/bookings/new
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: the mill/ticket is a new optional booking field (mill_ticket) picked from the mill master beside the yarn count+type; the popup creates a mill via the shared MillForm, old bookings fall back to yarn.ticket, and a legacy yarn's stored ticket is accepted so their product identity saves unchanged

C280

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/orders/new?type=OUTSOURCE
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: only OUTSOURCE swaps to job rate -> picks -> rate in the background Price form and its summary; JW keeps C254's rate -> picks -> job rate, SO unchanged, wizard untouched

C281

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/gatepasses/new?kind=YARN_IN
  • verify: -
  • acceptance:
    • Tapping the booking row on /gatepasses/new?kind=YARN_IN opens a separate popup titled Pick a pending booking with Job work and Yarn booking tabs, each showing its count
    • each tab lists pending bookings in a table (booking no · yarn · trader · rate · bags · status)
    • choosing a row fills the booking and advances/closes
    • the inline table no longer renders inside the wizard/field popup
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: The pending booking table moves into its own popup opened from the booking row, with Job work (no purchase rate) and Yarn booking tabs, the SO lead/quote picker shape (OrderTablePicker); choosing a row fills the same bookingPick and advances exactly as before, and the table is no longer rendered inline in the wizard/field popup.

C282

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/gatepasses/new?kind=YARN_IN
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: the intimation number is the existing GP number generated on save (GP-YYMMDD-XXXX) and the system date is the server's systemDate; both move out of the Which-movement section into a booking-style top card above the form, with no duplicate row and no change to the other kinds

C283

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/gatepasses/new?kind=YARN_IN
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: the added GP no is the trader/party physical gatepass number recorded in the existing partnerGpNo column (no migration), optional, max 64 chars, letters/digits/space/-// only; the auto GP-YYMMDD-XXXX intimation number stays display-only in the C282 top card and is never overridden

C284

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/orders/new/job-work
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: switching the job-work unit clears the quantity so the beam wheel opens on 1 (and metres on 1000); a metre quantity is never reinterpreted as beams, and a save with no quantity still fails validation as before

C285

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/orders?type=JW
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: natural-width table with horizontal scroll is the intended fix (not hiding or trimming columns), applied only to the Job-work tab where C140 forced the compact fit; column set, popup and actions unchanged

C286

  • status: done
  • priority: P1
  • target: -
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting

C287

  • status: done
  • priority: P1
  • target: -
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: no screen named: apply the app-wide ergonomics fix — a normal navigation opens the new screen at its top (hash targets and back/forward unchanged), one reversible layout file, no data change

C288

  • status: done
  • priority: P1
  • target: src/app.css
  • verify: script
  • acceptance:
    • bun scripts/color-contrast.ts exits 0: body >=7:1, muted /60 >=4.5:1, every status tone >=4.5:1 as text and as white on its chip, header strip >1.05:1 vs white
    • reverting thead th to #fafafa makes it exit 1
    • src/app.css keeps themes: light --default with no second theme or data-theme toggle
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | assumed: no screen named: fix the app-wide token layer in src/app.css — body ink zinc-900, status hues at the 700 tones with white content, visible zinc-100 table header strip; one reversible file, no markup, no theme change | pre-checked: row-watch: read the row and its target before starting

C289

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: -
  • live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: the scrollbar is the dashboard's position cue: one app-wide monochrome skin in src/app.css (10px, rounded zinc-400 thumb, zinc-900 under the pointer) plus a desktop-only section rail on the dashboard — one tick per board section mapped onto the same track as the thumb, active tick follows the reader, click jumps — no new data, removed by deleting ScrollMap.svelte and its two lines in +page.svelte

C290

  • status: done
  • priority: P1
  • target: -
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: 789559e4be7b716c2786c4690abf968d7e43c24b
  • live: 789559e4be7b716c2786c4690abf968d7e43c24b
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: the phone's bar is the C289 rail made draggable: show it at every width (right-1 on phones, sm:right-4), take the drag with pointer capture + touch-action none so the gesture is ours, keep ticks as click-to-jump, no new data or screen — reversible by restoring hidden lg:block

C291

  • status: done
  • priority: P1
  • target: src/lib/components/ScrollMap.svelte
  • verify: script
  • acceptance:
    • bun scripts/scroll-map.ts exits 0: the rail is a 44px lane on phones (24px from sm) holding a 6px zinc-400 bar pinned to the edge, no grey track slab, the bar darkens on hover and while dragging, tick pips clear of the ink
    • reverting the lane to w-2 / the track to bg-base-300 makes it exit 1
  • owner: -
  • commits: 9a6ab97bf4737217ad04dca886dd5692d5dca372
  • live: 9a6ab97bf4737217ad04dca886dd5692d5dca372
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: C291: the finger target is the lane, the ink stays subtle — 44px lane on phones / 24px desktop, 6px zinc-400 bar pinned to the edge, no grey track slab, same drag map and tick jumps; reversible by restoring w-2/right-1 and the bg-base-300 track

C292

  • status: done
  • priority: P1
  • target: scripts/daisy-audit.ts, src/routes/+layout.svelte, src/routes/+page.svelte
  • verify: script
  • acceptance:
    • bun scripts/daisy-audit.ts exits 0: daisyUI is the only UI kit (lucide icons excepted — daisyUI ships none), src/app.css loads only tailwind + daisyUI with the single pinned light theme, src/app.html loads no external UI asset, and every visible input/select/textarea/table/progress carries its daisyUI class
    • adding bootstrap to package.json or reverting the header search / dashboard bar to raw utilities makes it exit 1
  • owner: -
  • commits: 5cbe9b680f92e469ada36a44c6cffc3373bf1b7f
  • live: 5cbe9b680f92e469ada36a44c6cffc3373bf1b7f
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: C292: daisyUI is the app's only kit — read as (a) icons stay (lucide-svelte; daisyUI has no icon set), (b) paper sheets keep their own .tbl grid (daisyUI has no print component) and are named in PAPER_SHEETS, (c) layout buttons (rows, tiles, keypad keys, backdrops) keep utilities but no button is left unstyled, (d) one exemption list for controls daisyUI cannot express (the NumberWheel typing slot), which fails when stale

C293

  • status: done
  • priority: P1
  • target: https://trading.tynolabs.com/
  • verify: -
  • acceptance: (none recorded — lane must write observable checks first)
  • owner: -
  • commits: d1e22c2e50dff79fddb3eb7d4fc20ab9a14e249c
  • live: d1e22c2e50dff79fddb3eb7d4fc20ab9a14e249c
  • notes: - | pre-checked: row-watch: read the row and its target before starting

C294

  • status: done
  • priority: P1
  • target: src/lib/components/ScrollMap.svelte, src/app.css, scripts/scroll-map.ts, docs/UIPATTERN.md
  • verify: script
  • acceptance:
    • the dashboard shows one vertical scrollbar, not two: the rail marks its screen (data-scroll-rail) and the shell's native bar is hidden there while the rail is mounted
    • every other screen keeps the app-wide scroll skin
    • bun scripts/scroll-map.ts ALL PASS and fails 2 checks on the pre-fix CSS
  • owner: -
  • commits: 809d7434fccb0118f167edc2d68377e156175d83
  • live: 809d7434fccb0118f167edc2d68377e156175d83
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: the rail is the dashboard's scrollbar (owner vocabulary, C289/C291); the native bar drawn under it is the extra one - hide it there only, app-wide skin untouched

C295

  • status: done
  • priority: P1
  • target: src/app.css, src/lib/components/ScrollMap.svelte, scripts/scroll-map.ts, docs/UIPATTERN.md
  • verify: script
  • acceptance:
    • the dashboard draws the app-wide skinned bar and no other: no screen hides it (no scrollbar-width:none, no rail marker selector)
    • the rail paints no thumb ink and keeps its tick pips + drag lane
    • bun scripts/scroll-map.ts ALL PASS and fails 5 checks on the pre-fix CSS
  • owner: -
  • commits: 1f876750e9d2a689fff0df11333332bda0d2163a
  • live: 1f876750e9d2a689fff0df11333332bda0d2163a
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: og = the app-wide skinned scrollbar in app.css (10px zinc thumb); the rail keeps its ticks + the invisible 44px drag lane and paints no bar of its own

C296

  • status: done
  • priority: P1
  • target: src/lib/nav.ts, src/routes/+layout.svelte, scripts/nav-audit.ts, docs/UIPATTERN.md
  • verify: script
  • acceptance:
    • the labelled sidebar draws the two standalone rows plus one section's links only: 10 rows at rest and 22 at worst with a section open for any role (45 before), and exactly one section is open
    • every screen in src/routes is a sidebar row, a utility link or a declared HIDDEN entry with its reason, and no screen has two rows or two rows one name
    • bun scripts/nav-audit.ts ALL PASS (16 checks) and exits 1 with 4 FAILs on the pre-fix shell (no #lib/nav import, 50 inline href literals, no aria-expanded toggle, no icon map)
  • owner: -
  • commits: 6c945414538ff12e7b3920e3c50bd138bafc4422
  • live: 6c945414538ff12e7b3920e3c50bd138bafc4422
  • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: minimal sidebar = one work group open at a time (the one that owns the current screen, or the last tapped); the collapsed desktop rail keeps every icon because a rail is a launcher, not a map; flow screens stay HIDDEN-but-declared; the eight existing groups are the organisation

C297

  • status: done
  • priority: P1
  • target: src/lib/components/ListToolbar.svelte, src/lib/components/RecordDialog.svelte, src/lib/components/SmartTable.svelte, src/routes/pending/+page.svelte, scripts/readability-audit.ts, docs/UIPATTERN.md
  • verify: script
  • acceptance:
    • ListToolbar: every control is a lucide icon + its word (Funnel filter badge, Clear, CSV, prev/next chevrons, 'Showing 1-50 of 300' count) and every filter select is aria-labelled
    • RecordDialog: fields are a two-column chip grid and the action row is first=primary then outline with a worded Close and 44px phone taps
    • SmartTable default row action is a btn btn-outline btn-xs with ChevronRight, not a text link
    • /pending renders one card per parked lot and booking with unchanged POST actions/hidden ids/contract picker/enhance and no
    • bun scripts/readability-audit.ts ALL PASS (24 checks) and 16 FAILs on the pre-fix tree
    • svelte-syntax + daisy-audit + bun run check green in the touched files
    • no route/field/validation/schema change
    • owner: -
    • commits: 768a4ff4c72dc5e63894c0bce5453d480481c6c0
    • live: 768a4ff4c72dc5e63894c0bce5453d480481c6c0
    • notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: throughout the website = the shared surfaces first (list toolbar, row popup, plain-table row action) plus the one action screen still on dense tables; icons always come with their word, never icon-only; cards only where they replace a dense table on a phone-first action screen; no route/field/POST change
    • C298

      • status: done
      • priority: P1
      • target: src/app.html, src/lib/nav.ts, src/routes/+layout.svelte, src/hooks.server.ts, src/lib/staticCache.ts, scripts/lighthouse-audit.ts
      • verify: script
      • acceptance:
        • every screen has a branded (titleFor: dashboard = 'Trading — greige platform', /signin = 'Sign in · Trading', /orders?type=SO = 'Sale · Trading', any nav row, hidden screen or utility named) and the root layout renders it in <a href="svelte:head">svelte:head</a> while a page's own <title> still wins</li> <li>app.html carries <html lang>, a 60-160 char meta description, theme-color equal to the manifest's, a light-only color-scheme, the Inter stylesheet off the critical path (media=print + onload swap, <noscript> fallback) and the manifest+favicon links</li> <li>the server hook gives static assets (icon, manifest, robots.txt) cache-control max-age=86400 and leaves /_app/immutable/**, page loads and /upload-file untouched</li> <li>bun scripts/lighthouse-audit.ts ALL PASS (22 checks) and exits 1 with 18 FAILs on the pre-fix tree</li> <li>no route, field, validation, query, action, schema, theme or role rule changes</li> </ul> </li> <li>owner: -</li> <li>commits: 721f3051089a2bfbadb1be01fcb4a16acf502676</li> <li>live: 721f3051089a2bfbadb1be01fcb4a16acf502676</li> <li>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: the server-rendered head and headers are this row's whole surface: a per-screen title from the nav map (the sidebar row names the screen), description/theme-color/color-scheme, the third-party font off the critical path, and a static-asset cache policy; app-level gzip is skipped because Cloudflare already compresses text for the public URL and re-encoding on this phone's CPU would cost more than it saves; browser-only audits (contrast, CLS, tap targets, LCP) stay for later rows</li> </ul> <h3>C299</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: src/routes/+page.svelte, scripts/dashboard-audit.ts, docs/UIPATTERN.md</li> <li>verify: script</li> <li>acceptance:<ul> <li>the home page draws nine section rows with exactly one open at rest (the row whose cards carry the most bad/warn KPIs) and every closed row shows N red / N watch / N cards</li> <li>cards render only inside a row: phone carousel (C293) + sm+ grid, 29 cards x 2 surfaces, card language (tooltip, KPI chips, gm progress bars) unchanged</li> <li>one New dropdown in the header reaches the 8 role-filtered type-fixed forms with an icon + word each at min-h-11, and no Quick add block is left at the bottom</li> <li>page order is needs action -> dates -> 14-day pulse -> boards, with the period GET form, the SSE attention strip and the ScrollMap ticks kept</li> <li>bun scripts/dashboard-audit.ts ALL PASS (23 checks) and exits 1 with 10 FAILs on the pre-fix file</li> <li>no route/action/field/validation/schema/theme/role change and no edit/delete affordance</li> </ul> </li> <li>owner: -</li> <li>commits: 4a9021d575a5e818517283c9d13dc39194331c9b</li> <li>live: 4a9021d575a5e818517283c9d13dc39194331c9b</li> <li>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: dashboard = the master board at /, not the /board/[slug] component pages; chaos = hierarchy and reach, so every card and number stays and the fix is one open collapse row + one typed New control on top + a red/watch/cards tally on every closed row; the engine's nine SECTIONS rows are the organisation; the phone carousel stays inside the open section because C293's swipe is signed behaviour; the period filter keeps its place and its GET form</li> </ul> <h3>C300</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: src/lib/components/focus/FocusEntry.svelte, src/lib/focusWizard.ts, scripts/focus-wizard-audit.ts, docs/FOCUS-ENTRY.md</li> <li>verify: script</li> <li>acceptance:<ul> <li>the shared entry wizard opens on the first step whose value is still empty (winding with a sizing-gate carry answering winderId/sizerSetNo/expectedKg opens on recNet)</li> <li>a form whose every step is already answered opens on its summary with no wizard popup</li> <li>no step is lost - every step still opens from its summary row and a cold form still opens on step 0</li> <li>Next walks forward over steps a carry already answered</li> <li>the signed booking/tippan/order/quote step lists and every POST name, action, field, validation, schema, theme and role rule are unchanged</li> <li>bun scripts/focus-wizard-audit.ts ALL PASS (15) and 3 FAILs with exit 1 on the pre-fix shell</li> </ul> </li> <li>owner: -</li> <li>commits: 09d39df211ec42574710c163618bdbb9cd1cfcd9</li> <li>live: 09d39df211ec42574710c163618bdbb9cd1cfcd9</li> <li>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: wizard = the shared one-field FocusEntry shell: it starts on the first step whose value is still empty and stays closed when every step is answered, carried values are confirmed from their summary row, and the signed booking/tippan/order/quote step splits are left exactly as the owner last fixed them</li> </ul> <h3>C301</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: <a href="https://trading.tynolabs.com/gatepasses">https://trading.tynolabs.com/gatepasses</a></li> <li>verify: script</li> <li>acceptance:<ul> <li>the New gatepass control on /gatepasses is one plain link — no dropdown menu of gatepass types, no summary element</li> <li>on a kind screen (/gatepasses?kind=WINDING, ?kind=DIRECT, …) that link opens /gatepasses/new?kind=<that kind> and the form's badge shows that kind</li> <li>on the unfiltered /gatepasses the link opens the plain /gatepasses/new (validated default, never 500)</li> <li>the empty-state New gatepass button carries the same kind href</li> <li>every kind stays reachable (the sidebar's eight kind rows) and the list body, filters, tabs, totals and row dialogs are unchanged</li> </ul> </li> <li>owner: -</li> <li>commits: 1bf6e33a1218e7b896dbb142486aebde83e42441</li> <li>live: 1bf6e33a1218e7b896dbb142486aebde83e42441</li> <li>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: the screen that is open means its kind filter: a /gatepasses?kind=… screen (the eight sidebar rows) opens that same kind's new record, the unfiltered All screen opens the default form, and the kinds stay reachable from the sidebar rows so the removed menu strands nothing</li> </ul> <h3>C302</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: <a href="https://trading.tynolabs.com/gatepasses/new?kind=YARN_IN">https://trading.tynolabs.com/gatepasses/new?kind=YARN_IN</a></li> <li>verify: -</li> <li>acceptance:<ul> <li>/gatepasses/new?kind=YARN_IN asks a Yarn use (warp / weft) row with Warp / Weft / Both</li> <li>a picked booking prefills it from the booking's own warp/weft tag and it stays tappable to change</li> <li>saving posts warpWeft (warp|weft|both) into the creation event and the record page shows Yarn use</li> <li>an unknown posted value is a visible field error and is never stored</li> <li>the yarn-in's delivered lot carries the same tag on /lots and the lot record (a soft tag, nothing locks a warp lot out of weft use)</li> <li>the other seven kinds' forms are unchanged (no such row)</li> </ul> </li> <li>owner: -</li> <li>commits: f163017badfa44c7d4c51541e987a151a593cf3f</li> <li>live: f163017badfa44c7d4c51541e987a151a593cf3f</li> <li>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: the 'loose link that can change later' means a soft TAG, never a constraint: it defaults from the picked booking's own warp/weft, stays optional and tappable on the form, lands on the delivered lot (lot.warp_weft, already shown on /lots and the lot record) and nothing in the system locks a warp lot out of weft use; a later change is an appendage/amend, never an overwrite, and no edit screen is added</li> </ul> <h3>C303</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: <a href="https://trading.tynolabs.com/gatepasses/new?kind=YARN_IN">https://trading.tynolabs.com/gatepasses/new?kind=YARN_IN</a></li> <li>verify: -</li> <li>acceptance:<ul> <li>the yarn-in reference picker shows three source tabs — SO / production order, Yarn booking, Job work — in that order, all three always present</li> <li>the SO / production order tab lists every open SO and open PROD order with its own requirement, computed by the quote formula (src/lib/server/yarnMath.ts computeDesignWeights, docs/COSTING.md §5) × the order's mtrs — one line per warp row and per weft row (multiple yarns never merged), warp at the quote's costing weight and weft with waste</li> <li>each SO / production order row shows kgs received till date / kgs to be received, the requirement being what the quote formula gives and the pending figure never negative</li> <li>the Yarn booking tab shows total kgs received / total kgs booked per booking</li> <li>the Job work tab shows the weft requirement computed the same way (quote formula × mtrs) and the kgs received / kgs booked for that job-work booking</li> <li>picking a row from any of the three tabs still fills the form exactly as today (trader, yarn count/type/ticket, rate, warp/weft tag where the source has one) and posts only the fields the form posts today</li> <li>an order or booking whose design / construction is missing shows — in the kg columns, never 0, NaN or a 500, and stays pickable</li> </ul> </li> <li>owner: -</li> <li>commits: 28faca5194139eadc06ab5d7bdba4f9bfd881058</li> <li>live: 28faca5194139eadc06ab5d7bdba4f9bfd881058</li> <li>notes: - | pre-checked: row-watch: read the row and its target before starting | owner amended 2026-10-29: three reference sources for a yarn inward (SO trading / production order, yarn booking, job work)</li> </ul> <h3>C304</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: <a href="https://trading.tynolabs.com/gatepasses/new?kind=YARN_IN">https://trading.tynolabs.com/gatepasses/new?kind=YARN_IN</a></li> <li>verify: -</li> <li>acceptance: (none recorded — lane must write observable checks first)</li> <li>owner: -</li> <li>commits: 587bf8e51a184270391874986669e2771c0d9ba9</li> <li>live: 587bf8e51a184270391874986669e2771c0d9ba9</li> <li>notes: - | pre-checked: row-watch: read the row and its target before starting</li> </ul> <h3>C305</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: <a href="https://trading.tynolabs.com/gatepasses/new?kind=YARN_IN">https://trading.tynolabs.com/gatepasses/new?kind=YARN_IN</a></li> <li>verify: -</li> <li>acceptance: (none recorded — lane must write observable checks first)</li> <li>owner: -</li> <li>commits: ad3dee5747a63333d232ed04839c9455f337f189</li> <li>live: ad3dee5747a63333d232ed04839c9455f337f189</li> <li>notes: C305: the yarn-in photo section is one Gatepass photo row; ocrDoc/document/dictateText rows and their dead client code removed; server fields untouched | assumed: the kept field is the existing image row (file name + Add/Replace), and the detail page's read-only uploads card stays for legacy records</li> </ul> <h3>C306</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: <a href="https://trading.tynolabs.com/gatepasses/new?kind=YARN_IN">https://trading.tynolabs.com/gatepasses/new?kind=YARN_IN</a></li> <li>verify: -</li> <li>acceptance: (none recorded — lane must write observable checks first)</li> <li>owner: -</li> <li>commits: c61fbf0f510823c58912f7fbe5b92bebcf342ff3</li> <li>live: c61fbf0f510823c58912f7fbe5b92bebcf342ff3</li> <li>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: the OCR detection is a wizard step (the owner named the wizard pop-up), reading through the existing /api/capture-ocr gatepass reader, offered on a fresh yarn-in only (C300 carries keep their flow; the summary row still opens it), and a read prefills the form's own count/type/mill/bags/vehicle/transport rows only — no new POST name, and the read wins over an earlier value</li> </ul> <h3>C307</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: <a href="https://trading.tynolabs.com/gatepasses/new?kind=YARN_IN">https://trading.tynolabs.com/gatepasses/new?kind=YARN_IN</a></li> <li>verify: -</li> <li>acceptance: (none recorded — lane must write observable checks first)</li> <li>owner: -</li> <li>commits: 29f804318e45664475963333584c13ef9c22f95d</li> <li>live: 29f804318e45664475963333584c13ef9c22f95d</li> <li>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: The yarn-in wizard is ordered gatepassRead, warpWeft, bags, bookingPick, countYarn, yarnTypeCode, ticket, destPlace, partnerGpNo; point 5 is the yarn rows the form actually draws (yarn booking: one static row, so no step; SO order / job work: three picks); OCR-filled steps are skipped by C300 while answered and points 1, 2 and 4 always show; the C113 booking gate, the optional warp/weft and the optional trader's GP no are kept as they are; and since bags and warp/weft are now asked before the reference pick, a pick fills them only when the form has none (no silent overwrite of a typed or OCR-read value).</li> </ul> <h3>C308</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: <a href="https://trading.tynolabs.com/gatepasses/new?kind=YARN_IN">https://trading.tynolabs.com/gatepasses/new?kind=YARN_IN</a></li> <li>verify: -</li> <li>acceptance:<ul> <li>the yarn-in form shows a Verify fields button at the top of the screen</li> <li>tapping it pins the uploaded gatepass photo in a frozen pane on the top third of the screen, zoomable in and out, while the rest of the form scrolls beneath it</li> <li>a small cross on the pane closes it and the form returns to its normal layout</li> <li>the pane shows the Gatepass photo when one was uploaded, else the file the read step saved, and says there is no gatepass yet when there is neither</li> <li>the other seven kinds' forms are unchanged (no such button or pane)</li> <li>no new POST name, column, migration, route or edit/delete screen</li> </ul> </li> <li>owner: -</li> <li>commits: c938b7fa2d0171638ed0a94b747dac30db01e4d3</li> <li>live: c938b7fa2d0171638ed0a94b747dac30db01e4d3</li> <li>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: the frozen pane is the shipped gatepass photo (the Gatepass photo row when it has one, else the file the gatepass read saved) and it covers the top third of the viewport (33vh, sticky) with the form scrolling under it, not a second copy of the photo row; the button is on the yarn-in form only, the row's target; the shared field popups and the wizard stay full-screen overlays exactly as they are, so the pane is used against the summary rows and a field is checked from its row value; ?verify=1 reopens the pane after a reload; zoom is a 50-400% width scale in 25% steps (pinch is the browser's own zoom)</li> </ul> <h3>C309</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: <a href="https://trading.tynolabs.com/gatepasses/new?kind=YARN_IN">https://trading.tynolabs.com/gatepasses/new?kind=YARN_IN</a></li> <li>verify: -</li> <li>acceptance:<ul> <li>each reference tab shows ONE kgs pending / required column (no separate kg-in, pending or requirement columns)</li> <li>a quality with multiple warp/weft yarns lists its counts in that same cell, with — for a figure that cannot be computed</li> <li>the SO / production order and yarn booking tabs take several picks and can be mixed</li> <li>the job-work tab takes one pick and clears any other</li> <li>with more than one pick the form shows a live split of the gatepass's boxes with each row's yarn count, pending kg, a +/- one-bag stepper capped at its pending, the kg those boxes carry and its further pending</li> <li>changing the bags re-divides</li> <li>a job-work reference mixed with another, an unknown reference and a split taking more boxes than the gatepass are visible field errors on save and nothing is stored</li> <li>a valid mixed split saves and rides the creation event, the first pick still posting the bookingId</li> <li>no new column, migration, route or edit/delete screen and the other seven kinds unchanged</li> </ul> </li> <li>owner: -</li> <li>commits: 04c27ab007f7d1fcc89ec1d565a74653d6b7a7d0</li> <li>live: 04c27ab007f7d1fcc89ec1d565a74653d6b7a7d0</li> <li>notes: - | assumed: one kgs pending / required column per tab (count-wise in that cell when the quality has several warp/weft yarns, requirement per count and pending per order since received kg is tracked per order); the SO / production order and yarn booking tabs are multi-select and mix, the job-work tab is picked alone and clears the others; the first pick stays the form's single reference (yarn identity, trader, posted bookingId) and the box split rides the creation event as allocation, never a new booking; the equal split is recomputed from the bags and each row's cap whenever either changes, with the +/- stepper as the user's override; the SO tab keeps every open SO/PROD order (C303's list unchanged) | pre-checked: read the yarn-in reference block: the picker is single-select today (bookingPick/batch state in gatepasses/new/+page.svelte) and the server loads openOrders + openBookings + job work; the alloc grid is new state on the same page, no schema</li> </ul> <h3>C310</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: <a href="https://trading.tynolabs.com/masters">https://trading.tynolabs.com/masters</a></li> <li>verify: -</li> <li>acceptance:<ul> <li>the yarn form (Add and Edit) shows a Mill / ticket picker whose options are the mill/ticket master values plus the yarn's own current mill</li> <li>a yarn saved with a mill stores it and its name reads count + type + mill</li> <li>blank keeps a mill-less yarn</li> <li>a mill outside the mill-master name rule is a visible error on save and nothing is stored</li> <li>no new column, migration, route or edit/delete screen and the other master tabs unchanged</li> </ul> </li> <li>owner: -</li> <li>commits: e87d2e729a6c1aa34ad8e47462325684223adfc8</li> <li>live: e87d2e729a6c1aa34ad8e47462325684223adfc8</li> <li>notes: - | assumed: mill / ticket is an optional picker from the mill/ticket master (blank = no mill; the booking's own step fills it), the yarn name keeps count + type + mill, and both yarn actions enforce the mill master's MILL_RE | pre-checked: YarnForm.svelte keeps ticket as a HIDDEN input (line 70) — the mill field was dropped from the form while the column and the mill/ticket master (tab mill-ticket) remain, so this is re-mounting an existing field against an existing master</li> </ul> <h3>C311</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: <a href="https://trading.tynolabs.com/masters">https://trading.tynolabs.com/masters</a></li> <li>verify: -</li> <li>acceptance:<ul> <li>Masters → Counts tab (/masters?tab=count) lists every distinct yarn count once, ascending, plus any count added there by hand</li> <li>Add count stores a positive number and it appears in the list at once: 0 / abc / 61.555 / 12345 are visible field errors and nothing is stored</li> <li>The yarn form Count field offers the count master values one-tap and still accepts a typed number, with the same rule shown as a field error on create and edit</li> <li>A count already on a yarn or already in the master is refused with a visible duplicate message (409) and nothing is stored</li> <li>No edit/delete screen added, and the other master tabs plus the yarn mill picker and the booking wizard quick-add yarn behave exactly as before</li> </ul> </li> <li>owner: -</li> <li>commits: 5fa8e65af91d7edec97555ede56fec9ac2774196</li> <li>live: 5fa8e65af91d7edec97555ede56fec9ac2774196</li> <li>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: the count master is a projection of the yarn master's counts plus hand-added counts (like C168 mill/weave), the yarn Count field offers the master as a datalist and still takes a typed number, and one COUNT_RE (>0, 4 digits, 2 decimals) is enforced on the count form and on yarn create/edit</li> </ul> <h3>C312</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: <a href="https://trading.tynolabs.com/masters">https://trading.tynolabs.com/masters</a></li> <li>verify: script</li> <li>acceptance:<ul> <li>a Type master tab lists every yarn type once — codes already on a yarn project in, a code added by hand is stored with its label</li> <li>the yarn form's Type field offers the type master's codes with their labels and a code added there saves on a yarn</li> <li>a type already on a yarn or in the master is refused with a visible duplicate message (409) and nothing is stored</li> <li>a type code or label outside the standard format gets a visible field error on the type form and on yarn create/edit (400), nothing stored</li> <li>no edit/delete screen added, and the other master tabs plus the yarn mill/count pickers behave exactly as before</li> </ul> </li> <li>owner: -</li> <li>commits: a377f89b7be093a0b55a4d2833ab6b762616599d</li> <li>live: a377f89b7be093a0b55a4d2833ab6b762616599d</li> <li>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: the type master is the projection of the yarn master's own type_code plus hand-added codes, each with an optional label; new codes beyond the standard eight are allowed and the gatepass yarn-type rule follows them; the yarn Type field is a picker over the master that also keeps a yarn's own legacy value</li> </ul> <h3>C313</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: <a href="https://trading.tynolabs.com/gatepasses/new?kind=YARN_IN">https://trading.tynolabs.com/gatepasses/new?kind=YARN_IN</a></li> <li>verify: -</li> <li>acceptance:<ul> <li>an SO / production order or job-work pick asks ONE yarn row from the yarn master (count + type + mill in one line), not three</li> <li>the create action stores the picked yarn's count, type and mill from the yarn id alone</li> <li>a stale yarn id is a visible 400 field error and saves nothing</li> <li>a yarn booking still inherits its own yarn and asks nothing new</li> <li>the wizard asks the same one row in place of the three</li> </ul> </li> <li>owner: -</li> <li>commits: 1b3ed3807b5c4a213d42458f3a67efcefb7dbc3f</li> <li>live: 1b3ed3807b5c4a213d42458f3a67efcefb7dbc3f</li> <li>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: the picked yarn-master row is the authority for count + type + mill — it posts as a new optional yarnId and the create action reads the three off the master (legacy countYarn/yarnTypeCode/ticket still accepted), a stale id is a visible 400, and the pick is required only when a picked reference has no yarn to inherit</li> </ul> <h3>C314</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: <a href="https://trading.tynolabs.com/gatepasses/new?kind=YARN_IN">https://trading.tynolabs.com/gatepasses/new?kind=YARN_IN</a></li> <li>verify: -</li> <li>acceptance:<ul> <li>the yarn-in wizard asks Bags, then Cones and Bag weight (kg/bag) right after it, and the POST stores all three on the gatepass</li> <li>cones and bag weight offer the same yarn's previous values as one-tap chips and stay blank when it has none</li> <li>a bag weight of 0/'abc' or a junk/negative cone count is a visible field error (400) and stores nothing</li> <li>a receipt carrying its own bag weight counts toward the reference's received kg even with no net</li> <li>every other kind's rows and posts are unchanged</li> </ul> </li> <li>owner: -</li> <li>commits: 0879d0351102dc126fe818fc48776bace8879457</li> <li>live: 0879d0351102dc126fe818fc48776bace8879457</li> <li>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: the row's two new fields are the gatepass's own total cones (the existing cones column) and a new kg-per-bag column bagWt; the same yarn means the same yarn count as the existing bags suggestions, values come from past YARN_IN/DIRECT receipts, and the bag weight is optional (net ₹ receipts still work)</li> </ul> <h3>C315</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: src/lib/server/intake.ts, src/lib/server/captureOcr.ts, src/lib/server/captureRouting.ts, src/routes/gatepasses/new/+page.svelte</li> <li>verify: browser</li> <li>acceptance:<ul> <li>a gatepass whose printed Booking No. matches an open reference arrives with that reference pre-selected (yarn/count/type/trader/rate filled from it)</li> <li>a number matching nothing open rides as a searchable chip, nothing is picked</li> <li>the read still commits nothing</li> </ul> </li> <li>owner: -</li> <li>commits: dca5f8f403bbbf7998e26f627e738617a86be5c1</li> <li>live: dca5f8f403bbbf7998e26f627e738617a86be5c1</li> <li>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: the read extracts the trader's printed Booking No. (intake + DOC_SYSTEM + routing); the gatepass load resolves it against the open/partial bookings already in the reference picker and pre-selects that one row (trader, yarn, count, type and rate then come from the booking); an unmatched number only seeds the picker's search and shows as a chip; a direct-delivery read still opens DIRECT; nothing is posted or committed by the read</li> </ul> <h3>C316</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: src/lib/server/intake.ts, src/lib/server/captureOcr.ts, src/lib/yarnTypes.ts, src/lib/gatepassOcr.ts, src/routes/gatepasses/new/+page.svelte</li> <li>verify: browser</li> <li>acceptance:<ul> <li>'61s Combed Compact - Classic Yarn' reads count 61 + type CCW with no literal CW on the paper</li> <li>40 CW / 30s KW / 150 Dn also read</li> <li>the resolved value is one yarn-master entry (count+type+mill), else a suggestion chip</li> <li>type words map to the type master (C312)</li> </ul> </li> <li>owner: -</li> <li>commits: 5e9fe6660dd510422e8b26902fb5823b4deec34c</li> <li>live: 5e9fe6660dd510422e8b26902fb5823b4deec34c</li> <li>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: the reader's type vocabulary is the type master's built-in list (src/lib/yarnTypes.ts, C312) plus the words its labels carry — karded/combed/combed compact/karded compact/denier/hank/lycra/slub — mapped to canonical codes; a hand-added master code can still be read when the paper prints the code itself; the prefill carries count+type in countYarn as it already did, and the form splits it; an unmatched read is a chip (C319 owns the tap-to-create chain)</li> </ul> <h3>C317</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: src/lib/server/intake.ts, src/lib/server/captureOcr.ts, src/lib/server/formMemory.ts</li> <li>verify: script</li> <li>acceptance:<ul> <li>the spinner line 'Gvg Elite Yarns And Fabrics (tex Div Of Gvg Paper Mills) Gpm' resolves to the mill master's entry (GVG Classic)</li> <li>the word 'Vishnu' in 'Vishnu Chambers, Shahu Corner' never becomes a mill</li> <li>an unknown mill is offered, never invented</li> <li>[reopen 2026-10-29] does not work on the real paper: readMill() returns {} for the Goenka gatepass because the spinner line 'Gvg Elite Yarns And Fabrics (tex Div Of Gvg Paper Mils) Gpm' sits directly under the goods line '61s Combed Compact - Classic Yarn 520524 3 ...' and the 6-digit HSN code 520524 trips ADDRESS_RE, so addressContext() marks the NEXT line as address and the spinner line is skipped (probe on the live draft's raw_text: ticket undefined, millHint undefined). Fix the neighbour poisoning and add this paper as a regression test.</li> </ul> </li> <li>owner: -</li> <li>commits: 2d7d2dbc9bf767d38607aa9cc805ebaf5076178d, 2a0b608d901b4ba6c1966e0b071e1e440e2cf72f</li> <li>live: 2d7d2dbc9bf767d38607aa9cc805ebaf5076178d</li> <li>notes: does not work on the real paper: readMill() returns {} for the Goenka gatepass because the spinner line 'Gvg Elite Yarns And Fabrics (tex Div Of Gvg Paper Mils) Gpm' sits directly under the goods line '61s Combed Compact - Classic Yarn 520524 3 ...' and the 6-digit HSN code 520524 trips ADDRESS_RE, so addressContext() marks the NEXT line as address and the spinner line is skipped (probe on the live draft's raw_text: ticket undefined, millHint undefined). Fix the neighbour poisoning and add this paper as a regression test. | pre-checked: reproduced on the live draft's raw_text: readMill() returns {} because the goods line's 6-digit HSN code 520524 trips ADDRESS_RE and addressContext() then marks the spinner line below it as an address, so printedMillName skips it; the Goenka paper is the regression case | assumed: the fix is the neighbour rule in intake.ts addressContext(): a line is an address by its address words, or by a bare 6-digit number unless that line names a mill/spinner; only the address WORDS spread to neighbours, and never over a mill/spinner line — so the HSN on the goods line no longer hides the spinner below it and a spinner printed above a two-line address still reads. The regression lives in scripts/mill-read-audit.ts (this checkout has no tests/ suite).</li> </ul> <h3>C318</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: src/lib/server/formMemory.ts, src/lib/server/captureOcr.ts, src/routes/gatepasses/new/+page.server.ts</li> <li>verify: browser</li> <li>acceptance:<ul> <li>a value the user corrected on save is learned against the read transcript's words</li> <li>a later read carrying the same words resolves that field from memory before the gateway is asked</li> <li>the gatepass save still succeeds when the memory write fails</li> </ul> </li> <li>owner: -</li> <li>commits: 2fb66ab0f34e6cf59117900e950a3e3278bbbe69</li> <li>live: 2fb66ab0f34e6cf59117900e950a3e3278bbbe69</li> <li>notes: - | jobwork | outsource | production | booking and no gatepass caller exists; parseReadFields/changedFromRead and the best-effort learn contract are already there to reuse; the draft already stores the read transcript, the form already posts it back | pre-checked: row-watch: read the row and its target before starting | assumed: the gatepass teaches form memory the kinds it carries (count, type, ticket/mill, godown, transporter, yarn) from the draft the form was opened with: the transcript words link to the value the user confirmed, and the next read applies them ahead of the model's answer; godown is kept in the read's own vocabulary (our-godown→godown); a confirmed mill the master lacks is kept verbatim, a mill the master carries reads in the master's spelling; the yarn kind is learnt but not replayed (the inward's count/type/mill already come from that row)</li> </ul> <h3>C319</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: src/lib/components/focus/FocusEntry.svelte, src/lib/components/gate/GatepassOcrRead.svelte, src/routes/masters/+page.svelte, src/routes/gatepasses/new/+page.svelte</li> <li>verify: browser</li> <li>acceptance:<ul> <li>an unmatched read value appears as a chip that opens the right master prefilled (yarn from count/type/mill, a new mill chaining into mill/ticket and back)</li> <li>saving returns to the yarn inward intimation with the new entry selected</li> <li>nothing is created without the user's tap</li> </ul> </li> <li>owner: -</li> <li>commits: d68f270adf059ba090d5292b469097bcd00255b3</li> <li>live: d68f270adf059ba090d5292b469097bcd00255b3</li> <li>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: the read's chip carries count+type in ?new= and the mill in ?mill=; the yarn master's mill field is the same + chip into ?tab=mill-ticket&new=<mill>&returnTo=<the yarn link> and comes back; a yarn save returns to the form as ?yarnId=<id>&ticket=<mill> and the inward shows that yarn row selected (the master row is the authority for count/type/mill); the masters page opens only the yarn and mill/ticket add dialogs on ?new= (the other masters are C320/C321), the return target must be a path on this app, and nothing is written before the user's own Add tap</li> </ul> <h3>C320</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: src/routes/gatepasses/new/+page.svelte, src/lib/components/focus/FocusEntry.svelte, src/routes/masters/+page.svelte</li> <li>verify: browser</li> <li>acceptance:<ul> <li>godown/location, party/trader and transporter each offer the read value as a chip into their own master, prefilled, returning selected</li> <li>no master is written without a user tap</li> </ul> </li> <li>owner: -</li> <li>commits: ed327d9779857dae505a49b98e29eccecf777724</li> <li>live: ed327d9779857dae505a49b98e29eccecf777724</li> <li>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: the chip stands on the value the form carries (the read's transporter, the picked reference's printed supplier that matched no party, a named pickup place that is not a Godown/Sizing party); the location master is the party rows of category Godown or Sizing; a save returns ?field=&partyId=&party= to the form, which selects it (a created trader rides sourcePartyId, which the yarn-in/direct delivery already posts and the server reads before the booking's); a value the master already carries shows no chip and nothing is written without the user's Add tap</li> </ul> <h3>C321</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: src/lib/components/focus/FocusEntry.svelte, src/routes/masters/+page.svelte, src/routes/masters/+page.server.ts</li> <li>verify: browser</li> <li>acceptance:<ul> <li>typing a value absent from the master shows '+ <typed text>' as the last row of the pick list, on every master-backed field</li> <li>tapping opens that master's add dialog prefilled from ?tab=&new=</li> <li>the saved entry returns selected to the field</li> <li>nothing changes when the text matches a value</li> </ul> </li> <li>owner: -</li> <li>commits: ffdc9b5a3a9effd8cc6abefebbf58a858cfdf47d</li> <li>live: ffdc9b5a3a9effd8cc6abefebbf58a858cfdf47d</li> <li>notes: - | pre-checked: row-watch: read the row and its target before starting</li> </ul> <h3>C322</h3> <ul> <li>status: done</li> <li>priority: P0</li> <li>target: src/lib/server/intake.ts</li> <li>verify: script</li> <li>acceptance:<ul> <li>a header printed 'GATE PASS' reads intent=gatepass (today it lands on booking)</li> <li>the glued 'gatepass' case keeps working</li> <li>a regression test named for the spaced header passes fixed and fails pre-fix</li> </ul> </li> <li>owner: -</li> <li>commits: 48129381179aa383299554d2a14a33d47181ee2a</li> <li>live: 48129381179aa383299554d2a14a33d47181ee2a</li> <li>notes: - | gatepass)\b, so 'GATE PASS' falls through to the booking pattern on 'Booking No. : 1128'; a one-line regex plus a test named for it | pre-checked: row-watch: read the row and its target before starting | assumed: the fix is the one-line gate\s*pass intent pattern in intake.ts (it still matches the glued GATEPASS OCR seam); the regression lives in scripts/mill-read-audit.ts because this checkout has no tests/ suite (7668c583, deploy --no-suite)</li> </ul> <h3>C323</h3> <ul> <li>status: done</li> <li>priority: P2</li> <li>target: src/lib/server/formMemory.ts, src/routes/tippans/new/+page.server.ts, src/routes/samples/+page.server.ts, src/routes/quote</li> <li>verify: browser</li> <li>acceptance:<ul> <li>the tippan, sample and quote reads learn on save and resolve on the next read, the same loop the order and booking readers use</li> <li>a memory write never fails a form's save</li> </ul> </li> <li>owner: -</li> <li>commits: 2f48b674ff0caf6e0da87020deef96a8f41d8a81</li> <li>live: 2f48b674ff0caf6e0da87020deef96a8f41d8a81</li> <li>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: the tippan/sample/quote reads are the capture drafts those forms are opened with (?draftId=): each load resolves this form's memory for the draft's transcript words (memory wins, the read's own answer fills the rest, ids kept only when the form's master list has them) and each save learns only the fields the user changed or supplied, best-effort so a memory write never fails the save; the quote wizard's dictate step resolves memory through a ?/memory action before its fuzzy matcher; a tippan read's party fills the sizer (never the weaver); learning stays per form (a sample word never rewrites a quote); no new intent, endpoint, column, migration, POST name or edit/delete screen</li> </ul> <h3>C324</h3> <ul> <li>status: done</li> <li>priority: P0</li> <li>target: scripts/deploy.sh, vite.config.ts</li> <li>verify: script</li> <li>acceptance:<ul> <li>a build runs into build.next while the running app keeps serving the complete previous build</li> <li>the swap is a rename immediately before the restart, with build.prev kept for rollback</li> <li>the previous build's hashed client chunks are carried into the new build so a tab opened before the ship keeps working</li> <li>a page load and /queue/__data.json stay 200 for the whole build</li> </ul> </li> <li>owner: -</li> <li>commits: cd01e5d33496d474ab6bc3f66b2ae3d898746bbd</li> <li>live: cd01e5d33496d474ab6bc3f66b2ae3d898746bbd</li> <li>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: build into build.next (ADAPTER_OUT) while the running app keeps serving the complete build/; immediately before the restart build-swap.ts carries the served build's _app/immutable chunks into the new build, registers them in its generated asset table, then swaps with two renames (build -> build.prev for rollback, build.next -> build); build.prev/build.next are gitignored; no app route, column, migration or edit/delete screen</li> </ul> <h3>C325</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: src/lib/server/captureOcr.ts, src/routes/api/capture-ocr/+server.ts, src/routes/gatepasses/new/+page.svelte</li> <li>verify: browser</li> <li>acceptance:<ul> <li>the file a gatepass read saved becomes the form's Gatepass photo (image) by default, not just the verify pane's file</li> <li>the operator can still replace it with a better snap</li> <li>the read's own copy stays attached to the draft</li> </ul> </li> <li>owner: -</li> <li>commits: 0cec2049013da6509adac9a869869a4ff2bf95dc</li> <li>live: 0cec2049013da6509adac9a869869a4ff2bf95dc</li> <li>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: a gatepass read's file is COPIED (same name) into the screenshots upload drop so the form's existing image field / /upload-file?bin=screenshots resolves it — the draft keeps its own copy at screenshots/capture; only a gatepass read and only an image (a PDF read leaves the photo field empty); the photo is set only when the field is empty or still holds the previous read's file, so an operator's own earlier snap is never overwritten and the row's Replace still wins; no new field, POST name, column or route</li> </ul> <h3>C326</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: src/routes/gatepasses/new/+page.svelte</li> <li>verify: browser</li> <li>acceptance:<ul> <li>two fingers on the gatepass in the verify pane pinch it between 50% and 400% around the fingers' midpoint, and the page behind never zooms</li> <li>one finger drags the zoomed photo left/right and up/down inside the pane while the rest of the form still scrolls</li> <li>the - / + buttons, the live percentage and the cross work exactly as before, and a PDF gatepass keeps its own viewer</li> </ul> </li> <li>owner: -</li> <li>commits: 8c129c8df49436636608c61ed48229051d48006a</li> <li>live: 8c129c8df49436636608c61ed48229051d48006a</li> <li>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: a pinch is the phone's standard viewer gesture — two fingers, 50%-400%, around the fingers' midpoint — with one finger panning; the PDF keeps its own viewer; the photo box, not the page, owns touch while the pane is open</li> </ul> <h3>C327</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: src/routes/gatepasses/new/+page.svelte</li> <li>verify: browser</li> <li>acceptance:<ul> <li>Start OCR and Start Wizard sit at the top of the yarn-in screen and open the same wizard/read step the form already has</li> <li>nothing new is built behind them</li> </ul> </li> <li>owner: -</li> <li>commits: ff9e3141576bbc5975ffb3d099e31c48324d7e00</li> <li>live: ff9e3141576bbc5975ffb3d099e31c48324d7e00</li> <li>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: Start Wizard reopens the existing wizard at its first still-needed step (the C141/C300 walk); Start OCR opens the existing gatepassRead step, or its popup when a carried yarn-in has that id out of the walk. Both buttons sit always in the yarn-in header and only call the wizard the form already has - no new step, field, POST name or save path.</li> </ul> <h3>C328</h3> <ul> <li>status: done</li> <li>priority: P0</li> <li>target: scripts/deploy.sh, scripts/row-watch.sh</li> <li>verify: script</li> <li>acceptance:<ul> <li>a pull that conflicts stops the deploy with a message and a conflicted mark, and the tree keeps the conflict for a human</li> <li>no commit + push can include a file containing <<<<<<<, ======= or >>>>>>></li> <li>the guard has a regression test named for the 2026-10-29 marker incident</li> </ul> </li> <li>owner: -</li> <li>commits: 8dc6f4f2bad25d47781f852902f1dc42d46a1f97</li> <li>live: 8dc6f4f2bad25d47781f852902f1dc42d46a1f97</li> <li>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: Guard lives in its own script (scripts/check-conflict-markers.sh) with a --self-test named for the 2026-10-29 incident, run as deploy step 0a - this checkout has no tests/ suite (7668c583, same reading as A251); markers are line-anchored (open/close with a space, a bare line of seven equals) so an inline mention in prose is not one; a failed but non-conflicted pull exits 5 with no mark so a network blip is not read as a conflict; .deploy-conflicted is gitignored and clears itself once the tree is resolved.</li> </ul> <h3>C329</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: <a href="https://trading.tynolabs.com/gatepasses/new?kind=YARN_IN">https://trading.tynolabs.com/gatepasses/new?kind=YARN_IN</a></li> <li>verify: -</li> <li>acceptance:<ul> <li>the read of a paper printing 'Gate Pass No. : GSL/5546' sets the yarn-in's Trader's GP no row to GSL/5546 and the read card lists 'Trader GP GSL/5546'</li> <li>a bare number with no label, a following word, or junk characters never fill the row</li> <li>the carried value is validated on the field's rule (letters/digits/space/hyphen/slash, 24 max on the read) and junk lands empty</li> </ul> </li> <li>owner: -</li> <li>commits: 89a171fa9a607cf8f862537d38dec7848ed905d3</li> <li>live: 89a171fa9a607cf8f862537d38dec7848ed905d3</li> <li>notes: - | pre-checked: grepped intake.ts/captureOcr.ts/captureRouting.ts: no gpNo field anywhere (bookingNo arrived with C315; partnerGpNo is a form field only) and the Goenka draft has no gatepass number while the paper prints 'Gate Pass No. : GSL/5546' — a new field end to end, mirroring bookingNo | assumed: the read caps at the row's stated 24 while the existing field stays 64 (Q262); the printed label is part of the match so a bare number is never taken as the trader's GP no</li> </ul> <h3>C330</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: <a href="https://trading.tynolabs.com/gatepasses/new?kind=YARN_IN">https://trading.tynolabs.com/gatepasses/new?kind=YARN_IN</a></li> <li>verify: -</li> <li>acceptance:<ul> <li>the read card lists every value the read took — booking no, count, type, mill, bags, gross, net, vehicle, transport, trader GP no and expected date — and nothing it did not</li> <li>a read booking number that names no open reference rides as the 'matches nothing open' chip and seeds the reference table's search, and one that matches picks nothing</li> <li>a read value lands only on that field's own rule — a junk weight, booking no or date stays empty and is never listed</li> </ul> </li> <li>owner: -</li> <li>commits: be9ab5826669643b3a87653766b64acdb6bf07b1</li> <li>live: be9ab5826669643b3a87653766b64acdb6bf07b1</li> <li>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: the badge list names every value the read took (booking no, weights and expected date included) while only the rows this kind shows are filled — weights/expected date only on the kinds that show them, an unmatched booking no only seeds the reference table's search</li> </ul> <h3>C331</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: <a href="https://trading.tynolabs.com/gatepasses/new?kind=YARN_IN">https://trading.tynolabs.com/gatepasses/new?kind=YARN_IN</a></li> <li>verify: -</li> <li>acceptance: (none recorded — lane must write observable checks first)</li> <li>owner: -</li> <li>commits: 94faa4f95f980f14c442ec9ae2f8f0ab446fd0cf</li> <li>live: 94faa4f95f980f14c442ec9ae2f8f0ab446fd0cf</li> <li>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: the read's count is the identity; a master row's own name is its natural identity (the number it leads with, the type it names) with its columns as fallback; type and mill only narrow, never disqualify a unique count; more than one distinct yarn left = no pick and the read shows as the + chip into the yarn master (C319)</li> </ul> <h3>C332</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: src/routes/gatepasses/new/+page.svelte</li> <li>verify: browser</li> <li>acceptance:<ul> <li>the cones row reads 'Cones per bag', not 'Cones in this delivery', on the yarn-in (and on every kind that shows it)</li> </ul> </li> <li>owner: -</li> <li>commits: 77717004d5048cbd585ef26a9abf6ad2432ff1b9</li> <li>live: 77717004d5048cbd585ef26a9abf6ad2432ff1b9</li> <li>notes: - | pre-checked: grepped the yarn-in goods rows: the row renders 'Cones in this delivery' from gatepasses/new/+page.svelte but posts the delivery TOTAL in <code>cones</code> (the existing cone_per_bag column went unposted on this kind), so the fix is the label and the figure it takes | assumed: Cones per bag is entered per bag and the delivery total is derived (bags × cones/bag), posted in the existing cones column so the lot/bag grain and reports are unchanged; the per-bag figure goes to gatepass.cone_per_bag; the row keeps the bags rule (> 0 whole when given) on both surfaces; other kinds' 'Total cones (all bags)' row is untouched</li> </ul> <h3>C333</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: src/routes/gatepasses/new/+page.svelte, src/routes/gatepasses/new/schema.ts</li> <li>verify: browser</li> <li>acceptance:<ul> <li>every row the yarn-in wizard shows is required except remark, enforced on the client and in the create action with a per-field message</li> </ul> </li> <li>owner: -</li> <li>commits: 271029f1ccb6560086402df62c1fc48ec180f47e</li> <li>live: 271029f1ccb6560086402df62c1fc48ec180f47e</li> <li>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: every yarn-in row is compulsory except the remark: the reference, the yarn (when the row renders), the trader's GP no, the pickup location, the bags, the cones per bag, the bag weight, the warp/weft use and the gatepass photo; compulsory = the row was filled (a posted 0 counts, its own range rule still applies), the OCR read card stays optional so manual entry survives, and the reference/yarn identity are enforced client-side plus the action's existing checks (a single SO-order pick posts no id today, so the action cannot see that one)</li> </ul> <h3>C334</h3> <ul> <li>status: done</li> <li>priority: P2</li> <li>target: src/routes/gatepasses/new/+page.svelte, src/lib/components/focus/FocusEntry.svelte, src/lib/components/gate/GatepassOcrRead.svelte</li> <li>verify: browser</li> <li>acceptance:<ul> <li>the long one-line explanations are gone from the page header, the field popups and the read wizard, leaving the short label plus the field itself</li> <li>no behaviour changes</li> </ul> </li> <li>owner: -</li> <li>commits: 77e4952eefa032cbb8157be6370d5879ca4eeda7</li> <li>live: 77e4952eefa032cbb8157be6370d5879ca4eeda7</li> <li>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: C334 reading: 'the long one-line explanations' = the page header hint, the FocusEntry step/pop-up sub line, the money rate instruction line and the OCR read card's hint + chip help paragraphs; the pop-up now carries the short label and the field only, so the callers' sub strings are inert there (kept in source, no behaviour touched), the plate pop-up's own sub goes with the gatepass row, and each kind's Route fallback in the saved summary becomes '—' instead of the deleted hint sentence. Static rows stay tappable where they carry a note. Other screens' own hint components (orders/new, BookingCapture) are a later sweep, not this row.</li> </ul> <h3>C335</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: src/routes/gatepasses/new/+page.svelte, src/routes/bookings/new/+page.server.ts, src/routes/bookings/new/+page.svelte</li> <li>verify: browser</li> <li>acceptance:<ul> <li>a read booking number that matches no open reference shows as 'Add Booking No. <no>' in the reference picker</li> <li>tapping it opens the booking form prefilled with that number and the read's count/type/mill/bags</li> <li>saving returns to the yarn-in with the new booking selected</li> <li>nothing is created without the tap</li> </ul> </li> <li>owner: -</li> <li>commits: d1b67cbd815c0d61b2e17e02a645561c01119249</li> <li>live: d1b67cbd815c0d61b2e17e02a645561c01119249</li> <li>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: the chip opens /bookings/new with traderBookingNo=<read no>&count=&type=&mill=&bags=&returnTo=<this form>, each validated on the booking load by the form's own rules (junk lands empty, never echoed); the read's count+type+mill resolve the yarn-master row by the same parts rule C331 uses, the mill fills Mill/ticket, the bags fill Bags, and an unresolved yarn rides the Add-yarn dialog prefilled (never created); returnTo is safeReturnTo (paths on this app only) and the booking's save redirects to it with ?bookingId=<id>&created=<id>, so the yarn-in selects the new booking; the chip keeps C315's own guard (a read number that matched nothing open, no reference picked yet) and writes nothing by itself.</li> </ul> <h3>C336</h3> <ul> <li>status: done</li> <li>priority: P0</li> <li>target: src/lib/server/intake.ts, src/lib/server/captureOcr.ts, src/lib/gatepassOcr.ts, src/routes/gatepasses/new/+page.svelte</li> <li>verify: browser</li> <li>acceptance:<ul> <li>a gatepass read carries docIssuer (the letterhead, e.g. Goenka Syndicate Private Limited), not the buyer</li> <li>it shows on the read card and rides the draft/prefill</li> <li>two photos from different traders get different issuers</li> </ul> </li> <li>owner: -</li> <li>commits: 2365c23217926d70f6daa338d7f0eb846fe9961d</li> <li>live: 2365c23217926d70f6daa338d7f0eb846fe9961d</li> <li>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: docIssuer = the first firm-suffixed, non-address line in the top block before any label; validated as letters/digits/&.,'()- 3-80 chars on the reader and the form carry, blank when absent; the model only fills a gap</li> </ul> <h3>C337</h3> <ul> <li>status: done</li> <li>priority: P0</li> <li>target: src/lib/server/docFormatMemory.ts, src/lib/server/schema-foundation.ts, src/lib/server/captureOcr.ts, src/routes/gatepasses/new/+page.server.ts</li> <li>verify: script</li> <li>acceptance:<ul> <li>a field the user supplies after a missed read is stored against the issuer as an anchor (label text, or a position hint when unlabelled) plus the value's shape</li> <li>a later gatepass from the same issuer fills that field from the learned anchor before the model's answer is merged, with no manual step</li> <li>nothing is learned without a user save</li> <li>the anchor is offered, never written into a committed document by itself</li> </ul> </li> <li>owner: -</li> <li>commits: 9c57386e3f801a6743a9acf052c3f18f347716e0</li> <li>live: 9c57386e3f801a6743a9acf052c3f18f347716e0</li> <li>notes: - | assumed: learned layout keyed on the letterhead exactly as read (no fuzzy issuer match); learns only bookingNo/partnerGpNo/ticket; pre-fills only a gatepass read; never overrides a value the reader already produced; written only by the gatepass create save | pre-checked: row-watch: read the row and its target before starting</li> </ul> <h3>C338</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: -</li> <li>verify: -</li> <li>acceptance: (none recorded — lane must write observable checks first)</li> <li>owner: -</li> <li>commits: 21144de5492b5b158fa5d70a84acb573eaaeca70</li> <li>live: 21144de5492b5b158fa5d70a84acb573eaaeca70</li> <li>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: the learned layout is spoken to the reader as a text-only follow-up call over the transcript the first read already produced (no image re-sent, no extra cost on a first read of a new issuer), and the read card names the issuer + its known fields whenever that issuer has learned rows</li> </ul> <h3>C339</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: scripts/row-watch.sh, scripts/queue-next.ts</li> <li>verify: script</li> <li>acceptance:<ul> <li>two row sessions run at once and never on rows whose target files overlap</li> <li>builds stay serial (heavy.sh)</li> <li>rows/hour measured before and after from screenshots/row-watch.log</li> <li>a row that dies leaves no claim and the second worker picks the next non-overlapping row</li> </ul> </li> <li>owner: -</li> <li>commits: d7b4d4ce285260a1d21936fc70aaf7cdc10969d3</li> <li>live: d7b4d4ce285260a1d21936fc70aaf7cdc10969d3</li> <li>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: a docs-only target is never a conflict (the batch planner's rule since 2026-10-01), two hot files are exclusive, and the two lanes stay in this one checkout (no worktrees) with integration and board writes serialised on .row-integrate.lock / .row-board.lock</li> </ul> <h3>C340</h3> <ul> <li>status: done</li> <li>priority: P2</li> <li>target: scripts/row-watch.sh</li> <li>verify: script</li> <li>acceptance:<ul> <li>the row prompt carries the row text, acceptance and target files</li> <li>the session only reads STATUS/BUILD-LOG/PLANNING when the row changes flow or a decision</li> <li>turn count per row drops and rows/hour rises, measured from the log</li> </ul> </li> <li>owner: -</li> <li>commits: ea465de0e63aa836667660fb4ea7e3ef26b667e0</li> <li>live: ea465de0e63aa836667660fb4ea7e3ef26b667e0</li> <li>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: the row brief is parsed inside row-watch.sh (QUEUE.md block + CORRECTIONS.md text) rather than adding a --show mode to queue-next.ts — the row's target is the watcher and the lane guard keys on target files, so the whole change stays in one file</li> </ul> <h3>C341</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: -</li> <li>verify: -</li> <li>acceptance: (none recorded — lane must write observable checks first)</li> <li>owner: -</li> <li>commits: 9303e83252809be8316af3a31826b023ed83b024</li> <li>live: 9303e83252809be8316af3a31826b023ed83b024</li> <li>notes: - | pre-checked: row-watch: read the row and its target before starting</li> </ul> <h3>C342</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: src/lib/server/schema-foundation.ts</li> <li>verify: -</li> <li>acceptance: (none recorded — lane must write observable checks first)</li> <li>owner: -</li> <li>commits: fac2d8be30f6c7fa6ad3d535a1d423a5520e69ae</li> <li>live: fac2d8be30f6c7fa6ad3d535a1d423a5520e69ae</li> <li>notes: - | pre-checked: row-watch: read the row and its target before starting</li> </ul> <h3>C343</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: src/lib/server/costing</li> <li>verify: script</li> <li>acceptance:<ul> <li>bun run src/lib/server/costing/costing.test.ts exits 0 with every case passing (WAC in and out, key and track separation, release at locked cost, shortfall re-price, salvage roll-up, zero-cost isolation, PO P and L, variance, leg freeze and accrual, substitution quantity-only)</li> <li>the costing modules import no db, no drizzle and no route, so every export is pure</li> <li>bunx tsc --noEmit adds no diagnostic in src/lib/server/costing/</li> </ul> </li> <li>owner: -</li> <li>commits: 68af02a05e4dfb586cb18d1e392d0fd9175d12e7</li> <li>live: 68af02a05e4dfb586cb18d1e392d0fd9175d12e7</li> <li>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: tests live beside the engine (src/lib/server/costing/costing.test.ts) and run with bun run src/lib/server/costing/costing.test.ts because bun test cannot scan a missing ./tests root; WAC counts inward entries only and excludes zero-cost/salvage entries from the average (their quantity stays), salvage is always zero fabric value and its proceeds are SO revenue; money is never rounded inside the engine, only at presentation</li> </ul> <h3>C344</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: src/routes/lots</li> <li>verify: script</li> <li>acceptance:<ul> <li>bun /tmp/opencode/c344-proof.ts exits 0 against a scratch copy of data.db with every case passing (pool in at the booking rate, key count+type+grade, free vs apportioned, issue out at the WAC of its moment, yarn cost leg at that same WAC, idempotent per document, a later purchase moves only future issues, zero-cost kg kept out of the average, no-order issue writes nothing, grade rule blank|A+|A|B|C)</li> <li>yarn master saves grade through the shared yarnGradeError rule and the yarn form refuses a value outside it</li> <li>bunx tsc --noEmit adds no diagnostic in the touched files</li> </ul> </li> <li>owner: -</li> <li>commits: 821d442821d551af2859b819b52480a459fad1c4</li> <li>live: 821d442821d551af2859b819b52480a459fad1c4</li> <li>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: the receipt's ₹/kg is the gatepass booking's ratePerKg (no new field, no price invented); a booking-less receipt writes a zero-cost pool entry (kg kept, average untouched); the pool key is the yarn master's count+type+grade read at receipt time, an ungraded yarn is its own pool; free = pool in with no order, apportioned-to-PO = pool in carrying the PO the receipt was marked for; a weft issue writes the pool out + yarn cost leg only when the loom's beam resolves a production order (an internal move writes no cost); grade is blank or A+/A/B/C folded to upper case on both surfaces</li> </ul> <h3>C345</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: src/routes/orders/new</li> <li>verify: -</li> <li>acceptance: (none recorded — lane must write observable checks first)</li> <li>owner: -</li> <li>commits: a475aa292da8c7112d0b7ac83c4ee4631fa3f5a3</li> <li>live: a475aa292da8c7112d0b7ac83c4ee4631fa3f5a3</li> <li>notes: - | pre-checked: row-watch: read the row and its target before starting</li> </ul> <h3>C346</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: src/routes/orders/new</li> <li>verify: -</li> <li>acceptance: (none recorded — lane must write observable checks first)</li> <li>owner: -</li> <li>commits: 55bffd7dc8d14dfd727e10c005fe560c14593622</li> <li>live: 55bffd7dc8d14dfd727e10c005fe560c14593622</li> <li>notes: - | pre-checked: row-watch: read the row and its target before starting</li> </ul> <h3>C347</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: src/routes/orders/[id]</li> <li>verify: -</li> <li>acceptance: (none recorded — lane must write observable checks first)</li> <li>owner: -</li> <li>commits: fc9793aed09368b1c4237275742df58ee2cd1585</li> <li>live: fc9793aed09368b1c4237275742df58ee2cd1585</li> <li>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: a cut releases the newest hold first at its locked cost; a rise, a quality change and a pick change leave the gap for the one rebalance action (release in the amend save, reassign only there); cancelling releases every hold at locked cost and the production orders survive unassigned; a PO held by a live sale or already complete refuses cancellation</li> </ul> <h3>C348</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: src/routes/checking</li> <li>verify: -</li> <li>acceptance:<ul> <li>checking accepts grades A/B/C/R/X and refuses anything else on both surfaces</li> <li>R grades to FG (sellable) and X to reject</li> <li>a graded X roll leaves one pool_entry track=salvage at unit cost 0, which never moves the produced WAC</li> <li>a grade X roll may only name a damaged sale order (grade error on a normal one)</li> <li>salvage P&L rolls into the parent SO, else stays in the damaged SO</li> <li>bun run src/lib/server/rollGrade.test.ts green</li> </ul> </li> <li>owner: -</li> <li>commits: e67bcbf46402f6c72da4db6e84151b14c27ffcd5</li> <li>live: e67bcbf46402f6c72da4db6e84151b14c27ffcd5</li> <li>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: X keeps status reject (the FG dispatch gate refuses it, as a non-usable roll should); the damaged-SO gate is enforced where a roll names its order on the checking form — mark the order a damaged lot or leave the order blank | assumed: the checking hook writes only the zero-cost salvage pool entry — no produced-track out, because the produced pool is keyed by quality+pick and metres cannot be attributed back to one roll; the salvage track cannot move any average (pool.ts isZeroCost) | assumed: salvage P&L roll-up is pure arithmetic in costing/pnl (salvageOwner/salvageFor): a damaged SO with a parent rolls its proceeds into the parent, else it keeps them in its own P&L; no new screen</li> </ul> <h3>C349</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: src/routes/fabric-purchase</li> <li>verify: -</li> <li>acceptance:<ul> <li>a purchase writes one PURCHASE fabric_purchase order, one purchase cost leg at the landed ₹/m and one purchased pool entry</li> <li>the purchased WAC is keyed quality+pick and the produced WAC never moves</li> <li>assignment to a live sale order writes one market apportionment at the locked cost and over-coverage is refused</li> <li>supplier, quality, pick, mtrs, rate, freight, GST and date each validate on both surfaces</li> <li>bun run src/lib/server/fabricPurchase.test.ts green</li> </ul> </li> <li>owner: -</li> <li>commits: 3b7b9120d72f47cdb1f00e2a2af1245fe93b5ed2</li> <li>live: 3b7b9120d72f47cdb1f00e2a2af1245fe93b5ed2</li> <li>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: GST is input credit (excluded from WAC, kept on the leg as gst_pct) and freight is capitalised; the single cost leg carries the landed ₹/m while order.rate keeps the invoiced ₹/m | assumed: assignment writes the market cost_apportionment only, no purchased-pool out entry — the same rule C346's market source already follows, so nothing has to learn to release it | assumed: no new approval gate: a fabric purchase is recorded approved at entry with the signed-in user; order.type is a new PURCHASE word so no existing PROD/SO reader picks it up | assumed: quality is picked from the design master (qualityKey = design.qualityName), pick editable and validated as a whole number above 0, so a typo cannot open a second purchased pool</li> </ul> <h3>C350</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: src/routes/reports</li> <li>verify: -</li> <li>acceptance: (none recorded — lane must write observable checks first)</li> <li>owner: -</li> <li>commits: f5c8ae7b09b14604c35a95b72f6af8519b83abe3</li> <li>live: f5c8ae7b09b14604c35a95b72f6af8519b83abe3</li> <li>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: stock lines read straight from pool_entry (C343 balance) so every column reconciles: yarn keyed count+type+grade with own/party and in-house/sizer/weaver/transit split by the lot each entry names, fabric keyed quality+pick (+grade where a hold or roll names one) on the produced and purchased tracks at that track's own WAC | assumed: pick/grade/track filters are GET params on the existing /reports screen with their own rules on both surfaces: pick whole > 0 (input type=number min=1 step=1 max=9999; server /^[0-9]+$/ and > 0), grade one of A+/A/B/C case-folded, track yarn | produced | purchased; junk is dropped, never queried | assumed: no new screen, no migration, no write path: reports.ts gains the pure aggregators plus two table builders, /reports gains the filter row and the second stock table, /lots' Pool column gains wip (an out entry to a live order), the dump edge gains the fabricstock slug</li> </ul> <h3>C351</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: src/routes/gatepasses/new</li> <li>verify: -</li> <li>acceptance:<ul> <li>a DIRECT delivery naming a Weaver-category party saves and its lot's location is weaver</li> <li>a DIRECT naming a Sizing or Godown party still lands at sizer and our premises stays in-house</li> <li>a weaver location with a non-weaver party is a visible field error on the POST (server) and un-pickable in the picker (client)</li> <li>bun run src/lib/server/directDelivery.test.ts green</li> </ul> </li> <li>owner: -</li> <li>commits: 9ea4bd27c8e4b0d482e2755ed7b30ff66ae59f22</li> <li>live: 9ea4bd27c8e4b0d482e2755ed7b30ff66ae59f22</li> <li>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: a weaver location accepts only a Weaver-category party on both surfaces (a hand-forged sizer/weaver mismatch is a visible field error); the weaver rows are additive to the DIRECT picker only (yarn-in pickup places and the beams' sizer list unchanged); the receipt's own ₹/kg still stands, so a direct delivery to a weaver changes no WAC</li> </ul> <h3>C352</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: src/routes/bookings/new</li> <li>verify: -</li> <li>acceptance:<ul> <li>a booking saves freight and purchase brokerage (optional rupees >= 0, 2 decimals max) and they never enter the booking's GST amounts</li> <li>the inward receipt shows booked kg, billed vs arrived (short absorbed) and the landed Rs/kg, recomputed as the weighed kg is typed</li> <li>the yarn pool's in entry lands at (basic amount + freight + brokerage) / arrived kg and issueYarnToOrder freezes the PO yarn leg at that landed WAC</li> <li>a full receipt with no add-ons still lands at the booking's own rate</li> <li>bun run src/lib/server/landedCost.test.ts green</li> </ul> </li> <li>owner: -</li> <li>commits: -</li> <li>live: a77641f2e2cb3e87da086b07a708fac24d971e94</li> <li>notes: shipped in 7149bbe6, live-check 83/83; blocked only by the /reports 500 (costBasis missing from the load), fixed and proved</li> </ul> <h3>C353</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: src/lib/server/costing</li> <li>verify: -</li> <li>acceptance:<ul> <li>warping books at Rs per kg of warp and sizing at Rs per kg of warp sent, with a bill's billing kg reversed from the received count and carried as the quantity variance</li> <li>weaving books picks/m x Rs/pick /100 on good mtrs, the rate booked per order (no master) with an internal rate for in-house looms</li> <li>checking books Rs per metre actually checked including X, at the quality's rate (yearly default, editable per leg), and mending never books</li> <li>packing and loading book a direct rupee amount</li> <li>every leg field is validated on the server action and on the form (positive quantity/rate/picks/good mtrs with 2 decimals, a count pair 0-400, the internal rate when in-house)</li> <li>bun run src/lib/server/costing/costing.test.ts green (19/19) and bookCostLeg proved on a data.db copy (27/27)</li> </ul> </li> <li>owner: -</li> <li>commits: -</li> <li>live: a77641f2e2cb3e87da086b07a708fac24d971e94</li> <li>notes: shipped in 7149bbe6, live-check 83/83; same /reports 500 block, fixed</li> </ul> <h3>C354</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: src/routes/bills</li> <li>verify: -</li> <li>acceptance:<ul> <li>bun run src/lib/server/bills.test.ts green 6/6 (allocation by quantity, the qty/rate split, the restatement cascade, the close rules)</li> <li>a bill allocates over the open provisional legs of its kind and every line's qty + rate variance adds back to its amount variance</li> <li>a settled leg becomes actual with bill no/date/party and GST and the order unit cost + produced pool entry + every sale-order hold are restated</li> <li>a sale order P&L stays provisional until the last bill auto-closes it and a manual close without a reason is refused</li> <li>a repeated bill number from the same vendor and a never-billed kind are refused and every bill field validates on both surfaces</li> <li>bunx tsc --noEmit adds no diagnostic in the touched files</li> </ul> </li> <li>owner: -</li> <li>commits: -</li> <li>live: a77641f2e2cb3e87da086b07a708fac24d971e94</li> <li>notes: shipped in 7149bbe6, live-check 83/83; same /reports 500 block, fixed</li> </ul> <h3>C355</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: src/routes/orders/[id]</li> <li>verify: -</li> <li>acceptance:<ul> <li>a sale order's P&L reads on the DELIVERED metres: revenue = delivered m x rate, cost = those metres at the locked unit cost, margin = what is left</li> <li>every line is exactly its percentage of the selling price and the lines add back to price - cost</li> <li>overhead defaults to 1% company-wide and is editable per sale as an append-only so:pnl:lines save (never an edit)</li> <li>the quote engine prices the same gross-up (price = cost x 100/(100 - sum p)) with the 1% overhead replacing the 6.5% other expenses, and no stored design value pulls the old 6.5 back</li> <li>a three-decimal share, shares reaching 100% and a non-sale order are refused with the field named on both surfaces</li> <li>bun run src/lib/server/costing/costing.test.ts 22/22 PASS incl. the split, gross-up and quote-parity cases</li> </ul> </li> <li>owner: -</li> <li>commits: -</li> <li>live: 9ea4bd27c8e4b0d482e2755ed7b30ff66ae59f22</li> <li>notes: already shipped in 7149bbe6, live 83/83 — re-closed after answering the stale watcher question</li> </ul> <h3>C356</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: src/routes/expenses</li> <li>verify: -</li> <li>acceptance: (none recorded — lane must write observable checks first)</li> <li>owner: -</li> <li>commits: a77641f2e2cb3e87da086b07a708fac24d971e94</li> <li>live: a77641f2e2cb3e87da086b07a708fac24d971e94</li> <li>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: The level is a choice on the entry form with the sale order (direct to P&L) as the default; the producing-order leg form stops offering 'exceptional' so every exceptional charge is entered here with its paper and reason; amount is rupees to 2 decimals under ₹1 crore; a booked charge is 'actual' because its document is in hand; a sale-order charge shows as one direct line in that sale's P&L card and never in a metre cost.</li> </ul> <h3>C357</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: src/routes/lots</li> <li>verify: -</li> <li>acceptance: (none recorded — lane must write observable checks first)</li> <li>owner: -</li> <li>commits: d91f165d9b03735f64c1d269a461173a2b87da50</li> <li>live: d91f165d9b03735f64c1d269a461173a2b87da50</li> <li>notes: - | assumed: one opening line per pool key (a key already entered refuses a second, import is all-or-nothing so a re-run never doubles stock); a blank value books zero-cost stock exactly like an unpriced receipt; the entry screen is a plain daisyUI card + ReviewSheet mirroring C349's /fabric-purchase (a one-time office entry with an optional paste import), not the FocusEntry wizard; no schema change — pool_entry already carries source=opening | assumed: owner-approved: opening stock entered once per pool key with values, blank = zero-cost, no schema change | pre-checked: row-watch: read the row and its target before starting | assumed: a yarn type is the master's spelling: the form's code and every pasted line resolve to it case-insensitively ('ccw' -> 'CCW') and an unknown type is refused by line, so one pool key is one bucket and the opening stock always feeds the WAC it belongs to; the fabric quality keeps the same rule it already had</li> </ul> <h3>C358</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: src/routes/orders/[id]</li> <li>verify: -</li> <li>acceptance: (none recorded — lane must write observable checks first)</li> <li>owner: -</li> <li>commits: 8bacb02e106a82727d32ca9aa07bccdc2642b74a</li> <li>live: 8bacb02e106a82727d32ca9aa07bccdc2642b74a</li> <li>notes: - | assumed: delivered mtrs = this order's dispatch slips in loaded | delivered (dispatch's own auto-delivery measure); fulfilled = the existing delivered status; blank tolerance = 0 (a 1 m miss with no stated tolerance is blocked and names the amendment); a shortfall releases the remainder through C347's release plan at each hold's locked cost; an excess is apportioned only from free stock (produced/market pool) or an existing open production order at that source's current cost — new_po refused; reversal rides C152's order_change rail as fulfil-reverse: owner/admin applies at once, anyone else leaves a pending /approvals item, and it returns the status only (released holds and the extra apportionment stay written, append-only); note optional <=280, a coverage line positive 2dp within that source's free metres and the lines exactly equal to the excess, reversal reason required <=280 — both surfaces | assumed: owner-approved: fulfil only inside tolerance, else amend first; excess apportioned from free stock or an existing PO; reversal needs owner approval | pre-checked: row-watch: read the row and its target before starting | assumed: re-pass: appendAmendment's kind union widened to admit 'ops-complete' (the value C154's completion already persists in that text column) instead of casting at the call site — type-only widening, no write/reader/schema change, reversible; the fulfilment flow is unchanged</li> </ul> <h3>C359</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: <a href="https://trading.tynolabs.com/gatepasses/new?kind=YARN_IN">https://trading.tynolabs.com/gatepasses/new?kind=YARN_IN</a></li> <li>verify: -</li> <li>acceptance: (none recorded — lane must write observable checks first)</li> <li>owner: -</li> <li>commits: 8defbdbd0bbf6cc2499d0a3eae47c0fa50390312</li> <li>live: 8defbdbd0bbf6cc2499d0a3eae47c0fa50390312</li> <li>notes: - | assumed: a printed godown address is a location, not a movement: kind is carried only on an explicit signal (booking no → YARN_IN; exact godown/premises/sizer or the words 'direct delivery' → DIRECT), otherwise the form keeps its YARN_OUT default; the address never fills destPlace | assumed: owner-approved: DIRECT only on an explicit signal, a read booking no wins as YARN_IN, a printed godown address is a location not an intent | pre-checked: row-watch: read the row and its target before starting</li> </ul> <h3>C360</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: src/routes/gatepasses/new/+page.svelte, src/lib/components/focus/FocusEntry.svelte, src/routes/masters/+page.svelte, src/routes/bookings/new/+page.svelte</li> <li>verify: browser</li> <li>acceptance:<ul> <li>a create chip opens the child form in a modal over the gatepass form, whose state is untouched while it is open</li> <li>after saving, the modal closes and the new entry is selected in the field that opened it</li> <li>closing the modal returns to the form exactly where it was</li> </ul> </li> <li>owner: -</li> <li>commits: 09ca2497b347251c60b16d46d3ea89659a553de0</li> <li>live: 09ca2497b347251c60b16d46d3ea89659a553de0</li> <li>notes: - | assumed: a same-origin iframe of the existing child route, one postMessage back on save; the parent never navigates | assumed: iframe modal + postMessage; a created booking row shows its number and the read's yarn with '—' remainders | pre-checked: row-watch: read the row and its target before starting | assumed: the location master lands on the row that asked it: field=location from the pickup row's own create link is applied to destPlace on every kind except DIRECT; the drain's build blocker (openingStock -> server/costing/pool) is fixed in this pass by moving the pool-key builders to #lib/poolKey.ts</li> </ul> <h3>C361</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: -</li> <li>verify: -</li> <li>acceptance: (none recorded — lane must write observable checks first)</li> <li>owner: -</li> <li>commits: 97a1dfb9a3b465ff9fdb50bc1fbc1fbf336f5d40</li> <li>live: 97a1dfb9a3b465ff9fdb50bc1fbc1fbf336f5d40</li> <li>notes: - | pre-checked: row-watch: read the row and its target before starting</li> </ul> <h3>C362</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: -</li> <li>verify: -</li> <li>acceptance: (none recorded — lane must write observable checks first)</li> <li>owner: -</li> <li>commits: 1e559f2c918a5ac995cb4552213b06bac7b49d91</li> <li>live: 1e559f2c918a5ac995cb4552213b06bac7b49d91</li> <li>notes: - | pre-checked: row-watch: read the row and its target before starting</li> </ul> <h3>C363</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: <a href="https://trading.tynolabs.com/gatepasses/new?kind=YARN_IN">https://trading.tynolabs.com/gatepasses/new?kind=YARN_IN</a></li> <li>verify: -</li> <li>acceptance: (none recorded — lane must write observable checks first)</li> <li>owner: -</li> <li>commits: 1db8bd0ab13c212ff36636e1209cab4246aeaef9</li> <li>live: 1db8bd0ab13c212ff36636e1209cab4246aeaef9</li> <li>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: zoom stays capped at 400% (existing VERIFY_ZOOM_MAX); a photo wider than the pane anchors left and pans inside the overflow-auto box</li> </ul> <h3>C364</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: src/lib/server/costing/pool.ts, src/lib/server/lots.ts, src/lib/server/reports.ts</li> <li>verify: -</li> <li>acceptance:<ul> <li>bun test the two-ledger cases green (free WAC unchanged by an earmark</li> <li>the PO rate is the booking landed rate)</li> <li>/reports shows free and earmarked kg as separate columns</li> <li>an earmark above the received kg is refused on the form and in the action</li> </ul> </li> <li>owner: -</li> <li>commits: f5290aa173dcba2b17d011525d1c4f68724c7b60</li> <li>live: f5290aa173dcba2b17d011525d1c4f68724c7b60</li> <li>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: Earmark = the PO tag on a yarn pool entry (booking orderSplit first, else the receipt's order-tagged boxes, else the carried order), split pro rata to the received kg; free pool = untagged entries alone; an issue prices its own earmark first then free stock at WAC, one out entry per part; the report keeps free and earmarked kg apart with WIP beside.</li> </ul> <h3>C365</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: src/lib/server/lots.ts, src/routes/bookings/new/+page.server.ts, src/routes/orders/[id]/+page.server.ts</li> <li>verify: -</li> <li>acceptance:<ul> <li>issuing yarn with no earmark leaves the PO yarn cost at 0 (test)</li> <li>a 200 kg earmark at Rs210 writes a Rs42000 leg (test)</li> <li>the PO record lists the bucket rows with their source</li> </ul> </li> <li>owner: -</li> <li>commits: e7475c35added441a4103950eb2f59200e75c8f9</li> <li>live: e7475c35added441a4103950eb2f59200e75c8f9</li> <li>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: The Against split's kg per PO is derived from bags x bagWt; only a production order (role po / PROD) takes the yarn leg (SO/JW keep their own cost basis); a free-stock draw writes the leg only, no pool move; the landed rate is read from the booking, never typed.</li> </ul> <h3>C366</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: src/lib/server/schema-foundation.ts, src/lib/server/poLifecycle.ts, src/routes/orders/[id]/+page.svelte</li> <li>verify: -</li> <li>acceptance: (none recorded — lane must write observable checks first)</li> <li>owner: -</li> <li>commits: bcc1e198b85a8f4a9a48a5bbfe4cd0d4990144a8</li> <li>live: bcc1e198b85a8f4a9a48a5bbfe4cd0d4990144a8</li> <li>notes: - | pre-checked: read poLifecycle.ts stampProductionOrder (one weaving leg from order.picks and jobRate) and the order table (single picks/jobRate); a segment table plus a per-segment leg is the smallest shape | assumed: the order's own picks/jobRate/planned mtrs are the default first segment (synthetic, seq 1); stored segments append at seq 2+, each writing one provisional weaving leg at pick×₹/pick÷100 over its own planned mtrs; in-house uses the segment's internal ₹/pick with no bill party; segments lock once any fabric_in row exists for the PO; tippan picker offers the PO's recent tippans</li> </ul> <h3>C367</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: src/routes/fabric-in/+page.server.ts, src/routes/checking/+page.server.ts, src/lib/server/poLifecycle.ts</li> <li>verify: -</li> <li>acceptance:<ul> <li>two segments at different picks give two different Rs/m on the same PO (test)</li> <li>a lot with 10 percent X raises its sellable Rs/m by exactly the X-borne costs (test)</li> <li>the produced pool holds one row per lot with its own unit cost</li> </ul> </li> <li>owner: -</li> <li>commits: ba1af6951badec1f33454a0f45df4742b4e6a386</li> <li>live: ba1af6951badec1f33454a0f45df4742b4e6a386</li> <li>notes: - | pre-checked: row-watch: read the row and its target before starting</li> </ul> <h3>C368</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: src/routes/checking/+page.server.ts, src/lib/server/costing/pnl.ts</li> <li>verify: -</li> <li>acceptance:<ul> <li>1000 m at Rs80000 with 50 X gives Rs84.21/m for A and B alike and 0 for X (test)</li> <li>the checking leg counts the X mtrs</li> <li>a lot with zero sellable mtrs is refused</li> </ul> </li> <li>owner: -</li> <li>commits: 90e00be34a41729c9285242ef4f0c74d3ca66f72</li> <li>live: 90e00be34a41729c9285242ef4f0c74d3ca66f72</li> <li>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: Grade-blind ₹/m is one engine rule (costing/pnl: isSellableGrade, lotUnitCost, gradeUnitCost, lotSellableError) used by lotCost and the completion gate; the checking action records the lot's checked mtrs (graded rolls, X included) on the roll:checked event; a fabric-in lot roll grades with no beam; X still needs a damaged sale order (C348, unchanged).</li> </ul> <h3>C369</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: src/routes/beams/[id]/+page.server.ts, src/lib/server/schema-foundation.ts</li> <li>verify: -</li> <li>acceptance:<ul> <li>carried Rs30000 and market Rs27500 leaves a Rs2500 loss on the cancelled PO and Rs27500 on the receiving PO (test)</li> <li>the transfer form shows the three hints and accepts typed values</li> <li>a partial beam splits by kg (test)</li> </ul> </li> <li>owner: -</li> <li>commits: 89654a08c0b5f4dd65e6c3524d0dba91e700964b</li> <li>live: 89654a08c0b5f4dd65e6c3524d0dba91e700964b</li> <li>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: PO-to-PO only; sizing gate = the from-PO sizing cost leg; variance is a signed exceptional leg on the transferring PO; a partial leaves the beam and raises no BEAM_IN; carried = beam kg x the from-PO yarn/warping/sizing rate</li> </ul> <h3>C370</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: src/lib/server/poLifecycle.ts, src/routes/orders/[id]/+page.svelte</li> <li>verify: -</li> <li>acceptance:<ul> <li>a PO from a quote at Rs12/m planned and Rs13.20/m actual shows a +10 percent drift (test)</li> <li>a stock PO shows no budget row</li> <li>a quote cannot be revised after the SO exists (refused)</li> </ul> </li> <li>owner: -</li> <li>commits: 794e4e81c514611280cd31d6c89a293973b0c23d</li> <li>live: 794e4e81c514611280cd31d6c89a293973b0c23d</li> <li>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: Budget = quote planned ₹/m per leg (yarn = warp + weft, warping, sizing, weaving) x the PO's own planned mtrs, snapshotted into the existing po:planned event payload at PO creation (no new table); a stock PO and an SO with no quote carry none; drift per leg = costing/pnl variance() over the PO's booked po-level legs; the quote freeze is enforced by refusing a second live SO on the same quote (no in-place quote edit exists).</li> </ul> <h3>C371</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: src/lib/server/soCoverage.ts, src/lib/server/costing/pnl.ts</li> <li>verify: -</li> <li>acceptance:<ul> <li>SO at Rs8.75/pick apportioned to PO-1, fabric delivered from a 72-pick lot, gives 8.75 x 72 / 100 per m and not PO-2 rate (test)</li> <li>the delivering PO shows the variance</li> <li>a lot without a pick cannot be apportioned</li> </ul> </li> <li>owner: -</li> <li>commits: 68e6147b941b6321d1fc067954e0eb1c5c131ace</li> <li>live: 68e6147b941b6321d1fc067954e0eb1c5c131ace</li> <li>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: Committed leg rates are read live from the delivering PO's cost legs (+ its ₹/pick), keyed to the sale's apportionment line, no schema change: the line carries them in its reading, so a later bill is the PO's variance and never a re-price of the locked sale. The delivered pick is the fabric-in lots' pick weighted by metres. Only pool/market lots are refused without a pick (a PO line's pick arrives with its lot).</li> </ul> <h3>C372</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: src/lib/server/poLifecycle.ts</li> <li>verify: -</li> <li>acceptance:<ul> <li>a PO holding 200 kg at Rs210 cancelled puts 200 kg at Rs210 into free stock and raises the pool value by Rs42000 (test)</li> <li>a beam transfer variance posts to the cancelled PO (test)</li> </ul> </li> <li>owner: -</li> <li>commits: 4dfba036d04122377d3257a061fe638925e77f5d</li> <li>live: 4dfba036d04122377d3257a061fe638925e77f5d</li> <li>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: Cancelling a PO writes one yarn release pair (out of the order's earmark, in to free stock) both valued at qty x the carried unit cost, so the free pool value rises by exactly the release value; produced fabric is already untagged and stays in the free pool at its lot cost; no cost leg is added, reversed or edited (append-only), a provisional sizing/weaving commitment is not charged, and conversionAccrued reports only the actual non-yarn legs already posted (a beam transfer variance stays on the cancelled PO).</li> </ul> <h3>C373</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: src/lib/server/bills.ts, src/routes/bills/+page.server.ts</li> <li>verify: -</li> <li>acceptance:<ul> <li>a Rs50000 sizing bill split 60/40 across two POs writes two actual legs (test)</li> <li>an unallocated bill is refused by the action (test)</li> <li>the form shows the open quantity and the remainder</li> </ul> </li> <li>owner: -</li> <li>commits: 9bef6eadb871590ba24fb9920af243f25b992d42</li> <li>live: 9bef6eadb871590ba24fb9920af243f25b992d42</li> <li>notes: - | assumed: Every bill is apportioned by hand at entry: a share is a positive 2-decimal amount per open committed leg, no order listed twice, a share capped at that leg's open committed amount (an over-commitment is a supplementary leg first), and the shares must add back to the bill exactly; the form suggests by open committed quantity (tap to fill) and shows each order's open quantity, its committed Rs and the live remainder, but a bill with no allocation cannot be saved on any entry path (form or paste). | pre-checked: row-watch: read the row and its target before starting | assumed: the write path is proved against a temp libSQL db replayed from drizzle/ (the legacy unquoted REFERENCES order( in 0016 repaired on replay) through the real recordBill: no allocation refused with no leg written, then the 60/40 Rs50000 bill writes two actual legs of Rs30000 and Rs���������������������������������������</li> </ul> <h3>C374</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: src/lib/server/schema-foundation.ts, src/routes/quote/new/+page.server.ts</li> <li>verify: -</li> <li>acceptance:<ul> <li>a quote saved with 1 percent brokerage, pass-on 0.5 and freight excluded shows all three on the SO read-only</li> <li>a percentage above 100 is refused on form and action</li> <li>freight default is excluded and buyer-borne</li> </ul> </li> <li>owner: -</li> <li>commits: e254bd25, 44fe59c6129ede97ea7207f29d6b635754ceb79a</li> <li>live: 79bcd063edab25c8e219793fab45d3091eea0e40</li> <li>notes: - | assumed: delivery-term enum = ex-mill | fob | cif | ddp; recovery enum = on-top (excluded, buyer bears — the default) | in-rate; both percentages 0-100 with blank = none, refused on the quote popup form and on the create action; only a quote-linked SO shows the four read-only and takes them from the quote, so a direct/job-work SO keeps its existing editable brokerage; the re-quote change list does not diff the four new terms this row | pre-checked: row-watch: read the row and its target before starting</li> </ul> <h3>C375</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: src/routes/orders/new/+page.server.ts, src/routes/orders/new/orderLogic.ts</li> <li>verify: -</li> <li>acceptance:<ul> <li>saving an SO with no quote is refused with a field error</li> <li>the same quote cannot produce a second SO</li> <li>a changed rate is stored on the SO while the quote keeps its own</li> <li>no approval event is written for an SO</li> </ul> </li> <li>owner: -</li> <li>commits: e254bd254de10ce50e82102c4b6d3b9cfaf66888</li> <li>live: e254bd254de10ce50e82102c4b6d3b9cfaf66888</li> <li>notes: - | pre-checked: read the create action (quote link optional today, orderNeedsOwnerApproval gates status), quoteRevisionError one-shot check, and the coverage write that keys off approval | assumed: picks prefill from the quote's inputs_json.pick (per inch); a posted picks value still wins | assumed: buyer / quality / broker inherit only when the quote carries them (a fresh-construction quote keeps the posted quality); an unresolvable quote broker_id reads as DIRECT | assumed: the delivery window prefills dueDays only; the start/end dates land with C378 | assumed: the damaged (X) sale is exempt from the compulsory quote (D21) and keeps free entry until C390</li> </ul> <h3>C376</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: src/routes/orders/new/trading/+page.svelte, src/lib/components/orders/OrderEntryForm.svelte</li> <li>verify: -</li> <li>acceptance:<ul> <li>the route renders the quote table when no quote is chosen</li> <li>back clears the choice</li> <li>changing the quote resets the four sales fields</li> <li>a searched quote row opens the form prefilled</li> </ul> </li> <li>owner: -</li> <li>commits: 79bcd063edab25c8e219793fab45d3091eea0e40</li> <li>live: 79bcd063edab25c8e219793fab45d3091eea0e40</li> <li>notes: - | pre-checked: read the load that already ships openQuotes with rate/estQty/validity, and the existing quote picker sheet; this turns the picker into the landing state | assumed: the pending-quotes table reads days open from quote.created_at (added additively to the shared order load); Change/Back go back to the table so the next pick re-mounts the form from the new quote (a full reset), while an in-form quote change runs salesResetForQuote on the four sales fields; the reset's tolerance is the D25 5% default held in form state — the sale-tolerance input and its validation stay C378's; capture/draft/lead carries (?new=1, ?draftId=, ?partyId=, ?rate=, ?designId=, ?qty=, ?leadId=) still open the form so no read off a document is dropped</li> </ul> <h3>C377</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: src/lib/components/orders/OrderEntryForm.svelte, src/routes/orders/new/orderLogic.ts</li> <li>verify: -</li> <li>acceptance:<ul> <li>the form opens on quantity with the keyboard up and Next moves focus without closing it</li> <li>the quote strip shows the rate on every step</li> <li>no 14-step or hidden-section markup remains for the SO</li> <li>label width stays under half the row</li> </ul> </li> <li>owner: -</li> <li>commits: a6be19429dcca80d811aa9148bcce3de4685347e</li> <li>live: a6be19429dcca80d811aa9148bcce3de4685347e</li> <li>notes: - | pre-checked: row-watch: read the row and its target before starting</li> </ul> <h3>C378</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: src/lib/server/schema-foundation.ts, src/routes/orders/new/orderLogic.ts</li> <li>verify: -</li> <li>acceptance:<ul> <li>an SO saved with 7 percent tolerance stores 7 and 30 is refused</li> <li>an end before start is refused</li> <li>the record shows both dates instead of day counts</li> <li>the form no longer asks due days or sales promise</li> </ul> </li> <li>owner: -</li> <li>commits: 78b7b3e2c817736016ab4dd593eed094beac580c</li> <li>live: 78b7b3e2c817736016ab4dd593eed094beac580c</li> <li>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: tol_pct reuses the existing order.tolerance_pct column (C379) instead of a duplicate column; the two dates are additive nullable columns, optional at booking (a quote may name no window) but always validated when present; only the SO retires due_days/promised_days — the job-work/outsource production forms keep theirs; the dispatch band's own ceiling moves with the form (0-25%), so a stored 25% is never silently read as 5%.</li> </ul> <h3>C379</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: src/routes/dispatch/+page.server.ts, src/lib/server/soCoverage.ts</li> <li>verify: -</li> <li>acceptance:<ul> <li>a dispatch pushing cumulative metres past the band is refused with an amendment requirement</li> <li>X metres do not move the cumulative figure</li> <li>a dispatch below the hinted lot size saves</li> </ul> </li> <li>owner: -</li> <li>commits: 79bcd063edab25c8e219793fab45d3091eea0e40</li> <li>live: 79bcd063edab25c8e219793fab45d3091eea0e40</li> <li>notes: - | pre-checked: row-watch: read the row and its target before starting</li> </ul> <h3>C380</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: src/lib/server/soCoverage.ts, src/routes/orders/[id]/+page.server.ts</li> <li>verify: -</li> <li>acceptance:<ul> <li>a plan 3 percent under the quantity is accepted</li> <li>an order with no cover is not ready to produce</li> <li>an over-cover dispatch creates a pending item and no release</li> <li>an under-cover completion releases the difference</li> </ul> </li> <li>owner: -</li> <li>commits: 6364cd4f265d8d825cabd03c4e372de973d52708</li> <li>live: 6364cd4f265d8d825cabd03c4e372de973d52708</li> <li>notes: - | pre-checked: row-watch: read the row and its target before starting</li> </ul> <h3>C381</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: src/lib/server/schema-foundation.ts, src/routes/dispatch/+page.server.ts</li> <li>verify: -</li> <li>acceptance:<ul> <li>an SO saves with no consignee</li> <li>dispatch without one is refused</li> <li>a consignee party with category Others can be created and picked</li> <li>the decision shows as decide-at-fulfilment until resolved</li> </ul> </li> <li>owner: -</li> <li>commits: 09e74cedb6b59b0a1026467ca3948ea5e232a8d3</li> <li>live: 09e74cedb6b59b0a1026467ca3948ea5e232a8d3</li> <li>notes: - | assumed: consignee = one nullable party link (Others | Godown | Transport, active); blank = decide at fulfilment; a booked consignee is read-only for planning and dispatch | assumed: the consignee build already landed in 9abcc4cf (committed under the C389 label) — this session re-proves the four acceptance lines instead of re-implementing; a create POST that omits active leaves the party inactive and PartyForm's own toggle stays the decider (A365) | pre-checked: row-watch: read the row and its target before starting</li> </ul> <h3>C382</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: src/lib/server/schema-foundation.ts, src/routes/orders/new/+page.server.ts</li> <li>verify: -</li> <li>acceptance:<ul> <li>a migrated order resolves its broker by id</li> <li>a broker rename no longer orphans past orders</li> <li>an unknown broker is refused on the form and the action</li> </ul> </li> <li>owner: -</li> <li>commits: 8186960a263cbc90cf0b1c80a6476cfb22848058</li> <li>live: 8186960a263cbc90cf0b1c80a6476cfb22848058</li> <li>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: the broker picker posts the master id (name kept as the label and the booking's history), DIRECT stays a sentinel with no link, and the name→id backfill runs from apply-db.sh because drizzle-kit push never replays a migration file</li> </ul> <h3>C383</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: src/routes/orders/new/+page.server.ts, src/routes/orders/[id]/+page.server.ts</li> <li>verify: -</li> <li>acceptance:<ul> <li>an order saved on a 0 percent 30 days slab stores cd_pct 0 and payment_days 30</li> <li>pendingOpsCondition no longer flags it</li> <li>the ops form shows the values prefilled</li> </ul> </li> <li>owner: -</li> <li>commits: 9a1119a2378bea81c19275cc1f1166ff0c45332f</li> <li>live: 9a1119a2378bea81c19275cc1f1166ff0c45332f</li> <li>notes: - | pre-checked: row-watch: read the row and its target before starting</li> </ul> <h3>C384</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: src/routes/orders/new/orderLogic.ts</li> <li>verify: -</li> <li>acceptance:<ul> <li>rate 0 is refused</li> <li>picks 0 and 201 are refused</li> <li>5500 metres is refused and 5000 accepted</li> <li>the same buyer PO number twice is refused</li> <li>the placeholder shows a per-inch example</li> </ul> </li> <li>owner: -</li> <li>commits: 6b6d64492b9c7ad42f77c6ccc37ab93f87e208e6</li> <li>live: 6b6d64492b9c7ad42f77c6ccc37ab93f87e208e6</li> <li>notes: - | assumed: Rate > 0 for every kind and role; picks whole 1–200 per inch; quantity a multiple of 1,000 metres except beams and damaged sales; one buyer PO once per buyer (server-side at save; a cancelled order releases it); picks placeholder e.g. 64 | assumed: picks history written before the per-inch rule (e.g. 4,000) is never offered back as a prefill or a coin — the field stays blank instead; a damaged (X) sale is exempt from the 1,000 m step | pre-checked: row-watch: read the row and its target before starting</li> </ul> <h3>C385</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: src/lib/components/orders/OrderEntryForm.svelte</li> <li>verify: -</li> <li>acceptance:<ul> <li>a simulated failure shows a banner and lands on the offending field with its message</li> <li>the hidden container no longer holds error markup</li> <li>a success still redirects as today</li> </ul> </li> <li>owner: -</li> <li>commits: 8fe5689536dc2e549183fcf1d2cde81a76be6588, 06d1186a8ff2f03336766c453520be2f160c0997</li> <li>live: 06d1186a8ff2f03336766c453520be2f160c0997</li> <li>notes: pre-checked: row-watch: read the row and its target before starting | assumed: no runnable test harness in this checkout (tests/ removed, bunfig root=./tests) - the orderLogic.test.ts fieldErrorJump cases ship with the helper; proof here is bun run check + tsc clean on the touched files, the rendered-failure check waits for the deploy gate</li> </ul> <h3>C386</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: src/lib/server/queue.ts, src/routes/orders/[id]/+page.svelte</li> <li>verify: -</li> <li>acceptance:<ul> <li>an order with sales and cover complete but no planning is ready to produce</li> <li>the planning board lists it with its age</li> <li>the rail shows the three states</li> <li>a role lands on its board after sign-in</li> </ul> </li> <li>owner: -</li> <li>commits: f289ed24ef537f6f79c0258fb1bc618340489151, 91cfa1af6972dbc76ddd3b7bf90e8075084250cf</li> <li>live: f289ed24ef537f6f79c0258fb1bc618340489151</li> <li>notes: - | assumed: the sales board stays the queue's existing reading (SOs still waiting for owner approval; D23 means an ordinary booked SO never sits there), the landing page renders exactly stageSectionsFor(role) from the one pendingBoard query, row limits stay MAX=6 for sales/PPC and 20 for planning, and the Orders list gets no extra planning-pending chip this row (the board already lists it) | pre-checked: row-watch: read the row and its target before starting | assumed: an admin owns every stage like the owner — stageSectionsFor now maps admin to sales,planning,ppc, the same owner-or-admin reading ops.ts and the record's stageRoleOpen already use</li> </ul> <h3>C387</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: src/routes/orders/[id]/+page.svelte, src/routes/orders/[id]/+page.server.ts</li> <li>verify: -</li> <li>acceptance:<ul> <li>an order with no image lets planning attach one</li> <li>the photo stays visible while a field is edited</li> <li>saving the planning stage clears the order from the planning board</li> </ul> </li> <li>owner: -</li> <li>commits: 5300a82ce7ea1159e5ade1f568bbe76d43f2034a</li> <li>live: 5300a82ce7ea1159e5ade1f568bbe76d43f2034a</li> <li>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: planning is complete on the append-only so:planning-complete event (the board is open SOs minus that event), the buyer order image is an order_attachment saved with the existing capture store, and the consignee rides dispatch_city until C381</li> </ul> <h3>C388</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: src/lib/components/orders/OrderEntryForm.svelte</li> <li>verify: -</li> <li>acceptance:<ul> <li>picking a quality with an alias writes it to order.alias</li> <li>typing the alias finds and selects the quality</li> <li>a typed alias overrides the inherited one</li> </ul> </li> <li>owner: -</li> <li>commits: fd1ff1480853871d1398b154266e0173675fc181, 4cf3d68e664f50e85223ff126def4555f8fc1a7e</li> <li>live: 4cf3d68e664f50e85223ff126def4555f8fc1a7e</li> <li>notes: - | pre-checked: row-watch: read the row and its target before starting</li> </ul> <h3>C389</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: src/lib/server/costBasis.ts, src/lib/server/reports.ts</li> <li>verify: -</li> <li>acceptance:<ul> <li>the report shows the same numbers as the cost engine for a covered order</li> <li>no new order_cost rows are written</li> <li>the form no longer offers the field</li> </ul> </li> <li>owner: -</li> <li>commits: 9abcc4cf1a876ab3ffebc6165c4f5a5d60100aed</li> <li>live: 9abcc4cf1a876ab3ffebc6165c4f5a5d60100aed</li> <li>notes: - | pre-checked: row-watch: read the row and its target before starting</li> </ul> <h3>C390</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: src/routes/orders/new/+page.server.ts, src/lib/components/orders/OrderEntryForm.svelte</li> <li>verify: -</li> <li>acceptance:<ul> <li>the damaged form saves without a quote</li> <li>a metre figure above the lot balance is refused</li> <li>the source order link is stored</li> <li>the sale is marked as damaged</li> </ul> </li> <li>owner: -</li> <li>commits: ebe1a5e5842a31f423bc1b5d3405a4ab59c05ebe, 10c0250968b226743c731fc7cf4ba439de189d21</li> <li>live: ebe1a5e5842a31f423bc1b5d3405a4ab59c05ebe</li> <li>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: the damaged lot is the salvage pool key (quality · pick) — the only place grade X metres live; the sale writes the pool's zero-cost out entry so the metre cap is cumulative, and the source SO is read from the lot's own entries rather than re-typed</li> </ul> <h3>C391</h3> <ul> <li>status: withdrawn</li> <li>priority: P1</li> <li>target: src/lib/components/orders/OrderEntryForm.svelte</li> <li>verify: -</li> <li>acceptance:<ul> <li>a draft saved after typing quantity restores it</li> <li>a hidden field never appears in the snapshot</li> <li>switching type or role does not leak a prior draft hidden values</li> </ul> </li> <li>owner: -</li> <li>commits: -</li> <li>live: -</li> <li>notes: - | pre-checked: withdrawn 2026-10-31: merged into C393 — same file, one session covers the draft snapshot and the split</li> </ul> <h3>C392</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: src/routes/orders/[id]/+page.server.ts, src/routes/orders/[id]/+page.svelte</li> <li>verify: -</li> <li>acceptance:<ul> <li>the ops form no longer edits the sale rate or the cash discount</li> <li>dispatch city is replaced by the planning consignee</li> <li>a value typed on one surface is never silently overwritten by the other</li> </ul> </li> <li>owner: -</li> <li>commits: a59966b54f18f3aa8b2cd6eab0d301035221f47d</li> <li>live: a59966b54f18f3aa8b2cd6eab0d301035221f47d</li> <li>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: The ops card shows the rate and cash discount read-only and never posts them; the action takes the row's own values. A sale's send-to city follows planning's consignee; a non-SO order keeps its city (Q368/A368). The commercial set is a booking gate, so a sales-role completion is not asked for fields the card cannot carry.</li> </ul> <h3>C393</h3> <ul> <li>status: withdrawn</li> <li>priority: P1</li> <li>target: src/lib/components/orders/OrderEntryForm.svelte</li> <li>verify: -</li> <li>acceptance:<ul> <li>no single order-form component over 900 lines</li> <li>the form still saves identically and bunx tsc --noEmit adds no error</li> <li>a draft restores only the fields the form shows, and a hidden field never appears in the snapshot</li> </ul> </li> <li>owner: -</li> <li>commits: -</li> <li>live: -</li> <li>notes: - | pre-checked: withdrawn 2026-10-31: folded into C395 — the rebuild deletes the sections the split was needed for, and the draft-snapshot rule is part of its acceptance</li> </ul> <h3>C394</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: docs/contracts/so-form.json, src/lib/contracts.ts</li> <li>verify: -</li> <li>acceptance:<ul> <li>the loader returns the SO contract typed</li> <li>a malformed contract fails with its path</li> <li>a form has no field list outside its contract file</li> </ul> </li> <li>owner: -</li> <li>commits: 4a0db8449bf13a114b923502547b6ef6395f340e, 1db7c5723cc81305d6a5f6f681873be19d010c5a</li> <li>live: 4a0db8449bf13a114b923502547b6ef6395f340e</li> <li>notes: - | pre-checked: row-watch: read the row and its target before starting</li> </ul> <h3>C395</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: src/lib/components/orders/OrderEntryForm.svelte, src/routes/orders/new/trading/+page.svelte, src/routes/orders/new/orderLogic.ts</li> <li>verify: -</li> <li>acceptance:<ul> <li>the rendered sales form has exactly quantity, delivery start, delivery end, rate, tolerance and remark</li> <li>both promise dates are prefilled from the quote and editable</li> <li>buyer order no, cut size, rolls, consignee and coverage are absent</li> <li>the table screen has no Create SO button</li> <li>a draft restores only the six fields</li> <li>saving books the SO with the quote carried</li> </ul> </li> <li>owner: -</li> <li>commits: f1bd7d46debd2b09850de73acbbb8136d6053b3a, fe9e3379c07934efa060030e01f00ae9156e0d40</li> <li>live: fe9e3379c07934efa060030e01f00ae9156e0d40</li> <li>notes: - | pre-checked: C395 implemented and gated (check exit 0, tsc adds no error); SSR render shows the six contract fields</li> </ul> <h3>C396</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: src/routes/orders/new/orderLogic.test.ts, src/lib/contracts.ts, src/lib/components/orders/OrderEntryForm.svelte</li> <li>verify: -</li> <li>acceptance:<ul> <li>the test reads the contract and passes on the shipped field list</li> <li>re-adding rolls to the sales form fails it</li> <li>deleting a contract field fails it</li> <li>the failure names the contract entry</li> </ul> </li> <li>owner: -</li> <li>commits: 89bee571ceeb5e788083eabf074984d31cece900, fcefaba1f28f5572beb904a5186f8519c7beaf8e, dd6beb612dd6b9454dcead5dbb7474e6af17b933</li> <li>live: -</li> <li>notes: - | assumed: the shipped sales form is src/lib/components/orders/SoOrderForm.svelte (C395 moved the SO there), so the contract test reads that screen's control chain and leaves OrderEntryForm to the job-work/production/damaged forms; a field's control is a branch on f.name === 'x' in draw order — a hidden input or a name used only in a helper is not a control | assumed: C396 re-run verified the already-present work against the real tree (a contract field removed, a rolls branch added to SoOrderForm, both restored): the test reads docs/contracts/so-form.json and SoOrderForm.svelte, never OrderEntryForm, and with no tests/ directory in this checkout the one file ran against a throwaway preload removed afterwards | assumed: tests/setup.ts restored verbatim from 7668c583^ and kept (bunfig preloads it; without it no bun test runs in this checkout); the contract/test files are unchanged and the two stale readings (four fields, OrderEntryForm.svelte) stay superseded by C395 | assumed: the shipped field list the test passes on is the contract's own list read from docs/contracts/so-form.json on disk, not a second hardcoded copy: a hardcoded copy makes a legitimate contract edit (field added to contract and screen) fail, the opposite of the row rule | assumed: a braced string literal control name is the same control as a quoted one, so the braced rolls control belongs in the absent check; the shipped field list stays the contract own six from docs/contracts/so-form.json, and OrderEntryForm stays out as C395 superseded it | assumed: a contract may list its entries in any document order (order alone decides the draw order), so every failure pointer must read the contract's own line (docIndex), not the sorted position | assumed: a hidden input is the form envelope, not a field: only visible controls are checked, the same rule assertRenderedForm applies; the row's four-field / OrderEntryForm.svelte readings stay superseded by C395 | auto-answered (Pareto): do the row exactly as written; anything it does not name keeps its current behaviour (attempt 2) | pre-checked: row-watch: read the row and its target before starting | assumed: a contract field with no branch of its own is drawn by the chain's {:else} when that branch writes name={f.name}, so one contract edit completes a field on this form; a header that names a field without a control is not a drawn field</li> </ul> <h3>C397</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: scripts/form-contract-check.ts, src/lib/contracts.ts, src/lib/components/orders/OrderEntryForm.svelte</li> <li>verify: -</li> <li>acceptance:<ul> <li>the check passes on the live build</li> <li>a hidden error div fails it with the element printed</li> <li>a table missing the quote-no column fails it</li> <li>it runs in about a second per form</li> </ul> </li> <li>owner: -</li> <li>commits: cbced940286d1a4f577faad76d913ef1e64f159d</li> <li>live: -</li> <li>notes: - | assumed: the first SSR 500 after a Vite '(ssr) program reload' is the dev server's module init, not the screen's contract, so the check reads the page once more before it judges; a screen that 500s twice still fails | auto-answered (Pareto): yes — re-run the row unchanged: the failure was the integration (deploy/commit), not the row's work, so the safe reading is another attempt (attempt 2) | pre-checked: row-watch: read the row and its target before starting | assumed: the hidden-markup clause is a rule about the rendered screen, not only the create form, so the table screen carries it too; a refused 127.0.0.1 connection is the host's IPv6-only binding, not a missing app, so one localhost retry is the safe reading | assumed: the row builds the SO entry form, so it is built from docs/contracts/so-form.json and now names it (the block's owner-approved field inventory)</li> </ul> <h3>C398</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: src/lib/components/ScreenShell.svelte, src/routes/quote/new/+page.svelte, src/lib/components/orders/OrderEntryForm.svelte, src/lib/components/focus/focusSpec.test.ts</li> <li>verify: -</li> <li>acceptance:<ul> <li>quote and SO render the same shell and layer classes</li> <li>no popup sets its own width or backdrop</li> <li>the SO page header is reachable under the layer</li> <li>light mode only</li> </ul> </li> <li>owner: -</li> <li>commits: 16ce62b7d9ab28885edf15554dada19e52532168</li> <li>live: -</li> <li>notes: - | assumed: one layer width for every popup (max-w-xs one-field popups widen to max-w-md; identical on a phone, wider only on a desk), the blur + bg-black/70 keyboard variant stays inside the spec (C144 behaviour unchanged), and the shell header pins (sticky) while the layer starts at top-14 so the page header stays reachable | auto-answered (Pareto): yes — re-run the row unchanged: the failure was the integration (deploy/commit), not the row's work, so the safe reading is another attempt | pre-checked: row-watch: read the row and its target before starting | assumed: the row's same-shell rule covers every branch of the two screens, so the sale screen's damaged (X) branch takes ScreenShell too; the spec, ScreenShell, FocusLayer and the seven quote popups stay exactly as committed in f2ed3993 (already at HEAD, swept into a C396 commit) and this run changes only the branch that still drew its own page (min-h-screen/bg-base-200/max-w-xl/own header), with a guard case in focusSpec.test.ts | assumed: the row builds the SO entry form, so it is built from docs/contracts/so-form.json and now names it (the block's owner-approved field inventory)</li> </ul> <h3>C399</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: src/lib/historyLayer.ts, src/lib/components/orders/OrderEntryForm.svelte, src/lib/components/quote/TermsPopup.svelte</li> <li>verify: -</li> <li>acceptance:<ul> <li>with the layer open back closes only the layer and the form stays</li> <li>a second back reaches the quote table</li> <li>history.length grows by exactly one per layer</li> <li>the audit fails a layer that skips the helper</li> </ul> </li> <li>owner: -</li> <li>commits: f47d88c51a89d4fa1be8f56c26bfdf91ca4bb191</li> <li>live: -</li> <li>notes: - | assumed: the back helper lands in focus/FocusLayer.svelte (the shared layer both targets already render) rather than in OrderEntryForm/TermsPopup, so one push per open layer and no caller can double-push; a layer with no dismiss pushes nothing; layers on other screens are baselined, not migrated this row | auto-answered (Pareto): yes — re-run the row unchanged: the failure was the integration (deploy/commit), not the row's work, so the safe reading is another attempt | pre-checked: row-watch: read the row and its target before starting | assumed: C399's helper, FocusLayer wiring and audit were already at HEAD, swept into f2ed3993 (a C396 commit), so the row kept returning because its targets never moved; the sound fix for the back defect is in the helper, where each layer's pushed state now carries its own id, and the two component targets need no markup change because they already render FocusLayer | assumed: the row builds the SO entry form, so it is built from docs/contracts/so-form.json and now names it (the block's owner-approved field inventory)</li> </ul> <h3>C400</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: AGENTS.md, scripts/row-watch.sh</li> <li>verify: -</li> <li>acceptance:<ul> <li>AGENTS.md and the row prompt carry the rule</li> <li>assertAbsent exists and is used</li> <li>a row that leaves the old placement fails the contract test</li> </ul> </li> <li>owner: -</li> <li>commits: 61d44bac0c2fc2883bf1d2d4812c88d7bdd1cb31, 9cb1542d3d3c48bd11f48326be5bdba1ff0ed8b1, c41a0793aa0d43e244368cf3e06b875abbfd9df5</li> <li>live: -</li> <li>notes: - | assumed: assertAbsent already exists from C396, so C400 adds no second helper — the SO contract test's C400 case (remark moved to dispatch, still drawn) is the proof; moved and removed are one assertion, and the rule lives in AGENTS.md + the row prompt only, with the prompt line escaping its backticks because that heredoc is unquoted | assumed: the row prompt means both surfaces a row session reads - the watcher's per-row brief and .opencode/agent/row.md - so the rule goes in both; the enforcement stays the existing assertAbsent/assertFormSpec, no new checker | auto-answered (Pareto): do the row exactly as written; anything it does not name keeps its current behaviour (attempt 2) | pre-checked: row-watch: read the row and its target before starting</li> </ul> <h3>C401</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: AGENTS.md, docs/QUEUE-AUTO.md, scripts/queue-next.ts, tests/queueScreenHold.test.ts</li> <li>verify: -</li> <li>acceptance:<ul> <li>adding a row on an open row target is reported</li> <li>the two docs state the rule</li> <li>an existing serialised clash still runs after the first closes</li> </ul> </li> <li>owner: -</li> <li>commits: 6c6a93d4162df8b8e5ae33579d32d6e5d0fc2ee0</li> <li>live: -</li> <li>notes: - | assumed: block = the rows open on the board now (the line is serial, so the earlier open row owns the screen); only a pending row is held, never a reopen/verify row; blocked-owner and withdrawn rows hold nothing; doc-only targets exempt | auto-answered (Pareto): do the row exactly as written; anything it does not name keeps its current behaviour (attempt 2) | pre-checked: row-watch: read the row and its target before starting</li> </ul> <h3>C402</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: AGENTS.md, scripts/contract-gate-check.ts, docs/QUEUE.md</li> <li>verify: -</li> <li>acceptance:<ul> <li>AGENTS states inventory-before-queue</li> <li>a block row without a contract reference is refused at precheck</li> </ul> </li> <li>owner: -</li> <li>commits: 9403baf433841f468d77a8708b0f76dfef100d50</li> <li>live: -</li> <li>notes: - | assumed: the refusal must reach the plan, not only the CLI — row-watch records its pre-check even when the gate refuses (it ignores the exit code), so the gate sits in needsPrecheck: a block row with no contract waits as needs-pre-check even when a record exists; fewest files, no new hold status, self-healing once a pre-check names an existing contract | auto-answered (Pareto): do the row exactly as written; anything it does not name keeps its current behaviour (attempt 2) | pre-checked: row-watch: read the row and its target before starting</li> </ul> <h3>C403</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: <a href="http://127.0.0.1:5173/orders/new/trading?quoteId=c68-quote-01">http://127.0.0.1:5173/orders/new/trading?quoteId=c68-quote-01</a>, docs/contracts/so-form.json, src/lib/components/orders/SoOrderForm.svelte, src/lib/contracts.test.ts, src/routes/orders/new/orderLogic.test.ts, docs/PLANNING.md, docs/BUILD-LOG.md</li> <li>verify: -</li> <li>acceptance: (none recorded — lane must write observable checks first)</li> <li>owner: -</li> <li>commits: 74ee4aae0ada9289919eb91cb9f2973d1adc31c7</li> <li>live: -</li> <li>notes: - | pre-checked: row-watch: read the row and its target before starting</li> </ul> <h3>C404</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: <a href="http://127.0.0.1:5173/orders/new/trading?quoteId=c68-quote-01">http://127.0.0.1:5173/orders/new/trading?quoteId=c68-quote-01</a>, src/lib/components/orders/SoOrderForm.svelte, docs/PLANNING.md, docs/BUILD-LOG.md</li> <li>verify: -</li> <li>acceptance:<ul> <li>tapping the rate field expands a Previous entries portion under it, and tapping the quantity field does the same for quantity</li> <li>tapping a suggestion writes its value into that field and closes the portion</li> <li>no portion shows while neither field is tapped</li> </ul> </li> <li>owner: -</li> <li>commits: 48ebab6bdb6fb5518d0b2995b73b298d8c609fc0</li> <li>live: -</li> <li>notes: - | assumed: the row's two fields are rate and qty; the portion opens on focus and closes on a suggestion or its own Close, never on blur; the suggestions are the D25 coins already on the screen's data; tolerance and remark keep their existing inline chips</li> </ul> <h3>C405</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: <a href="http://127.0.0.1:5173/orders/new/trading?quoteId=c68-quote-01">http://127.0.0.1:5173/orders/new/trading?quoteId=c68-quote-01</a>, docs/contracts/so-form.json, src/lib/components/orders/SoOrderForm.svelte, src/lib/contracts.test.ts, src/routes/orders/new/orderLogic.ts, src/routes/orders/new/orderLogic.test.ts, docs/PLANNING.md, docs/BUILD-LOG.md</li> <li>verify: -</li> <li>acceptance: (none recorded — lane must write observable checks first)</li> <li>owner: -</li> <li>commits: 0ad263fb72ca29f3b53d3ddc072ef6624fdcfcf0</li> <li>live: -</li> <li>notes: - | assumed: terms like brokerage is the four D17/D18 commercial terms the quote carries (brokerage, pass-on, delivery term, freight recovery), shown on the read-only quote strip, never asked on the form; a quote that states none shows a dash</li> </ul> <h3>C406</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: <a href="http://127.0.0.1:5173/orders/new/trading?quoteId=c68-quote-01">http://127.0.0.1:5173/orders/new/trading?quoteId=c68-quote-01</a>, src/lib/components/orders/SoOrderForm.svelte, src/routes/orders/new/orderLogic.ts, src/routes/orders/new/orderLogic.test.ts, src/routes/orders/new/+page.server.ts</li> <li>verify: -</li> <li>acceptance:<ul> <li>delivery start and end sit side by side in one two-column row</li> <li>the form shows the window period in days</li> <li>the period chips offer the quote, buyer, quality and recent spans then the 7/15/30/40 ladder</li> <li>tapping a chip sets delivery end to start plus its days and leaves the start where it was</li> </ul> </li> <li>owner: -</li> <li>commits: a04a0897336cdd9807873fe05b5d1cad6ab5a220</li> <li>live: -</li> <li>notes: form block: docs/contracts/so-form.json read - its six fields, their order, rules and prefills are unchanged; this row changes only how the two delivery dates are drawn and suggested | assumed: period chips are the spans already in use - the quote window, this buyer last window, this quality, the last three orders - then the usual 7/15/30/40 ladder; a tap rewrites only delivery end (start plus N days), start never moves, both keep existing validation.</li> </ul> <h3>C407</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: src/lib/components/orders/SoOrderForm.svelte, src/routes/orders/new/orderLogic.ts, src/routes/orders/new/orderLogic.test.ts</li> <li>verify: -</li> <li>acceptance: (none recorded — lane must write observable checks first)</li> <li>owner: -</li> <li>commits: 6f40a18d5c51e3c5ead6c5ecae6753b31089feb2</li> <li>live: -</li> <li>notes: -</li> </ul> <h3>C408</h3> <ul> <li>status: done</li> <li>priority: P1</li> <li>target: src/routes/orders/+page.svelte, docs/PLANNING.md, docs/BUILD-LOG.md</li> <li>verify: -</li> <li>acceptance:<ul> <li>a saved order confirms with the app-wide popup toast and not an inline banner</li> <li>the toast carries the same words (Added - order SO-261104-U7IO)</li> <li>the new row still flashes row-highlight for 4.2s</li> </ul> </li> <li>owner: -</li> <li>commits: 55c2b913846c82fc5253e9f66cff51ad4f36cc14</li> <li>live: -</li> <li>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: the popup is the app-wide toast (notify, rendered by Toasts in the root layout); it replaces the inline confirmation banner on the orders list while the new row keeps flashing row-highlight for 4.2s; only the orders list changes - the other lists keep their own inline confirmations until their own rows</li> </ul> <h3>C409</h3> <ul> <li>status: doing</li> <li>priority: P1</li> <li>target: src/lib/components/SuggestionChips.svelte, src/lib/components/quote/TermEditor.svelte, src/lib/components/quote/NewSummary.svelte, src/lib/components/quote/NewCalc.svelte, src/lib/components/quote/TermsPopup.svelte, src/routes/quote/new/+page.svelte, src/routes/quote/new/quoteNewState.svelte.ts, src/lib/components/focus/focusSpec.test.ts, docs/PLANNING.md, docs/BUILD-LOG.md, docs/OWNERSHIP.md, docs/FOCUS-ENTRY.md</li> <li>verify: -</li> <li>acceptance:<ul> <li>tapping a quote term opens its suggestions under that row in the page, with no popup</li> <li>tapping a suggestion fills the field and the editor stays until Done or Close</li> <li>the sale form and the quote terms draw the same suggestion chips</li> <li>no term field, value or saveTerm write changed</li> </ul> </li> <li>owner: -</li> <li>commits: -</li> <li>live: -</li> <li>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: 'throughout the website' starts with the quote term popup (the popup whose purpose is the suggestion list); the signed FOCUS-ENTRY wizards and field popups are the entry pattern itself and keep their popups; two new files, the old popup deleted with its only caller, reversible</li> </ul> <!----></div></article></div></div><!--]--><!--]--><!--]--><!----></div></main> <!--[-1--><!--]--><!----></div></div><!--]--><!--]--><!--]--><!----> <!--[-1--><!--]--><!--]--> <script> { __sveltekit_1ib7f33 = { base: new URL("..", location).pathname.slice(0, -1), version: "1793797649325" }; const element = document.currentScript.parentElement; import("../_app/immutable/entry/start.DrcVuqU3.js").then(async (kit) => { kit.init(__sveltekit_1ib7f33); const app = await import("../_app/immutable/entry/app.Aj3X7NZp.js"); kit.start(app, element, { node_ids: [0, 19], data: [{type:"data",data:{session:null,path:"/docs/QUEUE",search:""},uses:{url:1}},{type:"data",data:{title:"QUEUE.md — runner-owned machine ledger (generated)",file:"QUEUE.md",html:"\u003Ch1>QUEUE.md — runner-owned machine ledger (generated)\u003C/h1>\n\u003Cblockquote>\n\u003Cp>\u003Cstrong>FILE OWNERSHIP:\u003C/strong> written ONLY by \u003Ccode>scripts/queue-next.ts --sync\u003C/code>\n(the runner). It is a \u003Cem>projection\u003C/em> of the owner's \u003Ccode>docs/CORRECTIONS.md\u003C/code>\nPending table plus the reopen feed; the owner never edits it. Batching\nrules: \u003Ccode>docs/OWNERSHIP.md\u003C/code>. Do not hand-edit a block's \u003Ccode>status\u003C/code> to\n\u003Ccode>done\u003C/code> — the \u003Ccode>verifier\u003C/code> agent does that on proof.\u003C/p>\n\u003Cp>Regenerate/enrich: \u003Ccode>bun scripts/queue-next.ts --sync\u003C/code>\nInspect: \u003Ccode>bun scripts/queue-next.ts --list\u003C/code>\nPlan next batch: \u003Ccode>bun scripts/queue-next.ts --next\u003C/code>\u003C/p>\n\u003C/blockquote>\n\u003Ch3>C131\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/masters\">https://trading.tynolabs.com/masters\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting\u003C/li>\n\u003C/ul>\n\u003Ch3>C132\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/masters?tab=party\">https://trading.tynolabs.com/masters?tab=party\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: Retire the opening-balance field on every authoring/display surface only; keep the party.opening_balance column and legacy values untouched (mirrors C131).\u003C/li>\n\u003C/ul>\n\u003Ch3>C133\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/masters?tab=party\">https://trading.tynolabs.com/masters?tab=party\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: Retire the due-days field on every authoring/display surface only; keep the party.due_days column and legacy values untouched (mirrors C132).\u003C/li>\n\u003C/ul>\n\u003Ch3>C134\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/masters?tab=party\">https://trading.tynolabs.com/masters?tab=party\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: Mobile/email rules already exist (PLANNING 141); C134 is read as: keep them and make the mobile/email inputs actively relevant at the keyboard (mobile strips non-pattern characters as typed; stale errors clear on edit). Nothing else changes.\u003C/li>\n\u003C/ul>\n\u003Ch3>C135\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/masters?tab=party\">https://trading.tynolabs.com/masters?tab=party\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: Godown is a master label added to the party-category vocabulary; no downstream filter (gatepasses trader picker) changes. New value only, reversible; revisit only if the owner wants Godown parties hidden from pickers.\u003C/li>\n\u003C/ul>\n\u003Ch3>C136\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/masters?tab=party\">https://trading.tynolabs.com/masters?tab=party\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: Keep +91 storage byte-identical (bare 10 digits); persist other known codes as \u003Cdial>\u003Clocal>; shared whitelist in src/lib/countryCodes.ts; reversible and additive.\u003C/li>\n\u003C/ul>\n\u003Ch3>C137\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/masters?tab=party\">https://trading.tynolabs.com/masters?tab=party\u003C/a>\u003C/li>\n\u003Cli>verify: /tmp/opencode/c137-proof.ts\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>party tab renders no visible phone input but a hidden round-trip name=phone input\u003C/li>\n\u003Cli>a create POST with phone=not-a-phone returns only 'party name required' (no phone-format error)\u003C/li>\n\u003Cli>blank name still rejected\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: C137 = drop the visible party Phone input + validation only; preserve existing phone data via a hidden round-trip input; keep the record-detail Phone row.\u003C/li>\n\u003C/ul>\n\u003Ch3>C138\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/masters?tab=party\">https://trading.tynolabs.com/masters?tab=party\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: MSME stored as free-text (trimmed string; blank -> null); label 'MSME (Udyam Aadhar) no.'; shown in the party form and the record detail; no format validation; no list column.\u003C/li>\n\u003C/ul>\n\u003Ch3>C139\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/masters?tab=party\">https://trading.tynolabs.com/masters?tab=party\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>Party form at /masters?tab=party renders no visible Own unit toggle\u003C/li>\n\u003Cli>a hidden isOwnUnit round-trip input is present\u003C/li>\n\u003Cli>creating an own-unit party stores is_own_unit=1 and editing another field leaves it 1\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: remove only the visible 'Own unit' toggle; keep the is_own_unit column/data and the detail/list rows; hidden round-trip input preserves the value on edit\u003C/li>\n\u003C/ul>\n\u003Ch3>C140\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/masters?tab=party\">https://trading.tynolabs.com/masters?tab=party\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>typing abcde-1234f into PAN normalises to ABCDE1234F as you type\u003C/li>\n\u003Cli>typing 27abcde-1234f1z5 into GSTIN normalises to 27ABCDE1234F1Z5 as you type\u003C/li>\n\u003Cli>a malformed PAN/GSTIN still shows the existing per-field error on save\u003C/li>\n\u003Cli>that error clears as soon as the field is edited\u003C/li>\n\u003Cli>a valid PAN/GSTIN saves exactly as before\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: PAN/GSTIN rules predate the correction; the row wants them relevant at the keyboard (mirror C134/A94) - normalise-as-you-type + clear stale error, existing rules/messages unchanged\u003C/li>\n\u003C/ul>\n\u003Ch3>C141\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/masters?tab=party\">https://trading.tynolabs.com/masters?tab=party\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>party record dialog shows Edit fields and no standalone Amend control\u003C/li>\n\u003Cli>entering edit shows the Correction remark field among the other fields\u003C/li>\n\u003Cli>Cancel sits beside Save and returns to the read-only view\u003C/li>\n\u003Cli>saving an edit with a remark writes one amendment whose reason is the remark\u003C/li>\n\u003Cli>saving an edit with no remark writes none\u003C/li>\n\u003Cli>other master tabs keep their Amend control\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: Party tab only: the edit form carries the correction remark alongside the fields, Cancel + Save sit side by side, and the standalone Amend control is removed (the remark is written to the audit trail as an amendment on save). Other master tabs are unchanged.\u003C/li>\n\u003C/ul>\n\u003Ch3>C142\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/masters?tab=party\">https://trading.tynolabs.com/masters?tab=party\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: C142 = delete the Suggest button from the party Acronym field only; the auto-suggest-from-name behaviour and the acronym field itself are untouched.\u003C/li>\n\u003C/ul>\n\u003Ch3>C143\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/masters?tab=payment-terms\">https://trading.tynolabs.com/masters?tab=payment-terms\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting\u003C/li>\n\u003C/ul>\n\u003Ch3>C144\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/masters?tab=payment-terms\">https://trading.tynolabs.com/masters?tab=payment-terms\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting\u003C/li>\n\u003C/ul>\n\u003Ch3>C145\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/masters?tab=payment-terms\">https://trading.tynolabs.com/masters?tab=payment-terms\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: Target is the design master (/masters?tab=design) — same ?tab=payment-terms batch mislabel as C143/C144 (Q103/Q104). Permissible counts live per row inside the existing warp_rows/weft_rows JSON as permissible:[...]; the grid posts the same warpRowsJson/weftRowsJson names so buildDesignValues/designErrors keep working.\u003C/li>\n\u003C/ul>\n\u003Ch3>C146\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/masters?tab=payment-terms\">https://trading.tynolabs.com/masters?tab=payment-terms\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: C146 = remove the raw-JSON warp/weft field presentation (its literal target, already gone with C145); keep the C145 grid, relabel it Warp/Weft, and drop the JSON claim from static/masters-fields.html\u003C/li>\n\u003C/ul>\n\u003Ch3>C147\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/masters?tab=payment-terms\">https://trading.tynolabs.com/masters?tab=payment-terms\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: the quality name is derived (server builder + form preview share one helper) in the format width``reed/denting\u003Cem>pick/warp\u003C/em>weft-weave; the design-master target is the C143-C150 batch mislabel (Q103-Q107)\u003C/li>\n\u003C/ul>\n\u003Ch3>C148\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/masters?tab=payment-terms\">https://trading.tynolabs.com/masters?tab=payment-terms\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: C148 = design master (masters?tab=design, batch mislabel); the removed field is the visible Pick (PPI) input; the derived name writes the literal Pick in the pick slot; stored pick preserved by a hidden carry on edit\u003C/li>\n\u003C/ul>\n\u003Ch3>C149\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/masters?tab=payment-terms\">https://trading.tynolabs.com/masters?tab=payment-terms\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: the design-master fields are removed from the UI/client/server validation and from buildDesignValues so an edit never overwrites the stored gsm_target/utl (checking report still reads them); columns stay, no migration\u003C/li>\n\u003C/ul>\n\u003Ch3>C150\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/masters?tab=payment-terms\">https://trading.tynolabs.com/masters?tab=payment-terms\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: drop the '— EPI = reed × denting ÷ 2' suffix from the Denting field label in DesignForm.svelte, keep 'Denting (ends per dent)'; ?tab=payment-terms is the C143-C150 batch mislabel so the design master is the surface; no input name, stored value, client rule or server validation moves.\u003C/li>\n\u003C/ul>\n\u003Ch3>C151\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/masters?tab=party\">https://trading.tynolabs.com/masters?tab=party\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting\u003C/li>\n\u003C/ul>\n\u003Ch3>C152\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/masters?tab=party\">https://trading.tynolabs.com/masters?tab=party\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting\u003C/li>\n\u003C/ul>\n\u003Ch3>C153\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/masters?tab=party\">https://trading.tynolabs.com/masters?tab=party\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: Target /tippans/new (sheet) and ?tab=party (queue) are the C143-C152 batch mislabel (Q103-Q111); the only 'L2L (104)' label is on the design master form, so remove '(104)' there and nowhere else.\u003C/li>\n\u003C/ul>\n\u003Ch3>C154\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/masters?tab=party\">https://trading.tynolabs.com/masters?tab=party\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting\u003C/li>\n\u003C/ul>\n\u003Ch3>C155\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/masters?tab=party\">https://trading.tynolabs.com/masters?tab=party\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: Only the /masters page tables (all 7 tabs) are in scope; the 'Open' links on /tippans and /reconciliations are not master tables and stay. rowHref already opened the record on row-tap, so removing the duplicate Open column is the whole change.\u003C/li>\n\u003C/ul>\n\u003Ch3>C156\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/masters\">https://trading.tynolabs.com/masters\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting\u003C/li>\n\u003C/ul>\n\u003Ch3>C157\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/masters\">https://trading.tynolabs.com/masters\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: Target is the design master (/masters?tab=design): the warp/weft grid with permissible counts exists only in DesignRowsGrid there (same C143-C152 batch mislabel as Q111). The permissible-count picker stays a multi-select checkbox list (C152 stored it as permissible:number[]); the fix is a search input inside the dropdown that filters the yarn-master counts, empty = all, no min length. Transient permQuery is per-row UI state, excluded from the posted JSON and from server validation, so no schema/field/validation change; POST names, JSON shape, distribute and both grid layouts are untouched.\u003C/li>\n\u003C/ul>\n\u003Ch3>C158\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/masters\">https://trading.tynolabs.com/masters\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: C158 = design master (/masters?tab=design); remove Mode from every authoring/display surface (DesignForm select + client rule, designErrors server rule, MASTER_FIELDS detail row, SmartTable Mode column) and from buildDesignValues so an edit never overwrites the stored mode_pref; the design.mode_pref column and BOTH default stay (no migration) so the SO mode prefill keeps working (mirrors C149).\u003C/li>\n\u003C/ul>\n\u003Ch3>C159\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: -\u003C/li>\n\u003Cli>verify: bunx tsc --noEmit = 140 (< 147 baseline); bun run build green on @sveltejs/adapter-bun; built server boots (GET / -> 303, /signin -> 200, cookieless POST /api/events -> 403); bun run check exit 0\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: Safe 80/20: migrate deps/config/aliases/removed-API call sites exactly as the official sv migrate sveltekit-3 did; keep deprecated-but-working API usages (json/text) and proven false-positive review findings (delta identifiers here are qty steps; enhanced forms post to their own page). Official @sveltejs/adapter-bun (community peers Kit 2). No schema/POST/validation change; reversible by restoring the old dep pins + svelte.config.js. | landed: deps @sveltejs/kit@^3.1.0 / svelte@^5.57.1 / zod@^4.6.7 / sveltekit-superforms@^3.0.0; svelte-adapter-bun -> @sveltejs/adapter-bun@^1.0.0; svelte.config.js deleted (config in vite.config.ts); tsconfig extends $app/tsconfig; $lib -> #lib subpath + .js across ~196 files; $app/environment->$app/env, $app/stores->$app/state, ActionResult from $app/forms; src/env.ts feeds $app/env/private; invalidateAll->refreshAll, goto keepFocus->reset:false, replaceState->replace. PLANNING §441, BUILD-LOG.\u003C/li>\n\u003C/ul>\n\u003Ch3>C160\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/masters\">https://trading.tynolabs.com/masters\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: 711c8b9\u003C/li>\n\u003Cli>live: 711c8b9\u003C/li>\n\u003Cli>notes: landed: weave sub-master projected from design rows + pick-or-type datalist + case-insensitive de-dup/validation (WEAVE_RE) — PLANNING §448, BUILD-LOG; code swept into 711c8b9 after a deploy-scheduled queue-watch restart (SIGTERM) killed the C160 session mid-work; row-watch now runs --unstick before picking a row so a restart can no longer strand a doing row\u003C/li>\n\u003C/ul>\n\u003Ch3>C161\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/orders/new/trading\">https://trading.tynolabs.com/orders/new/trading\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: the reported 500 is the order form's post-save read-back GET /api/orders/[id] (order.quality is not a column; the quality is design.qualityName) — fix that one endpoint by joining the design master, keep the response shape and both callers unchanged\u003C/li>\n\u003C/ul>\n\u003Ch3>C162\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/quote\">https://trading.tynolabs.com/quote\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: = latest quote for the design_id, newest inputs_json.warpReedSpace/weftReedSpace, carried via adj only when it differs from the master; empty/absent falls back to the master.\u003C/li>\n\u003C/ul>\n\u003Ch3>C163\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/quote\">https://trading.tynolabs.com/quote\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: job rate = inputs_json.jobRatePaise of the newest quote for the design_id, falling back to the design master when there is no history; set directly on the wizard's job-rate field (no 'edited' badge, unlike wrs/frs) — no field added, no schema change, reversible.\u003C/li>\n\u003C/ul>\n\u003Ch3>C164\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/quote\">https://trading.tynolabs.com/quote\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: warp sizing rate = the yarn master siz_rate for the row's count (first count+system match, then count-only); fills a blank row, re-prefills only a value this prefill wrote when the count moves to another master count, and never overwrites a quote/design/hand-typed rate. No field added, no schema change, reversible.\u003C/li>\n\u003C/ul>\n\u003Ch3>C165\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/quote\">https://trading.tynolabs.com/quote\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting\u003C/li>\n\u003C/ul>\n\u003Ch3>C166\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/quote\">https://trading.tynolabs.com/quote\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: Remove only the visible sizing-GST field from the new-quote wizard summary (/quote/new): drop the 'Warp n siz GST' tap-row and the sizGst branch of openYarnField. The stored sizGst value stays (yarn-master prefill + the costing path unchanged, blank = follow Fabric GST); RowEd.sizGst is untouched; /quote/edit's own per-warp Siz GST input stays because the row names /quote. No field added, no schema change, reversible.\u003C/li>\n\u003C/ul>\n\u003Ch3>C167\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/tippans/new\">https://trading.tynolabs.com/tippans/new\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>/tippans/new serves no mill/ticket field: no yMill hidden input and no mill/ticket summary/wizard row\u003C/li>\n\u003Cli>TippanWizard.svelte declares no yMill prop or step\u003C/li>\n\u003Cli>the create action derives yarnIssue.mill from the assigned yarn/gatepass and never from a posted yMill\u003C/li>\n\u003Cli>existing tippan records and prints still show the mill derived from their source, unchanged\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: Removed only the mill/ticket entry field from /tippans/new (state + hidden input + wizard prop/binding + gatepass ticket carry + PREFILLABLE entry + the create action's raw(fd,'yMill') read); the tippan's stored mill stays, derived from the assigned yarn or its gatepass (r.issue.mill | gpRow.ticket), so record/print/existing rows are unchanged. No schema, POST-name, record or print change — fewest files, reversible.\u003C/li>\n\u003C/ul>\n\u003Ch3>C168\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: -\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>masters load exposes mills = distinct rate-board tickets, case-insensitively deduped, first spelling canonical, sorted\u003C/li>\n\u003Cli>a new rate ticket appears in mills on the next load with no other action\u003C/li>\n\u003Cli>the yarn Add/Edit Ticket/mill input is a pick-or-type datalist fed by mills\u003C/li>\n\u003Cli>no schema change/migration and stored yarn tickets unchanged\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: The mill/ticket master is a derived projection of the rate board's ticket column (mirroring C160's weave sub-master), not a new table/tab; it feeds a pick-or-type datalist on the yarn master's Ticket/mill field so any count+type shows all mills. No schema change, stored yarns untouched, reversible.\u003C/li>\n\u003C/ul>\n\u003Ch3>C169\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/tippans/new\">https://trading.tynolabs.com/tippans/new\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>masters design tab: focusing or typing in the Weave field shows the filtered weave-master list above the input\u003C/li>\n\u003Cli>tapping a row fills the field with the stored spelling\u003C/li>\n\u003Cli>typing a weave not in the master stays in the field and is saved (canonicalWeave adds it), appearing in the master and the next dropdown\u003C/li>\n\u003Cli>the design tab shows a read-only Weave master panel with the count and every distinct weave (case-insensitive unique)\u003C/li>\n\u003Cli>name=weave, WEAVE_RE and designErrors are unchanged and no schema/migration exists\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: C169 surface is the design master (/masters?tab=design) — /tippans/new carries no weave field (weave is derived from the picked design), so the target is the same C143–C157 batch mislabel; the weave master stays a projection of design rows (C160) and is now shown read-only on the design tab, and the Weave field becomes a visible searchable dropdown that still accepts a new weave; no schema change, no POST-name/validation change, reversible.\u003C/li>\n\u003C/ul>\n\u003Ch3>C170\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/orders/new/trading\">https://trading.tynolabs.com/orders/new/trading\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting\u003C/li>\n\u003C/ul>\n\u003Ch3>C171\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/orders/new/trading\">https://trading.tynolabs.com/orders/new/trading\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting\u003C/li>\n\u003C/ul>\n\u003Ch3>C172\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/orders/new/trading\">https://trading.tynolabs.com/orders/new/trading\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: Brokerage slot = 1% across the field's existing 0–100 range, coins exactly 1% and 2%, wheel floors a fractional typed value into its slot; no field added so server readNum(0–100) and the client decimal guard stay unchanged; reversible (restore the single input/subtitle).\u003C/li>\n\u003C/ul>\n\u003Ch3>C173\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/orders/new/trading\">https://trading.tynolabs.com/orders/new/trading\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: Pass-on wheel slot = 0.25% across the existing 0-100 range, coins exactly 0.5% and 2%, wheel keeps a fractional typed value (snaps to nearest 0.25 slot for display); no field added so server readNum(0-100) and the client decimal guard stay unchanged; reversible (restore the plain input/subtitle).\u003C/li>\n\u003C/ul>\n\u003Ch3>C174\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/orders?operations=1\">https://trading.tynolabs.com/orders?operations=1\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: own-key guard only in the target file src/routes/orders/+page.server.ts (Object.hasOwn for rawSort); the identical SORT_COLS[rawSort] idiom on the nine sibling list pages is a separate reversible follow-up, not this row's file\u003C/li>\n\u003C/ul>\n\u003Ch3>C175\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/orders/new/trading\">https://trading.tynolabs.com/orders/new/trading\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>deliver-in popup shows a Start date and an End date, each with Today/+2d/+7d/+15d/+30d/+40d chips and a ±1-day stepper\u003C/li>\n\u003Cli>a chip/step rewrites that date and the window resolves to the whole-day span\u003C/li>\n\u003Cli>the hidden input still posts name=dueDays as a non-negative integer (blank stays blank)\u003C/li>\n\u003Cli>bun helper proof for addDaysIso/deliverSpanDays passes\u003C/li>\n\u003Cli>bun run check is 0 errors\u003C/li>\n\u003Cli>tsc adds no error in the touched files\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: keep dueDays integer as the one stored value; deliver start/end are UI-only dates over it (addDaysIso/deliverSpanDays), no schema/migration; window resolves to the whole-day span, clamped >=0; summary reads 'N day(s)'\u003C/li>\n\u003C/ul>\n\u003Ch3>C176\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/masters\">https://trading.tynolabs.com/masters\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: mill master = board projection (C168) UNION a new insert-only mill table; name required + MILL_RE(1-40) on both surfaces; case-insensitive dedupe across both sources; no rate columns, quote popup untouched\u003C/li>\n\u003C/ul>\n\u003Ch3>C177\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/masters\">https://trading.tynolabs.com/masters\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>weave tab shows an Add weave button opening a modal\u003C/li>\n\u003Cli>submitting a new weave adds it to the weave master list\u003C/li>\n\u003Cli>a case-insensitive duplicate of a design or stored weave is refused 409\u003C/li>\n\u003Cli>a non-conforming name is refused 400 on both surfaces\u003C/li>\n\u003Cli>buildWeaveValues returns name+active\u003C/li>\n\u003Cli>bunx tsc --noEmit adds no error in the touched files\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: weave master = design-weave projection (C160) UNION a new insert-only weave table; name required + WEAVE_RE(1-20) on both surfaces; case-insensitive dedupe across both sources; no construction columns\u003C/li>\n\u003C/ul>\n\u003Ch3>C178\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/orders?type=SO\">https://trading.tynolabs.com/orders?type=SO\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>every list page (hishob, bookings, tippans, gatepasses, lots, beams, samples, drafts) returns non-500 for ?sort=\u003Cstrong>proto\u003C/strong> / constructor / toString / hasOwnProperty and 200 on its base load\u003C/li>\n\u003Cli>every real sort key still sorts and /orders is unchanged (already guarded by C174)\u003C/li>\n\u003Cli>bunx tsc --noEmit adds no error in the touched files\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: C178 is the same inherited-property sort 500 C174 fixed on /orders (A130 named the sibling loads as the follow-up); apply the one-line own-key guard to the eight remaining list loads so no list table 500s on a non-own sort value — one line per file, behaviour unchanged for real keys, reversible\u003C/li>\n\u003C/ul>\n\u003Ch3>C179\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/orders/new/trading\">https://trading.tynolabs.com/orders/new/trading\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>the operations/production fields are shown on this order form\u003C/li>\n\u003Cli>the sales person may fill or skip them (non-compulsory)\u003C/li>\n\u003Cli>OCR of the contract copy prefills the operations fields on this same form\u003C/li>\n\u003Cli>skipping them still saves the order and lists it on the operations queue\u003C/li>\n\u003Cli>the operations user later completes the same fields as an appendage (before/after, never a silent edit)\u003C/li>\n\u003Cli>bunx tsc --noEmit adds no error in the touched files\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting\u003C/li>\n\u003C/ul>\n\u003Ch3>C180\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/orders/new/job-work\">https://trading.tynolabs.com/orders/new/job-work\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>the operations/production fields are shown on this order form\u003C/li>\n\u003Cli>the sales person may fill or skip them (non-compulsory)\u003C/li>\n\u003Cli>OCR of the contract copy prefills the operations fields on this same form\u003C/li>\n\u003Cli>skipping them still saves the order and lists it on the operations queue\u003C/li>\n\u003Cli>the operations user later completes the same fields as an appendage (before/after, never a silent edit)\u003C/li>\n\u003Cli>bunx tsc --noEmit adds no error in the touched files\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: C180 mirrors C179 for the Job Work SO: same four ops fields (lotSizeMtrPerRoll, rolls, dispatchCity, promisedDays) added by kind ['SO','JW'], optional, step-less single-field boxes, server validation unchanged; OCR reachability restored as a JW-only, picker-free source step reading the contract copy; OUTSOURCE/PROD untouched.\u003C/li>\n\u003C/ul>\n\u003Ch3>C181\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/orders/new/production-order\">https://trading.tynolabs.com/orders/new/production-order\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>the operations/production fields are shown on this order form\u003C/li>\n\u003Cli>the sales person may fill or skip them (non-compulsory)\u003C/li>\n\u003Cli>OCR of the contract copy prefills the operations fields on this same form\u003C/li>\n\u003Cli>skipping them still saves the order and lists it on the operations queue\u003C/li>\n\u003Cli>the operations user later completes the same fields as an appendage (before/after, never a silent edit)\u003C/li>\n\u003Cli>bunx tsc --noEmit adds no error in the touched files\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: C181 mirrors C179/C180 for the Stock (Production) order: the same four ops fields (lotSizeMtrPerRoll, rolls, dispatchCity, promisedDays) join ORDER_FIELD_SPEC by kind ['SO','JW','PROD'], all required:false, each a step-less summary row opening its own single-field box; the source step returns for PROD as a contract-copy READ only (picker stays SO-only); client inputs gain the sibling pattern rules (decimal for cut size, whole number for rolls/sales promise), server validation unchanged and already kind-agnostic; OUTSOURCE untouched.\u003C/li>\n\u003C/ul>\n\u003Ch3>C182\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/orders/new/job-work\">https://trading.tynolabs.com/orders/new/job-work\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>the job work wizard opens on the 'Loom width and panna?' popup as its first step\u003C/li>\n\u003Cli>the job work form's Kind section leads with 'Loom width (from master)' then 'No. of panna (panels together)'\u003C/li>\n\u003Cli>both fields keep their existing validation (loom-master widths, panna a whole number >= 1)\u003C/li>\n\u003Cli>the Trading SO and Production Order forms have no loom step or fields\u003C/li>\n\u003Cli>bunx tsc --noEmit adds no error in the touched files\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: loom width + panna are literally first on the JW wizard (before the contract-read source step) and lead the JW form's kind section; the shared job-work code also applies it to OUTSOURCE; SO/PROD unaffected; C146's fields and their existing validation (loomWidth in the loom master's width set, panna a whole number ≥1) are unchanged\u003C/li>\n\u003C/ul>\n\u003Ch3>C183\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/quote/new\">https://trading.tynolabs.com/quote/new\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting\u003C/li>\n\u003C/ul>\n\u003Ch3>C184\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/quote/new\">https://trading.tynolabs.com/quote/new\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: the payment dhara field = the /quote/new summary form's 'Payment dhara' row; 'in the end' = last section of the full form, after Construction, just above the actions (the wizard's dhara step is already last among steps). One file (NewSummary.svelte), reversible, no behaviour change.\u003C/li>\n\u003C/ul>\n\u003Ch3>C185\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/quote/new\">https://trading.tynolabs.com/quote/new\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>on /quote/new's calc screen, when a side has more than one valid yarn row, each warp and each weft is listed with its own ₹/m cost and g/m weight\u003C/li>\n\u003Cli>the existing warp/weft totals are unchanged\u003C/li>\n\u003Cli>a side with a single row shows no per-yarn breakdown\u003C/li>\n\u003Cli>the per-row figures match the engine's warpRowCosts/weftRowCosts and warpRowKg/weftRowKg\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: second page = the calc/numbers screen (NewCalc.svelte); show per-warp and per-weft cost+weight only when a side has >1 valid rows, using the engine's existing per-row arrays (C.warpRowCosts/weftRowCosts, W.warpRowKg/weftRowKg) filtered by positive count so indices align; totals unchanged; one file; reversible.\u003C/li>\n\u003C/ul>\n\u003Ch3>C186\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/quote/new\">https://trading.tynolabs.com/quote/new\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>on /quote/new the Est qty (mtrs) term popup shows a scroll entry stepping 1000 mtr per slot\u003C/li>\n\u003Cli>typing a figure is kept as typed and opening the popup does not rewrite an existing estimate\u003C/li>\n\u003Cli>coins list previous sale orders (type='SO') of the same quality, most recent first, up to 4\u003C/li>\n\u003Cli>coins fall back to the browser's last-used estimate when there is no order history and no coins row shows when neither exists\u003C/li>\n\u003Cli>estQty still posts and validates (junk / <0 / >1000000 fail), no new field\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: coins = previous type='SO' order rows of the same design (positive metre qty, recent-first, dedupe, max 4), browser last-used as fallback; wheel = NumberWheel one slot 1000 mtr, floor one slot, top = server's 1,000,000-mtr estQty cap, typeable keeps a typed figure\u003C/li>\n\u003C/ul>\n\u003Ch3>C187\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/quote/new\">https://trading.tynolabs.com/quote/new\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>on /quote/new the Delivery end term popup shows coins +10d, +20d, +30d, +40d, +50d, +60d\u003C/li>\n\u003Cli>tapping a coin fills the date with the chosen Delivery start + that many days, or today + days when no start is set\u003C/li>\n\u003Cli>the Delivery start popup still shows its C105 quality-typical coins unchanged\u003C/li>\n\u003Cli>deliveryEnd still posts and still validates (a non-date fails), no new field\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: delivery-end coins = +10/+20/+30/+40/+50/+60 days added to dStart when set, else today; suggestions only, dStart coins untouched. Q140/A140\u003C/li>\n\u003C/ul>\n\u003Ch3>C188\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/orders\">https://trading.tynolabs.com/orders\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>the orders list shows no fixture order number (order_no glob SO-C\u003Cdigits>-\u003Cepoch>, SO-AIR*, SO-AM-\u003Cem>, SO-ML-\u003C/em>, SO-E2E*)\u003C/li>\n\u003Cli>real orders numbered SO-YYMMDD-XXXX are untouched\u003C/li>\n\u003Cli>data.db is backed up before any delete\u003C/li>\n\u003Cli>every candidate row is checked first for linked booking/amendment/event children and none referenced is removed\u003C/li>\n\u003Cli>the fix is proved by listing order_no values after the purge\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: Fixture-subtree purge (Q141): delete the fixture order and its linked child rows (evt/amendment/order_attachment/roll/dispatch_slip/lot) in one transaction after backing up data.db; the acceptance protection clause means no referenced child is left dangling, not that a referenced fixture stays. Real SO-YYMMDD-XXXX never match the globs.\u003C/li>\n\u003C/ul>\n\u003Ch3>C189\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: -\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: Q142/A142: the official DeepSeek key is set in the host .env (never committed) and .env.example documents url+model; the official API only accepts model deepseek-flash (display name DeepSeek-V4.1-Flash), proven by GET /models.\u003C/li>\n\u003C/ul>\n\u003Ch3>C190\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/samples\">https://trading.tynolabs.com/samples\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: rate wheel min 0 max 999 step 0.25 typeable, up to 6 distinct recent order rates of the quality as coins; no strict 0.25-multiple validation (a typed fractional rate posts as before) — fewest files, existing rate validation untouched, reversible\u003C/li>\n\u003C/ul>\n\u003Ch3>C191\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/samples\">https://trading.tynolabs.com/samples\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting\u003C/li>\n\u003C/ul>\n\u003Ch3>C192\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/samples\">https://trading.tynolabs.com/samples\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>[reopen 2026-10-18] never implemented — board marked done (3870b04) but the purpose field is still live in samples/+page.svelte and +page.server.ts; the 'row C192' commit fa08fe5 carried only docs (C206-C218). Reopened per owner 2026-10-18.\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: never implemented — board marked done (3870b04) but the purpose field is still live in samples/+page.svelte and +page.server.ts; the 'row C192' commit fa08fe5 carried only docs (C206-C218). Reopened per owner 2026-10-18. | assumed: Purpose removed from the samples form only: the svelte form/prefill/state and the samples create action stop reading or posting it; the capture-draft confirm still writes the nullable sample_order.purpose from the slip and the column stays (existing data preserved, reversible, two target files). | pre-checked: row-watch: read the row and its target before starting\u003C/li>\n\u003C/ul>\n\u003Ch3>C193\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/samples\">https://trading.tynolabs.com/samples\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: The correction does not settle WHICH spot 'top of the form' is nor the displayed value: read it as a new first summary section named 'Sample' holding the existing read-only 'Sample no · Auto' row (value stays 'Auto' like every other doc-number row), moved up from the bottom of 'Charge or waive'. Display-only, one .svelte file, reversible; nothing else about the form or the server changes.\u003C/li>\n\u003C/ul>\n\u003Ch3>C194\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/hishob\">https://trading.tynolabs.com/hishob\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: remove Hishob (/hishob) and Reports (/reports) from the Orders nav group (both are reports); place both in a new 'Reports' nav group with the same roles. Display-only, one file, reversible by moving the two children back.\u003C/li>\n\u003C/ul>\n\u003Ch3>C195\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/bookings/new\">https://trading.tynolabs.com/bookings/new\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>On /bookings/new, selecting an open order shows its warp/weft · count+type · already-assigned-kg grid, each assigned figure expanding to its date + mill ticket\u003C/li>\n\u003Cli>selecting more than one production order makes the bags step ask bags per order and blocks save until the shares are positive whole numbers summing to the total\u003C/li>\n\u003Cli>a single order or the pending bucket posts exactly as before\u003C/li>\n\u003Cli>the split is validated server-side.\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: The grid is read-only context built from the order design's warp/weft rows + open bookings against that order; multi-select is PROD-only (an SO/pending replaces the selection); the primary order keeps the existing cost link, the split is an additive nullable JSON column, and the grid also renders for an SO harmlessly.\u003C/li>\n\u003C/ul>\n\u003Ch3>C196\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/bookings/new\">https://trading.tynolabs.com/bookings/new\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>On /bookings/new, picking a yarn whose own master row has no booking history but whose count+system+type+mill matches another master that was booked, prefill cones/bag and bag wt from that last booking untouched-only, with the 'last booking' badge\u003C/li>\n\u003Cli>the wizard's cones/bag + bag wt one-tap coins show that same last value\u003C/li>\n\u003Cli>supplier/broker/lot/payment term/rate still prefill only from the exact selected master\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: cone/bag + bag wt prefill from the last booking whose yarn matches the selected yarn's count+system+type+mill (not the exact master id); the other history fields keep exact-id matching\u003C/li>\n\u003C/ul>\n\u003Ch3>C197\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/bookings/new\">https://trading.tynolabs.com/bookings/new\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting\u003C/li>\n\u003C/ul>\n\u003Ch3>C198\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/orders/new/trading\">https://trading.tynolabs.com/orders/new/trading\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: C198 is reorder-only: apply the owner's sequence to both faces (the shared ORDER_FIELD_SPEC + WIZARD_STEPS); keep the system date read-only at the top (C135) and keep both quote/lead link rows adjacent (the wizard already asks them as one box); protect C182's job-work loom-first step.\u003C/li>\n\u003C/ul>\n\u003Ch3>C199\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/orders/new/job-work\">https://trading.tynolabs.com/orders/new/job-work\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>JW form order: buyer's order no > booking date > system date > loom width (from master) > no. of panna > beams whose > broker > buyer > quality > rate > picks > job rate > qty > counted in > send as > deliver-in days > cut size > rolls > payment dhara > cash discount % days > brokerage % > capture draft > remark\u003C/li>\n\u003Cli>JW form shows ONE loom width (legacy loomType gone)\u003C/li>\n\u003Cli>JW form drops Send to city, Sales promise and Broker/weaver confirmation\u003C/li>\n\u003Cli>JW wizard: loom > booking date > source > broker > buyer > quality > rate > picks > job rate > qty\u003C/li>\n\u003Cli>trading SO (C198) and legacy OUTSOURCE forms unchanged\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: C199 is a JW-only reorder+removal: (1) retire the duplicate legacy loomType for JW (keep master-driven loomWidth, C146/C182); (2) keep the derived rate field/wizard step (not in the explicit remove list; C142) so the visible buyer/quality/rate/picks/job-rate sequence stands; (3) drop dispatchCity, promisedDays and contractFile on JW only; (4) keep the job-work wizard opening on loom (C182) with booking date next; (5) leave the legacy OUTSOURCE form (loomType, contractFile, city, promise) untouched — fewest files, keep existing behaviour, reversible\u003C/li>\n\u003C/ul>\n\u003Ch3>C200\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/orders/new/job-work\">https://trading.tynolabs.com/orders/new/job-work\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: sourceDraftId shows on JW+OUTSOURCE, not tied to contractFile (C199 made contractFile OUTSOURCE-only); the field's upload uses the capture gateway (/api/capture-ocr) so it writes a draft and links it — party/quality prefill from the read's masters, full field-prefill stays the wizard's order-OCR — one file, reversible\u003C/li>\n\u003C/ul>\n\u003Ch3>C201\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/bookings/new\">https://trading.tynolabs.com/bookings/new\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>New booking form carries an optional Own firm row whose options are exactly the party-master rows with category OwnUnit\u003C/li>\n\u003Cli>legacy blank bookings still save and post firm_name empty\u003C/li>\n\u003Cli>a saved booking stores the picked name in booking.firm_name and it appears in the summary/review\u003C/li>\n\u003Cli>a POST naming a non-OwnUnit party returns 400 with the firmName error and stores nothing\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: own party type = party.category 'OwnUnit'; field optional + master-validated; stored as nullable text column booking.firm_name; pick-list rendered as the wizard's last step (index 13) to avoid clashing with the pending C207-C210 booking reorder rows; no auto-prefill.\u003C/li>\n\u003C/ul>\n\u003Ch3>C202\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/quote\">https://trading.tynolabs.com/quote\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting\u003C/li>\n\u003C/ul>\n\u003Ch3>C203\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/quote\">https://trading.tynolabs.com/quote\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | assumed: Prefill L2L from the design's most recent quote (inputs_json.l2l) via the existing lastQuoteRows map, winning over the design master exactly like wrs/frs/job; the L2L popup's suggestion coins lead with that last actual value, then fall back to the common master coins. No new field, no validation change. | pre-checked: row-watch: read the row and its target before starting\u003C/li>\n\u003C/ul>\n\u003Ch3>C204\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/quote\">https://trading.tynolabs.com/quote\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting\u003C/li>\n\u003C/ul>\n\u003Ch3>C205\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/orders\">https://trading.tynolabs.com/orders\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting\u003C/li>\n\u003C/ul>\n\u003Ch3>C206\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/orders\">https://trading.tynolabs.com/orders\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: Create from the picker reuses the real party master form (PartyForm posted to /masters?/createParty) with no page reload; the new row is kept in the order form's local list and auto-selected. Category defaults: Party for a buyer, Weaver for an OUTSOURCE buyer, Broker for a broker. No new order field, so no new validation.\u003C/li>\n\u003C/ul>\n\u003Ch3>C207\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/bookings/new\">https://trading.tynolabs.com/bookings/new\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting\u003C/li>\n\u003C/ul>\n\u003Ch3>C208\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/bookings/new\">https://trading.tynolabs.com/bookings/new\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting\u003C/li>\n\u003C/ul>\n\u003Ch3>C209\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/bookings/new\">https://trading.tynolabs.com/bookings/new\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: Trader's booking no + booking date are optional (booking saves without them); trader no max 60 chars of letters/digits/space and / . _ -, booking date a real calendar day that starts on today's system date, untouched-only.\u003C/li>\n\u003C/ul>\n\u003Ch3>C210\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/bookings/new\">https://trading.tynolabs.com/bookings/new\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting\u003C/li>\n\u003C/ul>\n\u003Ch3>C211\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: src/routes/users/**, src/routes/+layout.server.ts, src/routes/+layout.svelte\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>owner opens /users and sees the existing logins + a create-login form\u003C/li>\n\u003Cli>owner creates a guard login (name/email/password/role) and the new user's role is guard\u003C/li>\n\u003Cli>a signed-out or non-owner session cannot reach /users\u003C/li>\n\u003Cli>creating a login with a duplicate email is refused with an inline error\u003C/li>\n\u003Cli>there is no edit or delete action\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting\u003C/li>\n\u003C/ul>\n\u003Ch3>C212\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/gatepasses/new?kind=YARN_IN\">https://trading.tynolabs.com/gatepasses/new?kind=YARN_IN\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>the yarn booking field on /gatepasses/new?kind=YARN_IN opens a table of bookings (not a search drop-down)\u003C/li>\n\u003Cli>only bookings not yet fully received (status open or partial) are listed\u003C/li>\n\u003Cli>tapping a table row selects that booking and carries its yarn, trader and rate\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: pending = booking.status open | partial (not yet fully received); the table applies to the shared yarn-booking field on both booking-driven kinds (YARN_IN and DIRECT) since it is one list/one field; other kinds keep their prefill picker\u003C/li>\n\u003C/ul>\n\u003Ch3>C213\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/gatepasses/new?kind=YARN_IN\">https://trading.tynolabs.com/gatepasses/new?kind=YARN_IN\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting\u003C/li>\n\u003C/ul>\n\u003Ch3>C214\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/gatepasses/new?kind=YARN_IN\">https://trading.tynolabs.com/gatepasses/new?kind=YARN_IN\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: reuse /api/capture-ocr for the OCR row (it saves the file and returns validated prefill); apply only the values this form shows/mounts (bags, vehicle, transport) and let the user confirm each; the signed gatepass copy gets its own document upload; dictation is a Web Speech textarea saved with the record and only prefills an explicit bags/plate mention; all three ride the creation event payload (no column, no migration); image stays the GP photo.\u003C/li>\n\u003C/ul>\n\u003Ch3>C215\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/gatepasses/new?kind=YARN_IN\">https://trading.tynolabs.com/gatepasses/new?kind=YARN_IN\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: form name = the YARN_IN kind label on /gatepasses/new (badge + list dropdown + FocusEntry title); generic h1 and nav left as-is\u003C/li>\n\u003C/ul>\n\u003Ch3>C216\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/gatepasses/new?kind=YARN_IN\">https://trading.tynolabs.com/gatepasses/new?kind=YARN_IN\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting\u003C/li>\n\u003C/ul>\n\u003Ch3>C217\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/gatepasses/new?kind=YARN_IN\">https://trading.tynolabs.com/gatepasses/new?kind=YARN_IN\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>On /gatepasses/new?kind=YARN_IN the rows read Booking, Yarn (count + type + mill name), Yarn inward intimation no, System date, Location of pickup, Bags to be received, Remark in that order\u003C/li>\n\u003Cli>a picked booking fills the Yarn row\u003C/li>\n\u003Cli>Remark accepts 200 chars and rejects 201 server-side and caps the input\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: remarks = a new optional Remark row (max 200, event payload); reorder applies to the six named YARN_IN entry rows, static meta kept, uploads after\u003C/li>\n\u003C/ul>\n\u003Ch3>C218\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/gatepasses/new?kind=YARN_IN\">https://trading.tynolabs.com/gatepasses/new?kind=YARN_IN\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>On /gatepasses/new?kind=YARN_IN the Kind row is gone — the rows read Booking, Yarn (count + type + mill name), Yarn inward intimation no, System date, Location of pickup, Bags to be received, Remark\u003C/li>\n\u003Cli>every other kind still shows its Kind row\u003C/li>\n\u003Cli>the YARN_IN after-save summary no longer lists Kind\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: remove kind = drop the Kind row/chip on the standalone YARN_IN form only (and its after-save summary line); keep the top-right form-name badge (C215), the direction marker, the hidden POST kind/direction markers and the list menu — fewest files, reversible, no other kind touched\u003C/li>\n\u003C/ul>\n\u003Ch3>C219\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/samples\">https://trading.tynolabs.com/samples\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>On /samples the new-sample form's Charge or waive section asks only Charge or Waive — picking Waive shows no Waive ₹ amount field (Rate shows only when charging)\u003C/li>\n\u003Cli>A waive save writes charge_type=waive, waiver_amt=0, rate=null, and the sample list Charge column shows a green waive badge\u003C/li>\n\u003Cli>A charge still requires Rate and writes charge_type=charged with the typed rate\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: waive = complete waive: drop the amount field; store waiverAmt=0, chargeType='waive', rate=null, auto-approved (waiverBy/waiverApprovedBy='user') because the >₹1000 owner gate needs an amount; list badge reads chargeType not the amount; fewest files (samples page + server), reversible\u003C/li>\n\u003C/ul>\n\u003Ch3>C220\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/samples\">https://trading.tynolabs.com/samples\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>On /samples the new-sample form shows no Rate source row in Charge or waive (Rate still appears only when Charge is picked)\u003C/li>\n\u003Cli>a charge save still stores the typed rate\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting\u003C/li>\n\u003C/ul>\n\u003Ch3>C221\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/samples\">https://trading.tynolabs.com/samples\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: remove the complete 'From (context)' section (lead picker, order picker, Capture draft static row) and the lead/order carry plumbing + server leadOptions/orderOptions; keep the hidden draftId POST and prefill so a draft still saves the same\u003C/li>\n\u003C/ul>\n\u003Ch3>C222\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/bookings/new\">https://trading.tynolabs.com/bookings/new\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: shared NumberWheel typeable input: while typing do not sync text from value (so backspace clears the last digit) and do not re-canonicalise on emit; canonicalise on blur. Empty/partial text left as typed; wheel range clamp unchanged.\u003C/li>\n\u003C/ul>\n\u003Ch3>C223\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/orders/new/trading\">https://trading.tynolabs.com/orders/new/trading\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: no broker selected (buyer present, non-PROD) is a DIRECT order: store brokerName 'DIRECT', brokeragePct 1, passOnPct 1 on save, accepting an incoming 'DIRECT' as no-broker too; directOrderDefaults treats our own 'DIRECT' as empty so the form effect is stable; a typed value (0 included) always wins; PROD unchanged\u003C/li>\n\u003C/ul>\n\u003Ch3>C224\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/quote/new?quoteId=aemxzq7f45xw\">https://trading.tynolabs.com/quote/new?quoteId=aemxzq7f45xw\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>Tap Reuse on a quote row: lands on /quote/new?quoteId=\u003Cid>&reuse=1 with fields prefilled and NO 'Editing' banner\u003C/li>\n\u003Cli>Calculate/save mints a fresh quote number (Edit still opens the carried 'Editing' form)\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: Reuse opens the same prefilled summary form as a new quote (no edit carry, fresh number), keeping Edit as-is — the correction only names Reuse; fewest files, reversible\u003C/li>\n\u003C/ul>\n\u003Ch3>C225\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/orders/new/trading\">https://trading.tynolabs.com/orders/new/trading\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: the two lists are role-scoped on the one Trading SO form (production role -> production set, sales role -> sales set); Buyer stays buyer-or-broker; other roles and kinds unchanged\u003C/li>\n\u003C/ul>\n\u003Ch3>C226\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/orders/new/trading\">https://trading.tynolabs.com/orders/new/trading\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting\u003C/li>\n\u003C/ul>\n\u003Ch3>C227\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/orders/new/trading\">https://trading.tynolabs.com/orders/new/trading\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: Booking no. = the buyer's booking/order no already stored as partyContractNo; add it as a Trading SO-only wizard step right after the source/OCR step, with a standard 60-char reference-format validation on both surfaces; job work/outsource/stock and the yarn cost-basis booking are unchanged.\u003C/li>\n\u003C/ul>\n\u003Ch3>C228\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/orders/new/trading\">https://trading.tynolabs.com/orders/new/trading\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: C228 ships as the owner-approved ± stepper on the trading wizard's rate step: each tap nudges ₹0.25 (rounded to 2 dp), the centre stays typeable for any amount, and typed decimals are kept instead of floored. The desktop Price section rate input and the ops popup wheel are untouched; no server validation change.\u003C/li>\n\u003C/ul>\n\u003Ch3>C229\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/orders/new/trading\">https://trading.tynolabs.com/orders/new/trading\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: rate is money: formatRate() shows/stores 2 dp on /orders/new/trading (wizard + section input + prefills/coins), validateOrderFields rounds rate to 2 dp; ops popup untouched.\u003C/li>\n\u003C/ul>\n\u003Ch3>C230\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/orders/new/trading\">https://trading.tynolabs.com/orders/new/trading\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: C230 = the trading wizard's picks ± now moves 1 per tap (was 100); the C142 same-quality+party suggestion coins already ship and stay as they are; job work's picks input and rate maths untouched.\u003C/li>\n\u003C/ul>\n\u003Ch3>C231\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/orders/new/trading\">https://trading.tynolabs.com/orders/new/trading\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting\u003C/li>\n\u003C/ul>\n\u003Ch3>C232\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/orders/new/trading\">https://trading.tynolabs.com/orders/new/trading\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting\u003C/li>\n\u003C/ul>\n\u003Ch3>C233\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/orders/new/trading\">https://trading.tynolabs.com/orders/new/trading\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: the +/- stepper applies to the wizard brokerage scroll only; the summary popup's plain brokerage input and the 1%/2% coins stay as they are (fewest files, reversible)\u003C/li>\n\u003C/ul>\n\u003Ch3>C234\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/orders/new/trading\">https://trading.tynolabs.com/orders/new/trading\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting\u003C/li>\n\u003C/ul>\n\u003Ch3>C235\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/orders\">https://trading.tynolabs.com/orders\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting\u003C/li>\n\u003C/ul>\n\u003Ch3>C236\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/orders/new/production-order\">https://trading.tynolabs.com/orders/new/production-order\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: PROD staged: sales set = booking date+buyer+broker+quality+rate+picks+dueDays+payment dhara+CD+brokerage+pass-on; production set = buyer PO no+send as+cut size+rolls; qty already mandatory; quote/lead optional and the picker locks after manual entry; production completion enforces the same four.\u003C/li>\n\u003C/ul>\n\u003Ch3>C237\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/orders/new/trading\">https://trading.tynolabs.com/orders/new/trading\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: C237: fix scoped to the one control the operator sees on /orders/new/trading — the §4b send-as field pop-up; the hidden POST select and the order-detail page's send-as controls are left as-is (fewest files, reversible, invisible either way). No field added, so no validation change.\u003C/li>\n\u003C/ul>\n\u003Ch3>C238\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/orders/new/trading\">https://trading.tynolabs.com/orders/new/trading\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting\u003C/li>\n\u003C/ul>\n\u003Ch3>C239\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/orders/new/trading\">https://trading.tynolabs.com/orders/new/trading\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: C239: suggestion coins are quality-only (designId), newest first, de-duplicated, max 4; the party no longer filters coins though it still drives the C142 prefill; coins also show under the section picks input for non-job-work kinds; load reads a dedicated picksHistory (200, picks not null) so a quality older than the 40-row recent list still gets coins. No field/POST/schema/validation change.\u003C/li>\n\u003C/ul>\n\u003Ch3>C240\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/orders\">https://trading.tynolabs.com/orders\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: C240: aliases for both cells in the wide orders table (party acronym/name, quality alias/name), column order unchanged (Party then Quality); record popup keeps full names; reuse existing partyCell/qualityCell helpers.\u003C/li>\n\u003C/ul>\n\u003Ch3>C241\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/orders\">https://trading.tynolabs.com/orders\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: C241: "booking date" means the wizard's own booking date (order.orderDate, C135), shown as the first column of the wide /orders table, sorted by that raw date while displaying d MMM yy; the compact Job-work table (C140, four phone columns) and the existing trailing "Booked" system-date column stay exactly as they are. Display-only, one file.\u003C/li>\n\u003C/ul>\n\u003Ch3>C242\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/orders\">https://trading.tynolabs.com/orders\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: the table's Status column shows short badge words (Open / In Prod / Delivered / Closed / Pending / Confirmed / Cancelled) and the Progress column shows one abbreviated leading fact (e.g. '3 rl · 1.2k m sent'); the record popup keeps the full status and progress text; display-only, one file (src/routes/orders/+page.svelte)\u003C/li>\n\u003C/ul>\n\u003Ch3>C243\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/orders\">https://trading.tynolabs.com/orders\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: C243: the row popup is the only action surface on /orders (C140's rule); the table's trailing actions column is removed for all tabs, including the Reuse/Requote links, because the popup already carries the same destinations. Display-only, one file (src/routes/orders/+page.svelte).\u003C/li>\n\u003C/ul>\n\u003Ch3>C244\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/orders/new/trading\">https://trading.tynolabs.com/orders/new/trading\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: C244: 'open' means what the Leads/Quote list screens show — lost leads (not converted/deleted, no generated quote) and non-terminal quotes (open/approved/draft/sent, no generated SO) even when the printed validity date has passed; the picker and the create action share that set. The wizard's sourceLink picker opens as a modal (popup) with Lead/Quote tabs instead of inline.\u003C/li>\n\u003C/ul>\n\u003Ch3>C245\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/orders/new/trading\">https://trading.tynolabs.com/orders/new/trading\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting\u003C/li>\n\u003C/ul>\n\u003Ch3>C246\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: -\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: C246: two separate append-only reference masters (loom_class, loom_type) unioned with built-in values and values already on looms; the loom form reads them and validates against them. Class = 2-3 digit width in cm (optional cm suffix normalised), type = 2-20 letters/digits + space/-/_. C247's combined master is left to C247.\u003C/li>\n\u003C/ul>\n\u003Ch3>C247\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/masters?tab=loom\">https://trading.tynolabs.com/masters?tab=loom\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: C247: loom_type gains a width column and is the combined master; Loom class stays as the width source/tab. The loom form has ONE Loom type select whose value is width | type; the loom keeps loom_class/loom_type text (downstream screens untouched) plus a nullable loom_type_id link filled when the picked pair is a stored master row. Blank-width C246 type rows apply to every class width; values already on looms and built-in pairs stay selectable. Recorded reading: keep the class master, no table or data dropped — reversible, fewest files.\u003C/li>\n\u003C/ul>\n\u003Ch3>C248\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/orders/new/job-work\">https://trading.tynolabs.com/orders/new/job-work\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: C248: 'loom type' = the job-work loom width (loomWidth); panna prefills from the last order with that quality + width whichever party, and the old quality+party panna is only the fallback while no width is chosen. Blank when that width has no prior panna.\u003C/li>\n\u003C/ul>\n\u003Ch3>C249\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/orders/new/job-work\">https://trading.tynolabs.com/orders/new/job-work\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting\u003C/li>\n\u003C/ul>\n\u003Ch3>C250\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/orders\">https://trading.tynolabs.com/orders\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: production wizard = SO→/production/trading, OUTSOURCE→/production/job-commercial, PROD→/production/production-order, JW→/orders/\u003Cid>#operations (no JW production screen); chip reads 'Details pending' beside Status and as the Ops column on the job-work table; only role 'production' gets Fill details and loses New.\u003C/li>\n\u003C/ul>\n\u003Ch3>C251\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/orders/new/trading\">https://trading.tynolabs.com/orders/new/trading\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | job-work | production-order all compose the same OrderEntryForm component, so one row covers all three. No schema change expected (visibility only). | pre-checked: row-watch: read the row and its target before starting | assumed: Role visibility is spec-level on both faces; buyer/qty/kind/system date/remark are universal; hidden fields post their carried values through hidden inputs; JW production gains the same four compulsory physical fields as SO/PROD production.\u003C/li>\n\u003C/ul>\n\u003Ch3>C252\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/production/trading\">https://trading.tynolabs.com/production/trading\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: C252: role visibility+requiredness is spec-level on the production summary, its popups and the save gate; production's compulsory set is the four physical fields on every side; sales' set is the seven commercial fields; /production access stays owner/planner/production/checker/godown (no access change).\u003C/li>\n\u003C/ul>\n\u003Ch3>C253\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/orders/new/job-work\">https://trading.tynolabs.com/orders/new/job-work\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: C253: rate per metre = jobRate × picks ÷ 100, derived; removed from the JW wizard but kept read-only in the background Price section and summary; OUTSOURCE keeps its editable form and explicit-rate-wins rule, only its auto maths follows ÷100.\u003C/li>\n\u003C/ul>\n\u003Ch3>C254\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/orders/new/job-work\">https://trading.tynolabs.com/orders/new/job-work\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: C254: 'form' is the background Price section; only the job-rate and rate-per-metre blocks swap, Picks stays between them (rate → picks → job rate), matching the summary's ORDER_FIELD_SPEC order; the shared OrderEntryForm makes OUTSOURCE read the same order too. No wizard change (the JW rate step is already gone per C253).\u003C/li>\n\u003C/ul>\n\u003Ch3>C255\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/orders/new/job-work\">https://trading.tynolabs.com/orders/new/job-work\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting\u003C/li>\n\u003C/ul>\n\u003Ch3>C256\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/orders?type=JW\">https://trading.tynolabs.com/orders?type=JW\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: C256: seven requested JW columns in the owner's order (booking date, order no, quality alias, party alias, mtr/beam, job rate, status), then the C250 Ops marker; job rate shown from order.jobRate as ₹/pick; Mtr/beam uses the order qty + qtyUnit.\u003C/li>\n\u003C/ul>\n\u003Ch3>C257\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/orders?type=JW\">https://trading.tynolabs.com/orders?type=JW\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: C257: chat/share stay in the row popup (C140/C153) and are always enabled for job-work rows; with a mobile they deep-link to the party, without one they open WhatsApp's contact picker with the same prefilled text.\u003C/li>\n\u003C/ul>\n\u003Ch3>C258\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/orders?type=JW\">https://trading.tynolabs.com/orders?type=JW\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: Hide Book yarn only on a JW row's actions; SO/Outsource/Stock keep it and the order detail page already omits it for JW\u003C/li>\n\u003C/ul>\n\u003Ch3>C259\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/orders?type=JW\">https://trading.tynolabs.com/orders?type=JW\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: C259: drop New tippan only from the JW row's actions in the orders list popup (the JW detail page already shows beam-out/yarn-inward, not sizing tippan); SO/Outsource/Stock keep it, other popup actions untouched — fewest files, reversible\u003C/li>\n\u003C/ul>\n\u003Ch3>C260\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/orders/new/job-work\">https://trading.tynolabs.com/orders/new/job-work\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: job-work picks gets the same ±1 stepper and the same quality's most recent distinct picks (up to 4, from stored picks history, quality-only — no party filter, no fallback) as coins; tapping a coin or the stepper keeps the JW rate = job rate × picks live. No new field, so no new validation; the existing whole-number >0 rule stays on both surfaces.\u003C/li>\n\u003C/ul>\n\u003Ch3>C261\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/orders?type=JW\">https://trading.tynolabs.com/orders?type=JW\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: C261: the Job-work tab (?type=JW) renders only the Job Work SO draft; SO/PROD tabs likewise render only their own; the All tab keeps all three as before. Draft offers filtered client-side by data.fType — no server/DB change, no new field, no validation change.\u003C/li>\n\u003C/ul>\n\u003Ch3>C262\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/orders?type=JW\">https://trading.tynolabs.com/orders?type=JW\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting\u003C/li>\n\u003C/ul>\n\u003Ch3>C263\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/orders/new/job-work\">https://trading.tynolabs.com/orders/new/job-work\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting\u003C/li>\n\u003C/ul>\n\u003Ch3>C264\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/orders?type=OUTSOURCE\">https://trading.tynolabs.com/orders?type=OUTSOURCE\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: C264: the four order forms share one draft mechanism keyed order-new-draft[-TYPE]; the generic OUTSOURCE form (null fixedType) keys order-new-draft, so it becomes a fourth draft offer and the existing fType tab filter shows each kind only its own (All keeps all four). Client-side, no server/DB change, no new field so no new validation. | assumed: C264: add the generic OUTSOURCE form's own draft offer (key order-new-draft, type OUTSOURCE, href /orders/new?type=OUTSOURCE) as the fourth entry; the existing filter (!data.fType | data.fType === d.type) then gives each kind tab only its own draft and the All tab keeps all four. No server/DB change, no new field, no validation change.\u003C/li>\n\u003C/ul>\n\u003Ch3>C265\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/orders/new?type=OUTSOURCE\">https://trading.tynolabs.com/orders/new?type=OUTSOURCE\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: C265 removes the four OUTSOURCE-only fields (tcsEffRate, tcsUncondRate, tcsLiability, deliveryGpId) from the booking form's one spec ORDER_FIELD_SPEC and its hardcoded terms block, records them in ORDER_INTENTIONALLY_HIDDEN, and leaves the server action, DB columns, order-record page and production-ops face untouched — fewest files, reversible, and a past order keeps the values it booked.\u003C/li>\n\u003C/ul>\n\u003Ch3>C266\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/orders/new?type=OUTSOURCE\">https://trading.tynolabs.com/orders/new?type=OUTSOURCE\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: C266 = C255's shared-form change: 'end of terms' means the last field of the Terms section (after the Outsource terms block), not nested inside that collapse; no further code change, same beamsSource POST/options/validation (no new field, so no new validation).\u003C/li>\n\u003C/ul>\n\u003Ch3>C267\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/orders/new?type=OUTSOURCE\">https://trading.tynolabs.com/orders/new?type=OUTSOURCE\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: C267: OUTSOURCE is the job-work form with its kind fixed by the URL; wizard/fields/rate/OCR match JW exactly and the only naming change is partyContractNo -> Weaver's order no. The party field keeps its existing buyer/weaver picker because the row names only the order no. Brokerage stays for C268.\u003C/li>\n\u003C/ul>\n\u003Ch3>C268\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/orders/new?type=OUTSOURCE\">https://trading.tynolabs.com/orders/new?type=OUTSOURCE\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: remove brokerage means the outsource form no longer shows or books brokerage (weaver job rate is the whole price); JW keeps its 1%, past outsource orders keep their booked value, fewest files/reversible\u003C/li>\n\u003C/ul>\n\u003Ch3>C269\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/orders/new/production-order\">https://trading.tynolabs.com/orders/new/production-order\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: C269 = the production-order form keeps only yarn allocation (costBookingId) + remark from its Terms section; 'buyer, rate, send to city' and every other term/paper field leave the shared spec for PROD, while SO/JW/OUTSOURCE keep them. Buyer's order no/quote/lead/broker/booking date stay for C270. Fewest files (one spec + one component), reversible, past orders keep their booked values.\u003C/li>\n\u003C/ul>\n\u003Ch3>C270\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/orders/new/production-order\">https://trading.tynolabs.com/orders/new/production-order\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: C270 = remove the buyer's order no, quote, lead, broker and booking date from the production-order form only; a value a quote/OCR/history held is not smuggled back as a hidden POST; the contract kinds (SO/JW/OUTSOURCE) and past production orders keep the fields they stored; the production stage still fills the buyer's order no at order-record completion.\u003C/li>\n\u003C/ul>\n\u003Ch3>C271\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/orders/new/job-work\">https://trading.tynolabs.com/orders/new/job-work\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: C271 removes panna as a wizard step only: it stays a summary row that opens its own single-field box, required=false, prefilled from history, and saved unchanged.\u003C/li>\n\u003C/ul>\n\u003Ch3>C272\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/masters?tab=loom\">https://trading.tynolabs.com/masters?tab=loom\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: C272 removes the Loom class master tab/form/action only: the loom_type master is the single width+type master with its width typed in cm (2-3 digits, cm suffix stripped, validated client+server), and the loom_class table, loom.loomClass column and stored values stay because beams/board/print read them; no data dropped, no schema change.\u003C/li>\n\u003C/ul>\n\u003Ch3>C273\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/bookings/new\">https://trading.tynolabs.com/bookings/new\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: C273 adds the OCR + dictation controls to the booking wizard's first popup: both only PREFILL every booking field the read understands (not just the booking no), OCR reuses /api/capture-ocr so the slip is kept as a capture draft, speech/typed text goes to /api/booking-understand, and the existing form validation + confirm sheet remain the only save path.\u003C/li>\n\u003C/ul>\n\u003Ch3>C274\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/bookings/new\">https://trading.tynolabs.com/bookings/new\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: C274 mirrors the order form's C141 pattern: the wizard still auto-opens, a header 'Start the wizard' button appears only when it is closed, and it reopens at step 0 (the capture popup); no field, POST name, validation, or save path changes.\u003C/li>\n\u003C/ul>\n\u003Ch3>C275\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/bookings/new\">https://trading.tynolabs.com/bookings/new\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: Delivery end is an optional new delivery_end column; all four delivery controls share one wizard popup; interval coins 3/5/7/10 with 1-day and 1-bag steppers; bags-per-interval suggestion = ceil(total bags ÷ inclusive interval count), stopping once the user edits it; end date optional, requires the start and is never before it — existing saves and blanks unchanged.\u003C/li>\n\u003C/ul>\n\u003Ch3>C276\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/bookings/new\">https://trading.tynolabs.com/bookings/new\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: Supplier options are the Supplier-category party master plus historic booking names, so old prefills stay selectable; the field remains optional and saves the same text, and a new supplier is created through the same PartyForm with category Supplier, selected in the wizard without a page reload.\u003C/li>\n\u003C/ul>\n\u003Ch3>C277\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/bookings/new\">https://trading.tynolabs.com/bookings/new\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: Broker options are the Broker-category party master plus brokers just created in this wizard, deduped and sorted; a new broker is created with the shared PartyForm (category Broker), then selected and the wizard advances; the booking broker stays optional and the existing server rule (Broker must be picked from masters) is unchanged. Fewest files, reversible, no data rewritten.\u003C/li>\n\u003C/ul>\n\u003Ch3>C278\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/bookings/new\">https://trading.tynolabs.com/bookings/new\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: reuse the masters YarnForm in a nested popup posting to /masters?/createYarn; on save refresh page data, select the new yarn and advance the wizard (mirrors the broker picker), no new booking field or column\u003C/li>\n\u003C/ul>\n\u003Ch3>C279\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/bookings/new\">https://trading.tynolabs.com/bookings/new\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: the mill/ticket is a new optional booking field (mill_ticket) picked from the mill master beside the yarn count+type; the popup creates a mill via the shared MillForm, old bookings fall back to yarn.ticket, and a legacy yarn's stored ticket is accepted so their product identity saves unchanged\u003C/li>\n\u003C/ul>\n\u003Ch3>C280\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/orders/new?type=OUTSOURCE\">https://trading.tynolabs.com/orders/new?type=OUTSOURCE\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: only OUTSOURCE swaps to job rate -> picks -> rate in the background Price form and its summary; JW keeps C254's rate -> picks -> job rate, SO unchanged, wizard untouched\u003C/li>\n\u003C/ul>\n\u003Ch3>C281\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/gatepasses/new?kind=YARN_IN\">https://trading.tynolabs.com/gatepasses/new?kind=YARN_IN\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>Tapping the booking row on /gatepasses/new?kind=YARN_IN opens a separate popup titled Pick a pending booking with Job work and Yarn booking tabs, each showing its count\u003C/li>\n\u003Cli>each tab lists pending bookings in a table (booking no · yarn · trader · rate · bags · status)\u003C/li>\n\u003Cli>choosing a row fills the booking and advances/closes\u003C/li>\n\u003Cli>the inline table no longer renders inside the wizard/field popup\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: The pending booking table moves into its own popup opened from the booking row, with Job work (no purchase rate) and Yarn booking tabs, the SO lead/quote picker shape (OrderTablePicker); choosing a row fills the same bookingPick and advances exactly as before, and the table is no longer rendered inline in the wizard/field popup.\u003C/li>\n\u003C/ul>\n\u003Ch3>C282\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/gatepasses/new?kind=YARN_IN\">https://trading.tynolabs.com/gatepasses/new?kind=YARN_IN\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: the intimation number is the existing GP number generated on save (GP-YYMMDD-XXXX) and the system date is the server's systemDate; both move out of the Which-movement section into a booking-style top card above the form, with no duplicate row and no change to the other kinds\u003C/li>\n\u003C/ul>\n\u003Ch3>C283\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/gatepasses/new?kind=YARN_IN\">https://trading.tynolabs.com/gatepasses/new?kind=YARN_IN\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: the added GP no is the trader/party physical gatepass number recorded in the existing partnerGpNo column (no migration), optional, max 64 chars, letters/digits/space/-// only; the auto GP-YYMMDD-XXXX intimation number stays display-only in the C282 top card and is never overridden\u003C/li>\n\u003C/ul>\n\u003Ch3>C284\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/orders/new/job-work\">https://trading.tynolabs.com/orders/new/job-work\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: switching the job-work unit clears the quantity so the beam wheel opens on 1 (and metres on 1000); a metre quantity is never reinterpreted as beams, and a save with no quantity still fails validation as before\u003C/li>\n\u003C/ul>\n\u003Ch3>C285\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/orders?type=JW\">https://trading.tynolabs.com/orders?type=JW\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: natural-width table with horizontal scroll is the intended fix (not hiding or trimming columns), applied only to the Job-work tab where C140 forced the compact fit; column set, popup and actions unchanged\u003C/li>\n\u003C/ul>\n\u003Ch3>C286\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: -\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting\u003C/li>\n\u003C/ul>\n\u003Ch3>C287\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: -\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: no screen named: apply the app-wide ergonomics fix — a normal navigation opens the new screen at its top (hash targets and back/forward unchanged), one reversible layout file, no data change\u003C/li>\n\u003C/ul>\n\u003Ch3>C288\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: src/app.css\u003C/li>\n\u003Cli>verify: script\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>bun scripts/color-contrast.ts exits 0: body >=7:1, muted /60 >=4.5:1, every status tone >=4.5:1 as text and as white on its chip, header strip >1.05:1 vs white\u003C/li>\n\u003Cli>reverting thead th to #fafafa makes it exit 1\u003C/li>\n\u003Cli>src/app.css keeps themes: light --default with no second theme or data-theme toggle\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | assumed: no screen named: fix the app-wide token layer in src/app.css — body ink zinc-900, status hues at the 700 tones with white content, visible zinc-100 table header strip; one reversible file, no markup, no theme change | pre-checked: row-watch: read the row and its target before starting\u003C/li>\n\u003C/ul>\n\u003Ch3>C289\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/\">https://trading.tynolabs.com/\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 3fe635a3572453c6cad69d9fd6995eb0a04f03b7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: the scrollbar is the dashboard's position cue: one app-wide monochrome skin in src/app.css (10px, rounded zinc-400 thumb, zinc-900 under the pointer) plus a desktop-only section rail on the dashboard — one tick per board section mapped onto the same track as the thumb, active tick follows the reader, click jumps — no new data, removed by deleting ScrollMap.svelte and its two lines in +page.svelte\u003C/li>\n\u003C/ul>\n\u003Ch3>C290\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: -\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: 789559e4be7b716c2786c4690abf968d7e43c24b\u003C/li>\n\u003Cli>live: 789559e4be7b716c2786c4690abf968d7e43c24b\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: the phone's bar is the C289 rail made draggable: show it at every width (right-1 on phones, sm:right-4), take the drag with pointer capture + touch-action none so the gesture is ours, keep ticks as click-to-jump, no new data or screen — reversible by restoring hidden lg:block\u003C/li>\n\u003C/ul>\n\u003Ch3>C291\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: src/lib/components/ScrollMap.svelte\u003C/li>\n\u003Cli>verify: script\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>bun scripts/scroll-map.ts exits 0: the rail is a 44px lane on phones (24px from sm) holding a 6px zinc-400 bar pinned to the edge, no grey track slab, the bar darkens on hover and while dragging, tick pips clear of the ink\u003C/li>\n\u003Cli>reverting the lane to w-2 / the track to bg-base-300 makes it exit 1\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: 9a6ab97bf4737217ad04dca886dd5692d5dca372\u003C/li>\n\u003Cli>live: 9a6ab97bf4737217ad04dca886dd5692d5dca372\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: C291: the finger target is the lane, the ink stays subtle — 44px lane on phones / 24px desktop, 6px zinc-400 bar pinned to the edge, no grey track slab, same drag map and tick jumps; reversible by restoring w-2/right-1 and the bg-base-300 track\u003C/li>\n\u003C/ul>\n\u003Ch3>C292\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: scripts/daisy-audit.ts, src/routes/+layout.svelte, src/routes/+page.svelte\u003C/li>\n\u003Cli>verify: script\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>bun scripts/daisy-audit.ts exits 0: daisyUI is the only UI kit (lucide icons excepted — daisyUI ships none), src/app.css loads only tailwind + daisyUI with the single pinned light theme, src/app.html loads no external UI asset, and every visible input/select/textarea/table/progress carries its daisyUI class\u003C/li>\n\u003Cli>adding bootstrap to package.json or reverting the header search / dashboard bar to raw utilities makes it exit 1\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: 5cbe9b680f92e469ada36a44c6cffc3373bf1b7f\u003C/li>\n\u003Cli>live: 5cbe9b680f92e469ada36a44c6cffc3373bf1b7f\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: C292: daisyUI is the app's only kit — read as (a) icons stay (lucide-svelte; daisyUI has no icon set), (b) paper sheets keep their own .tbl grid (daisyUI has no print component) and are named in PAPER_SHEETS, (c) layout buttons (rows, tiles, keypad keys, backdrops) keep utilities but no button is left unstyled, (d) one exemption list for controls daisyUI cannot express (the NumberWheel typing slot), which fails when stale\u003C/li>\n\u003C/ul>\n\u003Ch3>C293\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/\">https://trading.tynolabs.com/\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: d1e22c2e50dff79fddb3eb7d4fc20ab9a14e249c\u003C/li>\n\u003Cli>live: d1e22c2e50dff79fddb3eb7d4fc20ab9a14e249c\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting\u003C/li>\n\u003C/ul>\n\u003Ch3>C294\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: src/lib/components/ScrollMap.svelte, src/app.css, scripts/scroll-map.ts, docs/UIPATTERN.md\u003C/li>\n\u003Cli>verify: script\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>the dashboard shows one vertical scrollbar, not two: the rail marks its screen (data-scroll-rail) and the shell's native bar is hidden there while the rail is mounted\u003C/li>\n\u003Cli>every other screen keeps the app-wide scroll skin\u003C/li>\n\u003Cli>bun scripts/scroll-map.ts ALL PASS and fails 2 checks on the pre-fix CSS\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: 809d7434fccb0118f167edc2d68377e156175d83\u003C/li>\n\u003Cli>live: 809d7434fccb0118f167edc2d68377e156175d83\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: the rail is the dashboard's scrollbar (owner vocabulary, C289/C291); the native bar drawn under it is the extra one - hide it there only, app-wide skin untouched\u003C/li>\n\u003C/ul>\n\u003Ch3>C295\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: src/app.css, src/lib/components/ScrollMap.svelte, scripts/scroll-map.ts, docs/UIPATTERN.md\u003C/li>\n\u003Cli>verify: script\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>the dashboard draws the app-wide skinned bar and no other: no screen hides it (no scrollbar-width:none, no rail marker selector)\u003C/li>\n\u003Cli>the rail paints no thumb ink and keeps its tick pips + drag lane\u003C/li>\n\u003Cli>bun scripts/scroll-map.ts ALL PASS and fails 5 checks on the pre-fix CSS\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: 1f876750e9d2a689fff0df11333332bda0d2163a\u003C/li>\n\u003Cli>live: 1f876750e9d2a689fff0df11333332bda0d2163a\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: og = the app-wide skinned scrollbar in app.css (10px zinc thumb); the rail keeps its ticks + the invisible 44px drag lane and paints no bar of its own\u003C/li>\n\u003C/ul>\n\u003Ch3>C296\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: src/lib/nav.ts, src/routes/+layout.svelte, scripts/nav-audit.ts, docs/UIPATTERN.md\u003C/li>\n\u003Cli>verify: script\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>the labelled sidebar draws the two standalone rows plus one section's links only: 10 rows at rest and 22 at worst with a section open for any role (45 before), and exactly one section is open\u003C/li>\n\u003Cli>every screen in src/routes is a sidebar row, a utility link or a declared HIDDEN entry with its reason, and no screen has two rows or two rows one name\u003C/li>\n\u003Cli>bun scripts/nav-audit.ts ALL PASS (16 checks) and exits 1 with 4 FAILs on the pre-fix shell (no #lib/nav import, 50 inline href literals, no aria-expanded toggle, no icon map)\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: 6c945414538ff12e7b3920e3c50bd138bafc4422\u003C/li>\n\u003Cli>live: 6c945414538ff12e7b3920e3c50bd138bafc4422\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: minimal sidebar = one work group open at a time (the one that owns the current screen, or the last tapped); the collapsed desktop rail keeps every icon because a rail is a launcher, not a map; flow screens stay HIDDEN-but-declared; the eight existing groups are the organisation\u003C/li>\n\u003C/ul>\n\u003Ch3>C297\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: src/lib/components/ListToolbar.svelte, src/lib/components/RecordDialog.svelte, src/lib/components/SmartTable.svelte, src/routes/pending/+page.svelte, scripts/readability-audit.ts, docs/UIPATTERN.md\u003C/li>\n\u003Cli>verify: script\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>ListToolbar: every control is a lucide icon + its word (Funnel filter badge, Clear, CSV, prev/next chevrons, 'Showing 1-50 of 300' count) and every filter select is aria-labelled\u003C/li>\n\u003Cli>RecordDialog: fields are a two-column chip grid and the action row is first=primary then outline with a worded Close and 44px phone taps\u003C/li>\n\u003Cli>SmartTable default row action is a btn btn-outline btn-xs with ChevronRight, not a text link\u003C/li>\n\u003Cli>/pending renders one card per parked lot and booking with unchanged POST actions/hidden ids/contract picker/enhance and no \u003Ctable>\u003C/li>\n\u003Cli>bun scripts/readability-audit.ts ALL PASS (24 checks) and 16 FAILs on the pre-fix tree\u003C/li>\n\u003Cli>svelte-syntax + daisy-audit + bun run check green in the touched files\u003C/li>\n\u003Cli>no route/field/validation/schema change\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: 768a4ff4c72dc5e63894c0bce5453d480481c6c0\u003C/li>\n\u003Cli>live: 768a4ff4c72dc5e63894c0bce5453d480481c6c0\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: throughout the website = the shared surfaces first (list toolbar, row popup, plain-table row action) plus the one action screen still on dense tables; icons always come with their word, never icon-only; cards only where they replace a dense table on a phone-first action screen; no route/field/POST change\u003C/li>\n\u003C/ul>\n\u003Ch3>C298\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: src/app.html, src/lib/nav.ts, src/routes/+layout.svelte, src/hooks.server.ts, src/lib/staticCache.ts, scripts/lighthouse-audit.ts\u003C/li>\n\u003Cli>verify: script\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>every screen has a branded \u003Ctitle> (titleFor: dashboard = 'Trading — greige platform', /signin = 'Sign in · Trading', /orders?type=SO = 'Sale · Trading', any nav row, hidden screen or utility named) and the root layout renders it in \u003Ca href=\"svelte:head\">svelte:head\u003C/a> while a page's own \u003Ctitle> still wins\u003C/li>\n\u003Cli>app.html carries \u003Chtml lang>, a 60-160 char meta description, theme-color equal to the manifest's, a light-only color-scheme, the Inter stylesheet off the critical path (media=print + onload swap, \u003Cnoscript> fallback) and the manifest+favicon links\u003C/li>\n\u003Cli>the server hook gives static assets (icon, manifest, robots.txt) cache-control max-age=86400 and leaves /_app/immutable/**, page loads and /upload-file untouched\u003C/li>\n\u003Cli>bun scripts/lighthouse-audit.ts ALL PASS (22 checks) and exits 1 with 18 FAILs on the pre-fix tree\u003C/li>\n\u003Cli>no route, field, validation, query, action, schema, theme or role rule changes\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: 721f3051089a2bfbadb1be01fcb4a16acf502676\u003C/li>\n\u003Cli>live: 721f3051089a2bfbadb1be01fcb4a16acf502676\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: the server-rendered head and headers are this row's whole surface: a per-screen title from the nav map (the sidebar row names the screen), description/theme-color/color-scheme, the third-party font off the critical path, and a static-asset cache policy; app-level gzip is skipped because Cloudflare already compresses text for the public URL and re-encoding on this phone's CPU would cost more than it saves; browser-only audits (contrast, CLS, tap targets, LCP) stay for later rows\u003C/li>\n\u003C/ul>\n\u003Ch3>C299\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: src/routes/+page.svelte, scripts/dashboard-audit.ts, docs/UIPATTERN.md\u003C/li>\n\u003Cli>verify: script\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>the home page draws nine section rows with exactly one open at rest (the row whose cards carry the most bad/warn KPIs) and every closed row shows N red / N watch / N cards\u003C/li>\n\u003Cli>cards render only inside a row: phone carousel (C293) + sm+ grid, 29 cards x 2 surfaces, card language (tooltip, KPI chips, gm progress bars) unchanged\u003C/li>\n\u003Cli>one New dropdown in the header reaches the 8 role-filtered type-fixed forms with an icon + word each at min-h-11, and no Quick add block is left at the bottom\u003C/li>\n\u003Cli>page order is needs action -> dates -> 14-day pulse -> boards, with the period GET form, the SSE attention strip and the ScrollMap ticks kept\u003C/li>\n\u003Cli>bun scripts/dashboard-audit.ts ALL PASS (23 checks) and exits 1 with 10 FAILs on the pre-fix file\u003C/li>\n\u003Cli>no route/action/field/validation/schema/theme/role change and no edit/delete affordance\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: 4a9021d575a5e818517283c9d13dc39194331c9b\u003C/li>\n\u003Cli>live: 4a9021d575a5e818517283c9d13dc39194331c9b\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: dashboard = the master board at /, not the /board/[slug] component pages; chaos = hierarchy and reach, so every card and number stays and the fix is one open collapse row + one typed New control on top + a red/watch/cards tally on every closed row; the engine's nine SECTIONS rows are the organisation; the phone carousel stays inside the open section because C293's swipe is signed behaviour; the period filter keeps its place and its GET form\u003C/li>\n\u003C/ul>\n\u003Ch3>C300\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: src/lib/components/focus/FocusEntry.svelte, src/lib/focusWizard.ts, scripts/focus-wizard-audit.ts, docs/FOCUS-ENTRY.md\u003C/li>\n\u003Cli>verify: script\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>the shared entry wizard opens on the first step whose value is still empty (winding with a sizing-gate carry answering winderId/sizerSetNo/expectedKg opens on recNet)\u003C/li>\n\u003Cli>a form whose every step is already answered opens on its summary with no wizard popup\u003C/li>\n\u003Cli>no step is lost - every step still opens from its summary row and a cold form still opens on step 0\u003C/li>\n\u003Cli>Next walks forward over steps a carry already answered\u003C/li>\n\u003Cli>the signed booking/tippan/order/quote step lists and every POST name, action, field, validation, schema, theme and role rule are unchanged\u003C/li>\n\u003Cli>bun scripts/focus-wizard-audit.ts ALL PASS (15) and 3 FAILs with exit 1 on the pre-fix shell\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: 09d39df211ec42574710c163618bdbb9cd1cfcd9\u003C/li>\n\u003Cli>live: 09d39df211ec42574710c163618bdbb9cd1cfcd9\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: wizard = the shared one-field FocusEntry shell: it starts on the first step whose value is still empty and stays closed when every step is answered, carried values are confirmed from their summary row, and the signed booking/tippan/order/quote step splits are left exactly as the owner last fixed them\u003C/li>\n\u003C/ul>\n\u003Ch3>C301\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/gatepasses\">https://trading.tynolabs.com/gatepasses\u003C/a>\u003C/li>\n\u003Cli>verify: script\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>the New gatepass control on /gatepasses is one plain link — no dropdown menu of gatepass types, no summary element\u003C/li>\n\u003Cli>on a kind screen (/gatepasses?kind=WINDING, ?kind=DIRECT, …) that link opens /gatepasses/new?kind=\u003Cthat kind> and the form's badge shows that kind\u003C/li>\n\u003Cli>on the unfiltered /gatepasses the link opens the plain /gatepasses/new (validated default, never 500)\u003C/li>\n\u003Cli>the empty-state New gatepass button carries the same kind href\u003C/li>\n\u003Cli>every kind stays reachable (the sidebar's eight kind rows) and the list body, filters, tabs, totals and row dialogs are unchanged\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: 1bf6e33a1218e7b896dbb142486aebde83e42441\u003C/li>\n\u003Cli>live: 1bf6e33a1218e7b896dbb142486aebde83e42441\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: the screen that is open means its kind filter: a /gatepasses?kind=… screen (the eight sidebar rows) opens that same kind's new record, the unfiltered All screen opens the default form, and the kinds stay reachable from the sidebar rows so the removed menu strands nothing\u003C/li>\n\u003C/ul>\n\u003Ch3>C302\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/gatepasses/new?kind=YARN_IN\">https://trading.tynolabs.com/gatepasses/new?kind=YARN_IN\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>/gatepasses/new?kind=YARN_IN asks a Yarn use (warp / weft) row with Warp / Weft / Both\u003C/li>\n\u003Cli>a picked booking prefills it from the booking's own warp/weft tag and it stays tappable to change\u003C/li>\n\u003Cli>saving posts warpWeft (warp|weft|both) into the creation event and the record page shows Yarn use\u003C/li>\n\u003Cli>an unknown posted value is a visible field error and is never stored\u003C/li>\n\u003Cli>the yarn-in's delivered lot carries the same tag on /lots and the lot record (a soft tag, nothing locks a warp lot out of weft use)\u003C/li>\n\u003Cli>the other seven kinds' forms are unchanged (no such row)\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: f163017badfa44c7d4c51541e987a151a593cf3f\u003C/li>\n\u003Cli>live: f163017badfa44c7d4c51541e987a151a593cf3f\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: the 'loose link that can change later' means a soft TAG, never a constraint: it defaults from the picked booking's own warp/weft, stays optional and tappable on the form, lands on the delivered lot (lot.warp_weft, already shown on /lots and the lot record) and nothing in the system locks a warp lot out of weft use; a later change is an appendage/amend, never an overwrite, and no edit screen is added\u003C/li>\n\u003C/ul>\n\u003Ch3>C303\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/gatepasses/new?kind=YARN_IN\">https://trading.tynolabs.com/gatepasses/new?kind=YARN_IN\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>the yarn-in reference picker shows three source tabs — SO / production order, Yarn booking, Job work — in that order, all three always present\u003C/li>\n\u003Cli>the SO / production order tab lists every open SO and open PROD order with its own requirement, computed by the quote formula (src/lib/server/yarnMath.ts computeDesignWeights, docs/COSTING.md §5) × the order's mtrs — one line per warp row and per weft row (multiple yarns never merged), warp at the quote's costing weight and weft with waste\u003C/li>\n\u003Cli>each SO / production order row shows kgs received till date / kgs to be received, the requirement being what the quote formula gives and the pending figure never negative\u003C/li>\n\u003Cli>the Yarn booking tab shows total kgs received / total kgs booked per booking\u003C/li>\n\u003Cli>the Job work tab shows the weft requirement computed the same way (quote formula × mtrs) and the kgs received / kgs booked for that job-work booking\u003C/li>\n\u003Cli>picking a row from any of the three tabs still fills the form exactly as today (trader, yarn count/type/ticket, rate, warp/weft tag where the source has one) and posts only the fields the form posts today\u003C/li>\n\u003Cli>an order or booking whose design / construction is missing shows — in the kg columns, never 0, NaN or a 500, and stays pickable\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: 28faca5194139eadc06ab5d7bdba4f9bfd881058\u003C/li>\n\u003Cli>live: 28faca5194139eadc06ab5d7bdba4f9bfd881058\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | owner amended 2026-10-29: three reference sources for a yarn inward (SO trading / production order, yarn booking, job work)\u003C/li>\n\u003C/ul>\n\u003Ch3>C304\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/gatepasses/new?kind=YARN_IN\">https://trading.tynolabs.com/gatepasses/new?kind=YARN_IN\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: 587bf8e51a184270391874986669e2771c0d9ba9\u003C/li>\n\u003Cli>live: 587bf8e51a184270391874986669e2771c0d9ba9\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting\u003C/li>\n\u003C/ul>\n\u003Ch3>C305\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/gatepasses/new?kind=YARN_IN\">https://trading.tynolabs.com/gatepasses/new?kind=YARN_IN\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: ad3dee5747a63333d232ed04839c9455f337f189\u003C/li>\n\u003Cli>live: ad3dee5747a63333d232ed04839c9455f337f189\u003C/li>\n\u003Cli>notes: C305: the yarn-in photo section is one Gatepass photo row; ocrDoc/document/dictateText rows and their dead client code removed; server fields untouched | assumed: the kept field is the existing image row (file name + Add/Replace), and the detail page's read-only uploads card stays for legacy records\u003C/li>\n\u003C/ul>\n\u003Ch3>C306\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/gatepasses/new?kind=YARN_IN\">https://trading.tynolabs.com/gatepasses/new?kind=YARN_IN\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: c61fbf0f510823c58912f7fbe5b92bebcf342ff3\u003C/li>\n\u003Cli>live: c61fbf0f510823c58912f7fbe5b92bebcf342ff3\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: the OCR detection is a wizard step (the owner named the wizard pop-up), reading through the existing /api/capture-ocr gatepass reader, offered on a fresh yarn-in only (C300 carries keep their flow; the summary row still opens it), and a read prefills the form's own count/type/mill/bags/vehicle/transport rows only — no new POST name, and the read wins over an earlier value\u003C/li>\n\u003C/ul>\n\u003Ch3>C307\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/gatepasses/new?kind=YARN_IN\">https://trading.tynolabs.com/gatepasses/new?kind=YARN_IN\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: 29f804318e45664475963333584c13ef9c22f95d\u003C/li>\n\u003Cli>live: 29f804318e45664475963333584c13ef9c22f95d\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: The yarn-in wizard is ordered gatepassRead, warpWeft, bags, bookingPick, countYarn, yarnTypeCode, ticket, destPlace, partnerGpNo; point 5 is the yarn rows the form actually draws (yarn booking: one static row, so no step; SO order / job work: three picks); OCR-filled steps are skipped by C300 while answered and points 1, 2 and 4 always show; the C113 booking gate, the optional warp/weft and the optional trader's GP no are kept as they are; and since bags and warp/weft are now asked before the reference pick, a pick fills them only when the form has none (no silent overwrite of a typed or OCR-read value).\u003C/li>\n\u003C/ul>\n\u003Ch3>C308\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/gatepasses/new?kind=YARN_IN\">https://trading.tynolabs.com/gatepasses/new?kind=YARN_IN\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>the yarn-in form shows a Verify fields button at the top of the screen\u003C/li>\n\u003Cli>tapping it pins the uploaded gatepass photo in a frozen pane on the top third of the screen, zoomable in and out, while the rest of the form scrolls beneath it\u003C/li>\n\u003Cli>a small cross on the pane closes it and the form returns to its normal layout\u003C/li>\n\u003Cli>the pane shows the Gatepass photo when one was uploaded, else the file the read step saved, and says there is no gatepass yet when there is neither\u003C/li>\n\u003Cli>the other seven kinds' forms are unchanged (no such button or pane)\u003C/li>\n\u003Cli>no new POST name, column, migration, route or edit/delete screen\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: c938b7fa2d0171638ed0a94b747dac30db01e4d3\u003C/li>\n\u003Cli>live: c938b7fa2d0171638ed0a94b747dac30db01e4d3\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: the frozen pane is the shipped gatepass photo (the Gatepass photo row when it has one, else the file the gatepass read saved) and it covers the top third of the viewport (33vh, sticky) with the form scrolling under it, not a second copy of the photo row; the button is on the yarn-in form only, the row's target; the shared field popups and the wizard stay full-screen overlays exactly as they are, so the pane is used against the summary rows and a field is checked from its row value; ?verify=1 reopens the pane after a reload; zoom is a 50-400% width scale in 25% steps (pinch is the browser's own zoom)\u003C/li>\n\u003C/ul>\n\u003Ch3>C309\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/gatepasses/new?kind=YARN_IN\">https://trading.tynolabs.com/gatepasses/new?kind=YARN_IN\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>each reference tab shows ONE kgs pending / required column (no separate kg-in, pending or requirement columns)\u003C/li>\n\u003Cli>a quality with multiple warp/weft yarns lists its counts in that same cell, with — for a figure that cannot be computed\u003C/li>\n\u003Cli>the SO / production order and yarn booking tabs take several picks and can be mixed\u003C/li>\n\u003Cli>the job-work tab takes one pick and clears any other\u003C/li>\n\u003Cli>with more than one pick the form shows a live split of the gatepass's boxes with each row's yarn count, pending kg, a +/- one-bag stepper capped at its pending, the kg those boxes carry and its further pending\u003C/li>\n\u003Cli>changing the bags re-divides\u003C/li>\n\u003Cli>a job-work reference mixed with another, an unknown reference and a split taking more boxes than the gatepass are visible field errors on save and nothing is stored\u003C/li>\n\u003Cli>a valid mixed split saves and rides the creation event, the first pick still posting the bookingId\u003C/li>\n\u003Cli>no new column, migration, route or edit/delete screen and the other seven kinds unchanged\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: 04c27ab007f7d1fcc89ec1d565a74653d6b7a7d0\u003C/li>\n\u003Cli>live: 04c27ab007f7d1fcc89ec1d565a74653d6b7a7d0\u003C/li>\n\u003Cli>notes: - | assumed: one kgs pending / required column per tab (count-wise in that cell when the quality has several warp/weft yarns, requirement per count and pending per order since received kg is tracked per order); the SO / production order and yarn booking tabs are multi-select and mix, the job-work tab is picked alone and clears the others; the first pick stays the form's single reference (yarn identity, trader, posted bookingId) and the box split rides the creation event as allocation, never a new booking; the equal split is recomputed from the bags and each row's cap whenever either changes, with the +/- stepper as the user's override; the SO tab keeps every open SO/PROD order (C303's list unchanged) | pre-checked: read the yarn-in reference block: the picker is single-select today (bookingPick/batch state in gatepasses/new/+page.svelte) and the server loads openOrders + openBookings + job work; the alloc grid is new state on the same page, no schema\u003C/li>\n\u003C/ul>\n\u003Ch3>C310\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/masters\">https://trading.tynolabs.com/masters\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>the yarn form (Add and Edit) shows a Mill / ticket picker whose options are the mill/ticket master values plus the yarn's own current mill\u003C/li>\n\u003Cli>a yarn saved with a mill stores it and its name reads count + type + mill\u003C/li>\n\u003Cli>blank keeps a mill-less yarn\u003C/li>\n\u003Cli>a mill outside the mill-master name rule is a visible error on save and nothing is stored\u003C/li>\n\u003Cli>no new column, migration, route or edit/delete screen and the other master tabs unchanged\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: e87d2e729a6c1aa34ad8e47462325684223adfc8\u003C/li>\n\u003Cli>live: e87d2e729a6c1aa34ad8e47462325684223adfc8\u003C/li>\n\u003Cli>notes: - | assumed: mill / ticket is an optional picker from the mill/ticket master (blank = no mill; the booking's own step fills it), the yarn name keeps count + type + mill, and both yarn actions enforce the mill master's MILL_RE | pre-checked: YarnForm.svelte keeps ticket as a HIDDEN input (line 70) — the mill field was dropped from the form while the column and the mill/ticket master (tab mill-ticket) remain, so this is re-mounting an existing field against an existing master\u003C/li>\n\u003C/ul>\n\u003Ch3>C311\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/masters\">https://trading.tynolabs.com/masters\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>Masters → Counts tab (/masters?tab=count) lists every distinct yarn count once, ascending, plus any count added there by hand\u003C/li>\n\u003Cli>Add count stores a positive number and it appears in the list at once: 0 / abc / 61.555 / 12345 are visible field errors and nothing is stored\u003C/li>\n\u003Cli>The yarn form Count field offers the count master values one-tap and still accepts a typed number, with the same rule shown as a field error on create and edit\u003C/li>\n\u003Cli>A count already on a yarn or already in the master is refused with a visible duplicate message (409) and nothing is stored\u003C/li>\n\u003Cli>No edit/delete screen added, and the other master tabs plus the yarn mill picker and the booking wizard quick-add yarn behave exactly as before\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: 5fa8e65af91d7edec97555ede56fec9ac2774196\u003C/li>\n\u003Cli>live: 5fa8e65af91d7edec97555ede56fec9ac2774196\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: the count master is a projection of the yarn master's counts plus hand-added counts (like C168 mill/weave), the yarn Count field offers the master as a datalist and still takes a typed number, and one COUNT_RE (>0, 4 digits, 2 decimals) is enforced on the count form and on yarn create/edit\u003C/li>\n\u003C/ul>\n\u003Ch3>C312\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/masters\">https://trading.tynolabs.com/masters\u003C/a>\u003C/li>\n\u003Cli>verify: script\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>a Type master tab lists every yarn type once — codes already on a yarn project in, a code added by hand is stored with its label\u003C/li>\n\u003Cli>the yarn form's Type field offers the type master's codes with their labels and a code added there saves on a yarn\u003C/li>\n\u003Cli>a type already on a yarn or in the master is refused with a visible duplicate message (409) and nothing is stored\u003C/li>\n\u003Cli>a type code or label outside the standard format gets a visible field error on the type form and on yarn create/edit (400), nothing stored\u003C/li>\n\u003Cli>no edit/delete screen added, and the other master tabs plus the yarn mill/count pickers behave exactly as before\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: a377f89b7be093a0b55a4d2833ab6b762616599d\u003C/li>\n\u003Cli>live: a377f89b7be093a0b55a4d2833ab6b762616599d\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: the type master is the projection of the yarn master's own type_code plus hand-added codes, each with an optional label; new codes beyond the standard eight are allowed and the gatepass yarn-type rule follows them; the yarn Type field is a picker over the master that also keeps a yarn's own legacy value\u003C/li>\n\u003C/ul>\n\u003Ch3>C313\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/gatepasses/new?kind=YARN_IN\">https://trading.tynolabs.com/gatepasses/new?kind=YARN_IN\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>an SO / production order or job-work pick asks ONE yarn row from the yarn master (count + type + mill in one line), not three\u003C/li>\n\u003Cli>the create action stores the picked yarn's count, type and mill from the yarn id alone\u003C/li>\n\u003Cli>a stale yarn id is a visible 400 field error and saves nothing\u003C/li>\n\u003Cli>a yarn booking still inherits its own yarn and asks nothing new\u003C/li>\n\u003Cli>the wizard asks the same one row in place of the three\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: 1b3ed3807b5c4a213d42458f3a67efcefb7dbc3f\u003C/li>\n\u003Cli>live: 1b3ed3807b5c4a213d42458f3a67efcefb7dbc3f\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: the picked yarn-master row is the authority for count + type + mill — it posts as a new optional yarnId and the create action reads the three off the master (legacy countYarn/yarnTypeCode/ticket still accepted), a stale id is a visible 400, and the pick is required only when a picked reference has no yarn to inherit\u003C/li>\n\u003C/ul>\n\u003Ch3>C314\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/gatepasses/new?kind=YARN_IN\">https://trading.tynolabs.com/gatepasses/new?kind=YARN_IN\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>the yarn-in wizard asks Bags, then Cones and Bag weight (kg/bag) right after it, and the POST stores all three on the gatepass\u003C/li>\n\u003Cli>cones and bag weight offer the same yarn's previous values as one-tap chips and stay blank when it has none\u003C/li>\n\u003Cli>a bag weight of 0/'abc' or a junk/negative cone count is a visible field error (400) and stores nothing\u003C/li>\n\u003Cli>a receipt carrying its own bag weight counts toward the reference's received kg even with no net\u003C/li>\n\u003Cli>every other kind's rows and posts are unchanged\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: 0879d0351102dc126fe818fc48776bace8879457\u003C/li>\n\u003Cli>live: 0879d0351102dc126fe818fc48776bace8879457\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: the row's two new fields are the gatepass's own total cones (the existing cones column) and a new kg-per-bag column bagWt; the same yarn means the same yarn count as the existing bags suggestions, values come from past YARN_IN/DIRECT receipts, and the bag weight is optional (net ₹ receipts still work)\u003C/li>\n\u003C/ul>\n\u003Ch3>C315\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: src/lib/server/intake.ts, src/lib/server/captureOcr.ts, src/lib/server/captureRouting.ts, src/routes/gatepasses/new/+page.svelte\u003C/li>\n\u003Cli>verify: browser\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>a gatepass whose printed Booking No. matches an open reference arrives with that reference pre-selected (yarn/count/type/trader/rate filled from it)\u003C/li>\n\u003Cli>a number matching nothing open rides as a searchable chip, nothing is picked\u003C/li>\n\u003Cli>the read still commits nothing\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: dca5f8f403bbbf7998e26f627e738617a86be5c1\u003C/li>\n\u003Cli>live: dca5f8f403bbbf7998e26f627e738617a86be5c1\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: the read extracts the trader's printed Booking No. (intake + DOC_SYSTEM + routing); the gatepass load resolves it against the open/partial bookings already in the reference picker and pre-selects that one row (trader, yarn, count, type and rate then come from the booking); an unmatched number only seeds the picker's search and shows as a chip; a direct-delivery read still opens DIRECT; nothing is posted or committed by the read\u003C/li>\n\u003C/ul>\n\u003Ch3>C316\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: src/lib/server/intake.ts, src/lib/server/captureOcr.ts, src/lib/yarnTypes.ts, src/lib/gatepassOcr.ts, src/routes/gatepasses/new/+page.svelte\u003C/li>\n\u003Cli>verify: browser\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>'61s Combed Compact - Classic Yarn' reads count 61 + type CCW with no literal CW on the paper\u003C/li>\n\u003Cli>40 CW / 30s KW / 150 Dn also read\u003C/li>\n\u003Cli>the resolved value is one yarn-master entry (count+type+mill), else a suggestion chip\u003C/li>\n\u003Cli>type words map to the type master (C312)\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: 5e9fe6660dd510422e8b26902fb5823b4deec34c\u003C/li>\n\u003Cli>live: 5e9fe6660dd510422e8b26902fb5823b4deec34c\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: the reader's type vocabulary is the type master's built-in list (src/lib/yarnTypes.ts, C312) plus the words its labels carry — karded/combed/combed compact/karded compact/denier/hank/lycra/slub — mapped to canonical codes; a hand-added master code can still be read when the paper prints the code itself; the prefill carries count+type in countYarn as it already did, and the form splits it; an unmatched read is a chip (C319 owns the tap-to-create chain)\u003C/li>\n\u003C/ul>\n\u003Ch3>C317\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: src/lib/server/intake.ts, src/lib/server/captureOcr.ts, src/lib/server/formMemory.ts\u003C/li>\n\u003Cli>verify: script\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>the spinner line 'Gvg Elite Yarns And Fabrics (tex Div Of Gvg Paper Mills) Gpm' resolves to the mill master's entry (GVG Classic)\u003C/li>\n\u003Cli>the word 'Vishnu' in 'Vishnu Chambers, Shahu Corner' never becomes a mill\u003C/li>\n\u003Cli>an unknown mill is offered, never invented\u003C/li>\n\u003Cli>[reopen 2026-10-29] does not work on the real paper: readMill() returns {} for the Goenka gatepass because the spinner line 'Gvg Elite Yarns And Fabrics (tex Div Of Gvg Paper Mils) Gpm' sits directly under the goods line '61s Combed Compact - Classic Yarn 520524 3 ...' and the 6-digit HSN code 520524 trips ADDRESS_RE, so addressContext() marks the NEXT line as address and the spinner line is skipped (probe on the live draft's raw_text: ticket undefined, millHint undefined). Fix the neighbour poisoning and add this paper as a regression test.\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: 2d7d2dbc9bf767d38607aa9cc805ebaf5076178d, 2a0b608d901b4ba6c1966e0b071e1e440e2cf72f\u003C/li>\n\u003Cli>live: 2d7d2dbc9bf767d38607aa9cc805ebaf5076178d\u003C/li>\n\u003Cli>notes: does not work on the real paper: readMill() returns {} for the Goenka gatepass because the spinner line 'Gvg Elite Yarns And Fabrics (tex Div Of Gvg Paper Mils) Gpm' sits directly under the goods line '61s Combed Compact - Classic Yarn 520524 3 ...' and the 6-digit HSN code 520524 trips ADDRESS_RE, so addressContext() marks the NEXT line as address and the spinner line is skipped (probe on the live draft's raw_text: ticket undefined, millHint undefined). Fix the neighbour poisoning and add this paper as a regression test. | pre-checked: reproduced on the live draft's raw_text: readMill() returns {} because the goods line's 6-digit HSN code 520524 trips ADDRESS_RE and addressContext() then marks the spinner line below it as an address, so printedMillName skips it; the Goenka paper is the regression case | assumed: the fix is the neighbour rule in intake.ts addressContext(): a line is an address by its address words, or by a bare 6-digit number unless that line names a mill/spinner; only the address WORDS spread to neighbours, and never over a mill/spinner line — so the HSN on the goods line no longer hides the spinner below it and a spinner printed above a two-line address still reads. The regression lives in scripts/mill-read-audit.ts (this checkout has no tests/ suite).\u003C/li>\n\u003C/ul>\n\u003Ch3>C318\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: src/lib/server/formMemory.ts, src/lib/server/captureOcr.ts, src/routes/gatepasses/new/+page.server.ts\u003C/li>\n\u003Cli>verify: browser\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>a value the user corrected on save is learned against the read transcript's words\u003C/li>\n\u003Cli>a later read carrying the same words resolves that field from memory before the gateway is asked\u003C/li>\n\u003Cli>the gatepass save still succeeds when the memory write fails\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: 2fb66ab0f34e6cf59117900e950a3e3278bbbe69\u003C/li>\n\u003Cli>live: 2fb66ab0f34e6cf59117900e950a3e3278bbbe69\u003C/li>\n\u003Cli>notes: - | jobwork | outsource | production | booking and no gatepass caller exists; parseReadFields/changedFromRead and the best-effort learn contract are already there to reuse; the draft already stores the read transcript, the form already posts it back | pre-checked: row-watch: read the row and its target before starting | assumed: the gatepass teaches form memory the kinds it carries (count, type, ticket/mill, godown, transporter, yarn) from the draft the form was opened with: the transcript words link to the value the user confirmed, and the next read applies them ahead of the model's answer; godown is kept in the read's own vocabulary (our-godown→godown); a confirmed mill the master lacks is kept verbatim, a mill the master carries reads in the master's spelling; the yarn kind is learnt but not replayed (the inward's count/type/mill already come from that row)\u003C/li>\n\u003C/ul>\n\u003Ch3>C319\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: src/lib/components/focus/FocusEntry.svelte, src/lib/components/gate/GatepassOcrRead.svelte, src/routes/masters/+page.svelte, src/routes/gatepasses/new/+page.svelte\u003C/li>\n\u003Cli>verify: browser\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>an unmatched read value appears as a chip that opens the right master prefilled (yarn from count/type/mill, a new mill chaining into mill/ticket and back)\u003C/li>\n\u003Cli>saving returns to the yarn inward intimation with the new entry selected\u003C/li>\n\u003Cli>nothing is created without the user's tap\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: d68f270adf059ba090d5292b469097bcd00255b3\u003C/li>\n\u003Cli>live: d68f270adf059ba090d5292b469097bcd00255b3\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: the read's chip carries count+type in ?new= and the mill in ?mill=; the yarn master's mill field is the same + chip into ?tab=mill-ticket&new=\u003Cmill>&returnTo=\u003Cthe yarn link> and comes back; a yarn save returns to the form as ?yarnId=\u003Cid>&ticket=\u003Cmill> and the inward shows that yarn row selected (the master row is the authority for count/type/mill); the masters page opens only the yarn and mill/ticket add dialogs on ?new= (the other masters are C320/C321), the return target must be a path on this app, and nothing is written before the user's own Add tap\u003C/li>\n\u003C/ul>\n\u003Ch3>C320\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: src/routes/gatepasses/new/+page.svelte, src/lib/components/focus/FocusEntry.svelte, src/routes/masters/+page.svelte\u003C/li>\n\u003Cli>verify: browser\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>godown/location, party/trader and transporter each offer the read value as a chip into their own master, prefilled, returning selected\u003C/li>\n\u003Cli>no master is written without a user tap\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: ed327d9779857dae505a49b98e29eccecf777724\u003C/li>\n\u003Cli>live: ed327d9779857dae505a49b98e29eccecf777724\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: the chip stands on the value the form carries (the read's transporter, the picked reference's printed supplier that matched no party, a named pickup place that is not a Godown/Sizing party); the location master is the party rows of category Godown or Sizing; a save returns ?field=&partyId=&party= to the form, which selects it (a created trader rides sourcePartyId, which the yarn-in/direct delivery already posts and the server reads before the booking's); a value the master already carries shows no chip and nothing is written without the user's Add tap\u003C/li>\n\u003C/ul>\n\u003Ch3>C321\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: src/lib/components/focus/FocusEntry.svelte, src/routes/masters/+page.svelte, src/routes/masters/+page.server.ts\u003C/li>\n\u003Cli>verify: browser\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>typing a value absent from the master shows '+ \u003Ctyped text>' as the last row of the pick list, on every master-backed field\u003C/li>\n\u003Cli>tapping opens that master's add dialog prefilled from ?tab=&new=\u003C/li>\n\u003Cli>the saved entry returns selected to the field\u003C/li>\n\u003Cli>nothing changes when the text matches a value\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: ffdc9b5a3a9effd8cc6abefebbf58a858cfdf47d\u003C/li>\n\u003Cli>live: ffdc9b5a3a9effd8cc6abefebbf58a858cfdf47d\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting\u003C/li>\n\u003C/ul>\n\u003Ch3>C322\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P0\u003C/li>\n\u003Cli>target: src/lib/server/intake.ts\u003C/li>\n\u003Cli>verify: script\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>a header printed 'GATE PASS' reads intent=gatepass (today it lands on booking)\u003C/li>\n\u003Cli>the glued 'gatepass' case keeps working\u003C/li>\n\u003Cli>a regression test named for the spaced header passes fixed and fails pre-fix\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: 48129381179aa383299554d2a14a33d47181ee2a\u003C/li>\n\u003Cli>live: 48129381179aa383299554d2a14a33d47181ee2a\u003C/li>\n\u003Cli>notes: - | gatepass)\\b, so 'GATE PASS' falls through to the booking pattern on 'Booking No. : 1128'; a one-line regex plus a test named for it | pre-checked: row-watch: read the row and its target before starting | assumed: the fix is the one-line gate\\s*pass intent pattern in intake.ts (it still matches the glued GATEPASS OCR seam); the regression lives in scripts/mill-read-audit.ts because this checkout has no tests/ suite (7668c583, deploy --no-suite)\u003C/li>\n\u003C/ul>\n\u003Ch3>C323\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P2\u003C/li>\n\u003Cli>target: src/lib/server/formMemory.ts, src/routes/tippans/new/+page.server.ts, src/routes/samples/+page.server.ts, src/routes/quote\u003C/li>\n\u003Cli>verify: browser\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>the tippan, sample and quote reads learn on save and resolve on the next read, the same loop the order and booking readers use\u003C/li>\n\u003Cli>a memory write never fails a form's save\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: 2f48b674ff0caf6e0da87020deef96a8f41d8a81\u003C/li>\n\u003Cli>live: 2f48b674ff0caf6e0da87020deef96a8f41d8a81\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: the tippan/sample/quote reads are the capture drafts those forms are opened with (?draftId=): each load resolves this form's memory for the draft's transcript words (memory wins, the read's own answer fills the rest, ids kept only when the form's master list has them) and each save learns only the fields the user changed or supplied, best-effort so a memory write never fails the save; the quote wizard's dictate step resolves memory through a ?/memory action before its fuzzy matcher; a tippan read's party fills the sizer (never the weaver); learning stays per form (a sample word never rewrites a quote); no new intent, endpoint, column, migration, POST name or edit/delete screen\u003C/li>\n\u003C/ul>\n\u003Ch3>C324\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P0\u003C/li>\n\u003Cli>target: scripts/deploy.sh, vite.config.ts\u003C/li>\n\u003Cli>verify: script\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>a build runs into build.next while the running app keeps serving the complete previous build\u003C/li>\n\u003Cli>the swap is a rename immediately before the restart, with build.prev kept for rollback\u003C/li>\n\u003Cli>the previous build's hashed client chunks are carried into the new build so a tab opened before the ship keeps working\u003C/li>\n\u003Cli>a page load and /queue/__data.json stay 200 for the whole build\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: cd01e5d33496d474ab6bc3f66b2ae3d898746bbd\u003C/li>\n\u003Cli>live: cd01e5d33496d474ab6bc3f66b2ae3d898746bbd\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: build into build.next (ADAPTER_OUT) while the running app keeps serving the complete build/; immediately before the restart build-swap.ts carries the served build's _app/immutable chunks into the new build, registers them in its generated asset table, then swaps with two renames (build -> build.prev for rollback, build.next -> build); build.prev/build.next are gitignored; no app route, column, migration or edit/delete screen\u003C/li>\n\u003C/ul>\n\u003Ch3>C325\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: src/lib/server/captureOcr.ts, src/routes/api/capture-ocr/+server.ts, src/routes/gatepasses/new/+page.svelte\u003C/li>\n\u003Cli>verify: browser\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>the file a gatepass read saved becomes the form's Gatepass photo (image) by default, not just the verify pane's file\u003C/li>\n\u003Cli>the operator can still replace it with a better snap\u003C/li>\n\u003Cli>the read's own copy stays attached to the draft\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: 0cec2049013da6509adac9a869869a4ff2bf95dc\u003C/li>\n\u003Cli>live: 0cec2049013da6509adac9a869869a4ff2bf95dc\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: a gatepass read's file is COPIED (same name) into the screenshots upload drop so the form's existing image field / /upload-file?bin=screenshots resolves it — the draft keeps its own copy at screenshots/capture; only a gatepass read and only an image (a PDF read leaves the photo field empty); the photo is set only when the field is empty or still holds the previous read's file, so an operator's own earlier snap is never overwritten and the row's Replace still wins; no new field, POST name, column or route\u003C/li>\n\u003C/ul>\n\u003Ch3>C326\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: src/routes/gatepasses/new/+page.svelte\u003C/li>\n\u003Cli>verify: browser\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>two fingers on the gatepass in the verify pane pinch it between 50% and 400% around the fingers' midpoint, and the page behind never zooms\u003C/li>\n\u003Cli>one finger drags the zoomed photo left/right and up/down inside the pane while the rest of the form still scrolls\u003C/li>\n\u003Cli>the - / + buttons, the live percentage and the cross work exactly as before, and a PDF gatepass keeps its own viewer\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: 8c129c8df49436636608c61ed48229051d48006a\u003C/li>\n\u003Cli>live: 8c129c8df49436636608c61ed48229051d48006a\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: a pinch is the phone's standard viewer gesture — two fingers, 50%-400%, around the fingers' midpoint — with one finger panning; the PDF keeps its own viewer; the photo box, not the page, owns touch while the pane is open\u003C/li>\n\u003C/ul>\n\u003Ch3>C327\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: src/routes/gatepasses/new/+page.svelte\u003C/li>\n\u003Cli>verify: browser\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>Start OCR and Start Wizard sit at the top of the yarn-in screen and open the same wizard/read step the form already has\u003C/li>\n\u003Cli>nothing new is built behind them\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: ff9e3141576bbc5975ffb3d099e31c48324d7e00\u003C/li>\n\u003Cli>live: ff9e3141576bbc5975ffb3d099e31c48324d7e00\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: Start Wizard reopens the existing wizard at its first still-needed step (the C141/C300 walk); Start OCR opens the existing gatepassRead step, or its popup when a carried yarn-in has that id out of the walk. Both buttons sit always in the yarn-in header and only call the wizard the form already has - no new step, field, POST name or save path.\u003C/li>\n\u003C/ul>\n\u003Ch3>C328\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P0\u003C/li>\n\u003Cli>target: scripts/deploy.sh, scripts/row-watch.sh\u003C/li>\n\u003Cli>verify: script\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>a pull that conflicts stops the deploy with a message and a conflicted mark, and the tree keeps the conflict for a human\u003C/li>\n\u003Cli>no commit + push can include a file containing <<<<<<<, ======= or >>>>>>>\u003C/li>\n\u003Cli>the guard has a regression test named for the 2026-10-29 marker incident\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: 8dc6f4f2bad25d47781f852902f1dc42d46a1f97\u003C/li>\n\u003Cli>live: 8dc6f4f2bad25d47781f852902f1dc42d46a1f97\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: Guard lives in its own script (scripts/check-conflict-markers.sh) with a --self-test named for the 2026-10-29 incident, run as deploy step 0a - this checkout has no tests/ suite (7668c583, same reading as A251); markers are line-anchored (open/close with a space, a bare line of seven equals) so an inline mention in prose is not one; a failed but non-conflicted pull exits 5 with no mark so a network blip is not read as a conflict; .deploy-conflicted is gitignored and clears itself once the tree is resolved.\u003C/li>\n\u003C/ul>\n\u003Ch3>C329\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/gatepasses/new?kind=YARN_IN\">https://trading.tynolabs.com/gatepasses/new?kind=YARN_IN\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>the read of a paper printing 'Gate Pass No. : GSL/5546' sets the yarn-in's Trader's GP no row to GSL/5546 and the read card lists 'Trader GP GSL/5546'\u003C/li>\n\u003Cli>a bare number with no label, a following word, or junk characters never fill the row\u003C/li>\n\u003Cli>the carried value is validated on the field's rule (letters/digits/space/hyphen/slash, 24 max on the read) and junk lands empty\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: 89a171fa9a607cf8f862537d38dec7848ed905d3\u003C/li>\n\u003Cli>live: 89a171fa9a607cf8f862537d38dec7848ed905d3\u003C/li>\n\u003Cli>notes: - | pre-checked: grepped intake.ts/captureOcr.ts/captureRouting.ts: no gpNo field anywhere (bookingNo arrived with C315; partnerGpNo is a form field only) and the Goenka draft has no gatepass number while the paper prints 'Gate Pass No. : GSL/5546' — a new field end to end, mirroring bookingNo | assumed: the read caps at the row's stated 24 while the existing field stays 64 (Q262); the printed label is part of the match so a bare number is never taken as the trader's GP no\u003C/li>\n\u003C/ul>\n\u003Ch3>C330\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/gatepasses/new?kind=YARN_IN\">https://trading.tynolabs.com/gatepasses/new?kind=YARN_IN\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>the read card lists every value the read took — booking no, count, type, mill, bags, gross, net, vehicle, transport, trader GP no and expected date — and nothing it did not\u003C/li>\n\u003Cli>a read booking number that names no open reference rides as the 'matches nothing open' chip and seeds the reference table's search, and one that matches picks nothing\u003C/li>\n\u003Cli>a read value lands only on that field's own rule — a junk weight, booking no or date stays empty and is never listed\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: be9ab5826669643b3a87653766b64acdb6bf07b1\u003C/li>\n\u003Cli>live: be9ab5826669643b3a87653766b64acdb6bf07b1\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: the badge list names every value the read took (booking no, weights and expected date included) while only the rows this kind shows are filled — weights/expected date only on the kinds that show them, an unmatched booking no only seeds the reference table's search\u003C/li>\n\u003C/ul>\n\u003Ch3>C331\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/gatepasses/new?kind=YARN_IN\">https://trading.tynolabs.com/gatepasses/new?kind=YARN_IN\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: 94faa4f95f980f14c442ec9ae2f8f0ab446fd0cf\u003C/li>\n\u003Cli>live: 94faa4f95f980f14c442ec9ae2f8f0ab446fd0cf\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: the read's count is the identity; a master row's own name is its natural identity (the number it leads with, the type it names) with its columns as fallback; type and mill only narrow, never disqualify a unique count; more than one distinct yarn left = no pick and the read shows as the + chip into the yarn master (C319)\u003C/li>\n\u003C/ul>\n\u003Ch3>C332\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: src/routes/gatepasses/new/+page.svelte\u003C/li>\n\u003Cli>verify: browser\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>the cones row reads 'Cones per bag', not 'Cones in this delivery', on the yarn-in (and on every kind that shows it)\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: 77717004d5048cbd585ef26a9abf6ad2432ff1b9\u003C/li>\n\u003Cli>live: 77717004d5048cbd585ef26a9abf6ad2432ff1b9\u003C/li>\n\u003Cli>notes: - | pre-checked: grepped the yarn-in goods rows: the row renders 'Cones in this delivery' from gatepasses/new/+page.svelte but posts the delivery TOTAL in \u003Ccode>cones\u003C/code> (the existing cone_per_bag column went unposted on this kind), so the fix is the label and the figure it takes | assumed: Cones per bag is entered per bag and the delivery total is derived (bags × cones/bag), posted in the existing cones column so the lot/bag grain and reports are unchanged; the per-bag figure goes to gatepass.cone_per_bag; the row keeps the bags rule (> 0 whole when given) on both surfaces; other kinds' 'Total cones (all bags)' row is untouched\u003C/li>\n\u003C/ul>\n\u003Ch3>C333\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: src/routes/gatepasses/new/+page.svelte, src/routes/gatepasses/new/schema.ts\u003C/li>\n\u003Cli>verify: browser\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>every row the yarn-in wizard shows is required except remark, enforced on the client and in the create action with a per-field message\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: 271029f1ccb6560086402df62c1fc48ec180f47e\u003C/li>\n\u003Cli>live: 271029f1ccb6560086402df62c1fc48ec180f47e\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: every yarn-in row is compulsory except the remark: the reference, the yarn (when the row renders), the trader's GP no, the pickup location, the bags, the cones per bag, the bag weight, the warp/weft use and the gatepass photo; compulsory = the row was filled (a posted 0 counts, its own range rule still applies), the OCR read card stays optional so manual entry survives, and the reference/yarn identity are enforced client-side plus the action's existing checks (a single SO-order pick posts no id today, so the action cannot see that one)\u003C/li>\n\u003C/ul>\n\u003Ch3>C334\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P2\u003C/li>\n\u003Cli>target: src/routes/gatepasses/new/+page.svelte, src/lib/components/focus/FocusEntry.svelte, src/lib/components/gate/GatepassOcrRead.svelte\u003C/li>\n\u003Cli>verify: browser\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>the long one-line explanations are gone from the page header, the field popups and the read wizard, leaving the short label plus the field itself\u003C/li>\n\u003Cli>no behaviour changes\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: 77e4952eefa032cbb8157be6370d5879ca4eeda7\u003C/li>\n\u003Cli>live: 77e4952eefa032cbb8157be6370d5879ca4eeda7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: C334 reading: 'the long one-line explanations' = the page header hint, the FocusEntry step/pop-up sub line, the money rate instruction line and the OCR read card's hint + chip help paragraphs; the pop-up now carries the short label and the field only, so the callers' sub strings are inert there (kept in source, no behaviour touched), the plate pop-up's own sub goes with the gatepass row, and each kind's Route fallback in the saved summary becomes '—' instead of the deleted hint sentence. Static rows stay tappable where they carry a note. Other screens' own hint components (orders/new, BookingCapture) are a later sweep, not this row.\u003C/li>\n\u003C/ul>\n\u003Ch3>C335\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: src/routes/gatepasses/new/+page.svelte, src/routes/bookings/new/+page.server.ts, src/routes/bookings/new/+page.svelte\u003C/li>\n\u003Cli>verify: browser\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>a read booking number that matches no open reference shows as 'Add Booking No. \u003Cno>' in the reference picker\u003C/li>\n\u003Cli>tapping it opens the booking form prefilled with that number and the read's count/type/mill/bags\u003C/li>\n\u003Cli>saving returns to the yarn-in with the new booking selected\u003C/li>\n\u003Cli>nothing is created without the tap\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: d1b67cbd815c0d61b2e17e02a645561c01119249\u003C/li>\n\u003Cli>live: d1b67cbd815c0d61b2e17e02a645561c01119249\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: the chip opens /bookings/new with traderBookingNo=\u003Cread no>&count=&type=&mill=&bags=&returnTo=\u003Cthis form>, each validated on the booking load by the form's own rules (junk lands empty, never echoed); the read's count+type+mill resolve the yarn-master row by the same parts rule C331 uses, the mill fills Mill/ticket, the bags fill Bags, and an unresolved yarn rides the Add-yarn dialog prefilled (never created); returnTo is safeReturnTo (paths on this app only) and the booking's save redirects to it with ?bookingId=\u003Cid>&created=\u003Cid>, so the yarn-in selects the new booking; the chip keeps C315's own guard (a read number that matched nothing open, no reference picked yet) and writes nothing by itself.\u003C/li>\n\u003C/ul>\n\u003Ch3>C336\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P0\u003C/li>\n\u003Cli>target: src/lib/server/intake.ts, src/lib/server/captureOcr.ts, src/lib/gatepassOcr.ts, src/routes/gatepasses/new/+page.svelte\u003C/li>\n\u003Cli>verify: browser\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>a gatepass read carries docIssuer (the letterhead, e.g. Goenka Syndicate Private Limited), not the buyer\u003C/li>\n\u003Cli>it shows on the read card and rides the draft/prefill\u003C/li>\n\u003Cli>two photos from different traders get different issuers\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: 2365c23217926d70f6daa338d7f0eb846fe9961d\u003C/li>\n\u003Cli>live: 2365c23217926d70f6daa338d7f0eb846fe9961d\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: docIssuer = the first firm-suffixed, non-address line in the top block before any label; validated as letters/digits/&.,'()- 3-80 chars on the reader and the form carry, blank when absent; the model only fills a gap\u003C/li>\n\u003C/ul>\n\u003Ch3>C337\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P0\u003C/li>\n\u003Cli>target: src/lib/server/docFormatMemory.ts, src/lib/server/schema-foundation.ts, src/lib/server/captureOcr.ts, src/routes/gatepasses/new/+page.server.ts\u003C/li>\n\u003Cli>verify: script\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>a field the user supplies after a missed read is stored against the issuer as an anchor (label text, or a position hint when unlabelled) plus the value's shape\u003C/li>\n\u003Cli>a later gatepass from the same issuer fills that field from the learned anchor before the model's answer is merged, with no manual step\u003C/li>\n\u003Cli>nothing is learned without a user save\u003C/li>\n\u003Cli>the anchor is offered, never written into a committed document by itself\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: 9c57386e3f801a6743a9acf052c3f18f347716e0\u003C/li>\n\u003Cli>live: 9c57386e3f801a6743a9acf052c3f18f347716e0\u003C/li>\n\u003Cli>notes: - | assumed: learned layout keyed on the letterhead exactly as read (no fuzzy issuer match); learns only bookingNo/partnerGpNo/ticket; pre-fills only a gatepass read; never overrides a value the reader already produced; written only by the gatepass create save | pre-checked: row-watch: read the row and its target before starting\u003C/li>\n\u003C/ul>\n\u003Ch3>C338\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: -\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: 21144de5492b5b158fa5d70a84acb573eaaeca70\u003C/li>\n\u003Cli>live: 21144de5492b5b158fa5d70a84acb573eaaeca70\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: the learned layout is spoken to the reader as a text-only follow-up call over the transcript the first read already produced (no image re-sent, no extra cost on a first read of a new issuer), and the read card names the issuer + its known fields whenever that issuer has learned rows\u003C/li>\n\u003C/ul>\n\u003Ch3>C339\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: scripts/row-watch.sh, scripts/queue-next.ts\u003C/li>\n\u003Cli>verify: script\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>two row sessions run at once and never on rows whose target files overlap\u003C/li>\n\u003Cli>builds stay serial (heavy.sh)\u003C/li>\n\u003Cli>rows/hour measured before and after from screenshots/row-watch.log\u003C/li>\n\u003Cli>a row that dies leaves no claim and the second worker picks the next non-overlapping row\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: d7b4d4ce285260a1d21936fc70aaf7cdc10969d3\u003C/li>\n\u003Cli>live: d7b4d4ce285260a1d21936fc70aaf7cdc10969d3\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: a docs-only target is never a conflict (the batch planner's rule since 2026-10-01), two hot files are exclusive, and the two lanes stay in this one checkout (no worktrees) with integration and board writes serialised on .row-integrate.lock / .row-board.lock\u003C/li>\n\u003C/ul>\n\u003Ch3>C340\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P2\u003C/li>\n\u003Cli>target: scripts/row-watch.sh\u003C/li>\n\u003Cli>verify: script\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>the row prompt carries the row text, acceptance and target files\u003C/li>\n\u003Cli>the session only reads STATUS/BUILD-LOG/PLANNING when the row changes flow or a decision\u003C/li>\n\u003Cli>turn count per row drops and rows/hour rises, measured from the log\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: ea465de0e63aa836667660fb4ea7e3ef26b667e0\u003C/li>\n\u003Cli>live: ea465de0e63aa836667660fb4ea7e3ef26b667e0\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: the row brief is parsed inside row-watch.sh (QUEUE.md block + CORRECTIONS.md text) rather than adding a --show mode to queue-next.ts — the row's target is the watcher and the lane guard keys on target files, so the whole change stays in one file\u003C/li>\n\u003C/ul>\n\u003Ch3>C341\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: -\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: 9303e83252809be8316af3a31826b023ed83b024\u003C/li>\n\u003Cli>live: 9303e83252809be8316af3a31826b023ed83b024\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting\u003C/li>\n\u003C/ul>\n\u003Ch3>C342\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: src/lib/server/schema-foundation.ts\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: fac2d8be30f6c7fa6ad3d535a1d423a5520e69ae\u003C/li>\n\u003Cli>live: fac2d8be30f6c7fa6ad3d535a1d423a5520e69ae\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting\u003C/li>\n\u003C/ul>\n\u003Ch3>C343\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: src/lib/server/costing\u003C/li>\n\u003Cli>verify: script\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>bun run src/lib/server/costing/costing.test.ts exits 0 with every case passing (WAC in and out, key and track separation, release at locked cost, shortfall re-price, salvage roll-up, zero-cost isolation, PO P and L, variance, leg freeze and accrual, substitution quantity-only)\u003C/li>\n\u003Cli>the costing modules import no db, no drizzle and no route, so every export is pure\u003C/li>\n\u003Cli>bunx tsc --noEmit adds no diagnostic in src/lib/server/costing/\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: 68af02a05e4dfb586cb18d1e392d0fd9175d12e7\u003C/li>\n\u003Cli>live: 68af02a05e4dfb586cb18d1e392d0fd9175d12e7\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: tests live beside the engine (src/lib/server/costing/costing.test.ts) and run with bun run src/lib/server/costing/costing.test.ts because bun test cannot scan a missing ./tests root; WAC counts inward entries only and excludes zero-cost/salvage entries from the average (their quantity stays), salvage is always zero fabric value and its proceeds are SO revenue; money is never rounded inside the engine, only at presentation\u003C/li>\n\u003C/ul>\n\u003Ch3>C344\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: src/routes/lots\u003C/li>\n\u003Cli>verify: script\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>bun /tmp/opencode/c344-proof.ts exits 0 against a scratch copy of data.db with every case passing (pool in at the booking rate, key count+type+grade, free vs apportioned, issue out at the WAC of its moment, yarn cost leg at that same WAC, idempotent per document, a later purchase moves only future issues, zero-cost kg kept out of the average, no-order issue writes nothing, grade rule blank|A+|A|B|C)\u003C/li>\n\u003Cli>yarn master saves grade through the shared yarnGradeError rule and the yarn form refuses a value outside it\u003C/li>\n\u003Cli>bunx tsc --noEmit adds no diagnostic in the touched files\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: 821d442821d551af2859b819b52480a459fad1c4\u003C/li>\n\u003Cli>live: 821d442821d551af2859b819b52480a459fad1c4\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: the receipt's ₹/kg is the gatepass booking's ratePerKg (no new field, no price invented); a booking-less receipt writes a zero-cost pool entry (kg kept, average untouched); the pool key is the yarn master's count+type+grade read at receipt time, an ungraded yarn is its own pool; free = pool in with no order, apportioned-to-PO = pool in carrying the PO the receipt was marked for; a weft issue writes the pool out + yarn cost leg only when the loom's beam resolves a production order (an internal move writes no cost); grade is blank or A+/A/B/C folded to upper case on both surfaces\u003C/li>\n\u003C/ul>\n\u003Ch3>C345\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: src/routes/orders/new\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: a475aa292da8c7112d0b7ac83c4ee4631fa3f5a3\u003C/li>\n\u003Cli>live: a475aa292da8c7112d0b7ac83c4ee4631fa3f5a3\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting\u003C/li>\n\u003C/ul>\n\u003Ch3>C346\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: src/routes/orders/new\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: 55bffd7dc8d14dfd727e10c005fe560c14593622\u003C/li>\n\u003Cli>live: 55bffd7dc8d14dfd727e10c005fe560c14593622\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting\u003C/li>\n\u003C/ul>\n\u003Ch3>C347\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: src/routes/orders/[id]\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: fc9793aed09368b1c4237275742df58ee2cd1585\u003C/li>\n\u003Cli>live: fc9793aed09368b1c4237275742df58ee2cd1585\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: a cut releases the newest hold first at its locked cost; a rise, a quality change and a pick change leave the gap for the one rebalance action (release in the amend save, reassign only there); cancelling releases every hold at locked cost and the production orders survive unassigned; a PO held by a live sale or already complete refuses cancellation\u003C/li>\n\u003C/ul>\n\u003Ch3>C348\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: src/routes/checking\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>checking accepts grades A/B/C/R/X and refuses anything else on both surfaces\u003C/li>\n\u003Cli>R grades to FG (sellable) and X to reject\u003C/li>\n\u003Cli>a graded X roll leaves one pool_entry track=salvage at unit cost 0, which never moves the produced WAC\u003C/li>\n\u003Cli>a grade X roll may only name a damaged sale order (grade error on a normal one)\u003C/li>\n\u003Cli>salvage P&L rolls into the parent SO, else stays in the damaged SO\u003C/li>\n\u003Cli>bun run src/lib/server/rollGrade.test.ts green\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: e67bcbf46402f6c72da4db6e84151b14c27ffcd5\u003C/li>\n\u003Cli>live: e67bcbf46402f6c72da4db6e84151b14c27ffcd5\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: X keeps status reject (the FG dispatch gate refuses it, as a non-usable roll should); the damaged-SO gate is enforced where a roll names its order on the checking form — mark the order a damaged lot or leave the order blank | assumed: the checking hook writes only the zero-cost salvage pool entry — no produced-track out, because the produced pool is keyed by quality+pick and metres cannot be attributed back to one roll; the salvage track cannot move any average (pool.ts isZeroCost) | assumed: salvage P&L roll-up is pure arithmetic in costing/pnl (salvageOwner/salvageFor): a damaged SO with a parent rolls its proceeds into the parent, else it keeps them in its own P&L; no new screen\u003C/li>\n\u003C/ul>\n\u003Ch3>C349\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: src/routes/fabric-purchase\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>a purchase writes one PURCHASE fabric_purchase order, one purchase cost leg at the landed ₹/m and one purchased pool entry\u003C/li>\n\u003Cli>the purchased WAC is keyed quality+pick and the produced WAC never moves\u003C/li>\n\u003Cli>assignment to a live sale order writes one market apportionment at the locked cost and over-coverage is refused\u003C/li>\n\u003Cli>supplier, quality, pick, mtrs, rate, freight, GST and date each validate on both surfaces\u003C/li>\n\u003Cli>bun run src/lib/server/fabricPurchase.test.ts green\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: 3b7b9120d72f47cdb1f00e2a2af1245fe93b5ed2\u003C/li>\n\u003Cli>live: 3b7b9120d72f47cdb1f00e2a2af1245fe93b5ed2\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: GST is input credit (excluded from WAC, kept on the leg as gst_pct) and freight is capitalised; the single cost leg carries the landed ₹/m while order.rate keeps the invoiced ₹/m | assumed: assignment writes the market cost_apportionment only, no purchased-pool out entry — the same rule C346's market source already follows, so nothing has to learn to release it | assumed: no new approval gate: a fabric purchase is recorded approved at entry with the signed-in user; order.type is a new PURCHASE word so no existing PROD/SO reader picks it up | assumed: quality is picked from the design master (qualityKey = design.qualityName), pick editable and validated as a whole number above 0, so a typo cannot open a second purchased pool\u003C/li>\n\u003C/ul>\n\u003Ch3>C350\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: src/routes/reports\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: f5c8ae7b09b14604c35a95b72f6af8519b83abe3\u003C/li>\n\u003Cli>live: f5c8ae7b09b14604c35a95b72f6af8519b83abe3\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: stock lines read straight from pool_entry (C343 balance) so every column reconciles: yarn keyed count+type+grade with own/party and in-house/sizer/weaver/transit split by the lot each entry names, fabric keyed quality+pick (+grade where a hold or roll names one) on the produced and purchased tracks at that track's own WAC | assumed: pick/grade/track filters are GET params on the existing /reports screen with their own rules on both surfaces: pick whole > 0 (input type=number min=1 step=1 max=9999; server /^[0-9]+$/ and > 0), grade one of A+/A/B/C case-folded, track yarn | produced | purchased; junk is dropped, never queried | assumed: no new screen, no migration, no write path: reports.ts gains the pure aggregators plus two table builders, /reports gains the filter row and the second stock table, /lots' Pool column gains wip (an out entry to a live order), the dump edge gains the fabricstock slug\u003C/li>\n\u003C/ul>\n\u003Ch3>C351\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: src/routes/gatepasses/new\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>a DIRECT delivery naming a Weaver-category party saves and its lot's location is weaver\u003C/li>\n\u003Cli>a DIRECT naming a Sizing or Godown party still lands at sizer and our premises stays in-house\u003C/li>\n\u003Cli>a weaver location with a non-weaver party is a visible field error on the POST (server) and un-pickable in the picker (client)\u003C/li>\n\u003Cli>bun run src/lib/server/directDelivery.test.ts green\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: 9ea4bd27c8e4b0d482e2755ed7b30ff66ae59f22\u003C/li>\n\u003Cli>live: 9ea4bd27c8e4b0d482e2755ed7b30ff66ae59f22\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: a weaver location accepts only a Weaver-category party on both surfaces (a hand-forged sizer/weaver mismatch is a visible field error); the weaver rows are additive to the DIRECT picker only (yarn-in pickup places and the beams' sizer list unchanged); the receipt's own ₹/kg still stands, so a direct delivery to a weaver changes no WAC\u003C/li>\n\u003C/ul>\n\u003Ch3>C352\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: src/routes/bookings/new\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>a booking saves freight and purchase brokerage (optional rupees >= 0, 2 decimals max) and they never enter the booking's GST amounts\u003C/li>\n\u003Cli>the inward receipt shows booked kg, billed vs arrived (short absorbed) and the landed Rs/kg, recomputed as the weighed kg is typed\u003C/li>\n\u003Cli>the yarn pool's in entry lands at (basic amount + freight + brokerage) / arrived kg and issueYarnToOrder freezes the PO yarn leg at that landed WAC\u003C/li>\n\u003Cli>a full receipt with no add-ons still lands at the booking's own rate\u003C/li>\n\u003Cli>bun run src/lib/server/landedCost.test.ts green\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: a77641f2e2cb3e87da086b07a708fac24d971e94\u003C/li>\n\u003Cli>notes: shipped in 7149bbe6, live-check 83/83; blocked only by the /reports 500 (costBasis missing from the load), fixed and proved\u003C/li>\n\u003C/ul>\n\u003Ch3>C353\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: src/lib/server/costing\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>warping books at Rs per kg of warp and sizing at Rs per kg of warp sent, with a bill's billing kg reversed from the received count and carried as the quantity variance\u003C/li>\n\u003Cli>weaving books picks/m x Rs/pick /100 on good mtrs, the rate booked per order (no master) with an internal rate for in-house looms\u003C/li>\n\u003Cli>checking books Rs per metre actually checked including X, at the quality's rate (yearly default, editable per leg), and mending never books\u003C/li>\n\u003Cli>packing and loading book a direct rupee amount\u003C/li>\n\u003Cli>every leg field is validated on the server action and on the form (positive quantity/rate/picks/good mtrs with 2 decimals, a count pair 0-400, the internal rate when in-house)\u003C/li>\n\u003Cli>bun run src/lib/server/costing/costing.test.ts green (19/19) and bookCostLeg proved on a data.db copy (27/27)\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: a77641f2e2cb3e87da086b07a708fac24d971e94\u003C/li>\n\u003Cli>notes: shipped in 7149bbe6, live-check 83/83; same /reports 500 block, fixed\u003C/li>\n\u003C/ul>\n\u003Ch3>C354\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: src/routes/bills\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>bun run src/lib/server/bills.test.ts green 6/6 (allocation by quantity, the qty/rate split, the restatement cascade, the close rules)\u003C/li>\n\u003Cli>a bill allocates over the open provisional legs of its kind and every line's qty + rate variance adds back to its amount variance\u003C/li>\n\u003Cli>a settled leg becomes actual with bill no/date/party and GST and the order unit cost + produced pool entry + every sale-order hold are restated\u003C/li>\n\u003Cli>a sale order P&L stays provisional until the last bill auto-closes it and a manual close without a reason is refused\u003C/li>\n\u003Cli>a repeated bill number from the same vendor and a never-billed kind are refused and every bill field validates on both surfaces\u003C/li>\n\u003Cli>bunx tsc --noEmit adds no diagnostic in the touched files\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: a77641f2e2cb3e87da086b07a708fac24d971e94\u003C/li>\n\u003Cli>notes: shipped in 7149bbe6, live-check 83/83; same /reports 500 block, fixed\u003C/li>\n\u003C/ul>\n\u003Ch3>C355\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: src/routes/orders/[id]\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>a sale order's P&L reads on the DELIVERED metres: revenue = delivered m x rate, cost = those metres at the locked unit cost, margin = what is left\u003C/li>\n\u003Cli>every line is exactly its percentage of the selling price and the lines add back to price - cost\u003C/li>\n\u003Cli>overhead defaults to 1% company-wide and is editable per sale as an append-only so:pnl:lines save (never an edit)\u003C/li>\n\u003Cli>the quote engine prices the same gross-up (price = cost x 100/(100 - sum p)) with the 1% overhead replacing the 6.5% other expenses, and no stored design value pulls the old 6.5 back\u003C/li>\n\u003Cli>a three-decimal share, shares reaching 100% and a non-sale order are refused with the field named on both surfaces\u003C/li>\n\u003Cli>bun run src/lib/server/costing/costing.test.ts 22/22 PASS incl. the split, gross-up and quote-parity cases\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: 9ea4bd27c8e4b0d482e2755ed7b30ff66ae59f22\u003C/li>\n\u003Cli>notes: already shipped in 7149bbe6, live 83/83 — re-closed after answering the stale watcher question\u003C/li>\n\u003C/ul>\n\u003Ch3>C356\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: src/routes/expenses\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: a77641f2e2cb3e87da086b07a708fac24d971e94\u003C/li>\n\u003Cli>live: a77641f2e2cb3e87da086b07a708fac24d971e94\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: The level is a choice on the entry form with the sale order (direct to P&L) as the default; the producing-order leg form stops offering 'exceptional' so every exceptional charge is entered here with its paper and reason; amount is rupees to 2 decimals under ₹1 crore; a booked charge is 'actual' because its document is in hand; a sale-order charge shows as one direct line in that sale's P&L card and never in a metre cost.\u003C/li>\n\u003C/ul>\n\u003Ch3>C357\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: src/routes/lots\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: d91f165d9b03735f64c1d269a461173a2b87da50\u003C/li>\n\u003Cli>live: d91f165d9b03735f64c1d269a461173a2b87da50\u003C/li>\n\u003Cli>notes: - | assumed: one opening line per pool key (a key already entered refuses a second, import is all-or-nothing so a re-run never doubles stock); a blank value books zero-cost stock exactly like an unpriced receipt; the entry screen is a plain daisyUI card + ReviewSheet mirroring C349's /fabric-purchase (a one-time office entry with an optional paste import), not the FocusEntry wizard; no schema change — pool_entry already carries source=opening | assumed: owner-approved: opening stock entered once per pool key with values, blank = zero-cost, no schema change | pre-checked: row-watch: read the row and its target before starting | assumed: a yarn type is the master's spelling: the form's code and every pasted line resolve to it case-insensitively ('ccw' -> 'CCW') and an unknown type is refused by line, so one pool key is one bucket and the opening stock always feeds the WAC it belongs to; the fabric quality keeps the same rule it already had\u003C/li>\n\u003C/ul>\n\u003Ch3>C358\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: src/routes/orders/[id]\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: 8bacb02e106a82727d32ca9aa07bccdc2642b74a\u003C/li>\n\u003Cli>live: 8bacb02e106a82727d32ca9aa07bccdc2642b74a\u003C/li>\n\u003Cli>notes: - | assumed: delivered mtrs = this order's dispatch slips in loaded | delivered (dispatch's own auto-delivery measure); fulfilled = the existing delivered status; blank tolerance = 0 (a 1 m miss with no stated tolerance is blocked and names the amendment); a shortfall releases the remainder through C347's release plan at each hold's locked cost; an excess is apportioned only from free stock (produced/market pool) or an existing open production order at that source's current cost — new_po refused; reversal rides C152's order_change rail as fulfil-reverse: owner/admin applies at once, anyone else leaves a pending /approvals item, and it returns the status only (released holds and the extra apportionment stay written, append-only); note optional <=280, a coverage line positive 2dp within that source's free metres and the lines exactly equal to the excess, reversal reason required <=280 — both surfaces | assumed: owner-approved: fulfil only inside tolerance, else amend first; excess apportioned from free stock or an existing PO; reversal needs owner approval | pre-checked: row-watch: read the row and its target before starting | assumed: re-pass: appendAmendment's kind union widened to admit 'ops-complete' (the value C154's completion already persists in that text column) instead of casting at the call site — type-only widening, no write/reader/schema change, reversible; the fulfilment flow is unchanged\u003C/li>\n\u003C/ul>\n\u003Ch3>C359\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/gatepasses/new?kind=YARN_IN\">https://trading.tynolabs.com/gatepasses/new?kind=YARN_IN\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: 8defbdbd0bbf6cc2499d0a3eae47c0fa50390312\u003C/li>\n\u003Cli>live: 8defbdbd0bbf6cc2499d0a3eae47c0fa50390312\u003C/li>\n\u003Cli>notes: - | assumed: a printed godown address is a location, not a movement: kind is carried only on an explicit signal (booking no → YARN_IN; exact godown/premises/sizer or the words 'direct delivery' → DIRECT), otherwise the form keeps its YARN_OUT default; the address never fills destPlace | assumed: owner-approved: DIRECT only on an explicit signal, a read booking no wins as YARN_IN, a printed godown address is a location not an intent | pre-checked: row-watch: read the row and its target before starting\u003C/li>\n\u003C/ul>\n\u003Ch3>C360\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: src/routes/gatepasses/new/+page.svelte, src/lib/components/focus/FocusEntry.svelte, src/routes/masters/+page.svelte, src/routes/bookings/new/+page.svelte\u003C/li>\n\u003Cli>verify: browser\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>a create chip opens the child form in a modal over the gatepass form, whose state is untouched while it is open\u003C/li>\n\u003Cli>after saving, the modal closes and the new entry is selected in the field that opened it\u003C/li>\n\u003Cli>closing the modal returns to the form exactly where it was\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: 09ca2497b347251c60b16d46d3ea89659a553de0\u003C/li>\n\u003Cli>live: 09ca2497b347251c60b16d46d3ea89659a553de0\u003C/li>\n\u003Cli>notes: - | assumed: a same-origin iframe of the existing child route, one postMessage back on save; the parent never navigates | assumed: iframe modal + postMessage; a created booking row shows its number and the read's yarn with '—' remainders | pre-checked: row-watch: read the row and its target before starting | assumed: the location master lands on the row that asked it: field=location from the pickup row's own create link is applied to destPlace on every kind except DIRECT; the drain's build blocker (openingStock -> server/costing/pool) is fixed in this pass by moving the pool-key builders to #lib/poolKey.ts\u003C/li>\n\u003C/ul>\n\u003Ch3>C361\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: -\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: 97a1dfb9a3b465ff9fdb50bc1fbc1fbf336f5d40\u003C/li>\n\u003Cli>live: 97a1dfb9a3b465ff9fdb50bc1fbc1fbf336f5d40\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting\u003C/li>\n\u003C/ul>\n\u003Ch3>C362\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: -\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: 1e559f2c918a5ac995cb4552213b06bac7b49d91\u003C/li>\n\u003Cli>live: 1e559f2c918a5ac995cb4552213b06bac7b49d91\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting\u003C/li>\n\u003C/ul>\n\u003Ch3>C363\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"https://trading.tynolabs.com/gatepasses/new?kind=YARN_IN\">https://trading.tynolabs.com/gatepasses/new?kind=YARN_IN\u003C/a>\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: 1db8bd0ab13c212ff36636e1209cab4246aeaef9\u003C/li>\n\u003Cli>live: 1db8bd0ab13c212ff36636e1209cab4246aeaef9\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: zoom stays capped at 400% (existing VERIFY_ZOOM_MAX); a photo wider than the pane anchors left and pans inside the overflow-auto box\u003C/li>\n\u003C/ul>\n\u003Ch3>C364\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: src/lib/server/costing/pool.ts, src/lib/server/lots.ts, src/lib/server/reports.ts\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>bun test the two-ledger cases green (free WAC unchanged by an earmark\u003C/li>\n\u003Cli>the PO rate is the booking landed rate)\u003C/li>\n\u003Cli>/reports shows free and earmarked kg as separate columns\u003C/li>\n\u003Cli>an earmark above the received kg is refused on the form and in the action\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: f5290aa173dcba2b17d011525d1c4f68724c7b60\u003C/li>\n\u003Cli>live: f5290aa173dcba2b17d011525d1c4f68724c7b60\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: Earmark = the PO tag on a yarn pool entry (booking orderSplit first, else the receipt's order-tagged boxes, else the carried order), split pro rata to the received kg; free pool = untagged entries alone; an issue prices its own earmark first then free stock at WAC, one out entry per part; the report keeps free and earmarked kg apart with WIP beside.\u003C/li>\n\u003C/ul>\n\u003Ch3>C365\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: src/lib/server/lots.ts, src/routes/bookings/new/+page.server.ts, src/routes/orders/[id]/+page.server.ts\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>issuing yarn with no earmark leaves the PO yarn cost at 0 (test)\u003C/li>\n\u003Cli>a 200 kg earmark at Rs210 writes a Rs42000 leg (test)\u003C/li>\n\u003Cli>the PO record lists the bucket rows with their source\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: e7475c35added441a4103950eb2f59200e75c8f9\u003C/li>\n\u003Cli>live: e7475c35added441a4103950eb2f59200e75c8f9\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: The Against split's kg per PO is derived from bags x bagWt; only a production order (role po / PROD) takes the yarn leg (SO/JW keep their own cost basis); a free-stock draw writes the leg only, no pool move; the landed rate is read from the booking, never typed.\u003C/li>\n\u003C/ul>\n\u003Ch3>C366\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: src/lib/server/schema-foundation.ts, src/lib/server/poLifecycle.ts, src/routes/orders/[id]/+page.svelte\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: bcc1e198b85a8f4a9a48a5bbfe4cd0d4990144a8\u003C/li>\n\u003Cli>live: bcc1e198b85a8f4a9a48a5bbfe4cd0d4990144a8\u003C/li>\n\u003Cli>notes: - | pre-checked: read poLifecycle.ts stampProductionOrder (one weaving leg from order.picks and jobRate) and the order table (single picks/jobRate); a segment table plus a per-segment leg is the smallest shape | assumed: the order's own picks/jobRate/planned mtrs are the default first segment (synthetic, seq 1); stored segments append at seq 2+, each writing one provisional weaving leg at pick×₹/pick÷100 over its own planned mtrs; in-house uses the segment's internal ₹/pick with no bill party; segments lock once any fabric_in row exists for the PO; tippan picker offers the PO's recent tippans\u003C/li>\n\u003C/ul>\n\u003Ch3>C367\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: src/routes/fabric-in/+page.server.ts, src/routes/checking/+page.server.ts, src/lib/server/poLifecycle.ts\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>two segments at different picks give two different Rs/m on the same PO (test)\u003C/li>\n\u003Cli>a lot with 10 percent X raises its sellable Rs/m by exactly the X-borne costs (test)\u003C/li>\n\u003Cli>the produced pool holds one row per lot with its own unit cost\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: ba1af6951badec1f33454a0f45df4742b4e6a386\u003C/li>\n\u003Cli>live: ba1af6951badec1f33454a0f45df4742b4e6a386\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting\u003C/li>\n\u003C/ul>\n\u003Ch3>C368\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: src/routes/checking/+page.server.ts, src/lib/server/costing/pnl.ts\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>1000 m at Rs80000 with 50 X gives Rs84.21/m for A and B alike and 0 for X (test)\u003C/li>\n\u003Cli>the checking leg counts the X mtrs\u003C/li>\n\u003Cli>a lot with zero sellable mtrs is refused\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: 90e00be34a41729c9285242ef4f0c74d3ca66f72\u003C/li>\n\u003Cli>live: 90e00be34a41729c9285242ef4f0c74d3ca66f72\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: Grade-blind ₹/m is one engine rule (costing/pnl: isSellableGrade, lotUnitCost, gradeUnitCost, lotSellableError) used by lotCost and the completion gate; the checking action records the lot's checked mtrs (graded rolls, X included) on the roll:checked event; a fabric-in lot roll grades with no beam; X still needs a damaged sale order (C348, unchanged).\u003C/li>\n\u003C/ul>\n\u003Ch3>C369\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: src/routes/beams/[id]/+page.server.ts, src/lib/server/schema-foundation.ts\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>carried Rs30000 and market Rs27500 leaves a Rs2500 loss on the cancelled PO and Rs27500 on the receiving PO (test)\u003C/li>\n\u003Cli>the transfer form shows the three hints and accepts typed values\u003C/li>\n\u003Cli>a partial beam splits by kg (test)\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: 89654a08c0b5f4dd65e6c3524d0dba91e700964b\u003C/li>\n\u003Cli>live: 89654a08c0b5f4dd65e6c3524d0dba91e700964b\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: PO-to-PO only; sizing gate = the from-PO sizing cost leg; variance is a signed exceptional leg on the transferring PO; a partial leaves the beam and raises no BEAM_IN; carried = beam kg x the from-PO yarn/warping/sizing rate\u003C/li>\n\u003C/ul>\n\u003Ch3>C370\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: src/lib/server/poLifecycle.ts, src/routes/orders/[id]/+page.svelte\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>a PO from a quote at Rs12/m planned and Rs13.20/m actual shows a +10 percent drift (test)\u003C/li>\n\u003Cli>a stock PO shows no budget row\u003C/li>\n\u003Cli>a quote cannot be revised after the SO exists (refused)\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: 794e4e81c514611280cd31d6c89a293973b0c23d\u003C/li>\n\u003Cli>live: 794e4e81c514611280cd31d6c89a293973b0c23d\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: Budget = quote planned ₹/m per leg (yarn = warp + weft, warping, sizing, weaving) x the PO's own planned mtrs, snapshotted into the existing po:planned event payload at PO creation (no new table); a stock PO and an SO with no quote carry none; drift per leg = costing/pnl variance() over the PO's booked po-level legs; the quote freeze is enforced by refusing a second live SO on the same quote (no in-place quote edit exists).\u003C/li>\n\u003C/ul>\n\u003Ch3>C371\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: src/lib/server/soCoverage.ts, src/lib/server/costing/pnl.ts\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>SO at Rs8.75/pick apportioned to PO-1, fabric delivered from a 72-pick lot, gives 8.75 x 72 / 100 per m and not PO-2 rate (test)\u003C/li>\n\u003Cli>the delivering PO shows the variance\u003C/li>\n\u003Cli>a lot without a pick cannot be apportioned\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: 68e6147b941b6321d1fc067954e0eb1c5c131ace\u003C/li>\n\u003Cli>live: 68e6147b941b6321d1fc067954e0eb1c5c131ace\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: Committed leg rates are read live from the delivering PO's cost legs (+ its ₹/pick), keyed to the sale's apportionment line, no schema change: the line carries them in its reading, so a later bill is the PO's variance and never a re-price of the locked sale. The delivered pick is the fabric-in lots' pick weighted by metres. Only pool/market lots are refused without a pick (a PO line's pick arrives with its lot).\u003C/li>\n\u003C/ul>\n\u003Ch3>C372\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: src/lib/server/poLifecycle.ts\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>a PO holding 200 kg at Rs210 cancelled puts 200 kg at Rs210 into free stock and raises the pool value by Rs42000 (test)\u003C/li>\n\u003Cli>a beam transfer variance posts to the cancelled PO (test)\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: 4dfba036d04122377d3257a061fe638925e77f5d\u003C/li>\n\u003Cli>live: 4dfba036d04122377d3257a061fe638925e77f5d\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: Cancelling a PO writes one yarn release pair (out of the order's earmark, in to free stock) both valued at qty x the carried unit cost, so the free pool value rises by exactly the release value; produced fabric is already untagged and stays in the free pool at its lot cost; no cost leg is added, reversed or edited (append-only), a provisional sizing/weaving commitment is not charged, and conversionAccrued reports only the actual non-yarn legs already posted (a beam transfer variance stays on the cancelled PO).\u003C/li>\n\u003C/ul>\n\u003Ch3>C373\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: src/lib/server/bills.ts, src/routes/bills/+page.server.ts\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>a Rs50000 sizing bill split 60/40 across two POs writes two actual legs (test)\u003C/li>\n\u003Cli>an unallocated bill is refused by the action (test)\u003C/li>\n\u003Cli>the form shows the open quantity and the remainder\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: 9bef6eadb871590ba24fb9920af243f25b992d42\u003C/li>\n\u003Cli>live: 9bef6eadb871590ba24fb9920af243f25b992d42\u003C/li>\n\u003Cli>notes: - | assumed: Every bill is apportioned by hand at entry: a share is a positive 2-decimal amount per open committed leg, no order listed twice, a share capped at that leg's open committed amount (an over-commitment is a supplementary leg first), and the shares must add back to the bill exactly; the form suggests by open committed quantity (tap to fill) and shows each order's open quantity, its committed Rs and the live remainder, but a bill with no allocation cannot be saved on any entry path (form or paste). | pre-checked: row-watch: read the row and its target before starting | assumed: the write path is proved against a temp libSQL db replayed from drizzle/ (the legacy unquoted REFERENCES order( in 0016 repaired on replay) through the real recordBill: no allocation refused with no leg written, then the 60/40 Rs50000 bill writes two actual legs of Rs30000 and Rs\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u003C/li>\n\u003C/ul>\n\u003Ch3>C374\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: src/lib/server/schema-foundation.ts, src/routes/quote/new/+page.server.ts\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>a quote saved with 1 percent brokerage, pass-on 0.5 and freight excluded shows all three on the SO read-only\u003C/li>\n\u003Cli>a percentage above 100 is refused on form and action\u003C/li>\n\u003Cli>freight default is excluded and buyer-borne\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: e254bd25, 44fe59c6129ede97ea7207f29d6b635754ceb79a\u003C/li>\n\u003Cli>live: 79bcd063edab25c8e219793fab45d3091eea0e40\u003C/li>\n\u003Cli>notes: - | assumed: delivery-term enum = ex-mill | fob | cif | ddp; recovery enum = on-top (excluded, buyer bears — the default) | in-rate; both percentages 0-100 with blank = none, refused on the quote popup form and on the create action; only a quote-linked SO shows the four read-only and takes them from the quote, so a direct/job-work SO keeps its existing editable brokerage; the re-quote change list does not diff the four new terms this row | pre-checked: row-watch: read the row and its target before starting\u003C/li>\n\u003C/ul>\n\u003Ch3>C375\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: src/routes/orders/new/+page.server.ts, src/routes/orders/new/orderLogic.ts\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>saving an SO with no quote is refused with a field error\u003C/li>\n\u003Cli>the same quote cannot produce a second SO\u003C/li>\n\u003Cli>a changed rate is stored on the SO while the quote keeps its own\u003C/li>\n\u003Cli>no approval event is written for an SO\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: e254bd254de10ce50e82102c4b6d3b9cfaf66888\u003C/li>\n\u003Cli>live: e254bd254de10ce50e82102c4b6d3b9cfaf66888\u003C/li>\n\u003Cli>notes: - | pre-checked: read the create action (quote link optional today, orderNeedsOwnerApproval gates status), quoteRevisionError one-shot check, and the coverage write that keys off approval | assumed: picks prefill from the quote's inputs_json.pick (per inch); a posted picks value still wins | assumed: buyer / quality / broker inherit only when the quote carries them (a fresh-construction quote keeps the posted quality); an unresolvable quote broker_id reads as DIRECT | assumed: the delivery window prefills dueDays only; the start/end dates land with C378 | assumed: the damaged (X) sale is exempt from the compulsory quote (D21) and keeps free entry until C390\u003C/li>\n\u003C/ul>\n\u003Ch3>C376\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: src/routes/orders/new/trading/+page.svelte, src/lib/components/orders/OrderEntryForm.svelte\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>the route renders the quote table when no quote is chosen\u003C/li>\n\u003Cli>back clears the choice\u003C/li>\n\u003Cli>changing the quote resets the four sales fields\u003C/li>\n\u003Cli>a searched quote row opens the form prefilled\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: 79bcd063edab25c8e219793fab45d3091eea0e40\u003C/li>\n\u003Cli>live: 79bcd063edab25c8e219793fab45d3091eea0e40\u003C/li>\n\u003Cli>notes: - | pre-checked: read the load that already ships openQuotes with rate/estQty/validity, and the existing quote picker sheet; this turns the picker into the landing state | assumed: the pending-quotes table reads days open from quote.created_at (added additively to the shared order load); Change/Back go back to the table so the next pick re-mounts the form from the new quote (a full reset), while an in-form quote change runs salesResetForQuote on the four sales fields; the reset's tolerance is the D25 5% default held in form state — the sale-tolerance input and its validation stay C378's; capture/draft/lead carries (?new=1, ?draftId=, ?partyId=, ?rate=, ?designId=, ?qty=, ?leadId=) still open the form so no read off a document is dropped\u003C/li>\n\u003C/ul>\n\u003Ch3>C377\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: src/lib/components/orders/OrderEntryForm.svelte, src/routes/orders/new/orderLogic.ts\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>the form opens on quantity with the keyboard up and Next moves focus without closing it\u003C/li>\n\u003Cli>the quote strip shows the rate on every step\u003C/li>\n\u003Cli>no 14-step or hidden-section markup remains for the SO\u003C/li>\n\u003Cli>label width stays under half the row\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: a6be19429dcca80d811aa9148bcce3de4685347e\u003C/li>\n\u003Cli>live: a6be19429dcca80d811aa9148bcce3de4685347e\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting\u003C/li>\n\u003C/ul>\n\u003Ch3>C378\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: src/lib/server/schema-foundation.ts, src/routes/orders/new/orderLogic.ts\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>an SO saved with 7 percent tolerance stores 7 and 30 is refused\u003C/li>\n\u003Cli>an end before start is refused\u003C/li>\n\u003Cli>the record shows both dates instead of day counts\u003C/li>\n\u003Cli>the form no longer asks due days or sales promise\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: 78b7b3e2c817736016ab4dd593eed094beac580c\u003C/li>\n\u003Cli>live: 78b7b3e2c817736016ab4dd593eed094beac580c\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: tol_pct reuses the existing order.tolerance_pct column (C379) instead of a duplicate column; the two dates are additive nullable columns, optional at booking (a quote may name no window) but always validated when present; only the SO retires due_days/promised_days — the job-work/outsource production forms keep theirs; the dispatch band's own ceiling moves with the form (0-25%), so a stored 25% is never silently read as 5%.\u003C/li>\n\u003C/ul>\n\u003Ch3>C379\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: src/routes/dispatch/+page.server.ts, src/lib/server/soCoverage.ts\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>a dispatch pushing cumulative metres past the band is refused with an amendment requirement\u003C/li>\n\u003Cli>X metres do not move the cumulative figure\u003C/li>\n\u003Cli>a dispatch below the hinted lot size saves\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: 79bcd063edab25c8e219793fab45d3091eea0e40\u003C/li>\n\u003Cli>live: 79bcd063edab25c8e219793fab45d3091eea0e40\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting\u003C/li>\n\u003C/ul>\n\u003Ch3>C380\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: src/lib/server/soCoverage.ts, src/routes/orders/[id]/+page.server.ts\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>a plan 3 percent under the quantity is accepted\u003C/li>\n\u003Cli>an order with no cover is not ready to produce\u003C/li>\n\u003Cli>an over-cover dispatch creates a pending item and no release\u003C/li>\n\u003Cli>an under-cover completion releases the difference\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: 6364cd4f265d8d825cabd03c4e372de973d52708\u003C/li>\n\u003Cli>live: 6364cd4f265d8d825cabd03c4e372de973d52708\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting\u003C/li>\n\u003C/ul>\n\u003Ch3>C381\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: src/lib/server/schema-foundation.ts, src/routes/dispatch/+page.server.ts\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>an SO saves with no consignee\u003C/li>\n\u003Cli>dispatch without one is refused\u003C/li>\n\u003Cli>a consignee party with category Others can be created and picked\u003C/li>\n\u003Cli>the decision shows as decide-at-fulfilment until resolved\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: 09e74cedb6b59b0a1026467ca3948ea5e232a8d3\u003C/li>\n\u003Cli>live: 09e74cedb6b59b0a1026467ca3948ea5e232a8d3\u003C/li>\n\u003Cli>notes: - | assumed: consignee = one nullable party link (Others | Godown | Transport, active); blank = decide at fulfilment; a booked consignee is read-only for planning and dispatch | assumed: the consignee build already landed in 9abcc4cf (committed under the C389 label) — this session re-proves the four acceptance lines instead of re-implementing; a create POST that omits active leaves the party inactive and PartyForm's own toggle stays the decider (A365) | pre-checked: row-watch: read the row and its target before starting\u003C/li>\n\u003C/ul>\n\u003Ch3>C382\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: src/lib/server/schema-foundation.ts, src/routes/orders/new/+page.server.ts\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>a migrated order resolves its broker by id\u003C/li>\n\u003Cli>a broker rename no longer orphans past orders\u003C/li>\n\u003Cli>an unknown broker is refused on the form and the action\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: 8186960a263cbc90cf0b1c80a6476cfb22848058\u003C/li>\n\u003Cli>live: 8186960a263cbc90cf0b1c80a6476cfb22848058\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: the broker picker posts the master id (name kept as the label and the booking's history), DIRECT stays a sentinel with no link, and the name→id backfill runs from apply-db.sh because drizzle-kit push never replays a migration file\u003C/li>\n\u003C/ul>\n\u003Ch3>C383\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: src/routes/orders/new/+page.server.ts, src/routes/orders/[id]/+page.server.ts\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>an order saved on a 0 percent 30 days slab stores cd_pct 0 and payment_days 30\u003C/li>\n\u003Cli>pendingOpsCondition no longer flags it\u003C/li>\n\u003Cli>the ops form shows the values prefilled\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: 9a1119a2378bea81c19275cc1f1166ff0c45332f\u003C/li>\n\u003Cli>live: 9a1119a2378bea81c19275cc1f1166ff0c45332f\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting\u003C/li>\n\u003C/ul>\n\u003Ch3>C384\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: src/routes/orders/new/orderLogic.ts\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>rate 0 is refused\u003C/li>\n\u003Cli>picks 0 and 201 are refused\u003C/li>\n\u003Cli>5500 metres is refused and 5000 accepted\u003C/li>\n\u003Cli>the same buyer PO number twice is refused\u003C/li>\n\u003Cli>the placeholder shows a per-inch example\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: 6b6d64492b9c7ad42f77c6ccc37ab93f87e208e6\u003C/li>\n\u003Cli>live: 6b6d64492b9c7ad42f77c6ccc37ab93f87e208e6\u003C/li>\n\u003Cli>notes: - | assumed: Rate > 0 for every kind and role; picks whole 1–200 per inch; quantity a multiple of 1,000 metres except beams and damaged sales; one buyer PO once per buyer (server-side at save; a cancelled order releases it); picks placeholder e.g. 64 | assumed: picks history written before the per-inch rule (e.g. 4,000) is never offered back as a prefill or a coin — the field stays blank instead; a damaged (X) sale is exempt from the 1,000 m step | pre-checked: row-watch: read the row and its target before starting\u003C/li>\n\u003C/ul>\n\u003Ch3>C385\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: src/lib/components/orders/OrderEntryForm.svelte\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>a simulated failure shows a banner and lands on the offending field with its message\u003C/li>\n\u003Cli>the hidden container no longer holds error markup\u003C/li>\n\u003Cli>a success still redirects as today\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: 8fe5689536dc2e549183fcf1d2cde81a76be6588, 06d1186a8ff2f03336766c453520be2f160c0997\u003C/li>\n\u003Cli>live: 06d1186a8ff2f03336766c453520be2f160c0997\u003C/li>\n\u003Cli>notes: pre-checked: row-watch: read the row and its target before starting | assumed: no runnable test harness in this checkout (tests/ removed, bunfig root=./tests) - the orderLogic.test.ts fieldErrorJump cases ship with the helper; proof here is bun run check + tsc clean on the touched files, the rendered-failure check waits for the deploy gate\u003C/li>\n\u003C/ul>\n\u003Ch3>C386\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: src/lib/server/queue.ts, src/routes/orders/[id]/+page.svelte\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>an order with sales and cover complete but no planning is ready to produce\u003C/li>\n\u003Cli>the planning board lists it with its age\u003C/li>\n\u003Cli>the rail shows the three states\u003C/li>\n\u003Cli>a role lands on its board after sign-in\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: f289ed24ef537f6f79c0258fb1bc618340489151, 91cfa1af6972dbc76ddd3b7bf90e8075084250cf\u003C/li>\n\u003Cli>live: f289ed24ef537f6f79c0258fb1bc618340489151\u003C/li>\n\u003Cli>notes: - | assumed: the sales board stays the queue's existing reading (SOs still waiting for owner approval; D23 means an ordinary booked SO never sits there), the landing page renders exactly stageSectionsFor(role) from the one pendingBoard query, row limits stay MAX=6 for sales/PPC and 20 for planning, and the Orders list gets no extra planning-pending chip this row (the board already lists it) | pre-checked: row-watch: read the row and its target before starting | assumed: an admin owns every stage like the owner — stageSectionsFor now maps admin to sales,planning,ppc, the same owner-or-admin reading ops.ts and the record's stageRoleOpen already use\u003C/li>\n\u003C/ul>\n\u003Ch3>C387\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: src/routes/orders/[id]/+page.svelte, src/routes/orders/[id]/+page.server.ts\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>an order with no image lets planning attach one\u003C/li>\n\u003Cli>the photo stays visible while a field is edited\u003C/li>\n\u003Cli>saving the planning stage clears the order from the planning board\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: 5300a82ce7ea1159e5ade1f568bbe76d43f2034a\u003C/li>\n\u003Cli>live: 5300a82ce7ea1159e5ade1f568bbe76d43f2034a\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: planning is complete on the append-only so:planning-complete event (the board is open SOs minus that event), the buyer order image is an order_attachment saved with the existing capture store, and the consignee rides dispatch_city until C381\u003C/li>\n\u003C/ul>\n\u003Ch3>C388\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: src/lib/components/orders/OrderEntryForm.svelte\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>picking a quality with an alias writes it to order.alias\u003C/li>\n\u003Cli>typing the alias finds and selects the quality\u003C/li>\n\u003Cli>a typed alias overrides the inherited one\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: fd1ff1480853871d1398b154266e0173675fc181, 4cf3d68e664f50e85223ff126def4555f8fc1a7e\u003C/li>\n\u003Cli>live: 4cf3d68e664f50e85223ff126def4555f8fc1a7e\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting\u003C/li>\n\u003C/ul>\n\u003Ch3>C389\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: src/lib/server/costBasis.ts, src/lib/server/reports.ts\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>the report shows the same numbers as the cost engine for a covered order\u003C/li>\n\u003Cli>no new order_cost rows are written\u003C/li>\n\u003Cli>the form no longer offers the field\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: 9abcc4cf1a876ab3ffebc6165c4f5a5d60100aed\u003C/li>\n\u003Cli>live: 9abcc4cf1a876ab3ffebc6165c4f5a5d60100aed\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting\u003C/li>\n\u003C/ul>\n\u003Ch3>C390\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: src/routes/orders/new/+page.server.ts, src/lib/components/orders/OrderEntryForm.svelte\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>the damaged form saves without a quote\u003C/li>\n\u003Cli>a metre figure above the lot balance is refused\u003C/li>\n\u003Cli>the source order link is stored\u003C/li>\n\u003Cli>the sale is marked as damaged\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: ebe1a5e5842a31f423bc1b5d3405a4ab59c05ebe, 10c0250968b226743c731fc7cf4ba439de189d21\u003C/li>\n\u003Cli>live: ebe1a5e5842a31f423bc1b5d3405a4ab59c05ebe\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: the damaged lot is the salvage pool key (quality · pick) — the only place grade X metres live; the sale writes the pool's zero-cost out entry so the metre cap is cumulative, and the source SO is read from the lot's own entries rather than re-typed\u003C/li>\n\u003C/ul>\n\u003Ch3>C391\u003C/h3>\n\u003Cul>\n\u003Cli>status: withdrawn\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: src/lib/components/orders/OrderEntryForm.svelte\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>a draft saved after typing quantity restores it\u003C/li>\n\u003Cli>a hidden field never appears in the snapshot\u003C/li>\n\u003Cli>switching type or role does not leak a prior draft hidden values\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: -\u003C/li>\n\u003Cli>notes: - | pre-checked: withdrawn 2026-10-31: merged into C393 — same file, one session covers the draft snapshot and the split\u003C/li>\n\u003C/ul>\n\u003Ch3>C392\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: src/routes/orders/[id]/+page.server.ts, src/routes/orders/[id]/+page.svelte\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>the ops form no longer edits the sale rate or the cash discount\u003C/li>\n\u003Cli>dispatch city is replaced by the planning consignee\u003C/li>\n\u003Cli>a value typed on one surface is never silently overwritten by the other\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: a59966b54f18f3aa8b2cd6eab0d301035221f47d\u003C/li>\n\u003Cli>live: a59966b54f18f3aa8b2cd6eab0d301035221f47d\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: The ops card shows the rate and cash discount read-only and never posts them; the action takes the row's own values. A sale's send-to city follows planning's consignee; a non-SO order keeps its city (Q368/A368). The commercial set is a booking gate, so a sales-role completion is not asked for fields the card cannot carry.\u003C/li>\n\u003C/ul>\n\u003Ch3>C393\u003C/h3>\n\u003Cul>\n\u003Cli>status: withdrawn\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: src/lib/components/orders/OrderEntryForm.svelte\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>no single order-form component over 900 lines\u003C/li>\n\u003Cli>the form still saves identically and bunx tsc --noEmit adds no error\u003C/li>\n\u003Cli>a draft restores only the fields the form shows, and a hidden field never appears in the snapshot\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: -\u003C/li>\n\u003Cli>notes: - | pre-checked: withdrawn 2026-10-31: folded into C395 — the rebuild deletes the sections the split was needed for, and the draft-snapshot rule is part of its acceptance\u003C/li>\n\u003C/ul>\n\u003Ch3>C394\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: docs/contracts/so-form.json, src/lib/contracts.ts\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>the loader returns the SO contract typed\u003C/li>\n\u003Cli>a malformed contract fails with its path\u003C/li>\n\u003Cli>a form has no field list outside its contract file\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: 4a0db8449bf13a114b923502547b6ef6395f340e, 1db7c5723cc81305d6a5f6f681873be19d010c5a\u003C/li>\n\u003Cli>live: 4a0db8449bf13a114b923502547b6ef6395f340e\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting\u003C/li>\n\u003C/ul>\n\u003Ch3>C395\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: src/lib/components/orders/OrderEntryForm.svelte, src/routes/orders/new/trading/+page.svelte, src/routes/orders/new/orderLogic.ts\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>the rendered sales form has exactly quantity, delivery start, delivery end, rate, tolerance and remark\u003C/li>\n\u003Cli>both promise dates are prefilled from the quote and editable\u003C/li>\n\u003Cli>buyer order no, cut size, rolls, consignee and coverage are absent\u003C/li>\n\u003Cli>the table screen has no Create SO button\u003C/li>\n\u003Cli>a draft restores only the six fields\u003C/li>\n\u003Cli>saving books the SO with the quote carried\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: f1bd7d46debd2b09850de73acbbb8136d6053b3a, fe9e3379c07934efa060030e01f00ae9156e0d40\u003C/li>\n\u003Cli>live: fe9e3379c07934efa060030e01f00ae9156e0d40\u003C/li>\n\u003Cli>notes: - | pre-checked: C395 implemented and gated (check exit 0, tsc adds no error); SSR render shows the six contract fields\u003C/li>\n\u003C/ul>\n\u003Ch3>C396\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: src/routes/orders/new/orderLogic.test.ts, src/lib/contracts.ts, src/lib/components/orders/OrderEntryForm.svelte\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>the test reads the contract and passes on the shipped field list\u003C/li>\n\u003Cli>re-adding rolls to the sales form fails it\u003C/li>\n\u003Cli>deleting a contract field fails it\u003C/li>\n\u003Cli>the failure names the contract entry\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: 89bee571ceeb5e788083eabf074984d31cece900, fcefaba1f28f5572beb904a5186f8519c7beaf8e, dd6beb612dd6b9454dcead5dbb7474e6af17b933\u003C/li>\n\u003Cli>live: -\u003C/li>\n\u003Cli>notes: - | assumed: the shipped sales form is src/lib/components/orders/SoOrderForm.svelte (C395 moved the SO there), so the contract test reads that screen's control chain and leaves OrderEntryForm to the job-work/production/damaged forms; a field's control is a branch on f.name === 'x' in draw order — a hidden input or a name used only in a helper is not a control | assumed: C396 re-run verified the already-present work against the real tree (a contract field removed, a rolls branch added to SoOrderForm, both restored): the test reads docs/contracts/so-form.json and SoOrderForm.svelte, never OrderEntryForm, and with no tests/ directory in this checkout the one file ran against a throwaway preload removed afterwards | assumed: tests/setup.ts restored verbatim from 7668c583^ and kept (bunfig preloads it; without it no bun test runs in this checkout); the contract/test files are unchanged and the two stale readings (four fields, OrderEntryForm.svelte) stay superseded by C395 | assumed: the shipped field list the test passes on is the contract's own list read from docs/contracts/so-form.json on disk, not a second hardcoded copy: a hardcoded copy makes a legitimate contract edit (field added to contract and screen) fail, the opposite of the row rule | assumed: a braced string literal control name is the same control as a quoted one, so the braced rolls control belongs in the absent check; the shipped field list stays the contract own six from docs/contracts/so-form.json, and OrderEntryForm stays out as C395 superseded it | assumed: a contract may list its entries in any document order (order alone decides the draw order), so every failure pointer must read the contract's own line (docIndex), not the sorted position | assumed: a hidden input is the form envelope, not a field: only visible controls are checked, the same rule assertRenderedForm applies; the row's four-field / OrderEntryForm.svelte readings stay superseded by C395 | auto-answered (Pareto): do the row exactly as written; anything it does not name keeps its current behaviour (attempt 2) | pre-checked: row-watch: read the row and its target before starting | assumed: a contract field with no branch of its own is drawn by the chain's {:else} when that branch writes name={f.name}, so one contract edit completes a field on this form; a header that names a field without a control is not a drawn field\u003C/li>\n\u003C/ul>\n\u003Ch3>C397\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: scripts/form-contract-check.ts, src/lib/contracts.ts, src/lib/components/orders/OrderEntryForm.svelte\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>the check passes on the live build\u003C/li>\n\u003Cli>a hidden error div fails it with the element printed\u003C/li>\n\u003Cli>a table missing the quote-no column fails it\u003C/li>\n\u003Cli>it runs in about a second per form\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: cbced940286d1a4f577faad76d913ef1e64f159d\u003C/li>\n\u003Cli>live: -\u003C/li>\n\u003Cli>notes: - | assumed: the first SSR 500 after a Vite '(ssr) program reload' is the dev server's module init, not the screen's contract, so the check reads the page once more before it judges; a screen that 500s twice still fails | auto-answered (Pareto): yes — re-run the row unchanged: the failure was the integration (deploy/commit), not the row's work, so the safe reading is another attempt (attempt 2) | pre-checked: row-watch: read the row and its target before starting | assumed: the hidden-markup clause is a rule about the rendered screen, not only the create form, so the table screen carries it too; a refused 127.0.0.1 connection is the host's IPv6-only binding, not a missing app, so one localhost retry is the safe reading | assumed: the row builds the SO entry form, so it is built from docs/contracts/so-form.json and now names it (the block's owner-approved field inventory)\u003C/li>\n\u003C/ul>\n\u003Ch3>C398\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: src/lib/components/ScreenShell.svelte, src/routes/quote/new/+page.svelte, src/lib/components/orders/OrderEntryForm.svelte, src/lib/components/focus/focusSpec.test.ts\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>quote and SO render the same shell and layer classes\u003C/li>\n\u003Cli>no popup sets its own width or backdrop\u003C/li>\n\u003Cli>the SO page header is reachable under the layer\u003C/li>\n\u003Cli>light mode only\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: 16ce62b7d9ab28885edf15554dada19e52532168\u003C/li>\n\u003Cli>live: -\u003C/li>\n\u003Cli>notes: - | assumed: one layer width for every popup (max-w-xs one-field popups widen to max-w-md; identical on a phone, wider only on a desk), the blur + bg-black/70 keyboard variant stays inside the spec (C144 behaviour unchanged), and the shell header pins (sticky) while the layer starts at top-14 so the page header stays reachable | auto-answered (Pareto): yes — re-run the row unchanged: the failure was the integration (deploy/commit), not the row's work, so the safe reading is another attempt | pre-checked: row-watch: read the row and its target before starting | assumed: the row's same-shell rule covers every branch of the two screens, so the sale screen's damaged (X) branch takes ScreenShell too; the spec, ScreenShell, FocusLayer and the seven quote popups stay exactly as committed in f2ed3993 (already at HEAD, swept into a C396 commit) and this run changes only the branch that still drew its own page (min-h-screen/bg-base-200/max-w-xl/own header), with a guard case in focusSpec.test.ts | assumed: the row builds the SO entry form, so it is built from docs/contracts/so-form.json and now names it (the block's owner-approved field inventory)\u003C/li>\n\u003C/ul>\n\u003Ch3>C399\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: src/lib/historyLayer.ts, src/lib/components/orders/OrderEntryForm.svelte, src/lib/components/quote/TermsPopup.svelte\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>with the layer open back closes only the layer and the form stays\u003C/li>\n\u003Cli>a second back reaches the quote table\u003C/li>\n\u003Cli>history.length grows by exactly one per layer\u003C/li>\n\u003Cli>the audit fails a layer that skips the helper\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: f47d88c51a89d4fa1be8f56c26bfdf91ca4bb191\u003C/li>\n\u003Cli>live: -\u003C/li>\n\u003Cli>notes: - | assumed: the back helper lands in focus/FocusLayer.svelte (the shared layer both targets already render) rather than in OrderEntryForm/TermsPopup, so one push per open layer and no caller can double-push; a layer with no dismiss pushes nothing; layers on other screens are baselined, not migrated this row | auto-answered (Pareto): yes — re-run the row unchanged: the failure was the integration (deploy/commit), not the row's work, so the safe reading is another attempt | pre-checked: row-watch: read the row and its target before starting | assumed: C399's helper, FocusLayer wiring and audit were already at HEAD, swept into f2ed3993 (a C396 commit), so the row kept returning because its targets never moved; the sound fix for the back defect is in the helper, where each layer's pushed state now carries its own id, and the two component targets need no markup change because they already render FocusLayer | assumed: the row builds the SO entry form, so it is built from docs/contracts/so-form.json and now names it (the block's owner-approved field inventory)\u003C/li>\n\u003C/ul>\n\u003Ch3>C400\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: AGENTS.md, scripts/row-watch.sh\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>AGENTS.md and the row prompt carry the rule\u003C/li>\n\u003Cli>assertAbsent exists and is used\u003C/li>\n\u003Cli>a row that leaves the old placement fails the contract test\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: 61d44bac0c2fc2883bf1d2d4812c88d7bdd1cb31, 9cb1542d3d3c48bd11f48326be5bdba1ff0ed8b1, c41a0793aa0d43e244368cf3e06b875abbfd9df5\u003C/li>\n\u003Cli>live: -\u003C/li>\n\u003Cli>notes: - | assumed: assertAbsent already exists from C396, so C400 adds no second helper — the SO contract test's C400 case (remark moved to dispatch, still drawn) is the proof; moved and removed are one assertion, and the rule lives in AGENTS.md + the row prompt only, with the prompt line escaping its backticks because that heredoc is unquoted | assumed: the row prompt means both surfaces a row session reads - the watcher's per-row brief and .opencode/agent/row.md - so the rule goes in both; the enforcement stays the existing assertAbsent/assertFormSpec, no new checker | auto-answered (Pareto): do the row exactly as written; anything it does not name keeps its current behaviour (attempt 2) | pre-checked: row-watch: read the row and its target before starting\u003C/li>\n\u003C/ul>\n\u003Ch3>C401\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: AGENTS.md, docs/QUEUE-AUTO.md, scripts/queue-next.ts, tests/queueScreenHold.test.ts\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>adding a row on an open row target is reported\u003C/li>\n\u003Cli>the two docs state the rule\u003C/li>\n\u003Cli>an existing serialised clash still runs after the first closes\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: 6c6a93d4162df8b8e5ae33579d32d6e5d0fc2ee0\u003C/li>\n\u003Cli>live: -\u003C/li>\n\u003Cli>notes: - | assumed: block = the rows open on the board now (the line is serial, so the earlier open row owns the screen); only a pending row is held, never a reopen/verify row; blocked-owner and withdrawn rows hold nothing; doc-only targets exempt | auto-answered (Pareto): do the row exactly as written; anything it does not name keeps its current behaviour (attempt 2) | pre-checked: row-watch: read the row and its target before starting\u003C/li>\n\u003C/ul>\n\u003Ch3>C402\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: AGENTS.md, scripts/contract-gate-check.ts, docs/QUEUE.md\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>AGENTS states inventory-before-queue\u003C/li>\n\u003Cli>a block row without a contract reference is refused at precheck\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: 9403baf433841f468d77a8708b0f76dfef100d50\u003C/li>\n\u003Cli>live: -\u003C/li>\n\u003Cli>notes: - | assumed: the refusal must reach the plan, not only the CLI — row-watch records its pre-check even when the gate refuses (it ignores the exit code), so the gate sits in needsPrecheck: a block row with no contract waits as needs-pre-check even when a record exists; fewest files, no new hold status, self-healing once a pre-check names an existing contract | auto-answered (Pareto): do the row exactly as written; anything it does not name keeps its current behaviour (attempt 2) | pre-checked: row-watch: read the row and its target before starting\u003C/li>\n\u003C/ul>\n\u003Ch3>C403\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"http://127.0.0.1:5173/orders/new/trading?quoteId=c68-quote-01\">http://127.0.0.1:5173/orders/new/trading?quoteId=c68-quote-01\u003C/a>, docs/contracts/so-form.json, src/lib/components/orders/SoOrderForm.svelte, src/lib/contracts.test.ts, src/routes/orders/new/orderLogic.test.ts, docs/PLANNING.md, docs/BUILD-LOG.md\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: 74ee4aae0ada9289919eb91cb9f2973d1adc31c7\u003C/li>\n\u003Cli>live: -\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting\u003C/li>\n\u003C/ul>\n\u003Ch3>C404\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"http://127.0.0.1:5173/orders/new/trading?quoteId=c68-quote-01\">http://127.0.0.1:5173/orders/new/trading?quoteId=c68-quote-01\u003C/a>, src/lib/components/orders/SoOrderForm.svelte, docs/PLANNING.md, docs/BUILD-LOG.md\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>tapping the rate field expands a Previous entries portion under it, and tapping the quantity field does the same for quantity\u003C/li>\n\u003Cli>tapping a suggestion writes its value into that field and closes the portion\u003C/li>\n\u003Cli>no portion shows while neither field is tapped\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: 48ebab6bdb6fb5518d0b2995b73b298d8c609fc0\u003C/li>\n\u003Cli>live: -\u003C/li>\n\u003Cli>notes: - | assumed: the row's two fields are rate and qty; the portion opens on focus and closes on a suggestion or its own Close, never on blur; the suggestions are the D25 coins already on the screen's data; tolerance and remark keep their existing inline chips\u003C/li>\n\u003C/ul>\n\u003Ch3>C405\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"http://127.0.0.1:5173/orders/new/trading?quoteId=c68-quote-01\">http://127.0.0.1:5173/orders/new/trading?quoteId=c68-quote-01\u003C/a>, docs/contracts/so-form.json, src/lib/components/orders/SoOrderForm.svelte, src/lib/contracts.test.ts, src/routes/orders/new/orderLogic.ts, src/routes/orders/new/orderLogic.test.ts, docs/PLANNING.md, docs/BUILD-LOG.md\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: 0ad263fb72ca29f3b53d3ddc072ef6624fdcfcf0\u003C/li>\n\u003Cli>live: -\u003C/li>\n\u003Cli>notes: - | assumed: terms like brokerage is the four D17/D18 commercial terms the quote carries (brokerage, pass-on, delivery term, freight recovery), shown on the read-only quote strip, never asked on the form; a quote that states none shows a dash\u003C/li>\n\u003C/ul>\n\u003Ch3>C406\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: \u003Ca href=\"http://127.0.0.1:5173/orders/new/trading?quoteId=c68-quote-01\">http://127.0.0.1:5173/orders/new/trading?quoteId=c68-quote-01\u003C/a>, src/lib/components/orders/SoOrderForm.svelte, src/routes/orders/new/orderLogic.ts, src/routes/orders/new/orderLogic.test.ts, src/routes/orders/new/+page.server.ts\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>delivery start and end sit side by side in one two-column row\u003C/li>\n\u003Cli>the form shows the window period in days\u003C/li>\n\u003Cli>the period chips offer the quote, buyer, quality and recent spans then the 7/15/30/40 ladder\u003C/li>\n\u003Cli>tapping a chip sets delivery end to start plus its days and leaves the start where it was\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: a04a0897336cdd9807873fe05b5d1cad6ab5a220\u003C/li>\n\u003Cli>live: -\u003C/li>\n\u003Cli>notes: form block: docs/contracts/so-form.json read - its six fields, their order, rules and prefills are unchanged; this row changes only how the two delivery dates are drawn and suggested | assumed: period chips are the spans already in use - the quote window, this buyer last window, this quality, the last three orders - then the usual 7/15/30/40 ladder; a tap rewrites only delivery end (start plus N days), start never moves, both keep existing validation.\u003C/li>\n\u003C/ul>\n\u003Ch3>C407\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: src/lib/components/orders/SoOrderForm.svelte, src/routes/orders/new/orderLogic.ts, src/routes/orders/new/orderLogic.test.ts\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\n(none recorded — lane must write observable checks first)\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: 6f40a18d5c51e3c5ead6c5ecae6753b31089feb2\u003C/li>\n\u003Cli>live: -\u003C/li>\n\u003Cli>notes: -\u003C/li>\n\u003C/ul>\n\u003Ch3>C408\u003C/h3>\n\u003Cul>\n\u003Cli>status: done\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: src/routes/orders/+page.svelte, docs/PLANNING.md, docs/BUILD-LOG.md\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>a saved order confirms with the app-wide popup toast and not an inline banner\u003C/li>\n\u003Cli>the toast carries the same words (Added - order SO-261104-U7IO)\u003C/li>\n\u003Cli>the new row still flashes row-highlight for 4.2s\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: 55c2b913846c82fc5253e9f66cff51ad4f36cc14\u003C/li>\n\u003Cli>live: -\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: the popup is the app-wide toast (notify, rendered by Toasts in the root layout); it replaces the inline confirmation banner on the orders list while the new row keeps flashing row-highlight for 4.2s; only the orders list changes - the other lists keep their own inline confirmations until their own rows\u003C/li>\n\u003C/ul>\n\u003Ch3>C409\u003C/h3>\n\u003Cul>\n\u003Cli>status: doing\u003C/li>\n\u003Cli>priority: P1\u003C/li>\n\u003Cli>target: src/lib/components/SuggestionChips.svelte, src/lib/components/quote/TermEditor.svelte, src/lib/components/quote/NewSummary.svelte, src/lib/components/quote/NewCalc.svelte, src/lib/components/quote/TermsPopup.svelte, src/routes/quote/new/+page.svelte, src/routes/quote/new/quoteNewState.svelte.ts, src/lib/components/focus/focusSpec.test.ts, docs/PLANNING.md, docs/BUILD-LOG.md, docs/OWNERSHIP.md, docs/FOCUS-ENTRY.md\u003C/li>\n\u003Cli>verify: -\u003C/li>\n\u003Cli>acceptance:\u003Cul>\n\u003Cli>tapping a quote term opens its suggestions under that row in the page, with no popup\u003C/li>\n\u003Cli>tapping a suggestion fills the field and the editor stays until Done or Close\u003C/li>\n\u003Cli>the sale form and the quote terms draw the same suggestion chips\u003C/li>\n\u003Cli>no term field, value or saveTerm write changed\u003C/li>\n\u003C/ul>\n\u003C/li>\n\u003Cli>owner: -\u003C/li>\n\u003Cli>commits: -\u003C/li>\n\u003Cli>live: -\u003C/li>\n\u003Cli>notes: - | pre-checked: row-watch: read the row and its target before starting | assumed: 'throughout the website' starts with the quote term popup (the popup whose purpose is the suggestion list); the signed FOCUS-ENTRY wizards and field popups are the entry pattern itself and keep their popups; two new files, the old popup deleted with its only caller, reversible\u003C/li>\n\u003C/ul>\n"},uses:{params:["slug"]}}], form: null, error: null }); }); } </script> </div> </body> </html>