# Known limitations This is an experimental, single-host plugin. The current compatibility tests do not establish that all collaboration, isolation or acceptance problems are solved. ## Execution and resources - The default attempt lease is 120 seconds. The runtime renews it only while the adapter identifies an owned, uncancelled native model/tool/verification operation or provider retry, and renewal is bounded by the mission deadline. A live model stream republishes its operation every `activityHeartbeatMs` (default 1000 ms; 0 disables the republish timer), so a long chunking stream cannot let the lease expire, while a claimed task with no live operation still expires. This identifies operation liveness, not useful progress. A stuck operation still relies on its provider/tool timeout, cancellation or mission deadline. Persisted activity alone never authorizes renewal after restart. - The primary agent chooses and can revise resource budgets. Token accounting uses provider-reported worker usage; cache-read input is charged at `cacheReadWeight` (default 0.1, bounded 0..1) while every raw bucket stays exact for display, and the runtime emits an approaching-limit warning at each `budgetWarnAt` fraction (default 0.7 and 0.9). A step is refused when consumed usage plus an estimate for requests still streaming (each worker's average per-request usage) reaches the ceiling, so an unusually large in-flight request can still exceed it. Usage buckets (uncached input, cache read, cache write, output including reasoning, physical requests) are recorded per worker and per mission; the owner conversation's usage is attributed to its newest live mission or planning request by time window and is not charged to the pool. Failed provider attempts that report no usage remain uncounted. - Boundary compaction calls the host compaction engine after a verdict closes a unit of work, only for an idle worker whose last request exceeded `boundaryCompactionTokens` prompt tokens (default 250000). The summary request costs tokens once and is accounted like any other; without a loaded compaction engine no compaction happens. - Mission duration is elapsed wall-clock time from creation. Pausing does not freeze the clock; the primary can revise the duration explicitly. - POSIX process groups are required. Windows execution is not supported. - The real-Harness composition checks (`npm run test:harness`, `test:pack`, `test:profile`) require a host that permits nested `sandbox_apply`, because the composition fixture requests `workspace-write`. Inside an outer workspace-write sandbox, macOS denies the nested sandbox (`sandbox-exec: sandbox_apply: Operation not permitted`) and the composition fails with `SandboxUnavailableError`. `test:pack` and `test:profile` detect this before the composition and abort with the prerequisite; `DSH_SWARM_SKIP_SANDBOX_PREFLIGHT=1` attempts the composition anyway. This is a host prerequisite, not a product defect. `npm run test:isolation` is host-only for the same reason: it drives the real `@deepseek-ai/dsh-sandbox-local` provider through `confinedCheckArgv`, so it needs a built supported Harness checkout and a host that permits the platform sandbox; it lives outside `tests/*.test.mjs` and is not a worker check. - Worker sessions add the same constraint to every worker bash/tool call, because the adapter confines them with the mission's sandbox mode. A real Loader composition driven from inside a worker session therefore fails with `SANDBOX_UNAVAILABLE` even when the outer host is otherwise healthy; this is worker-side only. The fault-injection suite's provider-fault tier (F3a/F3b/F3c) registers an identity sandbox provider and an unsandboxed `bash-local` shell for that tier, because the provider-fault invariants do not depend on OS confinement; no assertion was weakened. The host gate runs unsandboxed, where `npm run test:harness`, `test:web` and `npm run test:command-web` pass. - The worker close-out nudge bound `maxIdleCloseouts` (default 2) is accepted by `RuntimeConfig` and used by the close-out path and the fault suite, but it is not exposed in the plugin `Config`, so plugin users cannot shorten or lengthen it yet. - The fault-injection suite must run in a git-backed checkout. F4 executes `scripts/round.mjs promote --commit HEAD` and asserts the refusal, so from a `git archive` export without `.git` it fails with exit 1 instead of the expected 2. The host check runner and the round gate use a clone or worktree, where `npm run test:faults` is 20/20; a shallow (`--depth 1`) clone also works since owner commit `e1ed0dc`, which makes `promote` refuse on the missing gate before it resolves the artifact's parent. Tier B (F3a/F3b/F3c) additionally needs a built supported Harness checkout: `DSH_HARNESS_ROOT` or `DSH_SOURCE`, or a `~/.dsh/source/current` (or sibling `deepseek-harness-rc1`/`deepseek-harness-latest`) checkout whose packages are built and match `compatibility.json`. Without one, `npm run test:faults` fails with `The fault suite needs a built Harness checkout; set DSH_HARNESS_ROOT (see compatibility.json)`. ## Tool authority and verification - The worker guard is a name-based deny list, not a complete capability allowlist. Other profile tools, including scheduling tools such as `cron_add`, may have external effects that the list does not cover. No separate network/credential policy or adversarial multi-tenant isolation is provided. - Declared scopes are checked when artifacts are captured; they are not per-shell-write allowlists. - Workers cannot write git metadata. A member worktree's index, refs and `.git/worktrees//` live under the shared git common directory outside the worker-writable path, so a worker-side `git add`/`git commit` fails with `index.lock: Operation not permitted`. Publication is host-side: the assignment instructions state the constraint, a denied write is reported as a typed error naming `swarm_submit`, and `swarm_submit` captures the workspace without any worker-side commit. - The `node_modules` symlink a member creates to run declared checks is toolchain state, not work. `.gitignore` declares `node_modules/` (a directory-only pattern), so that symlink stays untracked; an untracked dependency link would otherwise refuse the next task preparation and fail artifact capture. Preparation ignores an untracked dependency link (symlink or directory, including configured `verificationDependencyDirs` names) while still refusing real uncommitted work and lookalike regular files, and capture excludes it from the changed set, unstages a previously staged link, and keeps it out of the commit. A path tracked in HEAD is always ordinary work. The workspace-escape symlink guard resolves the whole link chain against the committed tree, not just the target string, so a link that points at a pre-existing escaping link is refused by capture as well (F-C1); delivery applies the same chain resolution before its first write. - Verification checkouts make ignored dependency directories named in `verificationDependencyDirs` (default `node_modules`, matched at any depth) available to declared checks instead of installing their own. A check therefore runs against committed files plus the installed toolchain, which is not part of the artifact and may differ from a fresh install; build outputs and other ignored paths are never provided. Every declared check runs under the Harness sandbox rooted at the disposable checkout, and it is refused unless the host reports **full** enforcement (F-29), so a partial backend (Windows ACL, an older Landlock ABI) cannot silently weaken the boundary. With the default `verificationDependencyMode: 'link'` that directory is a read-through symlink: the check reads the real toolchain, but a write whose resolved path leaves the checkout — including a write through the link into the source checkout — is refused by the full-enforcement sandbox, which matches resolved paths. `verificationDependencyMode: 'copy'` clones the directory into the checkout instead, so write isolation does not depend on the sandbox backend, at the cost of copying the tree. An unconfined `Workspaces` (the identity `confineCheck` that unit tests inject) has no such boundary, and reads still depend on mutable toolchain state either way. Exit 127 is annotated as a missing command rather than an artifact defect. `npm run test:isolation` is the host-only proof that a declared check cannot write into the source checkout; it is not part of the worker check set. - Independent host verification proves that the declared checks ran against the exact artifact. It does not prove those checks are meaningful. Initial automatic checks come from the primary, but participant proposals remain possible and there is no mandatory mission-wide acceptance baseline imposed on every artifact. - Automatic planning uses the owner's ordinary Harness agent and tools. The prompt supplies a frozen planning directory, while the owner's native cwd remains its source project; following the read-only snapshot path is not a separate OS enforcement boundary. Worker baselines are enforced by the runtime. Advanced `swarm_create`/staging tools bind their workspace to the calling session's working directory, like the native command's workflow; a plan that names a different real path is rejected before any work starts. ## Storage and recovery - Default plugin state paths use `~/.dsh/agent-swarm`, independently of `DSH_HOME`. Separate hosts must configure distinct `statePath` and `workspacesRoot`; sharing one database is rejected by an exclusive owner lock. - Live update cursors upgrade the database from schema 1 to schema 2. Older plugin builds reject schema 2, so downgrade requires a consistent pre-upgrade database backup or separate state path. Keep the matching workspaces, recovery journals and Git refs. - Automatic startup snapshots tracked files and non-ignored untracked files without moving the branch or changing the real index. Ignored untracked files, including dependencies or local environment files, are not included. Unsupported states such as unresolved conflicts, or dirty or diverged submodules, must be resolved first. A clean uninitialized submodule whose recorded gitlink matches the parent commit is accepted. The capture checks for concurrent edits and retries; it is not a filesystem-wide atomic snapshot. - Worker worktrees, planning snapshots and artifact refs are retained after stop/completion. Startup preserves source working files, index and branch; **Apply result** explicitly updates only working files. Result comparison uses the saved snapshot, and conflicts are returned without source changes. Shared Git objects, refs and metadata remain under `.git`; cleanup remains explicit. - Stable IDs and a durable inbox recovery journal cover tested stop/restart paths. They do not guarantee exactly-once external tool side effects or recovery from arbitrary disk faults. - Applying a result is not a filesystem-wide atomic transaction. Concurrent edits trigger rollback; if later edits prevent restoration, the error identifies retained recovery copies. A hard process or disk failure during the write phase may require recovering those copies manually. Submodule changes and directory/file conversions are not automatically applied. Snapshot storage must be outside the source repository. - Outbox retries lack complete failure counters, backoff and delivery diagnostics. Offline-owner notifications can remain pending. Process-lock detection does not distinguish PID reuse, and a full WAL/umask permission matrix has not been validated. ## Interface and model behavior - The live sidebar observes committed changes through native RPC long polling, with bounded change history and keepalives. Updates carry changed mission snapshots rather than individual text tokens. There is no fixed two-second refresh delay, but a busy host, browser or network can still delay delivery; this is not a hard real-time guarantee. A disconnected panel marks its retained activity as stale; reconnecting or reopening fetches authoritative state, with full-snapshot fallback when its cursor cannot be replayed. Conversation cards remain historical snapshots; an explicit observation creates a new snapshot. - Cold worker history is a read-only text/tool projection, not the complete native chat UI. Media is represented by type, and long entries are explicitly truncated. A live worker's native chat composer may remain writable; mission-management permissions are checked separately. - Swarm tools are registered globally, then hidden per session by role: ordinary sessions see the entry set, sessions that own a request or mission see the management set, workers see member tools, subagent sessions see none. Hiding is presentation through the host's scoped restriction; the runtime guard and owner checks remain the authority boundary. Role changes alter the cached prompt prefix once, when a session becomes an owner. - Observation output is focused (current task, prerequisites, review source, run references, recent events) with cursors and by-id paging, but it is not bounded by one fixed byte limit: a task record with very long acceptance or objective text is returned whole up to the excerpt limits. - Owner notices are sent only for rejection, challenge, worker failure, budget exhaustion, a stalled board and completion. Submission and acceptance appear in the panel and event log only; an owner who wants routine progress must observe explicitly. - Owner sessions now see the owner-only `swarm_cancel` tool and the assignment instructions state the git-write constraint, so the model-visible golden snapshot (`tests/fixtures/model-visible.expected.json`) changed with the runtime-integrity artifact. `npm run test:harness` owns that snapshot and must be re-run on a sandbox-capable host to confirm it; this worker host cannot run it (see Execution and resources). - Correct plan generation and useful acceptance criteria still depend on the model and task description. The primary can repair validation errors, but deterministic test fixtures do not establish a general real-model success rate. ## Round-2 deferred defects, advisories and round-4 boundaries Round 2 deferred four defects and accepted two advisories without ranking them. Round 4 fixes or bounds them; this packaged list exists so consumers do not have to read the non-packaged remediation ledgers. - **W8 (a provider-rejected reasoning effort was admitted) — fixed in round 4.** A start rejection that names an unsupported `reasoningEffort` is retried once without that field and records a durable `member/effort-downgraded` event; the admitted member keeps no effort. If the retry is rejected too, admission fails with a typed message, the member is stopped, and durable `member/effort-rejected` and `member/failed` events are written. Residual: the downgrade clears the requested effort rather than selecting a supported one. - **W9 (a preparation failure was terminal) — fixed in round 4.** A failed preparation is recovered or re-created with a clean baseline instead of blocking the task permanently, with a regression test that fails on the pre-fix head. Residual: a real repeated failure still consumes recovery credit until the attempt limit. - **W12 (a pending task's dependency set could not be extended) — fixed in round 4.** Cancellation now has a lineage repair path: a replacement may cover a cancelled task and dependents re-resolve to it, and a running sibling review is retired both by a verdict and by cancellation with a durable event. - **W14 (declared checks were not reconciled with the execution environment) — addressed in round 4.** Admission reconciles an objective's write directives with the declared scope and named deliverables with the effective ignore rules, so a plan that cannot run is rejected before work starts. Residual: a check that needs a host capability (a built Harness checkout, nested sandbox or browser) remains a documented host prerequisite, not something admission can detect. - **A1 advisory (read-check-write race in the abandoned-task repair) — covered in round 4.** The repair now has a deterministic regression test: the checkpoint takes a per-record lock, waits for a competing owner and declines to overwrite a newer owner's record. The window only opened on an ownership switch within one epoch, and the observed manifestation was a spurious handoff failure rather than a clobber. - **A2 advisory (a real non-symlink untracked dependency directory was not excluded) — fixed in round 4.** Preparation and capture now recognize the dependency directory by its ancestor component, so an untracked dependency tree never blocks preparation or enters an artifact, and a staged dependency directory is unstaged. Residual: a regular file that merely shares the dependency name is ordinary work and is still refused as uncommitted work. **Single-host, single-writer.** Admission, lease and budget accounting is durable but scoped to one host and one writer process at a time: every mutation serializes through a single SQLite writer connection. A competing writer is classified as `writer_busy` and retried with bounded backoff; progress is not guaranteed under sustained contention. Two writers against one store file, or one store shared across hosts, are unsupported. Multi-host horizontal scaling requires external coordination and is out of scope for this release. **The full verification suite requires the repository checkout, not the installed tarball.** The published tarball ships built `lib/`, the manifest, `cordis.patch.yml`, four documents and `scripts/packed-smoke.mjs`. `npm run test:packed` verifies that shipped layout. `test`, `test:harness`, `test:faults`, `test:pack`, `test:profile`, `test:web`, `test:command-web` and the host-only `test:isolation` need `src/`, `tsconfig*.json`, `scripts/` and `tests/` from the repository; fault tier B additionally needs a built Harness checkout.