perf(engine): match globs in memory against git-tracked files#474
Conversation
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_923ba3cb-cf9c-471e-92d2-58ebbf982883) |
|
Warning Review limit reached
Next review available in: 48 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 (2)
📝 WalkthroughWalkthroughThe change adds ARCH-023 and an enforcement rule for restricting filesystem glob scans. Engine glob utilities now validate and expand patterns, match against Git-tracked files, and provide a scan fallback. Git file resolution subtracts deleted worktree files and coordinates subprocesses with 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 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: |
c9bcf7d
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://1f5a55f7.archgate-cli.pages.dev |
| Branch Preview URL: | https://perf-engine-in-memory-glob-m.archgate-cli.pages.dev |
Code Coverage
Full HTML report available in workflow artifacts. Per-directory breakdown
|
Every ADR scope resolution and rule-facing file listing (ctx.glob, ctx.grepFiles) walked the filesystem with Bun.Glob#scan() and filtered against the git-tracked set only afterwards. On a project with 333 tracked files and 43,645 filesystem entries (.venv/, data/), a single check performed ~70 full walks, pegging CPU: engine time 1147ms. - Add src/engine/glob-utils.ts: match patterns in memory against the git ls-files set via Bun.Glob#match() (handles dot-paths without options and brace-with-/ groups natively, unlike scan). Scanning is now fallback-only (non-git / respectGitignore: false). The sandbox contract (no .. / absolute patterns, incl. brace alternatives) is validated identically on both paths. - Subtract git ls-files --deleted from the tracked set so in-memory matching only sees files that exist on disk; use Promise.allSettled so a rejected spawn cannot abandon a still-running sibling whose cwd handle locks the directory on Windows (EBUSY). - Add per-run caches in runChecks (glob results + file text, shared promises; glob arrays copied on return; readJSON deliberately uncached to avoid mutable-object leakage between rules). - New ADR ARCH-023 with a companion rule confining engine scan call sites to glob-utils.ts/git-files.ts; extend ARCH-007 with the allSettled lesson. Measured on the affected project: engine 1147ms -> 160ms (7.2x), wall 2.55s -> ~0.9s. This repo's own check: 564ms -> 186ms. Signed-off-by: Rhuan Barreto <rhuan@barreto.work>
3497c23 to
d0d4aad
Compare
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_f12cfd4f-9075-46e7-8c94-68bf474c1f2b) |
Signed-off-by: Rhuan Barreto <rhuan@barreto.work>
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_00cfe663-0c8d-497d-b5cf-c1fa79d1451c) |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 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 `@tests/engine/glob-utils.test.ts`:
- Around line 101-112: Remove the 15-second timeout override from the “tracked
set excludes files deleted from the worktree” test, or increase it above the
project’s 60-second global timeout. Keep the test behavior and assertions
unchanged, and only retain an override if this genuinely slow subprocess-based
test requires more than 60 seconds.
🪄 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: 3a6bc20a-4742-4081-b679-faa8b819b53f
📒 Files selected for processing (11)
.archgate/adrs/ARCH-007-cross-platform-subprocess-execution.md.archgate/adrs/ARCH-023-engine-file-listing-via-in-memory-git-tracked-matching.md.archgate/adrs/ARCH-023-engine-file-listing-via-in-memory-git-tracked-matching.rules.ts.claude/agent-memory/archgate-developer/MEMORY.md.claude/agent-memory/archgate-developer/project_rules_engine_internals.mdsrc/engine/git-files.tssrc/engine/glob-utils.tssrc/engine/runner.tstests/engine/expand-brace-pattern.test.tstests/engine/glob-utils.test.tstests/engine/runner.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 (14)
tests/**/*.test.ts
📄 CodeRabbit inference engine (.archgate/adrs/ARCH-005-testing-standards.md)
tests/**/*.test.ts: Use Bun's built-in test runner (bun:test) for all test files, and place tests undertests/mirroring thesrc/directory structure with<module-name>.test.tsnaming.
Use temp directories (mkdtemp) for filesystem tests, and clean them up inafterEachorafterAll.
Close external SDK instances (servers, clients, transports, connections) inafterEachorafterAll, managing their lifecycle in hooks rather than inside individual test bodies.
When a test creates a temporary git repository and runsgit commit, configure localuser.emailanduser.nameimmediately aftergit init.
Test public module interfaces, not private implementation details.
Use descriptive test names that explain the expected behavior.
Every runnabletest()/it()must contain at least oneexpect()assertion; smoke tests must make the contract explicit withexpect(() => fn()).not.toThrow()orawait expect(promise).resolves.toBeUndefined().
Usetest.skip,test.skipIf, ortest.todofor intentionally empty or disabled tests; do not use barereturnor empty callbacks to skip work.
If the firstexpect()is being added to a previously assertion-less test file, addexpectto thebun:testimport.
When mockingfetchin tests, assign directly toglobalThis.fetchand restore the original or usemock.restore()afterward.
WrapspyOn()and inlinemockImplementation()usage intry/finally, or create and restore spies in hooks, somockRestore()always runs.
Only raise a per-test timeout above the globalbun test --timeout 60000; never set a shorter per-test timeout.
Mock first-party modules withimport * as modplusspyOn(mod, "fn"), notmock.module().
When a test needs to redirect user-scope paths, mockos.homedir()instead of relying onHOME/Bun.env.HOME; restore the spy in test hooks.
Do not depend on network access in unit tests.
Do not leave temp files after test runs.
Do not leave external SDK instances open after tests...
Files:
tests/engine/expand-brace-pattern.test.tstests/engine/runner.test.tstests/engine/glob-utils.test.ts
**/*.{ts,tsx,js,jsx,mjs,cjs}
📄 CodeRabbit inference engine (.archgate/adrs/ARCH-006-dependency-policy.md)
**/*.{ts,tsx,js,jsx,mjs,cjs}: Use Bun built-ins for file I/O (Bun.file,Bun.write), HTTP, subprocess execution (Bun.spawn), globbing (Bun.Glob), and testing (bun:test).
Do not use Node.js-specific APIs when Bun alternatives exist; for example, 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/expand-brace-pattern.test.tstests/engine/runner.test.tssrc/engine/glob-utils.tstests/engine/glob-utils.test.tssrc/engine/git-files.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.
Files:
tests/engine/expand-brace-pattern.test.tstests/engine/runner.test.tstests/engine/glob-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/expand-brace-pattern.test.tstests/engine/runner.test.tssrc/engine/glob-utils.tstests/engine/glob-utils.test.tssrc/engine/git-files.tssrc/engine/runner.ts
**
⚙️ CodeRabbit configuration file
**: # CLAUDE.mdArchgate is a CLI tool for AI governance via Architecture Decision Records (ADRs) — combining human-readable docs with machine-checkable rules. The CLI dogfoods itself via ADRs in
.archgate/adrs/. AI features are delivered as a Claude Code plugin (../plugins/claude-code), not via direct API calls.Technology Stack
- Runtime: Bun (>=1.2.21) — not Node.js compatible
- Language: TypeScript (strict mode, ESNext, ES modules)
- CLI framework: Commander.js (
@commander-js/extra-typings)- Linter: Oxlint | Formatter: Oxfmt | Dead exports: Knip | Commits: Conventional Commits
Commands
bun run src/cli.ts <command> # run CLI locally bun run lint # oxlint bun run typecheck # tsc --build bun run format # oxfmt --write bun run format:check # oxfmt --check bun run test # all tests (not bare `bun test` — picks up --timeout; see GEN-003) bun run knip # dead export detection bun run validate # MANDATORY: lint + typecheck + format:check + test + ADR check + knip + build check bun run build:check # verify build compiles (CI builds binaries via release workflow) bun run commit # conventional commit wizardValidation Gate
bun run validatemust pass before any task is considered complete. Fail-fast pipeline: lint → typecheck → format:check → test → ADR check → knip → build check. Mirrors CI in.github/workflows/code-pull-request.yml.Git Hooks (Git 2.54+)
Config-based hooks in
.githooksrun validation locally before commits and pushes:
- pre-commit: lint + typecheck + format:check (~15s)
- pre-push: full
bun run validate(~60s, mirrors CI)Activate once per clone:
git config --local include.path ../.githooksOpt out of a specific hook:
git config --local hook.<name>.enabled false. Skip all hooks for a single commit:git commit --no-verify.#...
Files:
tests/engine/expand-brace-pattern.test.tstests/engine/runner.test.tssrc/engine/glob-utils.tstests/engine/glob-utils.test.tssrc/engine/git-files.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:
tests/engine/expand-brace-pattern.test.tstests/engine/runner.test.tssrc/engine/glob-utils.tstests/engine/glob-utils.test.tssrc/engine/git-files.tssrc/engine/runner.ts
.archgate/adrs/**
⚙️ CodeRabbit configuration file
.archgate/adrs/**: ---
id: ARCH-001
title: Command Structure
domain: architecture
rules: true
files: ["src/commands/**/*.ts"]Context
The CLI needs a consistent pattern for defining and registering commands. As the command surface grows (init, check, adr, review-context, session-context, upgrade, clean), the registration mechanism must scale without introducing hidden coupling or making the dependency graph opaque.
Alternatives considered:
- Auto-discovery via
executableDir()— Commander.js supports automatic command discovery by scanning a directory for executable files. This eliminates manual imports but hides the dependency graph: adding or removing a command has no type-checked reference, making dead command detection impossible. It also requires each command to be a standalone executable, which prevents in-process testing and forces separate process spawning for every subcommand invocation.- Plugin-based registration — A plugin system where commands register themselves via a manifest or hook (similar to Oclif or Clipanion). This adds flexibility for third-party extensions but introduces significant complexity for an internal CLI with a known, finite set of commands. The indirection makes it harder to trace which code handles which command.
- Single-file command map — Define all commands in a single file as a map of name-to-handler. Simple but creates a monolithic file that grows with every command, making merge conflicts frequent and readability poor.
The explicit register pattern strikes the right balance: each command owns its registration logic, the entry point makes all commands visible at a glance, and in-process execution enables straightforward testing without process spawning.
Decision
Commands live in src/commands/ and export a register*Command(program) function. The main entry point (src/cli.ts) explicitly imports and calls each register function. Subcommands (e.g., adr create, adr list) use nested directories wi...
Files:
.archgate/adrs/ARCH-007-cross-platform-subprocess-execution.md.archgate/adrs/ARCH-023-engine-file-listing-via-in-memory-git-tracked-matching.rules.ts.archgate/adrs/ARCH-023-engine-file-listing-via-in-memory-git-tracked-matching.md
src/**/*.ts
📄 CodeRabbit inference engine (.archgate/adrs/ARCH-003-output-formatting.md)
src/**/*.ts: UsestyleText(format, text)fromnode:utilfor all terminal colors and formatting in CLI source files; do not use raw ANSI escape codes or third-party color libraries.
Commands that produce structured results and support--jsonmust emit machine-readable JSON to stdout with no colors or decorative formatting.
When a command supports--json, useformatJSON()fromsrc/helpers/output.tsfor JSON serialization, and passforcePretty: truewhen the user explicitly provided--json.
UseisAgentContext()fromsrc/helpers/output.tsto enable auto-JSON behavior for commands that support both human-readable and JSON output modes.
CLI output must not include emoji; use text symbols and colors instead.
Send normal command output to stdout withconsole.log(), and send errors, warnings, and debug messages to stderr vialogError(),logWarn(), andlogDebug().
Keep CLI output concise and scannable by using whitespace and alignment instead of long text blocks.
RespectNO_COLORautomatically by relying onstyleText; do not add custom color-environment handling in CLI code.
Do not output progress spinners unless there is a TTY check.
Do not assume piped output means agent context whenCIis set; CI runners should still receive human-readable output.
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.Make large production thresholds injectable via an optional parameter that defaults to the module constant, so tests can supply a small value instead of generating huge fixtures.
src/**/*.ts: Useawait Bun.file(path).json()when reading JSON files in Bun TypeScript source code; do not useJSON.parse(await Bun.file(path).text())or `JSON.parse(fs.readFile...
Files:
src/engine/glob-utils.tssrc/engine/git-files.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/glob-utils.tssrc/engine/git-files.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/glob-utils.tssrc/engine/git-files.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: The rules engine must list project files by matching glob patterns in memory against the git-tracked file set, rather than walking the filesystem.
The glob pattern and every brace-expanded alternative must passsafeGlobvalidation before matching or scanning.
Per-run caches must share glob results and file text across rule contexts; cached glob arrays must be copied before being returned, whilereadJSONresults must not be cached.
Route new engine file listings throughlistMatchingFilesfor sandboxed rule-facing patterns ormatchTrackedFilesfor trusted ADR frontmatter patterns.
Do not filter filesystem scan results against the tracked set as a substitute for in-memory matching.
Do not hardcode ignore directories such asnode_modules/or.venv/; use Git's standard ignore handling throughgit ls-files.
Files:
src/engine/glob-utils.tssrc/engine/git-files.tssrc/engine/runner.ts
src/engine/glob-utils.ts
📄 CodeRabbit inference engine (.archgate/adrs/ARCH-023-engine-file-listing-via-in-memory-git-tracked-matching.md)
matchTrackedFilesandlistMatchingFilesmust perform in-memory matching usingBun.Glob#match().
Files:
src/engine/glob-utils.ts
src/engine/{glob-utils,git-files}.ts
📄 CodeRabbit inference engine (.archgate/adrs/ARCH-023-engine-file-listing-via-in-memory-git-tracked-matching.md)
src/engine/{glob-utils,git-files}.ts:Bun.Glob#scan()is permitted only as a fallback when no tracked file set exists, and scan call sites must remain confined toglob-utils.tsandgit-files.ts.
RemainingBun.Glob#scan()fallback calls must pass{ dot: true }.
Files:
src/engine/glob-utils.tssrc/engine/git-files.ts
src/engine/git-files.ts
📄 CodeRabbit inference engine (.archgate/adrs/ARCH-023-engine-file-listing-via-in-memory-git-tracked-matching.md)
src/engine/git-files.ts:getGitTrackedFilesmust define the file universe usinggit ls-files --cached --others --exclude-standardminusgit ls-files --deleted.
Pass the tracked file set fromgetGitTrackedFileswhenever the target is a Git repository andrespectGitignoreis not false.
Files:
src/engine/git-files.ts
src/engine/runner.ts
📄 CodeRabbit inference engine (.archgate/adrs/ARCH-022-ast-aware-rule-context.md)
src/engine/runner.ts: Implementctx.ast(path, language)insidecreateRuleContext()with all dispatch hidden from rule authors.
Forlanguage: "typescript"and"javascript",ctx.ast()must reuse the existing in-processmeriyahparser; no subprocess may be spawned for these branches.
Factor the duplicatedparseModule()logic into a shared helper that is used by bothrule-scanner.tsand thectx.ast()TypeScript/JavaScript branch.
Forlanguage: "python"and"ruby",ctx.ast()must useBun.spawnwith array-based arguments only, with no shell interpolation.
Before any Python/Ruby interpreter is invoked,ctx.ast()must run the guardrail sequence in order: path safety, language plausibility check, interpreter availability probe, then guarded invocation.
ctx.ast()must use the samesafePath()sandboxing asreadFile/globbefore accessing a target file.
ctx.ast()must reject files whose extension and/or leading content do not plausibly match the requested language before running an interpreter.
ctx.ast()must probe interpreter availability once percheckinvocation, cache the result, and reuse the first working candidate executable name.
On Windows, the interpreter probe must consider platform-appropriate candidates in order (includingpyviaisWindows()); on non-Windows, it must use the non-Windows candidate order.
The Python branch must run in isolated mode (python -I -c ...) to prevent the working directory from shadowing standard-library imports.
The Python and Ruby serializers must strip a leading UTF-8 BOM before parsing.
ctx.ast()must throw on missing interpreter or parse failure, and must not returnnullor any other sentinel value.
The thrown error messages fromctx.ast()must distinguish interpreter-unavailable failures from parse-failure errors.
ctx.ast()must not exposeBun.spawn,child_process, or any other raw subprocess primitive onRuleContext; it is the only sanctioned tooling entrypoint.
`ctx.ast(...
Files:
src/engine/runner.ts
🧠 Learnings (3)
📓 Common learnings
Learnt from: CR
Repo: archgate/cli
Timestamp: 2026-07-13T15:03:45.533Z
Learning: Any exception allowing `Bun.$` in a test must be documented with a comment explaining why it is acceptable.
📚 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-007-cross-platform-subprocess-execution.md.archgate/adrs/ARCH-023-engine-file-listing-via-in-memory-git-tracked-matching.md
📚 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/MEMORY.md.claude/agent-memory/archgate-developer/project_rules_engine_internals.md
🪛 LanguageTool
.archgate/adrs/ARCH-023-engine-file-listing-via-in-memory-git-tracked-matching.md
[locale-violation] ~12-~12: In American English, ‘afterward’ is the preferred variant. ‘Afterwards’ is more commonly used in British English and other dialects.
Context: ...sults against the git-tracked file set afterwards. The walk cost was paid in full before...
(AFTERWARDS_US)
[style] ~60-~60: Consider an alternative for the overused word “exactly”.
Context: ...source of truth:** The file universe is exactly what git considers part of the project ...
(EXACTLY_PRECISELY)
🪛 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 (10)
.archgate/adrs/ARCH-007-cross-platform-subprocess-execution.md (1)
61-61: LGTM!Also applies to: 70-70
.archgate/adrs/ARCH-023-engine-file-listing-via-in-memory-git-tracked-matching.md (1)
21-21: 🎯 Functional CorrectnessPin the
Bun.Glob#match()dot-segment claim with a regression test — it's restated in two files but only asserted, not shown as tested here.Both files state that
Bun.Glob#match()matches dot-prefixed path segments with no option required, in contrast toscan()'sdot: truerequirement (ARCH-020). Public Bun docs corroborate thatmatch(path: string): booleanexposes no options parameter at all (unlikeScanOptions.dot), which is consistent with the claim, but no official example explicitly demonstrates a**-style pattern matching a dot-prefixed segment via.match(). Since this behavior is the entire justification for skippingdot: trueon the in-memory fast path, a future Bun release changing it would silently reintroduce the exact class of bug ARCH-020 exists to prevent.
.archgate/adrs/ARCH-023-engine-file-listing-via-in-memory-git-tracked-matching.md#L21-L21: consider adding a one-line pointer to where this is regression-tested (e.g.tests/engine/glob-utils.test.ts), or note it explicitly as an assumption to re-verify on Bun upgrades..archgate/adrs/ARCH-023-engine-file-listing-via-in-memory-git-tracked-matching.md#L59-L59: same — the "Correctness" consequence bullet rests on this same assumption..claude/agent-memory/archgate-developer/project_rules_engine_internals.md#L9-L9: the "verified 2026-07-13, Bun 1.3.14" note is good practice; consider recording how it was verified (e.g. link to the specific test) so the verification is reproducible on future Bun bumps..archgate/adrs/ARCH-023-engine-file-listing-via-in-memory-git-tracked-matching.rules.ts (1)
8-54: LGTM!.claude/agent-memory/archgate-developer/MEMORY.md (1)
45-45: LGTM!tests/engine/runner.test.ts (1)
85-119: LGTM!src/engine/glob-utils.ts (1)
1-121: LGTM!src/engine/git-files.ts (1)
8-8: LGTM!Also applies to: 51-76, 111-135
tests/engine/glob-utils.test.ts (1)
1-100: LGTM!Also applies to: 113-113
src/engine/runner.ts (1)
35-35: LGTM!Also applies to: 89-108, 136-165, 214-214, 280-287, 307-308, 320-320, 353-353, 424-427, 465-466
tests/engine/expand-brace-pattern.test.ts (1)
8-10: LGTM!
Signed-off-by: Rhuan Barreto <rhuan@barreto.work>
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_80139812-4849-4268-bdd4-0908adb8aa4c) |
… PRs Signed-off-by: Rhuan Barreto <rhuan@barreto.work>
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_b2c5be8a-3ee9-4e3d-906e-9e2a4df9bd15) |
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/engine/runner.ts (1)
128-138: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value
createRuleContextnow takes 9 positional parameters.Readability/maintainability nit: with
cachesadded, callers must track 9 positional args in the right order (trackedFiles,interpreterCache,cachesare easy to transpose since they're all reference types). Consider bundling the run-scoped values (interpreterCache,caches,trackedFiles) into a single options object in a future pass.Also applies to: 457-467
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/engine/runner.ts` around lines 128 - 138, Refactor createRuleContext and its callers to accept a single options object containing the run-scoped values trackedFiles, interpreterCache, and caches instead of separate positional parameters. Update every invocation, including the referenced call site, to pass named properties while preserving the existing RuleContext behavior.
🤖 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
@.archgate/adrs/ARCH-023-engine-file-listing-via-in-memory-git-tracked-matching.md:
- Around line 28-31: Clarify item `#4` so “both paths” explicitly refers only to
the two internal branches of listMatchingFiles: tracked/in-memory matching and
scan fallback. State that safeGlob validation applies to the pattern and every
brace-expanded alternative in those branches, while
resolveScopedFiles/matchTrackedFiles for trusted ADR frontmatter patterns remain
outside this sandbox requirement.
---
Outside diff comments:
In `@src/engine/runner.ts`:
- Around line 128-138: Refactor createRuleContext and its callers to accept a
single options object containing the run-scoped values trackedFiles,
interpreterCache, and caches instead of separate positional parameters. Update
every invocation, including the referenced call site, to pass named properties
while preserving the existing RuleContext behavior.
🪄 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: 97aaacf7-f791-4316-b112-443b40ba32cd
📒 Files selected for processing (12)
.archgate/adrs/ARCH-007-cross-platform-subprocess-execution.md.archgate/adrs/ARCH-023-engine-file-listing-via-in-memory-git-tracked-matching.md.archgate/adrs/ARCH-023-engine-file-listing-via-in-memory-git-tracked-matching.rules.ts.claude/agent-memory/archgate-developer/MEMORY.md.claude/agent-memory/archgate-developer/feedback_public_repo_privacy.md.claude/agent-memory/archgate-developer/project_rules_engine_internals.mdsrc/engine/git-files.tssrc/engine/glob-utils.tssrc/engine/runner.tstests/engine/expand-brace-pattern.test.tstests/engine/glob-utils.test.tstests/engine/runner.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 (14)
tests/**/*.test.ts
📄 CodeRabbit inference engine (.archgate/adrs/ARCH-005-testing-standards.md)
tests/**/*.test.ts: Use Bun's built-in test runner (bun:test) for all test files, and place tests undertests/mirroring thesrc/directory structure with<module-name>.test.tsnaming.
Use temp directories (mkdtemp) for filesystem tests, and clean them up inafterEachorafterAll.
Close external SDK instances (servers, clients, transports, connections) inafterEachorafterAll, managing their lifecycle in hooks rather than inside individual test bodies.
When a test creates a temporary git repository and runsgit commit, configure localuser.emailanduser.nameimmediately aftergit init.
Test public module interfaces, not private implementation details.
Use descriptive test names that explain the expected behavior.
Every runnabletest()/it()must contain at least oneexpect()assertion; smoke tests must make the contract explicit withexpect(() => fn()).not.toThrow()orawait expect(promise).resolves.toBeUndefined().
Usetest.skip,test.skipIf, ortest.todofor intentionally empty or disabled tests; do not use barereturnor empty callbacks to skip work.
If the firstexpect()is being added to a previously assertion-less test file, addexpectto thebun:testimport.
When mockingfetchin tests, assign directly toglobalThis.fetchand restore the original or usemock.restore()afterward.
WrapspyOn()and inlinemockImplementation()usage intry/finally, or create and restore spies in hooks, somockRestore()always runs.
Only raise a per-test timeout above the globalbun test --timeout 60000; never set a shorter per-test timeout.
Mock first-party modules withimport * as modplusspyOn(mod, "fn"), notmock.module().
When a test needs to redirect user-scope paths, mockos.homedir()instead of relying onHOME/Bun.env.HOME; restore the spy in test hooks.
Do not depend on network access in unit tests.
Do not leave temp files after test runs.
Do not leave external SDK instances open after tests...
Files:
tests/engine/expand-brace-pattern.test.tstests/engine/glob-utils.test.tstests/engine/runner.test.ts
**/*.{ts,tsx,js,jsx,mjs,cjs}
📄 CodeRabbit inference engine (.archgate/adrs/ARCH-006-dependency-policy.md)
**/*.{ts,tsx,js,jsx,mjs,cjs}: Use Bun built-ins for file I/O (Bun.file,Bun.write), HTTP, subprocess execution (Bun.spawn), globbing (Bun.Glob), and testing (bun:test).
Do not use Node.js-specific APIs when Bun alternatives exist; for example, 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/expand-brace-pattern.test.tstests/engine/glob-utils.test.tstests/engine/runner.test.tssrc/engine/glob-utils.tssrc/engine/git-files.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.
Files:
tests/engine/expand-brace-pattern.test.tstests/engine/glob-utils.test.tstests/engine/runner.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/expand-brace-pattern.test.tstests/engine/glob-utils.test.tstests/engine/runner.test.tssrc/engine/glob-utils.tssrc/engine/git-files.tssrc/engine/runner.ts
**
⚙️ CodeRabbit configuration file
**: # CLAUDE.mdArchgate is a CLI tool for AI governance via Architecture Decision Records (ADRs) — combining human-readable docs with machine-checkable rules. The CLI dogfoods itself via ADRs in
.archgate/adrs/. AI features are delivered as a Claude Code plugin (../plugins/claude-code), not via direct API calls.Technology Stack
- Runtime: Bun (>=1.2.21) — not Node.js compatible
- Language: TypeScript (strict mode, ESNext, ES modules)
- CLI framework: Commander.js (
@commander-js/extra-typings)- Linter: Oxlint | Formatter: Oxfmt | Dead exports: Knip | Commits: Conventional Commits
Commands
bun run src/cli.ts <command> # run CLI locally bun run lint # oxlint bun run typecheck # tsc --build bun run format # oxfmt --write bun run format:check # oxfmt --check bun run test # all tests (not bare `bun test` — picks up --timeout; see GEN-003) bun run knip # dead export detection bun run validate # MANDATORY: lint + typecheck + format:check + test + ADR check + knip + build check bun run build:check # verify build compiles (CI builds binaries via release workflow) bun run commit # conventional commit wizardValidation Gate
bun run validatemust pass before any task is considered complete. Fail-fast pipeline: lint → typecheck → format:check → test → ADR check → knip → build check. Mirrors CI in.github/workflows/code-pull-request.yml.Git Hooks (Git 2.54+)
Config-based hooks in
.githooksrun validation locally before commits and pushes:
- pre-commit: lint + typecheck + format:check (~15s)
- pre-push: full
bun run validate(~60s, mirrors CI)Activate once per clone:
git config --local include.path ../.githooksOpt out of a specific hook:
git config --local hook.<name>.enabled false. Skip all hooks for a single commit:git commit --no-verify.#...
Files:
tests/engine/expand-brace-pattern.test.tstests/engine/glob-utils.test.tstests/engine/runner.test.tssrc/engine/glob-utils.tssrc/engine/git-files.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:
tests/engine/expand-brace-pattern.test.tstests/engine/glob-utils.test.tstests/engine/runner.test.tssrc/engine/glob-utils.tssrc/engine/git-files.tssrc/engine/runner.ts
.archgate/adrs/**
⚙️ CodeRabbit configuration file
.archgate/adrs/**: ---
id: ARCH-001
title: Command Structure
domain: architecture
rules: true
files: ["src/commands/**/*.ts"]Context
The CLI needs a consistent pattern for defining and registering commands. As the command surface grows (init, check, adr, review-context, session-context, upgrade, clean), the registration mechanism must scale without introducing hidden coupling or making the dependency graph opaque.
Alternatives considered:
- Auto-discovery via
executableDir()— Commander.js supports automatic command discovery by scanning a directory for executable files. This eliminates manual imports but hides the dependency graph: adding or removing a command has no type-checked reference, making dead command detection impossible. It also requires each command to be a standalone executable, which prevents in-process testing and forces separate process spawning for every subcommand invocation.- Plugin-based registration — A plugin system where commands register themselves via a manifest or hook (similar to Oclif or Clipanion). This adds flexibility for third-party extensions but introduces significant complexity for an internal CLI with a known, finite set of commands. The indirection makes it harder to trace which code handles which command.
- Single-file command map — Define all commands in a single file as a map of name-to-handler. Simple but creates a monolithic file that grows with every command, making merge conflicts frequent and readability poor.
The explicit register pattern strikes the right balance: each command owns its registration logic, the entry point makes all commands visible at a glance, and in-process execution enables straightforward testing without process spawning.
Decision
Commands live in src/commands/ and export a register*Command(program) function. The main entry point (src/cli.ts) explicitly imports and calls each register function. Subcommands (e.g., adr create, adr list) use nested directories wi...
Files:
.archgate/adrs/ARCH-007-cross-platform-subprocess-execution.md.archgate/adrs/ARCH-023-engine-file-listing-via-in-memory-git-tracked-matching.rules.ts.archgate/adrs/ARCH-023-engine-file-listing-via-in-memory-git-tracked-matching.md
src/**/*.ts
📄 CodeRabbit inference engine (.archgate/adrs/ARCH-003-output-formatting.md)
src/**/*.ts: UsestyleText(format, text)fromnode:utilfor all terminal colors and formatting in CLI source files; do not use raw ANSI escape codes or third-party color libraries.
Commands that produce structured results and support--jsonmust emit machine-readable JSON to stdout with no colors or decorative formatting.
When a command supports--json, useformatJSON()fromsrc/helpers/output.tsfor JSON serialization, and passforcePretty: truewhen the user explicitly provided--json.
UseisAgentContext()fromsrc/helpers/output.tsto enable auto-JSON behavior for commands that support both human-readable and JSON output modes.
CLI output must not include emoji; use text symbols and colors instead.
Send normal command output to stdout withconsole.log(), and send errors, warnings, and debug messages to stderr vialogError(),logWarn(), andlogDebug().
Keep CLI output concise and scannable by using whitespace and alignment instead of long text blocks.
RespectNO_COLORautomatically by relying onstyleText; do not add custom color-environment handling in CLI code.
Do not output progress spinners unless there is a TTY check.
Do not assume piped output means agent context whenCIis set; CI runners should still receive human-readable output.
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.Make large production thresholds injectable via an optional parameter that defaults to the module constant, so tests can supply a small value instead of generating huge fixtures.
src/**/*.ts: Useawait Bun.file(path).json()when reading JSON files in Bun TypeScript source code; do not useJSON.parse(await Bun.file(path).text())or `JSON.parse(fs.readFile...
Files:
src/engine/glob-utils.tssrc/engine/git-files.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/glob-utils.tssrc/engine/git-files.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/glob-utils.tssrc/engine/git-files.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: Insrc/engine/, list project files by matching glob patterns in memory against the git-tracked file set, rather than walking the filesystem.
Before matching or scanning, validate the glob pattern and every brace-expanded alternative withsafeGlob; reject absolute paths and..segments.
ShareRunCachesacross rule contexts for per-run glob results and file text; cache promises, copy cached glob arrays before returning them, and do not cache mutablereadJSONresults.
Route new engine file listings throughlistMatchingFilesfor sandboxed rule-facing patterns ormatchTrackedFilesfor trusted ADR frontmatter patterns.
When the target is a Git repository andrespectGitignoreis notfalse, pass the tracked set fromgetGitTrackedFiles.
Do not filter filesystem scan results against the tracked set as a substitute for in-memory matching.
Do not hardcode ignore lists such asnode_modules/or.venv/; use.gitignorethroughgit ls-filesas the authoritative source.
Files:
src/engine/glob-utils.tssrc/engine/git-files.tssrc/engine/runner.ts
src/engine/glob-utils.ts
📄 CodeRabbit inference engine (.archgate/adrs/ARCH-023-engine-file-listing-via-in-memory-git-tracked-matching.md)
matchTrackedFilesandlistMatchingFilesmust perform in-memory matching withBun.Glob#match().
Files:
src/engine/glob-utils.ts
src/engine/{glob-utils,git-files}.ts
📄 CodeRabbit inference engine (.archgate/adrs/ARCH-023-engine-file-listing-via-in-memory-git-tracked-matching.md)
src/engine/{glob-utils,git-files}.ts:Bun.Glob#scan()is permitted only as a fallback when no tracked set exists; no other engine file may call it.
All remainingBun.Glob#scan()fallbacks must pass{ dot: true }.
Files:
src/engine/glob-utils.tssrc/engine/git-files.ts
src/engine/git-files.ts
📄 CodeRabbit inference engine (.archgate/adrs/ARCH-023-engine-file-listing-via-in-memory-git-tracked-matching.md)
getGitTrackedFilesmust define the file universe usinggit ls-files --cached --others --exclude-standard, minusgit ls-files --deleted.
Files:
src/engine/git-files.ts
src/engine/runner.ts
📄 CodeRabbit inference engine (.archgate/adrs/ARCH-022-ast-aware-rule-context.md)
src/engine/runner.ts: Implementctx.ast(path, language)insidecreateRuleContext()with all dispatch hidden from rule authors.
Forlanguage: "typescript"and"javascript",ctx.ast()must reuse the existing in-processmeriyahparser; no subprocess may be spawned for these branches.
Factor the duplicatedparseModule()logic into a shared helper that is used by bothrule-scanner.tsand thectx.ast()TypeScript/JavaScript branch.
Forlanguage: "python"and"ruby",ctx.ast()must useBun.spawnwith array-based arguments only, with no shell interpolation.
Before any Python/Ruby interpreter is invoked,ctx.ast()must run the guardrail sequence in order: path safety, language plausibility check, interpreter availability probe, then guarded invocation.
ctx.ast()must use the samesafePath()sandboxing asreadFile/globbefore accessing a target file.
ctx.ast()must reject files whose extension and/or leading content do not plausibly match the requested language before running an interpreter.
ctx.ast()must probe interpreter availability once percheckinvocation, cache the result, and reuse the first working candidate executable name.
On Windows, the interpreter probe must consider platform-appropriate candidates in order (includingpyviaisWindows()); on non-Windows, it must use the non-Windows candidate order.
The Python branch must run in isolated mode (python -I -c ...) to prevent the working directory from shadowing standard-library imports.
The Python and Ruby serializers must strip a leading UTF-8 BOM before parsing.
ctx.ast()must throw on missing interpreter or parse failure, and must not returnnullor any other sentinel value.
The thrown error messages fromctx.ast()must distinguish interpreter-unavailable failures from parse-failure errors.
ctx.ast()must not exposeBun.spawn,child_process, or any other raw subprocess primitive onRuleContext; it is the only sanctioned tooling entrypoint.
`ctx.ast(...
Files:
src/engine/runner.ts
🧠 Learnings (2)
📚 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/feedback_public_repo_privacy.md.claude/agent-memory/archgate-developer/MEMORY.md.claude/agent-memory/archgate-developer/project_rules_engine_internals.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-007-cross-platform-subprocess-execution.md.archgate/adrs/ARCH-023-engine-file-listing-via-in-memory-git-tracked-matching.md
🪛 LanguageTool
.archgate/adrs/ARCH-023-engine-file-listing-via-in-memory-git-tracked-matching.md
[locale-violation] ~12-~12: In American English, ‘afterward’ is the preferred variant. ‘Afterwards’ is more commonly used in British English and other dialects.
Context: ...sults against the git-tracked file set afterwards. The walk cost was paid in full before...
(AFTERWARDS_US)
[style] ~60-~60: Consider an alternative for the overused word “exactly”.
Context: ...source of truth:** The file universe is exactly what git considers part of the project ...
(EXACTLY_PRECISELY)
🪛 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 (15)
.claude/agent-memory/archgate-developer/project_rules_engine_internals.md (1)
8-10: MD041 static-analysis hint is a known false positive for this file class — no action needed.Content itself (expandBracePattern relocation, Bun.Glob match/scan semantics, ARCH-023 rationale, deferred load-cache follow-up) is accurate and consistent with the code changes in this PR.
Based on learnings, agent-memory files under
.claude/agent-memory/use YAML frontmatter with aname:field as the title and don't require a top-level H1; markdownlint isn't part of this repo'sbun run validatepipeline (oxlint/oxfmt only), so this MD041 finding should not be flagged.Source: Learnings
.archgate/adrs/ARCH-007-cross-platform-subprocess-execution.md (1)
61-61: LGTM!Also applies to: 70-70
.archgate/adrs/ARCH-023-engine-file-listing-via-in-memory-git-tracked-matching.rules.ts (2)
1-19: LGTM!Also applies to: 23-55
20-22: 🎯 Functional CorrectnessNo issue here.
.claude/agent-memory/archgate-developer/MEMORY.md (1)
25-25: LGTM!Also applies to: 45-45
.claude/agent-memory/archgate-developer/feedback_public_repo_privacy.md (1)
13-14: LGTM!src/engine/glob-utils.ts (4)
9-23: LGTM!
25-56: LGTM!
58-80: LGTM!
82-121: LGTM!src/engine/git-files.ts (1)
8-8: LGTM!Also applies to: 51-76, 111-135
tests/engine/glob-utils.test.ts (1)
1-113: LGTM!src/engine/runner.ts (1)
91-165: LGTM! The per-run cache design (promise-based in-flight sharing, copy-on-return forctx.glob, deliberately-uncachedreadJSON) matches ARCH-023's contract precisely, and the new isolation test inrunner.test.tsbacks it up.Also applies to: 214-214, 279-320, 351-359
tests/engine/expand-brace-pattern.test.ts (1)
8-10: LGTM!tests/engine/runner.test.ts (1)
85-119: LGTM! Solid regression test directly exercising the shared-cache isolation contract added inrunner.ts.
…anches Signed-off-by: Rhuan Barreto <rhuan@barreto.work>
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_25303b94-c298-4c93-b6f4-dd2569c81f76) |
# archgate ## [0.48.4](v0.48.3...v0.48.4) (2026-07-13) ### Performance Improvements * **engine:** match globs in memory against git-tracked files ([#474](#474)) ([457b835](457b835)), closes [oven-sh/bun#32596](oven-sh/bun#32596) --- This PR was generated with [simple-release](https://github.com/TrigenSoftware/simple-release). <details> <summary>📄 Cheatsheet</summary> <br> You can configure the bot's behavior through a pull request comment using the `!simple-release/set-options` command. ### Command Format ````md !simple-release/set-options ```json { "bump": {}, "publish": {} } ``` ```` ### Useful Parameters #### Bump | Parameter | Type | Description | |-----------|------|-------------| | `version` | `string` | Force set specific version | | `as` | `'major' \| 'minor' \| 'patch' \| 'prerelease'` | Release type | | `prerelease` | `string` | Pre-release identifier (e.g., "alpha", "beta") | | `firstRelease` | `boolean` | Whether this is the first release | | `skip` | `boolean` | Skip version bump | | `byProject` | `Record<string, object>` | Per-project bump options for monorepos | #### Publish | Parameter | Type | Description | |-----------|------|-------------| | `skip` | `boolean` | Skip publishing | | `access` | `'public' \| 'restricted'` | Package access level | | `tag` | `string` | Tag for npm publication | ### Usage Examples #### Force specific version ````md !simple-release/set-options ```json { "bump": { "version": "2.0.0" } } ``` ```` #### Force major bump ````md !simple-release/set-options ```json { "bump": { "as": "major" } } ``` ```` #### Create alpha pre-release ````md !simple-release/set-options ```json { "bump": { "prerelease": "alpha" } } ``` ```` #### Publish with specific access and tag ````md !simple-release/set-options ```json { "bump": { "prerelease": "beta" }, "publish": { "access": "public", "tag": "beta" } } ``` ```` ### Access Restrictions The command can only be used by users with permissions: - repository owner - organization member - collaborator ### Notes - The last comment with `!simple-release/set-options` command takes priority - JSON must be valid, otherwise the command will be ignored - Parameters apply only to the current release execution - The command can be updated by editing the comment or adding a new one </details> <!-- Please do not edit this comment. simple-release-pull-request: true simple-release-branch-from: release simple-release-branch-to: main --> Signed-off-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Problem
archgate checkpegged CPU on real-world projects. Root cause: every ADR scope resolution and every rule-facing file listing (ctx.glob,ctx.grepFiles) walked the filesystem withBun.Glob#scan()and filtered against the git-tracked set only afterwards — the traversal cost was paid in full before the filter ran. On a project with 333 tracked files and 43,645 filesystem entries (.venv/,data/), one check performed ~70 full walks (one per ADR scope + one per rule glob), all in parallel.Fix
src/engine/glob-utils.ts, new): match patterns against thegit ls-files --cached --others --exclude-standardset (minus--deleted) viaBun.Glob#match().match()handles dot-prefixed segments without options and brace-with-/groups natively (Bun.Glob.scan() silently returns empty results for brace patterns containing path separators oven-sh/bun#32596 affects scanning only). Scanning is now fallback-only (non-git project /respectGitignore: false), confined toglob-utils.ts/git-files.ts. The rule-sandbox contract (no../absolute patterns, including brace-expanded alternatives) is validated identically on both paths and pinned by tests.runner.ts): glob results (keyed by pattern + tracked mode) and file text (keyed by abs path) shared across all rule contexts as promises; glob arrays copied on return so one rule's mutation can't corrupt another's view;readJSONdeliberately uncached (mutable-object leakage).git-files.ts):Promise.allSettledinstead ofPromise.allfor the twogit ls-filesspawns — a rejection (non-git dir) previously abandoned the in-flight sibling, whose live cwd handle locks the directory on Windows (EBUSY on temp-dir cleanup).Governance
scan()call sites to the two fallback modules — dogfooded clean and fire-tested against a planted violation.Promise.allSettledDo/Don't.Results
checkFollow-up (separate PR)
The remaining ~700ms of wall clock is Bun startup + re-transpiling/parsing every
.rules.tsper invocation — planned content-hash cache under~/.archgate/.Validation
bun run validatepasses (lint, typecheck, format, 1454 tests, ADR check 44/44, knip, build).