footprintjs 9.46.0 → 9.46.1

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 (56) hide show
  1. package/CLAUDE.md +6 -6
  2. package/dist/esm/lib/decide/evaluator.js +2 -2
  3. package/dist/esm/lib/decide/evidence.js +2 -2
  4. package/dist/esm/lib/engine/handlers/servedPause.js +2 -2
  5. package/dist/esm/lib/memory/RecordFrame.d.ts +41 -6
  6. package/dist/esm/lib/memory/RecordFrame.js +36 -5
  7. package/dist/esm/lib/memory/SharedMemory.d.ts +1 -1
  8. package/dist/esm/lib/memory/SharedMemory.js +2 -2
  9. package/dist/esm/lib/memory/StageContext.d.ts +21 -14
  10. package/dist/esm/lib/memory/StageContext.js +36 -74
  11. package/dist/esm/lib/memory/borrowedMutation.d.ts +1 -1
  12. package/dist/esm/lib/memory/borrowedMutation.js +2 -2
  13. package/dist/esm/lib/memory/honesty.d.ts +4 -3
  14. package/dist/esm/lib/memory/honesty.js +5 -4
  15. package/dist/esm/lib/memory/index.d.ts +4 -2
  16. package/dist/esm/lib/memory/index.js +6 -4
  17. package/dist/esm/lib/memory/placeholders.d.ts +23 -28
  18. package/dist/esm/lib/memory/placeholders.js +24 -29
  19. package/dist/esm/lib/memory/recordCommit.d.ts +5 -3
  20. package/dist/esm/lib/memory/recordCommit.js +7 -5
  21. package/dist/esm/lib/memory/redaction.d.ts +78 -40
  22. package/dist/esm/lib/memory/redaction.js +130 -64
  23. package/dist/esm/lib/memory/runAddress.d.ts +20 -0
  24. package/dist/esm/lib/memory/runAddress.js +25 -0
  25. package/dist/esm/lib/memory/scrub.d.ts +51 -0
  26. package/dist/esm/lib/memory/scrub.js +72 -0
  27. package/dist/esm/lib/memory/utils.d.ts +3 -3
  28. package/dist/esm/lib/memory/utils.js +4 -4
  29. package/dist/lib/decide/evaluator.js +3 -3
  30. package/dist/lib/decide/evidence.js +3 -3
  31. package/dist/lib/engine/handlers/servedPause.js +3 -3
  32. package/dist/lib/memory/RecordFrame.js +36 -5
  33. package/dist/lib/memory/SharedMemory.js +2 -2
  34. package/dist/lib/memory/StageContext.js +42 -80
  35. package/dist/lib/memory/borrowedMutation.js +2 -2
  36. package/dist/lib/memory/honesty.js +5 -4
  37. package/dist/lib/memory/index.js +6 -4
  38. package/dist/lib/memory/placeholders.js +25 -30
  39. package/dist/lib/memory/recordCommit.js +9 -7
  40. package/dist/lib/memory/redaction.js +144 -75
  41. package/dist/lib/memory/runAddress.js +29 -0
  42. package/dist/lib/memory/scrub.js +77 -0
  43. package/dist/lib/memory/utils.js +4 -4
  44. package/dist/types/lib/memory/RecordFrame.d.ts +41 -6
  45. package/dist/types/lib/memory/SharedMemory.d.ts +1 -1
  46. package/dist/types/lib/memory/StageContext.d.ts +21 -14
  47. package/dist/types/lib/memory/borrowedMutation.d.ts +1 -1
  48. package/dist/types/lib/memory/honesty.d.ts +4 -3
  49. package/dist/types/lib/memory/index.d.ts +4 -2
  50. package/dist/types/lib/memory/placeholders.d.ts +23 -28
  51. package/dist/types/lib/memory/recordCommit.d.ts +5 -3
  52. package/dist/types/lib/memory/redaction.d.ts +78 -40
  53. package/dist/types/lib/memory/runAddress.d.ts +20 -0
  54. package/dist/types/lib/memory/scrub.d.ts +51 -0
  55. package/dist/types/lib/memory/utils.d.ts +3 -3
  56. package/package.json +1 -1
