spec+plan: lobes fits the machine it lands on — per-machine hardware profiles#108
Conversation
…gue /think)
Converged /think frame + exported spec for per-card hardware profiles.
Today the packaged templates hardcode one tuning for the DGX Spark GB10
(sm_121). Bringing the fleet up on a Jetson AGX Thor (sm_110) showed it does
not transfer: 1 of 4 roles came up correct on first boot, and reaching 3 of 4
took four hand-edits to the generated docker-compose.yml —
cortex crash-looped: --kv-cache-dtype=fp8 asserts k_scale > 0, but the
NVFP4 MTP checkpoint carries no calibrated KV scales -> auto
embedder hung: the auto-picked FLASH_ATTN pooling path never answers a
request -> --attention-config={"backend": "TRITON_ATTN"}
reranker killed its engine (cudaErrorLaunchFailure) -> Triton + --enforce-eager;
still returns wrong rankings (#105, verify on GB10: #106)
senses came up clean, no changes
The spec makes the profile the machine contract: which roles are feasible, which
model serves each, and every machine-dependent knob. Spark (default) + Thor ship
supported; Orin / Orin Nano Super are named but unvalidated; an unrecognised card
refuses-or-warns rather than silently applying the Spark profile. Every role gains
a correctness probe — "healthy" must stop meaning "semantically wrong".
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RZNRUXYv84HUQ5ULQ5qJgz
… /spec-to-plan)
Converged plan for the per-machine-profiles spec. Waves are file-disjoint so
they parallelise at merge, not just on paper:
w1 t1 profile schema + spark/thor profiles lobes/profiles/
t2 card detection lobes/runtime/_detect.py
t3 parameterise the compose templates lobes/templates/
t7 per-role correctness probes lobes/assess.py
w2 t4 init applies the resolved profile cli/_commands/init.py
t6 role feasibility -> capabilities/gw lobes/gateway/
w3 t5 doctor/status report the profile cli/_commands/{doctor,status}.py
t10 validate the Thor profile on the box evidence
w4 t11 docs + honest support table docs/
t7 deliberately has no dependency on the profile work: the probes are worth
having even if profiles slip, and t7's acceptance criterion is that the rerank
probe FAILS on Thor today. A probe that only ever passes is theatre.
On Thor the reranker stays served and advertised — it runs, it is just not yet
correct. Its ordering probe is a known failure pointing at #105/#106, which is
where the fix lands; the role is not hidden to make the plan look green.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RZNRUXYv84HUQ5ULQ5qJgz
Two corrections to the converged spec/plan, both from review: 1. The spec's before-state was WRONG. It claimed lobes had no machine-profile concept. It does: lobes/profiles.py already ships MachineProfile / MACHINE_PROFILES (spark/thor/blackwell/generic) and detect_machine(), wired to VLLM_MACHINE and used by switch/benchmark. The real gaps — now stated honestly — are that it is one knob-set per MACHINE not per ROLE; it lacks the knobs that actually mattered on Thor (kv-cache dtype, enforce-eager, model-per-role, role feasibility); the FLEET compose (the default path) ignores it and hardcodes the Spark values; its thor row is an unvalidated guess (status="configured": flashinfer / 32768 / util 0.6) that live Thor testing contradicts; and detect_machine() silently falls back to "generic" rather than admitting it does not know the card. 2. Per-chip knowledge goes behind a STRATEGY PATTERN (new task t12, wave 1, foundational). One module per chip under lobes/machines/ owning its own detection signature, per-role knobs and provenance, plus a small shared registry. Adding a chip = one new file + one registration line — never an edit to a shared table, and a change for one chip cannot break another. Nothing is deleted: the legacy API keeps working, rebuilt FROM the registry. The honesty condition on t12 is that extensibility is PROVEN, not asserted: a test registers a synthetic chip and shows detection, profile resolution and knob rendering all pick it up with zero edits to profiles.py / _detect.py / init.py, with every pre-existing test passing unmodified. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RZNRUXYv84HUQ5ULQ5qJgz
The version-bump script updates pyproject.toml but not uv.lock, so the lock kept claiming 0.40.1 and every `uv run` re-dirtied the working tree. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RZNRUXYv84HUQ5ULQ5qJgz
PR Summary by QodoDocs: spec + plan for per-machine hardware profiles (Spark/Thor first)
AI Description
Diagram
High-Level Assessment
Files changed (8)
|
The 0.40.3 entry had two '### Fixed' headings under the same parent. MD024 is configured siblings_only, so duplicates across releases are fine but duplicates within one are not. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RZNRUXYv84HUQ5ULQ5qJgz
Code Review by Qodo
Context used✅ Tickets:
🎫 verify reranker ORDERING on the DGX Spark GB10 — nothing currently checks it, it may be wrong there too 🎫 reranker returns wrong rankings on Jetson AGX Thor (sm_110) — and crashes the engine under CUDA graphs 🎫 default install should assume a SMALL box, not a 128 GB Blackwell — conservative base profile + a weak default model✅ Compliance rules (platform):
27 rules✅ Skills:
doc-test-alignment, cicd 1.
|
…proposed rework claims (traits, #107 base profile, golden renders) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TJc5yvfweHP2AEccKNeaVd
|
Fixed in cd2dbb7 — the empty
|
|
Fixed in bdd9dbb — the changelog now says ten tasks over four waves (twelve drafted, two rejected during convergence), matching the exported plan markdown and the plan JSON.
|
… small base (#107), upgrade compat Re-converged the frame and re-exported spec + plan on the user's decisions: - Per-machine knowledge keys on the CAUSAL TRAIT (sm_110, unscaled-fp8-KV), not the board name — 3 of the 4 Thor hand-edits trace to sm_110, 1 to the checkpoint, none to 'Thor'; a machine profile is a validated bundle (detection signature + memory budget + model-per-role + traits). - t13: golden rendered compose/.env per shipped profile, byte-diffed in CI — a Thor-side change cannot silently alter Spark's rendering (and vice versa). - t14: an UNKNOWN card warns and serves a conservative small base (no 27B) instead of refusing — the unknown-card slice of #107; the rest stays deferred. - t15: upgrading lobes-cli never breaks an existing scaffold (zero bytes changed in the deployment dir; old env names honoured; re-init is diffed and --apply-gated). - Parked as tracked risks on t3: verify on the GB10 whether the fp8-KV crash is checkpoint-driven (shared fix, not a thor trait) and whether VLLM_ATTENTION_BACKEND is truly dead on its pinned image. - Packaging per #107 recorded: profiles ship in the wheel; no pip extras. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TJc5yvfweHP2AEccKNeaVd
|
…spec/brain-shapes Resolves the every-PR-bump collision on CHANGELOG.md / pyproject.toml / uv.lock by taking main's side (0.41.0); the branch's own 0.40.4 bump is dropped and re-applied on top as 0.41.1. #110 landed the #108 profile substrate this spec+plan composes on. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01U9ybFURhQxT9UpCgQNVL67
#110 merged mid-flight (the #108 implementation, 0.41.0), so the frame and plan are re-cut against what actually shipped: the dropped-lobe contract is now flag-not-omit (capabilities feasible:false, /v1/models omits, generate lane 404 role_infeasible — c11/h3 rejected, c17/h13 recaptured and covered by t5); shapes own all six Colleague roles per user decision (stt/tts are first-class shape members over the audio overlay — c18, t1); shape data files are TOML matching lobes/profiles/builtin/; t1/t3/t5 instructions now name the landed modules instead of 'when it lands'. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01U9ybFURhQxT9UpCgQNVL67



Docs only — spec and plan, no implementation. This PR is the converged
/thinkspec and/spec-to-planplan for per-machine hardware profiles. The code is deliberately not here: it was built, reviewed, and then reverted so the design can be agreed before implementation lands.Why
The fleet was brought up on a Jetson AGX Thor (aarch64, sm_110, 122 GB unified, CUDA 13.0) — not the DGX Spark GB10 (sm_121) the templates are tuned for. The shipped configuration scored 1 of 4 roles correct on first boot:
senses(Gemma 4 12B)cortex(27B NVFP4 + MTP)assert layer.k_scale > 0.0--kv-cache-dtype=auto— the checkpoint carries no calibrated KV scales (kv_cache_quant_algo: null), so fp8 cannot workembedder/healthstayed green throughout--attention-config={"backend": "TRITON_ATTN"}— the auto-picked FLASH_ATTN pooling path hangsrerankerCUDA error: unspecified launch failure--enforce-eagerstops the crash; it still returns wrong rankings (#105, verify on GB10: #106)Reaching 3 of 4 took four hand-edits to the generated compose. Every one was found by crashing into it.
The
cortexfp8 failure is not Thor-specific — it would fail identically on a GB10 with this vLLM nightly.What the spec commits to
cortexrather than only disabling it), and every machine knob — util, context, quantization, KV dtype, attention backend, enforce-eager, max-num-seqs.lobes/machines/<chip>.py) owning its own detection signature, knobs and provenance, plus a small registry. Adding a chip = one new file + one registration line — never an edit to a shared table, and a change for one chip cannot break another. Nothing is deleted:MachineProfile/MACHINE_PROFILES/detect_machine()keep working, rebuilt from the registry.embedmust rank a paraphrase above an unrelated string;rerankmust put the relevant document first;cortexmust answer a known-answer question. A role that is/health-green but semantically wrong must fail. Today nothing in lobes checks rerank ordering — which is exactly how a reranker that ranks "Bananas are yellow" above the correct document passes every check we have.Correction in this PR
The first cut of the spec was wrong and the third commit fixes it. It claimed lobes had no machine-profile concept. It does —
lobes/profiles.pyalready shipsMachineProfile/MACHINE_PROFILES(spark/thor/blackwell/generic) anddetect_machine(). The real gaps are narrower and now stated honestly: one knob-set per machine, not per role; missing exactly the knobs Thor needed; the fleet compose ignores it entirely; itsthorrow is an unvalidated guess (status="configured": flashinfer / 32768 / util 0.6) that live testing contradicts; anddetect_machine()silently falls back togenericinstead of admitting it doesn't know the card.Plan
Eleven tasks, four file-disjoint waves.
t12(strategy pattern) is foundational and lands first. Its honesty condition is that extensibility is proven, not asserted — a test registers a synthetic chip and shows detection, profile resolution and knob rendering all pick it up with zero edits toprofiles.py/_detect.py/init.py, with every pre-existing test passing unmodified.The Thor reranker stays served and advertised — it runs, it is simply not yet correct. Its ordering probe is recorded as a known failure pointing at #105 / #106, rather than the role being hidden to make the plan look green.
Related
Test plan
Docs only: no source changes. Full suite green at the 1188 baseline;
afi cli doctor --strictpasses; version bumped 0.40.1 → 0.40.3.🤖 Generated with Claude Code
https://claude.ai/code/session_01RZNRUXYv84HUQ5ULQ5qJgz