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

- 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 13:33:51 -06:00
co-authored by Claude Opus 5.5
parent 1ae6819289
commit 1cd6688247
101 changed files with 3871 additions and 1098 deletions
+9 -3
View File
@@ -272,7 +272,13 @@ The apply runs in one transaction with a 5-second lock timeout. A packet row loc
5. **Past draft: change orders** (action `vis_open_co`). See "Change orders from the feed". Filed packets get nothing.
6. **Retire moved drafts** (action `vis_retire_draft`). A live draft made by the feed, with no drawing pages and no hand uploads, that is not among this run's candidates, and whose every leg now sits on another live candidate, is soft-removed with reason `moved`. `visual.moved` records where the legs went. Log "Retired: work orders moved to another packet". It is hidden from the boards and, being removed, is never recreated.
7. **Work order gone.** Skipped on a suspect batch. Each tracked leg VISUAL did not return gets `missing_runs + 1`. At 2 the leg gets `gone_at`, the packet gets flag `wo_gone` and `wo_gone_at`, and the log says "Work order <key> no longer in VISUAL". A leg that comes back resets to 0. When no leg is gone any more the flag goes and the log says "Work order back in VISUAL". The feed never removes a packet for this.
8. **Closed and cancelled.** Each leg's status code is stored, with ticket hours and the time observed. When every leg is C, `visual_closed_at` is set and the log says "Closed in VISUAL (observed)". Any leg X sets flag `cancelled` and `visual_cancelled_at`. The flag goes when no leg is X. A cancelled draft is not removed.
8. **Closed and cancelled.** Each leg's status code is stored, with ticket hours and the time observed. When every leg is C, `visual_closed_at` is set. Any leg X sets flag `cancelled` and `visual_cancelled_at`. The flag goes when no leg is X. A cancelled draft is not removed.
Since change C5 (Gitea issue 31, built 2026-10-30) the feed also sets and clears the packet's close in VISUAL, `vclosed_at`, on a VISUAL packet that is not filed or removed. It is the one writer there; Clerical sets it only on hand packets.
- When every leg has a status and each is C or X, the feed sets `vclosed_at` to now, with `vclosed_by` null (an existing value is kept). The log says "Closed in VISUAL (observed)" and the run counts `closed_observed`. The Clerical board then moves the packet from "Ready to close" to "Ready for data book" by itself.
- When a leg shows open again (a status that is not C or X) on a packet with `vclosed_at` set, the feed clears `vclosed_at`, `vclosed_by` and `visual_closed_at`. The log says "Open again in VISUAL (observed)" with the open work orders as the note. No count.
- The feed does this in any status before filed, so a packet can come back from Q.C. already "Ready for data book". A filed packet is never touched.
- FILE on a VISUAL packet needs `vclosed_at` set and no leg open, on both routes (precondition `closed_in_visual`, see [POLICY.md](POLICY.md), "Filing").
- A leg flagged `wo_gone` keeps its last status. If that status was open, the packet cannot file. Asked on Gitea issue 31 on 2026-10-30: count a leg gone for 2 runs as closed, or let an Admin close it with a reason.
9. **Auto-release** when `auto_release` is on and the feed is not paused: up to `auto_release_max` (default 25) live drafts made by the feed with the drawing attached, no flags at all, and the rev confirmed by the drawing job. A draft whose heat map is unanswered gets "yes" when it has a real material line (not a sub-assembly, not n/a, not consumable) and "no" otherwise. Then action `vis_auto_release` moves it to the warehouse with an automatic warehouse stage row and a transition row. The policy's preconditions (heat map answered, drawing attached) still apply.
10. **Summary.** One audit row `feed.run` with the counts, and one `feed` event to the screens after commit.
@@ -417,7 +423,7 @@ Flags live in `packets.flags`. A draft with any flag shows in Clerical's Flagged
With both hand flags the text is "Drawing and BOM uploaded by hand - check it and send it on". Hand drafts keep their phase 2 text.
"Closed in VISUAL" is not a flag. It is an observed state (`visual_closed_at`), shown on the packet. Filing a Data Book packet needs it, as the `vclosed_if_databook` precondition says.
"Closed in VISUAL" is not a flag. It is an observed state, shown on the packet: `vclosed_at` when every leg is closed or cancelled, `visual_closed_at` when every leg is C. Filing a VISUAL packet needs `vclosed_at` and no open leg, on both routes, as the `closed_in_visual` precondition says (change C5).
### Hand uploads
@@ -506,7 +512,7 @@ The packet read model has a `labor` field from `visual_labor`. It joins the pack
`labor` is null for a hand packet, or when no `visual_labor` row matches. The packet page shows the sum beside the station clock, as `VISUAL tickets 3.2 h`.
The station timer stays the clock of record (open question 1, default kept). The ticket hours are shown for comparison only. Nothing is computed from them, and they never change the clock. The screen reads them from PostgreSQL, never from VISUAL.
The station timer stays and is shown as before. Since change C1 (Gitea issue 1, built 2026-10-30) the ticket hours decide "over target" on the Project Management reports: ticket hours above the work-order target. A packet with no ticket hours is not over target. The ticket hours never change the clock. The screen reads them from PostgreSQL, never from VISUAL.
## What the screens read