borgmcp-shared 0.14.0 → 1.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.
Files changed (43) hide show
  1. package/README.md +4 -3
  2. package/RELEASES.md +7 -0
  3. package/dist/conformance/adapter.d.ts +9 -2
  4. package/dist/conformance/adapter.d.ts.map +1 -1
  5. package/dist/conformance/adapter.js +128 -43
  6. package/dist/conformance/adapter.js.map +1 -1
  7. package/dist/conformance/index.d.ts +25 -3
  8. package/dist/conformance/index.d.ts.map +1 -1
  9. package/dist/conformance/index.js +73 -18
  10. package/dist/conformance/index.js.map +1 -1
  11. package/dist/protocol/contract.d.ts +1 -1
  12. package/dist/protocol/contract.d.ts.map +1 -1
  13. package/dist/protocol/contract.js +13 -18
  14. package/dist/protocol/contract.js.map +1 -1
  15. package/dist/protocol/coordination.d.ts +10 -0
  16. package/dist/protocol/coordination.d.ts.map +1 -1
  17. package/dist/protocol/coordination.js +20 -6
  18. package/dist/protocol/coordination.js.map +1 -1
  19. package/dist/protocol/errors.d.ts +1 -1
  20. package/dist/protocol/errors.d.ts.map +1 -1
  21. package/dist/protocol/errors.js +1 -1
  22. package/dist/protocol/errors.js.map +1 -1
  23. package/dist/protocol/types.d.ts +1 -5
  24. package/dist/protocol/types.d.ts.map +1 -1
  25. package/dist/protocol/version.d.ts +1 -1
  26. package/dist/protocol/version.js +1 -1
  27. package/dist/templates.d.ts +1 -3
  28. package/dist/templates.d.ts.map +1 -1
  29. package/dist/templates.js +7 -79
  30. package/dist/templates.js.map +1 -1
  31. package/docs/compatibility.md +9 -0
  32. package/docs/release-records.json +14 -0
  33. package/docs/releases/1.0.0.md +11 -0
  34. package/docs/template-lifecycle.md +1 -1
  35. package/package.json +1 -1
  36. package/src/conformance/adapter.ts +232 -52
  37. package/src/conformance/index.ts +88 -22
  38. package/src/protocol/contract.ts +15 -21
  39. package/src/protocol/coordination.ts +36 -7
  40. package/src/protocol/errors.ts +1 -1
  41. package/src/protocol/types.ts +1 -5
  42. package/src/protocol/version.ts +2 -2
  43. package/src/templates.ts +7 -81
@@ -97,6 +97,15 @@ per-recipient acknowledgement timestamps and separate advisory claims. A v10
97
97
  peer and a v11 peer reject each other during credential-free preflight before
98
98
  either peer dispatches the new query.
99
99
 
100
+ `borgmcp-shared@1.0.0` carries protocol v12. It adds cursorless exact-entry
101
+ lookup by canonical UUID or unique eight-hex prefix, with typed unknown and
102
+ ambiguous-prefix refusals. Every append request must also choose exactly one
103
+ explicit audience through `to: "broadcast"` or a non-empty recipient-selector
104
+ array. The public append request has no `visibility` or `recipientDroneIds`,
105
+ message taxonomy classifies prefixes and lifecycle only, and routing never falls
106
+ open. A v11 peer and a v12 peer reject each other during credential-free
107
+ preflight before either new contract is dispatched.
108
+
100
109
  Removing or reinterpreting an existing field is a protocol-breaking change even
101
110
  when TypeScript permits it. Implementations must not infer compatibility from a
102
111
  successful build alone — they must run the shared conformance suite against the
@@ -229,5 +229,19 @@
229
229
  "verify_job_id": null,
230
230
  "publish_job_id": null,
231
231
  "artifact_integrity": "sha512-AT5xOpd99U1Xd2waRJs01i2fz9ApMzd+NXQh0WMwTUknSsHpaQaEtGjcxtEDZG6MbB6nWfhoWG1ZZm9Fdkoytg=="
