Plugin install, replacement, and uninstall clear process memos through
registerPluginMetadataProcessMemoLifecycleClear, but four executable-
authority caches never registered, so retired plugin callbacks kept
executing after the registry moved on:
- createConfigScopedPromiseLoader (document/web-content extractor lists)
now self-registers its clear at the factory, so no caller can leak
resolved plugin callbacks past a lifecycle change.
- Provider policy surface maps (bundled + external, including cached
negative entries) clear on lifecycle changes.
- Public surface loader now drops module exports, loader closures, and
native require cache entries, not just resolved locations.
- SDK facade loader registers the same clear for facade exports and
loader state; imported-plugin history is preserved as diagnostics.
The tracked-roots + native-require eviction pattern from provider
discovery is extracted into clearPluginModuleLoaderLifecycleCache and
reused by provider discovery, doctor contracts, the public surface
loader, and the facade loader, removing two near-copies.
Regression tests fail pre-fix: replaced or uninstalled plugin callbacks
must not run after clearPluginMetadataLifecycleCaches, proven down to
on-disk artifact replacement through the native require chain.
* fix(control-ui): stop config form save from corrupting 64-bit id strings
Saving the schema-driven config form coerced every numeric-looking string
to a JS number before submission. For union-typed fields such as
tools.elevated.allowFrom.* (anyOf: string | number), string entries
holding 64-bit ids (Discord/Telegram snowflakes) were rewritten through
Number(), which rounds past 2^53:
"1048113311314608148" -> 1048113311314608100. The corruption also hit
untouched fields, because serialization coerces the whole form, so merely
saving an unrelated setting silently broke elevated-approval allowlists
(fail-closed: the real user id no longer matched).
Two guards fix this:
- coerceFormValues keeps a string that already satisfies a string variant
of an anyOf/oneOf union instead of parsing it into another variant's
number.
- coerceConfigFormNumberString refuses lossy integer parses: plain
integer text beyond Number.MAX_SAFE_INTEGER that does not round-trip
through BigInt stays a string, so pure number/integer fields fail
validation loudly instead of storing a corrupted id.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(control-ui): harden 64-bit config id preservation
* fix(control-ui): validate mixed-union scalar branches
* test(control-ui): prove real gateway id preservation
* test(control-ui): use communications route for config proof
* test(control-ui): grant config proof admin scope
* test(control-ui): reopen raw config for proof
* fix(control-ui): preserve explicit union input types
* test(control-ui): exercise union collection draft
* ci: retry flaky control ui e2e
* fix(control-ui): preserve mixed scalar branch types
* ci: retry service worker e2e
* fix(control-ui): preserve typeless string union branches
* fix(control-ui): reject lossy decimal coercion
* fix(control-ui): reject lossy pure numeric input
* fix(control-ui): preserve exact numeric branch semantics
* ci: retry checkout rate limit
* ci(control-ui): capture real gateway proof
* test(control-ui): frame config proof values
* ci: retry checkout download
* test(control-ui): prove Gateway-served production bundle
* fix(control-ui): preserve exact incremental union edits
* refactor(control-ui): isolate scalar edit session state
* fix(control-ui): keep scalar edit branch type internal
* fix(control-ui): avoid detached focus selector
* fix(control-ui): round-trip exact numeric branches
* refactor(control-ui): share exact scalar formatting
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Give maintainers immediate visibility when Mantis is requested. Bare mentions now react, link the active run, and keep one run-owned status comment through proof, short-circuit, or failure.
Co-authored-by: Ayaan Zaidi <hi@obviy.us>
* fix(ollama): carry real Ollama Cloud context windows and capabilities
The ollama-cloud catalog still described three models (minimax-m2.7, glm-5.1,
glm-5.2) plus a retired kimi-k2.5. Every other cloud model — including kimi-k3,
the current flagship — was absent, so core synthesized it at the generic
DEFAULT_CONTEXT_TOKENS of 200k. A kimi-k3 session therefore ran with 200,000 of
its real 1,048,576 token window: 80% of the context silently discarded, with no
warning anywhere in the product.
Describe the full current cloud lineup with context windows, input modalities
and reasoning support verified against live /api/show and the ollama.com model
pages. Only mistral-large-3 lacks thinking (vision + tools + cloud only).
Suffixed refs shared the same defect from the other side: the default lookup is
keyed bare, so `kimi-k3:cloud` missed it and fell to the 128k plugin default.
A hardcoded glm-5.2 literal in buildOllamaModelDefinition had been papering over
that for exactly one model; replace it with a lookup through the canonical
cloud-id normalizer, which model-reasoning.ts already owned, and drop the
duplicate spelling of that helper.
* fix(ollama): cover exact cloud catalog variants
* fix(ollama): remove invalid cloud aliases
* fix(ollama): default Ollama Cloud onboarding to minimax-m3
Cloud onboarding derives `defaultModel` from the first entry of
OLLAMA_CLOUD_DEFAULT_MODELS, so array order silently owned the out-of-box
model choice. Put minimax-m3 (524,288 ctx, thinking + tools + vision) at
index 0, add it to the bundled rows it was missing from, and document the
ordering contract at the declaration.
Pin the resolved default id in the cloud setup tests so a reorder cannot
move it unnoticed, and align the provider doc's onboarding default and
fallback row list.
Claude-Session: https://claude.ai/code/session_01QXUQuDVataA5o16kxNnmoX
* fix(ollama): preserve default and shared model contracts
* test(ollama): consolidate cloud setup capability expectations
---------
Co-authored-by: VACInc <3279061+VACInc@users.noreply.github.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
* fix(tasks): rank terminal tasks by completion and keep Recent terminal-only
- updateTaskStateByRunId backfills lastEventAt from endedAt for terminal
finalizers (mirrors markTaskTerminalById), keeping activity monotonic
- both taskUpdatedAt projections rank terminal tasks by the maximum
available activity timestamp, healing stale rows while preserving later
delivery/terminal-outcome events recorded after completion
- Tasks page Recent fetch filters to terminal statuses so queued/running
rows cannot starve the Recent section
Related to #100911
* refactor(tasks): normalize completion at registry owner
Absorb terminal timestamp ordering into the canonical registry lifecycle boundary, remove duplicated projection and writer policy, and prove Recent remains visible behind 200 active tasks in Chromium.
Co-authored-by: SunnyShu0925 <shu.zongyu@xydigit.com>
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
* fix(gateway): admit recovering workers during startup
* fix(gateway): admit recovering nodes during startup
* fix(crabbox): bind worker desktop to XFCE session
* fix(workers): reuse Git base during workspace transfer
large clean/stale worktrees were downloading every tracked file after the verified base pack, crossing transfer authority; selectively checkout desired base-index paths, preserving deletions and symlink confinement.
* fix(workers): clone reachable stale workspace commits
tip-only origin detection forced published ancestor commits through heavyweight Gateway transfer; the existing exact checkout and manifest verification safely own reachability/fallback.
* perf(workers): use blobless origin clones
* fix(workers): bundle undici in worker deploy artifact
applyFalConfig wrote the default image model to
agents.defaults.imageGenerationModel, a retired key the runtime never
reads (image generation resolves agents.defaults.mediaModels.image,
and the retired key is reported as an unrecognized dead key by
config validation). After fal onboarding, image_generate still failed
with "No image-generation model configured." until a doctor --fix
migration ran. Write mediaModels.image directly, matching the vydra
and pixverse onboarding flows.
Reconcile code and command aliases after trusted-policy and hook rewrites so explicit blank or non-string mutations fail closed, including simultaneous valid rewrites. Add owner-boundary regression coverage and document the contract.
* fix: unblock replies after recovery owner release conflict
* fix(diagnostics): keep an unreclaimed active run as an observed skip
Removing the noop outcome left recoverStuckDiagnosticSession able to fall off
the end of its try block when an active run neither aborted nor released,
returning undefined from a Promise<StuckSessionRecoveryOutcome> (tsgo TS2366).
Report that residual path as skipped/active_embedded_run so the watchdog never
clears diagnostic state for work that still owns its session.
* fix(sessions): compare persisted row bytes in session-entry replacement CAS
The replacement projection snapshotted entries with the status/store readers
(no participant projection) and revalidated inside the transaction with
readExactSessionEntryRow, which merges session_participants into the entry.
Any row with a participant that is not its owner therefore serialized
differently on the two sides, so the compare-and-swap threw "SQLite session
entry changed before replacement" on every attempt with no concurrent write
at all. Startup orphan marking selects by status, so such a session could
never be repaired: it stayed status=running across restarts, its rotated
session id never persisted, and every later turn failed with "changed while
starting work", retried by the ingress spool for 24h.
Compare the persisted entry_json bytes on both sides, the same raw-bytes CAS
the sibling lifecycle and projection paths already use, so separately mutable
decorations (participants today, owner columns next) cannot invalidate a
logical-session write. Renames the raw reader to readExactSessionEntryJson
now that it is the general CAS reader rather than repair-only, and aligns
shouldRemoveSessionEntry with the participants-excluding equality its own
callers already use.
* fix(sessions): fail closed when a selected replacement row has no persisted bytes
The raw-bytes CAS could not distinguish "row unchanged" from "row gone". If a
selected row was deleted between hydrating the snapshot entry and reading its
persisted bytes, both the snapshot and the transaction read undefined, the
compare agreed, the transaction's source map stayed empty, and the stale
replacement was written back into the deleted key.
A selected key must hold bytes, so treat a missing snapshot read as the
conflict it is. Reported by ClawSweeper on the previous head.
---------
Co-authored-by: VACInc <3279061+VACInc@users.noreply.github.com>
With message preview off, rows collapse to one line and the second-row icon
logic (spinner, unread dot, badges, facepile, trail) rides beside the title.
Two defects broke that:
- Long titles crushed the icon endcap: the single-line title used flex-basis
auto, so overflow shrink was distributed onto the endcap (24px -> ~7px),
clipping the status icons. Basis 0 now mirrors the two-line subtitle
contract: text absorbs all shrink before icons do.
- Native catalog session rows always rendered the two-line skeleton with an
empty details line (46px vs 30px) and never collapsed, in both preview
modes. Catalog rows never carry preview text, so they are now always
single-line.
Regression coverage: long-title endcap geometry in
chat-flow.sidebar-presentation.e2e.test.ts (fails pre-fix), and
codex-sessions.e2e.test.ts density assertions updated to the new
all-single-line contract.
Add trusted ClawSweeper-label and maintainer-comment dispatch for Mantis Telegram proof. Short-circuit non-visible PRs before desktop setup while preserving exact-head, fork, credential, and comment-ownership boundaries.
* fix(apple): gate gateway RPC polling on the hello method catalog
Released 2026.7.x gateways authorize before method dispatch and reject
unknown methods with INVALID_REQUEST / "missing scope: operator.admin",
which never names the method, so the shared Swift kit's error-text
matchers could not detect an unsupported gateway: queued sends wedged in
a delay-free sessions.branches.list reconcile loop, question.list burned
its retry budget per health event, and progressCard.get fired a rejected
fetch per event.
Port the Android fix pattern (#126540): generalize the progressCard-only
transport seam into tri-state gatewayAdvertisesMethod(_:), make hello
catalog parsing distinguish absent (nil) from empty, route branch
listing through a catalog-checking dispatch point with a typed
BranchListingUnadvertisedError, tighten error-text matching to the
modern "unknown method:" shape, and skip question.list/progressCard.get
when unadvertised. Regression tests encode the exact 2026.7.1-2 wire
shape and fail pre-fix (A/B verified).
* fix(apple): keep explicit unsupported branch-listing replies releasing sends
ClawSweeper P1: the tightened matcher dropped the shipped acceptance of
explicit unsupported/unimplemented GatewayResponseError replies that
name sessions.branches.list, which would wedge queued sends on a
pre-catalog gateway emitting that shape. Collapse the matcher onto the
bridged localizedDescription (errorDescription always prefixes the
method name), preserving both legacy qualifier shapes while still
rejecting bare missing-scope denials and the old false-positive-prone
INVALID_REQUEST arm; add the releasing-send regression test.