{
  "repo": "core",
  "version": "7.22.0",
  "from": "303786b689a29bf05decde04e88cda8ccb6d9593",
  "to": "v7.22.0",
  "added": [
    {
      "name": "McpReconnectResult",
      "kind": "interface",
      "tier": "advanced",
      "at": [
        "src/core/mcp.ts:358",
        "src/index.ts:346"
      ],
      "criteriaCovered": true,
      "breaking": false
    },
    {
      "name": "RETENTION_CASCADE_DOMAINS",
      "kind": "variable",
      "tier": "advanced",
      "at": [
        "src/core/retention.ts:88",
        "src/index.ts:422"
      ],
      "criteriaCovered": false,
      "breaking": false
    },
    {
      "name": "RETENTION_CASCADE_EXEMPT",
      "kind": "variable",
      "tier": "advanced",
      "at": [
        "src/core/retention.ts:93",
        "src/index.ts:423"
      ],
      "criteriaCovered": false,
      "breaking": false
    },
    {
      "name": "autoRunOnRecommendationEffective",
      "kind": "function",
      "tier": "internal",
      "at": [
        "src/core/runner/memory-consolidation-driver.ts:188",
        "src/index.ts:2372"
      ],
      "criteriaCovered": false,
      "breaking": false
    }
  ],
  "removed": [],
  "changed": [],
  "narrowed": [
    {
      "id": "F5",
      "source": "behaviorFlips.summary",
      "text": "NARROWING (allow -> mandated ask) on deployments WITH a wired deny judge, the CONTENTS half of the same arm (#862 (1)). The arm now reads the PROGRAM bash runs (the same `slotVerb` the option-slot rows travel with, `src/tools/fs/bash-readonly-classifier.ts:3380`, gate `:3461`) instead of the synthetic scan head, and `egrep`/`fgrep` share grep's row (`:2129-2131`). `tar`'s create mode is a CONTENTS row because `tar -cf - .` writes the archive to stdout (`:2139`). MEASURED on the merge tree with four built-in tiers selected: `rg x`, `ag x`, `ack x`, `egrep -r x .`, `fgrep -r x .`, `tar czf a.tgz src` = MANDATED on both doctrines; on the 7.21.1 artifact the same spellings read run (default) / plain ask (classify). Who needs it: one security property had two answers decided by whether a name was on a deployment's allow list. Who is hurt: a deployment that selects built-in tiers or writes its own `readDenyPatterns` — those spellings now cost a card, and a headless lane refuses them (a backup script running `tar czf` fails closed until the deployment says otherwise). Compensation: the deployment's own ways out are unchanged (`readDenyBuiltinTiers` / `readDenyBuiltinExclude`, or the `ExecutionEnv` the command runs in), and #873 is filed to make the third precondition (is a deny row actually under this traversal root) answerable at execution time."
    },
    {
      "id": "F8",
      "source": "behaviorFlips.after",
      "text": "MEASURED on the merge tree: the six wrapper spellings = run on the default/off doctrine. STATED PRECISION on the CHANGELOG's `the verdict their unwrapped command has`: that is true of the boundary seat; under the CLASSIFY doctrine the wrapper's own name is not on the read-only allow table, so `timeout 1.5 cat notes.txt` reads a plain, rule-clearable `ask` there rather than zero asks (`cat notes.txt` alone reads run). The narrowing half of the duration fix, MEASURED under an ON deny posture: `timeout 1.5 grep -r x .`, `timeout .5 …`, `timeout 5s …`, `timeout 300 …`, `timeout -k 5 300 …` and `nice -5 grep -r x .` all = MANDATED; `timeout 1.5 cat notes.txt` = run in root; `timeout 1.5 cat .npmrc` = MANDATED."
    },
    {
      "id": "F14",
      "source": "behaviorFlips.summary",
      "text": "NARROWED READING of one persisted cell, plus one additive key (#862 / #858 (i-a) / #713). `safetyAxisOf` (`src/core/ask-origin.ts:468`) still decides WHETHER a raise happened by exactly the same rule — so `CheckpointGate.kind` is byte-identical (`irreversible_ask` for every park that had it, `human` for every park that did not) — and now also decides WHICH axis it lands on: the engine's SHELL SEAT raises are `shell: true` with `irreversible: false`; a tool's OWN `always`/`maybe` declaration keeps `irreversible`. The two are MUTUALLY EXCLUSIVE. `SafetyAxis.shell?: boolean` is the new optional member (`src/core/checkpoint-store.ts:138`); `SAFETY_AXIS_VOCABULARY.safetyAxis` already listed the word, so the key it named now exists. `buildRiskDescriptor` drops the `!shell &&` correction it carried. Who needs it: the durable record said `tool X performs an irreversible action` about a card whose question is about TEXT — which files the words of a command may name — while `buildRiskDescriptor`, minting at the SAME moment from the same inputs, graded it `axes: { shell: true }`, severity 3. Two derivations, opposite answers, one gate row. Who is hurt: @server @cli — a resolver that reads `safetyAxis.irreversible` to decide `does this need a real person?` FLIPS for the whole read-boundary family. Compensation: read `irreversible || shell` to keep today's answer; the budget face is unchanged because `kind` did not move; `RiskDescriptor.axes` is unchanged."
    },
    {
      "id": "F18",
      "source": "behaviorFlips.summary",
      "text": "NARROWING (a floor, not a default): a task that declares memory OFF hands that fact to every child, grandchild and revived cycle (#863 W3). The fact rides `ParentSpecSeat.memoryOff?: true` (`src/core/parent-spec-seat.ts:46`), minted ONLY from an explicit `enabled: false` (`:63` — an absent `memory` is silence, not an off statement), and `applyParentSpecSeat` stamps it as the third unconditional REMOVAL beside `oneShot: true` and `memoryPersistenceCapable: false` (`:94`). It REWRITES rather than deletes: the child keeps its own scopes and gets `enabled: false`, because the next mint reads `spec.memory.enabled === false` and a deleted `memory` would end the floor one level down. The revival lane gains the matching clamp (`createSubagentResume` deps' `currentClamps.memoryOff?`, `src/agents/subagent.ts:1467`, folded `:1667`), filled on the cross-run `SendMessage` wake from the sender's own seat (`src/agents/send-message-tool.ts:2167`). Who needs it: a task that had turned memory off could delegate to an agent definition that turned it back on, and the child's harvest committed notes the declaring task had asked not to have. Who is hurt: a deployment that ALREADY spells `memory: { …, enabled: false }` on a parent — its children's own `memory` declarations no longer mount. Compensation: the type surface is additive and an absent `memoryOff` reads exactly as 7.21.x did; OFF means the memory FACE is not mounted, never a filesystem prohibition."
    },
    {
      "id": "F19",
      "source": "behaviorFlips.summary",
      "text": "NARROWING (a recommendation arrives one session later): the consolidation threshold excludes the session doing the asking (#863 G-17). ONE reading, `sessionsSinceExcludingCurrent(row)` (`src/core/memory-engine/consolidation.ts:442`), is what both doors compare and what every sentence reports: the recommendation edge (`:458`, `:464`), the snapshot door's unforced session gate, and that gate's refusal text. The ring and its `count` are UNCHANGED — they still include the calling session, which is exactly what makes a second harvest of it not a second session. Who needs it: the counted session is not material to a decision taken on its own behalf — the bookkeeping also runs on the SUSPEND path, so it may still be running, and at a terminal harvest its notes are the ones the harvest just wrote; the reference CLI filters the current session out before comparing. Who is hurt: every deployment sees `memory.consolidation_recommended` one session later, and with the 7.21.1 default-on arming the automatic run fires one session later too. Compensation: AT THE CROSSING the reported figure is unchanged, because the crossing IS the threshold (5 before, 5 now); `force` bypasses the snapshot door as before."
    },
    {
      "id": "F21",
      "source": "behaviorFlips.summary",
      "text": "ADDITIVE EXPORTS +2 and a spelled-out retention clause (#514, @server). `RETENTION_CASCADE_DOMAINS` (`src/core/retention.ts:88`) and `RETENTION_CASCADE_EXEMPT` (`:93`) are exported from the package root, carry two contract sentences (`retention.cascade_domains`, `retention.governance_records_outlive_the_purge`), and are pinned disjoint and identical to the layout coordinates they name. A session purge must NOT delete `session-pollution/`, `session-capture-optout/` or `lineage.json`. Also in this ticket: the session-pollution marker takes its twin's `lstat` arbitration for absence — a DANGLING entry at a marker's pathname is `present but unreadable` (fail-closed), never clean absence, which the capture opt-out record has read that way since 6.0.0-RC. Who needs it: `ManagedRetentionCapability`'s three operations named checkpoint rows, session trees and orphan tool results and were SILENT about the memory control plane's governance legs — a cascade written as `delete everything belonging to session S` would plausibly have reached them. Who is hurt: nobody — this is a disambiguation, not a narrowing of a stated obligation. Compensation: with the incarnation seat wired, retaining the three records can no longer bind a later occupant, so there is no compliance reason left to delete them; a deployment whose control plane is healthy sees no difference from the `lstat` change."
    }
  ],
  "closedSetMembers": [
    {
      "set": "ENGINE_NOTICE_CODES",
      "at": [
        "src/core/governance-codes.ts:312"
      ],
      "newSet": false,
      "added": [
        "mcp.server_redialed"
      ],
      "removed": [],
      "breaking": false,
      "criteriaCovered": true
    },
    {
      "set": "RETENTION_CASCADE_DOMAINS",
      "at": [
        "src/core/retention.ts:88"
      ],
      "newSet": true,
      "added": [
        "checkpoints",
        "orphan-tool-results",
        "session-trees"
      ],
      "removed": [],
      "breaking": false,
      "criteriaCovered": false
    },
    {
      "set": "RETENTION_CASCADE_EXEMPT",
      "at": [
        "src/core/retention.ts:93"
      ],
      "newSet": true,
      "added": [
        "lineage.json",
        "session-capture-optout",
        "session-pollution"
      ],
      "removed": [],
      "breaking": false,
      "criteriaCovered": false
    }
  ],
  "closedSetsUnreadable": [],
  "typeKeys": [
    {
      "type": "AutoModeClassified",
      "at": [
        "src/core/auto-mode.ts:483"
      ],
      "added": [
        "notAsked"
      ],
      "removed": [],
      "breaking": false,
      "criteriaCovered": true
    },
    {
      "type": "AutoModeDeciderOptions",
      "at": [
        "src/core/auto-mode.ts:450"
      ],
      "added": [
        "assemble"
      ],
      "removed": [],
      "breaking": false,
      "criteriaCovered": true
    },
    {
      "type": "BashReadonlyRootBoundary",
      "at": [
        "src/tools/fs/bash-readonly-classifier.ts:553"
      ],
      "added": [
        "denyEntries"
      ],
      "removed": [],
      "breaking": false,
      "criteriaCovered": true
    },
    {
      "type": "CompoundReadonlyVerdict",
      "at": [
        "src/tools/fs/bash-readonly-classifier.ts:609"
      ],
      "added": [
        "outOfRootGrantCoversExactPath",
        "segmentNameRefusal"
      ],
      "removed": [],
      "breaking": false,
      "criteriaCovered": false
    },
    {
      "type": "LineagePendingTxn",
      "at": [
        "src/core/memory-engine/layout.ts:2557"
      ],
      "added": [
        "incarnation"
      ],
      "removed": [],
      "breaking": false,
      "criteriaCovered": false
    },
    {
      "type": "MaterializedMcp",
      "at": [
        "src/core/mcp.ts:173"
      ],
      "added": [
        "reconnect"
      ],
      "removed": [],
      "breaking": false,
      "criteriaCovered": false
    },
    {
      "type": "MemoryEngineOptions",
      "at": [
        "src/core/memory-engine/engine.ts:556"
      ],
      "added": [
        "sessionIncarnation"
      ],
      "removed": [],
      "breaking": false,
      "criteriaCovered": false
    },
    {
      "type": "ParentSpecSeat",
      "at": [
        "src/core/parent-spec-seat.ts:37"
      ],
      "added": [
        "memoryOff"
      ],
      "removed": [],
      "breaking": false,
      "criteriaCovered": true
    },
    {
      "type": "ReadRootGrantCandidate",
      "at": [
        "src/core/tool-spec.ts:105"
      ],
      "added": [
        "covers"
      ],
      "removed": [],
      "breaking": false,
      "criteriaCovered": true
    },
    {
      "type": "RunnerDeps",
      "at": [
        "src/core/runner-deps.ts:104"
      ],
      "added": [
        "memorySessionIncarnation"
      ],
      "removed": [],
      "breaking": false,
      "criteriaCovered": true
    },
    {
      "type": "SafetyAxis",
      "at": [
        "src/core/checkpoint-store.ts:131"
      ],
      "added": [
        "shell"
      ],
      "removed": [],
      "breaking": false,
      "criteriaCovered": true
    },
    {
      "type": "SessionCaptureOptOutRecord",
      "at": [
        "src/core/memory-engine/layout.ts:2093"
      ],
      "added": [
        "incarnation"
      ],
      "removed": [],
      "breaking": false,
      "criteriaCovered": true
    },
    {
      "type": "TaskStream",
      "at": [
        "src/core/task-stream.ts:13"
      ],
      "added": [
        "reconnectMcpServer"
      ],
      "removed": [],
      "breaking": false,
      "criteriaCovered": true
    },
    {
      "type": "TraceEvent",
      "at": [
        "src/core/trace.ts:60"
      ],
      "added": [
        "auto_mode.classified.notAsked"
      ],
      "removed": [],
      "breaking": false,
      "criteriaCovered": false
    },
    {
      "type": "WiringFacts",
      "at": [
        "src/core/wiring-manifest.ts:396"
      ],
      "added": [
        "readDenyBuiltinTiersActive"
      ],
      "removed": [],
      "breaking": false,
      "criteriaCovered": false
    },
    {
      "type": "WiringManifest",
      "at": [
        "src/core/wiring-manifest.ts:164"
      ],
      "added": [
        "readDeny"
      ],
      "removed": [],
      "breaking": false,
      "criteriaCovered": true
    }
  ],
  "declarationMoves": [
    {
      "name": "autoRunOnRecommendationEffective",
      "kind": "function",
      "onSurface": true,
      "from": [
        "src/core/runner/memory-consolidation-driver.ts"
      ],
      "to": [
        "src/core/runner/memory-consolidation-driver.ts",
        "src/index.ts"
      ]
    }
  ],
  "mintMoves": [],
  "criteriaObserves": [
    {
      "kind": "engineNoticeCode",
      "name": "mcp.server_redialed",
      "assertions": [
        "G1.d"
      ]
    },
    {
      "kind": "engineNoticeCode",
      "name": "memory.consolidation_recommended",
      "assertions": [
        "G13.a"
      ]
    },
    {
      "kind": "engineNoticeCode",
      "name": "task.user_steer_undrained",
      "assertions": [
        "G10.a",
        "G10.b"
      ]
    },
    {
      "kind": "typeMember",
      "name": "AskRequest.readRootCandidate",
      "assertions": [
        "G8.b"
      ]
    },
    {
      "kind": "typeMember",
      "name": "AutoModeClassified.cause",
      "assertions": [
        "G11.a"
      ]
    },
    {
      "kind": "typeMember",
      "name": "AutoModeClassified.notAsked",
      "assertions": [
        "G11.a"
      ]
    },
    {
      "kind": "typeMember",
      "name": "AutoModeDeciderOptions.assemble",
      "assertions": [
        "G11.b"
      ]
    },
    {
      "kind": "typeMember",
      "name": "BashReadonlyRootBoundary.denyEntries",
      "assertions": [
        "G2.c"
      ]
    },
    {
      "kind": "typeMember",
      "name": "BashReadonlyRootBoundary.denyMatch",
      "assertions": [
        "G2.c"
      ]
    },
    {
      "kind": "typeMember",
      "name": "CheckpointGate.kind",
      "assertions": [
        "G9.b"
      ]
    },
    {
      "kind": "typeMember",
      "name": "CheckpointGate.safetyAxis",
      "assertions": [
        "G9.a",
        "G9.c"
      ]
    },
    {
      "kind": "typeMember",
      "name": "CompoundReadonlyVerdict.checkedPaths",
      "assertions": [
        "G4.a",
        "G4.b"
      ]
    },
    {
      "kind": "typeMember",
      "name": "CompoundReadonlyVerdict.outOfRootPaths",
      "assertions": [
        "G4.a",
        "G7.b"
      ]
    },
    {
      "kind": "typeMember",
      "name": "HarvestReport.consolidationRecommended",
      "assertions": [
        "G13.a"
      ]
    },
    {
      "kind": "typeMember",
      "name": "ManagedRetentionCapability.deleteExpiredSessions",
      "assertions": [
        "G14.c"
      ]
    },
    {
      "kind": "typeMember",
      "name": "ManagedRetentionCapability.listRetentionDomains",
      "assertions": [
        "G14.c"
      ]
    },
    {
      "kind": "typeMember",
      "name": "MaterializedMcp.instructionsDelta",
      "assertions": [
        "G1.c"
      ]
    },
    {
      "kind": "typeMember",
      "name": "MaterializedMcp.statuses",
      "assertions": [
        "G1.c",
        "G1.e"
      ]
    },
    {
      "kind": "typeMember",
      "name": "McpReconnectResult.outcome",
      "assertions": [
        "G1.a"
      ]
    },
    {
      "kind": "typeMember",
      "name": "McpReconnectResult.status",
      "assertions": [
        "G1.b"
      ]
    },
    {
      "kind": "typeMember",
      "name": "McpReconnectResult.tools",
      "assertions": [
        "G1.b"
      ]
    },
    {
      "kind": "typeMember",
      "name": "McpRefreshResult.status",
      "assertions": [
        "G1.c"
      ]
    },
    {
      "kind": "typeMember",
      "name": "ParentSpecSeat.memoryOff",
      "assertions": [
        "G12.b",
        "G12.c"
      ]
    },
    {
      "kind": "typeMember",
      "name": "ReadRootGrantCandidate.covers",
      "assertions": [
        "G8.a"
      ]
    },
    {
      "kind": "typeMember",
      "name": "ReversibilityVerdict.cause",
      "assertions": [
        "G2.b",
        "G5.c"
      ]
    },
    {
      "kind": "typeMember",
      "name": "ReversibilityVerdict.mandated",
      "assertions": [
        "G2.a",
        "G2.b",
        "G3.c",
        "G5.a",
        "G5.b",
        "G5.c",
        "G6.a",
        "G7.a",
        "G7.b",
        "G7.c"
      ]
    },
    {
      "kind": "typeMember",
      "name": "ReversibilityVerdict.readRootCandidate",
      "assertions": [
        "G8.a",
        "G8.c"
      ]
    },
    {
      "kind": "typeMember",
      "name": "RiskDescriptor.axes",
      "assertions": [
        "G9.b"
      ]
    },
    {
      "kind": "typeMember",
      "name": "RunnerDeps.autoRunOnRecommendation",
      "assertions": [
        "G12.a"
      ]
    },
    {
      "kind": "typeMember",
      "name": "RunnerDeps.memorySessionIncarnation",
      "assertions": [
        "G14.a"
      ]
    },
    {
      "kind": "typeMember",
      "name": "RunnerDeps.readDenyBuiltinTiers",
      "assertions": [
        "G3.a",
        "G3.d"
      ]
    },
    {
      "kind": "typeMember",
      "name": "SafetyAxis.shell",
      "assertions": [
        "G9.a"
      ]
    },
    {
      "kind": "typeMember",
      "name": "SessionCaptureOptOutRecord.incarnation",
      "assertions": [
        "G14.a"
      ]
    },
    {
      "kind": "typeMember",
      "name": "SessionCaptureRecordStore.read",
      "assertions": [
        "G14.b"
      ]
    },
    {
      "kind": "typeMember",
      "name": "TaskStream.reconnectMcpServer",
      "assertions": [
        "G1.a"
      ]
    },
    {
      "kind": "typeMember",
      "name": "WiringManifest.autoConsolidation",
      "assertions": [
        "G12.a"
      ]
    },
    {
      "kind": "typeMember",
      "name": "WiringManifest.configFingerprint",
      "assertions": [
        "G3.b"
      ]
    },
    {
      "kind": "typeMember",
      "name": "WiringManifest.readDeny",
      "assertions": [
        "G3.b"
      ]
    }
  ],
  "consumersHint": {
    "cli": [],
    "server": [],
    "sdk": [],
    "note": "NOT SCANNED: sema-cli, sema-server, sema-sdk — an empty list for those repos means \"not checked out\", not \"no consumer\""
  },
  "breakingCount": 0,
  "breakingItems": [],
  "toResolvedAt": "2740e04646775728b4f56b1882a32731a9d307f6"
}
