feat(continuum-core/modules): L0-3a.1 — HippocampusModule skeleton (BrainRegion + ServiceModule, empty tick)#1473
Merged
Conversation
…er + RegionTelemetry (substrate prerequisite) Card: 71923a08-b3de-448a-98ef-fe7cc3e817c0 First sub-slice of L0-3a. Pure typed surface from BRAIN-REGIONS-SUBSTRATE.md (merged via #1470). No region implementations, no algorithms, no governor integration. Those land in L0-3a.1+ slices. ## New modules in continuum-core/src/runtime/ ### brain_region.rs The cognitive-cycle trait every region implements: - BrainRegion (async trait, dyn-compatible) - id() -> RegionId - pressure_profile() -> PressureProfile - async tick(ctx: &RegionContext) -> TickOutcome - async on_signal(signal: RegionSignal) -> Result<(), RegionError> // default no-op - RegionId (Cow<'static, str> newtype, const constructor for static IDs) - PressureProfile { memory_class, compute_class, responds_to } - MemoryClass: Light | Moderate | Heavy | VramSensitive - ComputeClass: Bookkeeping | Cpu | CpuVectorized | InferenceLight | InferenceHeavy - PressureSignalKind (kind-only mirror of governor::PressureSignal for static decl) - TickOutcome { published, consumed_since_last, pressure_observed, cadence_hint } - TickOutcome::idle() convenience constructor - CadenceHint: Faster | Hold | Slower | Sleep (region requests; governor decides) - RegionSignal: PersonaLifecycle | SleepTransition | SystemPressureChanged - PersonaLifecycle: Created | Destroyed - SleepPhase: Active | Idle | Sleep - PressureLevel: Nominal | Moderate | High | Critical - RegionContext { tick_number, persona_scope } // global vs per-persona - RegionError (thiserror): SignalRejected | NotReady | Internal ### ready_buffer.rs The publish/peek surface every region uses to hand off pre-staged results: - ReadyBuffer trait - peek(&self, key: &Key) -> Option<Value> // synchronous, MUST NOT block - publish(&self, key: Key, value: Value) // atomic replace - evict_stale(&self, max_age: Duration) -> usize - len() / is_empty() - DashMapReadyBuffer<K, V> default implementation - Arc-shared DashMap inner — cheap Clone hands out additional handles - Sharded concurrent access; wait-free reads in the common case - TimestampedEntry tracks published_at for evict_stale Semantic rules enforced in the doc + the trait: - Reads MUST NOT block / MUST NOT await - Staleness acceptable — empty buffer is signal, not block - Per-region buffers, not global ### region_telemetry.rs The per-tick telemetry shape: - RegionTelemetry { region_id, persona_id, tick_started_at, tick_duration, published, consumed_since_last, buffer_misses_since_last, pressure_observed } - consumption_fraction() -> Option<f32> // None when published == 0 - had_buffer_misses() -> bool Feeds the substrate governor's yield-learning loop (algorithm 7, lands L0-4c) and the operator surface (./jtag region/stats, region/yield). ## ts-rs bindings (11 emitted to shared/generated/runtime/) CadenceHint, ComputeClass, MemoryClass, PersonaLifecycle, PressureLevel, PressureProfile, PressureSignalKind, RegionId, RegionSignal, RegionTelemetry, SleepPhase, TickOutcome. Generated and validated by the ts-rs export_bindings_* tests. ## Tests 23 new unit tests across the three modules. All pass. - brain_region: 6 tests (trait impl, default on_signal noop, RegionId construction + Display, RegionContext global vs per-persona, TickOutcome::idle) - ready_buffer: 9 tests (publish+peek roundtrip, missing key, overwrite, evict_stale removes old + keeps fresh, evict ZERO clears everything, len/is_empty, clone shares Arc inner, dyn trait usage, with_capacity) - region_telemetry: 5 tests (consumption_fraction with publishes / zero / full, had_buffer_misses true / false) Plus ts-rs auto-generated export_bindings_* tests for all 11 types. Total: 74 tests pass in runtime::, 0 fail. ## Boy-scout cargo fmt applied across the package picked up some unrelated drift in governor/types.rs (line-width formatting on ts(export...) attributes). Including the fix. ## What is NOT in this card - No region implementations (HippocampusModule, MotorCortexModule, AttentionModule all land in later slices) - No algorithms (1-7 from COGNITION-ALGORITHMS.md land in subsequent cards) - No SubstrateGovernor integration (yield-learning loop is L0-4c) - No derive macro / scaffold generator (lands when ≥3 regions exist to motivate the abstraction — per outlier-validation in CLAUDE.md) ## Predecessors merged - #1469 (L0-2-CUTOVER-INVESTIGATION + RTOS-brain doctrine) — 2026-05-29 - #1470 (BRAIN-REGIONS-SUBSTRATE + COGNITION-ALGORITHMS docs) — 2026-05-29 ## Next slices L0-3a.1 HippocampusModule skeleton, L0-3a.2 Engram + EngramGraph types, L0-3a.3 Algorithm 4 (salience decay), L0-3a.4 Algorithm 2 (channel-as-bias), L0-3a.5 Algorithm 3 (activation spreading), L0-3a.6 Algorithm 1 (two-pool budget), L0-3a.7 Algorithm 5 (predictor + ready-buffer publish), L0-3a.8 holdout fixture suite, L0-3a.9 TS Hippocampus.ts deletion. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…rainRegion + ServiceModule, empty tick) Card: f8c51b26-9ddd-4107-97da-3237fc18ab4b Second sub-slice of L0-3a. Skeleton only — no algorithms, no command migration. Algorithms 1-5 from COGNITION-ALGORITHMS.md land in L0-3a.2 through L0-3a.7. Command surface migration (memory/* from MemoryModule) is L0-3a.1b. ## HippocampusModule - Implements ServiceModule with EMPTY command_prefixes + event_subscriptions (MemoryModule continues to handle memory/* commands until L0-3a.1b) - Implements BrainRegion (from #1471 trait machinery) with: - id = "hippocampus" (static) - pressure_profile: { MemoryClass::Heavy, ComputeClass::CpuVectorized, responds_to: [SystemMemHigh, InferenceQueueDepth] } - tick: idle — bumps internal monotonic counter, returns TickOutcome::idle() - on_signal: default no-op (L0-4d wires SleepTransition reaction) - Owns a DashMapReadyBuffer<EngramPrefetchKey, EngramPrefetch> exposed via engram_prefetch() — Arc-shared so motor cortex / attention can peek without going through the trait object - Shares MemoryState with MemoryModule via Arc — when L0-3a.1b absorbs command handling, migration is structurally trivial ## EngramPrefetch / EngramPrefetchKey Placeholder ready-buffer value type. Carries produced_at_tick so handlers can detect stale buffers without timestamp comparison. Real shape (engram set + scoring metadata + genome blend hint) lands L0-3a.2 with the actual Engram types. Key shape: (persona_id, channel_id) tuple. Per-region buffer doctrine — one prefetch per persona-per-channel. ## Outlier-validation hedge (docstring) The BrainRegion trait in #1471 has only one implementation candidate today. Module docstring explicitly checks the trait surface against two other plausible regions to prevent it ossifying around hippocampus: - Motor cortex (L0-4a): continuous candidate-utterance ranking. Differs in latency sensitivity. CadenceHint::Faster + per-key freshness semantics fit. - Attention (L0-4b): salience-map maintenance. Differs in publish-target (writes to shared PersonaCognition.salience, not own ready-buffer). TickOutcome.published counts either target without trait change. Both alternative shapes fit the same trait without forcing. Trait surface proven for 3 distinct region behaviors before any of them ship. ## Tests (7 pass, 0 fail) - region_id_is_stable_static_string - pressure_profile_declares_memory_heavy_compute_vectorized - idle_tick_returns_idle_outcome_and_bumps_counter - engram_prefetch_buffer_roundtrip - engram_prefetch_handle_is_shared_via_arc (verifies Arc-shared semantics) - service_module_handle_command_errors_for_unrouted_commands - service_module_config_has_empty_cmd_and_event_surfaces ## Scope: 2 files Modified: src/workers/continuum-core/src/modules/mod.rs (pub mod hippocampus) Added: src/workers/continuum-core/src/modules/hippocampus.rs (379 lines) Fmt-drift in unrelated files was split off into a companion PR following the same pattern as #1472, keeping this review focused. ## Predecessors - #1471 (L0-3a.0 trait machinery) — merged to canary - #1470 (BRAIN-REGIONS-SUBSTRATE + COGNITION-ALGORITHMS docs) — merged - #1469 (L0-2-CUTOVER-INVESTIGATION + RTOS-brain doctrine) — merged ## Next slices L0-3a.2 Engram + EngramGraph types → L0-3a.3 algorithm 4 (salience decay) → L0-3a.4 algorithm 2 (channel-as-bias) → L0-3a.5 algorithm 3 (activation spreading) → L0-3a.6 algorithm 1 (two-pool budget) → L0-3a.7 algorithm 5 (predictor + ready-buffer publish — the alive-feeling slice) → L0-3a.8 holdout fixture suite → L0-3a.9 TS Hippocampus.ts deletion. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
joelteply
added a commit
that referenced
this pull request
May 30, 2026
…dgeKind (algorithm 3 substrate) (#1474) Card: 8459bfa6-b40c-4c22-8f25-0963a7987c17 Sidecar substrate for algorithm 3 (activation spreading, COGNITION-ALGORITHMS.md §3). Pure storage layer — traversal logic lands in L0-3a.5. Does NOT modify the existing persona::engram admission membrane. ## What ships ### persona/engram_graph.rs (new, 376 lines) - EdgeKind enum — SharedEntity | SharedTopic | CitedIn | RecallCoOccurrence | ConversationalReply | TaskOutcome - EngramEdge { target: Uuid, kind: EdgeKind, weight: f32 } — algorithm-3 traversal payload - EngramGraph — DashMap<Uuid, Vec<EngramEdge>> sharded for concurrent writes - new() / with_capacity(n) / default() - add_edge(from, to, kind, weight) - neighbors(id) — outbound edges, O(1) amortized, insertion order preserved - in_degree(id) — inbound count, O(N) scan (cold path — algorithm 4 centrality) - edge_count() — telemetry - evict_engram(id) — removes outbound + inbound, idempotent - is_empty() ### ts-rs bindings shared/generated/persona/EdgeKind.ts shared/generated/persona/EngramEdge.ts ## Sidecar pattern Intentionally separate from persona::engram (the admission membrane): - engram.rs ships provenance, trust, content refs — WHERE engrams come from - engram_graph.rs ships connectivity — HOW engrams connect Keeping them separate means admission consumers don't grow algorithm-3 dependencies, and algorithm-3 consumers don't grow admission dependencies. Clean concern boundaries. ## Tests (16 pass, 0 fail) - new_engram_graph_is_empty - add_edge_increments_count - neighbors_returns_added_edges_in_insertion_order - neighbors_of_unknown_source_is_empty - weights_preserved_through_neighbors - in_degree_counts_inbound_edges_across_sources - in_degree_counts_repeated_edges_from_same_source - evict_engram_removes_outbound_edges - evict_engram_removes_inbound_edges_from_other_engrams - evict_engram_is_idempotent - concurrent_add_edge_from_threads_is_safe (8 threads × 100 edges, all targeting same id, in_degree=800) - default_constructor_matches_new - with_capacity_constructor_works - edge_kind_round_trips_through_serde - export_bindings_edgekind (ts-rs auto) - export_bindings_engramedge (ts-rs auto) ## What is NOT in this card - spread_activation function (L0-3a.5, algorithm 3 — reads this graph) - EdgeKind weights tuned by algorithm 7 (L0-4c yield-learning) - RecallMetadata sidecar (L0-3a.2b — salience, last_touched, access_count, embedding) - EngramRef shape (L0-3a.2b) - Engram admission membrane modifications (no changes to persona::engram) ## Predecessors - #1473 (L0-3a.1 HippocampusModule skeleton) — merged - #1471 (L0-3a.0 trait machinery) — merged - #1470 (cognition algorithms doc) — merged ## Flywheel test Third PR (after #1471, #1473) through the auto-merger flywheel that peer's #1091/#1092/#1093 enabled. Local fmt was scoped to ONLY my file (no widespread cargo fmt -p sweep), so no companion fmt-drift PR needed this time. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 task
joelteply
added a commit
that referenced
this pull request
May 30, 2026
The `avatars: ./src/models/avatars` additional_context was added in 9b1f6ca (April 2026) when the plan was to bake CC0 avatar VRMs into the continuum-core image. That plan never landed end-to-end — docker/continuum-core.Dockerfile lines 131-143 document the rollback: src/models is gitignored, the dir doesn't exist in CI checkouts, and the Dockerfile uses `RUN mkdir -p /app/avatars` as a placeholder instead of COPYing from the avatars context. The compose-side context declaration was left behind, dangling. No Dockerfile uses `--from=avatars` (verified by grep), so the declaration referenced nothing in build instructions. But docker compose validates that ALL additional_contexts resolve at build time — a missing local context dir fails the whole build with "stat /tmp/carl-smoke-NNNN/src/ models/avatars: no such file or directory". That's the exact failure mode currently blocking carl-install-smoke on PR #1475 (Mac Intel hardware tier) — any PR that touches install.sh triggers carl-install-smoke, which has been silently broken by this dangling context since the rollback. Other PRs (e.g. #1471, #1473, #1474) didn't touch install.sh so the check never ran on them; the break was invisible until now. Removing the line restores the carl-install-smoke happy path while keeping the Dockerfile's empty-dir placeholder intact. Restore the build context when the avatar-provisioning story lands (LFS, model-init download, or curl from a CC0 URL in CI before docker build) per the gap noted in docs/infrastructure/PR891-E2E-VALIDATION.md. Inline comment preserves the context-of-removal in the file so a future contributor doesn't re-add the dangling line. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
joelteply
added a commit
that referenced
this pull request
May 30, 2026
…se (#1476) The `avatars: ./src/models/avatars` additional_context was added in 9b1f6ca (April 2026) when the plan was to bake CC0 avatar VRMs into the continuum-core image. That plan never landed end-to-end — docker/continuum-core.Dockerfile lines 131-143 document the rollback: src/models is gitignored, the dir doesn't exist in CI checkouts, and the Dockerfile uses `RUN mkdir -p /app/avatars` as a placeholder instead of COPYing from the avatars context. The compose-side context declaration was left behind, dangling. No Dockerfile uses `--from=avatars` (verified by grep), so the declaration referenced nothing in build instructions. But docker compose validates that ALL additional_contexts resolve at build time — a missing local context dir fails the whole build with "stat /tmp/carl-smoke-NNNN/src/ models/avatars: no such file or directory". That's the exact failure mode currently blocking carl-install-smoke on PR #1475 (Mac Intel hardware tier) — any PR that touches install.sh triggers carl-install-smoke, which has been silently broken by this dangling context since the rollback. Other PRs (e.g. #1471, #1473, #1474) didn't touch install.sh so the check never ran on them; the break was invisible until now. Removing the line restores the carl-install-smoke happy path while keeping the Dockerfile's empty-dir placeholder intact. Restore the build context when the avatar-provisioning story lands (LFS, model-init download, or curl from a CC0 URL in CI before docker build) per the gap noted in docs/infrastructure/PR891-E2E-VALIDATION.md. Inline comment preserves the context-of-removal in the file so a future contributor doesn't re-add the dangling line. Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Card:
f8c51b26-9ddd-4107-97da-3237fc18ab4bSecond sub-slice of L0-3a, on top of #1471's BrainRegion trait machinery (now merged on canary). Skeleton only — no algorithms, no command migration. The first BrainRegion implementation; proves the trait surface fits a real region.
Two files, 380 insertions
continuum-core/src/modules/hippocampus.rscontinuum-core/src/modules/mod.rspub mod hippocampus;HippocampusModule
MemoryModulecontinues to handlememory/*until L0-3a.1b absorbs them. Defensive: if dispatch routes here despite empty prefixes, fails loudly.id = "hippocampus"(static, const-constructible)pressure_profile= { MemoryClass::Heavy (engram graph + working memory ring + ready-buffers), ComputeClass::CpuVectorized (scoring + activation spreading in future slices), responds_to:[SystemMemHigh, InferenceQueueDepth](consolidation depth drops under mem pressure; predictor backs off under inference queue depth) }tick= idle — bumps internal monotonic counter, returnsTickOutcome::idle(). Algorithm bodies drop in across L0-3a.3 through L0-3a.7on_signal= default no-op (L0-4d wires SleepTransition for deeper consolidation)DashMapReadyBuffer<EngramPrefetchKey, EngramPrefetch>exposed viaengram_prefetch()— Arc-shared so motor cortex + attention can peek without trait-object indirectionMemoryStatewithMemoryModuleviaArc— L0-3a.1b migration is structurally trivialEngramPrefetch / EngramPrefetchKey
Placeholder ready-buffer value/key types. Real shape (engram set + scoring metadata + genome blend hint) lands L0-3a.2. Key =
(persona_id, channel_id)— per-region per-persona-channel buffer, doctrine-aligned.Outlier-validation hedge (in the module docstring)
#1471's BrainRegion trait has only one implementation candidate today. To prevent the trait surface ossifying around hippocampus-specific concerns, the module docstring explicitly checks against two other plausible regions:
CadenceHint::Faster+ ReadyBuffer's per-key freshness semantic (publish overwrites, evict_stale prunes) fit cleanly.PersonaCognition.salience(CRDT counters), not own ready-buffer.BrainRegion::tick'sTickOutcome { published: N }counts shared-state writes equivalently — no trait change needed.Both alternative shapes fit without forcing. Trait surface is proven for at least 3 distinct region behaviors before any of them ship, per the CLAUDE.md outlier-validation strategy.
Tests (7 pass, 0 fail)
region_id_is_stable_static_stringpressure_profile_declares_memory_heavy_compute_vectorizedidle_tick_returns_idle_outcome_and_bumps_counter(uses fully-qualifiedBrainRegion::tickto disambiguate from ServiceModule's tick — note this trait-method ambiguity for L0-4a)engram_prefetch_buffer_roundtripengram_prefetch_handle_is_shared_via_arc(verifies Arc-shared semantics: writes via handle A visible to handle B)service_module_handle_command_errors_for_unrouted_commandsservice_module_config_has_empty_cmd_and_event_surfacesPredecessors
Next slice queue
L0-3a.2 Engram + EngramGraph types → L0-3a.3 algorithm 4 (salience-modulated decay) → L0-3a.4 algorithm 2 (channel-as-bias scoring) → L0-3a.5 algorithm 3 (activation spreading) → L0-3a.6 algorithm 1 (two-pool budget split) → L0-3a.7 algorithm 5 (predictor + ready-buffer publish — the alive-feeling slice) → L0-3a.8 holdout fixture suite → L0-3a.9 TS Hippocampus.ts deletion.
🤖 Generated with Claude Code