@remnic/core 9.6.23 → 9.6.25
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.
- package/dist/access-admin-ops-surface.js +1 -1
- package/dist/access-boundary.js +1 -1
- package/dist/access-cli.js +4 -4
- package/dist/access-http.js +3 -3
- package/dist/access-identity-continuity-surface.js +1 -1
- package/dist/access-lcm-surface.js +1 -1
- package/dist/access-mcp.js +2 -2
- package/dist/access-observe-write-surface.js +1 -1
- package/dist/access-operations-batch.js +1 -1
- package/dist/access-operations.d.ts +3 -3
- package/dist/access-operations.js +1 -1
- package/dist/access-recall-surface.js +1 -1
- package/dist/access-schema.d.ts +64 -64
- package/dist/access-service.js +1 -1
- package/dist/{chunk-KEY3FEMP.js → chunk-43VNWTBB.js} +3 -3
- package/dist/{chunk-A2OFRQ5B.js → chunk-N6VIXDT7.js} +2 -2
- package/dist/{chunk-ERA5RSMZ.js → chunk-P32IDSHD.js} +1 -1
- package/dist/{chunk-ERA5RSMZ.js.map → chunk-P32IDSHD.js.map} +1 -1
- package/dist/{chunk-D3D677BV.js → chunk-QLYLTKUG.js} +4 -4
- package/dist/{chunk-D3D677BV.js.map → chunk-QLYLTKUG.js.map} +1 -1
- package/dist/cli.js +4 -4
- package/dist/coding/coding-graph-types.d.ts +23 -1
- package/dist/coding/coding-graph-types.js +1 -1
- package/dist/coding/optional-coding-graph.js +1 -1
- package/dist/index.js +4 -4
- package/dist/orchestrator.js +4 -4
- package/dist/schemas.d.ts +74 -74
- package/dist/shared-context/manager.d.ts +8 -8
- package/dist/transfer/types.d.ts +66 -66
- package/package.json +2 -2
- package/src/access-http.test.ts +2 -2
- package/src/access-mcp.test.ts +2 -2
- package/src/access-mcp.ts +3 -3
- package/src/access-service-coding-write.test.ts +18 -18
- package/src/access-service-lcm-forgery.test.ts +5 -5
- package/src/access-service-observe-lcm-parity.test.ts +25 -25
- package/src/access-service-observe-scope.test.ts +16 -16
- package/src/access-service-project-tag.test.ts +2 -2
- package/src/access-service-raw-excerpt-read-gate.test.ts +1 -1
- package/src/coding/coding-graph-types.ts +23 -0
- package/src/coding/coding-namespace.test.ts +3 -3
- package/src/coding/wire-coding-context.test.ts +22 -22
- package/src/issue-1492-coding-mode-consistency.test.ts +2 -2
- /package/dist/{chunk-KEY3FEMP.js.map → chunk-43VNWTBB.js.map} +0 -0
- /package/dist/{chunk-A2OFRQ5B.js.map → chunk-N6VIXDT7.js.map} +0 -0
|
@@ -193,7 +193,7 @@ test("#1495 P1 FORGERY BLOCKED: a default-only caller cannot read another tenant
|
|
|
193
193
|
const victimRes = await service.observe(
|
|
194
194
|
observeRequest({
|
|
195
195
|
sessionKey: "alice:s1",
|
|
196
|
-
projectTag: "
|
|
196
|
+
projectTag: "Acme/Webshop",
|
|
197
197
|
}),
|
|
198
198
|
);
|
|
199
199
|
const victimWriteKey = probe.rows[0]!.session_id;
|
|
@@ -235,7 +235,7 @@ test("#1495 P1 FORGERY BLOCKED: a default-only caller cannot read another tenant
|
|
|
235
235
|
const service = new EngramAccessService(probe.orch);
|
|
236
236
|
|
|
237
237
|
const victimRes = await service.observe(
|
|
238
|
-
observeRequest({ sessionKey: "alice:s1", projectTag: "
|
|
238
|
+
observeRequest({ sessionKey: "alice:s1", projectTag: "Acme/Webshop" }),
|
|
239
239
|
);
|
|
240
240
|
const victimOverlayNs = victimRes.effectiveNamespace!;
|
|
241
241
|
assert.ok(victimOverlayNs.startsWith("alice-"));
|
|
@@ -268,7 +268,7 @@ test("#1495 P1 LEGITIMATE ACCESS PRESERVED: the victim still reads its OWN overl
|
|
|
268
268
|
|
|
269
269
|
// alice archives under her overlay AND binds the coding context to her session.
|
|
270
270
|
await service.observe(
|
|
271
|
-
observeRequest({ sessionKey: "alice:s1", projectTag: "
|
|
271
|
+
observeRequest({ sessionKey: "alice:s1", projectTag: "Acme/Webshop" }),
|
|
272
272
|
);
|
|
273
273
|
|
|
274
274
|
// A same-session lcmSearch by alice (no explicit namespace) must reach her rows:
|
|
@@ -330,7 +330,7 @@ test("#1505 codex P1 r2 FORGERY BLOCKED: explicit-namespace + sessionless lcmSea
|
|
|
330
330
|
|
|
331
331
|
// VICTIM archives overlay rows.
|
|
332
332
|
const victimRes = await service.observe(
|
|
333
|
-
observeRequest({ sessionKey: "alice:s1", projectTag: "
|
|
333
|
+
observeRequest({ sessionKey: "alice:s1", projectTag: "Acme/Webshop" }),
|
|
334
334
|
);
|
|
335
335
|
assert.ok(victimRes.effectiveNamespace!.startsWith("alice-"));
|
|
336
336
|
|
|
@@ -361,7 +361,7 @@ test("#1505 codex P1 r2 FORGERY BLOCKED: default-readable implicit + sessionless
|
|
|
361
361
|
const service = new EngramAccessService(probe.orch);
|
|
362
362
|
|
|
363
363
|
const victimRes = await service.observe(
|
|
364
|
-
observeRequest({ sessionKey: "alice:s1", projectTag: "
|
|
364
|
+
observeRequest({ sessionKey: "alice:s1", projectTag: "Acme/Webshop" }),
|
|
365
365
|
);
|
|
366
366
|
assert.ok(victimRes.effectiveNamespace!.startsWith("alice-"));
|
|
367
367
|
|
|
@@ -305,12 +305,12 @@ test("#1505 thread 2 (c) projectTag: observe LCM write key == recall reader key
|
|
|
305
305
|
const service = new EngramAccessService(probe.orch);
|
|
306
306
|
|
|
307
307
|
const res = await service.observe(
|
|
308
|
-
observeRequest({ sessionKey: "pi-geek:abc123", projectTag: "
|
|
308
|
+
observeRequest({ sessionKey: "pi-geek:abc123", projectTag: "Acme/Webshop" }),
|
|
309
309
|
);
|
|
310
310
|
|
|
311
311
|
const expectedNs = combineNamespaces(
|
|
312
312
|
"pi-geek",
|
|
313
|
-
projectNamespaceName(projectTagProjectId("
|
|
313
|
+
projectNamespaceName(projectTagProjectId("Acme/Webshop")),
|
|
314
314
|
);
|
|
315
315
|
const expectedKey = encodeNs(expectedNs, "pi-geek:abc123");
|
|
316
316
|
assert.equal(res.effectiveNamespace, expectedNs);
|
|
@@ -442,7 +442,7 @@ test("#1505 thread 2 (d) projectScope:false ⇒ raw sessionKey everywhere (singl
|
|
|
442
442
|
const service = new EngramAccessService(probe.orch);
|
|
443
443
|
|
|
444
444
|
const res = await service.observe(
|
|
445
|
-
observeRequest({ sessionKey: "pi-geek:abc123", projectTag: "
|
|
445
|
+
observeRequest({ sessionKey: "pi-geek:abc123", projectTag: "Acme/Webshop" }),
|
|
446
446
|
);
|
|
447
447
|
// No overlay ⇒ effective namespace is the default store ⇒ raw key.
|
|
448
448
|
assert.equal(res.effectiveNamespace, "default");
|
|
@@ -470,7 +470,7 @@ test("#1505 thread 2 (d) namespacesEnabled:false ⇒ raw sessionKey everywhere",
|
|
|
470
470
|
const service = new EngramAccessService(probe.orch);
|
|
471
471
|
|
|
472
472
|
const res = await service.observe(
|
|
473
|
-
observeRequest({ sessionKey: "pi-geek:abc123", projectTag: "
|
|
473
|
+
observeRequest({ sessionKey: "pi-geek:abc123", projectTag: "Acme/Webshop" }),
|
|
474
474
|
);
|
|
475
475
|
assert.equal(res.effectiveNamespace, "default");
|
|
476
476
|
assert.equal(probe.lcmWriteKeys[0], "pi-geek:abc123", "raw LCM write key");
|
|
@@ -501,14 +501,14 @@ test("#1505 thread 1: extraction provenance principal is the resolved principal
|
|
|
501
501
|
await service.observe(
|
|
502
502
|
observeRequest({
|
|
503
503
|
sessionKey: "pi-geek:abc123",
|
|
504
|
-
projectTag: "
|
|
504
|
+
projectTag: "Acme/Webshop",
|
|
505
505
|
skipExtraction: false, // exercise the extraction path
|
|
506
506
|
}),
|
|
507
507
|
);
|
|
508
508
|
|
|
509
509
|
const expectedNs = combineNamespaces(
|
|
510
510
|
"pi-geek",
|
|
511
|
-
projectNamespaceName(projectTagProjectId("
|
|
511
|
+
projectNamespaceName(projectTagProjectId("Acme/Webshop")),
|
|
512
512
|
);
|
|
513
513
|
assert.equal(probe.extractionCalls.length, 1);
|
|
514
514
|
// Provenance identity: the resolved principal, never a default parsed from the
|
|
@@ -590,7 +590,7 @@ test("#1505 thread 2: LCM read namespace honors authenticatedPrincipal (write-un
|
|
|
590
590
|
observeRequest({
|
|
591
591
|
sessionKey: "sess-1",
|
|
592
592
|
authenticatedPrincipal: "alice",
|
|
593
|
-
projectTag: "
|
|
593
|
+
projectTag: "Acme/Webshop",
|
|
594
594
|
}),
|
|
595
595
|
);
|
|
596
596
|
const writeKey = probe.lcmWriteKeys[0];
|
|
@@ -639,7 +639,7 @@ test("#1505 thread 2 compaction regression: flush/record overlay-derived key mat
|
|
|
639
639
|
const service = new EngramAccessService(probe.orch);
|
|
640
640
|
|
|
641
641
|
await service.observe(
|
|
642
|
-
observeRequest({ sessionKey: "pi-geek:abc123", projectTag: "
|
|
642
|
+
observeRequest({ sessionKey: "pi-geek:abc123", projectTag: "Acme/Webshop" }),
|
|
643
643
|
);
|
|
644
644
|
await service.lcmCompactionFlush({ sessionKey: "pi-geek:abc123" });
|
|
645
645
|
|
|
@@ -748,7 +748,7 @@ test("#1505 round 3: access lcmSearch routes the session_id through the SCOPED (
|
|
|
748
748
|
const service = new EngramAccessService(probe.orch);
|
|
749
749
|
|
|
750
750
|
await service.observe(
|
|
751
|
-
observeRequest({ sessionKey: "pi-geek:abc123", projectTag: "
|
|
751
|
+
observeRequest({ sessionKey: "pi-geek:abc123", projectTag: "Acme/Webshop" }),
|
|
752
752
|
);
|
|
753
753
|
const writeKey = probe.lcmWriteKeys[0];
|
|
754
754
|
// New #1495 P1 encoding: `\x1f<overlayNs>\x1f<sessionKey>`. Parse the overlay
|
|
@@ -872,8 +872,8 @@ test("#1505 round 3 thread 1: orchestrator LCM read key falls back to default wh
|
|
|
872
872
|
|
|
873
873
|
// Bind a coding context to sess-1 so the overlay would apply on alice's base.
|
|
874
874
|
probe.contexts.set("sess-1", {
|
|
875
|
-
projectId: "
|
|
876
|
-
projectName: "
|
|
875
|
+
projectId: "acme-webshop",
|
|
876
|
+
projectName: "Acme/Webshop",
|
|
877
877
|
} as unknown as CodingContext);
|
|
878
878
|
|
|
879
879
|
const lcmReadNamespaceForSession = Orchestrator.prototype[
|
|
@@ -914,8 +914,8 @@ test("#1505 round 3 thread 1: orchestrator LCM read key falls back to default wh
|
|
|
914
914
|
} as Partial<PluginConfig>);
|
|
915
915
|
|
|
916
916
|
probe.contexts.set("sess-1", {
|
|
917
|
-
projectId: "
|
|
918
|
-
projectName: "
|
|
917
|
+
projectId: "acme-webshop",
|
|
918
|
+
projectName: "Acme/Webshop",
|
|
919
919
|
} as unknown as CodingContext);
|
|
920
920
|
|
|
921
921
|
const lcmReadNamespaceForSession = Orchestrator.prototype[
|
|
@@ -944,8 +944,8 @@ test("#1505 round 3 thread 1: orchestrator LCM read key still uses the overlay w
|
|
|
944
944
|
} as Partial<PluginConfig>);
|
|
945
945
|
|
|
946
946
|
probe.contexts.set("pi-geek:abc123", {
|
|
947
|
-
projectId: "
|
|
948
|
-
projectName: "
|
|
947
|
+
projectId: "acme-webshop",
|
|
948
|
+
projectName: "Acme/Webshop",
|
|
949
949
|
} as unknown as CodingContext);
|
|
950
950
|
|
|
951
951
|
const lcmReadNamespaceForSession = Orchestrator.prototype[
|
|
@@ -977,8 +977,8 @@ test("#1505 round 3 thread 2: lcmSearch returns NO overlay rows when the princip
|
|
|
977
977
|
const service = new EngramAccessService(probe.orch);
|
|
978
978
|
|
|
979
979
|
probe.contexts.set("sess-1", {
|
|
980
|
-
projectId: "
|
|
981
|
-
projectName: "
|
|
980
|
+
projectId: "acme-webshop",
|
|
981
|
+
projectName: "Acme/Webshop",
|
|
982
982
|
} as unknown as CodingContext);
|
|
983
983
|
|
|
984
984
|
await service.lcmSearch({
|
|
@@ -1036,7 +1036,7 @@ test("#1505 round 4 thread (codex P2): compaction flush/record target the OVERLA
|
|
|
1036
1036
|
observeRequest({
|
|
1037
1037
|
sessionKey: "sess-1",
|
|
1038
1038
|
authenticatedPrincipal: "alice",
|
|
1039
|
-
projectTag: "
|
|
1039
|
+
projectTag: "Acme/Webshop",
|
|
1040
1040
|
}),
|
|
1041
1041
|
);
|
|
1042
1042
|
const writeKey = probe.lcmWriteKeys[0];
|
|
@@ -1080,8 +1080,8 @@ test("#1505 round 4 thread (codex P2): a read-only lcmSearch by the SAME write-o
|
|
|
1080
1080
|
const service = new EngramAccessService(probe.orch);
|
|
1081
1081
|
|
|
1082
1082
|
probe.contexts.set("sess-1", {
|
|
1083
|
-
projectId: "
|
|
1084
|
-
projectName: "
|
|
1083
|
+
projectId: "acme-webshop",
|
|
1084
|
+
projectName: "Acme/Webshop",
|
|
1085
1085
|
} as unknown as CodingContext);
|
|
1086
1086
|
|
|
1087
1087
|
await service.lcmSearch({
|
|
@@ -1115,7 +1115,7 @@ test("#1505 round 3 thread 2: lcmSearch still routes through the overlay key whe
|
|
|
1115
1115
|
observeRequest({
|
|
1116
1116
|
sessionKey: "sess-1",
|
|
1117
1117
|
authenticatedPrincipal: "alice",
|
|
1118
|
-
projectTag: "
|
|
1118
|
+
projectTag: "Acme/Webshop",
|
|
1119
1119
|
}),
|
|
1120
1120
|
);
|
|
1121
1121
|
const writeKey = probe.lcmWriteKeys[0];
|
|
@@ -1172,7 +1172,7 @@ test("#1505 thread NBHWs (codex P2): restrictive `default` WRITE policy + writab
|
|
|
1172
1172
|
observeRequest({
|
|
1173
1173
|
sessionKey: "sess-1",
|
|
1174
1174
|
authenticatedPrincipal: "alice",
|
|
1175
|
-
projectTag: "
|
|
1175
|
+
projectTag: "Acme/Webshop",
|
|
1176
1176
|
}),
|
|
1177
1177
|
);
|
|
1178
1178
|
const writeKey = probe.lcmWriteKeys[0];
|
|
@@ -1230,7 +1230,7 @@ test("#1505 thread NBHWz (sweep): restrictive `default` READ policy + readable s
|
|
|
1230
1230
|
|
|
1231
1231
|
// observe archives under pi-geek's readable+writable project overlay.
|
|
1232
1232
|
await service.observe(
|
|
1233
|
-
observeRequest({ sessionKey: "pi-geek:abc123", projectTag: "
|
|
1233
|
+
observeRequest({ sessionKey: "pi-geek:abc123", projectTag: "Acme/Webshop" }),
|
|
1234
1234
|
);
|
|
1235
1235
|
const writeKey = probe.lcmWriteKeys[0];
|
|
1236
1236
|
assertOverlayWriteKey(writeKey, "pi-geek-"); // observe must archive under pi-geek's overlay key, got ${writeKey}
|
|
@@ -1277,8 +1277,8 @@ test("#1505 codex P1 'Don't treat any readable namespace as default LCM access':
|
|
|
1277
1277
|
|
|
1278
1278
|
// Bind a coding context so the overlay WOULD apply on alice's base.
|
|
1279
1279
|
probe.contexts.set("sess-1", {
|
|
1280
|
-
projectId: "
|
|
1281
|
-
projectName: "
|
|
1280
|
+
projectId: "acme-webshop",
|
|
1281
|
+
projectName: "Acme/Webshop",
|
|
1282
1282
|
} as unknown as CodingContext);
|
|
1283
1283
|
|
|
1284
1284
|
const res = await service.lcmSearch({
|
|
@@ -162,14 +162,14 @@ test("#1495 projectTag: LCM, extraction, objective-state, and response all agree
|
|
|
162
162
|
const service = new EngramAccessService(probe.orch);
|
|
163
163
|
|
|
164
164
|
const res = await service.observe(
|
|
165
|
-
observeRequest({ sessionKey: "pi-geek:abc123", projectTag: "
|
|
165
|
+
observeRequest({ sessionKey: "pi-geek:abc123", projectTag: "Acme/Webshop" }),
|
|
166
166
|
);
|
|
167
167
|
|
|
168
168
|
// Effective write namespace == principal self base overlaid with the project,
|
|
169
169
|
// EXACTLY what a same-session project-scoped recall/store resolves.
|
|
170
170
|
const expected = combineNamespaces(
|
|
171
171
|
"pi-geek",
|
|
172
|
-
projectNamespaceName(projectTagProjectId("
|
|
172
|
+
projectNamespaceName(projectTagProjectId("Acme/Webshop")),
|
|
173
173
|
);
|
|
174
174
|
|
|
175
175
|
assert.equal(res.effectiveNamespace, expected, "response effectiveNamespace");
|
|
@@ -334,7 +334,7 @@ test("#1495 explicit namespace wins and project context does NOT silently overri
|
|
|
334
334
|
observeRequest({
|
|
335
335
|
sessionKey: "pi-geek:abc123",
|
|
336
336
|
namespace: "team",
|
|
337
|
-
projectTag: "
|
|
337
|
+
projectTag: "Acme/Webshop",
|
|
338
338
|
}),
|
|
339
339
|
);
|
|
340
340
|
|
|
@@ -364,7 +364,7 @@ test("#1495 projectScope:false ⇒ no overlay (unqualified write stays on config
|
|
|
364
364
|
const service = new EngramAccessService(probe.orch);
|
|
365
365
|
|
|
366
366
|
const res = await service.observe(
|
|
367
|
-
observeRequest({ sessionKey: "pi-geek:abc123", projectTag: "
|
|
367
|
+
observeRequest({ sessionKey: "pi-geek:abc123", projectTag: "Acme/Webshop" }),
|
|
368
368
|
);
|
|
369
369
|
|
|
370
370
|
assert.equal(res.effectiveNamespace, "default");
|
|
@@ -385,7 +385,7 @@ test("#1495 namespacesEnabled:false ⇒ single-store behavior preserved", async
|
|
|
385
385
|
const service = new EngramAccessService(probe.orch);
|
|
386
386
|
|
|
387
387
|
const res = await service.observe(
|
|
388
|
-
observeRequest({ sessionKey: "pi-geek:abc123", projectTag: "
|
|
388
|
+
observeRequest({ sessionKey: "pi-geek:abc123", projectTag: "Acme/Webshop" }),
|
|
389
389
|
);
|
|
390
390
|
|
|
391
391
|
assert.equal(res.effectiveNamespace, "default");
|
|
@@ -409,7 +409,7 @@ test("#1495 unauthorized explicit namespace throws BEFORE session context is att
|
|
|
409
409
|
observeRequest({
|
|
410
410
|
sessionKey: "pi-geek:abc123",
|
|
411
411
|
namespace: "victim-secret",
|
|
412
|
-
projectTag: "
|
|
412
|
+
projectTag: "Acme/Webshop",
|
|
413
413
|
}),
|
|
414
414
|
),
|
|
415
415
|
/not writable/,
|
|
@@ -445,7 +445,7 @@ test("#1505 thread 1/3: unauthorized OVERLAY self-base throws BEFORE coding cont
|
|
|
445
445
|
|
|
446
446
|
await assert.rejects(
|
|
447
447
|
service.observe(
|
|
448
|
-
observeRequest({ sessionKey: "pi-geek:abc123", projectTag: "
|
|
448
|
+
observeRequest({ sessionKey: "pi-geek:abc123", projectTag: "Acme/Webshop" }),
|
|
449
449
|
),
|
|
450
450
|
/not writable/,
|
|
451
451
|
);
|
|
@@ -491,13 +491,13 @@ test("#1505 thread jvO: restrictive default-namespace write policy does NOT reje
|
|
|
491
491
|
|
|
492
492
|
const expectedOverlay = combineNamespaces(
|
|
493
493
|
"pi-geek",
|
|
494
|
-
projectNamespaceName(projectTagProjectId("
|
|
494
|
+
projectNamespaceName(projectTagProjectId("Acme/Webshop")),
|
|
495
495
|
);
|
|
496
496
|
|
|
497
497
|
// FAIL-BEFORE: this threw `namespace is not writable: default`. PASS-AFTER:
|
|
498
498
|
// the observe is accepted exactly like memory_store/suggestion_submit would.
|
|
499
499
|
const res = await service.observe(
|
|
500
|
-
observeRequest({ sessionKey: "pi-geek:abc123", projectTag: "
|
|
500
|
+
observeRequest({ sessionKey: "pi-geek:abc123", projectTag: "Acme/Webshop" }),
|
|
501
501
|
);
|
|
502
502
|
|
|
503
503
|
// Every side effect uses the authorized overlay write target.
|
|
@@ -533,7 +533,7 @@ test("#1505 thread jvO: a genuine reject (unwritable self base) under a restrict
|
|
|
533
533
|
|
|
534
534
|
await assert.rejects(
|
|
535
535
|
service.observe(
|
|
536
|
-
observeRequest({ sessionKey: "pi-geek:abc123", projectTag: "
|
|
536
|
+
observeRequest({ sessionKey: "pi-geek:abc123", projectTag: "Acme/Webshop" }),
|
|
537
537
|
),
|
|
538
538
|
/not writable/,
|
|
539
539
|
);
|
|
@@ -553,12 +553,12 @@ test("#1495 scopeDebug exposes the resolved plan for callers/tests", async () =>
|
|
|
553
553
|
const service = new EngramAccessService(probe.orch);
|
|
554
554
|
|
|
555
555
|
const res = await service.observe(
|
|
556
|
-
observeRequest({ sessionKey: "pi-geek:abc123", projectTag: "
|
|
556
|
+
observeRequest({ sessionKey: "pi-geek:abc123", projectTag: "Acme/Webshop" }),
|
|
557
557
|
);
|
|
558
558
|
|
|
559
559
|
const expected = combineNamespaces(
|
|
560
560
|
"pi-geek",
|
|
561
|
-
projectNamespaceName(projectTagProjectId("
|
|
561
|
+
projectNamespaceName(projectTagProjectId("Acme/Webshop")),
|
|
562
562
|
);
|
|
563
563
|
assert.ok(res.scopeDebug, "scopeDebug must be present");
|
|
564
564
|
assert.equal(res.scopeDebug!.principal, "pi-geek");
|
|
@@ -611,9 +611,9 @@ test("#1495 the scope plan's writeNamespace matches resolveCodingScopedWriteName
|
|
|
611
611
|
const probe = makeObserveProbe(withSelfPolicyPrefix("pi-geek"));
|
|
612
612
|
// Bind a session coding context so both resolvers see the same project.
|
|
613
613
|
probe.contexts.set("pi-geek:abc123", {
|
|
614
|
-
projectId: projectTagProjectId("
|
|
614
|
+
projectId: projectTagProjectId("Acme/Webshop"),
|
|
615
615
|
branch: null,
|
|
616
|
-
rootPath: projectTagProjectId("
|
|
616
|
+
rootPath: projectTagProjectId("Acme/Webshop"),
|
|
617
617
|
defaultBranch: null,
|
|
618
618
|
});
|
|
619
619
|
const service = new EngramAccessService(probe.orch);
|
|
@@ -765,14 +765,14 @@ test("#1495 skipExtraction does not enqueue extraction but still archives LCM un
|
|
|
765
765
|
const res = await service.observe(
|
|
766
766
|
observeRequest({
|
|
767
767
|
sessionKey: "pi-geek:abc123",
|
|
768
|
-
projectTag: "
|
|
768
|
+
projectTag: "Acme/Webshop",
|
|
769
769
|
skipExtraction: true,
|
|
770
770
|
}),
|
|
771
771
|
);
|
|
772
772
|
|
|
773
773
|
const expected = combineNamespaces(
|
|
774
774
|
"pi-geek",
|
|
775
|
-
projectNamespaceName(projectTagProjectId("
|
|
775
|
+
projectNamespaceName(projectTagProjectId("Acme/Webshop")),
|
|
776
776
|
);
|
|
777
777
|
assert.equal(res.extractionQueued, false);
|
|
778
778
|
assert.equal(probe.extractionCalls.length, 0);
|
|
@@ -24,10 +24,10 @@ test("projectTag auto-resolution uses the shared project tag canonicalizer", asy
|
|
|
24
24
|
} as any);
|
|
25
25
|
|
|
26
26
|
await (service as any).maybeAttachCodingContext("session-a", {
|
|
27
|
-
projectTag: "
|
|
27
|
+
projectTag: "Acme/Webshop",
|
|
28
28
|
});
|
|
29
29
|
|
|
30
|
-
const projectId = projectTagProjectId("
|
|
30
|
+
const projectId = projectTagProjectId("Acme/Webshop");
|
|
31
31
|
assert.deepEqual(contexts.get("session-a"), {
|
|
32
32
|
projectId,
|
|
33
33
|
branch: null,
|
|
@@ -145,10 +145,26 @@ export interface SymbolIR {
|
|
|
145
145
|
export interface ImportIR {
|
|
146
146
|
/** Raw module specifier as written in source. */
|
|
147
147
|
readonly module: string;
|
|
148
|
+
/** Exported names as declared by the source module (pre-alias). */
|
|
148
149
|
readonly importedNames: readonly string[];
|
|
150
|
+
/**
|
|
151
|
+
* Alias-aware bindings (issue #1894 review): `local` is the identifier
|
|
152
|
+
* usable at call sites in THIS file; `exported` is the name in the
|
|
153
|
+
* source module. For non-aliased imports the two are equal. Optional so
|
|
154
|
+
* pre-existing IR consumers and JSON fixtures stay valid; when absent,
|
|
155
|
+
* consumers treat every `importedNames` entry as `local === exported`.
|
|
156
|
+
*/
|
|
157
|
+
readonly bindings?: readonly ImportBindingIR[];
|
|
149
158
|
readonly span: { readonly startByte: number; readonly endByte: number };
|
|
150
159
|
}
|
|
151
160
|
|
|
161
|
+
export interface ImportBindingIR {
|
|
162
|
+
/** Name exported by the source module. */
|
|
163
|
+
readonly exported: string;
|
|
164
|
+
/** Local identifier bound in the importing file. */
|
|
165
|
+
readonly local: string;
|
|
166
|
+
}
|
|
167
|
+
|
|
152
168
|
export interface ExportIR {
|
|
153
169
|
readonly name: string;
|
|
154
170
|
readonly span: { readonly startByte: number; readonly endByte: number };
|
|
@@ -156,6 +172,13 @@ export interface ExportIR {
|
|
|
156
172
|
|
|
157
173
|
export interface CallSiteIR {
|
|
158
174
|
readonly calleeNameCandidates: readonly string[];
|
|
175
|
+
/**
|
|
176
|
+
* True when the callee is a member/property access (`obj.save()`,
|
|
177
|
+
* `recv.field()`), issue #1894 review: bare-name heuristics must never
|
|
178
|
+
* bind these — method dispatch is Phase B (LSP) territory. Optional so
|
|
179
|
+
* pre-existing IR stays valid; absent = false.
|
|
180
|
+
*/
|
|
181
|
+
readonly memberAccess?: boolean;
|
|
159
182
|
readonly span: { readonly startByte: number; readonly endByte: number };
|
|
160
183
|
}
|
|
161
184
|
|
|
@@ -58,9 +58,9 @@ test("projectNamespaceName: empty input falls back to 'unknown'", () => {
|
|
|
58
58
|
});
|
|
59
59
|
|
|
60
60
|
test("projectTagProjectId: lossy tags get hash disambiguators", () => {
|
|
61
|
-
assert.equal(projectTagProjectId("
|
|
62
|
-
assert.notEqual(projectTagProjectId("
|
|
63
|
-
assert.match(projectTagProjectId("
|
|
61
|
+
assert.equal(projectTagProjectId("acme-webshop"), "tag:acme-webshop");
|
|
62
|
+
assert.notEqual(projectTagProjectId("acme/webshop"), projectTagProjectId("acme-webshop"));
|
|
63
|
+
assert.match(projectTagProjectId("acme/webshop"), /^tag:acme-webshop-[0-9a-f]{8}$/);
|
|
64
64
|
});
|
|
65
65
|
|
|
66
66
|
test("projectNamespaceName: length-capped to 64 chars, no trailing dash", () => {
|
|
@@ -39,11 +39,11 @@ test("recall schema accepts projectTag field", () => {
|
|
|
39
39
|
const result = validateRequest<RecallRequest>("recall", {
|
|
40
40
|
query: "test query",
|
|
41
41
|
sessionKey: "sess-1",
|
|
42
|
-
projectTag: "
|
|
42
|
+
projectTag: "acme-webshop",
|
|
43
43
|
});
|
|
44
44
|
assert.equal(result.success, true);
|
|
45
45
|
if (result.success) {
|
|
46
|
-
assert.equal(result.data.projectTag, "
|
|
46
|
+
assert.equal(result.data.projectTag, "acme-webshop");
|
|
47
47
|
}
|
|
48
48
|
});
|
|
49
49
|
|
|
@@ -52,7 +52,7 @@ test("recall schema accepts both cwd and projectTag", () => {
|
|
|
52
52
|
query: "test query",
|
|
53
53
|
sessionKey: "sess-1",
|
|
54
54
|
cwd: "/home/user/project",
|
|
55
|
-
projectTag: "
|
|
55
|
+
projectTag: "acme-webshop",
|
|
56
56
|
});
|
|
57
57
|
assert.equal(result.success, true);
|
|
58
58
|
});
|
|
@@ -89,11 +89,11 @@ test("observe schema accepts projectTag field", () => {
|
|
|
89
89
|
const result = validateRequest<ObserveRequest>("observe", {
|
|
90
90
|
sessionKey: "sess-1",
|
|
91
91
|
messages: [{ role: "user", content: "hello" }],
|
|
92
|
-
projectTag: "
|
|
92
|
+
projectTag: "globex-storefront",
|
|
93
93
|
});
|
|
94
94
|
assert.equal(result.success, true);
|
|
95
95
|
if (result.success) {
|
|
96
|
-
assert.equal(result.data.projectTag, "
|
|
96
|
+
assert.equal(result.data.projectTag, "globex-storefront");
|
|
97
97
|
}
|
|
98
98
|
});
|
|
99
99
|
|
|
@@ -185,13 +185,13 @@ test("set_coding_context with projectTag creates tag-based context", async () =>
|
|
|
185
185
|
const { mcp, calls } = makeMcp();
|
|
186
186
|
const result = await call(mcp, "engram.set_coding_context", {
|
|
187
187
|
sessionKey: "session-A",
|
|
188
|
-
projectTag: "
|
|
188
|
+
projectTag: "acme-webshop",
|
|
189
189
|
});
|
|
190
190
|
assert.deepEqual(result, { ok: true });
|
|
191
191
|
assert.equal(calls.length, 1);
|
|
192
|
-
assert.equal(calls[0]!.ctx?.projectId, "tag:
|
|
192
|
+
assert.equal(calls[0]!.ctx?.projectId, "tag:acme-webshop");
|
|
193
193
|
assert.equal(calls[0]!.ctx?.branch, null);
|
|
194
|
-
assert.equal(calls[0]!.ctx?.rootPath, "tag:
|
|
194
|
+
assert.equal(calls[0]!.ctx?.rootPath, "tag:acme-webshop");
|
|
195
195
|
assert.equal(calls[0]!.ctx?.defaultBranch, null);
|
|
196
196
|
});
|
|
197
197
|
|
|
@@ -199,16 +199,16 @@ test("set_coding_context with projectTag disambiguates lossy tags", async () =>
|
|
|
199
199
|
const { mcp, calls } = makeMcp();
|
|
200
200
|
await call(mcp, "engram.set_coding_context", {
|
|
201
201
|
sessionKey: "session-A",
|
|
202
|
-
projectTag: "
|
|
202
|
+
projectTag: "acme/webshop",
|
|
203
203
|
});
|
|
204
204
|
await call(mcp, "engram.set_coding_context", {
|
|
205
205
|
sessionKey: "session-B",
|
|
206
|
-
projectTag: "
|
|
206
|
+
projectTag: "acme-webshop",
|
|
207
207
|
});
|
|
208
208
|
|
|
209
209
|
assert.notEqual(calls[0]!.ctx?.projectId, calls[1]!.ctx?.projectId);
|
|
210
|
-
assert.match(calls[0]!.ctx?.projectId ?? "", /^tag:
|
|
211
|
-
assert.equal(calls[1]!.ctx?.projectId, "tag:
|
|
210
|
+
assert.match(calls[0]!.ctx?.projectId ?? "", /^tag:acme-webshop-[0-9a-f]{8}$/);
|
|
211
|
+
assert.equal(calls[1]!.ctx?.projectId, "tag:acme-webshop");
|
|
212
212
|
});
|
|
213
213
|
|
|
214
214
|
test("set_coding_context with codingContext takes precedence over projectTag", async () => {
|
|
@@ -221,7 +221,7 @@ test("set_coding_context with codingContext takes precedence over projectTag", a
|
|
|
221
221
|
rootPath: "/work/proj",
|
|
222
222
|
defaultBranch: "main",
|
|
223
223
|
},
|
|
224
|
-
projectTag: "
|
|
224
|
+
projectTag: "acme-webshop",
|
|
225
225
|
});
|
|
226
226
|
assert.equal(calls.length, 1);
|
|
227
227
|
assert.equal(calls[0]!.ctx?.projectId, "origin:abcd1234");
|
|
@@ -242,7 +242,7 @@ test("set_coding_context with codingContext=null clears (even with projectTag pr
|
|
|
242
242
|
await call(mcp, "engram.set_coding_context", {
|
|
243
243
|
sessionKey: "session-A",
|
|
244
244
|
codingContext: null,
|
|
245
|
-
projectTag: "
|
|
245
|
+
projectTag: "acme-webshop",
|
|
246
246
|
});
|
|
247
247
|
assert.equal(calls.length, 1);
|
|
248
248
|
assert.equal(calls[0]!.ctx, null);
|
|
@@ -252,11 +252,11 @@ test("set_coding_context projectTag via canonical alias remnic.*", async () => {
|
|
|
252
252
|
const { mcp, calls } = makeMcp();
|
|
253
253
|
const result = await call(mcp, "remnic.set_coding_context", {
|
|
254
254
|
sessionKey: "session-B",
|
|
255
|
-
projectTag: "
|
|
255
|
+
projectTag: "globex-storefront",
|
|
256
256
|
});
|
|
257
257
|
assert.deepEqual(result, { ok: true });
|
|
258
258
|
assert.equal(calls.length, 1);
|
|
259
|
-
assert.equal(calls[0]!.ctx?.projectId, "tag:
|
|
259
|
+
assert.equal(calls[0]!.ctx?.projectId, "tag:globex-storefront");
|
|
260
260
|
});
|
|
261
261
|
|
|
262
262
|
// ──────────────────────────────────────────────────────────────────────────
|
|
@@ -321,10 +321,10 @@ test("maybeAttachCodingContext: projectTag attaches tag-based context", async ()
|
|
|
321
321
|
): Promise<void>;
|
|
322
322
|
}).maybeAttachCodingContext.bind(service);
|
|
323
323
|
|
|
324
|
-
await maybeAttach("session-X", { projectTag: "
|
|
324
|
+
await maybeAttach("session-X", { projectTag: "acme-webshop" });
|
|
325
325
|
assert.equal(calls.length, 1);
|
|
326
|
-
assert.equal(calls[0]!.ctx?.projectId, "tag:
|
|
327
|
-
assert.equal(calls[0]!.ctx?.rootPath, "tag:
|
|
326
|
+
assert.equal(calls[0]!.ctx?.projectId, "tag:acme-webshop");
|
|
327
|
+
assert.equal(calls[0]!.ctx?.rootPath, "tag:acme-webshop");
|
|
328
328
|
});
|
|
329
329
|
|
|
330
330
|
test("maybeAttachCodingContext: skips when session already has context", async () => {
|
|
@@ -351,7 +351,7 @@ test("maybeAttachCodingContext: skips when session already has context", async (
|
|
|
351
351
|
): Promise<void>;
|
|
352
352
|
}).maybeAttachCodingContext.bind(service);
|
|
353
353
|
|
|
354
|
-
await maybeAttach("session-X", { projectTag: "
|
|
354
|
+
await maybeAttach("session-X", { projectTag: "acme-webshop" });
|
|
355
355
|
assert.equal(calls.length, 0, "should not overwrite existing context");
|
|
356
356
|
});
|
|
357
357
|
|
|
@@ -379,7 +379,7 @@ test("maybeAttachCodingContext: skips when projectScope disabled", async () => {
|
|
|
379
379
|
): Promise<void>;
|
|
380
380
|
}).maybeAttachCodingContext.bind(service);
|
|
381
381
|
|
|
382
|
-
await maybeAttach("session-X", { projectTag: "
|
|
382
|
+
await maybeAttach("session-X", { projectTag: "acme-webshop" });
|
|
383
383
|
assert.equal(calls.length, 0, "should not attach when projectScope is disabled");
|
|
384
384
|
});
|
|
385
385
|
|
|
@@ -407,7 +407,7 @@ test("maybeAttachCodingContext: skips when no sessionKey", async () => {
|
|
|
407
407
|
): Promise<void>;
|
|
408
408
|
}).maybeAttachCodingContext.bind(service);
|
|
409
409
|
|
|
410
|
-
await maybeAttach(undefined, { projectTag: "
|
|
410
|
+
await maybeAttach(undefined, { projectTag: "acme-webshop" });
|
|
411
411
|
assert.equal(calls.length, 0, "should not attach without sessionKey");
|
|
412
412
|
});
|
|
413
413
|
|
|
@@ -90,13 +90,13 @@ async function walkCollectDirs(root: string, out: Set<string>): Promise<void> {
|
|
|
90
90
|
// ─── Symptom A: coding-namespace derivation is stable across write/read ────
|
|
91
91
|
|
|
92
92
|
test("#1492 Symptom A: a project-scoped session derives ONE stable overlay namespace — the write/read convergence point", () => {
|
|
93
|
-
// The reporter's scenario: user "pi-geek" in project "
|
|
93
|
+
// The reporter's scenario: user "pi-geek" in project "Acme/Webshop". Both the
|
|
94
94
|
// observe write path and the recall read path must resolve the SAME scoped
|
|
95
95
|
// namespace. They do so by combining the principal base with the project
|
|
96
96
|
// overlay through exactly ONE helper (combineNamespaces); a second ad-hoc
|
|
97
97
|
// combination is what caused the original drift.
|
|
98
98
|
const principal = "pi-geek";
|
|
99
|
-
const projectId = projectTagProjectId("
|
|
99
|
+
const projectId = projectTagProjectId("Acme/Webshop");
|
|
100
100
|
const codingContext = {
|
|
101
101
|
projectId,
|
|
102
102
|
branch: null,
|
|
File without changes
|
|
File without changes
|