Skip to content

feat(engine): base-revision + comment access for ctx.ast() (closes #479)#480

Merged
rhuanbarreto merged 8 commits into
mainfrom
claude/ctx-ast-base-and-comments
Jul 16, 2026
Merged

feat(engine): base-revision + comment access for ctx.ast() (closes #479)#480
rhuanbarreto merged 8 commits into
mainfrom
claude/ctx-ast-base-and-comments

Conversation

@rhuanbarreto

@rhuanbarreto rhuanbarreto commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Closes #479. Both capability gaps that the sandbox tightening (#477 / ARCH-024) exposed, delivered through the sanctioned ctx.ast() door. Two commits, reviewable separately.

Front A — base-revision access (39e511f)

Rules can inspect a file at its base git revision, not only the working tree — the capability whose absence forced rule authors to shell out to a subprocess.

  • ast(path, language, { rev: "base" }) — parses the file at the comparison base commit. Same shapes, same throw contract.
  • fileAtBase(path): Promise<string | null> — raw base source, or null when no base is resolved or the file was added since the base.

The base is the merge base of --base and HEAD (the commit changedFiles diffs against). No new privileged path: git reads live in the already-sanctioned git-files.ts; all four ast() guardrails run in order; TS/JS parse in-process, Python/Ruby base content goes to an OS-temp file outside the project tree with the same -I isolation. ast({rev:'base'}) throws distinguishably (no-base vs added-file); fileAtBase returns null so a rule can branch without a try/catch.

Unblocks documentation-only / no-op change detection with zero subprocess use.

Front B — comment access (95db9bd)

Comment-governance rules can work against structured comment tokens instead of fragile line-regex.

  • ast(path, language, { comments: true }) attaches a comments array of { type: "line" | "block"; value; loc } to the tree.
  • typescript / javascript / python supported; ruby throws a clear "not supported yet" (Ripper.lex deferred).
  • value has delimiters stripped. TS/JS comments are scanned from the ORIGINAL source (Bun.Transpiler strips them before meriyah) — so comment loc is original-source-accurate even for TS, unlike the tree's own transpiled-relative loc. String/template aware; regex literals are a known blind spot.
  • Python comments come from tokenize via a second serializer ({_tree, comments}), same convert() preamble, same -I.

Folded into ast() (not a new method) so it rides the existing four-guardrail flow and single-ast-method stays satisfied. No new subprocess site, no new guardrail.

Why this is safe

Both features add no new subprocess site and no new guardrail. ARCH-022's four companion rules (ast-guardrail-ordering, no-unsanctioned-engine-subprocess, single-ast-method, python-subprocess-isolated) all still pass — the new code rides entirely inside them.

Test plan

  • tests/engine/runner-ast-base.test.ts — 10 cases: git reads, fileAtBase, TS {rev:'base'} vs working tree, comment-only structural equivalence, both throw cases, Python doc-only detection
  • tests/engine/runner-ast-comments.test.ts — 7 cases: TS line/block extraction (stripped values + original-source loc), string-awareness, JS, opt-in-only, ruby-throws, Python tokenize (incl. #-in-string exclusion + base+comments composition)
  • bun run validate — 44/44 ADR rules, 1523 tests, lint, typecheck, format, knip, build

ADR

Amends ARCH-022 with both surfaces, their guardrail-compliance arguments, the throw-vs-null contract, the original-source-loc advantage for TS comments, the honest limitations (regex blind spot; comments as a mild root-shape addition), and cross-references to ARCH-024.

Rules can now inspect a file at its base git revision, not only the working
tree — the capability whose absence forced rule authors to shell out to a
subprocess (the escape ARCH-024 closed). This restores it through the
sanctioned ctx.ast() door.

New surface:
- ast(path, language, { rev: "base" }) parses the file at the comparison base
  commit instead of the working tree, same shapes and throw contract.
- fileAtBase(path): Promise<string | null> returns the raw base source, or
  null when no base is resolved or the file did not exist at the base.

The base is the merge base of --base and HEAD — the same commit changedFiles
diffs against (three-dot ref...HEAD) — resolved once per run in git-files.ts.

No new privileged path: the git reads (git merge-base, git show) live in the
already-sanctioned git-files.ts site, and all four ast() guardrails run in
order for a base parse. TS/JS base source parses in-process via a shared
parseTsOrJsSource helper (factored into js-parser.ts). Python/Ruby base
content is written to an OS-temp file — outside the project tree — and handed
to the unchanged serializers with the same mandatory -I isolation.

ast({ rev: "base" }) throws (distinguishably) when no base is resolved or the
file was added since the base; fileAtBase reports both as null so a rule can
branch on "is there a base?" without a try/catch.

This unblocks documentation-only / no-op change detection (compare base and
working-tree ASTs; comments and formatting drop out of both shapes) with zero
subprocess use. Amends ARCH-022; behavioural coverage in
tests/engine/runner-ast-base.test.ts.

Signed-off-by: Rhuan Barreto <rhuan@barreto.work>
@cursor

cursor Bot commented Jul 16, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_a719d6ee-8668-41ea-8825-d4ccd374694d)

@coderabbitai

coderabbitai Bot commented Jul 16, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@rhuanbarreto, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 14 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

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 configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: c1b7cc33-3860-4d56-b4fc-a8c3e6a71610

📥 Commits

Reviewing files that changed from the base of the PR and between 0b3c7aa and 73d245b.

📒 Files selected for processing (21)
  • .archgate/adrs/ARCH-022-ast-aware-rule-context.md
  • .archgate/adrs/ARCH-022-ast-aware-rule-context.rules.ts
  • docs/public/llms-full.txt
  • docs/src/content/docs/guides/security.mdx
  • docs/src/content/docs/guides/writing-rules.mdx
  • docs/src/content/docs/nb/guides/security.mdx
  • docs/src/content/docs/nb/guides/writing-rules.mdx
  • docs/src/content/docs/nb/reference/rule-api.mdx
  • docs/src/content/docs/pt-br/guides/security.mdx
  • docs/src/content/docs/pt-br/guides/writing-rules.mdx
  • docs/src/content/docs/pt-br/reference/rule-api.mdx
  • docs/src/content/docs/reference/rule-api.mdx
  • src/engine/ast-support.ts
  • src/engine/glob-utils.ts
  • src/engine/js-parser.ts
  • src/engine/runner.ts
  • src/formats/rules.ts
  • src/helpers/rules-shim.ts
  • tests/engine/glob-utils.test.ts
  • tests/engine/runner-ast-base.test.ts
  • tests/engine/runner-ast-comments.test.ts
📝 Walkthrough

Walkthrough

The rule context now supports merge-base file reads, base-revision AST parsing, and structured comment extraction. Git helpers provide nullable revision operations; JavaScript and TypeScript sources are parsed directly, while Python and Ruby base sources use temporary files with cleanup. AST options, public declarations, generated typings, documentation, runner wiring, grep matching, ADR guidance, and tests were updated. Base AST failures throw for unavailable revisions or missing files, whereas fileAtBase() returns null.

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning src/engine/glob-utils.ts adds matchLines(), a new grep helper unrelated to ctx.ast() base-revision/comment access. Remove or split the grep helper into a separate PR unless it is required by #479, so this change stays focused on AST/base-revision work.
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and accurately summarizes the main change to ctx.ast(): base-revision and comment access.
Description check ✅ Passed The description clearly matches the PR and explains the base-revision and comment-access work.
Linked Issues check ✅ Passed The PR implements the requested base-revision access, fileAtBase, and structured comments through ctx.ast().

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jul 16, 2026

Copy link
Copy Markdown

Deploying archgate-cli with  Cloudflare Pages  Cloudflare Pages

Latest commit: 73d245b
Status: ✅  Deploy successful!
Preview URL: https://7c68ee52.archgate-cli.pages.dev
Branch Preview URL: https://claude-ctx-ast-base-and-comm.archgate-cli.pages.dev

View logs

@github-actions

github-actions Bot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Code Coverage

Metric Value
Lines 91.2% (8094 / 8872)
Threshold 90% minimum — met
Platforms Linux + Windows

Full HTML report available in workflow artifacts.

Per-directory breakdown
Directory Coverage Lines
src/commands/ 89.0% 1959 / 2200
src/engine/ 93.7% 1977 / 2111
src/formats/ 98.7% 148 / 150
src/helpers/ 90.9% 4010 / 4411

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 7

🤖 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 `@src/engine/ast-support.ts`:
- Around line 239-274: Update writeTempSourceFile to create a private temporary
directory securely, then exclusively create the source file inside it with mode
0600 rather than using the predictable PID/counter path and direct
writeFileSync. Return the file path and make cleanup remove the file and its
private directory in a finally-safe, best-effort manner, including cleanup when
file creation fails.

In `@src/engine/runner.ts`:
- Around line 435-442: The check flow must reuse baseRevPromise’s resolved
merge-base SHA when computing changedFiles instead of independently calling
getFilesChangedSinceRef with options.base. Update the changedFiles setup to diff
the resolved SHA against HEAD while preserving staged/default behavior and
inclusion of working-tree and untracked files; ensure baseRevPromise remains the
single base-resolution operation for the run.

In `@src/formats/rules.ts`:
- Around line 70-79: Update the RuleContext.ast() documentation in
src/formats/rules.ts lines 70-79 to state that callers must compare a structural
projection excluding location metadata, rather than promising identical ESTree
or Python AST trees for comment or formatting-only changes. Apply the same
qualification to the capability described in
.archgate/adrs/ARCH-022-ast-aware-rule-context.md line 107, preserving ARCH-022
as the governing semantic reference.
- Around line 187-197: The language-agnostic RuleContext.ast overload currently
omits optional AstOptions. Update the AstLanguage overload in
src/formats/rules.ts lines 187-197 and mirror the same opts?: AstOptions
parameter in src/helpers/rules-shim.ts lines 183-193, preserving the existing
language-specific overloads and return types.

In `@tests/engine/runner-ast-base.test.ts`:
- Line 4: Replace every writeFileSync call in the async tests with awaited
Bun.write calls using the existing joined paths and content, while retaining the
node:fs import only for mkdtempSync and mkdirSync.
- Around line 304-350: Extend the AST equivalence test matrix beside the
existing Python case with JavaScript and Ruby comparisons. Add a JavaScript
base-versus-working-tree AST check, and add a Ruby equivalent guarded by skipIf
for the Ruby interpreter, using the appropriate language identifiers, source
files, and serializers while preserving the existing doc-only versus real-edit
assertions.
- Around line 232-260: Update the comparison in the check callback of the
“typescript: a comment-only edit yields structurally identical trees” test to
recursively remove location fields from both complete ASTs and compare the
resulting trees, rather than comparing only top-level node types. Preserve the
existing comment-only scenario while ensuring changes such as `v = 1` versus `v
= 2` are detected.
🪄 Autofix (Beta)

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: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 0f42d986-b8e5-4669-90d6-21aaf9c959b1

📥 Commits

Reviewing files that changed from the base of the PR and between 18db14d and 39e511f.

📒 Files selected for processing (8)
  • .archgate/adrs/ARCH-022-ast-aware-rule-context.md
  • src/engine/ast-support.ts
  • src/engine/git-files.ts
  • src/engine/js-parser.ts
  • src/engine/runner.ts
  • src/formats/rules.ts
  • src/helpers/rules-shim.ts
  • tests/engine/runner-ast-base.test.ts
📜 Review details
⏰ Context from checks skipped due to timeout. (3)
  • GitHub Check: Smoke Test (Windows) / Windows
  • GitHub Check: Smoke Test (Linux) / Linux
  • GitHub Check: Cloudflare Pages
🧰 Additional context used
📓 Path-based instructions (18)
src/**/*.ts

📄 CodeRabbit inference engine (.archgate/adrs/ARCH-003-output-formatting.md)

src/**/*.ts: Use styleText(format, text) from node:util for all terminal colors and formatting in CLI source files; do not use raw ANSI escape codes or third-party color libraries.
Commands that produce structured results and support --json must emit machine-readable JSON to stdout with no colors or decorative formatting.
When a command supports --json, use formatJSON() from src/helpers/output.ts for JSON serialization, and pass forcePretty: true when the user explicitly provided --json.
Use isAgentContext() from src/helpers/output.ts to enable auto-JSON behavior for commands that support both human-readable and JSON output modes.
CLI output must not include emoji; use text symbols and colors instead.
Send normal command output to stdout with console.log(), and send errors, warnings, and debug messages to stderr via logError(), logWarn(), and logDebug().
Keep CLI output concise and scannable by using whitespace and alignment instead of long text blocks.
Respect NO_COLOR automatically by relying on styleText; do not add custom color-environment handling in CLI code.
Do not output progress spinners unless there is a TTY check.
Do not assume piped output means agent context when CI is set; CI runners should still receive human-readable output.

src/**/*.ts: Do not re-export symbols from another module in any source file; statements like export { X } from "./other" and export type { X } from "./other" are forbidden.
Import symbols directly from the module that defines them; do not import from a directory path such as ../formats expecting implicit index.ts resolution.

Make large production thresholds injectable via an optional parameter that defaults to the module constant, so tests can supply a small value instead of generating huge fixtures.

src/**/*.ts: Use await Bun.file(path).json() when reading JSON files in Bun TypeScript source code; do not use JSON.parse(await Bun.file(path).text()) or `JSON.parse(fs.readFile...

Files:

  • src/engine/ast-support.ts
  • src/formats/rules.ts
  • src/engine/git-files.ts
  • src/helpers/rules-shim.ts
  • src/engine/runner.ts
  • src/engine/js-parser.ts
**/*.{ts,tsx,js,jsx,mjs,cjs}

📄 CodeRabbit inference engine (.archgate/adrs/ARCH-006-dependency-policy.md)

**/*.{ts,tsx,js,jsx,mjs,cjs}: Use Bun built-ins for file I/O (Bun.file, Bun.write), HTTP, subprocess execution (Bun.spawn), globbing (Bun.Glob), and testing (bun:test).
Do not use Node.js-specific APIs when Bun alternatives exist; for example, use Bun.file() instead of fs.readFile() for simple reads.
Prefer node: built-in modules such as node:util, node:path, and node:fs over npm alternatives.
Do not use utility libraries for single functions, such as importing lodash for one helper like pick.
Do not use path aliases (tsconfig paths); use relative imports with Bun's native module resolution.
Do not install packages globally during development; use bunx for one-off tools.

Files:

  • src/engine/ast-support.ts
  • src/formats/rules.ts
  • src/engine/git-files.ts
  • src/helpers/rules-shim.ts
  • tests/engine/runner-ast-base.test.ts
  • src/engine/runner.ts
  • src/engine/js-parser.ts
src/**/!(*platform).ts

📄 CodeRabbit inference engine (.archgate/adrs/ARCH-009-platform-detection-helper.md)

src/**/!(*platform).ts: In src/ TypeScript source files, do not read process.platform directly; use src/helpers/platform.ts (isWindows(), isMacOS(), isLinux(), isWSL(), getPlatformInfo()) for all platform detection.
Use the centralized platform helper instead of duplicating OS/WSL detection logic inline anywhere in src/ TypeScript source.
When behavior differs between Linux and Windows, account for WSL by using isWSL() rather than assuming `

Files:

  • src/engine/ast-support.ts
  • src/formats/rules.ts
  • src/engine/git-files.ts
  • src/helpers/rules-shim.ts
  • src/engine/runner.ts
  • src/engine/js-parser.ts
{src,tests}/**/*.ts

📄 CodeRabbit inference engine (.archgate/adrs/LEGAL-001-spdx-license-headers.md)

{src,tests}/**/*.ts: Every TypeScript source file in src/ and tests/ must begin with // SPDX-License-Identifier: Apache-2.0 followed by // Copyright 2026 Archgate.
If a TypeScript file has a shebang line (for example #!/usr/bin/env bun in src/cli.ts), the SPDX license header must appear immediately after the shebang.
Use single-line // comments for the SPDX header; do not use block comments (/* */) or alternate license identifiers.

Files:

  • src/engine/ast-support.ts
  • src/formats/rules.ts
  • src/engine/git-files.ts
  • src/helpers/rules-shim.ts
  • tests/engine/runner-ast-base.test.ts
  • src/engine/runner.ts
  • src/engine/js-parser.ts
src/{helpers,engine}/**/*.ts

📄 CodeRabbit inference engine (.archgate/adrs/ARCH-002-error-handling.md)

Do not use console.log(), console.warn(), or console.info() directly in helper or engine files; use logInfo() or logWarn() instead.

Files:

  • src/engine/ast-support.ts
  • src/engine/git-files.ts
  • src/helpers/rules-shim.ts
  • src/engine/runner.ts
  • src/engine/js-parser.ts
src/engine/**/*.ts

📄 CodeRabbit inference engine (.archgate/adrs/ARCH-023-engine-file-listing-via-in-memory-git-tracked-matching.md)

src/engine/**/*.ts: In the rules engine, list project files by matching glob patterns in memory against the git-tracked file set rather than walking the filesystem.
Route new engine file listings through listMatchingFiles for rule-facing inputs or matchTrackedFiles for trusted ADR frontmatter patterns.
When the target is a Git repository and respectGitignore is not false, pass the tracked set from getGitTrackedFiles to matching operations.
Per-run RunCaches must share glob results keyed by pattern and tracked mode and file text keyed by absolute path; cached promises should share in-flight work, and returned glob arrays must be copied before exposing them to rules.
Do not cache readJSON results because rules receive mutable objects whose shared mutation could leak between rules.
Do not filter filesystem scan results against the tracked set as a substitute for in-memory matching, and do not hardcode ignore directories; use the Git-derived tracked set instead.

src/engine/**/*.ts: Engine code must not add unsanctioned subprocess mechanisms: child_process imports are prohibited, and Bun.spawn/Bun.spawnSync calls must remain confined to the sanctioned AST and git helpers.
Do not introduce tree-sitter, web-tree-sitter, native parser bindings, WASM grammars, or other new production dependencies for this AST feature.
Do not normalize Python or Ruby AST results into ESTree; document that AST node shapes are language-native and distinct.
For TypeScript AST results parsed from transpiled output, consumers must not treat node.loc as source-accurate; source locations are directly reliable only for JavaScript, so TypeScript locations must be re-located against the original source.

Files:

  • src/engine/ast-support.ts
  • src/engine/git-files.ts
  • src/engine/runner.ts
  • src/engine/js-parser.ts
src/engine/{runner,ast-support}.ts

📄 CodeRabbit inference engine (.archgate/adrs/ARCH-022-ast-aware-rule-context.md)

TypeScript and JavaScript AST parsing must reuse the shared in-process meriyah parser helper; Python and Ruby parsing must use their standard-library AST facilities through guarded Bun.spawn calls with array arguments.

Files:

  • src/engine/ast-support.ts
  • src/engine/runner.ts
**

⚙️ CodeRabbit configuration file

**: This project uses Archgate — an AI governance framework based on
Architecture Decision Records (ADRs). The ADRs in .archgate/adrs/
are the authoritative rules for this codebase. Each ADR has a companion
.rules.ts file with automated checks that run via archgate check.

When reviewing, you must:

  1. Treat ADR violations as blocking issues, not suggestions.
  2. Cite the specific ADR ID when flagging a violation (e.g., "Violates ARCH-006").
  3. Focus on semantic and contextual violations that automated rules cannot catch —
    the .rules.ts files already cover syntactic/structural patterns.
  4. If you are unsure whether something violates an ADR, flag it as a question
    rather than approving it.

Files:

  • src/engine/ast-support.ts
  • src/formats/rules.ts
  • src/engine/git-files.ts
  • src/helpers/rules-shim.ts
  • tests/engine/runner-ast-base.test.ts
  • src/engine/runner.ts
  • src/engine/js-parser.ts
src/formats/**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Use Zod schemas as the single source of truth; derive types with z.infer<> instead of defining separate interfaces, use safeParse(), and reuse AdrFrontmatterSchema.shape.* to avoid duplicating enums.

Files:

  • src/formats/rules.ts
src/formats/rules.ts

📄 CodeRabbit inference engine (.archgate/adrs/ARCH-022-ast-aware-rule-context.md)

RuleContext must expose exactly one ast(path, language, opts?) method, with language values typescript, javascript, python, or ruby; it must not expose per-language AST methods or raw subprocess primitives.

Files:

  • src/formats/rules.ts
src/engine/git-files.ts

📄 CodeRabbit inference engine (.archgate/adrs/ARCH-023-engine-file-listing-via-in-memory-git-tracked-matching.md)

getGitTrackedFiles must define the tracked-file universe using git ls-files --cached --others --exclude-standard minus git ls-files --deleted; the deleted-file subtraction is mandatory.

Files:

  • src/engine/git-files.ts
src/engine/{glob-utils,git-files}.ts

📄 CodeRabbit inference engine (.archgate/adrs/ARCH-023-engine-file-listing-via-in-memory-git-tracked-matching.md)

src/engine/{glob-utils,git-files}.ts: Bun.Glob#scan() is permitted only as a fallback when no tracked set exists, such as for non-Git targets or when respectGitignore: false; no other engine file may call it.
All remaining Bun.Glob#scan() fallback calls must pass { dot: true }.

Files:

  • src/engine/git-files.ts
src/engine/{runner,git-files}.ts

📄 CodeRabbit inference engine (.archgate/adrs/ARCH-022-ast-aware-rule-context.md)

src/engine/{runner,git-files}.ts: Base-revision AST access must use the merge base of --base and HEAD, preserve the same guardrail ordering, and confine git reads to git-files.ts; ast(..., { rev: "base" }) must throw on missing bases or absent files, while fileAtBase() must return null.
Rule code must access base content only through ast(path, language, { rev: "base" }) or fileAtBase() and must never spawn git or interpreters directly.

Files:

  • src/engine/git-files.ts
  • src/engine/runner.ts
src/helpers/rules-shim.ts

📄 CodeRabbit inference engine (.archgate/adrs/ARCH-022-ast-aware-rule-context.md)

The generated .rules.ts authoring shim must mirror the single RuleContext.ast() API and must not expose raw subprocess or filesystem primitives.

Files:

  • src/helpers/rules-shim.ts
tests/**/*.test.ts

📄 CodeRabbit inference engine (.archgate/adrs/ARCH-005-testing-standards.md)

tests/**/*.test.ts: Use Bun's built-in test runner (bun:test) for all test files, and place tests under tests/ mirroring the src/ directory structure with <module-name>.test.ts naming.
Use temp directories (mkdtemp) for filesystem tests, and clean them up in afterEach or afterAll.
Close external SDK instances (servers, clients, transports, connections) in afterEach or afterAll, managing their lifecycle in hooks rather than inside individual test bodies.
When a test creates a temporary git repository and runs git commit, configure local user.email and user.name immediately after git init.
Test public module interfaces, not private implementation details.
Use descriptive test names that explain the expected behavior.
Every runnable test()/it() must contain at least one expect() assertion; smoke tests must make the contract explicit with expect(() => fn()).not.toThrow() or await expect(promise).resolves.toBeUndefined().
Use test.skip, test.skipIf, or test.todo for intentionally empty or disabled tests; do not use bare return or empty callbacks to skip work.
If the first expect() is being added to a previously assertion-less test file, add expect to the bun:test import.
When mocking fetch in tests, assign directly to globalThis.fetch and restore the original or use mock.restore() afterward.
Wrap spyOn() and inline mockImplementation() usage in try/finally, or create and restore spies in hooks, so mockRestore() always runs.
Only raise a per-test timeout above the global bun test --timeout 60000; never set a shorter per-test timeout.
Mock first-party modules with import * as mod plus spyOn(mod, "fn"), not mock.module().
When a test needs to redirect user-scope paths, mock os.homedir() instead of relying on HOME/Bun.env.HOME; restore the spy in test hooks.
Do not depend on network access in unit tests.
Do not leave temp files after test runs.
Do not leave external SDK instances open after tests...

Files:

  • tests/engine/runner-ast-base.test.ts
tests/**/*.ts

📄 CodeRabbit inference engine (.archgate/adrs/ARCH-009-platform-detection-helper.md)

In test files, use _resetPlatformCache() to simulate different platforms instead of mocking or mutating process.platform directly.

Files:

  • tests/engine/runner-ast-base.test.ts
tests/engine/runner-ast*.test.ts

📄 CodeRabbit inference engine (.archgate/adrs/ARCH-022-ast-aware-rule-context.md)

AST behavior must be covered by tests, including per-language parsing, BOM handling, interpreter and parse failures, guardrail behavior, isolation from shadow modules, base-revision parsing, structural equivalence, and ast() throw versus fileAtBase() null semantics.

Files:

  • tests/engine/runner-ast-base.test.ts
src/engine/runner.ts

📄 CodeRabbit inference engine (.archgate/adrs/ARCH-022-ast-aware-rule-context.md)

src/engine/runner.ts: createRuleContext() must implement AST dispatch internally, and Python/Ruby AST requests must perform guardrails in this exact order before spawning: path safety, language plausibility, interpreter availability, and guarded invocation.
Python AST subprocesses must use isolated mode (python -I -c ...), and Python/Ruby interpreter availability must be probed once and cached per check invocation.
ctx.ast() must throw on missing interpreters or parse failures, with distinguishable error messages; it must never return null or silently downgrade failures.
AST parsing must strip a leading UTF-8 BOM for Python and Ruby sources before parsing.

Files:

  • src/engine/runner.ts
🧠 Learnings (2)
📚 Learning: 2026-07-02T16:03:33.031Z
Learnt from: rhuanbarreto
Repo: archgate/cli PR: 446
File: src/helpers/session-context-opencode.ts:81-100
Timestamp: 2026-07-02T16:03:33.031Z
Learning: For synchronous helper functions that use Bun’s sqlite sync API (i.e., they must remain synchronous), it’s acceptable to use `existsSync` from `node:fs` to check whether the SQLite database file exists. Avoid using `Bun.file(path).exists()` for this purpose because it’s async and would force the helper to become async (no equivalent synchronous Bun alternative). If the DB file is missing, throw/return a clear, actionable "No database found" error (per ARCH-006) rather than letting the sqlite open fail with a generic DB-open error.

Applied to files:

  • src/helpers/rules-shim.ts
📚 Learning: 2026-07-11T13:03:15.386Z
Learnt from: rhuanbarreto
Repo: archgate/cli PR: 467
File: .archgate/adrs/ARCH-011-consistent-project-root-resolution.md:0-0
Timestamp: 2026-07-11T13:03:15.386Z
Learning: For Markdown files formatted by oxfmt (especially ADRs), avoid inline code spans that contain escaped backticks, e.g. `\`...\`` inside a single `` `...` `` span. oxfmt may mis-parse these and, on re-format, can collapse spaces after later inline code spans on the same line, effectively removing any manually re-added spacing. Instead, rephrase the text so the message stays plain quoted text, and put any embedded command/fragment that needs code formatting (e.g., `archgate init`) in its own separate inline code span; keep surrounding punctuation/spacing outside the code span.

Applied to files:

  • .archgate/adrs/ARCH-022-ast-aware-rule-context.md
🪛 LanguageTool
.archgate/adrs/ARCH-022-ast-aware-rule-context.md

[style] ~97-~97: Consider an alternative for the overused word “exactly”.
Context: ...reter from a .rules.ts file — that is exactly the sandbox escape [ARCH-024](./ARCH-02...

(EXACTLY_PRECISELY)


[style] ~98-~98: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...eAtBase()are the sanctioned path. - **DON'T** returnnullfromast({ rev: "ba...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)

🔇 Additional comments (7)
src/formats/rules.ts (1)

80-82: LGTM!

Also applies to: 158-165

src/helpers/rules-shim.ts (1)

75-84: LGTM!

Also applies to: 156-162

.archgate/adrs/ARCH-022-ast-aware-rule-context.md (1)

51-65: LGTM!

Also applies to: 83-85, 97-98, 126-127, 140-141, 161-161

src/engine/git-files.ts (1)

321-345: LGTM!

Also applies to: 357-364, 377-383

src/engine/ast-support.ts (1)

211-237: LGTM!

Also applies to: 276-302

src/engine/js-parser.ts (1)

42-69: LGTM!

src/engine/runner.ts (1)

8-8: LGTM!

Also applies to: 25-41, 142-143, 187-216, 238-242, 266-306, 392-406, 474-478, 527-528

Comment thread src/engine/ast-support.ts Outdated
Comment thread src/engine/runner.ts Outdated
Comment thread src/formats/rules.ts
Comment thread src/formats/rules.ts
Comment thread tests/engine/runner-ast-base.test.ts Outdated
Comment thread tests/engine/runner-ast-base.test.ts
Comment thread tests/engine/runner-ast-base.test.ts
…e })

Comment-governance rules can now work against structured comment tokens
instead of fragile line-by-line regex — the comments-in-AST half of #479.
The returned tree carries a `comments` array of
{ type: "line" | "block"; value: string; loc } when the flag is set.

Folded into ast() rather than a separate method, so it runs inside the same
four-guardrail flow (ast-guardrail-ordering covers it) and single-ast-method
stays satisfied — the catch-all signature is unchanged.

- typescript/javascript/python supported; ruby throws a clear "not supported
  yet" (Ripper.lex is a deferred follow-up).
- value has delimiters stripped (//, /* */, #); Python has only line comments.
- TS/JS comments are scanned from the ORIGINAL source (extractJsComments in
  js-parser.ts), because Bun.Transpiler strips them before meriyah — which
  makes comment loc original-source-accurate even for TS, unlike the tree's
  transpiled-relative loc. String/template aware; regex literals are a known
  blind spot.
- Python comments come from tokenize via a second serializer that prints
  {_tree, comments}, unwrapped by the engine; same convert() preamble, same
  mandatory -I isolation.

No new subprocess site and no new guardrail. Also dedups the grep line-scan
into glob-utils.matchLines. Amends ARCH-022; coverage in
tests/engine/runner-ast-comments.test.ts.

Signed-off-by: Rhuan Barreto <rhuan@barreto.work>
@cursor

cursor Bot commented Jul 16, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_63e8f7a2-fa7d-4815-a0f2-0e9a56322361)

@rhuanbarreto rhuanbarreto changed the title feat(engine): base-revision access for ctx.ast() and ctx.fileAtBase() feat(engine): base-revision + comment access for ctx.ast() (closes #479) Jul 16, 2026
… allowlist

Covers the user-facing surface of this PR and the previously-undocumented
sandbox change from #477, across all three locales (en, nb, pt-br) per the
GEN-002 same-changeset i18n requirement.

reference/rule-api.mdx
- fileAtBase() method; AstOptions { rev, comments }; CommentToken type
- ast() section: base-revision parsing, comment collection (original-source
  loc, string-awareness, Python line-only), the two new throw cases
- AstNode: note the opt-in comments array

guides/writing-rules.mdx
- ctx.ast opts + ctx.fileAtBase entries
- worked examples: documentation-only-change detection via { rev: "base" },
  and comment governance via { comments: true }
- note that rule files may import only the safe four modules

guides/security.mdx (#477 gap — was still describing the old denylist)
- rewrite the sandbox section from denylist to allowlist model
- correct the now-wrong claims (literal dynamic imports ARE blocked; the
  scanner sees through escapes) and add require/import.meta.require,
  process.binding, Trojan-Source Unicode, and imported-rule scanning
- reframe the "review untrusted rules" note: strong first line of defense,
  not a complete sandbox (Reflect.get indirection remains a residual)

Cross-page anchors normalized to be locale-agnostic. llms-full.txt
regenerated. Validated: 44/44 ADR rules incl. GEN-002 i18n parity + drift.

Signed-off-by: Rhuan Barreto <rhuan@barreto.work>
@rhuanbarreto rhuanbarreto added the documentation Improvements or additions to documentation label Jul 16, 2026
@cursor

cursor Bot commented Jul 16, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_81f00788-7675-47f5-a512-382bca52448c)

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 10

🤖 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 `@docs/src/content/docs/guides/security.mdx`:
- Around line 46-53: Qualify the capability restrictions in
docs/src/content/docs/guides/security.mdx:46-53 and
docs/src/content/docs/nb/guides/security.mdx:46-53 as blocking recognized or
direct access paths, rather than guaranteeing a complete sandbox. Keep and align
the existing global-object indirection bypass warnings at
docs/src/content/docs/guides/security.mdx:133-136 and
docs/src/content/docs/nb/guides/security.mdx:133-136 with that qualification,
preserving equivalent English and Norwegian Bokmål meaning.

In `@docs/src/content/docs/guides/writing-rules.mdx`:
- Line 480: Update the no-base explanation near the Archgate command example:
state that ctx.changedFiles may include auto-detected working-tree changes, but
the rule becomes a no-op because ctx.fileAtBase(file) returns null without a
base reference. Keep the existing explanation about git and interpreter access
unchanged.
- Around line 450-452: Update the “Comparing against the base revision”
documentation to remove Python docstrings from the claim that comment-only edits
produce identical ASTs. Limit the example to comments and formatting, or
explicitly describe normalizing Python docstrings before comparing the ASTs.

In `@docs/src/content/docs/nb/reference/rule-api.mdx`:
- Around line 220-236: Document how to normalize positional metadata such as
loc, range, lineno, and related fields before comparing ASTs, or expose a
structural comparator that performs this normalization, in
docs/src/content/docs/nb/reference/rule-api.mdx lines 220-236. Update the
examples in docs/src/content/docs/nb/guides/writing-rules.mdx lines 450-467 and
docs/src/content/docs/pt-br/guides/writing-rules.mdx lines 450-467 to use the
normalized structural comparison instead of full AST equality.

In `@docs/src/content/docs/pt-br/guides/security.mdx`:
- Line 22: Update the security guide sentence describing rule execution to
remove the “sandbox de runtime” claim and instead reference the restricted
RuleContext API alongside the static security scanner. Preserve the explanation
that rules run in-process with the invoking user’s privileges and that imports
are controlled by an allowlist.

In `@docs/src/content/docs/pt-br/reference/rule-api.mdx`:
- Around line 227-233: The example’s changed-file comparison must guard the base
AST lookup with fileAtBase() before calling ctx.ast(..., { rev: "base" }).
Update the loop around structurallyEqual so files absent at the base, or runs
without a resolved base, are skipped when fileAtBase() returns null; retain
comparison and reporting for files present at the base.

In `@src/engine/glob-utils.ts`:
- Around line 15-33: Update matchLines to clone the supplied RegExp and use
exec() per line, resetting lastIndex before each execution, so global patterns
retain their actual match index. Preserve the existing GrepMatch construction
and one-based line and column values.

In `@src/engine/js-parser.ts`:
- Around line 87-97: Update the line-comment scanning loop in the JavaScript
parser to stop advancing on either "\n" or "\r", so comment values exclude all
line terminators while preserving the existing location and comment handling.

In `@src/engine/runner.ts`:
- Around line 222-225: Move the Ruby comment rejection in
createRuleContext()/ctx.ast() to after the language plausibility check. Preserve
ARCH-022 ordering: safePath, language-versus-extension/content plausibility
validation, interpreter availability probing, then guarded invocation; only
perform commentsUnsupportedError(language, path) after plausibility succeeds.

In `@tests/engine/runner-ast-comments.test.ts`:
- Around line 98-123: Extend the test “typescript: a comment marker inside a
string is not a comment” to include a TypeScript template literal containing
both // and /* ... */ markers, plus one genuine surrounding comment. Assert that
comment extraction returns only the real comment, preserving coverage for
template-aware original-source scanning required by ARCH-022.
🪄 Autofix (Beta)

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: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 02f17d64-3242-4d23-b53a-1bd2750d956d

📥 Commits

Reviewing files that changed from the base of the PR and between 39e511f and 3912af3.

📒 Files selected for processing (18)
  • .archgate/adrs/ARCH-022-ast-aware-rule-context.md
  • docs/public/llms-full.txt
  • docs/src/content/docs/guides/security.mdx
  • docs/src/content/docs/guides/writing-rules.mdx
  • docs/src/content/docs/nb/guides/security.mdx
  • docs/src/content/docs/nb/guides/writing-rules.mdx
  • docs/src/content/docs/nb/reference/rule-api.mdx
  • docs/src/content/docs/pt-br/guides/security.mdx
  • docs/src/content/docs/pt-br/guides/writing-rules.mdx
  • docs/src/content/docs/pt-br/reference/rule-api.mdx
  • docs/src/content/docs/reference/rule-api.mdx
  • src/engine/ast-support.ts
  • src/engine/glob-utils.ts
  • src/engine/js-parser.ts
  • src/engine/runner.ts
  • src/formats/rules.ts
  • src/helpers/rules-shim.ts
  • tests/engine/runner-ast-comments.test.ts
📜 Review details
⏰ Context from checks skipped due to timeout. (2)
  • GitHub Check: Smoke Test (Windows) / Windows
  • GitHub Check: Cloudflare Pages
🧰 Additional context used
📓 Path-based instructions (26)
src/**/*.ts

📄 CodeRabbit inference engine (.archgate/adrs/ARCH-003-output-formatting.md)

src/**/*.ts: Use styleText(format, text) from node:util for all terminal colors and formatting in CLI source files; do not use raw ANSI escape codes or third-party color libraries.
Commands that produce structured results and support --json must emit machine-readable JSON to stdout with no colors or decorative formatting.
When a command supports --json, use formatJSON() from src/helpers/output.ts for JSON serialization, and pass forcePretty: true when the user explicitly provided --json.
Use isAgentContext() from src/helpers/output.ts to enable auto-JSON behavior for commands that support both human-readable and JSON output modes.
CLI output must not include emoji; use text symbols and colors instead.
Send normal command output to stdout with console.log(), and send errors, warnings, and debug messages to stderr via logError(), logWarn(), and logDebug().
Keep CLI output concise and scannable by using whitespace and alignment instead of long text blocks.
Respect NO_COLOR automatically by relying on styleText; do not add custom color-environment handling in CLI code.
Do not output progress spinners unless there is a TTY check.
Do not assume piped output means agent context when CI is set; CI runners should still receive human-readable output.

src/**/*.ts: Do not re-export symbols from another module in any source file; statements like export { X } from "./other" and export type { X } from "./other" are forbidden.
Import symbols directly from the module that defines them; do not import from a directory path such as ../formats expecting implicit index.ts resolution.

Make large production thresholds injectable via an optional parameter that defaults to the module constant, so tests can supply a small value instead of generating huge fixtures.

src/**/*.ts: Use await Bun.file(path).json() when reading JSON files in Bun TypeScript source code; do not use JSON.parse(await Bun.file(path).text()) or `JSON.parse(fs.readFile...

Files:

  • src/engine/glob-utils.ts
  • src/engine/js-parser.ts
  • src/helpers/rules-shim.ts
  • src/formats/rules.ts
  • src/engine/runner.ts
  • src/engine/ast-support.ts
**/*.{ts,tsx,js,jsx,mjs,cjs}

📄 CodeRabbit inference engine (.archgate/adrs/ARCH-006-dependency-policy.md)

**/*.{ts,tsx,js,jsx,mjs,cjs}: Use Bun built-ins for file I/O (Bun.file, Bun.write), HTTP, subprocess execution (Bun.spawn), globbing (Bun.Glob), and testing (bun:test).
Do not use Node.js-specific APIs when Bun alternatives exist; for example, use Bun.file() instead of fs.readFile() for simple reads.
Prefer node: built-in modules such as node:util, node:path, and node:fs over npm alternatives.
Do not use utility libraries for single functions, such as importing lodash for one helper like pick.
Do not use path aliases (tsconfig paths); use relative imports with Bun's native module resolution.
Do not install packages globally during development; use bunx for one-off tools.

Files:

  • src/engine/glob-utils.ts
  • tests/engine/runner-ast-comments.test.ts
  • src/engine/js-parser.ts
  • src/helpers/rules-shim.ts
  • src/formats/rules.ts
  • src/engine/runner.ts
  • src/engine/ast-support.ts
src/**/!(*platform).ts

📄 CodeRabbit inference engine (.archgate/adrs/ARCH-009-platform-detection-helper.md)

src/**/!(*platform).ts: In src/ TypeScript source files, do not read process.platform directly; use src/helpers/platform.ts (isWindows(), isMacOS(), isLinux(), isWSL(), getPlatformInfo()) for all platform detection.
Use the centralized platform helper instead of duplicating OS/WSL detection logic inline anywhere in src/ TypeScript source.
When behavior differs between Linux and Windows, account for WSL by using isWSL() rather than assuming `

Files:

  • src/engine/glob-utils.ts
  • src/engine/js-parser.ts
  • src/helpers/rules-shim.ts
  • src/formats/rules.ts
  • src/engine/runner.ts
  • src/engine/ast-support.ts
{src,tests}/**/*.ts

📄 CodeRabbit inference engine (.archgate/adrs/LEGAL-001-spdx-license-headers.md)

{src,tests}/**/*.ts: Every TypeScript source file in src/ and tests/ must begin with // SPDX-License-Identifier: Apache-2.0 followed by // Copyright 2026 Archgate.
If a TypeScript file has a shebang line (for example #!/usr/bin/env bun in src/cli.ts), the SPDX license header must appear immediately after the shebang.
Use single-line // comments for the SPDX header; do not use block comments (/* */) or alternate license identifiers.

Files:

  • src/engine/glob-utils.ts
  • tests/engine/runner-ast-comments.test.ts
  • src/engine/js-parser.ts
  • src/helpers/rules-shim.ts
  • src/formats/rules.ts
  • src/engine/runner.ts
  • src/engine/ast-support.ts
src/{helpers,engine}/**/*.ts

📄 CodeRabbit inference engine (.archgate/adrs/ARCH-002-error-handling.md)

Do not use console.log(), console.warn(), or console.info() directly in helper or engine files; use logInfo() or logWarn() instead.

Files:

  • src/engine/glob-utils.ts
  • src/engine/js-parser.ts
  • src/helpers/rules-shim.ts
  • src/engine/runner.ts
  • src/engine/ast-support.ts
src/engine/**/*.ts

📄 CodeRabbit inference engine (.archgate/adrs/ARCH-023-engine-file-listing-via-in-memory-git-tracked-matching.md)

src/engine/**/*.ts: In the rules engine, list project files by matching glob patterns in memory against the git-tracked file set rather than walking the filesystem.
Route new engine file listings through listMatchingFiles for rule-facing inputs or matchTrackedFiles for trusted ADR frontmatter patterns.
When the target is a Git repository and respectGitignore is not false, pass the tracked set from getGitTrackedFiles to matching operations.
Per-run RunCaches must share glob results keyed by pattern and tracked mode and file text keyed by absolute path; cached promises should share in-flight work, and returned glob arrays must be copied before exposing them to rules.
Do not cache readJSON results because rules receive mutable objects whose shared mutation could leak between rules.
Do not filter filesystem scan results against the tracked set as a substitute for in-memory matching, and do not hardcode ignore directories; use the Git-derived tracked set instead.

src/engine/**/*.ts: Engine code MUST NOT introduce unsanctioned subprocess access: do not use child_process, Bun.$, or shell-interpolated commands; subprocesses for AST parsing belong only to the sanctioned AST support, and git subprocesses belong only to git-files.ts.
Rule execution code MUST NOT expose or directly invoke Bun.spawn, child_process, interpreters, or git from .rules.ts; rules must use ctx.ast() or fileAtBase() for structural and base-revision access.
Python and Ruby serializers MUST strip a leading UTF-8 BOM before parsing; Python AST subprocesses MUST use the standard-library facility under -I isolation, and Ruby must use built-in Ripper/JSON serialization.

Files:

  • src/engine/glob-utils.ts
  • src/engine/js-parser.ts
  • src/engine/runner.ts
  • src/engine/ast-support.ts
src/engine/glob-utils.ts

📄 CodeRabbit inference engine (.archgate/adrs/ARCH-023-engine-file-listing-via-in-memory-git-tracked-matching.md)

src/engine/glob-utils.ts: matchTrackedFiles and listMatchingFiles must perform tracked-file matching with Bun.Glob#match().
listMatchingFiles must validate the original pattern and every brace-expanded alternative with safeGlob before either matching tracked files or scanning fallback files.

Files:

  • src/engine/glob-utils.ts
src/engine/{glob-utils,git-files}.ts

📄 CodeRabbit inference engine (.archgate/adrs/ARCH-023-engine-file-listing-via-in-memory-git-tracked-matching.md)

src/engine/{glob-utils,git-files}.ts: Bun.Glob#scan() is permitted only as a fallback when no tracked set exists, such as for non-Git targets or when respectGitignore: false; no other engine file may call it.
All remaining Bun.Glob#scan() fallback calls must pass { dot: true }.

Files:

  • src/engine/glob-utils.ts
**

⚙️ CodeRabbit configuration file

**: This project uses Archgate — an AI governance framework based on
Architecture Decision Records (ADRs). The ADRs in .archgate/adrs/
are the authoritative rules for this codebase. Each ADR has a companion
.rules.ts file with automated checks that run via archgate check.

When reviewing, you must:

  1. Treat ADR violations as blocking issues, not suggestions.
  2. Cite the specific ADR ID when flagging a violation (e.g., "Violates ARCH-006").
  3. Focus on semantic and contextual violations that automated rules cannot catch —
    the .rules.ts files already cover syntactic/structural patterns.
  4. If you are unsure whether something violates an ADR, flag it as a question
    rather than approving it.

Files:

  • src/engine/glob-utils.ts
  • docs/src/content/docs/pt-br/guides/security.mdx
  • docs/src/content/docs/guides/security.mdx
  • docs/src/content/docs/nb/guides/security.mdx
  • docs/src/content/docs/pt-br/guides/writing-rules.mdx
  • docs/src/content/docs/guides/writing-rules.mdx
  • docs/src/content/docs/nb/guides/writing-rules.mdx
  • tests/engine/runner-ast-comments.test.ts
  • src/engine/js-parser.ts
  • docs/src/content/docs/nb/reference/rule-api.mdx
  • src/helpers/rules-shim.ts
  • docs/src/content/docs/reference/rule-api.mdx
  • src/formats/rules.ts
  • src/engine/runner.ts
  • docs/public/llms-full.txt
  • docs/src/content/docs/pt-br/reference/rule-api.mdx
  • src/engine/ast-support.ts
docs/src/content/docs/**/*.mdx

📄 CodeRabbit inference engine (.archgate/adrs/GEN-001-documentation-site.md)

docs/src/content/docs/**/*.mdx: Use MDX (.mdx) for all content pages under docs/src/content/docs/.
Escape literal curly braces in MDX when showing template syntax; do not use bare {} in prose or code-fence labels.

Files:

  • docs/src/content/docs/pt-br/guides/security.mdx
  • docs/src/content/docs/guides/security.mdx
  • docs/src/content/docs/nb/guides/security.mdx
  • docs/src/content/docs/pt-br/guides/writing-rules.mdx
  • docs/src/content/docs/guides/writing-rules.mdx
  • docs/src/content/docs/nb/guides/writing-rules.mdx
  • docs/src/content/docs/nb/reference/rule-api.mdx
  • docs/src/content/docs/reference/rule-api.mdx
  • docs/src/content/docs/pt-br/reference/rule-api.mdx
{docs/src/content/docs/**/*.mdx,docs/astro.config.mjs}

📄 CodeRabbit inference engine (.archgate/adrs/GEN-001-documentation-site.md)

When adding a new documentation page, create the MDX file in docs/src/content/docs/<category>/<slug>.mdx and add the page to docs/astro.config.mjs sidebar configuration.

Files:

  • docs/src/content/docs/pt-br/guides/security.mdx
  • docs/src/content/docs/guides/security.mdx
  • docs/src/content/docs/nb/guides/security.mdx
  • docs/src/content/docs/pt-br/guides/writing-rules.mdx
  • docs/src/content/docs/guides/writing-rules.mdx
  • docs/src/content/docs/nb/guides/writing-rules.mdx
  • docs/src/content/docs/nb/reference/rule-api.mdx
  • docs/src/content/docs/reference/rule-api.mdx
  • docs/src/content/docs/pt-br/reference/rule-api.mdx
docs/src/content/docs/**

📄 CodeRabbit inference engine (.archgate/adrs/GEN-001-documentation-site.md)

Do not create documentation content files outside docs/src/content/docs/; Starlight content must live in that exact directory structure.

Files:

  • docs/src/content/docs/pt-br/guides/security.mdx
  • docs/src/content/docs/guides/security.mdx
  • docs/src/content/docs/nb/guides/security.mdx
  • docs/src/content/docs/pt-br/guides/writing-rules.mdx
  • docs/src/content/docs/guides/writing-rules.mdx
  • docs/src/content/docs/nb/guides/writing-rules.mdx
  • docs/src/content/docs/nb/reference/rule-api.mdx
  • docs/src/content/docs/reference/rule-api.mdx
  • docs/src/content/docs/pt-br/reference/rule-api.mdx
docs/src/content/docs/**/*.{mdx,md}

📄 CodeRabbit inference engine (.archgate/adrs/GEN-002-docs-i18n.md)

docs/src/content/docs/**/*.{mdx,md}: For every English docs page under docs/src/content/docs/, create a translated file in each locale directory with the exact same relative path and filename, and ensure every locale file corresponds to an existing root file (no orphan translations).
When adding or modifying English documentation content, update the corresponding locale files in the same pull request.
Translate all user-facing prose in docs pages, including titles, descriptions, headings, paragraphs, list items, table text, and admonition content.
Translate user-visible text props in Starlight components such as <Card title="..."> and <LinkCard description="...">.
Keep code blocks, CLI commands, file paths, TypeScript identifiers, technical terms, import statements, component names, and link/href/slug attribute values in English.
Keep internal links unchanged and do not add locale prefixes (for example, use /guides/... rather than /pt-br/guides/...).
Preserve MDX curly-brace escaping (\{\}) in translated content.
Preserve Starlight component import statements identically in translated files.

Files:

  • docs/src/content/docs/pt-br/guides/security.mdx
  • docs/src/content/docs/guides/security.mdx
  • docs/src/content/docs/nb/guides/security.mdx
  • docs/src/content/docs/pt-br/guides/writing-rules.mdx
  • docs/src/content/docs/guides/writing-rules.mdx
  • docs/src/content/docs/nb/guides/writing-rules.mdx
  • docs/src/content/docs/nb/reference/rule-api.mdx
  • docs/src/content/docs/reference/rule-api.mdx
  • docs/src/content/docs/pt-br/reference/rule-api.mdx
docs/src/content/docs/pt-br/**/*.{mdx,md}

📄 CodeRabbit inference engine (.archgate/adrs/GEN-002-docs-i18n.md)

Use correct Portuguese diacritical marks in Brazilian Portuguese translations; never write unaccented Portuguese.

Files:

  • docs/src/content/docs/pt-br/guides/security.mdx
  • docs/src/content/docs/pt-br/guides/writing-rules.mdx
  • docs/src/content/docs/pt-br/reference/rule-api.mdx
docs/src/content/docs/nb/**/*.{mdx,md}

📄 CodeRabbit inference engine (.archgate/adrs/GEN-002-docs-i18n.md)

Use Norwegian Bokmål (not Nynorsk) for Norwegian translations, with the informal du form and correct Norwegian characters (æ, ø, å).

Files:

  • docs/src/content/docs/nb/guides/security.mdx
  • docs/src/content/docs/nb/guides/writing-rules.mdx
  • docs/src/content/docs/nb/reference/rule-api.mdx
tests/**/*.test.ts

📄 CodeRabbit inference engine (.archgate/adrs/ARCH-005-testing-standards.md)

tests/**/*.test.ts: Use Bun's built-in test runner (bun:test) for all test files, and place tests under tests/ mirroring the src/ directory structure with <module-name>.test.ts naming.
Use temp directories (mkdtemp) for filesystem tests, and clean them up in afterEach or afterAll.
Close external SDK instances (servers, clients, transports, connections) in afterEach or afterAll, managing their lifecycle in hooks rather than inside individual test bodies.
When a test creates a temporary git repository and runs git commit, configure local user.email and user.name immediately after git init.
Test public module interfaces, not private implementation details.
Use descriptive test names that explain the expected behavior.
Every runnable test()/it() must contain at least one expect() assertion; smoke tests must make the contract explicit with expect(() => fn()).not.toThrow() or await expect(promise).resolves.toBeUndefined().
Use test.skip, test.skipIf, or test.todo for intentionally empty or disabled tests; do not use bare return or empty callbacks to skip work.
If the first expect() is being added to a previously assertion-less test file, add expect to the bun:test import.
When mocking fetch in tests, assign directly to globalThis.fetch and restore the original or use mock.restore() afterward.
Wrap spyOn() and inline mockImplementation() usage in try/finally, or create and restore spies in hooks, so mockRestore() always runs.
Only raise a per-test timeout above the global bun test --timeout 60000; never set a shorter per-test timeout.
Mock first-party modules with import * as mod plus spyOn(mod, "fn"), not mock.module().
When a test needs to redirect user-scope paths, mock os.homedir() instead of relying on HOME/Bun.env.HOME; restore the spy in test hooks.
Do not depend on network access in unit tests.
Do not leave temp files after test runs.
Do not leave external SDK instances open after tests...

Files:

  • tests/engine/runner-ast-comments.test.ts
tests/**/*.ts

📄 CodeRabbit inference engine (.archgate/adrs/ARCH-009-platform-detection-helper.md)

In test files, use _resetPlatformCache() to simulate different platforms instead of mocking or mutating process.platform directly.

Files:

  • tests/engine/runner-ast-comments.test.ts
**/*.{test,spec}.ts

📄 CodeRabbit inference engine (.archgate/adrs/ARCH-022-ast-aware-rule-context.md)

AST context behavior MUST be covered by tests, including per-language parsing, guardrail behavior, interpreter failures, base-revision throw-versus-null semantics, comment extraction, original-source locations, and Ruby comment rejection.

Files:

  • tests/engine/runner-ast-comments.test.ts
src/engine/{runner,ast-support,js-parser}.ts

📄 CodeRabbit inference engine (.archgate/adrs/ARCH-022-ast-aware-rule-context.md)

TypeScript and JavaScript AST parsing MUST reuse the existing in-process meriyah parser. The duplicated parseModule() logic in rule-scanner.ts MUST be factored into one shared exported helper used by both the scanner and ctx.ast().

Files:

  • src/engine/js-parser.ts
  • src/engine/runner.ts
  • src/engine/ast-support.ts
src/helpers/rules-shim.ts

📄 CodeRabbit inference engine (.archgate/adrs/ARCH-022-ast-aware-rule-context.md)

The generated .rules.ts authoring shim MUST mirror the single RuleContext.ast() method and must not expose raw subprocess or filesystem primitives.

Files:

  • src/helpers/rules-shim.ts
docs/src/content/docs/reference/**/*.mdx

📄 CodeRabbit inference engine (.archgate/adrs/GEN-001-documentation-site.md)

Keep reference pages accurate to the CLI source code; when CLI APIs change, update the corresponding reference docs in the same PR.

Files:

  • docs/src/content/docs/reference/rule-api.mdx
src/formats/**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Use Zod schemas as the single source of truth; derive types with z.infer<> instead of defining separate interfaces, use safeParse(), and reuse AdrFrontmatterSchema.shape.* to avoid duplicating enums.

Files:

  • src/formats/rules.ts
src/formats/rules.ts

📄 CodeRabbit inference engine (.archgate/adrs/ARCH-022-ast-aware-rule-context.md)

RuleContext MUST expose exactly one ast(path, language, opts?) method supporting typescript, javascript, python, and ruby; do not add per-language AST methods.

Files:

  • src/formats/rules.ts
src/engine/runner.ts

📄 CodeRabbit inference engine (.archgate/adrs/ARCH-022-ast-aware-rule-context.md)

src/engine/runner.ts: createRuleContext() MUST implement ctx.ast() dispatch internally and execute guardrails in this order before subprocess invocation: safePath, language plausibility validation, interpreter availability probing, then guarded invocation.
Python and Ruby AST parsing MUST use Bun.spawn with array-based arguments; Python MUST run in isolated mode with -I, and interpreter candidates MUST be platform-appropriate and cached once per check invocation.
ctx.ast() MUST reject implausible language/file combinations before invoking Python or Ruby; for example, a Python request for config.json must fail without invoking the interpreter.
ctx.ast() MUST throw on missing interpreters and parse failures, with distinguishable error messages; it must never return null or another silent-failure sentinel.

Files:

  • src/engine/runner.ts
src/engine/{runner,ast-support,git-files}.ts

📄 CodeRabbit inference engine (.archgate/adrs/ARCH-022-ast-aware-rule-context.md)

Base-revision AST access MUST use the resolved merge base of --base and HEAD; git reads must remain in git-files.ts, while parsing must continue through the same AST guardrails and sanctioned helpers.

Files:

  • src/engine/runner.ts
  • src/engine/ast-support.ts
src/engine/{runner,ast-support}.ts

📄 CodeRabbit inference engine (.archgate/adrs/ARCH-022-ast-aware-rule-context.md)

src/engine/{runner,ast-support}.ts: ast(path, language, { rev: "base" }) MUST throw distinguishable errors when no base exists or the file did not exist at the base; fileAtBase(path) MUST return null for those absence cases.
With { comments: true }, ast() MUST attach structured comments as { type, value, loc }; comments are opt-in, Ruby comments are currently unsupported and must throw, and TypeScript/JavaScript locations must be derived from the original source.
The returned AST shape MUST remain language-native: ESTree for TypeScript/JavaScript, Python's standard ast representation, and Ruby's Ripper s-expression; do not normalize Python or Ruby into ESTree.

Files:

  • src/engine/runner.ts
  • src/engine/ast-support.ts
🧠 Learnings (2)
📚 Learning: 2026-07-02T16:03:33.031Z
Learnt from: rhuanbarreto
Repo: archgate/cli PR: 446
File: src/helpers/session-context-opencode.ts:81-100
Timestamp: 2026-07-02T16:03:33.031Z
Learning: For synchronous helper functions that use Bun’s sqlite sync API (i.e., they must remain synchronous), it’s acceptable to use `existsSync` from `node:fs` to check whether the SQLite database file exists. Avoid using `Bun.file(path).exists()` for this purpose because it’s async and would force the helper to become async (no equivalent synchronous Bun alternative). If the DB file is missing, throw/return a clear, actionable "No database found" error (per ARCH-006) rather than letting the sqlite open fail with a generic DB-open error.

Applied to files:

  • src/helpers/rules-shim.ts
📚 Learning: 2026-07-11T13:03:15.386Z
Learnt from: rhuanbarreto
Repo: archgate/cli PR: 467
File: .archgate/adrs/ARCH-011-consistent-project-root-resolution.md:0-0
Timestamp: 2026-07-11T13:03:15.386Z
Learning: For Markdown files formatted by oxfmt (especially ADRs), avoid inline code spans that contain escaped backticks, e.g. `\`...\`` inside a single `` `...` `` span. oxfmt may mis-parse these and, on re-format, can collapse spaces after later inline code spans on the same line, effectively removing any manually re-added spacing. Instead, rephrase the text so the message stays plain quoted text, and put any embedded command/fragment that needs code formatting (e.g., `archgate init`) in its own separate inline code span; keep surrounding punctuation/spacing outside the code span.

Applied to files:

  • .archgate/adrs/ARCH-022-ast-aware-rule-context.md
🪛 LanguageTool
docs/src/content/docs/pt-br/guides/security.mdx

[uncategorized] ~24-~24: Pontuação duplicada
Context: ...o import é rejeitado, em qualquer forma -- estático (import ... from), dinâmico ...

(DOUBLE_PUNCTUATION_XML)


[misspelling] ~35-~35: ‘Alias’ é uma forma do verbo ‘aliar’. O advérbio escreve-se “aliás”.
Context: ...ing(), process.dlopen()(em qualquer alias deprocess`) | Sim | | Acesso c...

(EASILY_CONFUSED_RARE_WORDS)


[grammar] ~36-~36: Possível erro de concordância de número.
Context: ...ess) | Sim | | Acesso computado a propriedades (Bun[variável], globalThis[variável]...

(GENERAL_NUMBER_AGREEMENT_ERRORS)


[uncategorized] ~37-~37: Conjunções alternativas ou disjuntivas devem ser separadas por vírgulas.
Context: ...Sim | | Atribuição a globalThis ou process.env | Sim | | Caracteres Unicode bidirecionais ou invisíveis ("Trojan Source") |...

(ALTERNATIVE_CONJUNCTIONS_COMMA)


[uncategorized] ~38-~38: Esta locução deve ser separada por vírgulas.
Context: ...u invisíveis ("Trojan Source") | Sim | Se qualquer um desses padrões ...

(VERB_COMMA_CONJUNCTION)


[style] ~42-~42: Para conferir mais clareza ao seu texto, busque usar uma linguagem mais concisa.
Context: ...ore de sintaxe já parseada, ele enxerga através de escapes: await import("\x6e...") reso...

(ATRAVES_DE_POR_VIA)


[uncategorized] ~44-~44: Se é uma abreviatura, falta um ponto. Se for uma expressão, coloque entre aspas.
Context: ...do você importa regras de terceiros com archgate adr import, cada .rules.ts é escaneado -- com u...

(ABREVIATIONS_PUNCTUATION)


[uncategorized] ~50-~50: Esta conjunção deve ser separada por vírgulas e só deve ser utilizada no início duma frase para efeitos de estilo.
Context: ...ext` é somente leitura. Regras reportam violações mas não podem modificar o codebase. - **Esc...

(VERB_COMMA_CONJUNCTION)


[style] ~51-~51: “segundos de tempo” é um pleonasmo. É preferível dizer “segundos”
Context: ...dos** -- cada regra é encerrada após 30 segundos de tempo de execução. - Afetar outras regras...

(PT_REDUNDANCY_REPLACE_SEGUNDOS_DE_TEMPO)


[uncategorized] ~52-~52: Esta conjunção deve ser separada por vírgulas e só deve ser utilizada no início duma frase para efeitos de estilo.
Context: ...* -- regras de ADRs diferentes rodam em paralelo mas não compartilham estado mutável através...

(VERB_COMMA_CONJUNCTION)

docs/src/content/docs/pt-br/guides/writing-rules.mdx

[uncategorized] ~179-~179: Pontuação duplicada
Context: ...falha de parse ou interpretador ausente -- nunca retorna null. ```typescript co...

(DOUBLE_PUNCTUATION_XML)


[uncategorized] ~194-~194: Se é uma abreviatura, falta um ponto. Se for uma expressão, coloque entre aspas.
Context: ...ase do git** -- a base de merge entre a ref --base e HEAD. Retorna null quand...

(ABREVIATIONS_PUNCTUATION)


[uncategorized] ~194-~194: Pontuação duplicada
Context: ...lquando nenhuma base é resolvida (sem--base`) ou o arquivo não existia na base ...

(DOUBLE_PUNCTUATION_XML)


[uncategorized] ~452-~452: Pontuação duplicada
Context: ... uma alteração é apenas de documentação -- a estrutura executável permanece intoca...

(DOUBLE_PUNCTUATION_XML)


[uncategorized] ~480-~480: Se é uma abreviatura, falta um ponto. Se for uma expressão, coloque entre aspas.
Context: ...} satisfies RuleSet; ``` Isso roda com archgate check --base <ref>; sem uma base, `ctx.changedFiles` fic...

(ABREVIATIONS_PUNCTUATION)


[uncategorized] ~484-~484: Se é uma abreviatura, falta um ponto. Se for uma expressão, coloque entre aspas.
Context: ...m tokens estruturados (type, value, loc) em vez de regex linha a linha. As pos...

(ABREVIATIONS_PUNCTUATION)


[uncategorized] ~499-~499: Pontuação duplicada
Context: ...ent.loc.start.line, }); } } ``` :::note Arquivos de regra podem importar ap...

(DOUBLE_PUNCTUATION_XML)


[uncategorized] ~500-~500: Esta locução deve ser separada por vírgulas, e só deve ser utilizada no início duma frase para efeitos de estilo.
Context: ...e:crypto`. Qualquer coisa que uma regra precise além disso -- parsear uma linguagem, ler uma revis...

(VERB_COMMA_CONJUNCTION)


[uncategorized] ~501-~501: Pontuação duplicada
Context: ...des/security/) para entender o porquê. ::: ## Níveis de severidade Cada regra po...

(DOUBLE_PUNCTUATION_XML)

.archgate/adrs/ARCH-022-ast-aware-rule-context.md

[style] ~108-~108: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...leAtBase()reports them asnull. - **DON'T** expect a comments` array without ...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[style] ~109-~109: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ... it is opt-in and absent otherwise. - DON'T request { comments: true } for `...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[style] ~110-~110: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...ipper.lex) is a deferred follow-up. - DON'T treat the TS/JS comment scan as re...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[style] ~130-~130: Consider an alternative for the overused word “exactly”.
Context: ...t is a mild departure from "the tree is exactly the language-native shape," particularl...

(EXACTLY_PRECISELY)

docs/src/content/docs/pt-br/reference/rule-api.mdx

[uncategorized] ~164-~164: Se é uma abreviatura, falta um ponto. Se for uma expressão, coloque entre aspas.
Context: ...comparação** -- a base de merge entre a ref --base e HEAD, o mesmo commit contr...

(ABREVIATIONS_PUNCTUATION)


[uncategorized] ~222-~222: Pontuação duplicada
Context: ...ileatbase) em vez da árvore de trabalho -- tudo o mais (formato de retorno, contra...

(DOUBLE_PUNCTUATION_XML)


[uncategorized] ~240-~240: Pontuação duplicada
Context: ...e retornada carrega um array comments -- dados estruturados de comentário para r...

(DOUBLE_PUNCTUATION_XML)


[uncategorized] ~267-~267: Se é uma abreviatura, falta um ponto. Se for uma expressão, coloque entre aspas.
Context: ...é uma vantagem deliberada em relação ao loc da própria árvore, que é relativo ao t...

(ABREVIATIONS_PUNCTUATION)


[uncategorized] ~267-~267: Pontuação duplicada
Context: ...anspilado para TypeScript (veja AstNode): os comentários são varridos a partir d...

(DOUBLE_PUNCTUATION_XML)


[uncategorized] ~267-~267: Se é uma abreviatura, falta um ponto. Se for uma expressão, coloque entre aspas.
Context: ...-fonte antes da transpilação, então seu loc nunca diverge. Comentários em Python s...

(ABREVIATIONS_PUNCTUATION)


[uncategorized] ~267-~267: Pontuação duplicada
Context: ... Python são sempre type: "line" (#) -- Python não tem comentários de bloco, e ...

(DOUBLE_PUNCTUATION_XML)


[typographical] ~267-~267: Símbolo sem par: “"” aparentemente está ausente
Context: ... tem comentários de bloco, e docstrings """ são expressões de string na árvore, ...

(UNPAIRED_BRACKETS)


[locale-violation] ~267-~267: “template” é um estrangeirismo. É preferível dizer “modelo”.
Context: ...cript reconhece literais de string e de template, mas não rastreia literais de expressão...

(PT_BARBARISMS_REPLACE_TEMPLATE)


[style] ~267-~267: “dentro de um” é uma expressão prolixa. É preferível dizer “num” ou “em um”.
Context: ...lar, então um delimitador de comentário dentro de um literal regex é um ponto cego conhecido...

(PT_WORDINESS_REPLACE_DENTRO_DE_UM)

🔇 Additional comments (16)
src/formats/rules.ts (1)

70-105: LGTM!

Also applies to: 129-130, 153-154, 184-191, 207-223

src/helpers/rules-shim.ts (1)

75-102: LGTM!

Also applies to: 126-127, 150-151, 178-184, 199-215

.archgate/adrs/ARCH-022-ast-aware-rule-context.md (1)

51-72: LGTM!

Also applies to: 90-94, 106-110, 119-120, 130-130, 140-143, 156-159, 179-179

docs/public/llms-full.txt (1)

2084-2115: LGTM!

Also applies to: 2195-2199, 2881-2905, 3153-3204, 5202-5204, 5293-5316, 5336-5343, 5355-5414, 5516-5517

docs/src/content/docs/reference/rule-api.mdx (1)

67-69: LGTM!

Also applies to: 158-181, 201-208, 220-279, 382-383

src/engine/ast-support.ts (2)

303-338: The existing secure temporary-file comment still applies.

The PID/counter filename and non-exclusive write retain the previously reported symlink and source-disclosure risk.


10-43: LGTM!

Also applies to: 73-141, 275-301, 340-387

docs/src/content/docs/guides/writing-rules.mdx (1)

177-201: LGTM!

Also applies to: 482-501

docs/src/content/docs/pt-br/reference/rule-api.mdx (1)

67-69: LGTM!

Also applies to: 158-208, 220-226, 236-279, 382-383

tests/engine/runner-ast-comments.test.ts (1)

1-97: LGTM!

Also applies to: 125-261

docs/src/content/docs/nb/guides/writing-rules.mdx (1)

177-201: LGTM!

Also applies to: 482-502

docs/src/content/docs/nb/reference/rule-api.mdx (2)

158-180: LGTM!

Also applies to: 201-208, 382-383


67-69: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Add opts?: AstOptions to the AstLanguage overload in src/formats/rules.ts.
Union-typed callers can’t pass the documented options unless this fallback signature includes opts, and the docs already reflect that API.

Suggested change
-ast(path: string, language: AstLanguage): Promise<AstNode>;
+ast(path: string, language: AstLanguage, opts?: AstOptions): Promise<AstNode>;
			> Likely an incorrect or invalid review comment.
docs/src/content/docs/pt-br/guides/security.mdx (1)

23-53: LGTM!

Also applies to: 133-137

docs/src/content/docs/pt-br/guides/writing-rules.mdx (1)

177-201: LGTM!

Also applies to: 482-502

src/engine/runner.ts (1)

22-29: LGTM!

Also applies to: 45-45, 138-221, 227-393

Comment thread docs/src/content/docs/guides/security.mdx Outdated
Comment thread docs/src/content/docs/guides/writing-rules.mdx Outdated
Comment thread docs/src/content/docs/guides/writing-rules.mdx Outdated
Comment thread docs/src/content/docs/nb/reference/rule-api.mdx
Comment thread docs/src/content/docs/pt-br/guides/security.mdx Outdated
Comment thread docs/src/content/docs/pt-br/reference/rule-api.mdx
Comment thread src/engine/glob-utils.ts
Comment thread src/engine/js-parser.ts
Comment thread src/engine/runner.ts Outdated
Comment thread tests/engine/runner-ast-comments.test.ts
…dent

The "review untrusted rules" note cited Reflect.get(Bun, "spawn") as a
residual bypass. The scanner-hardening PR (#481) closes reflective access,
so that example would become stale. Replace it with the durable residual —
anything built at runtime (a computed property name, a code string) is opaque
to a source scan — which holds regardless of which PR merges first. en + nb +
pt-br (GEN-002). llms-full regenerated.

Signed-off-by: Rhuan Barreto <rhuan@barreto.work>
@cursor

cursor Bot commented Jul 16, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_87341365-b885-424e-b5b9-90956358f7c8)

rhuanbarreto added a commit that referenced this pull request Jul 16, 2026
…x escapes (#481)

## Summary

The module allowlist (#477) stopped rule files from *importing*
dangerous modules — but `Bun`, `process`, and the global object are
**live globals** in the rule runtime, reachable with no import at all.
The scanner blocked the shapes `Bun.spawn` and `Bun[x]`, which is the
same losing game a module denylist was. Two fire-tested RCEs walked
straight around it, both reported `"pass": true` by `archgate check`:

```js
// (1) reflection / aliasing / destructuring / global-object aliases
Reflect.get(Bun, "spawn")([...]);        // also: const {spawn}=Bun; const B=Bun;
                                          //       globalThis.Bun.spawn / global.Bun.spawn / self.Bun.spawn
// (2) Function constructor via the .constructor chain === eval — bypasses even the module allowlist
(() => {}).constructor("return import('node:child_process')")();
```

## The fix — apply the allowlist philosophy to globals

Block **naming the capability source**, not the shapes of using it. Any
code reference to `Bun`, `process`, `globalThis`, `global`, `self`,
`Reflect`, `eval`, `Function`, `fetch`, `WebSocket`, `XMLHttpRequest`,
`EventSource`, or `require` is refused — in any position except a
property-key slot (`foo.process`, `{ process: 1 }` name a property, not
the global, and are fine). Blocking the *identifier* closes aliasing,
destructuring, and reflection in one rule. `global`/`self` are included
because Bun binds the global object under all three names.

Additionally block **`.constructor`** access (dotted + computed-literal)
on any receiver — the property-chain route to the `Function` constructor
(= eval).

**This simplified the scanner** (net **−157 lines**): the per-shape
`Bun`/`process` member denylists and the separate
`eval`/`Function`/`fetch`/`require` call checks are gone, subsumed by
the single identifier block. First-party and imported scans **converge**
— `scanImportedRuleSource()` now delegates — because a first-party rule
runs with full privilege too and a malicious PR can add one.

An audit confirmed **zero** of the repo's own `.rules.ts` reference
these globals as executable code (every mention is a searched-for
string), so there are **no false positives**.

## Known residual (documented + regression-tested)

A property name built at runtime — `const c = "constructor"; (() =>
{})[c]` — is unknowable to a static scanner, and blocking *all* computed
access would reject ordinary `arr[i]`/`obj[key]`. That route to eval is
left to **execution-time isolation**; the scan is defense-in-depth that
raises the bar from a trivial one-liner to runtime string construction,
not a jail. A test asserts this residual explicitly so it's a
deliberate, known gap.

## Test plan

- [x] `tests/engine/rule-scanner-escapes.test.ts` — new "reflective and
aliased access to runtime globals" block: aliasing, destructuring,
`Reflect.get`, the three global-object aliases,
`Object.getOwnPropertyDescriptor`, the Function-constructor chain
(dotted + computed-literal), eval/Function/fetch/require aliasing; plus
"legitimate global-adjacent code still passes" (`Object.keys`, a
property named `process`, a normal `ctx`-only rule) and the explicit
computed-variable residual
- [x] Fire test — both RCEs now refused end-to-end (`"pass": false`), no
payload written
- [x] `bun run validate` — 44/44 ADR rules (dogfooded on the repo's own
rules), 1527 tests, lint, typecheck, build

> [!WARNING]
> **BREAKING:** rule files may no longer name
`Bun`/`process`/`globalThis`/etc., even for benign reads (`Bun.env`,
`process.platform`, `Bun.Glob`). Rules interact with the project only
through `ctx`; a rule that genuinely needs such data is a `ctx` feature
request. Small false-positive surface: a rule using one of these names
as a local variable (`self`, `global`) must rename.

## ADR

Amends
[ARCH-024](https://github.com/archgate/cli/blob/main/.archgate/adrs/ARCH-024-rule-file-sandbox-boundary.md),
clause 4: rewrites the "escapes that name no module" model to "block
naming the global," documents the `.constructor` closure, the scan
convergence, and the computed-variable-key residual as the
static-analysis limit that execution-time isolation answers.

## Doc coordination

`guides/security.mdx` currently names `Reflect.get(Bun,"spawn")` as a
residual bypass (on `main`, and reworded in #480's rewrite). This PR
closes that specific residual, so that note should be updated to reflect
the *new* residual (a runtime-computed `.constructor` key). To avoid
editing soon-replaced text and redundant trilingual i18n churn here,
I'll make that doc update on the #480 branch (which owns the rewritten
security section) so the two don't conflict — flagging for whoever
sequences the merges.

---------

Signed-off-by: Rhuan Barreto <rhuan@barreto.work>
@archgatebot archgatebot Bot mentioned this pull request Jul 16, 2026
@cursor

cursor Bot commented Jul 16, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_42f369e5-93d1-4cb8-b26f-ddae827a4caf)

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
docs/public/llms-full.txt (1)

5362-5364: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Align all base-AST guidance with ARCH-022.

The documentation conflates ctx.changedFiles detection with availability of a parseable comparison base, and it shows an unguarded { rev: "base" } call even though ARCH-022 requires that API to throw for unresolved bases and added files.

  • docs/public/llms-full.txt#L5362-L5364: check fileAtBase(file) and require a resolved base before calling base AST parsing.
  • docs/public/llms-full.txt#L3183-L3183: replace the “changedFiles is empty” claim with the actual no-base/throw behavior.
🤖 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 `@docs/public/llms-full.txt` around lines 5362 - 5364, Update
docs/public/llms-full.txt at lines 5362-5364 to guard base AST parsing with
fileAtBase(file), calling ctx.ast(..., { rev: "base" }) only when a resolved
base exists; update lines 3183-3183 to describe the actual no-base behavior,
including that base parsing throws for unresolved bases or added files rather
than claiming changedFiles is empty.

Source: Path instructions

docs/src/content/docs/guides/security.mdx (1)

22-22: 🔒 Security & Privacy | 🟠 Major

Correct the runtime-sandbox wording in both locales.

Rules execute in-process with the invoking user’s privileges; the restricted RuleContext API and static scanner are the relevant controls, not a runtime sandbox.

  • docs/src/content/docs/guides/security.mdx#L22-L22: replace “runtime sandbox” with accurate RuleContext/static-scanner wording.
  • docs/src/content/docs/nb/guides/security.mdx#L22-L22: apply the equivalent correction in Norwegian Bokmål.

Violates ARCH-024.

🤖 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 `@docs/src/content/docs/guides/security.mdx` at line 22, Update the security
wording in docs/src/content/docs/guides/security.mdx at lines 22-22 to remove
the runtime-sandbox claim and describe the restricted RuleContext API and static
scanner as the relevant controls; apply the equivalent correction in Norwegian
Bokmål at docs/src/content/docs/nb/guides/security.mdx lines 22-22.

Source: Path instructions

🤖 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.

Outside diff comments:
In `@docs/public/llms-full.txt`:
- Around line 5362-5364: Update docs/public/llms-full.txt at lines 5362-5364 to
guard base AST parsing with fileAtBase(file), calling ctx.ast(..., { rev: "base"
}) only when a resolved base exists; update lines 3183-3183 to describe the
actual no-base behavior, including that base parsing throws for unresolved bases
or added files rather than claiming changedFiles is empty.

In `@docs/src/content/docs/guides/security.mdx`:
- Line 22: Update the security wording in
docs/src/content/docs/guides/security.mdx at lines 22-22 to remove the
runtime-sandbox claim and describe the restricted RuleContext API and static
scanner as the relevant controls; apply the equivalent correction in Norwegian
Bokmål at docs/src/content/docs/nb/guides/security.mdx lines 22-22.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 68cdbad1-b224-419f-8428-ed06ce5b32fe

📥 Commits

Reviewing files that changed from the base of the PR and between 3912af3 and 0b3c7aa.

📒 Files selected for processing (4)
  • docs/public/llms-full.txt
  • docs/src/content/docs/guides/security.mdx
  • docs/src/content/docs/nb/guides/security.mdx
  • docs/src/content/docs/pt-br/guides/security.mdx
📜 Review details
⏰ Context from checks skipped due to timeout. (3)
  • GitHub Check: Analyze (csharp)
  • GitHub Check: Smoke Test (Windows) / Windows
  • GitHub Check: Cloudflare Pages
🧰 Additional context used
📓 Path-based instructions (7)
docs/src/content/docs/**/*.mdx

📄 CodeRabbit inference engine (.archgate/adrs/GEN-001-documentation-site.md)

docs/src/content/docs/**/*.mdx: Use MDX (.mdx) for all content pages under docs/src/content/docs/.
Escape literal curly braces in MDX when showing template syntax; do not use bare {} in prose or code-fence labels.

Files:

  • docs/src/content/docs/guides/security.mdx
  • docs/src/content/docs/nb/guides/security.mdx
  • docs/src/content/docs/pt-br/guides/security.mdx
{docs/src/content/docs/**/*.mdx,docs/astro.config.mjs}

📄 CodeRabbit inference engine (.archgate/adrs/GEN-001-documentation-site.md)

When adding a new documentation page, create the MDX file in docs/src/content/docs/<category>/<slug>.mdx and add the page to docs/astro.config.mjs sidebar configuration.

Files:

  • docs/src/content/docs/guides/security.mdx
  • docs/src/content/docs/nb/guides/security.mdx
  • docs/src/content/docs/pt-br/guides/security.mdx
docs/src/content/docs/**

📄 CodeRabbit inference engine (.archgate/adrs/GEN-001-documentation-site.md)

Do not create documentation content files outside docs/src/content/docs/; Starlight content must live in that exact directory structure.

Files:

  • docs/src/content/docs/guides/security.mdx
  • docs/src/content/docs/nb/guides/security.mdx
  • docs/src/content/docs/pt-br/guides/security.mdx
docs/src/content/docs/**/*.{mdx,md}

📄 CodeRabbit inference engine (.archgate/adrs/GEN-002-docs-i18n.md)

docs/src/content/docs/**/*.{mdx,md}: For every English docs page under docs/src/content/docs/, create a translated file in each locale directory with the exact same relative path and filename, and ensure every locale file corresponds to an existing root file (no orphan translations).
When adding or modifying English documentation content, update the corresponding locale files in the same pull request.
Translate all user-facing prose in docs pages, including titles, descriptions, headings, paragraphs, list items, table text, and admonition content.
Translate user-visible text props in Starlight components such as <Card title="..."> and <LinkCard description="...">.
Keep code blocks, CLI commands, file paths, TypeScript identifiers, technical terms, import statements, component names, and link/href/slug attribute values in English.
Keep internal links unchanged and do not add locale prefixes (for example, use /guides/... rather than /pt-br/guides/...).
Preserve MDX curly-brace escaping (\{\}) in translated content.
Preserve Starlight component import statements identically in translated files.

Files:

  • docs/src/content/docs/guides/security.mdx
  • docs/src/content/docs/nb/guides/security.mdx
  • docs/src/content/docs/pt-br/guides/security.mdx
**

⚙️ CodeRabbit configuration file

**: This project uses Archgate — an AI governance framework based on
Architecture Decision Records (ADRs). The ADRs in .archgate/adrs/
are the authoritative rules for this codebase. Each ADR has a companion
.rules.ts file with automated checks that run via archgate check.

When reviewing, you must:

  1. Treat ADR violations as blocking issues, not suggestions.
  2. Cite the specific ADR ID when flagging a violation (e.g., "Violates ARCH-006").
  3. Focus on semantic and contextual violations that automated rules cannot catch —
    the .rules.ts files already cover syntactic/structural patterns.
  4. If you are unsure whether something violates an ADR, flag it as a question
    rather than approving it.

Files:

  • docs/src/content/docs/guides/security.mdx
  • docs/src/content/docs/nb/guides/security.mdx
  • docs/public/llms-full.txt
  • docs/src/content/docs/pt-br/guides/security.mdx
docs/src/content/docs/nb/**/*.{mdx,md}

📄 CodeRabbit inference engine (.archgate/adrs/GEN-002-docs-i18n.md)

Use Norwegian Bokmål (not Nynorsk) for Norwegian translations, with the informal du form and correct Norwegian characters (æ, ø, å).

Files:

  • docs/src/content/docs/nb/guides/security.mdx
docs/src/content/docs/pt-br/**/*.{mdx,md}

📄 CodeRabbit inference engine (.archgate/adrs/GEN-002-docs-i18n.md)

Use correct Portuguese diacritical marks in Brazilian Portuguese translations; never write unaccented Portuguese.

Files:

  • docs/src/content/docs/pt-br/guides/security.mdx
🧠 Learnings (1)
📓 Common learnings
Learnt from: CR
Repo: archgate/cli

Timestamp: 2026-07-16T14:15:19.264Z
Learning: Any proposal to add a bundled multi-language parser or grammar must be documented in a separate ADR, reviewed under the dependency-approval process, and approved before implementation.
🔇 Additional comments (4)
docs/public/llms-full.txt (1)

2084-2115: LGTM!

Also applies to: 2195-2199, 2881-2905, 3153-3182, 3185-3204, 5202-5204, 5293-5316, 5336-5343, 5355-5361, 5365-5369, 5373-5414, 5516-5517

docs/src/content/docs/guides/security.mdx (1)

24-53: LGTM!

Also applies to: 135-137

docs/src/content/docs/nb/guides/security.mdx (1)

24-46: LGTM!

Also applies to: 135-137

docs/src/content/docs/pt-br/guides/security.mdx (1)

48-53: LGTM!

Also applies to: 135-137

…l order

Addresses CodeRabbit review on PR #480:

- ast-support: write base-revision temp sources into a per-call private
  directory (mkdtempSync, 0700) with exclusive create (`wx`, mode 0600),
  and remove the whole directory on cleanup — closes the predictable-path
  symlink/disclosure risk on shared temp dirs.
- runner: resolve the merge base once and reuse that SHA for changedFiles,
  so the change set and base AST reads can never diff different commits.
- runner: move the Ruby-comment feature guard after the language
  plausibility guardrail (ARCH-022 ordering).
- glob-utils: matchLines uses a cloned regex + exec() so a global (`/g`)
  pattern reports the true column instead of collapsing to 1.
- js-parser: line comments stop on `\r` too, so `\r\n` files don't leave a
  trailing carriage return in the comment value.

Tests: Bun.write over writeFileSync; recursive location-free AST compare;
JavaScript + Ruby base-revision matrix cases; template-literal comment
markers; matchLines column regressions.

Docs (en/nb/pt-br): teach a location-free structural AST comparison (raw
serialization shifts with loc/lineno), guard base-parse examples with
fileAtBase(), correct the no-base explanation (fileAtBase null, not empty
changedFiles), and qualify the scanner as a static gate rather than a
complete runtime sandbox.

Signed-off-by: Rhuan Barreto <rhuan@barreto.work>
@cursor

cursor Bot commented Jul 16, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_4fd214c7-5741-4e4e-9c21-c473e9fdc80b)

…s JSDoc

The `AstOptions` doc claimed a comment-only edit "yields an identical
tree", but node positions (loc/range, lineno/col_offset) remain in the
tree, so a raw comparison differs. Match the guide docs: compare a
location-free projection. No behavior change.

Signed-off-by: Rhuan Barreto <rhuan@barreto.work>
@cursor

cursor Bot commented Jul 16, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_f81db83c-83de-4881-8c34-2bee84a08746)

The three literal-language overloads on RuleContext.ast() (typescript |
javascript, python, ruby) all accept opts?: AstOptions, but the
language-agnostic catch-all did not. A caller holding a dynamically-typed
AstLanguage — not a string literal — resolves to that catch-all and got
no editor completion for opts, and could not pass { rev: "base" } or
{ comments: true } to it at all.

Widened the catch-all in both src/formats/rules.ts and
src/helpers/rules-shim.ts (which mirror each other exactly), and updated
ARCH-022's single-ast-method rule to enforce the new byte-exact
three-parameter signature instead of the old two-parameter one.
Purely additive (opts stays optional) — no call site can break.

Fire-tested: reverting the catch-all to the old signature makes the rule
fail with the new message; restoring it passes 4/4 ARCH-022 checks.

Signed-off-by: Rhuan Barreto <rhuan@barreto.work>
@cursor

cursor Bot commented Jul 16, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_2f40b46d-5586-42cd-b032-ead63b964566)

@rhuanbarreto
rhuanbarreto merged commit 49feb1f into main Jul 16, 2026
24 checks passed
@rhuanbarreto
rhuanbarreto deleted the claude/ctx-ast-base-and-comments branch July 16, 2026 15:07
rhuanbarreto pushed a commit that referenced this pull request Jul 16, 2026
# archgate

## [0.49.0](v0.48.4...v0.49.0)
(2026-07-16)

### ⚠ BREAKING CHANGES

* **engine:** block naming runtime globals to close reflective sandbox
escapes (#481)
* **engine:** close rule-file sandbox escapes via module allowlist
(#477)
* **cli:** emit lean agent-facing JSON payloads by default (#476)

### Features

* **cli:** emit lean agent-facing JSON payloads by default
([#476](#476))
([04affa3](04affa3))
* **engine:** base-revision + comment access for ctx.ast() (closes
[#479](#479))
([#480](#480))
([49feb1f](49feb1f)),
closes [#477](#477)

### Bug Fixes

* **engine:** block naming runtime globals to close reflective sandbox
escapes ([#481](#481))
([6666df2](6666df2)),
closes [#477](#477)
[#480](#480)
* **engine:** close rule-file sandbox escapes via module allowlist
([#477](#477))
([18db14d](18db14d))

---
This PR was generated with
[simple-release](https://github.com/TrigenSoftware/simple-release).

<details>
<summary>📄 Cheatsheet</summary>
<br>



You can configure the bot's behavior through a pull request comment
using the `!simple-release/set-options` command.

### Command Format

````md
!simple-release/set-options

```json
{
  "bump": {},
  "publish": {}
}
```
````

### Useful Parameters

#### Bump

| Parameter | Type | Description |
|-----------|------|-------------|
| `version` | `string` | Force set specific version |
| `as` | `'major' \| 'minor' \| 'patch' \| 'prerelease'` | Release type
|
| `prerelease` | `string` | Pre-release identifier (e.g., "alpha",
"beta") |
| `firstRelease` | `boolean` | Whether this is the first release |
| `skip` | `boolean` | Skip version bump |
| `byProject` | `Record<string, object>` | Per-project bump options for
monorepos |

#### Publish

| Parameter | Type | Description |
|-----------|------|-------------|
| `skip` | `boolean` | Skip publishing |
| `access` | `'public' \| 'restricted'` | Package access level |
| `tag` | `string` | Tag for npm publication |

### Usage Examples

#### Force specific version

````md
!simple-release/set-options

```json
{
  "bump": {
    "version": "2.0.0"
  }
}
```
````

#### Force major bump

````md
!simple-release/set-options

```json
{
  "bump": {
    "as": "major"
  }
}
```
````

#### Create alpha pre-release

````md
!simple-release/set-options

```json
{
  "bump": {
    "prerelease": "alpha"
  }
}
```
````

#### Publish with specific access and tag

````md
!simple-release/set-options

```json
{
  "bump": {
    "prerelease": "beta"
  },
  "publish": {
    "access": "public",
    "tag": "beta"
  }
}
```
````

### Access Restrictions

The command can only be used by users with permissions:
- repository owner
- organization member
- collaborator

### Notes

- The last comment with `!simple-release/set-options` command takes
priority
- JSON must be valid, otherwise the command will be ignored
- Parameters apply only to the current release execution
- The command can be updated by editing the comment or adding a new one


</details>

<!--
  Please do not edit this comment.
  simple-release-pull-request: true
  simple-release-branch-from: release
  simple-release-branch-to: main
-->

Signed-off-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ctx.ast(): add base-revision access so sandbox hardening (#477) doesn't strand legitimate rules

1 participant