232
+ },
233
+ {
234
+ "outcome": "published",
235
+ "version": "0.14.0",
236
+ "tag": "v0.14.0",
237
+ "tag_object": "4ecd4e54bbf5a3dd719855ccc4d6f9db3939800f",
238
+ "commit": "a69926023d53268131e95b63efd141a17c634e2d",
239
+ "tree": "9074b05b687178fadc6d7cb40e55d8e5cf9cf248",
240
+ "workflow_run_id": 31957839605,
241
+ "workflow_run_attempt": 1,
242
+ "workflow_conclusion": "success",
243
+ "verify_job_id": null,
244
+ "publish_job_id": null,
245
+ "artifact_integrity": "sha512-rKRMxnxTnW+o3WOqtAFoih9IeRKCZw/lltqz7CbjC1riNq52CsZ871o1Fo7Fdk0WqwuzdFQmRJ7qOzPi08Q/QA=="
232
246
  }
233
247
  ]
@@ -0,0 +1,11 @@
1
+ This major release introduces the protocol v12 trustworthy-messaging contracts
2
+ used by the matching Borg MCP server and client major releases.
3
+
4
+ - Every append requires an explicit audience: scalar `"broadcast"` or a non-empty array of recipient selectors.
5
+ - Omitted, null, empty, malformed, and retired addressing inputs refuse before persistence; classification never supplies an audience or falls open.
6
+ - Public append requests no longer expose `visibility` or `recipientDroneIds`; stored and read entries retain resolved visibility and recipient IDs.
7
+ - Message taxonomy retains class, prefixes, and lifecycle only. Every bundled template and playbook requires explicit `to`, including `to: "broadcast"` for cube-wide messages.
8
+ - Routing echoes contain only the resolved class and recipients.
9
+ - Cursorless entry lookup accepts a canonical full UUID or one unique eight-hex prefix and returns the complete enriched log entry.
10
+ - Unknown or inaccessible entries return `NOT_FOUND`; ambiguous prefixes return `LOG_ENTRY_PREFIX_AMBIGUOUS` without selecting an arbitrary match.
11
+ - Entry lookup conformance proves no unread, acknowledgement, claim, log, or authority-state mutation.
@@ -48,7 +48,7 @@ Existing cubes are snapshots with local ownership, not replicas. They do not aut
48
48
 
49
49
  Use the existing focused controls; do not add a second template lifecycle mechanism:
50
50
 
51
- - `test/templates.test.ts` pins the built-in set, expected software-development roles and flags, host-neutral presentation copy, authority/scope language, role-size budgets, Builder minimum-sufficient-change ordering, taxonomy routing, generated/source equality, and no-clobber resolution.
51
+ - `test/templates.test.ts` pins the built-in set, expected software-development roles and flags, host-neutral presentation copy, authority/scope language, role-size budgets, Builder minimum-sufficient-change ordering, classification-only taxonomy, explicit log addressing, generated/source equality, and no-clobber resolution.
52
52
  - `test/role-section.test.ts` pins plain-label parsing, byte-identical parse/serialize for real template roles, and single-section replacement/insertion/deletion without clobbering unrelated text.
53
53
  - `test/packed-artifact.test.ts` installs the packed package and verifies the public named-template creation contract and shipped role text from the consumer surface.
54
54
  - `CUBE_TEMPLATE_ACCEPTANCE_CONFORMANCE` pins the closed accepted template-name set and invalid-name rejection. Stateful create vectors pin template identity to retry behavior.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "borgmcp-shared",
3
- "version": "0.14.0",
3
+ "version": "1.0.0",
4
4
  "description": "Shared protocol, domain, templates, and conformance contracts for Borg MCP implementations.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -7,6 +7,7 @@ import {
7
7
  decodeDeleteCubeResponseEnvelope,
8
8
  decodeAppendLogResultEnvelope,
9
9
  decodeAckStatusResultEnvelope,
10
+ decodeEntryQueryResultEnvelope,
10
11
  decodeDecisionResultEnvelope,
11
12
  decodeDecisionsResultEnvelope,
12
13
  decodeEnrollmentExchangeResponseEnvelope,
@@ -41,6 +42,7 @@ import {
41
42
  type StreamEvent,
42
43
  type DroneRuntimeMetadata,
43
44
  type CubeDocument,
45
+ type EnrichedStreamEntry,
44
46
  } from '../protocol/index.js';
