{
  "repo": "core",
  "version": "7.23.4",
  "from": "141b1687631b53cf2998a56c7541bb4aab5ca9af",
  "to": "v7.23.4",
  "added": [],
  "removed": [],
  "changed": [],
  "narrowed": [
    {
      "id": "F1",
      "source": "behaviorFlips.summary",
      "text": "NARROWING, the `bash_readonly` read-only shell face (`handsReadOnly`), deployments with a deny judge wired (#937 = sema-internal #67, P1; stock since design/199 — measured identical on 7.22.0 and 7.23.3): ONE deny judge for every read face. The v1 exception that kept `denyMatch` off the read-only shell face is retired: `readDenySeat()` (`src/tools/fs/read-deny.ts`) is the single adapter from the compiled deny set to a boundary's deny half, mounted by the structured read faces and now by `bash_readonly` at both of its judging moments — the lexical verdict and the execute-time recheck (`src/tools/fs/fs-bash.ts`, `{ deny: denySeat.denyMatch, containment: true }`). One mint for the deny refusal (`readDenyRefusal`) and one for the containment refusal (`readContainmentRefusal`). A containment GRANT (root rescue, overflow-spool recovery) answers containment only, never deny (codex r1/r2). Rules −4. WHO NEEDS IT: a deployment that mounts the read-only shell (server autonomy read-only tier) AND configures `readDenyPatterns` / `READ_DENY_BUILTIN_TIERS` — until now `cat .env` ran there at zero cards with the bytes returned. WHO IS AFFECTED: (a) on that face, a deny-listed read is REFUSED (`read_path_denied`, naming the pattern) — named spelling, glob, symlink target, and a recursive walk that would enter a deny row; (b) a recursive verb (`grep -r <needle> .`) on such a deployment is refused as a whole with the Grep tool named as the way out (KL-937b); (c) a bracket-named glob spelling may over-fire fail-closed (KL-937a). Deployments with no deny judge: byte-identical on this face; the full Bash face: unchanged (contrast column pinned)."
    }
  ],
  "closedSetMembers": [],
  "closedSetsUnreadable": [],
  "typeKeys": [
    {
      "type": "CompoundReadonlyVerdict",
      "at": [
        "src/tools/fs/bash-readonly-classifier.ts:644"
      ],
      "added": [
        "readDeniedPath",
        "readDeniedPattern"
      ],
      "removed": [],
      "breaking": false,
      "criteriaCovered": false
    }
  ],
  "declarationMoves": [],
  "mintMoves": [],
  "criteriaObserves": [
    {
      "kind": "taskEventField",
      "name": "tool_end.isError",
      "assertions": [
        "G1.a",
        "G1.b"
      ]
    }
  ],
  "consumersHint": {
    "cli": [
      "CompoundReadonlyVerdict"
    ],
    "server": [
      "CompoundReadonlyVerdict"
    ],
    "sdk": [],
    "note": "scanned cli@4e3b6980 server@866e273b sdk@0a6aeb7 — a name listed is MENTIONED there today, which is evidence of consumption, not proof of it"
  },
  "breakingCount": 0,
  "breakingItems": [],
  "toResolvedAt": "2a5d3b7f6c6d633510d8866e95d66e7b2b85446a"
}
