Skip to content

Feature/tempo pattern compiler#27

Merged
magmacomputing merged 8 commits intomainfrom
feature/tempo-pattern-compiler
May 7, 2026
Merged

Feature/tempo pattern compiler#27
magmacomputing merged 8 commits intomainfrom
feature/tempo-pattern-compiler

Conversation

@magmacomputing
Copy link
Copy Markdown
Owner

@magmacomputing magmacomputing commented May 6, 2026

new PatternCompiler

Summary by CodeRabbit

  • New Features

    • Added a Tempo.regexp() prototyping doc for previewing layout→regex compilation.
  • Bug Fixes

    • Safer pattern compilation: errors now log and fall back to safe regexes instead of throwing.
  • Documentation

    • New guide for preventing accidental commits/pushes to main and recovery workflows.
    • Expanded pattern compilation usage notes.
  • Refactor

    • Reworked pattern compilation internals and reorganized support modules.
    • Simplified CI to run standard tests only.
  • Tests

    • Added tests validating pattern compiler behavior and expansions.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 6, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Refactors Tempo's regex/pattern compilation into a per-state PatternCompiler, wires it into Tempo.regexp, delegates layout-order logic to a pure resolver, migrates many internal imports from tempo.*support.*, hardens utility error handling, updates tests/docs, and simplifies CI and some UI docs.

Changes

Pattern compiler, layout wiring, and Tempo integration

Layer / File(s) Summary
Data Shape / Types
packages/tempo/src/tempo.type.ts
Adds optional patternCompiler?: PatternCompiler to Internal.State.
Core Implementation
packages/tempo/src/engine/engine.pattern.ts
Adds PatternCompiler class with compileRegExp, setPatterns, clearCache; implements recursive placeholder expansion, anchored/case-insensitive normalization, dotted-name named-capture wrapping, depth guard, and two-tier caching. Exports setPatterns(state) wrapper that attaches a per-state compiler.
Wiring / Integration
packages/tempo/src/tempo.class.ts, packages/tempo/src/support/support.index.ts
Tempo.regexp() lazily instantiates state.patternCompiler and delegates compilation; setPatterns re-export moved to engine.pattern and re-wired in support index.
Tests
packages/tempo/test/engine/pattern_compiler_optimization.test.ts
Adds tests for nested placeholder expansion, circular-placeholder recursion-limit behavior, and repeated-placeholder consistency.
Docs
packages/tempo/doc/tempo.layout.md
Adds "Prototyping with Tempo.regexp()" example demonstrating layout→regex compilation.

Support layer renames and utility hardening

