Skip to content

feat: Thor hosts Qwen3.6-35B-A3B (unsloth) as the eighth role 'worker' — multimodal fast doer (0.54.6) - #162

Merged
OriNachum merged 34 commits into
mainfrom
spec/thor-worker-qwen3.6-35b-a3b
Jul 31, 2026
Merged

feat: Thor hosts Qwen3.6-35B-A3B (unsloth) as the eighth role 'worker' — multimodal fast doer (0.54.6)#162
OriNachum merged 34 commits into
mainfrom
spec/thor-worker-qwen3.6-35b-a3b

Conversation

@OriNachum

Copy link
Copy Markdown
Contributor

What

Converged devague spec + plan for the worker role: Thor moves off the Gemma 4 31B muse and hosts unsloth/Qwen3.6-35B-A3B-NVFP4 — a fast ground-work doer lobe with self-draft MTP.

  • Spec: docs/specs/2026-07-31-thor-worker-lobe-qwen3-6-35b-a3b.md (frame: 19 confirmed claims, 17 confirmed honesty conditions, 8 scope entries with provenance)
  • Plan: docs/plans/2026-07-31-thor-worker-lobe-qwen3-6-35b-a3b.md (9 tasks, 5 waves, 4 first-class risks)

Key decisions (operator-confirmed)

  • worker is a doer: repo_action allowed — the first role besides cortex permitted to act; forbidden only final_decision/security_decision.
  • Tier order: minor < multimodal < worker < muse < main; worker's role name is its tier, like muse.
  • Muse goes dormant: unhosted mesh-wide, no MUSE_PEER_ORIGIN, model=muse 404s role_infeasible with no referral. Code/shape/catalog stay in-tree (cite-don't-delete).
  • Measurement-gated (c20): gpu_mem_util/max_model_len, the sm_110 MoE backend, and the MTP verdict are measured by a live boot on the physical Thor before any value is committed — the thor-muse 0.40→0.55 lesson. Role ships DECLARED/UNVALIDATED until the acceptance transcript lands under docs/evidence/ (spec+plan: lobes fits the machine it lands on — per-machine hardware profiles #108).

Checkpoint facts (verified on HF 2026-07-31)

MoE 35B / ~3B active, 262144-token native (→1M), ships its own MTP draft module (--speculative-config '{"method": "mtp", "num_speculative_tokens": 2}'). Distinct from the in-catalog mmangkad sibling (32K native, MTP not carried). The card's flashinfer_b12x + sm_121a MoE advice is Spark-specific — Thor's sm_110 backend is a live measurement (risk r1).

Not in this PR

Implementation (waves t1–t9) follows via /assign-to-workforce; t7/t9 run on the physical Thor.

🤖 Generated with Claude Code

https://claude.ai/code/session_01VqwW6JvnPf4w7tydhFHwHj

OriNachum and others added 3 commits July 31, 2026 10:06
…devague /think)

Converged frame: Thor moves off the Gemma 4 31B muse and hosts
unsloth/Qwen3.6-35B-A3B-NVFP4 as 'worker' — a fast ground-work DOER
(repo_action allowed) with self-draft MTP. Muse goes dormant in-tree.
Budget/MoE-backend/MTP values are measurement-gated (decision c20).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VqwW6JvnPf4w7tydhFHwHj
…evague /spec-to-plan)

t1 catalog+tiers → t2 roles / t3 gateway → t4 template / t5 shapes /
t6 CLI / t8 docs → t7 live Thor measurement → t9 acceptance run.
Four non-blocking risks on t7 (sm_110 MoE backend, MTP loadability,
physical-box-only, nightly-pin kernel coverage).

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

Copy link
Copy Markdown

PR Summary by Qodo

Spec/plan: add Thor “worker” role for unsloth Qwen3.6-35B-A3B (0.54.6)

📝 Documentation ⚙️ Configuration changes 🕐 40+ Minutes

Grey Divider

AI Description

• Add exported spec + plan defining Thor’s new opt-in worker role and responsibilities.
• Document measurement-gated rollout tasks (catalog/roles/gateway/compose/shape/CLI/docs/acceptance
 evidence).
• Bump project version to 0.54.6 and record the change in CHANGELOG.
Diagram

graph TD
A["Spec (docs/specs)"] --> B["Plan (docs/plans)"] --> C["Future PR chain"] --> D["Live Thor measure"] --> E["Evidence transcript"]
C --> F["Version+Changelog"]
subgraph Legend
direction LR
_spec["Doc artifact"] ~~~ _impl["Implementation step"] ~~~ _evi["Evidence"]
end
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Split version bump/changelog into a separate PR
  • ➕ Keeps spec/plan PR purely documentary
  • ➕ Avoids tying semantic versioning to non-code artifacts
  • ➖ Conflicts with the stated operating rule to bump every PR in the chain
  • ➖ Adds overhead (extra PR/review) for minimal risk reduction
2. Keep spec/plan only in Markdown (omit .devague exports)
  • ➕ Reduces repository noise and duplicated content
  • ➕ Simplifies browsing for humans
  • ➖ Loses structured data useful for tooling/automation around claims/tasks/risks
  • ➖ Harder to enforce traceability between requirements and tasks
3. Publish as an RFC/issue instead of in-repo spec+plan
  • ➕ Easier iterative discussion and comment threading
  • ➕ Avoids merging long documents before implementation is underway
  • ➖ Harder to keep implementation and acceptance artifacts tightly coupled to source control
  • ➖ Less discoverable for future maintainers browsing the repo

Recommendation: Keep the current approach. Given the project’s workflow (spec+plan as first-class repo artifacts, version bump per PR chain, and measurement-gating before committing operational parameters), bundling the exported spec/plan with the 0.54.6 changelog/version update is coherent and minimizes process drift. The main review focus should be on role contract clarity (responsibilities/forbidden), the opt-in/infeasible-by-default guarantees, and whether the plan’s acceptance criteria are sufficiently falsifiable.

Files changed (8) +1031 / -3

Documentation (5) +1028 / -0
thor-worker-lobe-qwen3-6-35b-a3b.jsonAdd exported devague frame for worker role on Thor +447/-0

Add exported devague frame for worker role on Thor

• Adds the structured spec frame capturing claims, honesty conditions, scope exploration, and the measurement-gated decision for the new worker role hosted on Thor.

.devague/frames/thor-worker-lobe-qwen3-6-35b-a3b.json

thor-worker-lobe-qwen3-6-35b-a3b.jsonAdd exported devague plan (tasks/waves/risks) for worker rollout +384/-0

Add exported devague plan (tasks/waves/risks) for worker rollout

• Adds the structured plan with nine tasks, dependencies, acceptance criteria, and explicit physical-Thor measurement/acceptance risks for the worker rollout.

.devague/plans/thor-worker-lobe-qwen3-6-35b-a3b.json

CHANGELOG.mdAdd 0.54.6 changelog entry for worker spec+plan +16/-0

Add 0.54.6 changelog entry for worker spec+plan

• Documents the new worker role spec+plan, including role contract highlights, tier ordering, muse dormancy posture, and measurement gating.

CHANGELOG.md

2026-07-31-thor-worker-lobe-qwen3-6-35b-a3b.mdAdd human-readable build plan for worker role rollout +91/-0

Add human-readable build plan for worker role rollout

• Introduces the Markdown plan detailing tasks t1–t9, acceptance criteria, and key implementation risks, including physical Thor measurement gates.

docs/plans/2026-07-31-thor-worker-lobe-qwen3-6-35b-a3b.md

2026-07-31-thor-worker-lobe-qwen3-6-35b-a3b.mdAdd worker role spec for Thor (contract + measurement gating) +90/-0

Add worker role spec for Thor (contract + measurement gating)

• Introduces the Markdown spec defining before/after state, role responsibilities and forbidden responsibilities, opt-in behavior expectations, and required acceptance evidence.

docs/specs/2026-07-31-thor-worker-lobe-qwen3-6-35b-a3b.md

Other (3) +3 / -3
currentPoint devague current frame to thor-worker spec +1/-1

Point devague current frame to thor-worker spec

• Updates the devague pointer to the new thor-worker lobe frame slug, making it the active spec context.

.devague/current

