v0.0.31 β front-half delegation + pre-release audit
Added
-
Installer efficiency and Ink dependency hygiene (#1832): unchanged dependency payloads are reusable, the client replaces the deprecated
license-checkerchain withlicensee, the reviewed install-script allowlist covers esbuild and optional macOS fsevents for flows that permit lifecycle scripts, and the high-severity audit finding is resolved. -
Push-visible front-half review lifecycle (#1836): background design/plan review and convergence progress is now visible live in the Ink client β review-job launches, outcomes, and converge rounds surface as they happen (via the guarded
GET /eventsfeed) instead of only at the end of a turn. -
Phase-aware automation (#1827):
/autonow drives planning only up to the current approved plan, saves a boundary marker, and hard-exits with an operator notice to re-run/autofor execution; a re-plan creates a fresh boundary, and the staging/launch gate refuses an armed, un-exited boundary. -
The planning-to-execution hard-stop applies when design/decomposition review is enabled (the default); with review off, no approved-plan boundary forms and
/autoruns end-to-end. -
Watcher-driven front-half convergence (#1821-c/d):
/designand/plannow run their review rounds as board-visible background jobs and return PENDING while the watcher resumes reviewer, meta-reviewer, and reviser work independently for every design variant. Retries and restarts are safe (no duplicated rounds or lost feedback), anddesign_review.async_converge=falsekeeps the synchronous fallback. -
Durable front-half convergence state (#1821-a): design and decomposition review loops now persist their resumable round, cost, verdict, and artifact history under
.work/converge/so review work survives restarts. -
Decomposition confirmation:
/approve plan [--anyway]confirms a review-clean current R-B result, reports disabled review as stageable, and re-invalidates stale design/unit bindings without adding a manual staging gate or overriding HARD findings. -
Escalated front-half review:
/escalate reviewgives a HARD-blocked design or decomposition a fresh, default-four-round strong-coder convergence run without weakening approval or staging gates. -
Engine-owned lifecycle finding categories, fail-closed HARD/SOFT classification, deterministic artifact HARD checks, and idempotent accepted-review notes on design proposals and decomposition epics.
-
Front-half lifecycle convergence:
/designand/plannow review, strongly revise, and re-review drafts before returning, with model-distinct reviewers, engine-owned persistence, bounded TERMINAL findings, and loud DEGRADED failures. -
Per-invocation lifecycle cost envelope:
/designand/plannow estimate configured coder spend across review, meta-review, and revision calls against the default-$100design_review.cost_envelope_usdbackstop. -
Model-distinct lifecycle meta-review: R-A and R-B APPROVE verdicts now require a different-model reviewer-of-review, with authoritative blindspot findings and loud fail-closed meta unavailability.
-
Guided approved-design decomposition (#1794):
/plantriggers the one-epic-plus-all-units turn, fail-closed until scope+design are approved. -
Durable turn/action observability (#1790): every tool dispatch appends a redacted JSONL record to
turns.jsonl; new/turnsand/sessionHTTP readers expose it. -
Panel-led approvable designs (#1779):
design_review.modecan make the MPR decision panel an automatic pre-/designarchitecture/language gate. -
Front-half armed continuation (#1777, #1827): armed
/autodrives planning autonomously to the approved plan, hard-exits there, and drains implementation only after the operator re-runs/auto. -
Per-project live config overlays (#1778):
/config setvalues apply immediately and persist as a project-scoped overlay surviving/switchand restart. -
Durable direct-continuation forensics (#1745): silent continuation-tick exits, deferrals, and authoring-turn outcomes now write structured, deduplicated audit records.
-
Durable run observability (#1750, #1781): headless server retains a sanitized, size-rotated console log and archives bounded coder logs per run.
-
ACE learning-loop quality (#1748, #1751): near-duplicate lessons fold honestly by identifier/polarity, and retrieval keeps a reserved slot for proven lessons.
-
Engine-derived handover run records (#1752): handovers get an idempotent
## Run recordwith runtime facts and a precision-first tool-availability evidence gate. -
Active-initiative control-plane write jail (#1742 trust surface, #1743): a fail-closed guard refuses model file-tool mutation of the active initiative's control-plane directories.
-
Durable epic completion report and real poll transport (#1749, #1754; Slice 2): epic auto-close assembles an atomic, engine-stamped completion report with a durable
/healthpointer. -
Retroactive P2 notice activation (#1749, #1758, #1753): design-review-unavailable and code-review-skip notices now reach the real
/healthpoll transport, best-effort. -
Engine-stamped epic reconciliation records (#1754, #1749; Slice 1): epic auto-close writes a bounded, atomic reconciliation record of unreferenced required scope ids.
-
Handover internal-consistency gate (#1744): staging refuses a handover whose file is both forbidden-to-modify and required-to-modify by the same task.
-
Default-on, premise-free automatic code review (#1753, #1648):
code_review.modenow defaults tosimple, running one bounded reviewer pass per advanced unit. -
Design and decomposition review stages (#1758, slices 1β3): adds default-on, fail-closed R-A/R-B lifecycle review with engine-stamped, per-target evidence artifacts.
-
Design/decomposition review final remediation (#1758): closes gate gaps across create/claim/next-task launch seams and binds R-B approval to the unit-content hash.
-
Product-scope foundations (#1755):
record_scope//approve scopeadd a validated, versionedscope.mdartifact gating epics on approved, closed scope. -
Configurable automatic code-review stage in the dev-loop (#1614): an optional per-unit reviewer gate (
code_review.mode) blocks non-approved units until they pass or exhaust rounds.
Changed
- Board-visible front-half coder work (#1821-b): lifecycle reviewers, model-distinct meta-reviewers,
and strong-coder revisers now run as detachedreview-jobtasks through the shared handover/feedback
machinery while the convergence loop still waits synchronously. Review jobs remain board-visible but
are excluded from implementation-unit selection, continuation, and reconciliation; every synchronous
dispatch terminates even when its feedback is blocked or times out. - UTF-8 external-coder stdio (#1822): the synchronous CLI runner now decodes coder stdout and stderr
explicitly as UTF-8 with replacement for malformed bytes, independent of the host platform locale. - Canonical planning command (#1810):
/planis now the advertised decomposition verb; operator guidance names exact scope, design, planning, automation, and handover commands. - Design/decomposition convergence now stops when no HARD findings remain; SOFT findings are surfaced without revision, capped HARD findings are blocked, and
/approve design --anywaycannot override them. - Bounded front-half spend: reaching the lifecycle USD envelope after a reviewed round stops with the last residual findings as TERMINAL; exhaustion before any verdict is loud DEGRADED, and results plus durable evidence expose estimated spend and the envelope.
- Strong-coder front-half authoring: qwen remains the initial design/decomposition drafter, but an unscored MPR design is re-authored once and all HARD review findings are revised by an architecture-tier coder; qwen never reviews or revises.
- Canonical project command (#1800):
/initiativeis retired from the visible surface, kept only as a silent alias for/project.
Removed
- Obsolete weak front-half revise stage: full automation now waits at
/approve designafter internal strong-coder convergence instead of enqueueing a second qwen revision;/plan_unitsremains a silent back-compat alias.
Fixed
-
Reviser stream-output normalization (#1852): design/plan revisions produced by streaming coders
(Kimi message streams, Claude stream-json) are now correctly extracted into the saved artifact instead of
occasionally persisting empty or transcript-polluted output. Stream-shaped output with no extractable answer
logs a warning and falls back to the cleaned raw response instead of a silent empty artifact. -
Durable, fail-closed front-half convergence (#1840): asynchronous design/decomposition reviews now
survive restarts β interrupted review work resumes from its last consistent checkpoint or restarts cleanly
rather than re-running the whole loop (a narrow crash window may repay at most one already-finished review)
and never promotes unreviewed work. Unreadable or inconsistent review state ends in a
loud DEGRADED refusal rather than silently proceeding. -
Public export and release-prep correctness: public docs now use repository-root paths and match the
server's guarded route surface; export rewriting also handles top-level paths without a trailing slash
without collapsing historical move descriptions. The README's deterministic current-version marker is
restored so the README,docs/status.md, andpyproject.tomlversion stamps stay mutually consistent
across a release cut. -
Workspace-scoped project listing (#1838):
/project listnow shows only the projects in your current
workspace instead of every project ever registered;/project list --allstill exposes the complete
installation-global registry with workspace labels. Unresolvable project roots fail safe (they can narrow the
scoped view, never wrongly widen it), and/project useacross workspaces names the bound-root change only
when the target actually leaves the current workspace. -
Safe local-installer dependency reuse (#1832): Ink source and TypeScript-config changes invalidate the client cache; reuse additionally requires an exact completed-copy marker, a whole-tree match for built output, and successful resolution of every declared production dependency. Pip reuse requires both a pre-existing venv and successful imports of every installed runtime dependency. Cache writes remain strictly post-success and cache I/O or integrity failures still force a full install.
-
Detached review-job stdout transport (#1839): review jobs now return their verdict or revised body
through stdout without receiving a project file-write channel. After the logfile drainer finishes, the
engine publishes clean non-empty output asstatus: donefeedback, preserves failed or empty runs as
status: blockedwith their exit/tail reason, and never overwrites a coder-authored feedback file. -
Refusal-aware Ink tool results (#1834): returned
ERROR:/failure markers now replace optimistic tool completion summaries; refusedwrite_file/edit_filecalls render the refusal text and can no longer claim that a file was written. -
Desktop front-half review-job launches (#1833): detached reviewer, meta-reviewer, and reviser jobs now authorize and render the configured agent's canonical launch tuple, with synchronous-runner permission-bypass gating and Memory MCP injection, instead of presenting a synthesized Claude autopilot argv that a pool-derived tooling envelope correctly refuses.
-
Active-initiative artifact-path self-correction (#1823): wrong-slug vault write-jail refusals now name the sanctioned engine tool and teach the engine-derived active artifact root, while steering forbids deriving vault paths from the working directory or project name and reserves trusted scope, design, and unit artifacts for their engine tools.
-
Full-auto front-half notices now direct terminal HARD-blocked designs to
/escalate reviewinstead of/approve design, and no longer carry the dead review-path field in continuation state. -
Lifecycle hard checks now match only real MPR transport residue and exclude engine-authored accepted-review notes; common cosmetic reviewer labels normalize to SOFT while genuinely unknown categories remain fail-closed HARD.
-
Production-shaped MPR convergence: wrapped unscored decision reports now reach strong-coder re-authoring, transport/confidence sentinels are removed from reviewed trade-offs, and an unmapped architecture reviser tier can no longer fail open to routine coders.
-
Breaker-aware lifecycle reviewers: budget- or quota-exhausted R-A/R-B reviewers now trip the shared availability breaker and fail over once, including generic HTTP 402/payment-required failures even when a failed CLI writes stray stdout; exhausted pins and empty independent pools stay loudly unavailable.
-
Control-plane decoy-forgery jail (#1805): model file tools now refuse code-root-relative decoy vault shapes, explicitly canonicalize every active-root and target segment against Win32 trailing-dot/space aliases, and reject forged trusted frontmatter including BOM-prefixed, quoted, and case-varied declarations.
-
Consistent design command surface (#1793): bare
/designand/approve designnow behave consistently across single- and multi-proposal cases. -
System-first rolling-summary requests (#1796): merges multiple system messages into one leading copy so vLLM chat templates stop rejecting long conversations with HTTP 400.
-
Guided advisory-override continuation (#1795): an
--anyway-approved design now satisfies the design gate so guided mode proceeds toplan_units. -
Self-correcting product-scope row refusals (#1789): malformed scope rows now show a concrete corrected example, with a loop notice after three repeated refusals.
-
Schema-directed runtime string coercion (#1776):
/config setno longer coerces boolean-word tokens likeoffbefore checking whether the leaf is string-typed. -
Aborted client connections handled cleanly (#1782): aborted client connections no longer surface as 500 tracebacks in the durable engine console.
-
Trusted terminal delivery footprint at epic close (#1747): only an engine-stamped completion report can confer the vault's
deliverystage, closing a forge path. -
Language-aware code-root handovers (#1746, #1780): the staged code-root note names the right manifest file per approved design language instead of guessing.
-
Hermetic sibling-test environmental retries (#1769): the nested pytest gate retries kernel crashes, interruptions, and spawn errors up to three times.
-
Product-scope refusal completeness (#1755): the scope parser now handles bad UTF-8, trust metadata, and bounded proposal numbering with a negative test per refusal.
-
Pre-release public-export audit cleanup: fixes public metadata, contributor/demo guidance, roadmap wording, exporter caches, and adds a standard
.gitignore. -
Done-unit redispatch is closed at every dispatch seam (#1738): clients only launch coders after
/claimdurably returnsin_progress, closing a re-dispatch race. -
Client-launch autopilot slot accounting (#1733): the server now releases its autopilot concurrency reservation once execution is deferred to the client's pool.
-
Fail-closed public Windows engine installation (#1725): the desktop installer now checks venv creation, pip upgrade, and engine import before declaring success.
-
Uniform autopilot value-slot refusal (#1715): the tooling-envelope recognizer refuses any
---prefixed value in a model-authored slot, not just one denylisted flag. -
Honest reflection-worker shutdown (#1708):
ReflectionWorker.stop()now joins the in-flight reflection to completion instead of abandoning a running daemon. -
Incomplete local-install runtime guard (#1690): a partially written runtime install is marked incomplete and the launcher refuses to start it.
-
Fail-closed public Windows ink-client build (#1691): the installer uses lockfile-exact
npm ci, checks exit codes, and only wires the client when the build exists. -
Accurate task-class names in the code-agent guide (#1684): documents the live
complex/standard/routine/analysisclasses instead of ones the schema never defined. -
Memory MCP environment for persistently registered CLIs (#1683): memory env vars are now set independently of a per-CLI
mcp_templatefor persistently registered CLIs. -
In-engine Memory MCP wiring (#1682): the engine-native autopilot launch path now resolves the same read-only Memory MCP args as the thin client.
-
Live running-unit board state (#1674):
BOARD.mdrepublishes when a task transitions toin_progress, not only when the pipeline is idle. -
Python streamed-turn retry parity (#1670): the Python client now visibly retries a pre-stream 5xx on
/chat/streamwith the same backoff as Ink. -
Hermetic sibling-test assertion stability (#1665): the generation gate's nested pytest child now runs with plain assertions, avoiding assertion-rewrite corruption.
-
Runtime config survives a project switch (#1657): a
/config setoverride is now session-global and re-applied above the project overlay on every/switch. -
ACE adaptation durability (#1660):
PlaybookStore.adaptretries transient Windows file-lock failures and reports explicitquarantined/promotedoutcomes. -
Test-report count narrative (#1655): the report header now points to the generated summary instead of unguarded historical count arithmetic.
-
Authoritative feedback-agent completion events (#1673):
post_feedback.agentnow carries the filename-derived agent instead of the potentially stale requested agent. -
Code-agent configuration example (#1695): the public BYO-agent guide uses deployment-owned placeholders and shows complete
{mcp}wiring for read-only Memory MCP. -
Multi-agent client override isolation (#1675): legacy single-agent BYO overrides now apply only to a server-resolved Claude spec, not non-Claude registry agents.
-
Terminal tooling-envelope refusal handling (#1676): clients now report a pre-spawn envelope refusal without spending a run, and retain the claim instead of re-firing it.
-
Authoritative handover task labels and bounded validation visibility (#1622): staged handovers reconcile stale
Task ID:labels safely, and results carry a bounded validation excerpt. -
Self-healing FULL continuation (#1651): the reconciler heartbeat re-queues an idle armed continuation's turn, capped at three recovery attempts per unit.
-
Visible, bounded streamed-turn retries (#1650): the TypeScript client preserves error detail and visibly retries pre-stream 5xx responses on
/chat/streamwith abortable backoff. -
Automation-aware steering advice (#1649): steering now recommends
advance_pipeline/stage_handoveronly for legs the watcher/continuation doesn't already own. -
English-only terminal input chrome (#1646): the Ink input box now shows an English placeholder instead of German, and unused localized chrome strings were removed.
-
Source and published client links (#1642): the three
clients/ink/doc links now resolve in both the monorepo and the generated public export. -
Standalone ACK test imports (#1641): steering-state and command-spec parity tests now bootstrap the engine path directly instead of relying on import order.
-
MPR degradation formatter seam parity (#1640): the documented
degrade_formatseam is now actually bound to the engine's renderer, pinned by a parity test. -
Deployment-wide generation settings protected from project overlays (#1639): the
generationconfig prefix is now locked so a project overlay can't override it. -
Reference-environment-safe documented test counts (#1638):
gen_test_counts.pynow refuses local runs outside Linux/3.14 and accepts an authoritative CI summary instead. -
Fail-closed documented test-count generation (#1637): the count check now accepts only a clean pytest exit and retries transient failures instead of trusting a red suite.
-
Tight multiline client blocks regression fix (#1645): fixes a vertical-spacing regression from #1621 across the banner, guided input, listings, and coder status blocks.
-
Authoritative artifact-root steering (#1643): the steering block now shows the active unit's real resolved artifact root instead of a project-relative guess.
-
Visible pipeline routing corrections and bridge-safe shell offers (#1622):
advance_pipelinewarns on agent mismatch, andexecute_commandis hidden on Windows without a bridge. -
Flagship client and board display polish (#1621):
/boardhides internal managed-block markers from output, and the TS client tightens tool-call block rendering. -
Deterministic config-key suggestions (#1623):
/config setunknown-key refusals now resolve exact/ambiguous leaf names before falling back to edit-distance suggestion. -
MPR project routing and guidance (#1617): legacy
/project new --typenow warns it's ignored, and plugin workers inherit the invoking request's active-project context. -
Live reply-language config updates the active system prompt (#1620):
/config set generation.languagenow rewrites the live system prompt's response-language block in place. -
Completed coder feedback is surfaced before any next-unit nudge (#1619): steering now detects live
in_progressfeedback and warns against re-launching the coder. -
Design promotion provenance and typed vault edge (#1618):
/approve designnow stamps the proposal as promoted with a typedsupersedesedge inGRAPH.json. -
Empty
parallel_reasonbranches are reported honestly (#1616): a fan-out branch only counts as success when its content is actually non-empty. -
Orchestrator read-only vault introspection from a split code root (#1615): read-only file tools now fall back to the project root when using a split code root.
-
Implementation handovers preserve the epic-units dev-loop structure (#1613): ad-hoc
stage_handovercalls carrying implementation work are refused;plan_unitsis required. -
English-only
/autotoggle + public-export doc/comment polish (#1609): the client's/autostatus now printsON/OFFinstead of German, plus assorted export-doc fixes. -
Terminal client retries a tool result on a recoverable 401 (#1573): the TS client now buffers and retries a
401/403tool-result POST instead of dropping it. -
Provider dispatch no longer head-of-line-blocks across providers (#1562): dispatch now runs one executor per provider so a saturated provider can't starve an idle one.
-
German MPR runs resolve every role's German lens (#1557): the German lens overlay is re-keyed to current role labels so all 23 roles resolve correctly.
-
Cancel wakes a bridged tool wait so a dead client can't pin the agent lock (#1553):
ToolBridge.requestnow polls the cancel event instead of blocking the full 180s. -
ACE rollback surfaces a persistence failure instead of a false success (#1551):
PlaybookStore.rollbacknow checks its writes and reports failure instead of a false success. -
Engine-native coder launches are hardened to parity (#1548): in-engine coder launches now get process-group kill, a real timeout, and a capped log, matching other paths.
-
Session reload keeps the rolling summary (#1547):
load_sessionnow preserves the rolling-summary system message instead of deleting it on reload. -
Session persistence is atomic (#1546):
save_sessionnow writes via fsync'd temp file + atomic rename so a failed write can't truncate the checkpoint. -
Idle watchdog can abort a blocking synchronous plugin tool (#1545): plugin handlers now run in a daemon worker so a hung tool can no longer wedge the turn forever.
-
LLM requests honour a hard whole-request wall-clock cap (#1544): streaming generation now enforces a monotonic total deadline, closing a slow-drip evasion of existing timeouts.
-
Status poller no longer starts overlapping polls on a slow server (#1542): the health/tasks poller is now self-scheduling instead of firing on a fixed interval.
-
Exiting during
/workor/autoreaps in-flight coders before closing the session (#1541): exit now kills and awaits in-flight coder children before closing the session. -
Bridged
execute_commandno longer false-timeouts or buffers unbounded output (#1540): the timeout guard now checks exit/signal codes and output uses a bounded rolling tail. -
Sealed-session shutdown is promptly bounded (#1539):
SessionHandle.stop()now aborts in-flight requests via anAbortSignalinstead of waiting up to ~20 minutes. -
Signal-terminated coder is no longer misclassified as timed out (#1538): the timeout race guard now also checks
signalCode, not justexitCode. -
Skill scaffold refuses to overwrite atomically (#1537):
write_scaffoldnow preflights the whole target set so a later conflict can't leave a half-written scaffold. -
Skill spec rejects param sets that can't form a valid signature (#1536): the validator now rejects Python keywords and duplicate parameter names.
-
Tool-schema requiredness follows the signature, not the annotation (#1535): requiredness now derives from
param.default, fixing crashes and invalid null-arm schemas fromOptionaltypes. -
Lodestar resolves cross-domain capability dependencies (#1534):
build_backlognow computes implemented capabilities across every domain, not just the current one. -
Generator escapes descriptions per serialization context (#1533): the paved-road generator now escapes
--descriptionper template sink instead of substituting it raw. -
Doctor fails closed when a requested Lodestar plugin can't load (#1532): a Lodestar load failure now surfaces as a visible ERROR instead of silently running zero checks.
-
--validate-tasksno longer skips capability records (#1531): the doctor gate now validates capability-tagged task records against their full schema too. -
Busy
/chat/streamreturns a retryable 503 (#1563): the agent lock is now acquired before streaming headers commit, so a busy engine returns a retryable 503. -
/autoguidance matches the runtime cap (#1561): the/auto//autoplanflag summaries now describe the actual default task cap instead of claiming "unbounded". -
Tool-call parser is type-safe (#1558): malformed
tool_callselements are now skipped instead of raising anAttributeErrorthat escaped the retry loop. -
Roadmap drift check fails on API errors (#1560):
gen_roadmap.py --checknow fail-closes onghauth/permission and other API errors instead of soft-skipping. -
Boundary guard catches dynamic private imports (#1559): the public-boundary AST guard now also flags constant-string dynamic imports of private packages.
-
Scope forget purges ACE side files (#1552):
PlaybookStore.forgetnow removes the history and quarantine side files too, not just the active playbook. -
Stable boot-only memory and warm config overlays (#1549):
memory.json/warm.jsonnow resolve from the boot cwd instead of being cleared by later cwd changes. -
Bounded coder feedback-file reads (#1543): both clients now cap feedback/capture file reads at 1 MiB instead of reading unbounded coder-controlled files.
-
Bounded chunk-overlap expansion (#1550):
MemoryManager._chunksnow caps overlap at half the chunk size, preventing unbounded O(len) chunk-memory blowup. -
Warm tier recovers after a transient first-connect failure (#1556): a failed initial Valkey connect no longer permanently latches the warm tier off.
-
/fanoutprompt count is bounded (#1555): the endpoint now refuses more than a configured max prompt count before allocating any fan-out work. -
Bounded
/updatesubprocess teardown (#1522): timeout/output-limit failures now force-kill the whole build process tree with a bounded drain. -
Renewable client-run claim leases (#1525):
POST /claimnow stamps and renews a runtime-configurable lease so a dead client's claim can be reclaimed. -
Reliable Python tool-result delivery (#1523): the Python client now resends completed tool results through transient/5xx failures with capped backoff.
-
Per-connection slowloris deadline (#1528): the HTTP handler now applies a configurable socket timeout to request-line/header/body reads.
-
Corrupt project registry preservation (#1526): an invalid registry is now atomically quarantined to a sidecar with a warning instead of being silently replaced.
-
Display text cannot forge client control frames (#1524): the capture sink now strips NUL bytes from display text so tool output can't forge control frames.
-
Feedback task-ID path hardening (#1527):
POST /feedbacknow accepts only canonical task IDs and verifies the resolved path stays inside the feedback inbox. -
Scope guard on memory listing (#1530):
GET /memoriesnow enforces the mandatory partition guard, matching every other Mem0 route. -
Memory service binds loopback by default (#1529): the
memorycompose profile now binds127.0.0.1:8800instead of exposing the unauthenticated Mem0 API on the LAN. -
Python egress policy namespace enforcement (#1521): Python dependency analysis now canonicalizes
py:allow/deny entries so a namespaced deny can't be bypassed. -
Transactional runtime config cleanup (#1481): removes ~405 unreachable legacy-config lines and routes remaining switches through the clone/validate/derive/commit path.
-
F9 switch-parity guard and schema-owned external seams (#1484): the AST switch-parity guard resolves more dict-access patterns, and external seam config moves into the typed schema.
-
Honest firejail teardown semantics (#1500): firejail is now documented as best-effort-only for descendant teardown, with a one-time operator advisory.
-
Bounded Ink post-kill exit wait (#1500): timeout/cancellation now wait up to two seconds for a killed child to exit, mirroring the Python client's drain.
-
Real-bwrap setsid-reap proof (#1500): an opt-in test verifies real bubblewrap namespace teardown reaps a detached descendant via
fork()/setsid(). -
Bounded Python coder stderr and Windows tree-kill proof (#1502): the Python handover client now drains stderr into a bounded 256 KiB rolling tail, matching Ink.
Security
- Auth gate enforced on operator routes:
/events,/metrics, and/alertare now actually covered by
the deployment-secret (and, undersealed, live-session) gate the docs always described β previously their
guard was a silent no-op, so the review feed, runtime telemetry, and the alert/pager trigger answered
without the secret. The Ink client's authenticated/eventspoll is unaffected. - DNS-rebinding-safe
fetch_url: each redirect hop resolves its host once, fails closed if resolution
fails or any resolved address is non-public, and pins the validated IP for the connection while retaining
the original Host header and HTTPS SNI. Redirect targets are independently resolved and re-validated,
closing the resolver-to-connect DNS-rebinding window.