Skip to content

feat(core): compile-time meet feature gate (#4800)#4915

Merged
M3gA-Mind merged 8 commits into
tinyhumansai:mainfrom
oxoxDev:feat/4800-meet-feature-gate
Jul 16, 2026
Merged

feat(core): compile-time meet feature gate (#4800)#4915
M3gA-Mind merged 8 commits into
tinyhumansai:mainfrom
oxoxDev:feat/4800-meet-feature-gate

Conversation

@oxoxDev

@oxoxDev oxoxDev commented Jul 15, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Adds a compile-time Cargo meet feature (default-ON) gating meet (562 LOC) + meet_agent (5,298) + agent_meetings (8,909) — ≈14.7k LOC — composing with the runtime DomainSet::meet flag from feat(core): DomainSet on CoreBuilder + DomainRegistration filter seam (feature-gate prerequisite) #4796.
  • Default build is byte-identical — every change is cfg-off-only. Slim builds opt out via cargo build --no-default-features --features "<gates without meet>".
  • A load-bearing carve-out: meet_agent::wav::pack_pcm16le_mono_wav stays ungated because the always-on desktop_companion STT path calls it. Stubbing it would compile clean and silently feed a 0-byte WAV to cloud STT.
  • Sheds zero dependencies (meet = []) — the dep shed was pre-paid, see below.
  • Pattern: leaf-gate (meet) + facade/carve-out no-stub (meet_agent) + facade+stub (agent_meetings).

Problem

#4795 wants one compile-time feature gate per subsystem family; #4796 shipped the runtime DomainSet axis. This PR adds the compile-time half for the Meet family.

Three of the epic's DoD bullets are inapplicable here. Stating them with evidence rather than leaving boxes that imply missing work:

The real risk in this family is not the gate — it is the carve-out below.

Solution

  • Cargo.toml: meet = [] added to default — dep list intentionally empty, commented so nobody "fixes" it later.
  • The load-bearing carve-out. meet_agent::wav::pack_pcm16le_mono_wav stays compiled in all builds: the always-on desktop_companion domain (Platform group) calls it to pack PCM for STT. This is verified, not assumed — deliberately gating it produces error[E0433]: cannot find 'wav' in 'meet_agent', then reverted. So the warning in the module doc is tested, not aspirational. Note the failure mode this avoids: a stub here would compile clean and silently hand a 0-byte WAV to cloud STT — a silent-corruption bug, not a build error.
  • Leaf-gate for meet (registration sites want absence, so no stub).
  • Facade/carve-out, no stub for meet_agent — the module facade stays, wav stays compiled, the live STT/LLM/TTS loop is gated.
  • Facade+stub for agent_meetingsstub.rs mirrors the always-on caller surface with disabled-error / empty bodies, so core/all.rs needs no call-site cfg.
  • App forwarding (app/src-tauri/Cargo.toml): openhuman_core is default-features = false, so meet is added explicitly to keep the domain in the shipped desktop app. Verified via cargo tree -e features -i openhuman.
  • CI: no change needed — the rust-feature-gate-smoke lane is a deny-by-default allow-list (--no-default-features --features tokenjuice-treesitter), so a new default-ON gate is excluded automatically and the disabled combination is already covered.
  • Docs (AGENTS.md): gate-table row + the wav carve-out and its inverted dependency.

When off: the meet / meet_agent / agent_meetings namespaces are absent from /schema and their methods return a clean JSON-RPC unknown-method (-32000); desktop_companion STT is unaffected.

Submission Checklist

If a section does not apply to this change, mark the item as N/A with a one-line reason. Do not delete items.

  • Tests added or updated (happy path + at least one failure / edge case) per Testing Strategy — both-direction gate tests in core/all_tests.rs; the wav carve-out verified by deliberately gating it and observing the compile error.
  • N/A: no instrumented changed lines — the diff is compile-config only (#[cfg] attrs, a Cargo feature, a stub facade, docs); diff-cover reports no coverable lines. The directional gate tests cover the on/off behaviour. — Diff coverage ≥ 80%
  • N/A: compile-time build-config change, no user-facing feature row — Coverage matrix updated
  • N/A: no matrix rows affected — All affected feature IDs from the matrix are listed in the PR description under ## Related
  • No new external network dependencies introduced (mock backend used per Testing Strategy) — no deps added or removed; meet = [].
  • N/A: default build is byte-identical, so no release-cut surface changes — Manual smoke checklist updated if this touches release-cut surfaces (docs/RELEASE-MANUAL-SMOKE.md)
  • Linked issue closed via Closes #NNN in the ## Related section

Impact

  • Desktop / CLI / mobile / web: no behaviour change — default keeps meet on and the build is byte-identical. desktop_companion STT is unaffected in both configs by design (the wav carve-out).
  • Slim builds: drop ≈14.7k LOC and 3 RPC namespaces. No binary-size win from deps — zero crates shed.
  • Performance / security: reduced compile-time surface and attack surface in slim builds (no Meet bot Socket.IO path, no live call loop).
  • Migration / compatibility: none. Additive and default-preserving.

Related


AI Authored PR Metadata (required for Codex/Linear PRs)

Linear Issue

  • Key: N/A — GitHub-issue driven, no Linear ticket.
  • URL: N/A

Commit & Branch

  • Branch: feat/4800-meet-feature-gate
  • Commit SHA: 882798ac63f98a283d04ff47042212fcb7f41c66 (5 commits, 9 files, +186/-4)

Validation Run

  • N/A: no frontend changes — pnpm --filter openhuman-app format:check
  • N/A: no frontend changes — pnpm typecheck
  • Focused tests: scoped enabled-config tests pass; both-direction gate tests pass in their configs.
  • Rust fmt/check (if changed): cargo fmt clean · enabled cargo check 0 errors · disabled cargo check --no-default-features --features tokenjuice-treesitter 0 errors · clippy clean in both directions.
  • N/A: manifest-only change to app/src-tauri/Cargo.toml (one dep line), no Tauri Rust source touched — forwarding verified via cargo tree -e features -i openhuman — Tauri fmt/check (if changed)

Boot smoke (both directions, 2 runs for repeatability) — both configs built, linked, booted, and served /rpc:

  • Gate ON: all 3 namespaces present in /schema.
  • Gate OFF: all 3 namespaces absent; methods return a clean JSON-RPC unknown-method (-32000); the process survives.

Validation Blocked

  • command: cargo test --no-default-features
  • error: 2 pre-existing failures on main today — group_mapping_smoke and harness_excludes_gated_namespaces, both asserting the voice namespace uncfg'd (fallout from the merged voice gate feat(core): feature gate — voice #4803). CI cannot see them: the feature-gate smoke lane runs cargo check, which never compiles test code.
  • impact: Not introduced by this PR and not fixed by it. This PR cfg'd its own asserts and left voice's alone; the voice asserts are a separate, epic-level fix that is pending. Scoped enabled-config tests and both-direction cargo check are green.

Behavior Changes

  • Intended behavior change: new default-ON meet compile-time gate. Default build unchanged.
  • User-visible effect: none by default. Slim builds omit the 3 Meet namespaces. No tools are affected — Meet has none.

Parity Contract

  • Legacy behavior preserved: yes — every change is cfg-off-only, so the default build is byte-identical.
  • Guard/fallback/dispatch parity checks: gate ON reproduces current registration exactly (verified by boot smoke against the live /rpc); gate OFF yields absence at every registration site. The desktop_companion STT path keeps a real wav implementation in both configs — the carve-out is enforced by the compiler (verified by deliberately gating it and observing E0433), not by convention, specifically so it cannot silently degrade to a 0-byte WAV. Composes with, and does not replace, the runtime DomainSet::meet guard from feat(core): DomainSet on CoreBuilder + DomainRegistration filter seam (feature-gate prerequisite) #4796.

Duplicate / Superseded PR Handling

oxoxDev added 5 commits July 15, 2026 17:43
Defines the compile-time gate for the three Meet domains. Default-ON, so
the desktop build stays byte-identical; slim builds opt out via
--no-default-features.

Unlike `voice`, this gate sheds no dependencies — the Meet domains have
zero exclusive crates. `meet_agent::wav` is a hand-rolled RIFF writer
written precisely so Meet never needed `hound`, which `voice` already
owns and sheds. The gate's value is compile-time surface, not the dep
tree; Cargo.lock is unchanged, which confirms it.
…yhumansai#4800)

Applies one module pattern per domain, chosen by whether always-compiled
code reaches a non-registration symbol:

- meet          -> leaf-gate; its only outside reference is the registry.
- meet_agent    -> facade + carve-out, no stub; nothing outside the Meet
                   domain calls its gated submodules.
- agent_meetings -> facade + stub; the heartbeat planner and two
                   subscriber registrations reach in, so stub.rs supplies
                   no-op equivalents and those callers need no cfg.

The stub's no-ops are semantically exact rather than placeholders: a
register_* that registers nothing is the intended disabled behaviour, and
handle_calendar_meeting_candidate returning false means "Meet published no
card", so the planner correctly falls through to its generic reminder.

CARVE-OUT: meet_agent::wav stays ungated — desktop_companion (Platform,
always-on) calls pack_pcm16le_mono_wav and needs the real implementation.
It is dependency-free, so leaving it compiled costs nothing. Verified:
gating it fails the disabled build loudly at desktop_companion/pipeline.rs
with E0433. That failure must be fixed by reverting the cfg, never by
stubbing the function — a stub would trade a compile error for green CI
while silently corrupting companion STT. Recorded in the module doc.
Adds meet_controllers_registered_when_feature_on and its negative twin
meet_controllers_absent_when_feature_off, covering all three namespaces.
The negative half is the one that proves the gate removes anything — a
gate that never dropped a controller would still pass the positive test.

Also cfg's the group_for_namespace("meet") assert in group_mapping_smoke:
the helper is registry-derived, so with meet compiled out the namespace is
absent and the lookup correctly returns None. The neighbouring assert at
:765 needs no change — "meet" is in the *absent* list there, which holds
either way.

Note CI's smoke lane runs cargo check only and never compiles test code,
so a disabled-build test break is invisible to it; run the disabled test
lane locally after touching any gated surface.
The shell depends on the core with default-features = false and had no
features key, so a default-ON gate would silently drop from the shipped
app. Written as a multi-line array so the sibling gates in this epic
append cleanly rather than conflicting on one line.
…umansai#4800)

Records the three module patterns and the rule that picks between them,
the wav carve-out and why stubbing it is dangerous, and the fact that the
gate sheds no dependencies — so that last point isn't re-litigated by the
next reader expecting a voice-style dep drop.
@oxoxDev
oxoxDev requested a review from a team July 15, 2026 14:33
@coderabbitai

coderabbitai Bot commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

You’ve reached a temporary PR review limit under our Fair Usage Limits Policy.

Your recent review volume is higher than typical usage, so adaptive limits are currently applied.

Next review available in: 50 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

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 configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 975ace74-c258-4f89-a894-a92558fbc76a

📥 Commits

Reviewing files that changed from the base of the PR and between 97ade54 and 38a989e.

📒 Files selected for processing (9)
  • AGENTS.md
  • Cargo.toml
  • app/src-tauri/Cargo.toml
  • src/core/all.rs
  • src/core/all_tests.rs
  • src/openhuman/agent_meetings/mod.rs
  • src/openhuman/agent_meetings/stub.rs
  • src/openhuman/meet_agent/mod.rs
  • src/openhuman/mod.rs

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

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 882798ac63

ℹ️ About Codex in GitHub

Codex has been enabled to automatically 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 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread src/core/all.rs
Comment thread src/core/all.rs
oxoxDev and others added 3 commits July 15, 2026 20:24
…ure-gate

# Conflicts:
#	AGENTS.md
#	Cargo.toml
#	app/src-tauri/Cargo.toml
…ure-gate

# Conflicts:
#	Cargo.toml
#	app/src-tauri/Cargo.toml
@M3gA-Mind

Copy link
Copy Markdown
Collaborator

Maintainer review — addressing the two Codex bot findings (I made no code changes; assessment only):

① "Hide disabled Meet capabilities from about_app" — declining (false positive against convention).
src/openhuman/about_app/catalog_data.rs contains zero #[cfg(feature = …)] gates. The sibling default-ON gates already merged do the same: voice.ptt/conversation.send_voice (domain voice, gate #4803) and workflows.web3_defi (domain web3, gate #4802) leave their catalog rows ungated too. The about_app catalog is a static, build-invariant capability description; gating only the Meet rows here would make this PR inconsistent with every prior gate. If the project wants the catalog to track compiled-out domains, that's an epic-level pass across all gates (voice/web3/media/meet at once), not something to introduce unilaterally for meet. Declining as out-of-scope + convention-inconsistent.

② "Gate the backend Meet socket path as well" — valid; the PR's slim-build claim is overstated.
Confirmed: with meet off, src/openhuman/socket/event_handlers.rs (zero cfg) still accepts bot:* and publishes BackendMeet* bus events, and the always-compiled bridge at src/core/socketio.rs:1141 ("Backend Meet bot events → broadcast", no cfg) still re-emits them as agent_meetings:* to renderer sockets. The controller/subscriber gating is correct (the register_meeting_event_subscriber stub no-ops, so the agent-side MeetingEventSubscriber never fires), but the raw backend→renderer relay is independent of that and stays live. That contradicts this PR's Impact bullet — "reduced attack surface in slim builds (no Meet bot Socket.IO path)" — which is not actually delivered as written.

This is a real gap, but it sits at the same seam as the PR's own documented out-of-scope note (the startup.rs/#4796 runtime-divergence follow-up). Recommended resolution for the author: either (a) add #[cfg(feature = "meet")] to the bot:* arms in event_handlers.rs and the socketio agent_meetings bridge spawn, or (b) keep this PR's compile-time-surface scope but soften the security claim and track the socket relay under the #4796 runtime-gating follow-up. Not a merge blocker for the default build (byte-identical, CI green), but the slim-build security claim should not ship as-is.

@M3gA-Mind M3gA-Mind left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Approving — the gate is correct and CI is fully green (14 pass / 4 skipping, including Rust Quality, Rust Feature-Gate Smoke (gates off), and both Core and Tauri coverage lanes). Frontend Checks correctly skips as out-of-changed-area for a Rust-only change.

Verified:

  • Facade+stub follows the established voice/web3 pathfinder pattern; agent_meetings/stub.rs mirrors the always-on caller surface, so core/all.rs needs no call-site cfg.
  • Default build is byte-identical; both directions covered by registered-when-on / absent-when-off tests.
  • Swept for dangling refs: with meet off, the only Meet code still compiling is meet_agent::wav (dependency-free) plus the stub. No uncovered external references to gated symbols.

One accepted caveat, tracked rather than blocking — flagging it explicitly so the record is accurate:

The PR body states the slim build has "no Meet bot Socket.IO path" under Performance / security. That claim is not delivered as written. The backend→renderer Meet relay stays ungated and compiled with meet off:

  • src/core/socketio.rs — the agent_meetings bridge (io_agent_meetings at :636, agent_meetings:joined emit at :1181) has no cfg(feature = "meet") guard anywhere in the file.
  • src/openhuman/channels/socket/event_handlers.rs — the bot:* handlers likewise carry no meet gate.

This is not a default-build regression and not a correctness defect — the gate does what it says for compile-time surface, and this is consistent with the PR's existing out-of-scope note. But the attack-surface half of that claim does not hold today. Approving on the basis that the socket relay is scoped as a follow-up under #4796 (runtime gating).

Requested follow-up (non-blocking): either soften the security bullet in the PR body to match what ships, or open a #4796 child to gate socketio.rs / event_handlers.rs. Worth doing before anyone relies on the slim build for attack-surface reduction.

Credit where due: Codex flagged this; it is a genuine finding and was verified independently against the PR head.

@M3gA-Mind
M3gA-Mind merged commit 56841eb into tinyhumansai:main Jul 16, 2026
18 checks passed
M3gA-Mind pushed a commit to oxoxDev/openhuman that referenced this pull request Jul 16, 2026
Resolve sibling-gate conflicts with tinyhumansai#4915 (meet gate, tinyhumansai#4800) by union:
- Cargo.toml: keep both `meet` and `mcp` in default + both feature blocks
- app/src-tauri/Cargo.toml: forward both `meet` and `mcp`
- AGENTS.md: keep both gate-table rows and both gate sections
- src/core/all_tests.rs: keep all four both-direction gate tests
senamakel added a commit to M3gA-Mind/openhuman that referenced this pull request Jul 18, 2026
…umansai#4915)

Co-authored-by: Steven Enamakel <enamakel@tinyhumans.ai>
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.

feat(core): feature gate — meet

3 participants