Layer / File(s) Summary
Foundation: import/exports rename
packages/tempo/package.json, packages/tempo/src/support/...
Switch many internal imports/exports from tempo.* to support.* (symbols, enums, runtime, default, enum exports in package.json).
Utilities
packages/tempo/src/support/support.util.ts, packages/tempo/src/support/support.init.ts
Introduce isProxy, make hasOwn/proto unwrap-aware, refactor create() to log via logError and return {} instead of throwing; support.init changed to log and sanitize oversize/suspicious snippet patterns rather than throwing.
Symbols / Runtime / Register
packages/tempo/src/support/support.symbol.ts, packages/tempo/src/support/support.runtime.ts, packages/tempo/src/support/support.register.ts
Reformatted and expanded symbol declarations, adjusted imports to support.*, preserved runtime/registry behaviors.
Plugin & parsing import fixes
packages/tempo/src/plugin/*, packages/tempo/src/discrete/discrete.parse.ts
Updated local imports to support.* aliases (e.g., enums, utils).

Layout order extraction and resolver changes

Layer / File(s) Summary
Pure resolver removal/export
packages/tempo/src/parse/parse.resolver.ts
Removes exported resolveLayoutOrderPure (export relocated/consumed elsewhere).
Engine & Parser delegation
packages/tempo/src/engine/engine.layout.ts, packages/tempo/src/parse/parse.layout.ts
resolveLayoutOrder now delegates to resolveLayoutOrderPure; change-detection uses symbol identity comparison and preserves referential equality when unchanged. resolveLayoutClassificationOrder updated to accept non-string preferred items.
Tests
packages/tempo/test/engine/parse.layout.test.ts
Renamed top-level test suite label.

CI, docs, release notes, and minor UI

Layer / File(s) Summary
CI Workflow
.github/workflows/ci.yml
Removes test-parse-prefilter job and related benchmark steps; keeps single test job running npm test in packages/tempo.
Docs: branch-protection
doc/main_branch_protection.md
Adds docs describing local pre-commit/pre-push hooks to block main commits/pushes, override env vars, global hooks caveats, and recovery workflows for accidental main changes.
Release notes & config
packages/tempo/plan/RELEASE-D.md, .agent/workflows/interactive-testing.md
Marks alias extraction tasks completed; updates interactive REPL command to npx tsx --conditions=development --harmony-temporal --import ./bin/repl.ts.
UI doc tweak
packages/tempo/index.md
Changes .tempo-btn-brand:hover scoped CSS to hard-coded #2980b9/white.

Sequence Diagram(s)

(omitted)

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

  • magmacomputing/magma#25: Directly related—modifies the same Tempo codepaths (PatternCompiler, support.* refactor, Tempo.regexp wiring).
  • magmacomputing/magma#20: Related refactor—overlaps on layout-order resolution, pattern compilation/setPatterns, and Tempo internals.
  • magmacomputing/magma#22: Related CI change—this PR removes a prefilter job that PR #22 had added.

Poem

🐰 A little rabbit compiles the night,
weaving patterns tight and bright.
Support roads renamed and trimmed,
layouts dance where logic grinned.
Hops, caches, tests — all set right.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Feature/tempo pattern compiler' directly describes the main change: introduction of a new PatternCompiler class and related pattern compilation infrastructure.
Docstring Coverage ✅ Passed Docstring coverage is 87.50% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/tempo-pattern-compiler

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


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

❤️ Share

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

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 6

🧹 Nitpick comments (4)
packages/tempo/src/tempo.class.ts (1)

26-29: 💤 Low value

Consolidate the duplicate ./support/tempo.util.js imports.

Lines 26 and 29 both import from ./support/tempo.util.js. Merge into a single statement for readability.

♻️ Proposed change
-import { resolveMonthDay } from './support/tempo.util.js';
 import { DEFAULT_LAYOUT_CLASS, resolveLayoutOrder, getLayoutOrder } from './parse/parse.layout.js';
 import { datePattern } from './support/tempo.default.js';
-import { setProperty, proto, hasOwn, normalizeLayoutOrder } from './support/tempo.util.js';
+import { resolveMonthDay, setProperty, proto, hasOwn, normalizeLayoutOrder } from './support/tempo.util.js';
🤖 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 `@packages/tempo/src/tempo.class.ts` around lines 26 - 29, There are two
imports from the same module './support/tempo.util.js' (resolveMonthDay on one
line and setProperty, proto, hasOwn, normalizeLayoutOrder on the other);
consolidate them into a single import statement that imports resolveMonthDay,
setProperty, proto, hasOwn, and normalizeLayoutOrder together so only one import
from './support/tempo.util.js' remains (keep other imports like
DEFAULT_LAYOUT_CLASS, resolveLayoutOrder, getLayoutOrder, and datePattern
unchanged).
packages/tempo/src/tempo.type.ts (1)

19-19: ⚡ Quick win

Use import type to make the cycle erased at runtime.

engine.pattern.ts already imports types from tempo.type.ts (import type * as t from '../tempo.type.js'), so importing the runtime PatternCompiler value here closes the cycle at the value level. Since PatternCompiler is only used as a type annotation on line 229, switching to import type keeps the cycle purely at the type layer and avoids any module-evaluation order surprises.

♻️ Proposed change
-import { PatternCompiler } from './engine/engine.pattern.js';
+import type { PatternCompiler } from './engine/engine.pattern.js';
🤖 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 `@packages/tempo/src/tempo.type.ts` at line 19, The import of PatternCompiler
in tempo.type.ts creates a runtime cycle with engine.pattern.ts; change the
statement that currently imports PatternCompiler to a type-only import (use
"import type { PatternCompiler } from './engine/engine.pattern.js'") so the
symbol is erased at runtime—ensure PatternCompiler is only used as a type (e.g.,
in the type annotation where it is referenced) and not relied on as a runtime
value anywhere in tempo.type.ts.
doc/main_branch_protection.md (1)

38-40: 💤 Low value

Note the side-effect of core.hooksPath.

Setting core.hooksPath globally disables every per-repo .git/hooks/* for all repositories on the workstation (Husky, lefthook, lint-staged, etc.). Worth calling out so users who already rely on per-project hooks don't lose them silently. Consider mentioning that they should chain those tools from the global hook scripts, or scope this protection to specific repos via git config core.hooksPath (without --global).

🤖 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 `@doc/main_branch_protection.md` around lines 38 - 40, The doc currently
suggests running `git config --global core.hooksPath ...` without warning that
setting core.hooksPath globally disables all per-repo .git/hooks/* (breaking
Husky, lefthook, lint-staged, etc.); update the guidance in
main_branch_protection.md to call out this side-effect explicitly, and add
recommended alternatives: either chain existing per-project hooks from the
global hook scripts or scope the setting to individual repos using `git config
core.hooksPath` (no --global) so you don’t silently disable per-repo hooks;
reference the config key `core.hooksPath` and the global flag `--global` in the
text so readers know exactly what to change.
packages/tempo/src/engine/engine.pattern.ts (1)

38-44: 💤 Low value

Silent recursion bail-out hides misconfigured placeholders.

When d > 10 the matcher just returns src unchanged, so a circular snippet definition (e.g., {a}{b}{a}) yields a regex with literal {...} braces in it and no diagnostic. Worth a logError (or at least a debug log) so cyclic snippet authors notice.

📝 Suggested change
-		const matcher = (src: string, d = 0): string => {
-			if (d > 10) return src; // prevent infinite recursion
+		const matcher = (src: string, d = 0): string => {
+			if (d > 10) {
+				logError(this.#state.config, `PatternCompiler: recursion limit hit while expanding "${src}"`);
+				return src;
+			}
🤖 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 `@packages/tempo/src/engine/engine.pattern.ts` around lines 38 - 44, The
matcher function silently returns the original src on depth overflow (d > 10),
hiding circular placeholder definitions; update matcher to detect this recursion
limit and emit a diagnostic (e.g., call an existing logger like
logError/log.warn or the local logger instance) when d > 10 before returning,
including the problematic src and depth info to aid debugging (keep the existing
return behavior but add the log call inside the matcher).
🤖 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 `@doc/main_branch_protection.md`:
- Around line 28-33: The doc snippet hard-codes a personal absolute path
(/home/michael/Project/magma/.git/hooks/pre-commit) which will break for others;
update the example to use a generic placeholder or a repo-root lookup (e.g.
$(git rev-parse --show-toplevel)/.git/hooks/pre-commit) and show copying the
pre-commit and pre-push hooks into ~/.git-hooks, keeping the mkdir -p
~/.git-hooks and chmod +x ~/.git-hooks/* lines but replacing the absolute paths
with a placeholder like /path/to/repo/.git/hooks or the git command so
contributors can run the snippet on any machine.

In `@packages/tempo/plan/RELEASE-D.md`:
- Around line 17-21: The RELEASE-D.md checklist is inaccurate: the PR actually
includes the new PatternCompiler and cache extraction (see engine.pattern.ts and
tempo.class.ts) but the checklist only marks "Alias Resolution Engine
Extraction" items; update the checklist lines 9-14 to mark the "Pattern Compiler
+ Cache Extraction" items as completed (or split them into a separate PR entry
if you intend to keep them separate) and ensure the item text references the
PatternCompiler/Cache extraction so the release tracking matches the code
change.

In `@packages/tempo/src/engine/engine.pattern.ts`:
- Around line 29-36: The cache key in compileRegExp currently collapses all
non-null snippets into the same key (`cacheKey = \`${source}:${snippet ?
'custom' : 'global'}\``), causing different Snippet objects to collide and
return incorrect RegExp; fix by scoping the cache per Snippet identity: replace
or augment the current `#cache` with a WeakMap<Snippet, Map<string, RegExp>> (or
compute a stable digest of snippet entries) so compileRegExp uses
snippet-specific storage when snippet is provided (look for compileRegExp,
cacheKey, and this.#cache) and ensure lookups/sets use the inner Map keyed by
source to preserve caching for repeated calls with the same snippet object.
- Around line 76-86: The catch block should use the previously computed source
(not the original layout) when building the fallback regex, surface the original
error via logError, and avoid poisoning the cache with a fallback; specifically,
in the try/catch around matcher/expanded/compiled replace Match.escape(layout as
string) with Match.escape(source), call logError(e, { context: 'pattern compile
failed', pattern: source }) (or equivalent) before returning, and do not call
this.#cache.set(cacheKey, fallback) for the fallback (either skip caching the
fallback or mark it so setPatterns can invalidate it later) so transient compile
failures don’t persist; refer to matcher, expanded, compiled, fallback,
this.#cache and setPatterns when making the changes.
- Around line 102-109: The code builds snippet[Token.afx] using
snippet[Token.sep].source without checking existence; update the construction in
the block where enums?.NUMBER is handled so it guards snippet[Token.sep] (e.g.,
use optional chaining or a safe fallback like (snippet[Token.sep]?.source || '')
when composing the RegExp) to avoid accessing .source on undefined—locate the
snippet[Token.afx] assignment and replace the direct snippet[Token.sep].source
reference with a guarded expression.

In `@packages/tempo/src/tempo.class.ts`:
- Around line 889-896: The cache key in engine.pattern.ts conflates different
custom Snippet objects because it uses `${source}:${snippet ? 'custom' :
'global'}`; update caching in PatternCompiler.compileRegExp (or the cache
declaration) to differentiate by the actual snippet identity instead of just
presence—e.g., use a secondary map/WeakMap keyed by the snippet object (or
include a stable snippet identifier like snippet.name/snippet.id/snippet.source
in the key) so calls to PatternCompiler.compileRegExp(layout, snippet) return
distinct compiled patterns per snippet; alternatively, disable caching when a
custom snippet is provided. Ensure changes reference PatternCompiler and
compileRegExp to locate the code.

---

Nitpick comments:
In `@doc/main_branch_protection.md`:
- Around line 38-40: The doc currently suggests running `git config --global
core.hooksPath ...` without warning that setting core.hooksPath globally
disables all per-repo .git/hooks/* (breaking Husky, lefthook, lint-staged,
etc.); update the guidance in main_branch_protection.md to call out this
side-effect explicitly, and add recommended alternatives: either chain existing
per-project hooks from the global hook scripts or scope the setting to
individual repos using `git config core.hooksPath` (no --global) so you don’t
silently disable per-repo hooks; reference the config key `core.hooksPath` and
the global flag `--global` in the text so readers know exactly what to change.

In `@packages/tempo/src/engine/engine.pattern.ts`:
- Around line 38-44: The matcher function silently returns the original src on
depth overflow (d > 10), hiding circular placeholder definitions; update matcher
to detect this recursion limit and emit a diagnostic (e.g., call an existing
logger like logError/log.warn or the local logger instance) when d > 10 before
returning, including the problematic src and depth info to aid debugging (keep
the existing return behavior but add the log call inside the matcher).

In `@packages/tempo/src/tempo.class.ts`:
- Around line 26-29: There are two imports from the same module
'./support/tempo.util.js' (resolveMonthDay on one line and setProperty, proto,
hasOwn, normalizeLayoutOrder on the other); consolidate them into a single
import statement that imports resolveMonthDay, setProperty, proto, hasOwn, and
normalizeLayoutOrder together so only one import from './support/tempo.util.js'
remains (keep other imports like DEFAULT_LAYOUT_CLASS, resolveLayoutOrder,
getLayoutOrder, and datePattern unchanged).

In `@packages/tempo/src/tempo.type.ts`:
- Line 19: The import of PatternCompiler in tempo.type.ts creates a runtime
cycle with engine.pattern.ts; change the statement that currently imports
PatternCompiler to a type-only import (use "import type { PatternCompiler } from
'./engine/engine.pattern.js'") so the symbol is erased at runtime—ensure
PatternCompiler is only used as a type (e.g., in the type annotation where it is
referenced) and not relied on as a runtime value anywhere in tempo.type.ts.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 47da4174-1297-4b40-8459-5158bbde04b6

📥 Commits

Reviewing files that changed from the base of the PR and between 4b468d9 and 7e3928a.

📒 Files selected for processing (7)
  • doc/main_branch_protection.md
  • packages/tempo/plan/RELEASE-D.md
  • packages/tempo/src/engine/engine.pattern.ts
  • packages/tempo/src/support/support.index.ts
  • packages/tempo/src/support/tempo.util.ts
  • packages/tempo/src/tempo.class.ts
  • packages/tempo/src/tempo.type.ts
💤 Files with no reviewable changes (1)
  • packages/tempo/src/support/tempo.util.ts

Comment thread doc/main_branch_protection.md
Comment thread packages/tempo/plan/RELEASE-D.md
Comment thread packages/tempo/src/engine/engine.pattern.ts
Comment thread packages/tempo/src/engine/engine.pattern.ts
Comment thread packages/tempo/src/engine/engine.pattern.ts
Comment thread packages/tempo/src/tempo.class.ts Outdated
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

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 `@doc/main_branch_protection.md`:
- Around line 137-138: The doc currently instructs users to run "git reset
--hard origin/main" but omits a prior fetch; update the guidance around the git
reset step to first run a fetch so origin/main is up-to-date (i.e., add an
instruction to run git fetch origin before the git reset --hard origin/main
command) and mention that this prevents resetting to a stale origin/main
reference.

In `@packages/tempo/src/engine/engine.pattern.ts`:
- Around line 92-96: In the catch block in engine.pattern.ts (the RegExp compile
fallback in the function surrounding Match.escape), the call to logError uses
reversed arguments and optional chaining; change it to call logError with the
config object first and the error as a message (e.g. logError({ context:
'pattern compile failed', pattern: source }, e)) and remove the unnecessary ?.
so the compile error is logged correctly rather than being treated as the
config.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: cbc288fd-36a3-417d-8bff-2e69c16da553

📥 Commits

Reviewing files that changed from the base of the PR and between 7e3928a and 3b7a121.

📒 Files selected for processing (11)
  • .agent/workflows/interactive-testing.md
  • .github/workflows/ci.yml
  • doc/main_branch_protection.md
  • packages/tempo/index.md
  • packages/tempo/plan/RELEASE-D.md
  • packages/tempo/src/engine/engine.alias.ts
  • packages/tempo/src/engine/engine.pattern.ts
  • packages/tempo/src/support/tempo.init.ts
  • packages/tempo/src/support/tempo.util.ts
  • packages/tempo/src/tempo.class.ts
  • packages/tempo/src/tempo.type.ts
💤 Files with no reviewable changes (1)
  • .github/workflows/ci.yml
✅ Files skipped from review due to trivial changes (1)
  • packages/tempo/index.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/tempo/plan/RELEASE-D.md

Comment thread doc/main_branch_protection.md Outdated
Comment thread packages/tempo/src/engine/engine.pattern.ts
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (1)
packages/tempo/src/engine/engine.pattern.ts (1)

92-96: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

logError is still called with the wrong first argument.

The past review flagged that logError(config, ...msg) expects this.#state.config as its first argument. The ?. was removed and args were swapped, but the first argument is still a plain object literal { context: ..., pattern: source } rather than the config instance — so the error is still silently swallowed.

🐛 Proposed fix
-			logError({ context: 'pattern compile failed', pattern: source }, e);
+			logError(this.#state.config, `PatternCompiler: failed to compile layout "${source}"`, e);
🤖 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 `@packages/tempo/src/engine/engine.pattern.ts` around lines 92 - 96, The
logError call in the catch block is passing an object literal as the first
argument instead of the config instance, so the error is still swallowed; change
the call to pass this.#state.config as the first parameter and then supply the
contextual info and the caught error as subsequent args (i.e. call
logError(this.#state.config, { context: 'pattern compile failed', pattern:
source }, e)) in the catch inside the pattern compilation (references: logError,
this.#state.config, Match.escape, RegExp).
🧹 Nitpick comments (2)
doc/main_branch_protection.md (1)

6-8: ⚡ Quick win

Use neutral wording for shared documentation.

“I have already set up local hooks…” reads like a personal note and may mislead contributors into thinking hooks are preinstalled for them. Prefer repo-neutral wording.

Suggested patch
-I have already set up local hooks for the `magma` repository:
+This repository uses local hooks for the `magma` repository:
🤖 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 `@doc/main_branch_protection.md` around lines 6 - 8, The sentence "I have
already set up local hooks..." reads as a personal note and should be made
neutral for shared documentation; edit the document text that lists the hooks
(the lines mentioning "pre-commit" and "pre-push") to use repository-neutral
wording such as "Local hooks can be configured to:" or "Set up local hooks to:"
and rephrase the two bullets to describe the behavior ("pre-commit: prevents
direct commits to main", "pre-push: prevents pushing to remote main") without
implying they are already installed for the reader.
packages/tempo/src/engine/engine.pattern.ts (1)

57-57: ⚡ Quick win

new RegExp(Match.braces, 'g') is reconstructed on every recursive matcher call.

Match.braces is a static constant, so this RegExp can be hoisted to a module-level (or class-level) constant and reused across all invocations, avoiding repeated object allocation on hot parse paths.

♻️ Proposed refactor
+const BRACES_RE = new RegExp(Match.braces, 'g');
+
 export class PatternCompiler {
     ...
     compileRegExp(...) {
         ...
         const matcher = (source: string, d = 0): string => {
             ...
-            return source.replace(new RegExp(Match.braces, 'g'), (match, name) => {
+            return source.replace(BRACES_RE, (match, name) => {
🤖 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 `@packages/tempo/src/engine/engine.pattern.ts` at line 57, The code recreates
new RegExp(Match.braces, 'g') on every recursive matcher invocation; hoist this
RegExp into a module- or class-level constant (e.g., BRACES_REGEX) and replace
occurrences of new RegExp(Match.braces, 'g') inside the matcher function (the
source.replace call that uses Match.braces) with that constant so the same
RegExp instance is reused across all invocations.
🤖 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 `@doc/main_branch_protection.md`:
- Around line 143-144: The numbered step heading "# 3. Switch to your new branch
to continue working" is off-by-one in the recovery block; update that heading to
the correct sequence number to match the surrounding steps (e.g., change "# 3.
Switch to your new branch to continue working" to "# 4. Switch to your new
branch to continue working") so the instructions and the command "git checkout
feature/my-feature" align with the step ordering.

---

Duplicate comments:
In `@packages/tempo/src/engine/engine.pattern.ts`:
- Around line 92-96: The logError call in the catch block is passing an object
literal as the first argument instead of the config instance, so the error is
still swallowed; change the call to pass this.#state.config as the first
parameter and then supply the contextual info and the caught error as subsequent
args (i.e. call logError(this.#state.config, { context: 'pattern compile
failed', pattern: source }, e)) in the catch inside the pattern compilation
(references: logError, this.#state.config, Match.escape, RegExp).

---

Nitpick comments:
In `@doc/main_branch_protection.md`:
- Around line 6-8: The sentence "I have already set up local hooks..." reads as
a personal note and should be made neutral for shared documentation; edit the
document text that lists the hooks (the lines mentioning "pre-commit" and
"pre-push") to use repository-neutral wording such as "Local hooks can be
configured to:" or "Set up local hooks to:" and rephrase the two bullets to
describe the behavior ("pre-commit: prevents direct commits to main", "pre-push:
prevents pushing to remote main") without implying they are already installed
for the reader.

In `@packages/tempo/src/engine/engine.pattern.ts`:
- Line 57: The code recreates new RegExp(Match.braces, 'g') on every recursive
matcher invocation; hoist this RegExp into a module- or class-level constant
(e.g., BRACES_REGEX) and replace occurrences of new RegExp(Match.braces, 'g')
inside the matcher function (the source.replace call that uses Match.braces)
with that constant so the same RegExp instance is reused across all invocations.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: fdd35921-ffc8-4f54-9a35-c085993bda7a

📥 Commits

Reviewing files that changed from the base of the PR and between 3b7a121 and 97c2f0c.

📒 Files selected for processing (2)
  • doc/main_branch_protection.md
  • packages/tempo/src/engine/engine.pattern.ts

Comment thread doc/main_branch_protection.md Outdated
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

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

⚠️ Outside diff range comments (2)
packages/tempo/src/parse/parse.layout.ts (1)

81-86: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Hoist ownEntries(ordered) and guard against length mismatch.

Same root cause as in engine.layout.ts: ownEntries(ordered) is recomputed inside .some, and (ownEntries(ordered)[idx] as LayoutEntry)[0] will throw if layouts.length exceeds ordered's entry count. resolveLayoutClassificationOrder (Line 70) already gates this with a length comparison.

♻️ Proposed fix
-	const layouts = resolveLayoutOrderPure(ordered, monthDayLayouts, isMonthDay);
-	const changed = layouts.some((entry, idx) => entry[0] !== (ownEntries(ordered)[idx] as LayoutEntry)[0]);
-
-	if (changed) return Object.fromEntries(layouts) as Record<symbol, string>;
-	return ordered;
+	const layouts = resolveLayoutOrderPure(ordered, monthDayLayouts, isMonthDay);
+	const orderedEntries = ownEntries(ordered) as LayoutEntry[];
+	const changed = layouts.length === orderedEntries.length
+		&& layouts.some((entry, idx) => entry[0] !== orderedEntries[idx][0]);
+
+	return changed ? Object.fromEntries(layouts) as Record<symbol, string> : ordered;
🤖 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 `@packages/tempo/src/parse/parse.layout.ts` around lines 81 - 86, Hoist the
result of ownEntries(ordered) into a local variable before computing changed and
guard against length mismatch: compute const own = ownEntries(ordered) once,
then set changed based on either layouts.length !== own.length or
layouts.some((entry, idx) => entry[0] !== (own[idx] as LayoutEntry)[0]); update
the code around resolveLayoutOrderPure/ownEntries/layouts to use this guard so
you don't recompute ownEntries(ordered) inside .some or access out-of-range
indexes.
packages/tempo/src/engine/engine.layout.ts (1)

98-103: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Hoist ownEntries(ordered) and guard against length mismatch.

ownEntries(ordered) is re-evaluated on every iteration of .some, making the change-detection O(n²) and allocating a fresh entries array per element. Also, if resolveLayoutOrderPure ever returns more elements than ordered has own entries, (ownEntries(ordered)[idx] as LayoutEntry)[0] will throw on undefined[0]. The companion helper resolveLayoutClassificationOrder (Line 78) already guards with a length check first; please mirror that here.

♻️ Proposed fix
-	const layouts = resolveLayoutOrderPure(ordered, monthDayLayouts, isMonthDay);
-	const changed = layouts.some((entry, idx) => entry[0] !== (ownEntries(ordered)[idx] as LayoutEntry)[0]);
-
-	if (changed) return Object.fromEntries(layouts) as Record<symbol, string>;
-	return ordered;
+	const layouts = resolveLayoutOrderPure(ordered, monthDayLayouts, isMonthDay);
+	const orderedEntries = ownEntries(ordered) as LayoutEntry[];
+	const changed = layouts.length === orderedEntries.length
+		&& layouts.some((entry, idx) => entry[0] !== orderedEntries[idx][0]);
+
+	return changed ? Object.fromEntries(layouts) as Record<symbol, string> : ordered;
🤖 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 `@packages/tempo/src/engine/engine.layout.ts` around lines 98 - 103, Hoist
ownEntries(ordered) into a single const (e.g., const entries =
ownEntries(ordered)) before calling resolveLayoutOrderPure, guard that
layouts.length === entries.length and if they differ return ordered immediately,
then compute changed using entries (e.g., layouts.some((entry, idx) => entry[0]
!== (entries[idx] as LayoutEntry)[0])); update the return path to still use
Object.fromEntries(layouts) when changed; reference resolveLayoutOrderPure,
ownEntries, layouts, changed, and mirror the length-first check used in
resolveLayoutClassificationOrder.
🧹 Nitpick comments (3)
packages/tempo/test/engine/pattern_compiler_optimization.test.ts (1)

6-44: ⚡ Quick win

Tests share mutable global Tempo state; ordering matters.

Each test obtains the same internal state via (Tempo as any)[$Internal]() and writes to state.parse.snippet[getSymbol(...)], so mutations from earlier tests leak into later ones. Today this passes only because the symbol keys don't conflict in unintended ways (e.g. c set in test 1 is never overwritten, x is unique). Adding/reordering tests can produce confusing failures.

Consider snapshotting and restoring the affected snippet entries in beforeEach/afterEach, or using TempoRuntime.createScoped() so each test gets a clean compiler input.

🤖 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 `@packages/tempo/test/engine/pattern_compiler_optimization.test.ts` around
lines 6 - 44, Tests mutate shared Tempo internal state via (Tempo as
any)[$Internal]() and writing to state.parse.snippet[getSymbol(...)], causing
ordering-dependent leaks; fix by isolating state per test—either create a fresh
scoped runtime with TempoRuntime.createScoped() and use its internal state when
constructing PatternCompiler, or add beforeEach/afterEach that snapshots and
restores (or clears) state.parse.snippet entries touched by the tests (refer to
Tempo, $Internal, PatternCompiler, state.parse.snippet, getSymbol, and
TempoRuntime.createScoped to locate the code to change).
packages/tempo/src/engine/engine.pattern.ts (1)

50-50: 💤 Low value

Drop spurious optional chaining.

logWarn is a static import and #state is set in the constructor — neither can be nullish at this call site. The ?. on both makes the intent ambiguous (suggests they might be undefined). Same pattern is used correctly without ?. at line 96 (logError(this.#state.config, …)).

♻️ Proposed change
-				logWarn?.(this.#state?.config, `[PatternCompiler] Recursion limit exceeded in matcher (d > 10) for src:`, source, `depth:`, d);
+				logWarn(this.#state.config, `[PatternCompiler] Recursion limit exceeded in matcher (d > 10) for src:`, source, `depth:`, d);
🤖 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 `@packages/tempo/src/engine/engine.pattern.ts` at line 50, The log call uses
spurious optional chaining on both logWarn and this.#state which are guaranteed
to be defined; remove the `?.` so the call becomes logWarn(this.#state.config,
...) to match the pattern used by logError(this.#state.config, ...) and avoid
implying these values may be undefined; update the call in the
PatternCompiler/matcher recursion branch accordingly.
packages/tempo/src/parse/parse.layout.ts (1)

7-72: ⚖️ Poor tradeoff

Layout-ordering logic is duplicated across parse.layout.ts and engine.layout.ts and is starting to diverge.

createLayoutController, resolveLayoutClassificationOrder, resolveLayoutOrder, getLayoutOrder, the TOKEN_ALIAS/TOKEN_DESCRIPTION_BY_NAME maps, and DEFAULT_LAYOUT_CLASS are near-identical between the two files. They have already drifted in two ways:

  • LayoutController is typed as Record<PropertyKey, (string | symbol)[]> here vs Record<PropertyKey, string[]> in engine.layout.ts.
  • resolveLayoutClassificationOrder here additionally branches on typeof name === 'symbol' (Lines 51-58); the engine copy does not.

Future fixes will need to be applied in two places and are easy to forget. Consider keeping a single canonical implementation (e.g., in engine.layout.ts with the broader (string | symbol)[] signature) and re-exporting from parse.layout.ts, or extracting both into a shared support module.

🤖 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 `@packages/tempo/src/parse/parse.layout.ts` around lines 7 - 72, Duplicate
layout-ordering code between parse.layout.ts and engine.layout.ts should be
consolidated; extract createLayoutController, resolveLayoutClassificationOrder,
resolveLayoutOrder, getLayoutOrder, TOKEN_ALIAS, TOKEN_DESCRIPTION_BY_NAME, and
DEFAULT_LAYOUT_CLASS into a single shared module (or keep the canonical
implementation in engine.layout.ts) and re-export from parse.layout.ts. Ensure
the canonical signature uses LayoutController = Record<PropertyKey, (string |
symbol)[]> and retain the symbol-handling branch (the typeof name === 'symbol'
logic) inside resolveLayoutClassificationOrder so behavior stays consistent;
update imports in both files to use the shared exports and remove the duplicated
implementations.
🤖 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 `@packages/tempo/doc/tempo.layout.md`:
- Around line 88-94: The example output for Tempo.regexp is inaccurate:
compileRegExp (in engine.pattern.ts) wraps the whole expansion in an outer
capturing group and the default {sep} snippet is a named capture, so the doc
should either show the real produced pattern or be marked illustrative; update
the example to match actual output from Tempo.regexp (showing the leading ^( ...
)$ with the outer group and that {sep} expands to a named group like
(?<sep>...)), or add a clear “illustrative only” note. Reference: Tempo.regexp
and compileRegExp in engine.pattern.ts.

In `@packages/tempo/src/support/support.util.ts`:
- Around line 64-72: The create<T> function currently assumes proto(obj) is an
object and directly indexes into it, which will throw if proto(obj) is null
(e.g., Object.create(null)); first assign proto(obj) to a variable (e.g., const
prototype = proto(obj)), check that prototype is an object with
isObject(prototype) before accessing prototype[name], and if that check fails
call logError(...) and return {} as T; then proceed to validate entry with
isObject(entry) as before. This ensures create, proto, isObject and logError are
used to guard the prototype lookup and avoid TypeError.

---

Outside diff comments:
In `@packages/tempo/src/engine/engine.layout.ts`:
- Around line 98-103: Hoist ownEntries(ordered) into a single const (e.g., const
entries = ownEntries(ordered)) before calling resolveLayoutOrderPure, guard that
layouts.length === entries.length and if they differ return ordered immediately,
then compute changed using entries (e.g., layouts.some((entry, idx) => entry[0]
!== (entries[idx] as LayoutEntry)[0])); update the return path to still use
Object.fromEntries(layouts) when changed; reference resolveLayoutOrderPure,
ownEntries, layouts, changed, and mirror the length-first check used in
resolveLayoutClassificationOrder.

In `@packages/tempo/src/parse/parse.layout.ts`:
- Around line 81-86: Hoist the result of ownEntries(ordered) into a local
variable before computing changed and guard against length mismatch: compute
const own = ownEntries(ordered) once, then set changed based on either
layouts.length !== own.length or layouts.some((entry, idx) => entry[0] !==
(own[idx] as LayoutEntry)[0]); update the code around
resolveLayoutOrderPure/ownEntries/layouts to use this guard so you don't
recompute ownEntries(ordered) inside .some or access out-of-range indexes.

---

Nitpick comments:
In `@packages/tempo/src/engine/engine.pattern.ts`:
- Line 50: The log call uses spurious optional chaining on both logWarn and
this.#state which are guaranteed to be defined; remove the `?.` so the call
becomes logWarn(this.#state.config, ...) to match the pattern used by
logError(this.#state.config, ...) and avoid implying these values may be
undefined; update the call in the PatternCompiler/matcher recursion branch
accordingly.

In `@packages/tempo/src/parse/parse.layout.ts`:
- Around line 7-72: Duplicate layout-ordering code between parse.layout.ts and
engine.layout.ts should be consolidated; extract createLayoutController,
resolveLayoutClassificationOrder, resolveLayoutOrder, getLayoutOrder,
TOKEN_ALIAS, TOKEN_DESCRIPTION_BY_NAME, and DEFAULT_LAYOUT_CLASS into a single
shared module (or keep the canonical implementation in engine.layout.ts) and
re-export from parse.layout.ts. Ensure the canonical signature uses
LayoutController = Record<PropertyKey, (string | symbol)[]> and retain the
symbol-handling branch (the typeof name === 'symbol' logic) inside
resolveLayoutClassificationOrder so behavior stays consistent; update imports in
both files to use the shared exports and remove the duplicated implementations.

In `@packages/tempo/test/engine/pattern_compiler_optimization.test.ts`:
- Around line 6-44: Tests mutate shared Tempo internal state via (Tempo as
any)[$Internal]() and writing to state.parse.snippet[getSymbol(...)], causing
ordering-dependent leaks; fix by isolating state per test—either create a fresh
scoped runtime with TempoRuntime.createScoped() and use its internal state when
constructing PatternCompiler, or add beforeEach/afterEach that snapshots and
restores (or clears) state.parse.snippet entries touched by the tests (refer to
Tempo, $Internal, PatternCompiler, state.parse.snippet, getSymbol, and
TempoRuntime.createScoped to locate the code to change).
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: aa42f25e-5951-4506-bd6a-8d1fd90786f3

📥 Commits

Reviewing files that changed from the base of the PR and between 97c2f0c and 35b2dd3.

📒 Files selected for processing (26)
  • doc/main_branch_protection.md
  • packages/tempo/doc/tempo.layout.md
  • packages/tempo/package.json
  • packages/tempo/src/discrete/discrete.parse.ts
  • packages/tempo/src/engine/engine.layout.ts
  • packages/tempo/src/engine/engine.pattern.ts
  • packages/tempo/src/engine/engine.resolver.ts
  • packages/tempo/src/parse/parse.layout.ts
  • packages/tempo/src/parse/parse.resolver.ts
  • packages/tempo/src/plugin/plugin.util.ts
  • packages/tempo/src/plugin/term/term.quarter.ts
  • packages/tempo/src/plugin/term/term.season.ts
  • packages/tempo/src/support/support.default.ts
  • packages/tempo/src/support/support.enum.ts
  • packages/tempo/src/support/support.index.ts
  • packages/tempo/src/support/support.init.ts
  • packages/tempo/src/support/support.intl.ts
  • packages/tempo/src/support/support.register.ts
  • packages/tempo/src/support/support.runtime.ts
  • packages/tempo/src/support/support.symbol.ts
  • packages/tempo/src/support/support.util.ts
  • packages/tempo/src/tempo.class.ts
  • packages/tempo/src/tempo.type.ts
  • packages/tempo/test/engine/parse.layout.test.ts
  • packages/tempo/test/engine/pattern_compiler_optimization.test.ts
  • packages/tempo/test/plugins/plugin_registration.test.ts
💤 Files with no reviewable changes (1)
  • packages/tempo/src/parse/parse.resolver.ts
✅ Files skipped from review due to trivial changes (8)
  • packages/tempo/test/engine/parse.layout.test.ts
  • packages/tempo/test/plugins/plugin_registration.test.ts
  • packages/tempo/src/discrete/discrete.parse.ts
  • packages/tempo/src/plugin/term/term.quarter.ts
  • packages/tempo/src/plugin/plugin.util.ts
  • packages/tempo/src/support/support.enum.ts
  • packages/tempo/src/plugin/term/term.season.ts
  • packages/tempo/src/support/support.default.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/tempo/src/tempo.type.ts
  • packages/tempo/src/tempo.class.ts

Comment thread packages/tempo/doc/tempo.layout.md
Comment thread packages/tempo/src/support/support.util.ts
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Caution

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

⚠️ Outside diff range comments (1)
packages/tempo/src/engine/engine.layout.ts (1)

54-60: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Symbol preferences should match exact symbol identity first

On Line 71-73, symbol resolution only checks description/alias. A preferred symbol that exists in layout but lacks both won’t match, so classification is silently ignored for that token.

Proposed fix
 	const entries = ownEntries(layout) as LayoutEntry[];
 	const byName = new Map<string, LayoutEntry>();
+	const bySymbol = new Map<symbol, LayoutEntry>();
 	entries.forEach(([key, value]) => {
+		bySymbol.set(key, [key, value]);
 		const description = key.description ?? '';
 		if (description) byName.set(description, [key, value]);
 		const alias = TOKEN_ALIAS.get(key);
 		if (alias) byName.set(alias, [key, value]);
 	});
@@
 		const resolvedName = !isSym ? (TOKEN_DESCRIPTION_BY_NAME.get(name) ?? name) : undefined;
 		const entry = isSym
-			? (byName.get(description) ?? (alias ? byName.get(alias) : undefined))
+			? (bySymbol.get(name) ?? byName.get(description) ?? (alias ? byName.get(alias) : undefined))
 			: (byName.get(resolvedName!) ?? byName.get(name));

Also applies to: 71-73

🤖 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 `@packages/tempo/src/engine/engine.layout.ts` around lines 54 - 60, The
classification misses tokens whose preferred symbol matches the actual symbol
identity but lacks description/alias; when building the lookup in the block that
uses ownEntries(layout) and populates byName (and reads TOKEN_ALIAS), also add
an identity-based mapping keyed by the symbol itself (i.e., store the
LayoutEntry under the symbol key) and/or check symbol identity first when
resolving preferred symbols (compare preferredSymbol === key or consult a
symbol->LayoutEntry map) before falling back to description or alias lookups.
🧹 Nitpick comments (1)
packages/tempo/src/engine/engine.pattern.ts (1)

150-167: 💤 Low value

hasOwn check covers cross-state pollution; consider value-presence check too.

hasOwn(state, 'patternCompiler') only checks property existence, not value. If anything ever assigns state.patternCompiler = undefined (e.g. during a registry reset), the non-null assertion on line 166 (state.patternCompiler!) will throw. A defensive value check is cheap and avoids the surprise:

🛡️ Suggested guard
-	if (!hasOwn(state, 'patternCompiler'))
-		state.patternCompiler = new PatternCompiler({ state });
-
-	state.patternCompiler!.setPatterns();
+	if (!state.patternCompiler)
+		state.patternCompiler = new PatternCompiler({ state });
+
+	state.patternCompiler.setPatterns();
🤖 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 `@packages/tempo/src/engine/engine.pattern.ts` around lines 150 - 167, The
current guard uses hasOwn(state, 'patternCompiler') which only checks property
existence and can still leave state.patternCompiler undefined; update
setPatterns to verify the value (e.g., ensure state.patternCompiler is truthy or
an instance of PatternCompiler) before calling setPatterns(), so replace the
hasOwn-only check with a defensive value check (e.g., if
(!state.patternCompiler) state.patternCompiler = new PatternCompiler({ state
});) and then call state.patternCompiler.setPatterns(); this ensures
PatternCompiler and its setPatterns method are safe to invoke.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@packages/tempo/src/engine/engine.layout.ts`:
- Around line 54-60: The classification misses tokens whose preferred symbol
matches the actual symbol identity but lacks description/alias; when building
the lookup in the block that uses ownEntries(layout) and populates byName (and
reads TOKEN_ALIAS), also add an identity-based mapping keyed by the symbol
itself (i.e., store the LayoutEntry under the symbol key) and/or check symbol
identity first when resolving preferred symbols (compare preferredSymbol === key
or consult a symbol->LayoutEntry map) before falling back to description or
alias lookups.

---

Nitpick comments:
In `@packages/tempo/src/engine/engine.pattern.ts`:
- Around line 150-167: The current guard uses hasOwn(state, 'patternCompiler')
which only checks property existence and can still leave state.patternCompiler
undefined; update setPatterns to verify the value (e.g., ensure
state.patternCompiler is truthy or an instance of PatternCompiler) before
calling setPatterns(), so replace the hasOwn-only check with a defensive value
check (e.g., if (!state.patternCompiler) state.patternCompiler = new
PatternCompiler({ state });) and then call state.patternCompiler.setPatterns();
this ensures PatternCompiler and its setPatterns method are safe to invoke.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: c7a5496a-9a9a-47e2-88e2-01255138606c

📥 Commits

Reviewing files that changed from the base of the PR and between 35b2dd3 and 6d4f30f.

📒 Files selected for processing (11)
  • packages/tempo/doc/tempo.layout.md
  • packages/tempo/package.json
  • packages/tempo/src/engine/engine.layout.ts
  • packages/tempo/src/engine/engine.pattern.ts
  • packages/tempo/src/parse/parse.layout.ts
  • packages/tempo/src/support/support.util.ts
  • packages/tempo/src/tempo.class.ts
  • packages/tempo/src/tsconfig.json
  • packages/tempo/test/engine/parse.layout.test.ts
  • packages/tempo/test/engine/pattern_compiler_optimization.test.ts
  • packages/tempo/vitest.config.ts
💤 Files with no reviewable changes (3)
  • packages/tempo/src/tsconfig.json
  • packages/tempo/vitest.config.ts
  • packages/tempo/src/parse/parse.layout.ts
✅ Files skipped from review due to trivial changes (2)
  • packages/tempo/test/engine/parse.layout.test.ts
  • packages/tempo/test/engine/pattern_compiler_optimization.test.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • packages/tempo/src/tempo.class.ts
  • packages/tempo/package.json
  • packages/tempo/src/support/support.util.ts

@magmacomputing magmacomputing merged commit e66d9aa into main May 7, 2026
2 checks passed
@magmacomputing magmacomputing deleted the feature/tempo-pattern-compiler branch May 7, 2026 04:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant