instar 1.3.730 → 1.3.732

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 (83) hide show
  1. package/dist/commands/server.d.ts.map +1 -1
  2. package/dist/commands/server.js +161 -1
  3. package/dist/commands/server.js.map +1 -1
  4. package/dist/config/ConfigDefaults.d.ts.map +1 -1
  5. package/dist/config/ConfigDefaults.js +26 -0
  6. package/dist/config/ConfigDefaults.js.map +1 -1
  7. package/dist/core/CoherenceGate.d.ts +119 -0
  8. package/dist/core/CoherenceGate.d.ts.map +1 -1
  9. package/dist/core/CoherenceGate.js +342 -19
  10. package/dist/core/CoherenceGate.js.map +1 -1
  11. package/dist/core/CoherenceReviewer.d.ts +30 -0
  12. package/dist/core/CoherenceReviewer.d.ts.map +1 -1
  13. package/dist/core/CoherenceReviewer.js +14 -0
  14. package/dist/core/CoherenceReviewer.js.map +1 -1
  15. package/dist/core/ConversationRegistry.d.ts +260 -0
  16. package/dist/core/ConversationRegistry.d.ts.map +1 -0
  17. package/dist/core/ConversationRegistry.js +1151 -0
  18. package/dist/core/ConversationRegistry.js.map +1 -0
  19. package/dist/core/FileClassifier.d.ts.map +1 -1
  20. package/dist/core/FileClassifier.js +7 -0
  21. package/dist/core/FileClassifier.js.map +1 -1
  22. package/dist/core/PostUpdateMigrator.d.ts +13 -0
  23. package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
  24. package/dist/core/PostUpdateMigrator.js +105 -0
  25. package/dist/core/PostUpdateMigrator.js.map +1 -1
  26. package/dist/core/ResponseReviewDecisionLog.d.ts +45 -0
  27. package/dist/core/ResponseReviewDecisionLog.d.ts.map +1 -0
  28. package/dist/core/ResponseReviewDecisionLog.js +85 -0
  29. package/dist/core/ResponseReviewDecisionLog.js.map +1 -0
  30. package/dist/core/WriteDomainRegistry.d.ts.map +1 -1
  31. package/dist/core/WriteDomainRegistry.js +21 -0
  32. package/dist/core/WriteDomainRegistry.js.map +1 -1
  33. package/dist/core/conversationContextWiring.d.ts +51 -0
  34. package/dist/core/conversationContextWiring.d.ts.map +1 -0
  35. package/dist/core/conversationContextWiring.js +78 -0
  36. package/dist/core/conversationContextWiring.js.map +1 -0
  37. package/dist/core/conversationIdentity.d.ts +112 -0
  38. package/dist/core/conversationIdentity.d.ts.map +1 -0
  39. package/dist/core/conversationIdentity.js +141 -0
  40. package/dist/core/conversationIdentity.js.map +1 -0
  41. package/dist/core/deliverToConversation.d.ts +62 -0
  42. package/dist/core/deliverToConversation.d.ts.map +1 -0
  43. package/dist/core/deliverToConversation.js +85 -0
  44. package/dist/core/deliverToConversation.js.map +1 -0
  45. package/dist/core/devGatedFeatures.d.ts.map +1 -1
  46. package/dist/core/devGatedFeatures.js +6 -0
  47. package/dist/core/devGatedFeatures.js.map +1 -1
  48. package/dist/core/reviewers/conversational-tone.d.ts.map +1 -1
  49. package/dist/core/reviewers/conversational-tone.js +15 -1
  50. package/dist/core/reviewers/conversational-tone.js.map +1 -1
  51. package/dist/core/types.d.ts +76 -0
  52. package/dist/core/types.d.ts.map +1 -1
  53. package/dist/core/types.js.map +1 -1
  54. package/dist/core/untrustedConversationContext.d.ts +77 -0
  55. package/dist/core/untrustedConversationContext.d.ts.map +1 -0
  56. package/dist/core/untrustedConversationContext.js +134 -0
  57. package/dist/core/untrustedConversationContext.js.map +1 -0
  58. package/dist/monitoring/ReviewCanaryBattery.d.ts +160 -0
  59. package/dist/monitoring/ReviewCanaryBattery.d.ts.map +1 -0
  60. package/dist/monitoring/ReviewCanaryBattery.js +416 -0
  61. package/dist/monitoring/ReviewCanaryBattery.js.map +1 -0
  62. package/dist/scaffold/templates.d.ts.map +1 -1
  63. package/dist/scaffold/templates.js +15 -0
  64. package/dist/scaffold/templates.js.map +1 -1
  65. package/dist/server/AgentServer.d.ts +7 -0
  66. package/dist/server/AgentServer.d.ts.map +1 -1
  67. package/dist/server/AgentServer.js +13 -0
  68. package/dist/server/AgentServer.js.map +1 -1
  69. package/dist/server/CapabilityIndex.d.ts.map +1 -1
  70. package/dist/server/CapabilityIndex.js +15 -0
  71. package/dist/server/CapabilityIndex.js.map +1 -1
  72. package/dist/server/routes.d.ts +10 -0
  73. package/dist/server/routes.d.ts.map +1 -1
  74. package/dist/server/routes.js +114 -1
  75. package/dist/server/routes.js.map +1 -1
  76. package/package.json +1 -1
  77. package/src/data/builtin-manifest.json +64 -64
  78. package/src/scaffold/templates/jobs/instar/review-canary-battery.md +31 -0
  79. package/src/scaffold/templates.ts +15 -0
  80. package/upgrades/1.3.731.md +97 -0
  81. package/upgrades/1.3.732.md +107 -0
  82. package/upgrades/side-effects/context-aware-outbound-review.md +62 -0
  83. package/upgrades/side-effects/durable-conversation-identity-increment1.md +89 -0
