feat(engine): add ctx.readYAML and ctx.checkCase rule helpers - #497
Conversation
|
Warning Review limit reached
Next review available in: 9 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (6)
📝 WalkthroughWalkthroughAdds 🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (3 passed)
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. Comment |
Deploying archgate-cli with
|
| Latest commit: |
6ede380
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://1a38d32a.archgate-cli.pages.dev |
| Branch Preview URL: | https://feat-ctx-read-yaml-check-cas.archgate-cli.pages.dev |
Code Coverage
Full HTML report available in workflow artifacts. Per-directory breakdown
|
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 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/public/llms-full.txt`:
- Line 5223: Restore the actual parameterized return type for readYAML in both
documented locations: update docs/public/llms-full.txt lines 5223 and 5355-5369
so the signature renders Promise<ReadYamlResult> instead of Promise, including
the detailed API section.
In `@src/engine/safe-path.ts`:
- Around line 37-58: The safePath function only rejects symlinks at the final
path, so update it to inspect every existing path component from resolvedRoot
through absPath and reject any symbolic-link ancestor before returning. Preserve
the existing error handling for missing paths and access-denied UserErrors. Add
a test in tests/engine/safe-path.test.ts covering an ancestor-directory symlink
that points outside tempDir and asserting safePath rejects it.
In `@src/engine/yaml-utils.ts`:
- Line 11: Update FRONTMATTER_REGEX so the closing frontmatter delimiter must be
followed by the line ending or end of input, rejecting forms such as “----” and
“---note” while preserving valid closing fences.
In `@src/helpers/rules-shim.ts`:
- Around line 72-107: Update the generated CaseScheme JSDoc in the rules shim to
match the source contract, including the documented degenerate-value behavior
when a value matches multiple casing schemes. Preserve the existing CaseScheme
union and ensure its ambient documentation remains in parity with the
corresponding RuleContext surface.
🪄 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: cbe56a94-01d6-48d4-a372-c1747b98f5a4
📒 Files selected for processing (17)
.archgate/adrs/ARCH-022-ast-aware-rule-context.md.archgate/adrs/ARCH-022-ast-aware-rule-context.rules.ts.claude/agent-memory/archgate-developer/project_oxlint_gotchas.mddocs/public/llms-full.txtdocs/src/content/docs/nb/reference/rule-api.mdxdocs/src/content/docs/pt-br/reference/rule-api.mdxdocs/src/content/docs/reference/rule-api.mdxsrc/engine/check-case.tssrc/engine/runner.tssrc/engine/safe-path.tssrc/engine/yaml-utils.tssrc/formats/rules.tssrc/helpers/rules-shim.tstests/engine/check-case.test.tstests/engine/runner-yaml-case.test.tstests/engine/safe-path.test.tstests/engine/yaml-utils.test.ts
📜 Review details
⏰ Context from checks skipped due to timeout. (5)
- GitHub Check: Smoke Test (Windows) / Windows
- GitHub Check: Analyze (javascript-typescript)
- GitHub Check: Analyze (javascript-typescript)
- GitHub Check: Analyze (csharp)
- GitHub Check: Cloudflare Pages
🧰 Additional context used
📓 Path-based instructions (22)
src/**/*.ts
📄 CodeRabbit inference engine (.archgate/adrs/ARCH-004-no-barrel-files.md)
src/**/*.ts: Do not re-export symbols from another module in any source file; statements likeexport { X } from "./other"andexport type { X } from "./other"are forbidden.
Import symbols directly from the module that defines them; do not import from a directory path such as../formatsexpecting implicitindex.tsresolution.
src/**/*.ts: Useawait Bun.file(path).json()when reading JSON files in Bun TypeScript source code; do not useJSON.parse(await Bun.file(path).text())orJSON.parse(fs.readFileSync(path, "utf-8"))for file reads.
UseBun.JSONC.parse()when reading files that may contain comments, such astsconfig.json, instead of plainJSON.parse()on file contents.
ReserveJSON.parse()for parsing JSON strings from non-file sources such as API responses or string variables; do not use it as the default for reading JSON files.
src/**/*.ts: In TypeScript source files undersrc/, useBun.envinstead ofprocess.envfor all environment variable reads and writes;process.envmust not be used.
In TypeScript source files undersrc/, use nullish coalescing for environment-variable defaults, e.g.Bun.env.NODE_ENV ?? "production".
In TypeScript source files undersrc/, useBoolean(Bun.env.CI)for truthy checks on environment flags.
In TypeScript source files undersrc/, do not destructureBun.env(for example,const { HOME } = Bun.env); access properties individually instead.
In TypeScript source files undersrc/, do not referenceprocess.enveven in comments that suggest using it.
src/**/*.ts: Heavy dependencies such asinquirer,posthog-node,@sentry/*, and any similarly expensive runtime-only dependency MUST be loaded with dynamicimport()at the point of use, never as a static value import at module top level.
Type-only references to heavy modules must useimport type(for example,import type { PostHog } from "posthog-node"orimport type * as SentryNs from "@sentry/node-core/light"); type-only...
Files:
src/engine/check-case.tssrc/engine/safe-path.tssrc/engine/yaml-utils.tssrc/helpers/rules-shim.tssrc/formats/rules.tssrc/engine/runner.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, useBun.file()instead offs.readFile()for simple reads.
Prefernode:built-in modules such asnode:util,node:path, andnode:fsover npm alternatives.
Do not use utility libraries for single functions, such as importing lodash for one helper likepick.
Do not use path aliases (tsconfig paths); use relative imports with Bun's native module resolution.
Do not install packages globally during development; usebunxfor one-off tools.
Files:
src/engine/check-case.tstests/engine/check-case.test.tssrc/engine/safe-path.tstests/engine/safe-path.test.tstests/engine/yaml-utils.test.tssrc/engine/yaml-utils.tssrc/helpers/rules-shim.tstests/engine/runner-yaml-case.test.tssrc/formats/rules.tssrc/engine/runner.ts
src/**/!(*platform).ts
📄 CodeRabbit inference engine (.archgate/adrs/ARCH-009-platform-detection-helper.md)
src/**/!(*platform).ts: Insrc/TypeScript source files, do not readprocess.platformdirectly; usesrc/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 insrc/TypeScript source.
When behavior differs between Linux and Windows, account for WSL by usingisWSL()rather than assuming `
Files:
src/engine/check-case.tssrc/engine/safe-path.tssrc/engine/yaml-utils.tssrc/helpers/rules-shim.tssrc/formats/rules.tssrc/engine/runner.ts
{src,tests}/**/*.ts
📄 CodeRabbit inference engine (.archgate/adrs/LEGAL-001-spdx-license-headers.md)
{src,tests}/**/*.ts: Every TypeScript source file insrc/andtests/must begin with// SPDX-License-Identifier: Apache-2.0followed by// Copyright 2026 Archgate.
If a TypeScript file has a shebang line (for example#!/usr/bin/env buninsrc/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/check-case.tstests/engine/check-case.test.tssrc/engine/safe-path.tstests/engine/safe-path.test.tstests/engine/yaml-utils.test.tssrc/engine/yaml-utils.tssrc/helpers/rules-shim.tstests/engine/runner-yaml-case.test.tssrc/formats/rules.tssrc/engine/runner.ts
src/{helpers,engine}/**/*.ts
📄 CodeRabbit inference engine (.archgate/adrs/ARCH-002-error-handling.md)
Do not use
console.log(),console.warn(), orconsole.info()directly in helper or engine files; uselogInfo()orlogWarn()instead.
Files:
src/engine/check-case.tssrc/engine/safe-path.tssrc/engine/yaml-utils.tssrc/helpers/rules-shim.tssrc/engine/runner.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 throughlistMatchingFilesfor rule-facing inputs ormatchTrackedFilesfor trusted ADR frontmatter patterns.
When the target is a Git repository andrespectGitignoreis not false, pass the tracked set fromgetGitTrackedFilesto matching operations.
Per-runRunCachesmust 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 cachereadJSONresults 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: Do not addBun.spawn/Bun.spawnSyncorchild_processsubprocess sites outside the sanctioned AST support and git-files implementations.
Do not normalize Python or Ruby AST output into ESTree; preserve each language's native AST shape.
Do not invoke Python or Ruby interpreters before language plausibility validation, and do not re-probe interpreter availability for every file.
Usectx.ast(path, language, { rev: "base" })orfileAtBase()for base comparisons; rule code must never shell out to git or an interpreter directly.
Files:
src/engine/check-case.tssrc/engine/safe-path.tssrc/engine/yaml-utils.tssrc/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.tsfile with automated checks that run viaarchgate check.When reviewing, you must:
- Treat ADR violations as blocking issues, not suggestions.
- Cite the specific ADR ID when flagging a violation (e.g., "Violates ARCH-006").
- Focus on semantic and contextual violations that automated rules cannot catch —
the.rules.tsfiles already cover syntactic/structural patterns.- If you are unsure whether something violates an ADR, flag it as a question
rather than approving it.
Files:
src/engine/check-case.tstests/engine/check-case.test.tssrc/engine/safe-path.tstests/engine/safe-path.test.tstests/engine/yaml-utils.test.tsdocs/public/llms-full.txtsrc/engine/yaml-utils.tssrc/helpers/rules-shim.tsdocs/src/content/docs/pt-br/reference/rule-api.mdxtests/engine/runner-yaml-case.test.tsdocs/src/content/docs/reference/rule-api.mdxdocs/src/content/docs/nb/reference/rule-api.mdxsrc/formats/rules.tssrc/engine/runner.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 mutatingprocess.platformdirectly.
tests/**/*.ts: Use Bun's built-inbun:testrunner for all tests; do not import test utilities fromnode:test.
Shared test helpers must also userestoreEnvwhen restoring environment variables.
Files:
tests/engine/check-case.test.tstests/engine/safe-path.test.tstests/engine/yaml-utils.test.tstests/engine/runner-yaml-case.test.ts
tests/**/*.test.ts
📄 CodeRabbit inference engine (.archgate/adrs/ARCH-005-testing-standards.md)
tests/**/*.test.ts: Place tests intests/mirroring thesrc/directory structure, and name test files with the.test.tssuffix.
Test public module interfaces rather than private implementation details, use descriptive test names, and do not depend on network access.
Use isolated temporary directories created withmkdtempfor filesystem tests, and clean them up inafterEachorafterAll. Do not use hardcoded user or system paths.
Close external SDK instances such as servers, clients, and transports inafterEachorafterAll; manage their lifecycle in test hooks rather than individual test bodies.
When a temporary git repository performs commits, configure localuser.emailanduser.nameimmediately aftergit init; do not rely on global git identity.
Every runnabletest()orit()must contain at least oneexpect()assertion. Make implicit no-throw contracts explicit withnot.toThrow()orresolves.toBeUndefined(). Usetest.skiportest.todofor intentional placeholders.
Usetest.skipIf(condition),test.skip, ortest.todofor conditional or intentionally disabled tests; do not use bare early returns or empty callbacks to skip tests, and do not skip without a tracking issue.
When adding assertions to an older test file, importexpectfrombun:test.
Mock HTTP requests by assigning directly toglobalThis.fetch, and restore the original fetch implementation or mock inafterEach; do not mocknode:fetch.
Mock first-party modules withimport * as modandspyOn(mod, "fn"), restoring spies after each test; do not use process-globalmock.module()for first-party modules.
Wrap inlinespyOnormockImplementationusage intry/finallysomockRestore()always runs, or manage spies inbeforeEachandafterEach.
When redirecting user-scope paths, mocknode:os'shomedir()rather than relying on runtimeHOMEoverrides; use environment overrides only for code that reads environment variables directly at call time.
Re...
Files:
tests/engine/check-case.test.tstests/engine/safe-path.test.tstests/engine/yaml-utils.test.tstests/engine/runner-yaml-case.test.ts
src/helpers/rules-shim.ts
📄 CodeRabbit inference engine (.archgate/adrs/ARCH-022-ast-aware-rule-context.md)
Mirror every RuleContext surface change, including
ast,fileAtBase, ambient types, signatures, and accompanying JSDoc, in the generated rules shim.
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 underdocs/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.mdxdocs/src/content/docs/reference/rule-api.mdxdocs/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>.mdxand add the page todocs/astro.config.mjssidebar configuration.
Files:
docs/src/content/docs/pt-br/reference/rule-api.mdxdocs/src/content/docs/reference/rule-api.mdxdocs/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.mdxdocs/src/content/docs/reference/rule-api.mdxdocs/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 underdocs/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, andlink/href/slugattribute 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.mdxdocs/src/content/docs/reference/rule-api.mdxdocs/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
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
duform and correct Norwegian characters (æ,ø,å).
Files:
docs/src/content/docs/nb/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, usesafeParse(), and reuseAdrFrontmatterSchema.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 language-specific dispatch hidden from rule authors; document that returned AST shapes differ by language.
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: Implementctx.ast()insidecreateRuleContext()and execute path safety, language plausibility, interpreter availability probing, and guarded invocation in exactly that order before any subprocess is spawned.
Do not trustnode.locfor TypeScript AST nodes because parsing transpiled output changes locations; re-locate constructs in the original source before reporting lines. 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: Use array-basedBun.spawnarguments for Python/Ruby AST invocations; never expose raw subprocess or filesystem primitives through RuleContext.
Python AST subprocesses must use isolated mode (python -I -c ...) to prevent the target project's working directory from shadowing standard-library modules.
For TypeScript and JavaScript, reuse the in-processmeriyahparser; factor the duplicatedparseModule()logic into one shared exported helper used by bothrule-scanner.tsandctx.ast().
For Python and Ruby, use only the interpreters' standard-library AST facilities (astandRipper), with no tree-sitter, WASM grammar, native binding, or other new production dependency.
Probe Python/Ruby interpreter availability using platform-appropriate candidates, select the first resolved executable for the real invocation, and cache the probe once per check invocation.
Strip a leading UTF-8 BOM before parsing Python or Ruby source; retain Python-Iisolation.
ctx.ast()must throw on missing interpreters, parse failures, and base-revision absence; errors must distinguish environment failure, parse failure, missing base, and files absent at base.fileAtBase()alone returnsnullfor missing base or missing files.
Forast(..., { rev: "base" }), apply the same path-safety, language-plausibility, interpreter-probe, and guarded-invocation flow as working-tree parsing; parse TypeScript/JavaScript in process and use isolated temporary files for Python/Ruby base content.
When{ comments: true }is requested, attach structured rootcommentstokens withtype, delimiter-strippedvalue, andloc; omit the array otherwise.
Extract TypeScript/JavaScript comments from the original source, using a string/template-literal-aware scanner; do not treat regex-literal awareness as guaranteed.
Extract Python comments withtokenizeand Ruby comments withRipper.lex; tokenizer/lexer errors on otherwise parseable input degrade to an empt...
Files:
src/engine/runner.ts
src/engine/{runner,git-files}.ts
📄 CodeRabbit inference engine (.archgate/adrs/ARCH-022-ast-aware-rule-context.md)
Base-revision reads must use the merge base of
--baseand HEAD, matching the existing three-dotchangedFilescomparison; keep git reads confined togit-files.ts.
Files:
src/engine/runner.ts
🧠 Learnings (3)
📚 Learning: 2026-06-11T12:50:28.661Z
Learnt from: rhuanbarreto
Repo: archgate/cli PR: 406
File: .claude/agent-memory/archgate-developer/feedback_prefer_tests_over_adr_rules.md:8-18
Timestamp: 2026-06-11T12:50:28.661Z
Learning: In `archgate/cli`, for markdown files under `.claude/agent-memory/`, follow the established convention: use YAML frontmatter (with a `name:` field used as the document title) and do not require a top-level `#` (H1) heading. During code review, do not flag missing first-line/first-top-level H1 headings (e.g., MD041) for these agent-memory files since markdownlint is not part of the repo’s `bun run validate` lint pipeline (oxlint/oxfmt only).
Applied to files:
.claude/agent-memory/archgate-developer/project_oxlint_gotchas.md
📚 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
📚 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
🪛 LanguageTool
docs/src/content/docs/pt-br/reference/rule-api.mdx
[uncategorized] ~218-~218: Pontuação duplicada
Context: ...bjeto de resultado cobre as duas formas -- um mapeamento frontmatter anulável e ...
(DOUBLE_PUNCTUATION_XML)
[uncategorized] ~220-~220: Pontuação duplicada
Context: ...re null; content é o valor parseado -- faça o cast para o tipo esperado na sua...
(DOUBLE_PUNCTUATION_XML)
[uncategorized] ~220-~220: Encontrada possível ausência de vírgula.
Context: ...res --- de um stream multi-documento (manifestos Kubernetes, configurações de CI) nunca ...
(AI_PT_HYDRA_LEO_MISSING_COMMA)
[uncategorized] ~221-~221: Esta conjunção deve ser separada por vírgulas e só deve ser utilizada no início duma frase para efeitos de estilo.
Context: ..., espelhando fileAtBase), {} quando existe mas está vazio. content é o restante do c...
(VERB_COMMA_CONJUNCTION)
[uncategorized] ~221-~221: Pontuação duplicada
Context: ... do texto, sem espaços nas extremidades -- ele não é parseado como YAML. `rea...
(DOUBLE_PUNCTUATION_XML)
[uncategorized] ~404-~404: Pontuação duplicada
Context: ...tring segue um esquema de capitalização -- a substituição integrada para os regexe...
(DOUBLE_PUNCTUATION_XML)
[uncategorized] ~404-~404: Pontuação duplicada
Context: ...cisavam escrever à mão. Síncrono e puro -- não precisa de await. A correspondênc...
(DOUBLE_PUNCTUATION_XML)
🔇 Additional comments (20)
.archgate/adrs/ARCH-022-ast-aware-rule-context.rules.ts (2)
25-45: LGTM!
226-269: LGTM!.archgate/adrs/ARCH-022-ast-aware-rule-context.md (2)
97-97: LGTM!
152-158: LGTM!src/formats/rules.ts (1)
65-112: LGTM!Also applies to: 261-279, 335-342
src/helpers/rules-shim.ts (1)
244-261: LGTM!Also applies to: 312-319
docs/public/llms-full.txt (1)
5544-5580: LGTM!docs/src/content/docs/reference/rule-api.mdx (1)
69-72: LGTM!Also applies to: 199-251, 391-427
src/engine/check-case.ts (1)
1-41: LGTM!src/engine/yaml-utils.ts (1)
1-10: LGTM!Also applies to: 16-82
tests/engine/check-case.test.ts (1)
1-93: LGTM!docs/src/content/docs/nb/reference/rule-api.mdx (1)
69-72: LGTM!Also applies to: 199-251, 391-427
docs/src/content/docs/pt-br/reference/rule-api.mdx (1)
69-72: LGTM!Also applies to: 199-251, 391-427
src/engine/safe-path.ts (1)
11-18: LGTM!Also applies to: 25-31
src/engine/runner.ts (2)
3-3: LGTM!Also applies to: 12-18, 39-39, 51-53
383-400: 🎯 Functional CorrectnessNo shim parity issue for
readYAMLandcheckCase.
src/formats/rules.tsandsrc/helpers/rules-shim.tsboth declare matchingRuleContextmembers, includingReadYamlResultandCaseScheme..claude/agent-memory/archgate-developer/project_oxlint_gotchas.md (1)
15-15: LGTM!tests/engine/yaml-utils.test.ts (1)
1-101: LGTM!tests/engine/safe-path.test.ts (1)
25-65: LGTM!tests/engine/runner-yaml-case.test.ts (1)
1-170: LGTM!
|
Thanks — all four findings were real. Verified each against the code rather than applying them blind; three are fixed here in d370795, one is split out. 1. Worth flagging that the framing ("restore the return type") wasn't quite right: I never edited that file, and the damage was not specific to
2. 3. 4. Ancestor-symlink escape — real, pre-existing, and split out to #499. Confirmed by construction: But That PR also has the parts that don't fit in a footnote — the fix deliberately does not inspect components at or above the root (macOS |
7f74a84 to
b48dcb2
Compare
…ctory (#499) Split out of #497 at your request, following the same call you made on #491 (pre-existing security finding → standalone PR). Surfaced by CodeRabbit while reviewing #497. The finding is real and **predates that PR** — #497 only moved this code verbatim out of `runner.ts`, so the gap exists on `main` today. ## The escape `safePath()` `lstat`'d only the **final** path component. Given a symlinked ancestor: ``` <root>/linkdir -> /somewhere/outside ``` then `ctx.readFile("linkdir/secret.txt")` gets through every gate: 1. `resolveUserPath()` uses `resolve()`, which is **purely lexical** — it does not resolve symlinks, so the path stays `<root>/linkdir/secret.txt`. 2. `isWithinRoot()` is a string-prefix test on that lexical path — **passes**. 3. `lstatSync(absPath)` inspects only the leaf, which is an ordinary file, not a link — **passes**. 4. `Bun.file(absPath).text()` hands the path to the OS, which *does* resolve `linkdir` — and reads outside the project. So a `.rules.ts` file could read arbitrary files outside the project through a symlinked directory, which is exactly the boundary ARCH-024 exists to hold. ## The fix The leaf check and the ancestor check become one walk over every path component **below** the project root. Two deliberate constraints: - **Nothing at or above the root is inspected.** The project root's own location is the user's business, and on macOS the temp prefix is itself a symlink (`/var` → `/private/var`) — walking above the root would reject every path under a temp-dir root, breaking a large share of the test suite for no security gain. - **Each component is a boolean `lstat`, not a string comparison against `realpath`.** A `realpath`-and-compare implementation is one syscall instead of N and was my first instinct, but `realpath` case-canonicalizes on Windows and macOS, so it would reject case-mismatched-but-legitimate paths. The boolean question has no such failure mode. Verified directories are memoized per process. `safePath` runs once per glob result and sibling files share every ancestor, so without the memo the walk would re-`lstat` the same handful of directories thousands of times per check run (`grepFiles` × 40+ rules). ## Tests - `tests/engine/safe-path.test.ts` — ancestor symlink rejected, leaf symlink rejected, deep real-directory chain accepted, non-existent in-root path tolerated, root itself accepted, traversal rejected - `tests/commands/check-security.test.ts` — end-to-end through `runChecks`: a rule reading through a symlinked parent is blocked, and a rule reading a deeply nested real path still succeeds (guards against over-rejection) **The regression tests actually run on Windows.** They create the directory link with symlink type `"junction"` — ignored on POSIX (plain symlink), but on Windows a junction needs no admin privileges and `lstat` reports it as a symbolic link. The pre-existing file-symlink test still skips on Windows, since file symlinks require elevation or Developer Mode; that limitation is now isolated to that one case rather than covering the whole symlink surface. I confirmed the fix is load-bearing rather than trusting a green suite: with the guard call stubbed out, the ancestor test fails; with it in place, it passes. ## Note on overlap with #497 The helpers move to `src/engine/safe-path.ts` here because `runner.ts` sits **exactly** at the 500-line `max-lines` cap on `main` — the fix cannot land in place. #497 performs the same extraction independently for the same reason. The two versions of the file are identical apart from this fix, so whichever merges second needs a trivial rebase. `bun run validate` passes (lint, typecheck, format:check, full suite, `archgate check` 44/44, knip, build:check). Signed-off-by: Rhuan Barreto <rhuan@barreto.work>
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 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/scripts/generate-llms-full.ts`:
- Around line 77-82: Update the comment near stripJsx() to use forward-behavior
wording: explain that applying the component-tag patterns to code can remove
capitalized generic type arguments from fenced blocks and inline table spans,
while lowercase generic arguments remain intact. Replace the informal “ate” and
historical “affected” phrasing without changing the documented examples or
scope.
In `@src/engine/yaml-utils.ts`:
- Line 19: Update FRONTMATTER_REGEX to allow the closing fence immediately after
the opening fence’s newline, while continuing to capture multiline frontmatter
and preserve the existing delimiter and content handling. Ensure an empty block
such as “---\n---\nbody” matches and produces the documented empty frontmatter
object with “body” as content.
In `@src/formats/rules.ts`:
- Around line 261-279: The readYAML() JSDoc contract must match ReadYamlResult
and remain synchronized across both declarations. In src/formats/rules.ts lines
261-279, describe content as YamlValue instead of unknown and retain the
complete source semantics; mirror the corrected JSDoc, including extension
dispatch, frontmatter behavior, content handling, and failure conditions, in
src/helpers/rules-shim.ts lines 246-263.
🪄 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: 2fa43f2e-c92a-4f22-9313-1f7cd20525a6
📒 Files selected for processing (18)
.archgate/adrs/ARCH-022-ast-aware-rule-context.md.archgate/adrs/ARCH-022-ast-aware-rule-context.rules.ts.claude/agent-memory/archgate-developer/project_oxlint_gotchas.md.claude/agent-memory/archgate-developer/project_rules_engine_internals.md.claude/agent-memory/archgate-developer/project_test_isolation_gotchas.mddocs/public/llms-full.txtdocs/scripts/generate-llms-full.tsdocs/src/content/docs/nb/reference/rule-api.mdxdocs/src/content/docs/pt-br/reference/rule-api.mdxdocs/src/content/docs/reference/rule-api.mdxsrc/engine/check-case.tssrc/engine/runner.tssrc/engine/yaml-utils.tssrc/formats/rules.tssrc/helpers/rules-shim.tstests/engine/check-case.test.tstests/engine/runner-yaml-case.test.tstests/engine/yaml-utils.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 (23)
**/*.{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, useBun.file()instead offs.readFile()for simple reads.
Prefernode:built-in modules such asnode:util,node:path, andnode:fsover npm alternatives.
Do not use utility libraries for single functions, such as importing lodash for one helper likepick.
Do not use path aliases (tsconfig paths); use relative imports with Bun's native module resolution.
Do not install packages globally during development; usebunxfor one-off tools.
Files:
tests/engine/check-case.test.tssrc/engine/check-case.tssrc/engine/yaml-utils.tsdocs/scripts/generate-llms-full.tstests/engine/yaml-utils.test.tssrc/formats/rules.tssrc/helpers/rules-shim.tstests/engine/runner-yaml-case.test.tssrc/engine/runner.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 mutatingprocess.platformdirectly.
tests/**/*.ts: Use Bun's built-inbun:testrunner for all tests; do not import test utilities fromnode:test.
Shared test helpers must also userestoreEnvwhen restoring environment variables.
Files:
tests/engine/check-case.test.tstests/engine/yaml-utils.test.tstests/engine/runner-yaml-case.test.ts
{src,tests}/**/*.ts
📄 CodeRabbit inference engine (.archgate/adrs/LEGAL-001-spdx-license-headers.md)
{src,tests}/**/*.ts: Every TypeScript source file insrc/andtests/must begin with// SPDX-License-Identifier: Apache-2.0followed by// Copyright 2026 Archgate.
If a TypeScript file has a shebang line (for example#!/usr/bin/env buninsrc/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/check-case.test.tssrc/engine/check-case.tssrc/engine/yaml-utils.tstests/engine/yaml-utils.test.tssrc/formats/rules.tssrc/helpers/rules-shim.tstests/engine/runner-yaml-case.test.tssrc/engine/runner.ts
tests/**/*.test.ts
📄 CodeRabbit inference engine (.archgate/adrs/ARCH-005-testing-standards.md)
tests/**/*.test.ts: Place tests intests/mirroring thesrc/directory structure, and name test files with the.test.tssuffix.
Test public module interfaces rather than private implementation details, use descriptive test names, and do not depend on network access.
Use isolated temporary directories created withmkdtempfor filesystem tests, and clean them up inafterEachorafterAll. Do not use hardcoded user or system paths.
Close external SDK instances such as servers, clients, and transports inafterEachorafterAll; manage their lifecycle in test hooks rather than individual test bodies.
When a temporary git repository performs commits, configure localuser.emailanduser.nameimmediately aftergit init; do not rely on global git identity.
Every runnabletest()orit()must contain at least oneexpect()assertion. Make implicit no-throw contracts explicit withnot.toThrow()orresolves.toBeUndefined(). Usetest.skiportest.todofor intentional placeholders.
Usetest.skipIf(condition),test.skip, ortest.todofor conditional or intentionally disabled tests; do not use bare early returns or empty callbacks to skip tests, and do not skip without a tracking issue.
When adding assertions to an older test file, importexpectfrombun:test.
Mock HTTP requests by assigning directly toglobalThis.fetch, and restore the original fetch implementation or mock inafterEach; do not mocknode:fetch.
Mock first-party modules withimport * as modandspyOn(mod, "fn"), restoring spies after each test; do not use process-globalmock.module()for first-party modules.
Wrap inlinespyOnormockImplementationusage intry/finallysomockRestore()always runs, or manage spies inbeforeEachandafterEach.
When redirecting user-scope paths, mocknode:os'shomedir()rather than relying on runtimeHOMEoverrides; use environment overrides only for code that reads environment variables directly at call time.
Re...
Files:
tests/engine/check-case.test.tstests/engine/yaml-utils.test.tstests/engine/runner-yaml-case.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.tsfile with automated checks that run viaarchgate check.When reviewing, you must:
- Treat ADR violations as blocking issues, not suggestions.
- Cite the specific ADR ID when flagging a violation (e.g., "Violates ARCH-006").
- Focus on semantic and contextual violations that automated rules cannot catch —
the.rules.tsfiles already cover syntactic/structural patterns.- If you are unsure whether something violates an ADR, flag it as a question
rather than approving it.
Files:
tests/engine/check-case.test.tssrc/engine/check-case.tssrc/engine/yaml-utils.tsdocs/scripts/generate-llms-full.tstests/engine/yaml-utils.test.tssrc/formats/rules.tsdocs/src/content/docs/nb/reference/rule-api.mdxsrc/helpers/rules-shim.tstests/engine/runner-yaml-case.test.tsdocs/src/content/docs/pt-br/reference/rule-api.mdxdocs/src/content/docs/reference/rule-api.mdxsrc/engine/runner.tsdocs/public/llms-full.txt
src/**/*.ts
📄 CodeRabbit inference engine (.archgate/adrs/ARCH-004-no-barrel-files.md)
src/**/*.ts: Do not re-export symbols from another module in any source file; statements likeexport { X } from "./other"andexport type { X } from "./other"are forbidden.
Import symbols directly from the module that defines them; do not import from a directory path such as../formatsexpecting implicitindex.tsresolution.
src/**/*.ts: Useawait Bun.file(path).json()when reading JSON files in Bun TypeScript source code; do not useJSON.parse(await Bun.file(path).text())orJSON.parse(fs.readFileSync(path, "utf-8"))for file reads.
UseBun.JSONC.parse()when reading files that may contain comments, such astsconfig.json, instead of plainJSON.parse()on file contents.
ReserveJSON.parse()for parsing JSON strings from non-file sources such as API responses or string variables; do not use it as the default for reading JSON files.
src/**/*.ts: In TypeScript source files undersrc/, useBun.envinstead ofprocess.envfor all environment variable reads and writes;process.envmust not be used.
In TypeScript source files undersrc/, use nullish coalescing for environment-variable defaults, e.g.Bun.env.NODE_ENV ?? "production".
In TypeScript source files undersrc/, useBoolean(Bun.env.CI)for truthy checks on environment flags.
In TypeScript source files undersrc/, do not destructureBun.env(for example,const { HOME } = Bun.env); access properties individually instead.
In TypeScript source files undersrc/, do not referenceprocess.enveven in comments that suggest using it.
src/**/*.ts: Heavy dependencies such asinquirer,posthog-node,@sentry/*, and any similarly expensive runtime-only dependency MUST be loaded with dynamicimport()at the point of use, never as a static value import at module top level.
Type-only references to heavy modules must useimport type(for example,import type { PostHog } from "posthog-node"orimport type * as SentryNs from "@sentry/node-core/light"); type-only...
Files:
src/engine/check-case.tssrc/engine/yaml-utils.tssrc/formats/rules.tssrc/helpers/rules-shim.tssrc/engine/runner.ts
src/**/!(*platform).ts
📄 CodeRabbit inference engine (.archgate/adrs/ARCH-009-platform-detection-helper.md)
src/**/!(*platform).ts: Insrc/TypeScript source files, do not readprocess.platformdirectly; usesrc/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 insrc/TypeScript source.
When behavior differs between Linux and Windows, account for WSL by usingisWSL()rather than assuming `
Files:
src/engine/check-case.tssrc/engine/yaml-utils.tssrc/formats/rules.tssrc/helpers/rules-shim.tssrc/engine/runner.ts
src/{helpers,engine}/**/*.ts
📄 CodeRabbit inference engine (.archgate/adrs/ARCH-002-error-handling.md)
Do not use
console.log(),console.warn(), orconsole.info()directly in helper or engine files; uselogInfo()orlogWarn()instead.
Files:
src/engine/check-case.tssrc/engine/yaml-utils.tssrc/helpers/rules-shim.tssrc/engine/runner.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 throughlistMatchingFilesfor rule-facing inputs ormatchTrackedFilesfor trusted ADR frontmatter patterns.
When the target is a Git repository andrespectGitignoreis not false, pass the tracked set fromgetGitTrackedFilesto matching operations.
Per-runRunCachesmust 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 cachereadJSONresults 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/check-case.tssrc/engine/yaml-utils.tssrc/engine/runner.ts
src/engine/**
📄 CodeRabbit inference engine (.archgate/adrs/ARCH-022-ast-aware-rule-context.md)
src/engine/**: Do not add unsanctionedBun.spawn/Bun.spawnSynccalls orchild_processimports; AST subprocesses belong only in the sanctioned AST helper and git subprocesses ingit-files.ts.
Keep Python/Ruby AST results in their native language-specific shapes; do not normalize them into ESTree or another cross-language vocabulary.
UseisWindows()for platform detection when ordering interpreter candidates.
Files:
src/engine/check-case.tssrc/engine/yaml-utils.tssrc/engine/runner.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, usesafeParse(), and reuseAdrFrontmatterSchema.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, language, opts?)method supporting TypeScript, JavaScript, Python, and Ruby, with optional{ rev?: "base"; comments?: boolean }and language-native AST shapes.
Files:
src/formats/rules.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 underdocs/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/nb/reference/rule-api.mdxdocs/src/content/docs/pt-br/reference/rule-api.mdxdocs/src/content/docs/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>.mdxand add the page todocs/astro.config.mjssidebar configuration.
Files:
docs/src/content/docs/nb/reference/rule-api.mdxdocs/src/content/docs/pt-br/reference/rule-api.mdxdocs/src/content/docs/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/nb/reference/rule-api.mdxdocs/src/content/docs/pt-br/reference/rule-api.mdxdocs/src/content/docs/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 underdocs/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, andlink/href/slugattribute 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/nb/reference/rule-api.mdxdocs/src/content/docs/pt-br/reference/rule-api.mdxdocs/src/content/docs/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
duform and correct Norwegian characters (æ,ø,å).
Files:
docs/src/content/docs/nb/reference/rule-api.mdx
src/helpers/rules-shim.ts
📄 CodeRabbit inference engine (.archgate/adrs/ARCH-022-ast-aware-rule-context.md)
Mirror every RuleContext surface change, including
ast,fileAtBase, ambient types, signatures, and JSDoc, in the generated rules shim.
Files:
src/helpers/rules-shim.ts
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/engine/runner.ts
📄 CodeRabbit inference engine (.archgate/adrs/ARCH-022-ast-aware-rule-context.md)
src/engine/runner.ts: Implement AST dispatch internally increateRuleContext(); rule authors must not receive direct subprocess or filesystem primitives.
For Python and Ruby AST operations, execute guardrails in this exact order before any subprocess: path safety, language plausibility, interpreter availability probe, then guarded invocation.
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: UseBun.spawnwith array arguments for Python/Ruby AST subprocesses; never use shell interpolation,Bun.$, or direct child-process access from rules.
Run Python AST subprocesses with isolated mode (python -I -c ...) and strip a leading UTF-8 BOM before parsing Python or Ruby source.
Reuse the in-processmeriyahparser for TypeScript and JavaScript, factoring duplicatedparseModule()calls inrule-scanner.tsinto one shared exported helper used by both scanner andctx.ast().
Probe Python/Ruby interpreter availability using platform-appropriate candidates, select the first available executable for both probing and invocation, and cache the result once per check.
Throw on missing interpreters and parse failures, with distinguishable error messages; never returnnullor another silent-failure sentinel fromast().
Base AST reads must apply the same path-safety, language-plausibility, interpreter-probe, and guarded-invocation ordering as working-tree reads; missing base or base-added files must throw distinguishable errors.
ImplementfileAtBase(path)as the exception to AST failure semantics: returnnullwhen no base exists or the file did not exist at the base, rather than throwing.
When{ comments: true }is requested, attach structured root-level comments withtype, delimiter-strippedvalue, andloc; omit the comments array unless explicitly requested.
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)
For
{ rev: "base" }, resolve the merge base of--baseand HEAD, use the same base aschangedFiles, and keep git reads confined togit-files.ts.
Files:
src/engine/runner.ts
🧠 Learnings (6)
📚 Learning: 2026-06-11T12:50:28.661Z
Learnt from: rhuanbarreto
Repo: archgate/cli PR: 406
File: .claude/agent-memory/archgate-developer/feedback_prefer_tests_over_adr_rules.md:8-18
Timestamp: 2026-06-11T12:50:28.661Z
Learning: In `archgate/cli`, for markdown files under `.claude/agent-memory/`, follow the established convention: use YAML frontmatter (with a `name:` field used as the document title) and do not require a top-level `#` (H1) heading. During code review, do not flag missing first-line/first-top-level H1 headings (e.g., MD041) for these agent-memory files since markdownlint is not part of the repo’s `bun run validate` lint pipeline (oxlint/oxfmt only).
Applied to files:
.claude/agent-memory/archgate-developer/project_rules_engine_internals.md.claude/agent-memory/archgate-developer/project_test_isolation_gotchas.md.claude/agent-memory/archgate-developer/project_oxlint_gotchas.md
📚 Learning: 2026-07-25T00:05:20.592Z
Learnt from: rhuanbarreto
Repo: archgate/cli PR: 496
File: .claude/agent-memory/archgate-developer/project_test_isolation_gotchas.md:10-10
Timestamp: 2026-07-25T00:05:20.592Z
Learning: When reviewing documentation/agent-memory entries under `.claude/agent-memory/**`, do not enforce GEN-004’s “forward-only” comment/narrative requirement. These entries are allowed to keep historical/past-tense incident narratives and dated markers (e.g., `Found YYYY-MM-DD`) because the context is intended to help future agents evaluate edge cases. Outside this scope, GEN-004’s forward-only rule should still apply.
Applied to files:
.claude/agent-memory/archgate-developer/project_rules_engine_internals.md.claude/agent-memory/archgate-developer/project_test_isolation_gotchas.md.claude/agent-memory/archgate-developer/project_oxlint_gotchas.md
📚 Learning: 2026-07-25T00:05:58.884Z
Learnt from: rhuanbarreto
Repo: archgate/cli PR: 496
File: tests/helpers/auth.test.ts:38-46
Timestamp: 2026-07-25T00:05:58.884Z
Learning: When reviewing the Archgate CLI repository’s GEN-004 “concise forward-only narration” comments, don’t rely only on the automated phrase-based narration checks. Those checks can pass even when the comment wording describes historical/transfer semantics rather than current behavior (e.g., saying a prior restore “leaked” a value or a later subprocess “inherited it”). Manually verify that the comment describes the code’s current, forward behavior; flag or adjust comments that imply past/historical state transfer even if GEN-004 enforcement passes.
Applied to files:
tests/engine/check-case.test.tssrc/engine/check-case.tssrc/engine/yaml-utils.tsdocs/scripts/generate-llms-full.tstests/engine/yaml-utils.test.tssrc/formats/rules.tssrc/helpers/rules-shim.tstests/engine/runner-yaml-case.test.tssrc/engine/runner.ts
📚 Learning: 2026-07-25T00:05:59.109Z
Learnt from: rhuanbarreto
Repo: archgate/cli PR: 496
File: src/cli.ts:0-0
Timestamp: 2026-07-25T00:05:59.109Z
Learning: Code comments may include a concise issue/PR reference (per GEN-004) when it’s used to point readers to fuller rationale instead of inlining that rationale. During review, flag surrounding comment prose that reads like historical context or narrates refactors/relocations; a bare GEN-004-style reference is allowed and should not be flagged by itself.
Applied to files:
tests/engine/check-case.test.tssrc/engine/check-case.tssrc/engine/yaml-utils.tsdocs/scripts/generate-llms-full.tstests/engine/yaml-utils.test.tssrc/formats/rules.tssrc/helpers/rules-shim.tstests/engine/runner-yaml-case.test.tssrc/engine/runner.ts
📚 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] ~218-~218: Pontuação duplicada
Context: ...bjeto de resultado cobre as duas formas -- um mapeamento frontmatter anulável e ...
(DOUBLE_PUNCTUATION_XML)
[uncategorized] ~220-~220: Pontuação duplicada
Context: ...re null; content é o valor parseado -- faça o cast para o tipo esperado na sua...
(DOUBLE_PUNCTUATION_XML)
[uncategorized] ~220-~220: Encontrada possível ausência de vírgula.
Context: ...res --- de um stream multi-documento (manifestos Kubernetes, configurações de CI) nunca ...
(AI_PT_HYDRA_LEO_MISSING_COMMA)
[uncategorized] ~221-~221: Esta conjunção deve ser separada por vírgulas e só deve ser utilizada no início duma frase para efeitos de estilo.
Context: ..., espelhando fileAtBase), {} quando existe mas está vazio. content é o restante do c...
(VERB_COMMA_CONJUNCTION)
[uncategorized] ~221-~221: Pontuação duplicada
Context: ... do texto, sem espaços nas extremidades -- ele não é parseado como YAML. `rea...
(DOUBLE_PUNCTUATION_XML)
[uncategorized] ~404-~404: Pontuação duplicada
Context: ...tring segue um esquema de capitalização -- a substituição integrada para os regexe...
(DOUBLE_PUNCTUATION_XML)
[uncategorized] ~404-~404: Pontuação duplicada
Context: ...cisavam escrever à mão. Síncrono e puro -- não precisa de await. A correspondênc...
(DOUBLE_PUNCTUATION_XML)
🪛 markdownlint-cli2 (0.23.0)
.claude/agent-memory/archgate-developer/project_rules_engine_internals.md
[warning] 8-8: First line in a file should be a top-level heading
(MD041, first-line-heading, first-line-h1)
🔇 Additional comments (18)
tests/engine/check-case.test.ts (1)
1-93: LGTM!tests/engine/yaml-utils.test.ts (1)
1-127: LGTM!tests/engine/runner-yaml-case.test.ts (1)
1-169: LGTM!.claude/agent-memory/archgate-developer/project_oxlint_gotchas.md (1)
15-15: LGTM!.claude/agent-memory/archgate-developer/project_rules_engine_internals.md (1)
8-8: LGTM!.claude/agent-memory/archgate-developer/project_test_isolation_gotchas.md (1)
15-15: LGTM!src/engine/check-case.ts (1)
18-23: 🎯 Functional CorrectnessNo change needed. The
/uflag restricts these patterns so a final newline does not satisfy any scheme; values such as"Foo\n"failcamelCase.> Likely an incorrect or invalid review comment.src/formats/rules.ts (1)
65-112: LGTM!Also applies to: 335-342
src/helpers/rules-shim.ts (1)
72-115: LGTM!Also applies to: 314-321
docs/src/content/docs/nb/reference/rule-api.mdx (1)
69-72: LGTM!Also applies to: 199-251, 391-427
docs/src/content/docs/pt-br/reference/rule-api.mdx (1)
69-72: LGTM!Also applies to: 199-251, 391-427
docs/src/content/docs/reference/rule-api.mdx (1)
69-72: LGTM!Also applies to: 199-251, 391-427
docs/public/llms-full.txt (1)
5218-5226: LGTM!Also applies to: 5353-5404, 5544-5580
.archgate/adrs/ARCH-022-ast-aware-rule-context.rules.ts (1)
25-45: LGTM!Also applies to: 226-269
.archgate/adrs/ARCH-022-ast-aware-rule-context.md (1)
97-97: LGTM!Also applies to: 152-158
src/engine/runner.ts (3)
3-3: LGTM!Also applies to: 12-12, 39-39, 51-53
383-392: LGTM!
394-400: LGTM!
readYAML reads a YAML file or a Markdown file with YAML frontmatter,
returning one { frontmatter, content } object: extension-based dispatch
parses .yml/.yaml as a whole document (multi-document --- separators are
never misread as frontmatter) and every other file as an optional leading
frontmatter block plus body text. Values are typed as YamlValue, the
JSON-like data YAML's core schema produces.
checkCase validates a string against a casing scheme (kebab-case,
camelCase, PascalCase, snake_case, SCREAMING_SNAKE_CASE) — pure and
synchronous, with camelCase/PascalCase following the typescript-eslint
naming-convention definition.
Both helpers close the rule-file duplication gap discussed in #490: rule
files are sandboxed and cannot import shared modules, so common helpers
belong on ctx (ARCH-024).
The path-sandbox helpers move unchanged from runner.ts to
src/engine/safe-path.ts to keep runner.ts under the max-lines limit.
Closes #490
Signed-off-by: Rhuan Barreto <rhuan@barreto.work>
Adding readYAML and checkCase showed the RuleContext mirror between src/formats/rules.ts and the generated ambient shim in src/helpers/rules-shim.ts is maintained entirely by hand — only the ast() signature was enforced (single-ast-method). A drifted shim silently hands rule authors wrong types with no signal. The new rulecontext-shim-parity rule extracts the interface RuleContext member names from both surfaces and fails on any member present in one but missing from the other, in both directions. Extraction is a regex over raw text rather than ctx.ast(), because Bun.Transpiler erases type-only interface declarations before the tree is built. Signed-off-by: Rhuan Barreto <rhuan@barreto.work>
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
…ents stripJsx's component-tag patterns cannot tell a JSX tag from a TypeScript generic whose argument is capitalized, and they ran over code as well as prose. Promise<GrepMatch[]>, Promise<AstNode> and Promise<ReadYamlResult> were all published to llms-full.txt as a bare Promise, while lowercase arguments (Promise<string>) survived — so the AI-facing docs advertised the wrong contract for grep, grepFiles, ast and readYAML. Stripping now skips both fenced code blocks and inline code spans (the latter carried the same damage inside reference tables). Prose stripping is unchanged: JSX components, imports and admonition markers are still removed. Also address review feedback on the readYAML surface: - FRONTMATTER_REGEX now anchors both fences to their own line, so '----' or '---note' no longer terminate a block and leave stray characters at the head of the body. Trailing spaces/tabs are tolerated; end-of-input closing is accepted. - Mirror the CaseScheme degenerate-value note into the generated shim JSDoc, the manual parity item rulecontext-shim-parity deliberately does not cover. Signed-off-by: Rhuan Barreto <rhuan@barreto.work>
Two non-obvious lessons from the readYAML/checkCase work: - Directory symlinks in tests should use symlinkSync(target, path, "junction"). The type arg is ignored on POSIX but on Windows creates a junction, which needs no admin rights and which lstat reports as a symlink — so the test runs everywhere instead of silently skipping, as the pre-existing leaf-symlink test had been doing. - Commit before fire-testing a rule or guard: the mutate/verify/restore loop restores with git checkout, which discards all uncommitted work in that file, including the fix under test. Signed-off-by: Rhuan Barreto <rhuan@barreto.work>
FRONTMATTER_REGEX required a newline before the closing fence, so the
degenerate empty block `---\n---` did not match: readYAML returned
frontmatter: null and left both delimiters at the head of content,
contradicting the documented {}-for-empty-frontmatter contract. The body
group is now optional, and the undefined capture is coalesced.
The existing empty-block test passed because it used `---\n\n---`, whose
blank line the body group can capture — a near-empty variant, not the empty
case. Tests now cover the degenerate form directly, plus its end-of-input
and CRLF spellings.
Also address review feedback:
- readYAML's JSDoc described content as unknown in both the source interface
and the generated shim, left stale when content narrowed to YamlValue.
Both now state YamlValue and drop the obsolete cast advice.
- Reword the llms-full generator comment to describe current behavior
instead of narrating what previous output did.
Signed-off-by: Rhuan Barreto <rhuan@barreto.work>
GEN-004 landed in #496 while this branch was open, capping contiguous comment runs at 5 lines of prose. Ten blocks added here exceeded it. Each is trimmed to current-behavior essentials, with the rationale moved behind @see pointers to the ADR, the tests, or the type that carries the contract — the remedy GEN-004's own fix advice recommends. The rules.ts and rules-shim.ts JSDoc stay mirrored so ARCH-022's manual parity item holds. No behavior change; llms-full.txt regenerated for the trimmed prose. Signed-off-by: Rhuan Barreto <rhuan@barreto.work>
c011274 to
d6d305d
Compare
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 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/reference/rule-api.mdx`:
- Around line 218-234: Update the readYAML documentation to consistently state
that YamlValue content needs no cast: in
docs/src/content/docs/reference/rule-api.mdx:218-234, remove the readJSON-style
cast guidance; re-translate the corrected bullet in
docs/src/content/docs/nb/reference/rule-api.mdx:218-234 and
docs/src/content/docs/pt-br/reference/rule-api.mdx:218-234; then regenerate
docs/public/llms-full.txt:5353-5388 with docs/scripts/generate-llms-full.ts.
In `@src/engine/check-case.ts`:
- Around line 28-34: Update the scheme validation in the case-checking flow to
require scheme ownership via Object.hasOwn(CASE_PATTERNS, scheme) before
indexing CASE_PATTERNS. Treat inherited names such as constructor and toString
as unknown schemes and preserve the existing documented error; only call
pattern.test(value) after the own-property check succeeds.
🪄 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: ac1e26fb-3aed-4558-9a81-29f606ab3e5f
📒 Files selected for processing (18)
.archgate/adrs/ARCH-022-ast-aware-rule-context.md.archgate/adrs/ARCH-022-ast-aware-rule-context.rules.ts.claude/agent-memory/archgate-developer/project_oxlint_gotchas.md.claude/agent-memory/archgate-developer/project_rules_engine_internals.md.claude/agent-memory/archgate-developer/project_test_isolation_gotchas.mddocs/public/llms-full.txtdocs/scripts/generate-llms-full.tsdocs/src/content/docs/nb/reference/rule-api.mdxdocs/src/content/docs/pt-br/reference/rule-api.mdxdocs/src/content/docs/reference/rule-api.mdxsrc/engine/check-case.tssrc/engine/runner.tssrc/engine/yaml-utils.tssrc/formats/rules.tssrc/helpers/rules-shim.tstests/engine/check-case.test.tstests/engine/runner-yaml-case.test.tstests/engine/yaml-utils.test.ts
📜 Review details
⏰ Context from checks skipped due to timeout. (3)
- GitHub Check: Smoke Test (Windows) / Windows
- GitHub Check: Analyze (java-kotlin)
- GitHub Check: Cloudflare Pages
🧰 Additional context used
📓 Path-based instructions (24)
**/*.{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, useBun.file()instead offs.readFile()for simple reads.
Prefernode:built-in modules such asnode:util,node:path, andnode:fsover npm alternatives.
Do not use utility libraries for single functions, such as importing lodash for one helper likepick.
Do not use path aliases (tsconfig paths); use relative imports with Bun's native module resolution.
Do not install packages globally during development; usebunxfor one-off tools.
Files:
tests/engine/check-case.test.tssrc/engine/check-case.tssrc/engine/yaml-utils.tsdocs/scripts/generate-llms-full.tssrc/helpers/rules-shim.tstests/engine/runner-yaml-case.test.tssrc/formats/rules.tssrc/engine/runner.tstests/engine/yaml-utils.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 mutatingprocess.platformdirectly.
tests/**/*.ts: Use Bun's built-inbun:testrunner for all tests; do not import test utilities fromnode:test.
Shared test helpers must also userestoreEnvwhen restoring environment variables.
Files:
tests/engine/check-case.test.tstests/engine/runner-yaml-case.test.tstests/engine/yaml-utils.test.ts
{src,tests}/**/*.ts
📄 CodeRabbit inference engine (.archgate/adrs/LEGAL-001-spdx-license-headers.md)
{src,tests}/**/*.ts: Every TypeScript source file insrc/andtests/must begin with// SPDX-License-Identifier: Apache-2.0followed by// Copyright 2026 Archgate.
If a TypeScript file has a shebang line (for example#!/usr/bin/env buninsrc/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/check-case.test.tssrc/engine/check-case.tssrc/engine/yaml-utils.tssrc/helpers/rules-shim.tstests/engine/runner-yaml-case.test.tssrc/formats/rules.tssrc/engine/runner.tstests/engine/yaml-utils.test.ts
tests/**/*.test.ts
📄 CodeRabbit inference engine (.archgate/adrs/ARCH-005-testing-standards.md)
tests/**/*.test.ts: Place tests intests/mirroring thesrc/directory structure, and name test files with the.test.tssuffix.
Test public module interfaces rather than private implementation details, use descriptive test names, and do not depend on network access.
Use isolated temporary directories created withmkdtempfor filesystem tests, and clean them up inafterEachorafterAll. Do not use hardcoded user or system paths.
Close external SDK instances such as servers, clients, and transports inafterEachorafterAll; manage their lifecycle in test hooks rather than individual test bodies.
When a temporary git repository performs commits, configure localuser.emailanduser.nameimmediately aftergit init; do not rely on global git identity.
Every runnabletest()orit()must contain at least oneexpect()assertion. Make implicit no-throw contracts explicit withnot.toThrow()orresolves.toBeUndefined(). Usetest.skiportest.todofor intentional placeholders.
Usetest.skipIf(condition),test.skip, ortest.todofor conditional or intentionally disabled tests; do not use bare early returns or empty callbacks to skip tests, and do not skip without a tracking issue.
When adding assertions to an older test file, importexpectfrombun:test.
Mock HTTP requests by assigning directly toglobalThis.fetch, and restore the original fetch implementation or mock inafterEach; do not mocknode:fetch.
Mock first-party modules withimport * as modandspyOn(mod, "fn"), restoring spies after each test; do not use process-globalmock.module()for first-party modules.
Wrap inlinespyOnormockImplementationusage intry/finallysomockRestore()always runs, or manage spies inbeforeEachandafterEach.
When redirecting user-scope paths, mocknode:os'shomedir()rather than relying on runtimeHOMEoverrides; use environment overrides only for code that reads environment variables directly at call time.
Re...
Files:
tests/engine/check-case.test.tstests/engine/runner-yaml-case.test.tstests/engine/yaml-utils.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.tsfile with automated checks that run viaarchgate check.When reviewing, you must:
- Treat ADR violations as blocking issues, not suggestions.
- Cite the specific ADR ID when flagging a violation (e.g., "Violates ARCH-006").
- Focus on semantic and contextual violations that automated rules cannot catch —
the.rules.tsfiles already cover syntactic/structural patterns.- If you are unsure whether something violates an ADR, flag it as a question
rather than approving it.
Files:
tests/engine/check-case.test.tssrc/engine/check-case.tssrc/engine/yaml-utils.tsdocs/scripts/generate-llms-full.tssrc/helpers/rules-shim.tstests/engine/runner-yaml-case.test.tsdocs/src/content/docs/nb/reference/rule-api.mdxsrc/formats/rules.tssrc/engine/runner.tstests/engine/yaml-utils.test.tsdocs/src/content/docs/reference/rule-api.mdxdocs/src/content/docs/pt-br/reference/rule-api.mdxdocs/public/llms-full.txt
src/**/*.ts
📄 CodeRabbit inference engine (.archgate/adrs/ARCH-004-no-barrel-files.md)
src/**/*.ts: Do not re-export symbols from another module in any source file; statements likeexport { X } from "./other"andexport type { X } from "./other"are forbidden.
Import symbols directly from the module that defines them; do not import from a directory path such as../formatsexpecting implicitindex.tsresolution.
src/**/*.ts: Useawait Bun.file(path).json()when reading JSON files in Bun TypeScript source code; do not useJSON.parse(await Bun.file(path).text())orJSON.parse(fs.readFileSync(path, "utf-8"))for file reads.
UseBun.JSONC.parse()when reading files that may contain comments, such astsconfig.json, instead of plainJSON.parse()on file contents.
ReserveJSON.parse()for parsing JSON strings from non-file sources such as API responses or string variables; do not use it as the default for reading JSON files.
src/**/*.ts: In TypeScript source files undersrc/, useBun.envinstead ofprocess.envfor all environment variable reads and writes;process.envmust not be used.
In TypeScript source files undersrc/, use nullish coalescing for environment-variable defaults, e.g.Bun.env.NODE_ENV ?? "production".
In TypeScript source files undersrc/, useBoolean(Bun.env.CI)for truthy checks on environment flags.
In TypeScript source files undersrc/, do not destructureBun.env(for example,const { HOME } = Bun.env); access properties individually instead.
In TypeScript source files undersrc/, do not referenceprocess.enveven in comments that suggest using it.
src/**/*.ts: Heavy dependencies such asinquirer,posthog-node,@sentry/*, and any similarly expensive runtime-only dependency MUST be loaded with dynamicimport()at the point of use, never as a static value import at module top level.
Type-only references to heavy modules must useimport type(for example,import type { PostHog } from "posthog-node"orimport type * as SentryNs from "@sentry/node-core/light"); type-only...
Files:
src/engine/check-case.tssrc/engine/yaml-utils.tssrc/helpers/rules-shim.tssrc/formats/rules.tssrc/engine/runner.ts
src/**/!(*platform).ts
📄 CodeRabbit inference engine (.archgate/adrs/ARCH-009-platform-detection-helper.md)
src/**/!(*platform).ts: Insrc/TypeScript source files, do not readprocess.platformdirectly; usesrc/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 insrc/TypeScript source.
When behavior differs between Linux and Windows, account for WSL by usingisWSL()rather than assuming `
Files:
src/engine/check-case.tssrc/engine/yaml-utils.tssrc/helpers/rules-shim.tssrc/formats/rules.tssrc/engine/runner.ts
src/{helpers,engine}/**/*.ts
📄 CodeRabbit inference engine (.archgate/adrs/ARCH-002-error-handling.md)
Do not use
console.log(),console.warn(), orconsole.info()directly in helper or engine files; uselogInfo()orlogWarn()instead.
Files:
src/engine/check-case.tssrc/engine/yaml-utils.tssrc/helpers/rules-shim.tssrc/engine/runner.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 throughlistMatchingFilesfor rule-facing inputs ormatchTrackedFilesfor trusted ADR frontmatter patterns.
When the target is a Git repository andrespectGitignoreis not false, pass the tracked set fromgetGitTrackedFilesto matching operations.
Per-runRunCachesmust 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 cachereadJSONresults 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.Do not add
tree-sitter,web-tree-sitter, native parser bindings, WASM grammars, or other new production dependencies for this AST feature.
Files:
src/engine/check-case.tssrc/engine/yaml-utils.tssrc/engine/runner.ts
src/helpers/rules-shim.ts
📄 CodeRabbit inference engine (.archgate/adrs/ARCH-022-ast-aware-rule-context.md)
Mirror every RuleContext surface change, including
ast,fileAtBase, options, ambient types, signatures, and JSDoc, in the generated rules shim.
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 underdocs/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/nb/reference/rule-api.mdxdocs/src/content/docs/reference/rule-api.mdxdocs/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>.mdxand add the page todocs/astro.config.mjssidebar configuration.
Files:
docs/src/content/docs/nb/reference/rule-api.mdxdocs/src/content/docs/reference/rule-api.mdxdocs/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/nb/reference/rule-api.mdxdocs/src/content/docs/reference/rule-api.mdxdocs/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 underdocs/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, andlink/href/slugattribute 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/nb/reference/rule-api.mdxdocs/src/content/docs/reference/rule-api.mdxdocs/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
duform and correct Norwegian characters (æ,ø,å).
Files:
docs/src/content/docs/nb/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, usesafeParse(), and reuseAdrFrontmatterSchema.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, language, opts?)method, with language dispatch hidden from rule authors; document that returned AST shapes differ by language.
Files:
src/formats/rules.ts
src/engine/{runner.ts,ast-support.ts,js-parser.ts}
📄 CodeRabbit inference engine (.archgate/adrs/ARCH-022-ast-aware-rule-context.md)
Implement
ctx.ast()internally increateRuleContext()with exactly this guardrail order before subprocess execution: path safety, language plausibility, interpreter availability, and guarded invocation.
Files:
src/engine/runner.ts
src/engine/{runner.ts,ast-support.ts}
📄 CodeRabbit inference engine (.archgate/adrs/ARCH-022-ast-aware-rule-context.md)
src/engine/{runner.ts,ast-support.ts}: Use the existingmeriyahparser for TypeScript and JavaScript without spawning a subprocess, and factor parsing into a shared helper reused byrule-scanner.tsandctx.ast().
Use onlyBun.spawnwith array-based arguments for Python/Ruby AST subprocesses; do not use shell interpolation,Bun.$, or raw subprocess primitives exposed to rules.
Run Python AST parsing withpython -I -c ...isolation so the target project's working directory cannot shadow standard-library modules.
Probe Python/Ruby interpreter availability using platform-appropriate candidates, cache the result once per check invocation, and use the resolved executable for the real invocation.
Validate the requested file's extension and/or leading content against the requested AST language before invoking Python or Ruby.
ctx.ast()must throw on missing interpreters, parse failures, missing base revisions, and files absent at the base revision; errors must distinguish these causes in their messages and must never returnnull.
Preserve language-native AST shapes: ESTree for TypeScript/JavaScript, Python's standardastschema, and Ruby's native Ripper s-expressions; do not normalize them into a common shape.
Strip a leading UTF-8 BOM before Python and Ruby parsing using UTF-8-signature-aware file reads.
Do not trust TypeScript ASTnode.locpositions because parsing uses transpiled source; relocate reported constructs against the original source. JavaScript locations are source-accurate.
Files:
src/engine/runner.ts
src/engine/{runner.ts,safe-path.ts}
📄 CodeRabbit inference engine (.archgate/adrs/ARCH-022-ast-aware-rule-context.md)
Apply
safePath()and reject symlinks in every path component below the project root before reading or parsing an AST source file.
Files:
src/engine/runner.ts
src/engine/{git-files.ts,runner.ts}
📄 CodeRabbit inference engine (.archgate/adrs/ARCH-022-ast-aware-rule-context.md)
Implement
{ rev: "base" }AST reads andfileAtBase()using the merge base of--baseand HEAD, matching the three-dotchangedFilescomparison.
Files:
src/engine/runner.ts
src/engine/{ast-support.ts,runner.ts}
📄 CodeRabbit inference engine (.archgate/adrs/ARCH-022-ast-aware-rule-context.md)
For base Python/Ruby content, use a securely created private temporary directory and exclusive file creation, then pass the source through the same isolated AST subprocess programs.
Files:
src/engine/runner.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
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
🧠 Learnings (7)
📚 Learning: 2026-07-25T00:05:58.884Z
Learnt from: rhuanbarreto
Repo: archgate/cli PR: 496
File: tests/helpers/auth.test.ts:38-46
Timestamp: 2026-07-25T00:05:58.884Z
Learning: When reviewing the Archgate CLI repository’s GEN-004 “concise forward-only narration” comments, don’t rely only on the automated phrase-based narration checks. Those checks can pass even when the comment wording describes historical/transfer semantics rather than current behavior (e.g., saying a prior restore “leaked” a value or a later subprocess “inherited it”). Manually verify that the comment describes the code’s current, forward behavior; flag or adjust comments that imply past/historical state transfer even if GEN-004 enforcement passes.
Applied to files:
tests/engine/check-case.test.tssrc/engine/check-case.tssrc/engine/yaml-utils.tsdocs/scripts/generate-llms-full.tssrc/helpers/rules-shim.tstests/engine/runner-yaml-case.test.tssrc/formats/rules.tssrc/engine/runner.tstests/engine/yaml-utils.test.ts
📚 Learning: 2026-07-25T00:05:59.109Z
Learnt from: rhuanbarreto
Repo: archgate/cli PR: 496
File: src/cli.ts:0-0
Timestamp: 2026-07-25T00:05:59.109Z
Learning: Code comments may include a concise issue/PR reference (per GEN-004) when it’s used to point readers to fuller rationale instead of inlining that rationale. During review, flag surrounding comment prose that reads like historical context or narrates refactors/relocations; a bare GEN-004-style reference is allowed and should not be flagged by itself.
Applied to files:
tests/engine/check-case.test.tssrc/engine/check-case.tssrc/engine/yaml-utils.tsdocs/scripts/generate-llms-full.tssrc/helpers/rules-shim.tstests/engine/runner-yaml-case.test.tssrc/formats/rules.tssrc/engine/runner.tstests/engine/yaml-utils.test.ts
📚 Learning: 2026-06-11T12:50:28.661Z
Learnt from: rhuanbarreto
Repo: archgate/cli PR: 406
File: .claude/agent-memory/archgate-developer/feedback_prefer_tests_over_adr_rules.md:8-18
Timestamp: 2026-06-11T12:50:28.661Z
Learning: In `archgate/cli`, for markdown files under `.claude/agent-memory/`, follow the established convention: use YAML frontmatter (with a `name:` field used as the document title) and do not require a top-level `#` (H1) heading. During code review, do not flag missing first-line/first-top-level H1 headings (e.g., MD041) for these agent-memory files since markdownlint is not part of the repo’s `bun run validate` lint pipeline (oxlint/oxfmt only).
Applied to files:
.claude/agent-memory/archgate-developer/project_rules_engine_internals.md.claude/agent-memory/archgate-developer/project_oxlint_gotchas.md.claude/agent-memory/archgate-developer/project_test_isolation_gotchas.md
📚 Learning: 2026-07-25T00:05:20.592Z
Learnt from: rhuanbarreto
Repo: archgate/cli PR: 496
File: .claude/agent-memory/archgate-developer/project_test_isolation_gotchas.md:10-10
Timestamp: 2026-07-25T00:05:20.592Z
Learning: When reviewing documentation/agent-memory entries under `.claude/agent-memory/**`, do not enforce GEN-004’s “forward-only” comment/narrative requirement. These entries are allowed to keep historical/past-tense incident narratives and dated markers (e.g., `Found YYYY-MM-DD`) because the context is intended to help future agents evaluate edge cases. Outside this scope, GEN-004’s forward-only rule should still apply.
Applied to files:
.claude/agent-memory/archgate-developer/project_rules_engine_internals.md.claude/agent-memory/archgate-developer/project_oxlint_gotchas.md.claude/agent-memory/archgate-developer/project_test_isolation_gotchas.md
📚 Learning: 2026-07-25T10:10:28.469Z
Learnt from: rhuanbarreto
Repo: archgate/cli PR: 497
File: docs/scripts/generate-llms-full.ts:0-0
Timestamp: 2026-07-25T10:10:28.469Z
Learning: In the Archgate CLI repo, ensure comments and documentation in docs TypeScript sources use concise, forward-only, version-independent wording: describe the current behavior and its consequences (what happens now and why) rather than historical context such as prior bugs, previous/old outputs, or state-transfer narratives. Even when documenting a newly fixed bug, write the entry as a present-tense description of the behavior and impact rather than a “before/after” or history-based explanation (e.g., avoid historical-style explanations alongside comment tags like `stripJsxOutsideCode`).
Applied to files:
docs/scripts/generate-llms-full.ts
📚 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] ~218-~218: Pontuação duplicada
Context: ...bjeto de resultado cobre as duas formas -- um mapeamento frontmatter anulável e ...
(DOUBLE_PUNCTUATION_XML)
[uncategorized] ~220-~220: Pontuação duplicada
Context: ...re null; content é o valor parseado -- faça o cast para o tipo esperado na sua...
(DOUBLE_PUNCTUATION_XML)
[uncategorized] ~220-~220: Encontrada possível ausência de vírgula.
Context: ...res --- de um stream multi-documento (manifestos Kubernetes, configurações de CI) nunca ...
(AI_PT_HYDRA_LEO_MISSING_COMMA)
[uncategorized] ~221-~221: Esta conjunção deve ser separada por vírgulas e só deve ser utilizada no início duma frase para efeitos de estilo.
Context: ..., espelhando fileAtBase), {} quando existe mas está vazio. content é o restante do c...
(VERB_COMMA_CONJUNCTION)
[uncategorized] ~221-~221: Pontuação duplicada
Context: ... do texto, sem espaços nas extremidades -- ele não é parseado como YAML. `rea...
(DOUBLE_PUNCTUATION_XML)
[uncategorized] ~404-~404: Pontuação duplicada
Context: ...tring segue um esquema de capitalização -- a substituição integrada para os regexe...
(DOUBLE_PUNCTUATION_XML)
[uncategorized] ~404-~404: Pontuação duplicada
Context: ...cisavam escrever à mão. Síncrono e puro -- não precisa de await. A correspondênc...
(DOUBLE_PUNCTUATION_XML)
🪛 markdownlint-cli2 (0.23.0)
.claude/agent-memory/archgate-developer/project_rules_engine_internals.md
[warning] 8-8: First line in a file should be a top-level heading
(MD041, first-line-heading, first-line-h1)
🔇 Additional comments (18)
tests/engine/check-case.test.ts (1)
1-93: LGTM!tests/engine/yaml-utils.test.ts (1)
1-148: LGTM!tests/engine/runner-yaml-case.test.ts (1)
1-169: LGTM!.claude/agent-memory/archgate-developer/project_oxlint_gotchas.md (1)
15-15: LGTM!Also applies to: 17-18
.claude/agent-memory/archgate-developer/project_rules_engine_internals.md (1)
8-9: LGTM!Also applies to: 21-24
.claude/agent-memory/archgate-developer/project_test_isolation_gotchas.md (1)
15-15: LGTM!src/engine/check-case.ts (1)
1-3: LGTM!Also applies to: 5-18, 20-26
src/engine/yaml-utils.ts (1)
1-23: LGTM!Also applies to: 25-49, 51-88
src/engine/runner.ts (1)
12-12: LGTM!Also applies to: 39-39, 53-53, 143-144, 191-193, 242-245, 280-284, 350-353, 366-375, 377-383, 401-405
src/formats/rules.ts (1)
58-99: LGTM!Also applies to: 262-273, 325-332
src/helpers/rules-shim.ts (1)
72-110: LGTM!Also applies to: 267-278, 330-337
docs/src/content/docs/reference/rule-api.mdx (1)
69-72: LGTM!Also applies to: 391-427
docs/src/content/docs/nb/reference/rule-api.mdx (1)
69-72: LGTM!Also applies to: 391-427
docs/src/content/docs/pt-br/reference/rule-api.mdx (1)
69-72: LGTM!Also applies to: 391-427
docs/public/llms-full.txt (1)
870-871: LGTM!Also applies to: 3333-3333, 3347-3347, 3392-3392, 5218-5229, 5282-5282, 5294-5294, 5544-5580, 5743-5743, 6117-6117, 6325-6325, 6713-6713, 6819-6829, 6926-6927, 7022-7022, 7255-7255, 7268-7268, 7368-7388, 7493-7493, 7568-7568, 7582-7582, 7595-7595, 7695-7695, 7906-7906
docs/scripts/generate-llms-full.ts (1)
65-87: LGTM!Also applies to: 120-120, 153-153
.archgate/adrs/ARCH-022-ast-aware-rule-context.rules.ts (1)
23-41: LGTM!Also applies to: 221-264
.archgate/adrs/ARCH-022-ast-aware-rule-context.md (1)
97-97: LGTM!Also applies to: 152-158
checkCase guarded with a truthiness test on the looked-up pattern, so a scheme name inherited from Object.prototype — "constructor", "toString", "__proto__" — resolved to a function, passed the guard, and threw TypeError: pattern.test is not a function instead of the documented unknown-scheme error. Rule files can reach this by building a scheme name dynamically, which is exactly the case the throw exists to report clearly. Object.hasOwn now gates the lookup. Also fix the readYAML docs contradicting themselves on casting: the .yml/.yaml bullet still said to cast "as with readJSON" while the example below it narrowed the same value with a typeof check and a "no cast needed" comment. readJSON returns unknown and does need a cast; readYAML returns the narrower YamlValue and does not. Reworded in all three locales, with llms-full.txt regenerated. Signed-off-by: Rhuan Barreto <rhuan@barreto.work>
# archgate ## [0.51.0](v0.50.0...v0.51.0) (2026-07-26) ### Features * **adrs:** enforce concise, forward-only code comments (GEN-004) ([#496](#496)) ([9a114b3](9a114b3)), references [#2123](https://github.com/archgate/cli/issues/2123) * **adrs:** flag stray files at the repository root (GEN-005) ([#535](#535)) ([6a6e765](6a6e765)), closes [#514](#514), references [#500](#500) * **engine:** add ctx.readYAML and ctx.checkCase rule helpers ([#497](#497)) ([c5d82c5](c5d82c5)), closes [#490](#490), references [#490](#490) [#491](#491) [#499](#499) [#499](#499) [#499](#499) [#499](#499) * report truncated ADR briefings, trim the ADR corpus 15.6%, add GEN-005 briefing budget ([#501](#501)) ([a9dab40](a9dab40)) ### Bug Fixes * **docs:** relocate ADR content to clear briefing-budget warnings ([#531](#531)) ([c7419b3](c7419b3)) * **docs:** restore pt-br diacritics and enforce locale content integrity ([#523](#523)) ([db39104](db39104)), closes [#516](#516), references [#231](#231) * **engine:** allow symlinks that resolve inside the project root ([#500](#500)) ([387bf15](387bf15)) * **engine:** reject rule-file reads through a symlinked ancestor directory ([#499](#499)) ([a555f9d](a555f9d)), references [#497](#497) [#491](#491) [#497](#497) [#497](#497) [#497](#497) [#497](#497) * **engine:** scan top-level export declarations with a null source ([#493](#493)) ([d07db03](d07db03)), closes [#491](#491) * **engine:** stop dropping AST nodes with exotic literal values ([#494](#494)) ([0015542](0015542)), closes [#493](#493) [#493](#493) * **lint:** resolve no-bare-env-restore by captured key and lexical scope ([#524](#524)) ([7094a3a](7094a3a)), closes [#498](#498) * **rules:** make ARCH-020 and ARCH-023 match ctx.ast() instead of raw text ([#533](#533)) ([ad5529b](ad5529b)), closes [#513](#513), references [#486](#486) * **tests:** replace bun:test anti-patterns with idiomatic patterns ([#512](#512)) ([bcb086f](bcb086f)) --- 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" } } ``` ```` ### Custom Changelog Preamble You can add custom markdown to the top of the changelog (right after the version header) using the `!simple-release/set-preamble` command. The markdown after the command line becomes the preamble. ```md !simple-release/set-preamble ## What's new? - The website was completely redesigned - The new API gives you awesome possibilities ``` In a monorepo, pass the full package name after the command to target a single package's changelog. Wrap the name in backticks so GitHub keeps it as text instead of a mention: ```md !simple-release/set-preamble `@your-org/core` ## Core changes - New plugin system ``` Use one comment per package, plus one without a name for the whole release. ### Access Restrictions The commands 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 - The last `!simple-release/set-preamble` comment per package takes priority - JSON must be valid, otherwise the `set-options` command will be ignored - Parameters apply only to the current release execution - The commands 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>
Closes #490.
Context
#490 asked for shared helper modules importable from
.rules.tsfiles. That was declined in #491 — following relative imports would turn the scanner's single-file view into a recursive resolver plus containment checker, which becomes the security boundary (exactly what ARCH-024 declined and named as a tracked risk). The agreed path for the underlying duplication pain was to move the common helpers ontoctxinstead, andreadYAML(with frontmatter support) pluscheckCasewere the two named there.This PR adds both. The sandbox boundary is untouched — no new subprocess site, no new resolver, no new dependency (
Bun.YAMLis a runtime built-in, per ARCH-006).ctx.readYAML(path)Returns one object covering both YAML documents and Markdown frontmatter:
Dispatch is extension-based, not content-sniffing:
.yml/.yaml— the whole document parses as YAML.frontmatteris alwaysnull,contentis the parsed value. Because dispatch is by extension, a multi-document stream's---separators (Kubernetes manifests, CI configs) are never misread as a frontmatter block.----delimited block parses asfrontmatter:nullwhen absent,{}when present but empty.contentis the remaining body text, trimmed, and is not parsed as YAML.nullfor "no frontmatter" is deliberate and mirrorsfileAtBase(): "does this file have frontmatter?" is ordinary rule control flow, checkable with one null test rather than atry/catch.Values are typed
YamlValue(the JSON-like data YAML's core schema produces) rather thanunknown, so after atypeofcheck a rule can index into mappings and sequences without casting.Fail-closed like
ast(): a malformed.ymlfile, or a frontmatter block that is invalid YAML or parses to a non-mapping (scalar/sequence), throws — surfacing as a rule execution error (exit 2) instead of a silent false pass. Reads go through the samesafePathsandbox asreadFile, and share the per-run file-text cache; the parsed value is deliberately not cached, matchingreadJSON(rules receive a mutable object, and sharing one instance would leak mutations between rules).ctx.checkCase(value, scheme)Pure and synchronous — no
await. Schemes:kebab-case,camelCase,PascalCase,snake_case,SCREAMING_SNAKE_CASE. Matching is all-or-nothing and ASCII-only; the empty string matches no scheme.camelCase/PascalCasefollow the ecosystem convention (typescript-eslint'snaming-convention): a leading lower/uppercase letter followed by any ASCII alphanumerics, so acronym runs (parseURL,HTTPServer) match. An unrecognized scheme name throws rather than returningfalse, so a typo surfaces as a rule error instead of a silent false pass/fail.Incidental: ARCH-022 gains a fifth rule
Wiring these helpers made it concrete that the
RuleContextmirror betweensrc/formats/rules.tsand the generated ambient shim insrc/helpers/rules-shim.tsis maintained entirely by hand, and that only theast()signature was enforced (single-ast-method). A drifted shim silently hands rule authors wrong types with no signal.The new
rulecontext-shim-parityrule extracts theinterface RuleContextmember names from both surfaces and fails on any member present in one but missing from the other, in both directions. Extraction is a regex over raw text rather thanctx.ast()—Bun.Transpilererases type-only interface declarations before the tree is built, so the AST never contains them. Both failure directions were fire-tested against a deliberately drifted shim before committing; the rule is member-name parity only, so full signature/JSDoc parity stays a documented manual review item.Stacked on #499
safePath/isWithinRoot/resolveUserPathmove out ofrunner.tsintosrc/engine/safe-path.tsbecauserunner.tssits exactly at the 500-linemax-linescap. Review flagged that the extractedsafePathonlylstats the final path component, so a symlinked ancestor directory escapes the sandbox.That gap is pre-existing —
git diffagainstmainshows the extraction is byte-for-byte apart from line-wrapping — so the fix went to its own fast-trackable PR (#499), per the standing preference for pre-existing security findings.But this is the PR that creates
safe-path.ts, so merging it first would land a freshly-added file containing a known escape. Rather than leave that to merge-order convention, this PR is stacked on #499: the fix is present in this branch, the review thread is addressed in this PR's own diff, and the ordering hazard is structural rather than advisory.Tests
tests/engine/yaml-utils.test.ts— whole-document vs frontmatter dispatch, multi-document stream not misread as frontmatter, BOM, CRLF, empty block, body-never-parsed-as-YAML, invalid YAML, non-mapping blocktests/engine/check-case.test.ts— accept/reject tables per scheme, empty string, non-ASCII, unknown-scheme throwtests/engine/runner-yaml-case.test.ts— end-to-end throughrunChecks, including thesafePathsandbox onreadYAMLand a realistic kebab-case filename ruletests/engine/safe-path.test.ts— extracted sandbox helpersDocs
reference/rule-api.mdxin all three locales (en, nb, pt-br) per GEN-002: theRuleContextinterface listing plus newreadYAMLandcheckCasesections.bun run validatepasses (lint, typecheck, format:check, 1600+ tests,archgate check45/45, knip, build:check).