Skip to content

Persona tiles, profile v2, storage reorg, avatar rendering - #282

Merged
joelteply merged 17 commits into
mainfrom
feature/persona-tile-real-data
Mar 4, 2026
Merged

Persona tiles, profile v2, storage reorg, avatar rendering#282
joelteply merged 17 commits into
mainfrom
feature/persona-tile-real-data

Conversation

@joelteply

Copy link
Copy Markdown
Contributor

Summary

  • Storage reorganization: Migrate .continuum/ from repo-relative to $HOME/.continuum/ as persistent identity root. 40+ files migrated to SystemPaths, Rust paths purged to use $HOME
  • Profile v2: Full-bleed cover banner, gradient avatar with VRM 3D render support, pathway cards, writings feed, about section with real data
  • Avatar rendering: Bevy snapshot pipeline for 3D VRM avatar renders, then simplified to passive HEAD-check resolution (no Bevy allocation on profile view)
  • Profile action buttons: Hero-level Message (DM) and Video Call buttons on non-self profiles
  • Sidebar polish: Kill RAG overlay, merge rooms+DMs list, fix AI metrics display
  • Content tabs: Extract SCSS, add type icons, theme compliance
  • Persona widget: Reworked and rewired
  • LiveWidget fix: Eliminate infinite loop that was hanging the browser on call join
  • Genome distribution: Adapter pack/unpack/import with SHA-256 verification
  • Seed data: UserProfileEntity for all personas, PERSONA_PROFILE_DATA extraction

Key changes

Area What
Storage $HOME/.continuum/ as root, SystemPaths everywhere
Profile Full social profile page (cover, avatar, bio, pathways, writings, admin)
Avatars Passive /avatars/{id}.png HEAD check, works without profile entity
Actions Message + Video Call hero buttons on profiles
Live Fix infinite loop on call join
Sidebar Cleaner layout, merged rooms/DMs
Genome Adapter distribution with integrity verification

Test plan

  • Profile renders with avatar, badges, action buttons
  • Message button opens DM chat
  • Video Call button starts live call
  • Avatar resolves even without user_profiles entity
  • No browser hang on live call join
  • npm start deploys cleanly
  • TypeScript compiles with zero errors

🤖 Generated with Claude Code

joelteply added 17 commits March 2, 2026 20:52
…cation

Adds .genome.tgz archive format for adapter trading. pack() strips training
artifacts (checkpoints, optimizer state ~400MB), keeping only inference-essential
files. unpack() verifies SHA-256 integrity before accepting. importAdapter()
handles the full pipeline: unpack, verify, model compatibility check, ORM
registration. AdapterStore discovers imported adapters automatically.
Composite SystemPaths routes persistent data (genome, personas, database,
blobs, models, datasets) to $HOME/.continuum and runtime data (logs,
sessions, sockets, registry, temp) to $REPO/.continuum. 25+ consumers
import SystemPaths unchanged — routing is transparent.

- Expand ContinuumPaths interface with 7 missing sections (blobs, shared,
  reports, models, sockets, datasets, media) and genome.python
- Correct database paths from jtag/database/ to data/ (matches reality)
- Add createCompositeSystemPaths() factory and swap singleton
- Add ProjectPaths export for explicit repo-local access
- BlobStorage: hardcoded '.continuum/blobs' → SystemPaths.blobs.root
- RegistryPath: collapse 61-line parent-walk hack to SystemPaths delegates
- Constants: remove unused PATHS.LOGS and PATHS.SCREENSHOTS
- AdapterStore: dual-root scanning (primary $HOME + legacy $REPO bridge)
- 26 TypeScript files: bare .continuum paths → SystemPaths/GlobalPaths
- ArtifactsDaemon: moved STORAGE_PATHS + validateAndResolvePath from shared → server (browser bundle fix)
- Shell scripts: bare .continuum → $CONTINUUM_ROOT variable (start-workers, parallel-start, system-stop)
- Removed dead DatabaseConfig constants (LOGS_DIR, SIGNALS_DIR, SESSIONS_DIR) and ServerConfig dead methods
- generate-rust-bindings.ts: skip cargo test when Rust source unchanged (fixes 300s timeout)
- Added metadata comments to browser-bundled config files (BrowserSafeConfig, ConfigurationFactory)
_syncMediaState() checked audioClient existence but not isConnected.
Between audioClient creation and room.connect() completion,
applyMicState() early-returned without setting _lastAppliedMic,
causing .finally() to recurse infinitely as a microtask flood.