@@ -0,0 +1,45 @@
1
+ /**
2
+ * ResponseReviewDecisionLog — the durable would-block decision log
3
+ * (context-aware-outbound-review spec §D8, the flip-evidence store).
4
+ *
5
+ * The in-memory `CoherenceGate.reviewHistory` is pruned to 1000 entries and
6
+ * erased by every server restart — a data-gated enforcement-flip criterion
7
+ * ("a clean day on real traffic") cannot rest on a store any restart wipes.
8
+ * This append-only JSONL (`logs/response-review-decisions.jsonl`) is the
9
+ * restart-surviving record: one line per `_evaluate` verdict (ALL outcomes,
10
+ * not just would-blocks — the §D9.3 denominator matters), written at the same
11
+ * seam as `logAudit`, plus the two additive soak row types (counterfactual
12
+ * rows, §D9.4; canary/battery rows, §D9.4b — written through this SAME
13
+ * writer so there is exactly one file and one rotation policy).
14
+ *
15
+ * At-rest honesty (§D8): rows persist 200 credential-scrubbed chars of every
16
+ * reviewed turn plus topicId, as a plaintext machine-local file under
17
+ * filesystem permissions — the same posture as sibling JSONLs, NOT the
18
+ * encrypted vault. That is the trade for restart-surviving flip evidence.
19
+ *
20
+ * Failure direction: write failures are swallowed — telemetry must never
21
+ * affect a verdict or delivery (§D5: the D8 write is one of the individually
22
+ * contained context code paths; the HTTP seam above fails OPEN so nothing
23
+ * here may throw into `_evaluate`).
24
+ */
25
+ export declare class ResponseReviewDecisionLog {
26
+ private readonly logPath;
27
+ private readonly maxBytes;
28
+ constructor(logPath: string, options?: {
29
+ maxBytes?: number;
30
+ });
31
+ /** The absolute path of the JSONL file (for tests + observability). */
32
+ getPath(): string;
33
+ /**
34
+ * Append one row. Swallows every failure — the decision log is telemetry;
35
+ * a full disk or unwritable path must never affect a review verdict.
36
+ */
37
+ append(row: Record<string, unknown>): void;
38
+ /**
39
+ * Size rotation: when the file exceeds maxBytes, rename it to `<path>.1`
40
+ * (replacing the previous archive) and start fresh — the same bounded
41
+ * single-archive policy sibling JSONLs use. Contained; never throws.
42
+ */
43
+ private rotateIfNeeded;
44
+ }
45
+ //# sourceMappingURL=ResponseReviewDecisionLog.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ResponseReviewDecisionLog.d.ts","sourceRoot":"","sources":["../../src/core/ResponseReviewDecisionLog.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAQH,qBAAa,yBAAyB;IACpC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;gBAEtB,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE;IAK5D,uEAAuE;IACvE,OAAO,IAAI,MAAM;IAIjB;;;OAGG;IACH,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAW1C;;;;OAIG;IACH,OAAO,CAAC,cAAc;CAqBvB"}
@@ -0,0 +1,85 @@
1
+ /**
2
+ * ResponseReviewDecisionLog — the durable would-block decision log
3
+ * (context-aware-outbound-review spec §D8, the flip-evidence store).
4
+ *
5
+ * The in-memory `CoherenceGate.reviewHistory` is pruned to 1000 entries and
6
+ * erased by every server restart — a data-gated enforcement-flip criterion
7
+ * ("a clean day on real traffic") cannot rest on a store any restart wipes.
8
+ * This append-only JSONL (`logs/response-review-decisions.jsonl`) is the
9
+ * restart-surviving record: one line per `_evaluate` verdict (ALL outcomes,
10
+ * not just would-blocks — the §D9.3 denominator matters), written at the same
11
+ * seam as `logAudit`, plus the two additive soak row types (counterfactual
12
+ * rows, §D9.4; canary/battery rows, §D9.4b — written through this SAME
13
+ * writer so there is exactly one file and one rotation policy).
14
+ *
15
+ * At-rest honesty (§D8): rows persist 200 credential-scrubbed chars of every
16
+ * reviewed turn plus topicId, as a plaintext machine-local file under
17
+ * filesystem permissions — the same posture as sibling JSONLs, NOT the
18
+ * encrypted vault. That is the trade for restart-surviving flip evidence.
19
+ *
20
+ * Failure direction: write failures are swallowed — telemetry must never
21
+ * affect a verdict or delivery (§D5: the D8 write is one of the individually
22
+ * contained context code paths; the HTTP seam above fails OPEN so nothing
23
+ * here may throw into `_evaluate`).
24
+ */
25
+ import fs from 'node:fs';
26
+ import path from 'node:path';
27
+ import { SafeFsExecutor } from './SafeFsExecutor.js';
28
+ const DEFAULT_MAX_BYTES = 10 * 1024 * 1024; // 10MB, size-rotated like sibling JSONLs
29
+ export class ResponseReviewDecisionLog {
30
+ logPath;
31
+ maxBytes;
32
+ constructor(logPath, options) {
33
+ this.logPath = logPath;
34
+ this.maxBytes = options?.maxBytes ?? DEFAULT_MAX_BYTES;
35
+ }
36
+ /** The absolute path of the JSONL file (for tests + observability). */
37
+ getPath() {
38
+ return this.logPath;
39
+ }
40
+ /**
41
+ * Append one row. Swallows every failure — the decision log is telemetry;
42
+ * a full disk or unwritable path must never affect a review verdict.
43
+ */
44
+ append(row) {
45
+ try {
46
+ fs.mkdirSync(path.dirname(this.logPath), { recursive: true });
47
+ this.rotateIfNeeded();
48
+ fs.appendFileSync(this.logPath, JSON.stringify(row) + '\n', 'utf8');
49
+ }
50
+ catch {
51
+ // @silent-fallback-ok — §D8: decision-log write failures are swallowed;
52
+ // the verdict and delivery are unaffected (telemetry never gates).
53
+ }
54
+ }
55
+ /**
56
+ * Size rotation: when the file exceeds maxBytes, rename it to `<path>.1`
57
+ * (replacing the previous archive) and start fresh — the same bounded
58
+ * single-archive policy sibling JSONLs use. Contained; never throws.
59
+ */
60
+ rotateIfNeeded() {
61
+ try {
62
+ const stat = fs.statSync(this.logPath);
63
+ if (stat.size < this.maxBytes)
64
+ return;
65
+ const archive = `${this.logPath}.1`;
66
+ try {
67
+ SafeFsExecutor.safeRmSync(archive, {
68
+ force: true,
69
+ operation: 'ResponseReviewDecisionLog.rotate (drop the previous single archive)',
70
+ });
71
+ }
72
+ catch {
73
+ // @silent-fallback-ok — a stale archive that cannot be removed only
74
+ // means renameSync below may fail; that failure is caught too.
75
+ }
76
+ fs.renameSync(this.logPath, archive);
77
+ }
78
+ catch {
79
+ // @silent-fallback-ok — a missing file (ENOENT on first write) or a
80
+ // failed rotation both degrade to "keep appending"; telemetry never
81
+ // gates and the append itself is separately contained.
82
+ }
83
+ }
84
+ }
85
+ //# sourceMappingURL=ResponseReviewDecisionLog.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ResponseReviewDecisionLog.js","sourceRoot":"","sources":["../../src/core/ResponseReviewDecisionLog.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAErD,MAAM,iBAAiB,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC,yCAAyC;AAErF,MAAM,OAAO,yBAAyB;IACnB,OAAO,CAAS;IAChB,QAAQ,CAAS;IAElC,YAAY,OAAe,EAAE,OAA+B;QAC1D,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,QAAQ,GAAG,OAAO,EAAE,QAAQ,IAAI,iBAAiB,CAAC;IACzD,CAAC;IAED,uEAAuE;IACvE,OAAO;QACL,OAAO,IAAI,CAAC,OAAO,CAAC;IACtB,CAAC;IAED;;;OAGG;IACH,MAAM,CAAC,GAA4B;QACjC,IAAI,CAAC;YACH,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YAC9D,IAAI,CAAC,cAAc,EAAE,CAAC;YACtB,EAAE,CAAC,cAAc,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,IAAI,EAAE,MAAM,CAAC,CAAC;QACtE,CAAC;QAAC,MAAM,CAAC;YACP,wEAAwE;YACxE,mEAAmE;QACrE,CAAC;IACH,CAAC;IAED;;;;OAIG;IACK,cAAc;QACpB,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YACvC,IAAI,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,QAAQ;gBAAE,OAAO;YACtC,MAAM,OAAO,GAAG,GAAG,IAAI,CAAC,OAAO,IAAI,CAAC;YACpC,IAAI,CAAC;gBACH,cAAc,CAAC,UAAU,CAAC,OAAO,EAAE;oBACjC,KAAK,EAAE,IAAI;oBACX,SAAS,EAAE,qEAAqE;iBACjF,CAAC,CAAC;YACL,CAAC;YAAC,MAAM,CAAC;gBACP,oEAAoE;gBACpE,+DAA+D;YACjE,CAAC;YACD,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACvC,CAAC;QAAC,MAAM,CAAC;YACP,oEAAoE;YACpE,oEAAoE;YACpE,uDAAuD;QACzD,CAAC;IACH,CAAC;CACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"WriteDomainRegistry.d.ts","sourceRoot":"","sources":["../../src/core/WriteDomainRegistry.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"WriteDomainRegistry.d.ts","sourceRoot":"","sources":["../../src/core/WriteDomainRegistry.ts"],"names":[],"mappings":"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"}
@@ -181,6 +181,27 @@ export function buildWriteDomainRegistry(opts) {
181
181
  reg.add({ kind: 'route', method: 'PATCH', pathPrefix: '/evolution/', domain: 'machine-local', story: evolutionStory });
182
182
  reg.add({ kind: 'route', method: 'POST', pathPrefix: '/attention', domain: 'machine-local', story: attentionStory });
183
183
  reg.add({ kind: 'route', method: 'PATCH', pathPrefix: '/attention', domain: 'machine-local', story: attentionStory });
184
+ // ── Review canary battery trigger (context-aware-outbound-review §D9.4b) ──
185
+ // Machine-local by construction: the Bearer-gated soak trigger runs THIS
186
+ // machine's review pipeline against booby-trapped fixtures. Its only writes
187
+ // are (a) transient fixture rows in the per-machine topic-memory SQLite,
188
+ // scoped to reserved NEGATIVE topic ids and removed in a finally (plus the
189
+ // next run's pre-clean, R4-m4), and (b) append-only batterySummary /
190
+ // decision rows in logs/response-review-decisions.jsonl — per-machine soak
191
+ // EVIDENCE, never authority, never converged across machines. Re-running
192
+ // the battery regenerates everything the route ever writes.
193
+ reg.add({
194
+ kind: 'route',
195
+ method: 'POST',
196
+ pathPrefix: '/review/canary-battery/run',
197
+ domain: 'machine-local',
198
+ story: {
199
+ logical: 'ephemeral-rebuildable',
200
+ onSharedGitSyncedPath: true,
201
+ fileLevel: 'git-sync-excluded',
202
+ note: 'canary fixtures are finally-cleaned rows in the per-machine topic-memory SQLite (reserved negative topic ids); the D8 decision log is per-machine soak evidence; file-level arm shipped in FileClassifier sync exclusions (.instar/topic-memory.db + logs/response-review-decisions.jsonl)',
203
+ },
204
+ });
184
205
  return reg;
185
206
  }
