@sema-agent/core 7.25.0 → 7.26.0

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.
Files changed (75) hide show
  1. package/CHANGELOG.md +81 -0
  2. package/dist/core/arg-summary.d.ts +0 -7
  3. package/dist/core/arg-summary.js +2 -1
  4. package/dist/core/ask-origin.d.ts +84 -0
  5. package/dist/core/ask-origin.js +31 -3
  6. package/dist/core/auto-compaction.d.ts +5 -0
  7. package/dist/core/auto-compaction.js +7 -0
  8. package/dist/core/auto-mode-directive.d.ts +45 -0
  9. package/dist/core/auto-mode-directive.js +47 -0
  10. package/dist/core/checkpoint-store.d.ts +10 -1
  11. package/dist/core/engine-notice.d.ts +10 -0
  12. package/dist/core/gate-lanes.js +18 -10
  13. package/dist/core/governance-codes.d.ts +1 -1
  14. package/dist/core/governance-codes.js +3 -0
  15. package/dist/core/hooks.d.ts +3 -0
  16. package/dist/core/mcp-probe.d.ts +122 -0
  17. package/dist/core/mcp-probe.js +132 -0
  18. package/dist/core/memory-engine/engine.d.ts +6 -1
  19. package/dist/core/memory-engine/engine.js +30 -2
  20. package/dist/core/memory-engine/index.d.ts +1 -0
  21. package/dist/core/memory-engine/index.js +1 -0
  22. package/dist/core/memory-engine/shadowing.d.ts +58 -0
  23. package/dist/core/memory-engine/shadowing.js +40 -0
  24. package/dist/core/memory-engine/tools.d.ts +33 -1
  25. package/dist/core/memory-engine/tools.js +136 -31
  26. package/dist/core/memory-engine/types.d.ts +10 -0
  27. package/dist/core/memory.d.ts +60 -0
  28. package/dist/core/memory.js +47 -2
  29. package/dist/core/permission-rule-store.d.ts +51 -8
  30. package/dist/core/permission-rule-store.js +112 -65
  31. package/dist/core/reminder-mint.d.ts +41 -0
  32. package/dist/core/reminder-mint.js +55 -0
  33. package/dist/core/runner/compaction-restate.d.ts +9 -0
  34. package/dist/core/runner/compaction-restate.js +20 -0
  35. package/dist/core/runner/contracts.d.ts +18 -1
  36. package/dist/core/runner/denial-limit-arms.js +1 -1
  37. package/dist/core/runner/permission-rule-lanes.d.ts +5 -17
  38. package/dist/core/runner/permission-rule-lanes.js +5 -23
  39. package/dist/core/runner/prepare-ask-lane.js +2 -0
  40. package/dist/core/runner/prepare-context-lane.d.ts +4 -0
  41. package/dist/core/runner/prepare-context-lane.js +7 -2
  42. package/dist/core/runner/prepare-inherited-gate.d.ts +5 -1
  43. package/dist/core/runner/prepare-inherited-gate.js +4 -2
  44. package/dist/core/runner/prepare-memory.js +47 -6
  45. package/dist/core/runner/prepare-park-ask.js +1 -0
  46. package/dist/core/runner/prepare-policy-chain.js +8 -4
  47. package/dist/core/runner/prepare-suspend-saga.d.ts +2 -0
  48. package/dist/core/runner/prepare-suspend-saga.js +3 -1
  49. package/dist/core/runner/prepare-task.js +7 -4
  50. package/dist/core/runner/run-leg.js +9 -1
  51. package/dist/core/runner/run-recovery-lanes.js +2 -2
  52. package/dist/core/runner/run-terminal-adoption.js +2 -2
  53. package/dist/core/runner/run-turn-boundary.js +2 -2
  54. package/dist/core/store-contracts/permission-rule-write-contract.d.ts +20 -0
  55. package/dist/core/store-contracts/permission-rule-write-contract.js +77 -0
  56. package/dist/core/task-result.d.ts +11 -0
  57. package/dist/core/task-spec.d.ts +31 -0
  58. package/dist/core/tool-catalog-entries.js +3 -3
  59. package/dist/core/tool-policy.d.ts +38 -0
  60. package/dist/core/tool-policy.js +35 -24
  61. package/dist/core/types.d.ts +1 -1
  62. package/dist/index.d.ts +7 -2
  63. package/dist/index.js +6 -1
  64. package/dist/stores/file/permission-rule-store.js +48 -29
  65. package/dist/tools/fs/bash-lexer.d.ts +13 -0
  66. package/dist/tools/fs/bash-lexer.js +61 -0
  67. package/dist/tools/fs/bash-program-position.d.ts +32 -3
  68. package/dist/tools/fs/bash-program-position.js +33 -2
  69. package/dist/tools/fs/bash-readonly-classifier.d.ts +6 -4
  70. package/dist/tools/fs/bash-readonly-classifier.js +55 -18
  71. package/dist/tools/fs/shell-read-plan.js +9 -11
  72. package/package.json +1 -1
  73. package/test/export-surface.snapshot.json +29 -1
  74. package/wire-changes/core@7.25.1.json +64 -0
  75. package/wire-changes/core@7.26.0.json +695 -0