Also: purge all hardcoded /Users/joel paths from tracked source.
- shared/config.ts: gitignored (auto-generated at build time)
- tests/*.ts: use SystemPaths.genome.adapters
- generator specs: use $HOME placeholder in examples
- Add persona tile design doc
LoggerModule, ModuleLogger, SentinelModule, and inference prompt-replay
all used relative ".continuum/jtag/logs/..." paths that resolved from
cwd (src/) to the repo instead of $HOME. Every path now uses
dirs::home_dir() for absolute resolution.

WallManager.ts also fixed: __dirname-relative path replaced with
SystemPaths.root.

Files: logger.rs, module_logger.rs, sentinel/mod.rs, backends/mod.rs,
WallManager.ts
- Remove PositronicBridge diagnostic overlay (showDiagnostic, testBridgeConnection)
  that stuck a green "SUCCESS! RAG stored" div on every page load
- Merge DMListWidget into RoomListWidget with All/Rooms/DMs filter chips,
  delete standalone dm-list-widget and remove from layout
- Wire UserListWidget message button to create/open DM rooms via collaboration/dm
- Fix AI Performance metrics: Rust ORM FieldFilter is single-operator enum,
  combining $gte+$lte on same field silently failed — use $gte in SQL, $lte in TS
- Unswallow .catch(()=>{}) in AIProviderDaemon generation logging (4 sites)
- Add empty state to metrics chart when no data exists
- Extract inline CSS to content-tabs-widget.scss with CSS variables
- Add content type icons (💬 chat, 🎥 live, 🧠 persona, etc.) for tab differentiation
- Replace 13 hardcoded rgba() values with theme variables
- Add --content-error and --content-error-dim to all 6 themes
Kill emoji avatars — replaced with gradient+initial system (radial gradient
from accentColor with 48px initial letter). Three-tier: image URL when
avatarUrl set, gradient+initial default, never emoji.

Full-bleed cover banner (240px, generated gradient or coverUrl image) with
dark fade overlay. Avatar overlaps cover bottom edge by 40px.

New writings feed section between pathways and admin — queries wall_documents
and social/feed in parallel via Promise.allSettled. Feed cards show title,
excerpt, metadata (lines, bytes, votes, comments, relative time).

Extended UserVisualIdentity with avatarUrl?, coverUrl?, coverGradient? fields
(JSON blob, no migration needed).

Layout restructured: .profile-page is full-width, .profile-content is the
720px centered column for About/Pathways/Writings/Admin.
Scroll was broken because .content-view > * sets overflow:hidden on all
child widgets. Moved scroll container from :host to .profile-page inner div.

Removed social/feed query from writings section — it returns the global
MoltBook feed, not posts by the viewed persona. Showing someone else's
content on a profile page is misleading. Writings section now shows only
wall_documents authored by the user (createdBy filter).

Social posts will return when social/feed supports author filtering, or
when personas generate their own content through profile commands.
Profile entities were never created — user_profiles collection was empty.
Added profile entity creation to updatePersonaProfile() in seed helpers,
with distinct accent colors per persona (cyan helper, orange teacher,
pink codereview, etc.).

Widget now falls back to user.shortDescription and user.createdAt when
no profile entity bio/joinedAt exists, so profiles are never blank.

Seeded 16 persona profiles with bios, specialities, and brand colors.
Profile seeding was only in the first-time seed path — existing databases
never got UserProfileEntity records. Extracted profile data (bios, accent
colors, specialities) into PERSONA_PROFILE_DATA map and shared
ensurePersonaProfiles() function called from both code paths.

Made updatePersonaProfile() idempotent: checks if profile exists first,
updates if yes, creates if no. Safe for repeated runs.

Any repo user running npm start → data:seed now gets profiles.
Rust AvatarModule captures single-frame PNG snapshots from the Bevy
render pipeline — allocates a temporary slot, waits for model load,
grabs a clean frame after 40+, encodes RGBA→PNG via image crate, and
caches to ~/.continuum/avatars/. Served via new /avatars/ HTTP route.

Profile page auto-requests snapshots for AI personas on load, updates
UserProfileEntity with the avatar URL. Avatar enlarged to 200px.

User list tiles show VRM avatars as background-image in 42px circles
with cyan border glow, falling back to emoji when no snapshot exists.
Profile page no longer triggers avatar/snapshot (Bevy slot allocation)
on load. Instead uses a lightweight HTTP HEAD to check if the cached
PNG exists and links it to the profile entity. Avatar generation is
now only via explicit ./jtag avatar/snapshot command.
… profile entity

- Add Message and Video Call buttons to hero section (non-self profiles only)
- Message opens DM chat via existing openDm() flow
- Video Call starts live call via CollaborationLiveStart command
- Fix avatar not rendering when user_profiles collection is empty:
  resolvePassiveAvatar now sets in-memory profile for rendering even
  without a persisted profile entity
- SCSS: hero-btn styles with cyan (message) and green (call) theming
Copilot AI review requested due to automatic review settings March 4, 2026 14:43
@joelteply
joelteply merged commit ccd6ed0 into main Mar 4, 2026
2 of 3 checks passed
@joelteply
joelteply deleted the feature/persona-tile-real-data branch March 4, 2026 14:44

Copilot AI 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.

Pull request overview

This PR removes repo-local Continuum session artifacts and training-environment helper files, consistent with the shift toward storing persistent identity/session state outside the repository (e.g., under $HOME/.continuum/).

Changes:

  • Removed checked-in validation session runs and associated browser logs under .continuum/sessions/validation/
  • Removed .continuum/session-learnings.json (persisted session/learning state)
  • Removed genome Python environment / training helper scripts and default configuration doc under .continuum/

Reviewed changes

Copilot reviewed 80 out of 7574 changed files in this pull request and generated no comments.

Show a summary per file
File Description
.continuum/sessions/validation/run_0b791876b17e/session-info.json Removes stored validation session metadata from repo
.continuum/sessions/validation/run_0b791876b17e/logs/browser.log.json Removes stored validation browser log artifact
.continuum/sessions/validation/run_0b791876b17e/logs/browser.info.json Removes stored validation browser info artifact
.continuum/sessions/validation/run_0b63222b8db8/session-info.json Removes stored validation session metadata from repo
.continuum/sessions/validation/run_0b63222b8db8/logs/browser.log.json Removes stored validation browser log artifact
.continuum/sessions/validation/run_0b63222b8db8/logs/browser.info.json Removes stored validation browser info artifact
.continuum/sessions/validation/run_0ac9b8197e19/session-info.json Removes stored validation session metadata from repo
.continuum/sessions/validation/run_0ac9b8197e19/logs/browser.log.json Removes stored validation browser log artifact
.continuum/sessions/validation/run_0ac9b8197e19/logs/browser.info.json Removes stored validation browser info artifact
.continuum/sessions/validation/run_0a258d388535/session-info.json Removes stored validation session metadata from repo
.continuum/sessions/validation/run_0a258d388535/logs/browser.log.json Removes stored validation browser log artifact
.continuum/sessions/validation/run_0a258d388535/logs/browser.info.json Removes stored validation browser info artifact
.continuum/sessions/validation/run_09f6be35fb93/session-info.json Removes stored validation session metadata from repo
.continuum/sessions/validation/run_09f6be35fb93/logs/browser.log.json Removes stored validation browser log artifact
.continuum/sessions/validation/run_09f6be35fb93/logs/browser.info.json Removes stored validation browser info artifact
.continuum/sessions/validation/run_099efc4c8b57/session-info.json Removes stored validation session metadata from repo
.continuum/sessions/validation/run_0906f9ca853a/session-info.json Removes stored validation session metadata from repo
.continuum/sessions/validation/run_0906f9ca853a/logs/browser.log.json Removes stored validation browser log artifact
.continuum/sessions/validation/run_0906f9ca853a/logs/browser.info.json Removes stored validation browser info artifact
.continuum/sessions/validation/run_07ec16ae9613/session-info.json Removes stored validation session metadata from repo
.continuum/sessions/validation/run_07ec16ae9613/logs/browser.log.json Removes stored validation browser log artifact
.continuum/sessions/validation/run_07ec16ae9613/logs/browser.info.json Removes stored validation browser info artifact
.continuum/sessions/validation/run_07e002d725f3/session-info.json Removes stored validation session metadata from repo
.continuum/sessions/validation/run_07e002d725f3/logs/browser.log.json Removes stored validation browser log artifact
.continuum/sessions/validation/run_07e002d725f3/logs/browser.info.json Removes stored validation browser info artifact
.continuum/sessions/validation/run_0783a136fc5b/session-info.json Removes stored validation session metadata from repo
.continuum/sessions/validation/run_0783a136fc5b/logs/browser.log.json Removes stored validation browser log artifact
.continuum/sessions/validation/run_0783a136fc5b/logs/browser.info.json Removes stored validation browser info artifact
.continuum/sessions/validation/run_0770bdd843e9/session-info.json Removes stored validation session metadata from repo
.continuum/sessions/validation/run_0770bdd843e9/logs/browser.log.json Removes stored validation browser log artifact
.continuum/sessions/validation/run_0770bdd843e9/logs/browser.info.json Removes stored validation browser info artifact
.continuum/sessions/validation/run_0764c3c47018/session-info.json Removes stored validation session metadata from repo
.continuum/sessions/validation/run_0764c3c47018/logs/browser.log.json Removes stored validation browser log artifact
.continuum/sessions/validation/run_0764c3c47018/logs/browser.info.json Removes stored validation browser info artifact
.continuum/sessions/validation/run_075d45e0a8e7/session-info.json Removes stored validation session metadata from repo
.continuum/sessions/validation/run_06e3adc44fe1/session-info.json Removes stored validation session metadata from repo
.continuum/sessions/validation/run_06e3adc44fe1/logs/browser.log.json Removes stored validation browser log artifact
.continuum/sessions/validation/run_06e3adc44fe1/logs/browser.info.json Removes stored validation browser info artifact
.continuum/sessions/validation/run_06d9e6ac96fe/session-info.json Removes stored validation session metadata from repo
.continuum/sessions/validation/run_0690ad663cdd/session-info.json Removes stored validation session metadata from repo
.continuum/sessions/validation/run_0690ad663cdd/logs/browser.log.json Removes stored validation browser log artifact
.continuum/sessions/validation/run_0690ad663cdd/logs/browser.info.json Removes stored validation browser info artifact
.continuum/sessions/validation/run_06801e92a104/session-info.json Removes stored validation session metadata from repo
.continuum/sessions/validation/run_06801e92a104/logs/browser.log.json Removes stored validation browser log artifact
.continuum/sessions/validation/run_06801e92a104/logs/browser.info.json Removes stored validation browser info artifact
.continuum/sessions/validation/run_05dac86fb4da/session-info.json Removes stored validation session metadata from repo
.continuum/sessions/validation/run_05dac86fb4da/logs/browser.log.json Removes stored validation browser log artifact
.continuum/sessions/validation/run_05dac86fb4da/logs/browser.info.json Removes stored validation browser info artifact
.continuum/sessions/validation/run_04317ad00fb7/session-info.json Removes stored validation session metadata from repo
.continuum/sessions/validation/run_04317ad00fb7/logs/browser.log.json Removes stored validation browser log artifact
.continuum/sessions/validation/run_04317ad00fb7/logs/browser.info.json Removes stored validation browser info artifact
.continuum/sessions/validation/run_034544edafde/session-info.json Removes stored validation session metadata from repo
.continuum/sessions/validation/run_034544edafde/logs/browser.log.json Removes stored validation browser log artifact
.continuum/sessions/validation/run_034544edafde/logs/browser.info.json Removes stored validation browser info artifact
.continuum/sessions/validation/run_013fbae78cb8/session-info.json Removes stored validation session metadata from repo
.continuum/sessions/validation/run_00d68938215b/session-info.json Removes stored validation session metadata from repo
.continuum/sessions/validation/run_00d68938215b/logs/browser.log.json Removes stored validation browser log artifact
.continuum/sessions/validation/run_00d68938215b/logs/browser.info.json Removes stored validation browser info artifact
.continuum/session-learnings.json Removes stored session “learnings” state from repo
.continuum/genome/python/train-wrapper.sh Removes repo-local genome training wrapper script
.continuum/genome/python/test-training.sh Removes repo-local genome training test script
.continuum/genome/python/test-training-dataset.jsonl Removes repo-local training test dataset
.continuum/genome/python/requirements-frozen.txt Removes pinned training dependency list from repo-local storage
.continuum/genome/python/environment.yml Removes conda environment definition from repo-local storage
.continuum/genome/python/activate.sh Removes repo-local training env activation helper
.continuum/default/config.md Removes repo-local default Continuum config documentation

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

joelteply added a commit that referenced this pull request Aug 1, 2026
… ahead of decode (#282) (#2075)

Joel's steer: predict which experts will be hot BEFORE the inference
needs them. Measured on the RUN-1 fixture, the strongest signal is not
a prediction at all — prefill routing IS the decode hot set, extracted
early: the prefill union covers 66% of every decode token's experts
(vs 58% for full decode recency), and the prefill TAIL alone covers
47% at a third of the size. Stability selectors lose badly ("in all
prefill batches" = 1.4%) — recency-of-context dominates even within
one prompt, the same law RUN-1/RUN-2 measured across prompts. The
cache-dynamics problem is the big prefill batches (8637 experts vs
~4416 slots) churning out decode-relevant experts before decode
starts — so the moment to act is the boundary.

- segment::PrefillBoundaryDetector — classifies the first decode-sized
  segment (size < 0.8× min seen) from segment sizes alone; fires once;
  decode-only serves never fire. Pinned against the fixture's exact
  sizes.
- Driver publishes the plan IMMEDIATELY at the boundary (bandit is
  already seeded by the prefill batches) instead of waiting
  rewrite_every decode tokens — the warm-start window opens at decode
  token 1.

Fixture replay verified live: boundary fires between the 3854 prefill
tail and the first 1472 decode token; published plan carries 256
tier-0 pins + default_tier for the cold tail. 16/16 tests, clippy
clean.


Claude-Session: https://claude.ai/code/session_01LoTjvf5j3Ez13g6k8mRkFo

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
joelteply added a commit that referenced this pull request Aug 1, 2026
…reen (#141 slice 1) (#2076)

* feat(pager): prefill→decode boundary warm-start — extract the hot set ahead of decode (#282)

Joel's steer: predict which experts will be hot BEFORE the inference
needs them. Measured on the RUN-1 fixture, the strongest signal is not
a prediction at all — prefill routing IS the decode hot set, extracted
early: the prefill union covers 66% of every decode token's experts
(vs 58% for full decode recency), and the prefill TAIL alone covers
47% at a third of the size. Stability selectors lose badly ("in all
prefill batches" = 1.4%) — recency-of-context dominates even within
one prompt, the same law RUN-1/RUN-2 measured across prompts. The
cache-dynamics problem is the big prefill batches (8637 experts vs
~4416 slots) churning out decode-relevant experts before decode
starts — so the moment to act is the boundary.

- segment::PrefillBoundaryDetector — classifies the first decode-sized
  segment (size < 0.8× min seen) from segment sizes alone; fires once;
  decode-only serves never fire. Pinned against the fixture's exact
  sizes.
- Driver publishes the plan IMMEDIATELY at the boundary (bandit is
  already seeded by the prefill batches) instead of waiting
  rewrite_every decode tokens — the warm-start window opens at decode
  token 1.

Fixture replay verified live: boundary fires between the 3854 prefill
tail and the first 1472 decode token; published plan carries 256
tier-0 pins + default_tier for the cold tail. 16/16 tests, clippy
clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LoTjvf5j3Ez13g6k8mRkFo

* feat(positron): serving glass box — the beat-WASTE control loop on screen (#141 slice 1)

Joel's greenlight ("Take it. We are sota now"): the pager campaign's live
telemetry becomes a positron widget on the proven metrics-gauge spine —
one new view kind, one projector, one Lit panel, no new transport.

Rust:
- ServingViewState (kind="serving") in continuum-positron: header folded
  from the daemon's ServingSnapshot (model/ready/lanes/ctx/degraded — the
  process's own truth via current_serving(), zero new plumbing), pager
  series reusing MetricSeriesView (hit % / tok/s / fetch MB/s), bandit
  arm beliefs, and event cards for the discrete control-loop moments.
- positron_serving_source: 2s emitter cloned from the metrics-gauge
  shape; tails the GGML_MOE_CAPTURE_FILE JSONL the serving binary
  already appends ("Positron tails it" — the only live feed today),
  offset-tail with raw-length truncation detection (consumed-offset
  alone misses a new serve that outgrows it — pinned by test), torn-tail
  guard, PagerCaptureEvent's serde(default)s decoding both the raw C++
  perf feed and the future Rust decision feed. Event cards: serve-start,
  decay-switch, residency-shift (>1/8 jump). Arms labeled from the leaf
  crate's DECAY_ARMS ladder — data-driven, never invented.
- Honest absence throughout: no capture env → header-only serving-health
  widget; no snapshot → awaiting line; never a fabricated gauge.

TypeScript (the SysPanel spine end to end):
- ServingPanelView in patterns; SERVING_KIND seam; servingWidget()
  projection + WorkspaceLive.serving + left-rail stack slot;
  <serving-panel> light-DOM Lit renderer (header line, renderGaugeBody
  sparklines, arm chips with reward bars, newest-first event cards);
  registry + host subscribe + ChatWidget property; TUI parity case;
  4 view types vendored through the SDK barrels.

Validation: 3/3 new projector tests + view kind test green; crate suites
green; vendor-views in sync; typecheck clean except the pre-existing
renderChat.spec process error; lint adds ZERO errors (baseline 61
pre-existing, my files clean); client test suites 36/36.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LoTjvf5j3Ez13g6k8mRkFo

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
joelteply added a commit that referenced this pull request Aug 2, 2026
…e coverage from the live trace (#281/#282) (#2122)

Joel's directive: use the ML advantage for predictive scheduling. Before
any CUDA copy-stream work, the go/no-go must be MEASURED, not assumed:
exposed H2D per token = (1 − schedulable coverage) × the ~11GB expert
working set. This slice wires the #276-ported CrossLayerExpertPredictor
into the trace tail as a cross-TOKEN transition model and measures, live
from the real trace, the two halves of coverage:

- repeat_recall: experts already in the previous token's set — what pure
  recency residency covers for free (her measured 4416-stable warm set
  says this is high on decode).
- predicted_delta_recall: of the NON-repeat delta, how many the
  predictor called one token ahead — what prefetch adds on top.
- schedulable_coverage = both, over all experts: THE number that sizes
  her DeviceUploadFetcher's win before it's built.

Published on the serving.moe_host_cache_lease probe every plan write
(repeat/delta/coverage ×100). predicted_next() exposes the live delta
prediction — the future plan-file prefetch list (#273's third axis),
held back from the wire until the consumer coordinates the extension.
All prediction state resets with the stream (truncation/geometry) —
stale transitions never leak across serves.

Test pins the instrument's honesty: a repeating stream scores 100%
recency/zero delta; an alternating DISJOINT stream scores 0% recency
but the predictor learns the cycle and delta recall climbs ≥50% —
prediction covering exactly what recency cannot. First token scores
nothing (honest None, never a fake 100).

trace_tail 5/5; serving_daemon suite green.


Claude-Session: https://claude.ai/code/session_01LoTjvf5j3Ez13g6k8mRkFo

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
joelteply added a commit that referenced this pull request Aug 2, 2026
…coverage measurement

Merge fix: vision_sidecar's ServingTarget was missing resident_override (added by
#29). Plus a measurement test that drains the real K3 routed-access fixture through
the #282 predictive instrument and prints repeat_recall / predicted_delta /
schedulable_coverage — the go/no-go for the LiveUploadPager predictive pipeline
(H2D/token = (1 - coverage) x ~11GB). Prints, never asserts (real routing sample).
NOTE: can't run on windows-msvc (pre-existing cargo-test Unix-socket block, ipc/mod.rs);
runs on M5's Mac.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q4NU4VNiELPQfBpCacDZGc
joelteply added a commit that referenced this pull request Aug 3, 2026
#2109)

* chore(k3): bump llama.cpp submodule to eee635ba2 — K3 serving stack onto canary

Advances the vendored llama.cpp fork 30 commits (clean FF over canary's stale
66594cc3f): container-serve resident-override (LLAMA_RESIDENT_OVERRIDE), the
rung-2 ResidencyCache plan-file consumer, the score-hint/generation-bias
actuator, PagerCaptureEvent emit, fit-device --reserve-gb. Makes canary USE the
K3 misfit-serving stack (measured 0.33 tok/s WASTE-parity on a 32GB card).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q4NU4VNiELPQfBpCacDZGc

* docs(pager): RUN-1 K3 trace fixture + tkey->(layer,matrix) table for M5's replay

Live GGML_MOE_TRACE_FILE slice (12B records: u64 tkey + u32 e) + the reverse
table so BanditPlanController recovers (layer,expert): tkey=FNV-1a of
blk.{layer}.ffn_{gate,up,down}_exps.weight, e=within-layer expert idx, expert
identity=(layer,e) deduped across the 3 matrices. RUN-1 static-pin datum input.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q4NU4VNiELPQfBpCacDZGc

* docs(pager): reference RL-policy prototypes for M5's TierPolicy port

The actual std-only Rust prototypes written against live K3 traces this
session: trace_replay (recency beats LFU 3-4x), predictor (offline
learned-decay +5pts held-out), online_predictor (bandit 49.8 vs 47.8
best-fixed on non-stationary), self_optimize (joint speed×quality). These
are the faithful-port source for the learned policy behind TierPolicy
(continuum-core expert_tier_policy.rs, #276). Numbers are properties of
these exact constants + reward math — reproduce before improving.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q4NU4VNiELPQfBpCacDZGc

* docs(k3): GPU-resident hot experts design (task #23 'trend to full GPU')

The major GPU speedup: promote hot experts to persistent VRAM so decode's hot
path is GPU-native (zero fetch, zero copy). 3 increments (copy-skip -> VRAM hot
cache -> pipeline), the 32GB rate-distortion constraint (imatrix-enabled resident
shrink frees VRAM for the hot set), measured per-increment via k3-bench.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q4NU4VNiELPQfBpCacDZGc

* docs(k3): flag the input_cpy-persistence question gating increment 1 vs 2

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q4NU4VNiELPQfBpCacDZGc

* docs(k3): modular rework-proof impl for #23 — reuse ResidencyCache + DeviceUploadFetcher

Mechanism is the existing (buft,fetcher)-generic ResidencyCache; a VRAM cache =
same class + device buft + host->device fetcher. 3 small parameterized pieces
(DeviceUploadFetcher, instantiate w/ GGML_MOE_VRAM_CACHE_GB, seam hook). Stats
only tune params -> zero mechanism rework.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q4NU4VNiELPQfBpCacDZGc

* docs(arch): MoE serving on a governed budget (draft; M5 owns the governor seam)

Diagnoses the hardcoded-cache overcommit that collapsed K3 fetch bandwidth
(40GB pinned + mmap = 95.9GB on 63GB -> pagefile thrash -> 205 MB/s -> 0.027
tok/s) and lays out the clean architecture: governor owns the residency budget
net of the model's mmap footprint, plan-file is the one wire, ResidencyCache is
pure mechanism. Governor-interface sections marked [M5 OWNS] for her to edit.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q4NU4VNiELPQfBpCacDZGc

* docs(arch): answer the [M5 OWNS] governor-budget seam in place (net-of-mmap is explicit arithmetic; plan_file.budget_bytes is the lease wire)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LoTjvf5j3Ez13g6k8mRkFo

* docs(arch): measured governed-budget inputs + graduated serving/load path

Records the BigMama measurements feeding M5's #287 derivation (non-cache ~56GB,
per-token working set 5.5GB, governed budget ~6GB, fetch recovers to 2.5GB/s at
fit), the now-complete C++ cache mechanism (enable-from-plan, grow, shrink), and
the three-piece graduated path to serving/load kimi-k3 (catalog row + serving-lane
MoE launch + #287) replacing the rigged .bat.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q4NU4VNiELPQfBpCacDZGc

* windows: make continuum-core build + link on windows-msvc (first time)

start-server.sh now provisions the full Windows CUDA build env before the cargo
builds (the cargo/nvcc path had none, unlike the vcvars-wrapped llama cmake):
import MSVC via vswhere->VS2022-14.4x + a .bat env dump (cl.exe for nvcc), pin
CMAKE to the manifest install, force CMAKE_GENERATOR=Ninja (the VS18-2026 auto-
pick is undefined in cmake 3.30), add the Windows SDK bin (mt.exe/rc.exe), select
a complete CUDA toolkit + CUDA_PATH (a provisioning split left cuda-env with 0
import libs vs cuda-13.2's 12), and RUSTFLAGS -L for pocket-tts (which emits no
link-search) while re-carrying +crt-static so the /MT GPU stack still links.

Portability: expert_container.rs + commands/capacity.rs used Unix-only
std::os::unix::fs::FileExt::read_exact_at. Add crate::platform_io::pread_exact
(unix read_exact_at / windows seek_read loop) - one place for positioned reads.

Build validated (npm start exit 0, continuum-core lib clean). A separate runtime
hot-loop on the #2088 core at startup is tracked apart from this build fix.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q4NU4VNiELPQfBpCacDZGc

* feat(capacity): device_fit VRAM-partition calc for the governor

Pure calc the governor uses to fit a streaming-MoE's RESIDENT (non-expert)
tier to a device VRAM budget and reconcile it with the expert tier on ONE
budget — fixing the double-count where the expert pager was handed the full
VRAM ceiling while resident silently ate most of it.

Partition (in order): compute reserve -> resident (Native | device-fit
Override | Unfittable) -> sufficient-context KV -> everything left =
hot-expert VRAM budget (maximized: more on-GPU experts, fewer streams).
Context is derived + clamped, never hand-picked. Artifact resolver injected
(no hardcoded paths). Standalone-validated 7/7; M5 wires it into the daemon
spawn path + launch (ServingTarget.resident_override) per the K3 sprint split.

Refs #29 #31 #36. Arch-confirmed on real K3 UD-IQ2 (93 blk/896 exp/top-16).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q4NU4VNiELPQfBpCacDZGc

* feat(serving): resident-override plumbing on ServingTarget + launcher

Wire foundation for the governor's device_fit plan: ServingTarget carries
resident_override: Option<PathBuf>, and the launcher exports it as
LLAMA_RESIDENT_OVERRIDE so llama.cpp sources the precision-shrunk RESIDENT
(non-expert) tensors from the device-fit GGUF (all offloaded to GPU) while the
primary streams experts. All builders updated; defaults None (resident serves
as-shipped, no behavior change) until compute_resident_override + the
resolve-or-generate resolver (#35) land next. In-crate validated.

Refs #29 #36.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q4NU4VNiELPQfBpCacDZGc

* chore(vendor): bump llama.cpp fork to k3-adopt e3ce51df5

M5's per-layer KV accessors (n_head_kv_il + n_embd_head_{k,v}_il, continuum #238)
+ graph reconciliation. The K3 engine now builds against these — enables the
device_fit resident-override serve + honest per-layer K3 KV sizing.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q4NU4VNiELPQfBpCacDZGc

* feat(serving): compute_resident_override — wire device_fit into the plan

The governor now DECIDES the resident source per serve: compute_resident_override
derives resident_bytes (weights - expert_bytes_total) vs the governed VRAM ceiling
via capacity::device_fit, and sets ServingTarget.resident_override. A dense/small
model fits native (None); a >VRAM-resident MoE (K3) resolves a cached device-fit
override that fits, else Unfittable → route to grid / generate (#35), glass-boxed.

resolve_device_fit_override (model_registry::artifacts): looks up a per-user
device-fit cache convention (<storage_root>/device-fit/<id>/) + a resident-bytes
sidecar; returns the override only when its resident fits the usable budget. No
hardcoded paths; generation/HF discovery is #35. The resident-fit decision turns
only on resident_bytes vs budget — per-layer KV (#2107 ModelCapabilities) drives
the context/expert split elsewhere, so KV is not consulted here.

Refs #29 #35 #36. In-crate validated.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q4NU4VNiELPQfBpCacDZGc

* docs(arch): storage serving-tier governor — NVMe<->cold contention managed like VRAM/RAM

Joel: 'like vram and memory, this contention has to be managed between cold
storage and nvme.' Design: NVMe is a governed HOT-SERVING tier (a ResourcePool,
same TrackedDir + evict_at_least machinery as CargoTargetPool), whose eviction =
MIGRATE frozen/duplicate artifacts to the Cold drive, not a manual rm. Serving
asks ensure_hot_resident(model); composes with device_fit's Unfittable one tier
down (VRAM). Corrects the DriveRole bug: Cold (HDD) is FROZEN storage, never the
per-token streaming tier (HDD = unservable). Dissolves today's K3 container disk
fight: the C: IQ2 is a verified duplicate of the D: copy -> governor migrates it
off NVMe -> container fits, no human deletes anything.

Refs #12 #36. Design for M5's system_resources lane.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q4NU4VNiELPQfBpCacDZGc

* feat(capacity): verified cold-twin detection — safe-to-drop primitive for the storage tier

The gate the NVMe serving-tier eviction (#302) consults before dropping a frozen
GGUF: is an IDENTICAL twin already on cold storage? is_structural_twin (pure) =
same shard count + per-shard name + size, zero-byte shards never match. scan_shards
+ find_cold_twin are the thin fs layer. Never drop an NVMe artifact without a
VERIFIED cold twin (dropping 662GB on a path guess is the failure this guards).
Standalone-validated 5/5. Composes with device_fit + M5's NvmeServingTierPool.

Refs #12 #36. Design: STORAGE-SERVING-TIER-GOVERNOR.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q4NU4VNiELPQfBpCacDZGc

* chore(vendor): bump llama.cpp fork to k3-adopt c6469d5 — container-serve wired

Both halves of the DirContainerFetcher wire (BigMama fetcher + moe_pick_fetcher
branch 175ac9d6a; M5 caller-side encode + record_bytes reader c6469d5). Serving now
reads the aligned per-layer container (GGML_MOE_CONTAINER) instead of the scattered
raw GGUF — the honest ~2.6GB/s path. Retires the built-not-wired ContainerFetcher.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q4NU4VNiELPQfBpCacDZGc

* fix(serving): resident_override on vision_sidecar ServingTarget + K3 coverage measurement

Merge fix: vision_sidecar's ServingTarget was missing resident_override (added by
#29). Plus a measurement test that drains the real K3 routed-access fixture through
the #282 predictive instrument and prints repeat_recall / predicted_delta /
schedulable_coverage — the go/no-go for the LiveUploadPager predictive pipeline
(H2D/token = (1 - coverage) x ~11GB). Prints, never asserts (real routing sample).
NOTE: can't run on windows-msvc (pre-existing cargo-test Unix-socket block, ipc/mod.rs);
runs on M5's Mac.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q4NU4VNiELPQfBpCacDZGc

* feat(pager-driver): offline warm-coverage measurement (--synth-layers, --once, --budget-slots)

The moe-pager-driver gains an offline replay mode so any completed
GGML_MOE_TRACE_FILE can be scored on any box (windows-msvc clean by
crate constraint), not just tailed live next to a serve:

- --synth-layers N: synthesize the tkey->layer map from layer count
  alone (TkeyTable::for_layers, the same zero-config seam MoeTraceTail
  owns) instead of requiring an operator tkey-to-layer-matrix.json.
- --once: exit when the trace stops growing (EOF) and print a SUMMARY
  line with mean DECODE-token serving hit = warm schedulable coverage.
- --budget-slots N: override the predictor residency budget (default
  auto = first token x1.5) to measure the coverage-vs-free-VRAM curve
  (the device-fit tradeoff).

Measured on BigMama run2.trace (302 warm decode tokens): bandit
coverage 13.8% @250 slots -> 51.3% @2000 -> 65.7% @4024, beating naive
last-N recency by +7-9pts at matched VRAM.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q4NU4VNiELPQfBpCacDZGc

* feat(pager): measure cross-layer prefetch predictor ceiling — DEAD lever for K3

VDD offline measurement (cooccur-ceiling bin) on the real warm serve
trace (run2.trace, 122 held-out decode tokens, 11102 layer-steps):

  cross_layer_cooccur_hit           0.159   (adjacent-layer noisy-OR)
  recency_same_layer_hit            0.403   (last token, same layer)
  structure beyond recency         -0.244
  cooccur_recall_on_recency_misses  0.112   (11824/106058)

Adjacent-layer co-occurrence predicts <half what plain recency does, and
recovers only 11% of the experts recency misses (~base rate). K3 expert
routing has no exploitable cross-layer structure — the CrossLayerExpert-
Predictor prefetch lever is not worth wiring (saves the ggml pass-id
capture slice). Recency-family residency (the bandit EMA curve) is THE
signal; the only lever that lifts K3 is freeing VRAM (device-fit shrink)
so residency coverage can reach the measured 51%.

Caveat: adjacent-layer, one workload trace. Wider-predecessor noisy-OR
would regress toward the frequency baseline (which underperforms recency),
so a large lift is unlikely — but not measured here.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q4NU4VNiELPQfBpCacDZGc

* chore(vendor): bump llama.cpp to de29843e0 — device-resident expert cache half (#23)

Pins the fork at the DeviceUploadFetcher wiring (my half of the LiveUpload-
Pager H2D-kill). Off unless GGML_MOE_VRAM_CACHE_GB / plan device_budget_bytes
enables it; host serving path byte-for-byte unchanged. M5's expert-loop D2D
half lands next on the same seam.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q4NU4VNiELPQfBpCacDZGc

* chore(vendor): bump llama.cpp to 0fbe4e27a — quantize --resident-only + tier manifest (#40)

Enables the device-fit division: produce a small resident override per
precision tier + a (tier_label, resident_bytes) sidecar the governor reads
to co-optimize the VRAM split.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q4NU4VNiELPQfBpCacDZGc

* feat(pager): DivisionPolicy — the governor's VRAM-division RL brain (#2/#3)

The second control rung above the pager's DecayBandit. The pager decides
WHICH experts stay resident (reward=hit-rate, cheap, online). This decides
HOW TO DIVIDE the card — resident (non-expert) weights vs expert cache —
to MAXIMIZE tok/s. That reward (actual tok/s) is EXPENSIVE (a serve), so
naive online RL flails; the fix is SIM-WARM-START: predict tok/s per
division OFFLINE from the measured coverage curve, then a slow bandit
refines each arm from real measured tok/s.

- CoverageModel: piecewise-linear coverage(slots) over MEASURED points
  (k3_measured() = the trace-replay curve); saturates, never extrapolates up.
- predict_tok_s: coverage -> (1-coverage)*experts/token*expert_bytes H2D ->
  t_token -> tok/s. Higher coverage -> less H2D -> faster (the load-bearing
  property, tested).
- feasible_divisions: tier catalog (from --resident-only manifests) x
  HardwareBudget -> cache budget/slots per tier; drops VRAM-overflow tiers.
- DivisionBandit: warm_start from the predictor; observe(tier, measured_tok_s)
  overrides the prior on first serve then EMAs — the expensive reward spent
  only on the arm actually run.

Policy lives here (windows-clean, 4 tests pass); serving_daemon actuates it
(M5's #2: discover manifests, feed catalog+budget+live tok/s, apply the
chosen {resident_tier, device_budget_bytes} to the plan). Fractal control
law: pager (experts<->hit-rate) -> this (VRAM split<->tok/s) -> grid.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q4NU4VNiELPQfBpCacDZGc

* chore(vendor): bump llama.cpp to 2a32025dd — device-cache un-crashable (clamp to free VRAM + null-buffer guard, #23)

Testing convicted the segfault as VRAM oversubscription (K3 33GB resident +
env cache on a 32GB card, cudaMalloc lazy-VMM deferred fault). Fix: clamp
device budget to measured free VRAM (mine) + M5's D2D null-buffer guard.
Device cache now disables safely where there's no room (K3) and works
where there is (V4-Flash); can't crash from any budget source.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q4NU4VNiELPQfBpCacDZGc

* test(division): bandit learns residency saturation from measured V4-Flash curve

Feeds the real BigMama RTX 5090 --n-cpu-moe sweep (DeepSeek-V4-Flash UD-IQ2_M)
into DivisionBandit: 0 resident=1.39, 8 resident=1.69, 14 resident=1.68 tok/s.
Asserts the bandit converges on the SATURATION KNEE (8 layers), not max residency
— 8->14 layers buys nothing at +11GB VRAM. Encodes the measured finding that the
governor must learn 'minimal static residency + max device cache', the freed VRAM
belonging to the recency cache (#43), not to over-pinned static layers.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q4NU4VNiELPQfBpCacDZGc

* test(division): bandit finds non-monotonic device-cache budget optimum

Measured V4-Flash device-cache coverage curve (5090, GGML_MOE_VRAM_CACHE_GB sweep):
6GB/992slots=1.80, 12GB/1985=3.10, 22GB/3630=2.96 tok/s, all 100% hit. tok/s is
NON-MONOTONIC in budget: undersized churns, 12GB is the plateau knee, 22GB is no
better (100% hit but O(slots) reserve_slot eviction scan). predict_tok_s's monotonic
prior would pick 22GB; only the measured reward lands on 12GB — which frees ~20GB of
a 32GB card for co-resident lanes. Pins the invariant that the governor must not
oversize the cache and starve other models.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q4NU4VNiELPQfBpCacDZGc

* chore(vendor): bump llama.cpp to fa7e0d8e9 — #43 device-cache fix + async restore + enum fix

Includes the prefetch host_visible guard (THE #43 crash fix, validated 3.05 tok/s
V4-Flash device cache on the 5090), M5's async cpy_tensor_async restore, and the
moe-pack quant-enum fix. A fresh parent build now includes the un-crashable device
cache instead of the pre-fix pin.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q4NU4VNiELPQfBpCacDZGc

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants