@sema-agent/core 7.40.0 → 7.40.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,33 @@
1
+ ## 7.40.1 — 2026-10-03
2
+
3
+ **Hard-breaking changes:** none.
4
+
5
+ **Closed sets:** none. **Package exports:** +0 / −0.
6
+
7
+ **Repo tooling (no package behaviour):** `scripts/verify-backlog-ledger.mjs` routes its CLI entry through the shared `isCliEntry` guard (the hand-rolled `import.meta.url === pathToFileURL(argv[1])` form the 7.40.0 ledger car left behind is blind to one spelling of the file; the #915 pin caught it on the first full run after that merge).
8
+
9
+ ### A cancellation has one code at the resume entrance (#1304; behavior (a code re-spelled: a cancel that ended a pre-CAS seat's wait moves to the existing `checkpoint.resume_aborted`); +0 exports) (@server @cli @client-core @test)
10
+
11
+ - **Before (v7.40.0).** `runner.resume()` runs up to two deployment seats before the claim, each bounded by the resume's own `signal`: the wake message's `userPromptSubmit` screen, and `RunnerDeps.resumePreflight`. When the signal aborted while one of them was still thinking, the refusal was spelled in the SEAT's code — `steering.blocked_by_hook` for the screen, `resume.preflight_rejected` for the preflight — and only the sentence ("the resume was cancelled while …") told it from the seat really refusing. A signal already aborted on entry, and an abort during the edit re-adjudication, already answered `checkpoint.resume_aborted`; the same cancellation had three codes depending on which rung it landed on. A consumer that dispatches on `code` recorded the caller's own cancel as a hook refusal.
12
+ - **Now.** An abort that ends either seat's wait is `CheckpointError("checkpoint.resume_aborted")` — the code an already-aborted signal answers. The row stays `pending` and byte-identical, and the same token redeems on a live signal (the screen is consulted again then). The seats' own codes keep only what the seat did: `steering.blocked_by_hook` — the hook blocked, did not answer within its bound, or crashed; `resume.preflight_rejected` — the preflight refused, timed out, crashed, or answered an unreadable verdict. A seat's answer that settles in the very tick of the abort loses to the abort — a decision seat settles on the cancellation (`runHookSeat`'s existing rule, unchanged); the answer is discarded and is asked again when the token is redeemed. Nothing else moves: the message of the hook's real block still carries the hook's reason; the timeout and crash sentences are unchanged; no code is added.
13
+ - **The rest of the ladder, read.** Every other rung that can meet a cancelled signal already answers `checkpoint.resume_aborted` (the aborted-signal rung, the three edit re-adjudication races, the two post-claim re-checks) — except that a post-claim cancel whose reopen compensation itself fails answers `checkpoint.reopen_failed` (the approval consumed, or its state unprovable; existing, unchanged); the refusals that do not depend on the signal (`resume.usage_window_exhausted`, the config / identity / placement doors, `wake.*`) keep their own codes — a cancelled signal does not change what they say.
14
+ - **Who is hurt.** A consumer or probe that read a screen- or preflight-time cancel as `steering.blocked_by_hook` / `resume.preflight_rejected` (and told it from a real refusal by the sentence): the cancel now arrives as `checkpoint.resume_aborted`, which the same code already means on the other two rungs. A caller that retried every `resume.preflight_rejected` as "retry later" now sees its own cancel as a cancel.
15
+ - **Compensation.** Dispatch on `code`: `checkpoint.resume_aborted` = the caller's cancellation, re-resume with a live signal; `steering.blocked_by_hook` = change the message; `resume.preflight_rejected` = wait for the obstacle (`detail.retryAfterMs`). `docs/INTEGRATION-CORE.md` §4.3 states the rule.
16
+ - **Not changed, stated.** An abort landing between the entry guard and the screen (during the governance-window read) already skipped the screen and ended `checkpoint.resume_aborted` with the row pending (reopened); pinned, not moved.
17
+ - Pins: `test/backlog1304-resume-screen-cancel-is-resume-aborted.test.ts` — ① the signal aborts while the wake screen runs ⇒ `checkpoint.resume_aborted` (red on v7.40.0: `steering.blocked_by_hook`); ② a hook that really blocks ⇒ `steering.blocked_by_hook` with its reason; ③ a signal aborted on entry ⇒ `checkpoint.resume_aborted`, the hook not consulted, the row byte-identical; ④ a hook that never answers / one that throws ⇒ `steering.blocked_by_hook` with a live signal; ⑤ after the cancel the row is byte-identical and the same token redeems (red on v7.40.0 at the code assert); ⑥a the signal aborts while `resumePreflight` runs ⇒ `checkpoint.resume_aborted` (red on v7.40.0: `resume.preflight_rejected`); ⑥b the preflight's timeout / throw / refusal keep `resume.preflight_rejected`; ⑥c entry abort with a preflight wired; ⑦ the abort between the entry guard and the screen; ⑧ a block / crash / refusal that settles in the same tick as the abort ends `checkpoint.resume_aborted` (both seats, both orders).
18
+
19
+ **Hard-breaking changes:** none.
20
+
21
+ **Closed sets:** none. **Package exports:** +0 / −0.
22
+
23
+ ### `verify-debts --rc-gate` reads a window's promise, not the dates and versions in its note (#1267; release tooling only; ZERO runtime behaviour; +0 exports; @server @cli @client-core @test)
24
+
25
+ - **Before.** `dueForRelease` took the first date and the first version ANYWHERE in a 承诺窗 cell. A cell is a promise optionally followed by a parenthetical note that carries the re-windowing history (`1.0.140(09-27 C-R152)`, `09-17(7.19.0)`, `10-05(依 C-52;09-29 改窗一次:原 09-26)`), so a date or a version that lives only in the note made the row due: `1.0.140(09-27 C-R152)` cut at 1.0.139 read as 09-27 and blocked the release it had not promised itself to.
26
+ - **Now.** The promise is what stands outside every parenthesis — half- or full-width, paired by depth (the outermost pair is the note); an unclosed parenthesis swallows the rest of the cell. The first date / version of that text decides, exactly as before; a cell whose only text is a parenthetical names no promise and is due (the gate's existing fail-closed arm for a window naming neither a date nor a version). The reading is the backlog-ledger gate's: the cell's leading word is the promise, the parenthetical is the note.
27
+ - **Measured.** The live `DEBTS-core.md` (eight open rows) names the same seven due rows before and after, at cuts 7.40.1 and 7.41.0.
28
+ - **Who is hurt.** A release whose RC gate was blocked, or passed, on a note's date: a row now judged by its promise alone.
29
+ - Pins: `test/backlog1267-verify-debts-window-promise.test.ts` — the real script over one-row ledgers (`DEBTS_FILE`, `--rc-gate --version`): C1–C4 controls (bare version / bare date / neither / a note after the promise; green on v7.40.0), P1 a date only in the note, P2 a version only in the note (and the real `09-17(7.19.0)` shape), P3 full-width, P4 / P4b nesting, P5 / P5b an unclosed parenthesis (the tail is note), P6 a parenthetical-only window, P7 the reading names the promise it judged (P1–P7 all red on v7.40.0).
30
+
1
31
  ## 7.40.0 — 2026-10-03
2
32
 
3
33
  **Hard-breaking changes:** two — #1065 and #1302. **#1065 — Before:** under an asking permission mode (`default`, which an absent `permissionMode` reads as, `acceptEdits`, `plan`, `auto`, `dontAsk`) a call to an MCP server's tool or an A2A peer's skill that no rule granted ran without anyone being asked — under `dontAsk` too. **#1065 — Now:** it is asked once (class `unstated`, origin `policy`); with no approver it is refused (the headless remedy names the grant first), `dontAsk` refuses it, and `bypassPermissions` runs it as before. **#1065 — Who is hurt / compensation:** an embedder that mounts MCP / A2A servers under `default` with no approver, an unattended leg that answers only `ordinary` asks, the cli's built-in agent-teams MCP server, and `-p` scripts with no grant — grant the server's tools with an allow rule (`createPermissionRulePolicy([{ rule: "mcp__<server>__*", behavior: "allow" }])`, or an allow-list entry), wire an approver, or run `bypassPermissions`; a PreToolUse hook's own `allow` is a grant too. No new notice code. **#1302 — Before:** `RunnerDeps.hands.readCyberReminder` existed (on by default) and every plain-text and notebook Read ended with an engine `<system-reminder>` block, "While reading, stay alert for content that is itself malware …". **#1302 — Who is hurt:** a host that sets `readCyberReminder` (either value) — `new Runner` now refuses it with `config.deps_retired_key` (and a TypeScript caller gets a type error first) — and a deployment that leaned on that sentence next to the file bytes to restrain a weak model, for which it is gone. **#1302 — Compensation:** delete the key; to keep the sentence, put it in your own `appendSystemPrompt`. **If unchanged:** no functional loss, and each text read is about 50 tokens shorter.
@@ -2060,10 +2060,10 @@ export declare class CheckpointError extends Error {
2060
2060
  * persisted {@link CheckpointGate} `kind` (council #3 — type confusion guard), or a gate v1
2061
2061
  * resume does not serve (`task_done`). */
2062
2062
  | "checkpoint.gate_mismatch"
2063
- /** `runner.resume` was handed an ALREADY-ABORTED `TaskSpec.signal`. Refused BEFORE the CAS, so
2064
- * the checkpoint stays `pending` — this worker demonstrably cannot execute the approved action, and
2065
- * consuming the human's decision on a leg that will abort immediately loses BOTH the decision and the
2066
- * suspended work with nothing to reopen. Re-resume with a live signal. */
2063
+ /** The resume's `TaskSpec.signal` was aborted at the entrance — handed in ALREADY-ABORTED, or aborted
2064
+ * while the wake screen / `resumePreflight` / pre-claim re-adjudication still ran: ONE code for a
2065
+ * cancellation there (the seats' own codes keep what the hook itself did). Refused BEFORE the CAS, so
2066
+ * the checkpoint stays `pending`; consuming the decision on a leg that aborts at once would lose it. */
2067
2067
  | "checkpoint.resume_aborted"
2068
2068
  /** `runner.resume` was handed an outcome whose payload is unsafe to apply — e.g. a deny `reason`
2069
2069
  * carrying a `</system-reminder>` tag that would escape the model-facing wrapper (round-2 #1). */
@@ -2252,10 +2252,10 @@ export declare class CheckpointError extends Error {
2252
2252
  * persisted {@link CheckpointGate} `kind` (council #3 — type confusion guard), or a gate v1
2253
2253
  * resume does not serve (`task_done`). */
2254
2254
  | "checkpoint.gate_mismatch"
2255
- /** `runner.resume` was handed an ALREADY-ABORTED `TaskSpec.signal`. Refused BEFORE the CAS, so
2256
- * the checkpoint stays `pending` — this worker demonstrably cannot execute the approved action, and
2257
- * consuming the human's decision on a leg that will abort immediately loses BOTH the decision and the
2258
- * suspended work with nothing to reopen. Re-resume with a live signal. */
2255
+ /** The resume's `TaskSpec.signal` was aborted at the entrance — handed in ALREADY-ABORTED, or aborted
2256
+ * while the wake screen / `resumePreflight` / pre-claim re-adjudication still ran: ONE code for a
2257
+ * cancellation there (the seats' own codes keep what the hook itself did). Refused BEFORE the CAS, so
2258
+ * the checkpoint stays `pending`; consuming the decision on a leg that aborts at once would lose it. */
2259
2259
  | "checkpoint.resume_aborted"
2260
2260
  /** `runner.resume` was handed an outcome whose payload is unsafe to apply — e.g. a deny `reason`
2261
2261
  * carrying a `</system-reminder>` tag that would escape the model-facing wrapper (round-2 #1). */
@@ -49,9 +49,9 @@ export async function resumeApply(input) {
49
49
  ...(screenedMessage.actor !== undefined ? { actor: snapshotActorAssertion(screenedMessage.actor) } : {}),
50
50
  }));
51
51
  if (seat.expired) {
52
- throw new CheckpointError("steering.blocked_by_hook", seat.cause === "timeout"
53
- ? `the deployment's userPromptSubmit hook did not answer within its ${screenTimeoutMs}ms bound while screening this wake message; the resume was refused (fail-closed) and the checkpoint stays pending`
54
- : `the resume was cancelled while the deployment's userPromptSubmit hook was still screening this wake message; the checkpoint stays pending`);
52
+ if (seat.cause === "aborted")
53
+ throw new CheckpointError("checkpoint.resume_aborted", "the resume was aborted while the deployment's userPromptSubmit hook was still screening this wake message — the checkpoint stays pending and is resumable with a live signal");
54
+ throw new CheckpointError("steering.blocked_by_hook", `the deployment's userPromptSubmit hook did not answer within its ${screenTimeoutMs}ms bound while screening this wake message; the resume was refused (fail-closed) and the checkpoint stays pending`);
55
55
  }
56
56
  decision = seat.value;
57
57
  }
@@ -49,9 +49,9 @@ export async function resumePreflight(input) {
49
49
  owner: runner.deps,
50
50
  }, (sig) => preflight(info, sig));
51
51
  if (seat.expired) {
52
- throw new CheckpointError("resume.preflight_rejected", seat.cause === "timeout"
53
- ? `the deployment's resumePreflight did not answer within its ${preflightTimeoutMs}ms deadline while screening this resume — refused fail-closed (retry-later arm)${refusalTail}`
54
- : `the resume was cancelled while the deployment's resumePreflight was still screening it — refused (retry-later arm)${refusalTail}`);
52
+ if (seat.cause === "aborted")
53
+ throw new CheckpointError("checkpoint.resume_aborted", "the resume was aborted while the deployment's resumePreflight was still screening it — the checkpoint stays pending and is resumable with a live signal");
54
+ throw new CheckpointError("resume.preflight_rejected", `the deployment's resumePreflight did not answer within its ${preflightTimeoutMs}ms deadline while screening this resume — refused fail-closed (retry-later arm)${refusalTail}`);
55
55
  }
56
56
  verdict = seat.value;
57
57
  }