@@ -14,9 +14,27 @@ import type { SegmentTokens } from "./bash-lexer.js";
14
14
  export declare const NOT_AUTO_ALLOWED = "\u2014 not auto-allowed";
15
15
  /** argv[0] as the program bash will resolve it: `/usr/bin/cat` and `cat` are one name. */
16
16
  export declare function programBasename(word: string): string;
17
- /** A leading `NAME=value` word: an assignment bash applies to the command's environment rather than a
18
- * program name. Same shape the exit-code reader in `fs-bash.ts` skips for the same reason. */
19
- export declare const ASSIGNMENT_WORD: RegExp;
17
+ /**
18
+ * The `NAME=` / `NAME+=` prefix bash reads as an ASSIGNMENT — the ONE spelling of that grammar, matched where
19
+ * it is WRITTEN. Both operators, because bash reads both; the match IS the prefix, so a caller holding raw
20
+ * text can ask whether its token carries one bare. Every walk that strips leading assignments reads this:
21
+ * a second copy of the grammar is how one walk came to strip `A=x` and skip `A+=x`.
22
+ */
23
+ export declare const ASSIGNMENT_PREFIX: RegExp;
24
+ /**
25
+ * The prefix this raw token BEGINS with, or `undefined`.
26
+ *
27
+ * `name` is the VARIABLE the word assigns to, which is the part before any subscript: `A[0]=x` writes one
28
+ * element of `A`, so a reader asking "is `$A` settled" must not be told that `A[0]` is. `settlesWholeName` is
29
+ * false for exactly the two spellings that do not settle it — an append (the earlier content is not in the
30
+ * text) and a subscript (the other elements are not) — so a consumer of that question asks it once.
31
+ */
32
+ export declare function writtenAssignmentPrefix(token: string): {
33
+ readonly prefix: string;
34
+ readonly name: string;
35
+ readonly appends: boolean;
36
+ readonly settlesWholeName: boolean;
37
+ } | undefined;
20
38
  /** Shell control words that stand BEFORE a command: transparent for the boundary walk (the command behind them is
21
39
  * judged). */
22
40
  export declare const SHELL_CONTROL_PREFIXES: ReadonlySet<string>;
@@ -25,6 +43,17 @@ export declare const SHELL_BLOCK_WORDS: ReadonlySet<string>;
25
43
  /** A control word is a keyword only when bash sees it BARE: `'if'` / `"do"` / `\\!` are command names (a program
26
44
  * looked up on PATH, whose failure changes nothing), so a quoted or escaped spelling never counts as one. */
27
45
  export declare function isBareControlWord(toks: SegmentTokens, i: number, words: ReadonlySet<string>): boolean;
46
+ /**
47
+ * A word bash strips as an ASSIGNMENT before it chooses the program.
48
+ *
49
+ * WHAT HAS TO BE BARE IS THE PREFIX, NOT THE WORD, and it is ONE question for BOTH operators. Bash decides this
50
+ * before it removes any quoting, and only the NAME and the OPERATOR take part in it: quoting any of `NAME=` /
51
+ * `NAME+=` makes the whole word a program name looked up on PATH (`'A=x'`, `'A+=x'`, `A\+=x`), while quoting the
52
+ * VALUE does not (`A+=".env"` assigns `.env` exactly as `A+=.env` does — verified against the shell). A
53
+ * whole-word test conflates the two and reads the quoted VALUE as a program name; a FOLDED-word test conflates
54
+ * them the other way and reads the quoted PROGRAM NAME as an assignment, stepping over the real program.
55
+ */
56
+ export declare function isLeadingAssignmentWord(toks: SegmentTokens, i: number): boolean;
28
57
  /**
29
58
  * Programs that turn their STANDARD INPUT into the OPERANDS of another program, and EXEC that program directly.
30
59
  *
@@ -2,13 +2,44 @@ export const NOT_AUTO_ALLOWED = "— not auto-allowed";
2
2
  export function programBasename(word) {
3
3
  return word.includes("/") ? (word.split("/").pop() ?? word) : word;
4
4
  }
5
- export const ASSIGNMENT_WORD = /^[A-Za-z_][A-Za-z0-9_]*=/;
5
+ export const ASSIGNMENT_PREFIX = /^[A-Za-z_][A-Za-z0-9_]*(?:\[[^\]\s]*\])?\+?=/;
6
+ export function writtenAssignmentPrefix(token) {
7
+ const prefix = ASSIGNMENT_PREFIX.exec(token)?.[0];
8
+ if (prefix === undefined)
9
+ return undefined;
10
+ const appends = prefix.endsWith("+=");
11
+ const written = prefix.slice(0, prefix.length - (appends ? 2 : 1));
12
+ const bracket = written.indexOf("[");
13
+ return { prefix, name: bracket < 0 ? written : written.slice(0, bracket), appends, settlesWholeName: !appends && bracket < 0 };
14
+ }
6
15
  export const SHELL_CONTROL_PREFIXES = new Set(["!", "if", "then", "elif", "else", "while", "until", "do", "time"]);
7
16
  export const SHELL_BLOCK_WORDS = new Set(["for", "select", "case", "esac", "fi", "done", "function", "coproc", "[[", "]]", "in"]);
8
17
  export function isBareControlWord(toks, i, words) {
9
18
  const word = toks.folded[i];
10
19
  return word !== undefined && toks.raw[i] === word && words.has(word);
11
20
  }
21
+ export function isLeadingAssignmentWord(toks, i) {
22
+ const word = toks.folded[i];
23
+ const raw = toks.raw[i];
24
+ if (word === undefined || raw === undefined)
25
+ return false;
26
+ const written = writtenAssignmentPrefix(word);
27
+ return written !== undefined && prefixWrittenBare(raw, written);
28
+ }
29
+ function prefixWrittenBare(raw, written) {
30
+ if (!raw.startsWith(written.name))
31
+ return false;
32
+ let at = written.name.length;
33
+ if (written.prefix[at] === "[") {
34
+ if (raw[at] !== "[")
35
+ return false;
36
+ const close = raw.indexOf("]", at);
37
+ if (close < 0)
38
+ return false;
39
+ at = close + 1;
40
+ }
41
+ return raw.startsWith(written.appends ? "+=" : "=", at);
42
+ }
12
43
  export const ARGV_REENTRY_PROGRAM_RE = /^xargs$/;
13
44
  export const ARGV_REENTRY_DEFAULT_PROGRAM = "echo";
14
45
  const NO_DECLARED_OPTIONS = { optionArity: new Map() };
@@ -90,7 +121,7 @@ export function readProgramPosition(toks) {
90
121
  return none(undefined, []);
91
122
  const written = i;
92
123
  const assignments = [];
93
- while (i < folded.length && ASSIGNMENT_WORD.test(folded[i])) {
124
+ while (i < folded.length && isLeadingAssignmentWord(toks, i)) {
94
125
  assignments.push(i);
95
126
  i++;
96
127
  }
@@ -811,12 +811,14 @@ export declare function inlineProgramClause(model: InlineProgramModel, args: rea
811
811
  * command name. Names-only traversals (`find`, `ls -R`, `du`, `tree`, an archive write) are in the table
812
812
  * and answer `false` here — see {@link RecursiveReadFormModel.discloses}. */
