feat(kernel): gate the macOS Contacts cohort behind contacts - #5365
Conversation
Sheds `objc2`, `objc2-foundation`, `objc2-contacts` and `block2` — plus two
transitives, 6 packages total — from slim macOS builds. All four are used
exclusively by `memory::people::address_book`; verified by grepping every
`<crate>::` path in src/ and finding no other file.
Nearly free, because the off-state already existed: `address_book.rs` has
shipped a non-macOS `imp` stub returning an empty contact list since before the
gate. The change is to widen that stub's cfg from `not(target_os = "macos")` to
`not(all(target_os = "macos", feature = "contacts"))`, and narrow the real one
to match. So `read()`, `read_with()`, `AddressBookError` and
`SystemContactsSource` stay compiled in every build, the `people` RPC surface is
byte-identical, and an address-book refresh with the gate off seeds nothing
rather than failing. The in-module test's cfgs are updated in lockstep so the
empty-result assertion covers the gated-off macOS build too.
I had earlier deferred this gate as "unverifiable on a Linux dev box". That was
wrong: cargo resolves a foreign target's graph without building it, so the shed
is provable from any host —
cargo tree --target aarch64-apple-darwin -e normal --prefix none \
--no-default-features --features tokenjuice-treesitter
goes 294 → 288 packages, and `-i objc2` / `-i objc2-foundation` /
`-i objc2-contacts` / `-i block2` all report "did not match any packages" with
the feature off. Note that error IS the proof of absence — the exact non-zero
inversion `scripts/assert-shed.sh` exists to warn about; that script does not
take a `--target`, hence the raw cross-target invocation here.
The Linux kernel-floor ratchet is deliberately unchanged at 312/285/6: these
crates were never in the Linux graph, so this gate is a no-op there and there is
no number to lower.
Verified: default and gates-off builds clean; `memory::people` 49 tests pass;
`check-feature-forwarding.mjs` passes with `contacts` forwarded to the shell.
Co-authored-by: Medulla <medulla@tinyhumans.ai>
There was a problem hiding this comment.
senamakel has reached the 50-credit limit for trial accounts. To continue receiving code reviews, upgrade your plan.
|
Warning Review limit reachedYou’ve reached a temporary PR review limit under our Fair Usage Limits Policy. Next review available in: 15 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: CHILL Plan: Pro Run ID: 📒 Files selected for processing (6)
Comment |
There was a problem hiding this comment.
senamakel has reached the 50-credit limit for trial accounts. To continue receiving code reviews, upgrade your plan.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 82b6d01cec
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
The CI workflow now runs tests for the memory people address book module and includes it in the expected gated-test file set, ensuring the new module's tests are properly covered and the feature-gate smoke check remains accurate.
The regex used to detect gated test files now also matches `cfg(not(feature = ...))` attributes and `cfg(all(..., feature = "contacts"))` patterns, ensuring the allowlist check covers additional feature-gating styles used in the codebase.
There was a problem hiding this comment.
senamakel has reached the 50-credit limit for trial accounts. To continue receiving code reviews, upgrade your plan.
Summary
contactsfeature gatingmemory::people::address_book's macOS CNContactStore reader.objc2,objc2-foundation,objc2-contacts,block2and two transitives (294 → 288 in the slim profile), proven cross-target.address_book.rshas always shipped a non-macOSimpstub returning an empty contact list; the gate widens that stub's cfg.Problem
objc2,objc2-foundation,objc2-contactsandblock2are declared unconditionally in thecfg(target_os = "macos")dependency table, so every macOS build links the Contacts framework bindings — including headless, embedded and CI builds that never touch an address book.All four are used by exactly one file. Verified by grepping every
<crate>::path acrosssrc/and finding no other consumer:address_book.rsobjc2objc2-foundationobjc2-contactsblock2Solution
A leaf gate over a pre-existing off-state, which is what makes it cheap.
address_book.rsalready had:The change narrows the real implementation to
all(target_os = "macos", feature = "contacts")and widens the stub tonot(all(...)). Consequences:read(),read_with(),AddressBookErrorandSystemContactsSourcestay compiled in every build.peopleRPC surface is byte-identical — no controller, store or tool changes.The in-module test's cfgs are updated in lockstep, so its empty-result assertion now covers the gated-off macOS build rather than silently skipping it.
On verifying a macOS-only shed from Linux
I had earlier set this gate aside as "unverifiable on a Linux dev box, and it would not move the kernel-floor ratchet anyway, so claiming it would be dishonest." That reasoning was wrong on the first half.
cargo treeresolves a foreign target's dependency graph without building it:and with the feature off,
-i objc2,-i objc2-foundation,-i objc2-contactsand-i block2each reportdid not match any packages.Two things worth flagging for whoever verifies the next shed:
scripts/assert-shed.shwas written to warn about — a naiveif cargo tree -i …reads it backwards.assert-shed.shdoes not take a--target, which is why this PR uses the raw cross-target invocation. Teaching it--targetwould be a reasonable follow-up so target-specific sheds get the same guard as the rest.The second half of my earlier reasoning still stands: the ratchet is Linux-measured, so it correctly does not move here.
Submission Checklist
read_with(&SystemContactsSource)test's cfgs are updated so the empty-result assertion (the failure path: no contacts available ⇒Ok(vec![]), not an error) now also covers macOS-with-gate-off. No new test: the gate has no new behaviour to cover, only a wider cfg on a path that was already asserted on Linux/Windows.cfgattributes and the matching test cfgs;memory::peopleruns 49 tests.N/A: no feature rows added, removed, or renamed.## Related—N/A: no matrix feature IDs affected.N/A: this removes dependencies, adds none.N/A: no release-cut surface touched.contactsis default-ON and forwarded to the desktop shell, so the shipped app is unchanged.Closes #NNN—N/A: no dedicated tracking issue. Dependency-shed work under the kernelization program (Feature gates for core subsystems — tracking (lightweight harness builds) #4795 → refactor(kernel): collapse 124 flat domains into 31 gate-aligned families #5328 → feat(kernel): realign DomainGroup with the family directories #5332).Impact
Runtime/platform: none for the shipped desktop app.
contactsis default-ON and forwarded inapp/src-tauri/Cargo.toml(verified bycheck-feature-forwarding.mjs), so macOS builds behave exactly as before.Slim macOS builds (
--no-default-features) lose CNContactStore seeding and get the empty-list stub — the behaviour Linux and Windows already had.Compatibility: no public API change.
AddressBookContact,AddressBookError,SystemContactsSource,read,read_withall keep their signatures in both builds.Performance: removes the Contacts framework link and four crate compilations from slim macOS builds.
Security: slightly reduces the macOS TCC surface in slim builds — no CNContactStore access is compiled in at all, so there is nothing to prompt for.
Related
scripts/assert-shed.sha--targetflag so target-specific sheds are guarded like the rest, instead of relying on a hand-runcargo tree.runtime-nodegate (xz2+ the static liblzma C build). Design settled: facade + stub, forced byShellToolholdingOption<Arc<NodeBootstrap>>as an always-compiled struct field — not byagent/harness_init, whosenode_runtime_step()is a registration site and leaf-gateable on its own.memory-git(git2+ vendored libgit2) — cross-repo;vendor/tinycortexmust carve its inertmemory::difftypes out from behindgit-difffirst.AI Authored PR Metadata (required for Codex/Linear PRs)
Linear Issue
Commit & Branch
contacts-gatea90d7b707Validation Run
pnpm --filter openhuman-app format:check—cargo fmt --checkclean. Prettier halfN/A: no frontend files changed.pnpm typecheck—N/A: no TypeScript changed.cargo test --lib openhuman::memory::people→ 49 passed.cargo check --liband--no-default-features --features tokenjuice-treesitterboth clean.check-kernel-floor.shunmoved at 312/285/6 (expected — Linux no-op).check-feature-forwarding.mjspasses.Validation Blocked
command:a native macOS builderror:no macOS host availableimpact:The gated code is macOS-only, so the compiled path could not be exercised here. Mitigated as far as is possible from Linux: the dependency shed is proven by cross-target resolution (numbers above), and the code change is twocfgpredicates whose off-branch is the pre-existing, already-tested Linux/Windows stub. CI's macOS lanes will compile the on-branch.Behavior Changes
contactsis default-ON and forwarded to the desktop shell.Parity Contract
cfgpredicate narrowed. The off-branch is the stub that has always served Linux/Windows.check-feature-forwarding.mjsconfirms the new default-ON gate reaches the desktop shell — the check that exists becausevoice(Voice transcription unavailable — 'Voice transcription is unavailable in this build' error on latest release #4901) andtokenjuice-treesitter(AST-aware code compression silently disabled in desktop builds (tokenjuice-treesitter dropped) #4918) silently did not.Duplicate / Superseded PR Handling