Skip to content

feat(boot): model GGUF availability reports via boot_status (e9f50a36 A5)#1554

Open
joelteply wants to merge 1 commit into
feat/adapter-boot-linefrom
feat/model-boot-line
Open

feat(boot): model GGUF availability reports via boot_status (e9f50a36 A5)#1554
joelteply wants to merge 1 commit into
feat/adapter-boot-linefrom
feat/model-boot-line

Conversation

@joelteply

Copy link
Copy Markdown
Contributor

Summary

Card e9f50a36 slice A5 — the last in the boot-line series. Stacked on #1553#1552#1551#1550.

After AIProviderModule::register_adapters walks every llamacpp-local row in the model registry, it now emits one model: boot status line covering the readiness of every declared GGUF artifact. Cloud-only deploys (no llamacpp rows declared) get NO emission — the adapter: line already surfaces the "no offline path" state via Degraded: cloud only ....

What an operator sees

# All declared models present + loadable
[continuum-core-server] model: ✓ 1/1 loaded: qwen3-coder

# Some models present, some missing
[continuum-core-server] model: ⚠ 1/2 loaded; missing: vision-mmproj (pull hf.co/vision)

# All declared models missing (first-launch parity failure)
[continuum-core-server] model: ✗ 2 declared, 0 loaded — pull: qwen3-coder (hf.co/qwen), vision-mmproj (hf.co/vision)

# Cloud-only deploy — no line at all (handled by adapter:)

Why no model: line when registry is empty

The substrate's job at boot is to surface load-bearing decisions. A cloud-only deploy doesn't HAVE local model decisions to make — the adapter: line already covers the "no offline path" failure mode via Degraded: cloud only .... Burning a second line on model: ✓ 0/0 loaded would be noise.

What changed

  • crates/continuum-core/src/modules/ai_provider.rs:
    • New pure helper render_model_boot_status(models: &[Model]) -> Option<(BootStatusKind, String)>. Returns None for empty registry. Classifies each row as loaded (path set + file exists on disk) or missing (path absent OR file not on disk).
    • Single boot_status("model", kind, &detail) call right after the llamacpp registration loop, gated on model_registry::try_global() returning Some.
  • 6 new unit tests covering each case (11 total in the module's boot_status_tests).

Specific edge cases the tests pin

  • path_present_but_file_absent_classifies_as_missinggguf_local_path populated by the artifact resolver but file never pulled. The most common failure mode after a fresh clone; the substrate must classify as missing so the operator sees the download list, not a false "ready" claim.
  • missing_model_without_hint_still_named_in_detail — local-only model paths (not in any public registry) still surface as <id> (<no hint>) so the operator knows TOML is missing the URL.
  • no_models_returns_none_so_boot_line_is_skipped — cloud-only deploys explicitly skip emission.

Test plan

  • cargo test -p continuum-core --lib modules::ai_provider::boot_status_tests → 11/11 green.
  • cargo build -p continuum-core clean.

Composition

After this slice merges, the full boot view for a healthy production server is:

[continuum-core-server] probes: ✓ landing at /tmp/probes.jsonl
[continuum-core-server] logs: ✓ ~/.continuum/logs/...log (rolling daily, retention 7)
[continuum-core-server] boot-mode: ✓ full-citizen (hosts personas via AIRC; requires AIRC Healthy)
[continuum-core-server] airc: ✓ socket=~/.airc/runtime/airc.sock peer=12345678 room=general
[continuum-core-server] adapter: ✓ anthropic, llamacpp-local, docker-model-runner (3 providers)
[continuum-core-server] model: ✓ 1/1 loaded: qwen3-coder
[continuum-core-server] persona-home: ⚠ migrated Paige: ...   ← only when legacy layout detected

Sentinels grep [continuum-core-server] .*: ✗ for failures across every subsystem. The substrate refuses to lie about any of these states.

Closes the original e9f50a36 slice A series. Future card extensions (persona count, GPU tier, etc) plug into the same boot_status seam without re-litigating shape.

Card e9f50a36 slice A5 — the last in the boot-line series for now.
Stacked on #1553 (adapter boot line, with the round-1 reviewer fixes).

After `AIProviderModule::register_adapters` walks every llamacpp-
local row in the model registry, it now emits one `model:` boot
status line covering the readiness of every declared GGUF
artifact. Cloud-only deploys (no llamacpp rows declared) get NO
emission — the `adapter:` line already surfaces the
"no offline path" state via `Degraded: cloud only ...`.

The pure helper `render_model_boot_status(models: &[Model]) ->
Option<(BootStatusKind, String)>` classifies each row:

- All loaded → Ok, "<N>/<N> loaded: <names>".
- All missing → Failed, "<N> declared, 0 loaded — pull <hint1>,
  <hint2>, ...". First-launch parity failure — operator gets the
  download list inline.
- Mixed → Degraded, "<loaded>/<total> loaded; missing: <id>
  (pull <hint>), ...". The detail names every missing model with
  its gguf_hint so the operator has the download URL right there
  rather than grep'ing `registry.toml`.

A row with `gguf_local_path` set BUT the file absent from disk
classifies as missing — this is the most common failure mode
after a fresh clone (the artifact resolver populated the path
expectantly but the operator never pulled). Captured by the
`path_present_but_file_absent_classifies_as_missing` test.

Rows without a `gguf_hint` surface `<no hint>` as a visible
placeholder so the operator knows the TOML is missing the URL.

6 new unit tests (11 total in the module) cover each case, each
using a `test_model(id, hint, path)` helper that constructs a
minimal Model with sane defaults so the tests focus on the
classification logic, not on registry plumbing.

This completes the original e9f50a36 slice A series:

- probes: ✓ landing at /tmp/probes.jsonl
- logs: ✓ ~/.continuum/logs/...log (rolling daily, retention 7)
- boot-mode: ✓ full-citizen (...)
- airc: ✓ socket=... peer=... room=...
- adapter: ✓ anthropic, llamacpp-local, docker-model-runner (3 providers)
- model: ✓ 1/1 loaded: qwen3-coder
- persona-home: ⚠ migrated <name>: ...  ← only after legacy detection

Co-Authored-By: Claude Opus 4.7 <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.

1 participant