Skip to content

Module boundaries and CI ratchets - #1951

Merged
r3dbars merged 6 commits into
mainfrom
claude/cleanup-modules
Oct 2, 2026
Merged

r3dbars merged 6 commits into
mainfrom
claude/cleanup-modules

Conversation

@r3dbars

@r3dbars r3dbars commented Oct 2, 2026

Copy link
Copy Markdown
Owner

Stacked on #1950 (split the hotspot files) with #1948 (docs pass, which includes #1947) merged in. Review the last two commits; the rest is those PRs. Merge after them.

What this does

  • Module boundaries. .agents/modules.json maps every Sources/ Swift file to one of 17 modules and says what each may depend on. Core is split into tiers: core-vocab for anyone, mic-primitives for Speech, all of it for Meeting. scripts/dev/check-module-boundaries.py flags a type reference across an edge the manifest doesn't allow. Today's 70 crossings are in .agents/module-boundary-baseline.json, which can only shrink. Also --explain <file>, --graph, --self-test. agent-context.py now prints the module for each changed Sources/ path.
  • File-size ratchet. scripts/dev/check-file-size.py: no new Swift file over 800 lines, and the 45 that already are can't grow (.agents/file-size-baseline.json). --hotspots prints the over-1,500 list.
  • Wiring. Both run in linux-checks.sh (so check.sh quick and repo-hygiene) and have a test-matrix rule. Repo-hygiene also gets a named step for module boundaries, file size, test shape and source pins.
  • Concurrency census in CI. New .github/workflows/concurrency-census.yml on macos-26, only when Sources or the census change. To avoid flakes: if head is over the baseline, it counts the PR's base with the same compiler and fails only if a folder is above both (concurrency-census.py --allow-up-to). Kept out of swift-ci.yml because Transcripted Live: your meeting, live in Claude Code (mod + bundled helper) #1945 edits it. Costs one hosted macOS slot per Sources PR.
  • Docs. Each module's AGENTS.md gets a card (owns, public surface, may depend on, grandfathered crossings, entry points, tests, rules); new ones for UI/Shared and UI/MenuBar. Support, Observability and UI/Overlay cards live in Sources/AGENTS.md for now because Notch island is the only dictation window #1946 and Keep runtime heartbeat preference reads off the main thread #1941 edit those folder docs. Root AGENTS.md: the Core rule now matches reality (tiers), a "Module edges" trap, real pin counts (39 files) and hotspot numbers (4 files over 1,500). docs/repo-layout.md gets a modules table and a regenerated hotspot list. The split PR's doc notes are applied everywhere outside the Notch island is the only dictation window #1946/Keep runtime heartbeat preference reads off the main thread #1941 docs.

No Swift changed, so no behavior change and no product-surface change.

Not done, and why

Owner decisions

  • The Core rule rewording in AGENTS.md (tiers instead of "only through Meeting").
  • The 800-line freeze on new files.
  • UI modules may depend on AppState (allowed edge instead of a DI refactor).

Heads-up for other PRs

#1946 and #1924 grow TranscriptedSettingsView.swift / SpeakerPeopleSettingsSection.swift. If they merge after this, the file-size check will ask them for a reviewed baseline bump or a split. The test-matrix edit here is in a different hunk from #1945's.

Checks

  • check-module-boundaries.py --self-test, check-file-size.py --self-test, concurrency-census.py --self-test: pass
  • bash check.sh quick: pass (64 checks)
  • bash build-deps.sh --force, bash build.sh --no-open: pass
  • bash run-tests.sh: 20339 passed, 0 failed
  • bash scripts/dev/concurrency-census.sh --check: pass (114, same as baseline)
  • bash check.sh: every runnable check passed (build, tests, integration smoke, swift test, Tools tests, doc paths, the new ratchets). 3 matrix commands were BLOCKED as not runnable here (Lab build_and_run.sh --verify and the speaker-eval self-test flagged invalid-command, build-beta.sh needs operator input); they come from the stacked split/docs diff.
  • Independent review: not run on this diff yet.

🤖 Generated with Claude Code

.agents/modules.json maps every Sources/ file to one of 17 modules and says
what each may depend on, with Core split into tiers. check-module-boundaries.py
flags a reference to a type outside those edges; today's 70 crossings are
baselined and can only shrink. check-file-size.py fails on a new Swift file
over 800 lines and on a baselined one that grows. Both run in linux-checks.sh
(so check.sh quick and repo-hygiene) and have a test-matrix rule.
agent-context.py prints the module for each changed Sources/ path.

UI/Shared and UI/MenuBar get module cards.
The concurrency census runs in its own macOS workflow. When the head is over
the baseline it counts the PR's base with the same compiler and only fails if
a folder is above both, so a runner toolchain that reports more warnings than
the dev Mac can't turn every PR red.

Each module's AGENTS.md gets a card: what it owns, public surface, what it may
depend on, grandfathered crossings, entry points, tests, rules. Support,
Observability and UI/Overlay cards live in Sources/AGENTS.md until #1946 and
#1941 land, since those PRs edit their folder docs.

Root AGENTS.md: the Core rule now says what's true (tiers, Meeting gets all of
it), a Module edges trap, real pin and hotspot numbers. repo-layout gets a
modules table and a hotspot list from check-file-size. The split PR's doc
notes are applied everywhere outside the #1946/#1941 docs.
onStartFailed is now non-optional on the native start paths, so passing
nil can't silently drop the background-hotkey focus recovery. That's what
the deleted pin's commit message already claimed.

Census workflow:
- pushes to main get the same parent-commit fallback as PRs
- the base gets its own deps when Core or the deps recipe changed
- a head that doesn't typecheck fails outright instead of being compared
@r3dbars

r3dbars commented Oct 2, 2026

Copy link
Copy Markdown
Owner Author

Review verdict, applied in f9bec06. All four findings were real; all four fixed.

  1. Focus-recovery pin not actually held by the compiler (test-coverage, medium): fixed. onStartFailed is now @escaping () async -> Void, not optional, on startDictationAudioRecording, waitForEngineAndStart, performStartAttempt and DictationNativeMicrophoneStart.run. Passing nil no longer compiles. I didn't restore the text pin, since new source pins are blocked. The compiler can't catch a no-op closure, and the comment at the call says why it's required.
  2. Census on push to main had no fallback: fixed. Every event now compares against HEAD^1 (the PR's base, or the previous main commit on a push) with the same compiler.
  3. Base counted against the head's Core deps: fixed. If Sources/TranscriptedCore, Package.swift or build-deps.sh differ between base and head, the base worktree runs build-deps.sh --force and doesn't borrow the head's deps. Otherwise it still symlinks them. I raised the job timeout from 60 to 90 minutes to leave room for that.
  4. A head that doesn't typecheck could still pass: fixed. The step runs the census in report mode first, which only fails on a typecheck or deps error, and exits 1 right there. The over-baseline decision is a separate concurrency-census.py --mode check call.

Checks: bash build-deps.sh --force and bash build.sh --no-open pass. run-tests.sh --filter DictationRecordingStartAttempt passes 34/34. The local census report and check pass (114 = baseline). I parsed the workflow YAML and ran bash -n on the step. bash check.sh passed all 76 checks. Its proof says FAIL only for source-stability, because I committed while it was running. The new workflow paths (push fallback, base deps build) only run on a hosted runner, so I haven't seen them run there yet.

🤖 Generated with Claude Code

@r3dbars
r3dbars merged commit d2e5fad into main Oct 2, 2026
9 checks passed
@r3dbars
r3dbars deleted the claude/cleanup-modules branch October 2, 2026 07:00
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