813
813
  export declare function segmentSelectsRecursiveRead(name: string, args: readonly string[]): boolean;
814
- export declare function assignmentWordPayload(word: string): {
814
+ /** `raw` is the word as WRITTEN; it defaults to the folded spelling, which is the reading that expands most. */
815
+ export declare function assignmentWordPayload(word: string, raw?: string): {
815
816
  kind: "value";
816
817
  value: string;
817
818
  } | {
818
819
  kind: "unresolved";
819
820
  reason: string;
821
+ value?: string;
820
822
  } | undefined;
821
823
  /** WHICH programs are DECLARED not to open the value of a `NAME=value` ARGUMENT — an allow-list, because
822
824
  * the other polarity was measured false. `make PREFIX=/usr/local`, `cmake -D…`, `docker run -e HOME=/root`
@@ -834,9 +836,9 @@ export declare function assignmentWordPayload(word: string): {
834
836
  export declare const ASSIGNMENT_VALUE_NOT_PATHS: ReadonlySet<string>;
835
837
  /** The program the shell will RUN here and where its OWN argv begins — the two seats
836
838
  * {@link HeadedSegment.argvProgram} / {@link HeadedSegment.argvFrom} carry, from one reader so they cannot
837
- * disagree. Both assignment spellings are stripped BEFORE the program-position reader runs: it does not
838
- * read `NAME+=value` as an assignment (quoting makes `'A+=x'` a command NAME on folded text), so a leading
839
- * append word arrives AS the program and hides any launcher — measured on `A+=x env B=<outside> <prog>`. */
839
+ * disagree. The LEADING assignments (both spellings) are the program-position reader's own step, so this
840
+ * seat no longer strips them a second time: a second strip read the quoted `'A+=x'` as an assignment the
841
+ * one reader calls a program name, which is two readers with two answers. */
840
842
  export declare function argvProgramOf(tokens: SegmentTokens): {
841
843
  program: string;
842
844
  from: number;
@@ -1,6 +1,6 @@
1
1
  import { isAbsoluteForFamily, isAbsolutePathForm, isBlockedDevicePath, isShellRootedSpellingUnmapped, joinForFamily, nativeUncSpellingOf, normalizeAbsPathLexically, win32NamespaceScreen, pathFamilyOf } from "./safety.js";
2
- import { lexShellText, literalTildeSpelling, quoteMask, wordsOf, } from "./bash-lexer.js";
3
- import { ASSIGNMENT_WORD, COMMAND_LAUNCHERS, NOT_AUTO_ALLOWED, SHELL_BLOCK_WORDS, argvReentryUnjudged, isBareControlWord, programPositionRefusalSentence, readProgramPosition, } from "./bash-program-position.js";
2
+ import { lexShellText, literalTildeSpelling, ansiCQuoteClose, dollarOpensQuote, quoteMask, wordsOf, } from "./bash-lexer.js";
3
+ import { COMMAND_LAUNCHERS, NOT_AUTO_ALLOWED, SHELL_BLOCK_WORDS, argvReentryUnjudged, isBareControlWord, programPositionRefusalSentence, ASSIGNMENT_PREFIX, readProgramPosition, writtenAssignmentPrefix, } from "./bash-program-position.js";
4
4
  export const BASH_READONLY_DEFAULT_ALLOW = [
5
5
  "ls", "cat", "head", "tail", "wc", "pwd", "echo", "whoami", "uname",
6
6
  "grep", "cut", "tr", "basename", "dirname", "stat", "du", "df", "which",
@@ -208,7 +208,21 @@ function tokenizeSegment(segment) {
208
208
  }
209
209
  export function hasUnquotedExpansionMetachar(rawToken) {
210
210
  let open;
211
- for (const ch of rawToken) {
211
+ for (let i = 0; i < rawToken.length; i++) {
212
+ const ch = rawToken[i];
213
+ const opener = rawToken[i + 1];
214
+ if (open === undefined && ch === "$" && dollarOpensQuote(rawToken, i)) {
215
+ if (opener === '"') {
216
+ open = opener;
217
+ i += 1;
218
+ continue;
219
+ }
220
+ const close = ansiCQuoteClose(rawToken, i + 1);
221
+ if (close === undefined)
222
+ return true;
223
+ i = close;
224
+ continue;
225
+ }
212
226
  if (open === undefined && (ch === '"' || ch === "'")) {
213
227
  open = ch;
214
228
  continue;
@@ -1444,28 +1458,51 @@ function isGrepFileStdinLongOption(tok) {
1444
1458
  return name !== undefined && isLongOptionAbbrevOf(name, "file");
1445
1459
  }
1446
1460
  const CLUSTER_OPTION_CHAR = /[A-Za-z0-9]/;
1447
- const ASSIGNMENT_OR_APPEND_WORD = /^[A-Za-z_][A-Za-z0-9_]*\+?=/;
1448
- export function assignmentWordPayload(word) {
1449
- if (!ASSIGNMENT_OR_APPEND_WORD.test(word))
1461
+ function tildeExpandsInValue(rawValue) {
1462
+ if (rawValue === undefined)
1463
+ return false;
1464
+ for (let at = 0; at <= rawValue.length;) {
1465
+ if (rawValue[at] === "~") {
1466
+ let quoted = false;
1467
+ for (let k = at + 1; k < rawValue.length && rawValue[k] !== "/" && rawValue[k] !== ":"; k++) {
1468
+ if (rawValue[k] === "'" || rawValue[k] === '"' || rawValue[k] === "\\") {
1469
+ quoted = true;
1470
+ break;
1471
+ }
1472
+ }
1473
+ if (!quoted)
1474
+ return true;
1475
+ }
1476
+ const next = rawValue.indexOf(":", at);
1477
+ if (next < 0)
1478
+ return false;
1479
+ at = next + 1;
1480
+ }
1481
+ return false;
1482
+ }
1483
+ export function assignmentWordPayload(word, raw = word) {
1484
+ const written = writtenAssignmentPrefix(word);
1485
+ if (written === undefined)
1450
1486
  return undefined;
1451
- const eq = word.indexOf("=");
1452
- const value = word.slice(eq + 1);
1453
- if (word[eq - 1] === "+")
1454
- return { kind: "unresolved", reason: `"${word}" appends to a value the text does not contain` };
1455
- if (value.includes("~"))
1487
+ const eq = written.prefix.length - 1;
1488
+ const spelled = word.slice(eq + 1);
1489
+ const expands = tildeExpandsInValue(raw.startsWith(written.prefix) ? raw.slice(written.prefix.length) : undefined);
1490
+ const value = expands ? spelled : literalTildeSpelling(spelled);
1491
+ if (written.appends) {
1492
+ const reason = `"${word}" appends to a value the text does not contain`;
1493
+ return spelled === "" || expands ? { kind: "unresolved", reason } : { kind: "unresolved", reason, value };
1494
+ }
1495
+ if (expands)
1456
1496
  return { kind: "unresolved", reason: `"${word}" carries a tilde whose expansion the text does not settle` };
1457
- return value === "" ? undefined : { kind: "value", value };
1497
+ return spelled === "" ? undefined : { kind: "value", value };
1458
1498
  }
1459
1499
  export const ASSIGNMENT_VALUE_NOT_PATHS = new Set(["make", "gmake", "bmake", "cmake", "ninja", "meson", "docker", "podman"]);
1460
1500
  export function argvProgramOf(tokens) {
1461
- let lead = 0;
1462
- while (lead < tokens.folded.length && ASSIGNMENT_OR_APPEND_WORD.test(tokens.folded[lead]))
1463
- lead++;
1464
- const pos = readProgramPosition({ folded: tokens.folded.slice(lead), raw: tokens.raw.slice(lead) });
1501
+ const pos = readProgramPosition(tokens);
1465
1502
  if (pos.program === undefined)
1466
1503
  return undefined;
1467
- const at = lead + pos.program.index;
1468
- return ASSIGNMENT_OR_APPEND_WORD.test(tokens.folded[at] ?? "") ? undefined : { program: pos.program.basename, from: at };
1504
+ const at = pos.program.index;
1505
+ return ASSIGNMENT_PREFIX.test(tokens.folded[at] ?? "") ? undefined : { program: pos.program.basename, from: at };
1469
1506
  }
1470
1507
  export function attachedOptionPayloads(tok) {
1471
1508
  const literal = literalTildeSpelling;
@@ -285,7 +285,7 @@ function segmentFacts(segment, p, decl, nestedPlan) {
285
285
  reads.push({ spelled: word, raw, provenance: "unlisted_word", expands: "unresolvable" });
286
286
  continue;
287
287
  }
288
- if (assignmentWordPayload(word) !== undefined) {
288
+ if (assignmentWordPayload(word, toks.raw[j]) !== undefined) {
289
289
  pushAssignment(reads, toks, j, "env_assignment");
290
290
  continue;
291
291
  }
@@ -465,15 +465,13 @@ function redirectFact(r) {
465
465
  }
466
466
  function pushAssignment(reads, toks, k, provenance) {
467
467
  const word = toks.folded[k];
468
- const payload = assignmentWordPayload(word);
468
+ const payload = assignmentWordPayload(word, toks.raw[k]);
469
469
  if (payload === undefined)
470
470
  return;
471
- if (payload.kind === "value" && payload.value === SUBSTITUTION_PLACEHOLDER)
472
- return;
473
- if (payload.kind === "value")
474
- reads.push(bare(toks.raw[k], payload.value, provenance));
475
- else
471
+ if (payload.kind === "unresolved")
476
472
  reads.push({ spelled: word, raw: toks.raw[k], provenance, expands: "unresolvable" });
473
+ if (payload.value !== undefined && payload.value !== SUBSTITUTION_PLACEHOLDER)
474
+ reads.push(bare(toks.raw[k], payload.value, provenance));
477
475
  }
478
476
  function unlistedWords(reads, toks, from, launcherIndices, provenance, program) {
479
477
  const argv = program !== undefined ? { program: program.basename, from: program.index } : argvProgramOf(toks);
@@ -742,11 +740,11 @@ function listedVerbCandidates(name, args, rawArgs, reads) {
742
740
  positional.push({ word: t, raw: rawArgs[k] });
743
741
  push(k, t, "operand");
744
742
  if (!ASSIGNMENT_VALUE_NOT_PATHS.has(name)) {
745
- const payload = assignmentWordPayload(t);
746
- if (payload?.kind === "value")
747
- push(k, payload.value, "operand");
748
- else if (payload !== undefined)
743
+ const payload = assignmentWordPayload(t, rawArgs[k]);
744
+ if (payload?.kind === "unresolved")
749
745
  reads.push({ spelled: t, raw: rawArgs[k], provenance: "operand", expands: "unresolvable" });
746
+ if (payload?.value !== undefined)
747
+ push(k, payload.value, "operand");
750
748
  }
751
749
  }
752
750
  for (let k = 0; k < args.length; k++) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sema-agent/core",
3
- "version": "7.25.0",
3
+ "version": "7.26.0",
4
4
  "description": "Stateless, task-oriented AI agent core",
5
5
  "type": "module",
6
6
  "license": "BUSL-1.1",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "_comment": "design/87 L3 — frozen public export surface of src/index.ts (name -> kind). DO NOT edit by hand to silence a red test. A removed/changed entry = a SemVer-BREAKING change; bump MAJOR and update this fixture in the SAME commit (design/87 §4.2 / §5.2). Regenerate via REGEN in test/export-surface.test.ts.",
3
3
  "_tierComment": "#435 v1 — machine-readable layering of the public surface: stable = demonstrated by README.md / src/examples; internal = an `Internal`-marked name or a runner/engine deep-subtree declaration (the model seam src/engine/llm is excluded — it is the BYOM contract, not an engine internal); advanced = a supported export the front door does not walk you through. THIS IS AN INITIAL HEURISTIC, derived mechanically and expected to be refined ticket by ticket: no human reviewed these 1700+ entries one by one, and nothing here claims otherwise. Known bias: a short or English-word export name (ok, err, Result, Usage) can match ordinary prose in README.md and land `stable` on a coincidence. Every export MUST carry a tier — a new export with no row fails the gate in export-surface.test.ts.",
4
- "count": 2410,
4
+ "count": 2424,
5
5
  "exports": {
6
6
  "A2ATaskState": "type",
7
7
  "A2ATaskStateReversal": "type",
@@ -84,6 +84,7 @@
84
84
  "AggregateBudgetOptions": "interface",
85
85
  "AnthropicBrainConfig": "interface",
86
86
  "AppendLog": "class",
87
+ "ApproverPosture": "type",
87
88
  "ArtifactAction": "type",
88
89
  "ArtifactCallContext": "interface",
89
90
  "ArtifactCommitCertainty": "type",
@@ -716,6 +717,7 @@
716
717
  "McpInjectionDropFacts": "interface",
717
718
  "McpInjectionDropReason": "type",
718
719
  "McpLivenessState": "type",
720
+ "McpProbeResult": "interface",
719
721
  "McpReconnectResult": "interface",
720
722
  "McpRefreshResult": "interface",
721
723
  "McpServerLiveness": "interface",
@@ -984,6 +986,7 @@
984
986
  "PermissionRuleSyncContractHooks": "interface",
985
987
  "PermissionRuleSyncResult": "interface",
986
988
  "PermissionRuleSyncTransport": "type",
989
+ "PermissionRuleWriteContractHooks": "interface",
987
990
  "PermissionRuleWriter": "interface",
988
991
  "PersistedOrgRuleState": "interface",
989
992
  "PersistedRule": "interface",
@@ -1059,6 +1062,7 @@
1059
1062
  "READ_ONLY_EXACT_FORMS": "variable",
1060
1063
  "READ_ONLY_FLAG_ARITIES": "variable",
1061
1064
  "READ_ONLY_GLOB_PROGRAMS": "variable",
1065
+ "READ_ROOT_CANDIDATE_DIR_MAX": "variable",
1062
1066
  "READ_RULE_TOOL": "variable",
1063
1067
  "REAL_APPROVAL_CHECKPOINT_VERSION": "variable",
1064
1068
  "REASONING_BUDGET_SHARE": "variable",
@@ -1066,6 +1070,7 @@
1066
1070
  "RECOMMENDED_SENSITIVE_PATTERNS": "variable",
1067
1071
  "REMOTE_HARVEST_PER_FILE_BYTES": "variable",
1068
1072
  "REMOTE_MASS_DELETION_FUSE_RATIO": "variable",
1073
+ "REMOVAL_LIVENESS_WORDS": "variable",
1069
1074
  "RENDER_HINT_ACTIVITY_MAX_CHARS": "variable",
1070
1075
  "RENDER_HINT_MAX_CHARS": "variable",
1071
1076
  "RENDER_HINT_MAX_LIST": "variable",
@@ -1085,6 +1090,7 @@
1085
1090
  "RULE_OFFERS_ABSENCE_BASELINE": "variable",
1086
1091
  "RULE_STORE_UNREADABLE_KINDS": "variable",
1087
1092
  "RULE_SYNC_DROP_CODES": "variable",
1093
+ "RULE_WRITE_COMMITTED_WORDS": "variable",
1088
1094
  "RUN_WORKFLOW_TOOL_NAME": "variable",
1089
1095
  "RawPrefixInputs": "interface",
1090
1096
  "RawRuleSyncState": "interface",
@@ -1122,6 +1128,7 @@
1122
1128
  "RemoteMaterialization": "interface",
1123
1129
  "RemoteMemoryBaseline": "interface",
1124
1130
  "RemoteMemoryFile": "interface",
1131
+ "RemovalLiveness": "type",
1125
1132
  "RemoveResult": "type",
1126
1133
  "RemovedPermissionRule": "interface",
1127
1134
  "ReopenReason": "type",
@@ -1211,6 +1218,7 @@
1211
1218
  "RuleTicket": "type",
1212
1219
  "RuleTightenAddDelta": "interface",
1213
1220
  "RuleTombstone": "interface",
1221
+ "RuleWriteCommitted": "type",
1214
1222
  "RuleWriteDelta": "type",
1215
1223
  "RuleWriteOutcome": "type",
1216
1224
  "RunInternals": "interface",
@@ -1388,6 +1396,7 @@
1388
1396
  "SystemInjection": "interface",
1389
1397
  "SystemInjectionPriority": "type",
1390
1398
  "SystemInjectionQueue": "class",
1399
+ "TASK_OUTPUT_REPLAY_KINDS": "variable",
1391
1400
  "TEACHER_PROFILE": "variable",
1392
1401
  "TEACHER_PROMPT": "variable",
1393
1402
  "TEAMMATE_COMMUNICATION_ADDENDUM": "variable",
@@ -1421,6 +1430,7 @@
1421
1430
  "TaskNotificationPayload": "interface",
1422
1431
  "TaskNotificationStatus": "type",
1423
1432
  "TaskOutcome": "interface",
1433
+ "TaskOutputReplay": "type",
1424
1434
  "TaskRegistry": "class",
1425
1435
  "TaskRequestBody": "interface",
1426
1436
  "TaskResult": "interface",
@@ -1862,6 +1872,7 @@
1862
1872
  "deriveRepoControlPlaneDir": "function",
1863
1873
  "deriveRepoKey": "function",
1864
1874
  "deriveRepoMemoryDir": "function",
1875
+ "deriveShadowedSet": "function",
1865
1876
  "deriveSupersededSet": "function",
1866
1877
  "deriveTripwire": "function",
1867
1878
  "deriveWiringManifest": "function",
@@ -2095,6 +2106,7 @@
2095
2106
  "normalizePersistedRuleHit": "function",
2096
2107
  "normalizePromptEpoch": "function",
2097
2108
  "normalizePublishedPath": "function",
2109
+ "normalizeReadRootCandidate": "function",
2098
2110
  "normalizeRules": "function",
2099
2111
  "normalizeToolResultProvenance": "function",
2100
2112
  "noticeAudienceOf": "function",
@@ -2151,6 +2163,7 @@
2151
2163
  "peerSendVerdictSeverity": "function",
2152
2164
  "peerSessionBoxHandle": "function",
2153
2165
  "permissionRuleSyncContract": "function",
2166
+ "permissionRuleWriteContract": "function",
2154
2167
  "pgQuery": "function",
2155
2168
  "physicalPathOf": "function",
2156
2169
  "physicalPathOfExisting": "function",
@@ -2160,6 +2173,7 @@
2160
2173
  "prepareCardApproval": "function",
2161
2174
  "prepareCcImport": "function",
2162
2175
  "prepareStarterBatch": "function",
2176
+ "probeMcpServers": "function",
2163
2177
  "probeParkRoundTrip": "function",
2164
2178
  "probeSearchBackend": "function",
2165
2179
  "processFingerprint": "function",
@@ -2496,6 +2510,7 @@
2496
2510
  "AggregateBudgetOptions": "advanced",
2497
2511
  "AnthropicBrainConfig": "advanced",
2498
2512
  "AppendLog": "advanced",
2513
+ "ApproverPosture": "advanced",
2499
2514
  "ArtifactAction": "advanced",
2500
2515
  "ArtifactCallContext": "advanced",
2501
2516
  "ArtifactCommitCertainty": "advanced",
@@ -3128,6 +3143,7 @@
3128
3143
  "McpInjectionDropFacts": "advanced",
3129
3144
  "McpInjectionDropReason": "advanced",
3130
3145
  "McpLivenessState": "advanced",
3146
+ "McpProbeResult": "advanced",
3131
3147
  "McpReconnectResult": "advanced",
3132
3148
  "McpRefreshResult": "advanced",
3133
3149
  "McpServerLiveness": "advanced",
@@ -3396,6 +3412,7 @@
3396
3412
  "PermissionRuleSyncContractHooks": "advanced",
3397
3413
  "PermissionRuleSyncResult": "advanced",
3398
3414
  "PermissionRuleSyncTransport": "advanced",
3415
+ "PermissionRuleWriteContractHooks": "advanced",
3399
3416
  "PermissionRuleWriter": "advanced",
3400
3417
  "PersistedOrgRuleState": "stable",
3401
3418
  "PersistedRule": "advanced",
@@ -3471,6 +3488,7 @@
3471
3488
  "READ_ONLY_EXACT_FORMS": "advanced",
3472
3489
  "READ_ONLY_FLAG_ARITIES": "advanced",
3473
3490
  "READ_ONLY_GLOB_PROGRAMS": "advanced",
3491
+ "READ_ROOT_CANDIDATE_DIR_MAX": "advanced",
3474
3492
  "READ_RULE_TOOL": "advanced",
3475
3493
  "REAL_APPROVAL_CHECKPOINT_VERSION": "advanced",
3476
3494
  "REASONING_BUDGET_SHARE": "advanced",
@@ -3478,6 +3496,7 @@
3478
3496
  "RECOMMENDED_SENSITIVE_PATTERNS": "advanced",
3479
3497
  "REMOTE_HARVEST_PER_FILE_BYTES": "advanced",
3480
3498
  "REMOTE_MASS_DELETION_FUSE_RATIO": "advanced",
3499
+ "REMOVAL_LIVENESS_WORDS": "advanced",
3481
3500
  "RENDER_HINT_ACTIVITY_MAX_CHARS": "advanced",
3482
3501
  "RENDER_HINT_MAX_CHARS": "advanced",
3483
3502
  "RENDER_HINT_MAX_LIST": "advanced",
@@ -3497,6 +3516,7 @@
3497
3516
  "RULE_OFFERS_ABSENCE_BASELINE": "advanced",
3498
3517
  "RULE_STORE_UNREADABLE_KINDS": "advanced",
3499
3518
  "RULE_SYNC_DROP_CODES": "advanced",
3519
+ "RULE_WRITE_COMMITTED_WORDS": "advanced",
3500
3520
  "RUN_WORKFLOW_TOOL_NAME": "stable",
3501
3521
  "RawPrefixInputs": "advanced",
3502
3522
  "RawRuleSyncState": "advanced",
@@ -3534,6 +3554,7 @@
3534
3554
  "RemoteMaterialization": "advanced",
3535
3555
  "RemoteMemoryBaseline": "advanced",
3536
3556
  "RemoteMemoryFile": "advanced",
3557
+ "RemovalLiveness": "advanced",
3537
3558
  "RemoveResult": "advanced",
3538
3559
  "RemovedPermissionRule": "advanced",
3539
3560
  "ReopenReason": "stable",
@@ -3623,6 +3644,7 @@
3623
3644
  "RuleTicket": "advanced",
3624
3645
  "RuleTightenAddDelta": "advanced",
3625
3646
  "RuleTombstone": "advanced",
3647
+ "RuleWriteCommitted": "advanced",
3626
3648
  "RuleWriteDelta": "advanced",
3627
3649
  "RuleWriteOutcome": "advanced",
3628
3650
  "RunInternals": "internal",
@@ -3800,6 +3822,7 @@
3800
3822
  "SystemInjection": "advanced",
3801
3823
  "SystemInjectionPriority": "advanced",
3802
3824
  "SystemInjectionQueue": "advanced",
3825
+ "TASK_OUTPUT_REPLAY_KINDS": "advanced",
3803
3826
  "TEACHER_PROFILE": "advanced",
3804
3827
  "TEACHER_PROMPT": "advanced",
3805
3828
  "TEAMMATE_COMMUNICATION_ADDENDUM": "advanced",
@@ -3833,6 +3856,7 @@
3833
3856
  "TaskNotificationPayload": "advanced",
3834
3857
  "TaskNotificationStatus": "advanced",
3835
3858
  "TaskOutcome": "advanced",
3859
+ "TaskOutputReplay": "advanced",
3836
3860
  "TaskRegistry": "advanced",
3837
3861
  "TaskRequestBody": "advanced",
3838
3862
  "TaskResult": "stable",
@@ -4274,6 +4298,7 @@
4274
4298
  "deriveRepoControlPlaneDir": "advanced",
4275
4299
  "deriveRepoKey": "advanced",
4276
4300
  "deriveRepoMemoryDir": "advanced",
4301
+ "deriveShadowedSet": "advanced",
4277
4302
  "deriveSupersededSet": "advanced",
4278
4303
  "deriveTripwire": "advanced",
4279
4304
  "deriveWiringManifest": "advanced",
@@ -4507,6 +4532,7 @@
4507
4532
  "normalizePersistedRuleHit": "advanced",
4508
4533
  "normalizePromptEpoch": "advanced",
4509
4534
  "normalizePublishedPath": "advanced",
4535
+ "normalizeReadRootCandidate": "advanced",
4510
4536
  "normalizeRules": "advanced",
4511
4537
  "normalizeToolResultProvenance": "advanced",
4512
4538
  "noticeAudienceOf": "advanced",
@@ -4563,6 +4589,7 @@
4563
4589
  "peerSendVerdictSeverity": "advanced",
4564
4590
  "peerSessionBoxHandle": "advanced",
4565
4591
  "permissionRuleSyncContract": "advanced",
4592
+ "permissionRuleWriteContract": "advanced",
4566
4593
  "pgQuery": "advanced",
4567
4594
  "physicalPathOf": "advanced",
4568
4595
  "physicalPathOfExisting": "advanced",
@@ -4572,6 +4599,7 @@
4572
4599
  "prepareCardApproval": "advanced",
4573
4600
  "prepareCcImport": "advanced",
4574
4601
  "prepareStarterBatch": "advanced",
4602
+ "probeMcpServers": "advanced",
4575
4603
  "probeParkRoundTrip": "stable",
4576
4604
  "probeSearchBackend": "advanced",
4577
4605
  "processFingerprint": "advanced",
@@ -0,0 +1,64 @@
1
+ {
2
+ "repo": "core",
3
+ "version": "7.25.1",
4
+ "from": "b205840bf3354e748513a90e5d698b8dd8a639fd",
5
+ "to": "v7.25.1",
6
+ "added": [],
7
+ "removed": [],
8
+ "changed": [],
9
+ "narrowed": [
10
+ {
11
+ "id": "F1",
12
+ "source": "behaviorFlips.summary",
13
+ "text": "NARROWING (#993, P2, read boundary): a deny-listed path spelled through an assignment word or a quote form is REFUSED at zero cards on every shell face — bare `NAME+=value`, `NAME[sub]=value` (subscript may be quoted), a `$'…'` / `$\"…\"` body with no backslash, a tilde outside an expansion slot (`A=.env~`), and a declaration operand (`export`/`declare`/`local` …) of those spellings."
14
+ },
15
+ {
16
+ "id": "F3",
17
+ "source": "behaviorFlips.summary",
18
+ "text": "NARROWING (#993 E5): a QUOTED assignment-shaped first word (`'A=x' cmd`, `\"A+=x\" cmd`) is the program name bash runs, so it is judged as an unknown program and its path operands are judged — one bare-prefix question for `=` and `+=` alike; KL-945h closed."
19
+ },
20
+ {
21
+ "id": "F4",
22
+ "source": "behaviorFlips.summary",
23
+ "text": "NARROWING (#993 leg B / E7 / F3 / G2, irreversibility): the unverifiable-recursive-delete walk skips leading assignments with the same bare-prefix grammar and applies one state transition to every declaration operand, so `A+=x rm -rf $UNSET` and `export -n D+=$UNKNOWN; rm -rf $D` report a finding where they reported none; `export -n D=/tmp/safe; rm -rf \"$D\"` no longer over-asks."
24
+ }
25
+ ],
26
+ "closedSetMembers": [],
27
+ "closedSetsUnreadable": [],
28
+ "typeKeys": [],
29
+ "declarationMoves": [],
30
+ "mintMoves": [],
31
+ "criteriaObserves": [
32
+ {
33
+ "kind": "taskEventField",
34
+ "name": "tool_end.gate",
35
+ "assertions": [
36
+ "G1.a",
37
+ "G1.b"
38
+ ]
39
+ },
40
+ {
41
+ "kind": "taskEventField",
42
+ "name": "tool_end.structured",
43
+ "assertions": [
44
+ "G1.a"
45
+ ]
46
+ },
47
+ {
48
+ "kind": "typeMember",
49
+ "name": "AskRequest.requiresRealApproval",
50
+ "assertions": [
51
+ "G2.a"
52
+ ]
53
+ }
54
+ ],
55
+ "consumersHint": {
56
+ "cli": [],
57
+ "server": [],
58
+ "sdk": [],
59
+ "note": "NOT SCANNED: sema-cli, sema-server, sema-sdk — an empty list for those repos means \"not checked out\", not \"no consumer\""
60
+ },
61
+ "breakingCount": 0,
62
+ "breakingItems": [],
63
+ "toResolvedAt": "ce38d4e944d7b23bd648af718325db86e81b57c6"
64
+ }