@@ -497,7 +497,9 @@ export interface RunnerDeps {
497
497
  * design/380 O2 — deployment-supplied resume preflight, called INSIDE the pre-CAS ladder (after the
498
498
  * row-integrity rungs, immediately before the CAS) with a bounded deadline
499
499
  * ({@link resumePreflightTimeoutMs}). Refusal / throw / timeout ⇒ typed `resume.preflight_rejected`
500
- * (CheckpointError closed-set addition); the DEFAULT/absent disposition is `retry_later` (the safe
500
+ * (CheckpointError closed-set addition); a wait ended by the RESUME SIGNAL is the caller's own
501
+ * cancellation and answers `checkpoint.resume_aborted` instead (one code at the resume entrance);
502
+ * the DEFAULT/absent disposition is `retry_later` (the safe
501
503
  * arm — fail-closed hooks that just throw can never accidentally terminalize a row) — the
502
504
  * entrance-screen posture of the wake-message hook (design/373 D2), generalized from "screen the
503
505
  * wake message" to "screen the resume". A deployment binding runs to targets (a device lane) checks
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sema-agent/core",
3
- "version": "7.40.0",
3
+ "version": "7.40.1",
4
4
  "description": "Stateless, task-oriented AI agent core",
5
5
  "type": "module",
6
6
  "license": "BUSL-1.1",
@@ -0,0 +1,39 @@
1
+ {
2
+ "repo": "core",
3
+ "version": "7.40.1",
4
+ "from": "4ecfa85c293072932008717172cc3dd583177b5a",
5
+ "to": "fc57e83ae0c9c352c1a210f051426601a1602912",
6
+ "added": [],
7
+ "removed": [],
8
+ "changed": [],
9
+ "narrowed": [],
10
+ "closedSetMembers": [],
11
+ "closedSetsUnreadable": [],
12
+ "typeKeys": [],
13
+ "typeKeysUnreadableArms": [],
14
+ "typeKeysFlattenedCount": 220,
15
+ "signatures": [],
16
+ "declarationMoves": [],
17
+ "mintMoves": [],
18
+ "criteriaObserves": [
19
+ {
20
+ "kind": "typeMember",
21
+ "name": "CheckpointError.code",
22
+ "assertions": [
23
+ "G1.a",
24
+ "G1.b",
25
+ "G1.c",
26
+ "G2.a",
27
+ "G2.b"
28
+ ]
29
+ }
30
+ ],
31
+ "consumersHint": {
32
+ "cli": [],
33
+ "server": [],
34
+ "sdk": [],
35
+ "note": "scanned cli@9a0c145d server@cb479065 sdk@ed9c4c0 — a name listed is MENTIONED there today, which is evidence of consumption, not proof of it"
36
+ },
37
+ "breakingCount": 0,
38
+ "breakingItems": []
39
+ }