[object Object]

← back to Ticket System

TK-11372: post-patch blocking audit; split the skills scan to TK-11499

e8d4f1be12021ae395708a12767c7471a1f9190b · 2026-09-11 12:09:03 -0700 · Steve Abrams

Confirms the patch did not close one blocking call while leaving another in a
request path: server.js and lib.js now have zero sync subprocess calls, and
lib.js matters because tickets()/messages() run per request.

Secondary, deliberately NOT folded in: installedSkills() walks 583+22 dirs
with sync readFileSync+statSync, uncached, per GET /api/skills -- measured
mean 58ms / worst 502ms of loop blocking. Two orders of magnitude under the
outage and cannot affect /healthz, so it is filed as TK-11499 rather than
widening a candidate that DTD and Cody already passed byte-for-byte.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PkwT8hDyw7SCCkYBviZTbq

Files touched

Diff

commit e8d4f1be12021ae395708a12767c7471a1f9190b
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Fri Sep 11 12:09:03 2026 -0700

    TK-11372: post-patch blocking audit; split the skills scan to TK-11499
    
    Confirms the patch did not close one blocking call while leaving another in a
    request path: server.js and lib.js now have zero sync subprocess calls, and
    lib.js matters because tickets()/messages() run per request.
    
    Secondary, deliberately NOT folded in: installedSkills() walks 583+22 dirs
    with sync readFileSync+statSync, uncached, per GET /api/skills -- measured
    mean 58ms / worst 502ms of loop blocking. Two orders of magnitude under the
    outage and cannot affect /healthz, so it is filed as TK-11499 rather than
    widening a candidate that DTD and Cody already passed byte-for-byte.
    
    Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01PkwT8hDyw7SCCkYBviZTbq
---
 verification/tk11372/post-patch-blocking-audit.json | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/verification/tk11372/post-patch-blocking-audit.json b/verification/tk11372/post-patch-blocking-audit.json
new file mode 100644
index 00000000..1c5bc7b2
--- /dev/null
+++ b/verification/tk11372/post-patch-blocking-audit.json
@@ -0,0 +1,17 @@
+{
+  "ticket": "TK-11372",
+  "purpose": "Confirm the patch did not fix ONE blocking call while leaving another in a request or timer path — that would have been a false green.",
+  "subprocess_class": {
+    "server.js": "0 execSync / execFileSync / spawnSync remaining",
+    "lib.js": "0 execSync / execFileSync / spawnSync (matters because tickets() and messages() run per request)",
+    "verdict": "COMPLETE — the outage class is fully closed in the patched source"
+  },
+  "secondary_finding_NOT_the_outage_cause": {
+    "what": "installedSkills() at server.js:94 walks ~/.agents/skills (583 dirs) + ~/.codex/skills (22) with a synchronous readFileSync + statSync per dir, uncached, on every GET /api/skills",
+    "measured_blocking_cost": "581 skills found; mean 58.41ms, worst 502.37ms of event-loop blocking per request",
+    "severity": "LOW vs the outage — two orders of magnitude under the ~8s subprocess block, and it cannot affect /healthz. But a board page polling /api/skills injects up to ~0.5s stalls into every other request.",
+    "decision": "NOT folded into this activation. The reviewed candidate is kept byte-identical to what DTD and Cody passed; widening scope here is how false confidence gets introduced. Filed as its own follow-up instead.",
+    "suggested_fix": "cache installedSkills() behind a TTL like getRunning does, or move it to fs.promises"
+  },
+  "cost_usd": 0
+}

← ad5b5cac auto-data-snapshot: 2026-09-11T12:03:30 (1 data files) — dat  ·  back to Ticket System  ·  TK-11372: ACTIVATED and live-verified; residual symptom spli 97bd9fd6 →