45
47
  import {
46
48
  APPEND_LOG_IDEMPOTENCY_CONFORMANCE,
@@ -122,6 +124,7 @@ export interface ConformanceAuthorityState {
122
124
  enrollment_claims: number;
123
125
  activity_acknowledgements: number;
124
126
  activity_claims: number;
127
+ activity_log_entries: number;
125
128
  cubes: number;
126
129
  roles: number;
127
130
  grants: number;
@@ -217,12 +220,7 @@ export interface ConformanceAdmin {
217
220
  readonly isDefault?: boolean;
218
221
  readonly isMandatory?: boolean;
219
222
  }): Promise<ConformanceRole>;
220
- referenceRoleFromTaxonomy(cube: ConformanceCube, role: ConformanceRole): Promise<void>;
221
- configureMessageClassRouting(
222
- cube: ConformanceCube,
223
- className: string,
224
- recipientDroneIds: readonly string[],
225
- ): Promise<void>;
223
+ replaceLogEntryId(cube: ConformanceCube, currentId: string, replacementId: string): Promise<void>;
226
224
  createDrone(
227
225
  principal: ConformancePrincipal,
228
226
  cube: ConformanceCube,
@@ -302,6 +300,11 @@ export interface ConformanceOperations {
302
300
  cube: ConformanceCube,
303
301
  request: unknown,
304
302
  ): Promise<ConformanceHttpResponse>;
303
+ entryQuery(
304
+ credential: string,
305
+ cube: ConformanceCube,
306
+ request: unknown,
307
+ ): Promise<ConformanceHttpResponse>;
305
308
  ack(
306
309
  credential: string,
307
310
  cube: ConformanceCube,
@@ -387,6 +390,8 @@ export const ADAPTER_CONFORMANCE_FIXTURES = [
387
390
  { id: 'security.oversize-request', area: 'security' },
388
391
  { id: 'security.cross-cube-isolation', area: 'security' },
389
392
  { id: 'log.append-idempotency', area: 'log' },
393
+ { id: 'log.mandatory-addressing', area: 'log' },
394
+ { id: 'log.entry-query', area: 'log' },
390
395
  { id: 'log.read-cursor-tuple', area: 'cursor' },
391
396
  { id: 'sse.replay-live-transition', area: 'sse' },
392
397
  { id: 'cursor.explicit-expiry', area: 'cursor' },
@@ -1477,6 +1482,7 @@ export async function runAdapterConformance(
1477
1482
  documentCube,
1478
1483
  createProtocolEnvelope('document-foreign-citation', {
1479
1484
  post_id: '00000000-0000-4000-8000-00000000031f',
1485
+ to: 'broadcast',
1480
1486
  message: 'Foreign evidence must remain hidden.',
1481
1487
  documents: [foreignDocument.id],
1482
1488
  }),
@@ -1518,6 +1524,7 @@ export async function runAdapterConformance(
1518
1524
  documentCube,
1519
1525
  createProtocolEnvelope('document-citation', {
1520
1526
  post_id: '00000000-0000-4000-8000-000000000320',
1527
+ to: 'broadcast',
1521
1528
  message: 'See the document evidence.',
1522
1529
  documents: [created.id, successor.id],
1523
1530
  }),
@@ -1530,6 +1537,7 @@ export async function runAdapterConformance(
1530
1537
  documentCube,
1531
1538
  createProtocolEnvelope('document-citation-conflict', {
1532
1539
  post_id: '00000000-0000-4000-8000-000000000320',
1540
+ to: 'broadcast',
1533
1541
  message: 'See the document evidence.',
1534
1542
  documents: [successor.id],
1535
1543
  }),
@@ -1637,14 +1645,14 @@ export async function runAdapterConformance(
1637
1645
  documentCredential,
1638
1646
  documentCube,
1639
1647
  createProtocolEnvelope('document-unknown-citation', {
1640
- post_id: '00000000-0000-4000-8000-000000000321', message: 'Unknown.', documents: ['unknown_full_id'],
1648
+ post_id: '00000000-0000-4000-8000-000000000321', message: 'Unknown.', to: 'broadcast', documents: ['unknown_full_id'],
1641
1649
  }),
1642
1650
  ), 404, ErrorCode.DOCUMENT_NOT_FOUND, 'Unknown document citation');
1643
1651
  const longAccepted = await environment.operations.append(
1644
1652
  documentCredential,
1645
1653
  documentCube,
1646
1654
  createProtocolEnvelope('document-advisory', {
1647
- post_id: '00000000-0000-4000-8000-000000000322', message: 'x'.repeat(1025),
1655
+ post_id: '00000000-0000-4000-8000-000000000322', message: 'x'.repeat(1025), to: 'broadcast',
1648
1656
  }),
1649
1657
  );
1650
1658
  expectStatus(longAccepted, 201, 'Advisory log append');
@@ -1653,7 +1661,7 @@ export async function runAdapterConformance(
1653
1661
  documentCredential,
1654
1662
  documentCube,
1655
1663
  createProtocolEnvelope('document-hard-cap', {
1656
- post_id: '00000000-0000-4000-8000-000000000323', message: 'x'.repeat(4097),
1664
+ post_id: '00000000-0000-4000-8000-000000000323', message: 'x'.repeat(4097), to: 'broadcast',
1657
1665
  }),
1658
1666
  ), 413, ErrorCode.CONTENT_TOO_LARGE, 'Hard-cap log append');
1659
1667
  const citedRead = decodeReadLogResultEnvelope((await environment.operations.read(
@@ -1680,6 +1688,7 @@ export async function runAdapterConformance(
1680
1688
  const injectedBody = JSON.stringify(
1681
1689
  createProtocolEnvelope('inject-b1', {
1682
1690
  post_id: '00000000-0000-4000-8000-000000000301',
1691
+ to: 'broadcast',
1683
1692
  message: injectedMessage,
1684
1693
  }),
1685
1694
  );
@@ -1702,6 +1711,7 @@ export async function runAdapterConformance(
1702
1711
  cubeB,
1703
1712
  createProtocolEnvelope('inject-b2', {
1704
1713
  post_id: '00000000-0000-4000-8000-000000000302',
1714
+ to: 'broadcast',
1705
1715
  message: 'post-injection-sentinel',
1706
1716
  }),
1707
1717
  );
@@ -1752,6 +1762,7 @@ export async function runAdapterConformance(
1752
1762
  const baseBody = JSON.stringify(
1753
1763
  createProtocolEnvelope('oversize-a1', {
1754
1764
  post_id: '00000000-0000-4000-8000-000000000303',
1765
+ to: 'broadcast',
1755
1766
  message: 'must-not-persist',
1756
1767
  }),
1757
1768
  );
@@ -1784,6 +1795,7 @@ export async function runAdapterConformance(
1784
1795
  createProtocolEnvelope('append-b1', {
1785
1796
  post_id: '00000000-0000-4000-8000-000000000304',
1786
1797
  message: 'principal-b-secret',
1798
+ to: 'broadcast',
1787
1799
  }),
1788
1800
  );
1789
1801
  expectStatus(secretAppend, 201, 'Principal B append');
@@ -1810,16 +1822,12 @@ export async function runAdapterConformance(
1810
1822
  });
1811
1823
  const firstRecipient = await environment.admin.createDrone(principal, cube, role);
1812
1824
  const secondRecipient = await environment.admin.createDrone(principal, cube, role);
1813
- await environment.admin.configureMessageClassRouting(cube, 'conformance-review', [firstRecipient.id]);
1814
- await environment.admin.configureMessageClassRouting(cube, 'conformance-security', [firstRecipient.id]);
1815
1825
  const postId = '00000000-0000-4000-8000-000000000313';
1816
1826
  const initialPayload = {
1817
1827
  post_id: postId,
1818
1828
  message: 'once',
1819
- visibility: 'direct' as const,
1820
- recipientDroneIds: [firstRecipient.id],
1829
+ to: [firstRecipient.id],
1821
1830
  class: 'review',
1822
- to: ['Coordinator'],
1823
1831
  };
1824
1832
  const first = await environment.operations.append(
1825
1833
  credential,
@@ -1830,32 +1838,12 @@ export async function runAdapterConformance(
1830
1838
  const firstResult = decodeAppendLogResultEnvelope(first.body).payload;
1831
1839
  invariant(!firstResult.deduplicated, 'Initial append was reported as deduplicated.');
1832
1840
  for (const [index, vector] of APPEND_LOG_IDEMPOTENCY_CONFORMANCE.entries()) {
1833
- const classRouting = vector.mutation === 'resolved_class_routing';
1834
- const vectorPostId = classRouting
1835
- ? '00000000-0000-4000-8000-000000000314'
1836
- : postId;
1837
- if (classRouting) {
1838
- const baseline = await environment.operations.append(
1839
- credential,
1840
- cube,
1841
- createProtocolEnvelope('append-idempotency-class-baseline', {
1842
- post_id: vectorPostId,
1843
- message: 'once',
1844
- class: 'conformance-review',
1845
- }),
1846
- );
1847
- expectStatus(baseline, 201, 'Resolved class-routing baseline');
1848
- }
1849
- const payload = classRouting ? {
1850
- post_id: vectorPostId,
1851
- message: 'once',
1852
- class: 'conformance-security',
1853
- } : {
1841
+ const payload = {
1854
1842
  ...initialPayload,
1855
1843
  ...(vector.mutation === 'message' ? { message: 'changed' } : {}),
1856
- ...(vector.mutation === 'visibility' ? { visibility: 'broadcast' as const } : {}),
1857
- ...(vector.mutation === 'recipient_set' ? { recipientDroneIds: [secondRecipient.id] } : {}),
1858
- ...(vector.mutation === 'ignored_request_shape' ? { class: 'security', to: ['Security Auditor'] } : {}),
1844
+ ...(vector.mutation === 'audience' ? { to: 'broadcast' as const } : {}),
1845
+ ...(vector.mutation === 'recipient_set' ? { to: [secondRecipient.id] } : {}),
1846
+ ...(vector.mutation === 'classification' ? { class: 'security' } : {}),
1859
1847
  };
1860
1848
  const response = await environment.operations.append(
1861
1849
  vector.actor === 'same' ? credential : otherCredential,
@@ -1883,10 +1871,207 @@ export async function runAdapterConformance(
1883
1871
  );
1884
1872
  expectStatus(read, 200, 'Idempotent append read');
1885
1873
  invariant(
1886
- decodeReadLogResultEnvelope(read.body).payload.entries.length === 3,
1874
+ decodeReadLogResultEnvelope(read.body).payload.entries.length === 2,
1887
1875
  'Append collision controls persisted the wrong number of entries.',
1888
1876
  );
1889
- return { persisted_entries: 3, stable_entry: true, deduplicated: true, conflicts: 4, cross_author_created: true };
1877
+ return { persisted_entries: 2, stable_entry: true, deduplicated: true, conflicts: 3, cross_author_created: true };
1878
+ });
1879
+
1880
+ await record('log.mandatory-addressing', async () => {
1881
+ const cube = await environment.admin.createCube('mandatory-addressing-cube');
1882
+ await environment.admin.grantCube(principalA, cube);
1883
+ const role = await environment.admin.createRole(cube, {
1884
+ roleClass: 'worker',
1885
+ isHumanSeat: false,
1886
+ name: 'Structured Recipient',
1887
+ });
1888
+ const recipient = await environment.admin.createDrone(principalA, cube, role);
1889
+ const message = 'START NOW exact slice';
1890
+ const before = await environment.admin.observeAuthorityState();
1891
+ expectError(
1892
+ await environment.operations.append(
1893
+ credentialA,
1894
+ cube,
1895
+ createProtocolEnvelope('mandatory-addressing-omitted', {
1896
+ post_id: '30000000-0000-4000-8000-000000000001',
1897
+ message,
1898
+ }),
1899
+ ),
1900
+ 400,
1901
+ ErrorCode.INVALID_INPUT,
1902
+ 'Omitted mandatory addressing',
1903
+ );
1904
+ assertStateDelta(before, await environment.admin.observeAuthorityState(), {}, 'Mandatory-addressing refusal');
1905
+
1906
+ const broadcast = await environment.operations.append(
1907
+ credentialA,
1908
+ cube,
1909
+ createProtocolEnvelope('mandatory-addressing-broadcast', {
1910
+ post_id: '30000000-0000-4000-8000-000000000002',
1911
+ message,
1912
+ to: 'broadcast',
1913
+ }),
1914
+ );
1915
+ expectStatus(broadcast, 201, 'Explicit broadcast addressing');
1916
+ const broadcastResult = decodeAppendLogResultEnvelope(broadcast.body).payload;
1917
+ invariant(broadcastResult.entry.visibility === 'broadcast', 'Scalar broadcast did not produce broadcast visibility.');
1918
+ invariant(
1919
+ (broadcastResult.entry.recipient_drone_ids?.length ?? 0) === 0,
1920
+ 'Scalar broadcast unexpectedly resolved direct recipients.',
1921
+ );
1922
+ const directed = await environment.operations.append(
1923
+ credentialA,
1924
+ cube,
1925
+ createProtocolEnvelope('mandatory-addressing-directed', {
1926
+ post_id: '30000000-0000-4000-8000-000000000003',
1927
+ message,
1928
+ to: [recipient.id],
1929
+ class: 'cube-wide',
1930
+ }),
1931
+ );
1932
+ expectStatus(directed, 201, 'Recipient-selector union branch');
1933
+ const directedResult = decodeAppendLogResultEnvelope(directed.body).payload;
1934
+ invariant(directedResult.entry.visibility === 'direct', 'Explicit recipient selectors did not produce direct visibility.');
1935
+ invariant(
1936
+ directedResult.entry.recipient_drone_ids?.includes(recipient.id) === true,
1937
+ 'Explicit recipient selectors did not resolve the named recipient.',
1938
+ );
1939
+ invariant(
1940
+ directedResult.entry.recipient_drone_ids?.length === 1,
1941
+ 'Classification changed or fell open the explicit recipient set.',
1942
+ );
1943
+ return { refused_status: 400, code: ErrorCode.INVALID_INPUT, persisted: false, broadcast: true, union: true, no_fall_open: true };
1944
+ });
1945
+
1946
+ await record('log.entry-query', async () => {
1947
+ const cube = await environment.admin.createCube('entry-query-cube');
1948
+ await environment.admin.grantCube(principalA, cube);
1949
+ const role = await environment.admin.createRole(cube, {
1950
+ roleClass: 'worker',
1951
+ isHumanSeat: false,
1952
+ name: 'Entry Query Worker',
1953
+ });
1954
+ const acknowledgedRecipient = await environment.admin.createDrone(principalA, cube, role);
1955
+ const claimingRecipient = await environment.admin.createDrone(principalA, cube, role);
1956
+ const acknowledgedCredential = await environment.admin.issueManagedDroneSession(acknowledgedRecipient);
1957
+ const claimingCredential = await environment.admin.issueManagedDroneSession(claimingRecipient);
1958
+ const ids = [
1959
+ '11111111-0000-4000-8000-000000000001',
1960
+ '22222222-0000-4000-8000-000000000001',
1961
+ '22222222-0000-4000-8000-000000000002',
1962
+ ];
1963
+ const entries: EnrichedStreamEntry[] = [];
1964
+ for (const [index, id] of ids.entries()) {
1965
+ const response = await environment.operations.append(
1966
+ credentialA,
1967
+ cube,
1968
+ createProtocolEnvelope(`entry-query-append-${index}`, {
1969
+ post_id: `40000000-0000-4000-8000-00000000000${index}`,
1970
+ to: [acknowledgedRecipient.id, claimingRecipient.id],
1971
+ message: `entry-query-${index}`,
1972
+ }),
1973
+ );
1974
+ expectStatus(response, 201, `Entry-query fixture append ${index}`);
1975
+ const entry = decodeAppendLogResultEnvelope(response.body).payload.entry;
1976
+ await environment.admin.replaceLogEntryId(cube, entry.id, id);
1977
+ entries.push({ ...entry, id });
1978
+ }
1979
+
1980
+ expectStatus(
1981
+ await environment.operations.ack(
1982
+ acknowledgedCredential,
1983
+ cube,
1984
+ createProtocolEnvelope('entry-query-seed-ack', { entry_id: ids[0], kind: 'ack' }),
1985
+ ),
1986
+ 204,
1987
+ 'Entry-query acknowledgement seed',
1988
+ );
1989
+ expectStatus(
1990
+ await environment.operations.ack(
1991
+ claimingCredential,
1992
+ cube,
1993
+ createProtocolEnvelope('entry-query-seed-claim', { entry_id: ids[1], kind: 'claim' }),
1994
+ ),
1995
+ 204,
1996
+ 'Entry-query claim seed',
1997
+ );
1998
+
1999
+ const before = await environment.admin.observeAuthorityState();
2000
+ for (const [requestId, selector, expectedId] of [
2001
+ ['entry-query-full', ids[1], ids[1]],
2002
+ ['entry-query-prefix', '11111111', ids[0]],
2003
+ ] as const) {
2004
+ const response = await environment.operations.entryQuery(
2005
+ credentialA,
2006
+ cube,
2007
+ createProtocolEnvelope(requestId, { entry_id: selector }),
2008
+ );
2009
+ expectStatus(response, 200, requestId);
2010
+ const result = decodeEntryQueryResultEnvelope(response.body).payload;
2011
+ invariant(result.entry.id === expectedId, `${requestId} returned the wrong entry.`);
2012
+ }
2013
+ expectError(
2014
+ await environment.operations.entryQuery(
2015
+ credentialA,
2016
+ cube,
2017
+ createProtocolEnvelope('entry-query-unknown', { entry_id: 'ffffffff' }),
2018
+ ),
2019
+ 404,
2020
+ ErrorCode.NOT_FOUND,
2021
+ 'Unknown entry query',
2022
+ );
2023
+ expectError(
2024
+ await environment.operations.entryQuery(
2025
+ credentialA,
2026
+ cube,
2027
+ createProtocolEnvelope('entry-query-ambiguous', { entry_id: '22222222' }),
2028
+ ),
2029
+ 409,
2030
+ ErrorCode.LOG_ENTRY_PREFIX_AMBIGUOUS,
2031
+ 'Ambiguous entry query',
2032
+ );
2033
+ assertStateDelta(before, await environment.admin.observeAuthorityState(), {}, 'Entry query');
2034
+ const acknowledgementStatus = decodeAckStatusResultEnvelope((await environment.operations.ackStatus(
2035
+ credentialA,
2036
+ cube,
2037
+ createProtocolEnvelope('entry-query-ack-status', { entry_id: ids[0] }),
2038
+ )).body).payload;
2039
+ const claimStatus = decodeAckStatusResultEnvelope((await environment.operations.ackStatus(
2040
+ credentialA,
2041
+ cube,
2042
+ createProtocolEnvelope('entry-query-claim-status', { entry_id: ids[1] }),
2043
+ )).body).payload;
2044
+ invariant(
2045
+ acknowledgementStatus.recipients.some((recipient) =>
2046
+ recipient.drone_id === acknowledgedRecipient.id && recipient.acknowledged_at !== null
2047
+ ),
2048
+ 'Entry query removed the seeded acknowledgement.',
2049
+ );
2050
+ invariant(
2051
+ claimStatus.claims.some((claim) => claim.drone_id === claimingRecipient.id),
2052
+ 'Entry query removed the seeded claim.',
2053
+ );
2054
+ const unreadResponse = await environment.operations.read(
2055
+ credentialA,
2056
+ cube,
2057
+ createProtocolEnvelope('entry-query-unread', { cursor: null, limit: 10 }),
2058
+ );
2059
+ expectStatus(unreadResponse, 200, 'Entry-query unread read');
2060
+ const unread = decodeReadLogResultEnvelope(unreadResponse.body).payload;
2061
+ invariant(
2062
+ unread.entries.length === entries.length && entries.every((entry) => unread.entries.some((item) => item.id === entry.id)),
2063
+ 'Entry query consumed or advanced unread activity.',
2064
+ );
2065
+ return {
2066
+ full_uuid: true,
2067
+ unique_prefix: true,
2068
+ ambiguous_code: ErrorCode.LOG_ENTRY_PREFIX_AMBIGUOUS,
2069
+ unknown_code: ErrorCode.NOT_FOUND,
2070
+ unread_entry_available: true,
2071
+ acknowledgement_preserved: true,
2072
+ claim_preserved: true,
2073
+ mutation: 'none',
2074
+ };
1890
2075
  });
1891
2076
 
1892
2077
  const entries: Array<{ id: string; created_at: string; message: string }> = [];
@@ -1898,6 +2083,7 @@ export async function runAdapterConformance(
1898
2083
  cubeA,
1899
2084
  createProtocolEnvelope(`append-a${index + 1}`, {
1900
2085
  post_id: `00000000-0000-4000-8000-${String(305 + index).padStart(12, '0')}`,
2086
+ to: 'broadcast',
1901
2087
  message,
1902
2088
  }),
1903
2089
  );
@@ -1935,6 +2121,7 @@ export async function runAdapterConformance(
1935
2121
  cubeA,
1936
2122
  createProtocolEnvelope('append-a4', {
1937
2123
  post_id: '00000000-0000-4000-8000-000000000308',
2124
+ to: 'broadcast',
1938
2125
  message: 'delta',
1939
2126
  }),
1940
2127
  );
@@ -1962,6 +2149,7 @@ export async function runAdapterConformance(
1962
2149
  cubeA,
1963
2150
  createProtocolEnvelope('append-a5', {
1964
2151
  post_id: '00000000-0000-4000-8000-000000000309',
2152
+ to: 'broadcast',
1965
2153
  message: 'epsilon',
1966
2154
  }),
1967
2155
  );
@@ -2020,9 +2208,8 @@ export async function runAdapterConformance(
2020
2208
  cube,
2021
2209
  createProtocolEnvelope('ack-status-append', {
2022
2210
  post_id: '00000000-0000-4000-8000-000000000310',
2211
+ to: [acknowledgedRecipient.id, claimingRecipient.id],
2023
2212
  message: 'START NOW acknowledgement status fixture',
2024
- visibility: 'direct',
2025
- recipientDroneIds: [acknowledgedRecipient.id, claimingRecipient.id],
2026
2213
  }),
2027
2214
  );
2028
2215
  expectStatus(append, 201, 'Acknowledgement-status fixture append');
@@ -2614,8 +2801,7 @@ export async function runAdapterConformance(
2614
2801
  createProtocolEnvelope('evict-direct-target', {
2615
2802
  message: 'must-not-fan-out',
2616
2803
  post_id: '00000000-0000-4000-8000-000000000310',
2617
- visibility: 'direct',
2618
- recipientDroneIds: [evictedDrone.id],
2804
+ to: [evictedDrone.id],
2619
2805
  }),
2620
2806
  ),
2621
2807
  404,
@@ -2695,12 +2881,6 @@ export async function runAdapterConformance(
2695
2881
  isHumanSeat: true,
2696
2882
  name: 'Human Seat',
2697
2883
  });
2698
- const referencedRole = await environment.admin.createRole(roleContractCube, {
2699
- roleClass: 'worker',
2700
- isHumanSeat: false,
2701
- name: 'Routed Reviewer',
2702
- });
2703
- await environment.admin.referenceRoleFromTaxonomy(roleContractCube, referencedRole);
2704
2884
  const activeRole = await environment.admin.createRole(roleContractCube, {
2705
2885
  roleClass: 'worker',
2706
2886
  isHumanSeat: false,
@@ -2712,7 +2892,6 @@ export async function runAdapterConformance(
2712
2892
  [defaultRole, ErrorCode.DEFAULT_ROLE_REQUIRED, 'default role'],
2713
2893
  [mandatoryRole, ErrorCode.ROLE_REQUIRED, 'mandatory role'],
2714
2894
  [humanRole, ErrorCode.ROLE_REQUIRED, 'human-seat role'],
2715
- [referencedRole, ErrorCode.ROLE_REFERENCED, 'taxonomy-referenced role'],
2716
2895
  [activeRole, ErrorCode.ROLE_IN_USE, 'active-drone role'],
2717
2896
  ] as const;
2718
2897
  for (const [index, [role, code, label]] of refusals.entries()) {
@@ -2805,6 +2984,7 @@ export async function runAdapterConformance(
2805
2984
  roleContractCube,
2806
2985
  createProtocolEnvelope('role-delete-attribution', {
2807
2986
  post_id: '00000000-0000-4000-8000-000000000311',
2987
+ to: 'broadcast',
2808
2988
  message: 'attribution survives',
2809
2989
  }),
2810
2990
  );
@@ -2846,7 +3026,6 @@ export async function runAdapterConformance(
2846
3026
  ErrorCode.ROLE_IN_USE,
2847
3027
  ErrorCode.DEFAULT_ROLE_REQUIRED,
2848
3028
  ErrorCode.ROLE_REQUIRED,
2849
- ErrorCode.ROLE_REFERENCED,
2850
3029
  ],
2851
3030
  in_use_message_actionable: true,
2852
3031
  evicted_drone_retargeted: true,
@@ -3472,6 +3651,7 @@ export async function runAdapterConformance(
3472
3651
  cube,
3473
3652
  createProtocolEnvelope('delete-log', {
3474
3653
  post_id: '00000000-0000-4000-8000-000000000312',
3654
+ to: 'broadcast',
3475
3655
  message: 'deleted with cube',
3476
3656
  }),
3477
3657
  );