Skip to content

T-NRTX-mask-bare-pid-columns-in-findings

Status: open/ready · Impact: medium · Complexity: small

AUTO-DEFINED: this spec was best-effort machine-authored by /sdlc:task-auto-define on 2026-08-02 because the task is autonomy: autonomous/pr. Review the Goal, Approach, Today, Files-to-touch, and Acceptance-criteria carefully before trusting it.

The quality baseline finding-diff still false-flags a dashboard-test server banner as new-drift, because normalizeFinding’s PID mask only fires on the literal pid keyword. A banner line that carries the PID as a bare integer column can never match its baseline twin, so it surfaces as branch-introduced drift on every run regardless of what the branch touched.

The baseline finding-diff still false-flags a dashboard-test server banner as new-drift: the observed line was /private<TMPDIR> 27439 http://127.0.0.1:<PORT>/, where the normalizer masked the tempdir and the port but not the PID, so the line can never match its baseline twin. T-BQRU-quality-normalize-ports-pids-timings (closed/done, PR #473) added a PID mask to normalizeFinding in apps/sdlc/lib/services/quality/baseline.ts, but it is anchored on the literal pid keyword (/\bpid(\s*[:=]?\s*)\d{1,7}\b/gi), so a bare integer column carrying the PID slips through. Extend the normalizer to mask process-ephemeral bare-integer columns in server-banner lines (or drop server-banner lines from the finding set), with unit tests covering the observed line shape and a negative case proving unrelated integers stay unmasked.

T-HTN8-lease-gate-memo-fields

LocationRole today
apps/sdlc/lib/services/quality/baseline.ts#normalizeFindingMasks ephemeral tokens in a finding line, in five fixed steps: tmpdir roots, bare commit SHAs, ephemeral ports, PIDs, timing tokens. Step 4 is anchored on the literal pid keyword (/\bpid(\s*[:=]?\s*)\d{1,7}\b/gi), so a PID that appears as a bare integer column with no keyword survives masking.
apps/sdlc/lib/services/quality/baseline.ts#diffPer-verb set difference that normalizes both the current and baseline sides before subtracting. A line whose PID survives masking can never equal its baseline twin, so it is reported as branch-introduced drift on every run.
apps/sdlc/lib/services/dashboard/server.ts#listDashboardsEmits the offending banner shape — one row per running dashboard as `${proot} ${pid} ${url}`, where the PID is a bare padEnd(6) integer column carrying no pid keyword, next to a tmpdir-rooted project root and a http://127.0.0.1:<port>/ URL.
apps/sdlc/lib/services/quality/tests/quality_ops.test.tsHolds the T-BQRU normalizeFinding unit tests — positive cases for port/PID/timing, a combined multi-kind case, and the negative case found 12345 issues that pins bare integers as unmasked.

normalizeFinding gains a sixth mask that fires only on lines already recognizable as server banners after masks 1-5 have run — that is, lines carrying BOTH the `<TMPDIR>` sentinel AND the `<PORT>` sentinel. On such a line, every whitespace-delimited token that is a bare 2-to-7 digit integer collapses to `<PID>`, and runs of two or more spaces/tabs collapse to one space so that the emitter’s column padding (which varies with the PID’s digit count) stops contributing drift of its own.

The conjunction of the two sentinels is what keeps the mask narrow: a count-bearing line such as found 12345 issues or expected 4 on :49870 carries no tmpdir sentinel, so its integers stay untouched and a genuine count change still surfaces as drift.

  1. In apps/sdlc/lib/services/quality/baseline.ts#normalizeFinding, after the existing step 5 (timing tokens), add step 6 guarded on the banner shape:

    // 6. Bare-integer PID columns on server-banner lines.
    if (out.includes("<TMPDIR>") && out.includes("<PORT>")) {
    out = out
    .replace(/(?<=^|\s)\d{2,7}(?=\s|$)/g, "<PID>")
    .replace(/[ \t]{2,}/g, " ");
    }

    The guard runs on the already-masked out, not on the raw input, so the sentinels are present by the time it is evaluated. The 2-digit floor keeps single-digit counts out of the mask; the 7-digit ceiling matches step 4’s existing PID width.

  2. Extend the module docstring’s numbered mask list (the “Masks, in fixed order” block above normalizeFinding) with the new step 6, naming the two-sentinel guard and the reason it exists — the dashboard list banner row whose PID is a bare column.

  3. In apps/sdlc/lib/services/quality/tests/quality_ops.test.ts, add a describe block for T-NRTX next to the existing T-BQRU block covering: the observed banner shape; a diff() case where two banner rows differing only in PID and column padding cancel; and negative cases proving integers on non-banner lines stay unmasked.

  4. Run bun test against apps/sdlc/lib/services/quality/tests/quality_ops.test.ts and confirm the pre-existing T-BQRU cases (in particular the combined server /tmp/abc/sock 127.0.0.1:50000 pid 4242 (9ms) case, which carries both sentinels but no bare-integer token) still pass unchanged.

LocationKindChange
apps/sdlc/lib/services/quality/baseline.ts#normalizeFindingmodifyAdd mask step 6 — bare-integer PID columns plus padding collapse, guarded on the two-sentinel banner shape.
apps/sdlc/lib/services/quality/baseline.tsmodifyExtend the “Masks, in fixed order” docstring list with step 6 and its rationale.
apps/sdlc/lib/services/quality/tests/quality_ops.test.tsmodifyAdd the T-NRTX unit tests: banner shape, diff cancellation, and the non-banner negative cases.
  • AC-1: normalizeFinding("/tmp/proj-abc 27439 http://127.0.0.1:54321/") returns "<TMPDIR> <PID> http://127.0.0.1:<PORT>/".
  • AC-2: diff() returns [] for a verb whose current findings are ["/tmp/a 27439 http://127.0.0.1:54321/"] and whose baseline findings are ["/tmp/b 931 http://127.0.0.1:49870/"] — the PID, the padding width, and the port cancel.
  • AC-3: normalizeFinding("found 12345 issues") still returns "found 12345 issues", and normalizeFinding("expected 4 on :49870") still returns "expected 4 on :<PORT>" — neither line carries the tmpdir sentinel, so its integers are not masked.
  • AC-4: normalizeFinding("server /tmp/abc/sock 127.0.0.1:50000 pid 4242 (9ms)") still returns "server <TMPDIR> 127.0.0.1:<PORT> pid <PID> (<TIME>)" — the new mask leaves the pre-existing combined case byte-identical.
  • AC-5: bun test over apps/sdlc/lib/services/quality/tests/quality_ops.test.ts exits 0.
  • AC-6: the normalizeFinding module docstring lists six numbered masks, the sixth naming the two-sentinel banner guard.
  • Dropping server-banner lines from the finding set wholesale (the alternative the source task offered) — this task masks instead, so a genuine change in a banner line still surfaces as drift.
  • Changing listDashboards’s output format, column widths, or padding in apps/sdlc/lib/services/dashboard/server.ts.
  • Normalizing column padding on lines that carry no bare-integer PID column — for example the dashboard list header row.
  • Re-capturing, pruning, or rewriting baseline JSON files on disk; masking stays a diff-time concern, as it is today.
  • Widening the mask to lines that carry a URL but no tmpdir sentinel.
  • none

Spawned by /sdlc:spawn-task-pr on 2026-08-03 UTC from T-HTN8-lease-gate-memo-fields in git@github.com:sksizer/dev.git.


← Back to Tasks