current_planPoint devague current plan to thor-worker plan +1/-1

Point devague current plan to thor-worker plan

• Updates the devague pointer to the new thor-worker lobe plan slug, making it the active planning context.

.devague/current_plan

pyproject.tomlBump project version to 0.54.6 +1/-1

Bump project version to 0.54.6

• Increments the package version from 0.54.5 to 0.54.6 to match the changelog and PR chain conventions.

pyproject.toml

@qodo-code-review

qodo-code-review Bot commented Jul 31, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📜 Skill insights (0)

Context used
✅ Compliance rules (platform): 80 rules

Grey Divider


Remediation recommended

1. uv.lock version stale ✓ Resolved 🐞 Bug ☼ Reliability
Description
pyproject.toml bumps lobes-cli to 0.54.6 but uv.lock still records the editable lobes-cli package as
0.54.5, leaving the lockfile inconsistent with the project metadata. This can cause uv sync to
rewrite the lockfile (or fail in locked/frozen modes) and undermines reproducible installs.
Code

pyproject.toml[3]

+version = "0.54.6"
Relevance

●●● Strong

Past version bumps update uv.lock too; repo enforces version/lock alignment (PRs #67, #124, #133).

PR-#67
PR-#124
PR-#133

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The PR updates the project version to 0.54.6, but the committed uv.lock still lists the editable
lobes-cli package at 0.54.5. CI runs uv sync, indicating the lockfile is part of the expected
dependency workflow and should be kept consistent.

pyproject.toml[1-4]
uv.lock[441-445]
.github/workflows/tests.yml[31-35]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`pyproject.toml` was bumped to version `0.54.6`, but `uv.lock` still contains the root editable package entry for `lobes-cli` at `0.54.5`. This makes the lockfile stale/inconsistent and can lead to lockfile rewrites during `uv sync` or failures if the project (now or later) runs `uv` in a locked/frozen mode.

### Issue Context
The repo uses `uv sync` in CI, so keeping `uv.lock` aligned with `pyproject.toml` helps preserve reproducibility and avoids surprising lockfile churn.

### Fix
1. Run the repo’s standard uv workflow to refresh the lockfile (typically `uv lock` or `uv sync` which updates the lock).
2. Verify `uv.lock` now shows `lobes-cli` at `0.54.6`.
3. Commit the updated `uv.lock`.

### Fix Focus Areas
- pyproject.toml[1-4]
- uv.lock[441-445]
- .github/workflows/tests.yml[31-35]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

To customize comments, go to the Qodo configuration screen, or learn more in the docs.

Qodo Logo

Comment thread pyproject.toml
OriNachum and others added 16 commits July 31, 2026 11:37
…ear + tier

Adds the `worker` capability tier (thor-worker-lobe plan, t1): a new catalog
entry for unsloth/Qwen3.6-35B-A3B-NVFP4 — an MoE checkpoint that, unlike the
existing mmangkad/Qwen3.6-35B-A3B-NVFP4 candidate, ships its own MTP draft
module baked in (config.json: mtp_num_hidden_layers=1, quantization ignore
pattern "re:^mtp.*"). Fields verified against the checkpoint's actual
config.json (native_max_model_len=262144, quantization="compressed-tensors"
from quant_method) rather than card prose; hf_quant_config.json 404s (that
file is a modelopt-export convention, absent from this compressed-tensors
export). speculative_config matches the README's documented serve command
verbatim.

`TIER_ROLE` (catalog.py) and its mirror in gateway/_pressure_policy.py both
gain "worker": "worker", positioned so the derived ascending capability order
becomes minor < multimodal < worker < muse < main. runtime._parser.infer_parser
already resolves the id to qwen3_coder via the existing "qwen3.6" marker — no
_parser.py change needed.

Extends the existing MTP-carrier test guard (test_catalog.py) with an
explicit, cited allow-list for checkpoints that carry their own MTP draft
weights without an "-MTP" id suffix, since this entry is the first such case.

Full suite: 2598 passed, 15 skipped. black/isort/flake8/bandit clean.
unsloth/Qwen3.6-35B-A3B-NVFP4 catalog entry (role_hint=worker, 262144
native, compressed-tensors, self-hosted MTP); TIER_ROLE + pressure-policy
tiers gain worker at minor<multimodal<worker<muse<main.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VqwW6JvnPf4w7tydhFHwHj
Mirrors muse end-to-end in lobes/gateway/_config.py (thor-worker-lobe plan,
t3): _DEFAULT_WORKER, FEASIBLE_ENV/PEER_ORIGIN_ENV/PEER_PROXY_ENV/
PEER_API_KEY_ENV all gain a "worker" entry riding the same WORKER_* channel
convention, OPT_IN_BACKENDS becomes frozenset({"muse", "worker"}) so an
unwired worker is honestly infeasible by default (model=worker 404s
role_infeasible, never falls back), and build_config gains the
WORKER_BASE_URL-gated backend block.

Tests mirror muse's coverage across the four owned files: BASE_URL-gated
wiring (test_gateway_config_wiring.py), default-infeasible-when-unwired +
explicit-FEASIBLE-wins (test_gateway_feasibility.py), the four peer channels
(test_gateway_config_proxy.py), and — since worker's own backend wiring
already threads through the existing data-plane proxy machinery with no
server.py change needed — a wired-but-dropped forwarding case
(test_gateway_proxy.py).

t1 (catalog + TIER_ROLE) is already merged into this branch; t2 (roles.py
registry) is not, and is intentionally out of scope here.
WORKER_BASE_URL-gated backend; worker joins OPT_IN_BACKENDS (unwired =>
infeasible); WORKER_* on the four peer channels. Mirrors muse.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VqwW6JvnPf4w7tydhFHwHj
Widen lobes.roles + lobes.profiles.schema to the eighth Colleague-facing
role, `worker` (Qwen3.6-35B-A3B NVFP4, the fast ground-work DOER), added
structurally exactly like the seventh role `muse`:

- roles.ROLES gains "worker" (after muse, before embedder); every ROLE_*
  registry dict gets a worker entry: ROLE_BACKEND["worker"]="worker",
  ROLE_ROLE_HINT["worker"]="worker", ROLE_PATH["worker"]=/v1/chat/completions,
  ROLE_MAX_MODEL_LEN_ENV["worker"]="WORKER_MAX_MODEL_LEN".
- build_role_registry's gateway-fronted generate loop gains "worker" — it
  flows through the SAME #92/#115 ready/feasible/loaded clamp as muse, so an
  unwired worker (its gateway backend is sibling task t3) is honestly
  loaded=False, ready=False (clamped even against a stray live True signal).
- The doer contract: ROLE_RESPONSIBILITIES["worker"] carries
  execution/ground_work/bulk_transform/drafting PLUS tool_use AND repo_action
  — worker is the first role besides cortex permitted repo_action (it may ACT
  on the repo under cortex's direction). ROLE_FORBIDDEN["worker"] ==
  ("final_decision", "security_decision") — it never decides.
- schema.ROLES gains "worker" so a Profile may carry worker's full per-machine
  knob set; the unknown-role override rejection is unchanged.

Tests added/updated in the three owned files (test_roles.py,
test_roles_proxied.py, test_shapes.py schema-ROLES part). Sibling wiring
(gateway backend + OPT_IN_BACKENDS t3, profiles render/shapes ROLE_ENV_PREFIX/
ROLE_SERVICE/OPT_IN_CORE_ROLES + thor-worker-lobe shape, measure, capabilities
goldens) is intentionally out of scope and lands in later waves.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016hSuy5fv3zbCyjeAQ6b6oF
worker wired into every ROLE_* dict mirroring muse; doer contract
(repo_action allowed, forbidden final_decision/security_decision);
schema ROLES gains worker. NOTE: tree needs the opt-in-core + per-role
map integration (next commit) to be green.

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

The 8th-role vocabulary widening (t2) is inseparable from its opt-in-core
designation (t5): worker must be in OPT_IN_CORE_ROLES or it reads as a
default-hosted role and the goldens break. Executed t5 inline so the tree
greens atomically with t2:
- shapes.OPT_IN_CORE_ROLES += worker; base.toml vetoes worker on unknown cards
- per-role maps gain worker: render.ROLE_ENV_PREFIX, shape_render.ROLE_SERVICE
  + OPT_IN_CORE_ACTIVATION_ENV/COMPOSE_PROFILE, roles_measure family
- goldens regenerated: recognized-card renders byte-identical; base-card
  renders gain WORKER_FEASIBLE=false exactly like MUSE_FEASIBLE=false

Multimodal reconciliation (operator decision 2026-07-31): the checkpoint is
image+video (config.json vision_config, image/video token ids, no audio), so
worker is served MULTIMODAL — a seeing doer. catalog shape notes the ViT;
worker responsibilities gain image_understanding/video_understanding; the
compose lane must NOT pass --language-model-only (t4).

Test-expectation updates + up.py service map follow in the next commit.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VqwW6JvnPf4w7tydhFHwHj
…llow-through)

The worker checkpoint is multimodal (image+video); t9's acceptance was
text-only. Added three honest-outcome live probes: ground-truth image (with
negative control, like senses), video, and a thinking+coding task with MTP
active — each recording the real verdict, degrading the multimodal claim
honestly if vision/video does not serve (the #101 risk).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VqwW6JvnPf4w7tydhFHwHj
… length, context measurement

t9: TTFT + decode_tps + derived ms/token + prefill_tps (MTP on vs off with
draft-acceptance), open-ended writing-length + sustained decode, and a
long-context prefill probe confirming the effective served window.
t7: KV pool size + concurrency multiple at the served context (thor-muse
pattern) so served context is a measured capacity, not a flag value.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VqwW6JvnPf4w7tydhFHwHj
The worker role (unsloth/Qwen3.6-35B-A3B-NVFP4, opt-in-core multimodal
doer) landed its plumbing (roles.py, schema.py, gateway _config.py,
catalog.py, shapes.py, render.py, roles_measure.py) but `lobes up`'s own
hardcoded ROLE_SERVICE dict and a few CLI help strings still lacked it,
and the widened 8-role vocabulary broke a set of test expectation
literals still pinned to 7 roles.

- lobes/cli/_commands/up.py: add "worker": "vllm-worker" to ROLE_SERVICE
  (mirrors "muse": "vllm-muse"); add worker to the docstring's
  role->service table and the `role` argument's help string.
- lobes/cli/_commands/capabilities.py, overview.py, measure.py: bump the
  hardcoded "seven first-class roles (cortex/senses/muse/embedder/...)"
  help/docstring prose to eight roles with worker in capability order.
- tests/test_profile_schema.py, test_profile_render.py: ROLES /
  ROLE_ENV_PREFIX literals gain worker.
- tests/test_shapes.py: COLLEAGUE_ROLES / SHAPE_ROLES gain worker;
  OPT_IN_CORE_ROLES == ("muse", "worker"); DEFAULT_HOSTED_ROLES stays
  worker-free (opt-in-core is excluded from the default-hosted set).
- tests/test_dropped_lobe_honesty.py: spark-lobe/thor-lobe CLI/gateway
  agreement dicts gain "worker": False (unwired on both shapes).
- tests/test_roles.py: worker's feasible flag flips True -> False (an
  unwired opt-in-core role is honestly infeasible by default, exactly
  like muse - OPT_IN_BACKENDS); the responsibilities assertions gain
  image_understanding/video_understanding (worker is multimodal).
- tests/test_cli_capabilities.py: `lobes endpoint` role-coverage dict
  gains worker (resolves to the gateway URL, same as muse, despite
  being infeasible here).
- tests/test_cli_up.py: rename the ROLE_SERVICE-coverage test off a
  stale "six roles" count now that adding worker makes it pass again.
- tests/test_cli_measure.py: _FAMILY_BY_ROLE gains worker (family
  "llm"); rename off the stale "six roles" count.
- tests/test_shape_contract_matrix.py: worker is opt-in-core with no
  hosting shape built yet, so every built-in shape now drops it too -
  add a (<shape>, "worker") cell per shape alongside each existing
  (<shape>, "muse") cell, plus worker's model id and *_BASE_URL/
  *_SERVED_NAME wire-env keys in the shared helper dicts.
- tests/test_proxy_integration.py: regenerate the golden /capabilities
  byte literal with a "worker" entry (infeasible, unloaded, endpoint
  resolves to the gateway origin) inserted in ROLES order between
  "muse" and "embedder". Verified against the real
  build_role_registry() payload for the golden env before pasting it
  in, not just green-until-it-passes.

Left red on purpose: test_shape_goldens.py::
test_role_service_constants_exist_in_compose_templates still fails
because the vllm-worker compose service doesn't exist yet - that's a
parallel task's (t4) scope, not touched here.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016hSuy5fv3zbCyjeAQ6b6oF
… suite

up.py ROLE_SERVICE gains worker; capabilities/overview/measure prose bumped
to eight roles; all shape/vocab/contract/CLI test expectations updated for
the worker vocabulary + multimodal responsibilities; proxy capabilities
golden regenerated from the real registry. Only test_shape_goldens'
compose-service check remains red (t4 adds the vllm-worker service).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VqwW6JvnPf4w7tydhFHwHj
…3.5 MoE)

