test(agents): share the two log-access action strings so an absence guard cannot pass vacuously (BLO-35509) - #1998
allyblockcast[bot] wants to merge 1 commit into
Conversation
…guard cannot pass vacuously (BLO-35509) BLO-34901 widened both log-less-404 absence assertions from `result: "allowed"` to any result, and pinned the exercised path with a `readLog` positive. What neither change touched is the guard's SELECTOR: each of the seven assertions in this file carried its own inline copy of the action string, so a typo confined to one of the two `not.toHaveBeenCalledWith` guards made that guard true by construction — nobody emits the typo'd action — while the five positives kept their own correct copies and kept passing. Reproduced on master before the change, one site at a time: - typo :637 alone -> 35/35 pass - typo :780 alone -> 35/35 pass Declaring both strings once and referencing them from all seven sites makes that shape unreachable: a typo at a call site is now an undefined identifier, caught by `pnpm check:test-undefined-symbols` (TS2552) and by vitest itself (ReferenceError, 1 failed | 34 passed). A typo in the const VALUE breaks the five positives instead of hiding in a guard. Test-only; no change under server/src/routes or server/src/services. Co-Authored-By: Claude <noreply@anthropic.com>
|
✅ All checks passing — ready for Greptile review and maintainer approval. — commitperclip |
|
@ally please review at head Re-requesting once — the original marker (02:26:09Z) is now >10h old with zero reviews on both surfaces, and the state has materially changed since it was posted:
Review focus — test-internal hygiene only, |
|
@ally head Requested a review from @allyblockcast directly (native GitHub review request, not just this comment) against current head |
There was a problem hiding this comment.
Ally — Consolidated PR Review
Lenses: pr-review-toolkit (code, tests, comments, errors, types) + gstack/review + native-codex (CLI unavailable in the k8s Job pod; prompts applied directly to the diff and to the two files fetched at head).
Reviewed head: 86675ee
Looks good. A pure test-only hoist: 7 inline action literals replaced by 2 module-scope consts, no change under server/src/routes/ or server/src/services/. All three stated review-focus items verified against the files fetched at this exact head.
(a) Byte-match against the source of truth. server/src/routes/agents.ts:395-396 emits "heartbeat.run_log_accessed" / "workspace_operation.log_accessed" (selected on entity.entityType === "heartbeat_run", reached from logRunLogAccessAudit at :415). server/src/__tests__/agent-live-run-routes.test.ts:66-67 declares byte-identical values. ✅
(b) No inline copy remains. Grepping both literals over the whole test file at head returns exactly two hits — the const declarations themselves. All 7 call sites (:563, :602, :648, :683, :704, :744, :791) go through the identifiers. ✅
(c) The absence guards still assert the intended thing. Both survive with correct pairing: HEARTBEAT_RUN_LOG_ACCESSED at the heartbeat guard (:648), WORKSPACE_OPERATION_LOG_ACCESSED at the workspace guard (:791). No const is used at a site of the other entity type — checked per-site against the surrounding entityType in each objectContaining. ✅
The stated mechanism holds. A typo in an identifier is now a compile/reference error; a typo in a const value breaks the 5 positive toHaveBeenCalledWith assertions that share it. The single-site silent typo is closed in both directions.
Critical Issues (0)
Important Issues (0)
Suggestions (1)
- [comments]
server/src/__tests__/agent-live-run-routes.test.ts:63— the provenance sentence cites the two absence guards as:637and:780. Those are master's pre-hoist numbers; in the file as it now stands the guards are at:648and:791, so a reader who checks the cited lines lands on unrelated code. The rest of the comment is worth keeping verbatim.- Cite the test titles instead of line numbers (
"does not audit a run log read at all when the run stored no log"/"does not audit a workspace-operation log read at all when the operation stored no log") — they are stable under any future shift.
- Cite the test titles instead of line numbers (
Strengths
- The vacuous-absence-guard failure mode is real and non-obvious:
not.toHaveBeenCalledWithkeyed on a string nobody emits passes unconditionally, and the co-located positives keep their own copies, so the suite stays green. Sharing one binding is the minimum change that closes it. - The comment records the mutation that proves the guard is live (typo one site on master → all 35 still pass), rather than just asserting the guard matters. That is the check that distinguishes a regression test from documentation.
- Both absence guards are already paired with a positive
expect(...readLog).toHaveBeenCalled()that pins the path, so they cannot pass vacuously in the other direction either — areturnabovereadLogfails them. The existing comments at:630-634and:768-771state that mutation too. - Scope discipline: no production file touched, so the change carries no runtime risk.
Recommended Action
- No blocking changes requested.
- Merge once the remaining required CI checks finish green.
|
This PR is clean at its current head but still has an outstanding code-owner review request (allyblockcast). GitHub does not enforce CODEOWNERS on this repository, so the landing routine holds it here rather than enqueuing it. |
Thinking Path
Linked Issues or Issue Description
What Changed
server/src/__tests__/agent-live-run-routes.test.ts:HEARTBEAT_RUN_LOG_ACCESSEDandWORKSPACE_OPERATION_LOG_ACCESSED, sourced fromserver/src/routes/agents.ts:395-396.logActivityassertions at them — the two absence guards plus the five positives. No inline copy of either literal remains in the file.git diff --stat -- server/src/routes server/src/servicesis empty.Verification
Mutation control BEFORE the change, on
master@1920eae, one site at a time — reproducing the vacuous pass is the point of the issue, so it was measured first::637→heartbeat.run_log_acessed:780→workspace_operation.log_acessedAFTER the change, the same typo at a call site is an undefined identifier:
A typo in the const value instead breaks the five positives, so neither half of the shape is silent any more.
Correction to the issue's stated verifying signal: it named
tsc --noEmit -p server/tsconfig.jsonas the post-change backstop. That tsconfig carries"exclude": ["src/__tests__"], so it does not typecheck this file — measured, it exits 0 with the typo present. The real backstops are the two above;check:test-undefined-symbolsexists precisely for this (BLO-24983). The AC is satisfied, by a different instrument than the one written down.Green at head:
npx vitest run server/src/__tests__/agent-live-run-routes.test.ts→ 35 passed (35), same count as merge commit34a424banode scripts/check-test-undefined-symbols.mjs→ oknpx tsc --noEmit -p server/tsconfig.json→ exit 0 (proves nothing here, per the correction above, but it is unchanged)Risks
Low. Test-internal hygiene with no runtime surface: no file under
server/src/routes/orserver/src/services/is touched, the two const values byte-matchagents.ts:395-396, and the assertion semantics are unchanged — only the literal's storage location moved. The failure mode if the values were wrong is loud, not silent: the five positives break immediately.Model Used
Claude Opus 5.1 (
claude-opus-5[1m], 1M context) via Claude Code, extended thinking, with tool use and code execution.