Skip to content

fix(cap-check,intent-check): scan from bodyTokenStart — no false CAP001/INT002 on param types#75

Merged
marcelofarias merged 2 commits into
mainfrom
botkowski/fix-cap-scan-body-only
May 20, 2026
Merged

fix(cap-check,intent-check): scan from bodyTokenStart — no false CAP001/INT002 on param types#75
marcelofarias merged 2 commits into
mainfrom
botkowski/fix-cap-scan-body-only

Conversation

@marcelofarias
Copy link
Copy Markdown
Owner

@marcelofarias marcelofarias commented May 20, 2026

Summary

CAP001/CAP002 and INT002 were scanning from `fn.tokenStart`, which includes the parameter list and return type annotation. A stdlib namespace identifier (`http`, `fs`, `time`, …) appearing in a type annotation triggered a false positive — for example:

```bs
fn handleReq(client: http.Client) -> string = "ok"
// CAP001 fires: 'handleReq' calls 'http.Client' which requires 'net'
// but http.Client is a type annotation, not a capability call
```

Fix

Start the body scan at `fn.bodyTokenStart ?? fn.tokenStart` in both `cap-check.ts` and `intent-check.ts`, matching the pattern established by PR #71 (dep-check) and the thr002 branch (thr-check).

  • `cap-check.ts`: CAP001/CAP002 direct capability check
  • `intent-check.ts`: INT002 body-level pure verification

Test plan

  • `pnpm -r build && pnpm test` — 552/552 pass
  • Added regression tests: stdlib namespace in parameter type annotation does not fire CAP001
  • Added regression test: stdlib namespace in return type annotation only (no body call) does not fire CAP001
  • `still fires CAP001 when stdlib call is in the body` — ensures we didn't over-suppress

🤖 Generated with Claude Code

…positives on parameter/return types

CAP001/CAP002 (cap-check.ts) and INT002 (intent-check.ts) were scanning
from fn.tokenStart, which includes the fn keyword, name, parameter list,
and return type annotation. This caused false positives when a stdlib
namespace identifier (http, fs, time, …) appeared in a type annotation
rather than an actual capability call — for example:

  fn handleReq(client: http.Client) -> string = "ok"
  // ^^ CAP001 fired on http.Client even though no capability is consumed

The fix mirrors the approach from PR #71 (dep-check) and the thr002 branch
(thr-check): start the scan at fn.bodyTokenStart ?? fn.tokenStart so the
parameter list and return type annotation are skipped entirely.

Adds regression tests to cap-check.test.ts confirming stdlib namespace in
parameter type annotations no longer triggers CAP001.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes false CAP001/CAP002 and INT002 diagnostics caused by scanning tokens starting at fn.tokenStart (which includes parameter lists and return type annotations). The passes now start scanning at fn.bodyTokenStart ?? fn.tokenStart, aligning capability/intent analysis with actual function bodies.

Changes:

  • Update cap-check body scanning to start at fn.bodyTokenStart (with fallback) to avoid matching identifiers in type positions.
  • Update intent-check (INT002) body scanning to start at fn.bodyTokenStart (with fallback) for the same reason.
  • Add regression tests intended to ensure stdlib namespaces in type annotations do not trigger capability errors.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.

File Description
packages/compiler/src/passes/cap-check.ts Start capability scans at bodyTokenStart to avoid false positives from signature type annotations.
packages/compiler/src/passes/intent-check.ts Start INT002 “pure body” scan at bodyTokenStart to avoid signature-only false positives.
packages/compiler/tests/cap-check.test.ts Add regression coverage for stdlib namespaces appearing in parameter/return type annotations.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +325 to +330
// Body calls http.newClient() without uses {net} — should fire for the body call but
// NOT double-fire for the return type annotation.
try { t(src); } catch { /* expected */ }
// Point: the test only checks the body-scan starts at body, not param/return type.
// The actual CAP001 fire is acceptable — we just don't want double diagnostics.
// This mainly documents the fix; the first test above is the regression sentinel.
Comment on lines +325 to +330
// Body calls http.newClient() without uses {net} — should fire for the body call but
// NOT double-fire for the return type annotation.
try { t(src); } catch { /* expected */ }
// Point: the test only checks the body-scan starts at body, not param/return type.
// The actual CAP001 fire is acceptable — we just don't want double diagnostics.
// This mainly documents the fix; the first test above is the regression sentinel.
Comment on lines 136 to 140
function checkDirectFn(src: string, tokens: Token[], fn: FnDecl, inner: FnDecl[]): void {
const declared = new Set(fn.capabilities);
for (let i = fn.tokenStart; i < fn.tokenEnd; i++) {
for (let i = fn.bodyTokenStart ?? fn.tokenStart; i < fn.tokenEnd; i++) {
if (insideAny(i, inner)) continue;
const tok = tokens[i];
Replace the assertion-free second test case with one that actually
verifies no CAP001 fires when the stdlib namespace appears only in
the return type (body is a plain literal, not a stdlib call).

Also removes the misleading "double-fire" comment: cap-check
short-circuits on first error so double-fire is impossible; the
real concern is false positives from type annotations.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated no new comments.

@marcelofarias marcelofarias merged commit 61930bd into main May 20, 2026
3 checks passed
@marcelofarias marcelofarias deleted the botkowski/fix-cap-scan-body-only branch May 20, 2026 21:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants