fix(gate): the plan-code guard catches bare sprint and phase codes, and the purge takes the P ones

The sprint alternative matched only `(S6)` or `S3e2`, so the commonest purged form (`# S6:`,
`S3's`, `"""S6 —`, `S1 justified`) and every phase code (`P1`) would come back unflagged; the phase
codes had in fact survived the purge in 16 lines (Plex client sections, the upload's header shape),
now reworded around them.

One pattern now covers epic, roadmap, sprint and phase codes; the named exceptions are TV episode
notation, a fixture's season or episode title (`title="S1"`) and ruff's `E4/E7/E9`, and a ruff rule
like `S110` does not match. The case test lists the purged forms and no longer claims every form.
audit_metrics copies the definition (ASCII, as JavaScript's \b is) and reports it as
plan_code_lines / plan_code_files.
This commit is contained in:
2026-10-05 00:50:36 +02:00
parent 5257d57196
commit 5ca2a0e6ee
10 changed files with 47 additions and 40 deletions
+1 -1
View File
@@ -254,7 +254,7 @@ def as_user(db, override_dep, _configured):
@pytest.fixture
def upload_headers():
"""Build the headers `POST /api/downloads/upload` takes since P1.
"""Build the headers `POST /api/downloads/upload` takes (the file is the raw body).
Shared, because two test modules drive that route and a second copy of this is exactly the drift
that lets the wire shape change in one place only. The body IS the file now; the names ride as
+2 -2
View File
@@ -600,7 +600,7 @@ def test_the_display_name_header_reaches_the_job_and_is_bounded(
):
"""The second header, which had no backend test at all — and the length nothing bounded.
Since P1 the display name arrives in a REQUEST HEADER rather than as a form field, so the only
The display name arrives in a REQUEST HEADER rather than as a form field, so the only
limit on it was the header size. The column is varchar(255), so a longer one reached Postgres as
a DataError: a 500 AFTER the whole file had been transferred. It is truncated now, by the same
helper the metadata PATCH uses.
@@ -627,7 +627,7 @@ def test_the_display_name_header_reaches_the_job_and_is_bounded(
def test_the_upload_holds_no_db_transaction_while_the_body_streams(
as_user, make_user, db, _root, monkeypatch, upload_headers
):
"""P1 moved the body read behind the auth dependency, which put the whole transfer INSIDE the
"""Moving the body read behind the auth dependency put the whole transfer INSIDE the
request's database session: resolving the caller and reading the cap are SELECTs, SQLAlchemy 2.0
autobegins on the first one, and the session then holds one of the twenty pooled connections —
`idle in transaction` to Postgres, with no `idle_in_transaction_session_timeout` to end it — for