Repository navigation
v0.76.0
Cotal 0.76.0 is out!
Grab it: npm i cotal-ai@0.76.0
Changes in this release
-
The manager and the delivery daemon now name an injected
SecretStorethrough one rule,injectedSecretStoreIdentityin@cotal-ai/core: the store's declared identity, else the coordinate inCOTAL_SECRET_STORE, else a refusal. Each package kept its own copy before, so a change to one could have made the store challenge report two names for one shared store, and both now refuse an unnamed store with the same message.reloadStoreIdentityOffrom@cotal-ai/deliverytakes{ injected: true, store }or{ injected: false, identity }. The daemon's injected cred source no longer carries an identity, which nothing read and which was blank whenCOTAL_SECRET_STOREwas unset. See the upgrading guide. -
Refuse competing patched same-host consuming sessions without replacing their logical inbox owner. Preserve live control listeners and existing foreground actor material. Make fresh local foreground grants and departure cleanup generation-aware. This containment does not fence other hosts, broker URL aliases or older clients.
-
A detached
cotal spawn <persona> --resume <id> --on <instance>without--agentnow carries the session for the harness the target manager launches. The CLI used to pick the connector from--agentor its ownCOTAL_DEFAULT_AGENTalone, so a persona withagent: claudespawned by a caller whose default named another connector carried nothing, and a persona without a pin carried a Claude transcript to a manager whose own default then refused it. The CLI now asks the manager's newresolve-agentcommand, which loads the persona with the same visibility check asspawnand answers with the same flag, pin, caller default and manager default order.resolve-agentis minted besidespawnin the spawn capability and the operator instruments, and the manager cluster document moves to revision 26. With--agentthe CLI does not ask, so a manager that does not serve the command still takes that form. -
Comments in core, the manager and the runtime cite SPEC sections and code symbols instead of line numbers. Nine of those line numbers pointed at unrelated text, including the
EpGateState.spacedoc in core's published types, which also named §13.9 for the per-space auth bucket that §13.12 defines. The comments now name the alias-reuse gate in the manager's spawn path,resolveService'sinstanceIdoption and thepinnedInstanceIdit returns, the spawn affinity gate, the auth session ledger'sreconcileSessionForTakeover, and each SPEC section without a line. No behavior changes. -
A launch that resolves an empty read or post list now hands the session that empty list.
aclEnvused to omitCOTAL_SUBSCRIBE,COTAL_ALLOW_SUBSCRIBEandCOTAL_ALLOW_PUBLISHwhen the list was empty, so acotal spawn <persona> --subscribe ,or--allow-publish ,session fell back to the persona file's channels while its credential and launch record carried none. The launcher now sets the variable to an empty value, andconfigFromEnvfalls back to the persona file or join link only when the variable is unset. A hand-driven session that exports one of these variables as an empty string now gets an empty list instead of the persona's. -
An endpoint watching the channel registry now reports a registry entry it cannot decode as a
warningthat names the key and the decode error, and drops that entry from its cache. It used to keep the config it held before and report nothing, sochannelDeliveryClass, the join backstop request and the leave tombstone acted on a delivery class the registry no longer held, while a fresh registry read already resolved the same entry to the default. A per-channel entry that does not decode now resolves to the space default, and a=defaultsentry that does not decode leaves the built-in defaults in force, until a valid entry is written. -
resolveServicenow bounds the whole resolve by itsdeadlineMs, contract store reads included. The describe spends from that deadline and each closure walk gets what remains of it, so a slow or stalled store read fails the resolve withdeadline-exceededat the caller's deadline. Each walk used to run under its own 30 second budget, so a resolve given 300 ms could take seconds. Cancelling a resolve through itssignalnow settles a store read in flight instead of waiting for it to return, through a new optionalsignalonfetchContractClosure. Every caller that resolves an endpoint inherits the bound, includinginvokeService,cotal describe,cotal invokeand thecotal statusmanager probe. A resolve given no deadline is bounded as a whole by the 10 second default the describe already used. -
writeSecretFilenow sets mode0600on the open file before it writes the bytes, so replacing an existing file no longer keeps that file's mode on POSIX. The mode passed at open applied only when the call created the file, and a secret written over a0644file stayed0644. This coverscotal mint --outover an existing credentials file andcotal mint --signer --force. -
writeSecretFileand the create-only secret write now share one private write path, so the Windows rule that removes a file whose ACL could not be hardened lives in one place. The reason the create-only path checks the name withlstatSyncon Windows is now written once, in its doc comment. No runtime change. -
deregisterServiceInstanceno longer deletes a successor's status. When a restart of the same instance re-registered and wrote itsreadystatus between the deregistration's spec read and its status read, the deregistration deleted that status and reportedsuperseded, so the successor kept serving while every class scatter,cotal psincluded, skipped it as never converged. A status that observed a later registration than the spec read is now left alone. Thesupersededcontract, thecotal deregister-instancerefusal and the CLI docs no longer say nothing was removed: the spec stays, and a status that was removed observed the inspected registration or an earlier one. -
An endpoint now marks every refusal it raises before running the command with
outcome: not-executed, as SPEC 13.3 requires. Before, only the bind fence, the unmapped-target refusal and the args-schema refusal said so, and a wrong envelope version, sender, operation, contract digest or target mode, a missing deadline, a refused target or authority check, or a body that is not JSON came back with no outcome, which a caller has to read asunknown. The serve loop now decides the outcome from whether it has dispatched to the handler, so a check added ahead of the handler is covered too. A refusal the command itself raises is unchanged. A refusal whose reply does not serialize or is too large to publish, which comes back asinternalorresource-exhausted, now keeps the outcome it stated instead of dropping it. -
@cotal-ai/coreexportsREMOTE_MANAGER_AUTHORITY_OPERATIONS, the frozen list of manager-service authority operations, andRemoteManagerAuthorityRequest["operation"]is derived from it. The auth request parser checks the operation against the same list and builds its refusal from it, so an operation added to core is admitted by the host instead of compiling cleanly and being refused at runtime with the old list. The refusal now readsoperation must be one of prepare, activate, renew, session, retire, renewStandingBundle, renewRunDriver, transferReader. -
An OpenCode seat whose turn outlasts the consumer's ack wait no longer loses the role request it is working on to another holder of the role. The connector acks a batch only when its turn ends, and the 60-second ack wait used to run out under a longer turn, so the broker handed the same anycast to a second worker while the first was still on it. The batch a turn carries is now held in flight, and while it is held the agent restarts each delivery's ack wait with JetStream's in-progress ack at half the wait. A failed turn or a stop releases the batch and a crashed seat stops renewing it, so it redelivers after one ack wait as before, and a success or a user Stop acks it. Queued messages are not renewed, and the bounded inbox no longer evicts a held message to make room for them, which had stopped its renewal and left the finished turn nothing to ack. Renewal stops for good once the agent can no longer vouch that it still holds a copy: the wait ran out between renewals, the link was down past it, or the copy's connection was torn down. A durable
Deliverynow carriesredelivery(the broker's delivery count, the consumer's ack wait, andworking()), anInboxItemcarriesdeliveryCount, and a frame marks a copy the broker delivered more than once as redelivered. Delivery stays at-least-once: a request can still run twice, so work with side effects that must not repeat needs its own ownership or idempotency key. -
The cotal config reader now refuses a
spawnthat is not an object and aspawn.envthat is not a list of non-empty names, with the file and the field named, as it already does formodelPolicyandconnectors.<name>.mcpServers. Before, a stringspawn.envwas spread into one-letter names, so a seat received every one-letter variable the string spelled and not the one the operator named. A non-string entry or an object crashed every spawn and resume with a bareTypeError, and a non-objectspawnwas ignored. -
The spawn-name actor-token smoke parses the CLI's
spawn.tsand readsspawnNameErrorfrom the value imports of its@cotal-ai/coreimport declarations, so import-shaped text in a string or comment does not count. The cell used to search a fixed 400-character window before the first such import's closing brace, so it failed whenever the import list grew and pushed the name out of that window. -
A
conclavenow asks the host's stop before it opens, as every other effect does. A run whose driver has asked it to stop (an operator pause or a passed work horizon) is released (L5012) at the next conclave instead of opening it, and a program made only of conclaves no longer runs to completion after the stop. A settled conclave still replays under a stop. -
PRIMITIVES,EVENT_CONSTRUCTORS,PURE_PRIMITIVESandFORBIDDEN_NODESare now frozen through every row and nested array. A write to a row, or to thecalleea validationLangErrorcarries, throws instead of changing whatvalidateaccepts or reports for the rest of the process. -
cotal statusand thecotal setupcard now share one test for whether the web extension is installed: a package in the extensions manifest that providesweband is on disk. A manifest entry whose package directory is gone no longer readsinstalledin status while the card readsnot installed. A web package record that cannot be read is no longer reported as not installed: status names the error on itsWeb extensionrow and still prints theWeb processrow, and the setup card names it on its web row, also while the dashboard is listening.loadExtensionsManifestandinstalledExtensionVersionnow treat only a missing file as absent, so an extensions or package directory that cannot be searched throws its permission error instead of reading as no extensions or not installed. -
cotal status --componentsnow names aweb.sessionthat exists but cannot be read, for example after an ownership or mode change: the web row readsrefused · web.session unreadable: <error>. The reader used to treat every read error as no record, so a live dashboard readrefused · probe refused (no bound address recorded), and theWeb processrow and thecotal setupcard readdown. Those two rows now name the unreadable record as well. Only a missing, empty or partialweb.sessionstill reads as no record.cotal web --detachprints the launch link from the record that proved the dashboard ready instead of readingweb.sessionagain, so a read error after that point cannot report a failed start over a running dashboard. -
loadSeatWriterGenerationreads each seat writer generation through the same record reader as every other auth record. A generation entry that is a symlink, a directory or a FIFO is now refused as not a regular file instead of being followed, socotal down --preserve-stateno longer stamps a checkpoint with a generation read through a link. A generation file that does not parse is reported in the shared record message. -
Keep MCP alive while event recording waits for an initial mesh connection or a reconnect. Resume queued event publication when both the mesh binding and transport recover, and cancel the wait on shutdown without weakening required-recording failures.
-
The Claude Code event mapper now exposes only what the connector calls:
mapandforgetOpenRun. It dropscloseOpenRun,openRunanddiagnose, which nothing shipped called. TheStopandStopFailurehooks close a session's last run through the event holder, and the mapper's header now says so instead of saying that run never closes. No behavior changes. -
Correct workflow tool guidance for managed user-auth agents using their own issued participant-manager authority. Preserve run capability and unsupported-host refusals.
-
An OpenCode launch no longer refuses to start because of a recorded server that exits during the liveness check.
psalso fails for a pid that is gone by the time it runs, and that failure used to read as a server the platform could not inspect, so the launch failed withagent "<name>" is already running. The check now probes the pid again after a failedps, and only a pid that is still present keeps the fail-closed answer. -
An OpenCode agent launch no longer fails with
EISDIRwhen an empty directory sits at the agent'sserve.pid. The launcher now treats that directory as no record, removes it, and starts the server, and a directory that vanishes before that removal also counts as no record. A directory that holds files is refused withENOTEMPTYand left in place, and an unreadable record still fails the launch. -
Remove
allowManagerAuthorityfrom the exchange policy thathandleManagerServiceAuthoritytakes. Both exchange faces set it totrue, so its refusal could never fire, and the route table alone decides which face servesPOST /manager-service-authority. The docs and source comments now list that route on the public listener, which has always served it. A policy object literal that setsallowManagerAuthorityno longer compiles, and a JavaScript caller that set it tofalseis no longer refused by the handler; see the upgrading guide. -
Issue managed seats' manager-caller run authority when their current persona scope and fresh same-owner parent grant both carry run. Preserve the signed permission ceiling, actor-row lifecycle source, interactive issuance and ordinary legacy commands.
-
Add an owner-bound platform supervisor authority door to the hosted auth service. It reuses native manager registration and renewal, checks a current administrative assignment, confines issuance to one owner and lifecycle, and records the registration credentials' signed permission ceilings before returning material. Recorded permissions match the authority-plane signed native set at issuance and every renewal without widening.
endPlatformSupervisorAssignment(owner)ends an assignment the host recordedended: it retires the manager gate and the issued generations, so registration, activation and renewal refuse previously returned material by name before it expires. -
cotal actor revokenow mints its live-connection eviction credential with a 60 second lifetime instead of the supervisor profile's 24 hour default. The revoke-time eviction, the barrier evictors and the liveness oracles that call the delivery daemon'sctl.delivery-adminrail now share one connection helper, so the lifetime and the non-participating endpoint options are decided in one place. -
The auth-ledger and records scanners now run every sealed scan through one shared plane-guard helper,
guardedScan, besideScanGuard. It used to be written out three times: once in the ledger scanner and once in each of the records scanner's obligation and manager goal-index scans. A change to the before-and-after claim check is now made in one place. No behavior changes. -
A
renewRunDriverrenewal now checks the run it renews through oneholdsRunFencepredicate in@cotal-ai/auth, read through one run observer in the auth service. The renewal decision and the re-check right before issuance each kept a hand-written copy of the read and of the run fence comparison, so a change to what makes a run renewable could reach one copy and leave the other weaker or stricter without any suite noticing. Both still refuse with their ownconflictmessage. -
The hosted auth fence smoke takes its injected-store baseline after each plane's first start, which now puts the plane's instance identity into the store, so its store cells check that the fence and close write nothing on top of that record.
-
The CLI now decides whether a durable
cotalis on PATH with the sharedresolveOnPath, in one place. Before,cotalOnPath()kept its own scan that counted a directory namedcotalas installed, so with such a directory on PATH, or with.on PATH in a folder holding acotal/checkout, every hint printed a barecotal ...the shell could not run andnpx cotal-ai setupskipped the global-install offer. On Windows it now followsPATHEXTlike every other PATH lookup. The recovery hint for an older binary no longer names npx's transientcotalshim when.is on PATH. -
A static-auth foreground
cotal spawnnow deletes the agent's broker durables and read-ACL row when it exits even if its creds file cannot be removed. The retirement used to stop at a failed file removal (a read-only creds directory, a directory in the file's place), so the agent'sdm_anddlv_durables and ACL row stayed on the broker and the removal error escaped the spawn. The secret delete, the file removal and the broker teardown now each run, and every failed step is reported in one line. -
A foreground
cotal spawnnow resolves its--share-toolsselection before it provisions the agent. A selection naming a server the config does not declare used to refuse after provisioning and outside the launch rollback, so the refusal left what provisioning had created behind, such as a remote user-mode spawn's actor-token and sentinel-creds files. The refusal text is unchanged. The spawn also reads the cotal config once, so the model policy and the launch use the same file contents. -
A manifest
broker.idpthat embeds credentials (https://user:pass@host/...or the token formhttps://token@host/...) is now refused withbroker.idp must not embed credentials, the same rulebroker.serversalready followed. It used to pass validation, andcotal up -f --dry-runprinted the credential in its plan line. The refusal names the field and never repeats the value. -
cotal service statusnow refuses a service unit or launchd agent that records its mesh but no absolute root, with the uninstall-and-reinstall remedy. Before,--jsonreported a unit with no root as installed with no root and no manager record, the human output crashed withCannot read properties of undefined (reading 'state'), and a recorded root that was not an absolute path read the manager pidfile relative to the current directory. An installed status now always carries its unit, root and manager record. -
Foreground
cotal upandcotal up --detachnow run the steps between spawning nats-server and serving it through one sequence:.cotal/nats.pid, readiness, the broker version read and the server name check of a resumed or restored listener. A foregroundupwhose broker is below the 2.12 floor used to exit with the broker still running and.cotal/nats.pidrecorded but no mesh entry. It now stops the broker and removes the pidfile, as--detachdid. A foreground resume aftercotal down --preserve-statenow refuses a spawned listener that reports a foreign NATS server name, which only--detachchecked before. A foregroundupwhose broker never answers now removes.cotal/nats.piditself.up --detachnow writes.cotal/nats.pidas soon as the broker spawns, as foregroundupdoes, socotal downcan stop a broker whoseupdied before it was ready. When any of these failures stops a broker that ignores SIGTERM,upnow sends SIGKILL and removes the pidfile only once the broker has exited, where both modes used to exit with it still holding the port. -
The
useMesh()header comment, which ships in the CLI'sdist/console/mesh.js, no longer says theMeshViewmodel lives in@cotal-ai/core. It now points at../view/mesh-view.tsin the CLI package, where the class is defined. No runtime change. -
The
startDeliveryServicehandle'sclose()anddrain()now reject when the instance did not give its shard lease back: the lease row is still held after the close, by another holder or because the release did not commit, or the broker could not confirm the release. They used to resolve in every case, so a host that started a successor at once could be refused with "a live lease already exists" without any prior signal. The rest of the teardown still runs, and the bucket TTL still expires a row the instance left. A failed start keeps its own error and logs a release that also failed. -
cotal feedback-intakenow refuses a--portthat is not a decimal number from 1 to 65535 before it probes the broker, with an error that names--port. An out-of-range port such as70000used to pass argument parsing, so the intake connected and announced itself on the mesh beforelisten()failed withoptions.port should be >= 0 and < 65536. A hex or exponent spelling such as0x1f90or8080e0was accepted and bound that port. -
Add explicit pooled
ManagerOptions.execution: "none"with no Runtime object, early seat and workflow refusals, and immutable per-instance execution admission. Native control registration, renewal, goal recovery and maintenance remain available. Genuine selected participant Managers keep their own execution and terminal custody. Default runtime behavior is unchanged.Manager cluster revision 25 requires
execution,runHostingandterminalSessionsin status and adds custodynone. Callers must fetch the new closed output contract. -
An
askattempt and an escalatedcheckpointnow relay the instant their pause denies at, and the manager holds the relay to that instant. The relay used to send a duration the manager counted from its own acceptance, so the manager could still serve an attempt after its pause had expired, by the submit's round trip plus clock skew, or by up to a second from a one-second floor. The manager'sturncommand takesdeadlineAtas an alternative todeadlineMsand refuses a relay whose deadline has already passed withdeadline-exceeded. The run reads that refusal as nobody left to tell only when its own clock also shows the deadline passed. Anaskwhose deadline passes before its attempt's pause is minted now ends with its ownask-deadlineL4006 instead of an L4000 from the refused mint. -
cotal deregister-instanceand the manager's clean stop read the issuance-gate generation through core'sreadEndpointGateGeneration. When the instance holds its governance slot and its gate is absent or carries a delete marker, the refusal's diagnostic text now comes from core's reader rather than a hand-rolled "no issuance gate" message. The error class is unchanged: core still wraps the reader failure asunavailable. -
The events-grant smoke's two own-channel spawns now keep the persona's
workread set next to the foreign event channel, so the read-list check admits them and the own-channel rule is what refuses them. The suite is green again and its section 9 and open-mesh cells run. -
Refuse spawning another principal's owned persona on user-auth meshes unless the authenticated caller has current admin reach. Hosted runs use their admitted caller and the existing catalog visibility policy before connector loading or enrollment. Unowned operator personas and independently authorized manifest launches keep their behavior.
-
The manager's spawn provisioner connection now opens through the same
withScopedEndpointhelper as the delivery-admin evictors and the liveness probe. Before, it built its endpoint by hand with noerrorlistener, so a connection error on it, such as a broker permission violation during onboarding, ended the manager process with an unhandlederrorevent, and a failed stop replaced the onboarding result or error with the stop error. The provisioner credential keeps its five-minute lifetime. -
The manager's remote requests now take their
identitiesrecord from one function,publicIdentities, instead of nine hand copies. Seven of the copies built the record from the identity state's own keys behind a type cast, so a change to the identity set still compiled there and sent a record the host refuses, and a state with its keys in another order sent identities that the manager's own result checks would not match against the host's echo. The function names the five identities in the order the host echoes them, so a change to the set now fails to compile at that one place. -
A name held pending retirement keeps the departed seat's whole teardown target, and a same-name spawn or a resume re-drives that target unchanged. Before, both re-drives rebuilt it field by field and dropped the seat's recorded runtime reference, so under tmux a same-name spawn re-drove a static retirement that skipped the reap and freed the name while the predecessor seat still ran. The resume re-drive also dropped the launch's subscribe channels, which name the membership rows its teardown deletes.
-
Fix a hosted
checkpointwithonExpiry: "escalate"failing L4000 every time its first attempt expired. The escalated attempt read the first attempt's binding as its own, so it armed at the first attempt's already-passed deadline and never recorded its own. Each attempt now binds its index with its deadline: the escalation opens with a freshtimeout, records its addressee and deadline, and a resumed attempt keeps the deadline it recorded.
What's Changed
- fix(cli): stop the manifest broker.idp refusal from printing the value by @davidfarah2003 in #3333
- fix(orca): bound the driver's read-only CLI calls so a stalled Orca app cannot block the manager by @davidfarah2003 in #3334
- fix(website): resolve docs site links by repository path by @davidfarah2003 in #3338
- fix(connector-core): refuse unrecognised values in the connector on/off env flags by @davidfarah2003 in #3343
- feat(linear): serve Linear's hosted MCP server as a Cotal endpoint by @davidfarah2003 in #3339
- fix(core): freeze REMOTE_MANAGER_IDENTITY_NAMES at its declaration by @davidfarah2003 in #3346
- fix(examples): refuse an unknown persona in face-term instead of rendering ray by @davidfarah2003 in #3349
- fix(manager): state the readiness latch ordering in one short comment by @davidfarah2003 in #3350
- fix(core)!: remove Pane.confirm and the layout providers' blind Enter timers by @davidfarah2003 in #3354
- fix(runtime): route every poll and retry wait through one unref'd delay by @davidfarah2003 in #3358
- fix(core): describe the ep rows each control credential holds in the provision comments by @davidfarah2003 in #3359
- fix(auth): check the manager-service authority and maintenance envelopes through the shared core parser by @davidfarah2003 in #3364
- fix(web): judge the dashboard pidfile with the workspace pid contract by @davidfarah2003 in #3367
- fix(web): state the activity aggregation and membership route contracts in the present tense by @davidfarah2003 in #3366
- fix(remotion): pick the unicast card's addressee by name by @davidfarah2003 in #3374
- fix(connector-opencode): state the teardown rule without counting its callers by @davidfarah2003 in #3377
- fix(cli): state the ext remove labelling rule in one comment by @davidfarah2003 in #3383
- fix(remotion): draw the multicast and anycast fans through one shared wire helper by @davidfarah2003 in #3385
- fix(remotion): sequence each explainer snippet at the length it exports by @davidfarah2003 in #3384
- fix(remotion): remove the unused variant 2 wordmark and mark from the header helpers by @davidfarah2003 in #3389
- fix(seat): record an unmatched startup confirmation as the exit diagnostic by @davidfarah2003 in #3390
- fix(remotion): measure the anycast reviewer bracket from the peer pool by @davidfarah2003 in #3392
- fix(cli): name an ambiguous process record on its status row instead of aborting by @davidfarah2003 in #3393
- fix(core): check the manager-caller bearer binding in one core function by @davidfarah2003 in #3391
- fix(core,auth,delivery): check account nkeys through one exported predicate by @davidfarah2003 in #3399
- fix(connector-core): drop the reviewer handle from the JsonlFileSource seal doc by @davidfarah2003 in #3406
- fix(connector-core): state the principal lock's release boundary without its earlier-implementation narration by @davidfarah2003 in #3409
- fix(connector-core): state the subject-frontier comments as current rules by @davidfarah2003 in #3415
- fix(auth): keep the hosted auth plane's instance identity in the injected store by @davidfarah2003 in #3413
- fix(core): drop plan labels from the goal-writer reconcile-index and own-gate comments by @davidfarah2003 in #3416
- fix(core): verify cluster manifests with the contract store's closed parser by @davidfarah2003 in #3420
- fix(core): share one lazy service contract table across auth, manager and linear by @davidfarah2003 in #3423
- fix(remotion): read the wordmark width from WM_WIDTH at every call site by @davidfarah2003 in #3421
- fix(connector-core): name the DurableSource.read contract in the WAL frontier guard comment by @davidfarah2003 in #3424
- feat(auth): revoke hosted runs through the issuing host by @davidfarah2003 in #3419
- fix(manager): report a refused runtime stop on shutdown and failed resume by @davidfarah2003 in #3427
- fix(cli): read the launchd provenance header back through the comment syntax that wrote it by @davidfarah2003 in #3437
- fix(manager): free a self-exited seat on runtimes that cannot attach by @davidfarah2003 in #3432
- fix(web): escape dashboard text through one escaper shared from parts.js by @davidfarah2003 in #3438
- fix(remotion): pick the anycast claimer from the shared presence by @davidfarah2003 in #3442
- fix(workspace): read seat writer generations through the shared auth record reader by @davidfarah2003 in #3446
- fix(cli): point the useMesh header at the MeshView model in the cli package by @davidfarah2003 in #3448
- fix(core): mark every refusal the serve loop raises before dispatch not-executed by @davidfarah2003 in #3453
- fix(cli): name an unreadable web.session instead of reading it as no recorded address by @davidfarah2003 in #3455
- test(auth): take the hosted fence smoke's store baseline after each first start by @davidfarah2003 in #3456
- fix(auth)!: drop the manager-service authority flag that no face turns off by @davidfarah2003 in #3463
- fix(auth): derive the manager-service authority operations from one core list by @davidfarah2003 in #3464
- feat(auth): owner-bound platform supervisor authority with an ended-assignment fence by @davidfarah2003 in #3462
- refactor(auth): run every sealed scan through one plane-guard helper by @davidfarah2003 in #3466
- fix(cli): decide whether a durable cotal is on PATH through the shared resolver by @davidfarah2003 in #3467
- fix(manager): build remote request identities in one typed function by @davidfarah2003 in #3469
- fix(connector-opencode): read a recorded serve that exits before ps runs as not running by @davidfarah2003 in #3472
- fix(delivery): refuse a feedback-intake --port that is not a decimal port from 1 to 65535 by @davidfarah2003 in #3473
- refactor(core): give secret-fs one fail-closed write path by @davidfarah2003 in #3474
- fix(cli): refuse a service unit with no absolute recorded root in service status by @davidfarah2003 in #3477
- fix(runtime): hold an ask's relay to the deadline its pause denies at by @davidfarah2003 in #3478
- fix(core,manager,delivery)!: name an injected SecretStore through one core rule by @davidfarah2003 in #3480
- fix(cli): share one web-installed predicate between status and the setup card by @davidfarah2003 in #3482
- fix(core): refuse a malformed spawn block when the cotal config is read by @davidfarah2003 in #3483
- fix(release): refuse a package with no npm record before the OIDC exchange and derive the publishable set by @davidfarah2003 in #3481
- fix(lang): deep-freeze the exported syntax tables so a row write cannot change validation by @davidfarah2003 in #3487
- fix(core,manager,runtime): cite SPEC sections and symbols instead of line numbers in comments by @davidfarah2003 in #3486
- fix(connector-claude-code): narrow the event mapper to what the connector calls by @davidfarah2003 in #3488
- fix(core): bound the whole resolveService by its deadline, store reads included by @davidfarah2003 in #3485
- fix(auth): check the renewRunDriver run fence through one predicate by @davidfarah2003 in #3491
- fix(connector-opencode): remove an empty directory at serve.pid instead of failing with EISDIR by @davidfarah2003 in #3490
- fix(cli): refuse a manifest broker.idp that embeds credentials by @davidfarah2003 in #3497
- test(core): parse the spawn-name smoke's CLI core imports instead of matching text by @davidfarah2003 in #3498
- fix(core): leave a successor's status alone when deregistration races its registration by @davidfarah2003 in #3499
- fix(core): set a secret file's mode before writing over an existing file by @davidfarah2003 in #3500
- fix(manager): re-drive a retirement hold with its whole teardown target by @davidfarah2003 in #3501
- fix(connector-core): forward an empty launch ACL list instead of dropping it by @davidfarah2003 in #3503
- fix(runtime): bind each checkpoint attempt's own deadline so an escalation opens by @davidfarah2003 in #3504
- fix: preserve session custody and MCP reconnects by @davidfarah2003 in #3505
- fix(connector-opencode): keep a running turn's role request from reaching a second worker by @davidfarah2003 in #3509
- feat(auth): issue run authority to eligible managed seats by @davidfarah2003 in #3510
- feat(manager)!: add explicit pooled no-execution control by @davidfarah2003 in #3511
- fix(manager): enforce owned persona visibility before spawn by @davidfarah2003 in #3512
- test(connector): verify managed agents drive owned workflows by @davidfarah2003 in #3513
- fix(auth): bound the revoke-time eviction credential to 60 seconds by @davidfarah2003 in #3517
- fix(manager): read the deregister issuance gate through core's reader by @drakeo338 in #2694
- fix(cli): carry a detached resume for the harness the manager resolves by @davidfarah2003 in #3520
- fix(manager): open the spawn provisioner connection through the scoped endpoint helper by @davidfarah2003 in #3521
- test(manager): keep the persona read set in the events-grant own-channel spawns by @davidfarah2003 in #3525
- fix(core): report and drop an undecodable channel registry entry by @davidfarah2003 in #3530
- fix(lang): ask the host stop before a conclave opens by @davidfarah2003 in #3532
- fix(cli): run foreground and detached up through one spawn-to-ready sequence by @davidfarah2003 in #3538
- fix(delivery): reject a hosted close that did not release the shard lease by @davidfarah2003 in #3537
- fix(cli): run the foreground retirement's broker teardown when the creds removal fails by @davidfarah2003 in #3540
- fix(cli): resolve foreground --share-tools before provisioning by @davidfarah2003 in #3543
Full Changelog: v0.73.0...v0.76.0