refactor(modules): give module-serve failure responses one owner - #3441
Conversation
…le-serve failure responses createModuleResponse is called inline at every failure site in module-server.ts, and the same "Module not found" + HTTP_NOT_FOUND pair appears with both no-cache (ordinary miss) and no-store (admission rejection) depending on call site, with nothing naming the difference. Introduce moduleNotFound/moduleRejected (and the smaller set of other shapes actually used: moduleBadRequest, moduleMethodNotAllowed, moduleServiceUnavailable, unknownDependencySnapshot) so the security-relevant cacheability decision is stated once.
…e call sites Replace the 21 inline createModuleResponse failure calls (plus the 7 call sites that went through the local unknownDependencySnapshotModuleResponse wrapper, now deleted) with the named helpers from module-response.ts. Every Cache-Control directive is preserved exactly as it was: no-cache for ordinary misses (moduleNotFound), no-store for admission/protection rejections (moduleRejected) and the other uncacheable shapes. Success responses and the dynamic error-body catch blocks are left inline per scope. See .superpowers/sdd/module-response-report.md for the full before/after mapping.
Add clarifying comments at two sites where future edits could silently introduce regressions: 1. module-server.ts line 918: Explain why moduleRejected (no-store) is used here, not moduleNotFound (no-cache). A future tidy-upper seeing "Module not found" log next to moduleRejected would silently change it to moduleNotFound, turning a no-store (uncacheable) response into no-cache (cacheable) — leaking project layout across auth boundaries. 2. module-response.ts line 31: Document that this module is failure-only by design. If a future caller adds a 2xx success shape, the metric label logic would silently record success as "error" unless revisited.
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
|
Warning Review limit reached
Next review available in: 9 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughModule failure-response construction moved into shared helpers. ChangesModule response centralization
Estimated code review effort: 3 (Moderate) | ~25 minutes Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
src/modules/server/module-response.ts (1)
9-10: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueUse the required documentation style.
Replace em dashes with ASCII punctuation. Replace uppercase
MUSTwithmust.
src/modules/server/module-response.ts#L9-L10: Replace the em dash with a period or comma.src/modules/server/module-response.ts#L56-L60: Use lowercasemustfor the requirement..superpowers/sdd/module-response-report.md#L1-L1: Replace the em dash in the heading..superpowers/sdd/module-response-report.md#L13-L14: Replace the em dashes in the table descriptions.As per coding guidelines, use
mustfor requirements and do not use em dash or en dash characters.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/modules/server/module-response.ts` around lines 9 - 10, Apply the required documentation style across all listed sites: in src/modules/server/module-response.ts lines 9-10, replace the em dash with ASCII punctuation; in lines 56-60, change uppercase MUST to lowercase must; in .superpowers/sdd/module-response-report.md lines 1 and 13-14, replace each em dash with ASCII punctuation. Ensure no em dash or en dash characters remain in these documentation passages.Source: Coding guidelines
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.superpowers/sdd/module-response-report.md:
- Around line 55-58: Update the direct call-site total in the response report
from 21 to 20, while leaving the separately reported seven indirect wrapper call
sites and the cache-mode breakdown unchanged.
---
Nitpick comments:
In `@src/modules/server/module-response.ts`:
- Around line 9-10: Apply the required documentation style across all listed
sites: in src/modules/server/module-response.ts lines 9-10, replace the em dash
with ASCII punctuation; in lines 56-60, change uppercase MUST to lowercase must;
in .superpowers/sdd/module-response-report.md lines 1 and 13-14, replace each em
dash with ASCII punctuation. Ensure no em dash or en dash characters remain in
these documentation passages.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 4e2e01b9-c69a-4118-a011-9f04dc5b2272
📒 Files selected for processing (5)
.superpowers/sdd/module-response-report.md.superpowers/sdd/module-response-review.diffsrc/modules/server/module-response.test.tssrc/modules/server/module-response.tssrc/modules/server/module-server.ts
The .superpowers/ directory holds this session's scratch review artifacts (an implementation report and a generated review diff). Unlike docs/superpowers/ it is not gitignored, so two files were committed by accident. They are not part of the change and do not belong in the repo.
Replace em dashes with ASCII punctuation in the module-response doc blocks and lower-case the MUST requirement on moduleRejected.
|
Documentation-style nitpick addressed in d20c566.
The |
Gives module-serve failure responses one owner, so the difference between a cacheable miss and an uncacheable rejection is stated once instead of re-spelled at ~29 call sites. Zero behaviour change.
The defect
createModuleResponse(...)appeared 29 times inline inmodule-server.ts. The literal pair"Module not found", HTTP_NOT_FOUNDoccurred with:Cache-Control: no-cacheat one site — an ordinary miss, safe to revalidateCache-Control: no-storeat four others — protected-path and production-admission rejections, deliberately uncacheableSame message, same status, different cacheability, and nothing in the code naming the difference. A future edit that "tidied up the duplication" could silently make an authorization decision cacheable.
The change
New
src/modules/server/module-response.ts— the single owner of turning a module-serve failure into an HTTP Response, so the cacheability of a miss versus a rejection is decided in one place.Six named helpers, no options bag, no exported generic builder. The two that carry the meaning:
moduleNotFound(method)— ordinary miss,no-cachemoduleRejected(method)— admission / protected-path rejection,no-storemoduleRejected's docstring states the rule outright: "Do not change this tono-cacheto 'match' the not-found case; that is a security regression, not a cleanup."Converted: 20 direct call sites (6
no-cache, 14no-store) plus 7 that went through a localunknownDependencySnapshotModuleResponsewrapper, now deleted.module-server.tsis net −67 lines (−103/+36).Deliberately left inline: the success responses (
HTTP_OK+application/javascript), the two Transform Error JS-body blocks, the cached-release passthrough, and the dynamic catch-all whose status and body vary by error kind. Folding those in would have produced exactly the general-purpose builder this change exists to avoid.Evidence
deno task test:unit: 3801 passed / 27907 steps → 3807 / 27918, exactly +6 tests / +11 steps.module-server.test.ts(the 88-step fence, which asserts exactCache-Controlvalues) unchanged.deno task verify:quickexit 0;deno check src/modules/index.tsclean.createModuleResponsecall in the baseline file was parsed with a paren-balancing script capturing status +Cache-Control+Content-Type+Allow+ body, then aligned against the new helper sites. 20 sites, perfect 1:1, zero directive drift — nono-store→no-cacheflip and nono-cache→no-storeflip. The pairing was confirmed context-anchored (each conversion sits against its original adjacentlogger.warn), not merely ordinal.no-storeremain inline inmodule-server.ts(all 15 converted); 5no-cacheremain, being the deliberately-excluded success responses. 6 converted + 5 remaining = the original 11.unknownDependencySnapshot(method)calls, all 409 +no-store. Zero stale references repo-wide.Tests fence the property, not just the code
module-response.test.tspins exact status +Content-Type+Cache-Controlper helper. The load-bearing case asserts thatmoduleNotFoundandmoduleRejectedshare a status but differ inCache-Control— so collapsing the two helpers, or copy-pasting one into the other, fails the suite.One question this refactor answered
The
findSourceFilemiss site logs "Module not found" but usesno-store, unlike every other pure-miss site. Naming the distinction surfaced it immediately. Git provenance settles it: commite6083e701(#3290, "fix(security): bind hosted source and environment identity") added thatno-storewhere previously there was noCache-Controlat all.It is deliberate. That site sits after the protected-path and production-admission gates and computes its answer by probing the tenant's
projectDirthroughsecureFs— so a cacheable answer would make project-layout probing results storable.moduleRejectedis substantively correct there. A comment at the site now records this, because the adjacent "Module not found" log is otherwise an invitation to "correct" it into a security regression.Known follow-ups (not blocking)
respond()'s status→metric mapping (not_foundvserror) is failure-only by design; a comment now says a success shape must not be added without revisiting it.Allow,Content-Type,Cache-Control). Distinct keys into aHeadersmap — no observable difference.Summary by CodeRabbit
HEADresponse behavior and non-caching for unavailable or rejected requests.HEADrequests.