@@ -40,16 +40,41 @@
40
40
  * the facade held the verdict alone, and every path that wrote or read past
41
41
  * the facade — five of them — retained plaintext under a policy.
42
42
  *
43
- * TWO PLACEHOLDERS, BOTH HISTORICAL: the commit log and the mirror carry
44
- * `'REDACTED'` (`scrubPatch` / `redactPatch`, below — the strings unchanged since 4.x); every scope-tier view —
45
- * scope recorder events, `stageReads`/`stageWrites`, narrative — carries
46
- * `'[REDACTED]'`. Neither string changed in 9.19.0. The strings themselves are
47
- * owned by `memory/placeholders.ts` (`LOG_PLACEHOLDER` / `SCOPE_PLACEHOLDER`)
48
- * and spelled nowhere else in `src/` — this rule asks for the scope one by name.
43
+ * ONE VERDICT OWNER, ONE ENCODING OWNER (C4). This file DECIDES — the rule,
44
+ * and for a staged write {@link decideWrite} (the verdict),
45
+ * {@link inheritByIdentity} and {@link markStagedWrite} (the marks) — and is
46
+ * the engine's (L4, beside the run policy that carries the rule). The BYTES of a
47
+ * verdict are the record's: the frame hands its scrub (`whole`, or the
48
+ * `fields` inside the value — {@link scrubOf}) to `RecordFrame · write`, and
49
+ * the record's own scrub (`memory/scrub.ts`, L2) writes the log's placeholder
50
+ * at commit. Before C4 the scrub lived here too, so the record imported the
51
+ * engine's policy module to write a string.
52
+ *
53
+ * TWO PLACEHOLDERS, BOTH HISTORICAL, ONE PER OWNER: the commit log and the
54
+ * mirror carry `'REDACTED'` (`LOG_PLACEHOLDER`, `memory/placeholders.ts` — a
55
+ * record byte, written by `memory/scrub.ts`); every scope-tier view — scope
56
+ * recorder events, `stageReads`/`stageWrites`, narrative — carries
57
+ * `'[REDACTED]'` ({@link SCOPE_PLACEHOLDER}, below — the verdict's own).
58
+ * Neither string changed in 9.19.0 or since; each is spelled once in `src/`.
49
59
  */
50
60
  import type { StructuredErrorInfo } from '../errors/errorInfo.js';
51
61
  import type { RedactionMarks } from '../pause/types.js';
52
- import type { MemoryPatch } from './types.js';
62
+ import type { WriteScrub, WriteVerb } from './RecordFrame.js';
63
+ /**
64
+ * What the SCOPE CHANNEL carries where a value was scrubbed: a scope recorder's read, write and
65
+ * commit events, the `stageReads` / `stageWrites` retention, the narrative, a decision's evidence, an
66
+ * emit payload matched by `emitPatterns`, a pause payload's served form and a subflow's narrated seed
67
+ * (`onSubflowEntry`) — every value this verdict serves, unless its caller passes the log's string.
68
+ *
69
+ * Its twin is the RECORD's `LOG_PLACEHOLDER` (`'REDACTED'`, `memory/placeholders.ts`): the commit log,
70
+ * the redacted mirror and everything served from them. So NOT every recorder event carries this one:
71
+ * `onSubflowExit.outputState` serves the subflow's redacted mirror when a policy keeps one, and so
72
+ * carries the log's string (without a mirror — per-call marks alone — it is the subflow's heap
73
+ * retained under the rule, with this one). Both strings are historical and neither changed when it
74
+ * moved: this one was the constant `REDACTED` in this file until F4a, then `placeholders.ts ·
75
+ * SCOPE_PLACEHOLDER`, and since C4 it lives here again, beside the verdict that writes it.
76
+ */
77
+ export declare const SCOPE_PLACEHOLDER = "[REDACTED]";
53
78
  /**
54
79
  * Declarative key/path redaction for recorded state and boundary records.
55
80
  *
@@ -127,6 +152,14 @@ export type RedactionVerdict = {
127
152
  readonly paths: readonly string[];
128
153
  };
129
154
  export declare const CLEAR: RedactionVerdict;
155
+ /**
156
+ * The user-level NAME of `key` under `path` — the key itself at the top level, else the segments
157
+ * joined by a dot (`['profile'] + 'auth'` → `'profile.auth'`): what a verdict decides on, a mark
158
+ * holds, and the frame keys a stage's retained reads and writes by (`StageContext`). A name, not an
159
+ * address — a key may contain a dot — so it never goes into a trace path. No allocation for the
160
+ * common top-level key. (The record spells the same name for `readKeys`, `RecordFrame · noteRead`.)
161
+ */
162
+ export declare function userKeyOf(path: readonly string[], key: string): string;
130
163
  export declare class RedactionRule {
131
164
  private policy;
132
165
  private diagnosticRule;
@@ -298,7 +331,7 @@ export declare class RedactionRule {
298
331
  * (declared or themselves inherited). Run-wide, by name, like a mark.
299
332
  */
300
333
  inheritFields(target: string, paths: readonly string[]): void;
301
- /** The verdict of a key a mapper read — `runs` (the run namespaces) is selected when any namespaced key is. */
334
+ /** The verdict of a key a mapper read — `runs` (the run namespaces, `RUN_NAMESPACE`) is selected when any namespaced key is. */
302
335
  verdictOfRead(key: string, value: unknown): RedactionVerdict;
303
336
  /**
304
337
  * The retained / served form of a value at a path: the placeholder, a
@@ -381,6 +414,43 @@ export declare class RedactionRule {
381
414
  static scrubFields(value: unknown, paths: readonly string[], placeholder?: string): Record<string, unknown> | undefined;
382
415
  report(): RedactionReport;
383
416
  }
417
+ /**
418
+ * Step 1 — THE VERDICT for one staged write: an explicit per-call flag (`setValue(key, value, true)`)
419
+ * makes the value secret whole under its user-level key; else the `active` rule decides from the
420
+ * user-level path; with none (no rule, or an inert one — the caller passes `undefined`), clear, with no
421
+ * verdict call and no path allocation (the no-policy fast path). Marks nothing.
422
+ *
423
+ * ```ts
424
+ * decideWrite(new RedactionRule({ fields: { card: ['number'] } }), [], 'card', false); // { kind: 'fields', key: 'card', paths: ['number'] }
425
+ * decideWrite(undefined, ['profile'], 'auth', true); // { kind: 'whole', key: 'profile.auth' }
426
+ * ```
427
+ */
428
+ export declare function decideWrite(active: RedactionRule | undefined, path: readonly string[], key: string, explicit: boolean | undefined): RedactionVerdict;
429
+ /**
430
+ * Step 2 — IDENTITY: an OBJECT the stage read under a selected name (`selected` — the frame's selected
431
+ * reads, filled by its tracked reads), written under another name (`s.person = s.profile`), keeps that
432
+ * read's rule, matched by identity: a whole read marks the new key, a `fields` read hands it the fields
433
+ * (re-based under the written path), and the verdict is asked again. A new object, a primitive, or a
434
+ * write already whole is selected by its own name only — `verdict` comes back as it is. Decided BEFORE
435
+ * the write, because the verdict needs it: an inheritance stays even if the write then fails to stage.
436
+ */
437
+ export declare function inheritByIdentity(active: RedactionRule | undefined, verdict: RedactionVerdict, selected: WeakMap<object, RedactionVerdict> | undefined, path: readonly string[], key: string, value: unknown): RedactionVerdict;
438
+ /**
439
+ * Step 3's input — a verdict's BYTES for the record (`RecordFrame · write`): nothing when clear, the
440
+ * whole value, or the fields inside it. No allocation on the default path (clear) or for a whole verdict.
441
+ */
442
+ export declare function scrubOf(verdict: RedactionVerdict): WriteScrub | undefined;
443
+ /**
444
+ * Step 4 — the MARKS a staged write leaves; call it only once the write staged, so a write that fails to
445
+ * stage marks nothing. A delete clears its key's mark (and any fields a mapper handed it) on `active`,
446
+ * the rule that was active as the write BEGAN — none when it was inert, even if user code marked the key
447
+ * during the write. A whole verdict marks its key — the key that DECIDED it (`verdict.key`: an ancestor
448
+ * for a nested write under a whole-selected key) — for the rest of the run on `rule`, the run's rule as
449
+ * it stands NOW (user code during the write may have installed one; an explicit mark is what makes an
450
+ * inert rule active). A mark is a run-wide NAME: it stays when the stage's commit fails or a retry
451
+ * discards the attempt — the safe side; only a staged delete removes one.
452
+ */
453
+ export declare function markStagedWrite(active: RedactionRule | undefined, rule: RedactionRule | undefined, verdict: RedactionVerdict, path: readonly string[], key: string, verb: WriteVerb): void;
384
454
  /**
385
455
  * Path visits one walk may make — reachable only under a PATH-dependent
386
456
  * pattern over a value whose paths outnumber its objects (a linked history, a
@@ -518,35 +588,3 @@ export declare class MapperTaint {
518
588
  /** Does a value the mapper BUILT embed, by reference, a selected record it read or was handed? */
519
589
  private embedsSelected;
520
590
  }
521
- /**
522
- * The commit log's scrub: `patch` with {@link LOG_PLACEHOLDER} at every path in `redactedPaths` that
523
- * holds a defined value — the copy `recordCommit` records and feeds the redacted mirror.
524
- *
525
- * CLONE-FREE (9.33.0). The patch is the transaction buffer's commit-time payload, already the record's
526
- * own copy (`TransactionBuffer · commit` clones each surviving path once; the buffer is dropped at
527
- * commit), so the scrub copies only what it must not edit in place:
528
- * - no path to scrub (no policy, no per-call mark — the common case) → `patch` ITSELF, no copy at all;
529
- * - otherwise → a new root and a shallow copy of each container on a scrubbed path (`pathOps ·
530
- * ownSpine`), every other subtree shared with `patch`. `patch` is never edited.
531
- * The engine called the public {@link redactPatch} (a whole `structuredClone`) twice per commit before
532
- * 9.33.0. The bytes are the same: a scrubbed path holds the placeholder, every other path the value the
533
- * buffer cloned (pinned by the 9.18.1 / 9.19.1 redaction byte tests).
534
- *
535
- * Paths are scrubbed in the set's order, against the tree as scrubbed so far: a path under one already
536
- * scrubbed finds a string, not a container, and is left alone (as before).
537
- *
538
- * INTERNAL — the result shares structure with `patch`. A caller outside the commit path wants
539
- * {@link redactPatch}.
540
- *
541
- * @param redactedPaths DELIM-joined paths (`TransactionBuffer`'s `redactedPaths`; a bundle's
542
- * `redactedPaths` array works too).
543
- */
544
- export declare function scrubPatch(patch: MemoryPatch, redactedPaths: Iterable<string>): MemoryPatch;
545
- /**
546
- * Redacts sensitive values in a patch for logging/debugging — the PUBLIC scrub (`footprintjs/advanced`),
547
- * its contract unchanged since 4.x: a fresh deep copy of `patch` (`structuredClone`) with
548
- * {@link LOG_PLACEHOLDER} at every listed path that holds a defined value. Shares nothing with `patch`
549
- * and never edits it. (Moved here from `memory/utils.ts` in 9.33.0; the engine's own commit path uses the
550
- * clone-free {@link scrubPatch}.)
551
- */
552
- export declare function redactPatch(patch: MemoryPatch, redactedSet: Set<string>): MemoryPatch;