UNPKG

@sema-agent/core

Version:

Stateless, task-oriented AI agent core

706 lines (705 loc) • 23.2 kB
{ "repo": "core", "version": "7.31.0", "from": "dd49f2638b0c29a0ff735b8870b1534dce4e0485", "to": "v7.31.0", "added": [ { "name": "MEMORY_PROJECT_KEY_ABSENT_REASONS", "kind": "variable", "tier": "advanced", "at": [ "src/core/memory.ts:1091", "src/index.ts:1984" ], "criteriaCovered": false, "breaking": false }, { "name": "MemoryProjectKey", "kind": "type", "tier": "advanced", "at": [ "src/core/memory.ts:1103", "src/index.ts:1986" ], "criteriaCovered": true, "breaking": false }, { "name": "MemoryProjectKeyAbsentReason", "kind": "type", "tier": "advanced", "at": [ "src/core/memory.ts:1092", "src/index.ts:1985" ], "criteriaCovered": false, "breaking": false } ], "removed": [], "changed": [], "narrowed": [ { "id": "F3", "source": "behaviorFlips.summary", "text": "Additive deployment switch + one NARROWING (#1050; +1 `RunnerDeps` word, +1 config code; two refusal texts reworded, codes unchanged; +0 exports). (a) `RunnerDeps.fileHistoryCapture?: \"off\"` beside a real store: no run records (no first-touch, no boundary, no fork carry, no advisory; the leg's `wiring_manifest.fileHistory` reads `\"disabled\"`), and the store stays the restore seat — `restoreFiles` / `rewindFilesTo` converge to boundaries already in it. Every other value, and `\"off\"` with no real store (key omitted, or `fileHistoryStore: \"disabled\"`), refuses prepare `config.invalid_file_history_capture` before any store call. (b) `rewind.store_unconfigured` names its arm — an omitted store keeps `… this deployment wired no RunnerDeps.fileHistoryStore …`, a `\"disabled\"` seat says `… this deployment declared file history disabled (RunnerDeps.fileHistoryStore: \"disabled\") …` — and `rewind_snapshot.unresolvable`'s second sentence says boundaries exist only for turns that recorded history (KL-1047a closed). (c) NARROWING: `resumeAt` + `resumeAtMode: \"before\"` + `restoreFiles` converges to the target entry's OWN boundary or refuses `rewind_snapshot.unresolvable` with the files untouched (`entry \"<id>\" has no file-history boundary … never crosses into an earlier turn`); the fallback to the nearest boundary-carrying ancestor — which also reverted edits the kept conversation still shows — is removed (`rewindFilesTo` and `\"at\"` mode never walked). WHO IS HURT: a consumer matching the two refusal texts (switch on the code), a deployment writing `\"off\"` with no store, a consumer pinning the `config.*` code set, a caller sending a before-restore at a steer / follow-up entry or at a turn that recorded nothing. ORDER: core first. Residual KL-1050a." }, { "id": "F4", "source": "behaviorFlips.summary", "text": "Behaviour NARROWING (#1074; +0 exports, +0 wire keys): a stop ends the leg. A leg whose abort has fired issues no prompt — read at each leg's prompt door after everything that can fire it: the durable classifier denial-limit stop (inside the resume leg's decision application), a cancel landing while the approved call runs on a resume, while a parked steer is screened, or while the objective's image is fetched. `AgentHarness.prompt` mints its run controller before its own startup awaits, so a cancel landing while a prompt starts up reaches the loop, and a run aborted before its first turn ends `run aborted` (not `invalid_state`). After the durable stop: 0 model calls, 0 tool frames, one `done` carrying `classifier.denial_limit` and the notice's sentence, whatever limits are declared; a cancel before the prompt ends `failed` / `run aborted` with no model call. A continuation not sent stays owed: a steer parked on the consumed row is announced (`task.user_steer_undrained`), a review decision it would have delivered reopens its row, the objective leg publishes no `human_input` \"applied\" account, the suspended batch's unanswered siblings close \"never executed\". WHO IS HURT: a host or test that counted the post-stop turns or read a `limits.*` code off a stopped durable leg. Residuals KL-1074a–c." }, { "id": "F6", "source": "behaviorFlips.summary", "text": "Behaviour NARROWING (#1076b, #1080; +0 exports; +2 optional `MemorySessionHandle` keys `layerBaseline`, `accountLeg`; +0 wire keys; +1 incident code `memory.observation_settlement_unavailable`): bytes that appear in a read-only memory layer during a session are never adopted. A session's harvest compares each layer it holds read-only with a census taken at its materialize; every file whose bytes changed in that window and that no commit backs is recorded in the control plane (`layer-observations.json`). Every door through which uncommitted disk state enters the committed account consults it — the adopting read's edit / new-file / move arms, the lock-free retrieval face, a writer's harvest: a recorded divergence is NOT adopted — the committed copy is served, the file is left as found, and every session that meets it is told (`change NOT adopted: …` / `file NOT adopted: …`). A divergence nobody recorded (a git pull between sessions) is adopted as before; a commit that moves an entry's rev retires every record made against the old rev. While a transaction journal is pending the question is undecidable: the change is recorded UNDECIDED (never adopted meanwhile; `change NOT adopted yet …`); the first session that may write settles each undecided row after its preflight recovered the journal — a commit backing the bytes at their seat drops that row, a readable committed face that does not back them pins the row to the rev it read (an ordinary row from then on), an unreadable one keeps it undecided. A zero-copy backend without the committed-snapshot face (`committedSnapshotOf` — e.g. a wrapper that does not pass it through) records every such change undecided and never settles it; the engine states that ONCE per engine at materialize (`memory.observation_settlement_unavailable` on `MemoryEngineOptions.onIncident`). Writer presence (#1080): a writing session does not restore a read-only layer file while a session that writes that layer is live — liveness is the session-account row's leg (`terminatedAt` absent), never `closedAt` — it warns instead. WHO IS HURT: a legitimate write landing inside a session's window in a layer that session holds read-only (a git pull during it) is recorded and not adopted until a commit moves its rev or its bytes change (KL-1076b-a); a host relying on a zero-copy mount rewriting a hand-edited entry file into canonical bytes. Residuals KL-1076b-b – KL-1076b-o." }, { "id": "F7", "source": "behaviorFlips.summary", "text": "BREAKING (type: the optional `ResolvedCrossSessionInboundSetting.deprecatedLayers` is removed) + behaviour NARROWING (#1078; +0 exports): `crossSessionInbound`'s retired spelling `accept` reads exactly like any other unrecognized value — the layer is reported in `invalidLayers` with `decidedBy: \"invalid\"`, and the existing fail-closed rule forces `hold` whenever the standing value is looser (the drain holds each record with the `invalid-setting` cause, disclosed as `peer.inbound_disposition` with `disposition: \"held\"`); the per-leg spelling announcement and the module-local `CROSS_SESSION_INBOUND_DEPRECATED_SPELLINGS` (never exported) are gone. THREE SENTENCES — WHO IS HURT: a settings layer (managed / user / repo) still spelling `accept`, silently migrated to `next-turn` with one warning per leg on 7.30.x, now holds every cross-session message it would have delivered; a reader of `deprecatedLayers` gets a type error. COMPENSATION: settings-schema 6.0.0 already rejects `accept` at the schema door, so no currently valid settings file carries it, and the hold is announced through the same invalid-setting arm a typo takes. UPGRADE: write `next-turn` in every layer that says `accept`, and drop reads of `deprecatedLayers`." }, { "id": "F8", "source": "behaviorFlips.summary", "text": "Additive (#1079; +0 exports; +2 optional type keys; no checkpoint-version bump) + one NARROWING (#1088, tightening only). (a) The durable park row carries the mandate twin: `PendingAction` (`tool_approval` arm) `.mandated?: true` and `CheckpointSummary.mandated?: true` — present ⇔ no persisted allow rule and no standing answer may retire the parked question; `true` only, never `false`; minted from the SAME clearance-facts object the row's rule-offer factory reads, through the derivation the live card's `AskRequest.mandated` comes from; the summary screens it to the literal `true`. Three independent facts now ride a parked card: `requiresRealApproval` (only a person — implies the mandate), `mandated` (no rule), `ruleOffersAbsence` (what the offer lane has to give). Display metadata: no gate, CAS or resume path reads it; a row minted before it reads absent (unreported). (b) #1088: when a JSON-fidelity checkpoint backend's projection moves the parked value and the deployment's policy re-judges the stored shape, the re-judgment's ask JOINS the gate's facts, tightening only — its `requiresRealApproval` makes the park `irreversible_ask` with `gate.realApproval` (worded by the parked ask's own origin) and the row's `requiresRealApproval`; its mandate and an explicit ask-rule match join the clearance facts. A demand the first judgment already made is kept; a re-judgment that allows or asks plainly changes nothing. WHO IS HURT: (#1088) a budget resolver that auto-approved such a park (`human` → `irreversible_ask`) no longer may; a custom `CheckpointStore` must round-trip `mandated` (the store-contract kit now fails a whitelisting serializer)." } ], "closedSetMembers": [ { "set": "ENGINE_NOTICE_CODES", "at": [ "src/core/governance-codes.ts:317" ], "newSet": false, "added": [ "config.secret_env_scrubbed" ], "removed": [], "breaking": false, "criteriaCovered": true }, { "set": "SessionAccountWrite", "at": [ "src/core/memory-engine/delegation-settlement.ts:680" ], "newSet": true, "added": [ "absent", "stale", "written" ], "removed": [], "breaking": false, "criteriaCovered": false } ], "closedSetsUnreadable": [], "typeKeys": [ { "type": "CheckpointSummary", "at": [ "src/core/checkpoint-store.ts:2090" ], "added": [ "mandated" ], "addedDetail": [ { "key": "mandated", "optional": true } ], "addedRequired": [], "removed": [], "breaking": false, "criteriaCovered": true }, { "type": "MemorySessionHandle", "at": [ "src/core/memory-engine/types.ts:403" ], "added": [ "accountLeg", "layerBaseline" ], "addedDetail": [ { "key": "accountLeg", "optional": true }, { "key": "layerBaseline", "optional": true } ], "addedRequired": [], "removed": [], "breaking": false, "criteriaCovered": true }, { "type": "NodeLspManagerOptions", "at": [ "src/engine/lsp/node-lsp-manager.ts:77" ], "added": [ "onNotice" ], "addedDetail": [ { "key": "onNotice", "optional": true } ], "addedRequired": [], "removed": [], "breaking": false, "criteriaCovered": true }, { "type": "ParentSpecSeat", "at": [ "src/core/parent-spec-seat.ts:67" ], "added": [ "fileHistory" ], "addedDetail": [ { "key": "fileHistory", "optional": true } ], "addedRequired": [], "removed": [], "breaking": false, "criteriaCovered": false }, { "type": "PendingAction", "at": [ "src/core/checkpoint-store.ts:962" ], "added": [ "tool_approval.mandated" ], "addedDetail": [ { "key": "tool_approval.mandated", "optional": true } ], "addedRequired": [], "removed": [], "breaking": false, "criteriaCovered": false }, { "type": "ResolvedCrossSessionInboundSetting", "at": [ "src/agents/cross-session-judge.ts:54" ], "added": [], "addedDetail": [], "addedRequired": [], "removed": [ "deprecatedLayers" ], "breaking": true, "criteriaCovered": false }, { "type": "RunnerDeps", "at": [ "src/core/runner-deps.ts:105" ], "added": [ "fileHistoryCapture" ], "addedDetail": [ { "key": "fileHistoryCapture", "optional": true } ], "addedRequired": [], "removed": [], "breaking": false, "criteriaCovered": true }, { "type": "TaskSpec", "at": [ "src/core/task-spec.ts:55" ], "added": [ "fileHistory" ], "addedDetail": [ { "key": "fileHistory", "optional": true } ], "addedRequired": [], "removed": [], "breaking": false, "criteriaCovered": true }, { "type": "WiringFacts", "at": [ "src/core/wiring-manifest.ts:431" ], "added": [ "fileHistory" ], "addedDetail": [ { "key": "fileHistory", "optional": true } ], "addedRequired": [], "removed": [], "breaking": false, "criteriaCovered": false }, { "type": "WiringManifest", "at": [ "src/core/wiring-manifest.ts:183" ], "added": [ "fileHistory" ], "addedDetail": [ { "key": "fileHistory", "optional": true } ], "addedRequired": [], "removed": [], "breaking": false, "criteriaCovered": true } ], "typeKeysUnreadableArms": [], "typeKeysFlattenedCount": 214, "declarationMoves": [ { "name": "DEFAULT_MAX_ENTRY_DEPTH", "kind": "variable", "onSurface": true, "from": [ "src/core/memory-engine/file-backend.ts", "src/core/memory-engine/index.ts", "src/index.ts" ], "to": [ "src/core/memory-engine/entry-scan.ts", "src/core/memory-engine/file-backend.ts", "src/core/memory-engine/index.ts", "src/index.ts" ] }, { "name": "MEMORY_INDEX_FILENAME", "kind": "variable", "onSurface": true, "from": [ "src/core/memory-engine/file-backend.ts", "src/core/memory-engine/index.ts", "src/index.ts" ], "to": [ "src/core/memory-engine/entry-scan.ts", "src/core/memory-engine/file-backend.ts", "src/core/memory-engine/index.ts", "src/index.ts" ] }, { "name": "MEMORY_PROJECT_KEY_ABSENT_REASONS", "kind": "variable", "onSurface": true, "from": [ "src/core/memory.ts" ], "to": [ "src/core/memory.ts", "src/index.ts" ] }, { "name": "MemoryProjectKey", "kind": "type", "onSurface": true, "from": [ "src/core/memory.ts" ], "to": [ "src/core/memory.ts", "src/index.ts" ] }, { "name": "MemoryProjectKeyAbsentReason", "kind": "type", "onSurface": true, "from": [ "src/core/memory.ts" ], "to": [ "src/core/memory.ts", "src/index.ts" ] }, { "name": "ScannedEntryFile", "kind": "interface", "onSurface": true, "from": [ "src/core/memory-engine/file-backend.ts", "src/core/memory-engine/index.ts", "src/index.ts" ], "to": [ "src/core/memory-engine/entry-scan.ts", "src/core/memory-engine/file-backend.ts", "src/core/memory-engine/index.ts", "src/index.ts" ] }, { "name": "scanEntryFiles", "kind": "function", "onSurface": true, "from": [ "src/core/memory-engine/file-backend.ts", "src/core/memory-engine/index.ts", "src/index.ts" ], "to": [ "src/core/memory-engine/entry-scan.ts", "src/core/memory-engine/file-backend.ts", "src/core/memory-engine/index.ts", "src/index.ts" ] } ], "mintMoves": [], "criteriaObserves": [ { "kind": "engineNoticeCode", "name": "classifier.denial_limit", "assertions": [ "G4.a" ] }, { "kind": "engineNoticeCode", "name": "config.secret_env_scrubbed", "assertions": [ "G9.a" ] }, { "kind": "engineNoticeCode", "name": "peer.inbound_disposition", "assertions": [ "G7.a" ] }, { "kind": "taskEventField", "name": "done.result", "assertions": [ "G4.a" ] }, { "kind": "taskEventField", "name": "steering_injected.preview", "assertions": [ "G1.a" ] }, { "kind": "taskEventField", "name": "steering_injected.source", "assertions": [ "G1.a" ] }, { "kind": "taskEventField", "name": "tool_end.isError", "assertions": [ "G5.a" ] }, { "kind": "taskEventField", "name": "tool_end.output", "assertions": [ "G5.a" ] }, { "kind": "taskEventField", "name": "tool_start.toolCallId", "assertions": [ "G4.a" ] }, { "kind": "typeMember", "name": "Checkpoint.gate.realApproval", "assertions": [ "G8.a" ] }, { "kind": "typeMember", "name": "CheckpointSummary.gateKind", "assertions": [ "G8.a" ] }, { "kind": "typeMember", "name": "CheckpointSummary.mandated", "assertions": [ "G8.a" ] }, { "kind": "typeMember", "name": "EngineNotice.detail", "assertions": [ "G7.a", "G9.a" ] }, { "kind": "typeMember", "name": "HarvestReport.rejections", "assertions": [ "G6.a" ] }, { "kind": "typeMember", "name": "HarvestReport.restored", "assertions": [ "G6.a" ] }, { "kind": "typeMember", "name": "HarvestReport.warnings", "assertions": [ "G5.a", "G6.a", "G6.b" ] }, { "kind": "typeMember", "name": "MemoryEngine.eraseMemoryEntries", "assertions": [ "G5.a" ] }, { "kind": "typeMember", "name": "MemoryEngineOptions.onIncident", "assertions": [ "G6.b" ] }, { "kind": "typeMember", "name": "MemoryProjectKey.absent", "assertions": [ "G10.a" ] }, { "kind": "typeMember", "name": "MemoryProjectKey.scope", "assertions": [ "G10.a" ] }, { "kind": "typeMember", "name": "MemorySessionHandle.layerBaseline", "assertions": [ "G6.a" ] }, { "kind": "typeMember", "name": "MemorySessionHandle.materialized", "assertions": [ "G5.a", "G6.a", "G6.b" ] }, { "kind": "typeMember", "name": "NodeLspManagerOptions.onNotice", "assertions": [ "G9.a" ] }, { "kind": "typeMember", "name": "PendingAction.mandated", "assertions": [ "G8.a" ] }, { "kind": "typeMember", "name": "PendingAction.requiresRealApproval", "assertions": [ "G8.a" ] }, { "kind": "typeMember", "name": "ResolvedCrossSessionInboundSetting.decidedBy", "assertions": [ "G7.a" ] }, { "kind": "typeMember", "name": "ResolvedCrossSessionInboundSetting.invalidLayers", "assertions": [ "G7.a" ] }, { "kind": "typeMember", "name": "ResolvedCrossSessionInboundSetting.value", "assertions": [ "G7.a" ] }, { "kind": "typeMember", "name": "RunnerDeps.fileHistoryCapture", "assertions": [ "G3.a" ] }, { "kind": "typeMember", "name": "TaskResult.terminal.code", "assertions": [ "G2.a", "G3.a", "G3.b", "G4.a" ] }, { "kind": "typeMember", "name": "TaskResult.terminal.message", "assertions": [ "G3.a", "G3.b" ] }, { "kind": "typeMember", "name": "TaskSpec.fileHistory", "assertions": [ "G2.a" ] }, { "kind": "typeMember", "name": "TaskSpec.memory.projectKey", "assertions": [ "G10.a" ] }, { "kind": "typeMember", "name": "TaskSpec.restoreFiles", "assertions": [ "G3.b" ] }, { "kind": "typeMember", "name": "TaskSpec.resumeAtMode", "assertions": [ "G3.b" ] }, { "kind": "typeMember", "name": "WiringManifest.fileHistory", "assertions": [ "G2.a", "G3.a" ] } ], "consumersHint": { "cli": [ "CheckpointSummary", "ENGINE_NOTICE_CODES", "MEMORY_PROJECT_KEY_ABSENT_REASONS", "MemoryProjectKeyAbsentReason", "MemorySessionHandle", "ParentSpecSeat", "PendingAction", "RunnerDeps", "TaskSpec", "WiringFacts", "WiringManifest" ], "server": [ "CheckpointSummary", "ENGINE_NOTICE_CODES", "MEMORY_PROJECT_KEY_ABSENT_REASONS", "MemoryProjectKey", "MemorySessionHandle", "NodeLspManagerOptions", "ParentSpecSeat", "PendingAction", "RunnerDeps", "TaskSpec", "WiringFacts", "WiringManifest" ], "sdk": [ "CheckpointSummary", "ENGINE_NOTICE_CODES", "PendingAction", "RunnerDeps", "TaskSpec", "WiringManifest" ], "note": "scanned cli@4e593722 server@57709419 sdk@a9440f2 — a name listed is MENTIONED there today, which is evidence of consumption, not proof of it. Ledger files (**/docs/core-consumption/**, **/docs/wire-consumption/**, **/*LEDGER*.json) are not evidence of use — server: 1 name(s) matched ONLY in bookkeeping files and were set aside (ResolvedCrossSessionInboundSetting)" }, "breakingCount": 1, "breakingItems": [ "type lost keys: ResolvedCrossSessionInboundSetting -deprecatedLayers" ], "toResolvedAt": "3f6c68b65cc5b8f778b01c42cf4e838babf97be1" }