The eighth Colleague role `worker` (unsloth/Qwen3.6-35B-A3B-NVFP4) now has a
real compose service. Mirrors the vllm-muse opt-in-core precedent (profile
`worker`, no host port, embed/rerank health-gated boot ordering, gateway
backend wired only via WORKER_BASE_URL) but adapted for the Qwen multimodal
MoE:

- Rides the SAME Qwen/vLLM nightly lane (VLLM_NIGHTLY_IMAGE) as the primary,
  overridable via WORKER_IMAGE — NOT the Gemma lobes/vllm-gemma4:local tag.
- Served MULTIMODAL (image+video): deliberately NO --language-model-only.
- --quantization=compressed-tensors (the checkpoint's own quant_method).
- Baked-in self-draft MTP (--speculative-config method=mtp, no external draft).
- Qwen parser pair: --tool-call-parser=qwen3_coder --reasoning-parser=qwen3.
- --moe-backend overridable (flashinfer_b12x is Spark's sm_121 pick; Thor
  sm_110 UNCONFIRMED until the t7 live boot). GPU util 0.30 is a PLACEHOLDER
  measured live at t7, like thor-muse's 0.55.

Gateway environment gains the WORKER_* passthroughs (BASE_URL / SERVED_NAME /
MAX_MODEL_LEN / FEASIBLE / PEER_ORIGIN / PEER_PROXY / PEER_API_KEY), mirroring
muse. env.example documents every WORKER_* knob (opt-in, commented-out block).

Tests: new tests/test_worker_compose.py (profile gating, Qwen-lane image,
parser pair, self-draft MTP, no --language-model-only, gateway wiring, plus a
live `docker compose config` render). Greens
test_shape_goldens::test_role_service_constants_exist_in_compose_templates.
Recomputed the tool-parser tripwire (new vllm-worker + changed gateway hash;
every other service byte-identical) and regenerated the template-defaults
golden for the new ${WORKER_*:-default} surface.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016hSuy5fv3zbCyjeAQ6b6oF
vllm-worker on the Qwen nightly lane (NOT gemma image): compressed-tensors,
--max-model-len 262144, self-draft MTP, qwen3_coder+qwen3 parser pair, NO
--language-model-only (serves image+video). WORKER_* knobs in env.example +
gateway passthroughs. Greens test_shape_goldens; tripwires (tool-parser
service set, template-defaults golden) reconciled.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VqwW6JvnPf4w7tydhFHwHj
…(t8)

Documents the thor-worker-lobe plan's eighth Colleague role (unsloth/
Qwen3.6-35B-A3B-NVFP4, the fast ground-work DOER, first non-cortex role
permitted repo_action) across colleague-stack.md, deployment-shapes.md,
gateway-fleet.md, openai-api.md, machine-profiles.md, qwen3.6-35b-a3b-nvfp4.md,
gemma-4-31b-nvfp4.md, and CLAUDE.md. Every "cortex is the only lobe that
acts" style claim is updated to reflect worker's narrower repo_action grant.
Muse is documented dormant/unhosted mesh-wide (the Thor moved to hosting
worker instead) while its role, catalog entry, and thor-muse shape stay
in-tree. CLAUDE.md's stale "pressure degrades to minor" wording is corrected
to match the shipped code (429 shed, no degrade-to-minor substitution).
Worker's shape/compose-service/live-measured-budget pieces are described as
forthcoming (thor-worker-lobe plan tasks t4/t6/t7) — no number is invented.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016hSuy5fv3zbCyjeAQ6b6oF
colleague-stack/deployment-shapes/gateway-fleet/qwen3.6-35b-a3b docs +
CLAUDE.md updated to eight roles; worker's widened division of labour
(may act) recorded; muse documented dormant/unhosted (in-tree,
cite-don't-delete); stale 'degrades to minor' wording fixed to the
429-shed behaviour. Budget/MoE/MTP kept declared/UNVALIDATED (t7).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VqwW6JvnPf4w7tydhFHwHj
lobes up worker is wired (t6) — only the thor-worker hosting shape is
forthcoming (t7); CHANGELOG 0.54.6 now describes the shipped multimodal
worker role + muse dormancy + the pressure-shed doc fix.

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

Copy link
Copy Markdown
Contributor Author

Implementation landed — code side complete, fully green

The fannable waves (t1–t6, t8) are merged on this branch; the suite is 2678 passed / 0 failed, lint clean (black/isort/flake8/bandit), and the afi cli doctor --strict rubric gate passes.

What shipped

The worker role — an 8th first-class Colleague role serving unsloth/Qwen3.6-35B-A3B-NVFP4, wired end-to-end:

  • catalog gear + tier minor < multimodal < worker < muse < main (fields read from the checkpoint's real config.json, not card prose)
  • eight-role registry (roles.py + schema.py) with worker's doer contract
  • opt-in-core gateway backend (WORKER_BASE_URL; unwired ⇒ infeasible, never a silent fallback) + the four peer channels
  • shape machinery: OPT_IN_CORE_ROLES += worker, base.toml unknown-card veto, goldens byte-identical on recognized cards
  • profile-gated vllm-worker compose service on the Qwen nightly lane (compressed-tensors, qwen3_coder+qwen3 parser pair, self-draft MTP)
  • lobes up worker verb + capabilities/status/overview/measure (auto-derive from ROLES) + full docs

Mid-flight correction (operator catch)

The checkpoint is multimodal (image+video)config.json carries a ViT + image/video token ids. Reconciled before the dependent tasks ran: worker is served multimodal (no --language-model-only) — a seeing doer distinct from senses (which perceives but may not act); responsibilities gained image_understanding/video_understanding.

Muse

Dormant/unhosted mesh-wide (model=muse 404s role_infeasible, no referral); role/gear/thor-muse shape stay in-tree (cite-don't-delete).

NOT in this PR — the on-box phase (DECLARED/UNVALIDATED, #108)

  • t7 live boot on the physical Thor: measured gpu_mem_util/max_model_len, the sm_110 MoE backend, MTP acceptance, KV-pool/concurrency capacity → the thor-worker shape TOML.
  • t9 acceptance run: live image + video + thinking-coding probes and the full perf profile (TTFT, decode tok/s + per-token latency, writing length, effective context) → docs/evidence/.

No performance number or budget value is committed until t7/t9 measure it live.

🤖 Generated with Claude Code

https://claude.ai/code/session_01VqwW6JvnPf4w7tydhFHwHj

@OriNachum OriNachum changed the title spec+plan: Thor hosts Qwen3.6-35B-A3B (unsloth) as the eighth role, 'worker' (0.54.6) feat: Thor hosts Qwen3.6-35B-A3B (unsloth) as the eighth role 'worker' — multimodal fast doer (0.54.6) Jul 31, 2026
Live boot on the physical Jetson AGX Thor (2026-07-31,
docs/evidence/2026-07-31-accept-worker-thor.txt):
- boots + serves at util 0.45 / 262144: KV 41.78 GiB = 14.07x concurrency,
  weights 24.81 GiB; MTP self-draft loads + accepts 89.1%; decode 50.8 tok/s
  (thinking) / 73.5 sustained; image intake correct (red/blue + neg control);
  model=worker routes via gateway, model=muse 404s role_infeasible.
- KEY FIX: the vllm-worker lane must NOT force --moe-backend on sm_110 (every
  forced NVFP4 backend refused; vLLM auto-selects TRITON + a modular NVFP4
  kernel per path). Template no longer forces it; catalog moe_backend=.

thor-worker.toml lands with MEASURED budget; catalog status load-tested;
init --shape gains thor-worker; goldens + contract-matrix + compose tests
reconciled. Video intake still unverified (image proven).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VqwW6JvnPf4w7tydhFHwHj
Real Spark-webcam clip through worker's video_url path: 1572 video tokens
decoded, accurate scene/subject/motion description (finish=stop), NOT a
#101-style drop. Image was already proven; video was the last open capability.
worker is now a fully-validated multimodal (image+video) seeing doer.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VqwW6JvnPf4w7tydhFHwHj
OriNachum and others added 5 commits July 31, 2026 14:49
The 4 genuinely-open S8997 issues: test_chatterbox_pcm16.py (numpy-available
toggle) and test_readiness_peer_probe.py (capturing-handler class attrs) now
use monkeypatch (auto-restored) instead of manual save/restore.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VqwW6JvnPf4w7tydhFHwHj
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VqwW6JvnPf4w7tydhFHwHj
python:S3776 was the only genuinely open SonarCloud issue on
lobes/realtime/tts_client.py (18 against the 15 limit, line 330); the other
four issues in the same historical batch (S8513 x2, S8572, S8786) were
already fixed and merged on main in #157 (0.54.3) — confirmed via a live
SonarCloud query before touching anything, so this change is scoped to
S3776 only.

Extracted the per-attempt try/except tree out of _synthesize_single into a
new _attempt_synthesize() helper, plus a tiny _retry_or_give_up() shared by
its two transient-network-error arms (ConnectError, ReadTimeout). The
retry loop in _synthesize_single now just awaits the helper and checks the
_Retry sentinel — no other control flow moved. Verified behavior-identical:
same log messages, same t0/elapsed placement (client construction before
the timer, exactly as before), same retry-once-then-give-up semantics, same
log.exception in the catch-all arm.

Verified locally with flake8-cognitive-complexity (matches SonarCloud's 18
exactly pre-change; 6 post-change for _synthesize_single, all other
functions unchanged) since a live Sonar rescan isn't available from this
worktree. black/isort/flake8/bandit clean; 2609 passed / 11 skipped on the
full suite (skips are all live-deployment gated, unrelated), including the
httpx-gated tts_client tests run with `--with httpx --with numpy` to
exercise this file's own logic directly rather than relying on the
(correct) offline skip.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VqwW6JvnPf4w7tydhFHwHj
…r) into the worker PR

# Conflicts:
#	CHANGELOG.md
#	pyproject.toml
OriNachum and others added 7 commits July 31, 2026 15:24
SonarCloud python:S9073 flagged eight `assert A and B` composite
assertions in test_readiness_peer_probe.py and test_proxy_integration.py.
Split each into separate top-level asserts so a failure pinpoints which
half tripped, with no change in what's actually being verified.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016hSuy5fv3zbCyjeAQ6b6oF
SonarCloud python:S9073 flags `assert A and B` — split each top-level
`and` in an assert statement into separate asserts across
test_roles.py, test_worker_compose.py, and test_init_shape.py so a
failure pinpoints which half broke. Nested `and`s inside `not (...)`
or `any(... for ...)` are untouched — they aren't the composite
top-level assertion the rule targets.

python:S9083 flags empty-parens decorators; drop the `()` from
`@pytest.fixture()` in test_cli_measure.py.

Behavior-identical: same conditions asserted, same fixture.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016hSuy5fv3zbCyjeAQ6b6oF
Each `assert A and B` becomes two separate asserts so a failure
pinpoints which half failed. Behavior-identical; all 47 tests still
pass.
@sonarqubecloud

Copy link
Copy Markdown

@OriNachum
OriNachum merged commit ea04e1c into main Jul 31, 2026
10 checks passed
@OriNachum
OriNachum deleted the spec/thor-worker-qwen3.6-35b-a3b branch July 31, 2026 12:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant