Build Seth's changes C1 to C11 (Gitea issues 1, 8, 18, 23, 24, 25, 27, 31, 32, 33, 36)
ci / server (pull_request) Successful in 12m48s
ci / frontend (pull_request) Successful in 54s
ci / image (pull_request) Skipped
ci / e2e (pull_request) Successful in 4m38s

- C1 (issue 1): over target follows VISUAL ticket hours, not the timer.
- C2 (issue 24): a Q.C. reject always needs a reason; accept needs an NCR number after a reject without one.
- C3 (issue 25): an incomplete unit ITP blocks filing.
- C4 (issue 27): prints open the print dialog on the page, no new tab.
- C5 (issue 31): filing is blocked while VISUAL shows a work order open; the feed sets vclosed on VISUAL packets.
- C6 (issue 8): the data book leaves out the history pages.
- C7 (issue 18): the supervisor approves each received short; accept and filing wait for it.
- C8 (issue 23): per-department checklists, edited by the department supervisor or Admin, frozen at START.
- C9 (issue 32): Q.C. and Clerical may run the stamp check.
- C10 (issue 33): the PM screen and reports are for PS-ProjectMgmt and Admin only.
- C11 (issue 36): the Stall screen lists the packets assigned to the welder, at the supervisor's stall.

Migration 0011. Docs: PLAN (also issue 9 confirmed, issue 4 asked), POLICY, SECURITY, SCHEMA, FEED, README, CHANGELOG.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
2026-10-30 16:36:49 -06:00
co-authored by Claude Opus 5.5
parent 150c507a31
commit 70a97398f1
101 changed files with 3871 additions and 1098 deletions
+38 -30
View File
@@ -145,7 +145,8 @@ Each phase ends with passing tests, docs updated (README, CHANGELOG, SECURITY.md
| D1, D2, D4 | Deferred (envelope encryption, Key Vault) |
| D3 | IT's (host disk encryption on docker-1) |
| D5 | Closed, phase 4 (optional ClamAV) |
| D6, D7 | Phase 10 (decided 2026-10-28, Gitea issues 7 and 8: nothing is purged and filed packets are archived to the QNAP share at filing; the one data book leaves out the history pages) |
| D6 | Phase 10 (decided 2026-10-28, Gitea issue 7: nothing is purged and filed packets are archived to the QNAP share at filing) |
| D7 | Closed 2026-10-30 (Gitea issue 8, change C6: the one data book goes to the customer and leaves out the history pages) |
| M1 | Closed, phase 2 |
| M2 | Closed, phase 7 |
| M3 | Closed, phase 9 |
@@ -181,7 +182,7 @@ Conventions: identity bigints except users (uuid = AD objectGUID); Postgres enum
- **Inputs:** `Principal` (user, admin, support set, clerical_supervisor, shop dept to level map, station limits, session kind, or `system="visual-feed"`) and `PacketState` (status, dept, station, wh_skipped, routed_to, vclosed, removed, open COs, open shorts). Pure functions in `server/packetstation/policy/`, no I/O.
- **Custody** `holds()` is a direct port: draft CL; warehouse WH; ready and review dept lead or above; assigned and in_progress dept lead or above or works_on (worker in dept whose station limits include the station, and, tightened per the README, the assigned welder for start and submit); qc QC; complete CL; filed nobody.
- **Action enum** with a rule per action: who, from and to status, dept change, CO hold, preconditions, signature meaning, reason required. Transitions: SEND_TO_WAREHOUSE, RELEASE_TO_SHOP, SEND_DRAFT_TO_QC, RETURN_TO_CLERICAL, WH_RELEASE, WH_SEND_BACK, SEND_BACK_TO_WAREHOUSE, ASSIGN, UNASSIGN, PULL_BACK, START, SUBMIT, RETURN_TO_STATION, SEND_TO_QC, ROUTE_FROM_REVIEW, QC_REJECT, QC_ACCEPT, QC_ACCEPT_AND_ROUTE, FILE, ADMIN_REOPEN. Edits: EDIT_BOM, WH_RECEIVE_SHORT (a narrow endpoint that replaces onlyShortLines), EDIT_HEATS, EDIT_WELDS, EDIT_CHECKLIST, EDIT_STAGE_FIELDS, CLOCK, EDIT_QC, SET_WH_STAGE, EDIT_DEPT, MOVE_UNIT, EDIT_WOS, EDIT_DOCUMENT_SET, EDIT_HEADER, REV_APPROVE (clerical supervisor), SET_VCLOSED, SET_DATABOOK_AT, DOC_ADD, DOC_REMOVE, CO_ISSUE, CO_APPROVE, CO_REJECT, CO_HOLD_TOGGLE, CO_VERIFY, ITP_*, VIS_* (worker only).
- **Preconditions** as named predicates, now server-side: heat_map_answered, drawing_attached, bom_all_pulled_or_short, welder_set, checklist_complete, welds_recorded, filler_set, qc_book_spool_location, qc_missing_empty, reason_given, vclosed_if_databook (warning only when work orders are still open in VISUAL; block only when vclosed is unset and the route is Data Book), co_staged_if_dwg_change.
- **Preconditions** as named predicates, now server-side: heat_map_answered, drawing_attached, bom_all_pulled_or_short, welder_set, checklist_complete, welds_recorded, filler_set, qc_book_spool_location, qc_missing_empty, reason_given, closed_in_visual (replaced vclosed_if_databook on 2026-10-30, change C5: a VISUAL packet files only when the feed has seen every work order closed, on both routes; a hand packet on the Data Book route needs the Clerical confirm), itp_complete (C3), shorts_approved (C7), ncr_given (C2), co_staged_if_dwg_change.
- **Order of checks** keeps the old semantics: removed, wrong status, CO hold (applies to admins too), admin bypass of custody with a required IT reason, filed lock (only SET_DATABOOK_AT and ADMIN_REOPEN), who and custody, then preconditions (never bypassed).
- **`can` on reads:** every packet read returns `can: [...]` (passes role, custody, status and preconditions), `blocked: {action: [reasons]}` (passes role and custody but fails a precondition or the CO hold, so the UI can show a disabled control with the reason), `holder`. Boards evaluate transitions only from header columns plus an open-CO count.
- **Signatures:** required for SUBMIT, SEND_TO_QC, QC_ACCEPT, QC_ACCEPT_AND_ROUTE, QC_REJECT, FILE, ROUTE_FROM_REVIEW, ADMIN_REOPEN, CO_ISSUE, CO_VERIFY, CO_APPROVE, CO_REJECT, REV_APPROVE, hand uploads, ITP_BLOCK_SIGN, ITP_SIGN_OFF. The body carries `sign: {factor, secret}`; the server verifies the factor against the session's own user inside the transaction (PIN allowed in any session on any device, as the brief says; password everywhere), logs the attempt, applies the five-strike PIN disable and the three-strike session end, and writes the signatures row with a content hash over what was signed.
@@ -217,19 +218,19 @@ Conventions: identity bigints except users (uuid = AD objectGUID); Postgres enum
Need an answer before the named phase. Defaults apply if none arrives in time.
1. **Station timer** (Seth, before phase 5): keep, cross-check against labor tickets, or drop. Default: keep the timer, show ticket hours beside it. Phase 5 (2026-10-16) applied the default: the station timer is the clock of record and the VISUAL ticket hours are shown beside it. Decided by SethD on 2026-10-26, Gitea issue 1: keep the timer as built, but flag over target on the VISUAL ticket hours (change C1 below).
1. **Station timer** (Seth, before phase 5): keep, cross-check against labor tickets, or drop. Default: keep the timer, show ticket hours beside it. Phase 5 (2026-10-16) applied the default: the station timer is the clock of record and the VISUAL ticket hours are shown beside it. Decided by SethD on 2026-10-26, Gitea issue 1: keep the timer as built, but flag over target on the VISUAL ticket hours (change C1 below). Built on 2026-10-30.
2. **PDFs on the server** (confirm before phase 7): reportlab + pypdf + pypdfium2. Default: yes. Phase 7 (2026-10-17) applied the default: reportlab 5.0.1, pypdf and pypdfium2, with Pillow 13.0.0 for the rasters.
3. **Frontend stack** (confirm before phase 1): TypeScript + React + Vite. Default: yes. Plain JavaScript would not be faster for parity: the old 7,000 lines are screen code that must be rewritten either way, and typed API models cut rework.
4. **PIN defaults** (confirm): 6 to 12 digits, five attempts, 10-hour shop session, device cookie. Was open (Seth and Q.C., before phase 6): whether Q.C. accept and filing require the domain password even with a PIN set. Default: PIN is enough. Confirmed by SethD on 2026-10-26, Gitea issue 2: the PIN is enough for every sign-off, Q.C. accept and filing included. IT: device certificate later. The device cookie stays and no device certificate is planned: confirmed by Spencer (IT) on 2026-10-18, Gitea issue 3.
5. **Several open orders on a project** (before phase 3): which order a packet shows. Proposed rule: the open order whose line's top job is the packet's work order base, else the newest open order, else the newest closed one; the packet shows "via base" or "via project" and Clerical can override. Needs Seth's view. Phase 3 (2026-10-16) built the default in one function (`feed/orders.py`): a Clerical pin, else the base's own linked order, else the project order whose top job is the unit, else the project's first open order, else its newest; the source (`via`) is stored on the project and unit and shown on the project page, which lists every open order. Seth may change the rule later in that one place. SethD on 2026-10-28, Gitea issue 4: the order should follow the shop schedule, linked live so a job that is moved, pushed or pulled up changes what its packets show. That needs a discussion first; the rule stays as built until then.
5. **Several open orders on a project** (before phase 3): which order a packet shows. Proposed rule: the open order whose line's top job is the packet's work order base, else the newest open order, else the newest closed one; the packet shows "via base" or "via project" and Clerical can override. Needs Seth's view. Phase 3 (2026-10-16) built the default in one function (`feed/orders.py`): a Clerical pin, else the base's own linked order, else the project order whose top job is the unit, else the project's first open order, else its newest; the source (`via`) is stored on the project and unit and shown on the project page, which lists every open order. Seth may change the rule later in that one place. SethD on 2026-10-28, Gitea issue 4: the order should follow the shop schedule, linked live so a job that is moved, pushed or pulled up changes what its packets show. That needs a discussion first; the rule stays as built until then. SethD on 2026-10-29: the schedule is Presley's Production Planner, which the whole shop works from today. Asked on issue 4 (2026-10-30): what it is, where it lives, what a row holds and how often it changes. Packet Station would only read it.
6. **VISUAL_ENCRYPT** (IT, before production): yes once vsql has a trusted certificate; `no` until then.
7. **Policy tightenings** listed under "Challenges" 1 to 3 (Seth, before phase 2). Confirmed by SethD on 2026-10-26, Gitea issue 6: "good as shown". Every row is kept, filing for packets routed to Shipping included (Spencer read the answer that way on 2026-10-27).
8. **Repo location**: PacketStation2 as proposed, or another name.
9. **Retention period** (D6) and customer-facing data book copy (D7): deferred, but a decision from Seth and Q.C. lets a later phase close them. Gitea issue 7: SethD expects all data to be kept (2026-10-26). Spencer decided on 2026-10-27 that project files are also archived to an NFS share he sets up on the QNAP, with an Admin setting for the folder path that checks read and write (phase 10, "Archive location"). Nothing is deleted from Packet Station; the archive is a copy. Still open on issue 7: a minimum retention period, if any, and what goes into the archive and when. Decided on 2026-10-28: all data is kept and nothing is purged; at filing the data book and each of the packet's documents go to the archive with a manifest (SethD, Gitea issue 7). There is one data book, the customer copy, without the history pages (SethD, Gitea issue 8, change C6).
9. **Retention period** (D6) and customer-facing data book copy (D7): deferred, but a decision from Seth and Q.C. lets a later phase close them. Gitea issue 7: SethD expects all data to be kept (2026-10-26). Spencer decided on 2026-10-27 that project files are also archived to an NFS share he sets up on the QNAP, with an Admin setting for the folder path that checks read and write (phase 10, "Archive location"). Nothing is deleted from Packet Station; the archive is a copy. Still open on issue 7: a minimum retention period, if any, and what goes into the archive and when. Decided on 2026-10-28: all data is kept and nothing is purged; at filing the data book and each of the packet's documents go to the archive with a manifest (SethD, Gitea issue 7). There is one data book, the customer copy, without the history pages (SethD, Gitea issue 8, change C6). C6 was built on 2026-10-30, which closes D7. D6 (the archive) is phase 10.
Smaller questions from the design, with the default the build takes unless told otherwise:
10. Same-rev drawing re-release (new file, same rev) on an in-shop packet: default a drawing-origin change order, not a silent swap.
10. Same-rev drawing re-release (new file, same rev) on an in-shop packet: default a drawing-origin change order, not a silent swap. Confirmed by SethD on 2026-10-29, Gitea issue 9: keep the change order as built, so the shop confirms the new pages. A byte-identical file is still ignored.
11. Cancelled (X) work orders: default flag only, like gone; drafts are not removed. SethD on 2026-10-26, Gitea issue 10: the default is fine, left to Spencer. Kept as built.
12. Partspecs, title or folded-operation target changes on an in-shop packet: default no change order, as the old build. Confirmed by SethD on 2026-10-28, Gitea issue 11: only a new drawing rev, a quantity change or a removed operation opens a change order.
13. Work-order-gone confirmation after 2 consecutive runs and the 10% suspect-batch guard: defaults as stated. SethD left both numbers to Spencer on 2026-10-26, Gitea issue 12. The defaults stay unless Spencer changes them.
@@ -243,7 +244,7 @@ From phase 4 (2026-10-16), for Seth to veto:
19. The release gate has two server rules: every line not N/A is pulled or on an open short, and every pulled line that issued pieces has a heat unless it is N/A or a sub-assembly. The old build enforced both on the screen only. Default: both on the server. Confirmed by SethD on 2026-10-26, Gitea issue 16: both stay, so the warehouse fills the heat map for the parts it sends.
20. Hold and short reasons: the old build accepted any text. Default: closed sets on the server; "Other" on a hold needs a note. Confirmed by SethD on 2026-10-28, Gitea issue 17: keep the lists.
21. Receiving a short on a packet the warehouse no longer holds: default it stays a warehouse right (WH_RECEIVE_SHORT, any status but filed), and the holder of the packet (department lead or supervisor, Q.C., Clerical) can receive too, through edit_bom. Changed by SethD on 2026-10-28, Gitea issue 18 (change C7).
21. Receiving a short on a packet the warehouse no longer holds: default it stays a warehouse right (WH_RECEIVE_SHORT, any status but filed), and the holder of the packet (department lead or supervisor, Q.C., Clerical) can receive too, through edit_bom. Changed by SethD on 2026-10-28, Gitea issue 18 (change C7). Built on 2026-10-30: receiving works as before, and the department supervisor then approves each receipt.
22. Upload kinds and limits: default an MTR is PDF, PNG or JPG up to 25 MB, a hand BOM is XLSX or CSV up to 5 MB. ClamAV is optional and off unless CLAMAV_HOST is set; when set, an unreachable scanner refuses uploads (fail closed). Confirmed by Spencer (IT) on 2026-10-18, Gitea issue 19: the limits stay, and ClamAV stays off in both stacks because every workstation that uses Packet Station runs Microsoft Defender. The `clamav` profile stays in the build, unused.
23. The quota alert: default a `notification_events` row (phase 9 builds the delivery on this table) at 85 percent of the assets volume. Confirmed by Spencer (IT) on 2026-10-18, Gitea issue 20: 85 percent stays, and the alert goes to PS-Admins. Phase 9 seeds the `assets_quota` notification rule with PS-Admins as its recipient.
@@ -251,32 +252,32 @@ From phase 5 (2026-10-16), for Seth to veto:
24. Carried marks: when a packet is routed to another department, the welds, heat tags and heat table stay on the packet. The read model computes a `carried` flag. Nothing is copied. Default: computed, not copied. Confirmed by SethD on 2026-10-26, Gitea issue 21: the marks stay with the packet as it moves on, and a department that receives the packet (for example weld assembly after parts weld) adds its welds to the same weld map, so the data book carries one map.
25. The old build's manual "copy marks to the new sheet" button on a change order is not ported. On a page replacement only the heat table placement is copied to the new page. Welds and heat tags stay on the VOID page. Default: not ported in phase 5; a follow-up. Confirmed by SethD on 2026-10-26, Gitea issue 22: not ported. After a change order the department re-verifies the work, since a change can alter what was marked.
26. Checklist templates live in the `checklist_templates` settings row, with the old lists as defaults. Default: no screen edits them in phase 5; Admin editing comes in phase 9. Changed by SethD on 2026-10-26 and 2026-10-28, Gitea issue 23 (change C8).
26. Checklist templates live in the `checklist_templates` settings row, with the old lists as defaults. Default: no screen edits them in phase 5; Admin editing comes in phase 9. Changed by SethD on 2026-10-26 and 2026-10-28, Gitea issue 23 (change C8). Built on 2026-10-30: the `checklist_templates` row now holds the default lists by kind, used by a department that has no list of its own.
From phase 6 (2026-10-17), for Seth and Q.C. to veto:
27. Q.C. reject: the old build took any non-empty reason. Default: a reason of at least 8 characters, or a well-formed NCR number (`NCR-YYYY-NNNN`) in its place, or both. The NCR is stored on the inspection and linked to pesco-ncr. Applied in phase 6. Changed by SethD on 2026-10-26, Gitea issue 24 (change C2 below).
28. A filed packet in a unit and the unit's ITP: the ITP belongs to the unit, not to a packet, so ITP writes never look at a packet's status. Default: a filed packet does not lock the ITP. This resolves the phase 5 follow-up. Applied in phase 6. Changed by SethD on 2026-10-26, Gitea issue 25 (change C3 below).
27. Q.C. reject: the old build took any non-empty reason. Default: a reason of at least 8 characters, or a well-formed NCR number (`NCR-YYYY-NNNN`) in its place, or both. The NCR is stored on the inspection and linked to pesco-ncr. Applied in phase 6. Changed by SethD on 2026-10-26, Gitea issue 24 (change C2 below). Built on 2026-10-30.
28. A filed packet in a unit and the unit's ITP: the ITP belongs to the unit, not to a packet, so ITP writes never look at a packet's status. Default: a filed packet does not lock the ITP. This resolves the phase 5 follow-up. Applied in phase 6. Changed by SethD on 2026-10-26, Gitea issue 25 (change C3 below). Built on 2026-10-30: ITP writes still never look at a packet, but FILE waits until the unit's ITP is complete.
29. ITP status: the 0003 enum had `open`, `signed` and `reopened`. Default: `itp_status` gains `complete` for a signed-off ITP; a reopened ITP is `open` again with the reopen recorded. `signed` and `reopened` stay in the enum unused, since PostgreSQL cannot drop an enum value. Applied in phase 6.
30. Removing an ITP block signature: the old build let any Q.C. editor undo it. Default: the signer or an admin, while the ITP is open. The block's QN, remarks and customer fields stay. Applied in phase 6. Confirmed by SethD on 2026-10-26, Gitea issue 26: a fix to customer fields or an earlier step's remarks goes back to that step or to Clerical.
31. The signed ITP PDF on sign-off: default a hook (`pdf.itp.file_signed_itp_pdf`) that phase 7 builds. Today it files nothing, the sign-off log says `PDF filing reserved for phase 7`, and the automatic `qc_docs` ITP row is written only when the hook returns a file. Applied in phase 6. Phase 7 (2026-10-17) built the hook: the sign-off files the signed ITP PDF and the automatic ITP document in the same transaction, and a PDF that cannot be built fails the sign-off.
From phase 7 (2026-10-17), for Seth and Clerical to veto:
32. Prints: the old build pushed page images into the browser's print dialog and offered the same PDF when the dialog was blocked. Default: a print opens as a stamped PDF in a new browser tab, and the person prints it from the PDF viewer (Ctrl+P). One path is simpler and prints the same stamped pages. Phase 7 (2026-10-17) applied the default. Changed by SethD on 2026-10-26, Gitea issue 27 (change C4 below).
32. Prints: the old build pushed page images into the browser's print dialog and offered the same PDF when the dialog was blocked. Default: a print opens as a stamped PDF in a new browser tab, and the person prints it from the PDF viewer (Ctrl+P). One path is simpler and prints the same stamped pages. Phase 7 (2026-10-17) applied the default. Changed by SethD on 2026-10-26, Gitea issue 27 (change C4 below). Built on 2026-10-30.
33. When the data book is built: default on the server when the packet is filed, inside the filing transaction, stored as an asset on the seal. A data book that cannot be built fails the filing, so nothing is filed half way. Before filing, the data book can be viewed or downloaded at any time from status complete on; that copy is stamped "not yet filed". Phase 7 (2026-10-17) applied the default. Confirmed by SethD on 2026-10-26, Gitea issue 28.
34. Who may read the PDFs and the CSV: default every signed-in role that can open a packet, PM included. Every print and every export is logged with who, when, what and how many pages, in the append-only `print_log` and in the audit. Phase 7 (2026-10-17) applied the default. Confirmed by SethD on 2026-10-26, Gitea issue 29: everyone may view the whole packet; only the holder edits, and missing work goes back to the department that owes it.
35. The old "Original packet PDF" print kind: the rebuild has no VISUAL packet PDF. The drawing pages come from M-Files or a hand upload, and "Drawing (no markup)" prints them as attached. Default: the kind is gone. Phase 7 (2026-10-17) applied the default. Confirmed by SethD on 2026-10-28, Gitea issue 30: nothing is missed.
36. Filing while the feed still shows a work order open in VISUAL: default a second confirmation (`confirm_open_wos`), a warning and not a block, on both routes. The work orders are kept on the seal and in the log note. A hand packet has no feed state and no warning. Phase 7 (2026-10-17) applied the default. Changed by SethD on 2026-10-26, Gitea issue 31 (change C5 below).
37. The controlled-copy stamp carries a short signature made with the seal key, so a printed or exported copy can be checked against the server later. Default: phase 7 ships the signature, the check function and the print log; phase 9 adds the Admin screen that checks a copy. Phase 7 (2026-10-17) applied the default. Changed by SethD on 2026-10-28, Gitea issue 32 (change C9).
36. Filing while the feed still shows a work order open in VISUAL: default a second confirmation (`confirm_open_wos`), a warning and not a block, on both routes. The work orders are kept on the seal and in the log note. A hand packet has no feed state and no warning. Phase 7 (2026-10-17) applied the default. Changed by SethD on 2026-10-26, Gitea issue 31 (change C5 below). Built on 2026-10-30: `confirm_open_wos` is gone and filing is blocked. Two follow-up questions were asked on issue 31 on 2026-10-30 (see C5).
37. The controlled-copy stamp carries a short signature made with the seal key, so a printed or exported copy can be checked against the server later. Default: phase 7 ships the signature, the check function and the print log; phase 9 adds the Admin screen that checks a copy. Phase 7 (2026-10-17) applied the default. Changed by SethD on 2026-10-28, Gitea issue 32 (change C9). Built on 2026-10-30.
From phase 8 (2026-10-18), for Seth to veto. The phase 8 design numbered these 35 to 39; 35 to 37 were already taken by phase 7, so they follow on from 38.
38. Hours vs target: the station timer stays the clock of record. "Over target" means timer hours over the work-order target. VISUAL ticket hours are shown beside the timer in every hours table and never decide the flag. Phase 8 (2026-10-18) applied the default. Changed by SethD on 2026-10-26, Gitea issue 1 (change C1 below).
39. PM exports and who reads the reports: every PM export is logged as `report exported` in the audit and in `print_log`, with the scope and the period. Default: any signed-in role may read the PM reports (as every role may open every packet), not only PS-ProjectMgmt. Phase 8 (2026-10-18) applied the default. Changed by SethD on 2026-10-28, Gitea issue 33 (change C10).
38. Hours vs target: the station timer stays the clock of record. "Over target" means timer hours over the work-order target. VISUAL ticket hours are shown beside the timer in every hours table and never decide the flag. Phase 8 (2026-10-18) applied the default. Changed by SethD on 2026-10-26, Gitea issue 1 (change C1 below). Built on 2026-10-30.
39. PM exports and who reads the reports: every PM export is logged as `report exported` in the audit and in `print_log`, with the scope and the period. Default: any signed-in role may read the PM reports (as every role may open every packet), not only PS-ProjectMgmt. Phase 8 (2026-10-18) applied the default. Changed by SethD on 2026-10-28, Gitea issue 33 (change C10). Built on 2026-10-30.
40. Presence shows the display name and the role (the screen the person has open). Default: locked sessions drop out of presence at once; closing the tab drops out within the stream's ping cycle (25 seconds). Phase 8 (2026-10-18) applied the default. Confirmed by SethD on 2026-10-28, Gitea issue 34.
41. The find bar filters are applied by the server on every board and list, so a board never fetches more than it shows. Default: the KPI numbers follow the project pick only, not the other filters. Phase 8 (2026-10-18) applied the default. Confirmed by SethD on 2026-10-28, Gitea issue 35.
42. Mine is decided from the person's AD roles and the screen they are on. Default: the stall's Mine needs the picked station and shows nothing without one. Phase 8 (2026-10-18) applied the default. Changed by SethD on 2026-10-28, Gitea issue 36 (change C11).
42. Mine is decided from the person's AD roles and the screen they are on. Default: the stall's Mine needs the picked station and shows nothing without one. Phase 8 (2026-10-18) applied the default. Changed by SethD on 2026-10-28, Gitea issue 36 (change C11). Built on 2026-10-30.
From phase 9 (2026-10-21), for Seth or Spencer to veto:
@@ -289,24 +290,31 @@ From phase 9 (2026-10-21), for Seth or Spencer to veto:
49. New departments: default only shop departments can be added in the app (422 `support_fixed` for a support department). The support roles are fixed in the `role_kind` enum and the group map, so a new support department would map to no role. Phase 9 (2026-10-21) applied the default.
50. The profile CSV `stations` cell: default the cell is the person's whole list of station limits across departments and replaces every limit they had; `-` clears them all; an empty cell leaves them. Phase 9 (2026-10-21) applied the default.
51. A direct welder assign: default it does not check `profile_active`, so an Admin's inactive switch hides a person from the picker but a typed assign still works. Phase 9 (2026-10-21) applied the default; say if an inactive profile should be refused there too.
52. A checklist item added while a stage is open: default it applies to that open stage too, because completeness reads the live template, so the item must be ticked before submit. Phase 9 (2026-10-21) applied the default. Replaced by change C8: a template change applies to new packets only.
52. A checklist item added while a stage is open: default it applies to that open stage too, because completeness reads the live template, so the item must be ticked before submit. Phase 9 (2026-10-21) applied the default. Replaced by change C8: a template change applies to new packets only. Built on 2026-10-30: a stage freezes its list at START, so a change reaches only stages not yet started.
Changes decided by SethD on 2026-10-26, to build (phase 10 unless a later plan moves them). Each replaces a default above:
Changes decided by SethD on 2026-10-26. Each replaces a default above. All five were built on 2026-10-30 (branch `seth-changes`):
- C1 (issue 1, Q1 and Q38): the station timer stays and is shown as today, but "over target" is decided by the VISUAL ticket hours against the work-order target, not by the timer.
- C2 (issue 24, Q27): a Q.C. reject always needs a detailed reason; an NCR number no longer stands in for it. A rejected item cannot be accepted until an NCR number is entered. Q.C. can upload the NCR document to the packet, and it goes into the data book.
- C3 (issue 25, Q28): a packet whose unit has an ITP that is not complete cannot be filed, so no data book is built. The packet goes back to have the ITP completed.
- C4 (issue 27, Q32): prints go straight to the browser's print dialog from the page, as the old build did, with no new tab. The stamped pages stay the same.
- C5 (issue 31, Q36): filing is blocked, not warned, while VISUAL still shows a work order open. The packet waits in a Clerical "Ready to close" column until the feed sees VISUAL closed, then moves to "Ready for data book". This applies to both routes unless Seth says Shipping is different.
- C1 (issue 1, Q1 and Q38): the station timer stays and is shown as today, but "over target" is decided by the VISUAL ticket hours against the work-order target, not by the timer. Built 2026-10-30: `domain/pm.py` `is_over()` flags a packet when its ticket hours are above a target above zero, so a packet with no ticket hours is never over. The hours tables, the "Packets over target" table, the KPI, the summary line, the CSV and the report PDF follow, with columns named "Ticket h / target" and "Over target (tickets)". The timer column stays.
- C2 (issue 24, Q27): a Q.C. reject always needs a detailed reason; an NCR number no longer stands in for it. A rejected item cannot be accepted until an NCR number is entered. Q.C. can upload the NCR document to the packet, and it goes into the data book. Built 2026-10-30: QC_REJECT needs a reason of 8 characters and may also carry an NCR number. When a reject since the last accept has no NCR number, QC_ACCEPT and QC_ACCEPT_AND_ROUTE need one in the request (precondition `ncr_given`, 422 `ncr_required`); the number is stored on the accepting inspection and in the log. The packet read has `ncr_required`, and the Q.C. bar shows the NCR field as required. An `ncr` packet document is in section 5 of the data book.
- C3 (issue 25, Q28): a packet whose unit has an ITP that is not complete cannot be filed, so no data book is built. The packet goes back to have the ITP completed. Built 2026-10-30: precondition `itp_complete` on FILE. An ITP that is not complete (open, signed or reopened) blocks; a unit with no ITP does not. The reason shows under File in the close panel.
- C4 (issue 27, Q32): prints go straight to the browser's print dialog from the page, as the old build did, with no new tab. The stamped pages stay the same. Built 2026-10-30: every print in the app goes through `frontend/src/lib/printPdf.ts`, which renders the stamped PDF with pdf.js into a hidden print area and opens the print dialog. Viewing a PDF (data book, traveler, ITP PDF, PM report) still opens a tab. The server did not change.
- C5 (issue 31, Q36): filing is blocked, not warned, while VISUAL still shows a work order open. The packet waits in a Clerical "Ready to close" column until the feed sees VISUAL closed, then moves to "Ready for data book". This applies to both routes unless Seth says Shipping is different. Built 2026-10-30: precondition `closed_in_visual` replaces `vclosed_if_databook`. On a VISUAL packet the feed is the one writer of `vclosed_at`: it sets it when every leg is closed or cancelled and clears it when a leg shows open again, so the Clerical board moves the packet by itself. FILE needs it and no open leg, on both routes. A hand packet has no feed state, so Clerical still confirms the close by hand (SET_VCLOSED, Data Book route only); SET_VCLOSED is refused on a VISUAL packet. `confirm_open_wos` and the 409 `open_work_orders` are gone.
Asked on issue 31 on 2026-10-30, open until answered: (a) a work order deleted from VISUAL while open keeps its last status, so its packet can never file. Should a leg gone for 2 runs count as closed, or should an Admin close it with a reason? (b) Shipping packets now wait for the VISUAL close too. Is that right for Shipping, or should Shipping file without it? Until Seth answers, both stay as built.
Changes decided by SethD on 2026-10-28, to build in phase 10:
Changes decided by SethD on 2026-10-28. All six were built on 2026-10-30 (branch `seth-changes`):
- C6 (issue 8, Q9, D7): the data book leaves out the packet history pages. It is the one copy, and it goes to the customer. History stays readable in Packet Station.
- C7 (issue 18, Q21): every received short also needs the department supervisor's approval, one short at a time. The supervisor checks the part and its heat number against what the warehouse issued. A packet cannot be marked complete until every short is received and approved.
- C8 (issue 23, Q26 and Q52): checklists become per department. Each department supervisor edits their own department's checklist, Admin edits any, and Q.C. does not edit department checklists. A change applies to packets not yet started, never to packets already started.
- C9 (issue 32, Q37): the stamp check is open to Admin, Q.C. and Clerical.
- C10 (issue 33, Q39): the PM screen and its reports are for PS-ProjectMgmt and Admin only.
- C11 (issue 36, Q42): the Stall screen shows a welder the packets assigned to him, each at the stall the supervisor picked when assigning. The welder does not pick a stall. Moving a welder to another stall is a re-assign by the supervisor.
- C6 (issue 8, Q9, D7): the data book leaves out the packet history pages. It is the one copy, and it goes to the customer. History stays readable in Packet Station. Built 2026-10-30: section 7 "Record history" is gone and the data book has six sections. The change-order table it held moved to a "Change order record" page at the end of section 1, only when the packet has change orders. Say if that page should go too.
- C7 (issue 18, Q21): every received short also needs the department supervisor's approval, one short at a time. The supervisor checks the part and its heat number against what the warehouse issued. A packet cannot be marked complete until every short is received and approved. Built 2026-10-30: migration 0011 adds `short_approvals` (append-only, one row per receipt). New action SHORT_APPROVE: the supervisor of the packet's current department (a lead is not enough), Admin through the bypass, any status but filed, signature "Approve a received short", at `POST /api/packets/{id}/shorts/receipts/{receipt_id}/approve`. Precondition `shorts_approved` on QC_ACCEPT and FILE, not on QC_ACCEPT_AND_ROUTE. The Materials tab shows each receipt with who received it and who approved it. There is no list of receipts to approve on the supervisor board yet.
- C8 (issue 23, Q26 and Q52): checklists become per department. Each department supervisor edits their own department's checklist, Admin edits any, and Q.C. does not edit department checklists. A change applies to packets not yet started, never to packets already started. Built 2026-10-30: a department's own list is the settings row `checklist:<code>`; without one it uses the default for its kind (the weld or plain list in `checklist_templates`). `GET /api/checklists`, `GET` and `PUT /api/checklists/{dept}` with version compare-and-set. The department's Supervisor (not a lead) and Admin may save, in a password session. `packet_stages.checklist_template` (migration 0011) freezes the list at START, and every reader uses the frozen list when set. New screen `/checklists`.
- C9 (issue 32, Q37): the stamp check is open to Admin, Q.C. and Clerical. Built 2026-10-30: `POST /api/stamp-verify` and `POST /api/stamp-verify/pdf` for Admin and every Q.C. and Clerical level, in a password session. The `/api/admin` paths stay as aliases. New screen `/stamp-check`.
- C10 (issue 33, Q39): the PM screen and its reports are for PS-ProjectMgmt and Admin only. Built 2026-10-30: every `/api/pm/*` endpoint is 403 for anyone else. No other screen calls `/api/pm`. The PM screen entry shows only for those roles.
- C11 (issue 36, Q42): the Stall screen shows a welder the packets assigned to him, each at the stall the supervisor picked when assigning. The welder does not pick a stall. Moving a welder to another stall is a re-assign by the supervisor. Built 2026-10-30: `GET /api/stall/mine` lists the packets assigned to the person (assigned, in progress, in review), each with the station the supervisor picked, across stations. The Stall screen has no station picker, and the stall's Mine no longer needs a station. Someone with nothing assigned sees "Your supervisor assigns packets to you."
Known edges of C1 to C11 at deploy:
- Packets in flight. Every short receipt recorded before the deploy has no approval, so the supervisor approves it before the next Q.C. accept, or before filing a packet that is already complete. A Q.C. reject since the last accept that has no NCR number needs one at the next accept. Nothing is backfilled.
- Stages started before migration 0011. The migration freezes the open stage of every packet in progress, in review or at Q.C. to the default list for its kind, from the `checklist_templates` row. A department edit does not reach those stages. When that row is missing, such a stage has no frozen list and reads its department's live list until it closes. A packet whose stages all closed before 0011 also reads the live list, so a later edit changes what its checklist shows.
- The feed sets `vclosed_at` in any status before filed, so a packet can come back from Q.C. straight into "Ready for data book".
## Verification