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
+22 -8
View File
@@ -2,9 +2,9 @@
copy of sheet 1, a heat table, two welds, an MTR PDF and an MTR PNG, a short with a receipt, a packet document, a
Q.C. folder document, the closed stage and the Q.C. accept.
The index (seven sections in order, the expected rows), the page count, the cover, the index page, the void
sheet, the traceability page, the warning rows, the metadata, the stamp on every page and its signature, and the
stamp per mode. Nothing here reads VISUAL or M-Files."""
The index (six sections in order, the expected rows; no history pages since change C6), the page count, the cover,
the index page, the void sheet, the traceability page, the warning rows, the metadata, the stamp on every page and
its signature, and the stamp per mode. Nothing here reads VISUAL or M-Files."""
from __future__ import annotations
@@ -21,6 +21,7 @@ import pytest
from closehelpers import (
HEATS,
RECEIPT_HEAT,
add_doc,
builder_conn,
delete_asset_file,
flat,
@@ -43,7 +44,7 @@ pytestmark = needs_pg
NOW = datetime(2026, 10, 17, 21, 4, tzinfo=UTC)
SEAL = {"hash": "ab12cd34ef56" + "0" * 52, "key_id": "k1234567", "sealed_at": NOW}
SECTIONS = [1, 2, 3, 4, 5, 6, 7]
SECTIONS = [1, 2, 3, 4, 5, 6]
SIG_RE = re.compile(r"stamp ([0-9a-f]{16})")
DUMP_DIR = os.environ.get("DATABOOK_DUMP_DIR") # off unless set
@@ -98,13 +99,14 @@ def test_data_book_preview(shop: Shop) -> None:
assert len(reader.pages) == built.pages
rows = index(built)
# the seven sections, in order, each present
# the six sections, in order, each present
seen = [r["section"] for r in rows]
assert seen == sorted(seen) and sorted(set(seen)) == SECTIONS, seen
s1 = docs_in(rows, 1)
assert sum("approved drawing" in d for d in s1) == 2, s1
assert any(d.startswith("SUPERSEDED - VOID by CO-1") for d in s1), s1
assert s1[-1] == "Change order record", s1
drawing_rows = [r for r in rows if r["section"] == 1 and "approved drawing" in str(r["doc"])]
assert all(r["ref"] == "D-5001" and r["rev"] == "RB" for r in drawing_rows), drawing_rows
@@ -131,7 +133,8 @@ def test_data_book_preview(shop: Shop) -> None:
mtr_rows = [r for r in rows if r["section"] == 6]
assert mtr_rows[0]["ref"] == HEATS[1]
assert docs_in(rows, 7) == ["Packet record history"]
# change C6: no history pages; the book is the one copy and goes to the customer
assert not any("history" in str(r["doc"]).lower() for r in rows), rows
# pages: the parts plus the front matter (cover and index); page numbers point into the book
parts = sum(int(r["count"] or 0) for r in rows)
@@ -167,8 +170,10 @@ def test_data_book_preview(shop: Shop) -> None:
qc_page = next(r for r in rows if r["section"] == 4)["page"]
qc_lines = texts[int(qc_page) - 1].splitlines()
assert "AM" not in qc_lines and "PM" not in qc_lines, qc_lines # the date and time stay on one line
hist_page = next(r for r in rows if r["section"] == 7)["page"]
assert "CO-1 " in flat(texts[int(hist_page) - 1]) and "documents changed" in flat(texts[int(hist_page) - 1])
co_page = next(r for r in rows if r["doc"] == "Change order record")["page"]
assert "CO-1 " in flat(texts[int(co_page) - 1]) and "documents changed" in flat(texts[int(co_page) - 1])
whole = flat(" ".join(texts))
assert "RECORD HISTORY" not in whole.upper() and "Every action taken on this packet" not in whole
# metadata
meta = reader.metadata
@@ -230,6 +235,15 @@ def test_data_book_with_an_itp_document_has_no_itp_warning(shop: Shop) -> None:
assert not any(r["doc"] == "No signed ITP filed for this unit" for r in s5)
def test_data_book_carries_an_ncr_document(shop: Shop) -> None:
"""Change C2 asks the NCR document Q.C. uploads to be in the data book: every packet document kind is in
section 5, the NCR kind included."""
pkt = rich_complete(shop, mtrs=False)
add_doc(shop, pkt, title="NCR 2026-0017", kind="ncr")
s5 = docs_in(index(build(shop, pkt["id"])), 5)
assert any(d.startswith("NCR") and "NCR 2026-0017" in d for d in s5), s5
# ---------------------------------------------------------------- phase 8: against the old build's book