186
207
  //# sourceMappingURL=WriteDomainRegistry.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"WriteDomainRegistry.js","sourceRoot":"","sources":["../../src/core/WriteDomainRegistry.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"WriteDomainRegistry.js","sourceRoot":"","sources":["../../src/core/WriteDomainRegistry.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,51 @@
1
+ /**
2
+ * conversationContextWiring — the WIRING-layer principal computation for the
3
+ * context-aware outbound review feature (spec §D1/§D4, Know Your Principal).
4
+ *
5
+ * The CoherenceGate stays decoupled from src/users/ and src/memory/: it sees
6
+ * only the injected `conversationContextProvider` function. THIS module is
7
+ * what the server wires that provider to — it converts raw TopicMemory rows
8
+ * plus the topic's verified-operator binding into the provider's return shape:
9
+ * role-labeled rows with per-row `verifiedOperator` tags AND the window's
10
+ * structural `askLicenseMode` (R4-m1: the provider RETURNS the wiring-computed
11
+ * values — the gate copies the mode into `conversationContextMeta` and NEVER
12
+ * computes or infers it).
13
+ *
14
+ * Principal rules (§D4, all computed from AUTHENTICATED uids — never content):
15
+ * - Role comes from the store's `fromUser` column, never message text.
16
+ * - BOUND topic (TopicOperatorStore binding present): mode =
17
+ * 'verified-operator'; each user row whose authenticated `telegramUserId`
18
+ * matches the binding uid is tagged `verifiedOperator: true` (rendered
19
+ * `USER(verified-operator):`); non-matching and uid-less rows render plain
20
+ * `USER:` (weak corroboration by the prompt contract).
21
+ * - UNBOUND topic: 'single-sender' ONLY when EVERY user-role row in the
22
+ * window carries an authenticated uid AND exactly ONE distinct uid appears
23
+ * (R4-L1: "at most one" would misread a zero-uid window as licensed).
24
+ * A window containing ANY uid-less user-role row — or 2+ distinct uids, or
25
+ * zero user rows — computes 'weak-corroboration-only' (R3-M2: an
26
+ * unverifiable sender can never help LICENSE; fail-closed).
27
+ *
28
+ * A throw anywhere in here is a PROVIDER throw, caught at acquisition inside
29
+ * CoherenceGate._evaluate per §D5 (degrades to no context section).
30
+ */
31
+ import type { AskLicenseMode, ConversationContextMessage } from './untrustedConversationContext.js';
32
+ /** The subset of a TopicMemory row this computation reads. */
33
+ export interface ConversationSourceRow {
34
+ text: string;
35
+ fromUser: boolean;
36
+ /** Telegram numeric user ID — the authoritative authenticated identity. */
37
+ telegramUserId?: number | null;
38
+ }
39
+ /** The provider return shape (CoherenceGateOptions.conversationContextProvider). */
40
+ export interface ConversationContextProviderResult {
41
+ messages: ConversationContextMessage[];
42
+ askLicenseMode: AskLicenseMode;
43
+ }
44
+ /**
45
+ * Compute the provider result from raw rows + the topic's verified-operator
46
+ * binding (null when the topic is unbound). Pure and synchronous.
47
+ */
48
+ export declare function buildConversationContext(rows: ConversationSourceRow[], operator: {
49
+ uid: string;
50
+ } | null): ConversationContextProviderResult;
51
+ //# sourceMappingURL=conversationContextWiring.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conversationContextWiring.d.ts","sourceRoot":"","sources":["../../src/core/conversationContextWiring.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,OAAO,KAAK,EACV,cAAc,EACd,0BAA0B,EAC3B,MAAM,mCAAmC,CAAC;AAE3C,8DAA8D;AAC9D,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,OAAO,CAAC;IAClB,2EAA2E;IAC3E,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAChC;AAED,oFAAoF;AACpF,MAAM,WAAW,iCAAiC;IAChD,QAAQ,EAAE,0BAA0B,EAAE,CAAC;IACvC,cAAc,EAAE,cAAc,CAAC;CAChC;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CACtC,IAAI,EAAE,qBAAqB,EAAE,EAC7B,QAAQ,EAAE;IAAE,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,GAC/B,iCAAiC,CA6CnC"}
@@ -0,0 +1,78 @@
1
+ /**
2
+ * conversationContextWiring — the WIRING-layer principal computation for the
3
+ * context-aware outbound review feature (spec §D1/§D4, Know Your Principal).
4
+ *
5
+ * The CoherenceGate stays decoupled from src/users/ and src/memory/: it sees
6
+ * only the injected `conversationContextProvider` function. THIS module is
7
+ * what the server wires that provider to — it converts raw TopicMemory rows
8
+ * plus the topic's verified-operator binding into the provider's return shape:
9
+ * role-labeled rows with per-row `verifiedOperator` tags AND the window's
10
+ * structural `askLicenseMode` (R4-m1: the provider RETURNS the wiring-computed
11
+ * values — the gate copies the mode into `conversationContextMeta` and NEVER
12
+ * computes or infers it).
13
+ *
14
+ * Principal rules (§D4, all computed from AUTHENTICATED uids — never content):
15
+ * - Role comes from the store's `fromUser` column, never message text.
16
+ * - BOUND topic (TopicOperatorStore binding present): mode =
17
+ * 'verified-operator'; each user row whose authenticated `telegramUserId`
18
+ * matches the binding uid is tagged `verifiedOperator: true` (rendered
19
+ * `USER(verified-operator):`); non-matching and uid-less rows render plain
20
+ * `USER:` (weak corroboration by the prompt contract).
21
+ * - UNBOUND topic: 'single-sender' ONLY when EVERY user-role row in the
22
+ * window carries an authenticated uid AND exactly ONE distinct uid appears
23
+ * (R4-L1: "at most one" would misread a zero-uid window as licensed).
24
+ * A window containing ANY uid-less user-role row — or 2+ distinct uids, or
25
+ * zero user rows — computes 'weak-corroboration-only' (R3-M2: an
26
+ * unverifiable sender can never help LICENSE; fail-closed).
27
+ *
28
+ * A throw anywhere in here is a PROVIDER throw, caught at acquisition inside
29
+ * CoherenceGate._evaluate per §D5 (degrades to no context section).
30
+ */
31
+ /**
32
+ * Compute the provider result from raw rows + the topic's verified-operator
33
+ * binding (null when the topic is unbound). Pure and synchronous.
34
+ */
35
+ export function buildConversationContext(rows, operator) {
36
+ const boundUid = operator && typeof operator.uid === 'string' && operator.uid.length > 0
37
+ ? operator.uid
38
+ : null;
39
+ const messages = rows.map((r) => {
40
+ const role = r.fromUser ? 'user' : 'agent';
41
+ const msg = {
42
+ role,
43
+ text: typeof r.text === 'string' ? r.text : String(r.text ?? ''),
44
+ };
45
+ if (boundUid !== null &&
46
+ role === 'user' &&
47
+ r.telegramUserId !== null &&
48
+ r.telegramUserId !== undefined &&
49
+ String(r.telegramUserId) === boundUid) {
50
+ msg.verifiedOperator = true;
51
+ }
52
+ return msg;
53
+ });
54
+ let askLicenseMode;
55
+ if (boundUid !== null) {
56
+ // Bound topic: the binding IS the license authority. Uid-less rows are
57
+ // already rendered plain USER: (weak corroboration) by the tag rule above.
58
+ askLicenseMode = 'verified-operator';
59
+ }
60
+ else {
61
+ const userRows = rows.filter((r) => r.fromUser);
62
+ const uids = new Set();
63
+ let anyUidless = userRows.length === 0; // zero user rows can never license
64
+ for (const r of userRows) {
65
+ if (r.telegramUserId === null || r.telegramUserId === undefined) {
66
+ anyUidless = true;
67
+ }
68
+ else {
69
+ uids.add(String(r.telegramUserId));
70
+ }
71
+ }
72
+ askLicenseMode = !anyUidless && uids.size === 1
73
+ ? 'single-sender'
74
+ : 'weak-corroboration-only';
75
+ }
76
+ return { messages, askLicenseMode };
77
+ }
78
+ //# sourceMappingURL=conversationContextWiring.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conversationContextWiring.js","sourceRoot":"","sources":["../../src/core/conversationContextWiring.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAqBH;;;GAGG;AACH,MAAM,UAAU,wBAAwB,CACtC,IAA6B,EAC7B,QAAgC;IAEhC,MAAM,QAAQ,GAAG,QAAQ,IAAI,OAAO,QAAQ,CAAC,GAAG,KAAK,QAAQ,IAAI,QAAQ,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC;QACtF,CAAC,CAAC,QAAQ,CAAC,GAAG;QACd,CAAC,CAAC,IAAI,CAAC;IAET,MAAM,QAAQ,GAAiC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QAC5D,MAAM,IAAI,GAAqB,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC;QAC7D,MAAM,GAAG,GAA+B;YACtC,IAAI;YACJ,IAAI,EAAE,OAAO,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC;SACjE,CAAC;QACF,IACE,QAAQ,KAAK,IAAI;YACjB,IAAI,KAAK,MAAM;YACf,CAAC,CAAC,cAAc,KAAK,IAAI;YACzB,CAAC,CAAC,cAAc,KAAK,SAAS;YAC9B,MAAM,CAAC,CAAC,CAAC,cAAc,CAAC,KAAK,QAAQ,EACrC,CAAC;YACD,GAAG,CAAC,gBAAgB,GAAG,IAAI,CAAC;QAC9B,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC,CAAC,CAAC;IAEH,IAAI,cAA8B,CAAC;IACnC,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;QACtB,uEAAuE;QACvE,2EAA2E;QAC3E,cAAc,GAAG,mBAAmB,CAAC;IACvC,CAAC;SAAM,CAAC;QACN,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;QAChD,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;QAC/B,IAAI,UAAU,GAAG,QAAQ,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,mCAAmC;QAC3E,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;YACzB,IAAI,CAAC,CAAC,cAAc,KAAK,IAAI,IAAI,CAAC,CAAC,cAAc,KAAK,SAAS,EAAE,CAAC;gBAChE,UAAU,GAAG,IAAI,CAAC;YACpB,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC;YACrC,CAAC;QACH,CAAC;QACD,cAAc,GAAG,CAAC,UAAU,IAAI,IAAI,CAAC,IAAI,KAAK,CAAC;YAC7C,CAAC,CAAC,eAAe;YACjB,CAAC,CAAC,yBAAyB,CAAC;IAChC,CAAC;IAED,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,CAAC;AACtC,CAAC"}
@@ -0,0 +1,112 @@
1
+ /**
2
+ * conversationIdentity.ts — the SINGLE hash + identity surface for durable,
3
+ * channel-agnostic conversation identity (docs/specs/durable-conversation-identity.md §4).
4
+ *
5
+ * This module absorbs `slackRefreshBinding`'s key helpers and is the ONE place
6
+ * the legacy 32-bit sum-shift hash + mint-candidate formula live going forward.
7
+ * The three legacy copies (`server.ts slackChannelToSyntheticId`, the
8
+ * `routes.ts` build-heartbeat inline copy, `slackRefreshBinding.ts
9
+ * slackRoutingKeySyntheticId`) consolidate onto these exports in the §4
10
+ * foundation increment; a FOURTH copy of the mint idiom is a CI failure
11
+ * (tests/unit/conversation-identity-mint-idiom-ratchet.test.ts).
12
+ *
13
+ * Spec §3.1: the PRIMARY identity of a conversation is the structured tuple
14
+ * `(platform, channelId, threadTs?)` bound to a stable minted NEGATIVE id; the
15
+ * canonical key string (`slack:<teamId>:<channelId>[:<threadTs>]`) is its
16
+ * normalized LOOKUP form, and `workspaceId` is identity-adjacent metadata
17
+ * (upgradable in place, `_` placeholder when unknown). Telegram positive ids
18
+ * pass through unregistered, forever.
19
+ */
20
+ /** Tuple schema version (§Glossary). v1 is SINGLE-WORKSPACE: the tuple carries
21
+ * no workspaceId — correct only because exactly one workspace is enforced
22
+ * (§3.1). Phase 7.1 introduces schema-version 2 with workspaceId in the core. */
23
+ export declare const TUPLE_SCHEMA_VERSION = 1;
24
+ /**
25
+ * §3.3/§3.5 frozen constants — schema-v1, changed ONLY by a versioned
26
+ * migration (a mixed fleet comparing different bounds/windows would pick
27
+ * divergent accept/quarantine verdicts). Pinned by the §10 golden-parity test.
28
+ */
29
+ export declare const MAX_PROBE_DISTANCE = 64;
30
+ /** Probe direction is DOWN (`id -= 1`) and FROZEN FOREVER (frontloaded decision 2). */
31
+ export declare const PROBE_DIRECTION = -1;
32
+ /** HLC `physical` unit: MILLISECONDS since the Unix epoch (frozen, schema-v1 — R3-M10). */
33
+ export declare const HLC_ABS_MIN = 1767225600000;
34
+ export declare const HLC_ABS_MAX = 4102444800000;
35
+ /** §3.5 ingest shape clamps (also applied at the §6.3 mint site — security-M1c). */
36
+ export declare const SLACK_CHANNEL_ID_RE: RegExp;
37
+ export declare const SLACK_THREAD_TS_RE: RegExp;
38
+ export declare const SLACK_WORKSPACE_ID_RE: RegExp;
39
+ /** The unknown-workspace placeholder (§3.1) — upgrades in place to a concrete teamId. */
40
+ export declare const WORKSPACE_PLACEHOLDER = "_";
41
+ /** The Phase-1 structured tuple (§3.1). `threadTs: null` = channel-level. */
42
+ export interface ConversationTuple {
43
+ platform: 'slack';
44
+ channelId: string;
45
+ threadTs: string | null;
46
+ }
47
+ /**
48
+ * The frozen 32-bit sum-shift hash over a routing key — byte-identical to the
49
+ * three legacy copies (golden-parity pinned in §10). NEVER change this: mixed-
50
+ * fleet convergence and zero-loss adoption both depend on it (§3.3 properties 1/2).
51
+ */
52
+ export declare function sumShiftHash(input: string): number;
53
+ /**
54
+ * The deterministic mint CANDIDATE for a routing key (§3.3):
55
+ * `-(abs(hash) + 1)` — always negative, never 0, value-identical to
56
+ * `slackRoutingKeySyntheticId` (thread-aware: hashes `channelId[:threadTs]`).
57
+ * This is the mint candidate, no longer an identity authority — the registry
58
+ * is the collision authority.
59
+ */
60
+ export declare function candidateIdForRoutingKey(routingKey: string): number;
61
+ /** Adapter routing-key tail for a tuple: `<channelId>[:<threadTs>]` (§3.1). */
62
+ export declare function routingKeyForTuple(tuple: ConversationTuple): string;
63
+ /**
64
+ * Parse a Slack routing key (`C…` or `C…:<thread_ts>`) into a v1 tuple.
65
+ * Returns null when the shape is invalid (§3.6: callers treat as "no durable
66
+ * id" and keep legacy behavior — a typed refusal, never a throw).
67
+ * Shape validation here is the §7 mesh-forward guard (security-M1c): a
68
+ * forwarded/replayed inbound cannot supply a crafted key to force a target
69
+ * candidate.
70
+ */
71
+ export declare function tupleForRoutingKey(routingKey: string): ConversationTuple | null;
72
+ /**
73
+ * The §3.4 tupleKey — the IMMUTABLE byte-form used for the tuple index AND the
74
+ * `≺` tiebreak (§3.5.1: null `threadTs` compares as the EMPTY string, so a
75
+ * channel-level tuple deterministically precedes its own threads).
76
+ */
77
+ export declare function tupleKeyFor(tuple: ConversationTuple): string;
78
+ /**
79
+ * Canonical key (§3.1): `slack:<teamId>:<channelId>[:<threadTs>]` with `_`
80
+ * for an unknown teamId. The normalized lookup/display string — NOT the
81
+ * primary identity (the tuple is).
82
+ */
83
+ export declare function canonicalKeyFor(tuple: ConversationTuple, workspaceId: string | undefined): string;
84
+ /** Parse a canonical key back to `{ tuple, workspaceId }`, or null when malformed. */
85
+ export declare function parseCanonicalKey(key: string): {
86
+ tuple: ConversationTuple;
87
+ workspaceId: string;
88
+ } | null;
89
+ /** Result of a displacement walk (§3.3 probe / §3.5.1 step 2). */
90
+ export type DisplacementResult = {
91
+ ok: true;
92
+ id: number;
93
+ probes: number;
94
+ } | {
95
+ ok: false;
96
+ overflow: true;
97
+ };
98
+ /**
99
+ * The ONE shared displacement implementation (§3.3 = §3.5.1 step 2 — pinned by
100
+ * the §10 shared-implementation equivalence test; R2-adversarial-2). Walks the
101
+ * FROZEN down-sequence `candidate, candidate-1, candidate-2, …` and returns
102
+ * the first offset for which `collides(id)` is false, bounded by
103
+ * `MAX_PROBE_DISTANCE` (= the ingest coherence bound, so a local mint can
104
+ * never produce an id a peer's ingest would quarantine as a pre-squat).
105
+ *
106
+ * `collides` MUST be the pure §3.3 `candidateCollides` predicate — reserved
107
+ * canonicals (a), the alias table (b), and the GLOBAL displaced-assignment set
108
+ * (c) — each an O(1) lookup, NEVER a live-tuple scan (R2-scalability-1). A
109
+ * walk exceeding the bound degrades to the §3.6 pending-mint path.
110
+ */
111
+ export declare function walkDisplacement(candidate: number, collides: (id: number) => boolean): DisplacementResult;
112
+ //# sourceMappingURL=conversationIdentity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conversationIdentity.d.ts","sourceRoot":"","sources":["../../src/core/conversationIdentity.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH;;kFAEkF;AAClF,eAAO,MAAM,oBAAoB,IAAI,CAAC;AAEtC;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,KAAK,CAAC;AACrC,uFAAuF;AACvF,eAAO,MAAM,eAAe,KAAK,CAAC;AAClC,2FAA2F;AAC3F,eAAO,MAAM,WAAW,gBAAgB,CAAC;AACzC,eAAO,MAAM,WAAW,gBAAgB,CAAC;AAEzC,oFAAoF;AACpF,eAAO,MAAM,mBAAmB,QAAqB,CAAC;AACtD,eAAO,MAAM,kBAAkB,QAAoB,CAAC;AACpD,eAAO,MAAM,qBAAqB,QAAiB,CAAC;AACpD,yFAAyF;AACzF,eAAO,MAAM,qBAAqB,MAAM,CAAC;AAEzC,6EAA6E;AAC7E,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,OAAO,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAMlD;AAED;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAEnE;AAED,+EAA+E;AAC/E,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,iBAAiB,GAAG,MAAM,CAEnE;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,iBAAiB,GAAG,IAAI,CAO/E;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,iBAAiB,GAAG,MAAM,CAE5D;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAIjG;AAED,sFAAsF;AACtF,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG;IAAE,KAAK,EAAE,iBAAiB,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAQvG;AAED,kEAAkE;AAClE,MAAM,MAAM,kBAAkB,GAC1B;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACxC;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,EAAE,IAAI,CAAA;CAAE,CAAC;AAElC;;;;;;;;;;;;GAYG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,GAAG,kBAAkB,CASzG"}
@@ -0,0 +1,141 @@
1
+ /**
2
+ * conversationIdentity.ts — the SINGLE hash + identity surface for durable,
3
+ * channel-agnostic conversation identity (docs/specs/durable-conversation-identity.md §4).
4
+ *
5
+ * This module absorbs `slackRefreshBinding`'s key helpers and is the ONE place
6
+ * the legacy 32-bit sum-shift hash + mint-candidate formula live going forward.
7
+ * The three legacy copies (`server.ts slackChannelToSyntheticId`, the
8
+ * `routes.ts` build-heartbeat inline copy, `slackRefreshBinding.ts
9
+ * slackRoutingKeySyntheticId`) consolidate onto these exports in the §4
10
+ * foundation increment; a FOURTH copy of the mint idiom is a CI failure
11
+ * (tests/unit/conversation-identity-mint-idiom-ratchet.test.ts).
12
+ *
13
+ * Spec §3.1: the PRIMARY identity of a conversation is the structured tuple
14
+ * `(platform, channelId, threadTs?)` bound to a stable minted NEGATIVE id; the
15
+ * canonical key string (`slack:<teamId>:<channelId>[:<threadTs>]`) is its
16
+ * normalized LOOKUP form, and `workspaceId` is identity-adjacent metadata
17
+ * (upgradable in place, `_` placeholder when unknown). Telegram positive ids
18
+ * pass through unregistered, forever.
19
+ */
20
+ /** Tuple schema version (§Glossary). v1 is SINGLE-WORKSPACE: the tuple carries
21
+ * no workspaceId — correct only because exactly one workspace is enforced
22
+ * (§3.1). Phase 7.1 introduces schema-version 2 with workspaceId in the core. */
23
+ export const TUPLE_SCHEMA_VERSION = 1;
24
+ /**
25
+ * §3.3/§3.5 frozen constants — schema-v1, changed ONLY by a versioned
26
+ * migration (a mixed fleet comparing different bounds/windows would pick
27
+ * divergent accept/quarantine verdicts). Pinned by the §10 golden-parity test.
28
+ */
29
+ export const MAX_PROBE_DISTANCE = 64;
30
+ /** Probe direction is DOWN (`id -= 1`) and FROZEN FOREVER (frontloaded decision 2). */
31
+ export const PROBE_DIRECTION = -1;
32
+ /** HLC `physical` unit: MILLISECONDS since the Unix epoch (frozen, schema-v1 — R3-M10). */
33
+ export const HLC_ABS_MIN = 1767225600000; // 2026-01-01T00:00:00Z
34
+ export const HLC_ABS_MAX = 4102444800000; // 2100-01-01T00:00:00Z — documented horizon; re-pin via versioned migration WELL before
35
+ /** §3.5 ingest shape clamps (also applied at the §6.3 mint site — security-M1c). */
36
+ export const SLACK_CHANNEL_ID_RE = /^[CDG][A-Z0-9]+$/;
37
+ export const SLACK_THREAD_TS_RE = /^\d{10}\.\d{6}$/;
38
+ export const SLACK_WORKSPACE_ID_RE = /^T[A-Z0-9]+$/;
39
+ /** The unknown-workspace placeholder (§3.1) — upgrades in place to a concrete teamId. */
40
+ export const WORKSPACE_PLACEHOLDER = '_';
41
+ /**
42
+ * The frozen 32-bit sum-shift hash over a routing key — byte-identical to the
43
+ * three legacy copies (golden-parity pinned in §10). NEVER change this: mixed-
44
+ * fleet convergence and zero-loss adoption both depend on it (§3.3 properties 1/2).
45
+ */
46
+ export function sumShiftHash(input) {
47
+ let hash = 0;
48
+ for (let i = 0; i < input.length; i++) {
49
+ hash = ((hash << 5) - hash + input.charCodeAt(i)) | 0;
50
+ }
51
+ return hash;
52
+ }
53
+ /**
54
+ * The deterministic mint CANDIDATE for a routing key (§3.3):
55
+ * `-(abs(hash) + 1)` — always negative, never 0, value-identical to
56
+ * `slackRoutingKeySyntheticId` (thread-aware: hashes `channelId[:threadTs]`).
57
+ * This is the mint candidate, no longer an identity authority — the registry
58
+ * is the collision authority.
59
+ */
60
+ export function candidateIdForRoutingKey(routingKey) {
61
+ return -(Math.abs(sumShiftHash(routingKey)) + 1);
62
+ }
63
+ /** Adapter routing-key tail for a tuple: `<channelId>[:<threadTs>]` (§3.1). */
64
+ export function routingKeyForTuple(tuple) {
65
+ return tuple.threadTs ? `${tuple.channelId}:${tuple.threadTs}` : tuple.channelId;
66
+ }
67
+ /**
68
+ * Parse a Slack routing key (`C…` or `C…:<thread_ts>`) into a v1 tuple.
69
+ * Returns null when the shape is invalid (§3.6: callers treat as "no durable
70
+ * id" and keep legacy behavior — a typed refusal, never a throw).
71
+ * Shape validation here is the §7 mesh-forward guard (security-M1c): a
72
+ * forwarded/replayed inbound cannot supply a crafted key to force a target
73
+ * candidate.
74
+ */
75
+ export function tupleForRoutingKey(routingKey) {
76
+ const idx = routingKey.indexOf(':');
77
+ const channelId = idx === -1 ? routingKey : routingKey.slice(0, idx);
78
+ const threadTs = idx === -1 ? null : routingKey.slice(idx + 1);
79
+ if (!SLACK_CHANNEL_ID_RE.test(channelId))
80
+ return null;
81
+ if (threadTs !== null && !SLACK_THREAD_TS_RE.test(threadTs))
82
+ return null;
83
+ return { platform: 'slack', channelId, threadTs };
84
+ }
85
+ /**
86
+ * The §3.4 tupleKey — the IMMUTABLE byte-form used for the tuple index AND the
87
+ * `≺` tiebreak (§3.5.1: null `threadTs` compares as the EMPTY string, so a
88
+ * channel-level tuple deterministically precedes its own threads).
89
+ */
90
+ export function tupleKeyFor(tuple) {
91
+ return `${tuple.platform}\x1f${tuple.channelId}\x1f${tuple.threadTs ?? ''}`;
92
+ }
93
+ /**
94
+ * Canonical key (§3.1): `slack:<teamId>:<channelId>[:<threadTs>]` with `_`
95
+ * for an unknown teamId. The normalized lookup/display string — NOT the
96
+ * primary identity (the tuple is).
97
+ */
98
+ export function canonicalKeyFor(tuple, workspaceId) {
99
+ const team = workspaceId && SLACK_WORKSPACE_ID_RE.test(workspaceId) ? workspaceId : WORKSPACE_PLACEHOLDER;
100
+ const base = `${tuple.platform}:${team}:${tuple.channelId}`;
101
+ return tuple.threadTs ? `${base}:${tuple.threadTs}` : base;
102
+ }
103
+ /** Parse a canonical key back to `{ tuple, workspaceId }`, or null when malformed. */
104
+ export function parseCanonicalKey(key) {
105
+ const parts = key.split(':');
106
+ if (parts.length < 3 || parts.length > 4 || parts[0] !== 'slack')
107
+ return null;
108
+ const [, workspaceId, channelId, threadTs] = parts;
109
+ if (workspaceId !== WORKSPACE_PLACEHOLDER && !SLACK_WORKSPACE_ID_RE.test(workspaceId))
110
+ return null;
111
+ if (!SLACK_CHANNEL_ID_RE.test(channelId))
112
+ return null;
113
+ if (threadTs !== undefined && !SLACK_THREAD_TS_RE.test(threadTs))
114
+ return null;
115
+ return { tuple: { platform: 'slack', channelId, threadTs: threadTs ?? null }, workspaceId };
116
+ }
117
+ /**
118
+ * The ONE shared displacement implementation (§3.3 = §3.5.1 step 2 — pinned by
119
+ * the §10 shared-implementation equivalence test; R2-adversarial-2). Walks the
120
+ * FROZEN down-sequence `candidate, candidate-1, candidate-2, …` and returns
121
+ * the first offset for which `collides(id)` is false, bounded by
122
+ * `MAX_PROBE_DISTANCE` (= the ingest coherence bound, so a local mint can
123
+ * never produce an id a peer's ingest would quarantine as a pre-squat).
124
+ *
125
+ * `collides` MUST be the pure §3.3 `candidateCollides` predicate — reserved
126
+ * canonicals (a), the alias table (b), and the GLOBAL displaced-assignment set
127
+ * (c) — each an O(1) lookup, NEVER a live-tuple scan (R2-scalability-1). A
128
+ * walk exceeding the bound degrades to the §3.6 pending-mint path.
129
+ */
130
+ export function walkDisplacement(candidate, collides) {
131
+ let id = candidate;
132
+ let probes = 0;
133
+ while (collides(id)) {
134
+ id += PROBE_DIRECTION;
135
+ probes++;
136
+ if (probes > MAX_PROBE_DISTANCE)
137
+ return { ok: false, overflow: true };
138
+ }
139
+ return { ok: true, id, probes };
140
+ }
141
+ //# sourceMappingURL=conversationIdentity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conversationIdentity.js","sourceRoot":"","sources":["../../src/core/conversationIdentity.ts"],"names":[],"mappings":"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"}