Skip to content

feat(engine): support { comments: true } for ctx.ast() Ruby#485

Merged
rhuanbarreto merged 5 commits into
mainfrom
feat/ruby-ast-comments
Jul 17, 2026
Merged

feat(engine): support { comments: true } for ctx.ast() Ruby#485
rhuanbarreto merged 5 commits into
mainfrom
feat/ruby-ast-comments

Conversation

@rhuanbarreto

@rhuanbarreto rhuanbarreto commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Closes #484

Summary

ctx.ast(path, "ruby", { comments: true }) now returns the Ripper.sexp tree with a comments: CommentToken[] array attached, instead of throwing commentsUnsupportedError. Ruby was the last AstLanguage without comment access.

Design decisions

  • Two-pass, mirroring Python — a new RUBY_AST_WITH_COMMENTS_PROGRAM in src/engine/ast-support.ts runs Ripper.sexp for the tree plus a second, independent Ripper.lex pass for comments, emitting the exact {"_tree", "comments"} envelope the Python with-comments serializer uses. The shared finalizeAstResult() unwrap now handles both languages.
  • Line comments:on_comment lex events become type: "line" tokens: leading # stripped, trailing newline chomped, loc from the (line, col) lex tuple with the end column at the chomped token end — matching Python/TS-JS value and position semantics.
  • =begin/=end block comments are INCLUDED (explicit decision, not scoped out): the :on_embdoc_beg / :on_embdoc / :on_embdoc_end events of each region are combined into ONE type: "block" token whose value is the inner content (marker lines stripped, analogous to TS/JS stripping /* */) and whose loc spans the =begin line through the =end line.
  • Graceful lex degradation — the comment pass is wrapped in rescue StandardError, resetting to an empty comment list, so a lex failure on otherwise-parseable source never fails the whole parse (matches Python's tokenizer-error fallback).
  • Return shape — Ruby's tree is a JSON array, so comments rides on the returned sexp as a non-index property. A new RubyAstProgram root type (extends Array<unknown>, optional comments) types this in src/formats/rules.ts and the generated rules shim, mirroring EsTreeProgram/PythonAstModule.
  • Dead code removed — the early throw in runner.ts is gone, and commentsUnsupportedError is deleted entirely: the Ruby guard was its only remaining call site.
  • Character-offset columnsRipper.lex reports columns as byte offsets, which drift from the Python/TS character convention on non-ASCII lines. The serializer converts them to character offsets (via a byteslice of the source line), so comment loc columns share one unit across all four languages; the sexp tree's own node positions stay byte-based, as Ripper emits them. Pinned by a non-ASCII end-to-end test.
  • LF-normalized block values — Ruby's Windows text-mode read strips \r from CRLF files while POSIX preserves it, so the same checked-in file would have produced platform-dependent =begin/=end values. Block value line endings are now normalized to LF on every OS, pinned by a CRLF end-to-end test.
  • ARCH-022 updated — the ADR's "Ruby { comments: true } throws / deferred follow-up" prose (this issue IS that follow-up) is replaced with the shipped behavior, including the column-unit and LF-normalization conventions.

Acceptance criteria

  • ctx.ast(path, "ruby", { comments: true }) returns the tree with comments: CommentToken[] instead of throwing — covered by tests/engine/runner-ast-comments.test.ts through runChecks.
  • Comment value has the leading # stripped (and trailing newline chomped), matching Python/TS-JS convention.
  • A lex failure on otherwise-parseable source degrades to an empty comment list rather than failing the parse (rescue StandardError in the serializer, mirroring Python's tokenize fallback). The fallback path itself is not unit-tested — same coverage level as the Python program, since a deterministic Ripper.lex-only failure is not readily constructible.
  • Explicit decision on =begin/=end: included as type: "block", one token per region, marker lines stripped, loc spanning =begin through =end — documented and tested.
  • runner.ts's early throw removed; commentsUnsupportedError deleted (Ruby was its last case; knip is clean).
  • Documented in docs/*/reference/rule-api.mdx in all three locales (en, nb, pt-br); llms-full.txt regenerated.
  • Test coverage: fixtures with # line comments (leading, trailing, and a # inside a string that must NOT match) and an =begin/=end block verify value and loc for both token types, at both the serializer level (tests/engine/ast-support.test.ts) and through runChecks (tests/engine/runner-ast-comments.test.ts). Tests skip when no ruby interpreter is on PATH, following the existing pattern.

Validation

bun run validate passes (lint, typecheck, format:check, tests, ADR check, knip, build check); archgate check reports 44/44 rules passing.

Closes #484

Mirror Python's two-pass approach: RUBY_AST_WITH_COMMENTS_PROGRAM runs
Ripper.sexp for the tree plus a second Ripper.lex pass for comments,
emitting the same {_tree, comments} envelope the Python with-comments
serializer uses. # comments become type "line" tokens (leading #
stripped, newline chomped); each =begin/=end region becomes ONE type
"block" token with the marker lines stripped and loc spanning =begin
through =end. A Ripper.lex failure on otherwise-parseable source
degrades to an empty comment list instead of failing the parse.

Ruby's tree is an array, so the comments array rides on the returned
sexp as a non-index property (typed via the new RubyAstProgram root
type, mirrored in the rules shim). The early commentsUnsupportedError
throw in runner.ts is removed and the helper deleted — Ruby was its
last remaining case.

Docs updated in all three locales; llms-full.txt regenerated.

Signed-off-by: Rhuan Barreto <rhuan@barreto.work>
@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: 19 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: 88ef2bd7-f5f4-4017-8474-3de5fb2e36dd

📥 Commits

Reviewing files that changed from the base of the PR and between fc9a217 and 1d94f0d.

📒 Files selected for processing (10)
  • docs/public/llms-full.txt
  • docs/src/content/docs/nb/reference/rule-api.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/runner.ts
  • src/formats/rules.ts
  • src/helpers/rules-shim.ts
  • tests/engine/ast-support.test.ts
  • tests/engine/runner-ast-comments.test.ts
📝 Walkthrough

Walkthrough

Ruby AST parsing now supports { comments: true } through a second Ripper.lex pass. Line and =begin/=end block comments are returned with normalized values and character-based locations, attached to the root sexp array. Runtime selection, result finalization, public Ruby AST types, generated declarations, ADRs, and localized documentation are updated. Tests cover extraction, locations, non-ASCII text, CRLF normalization, syntax errors, and behavior without comment collection.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly states the main change: Ruby support for ctx.ast(..., { comments: true }).
Description check ✅ Passed The description directly matches the Ruby comment-support changes and design details.
Linked Issues check ✅ Passed The changes satisfy #484: Ruby comments now use a two-pass Ripper.sexp/Ripper.lex flow with fallback, docs, types, and tests.
Out of Scope Changes check ✅ Passed The extra ADR and llms-full doc updates are still related to the Ruby comment-support work, with no clearly unrelated changes.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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: 1d94f0d
Status: ✅  Deploy successful!
Preview URL: https://73b35117.archgate-cli.pages.dev
Branch Preview URL: https://feat-ruby-ast-comments.archgate-cli.pages.dev

View logs

…comments

Ripper reports byte-offset columns, and the with-comments serializer mixed
them with character lengths, so comment locs were wrong on non-ASCII lines
under every convention. Convert byte columns to character offsets so Ruby
comment locs share the Python/TS unit; the sexp tree's own node positions
stay byte-based as Ripper emits them.

Also normalize CRLF to LF inside =begin/=end block values: Windows
text-mode reads already strip the CR while POSIX preserves it, so the same
checked-in CRLF file produced platform-dependent values.

Update ARCH-022, the CommentToken JSDoc/shim, and all three doc locales to
pin both conventions, with end-to-end tests for each.

Signed-off-by: Rhuan Barreto <rhuan@barreto.work>
@rhuanbarreto
rhuanbarreto marked this pull request as ready for review July 16, 2026 21:29
@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_d6be18d2-b0f8-4814-a151-5e10ee834598)

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

cursor Bot commented Jul 17, 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_41833cd2-47ad-4789-97d5-b81202de2bcb)

@github-actions

github-actions Bot commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Code Coverage

Metric Value
Lines 91.3% (8118 / 8894)
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.8% 2001 / 2133
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: 5

🤖 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/formats/rules.ts`:
- Around line 180-183: Update the AstNode union in src/formats/rules.ts:180-183
and src/helpers/rules-shim.ts:173-177 to use RubyAstProgram instead of
RubyAstNode, alongside EsTreeProgram and PythonAstModule, so the non-literal
AstLanguage overload exposes the comments property.

In `@tests/engine/ast-support.test.ts`:
- Around line 326-456: Replace all five changed writeFileSync fixture writes in
tests/engine/ast-support.test.ts lines 326-456 and both changed writeFileSync
calls in tests/engine/runner-ast-comments.test.ts lines 201-251 with awaited
Bun.write calls, preserving each existing file path and content.
- Around line 326-338: Replace the fixture-writing writeFileSync calls in the
affected async tests with await Bun.write(file, content), preserving each
existing content value and file target. Update all occurrences in the test cases
represented by the listed ranges, including the shown fixture block.
- Around line 369-390: Add a test near the existing comment-free source test
that supplies Ruby input causing Ripper.lex to raise, then run the same
RUBY_AST_WITH_COMMENTS_PROGRAM subprocess flow and assert exitCode is 0, the
parsed envelope has a valid _tree, and envelope.comments equals [].

In `@tests/engine/runner-ast-comments.test.ts`:
- Around line 201-213: Replace both test-fixture writeFileSync calls in the
async test callbacks with awaited Bun.write calls, preserving the existing file
paths and contents.
🪄 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: 1c1c89d7-70c3-4125-b79c-2374077e6f40

📥 Commits

Reviewing files that changed from the base of the PR and between 0a4ec29 and fc9a217.

📒 Files selected for processing (11)
  • .archgate/adrs/ARCH-022-ast-aware-rule-context.md
  • docs/public/llms-full.txt
  • docs/src/content/docs/nb/reference/rule-api.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/runner.ts
  • src/formats/rules.ts
  • src/helpers/rules-shim.ts
  • tests/engine/ast-support.test.ts
  • tests/engine/runner-ast-comments.test.ts
📜 Review details
⏰ Context from checks skipped due to timeout. (3)
  • GitHub Check: Smoke Test (Windows) / Windows
  • GitHub Check: Analyze (csharp)
  • GitHub Check: Cloudflare Pages
🧰 Additional context used
📓 Path-based instructions (25)
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/ast-support.test.ts
  • tests/engine/runner-ast-comments.test.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:

  • tests/engine/ast-support.test.ts
  • src/helpers/rules-shim.ts
  • src/formats/rules.ts
  • tests/engine/runner-ast-comments.test.ts
  • src/engine/runner.ts
  • src/engine/ast-support.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/ast-support.test.ts
  • tests/engine/runner-ast-comments.test.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:

  • tests/engine/ast-support.test.ts
  • src/helpers/rules-shim.ts
  • src/formats/rules.ts
  • tests/engine/runner-ast-comments.test.ts
  • src/engine/runner.ts
  • src/engine/ast-support.ts
tests/engine/{runner-ast,runner-ast-base,runner-ast-comments,ast-support}.test.ts

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

Test AST parsing, guardrail behavior, throw-versus-null base semantics, Python isolation, comment extraction, original-source locations, Ruby character offsets, and BOM handling.

Files:

  • tests/engine/ast-support.test.ts
  • tests/engine/runner-ast-comments.test.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:

  • tests/engine/ast-support.test.ts
  • docs/public/llms-full.txt
  • src/helpers/rules-shim.ts
  • docs/src/content/docs/pt-br/reference/rule-api.mdx
  • docs/src/content/docs/reference/rule-api.mdx
  • src/formats/rules.ts
  • tests/engine/runner-ast-comments.test.ts
  • src/engine/runner.ts
  • docs/src/content/docs/nb/reference/rule-api.mdx
  • src/engine/ast-support.ts
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/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/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/helpers/rules-shim.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)

Keep the generated .rules.ts helper shim aligned with RuleContext, exposing exactly one AST method with the optional AstOptions parameter.

Files:

  • src/helpers/rules-shim.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/reference/rule-api.mdx
  • docs/src/content/docs/reference/rule-api.mdx
  • docs/src/content/docs/nb/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/reference/rule-api.mdx
  • docs/src/content/docs/reference/rule-api.mdx
  • docs/src/content/docs/nb/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/reference/rule-api.mdx
  • docs/src/content/docs/reference/rule-api.mdx
  • docs/src/content/docs/nb/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/reference/rule-api.mdx
  • docs/src/content/docs/reference/rule-api.mdx
  • docs/src/content/docs/nb/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/reference/rule-api.mdx
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)

Expose exactly one RuleContext.ast(path: string, language: AstLanguage, opts?: AstOptions): Promise<AstNode> method, with typescript, javascript, python, and ruby language support; do not add per-language AST methods.

Files:

  • src/formats/rules.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.

Files:

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

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

src/engine/runner.ts: Implement AST dispatch internally in createRuleContext(); rule authors must not directly access subprocess or filesystem primitives.
Do not trust node.loc for TypeScript parsed through Bun.Transpiler; re-locate findings in the original source. JavaScript locations are source-accurate.

Files:

  • src/engine/runner.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: For Python and Ruby AST parsing, perform guardrails in exactly this order before spawning: safe path validation, language plausibility validation, cached interpreter availability probing, then guarded invocation.
Use Bun.spawn with array-based arguments only for Python/Ruby AST subprocesses; never use shell interpolation, Bun.$, or raw command strings.
Run Python AST subprocesses with isolated mode (python -I -c ...) to prevent the target project's working directory from shadowing standard-library modules.
Probe platform-appropriate Python executable names (python3/python on non-Windows; python/python3/py on Windows using isWindows()), select the first available executable, and cache the result once per check invocation.
Reject files whose extension or leading content is implausible for the requested AST language before invoking Python or Ruby.
ctx.ast() must throw on missing interpreters and parse failures, with distinguishable error messages; it must never return null or another silent-failure sentinel.
For base Python/Ruby parsing, use a temporary file and the same guarded serializer invocation; do not bypass path safety, language checks, interpreter probing, or Python -I isolation.
Strip a leading UTF-8 BOM before Python and Ruby parsing using UTF-8-with-BOM handling.
Python comments must use tokenize, Ruby comments must use a second Ripper.lex pass, and tokenizer/lexing failures on otherwise parseable files must degrade to an empty comment list.
Do not normalize Python or Ruby AST output into ESTree; return each language's native AST shape, documenting that shapes differ by language.

Files:

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

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

src/engine/{runner,ast-support,js-parser}.ts: TypeScript and JavaScript AST parsing must reuse the existing in-process meriyah parser; factor duplicated parseModule() calls in rule-scanner.ts into one shared exported helper used by both scanner and ctx.ast().
Implement opt-in { comments: true } on ast() with a root comments array of { type, value, loc }; omit the array unless requested.

Files:

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

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

Support ast(path, language, { rev: "base" }) and fileAtBase(path) using the merge base of --base and HEAD; base AST parsing must retain the same guardrails and failure semantics.

Files:

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

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

src/engine/**: Do not add tree-sitter, web-tree-sitter, native language bindings, WASM grammars, or other new production parser dependencies under this decision.
Do not add Bun.spawn, Bun.spawnSync, or child_process subprocess calls outside the sanctioned AST support and git-files.ts sites; rule code must not shell out to git or interpreters.

Files:

  • src/engine/runner.ts
  • src/engine/ast-support.ts
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/reference/rule-api.mdx
🧠 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/reference/rule-api.mdx

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

(DOUBLE_PUNCTUATION_XML)


[uncategorized] ~271-~271: 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] ~271-~271: Pontuação duplicada
Context: ...anspilado para TypeScript (veja AstNode): os comentários são varridos a partir d...

(DOUBLE_PUNCTUATION_XML)


[uncategorized] ~271-~271: 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] ~271-~271: Pontuação duplicada
Context: ... Python são sempre type: "line" (#) -- Python não tem comentários de bloco, e ...

(DOUBLE_PUNCTUATION_XML)


[typographical] ~271-~271: 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)


[uncategorized] ~271-~271: Se é uma abreviatura, falta um ponto. Se for uma expressão, coloque entre aspas.
Context: ...moção dos delimitadores /* */) e cujo loc vai da linha do =begin até a linha d...

(ABREVIATIONS_PUNCTUATION)


[uncategorized] ~271-~271: Se é uma abreviatura, falta um ponto. Se for uma expressão, coloque entre aspas.
Context: ...naté a linha do=end. As colunas de loc` dos comentários Ruby são deslocamentos...

(ABREVIATIONS_PUNCTUATION)


[locale-violation] ~271-~271: “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] ~271-~271: “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)

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

[style] ~111-~111: 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 expect Ruby comment loc columns ...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)

🔇 Additional comments (13)
tests/engine/ast-support.test.ts (2)

11-11: LGTM!


297-325: LGTM!

Also applies to: 339-368, 391-425, 430-455, 457-470

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

19-27: LGTM!


198-200: LGTM!

Also applies to: 214-250, 252-269

src/formats/rules.ts (1)

242-246: LGTM!

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

230-234: LGTM!

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

5425-5425: LGTM!

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

271-271: LGTM!

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

271-271: LGTM!

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

271-271: LGTM!

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

66-72: LGTM!

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

147-211: LGTM!

src/engine/runner.ts (1)

288-294: LGTM!

Comment thread src/formats/rules.ts
Comment thread tests/engine/ast-support.test.ts Outdated
Comment thread tests/engine/ast-support.test.ts Outdated
Comment thread tests/engine/ast-support.test.ts
Comment thread tests/engine/runner-ast-comments.test.ts Outdated
rhuanbarreto added a commit that referenced this pull request Jul 17, 2026
## Problem

`code-pull-request.yml` and `dco.yml` gate every job on
`github.event.pull_request.draft == false`, but their `pull_request`
triggers only listed `[opened, edited, synchronize, reopened]`. A PR
opened as draft therefore got a run where every job was skipped — which
made the "Validate Code" fan-in gate report failure — and marking the PR
ready for review never triggered a fresh run, since `ready_for_review`
was not in the trigger list. The PR stayed stuck with a spurious
failed/skipped check until an unrelated push. This surfaced on #485,
#486, and #487.

## Fix

Add `ready_for_review` to the `pull_request` trigger `types` in both
workflows, so promoting a draft to ready triggers a run whose jobs
actually execute. Two-line diff, nothing else changed.

## Validation

- `bun run validate` passes (lint, typecheck, format:check, 1558 tests,
ADR check, knip, build check)
- `bun run cli check` clean: 44/44 rules pass, 0 warnings

Signed-off-by: Rhuan Barreto <rhuan@barreto.work>
@archgatebot archgatebot Bot mentioned this pull request Jul 17, 2026
- widen the AstNode fallback union to RubyAstProgram in rules.ts and
  rules-shim.ts so non-literal-language callers get typed access to
  the comments property (RubyAstNode stays exported for nested nodes)
- use Bun.write instead of writeFileSync in the new async test
  callbacks, per the Bun built-ins guideline
- add a Ripper.lex-failure test covering the rescue-StandardError
  degrade path: parse still exits 0 with a valid tree and an empty
  comments list

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

Copy link
Copy Markdown
Contributor Author

Addressed review feedback in d86a6c3: the AstNode fallback union in rules.ts and rules-shim.ts now uses RubyAstProgram (RubyAstNode stays exported for nested-node typing); the new async test callbacks in ast-support.test.ts and runner-ast-comments.test.ts write fixtures via Bun.write; and a new test forces Ripper.lex to raise (monkey-patch prelude, shipped program unmodified) to cover the rescue-StandardError degrade path — exit 0, valid _tree, comments: [].

@rhuanbarreto

Copy link
Copy Markdown
Contributor Author

@coderabbitai resume

@coderabbitai

coderabbitai Bot commented Jul 17, 2026

Copy link
Copy Markdown
✅ Action performed

Reviews resumed.

coderabbitai[bot]
coderabbitai Bot previously approved these changes Jul 17, 2026
Signed-off-by: Rhuan Barreto <rhuan@barreto.work>
@rhuanbarreto

Copy link
Copy Markdown
Contributor Author

@coderabbitai resume

@coderabbitai

coderabbitai Bot commented Jul 17, 2026

Copy link
Copy Markdown
✅ Action performed

Reviews resumed.

@rhuanbarreto
rhuanbarreto enabled auto-merge (squash) July 17, 2026 03:14
@rhuanbarreto
rhuanbarreto disabled auto-merge July 17, 2026 03:27
@rhuanbarreto
rhuanbarreto merged commit 36b891f into main Jul 17, 2026
23 checks passed
@rhuanbarreto
rhuanbarreto deleted the feat/ruby-ast-comments branch July 17, 2026 03:28
rhuanbarreto added a commit that referenced this pull request Jul 17, 2026
Integrates Ruby { comments: true } support (#485) with ctx.findAstNodes():
- tests/engine/ast-support.test.ts: kept both new suites; moved the
  findAstNodes unit tests to tests/engine/find-ast-nodes.test.ts to stay
  under the oxlint max-lines cap
- docs/public/llms-full.txt regenerated from the merged docs

Signed-off-by: Rhuan Barreto <rhuan@barreto.work>
rhuanbarreto pushed a commit that referenced this pull request Jul 17, 2026
# archgate

## [0.50.0](v0.49.0...v0.50.0)
(2026-07-17)

### Features

* **engine:** cache ctx.ast() parse results within a single check run
([#487](#487))
([40b39d3](40b39d3)),
closes [#482](#482)
* **engine:** ctx.findAstNodes() generic AST node collector
([#486](#486))
([f14b73b](f14b73b)),
closes [#483](#483)
* **engine:** support { comments: true } for ctx.ast() Ruby
([#485](#485))
([36b891f](36b891f)),
closes [#484](#484)

### Bug Fixes

* **ci:** run PR workflows when a draft is marked ready for review
([#488](#488))
([ab1fc96](ab1fc96)),
closes [#485](#485)
[#486](#486)

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

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ctx.ast(): support { comments: true } for Ruby

1 participant