Skip to content

build(memory): gate the git-backed diff ledger behind memory-git - #5477

Merged
senamakel merged 2 commits into
tinyhumansai:mainfrom
senamakel:build-time-phase4
Aug 10, 2026
Merged

senamakel merged 2 commits into
tinyhumansai:mainfrom
senamakel:build-time-phase4

Conversation

@senamakel

@senamakel senamakel commented Aug 10, 2026

Copy link
Copy Markdown
Member

Stacked on #5468. That PR is the contributor/product gate split; its commit is the first one here, and this diff collapses to the single build(memory): commit once it merges. Needs tinyhumansai/tinycortex#141 merged first — the gitlink is bumped to it.

Rebased onto current main (the old #5467 base is closed — #5469 landed those fixes upstream). Review feedback from the first round is addressed; see the bottom section.

Why

The largest native-build shed in the kernelization program. git2 with vendored libgit2 leaves the kernel profile and takes libgit2-sys and libz-sys with it — two of the five remaining native C builds, in one gate.

Profile Before After
kernel (flows) 305 / 282 / 4 native 302 / 279 / 2 native
contributor (default) 356 packages 353 packages

That is the target. MIGRATION-PLAN G6 set two native builds as the goal, and scripts/kernel-floor.limits has carried it as the stated aim since the 2026-08-01 baseline of 418 names / 6 native. What remains is libsqlite3-sys and ring — the memory store and TLS, both load-bearing. Reaching it does not retire the ratchet; an unmeasured floor grows back.

(The before-column moved because main gained the runtime-node gate while this was open, which shed lzma-sys. memory-git sheds the other two.)

memory-git is default-OFF, product-ON, and carries dep:git2 + tinycortex's git-diff and wiki-git.

The type carve-out is what makes this gateable at all

memory::diff::types compiles in both builds. The always-on subconscious memory profile renders CrossSourceDiff and ChangeKind into agent prompts, so stubbing them would put two definitions of one serde shape in the tree, free to drift apart.

tinycortex needed the matching split first — its git-diff gated the whole memory::diff module, so a libgit2-less host could not so much as name the types. tinyhumansai/tinycortex#141 leaves memory::diff::{types,source} ungated there (they are serde/std-only; only ledger.rs and ledger_helpers.rs touch git2) and keeps the Ledger/DiffEngine half behind the feature.

Stub vs #[cfg], decided per call site

Stubbed — the three ops entry points always-on code reaches: auto_snapshot_after_sync (memory::sources::sync), diff_since_checkpoint and create_checkpoint (the subconscious profile). Those domains stay feature-unaware.

They return an Err naming the gate, not an empty diff. An empty CrossSourceDiff asserts "your world did not change" — which the subconscious would faithfully act on. The error routes into a path the caller already handles by logging and skipping.

#[cfg]'d — the registration sites, because they want absence: the schema aggregators return empty vecs (memory_diff becomes unknown-method and drops off /schema) and MemoryDiffTool disappears from its single registration site. A registered tool that always errors is worse than an absent one; the model keeps choosing it and reporting the failure back to the user.

Capability honesty

The embedded driver drops Capability::Diff from advertised_capabilities() and as_diff() returns None. Both halves move together deliberately — audit_provider fails on either alone, which is the check that keeps them from drifting, and callers are entitled to trust the advertised set rather than probing every accessor.

The wiki mirror degrades, it does not fail

content::wiki_git::commit_summaries is gated at its two call sites rather than stubbed. The git wiki is a derived view: the summary's own content file is written either way, so skipping the mirror loses the mirror, not the summary. seal.rs's summary_committed gains a #[cfg(not(...))] sibling returning Ok(()) — accurate rather than lenient, since nothing the caller depended on failed to happen.

tests/memory_artifacts_e2e.rs opens the ledger with git2::Repository::open, so it declares required-features = ["memory-git"].

Tests

Both-ways tests in core::all_tests. The OFF half asserts memory is still registered alongside memory_diff being gone — the gate removes the git ledger, not the memory domain — because splitting that into two tests would let one regress silently.

Verification

cargo check --lib --tests                                          # contributor
cargo check --all-targets --features "$(scripts/ci/product-features.sh)"
cargo test --lib core::all::tests::memory_diff                     # OFF half
cargo test --lib --features <product> core::all::tests::memory_diff  # ON half
scripts/assert-shed.sh flows git2 libgit2-sys libz-sys             # all 3 shed
bash scripts/check-kernel-floor.sh                                 # ratchet written back
node scripts/ci/check-feature-forwarding.mjs
cargo fmt --all -- --check

Summary by CodeRabbit

  • New Features

    • Git-backed memory comparison capabilities can now be enabled independently, including memory diffs, checkpoints, and related tools.
    • Desktop builds support the memory comparison feature when included in the product configuration.
  • Bug Fixes

    • Improved feature handling ensures unavailable memory comparison capabilities are not advertised or registered when disabled.
  • Documentation

    • Clarified contributor and product feature sets, feature coverage, and configuration guidance.
  • Chores

    • Expanded automated validation and testing for feature combinations and product configuration consistency.

Round-1 review feedback

Finding Resolution
product-features.sh empty-list diagnostic unreachable Real bug, fixed. Worse than reported: grep -v exits 1 when it selects nothing, and set -e aborted inside the command substitution — a comments-only file exited 1 with no output at all. Now { grep -v ... || true; }, with the reason commented. The helper also takes an optional path so the self-test can drive that branch with a fixture instead of mutating the checked-in file; two regression tests added.
AGENTS.md kernel figures stale Fixed, plus several others in the same file that were stale before this PR (contributor 353/3-native, product 540/7-native and 16 gates not 15, kernel baseline still quoting 312/285/6 from 2026-08-02). All re-measured, not derived.
library-minimal-recipe.md obsolete Default column Agreed that annotating a wrong column is worse than fixing it. Replaced with the real Contrib/Product pair, both filled in from current state. desktop-automation gets dashes — that gate no longer exists.
provider_tests.rs bus comment No longer in this PR: that file belonged to the closed #5467, and the branch is rebased straight onto main.

tinyhumansai/tinycortex#141 also took its two review points: the carve-out tests moved to a #[path] sibling file matching that directory's convention, and the serde test now round-trips instead of only serialising — so a gated-away Deserialize derive fails it too.

@senamakel
senamakel requested a review from a team August 10, 2026 11:40
@coderabbitai

coderabbitai Bot commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The change separates contributor and product feature sets, adds exact forwarding validation, applies product features across Rust CI and coverage, and gates Git-backed memory functionality behind memory-git.

Changes

Feature gates and memory Git integration

Layer / File(s) Summary
Product feature manifest and forwarding checks
scripts/ci/product-features.*, scripts/lib/feature-forwarding.mjs, scripts/ci/check-feature-forwarding.mjs, scripts/__tests__/feature-forwarding.test.mjs
The product feature manifest and shell helper now provide the canonical product feature set. JavaScript checks validate exact forwarding, core feature names, default inheritance, unknown gates, and empty inputs. Tests cover parser and forwarding behavior.
Cargo feature matrix and CI execution
Cargo.toml, .github/workflows/*, scripts/ci/rust-coverage-changed.sh, scripts/test-rust-with-mock.sh, AGENTS.md, docs/library-minimal-recipe.md, scripts/kernel-floor.limits
Cargo uses a smaller contributor-default set and optional product gates. Test targets declare required features. Rust checks, coverage, and mock tests use product features explicitly. Documentation and kernel-floor baselines describe the split.
Memory Git feature surface
src/openhuman/memory/**, src/openhuman/tools/*, src/core/all_tests.rs, app/src-tauri/Cargo.toml, vendor/tinycortex
Git-backed memory modules, controllers, tools, capabilities, wiki mirroring, and desktop forwarding require memory-git. Disabled builds expose stubs, omit diff registrations, and retain the main memory namespace. Tests cover enabled and disabled registration.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant CI
  participant ProductFeaturesScript
  participant Cargo
  participant FeatureForwardingCheck
  CI->>ProductFeaturesScript: read product-features.txt
  ProductFeaturesScript->>Cargo: provide product feature list
  Cargo->>FeatureForwardingCheck: expose core and shell feature sets
  FeatureForwardingCheck->>CI: report exact forwarding result
Loading
sequenceDiagram
  participant DesktopBuild
  participant EmbeddedDriver
  participant MemoryDiffControllers
  participant MemoryDiffTool
  DesktopBuild->>EmbeddedDriver: enable memory-git
  EmbeddedDriver->>MemoryDiffControllers: register memory-diff namespace
  EmbeddedDriver->>MemoryDiffTool: expose diff capability
  MemoryDiffControllers->>MemoryDiffTool: register MemoryDiffTool
Loading

Possibly related PRs

Suggested labels: rust-core, memory

Suggested reviewers: m3ga-mind

Poem

I nipped the gates into a tidy row,
Product flags now clearly flow.
Git diff sleeps when its feature is bare,
Then wakes with tools and capability flair.
CI checks each path with care—
A rabbit-approved build in the air! 🐇

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed Docstring coverage is 100.00% 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.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes gating the git-backed memory diff ledger behind the new memory-git feature.

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.

@coderabbitai coderabbitai Bot added memory Memory store, memory tree, recall, summarization, and embeddings in src/openhuman/memory/. rust-core Core Rust runtime in src/: CLI, core_server, shared infrastructure. labels Aug 10, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🤖 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 `@AGENTS.md`:
- Line 431: Update the kernel-profile figures in the memory-git capability table
and the baseline references near the stated package/native-build counts so they
consistently reflect the PR objective: 307 to 304 packages and five to three
native builds. If the older six-build baseline is intentionally retained,
explicitly label it as historical rather than presenting it as current.

In `@docs/library-minimal-recipe.md`:
- Around line 42-48: Update the table in the minimal recipe documentation to
remove the obsolete Default column and its historical values, including
desktop-automation. Replace it with current Contrib and Product columns sourced
from the documented feature definitions, while preserving the Decision column
for library-host choices.

In `@scripts/ci/product-features.sh`:
- Around line 23-30: Update the LIST construction in the product-features
parsing flow so an input containing only comments or blank lines does not
terminate the script when grep finds no matches under pipefail and set -e. Use
awk or explicitly handle grep’s status, while preserving the existing empty LIST
check and its documented diagnostic and exit behavior.

In `@src/openhuman/memory/guard/provider_tests.rs`:
- Around line 307-320: Replace the fixed 200 ms sleep in the affected guard
success test with deterministic synchronization that waits for all relevant bus
delivery work to complete, using an available receiver, completion handle, or
test-bus drain mechanism after store/recall publishing. Then retain the filtered
assertion on recorder.seen for the "recording" driver, preserving the test’s
verification that successful guarded operations publish no event.
🪄 Autofix

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: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 1218eb8f-1809-423b-b145-253daa21f787

📥 Commits

Reviewing files that changed from the base of the PR and between c7e15ba and 3f70170.

⛔ Files ignored due to path filters (2)
  • Cargo.lock is excluded by !**/*.lock
  • app/src-tauri/Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (101)
  • .github/workflows/ci-lite.yml
  • .github/workflows/test-reusable.yml
  • AGENTS.md
  • Cargo.toml
  • app/src-tauri/Cargo.toml
  • app/src-tauri/src/whatsapp_data/mod.rs
  • app/src/components/settings/panels/VoicePanel.tsx
  • docs/library-minimal-recipe.md
  • scripts/__tests__/feature-forwarding.test.mjs
  • scripts/ci/check-feature-forwarding.mjs
  • scripts/ci/product-features.sh
  • scripts/ci/product-features.txt
  • scripts/ci/rust-coverage-changed.sh
  • scripts/kernel-floor.limits
  • scripts/lib/feature-forwarding.mjs
  • scripts/test-rust-with-mock.sh
  • src/core/all_tests.rs
  • src/core/bus.rs
  • src/core/jsonrpc.rs
  • src/core/mod.rs
  • src/openhuman/agent/artifacts/store_tests.rs
  • src/openhuman/agent/bus.rs
  • src/openhuman/agent/harness/session/runtime_tests.rs
  • src/openhuman/agent/harness/session/turn/tools.rs
  • src/openhuman/agent/learning/extract/signature.rs
  • src/openhuman/agent/learning/profile_md_renderer.rs
  • src/openhuman/agent/learning/startup.rs
  • src/openhuman/agent/orchestration/run_ledger_finalize.rs
  • src/openhuman/agent/orchestration/run_ledger_finalize_tests.rs
  • src/openhuman/agent/tinyagents/tools.rs
  • src/openhuman/agent/triage/escalation.rs
  • src/openhuman/agent/triage/evaluator.rs
  • src/openhuman/agent/triage/events.rs
  • src/openhuman/channels/bus.rs
  • src/openhuman/channels/host/adapters.rs
  • src/openhuman/channels/proactive.rs
  • src/openhuman/channels/providers/telegram/approval_surface.rs
  • src/openhuman/channels/providers/telegram/approval_surface_tests.rs
  • src/openhuman/channels/providers/telegram/bus.rs
  • src/openhuman/channels/providers/telegram/bus_tests.rs
  • src/openhuman/channels/routes_tests.rs
  • src/openhuman/channels/runtime/dispatch/processor.rs
  • src/openhuman/channels/runtime/test_support.rs
  • src/openhuman/channels/tests/health.rs
  • src/openhuman/channels/tests/runtime_dispatch.rs
  • src/openhuman/config/ops/agent.rs
  • src/openhuman/cron/bus.rs
  • src/openhuman/cron/scheduler_tests.rs
  • src/openhuman/desktop/notifications/bus.rs
  • src/openhuman/flows/bus.rs
  • src/openhuman/flows/ops.rs
  • src/openhuman/flows/ops_tests.rs
  • src/openhuman/inference/provider/factory_tests.rs
  • src/openhuman/inference/provider/openhuman_backend_model.rs
  • src/openhuman/inference/provider/ops/http_error.rs
  • src/openhuman/inference/provider/ops_tests.rs
  • src/openhuman/integrations/composio/ops/direct_mode.rs
  • src/openhuman/integrations/task_sources/bus.rs
  • src/openhuman/meet/backend_bot/calendar.rs
  • src/openhuman/memory/binding.rs
  • src/openhuman/memory/conversations/bus.rs
  • src/openhuman/memory/diff/mod.rs
  • src/openhuman/memory/diff/ops.rs
  • src/openhuman/memory/diff/stub.rs
  • src/openhuman/memory/driver/embedded/mod.rs
  • src/openhuman/memory/global.rs
  • src/openhuman/memory/guard/audit.rs
  • src/openhuman/memory/guard/provider_tests.rs
  • src/openhuman/memory/ops/sync.rs
  • src/openhuman/memory/store/client.rs
  • src/openhuman/memory/store/content/mod.rs
  • src/openhuman/memory/sync/composio/bus.rs
  • src/openhuman/memory/sync_events.rs
  • src/openhuman/memory/sync_pipeline_e2e_tests.rs
  • src/openhuman/memory/tinycortex/seal.rs
  • src/openhuman/memory/tinycortex/sync.rs
  • src/openhuman/memory/tree/ingest.rs
  • src/openhuman/memory/tree/tree_runtime/bus.rs
  • src/openhuman/security/approval/gate.rs
  • src/openhuman/security/credentials/bus.rs
  • src/openhuman/security/credentials/session_support.rs
  • src/openhuman/security/devices/bus.rs
  • src/openhuman/security/egress/emit_tests.rs
  • src/openhuman/security/keyring_consent/policy.rs
  • src/openhuman/skills/bus.rs
  • src/openhuman/skills/ops_create.rs
  • src/openhuman/skills/webhooks/bus.rs
  • src/openhuman/tools/mod.rs
  • src/openhuman/tools/ops.rs
  • src/openhuman/voice/bus.rs
  • src/openhuman/web_chat/event_bus.rs
  • tests/agent_harness_e2e.rs
  • tests/calendar_grounding_e2e.rs
  • tests/composio_list_tools_stack_overflow_regression.rs
  • tests/config_auth_app_state_connectivity_e2e.rs
  • tests/json_rpc_e2e.rs
  • tests/monitor_agent_e2e.rs
  • tests/subconscious_conversation_e2e.rs
  • tests/subconscious_fullstack_e2e.rs
  • tests/subconscious_triggers_e2e.rs
  • vendor/tinycortex

Comment thread AGENTS.md
Comment thread docs/library-minimal-recipe.md Outdated
Comment thread scripts/ci/product-features.sh
Comment thread src/openhuman/memory/guard/provider_tests.rs Outdated
`[features] default` was the product set, so every contributor paid for the
whole product on every edit: web3's ethers/secp256k1 cohort, `documents`'
zstd/bzip2 native builds, the cpal/hound/arboard/enigo/rdev stack behind
`voice`+`inference`, `contacts`' macOS objc2 cohort, `crash-reporting`'s sentry
tree, `tui`'s ratatui. A bare `cargo check` — and therefore rust-analyzer on
every keystroke — resolved 567 packages and ran 7 native C/C++ builds.

`default` is now the CONTRIBUTOR set: 9 gates that cost almost nothing to
compile, so `cargo check` still typechecks nearly the whole tree. Measured:
**567 -> 356 packages, 7 -> 5 native builds.** The kernel floor is untouched at
307/284/5 — this axis does not intersect the `flows` profile.

THIS DOES NOT CHANGE WHAT SHIPS. `app/src-tauri` has declared `openhuman_core`
with `default-features = false` since tinyhumansai#1061 and never inherited `default`; that
is precisely why a forwarding guard had to exist at all.

`check-feature-forwarding.mjs` worked by diffing the shell's forwarding list
against `[features] default`. That is a SUBSET check, and it was sound only
while `default` was the product set. Shrinking `default` makes it weaker with
every gate removed and vacuous if `default` ever empties — silently re-arming
and ~93k Sentry events. Landing the flip without the rewrite would have been
the same bug with a longer fuse.

The product set is now explicit, in `scripts/ci/product-features.txt`, and the
guard asserts three things:

1. the shell forwards EXACTLY that file — set equality, both directions. A
   dropped gate fails on `missing`; a gate the shell grew that the product
   never claimed fails on `unexpected`. Equality cannot pass vacuously.
2. every name in the file is a gate the core actually declares (catches a typo
   or a gate renamed out from under it).
3. every `default` gate is forwarded or allow-listed — the original check,
   retained because it still catches a contributor-set gate nobody shipped.

Two parsers read that file — this one and `product-features.sh`, which the CI
lanes use to build `--features`. A test asserts they agree, because if they
drifted CI would compile a different set than the guard checks.

A lane that relied on default features silently stops covering the product.
Every lane that builds or tests the product now passes
`--features "$(bash scripts/ci/product-features.sh)"`: core clippy, the unit
lane, the changed-files coverage lane, and `scripts/test-rust-with-mock.sh`.
Clippy runs TWICE, once per set — a lint that only fires with the gates off
(an import left unused once a domain is compiled out) is invisible to the
product lane and would be red on every contributor's machine while CI is green.

Four `tests/*.rs` targets name symbols that only exist behind `voice`, `web3`,
`inference` or `crash-reporting`, so they now declare `required-features`.
Without it a bare `cargo test` fails to COMPILE, in files the contributor did
not touch. With it cargo SKIPS them — the same silent-skip trap `--bins`
without `bin-tools` already had, which is why the lane comments spell it out:
`json_rpc_e2e` alone is >12k lines of RPC contract coverage.

`tui` ends up in NEITHER set (default-OFF and deliberately not forwarded), so
nothing in CI would compile it at all. The feature-gate-smoke lane now checks
it explicitly; a future gate in that position needs the same.

Note `required-features` is the blunt instrument — it costs the whole target
when a gate is off, where tinyhumansai#5021's per-symbol `#[cfg]` cleanup would keep the
ungated tests running. Taken deliberately for these four; noted in Cargo.toml.

Verified: contributor `cargo check --lib --tests`, product
`cargo check --all-targets --features <product>`, `--no-default-features
--features tui`, the 27 guard self-tests, the kernel-floor ratchet, and
`cargo fmt --all --check`.

Co-authored-by: Medulla <medulla@tinyhumans.ai>
Takes the kernel profile to **2 native builds — the spec target** (G6 in
MIGRATION-PLAN, and the goal named in `kernel-floor.limits`' own baseline
entry). `git2` with vendored libgit2 leaves and takes `libgit2-sys` **and**
`libz-sys` with it; together with the `runtime-node` gate already on main, only
`libsqlite3-sys` and `ring` remain, and both are load-bearing. Kernel floor
305/282/4 -> 302/279/2, from 418 names / 6 native when the program started.

`memory-git` is default-OFF, product-ON, carrying `dep:git2` plus tinycortex's
`git-diff` and `wiki-git`.

## The type carve-out is what makes this gateable

`memory::diff::types` compiles in BOTH builds. The always-on subconscious
memory profile renders `CrossSourceDiff` and `ChangeKind` into agent prompts,
so stubbing them would put two definitions of one serde shape in the tree, free
to drift. tinycortex needed the matching split first — its `git-diff` gated the
whole `memory::diff` module, so a libgit2-less host could not name the types at
all. Its `memory::diff::{types,source}` are ungated now (they reach no `git2`
symbol; only `ledger.rs` and `ledger_helpers.rs` do) and the
`Ledger`/`DiffEngine` half stays behind the feature. Gitlink bumped to it.

## Stub vs `#[cfg]`, decided per call site

Stubbed: the three `ops` entry points always-on code reaches —
`auto_snapshot_after_sync` (`memory::sources::sync`), `diff_since_checkpoint`
and `create_checkpoint` (the subconscious profile). Those domains stay
feature-unaware.

They return an `Err` naming the gate, not an empty diff. An empty
`CrossSourceDiff` asserts "your world did not change", which the subconscious
would act on; the error routes into a path the caller already handles by
logging and skipping.

`#[cfg]`'d: the registration sites, which want absence. The schema aggregators
return empty vecs (`memory_diff` becomes unknown-method and drops off
`/schema`) and `MemoryDiffTool` disappears from its single registration site —
a registered tool that always errors is worse than an absent one, because the
model keeps choosing it and reporting the failure to the user.

## Capability honesty

The embedded driver drops `Capability::Diff` from `advertised_capabilities()`
and `as_diff()` returns `None`. Both halves move together deliberately:
`audit_provider` fails on either alone, which is the check that keeps them from
drifting, and callers may trust the advertised set rather than probing every
accessor.

## The wiki mirror degrades, it does not fail

`content::wiki_git::commit_summaries` is gated at its two call sites rather
than stubbed. The git wiki is a derived view — the summary's own content file
is written either way — so skipping it loses the mirror, not the summary.
`seal.rs`'s `summary_committed` gains a `#[cfg(not(...))]` sibling returning
`Ok(())`: accurate rather than lenient, since nothing the caller depended on
failed to happen. `tests/memory_artifacts_e2e.rs` opens the ledger with
`git2::Repository::open`, so it declares `required-features = ["memory-git"]`.

## Review follow-ups from tinyhumansai#5477 also folded in

- `scripts/ci/product-features.sh` died with a bare exit 1 and no message on a
  comments-only file: `grep -v` exits 1 when it selects nothing, and `set -e`
  aborted inside the command substitution, making the explicit diagnostic
  unreachable. Fixed, and the helper now takes an optional path so the
  self-test can drive that path with a fixture rather than mutating the
  checked-in file. Two regression tests.
- Stale figures in AGENTS.md corrected against measurement (contributor
  353/3-native, product 540/7-native, kernel baseline 302/279/2).
- `docs/library-minimal-recipe.md`'s obsolete single `Default` column replaced
  with the real Contrib/Product pair rather than annotated as wrong.

Co-authored-by: Medulla <medulla@tinyhumans.ai>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

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

⚠️ Outside diff range comments (1)
.github/workflows/ci-lite.yml (1)

227-227: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Security Misconfiguration (CWE-494): Download of Code Without Integrity Check

Reachability: External

Use one reviewed, immutable CI image reference.

These containers resolve ghcr.io/tinyhumansai/openhuman_ci:latest at runtime. A moved tag can execute unreviewed shell code in CI. Pin these image references to reviewed commits or SHA digests instead of latest; action pins do not pin the container image.

  • .github/workflows/ci-lite.yml#L227: Pin the frontend-checks image.
  • .github/workflows/ci-lite.yml#L346: Pin the rust-quality image.
  • .github/workflows/ci-lite.yml#L429: Pin the rust-feature-gate-smoke image.
  • .github/workflows/ci-lite.yml#L576: Pin the rust-rss-bench image.
  • .github/workflows/ci-lite.yml#L624: Pin the rust-core-coverage image.
  • .github/workflows/ci-lite.yml# L722: Pin the rust-tauri-coverage image.
  • .github/workflows/ci-lite.yml#L814: Pin the scripts-tests image.
  • .github/workflows/ci-lite.yml#L853: Pin the test-inventory image.
  • .github/workflows/ci-lite.yml#L951: Pin the tinycortex-tests image.
  • .github/workflows/test-reusable.yml#L55: Pin the i18n-coverage image.
  • .github/workflows/test-reusable.yml#L80: Pin the unit-tests image.
  • .github/workflows/test-reusable.yml#L123: Pin the rust-core-tests image.
  • .github/workflows/test-reusable.yml#L220: Pin the tinycortex-tests image.
  • .github/workflows/test-reusable.yml#L291: Pin the rust-tauri-tests image.
🤖 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 @.github/workflows/ci-lite.yml at line 227, Replace the mutable latest image
reference used by the frontend-checks job in .github/workflows/ci-lite.yml:227
with the reviewed immutable commit reference or SHA digest. Apply the same
pinning change to the rust-quality, rust-feature-gate-smoke, rust-rss-bench,
rust-core-coverage, rust-tauri-coverage, scripts-tests, test-inventory, and
tinycortex-tests images in .github/workflows/ci-lite.yml at lines 346, 429, 576,
624, 722, 814, 853, and 951, and to the i18n-coverage, unit-tests,
rust-core-tests, tinycortex-tests, and rust-tauri-tests images in
.github/workflows/test-reusable.yml at lines 55, 80, 123, 220, and 291. Use one
reviewed immutable reference consistently instead of latest at every listed
site.

Source: Linters/SAST tools

🤖 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 `@AGENTS.md`:
- Around line 358-359: Update the Product row in AGENTS.md to document 17 gates
instead of 16, matching the 17 entries in scripts/ci/product-features.txt,
including memory-git. Leave the package and native-build counts unchanged.
- Line 432: The web3 dependency lists incorrectly include curve25519-dalek and
omit exclusive EVM crates. Update AGENTS.md lines 432-432 and
docs/library-minimal-recipe.md lines 57-57 to replace bitcoin, curve25519-dalek
with bitcoin, ethers-core, ethers-signers, coins-bip39, keeping both documents
consistent.

In `@scripts/kernel-floor.limits`:
- Line 45: Update the comment describing the 356→353 package-count change to
identify it as the contributor/default profile, or explicitly state the feature
selection, instead of calling it the default full-feature profile.

---

Outside diff comments:
In @.github/workflows/ci-lite.yml:
- Line 227: Replace the mutable latest image reference used by the
frontend-checks job in .github/workflows/ci-lite.yml:227 with the reviewed
immutable commit reference or SHA digest. Apply the same pinning change to the
rust-quality, rust-feature-gate-smoke, rust-rss-bench, rust-core-coverage,
rust-tauri-coverage, scripts-tests, test-inventory, and tinycortex-tests images
in .github/workflows/ci-lite.yml at lines 346, 429, 576, 624, 722, 814, 853, and
951, and to the i18n-coverage, unit-tests, rust-core-tests, tinycortex-tests,
and rust-tauri-tests images in .github/workflows/test-reusable.yml at lines 55,
80, 123, 220, and 291. Use one reviewed immutable reference consistently instead
of latest at every listed site.
🪄 Autofix

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: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: ac379ba0-650d-42ae-b361-076a8ee11143

📥 Commits

Reviewing files that changed from the base of the PR and between 3f70170 and a499125.

📒 Files selected for processing (14)
  • .github/workflows/ci-lite.yml
  • .github/workflows/test-reusable.yml
  • AGENTS.md
  • Cargo.toml
  • app/src-tauri/Cargo.toml
  • docs/library-minimal-recipe.md
  • scripts/__tests__/feature-forwarding.test.mjs
  • scripts/ci/product-features.sh
  • scripts/ci/product-features.txt
  • scripts/kernel-floor.limits
  • scripts/test-rust-with-mock.sh
  • src/core/all_tests.rs
  • src/openhuman/tools/ops.rs
  • vendor/tinycortex
🚧 Files skipped from review as they are similar to previous changes (8)
  • src/core/all_tests.rs
  • src/openhuman/tools/ops.rs
  • app/src-tauri/Cargo.toml
  • scripts/test-rust-with-mock.sh
  • Cargo.toml
  • vendor/tinycortex
  • scripts/tests/feature-forwarding.test.mjs
  • scripts/ci/product-features.sh

Comment thread AGENTS.md
Comment on lines +358 to +359
| **Contributor** | `[features] default` in `Cargo.toml` | What a bare `cargo check`, `cargo test` and rust-analyzer compile. 9 cheap gates. **353 packages / 3 native builds** (`libsqlite3-sys`, `lzma-sys`, `ring`). |
| **Product** | `scripts/ci/product-features.txt` | What the shipped desktop app has. 16 gates. **540 packages / 7 native builds** (adds `bzip2-sys`, `libgit2-sys`, `libz-sys`, `zstd-sys`). |

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Change the product gate count to 17.

scripts/ci/product-features.txt contains 17 product gates, including memory-git. Line [359] says 16. Make the documented count match the manifest.

🤖 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 `@AGENTS.md` around lines 358 - 359, Update the Product row in AGENTS.md to
document 17 gates instead of 16, matching the 17 entries in
scripts/ci/product-features.txt, including memory-git. Leave the package and
native-build counts unchanged.

Comment thread AGENTS.md
| ------- | ------- | ------- | ----- | ---------- |
| `voice` | OFF | ON | the `openhuman::voice` family (incl. `voice::audio_toolkit`) — STT/TTS providers, dictation server, always-on listening, podcast audio + email | `hound`, `lettre` |
| `inference` | OFF | ON | the `cpal` audio-device stack: microphone capture for voice, plus `desktop::accessibility::permissions`' mic-permission probe. Implied by `voice`. Off ⇒ the probe reports `Unknown`. **The name is historical** — it used to gate the bundled whisper.cpp STT engine, which no longer exists (see the scope note below); do not rename it, it is forwarded by name from the shell manifest and asserted by `INFERENCE_COMPILED_IN` | `cpal` |
| `web3` | OFF | ON | the `openhuman::web3` family (`web3`, `web3::wallet`, `web3::x402`) — crypto wallet (multi-chain sign/broadcast), swaps/bridges/dapp calls, x402 machine payments | `bitcoin`, `curve25519-dalek` |

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Use one correct web3 dependency list. Both documents list curve25519-dalek as shed, but it remains enabled through ed25519-dalek, and both omit the exclusive EVM crates.

  • AGENTS.md#L432-L432: replace bitcoin, curve25519-dalek with bitcoin, ethers-core, ethers-signers, coins-bip39.
  • docs/library-minimal-recipe.md#L57-L57: apply the same dependency list.
📍 Affects 2 files
  • AGENTS.md#L432-L432 (this comment)
  • docs/library-minimal-recipe.md#L57-L57
🤖 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 `@AGENTS.md` at line 432, The web3 dependency lists incorrectly include
curve25519-dalek and omit exclusive EVM crates. Update AGENTS.md lines 432-432
and docs/library-minimal-recipe.md lines 57-57 to replace bitcoin,
curve25519-dalek with bitcoin, ethers-core, ethers-signers, coins-bip39, keeping
both documents consistent.

# `None`, in lockstep — `audit_provider` fails on either
# half alone), and the git wiki mirror of summary nodes is
# skipped while the summaries themselves are still
# written. Default (full-feature) profile moved 356 -> 353.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Name the 353-package profile correctly.

After this PR, Cargo default is the contributor set, not the full product set. “Default (full-feature) profile” can misclassify the 356→353 measurement. Use “contributor/default profile” or state the exact feature selection.

🤖 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 `@scripts/kernel-floor.limits` at line 45, Update the comment describing the
356→353 package-count change to identify it as the contributor/default profile,
or explicitly state the feature selection, instead of calling it the default
full-feature profile.

@tinysweeper tinysweeper 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.

tinysweeper found nothing blocking. Approving.

             $0.0146 · 155,274 in / 47,957 out · 120,315 cached (77%) · z-ai/glm-5.2
critique:    $0.0074 · 50,400 in  / 27,601 out · 39,247 cached (78%)  · z-ai/glm-5.2
security:    $0.0033 · 29,049 in  / 11,743 out · 23,336 cached (80%)  · z-ai/glm-5.2
tests:       $0.0013 · 28,670 in  / 2,197 out  · 21,228 cached (74%)  · z-ai/glm-5.2
description: $0.0021 · 30,219 in  / 5,691 out  · 23,111 cached (76%)  · z-ai/glm-5.2

assert.deepEqual(result.unknown, [], 'product gates that are not real core gates');
});

