@sema-agent/core 6.0.0 → 7.0.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.
@@ -111,6 +111,17 @@ declare class FilePermissionRuleStore implements WritablePermissionRuleStore {
111
111
  /** Read and validate. Any refusal answers with an empty set AND says so — never a silent empty store. */
112
112
  private read;
113
113
  private disclose;
114
+ /**
115
+ * design/382 §4.3 — the AT-REST half of the durable two-member scope face: rows carrying a session
116
+ * scope, read out of persisted bytes (a hand edit or a foreign writer — the engine's own write arms
117
+ * refuse them loudly), are DROPPED from every read face and DISCLOSED. Never quarantined (the
118
+ * quarantine area is itself durable), never silently ridden: a session authorization must not gain
119
+ * an afterlife by being planted where the store cannot legally hold it. The write base
120
+ * (`current()`) is deliberately NOT screened — foreign bytes are left in place for a person to look
121
+ * at, exactly like every other damaged-row posture here; they simply never reach a live view, the
122
+ * sync wire (`readRaw`) or adjudication.
123
+ */
124
+ private screenDurableRows;
114
125
  private write;
115
126
  list(): Promise<StoredAllowRules>;
116
127
  /** The quarantine area (design/182 §5.2/§8.3): introspection only — never part of `list()`. */
@@ -1,7 +1,7 @@
1
1
  import { closeSync, constants as FS, existsSync, fsyncSync, lstatSync, mkdirSync, openSync, readFileSync, renameSync, unlinkSync, writeFileSync } from "node:fs";
2
2
  import { join } from "node:path";
3
3
  import { createHash, randomBytes } from "node:crypto";
4
- import { PERMISSION_RULE_WRITER, applySyncJoin, applyTombstones, assertDeleteDeltaCarriesNoAdd, assertRedemptionNotQuarantined, foldDelta, } from "../../core/permission-rule-store.js";
4
+ import { PERMISSION_RULE_WRITER, applySyncJoin, applyTombstones, assertDeleteDeltaCarriesNoAdd, assertRedemptionNotQuarantined, assertWriteDeltaScopeDurable, foldDelta, } from "../../core/permission-rule-store.js";
5
5
  import { canonicalize } from "../../core/canonical-json.js";
6
6
  import { BootLock } from "./fs-atomic.js";
7
7
  import { assertAdoptionBootGate } from "./adoption/marker.js";
@@ -158,6 +158,17 @@ class FilePermissionRuleStore {
158
158
  catch {
159
159
  }
160
160
  }
161
+ screenDurableRows(file) {
162
+ const isSession = (scope) => scope?.kind === "session";
163
+ const rules = file.rules.filter((r) => !isSession(r?.scope));
164
+ const tombstones = file.tombstones.filter((t) => !isSession(t?.scope));
165
+ const quarantined = (file.quarantined ?? []).filter((q) => !isSession(q?.scope));
166
+ const dropped = file.rules.length - rules.length + (file.tombstones.length - tombstones.length) + ((file.quarantined ?? []).length - quarantined.length);
167
+ if (dropped > 0) {
168
+ this.disclose(`${this.file} carries ${dropped} session-scope row(s) — a session authorization cannot live in the durable store (design/382 §4.3); those rows are ignored on every read face and never ride sync`);
169
+ }
170
+ return { rules, tombstones, quarantined };
171
+ }
161
172
  write(next) {
162
173
  assertSafeDir(this.dir);
163
174
  atomicPublish(this.dir, this.file, JSON.stringify({ ...next, checksum: checksumOf(next) }, null, 2));
@@ -166,16 +177,17 @@ class FilePermissionRuleStore {
166
177
  const r = this.read();
167
178
  if (!("file" in r))
168
179
  return { ...EMPTY_READ };
180
+ const screened = this.screenDurableRows(r.file);
169
181
  return {
170
- rules: applyTombstones(r.file.rules, r.file.tombstones),
171
- tombstones: r.file.tombstones,
182
+ rules: applyTombstones(screened.rules, screened.tombstones),
183
+ tombstones: screened.tombstones,
172
184
  rev: r.file.rev,
173
185
  checksum: r.file.checksum,
174
186
  };
175
187
  }
176
188
  async quarantined() {
177
189
  const r = this.read();
178
- return "file" in r ? (r.file.quarantined ?? []) : [];
190
+ return "file" in r ? this.screenDurableRows(r.file).quarantined : [];
179
191
  }
180
192
  async readOrgState() {
181
193
  const r = this.read();
@@ -245,14 +257,15 @@ class FilePermissionRuleStore {
245
257
  }),
246
258
  readRaw: async () => this.serialize(() => {
247
259
  const cur = this.current();
260
+ const screened = this.screenDurableRows(cur);
248
261
  return {
249
262
  actor: cur.actor,
250
263
  counter: cur.counter,
251
264
  rev: cur.rev,
252
- rules: structuredClone(cur.rules),
253
- tombstones: structuredClone(cur.tombstones),
265
+ rules: structuredClone(screened.rules),
266
+ tombstones: structuredClone(screened.tombstones),
254
267
  ...(cur.sync?.observedVector !== undefined ? { observedVector: structuredClone(cur.sync.observedVector) } : {}),
255
- quarantined: structuredClone(cur.quarantined ?? []),
268
+ quarantined: structuredClone(screened.quarantined),
256
269
  };
257
270
  }),
258
271
  apply: async (delta, opts) => this.serialize(() => {
@@ -287,8 +300,8 @@ class FilePermissionRuleStore {
287
300
  return { rev: cur.rev + 1, sync: report };
288
301
  }
289
302
  const next = delta.kind === "redemption-add"
290
- ? (assertRedemptionNotQuarantined(cur.quarantined ?? [], delta), { ...cur, rev: cur.rev + 1, rules: foldDelta(cur.rules, delta) })
291
- : (assertDeleteDeltaCarriesNoAdd(delta), { ...cur, rev: cur.rev + 1, tombstones: [...cur.tombstones, delta.tombstone] });
303
+ ? (assertWriteDeltaScopeDurable(delta), assertRedemptionNotQuarantined(cur.quarantined ?? [], delta), { ...cur, rev: cur.rev + 1, rules: foldDelta(cur.rules, delta) })
304
+ : (assertWriteDeltaScopeDurable(delta), assertDeleteDeltaCarriesNoAdd(delta), { ...cur, rev: cur.rev + 1, tombstones: [...cur.tombstones, delta.tombstone] });
292
305
  if (!this.writeAndVerify(next)) {
293
306
  throw new Error("the permission-rule store did not survive its own write; the change was not committed");
294
307
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sema-agent/core",
3
- "version": "6.0.0",
3
+ "version": "7.0.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": 1834,
4
+ "count": 1841,
5
5
  "exports": {
6
6
  "A2ATaskState": "type",
7
7
  "A2ATaskStateReversal": "type",
@@ -439,6 +439,7 @@
439
439
  "InMemoryRuleApprovalRecordStore": "class",
440
440
  "InMemorySessionPolicyStore": "class",
441
441
  "InMemorySessionRepo": "class",
442
+ "InMemorySessionRuleOverlay": "class",
442
443
  "InMemorySessionStorage": "class",
443
444
  "InMemoryStrategyStore": "class",
444
445
  "InMemoryToolResultStore": "class",
@@ -1002,6 +1003,9 @@
1002
1003
  "SessionPolicyError": "class",
1003
1004
  "SessionPolicyStore": "interface",
1004
1005
  "SessionRepo": "interface",
1006
+ "SessionRuleOverlay": "interface",
1007
+ "SessionRuleOverlayAdd": "interface",
1008
+ "SessionRuleOverlayApplyResult": "type",
1005
1009
  "SessionRulesRecord": "interface",
1006
1010
  "SessionStorage": "interface",
1007
1011
  "SessionStore": "interface",
@@ -1273,6 +1277,7 @@
1273
1277
  "assertWorkflowDeterminism": "function",
1274
1278
  "assertWorkflowPrimitivesWiring": "function",
1275
1279
  "assertWorkflowSandboxConformance": "function",
1280
+ "assertWriteDeltaScopeDurable": "function",
1276
1281
  "atomicWriteFile": "function",
1277
1282
  "attachToolContract": "function",
1278
1283
  "autoModeArmingRecipeOf": "function",
@@ -1537,7 +1542,9 @@
1537
1542
  "isTerminalTaskNotification": "function",
1538
1543
  "isTerminalWorkflowStatus": "function",
1539
1544
  "isThinkingLevel": "function",
1545
+ "isValidConsentScope": "function",
1540
1546
  "isValidCronExpr": "function",
1547
+ "isValidDurableScope": "function",
1541
1548
  "isValidReminderMark": "function",
1542
1549
  "isWslBashLauncher": "function",
1543
1550
  "isolationPermitsAutoAccept": "function",
@@ -2275,6 +2282,7 @@
2275
2282
  "InMemoryRuleApprovalRecordStore": "advanced",
2276
2283
  "InMemorySessionPolicyStore": "advanced",
2277
2284
  "InMemorySessionRepo": "internal",
2285
+ "InMemorySessionRuleOverlay": "advanced",
2278
2286
  "InMemorySessionStorage": "internal",
2279
2287
  "InMemoryStrategyStore": "advanced",
2280
2288
  "InMemoryToolResultStore": "stable",
@@ -2838,6 +2846,9 @@
2838
2846
  "SessionPolicyError": "advanced",
2839
2847
  "SessionPolicyStore": "advanced",
2840
2848
  "SessionRepo": "stable",
2849
+ "SessionRuleOverlay": "advanced",
2850
+ "SessionRuleOverlayAdd": "advanced",
2851
+ "SessionRuleOverlayApplyResult": "advanced",
2841
2852
  "SessionRulesRecord": "advanced",
2842
2853
  "SessionStorage": "internal",
2843
2854
  "SessionStore": "advanced",
@@ -3109,6 +3120,7 @@
3109
3120
  "assertWorkflowDeterminism": "advanced",
3110
3121
  "assertWorkflowPrimitivesWiring": "advanced",
3111
3122
  "assertWorkflowSandboxConformance": "advanced",
3123
+ "assertWriteDeltaScopeDurable": "advanced",
3112
3124
  "atomicWriteFile": "advanced",
3113
3125
  "attachToolContract": "advanced",
3114
3126
  "autoModeArmingRecipeOf": "advanced",
@@ -3373,7 +3385,9 @@
3373
3385
  "isTerminalTaskNotification": "advanced",
3374
3386
  "isTerminalWorkflowStatus": "advanced",
3375
3387
  "isThinkingLevel": "advanced",
3388
+ "isValidConsentScope": "advanced",
3376
3389
  "isValidCronExpr": "advanced",
3390
+ "isValidDurableScope": "advanced",
3377
3391
  "isValidReminderMark": "advanced",
3378
3392
  "isWslBashLauncher": "internal",
3379
3393
  "isolationPermitsAutoAccept": "advanced",