Skip to content

feat(search): optional user-config lexical alias source on both brain_search paths (Refs #995) - #1655

Draft
EtanHey wants to merge 3 commits into
mainfrom
claude/draft-pr-review-r6d95d
Draft

EtanHey wants to merge 3 commits into
mainfrom
claude/draft-pr-review-r6d95d

Conversation

@EtanHey

@EtanHey EtanHey commented Nov 5, 2026 •

Copy link
Copy Markdown
Owner

Change and evidence

Task marker: cloud-credit-20261105-brainlayer-hammer-aliases995 · Draft only, for the owning lead (routed to orc) to review. Not for merge as-is.

What #995 asked, and the path that is actually live

#994/#997 emptied the shipped alias data. #995's main item, the runtime user-config source, was never built. Tracing today's brain_search:

  1. Primary: MCPRouter → hybrid helper subprocess (brainbar_hybrid_helper.py) → Python _brain_search → _expanded_fts_query → _lexical_defense_variants → packaged JSON.
  2. Fallback (helper empty, failed or over budget): Swift BrainDatabase.expandedSearchQueries → lexicalDefenseReplacements, which is the empty literal [:].

Both paths now read one optional file with one contract. Fixing only path 1 would leave the fallback quietly without user aliases.

Config contract (also in docs/configuration.md → "Personal lexical aliases")

  • File: ~/.config/brainlayer/lexical_defense.local.json, or an absolute path in BRAINLAYER_LEXICAL_DEFENSE_LOCAL. Nothing creates or writes it.
  • Schema: {"version": 1, "entries": [{"canonical": str, "aliases"?: [str], "split_forms"?: [str]}]}
  • Missing file: no user aliases. Packaged behavior is unchanged; the Python loader returns the same packaged dictionary object.
  • Malformed: the whole file is ignored, with one warning per file version. That covers: over 64 KiB; not UTF-8 JSON; wrong or bool version; unknown keys; more than 256 entries; more than 16 surfaces per entry; a surface that is empty, longer than 64 characters, or punctuation-only.
  • Conflicts: a user entry that claims a packaged surface, or an earlier user entry's surface, is skipped whole and logged. Surfaces are compared by letters and digits, case-folded. Packaged entries can never change.
  • Cycles: A→B plus B→A collide under the conflict rule, so the later entry is skipped. Expansion is one hop, never transitive.
  • Freshness/caching: the file is stat()ed on every search and re-read only when (path, mtime, size) changes. Edits apply on the next search, with no restart of BrainBar or the helper.
  • User entries are protect_from_split=False with source user_config. The VoiceLayer/GBNF/JSON export script still reads only the packaged dictionary, so user terms never reach exported artifacts.
  • The packaged lexical_defense_dictionary.json is byte-for-byte unchanged (a sha256 check is in the test). private static let lexicalDefenseReplacements: [String: [String]] = [:] is unchanged, so the existing pin in test_brainbar_bundle_has_no_personal_lexical_defaults still holds.
  • tests/conftest.py: one delenv so an operator-exported override can't walk past the per-test HOME remap.

Proof (synthetic fixtures only: Zorbleth, qwvx, Plimsar, …)

Check Result
pytest tests/test_lexical_defense_user_aliases.py tests/test_lexical_defense.py tests/test_search_alias_expansion.py tests/test_search_handler.py tests/test_brainbar_hybrid_helper.py 93 passed
Old vs new: the e2e _brain_search("qwvx") test and the one-hop cycle test, run against main's src/ (stashed) OLD: 2 failed ([] == ['chunk-zorbleth'], ['Zorbleth'] == ['Zorbleth', 'qwvx']). NEW: 2 passed
Python mutants (7): conflict check removed, stamp ignored, byte bound removed, bool version accepted, earlier-user-entry claim dropped, lax top-level keys, per-entry surface bound removed 7/7 killed, re-run after the 395bbd8 refactor. The byte-bound mutant first survived; the fixture was fixed to schema-valid JSON plus whitespace padding, so only the byte bound can reject it
Every Python test that references brain-bar/Sources (12 files), plus test_ci_swift_gate.py and test_brainbar_update_script.py 1097 passed, 1 xfailed, 3 failed: they fail identically on unmodified main in this container (zstd snapshot, BrainBar socket routing, root-owned path while running as root). Environmental, not this change
ruff check / ruff format --check on changed Python clean
Native Swift compile (hosted CI): global model retirement (installed + native) on macos-15, Xcode 26.3, at 395bbd838c74 runs swift build --build-tests on brain-bar unconditionally (scripts/retirement_native.py) PASS (job). Both the BrainBar and BrainBarDaemon targets and the test target compile, including LexicalDefenseUserAliases.swift, the Daemon symlink and the new XCTest file. Only RetirementRatchetTests were executed there

UNRUN / limitations

  • No Swift toolchain in this Linux container. LexicalDefenseUserAliases.swift, the 3-line BrainDatabase wiring, the Daemon symlink and LexicalDefenseUserAliasesTests.swift (5 XCTests: absent→unchanged native search then a hit, edit/delete freshness, 13 malformed cases + non-UTF-8, conflict/cycle/one-hop) were not compiled or run by me. Hosted macOS CI compiled them at 395bbd8 (row above). Running the 5 new XCTests is still UNRUN. swift (macos-15) started at 06:25Z and the process died at 06:30Z: a SIGSEGV in pre-existing EntityCache.startRefreshTimer → tableColumns (use-after-close of a raw sqlite3*) during BrainBarMaintenanceRetryTests. That happened before the alphabetical suite order reached LexicalDefenseUserAliasesTests. Analysis is in the PR comment; the job is green on main. Nothing here claims installed or live behavior.
  • CI at 395bbd8 (final read 06:35Z): green: lint, CodeQL (incl. Swift), crash sweeps, test (3.12), installed-wheel imports, ratchet table (no RED rows), BrainBar no-enrichment render, and native swift build --build-tests. Red, judged not this PR's (one PR comment each): test (3.11), where ci-unit hit its 1800s budget at 98% on an untouched WAL test (main ran 28 min, here 37 min); and swift (macos-15), the EntityCache crash above. test (3.13) was cancelled by fail-fast. My re-run attempt returned 403, so the lead needs to re-run the failed jobs on run 41973840809.
  • Swift mutants: not run.
  • DeepSource: 6 inline findings were addressed in 395bbd8 (Swift force-unwrap and implicitly unwrapped optionals; Python complexity and global), and their threads are resolved. DeepSource: Python is also red on main d6b82f0. DeepSource: Swift is green on main but still red at 395bbd8, and it posted no new inline findings. Whatever it flags is only on the DeepSource dashboard, which I couldn't read, so the lead needs to look there.
  • Not run: the full Python suite, scripts/run_tests.sh, or the repo pre-push hook (core.hooksPath isn't set in this clone; nothing was bypassed). The conftest.py touch will trigger the automatic crash sweep in CI.
  • Normalization edge: Python uses NFKC+casefold+isalnum; Swift uses NFKC+lowercased+CharacterSet.alphanumerics. They are identical for ASCII and can differ on exotic scripts/marks. Documented, not unified.
  • Swift XCTests that use a default BrainDatabase read the real $HOME default path, because there is no HOME isolation on the Swift side. On a developer Mac that has a personal alias file, an existing search test could in theory see an extra expansion. The new tests inject their own path.
  • Out of scope per the dispatch: Lexical defense: personal alias entries were dropped by BL-0.1 (#994); add a runtime user-config source #995's N5 (benchmark relabel) and N6 (Phoenix whitespace URL).

Size: over the 400-line budget, reported rather than hidden

+645/−3 total at 395bbd8. Commit 1 c11f9a2 (Python path + conftest + tests) ≈ 333 lines, and the docs add 26. Commit 2 d4670a8 (Swift fallback + XCTests + docs) ≈ 318 lines. The two commits separate cleanly. If the lead wants it split, cherry-pick d4670a8 onto its own PR. 395bbd8 only addresses static-analysis findings across both halves, with no behavior change. This dispatch allowed one branch only, so I didn't push a second one.

Risks

  • A personal file with a common word as an alias widens FTS recall for that word. The user owns the file; packaged surfaces are protected.
  • stat() once per search on each path: negligible next to FTS.

Handoff — addressed to orc (dispatcher: copy into orchestrator/docs.local/plans/2026-11-04-claude-cloud-batch/collab.md; that file was not mounted here)

orc: #995 runtime user-alias source is implemented as a draft on claude/draft-pr-review-r6d95d @ 395bbd8. The Python path is proven (old fails, new passes; 7/7 mutants killed). The Swift fallback follows the same contract. It compiles on hosted macOS-15 at 395bbd8; its XCTests have not run yet: the swift (macos-15) process crashed first in pre-existing EntityCache code, which is green on main. test (3.11) hit a CI time budget. Both need one lead re-run (my re-run got 403), and EntityCache has a separate latent use-after-close bug worth its own PR. 645 lines, over budget. Python and Swift are separable commits, plus one static-analysis cleanup commit. Needs: lead review, the Swift CI result, and a cross-vendor (Codex) pair review. This is not final acceptance. Use Refs #995, not Fixes: N5/N6 remain open on the issue. No real user config, credentials, DB or Mac was touched, and no personal entries appear anywhere.

Loop-record: implementer=Claude Code cloud (Anthropic)/effort high; reviewer=none; rounds=0; defects=0


Generated by Claude Code

Note

Add optional user-config lexical alias source to both brain_search paths

  • Users can define personal lexical aliases in a JSON file, loaded from the user config directory or the BRAINLAYER_LEXICAL_DEFENSE_LOCAL environment override.
  • Adds a Swift source (LexicalDefenseUserAliases.swift, shared with the daemon via symlink) and a Python loader (lexical_defense.py) with strict whole-file validation: schema version, entry and surface counts, surface length, and byte limit. Any violation rejects the entire file.
  • Entries whose normalized surfaces conflict with packaged surfaces or earlier accepted entries are skipped with a warning. Alias expansion is one hop, not transitive.
  • Results are cached by file stamp (modification date and size); edits and deletions apply on the next lookup without restart. See docs/configuration.md for the format.
  • Behavioral Change: malformed or unreadable alias files leave the effective dictionary identical to the packaged baseline, and user entries are not protected from splitting.

Macroscope summarized d4670a8. (Automatic summaries will resume when PR exits draft mode or review begins).

…n search path (Refs #995)

Adds ~/.config/brainlayer/lexical_defense.local.json (override:
BRAINLAYER_LEXICAL_DEFENSE_LOCAL) merged at runtime on top of the packaged
dictionary. Missing file -> packaged dictionary unchanged. Strict bounded
schema; any violation rejects the whole file with one warning. User entries
never claim a packaged surface or an earlier user entry's surface. The file is
stat()ed per call and re-read only when (path, mtime_ns, size) changes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L3NoZGEuwfULsRM3NY1aJh
…earch fallback (Refs #995)

The hybrid helper (Python) and BrainBar's native fallback now expand the same
optional ~/.config/brainlayer/lexical_defense.local.json, with identical bounds,
whole-file rejection, conflict/cycle policy and stat-keyed freshness. The
packaged lexicalDefenseReplacements table stays the empty literal. Documents
the config contract and tightens the oversized fixture so only the byte bound
can reject it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L3NoZGEuwfULsRM3NY1aJh
@coderabbitai

coderabbitai Bot commented Nov 5, 2026

Copy link
Copy Markdown

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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

@deepsource-io

deepsource-io Bot commented Nov 5, 2026 •

Copy link
Copy Markdown

DeepSource Code Review

We reviewed changes in d6b82f0...395bbd8 on this pull request. Below is the summary for the review, and you can see the individual issues we found as inline review comments.

See full review on DeepSource ↗

Important

Some issues found as part of this review are outside of the diff in this pull request and aren't shown in the inline review comments due to GitHub's API limitations. You can see those issues on the DeepSource dashboard.

PR Report Card

Overall Grade   Security  

Reliability  

Complexity  

Hygiene  

Code Review Summary

Analyzer Status Updated (UTC) Details
Python Nov 5, 2026 5:24a.m. Review ↗
Swift Nov 5, 2026 5:24a.m. Review ↗
JavaScript Nov 5, 2026 5:24a.m. Review ↗
Shell Nov 5, 2026 5:24a.m. Review ↗
Secrets Nov 5, 2026 5:24a.m. Review ↗

Important

AI Review is run only on demand for your team. We're only showing results of static analysis review right now. To trigger AI Review, comment @deepsourcebot review on this thread.

Comment thread src/brainlayer/lexical_defense.py Resolved
Comment thread src/brainlayer/lexical_defense.py Resolved
…er alias source (Refs #995)

Swift: bind the canonical value instead of force-unwrapping it; the XCTest
case drops implicitly unwrapped properties and owns its one database locally.
Python: split per-entry validation out of parse_user_alias_entries and hold
the effective-dictionary cache in a lock-guarded list instead of a global.
No behavior change; 7/7 mutants still killed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L3NoZGEuwfULsRM3NY1aJh
@github-actions

github-actions Bot commented Nov 5, 2026

Copy link
Copy Markdown

BrainLayer ratchet

Every Value below was measured by this run. A row this machine cannot measure says n/a — <reason> instead of a number; baselines in Notes name their own machine, method and date and were not measured here.

Hosted success gives no verdict on mapped bytes, search p50/p95, idle CPU, hotlane backlog CPU, or fallback replay debt.

Row Status Value (measured by this run) Method Notes
commit provenance 🟢 GREEN measured 395bbd838c74 == PR head · checkout 395bbd838c74 commit graph + live PR head · in-process · runner Which commit this whole table is about. On a pull_request event the checkout is GitHub's synthetic merge ref, whose sha is not on the PR — #759's table printed 13fa724278bf while that PR's head was 4632f979 — so this row names the PR-head parent instead, the sha a reviewer can actually see. The comparison sha is read live from repos/{owner}/{repo}/pulls/{n} when the table is collected, not taken from the event payload, because the payload cannot know the run has been overtaken. Residual window, stated rather than papered over: a push landing between that read and the comment being posted is not caught here — the run for that push refreshes the table.
baseline attestation 🟢 GREEN baseline f421d1a7c5e6 matches the main attestation (run 41876229562 · main d6b82f04f6ba · 2026-11-04T17:18:27Z) main attestation artifact via Actions API · in-process · runner What every comparison is measured AGAINST, and who says so. The baseline fields of tests/fixtures/sprint_gate/corpus.json (queries, latency_baseline_ms, thresholds) are compared to the ratchet-attestation artifact of the latest successful push or (no-input) workflow_dispatch run of ratchet-attest.yml on main, fetched through the Actions API — a PR run cannot write to another run's artifacts. A field that differs is RED unless that main run measured the new value. The calibrated socket collector can license p50/p95; every absent measured path stays locked, so missing collection never passes as permission for a hand edit. Boundary: the comparator is this PR's checkout of ci_ratchet_table.py, diff-reviewable, not tamper-proof.
provenance 🟢 GREEN stamped 395bbd838c74 == HEAD, tree clean wheel stamp · in-process · runner Sha half of #749 keg-mode provenance: a keg built from this wheel can answer __build_sha__. The helper-age and served-process predicates need a running BrainBar and are measured only by scripts/sprint_gate.py on an installed Mac. The sha here is the checkout's — the explicit PR head in ratchet.yml — because that is what publish.yml stamps at release time; the PR-head sha this table describes is the one in commit provenance above.
fallback replay debt ⚪ n/a n/a — no fallback queue on this machine: the pending memories live in ~/Gits/*/docs.local/decisions, and docs.local/ is gitignored, so a runner checkout has no copy of them to count docs.local walk · machine with the fallback queue local-only; not enforced by hosted CI. intended_brain_store: true with no chunk_id means a memory reached disk and never reached the DB, so it answers no brain_search. Budget: 0. Any pending or unparseable file is a finding, never a band -- 122 of these sat from 2026-06-28 to 2026-09-05 because nothing counted them where a reader would look. Measured by walking the tree, so it is only ever measured on a machine that HAS the tree.
pre-push: delete-only push runs no suite 🟢 GREEN 0 suite starts · exit 0 real checkout hook · delete-only stdin · sentinel suite runner Bug SHA: 44ecbf5ba6f1ada3b965797559eee90c94b45595 (RED replay, 2026-10-06). Fix: #1084; measured at 395bbd838c743e3634ff639486d4c9a3c1bec7dd. Ceiling: 0 suite starts; hook must exit 0 and announce the delete-only skip.
mapped bytes ⚪ n/a n/a — no BrainBar daemon at /tmp/brainbar.sock: this row needs the daemon, its hybrid helper and the indexed corpus running together, and no GitHub-hosted runner has them (macOS included) — only a self-hosted Darwin/arm64 runner on an installed Mac would socket · installed Mac local-only; not enforced by hosted CI. Baseline 26.2 GB — installed Mac, socket, 2026-09-03, after R2 drained 15,070 → 0. Up from 16.8 GB because the drain left more vectors mapped under the same cap: the change is the drain, not a leak. Not measured by this run.
search p50/p95 ⚪ n/a n/a — no BrainBar daemon at /tmp/brainbar.sock: this row needs the daemon, its hybrid helper and the indexed corpus running together, and no GitHub-hosted runner has them (macOS included) — only a self-hosted Darwin/arm64 runner on an installed Mac would socket · installed Mac local-only; not enforced by hosted CI. Margin p50: margin unmeasured — 0 of the 5 attested green main runs it needs; no verdict is rendered from fewer. Margin p95: margin unmeasured — 0 of the 5 attested green main runs it needs; no verdict is rendered from fewer. Calibrated on MacBook-Pro.local at 2026-09-01T08:42:22Z under active_sprint_load (tests/fixtures/sprint_gate/corpus.json). Not measured by this run.
idle CPU ⚪ n/a n/a — no BrainBar daemon at /tmp/brainbar.sock: this row needs the daemon, its hybrid helper and the indexed corpus running together, and no GitHub-hosted runner has them (macOS included) — only a self-hosted Darwin/arm64 runner on an installed Mac would ps sampling · installed Mac local-only; not enforced by hosted CI. Ceiling: average CPU < 30% over a 60 s window (resource_budget in scripts/sprint_gate.py), ratified and kept as a hard budget. Margin daemon: margin unmeasured — 0 of the 5 attested green main runs it needs; no verdict is rendered from fewer. Margin helper: margin unmeasured — 0 of the 5 attested green main runs it needs; no verdict is rendered from fewer. Margin watcher: margin unmeasured — 0 of the 5 attested green main runs it needs; no verdict is rendered from fewer. Needs the BrainBar daemon, helper and watcher actually running. Not measured by this run.
hotlane backlog CPU ⚪ n/a n/a — live hotlane CPU evidence requires an installed Mac CPU/wall for backlog-encoding cycles · rolling 600 s · installed Mac local-only; not enforced by hosted CI. Default budget 60% of one core; BRAINLAYER_HOTLANE_CPU_BUDGET_PERCENT overrides. At least 30s of active backlog cycles required; yielded time excluded. Measures installed code.
signature_valid ⚪ n/a n/a — the macOS signature-parity job is trigger-gated and did not run on this PR: it touches no release or signing path (pyproject.toml, scripts/release-*, scripts/brainlayer-version-check.sh, publish.yml, ratchet.yml) and carries no ratchet:signatures label — a GitHub macOS runner bills at ~10× Linux minutes and rebuilds the keg venv from source codesign · installed keg scripts/release-verify-signatures.sh <keg> codesign-verifies every *.so/*.dylib under libexec/venv. The macOS parity job installs the published tap formula (etanhey/layers/brainlayer), so this row measures the release path — formula, published sdist and Homebrew's relocation — and not this PR's tree. Release-time baseline for the same keg on a different machine: 442 valid / 0 invalid — installed Mac (M4 Max), brew --prefix brainlayer 1.5.11, 2026-09-03.
BrainBar renders no enrichment status 🟢 GREEN 19 actual-view captures; active pending-store/replay retained macOS DEBUG binary · AppKit actual views · Vision OCR + icon RGBA comparison · private synthetic state Missing render capability/evidence is RED. Historical data is retained; this is source-build proof, not installed-app proof.
Watcher heartbeat freshness and recovery ⚪ n/a n/a — macOS native probe trigger-gated: no affected path or ratchet:heartbeat label private Python producer -> compiled Swift consumer Preserves genuine silence; independent agent stores cannot revive the watcher. Not a load or installed-UI measurement.
maintenance quiesce: services stay down under a reviving watchdog ⚪ n/a n/a — macOS replay trigger-gated: no affected path or ratchet:quiesce label real launchd · GitHub macOS runner · real maintenance + fleet-watchdog Fix: #1076 (bc6d690f4331387485678d0247e19e14e6ef8d97). Ceiling: 0 revivals; supervisor held, both resumed, no hold marker.
no cloud model call reachable anywhere 🟢 GREEN 522 source files; 460 installed imports; 3 native tests; wheel 4825d8439f2d; 0 candidate attempts immutable installed wheel (default + dev) + AST source + actual native BrainBar Synthetic private fixtures; SDK absence gated on merged R10b. Exact-head candidate proof, not deployment.

🟢 GREEN measured, within budget · 🔴 RED measured, out of budget — a finding to clear before merge · ⚪ n/a not measurable on this machine, never guessed.

No RED rows.

Measured on Linux/x86_64 · measured 395bbd838c74 · PR head 395bbd838c74 · checkout 395bbd838c74 · run · updated 2026-11-05 06:11:49 UTC

EtanHey commented Nov 5, 2026

Copy link
Copy Markdown
Owner Author

test (3.11) red at 395bbd8: CI time budget overrun, not a test failure. Job log: ERROR: ci-unit exceeded 1800s; last visible pytest node: tests/test_write_resilience_under_load.py::test_wal_file_bounded_after_checkpoint, exit 124, at 98% of the suite. No test failed before it.

Why I think it isn't this PR's:

I tried a single re-run of the failed jobs and got 403 Resource not accessible by integration, so I can't re-run it from this session. Ask for the lead: re-run the failed jobs on run 41973840809 once. A second timeout would make it real and worth investigating. No fix exists or is needed in this PR; I'm not widening the diff. swift (macos-15), which runs the new XCTests, is still queued in the same run.


Generated by Claude Code

EtanHey commented Nov 5, 2026

Copy link
Copy Markdown
Owner Author

swift (macos-15) red at 395bbd8: a native crash in pre-existing EntityCache code. No assertion failed. Job log: error: Exited with unexpected signal code 11, Program crashed: Bad pointer dereference.

  • Crashing thread: EntityCache.tableColumns(_:) (KnowledgeGraph/EntityCache.swift:64) ← EntityCache.load(from:) ← closure #1 in EntityCache.startRefreshTimer(db:) (:83), on a GCD worker thread. The x1 register holds PRAGMA table_info(kg_entities). The main thread was in BrainBarMaintenanceRetryTests.testActionOutcomesUseSupportedCLIAndNeverClaimMalformedOutputStarted.
  • Mechanism, as I read it: startRefreshTimer(db:) schedules a 60s repeating timer that captures a raw sqlite3* and calls load(from: db). An earlier fixture started that timer and closed its database without calling stopRefreshTimer(). About 60s later the timer fired on a freed handle. That is a latent use-after-close, which explains why it depends on timing.
  • Why it isn't this PR's: this diff doesn't touch EntityCache or the KG code. swift (macos-15) is green on main d6b82f0. XCTest runs suites alphabetically, so LexicalDefenseUserAliasesTests had not started when the process died. The only change before that point is a lazily-used stored property on BrainDatabase, which does no I/O at init. The same brain-bar package, test target included, compiled and its ratchet tests passed at this exact SHA in global model retirement (installed + native).
  • Re-run: I tried once for the 3.11 timeout and got 403 Resource not accessible by integration, so I can't re-run from this session. Ask for the lead: re-run the failed jobs on run 41973840809. That one action covers both test (3.11) and this job.
  • Proposed fix, out of scope here (it's a separate defect, so I haven't widened this PR): make the owner of the EntityCache timer call stopRefreshTimer() before sqlite3_close, or have the timer handler check a database-alive token instead of holding a raw pointer. The cleanest version is a small separate PR with a test that closes the database and advances past one refresh tick.

The 5 new LexicalDefenseUserAliasesTests XCTests therefore remain UNRUN. They compile, but no run has reached them yet.


Generated by Claude Code

This branch has not been deployed

No deployments
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.

2 participants