test('the shell helper reports an empty gate list instead of dying silently', () => {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

priority medium critique likely

Prior memory-git off-stub finding not visible in this file

The prior finding asked for a test asserting the memory-git off-stub returns Err rather than Ok-empty. No code related to memory-git appears anywhere in this file's diff, so the finding is neither addressed nor refuted here. It likely concerns a different file and remains open from this review's perspective.

*[RULE] no new root-level .rs files ·

Comment thread Cargo.toml
# gated-off domains, so every CI lane that builds or tests "the product" now
# passes `--features "$(scripts/ci/product-features.sh)"`. If you add a lane,
# decide which of the two sets it is testing and say so.
default = ["media", "skills", "flows", "mcp", "channels", "medulla", "http-server", "scheduler-gate", "file-logging"]

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

priority medium critique likely

Account for meet being dropped from the default feature set

The diff drops meet from the default feature set alongside web3, documents, voice/inference, contacts, crash-reporting, tui, and runtime-node, but the explanatory comment enumerating the turned-off gates does not mention meet at all. The stated rationale is that only the gates that "carry the graph" (expensive native-build cohorts) are turned off, and everything else stays on because it is cheap to compile. If meet is cheap it should remain in default; if it is expensive it should be listed alongside the other cohorts. As written, the comment and the feature list disagree, and a contributor reading the comment has no way to know that meet was intentionally excluded.

default = ["media", "skills", "flows", "mcp", "channels", "medulla", "http-server", "scheduler-gate", "file-logging"]

Old default contained meet; the new one does not, and no comment accounts for it.

[RULE] New Cargo domain features must be forwarded to app/src-tauri/Cargo.toml's features list, or explicitly added to INTENTIONALLY_NOT_FORWARDED with a reason. ·

Comment thread AGENTS.md

```bash
scripts/kernel-floor.sh flows # CI Linux: 312 packages / 285 names / 6 native
scripts/kernel-floor.sh flows # CI Linux: 304 packages / 281 names / 3 native

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

priority medium critique likely

kernel-floor example output no longer matches the stated CI baseline

The inline example and the CI baseline were identical in the old text (both 312 / 285 / 6) but now disagree. The example comment reads 304 packages / 281 names / 3 native while the baseline paragraph below it reads 302 packages / 279 unique names / 2 native builds. One of these is stale — likely the example, which appears to reflect an intermediate state (before aws-lc-sys left) rather than the final 2026-08-09 baseline. A reader copying the example to verify the ratchet will get a mismatch and not know which number to trust.

**[RULE] ** ·

// Guards the guard: empty input would make every assertion below vacuous.
assert.ok(productFeatures.length > 0, 'expected to parse at least one product gate');
assert.ok(coreFeatureNames.length > 0, 'expected to parse at least one core gate name');
const result = checkProductForwarding({ productFeatures, coreFeatureNames, shell });

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

priority medium critique likely

Assert result.ok in the real-manifest equality test

This integration test checks that the real product file and shell agree, but it only asserts on missing, unexpected, and unknown. If the real shell has defaultFeatures: true, checkProductForwarding returns ok: false with reason: 'shell-inherits-defaults' (as demonstrated by the unit test at line 210). In that scenario missing, unexpected, and unknown can all be empty arrays, which would make all three deepEqual assertions pass vacuously — the test would report success even though the guard is actually failing. Add assert.equal(result.ok, true) (or at minimum assert result.reason is undefined) so the test cannot pass when the shell inherits defaults.

[RULE] Prefer behavior over implementation ·

pub mod ops {
use super::*;

/// See [`super::super::ops::auto_snapshot_after_sync`].

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

priority medium tests likely

Add a test asserting the memory-git off-stub returns Err, not Ok-empty

The memory-git-off stub in src/openhuman/memory/diff/stub.rs returns Err from all three ops entry points, and the stub's own doc-comment explains why this matters: an empty CrossSourceDiff would tell the subconscious profile "your world did not change" and it would act on that, whereas Err makes it log and skip. That is a load-bearing behavioural choice with no test behind it. The two tests added in src/core/all_tests.rs assert controller registration/absence — they do not call auto_snapshot_after_sync, create_checkpoint, or diff_since_checkpoint and assert they return Err. If someone later changed Err(DISABLED.to_string()) to Ok(Snapshot::default()) or Ok(CrossSourceDiff::default()), no test would fail, and the failure mode is exactly the silent "nothing changed" report the stub exists to prevent. The #[cfg(not(feature = "memory-git"))] test lane is where this belongs — a test that calls each stub entry point and asserts it returns Err containing the feature name.

[RULE] Tests that hard-assert a gated family must be #[cfg]-gated in lockstep with the feature. ·

@tinysweeper

tinysweeper Bot commented Aug 10, 2026

Copy link
Copy Markdown

What this change touches

23 files, +1003 -77 across 10 components. The code graph knows nothing about these files yet — normal for newly added files, and a cold index otherwise.

flowchart LR
  n0["scripts/ci<br/>4 files +208 -19"]:::changed
  n1["src/openhuman<br/>8 files +179 -5<br/>1 finding"]:::flagged
  n2["root<br/>2 files +156 -27<br/>2 findings"]:::flagged
  n3["scripts/__tests__<br/>1 file +158 -3<br/>2 findings"]:::flagged
  n4["scripts/lib<br/>1 file +138 -3"]:::changed
  n5[".github/workflows<br/>2 files +49 -5"]:::changed
  n6["scripts<br/>2 files +44 -2"]:::changed
  n7["src/core<br/>1 file +44 -0"]:::changed
  n8["docs<br/>1 file +23 -13"]:::changed
  n9["app/src-tauri<br/>1 file +4 -0"]:::changed
  classDef changed fill:#0d4429,stroke:#238636,color:#e6edf3
  classDef impacted fill:#161b22,stroke:#6e7681,color:#c9d1d9
  classDef flagged fill:#5a1e02,stroke:#d93f0b,color:#ffffff
  classDef blocking fill:#67060c,stroke:#f85149,color:#ffffff
Loading

Green: changed. Grey: untouched, reached through an import or a call. Orange: has findings. Red: has a finding that blocks the merge.

Component Files Lines Findings
scripts/ci changed 4 +208 -19
src/openhuman changed 8 +179 -5 1 (medium)
(root) changed 2 +156 -27 2 (medium)
scripts/__tests__ changed 1 +158 -3 2 (medium)
scripts/lib changed 1 +138 -3
.github/workflows changed 2 +49 -5
scripts changed 2 +44 -2
src/core changed 1 +44 -0
docs changed 1 +23 -13
app/src-tauri changed 1 +4 -0
Changed files

scripts/ci

  • scripts/ci/check-feature-forwarding.mjs
  • scripts/ci/product-features.sh
  • scripts/ci/product-features.txt
  • scripts/ci/rust-coverage-changed.sh

src/openhuman

  • src/openhuman/memory/diff/mod.rs
  • src/openhuman/memory/diff/stub.rs
  • src/openhuman/memory/driver/embedded/mod.rs
  • src/openhuman/memory/store/content/mod.rs
  • src/openhuman/memory/tinycortex/seal.rs
  • src/openhuman/memory/tree/ingest.rs
  • src/openhuman/tools/mod.rs
  • src/openhuman/tools/ops.rs

(root)

  • AGENTS.md
  • Cargo.toml

scripts/__tests__

  • scripts/__tests__/feature-forwarding.test.mjs

scripts/lib

  • scripts/lib/feature-forwarding.mjs

.github/workflows

  • .github/workflows/ci-lite.yml
  • .github/workflows/test-reusable.yml

scripts

  • scripts/kernel-floor.limits
  • scripts/test-rust-with-mock.sh

src/core

  • src/core/all_tests.rs

docs

  • docs/library-minimal-recipe.md

app/src-tauri

  • app/src-tauri/Cargo.toml

tinysweeper 0.1.0

@tinysweeper tinysweeper Bot added the priority: p2 Soon. Real but survivable — a rough edge, a gap, a thing that will bite later. label Aug 10, 2026
@senamakel
senamakel merged commit fbe8865 into tinyhumansai:main Aug 10, 2026
32 of 37 checks passed
senamakel added a commit to nocstah/openhuman that referenced this pull request Sep 11, 2026
…nTakes the kernel profile to **2 native builds — the spec target** (G6 in\nMIGRATION-PLAN, and the goal named in `kernel-floor.limits`' own baseline\nentry). `git2` with vendored libgit2 leaves and takes `libgit2-sys` **and**\n`libz-sys` with it; together with the `runtime-node` gate already on main, only\n`libsqlite3-sys` and `ring` remain, and both are load-bearing. Kernel floor\n305/282/4 -> 302/279/2, from 418 names / 6 native when the program started.\n\n`memory-git` is default-OFF, product-ON, carrying `dep:git2` plus tinycortex's\n`git-diff` and `wiki-git`.\n\n## The type carve-out is what makes this gateable\n\n`memory::diff::types` compiles in BOTH builds. The always-on subconscious\nmemory profile renders `CrossSourceDiff` and `ChangeKind` into agent prompts,\nso stubbing them would put two definitions of one serde shape in the tree, free\nto drift. tinycortex needed the matching split first — its `git-diff` gated the\nwhole `memory::diff` module, so a libgit2-less host could not name the types at\nall. Its `memory::diff::{types,source}` are ungated now (they reach no `git2`\nsymbol; only `ledger.rs` and `ledger_helpers.rs` do) and the\n`Ledger`/`DiffEngine` half stays behind the feature. Gitlink bumped to it.\n\n## Stub vs `#[cfg]`, decided per call site\n\nStubbed: the three `ops` entry points always-on code reaches —\n`auto_snapshot_after_sync` (`memory::sources::sync`), `diff_since_checkpoint`\nand `create_checkpoint` (the subconscious profile). Those domains stay\nfeature-unaware.\n\nThey return an `Err` naming the gate, not an empty diff. An empty\n`CrossSourceDiff` asserts "your world did not change", which the subconscious\nwould act on; the error routes into a path the caller already handles by\nlogging and skipping.\n\n`#[cfg]`'d: the registration sites, which want absence. The schema aggregators\nreturn empty vecs (`memory_diff` becomes unknown-method and drops off\n`/schema`) and `MemoryDiffTool` disappears from its single registration site —\na registered tool that always errors is worse than an absent one, because the\nmodel keeps choosing it and reporting the failure to the user.\n\n## Capability honesty\n\nThe embedded driver drops `Capability::Diff` from `advertised_capabilities()`\nand `as_diff()` returns `None`. Both halves move together deliberately:\n`audit_provider` fails on either alone, which is the check that keeps them from\ndrifting, and callers may trust the advertised set rather than probing every\naccessor.\n\n## The wiki mirror degrades, it does not fail\n\n`content::wiki_git::commit_summaries` is gated at its two call sites rather\nthan stubbed. The git wiki is a derived view — the summary's own content file\nis written either way — so skipping it loses the mirror, not the summary.\n`seal.rs`'s `summary_committed` gains a `#[cfg(not(...))]` sibling returning\n`Ok(())`: accurate rather than lenient, since nothing the caller depended on\nfailed to happen. `tests/memory_artifacts_e2e.rs` opens the ledger with\n`git2::Repository::open`, so it declares `required-features = ["memory-git"]`.\n\n## Review follow-ups from tinyhumansai#5477 also folded in\n\n- `scripts/ci/product-features.sh` died with a bare exit 1 and no message on a\n  comments-only file: `grep -v` exits 1 when it selects nothing, and `set -e`\n  aborted inside the command substitution, making the explicit diagnostic\n  unreachable. Fixed, and the helper now takes an optional path so the\n  self-test can drive that path with a fixture rather than mutating the\n  checked-in file. Two regression tests.\n- Stale figures in AGENTS.md corrected against measurement (contributor\n  353/3-native, product 540/7-native, kernel baseline 302/279/2).\n- `docs/library-minimal-recipe.md`'s obsolete single `Default` column replaced\n  with the real Contrib/Product pair rather than annotated as wrong.\n\n
senamakel added a commit to nocstah/openhuman that referenced this pull request Sep 11, 2026
…\n\nbuild(memory): gate the git-backed diff ledger behind `memory-git`\n
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

memory Memory store, memory tree, recall, summarization, and embeddings in src/openhuman/memory/. priority: p2 Soon. Real but survivable — a rough edge, a gap, a thing that will bite later. rust-core Core Rust runtime in src/: CLI, core_server, shared infrastructure.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant