@farmslot/protocol 0.74.10 → 0.75.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 (140) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/dist/client-cache/artifact-response.d.ts +15 -0
  3. package/dist/client-cache/artifact-response.d.ts.map +1 -0
  4. package/dist/client-cache/artifact-response.js +103 -0
  5. package/dist/client-cache/artifact-response.js.map +1 -0
  6. package/dist/client-cache/cache.d.ts +6 -1
  7. package/dist/client-cache/cache.d.ts.map +1 -1
  8. package/dist/client-cache/cache.js +207 -33
  9. package/dist/client-cache/cache.js.map +1 -1
  10. package/dist/client-cache/command-method.d.ts +17 -4
  11. package/dist/client-cache/command-method.d.ts.map +1 -1
  12. package/dist/client-cache/command-method.js +221 -1
  13. package/dist/client-cache/command-method.js.map +1 -1
  14. package/dist/client-cache/conformance.d.ts +2 -5
  15. package/dist/client-cache/conformance.d.ts.map +1 -1
  16. package/dist/client-cache/conformance.js +4 -0
  17. package/dist/client-cache/conformance.js.map +1 -1
  18. package/dist/client-cache/content.d.ts +11 -0
  19. package/dist/client-cache/content.d.ts.map +1 -1
  20. package/dist/client-cache/content.js +43 -0
  21. package/dist/client-cache/content.js.map +1 -1
  22. package/dist/client-cache/index.d.ts +5 -2
  23. package/dist/client-cache/index.d.ts.map +1 -1
  24. package/dist/client-cache/index.js +5 -2
  25. package/dist/client-cache/index.js.map +1 -1
  26. package/dist/client-cache/network-cost.d.ts +4 -0
  27. package/dist/client-cache/network-cost.d.ts.map +1 -0
  28. package/dist/client-cache/network-cost.js +24 -0
  29. package/dist/client-cache/network-cost.js.map +1 -0
  30. package/dist/client-cache/prefetch.d.ts +17 -0
  31. package/dist/client-cache/prefetch.d.ts.map +1 -1
  32. package/dist/client-cache/prefetch.js +110 -47
  33. package/dist/client-cache/prefetch.js.map +1 -1
  34. package/dist/client-cache/read-stored.d.ts +7 -0
  35. package/dist/client-cache/read-stored.d.ts.map +1 -0
  36. package/dist/client-cache/read-stored.js +18 -0
  37. package/dist/client-cache/read-stored.js.map +1 -0
  38. package/dist/client-cache/registry.d.ts +309 -16
  39. package/dist/client-cache/registry.d.ts.map +1 -1
  40. package/dist/client-cache/registry.js +422 -27
  41. package/dist/client-cache/registry.js.map +1 -1
  42. package/dist/client-cache/run-details.d.ts +29 -0
  43. package/dist/client-cache/run-details.d.ts.map +1 -0
  44. package/dist/client-cache/run-details.js +145 -0
  45. package/dist/client-cache/run-details.js.map +1 -0
  46. package/dist/client-cache/run-list-versions.d.ts +2 -0
  47. package/dist/client-cache/run-list-versions.d.ts.map +1 -1
  48. package/dist/client-cache/run-list-versions.js +9 -0
  49. package/dist/client-cache/run-list-versions.js.map +1 -1
  50. package/dist/client-cache/store.d.ts +6 -0
  51. package/dist/client-cache/store.d.ts.map +1 -1
  52. package/dist/client-cache/store.js +25 -0
  53. package/dist/client-cache/store.js.map +1 -1
  54. package/dist/client-cache/transport.d.ts +8 -1
  55. package/dist/client-cache/transport.d.ts.map +1 -1
  56. package/dist/client-cache/transport.js +8 -0
  57. package/dist/client-cache/transport.js.map +1 -1
  58. package/dist/client-cache/types.d.ts +11 -1
  59. package/dist/client-cache/types.d.ts.map +1 -1
  60. package/dist/contracts/agents.d.ts +2 -0
  61. package/dist/contracts/agents.d.ts.map +1 -1
  62. package/dist/contracts/agents.js.map +1 -1
  63. package/dist/contracts/config.d.ts +10 -0
  64. package/dist/contracts/config.d.ts.map +1 -1
  65. package/dist/contracts/config.js +7 -0
  66. package/dist/contracts/config.js.map +1 -1
  67. package/dist/contracts/dispatch.d.ts +18 -0
  68. package/dist/contracts/dispatch.d.ts.map +1 -1
  69. package/dist/contracts/run-lifecycle-view.d.ts +9 -0
  70. package/dist/contracts/run-lifecycle-view.d.ts.map +1 -1
  71. package/dist/contracts/run-lifecycle-view.js +8 -0
  72. package/dist/contracts/run-lifecycle-view.js.map +1 -1
  73. package/dist/contracts/runs.d.ts +76 -7
  74. package/dist/contracts/runs.d.ts.map +1 -1
  75. package/dist/contracts/runs.js +33 -2
  76. package/dist/contracts/runs.js.map +1 -1
  77. package/dist/contracts/slot-recovery.d.ts +11 -0
  78. package/dist/contracts/slot-recovery.d.ts.map +1 -1
  79. package/dist/contracts/slot-recovery.js +11 -1
  80. package/dist/contracts/slot-recovery.js.map +1 -1
  81. package/dist/contracts/slots.d.ts +17 -0
  82. package/dist/contracts/slots.d.ts.map +1 -1
  83. package/dist/index.d.ts +3 -0
  84. package/dist/index.d.ts.map +1 -1
  85. package/dist/index.js +3 -0
  86. package/dist/index.js.map +1 -1
  87. package/dist/recipe/recording.d.ts +1 -1
  88. package/dist/recipe/recording.d.ts.map +1 -1
  89. package/dist/recipe/recording.js +2 -2
  90. package/dist/recipe/recording.js.map +1 -1
  91. package/dist/rpc/dispatch.d.ts +8 -0
  92. package/dist/rpc/dispatch.d.ts.map +1 -1
  93. package/dist/rpc/dispatch.js +8 -0
  94. package/dist/rpc/dispatch.js.map +1 -1
  95. package/dist/rpc/fleet.d.ts +3 -1
  96. package/dist/rpc/fleet.d.ts.map +1 -1
  97. package/dist/rpc/fleet.js.map +1 -1
  98. package/dist/rpc/native-session.d.ts +11 -0
  99. package/dist/rpc/native-session.d.ts.map +1 -1
  100. package/dist/rpc/native-session.js +9 -0
  101. package/dist/rpc/native-session.js.map +1 -1
  102. package/dist/rpc/run.d.ts +4 -0
  103. package/dist/rpc/run.d.ts.map +1 -1
  104. package/dist/rpc/run.js.map +1 -1
  105. package/dist/rpc/runner-models.d.ts +14 -3
  106. package/dist/rpc/runner-models.d.ts.map +1 -1
  107. package/dist/rpc/runner-models.js +37 -13
  108. package/dist/rpc/runner-models.js.map +1 -1
  109. package/dist/rpc/slot.d.ts +3 -2
  110. package/dist/rpc/slot.d.ts.map +1 -1
  111. package/dist/rpc/slot.js.map +1 -1
  112. package/dist/runs/list-trim.d.ts +13 -0
  113. package/dist/runs/list-trim.d.ts.map +1 -0
  114. package/dist/runs/list-trim.js +71 -0
  115. package/dist/runs/list-trim.js.map +1 -0
  116. package/dist/runs/list-version.d.ts +4 -0
  117. package/dist/runs/list-version.d.ts.map +1 -0
  118. package/dist/runs/list-version.js +9 -0
  119. package/dist/runs/list-version.js.map +1 -0
  120. package/dist/runs/review-chain.d.ts.map +1 -1
  121. package/dist/runs/review-chain.js +2 -1
  122. package/dist/runs/review-chain.js.map +1 -1
  123. package/dist/runs/run-family-groups.d.ts.map +1 -1
  124. package/dist/runs/run-family-groups.js +5 -4
  125. package/dist/runs/run-family-groups.js.map +1 -1
  126. package/dist/runs/run-list-view.d.ts.map +1 -1
  127. package/dist/runs/run-list-view.js +2 -1
  128. package/dist/runs/run-list-view.js.map +1 -1
  129. package/dist/slots/tracking-branch.d.ts +7 -0
  130. package/dist/slots/tracking-branch.d.ts.map +1 -1
  131. package/dist/slots/tracking-branch.js.map +1 -1
  132. package/dist/text-order.d.ts +7 -0
  133. package/dist/text-order.d.ts.map +1 -0
  134. package/dist/text-order.js +7 -0
  135. package/dist/text-order.js.map +1 -0
  136. package/dist/version.d.ts +1 -1
  137. package/dist/version.d.ts.map +1 -1
  138. package/dist/version.js +1 -1
  139. package/dist/version.js.map +1 -1
  140. package/package.json +1 -1
@@ -1,12 +1,22 @@
1
1
  import { providerAccountsDependencies, providerAccountsObservationParams, providerAccountsStoredData, } from '../contracts/provider-accounts.js';
2
+ import { jiraTicketKey } from '../rpc/dispatch.js';
2
3
  import { prForSlotObservationParams, prForSlotStoredData, prReviewCommentsObservationParams, prReviewCommentsStoredData, prStatusObservationParams, prStatusStoredData, } from '../rpc/pr-observations.js';
3
4
  import { Methods } from '../rpc/registry.js';
4
5
  import { runnerModelCatalogObservationParams, runnerModelCatalogResourceKey, runnerModelCatalogStoredData, runnerVisibleModelsObservationParams, runnerVisibleModelsStoredData, } from '../rpc/runner-models.js';
5
- import { analyticsParams, assessmentDependencies, assessmentHistoryParams, copilotRuntimeKey, domainParams, idParams, observerEvidenceParams, prAutomationDependencies, sessionContextParams, triageParams, } from './d07-domains.js';
6
+ import { analyticsParams, assessmentDependencies, assessmentHistoryParams, copilotRuntimeKey, domainId, domainParams, idParams, observerEvidenceParams, prAutomationDependencies, sessionContextParams, triageParams, } from './d07-domains.js';
6
7
  import { canonicalResourceJson } from './keys.js';
7
8
  import { nativeHistoryParams, nativeObservationDependencies } from './native-history.js';
8
9
  const mb = 1024 * 1024;
9
10
  export const UPSTREAM_QUERY_MAX_BYTES = 2 * mb;
11
+ /**
12
+ * Every listed run's `run.get` details: about 30 MB for a 137-run farm in 2026-11, so twice that
13
+ * with headroom. Background sync stops before it would exceed this, so it never evicts its own runs.
14
+ */
15
+ export const RUN_DETAIL_STORE_BYTES = 64 * mb;
16
+ /** A read keyed by its parameters keeps its most recently observed results up to these bytes. */
17
+ function keptUpTo(maxBytes) {
18
+ return { maxEntries: Number.MAX_SAFE_INTEGER, maxBytes };
19
+ }
10
20
  function requiredId(params, field) {
11
21
  const value = params && typeof params === 'object' ? Reflect.get(params, field) : undefined;
12
22
  if (typeof value !== 'string' || !value)
@@ -30,6 +40,13 @@ function roadmapListObservationParams(params) {
30
40
  delete observation.search;
31
41
  return observation;
32
42
  }
43
+ /** Execution template ids are `<flow>/<name>`; every other selector is one segment. */
44
+ function configurationSelector(key, item) {
45
+ if (typeof item !== 'string' || !item || item.includes('\\'))
46
+ return false;
47
+ const segments = key === 'executionTemplateId' ? item.split('/') : [item];
48
+ return segments.every((segment) => segment && !segment.includes('/') && segment !== '.' && segment !== '..');
49
+ }
33
50
  function configurationParams(params, allowed, required = []) {
34
51
  const input = params ?? {};
35
52
  if (typeof input !== 'object' || Array.isArray(input))
@@ -44,11 +61,7 @@ function configurationParams(params, allowed, required = []) {
44
61
  if (typeof item !== 'boolean')
45
62
  throw new Error('unfiltered must be a boolean');
46
63
  }
47
- else if (typeof item !== 'string' ||
48
- !item ||
49
- /[/\\]/.test(item) ||
50
- item === '.' ||
51
- item === '..') {
64
+ else if (!configurationSelector(key, item)) {
52
65
  throw new Error(`Invalid configuration selector: ${key}`);
53
66
  }
54
67
  }
@@ -69,13 +82,33 @@ function configurationDependencies(params) {
69
82
  ];
70
83
  }
71
84
  const configurationDefinition = {
72
- persisted: false,
85
+ persisted: true,
73
86
  maxBytes: 2 * mb,
87
+ retention: keptUpTo(8 * mb),
74
88
  live: true,
75
89
  requiresObservedRead: true,
76
90
  normalizeParams: (params) => configurationParams(params, []),
77
91
  dependencies: configurationDependencies,
78
92
  };
93
+ function dispatchObservationParams(params, allowed) {
94
+ const value = domainParams(params, allowed);
95
+ for (const [key, item] of Object.entries(value)) {
96
+ if (key === 'machines') {
97
+ if (!Array.isArray(item) || item.some((machine) => typeof machine !== 'string'))
98
+ throw new Error('Dispatch machines must be strings');
99
+ value[key] = [...new Set(item)].sort();
100
+ }
101
+ else if (key === 'forceRefresh' || key === 'skipPrepare') {
102
+ if (typeof item !== 'boolean')
103
+ throw new Error(`Dispatch ${key} must be a boolean`);
104
+ }
105
+ else if ((key === 'flowType' || key === 'variant') && item === null)
106
+ delete value[key];
107
+ else if (typeof item !== 'string')
108
+ throw new Error(`Dispatch ${key} must be a string`);
109
+ }
110
+ return value;
111
+ }
79
112
  function workerInventoryParams(params) {
80
113
  if (params == null)
81
114
  return { includeDisconnected: true };
@@ -104,6 +137,13 @@ function workerInventoryParams(params) {
104
137
  ...(machines.length ? { machines } : {}),
105
138
  };
106
139
  }
140
+ function validateWorkspacePath(value) {
141
+ if (value !== undefined &&
142
+ (typeof value !== 'string' ||
143
+ value.startsWith('/') ||
144
+ value.replace(/\\/g, '/').split('/').includes('..')))
145
+ throw new Error('Workspace path must stay relative');
146
+ }
107
147
  function workspaceParams(params) {
108
148
  if (!params || typeof params !== 'object' || Array.isArray(params))
109
149
  throw new Error('Workspace query requires parameters');
@@ -155,11 +195,7 @@ function workspaceParams(params) {
155
195
  requiredId(worker, field);
156
196
  }
157
197
  }
158
- if (value.path !== undefined &&
159
- (typeof value.path !== 'string' ||
160
- value.path.startsWith('/') ||
161
- value.path.replace(/\\/g, '/').split('/').includes('..')))
162
- throw new Error('Workspace path must stay relative');
198
+ validateWorkspacePath(value.path);
163
199
  if (value.includeUntracked !== undefined && typeof value.includeUntracked !== 'boolean')
164
200
  throw new Error('includeUntracked must be a boolean');
165
201
  if (value.includeUntracked && value.target !== 'worktree')
@@ -215,8 +251,9 @@ const workspaceDefinition = {
215
251
  dependencies: workspaceDependencies,
216
252
  };
217
253
  const domainDefinition = {
218
- persisted: false,
254
+ persisted: true,
219
255
  maxBytes: 2 * mb,
256
+ retention: keptUpTo(8 * mb),
220
257
  live: true,
221
258
  requiresObservedRead: true,
222
259
  normalizeParams: (params) => domainParams(params, []),
@@ -405,6 +442,28 @@ export function upstreamSourceObservation(data) {
405
442
  : {}),
406
443
  };
407
444
  }
445
+ function machineParams(params, extra = []) {
446
+ const value = domainParams(params, ['machine', 'machines', ...extra]);
447
+ const selectors = (one, many) => {
448
+ const list = value[many] ?? [];
449
+ if (!Array.isArray(list))
450
+ throw new Error(`${many} must be a list`);
451
+ const all = value[one] === undefined ? list : [value[one], ...list];
452
+ return [...new Set(all.map((entry) => domainId(entry, one)))].sort();
453
+ };
454
+ const selected = selectors('machine', 'machines');
455
+ const scoped = selectors('project', 'projects');
456
+ return {
457
+ ...(selected.length ? { machines: selected } : {}),
458
+ ...(scoped.length ? { projects: scoped } : {}),
459
+ };
460
+ }
461
+ function chatHistoryParams(params) {
462
+ const { limit, ...session } = domainParams(params, ['sessionId', 'limit']);
463
+ if (limit !== undefined && (!Number.isSafeInteger(limit) || Number(limit) < 1))
464
+ throw new Error('Invalid chat history limit');
465
+ return { ...sessionContextParams(session), ...(limit === undefined ? {} : { limit }) };
466
+ }
408
467
  /** Closed to runtime registration. Each migration changes its owning definition here. */
409
468
  export const RESOURCE_QUERY_DEFINITIONS = {
410
469
  [Methods.GATEWAY_STATUS]: {
@@ -651,6 +710,56 @@ export const RESOURCE_QUERY_DEFINITIONS = {
651
710
  { ...copilotRuntimeKey, sessionId: String(sessionContextParams(params).sessionId) },
652
711
  ],
653
712
  },
713
+ [Methods.DISPATCH_CANDIDATES]: {
714
+ persisted: true,
715
+ maxBytes: 2 * mb,
716
+ retention: { maxEntries: 50, maxBytes: 8 * mb },
717
+ timeoutMs: 60_000,
718
+ live: true,
719
+ normalizeParams: (params) => dispatchObservationParams(params, [
720
+ 'project',
721
+ 'flowType',
722
+ 'machines',
723
+ 'targetBranch',
724
+ 'ticketOrPr',
725
+ 'app',
726
+ 'prepareProfile',
727
+ 'skipPrepare',
728
+ 'forceRefresh',
729
+ 'lane',
730
+ 'familyId',
731
+ 'variant',
732
+ 'runner',
733
+ 'model',
734
+ ]),
735
+ dependencies: (params) => {
736
+ const runner = params && typeof params === 'object' ? Reflect.get(params, 'runner') : undefined;
737
+ return [
738
+ { family: 'slots', scope: 'farm' },
739
+ { family: 'node', scope: 'farm' },
740
+ { family: 'capabilities' },
741
+ { family: 'runs', scope: 'farm' },
742
+ ...configurationDependencies(params),
743
+ ...(typeof runner === 'string' ? [runnerModelCatalogResourceKey({ runner })] : []),
744
+ ];
745
+ },
746
+ },
747
+ [Methods.DISPATCH_MATCH_PROJECT]: {
748
+ persisted: true,
749
+ maxBytes: 1 * mb,
750
+ retention: { maxEntries: 100, maxBytes: 2 * mb },
751
+ live: true,
752
+ normalizeParams: (params) => {
753
+ const value = dispatchObservationParams(params, ['ticketOrPr', 'flowType']);
754
+ requiredId(value, 'ticketOrPr');
755
+ const ticket = String(value.ticketOrPr).trim();
756
+ value.ticketOrPr = ticket;
757
+ if (jiraTicketKey(ticket))
758
+ delete value.flowType;
759
+ return value;
760
+ },
761
+ dependencies: configurationDependencies,
762
+ },
654
763
  [Methods.CONFIG_PROJECTS]: {
655
764
  ...configurationDefinition,
656
765
  persisted: true,
@@ -721,7 +830,7 @@ export const RESOURCE_QUERY_DEFINITIONS = {
721
830
  dependencies: (params, nativeReaderId) => nativeObservationDependencies(Methods.NATIVE_SESSION_LIST, params, nativeReaderId ?? ''),
722
831
  },
723
832
  [Methods.NATIVE_SESSION_CATALOG]: {
724
- persisted: false,
833
+ persisted: true,
725
834
  maxBytes: 2 * mb,
726
835
  retention: { maxEntries: 1, maxBytes: 2 * mb },
727
836
  live: true,
@@ -737,7 +846,7 @@ export const RESOURCE_QUERY_DEFINITIONS = {
737
846
  dependencies: (params, nativeReaderId) => nativeObservationDependencies(Methods.NATIVE_PROFILE_LIST, params, nativeReaderId ?? ''),
738
847
  },
739
848
  [Methods.NATIVE_PROFILE_STATUS]: {
740
- persisted: false,
849
+ persisted: true,
741
850
  maxBytes: 2 * mb,
742
851
  retention: { maxEntries: 10, maxBytes: 2 * mb },
743
852
  live: true,
@@ -756,8 +865,9 @@ export const RESOURCE_QUERY_DEFINITIONS = {
756
865
  [Methods.NATIVE_SESSION_WORKSPACE_DIFF]: { ...workspaceDefinition, maxBytes: 5 * mb },
757
866
  [Methods.TMUX_WORKER_LIST]: {
758
867
  requiresObservedRead: true,
759
- persisted: false,
868
+ persisted: true,
760
869
  maxBytes: 2 * mb,
870
+ retention: keptUpTo(4 * mb),
761
871
  timeoutMs: 10_000,
762
872
  live: true,
763
873
  normalizeParams: workerInventoryParams,
@@ -786,8 +896,9 @@ export const RESOURCE_QUERY_DEFINITIONS = {
786
896
  dependencies: () => [{ family: 'planning', collection: 'work-graphs' }],
787
897
  },
788
898
  [Methods.WORK_GRAPH_GET]: {
789
- persisted: false,
899
+ persisted: true,
790
900
  maxBytes: 2 * mb,
901
+ retention: keptUpTo(16 * mb),
791
902
  live: true,
792
903
  normalizeParams: planningObservationParams,
793
904
  dependencies: (params) => [
@@ -819,8 +930,9 @@ export const RESOURCE_QUERY_DEFINITIONS = {
819
930
  ],
820
931
  },
821
932
  [Methods.ROADMAP_GET]: {
822
- persisted: false,
933
+ persisted: true,
823
934
  maxBytes: 2 * mb,
935
+ retention: keptUpTo(16 * mb),
824
936
  live: true,
825
937
  normalizeParams: planningObservationParams,
826
938
  dependencies: (params) => [
@@ -834,6 +946,7 @@ export const RESOURCE_QUERY_DEFINITIONS = {
834
946
  [Methods.SOURCES_STATUS]: {
835
947
  persisted: true,
836
948
  maxBytes: 2 * mb,
949
+ retention: { maxEntries: 1, maxBytes: 2 * mb },
837
950
  timeoutMs: 120_000,
838
951
  live: true,
839
952
  dependencies: () => [{ family: 'sources', scope: 'farm' }],
@@ -847,10 +960,11 @@ export const RESOURCE_QUERY_DEFINITIONS = {
847
960
  // Every write to any run changes the farm runs key, several times a minute on a busy farm.
848
961
  rereadIntervalMs: { runs: 30_000 },
849
962
  },
963
+ // Background sync stores every listed run's details (ADR-071 Amendment 2), so bytes bound it.
850
964
  [Methods.RUN_GET]: {
851
965
  persisted: true,
852
966
  maxBytes: 20 * mb,
853
- retention: { maxEntries: 50, maxBytes: 20 * mb },
967
+ retention: keptUpTo(RUN_DETAIL_STORE_BYTES),
854
968
  live: true,
855
969
  dependencies: (params) => [
856
970
  { family: 'run', runId: requiredId(params, 'runId') },
@@ -866,8 +980,9 @@ export const RESOURCE_QUERY_DEFINITIONS = {
866
980
  dependencies: () => [{ family: 'decisions', scope: 'farm' }],
867
981
  },
868
982
  [Methods.FAMILY_OBSERVABILITY_GET]: {
869
- persisted: false,
983
+ persisted: true,
870
984
  maxBytes: 2 * mb,
985
+ retention: keptUpTo(16 * mb),
871
986
  live: true,
872
987
  dependencies: (params) => [
873
988
  { family: 'family', familyId: requiredId(params, 'familyId') },
@@ -876,8 +991,9 @@ export const RESOURCE_QUERY_DEFINITIONS = {
876
991
  ],
877
992
  },
878
993
  [Methods.RUN_RECIPE_RUNS_FOR_RUN]: {
879
- persisted: false,
994
+ persisted: true,
880
995
  maxBytes: 2 * mb,
996
+ retention: keptUpTo(32 * mb),
881
997
  timeoutMs: 60_000,
882
998
  live: true,
883
999
  dependencies: (params) => [
@@ -886,8 +1002,9 @@ export const RESOURCE_QUERY_DEFINITIONS = {
886
1002
  ],
887
1003
  },
888
1004
  [Methods.RUN_SLOT_HISTORY]: {
889
- persisted: false,
1005
+ persisted: true,
890
1006
  maxBytes: 2 * mb,
1007
+ retention: keptUpTo(4 * mb),
891
1008
  live: true,
892
1009
  dependencies: () => [
893
1010
  { family: 'runs', scope: 'farm' },
@@ -895,8 +1012,9 @@ export const RESOURCE_QUERY_DEFINITIONS = {
895
1012
  ],
896
1013
  },
897
1014
  [Methods.RUN_FOR_SLOT]: {
898
- persisted: false,
1015
+ persisted: true,
899
1016
  maxBytes: 20 * mb,
1017
+ retention: keptUpTo(40 * mb),
900
1018
  live: true,
901
1019
  dependencies: (params) => [
902
1020
  { family: 'runs', scope: 'farm' },
@@ -904,8 +1022,9 @@ export const RESOURCE_QUERY_DEFINITIONS = {
904
1022
  ],
905
1023
  },
906
1024
  [Methods.RUN_RECIPE_RUNS_FOR_SLOT]: {
907
- persisted: false,
1025
+ persisted: true,
908
1026
  maxBytes: 2 * mb,
1027
+ retention: keptUpTo(16 * mb),
909
1028
  timeoutMs: 60_000,
910
1029
  live: true,
911
1030
  dependencies: (params) => [
@@ -914,8 +1033,9 @@ export const RESOURCE_QUERY_DEFINITIONS = {
914
1033
  ],
915
1034
  },
916
1035
  [Methods.RUN_TAGS_LIST]: {
917
- persisted: false,
1036
+ persisted: true,
918
1037
  maxBytes: 2 * mb,
1038
+ retention: keptUpTo(2 * mb),
919
1039
  live: true,
920
1040
  dependencies: () => [{ family: 'runs', scope: 'farm' }],
921
1041
  },
@@ -977,6 +1097,247 @@ export const RESOURCE_QUERY_DEFINITIONS = {
977
1097
  return [{ family: 'slot', slotId: requiredId(params, 'slotId') }];
978
1098
  },
979
1099
  },
1100
+ // ADR-071 Amendment 2: reads that screens used to send straight to the gateway. A read is
1101
+ // `live` only where every writer of its state publishes its keys; the others show their stored
1102
+ // result and reread when opened.
1103
+ [Methods.RUNTIME_POSTURE_STATUS]: {
1104
+ persisted: true,
1105
+ maxBytes: 1 * mb,
1106
+ retention: keptUpTo(16 * mb),
1107
+ live: true,
1108
+ normalizeParams: (params) => idParams(params, ['runId']),
1109
+ dependencies: (params) => [
1110
+ { family: 'run', runId: requiredId(params, 'runId') },
1111
+ { family: 'capabilities' },
1112
+ { family: 'sources', scope: 'farm' },
1113
+ ],
1114
+ },
1115
+ [Methods.RESOURCE_LIST]: {
1116
+ persisted: true,
1117
+ maxBytes: 1 * mb,
1118
+ retention: keptUpTo(16 * mb),
1119
+ live: true,
1120
+ normalizeParams: (params) => idParams(params, ['slotId']),
1121
+ dependencies: (params) => [
1122
+ { family: 'slot', slotId: requiredId(params, 'slotId') },
1123
+ { family: 'configuration', scope: 'farm' },
1124
+ { family: 'sources', scope: 'farm' },
1125
+ ],
1126
+ },
1127
+ // Probes slots and asks nodes for their panes, so changes never reread it on their own.
1128
+ [Methods.RESOURCE_PRESSURE_SNAPSHOT]: {
1129
+ persisted: true,
1130
+ maxBytes: 2 * mb,
1131
+ retention: keptUpTo(8 * mb),
1132
+ live: false,
1133
+ normalizeParams: (params) => machineParams(params, ['project', 'projects']),
1134
+ dependencies: () => [],
1135
+ },
1136
+ [Methods.RESOURCE_PRESSURE_HISTORY]: {
1137
+ persisted: true,
1138
+ maxBytes: 1 * mb,
1139
+ retention: keptUpTo(8 * mb),
1140
+ live: true,
1141
+ normalizeParams: (params) => machineParams(params),
1142
+ dependencies: (params) => {
1143
+ const machines = (machineParams(params).machines ?? []);
1144
+ // Every node sample advances the farm slots key, which covers an unfiltered read.
1145
+ return machines.length
1146
+ ? machines.map((nodeId) => ({ family: 'pressure', nodeId }))
1147
+ : [{ family: 'slots', scope: 'farm' }];
1148
+ },
1149
+ },
1150
+ // Runs simctl and adb on a cache miss; `refresh` stays an imperative probe.
1151
+ [Methods.RESOURCE_DEVICE_INVENTORY]: {
1152
+ persisted: true,
1153
+ maxBytes: 1 * mb,
1154
+ retention: keptUpTo(8 * mb),
1155
+ live: false,
1156
+ normalizeParams: (params) => {
1157
+ const { refresh, ...observation } = domainParams(params, ['slotId', 'refresh']);
1158
+ if (refresh !== undefined && refresh !== false)
1159
+ throw new Error('Device inventory observations cannot refresh');
1160
+ return idParams(observation, ['slotId']);
1161
+ },
1162
+ dependencies: () => [],
1163
+ },
1164
+ [Methods.SLOT_ACTION_LIST]: {
1165
+ persisted: true,
1166
+ maxBytes: 1 * mb,
1167
+ retention: keptUpTo(8 * mb),
1168
+ live: true,
1169
+ normalizeParams: (params) => {
1170
+ const value = domainParams(params, ['slotId', 'placement']);
1171
+ domainId(value.slotId, 'slotId');
1172
+ if (value.placement !== undefined)
1173
+ domainId(value.placement, 'placement');
1174
+ return value;
1175
+ },
1176
+ dependencies: (params) => [
1177
+ { family: 'slot', slotId: requiredId(params, 'slotId') },
1178
+ { family: 'configuration', scope: 'farm' },
1179
+ { family: 'sources', scope: 'farm' },
1180
+ ],
1181
+ },
1182
+ [Methods.GIT_FILES]: {
1183
+ persisted: true,
1184
+ maxBytes: 10 * mb,
1185
+ retention: { maxEntries: 8, maxBytes: 40 * mb },
1186
+ live: false,
1187
+ normalizeParams: (params) => idParams(params, ['slotId']),
1188
+ dependencies: () => [],
1189
+ },
1190
+ // Spec files are also edited outside the gateway, and nothing watches them yet.
1191
+ [Methods.BACKLOG_SPEC_GET]: {
1192
+ persisted: true,
1193
+ maxBytes: 2 * mb,
1194
+ retention: keptUpTo(16 * mb),
1195
+ live: false,
1196
+ normalizeParams: (params) => idParams(params, ['itemId']),
1197
+ dependencies: () => [{ family: 'planning', collection: 'backlog' }],
1198
+ },
1199
+ // Whether the refinement's tmux session exists is not observed.
1200
+ [Methods.BACKLOG_REFINEMENT_SESSION_GET]: {
1201
+ persisted: true,
1202
+ maxBytes: 256 * 1024,
1203
+ retention: keptUpTo(2 * mb),
1204
+ live: false,
1205
+ normalizeParams: (params) => idParams(params, ['itemId']),
1206
+ dependencies: () => [{ family: 'planning', collection: 'backlog' }],
1207
+ },
1208
+ [Methods.ROADMAP_REFINEMENT_SESSION_GET]: {
1209
+ persisted: true,
1210
+ maxBytes: 256 * 1024,
1211
+ retention: keptUpTo(2 * mb),
1212
+ live: false,
1213
+ normalizeParams: (params) => idParams(params, ['itemId']),
1214
+ dependencies: (params) => [
1215
+ { family: 'planning', collection: 'roadmap' },
1216
+ { family: 'planning', collection: 'roadmap', itemId: requiredId(params, 'itemId') },
1217
+ ],
1218
+ },
1219
+ [Methods.CHAT_HISTORY]: {
1220
+ persisted: true,
1221
+ maxBytes: 5 * mb,
1222
+ retention: keptUpTo(20 * mb),
1223
+ live: true,
1224
+ normalizeParams: chatHistoryParams,
1225
+ dependencies: (params) => [
1226
+ { ...copilotRuntimeKey, sessionId: String(chatHistoryParams(params).sessionId) },
1227
+ ],
1228
+ },
1229
+ // Creating, pinning and saving a session publish no key yet.
1230
+ [Methods.CHAT_SESSIONS]: {
1231
+ persisted: true,
1232
+ maxBytes: 1 * mb,
1233
+ retention: keptUpTo(1 * mb),
1234
+ live: false,
1235
+ normalizeParams: (params) => domainParams(params, []),
1236
+ dependencies: () => [copilotRuntimeKey],
1237
+ },
1238
+ // Pending confirmations expire, and issuing or confirming one publishes no key yet.
1239
+ [Methods.CHAT_LIST_ACTIONS]: {
1240
+ persisted: true,
1241
+ maxBytes: 256 * 1024,
1242
+ retention: keptUpTo(2 * mb),
1243
+ live: false,
1244
+ normalizeParams: sessionContextParams,
1245
+ dependencies: () => [],
1246
+ },
1247
+ // Audit records are appended to files without publishing a key.
1248
+ [Methods.INTELLIGENCE_ACTIONS_SUMMARY]: {
1249
+ persisted: true,
1250
+ maxBytes: 2 * mb,
1251
+ retention: keptUpTo(8 * mb),
1252
+ live: false,
1253
+ normalizeParams: (params) => {
1254
+ const value = domainParams(params, ['limit', 'dateFrom', 'dateTo']);
1255
+ if (value.limit !== undefined && !Number.isSafeInteger(value.limit))
1256
+ throw new Error('Invalid intelligence page size');
1257
+ for (const field of ['dateFrom', 'dateTo'])
1258
+ if (value[field] !== undefined && Number.isNaN(Date.parse(String(value[field]))))
1259
+ throw new Error(`Invalid intelligence selector: ${field}`);
1260
+ return value;
1261
+ },
1262
+ dependencies: () => [],
1263
+ },
1264
+ // Setting a cap publishes no key yet.
1265
+ [Methods.EVAL_SUITE_CAP_GET]: {
1266
+ timeoutMs: 30_000,
1267
+ persisted: true,
1268
+ maxBytes: 256 * 1024,
1269
+ retention: keptUpTo(2 * mb),
1270
+ live: false,
1271
+ normalizeParams: (params) => idParams(params, ['capGroupId']),
1272
+ dependencies: () => [],
1273
+ },
1274
+ [Methods.EVAL_TRIAL_RESULT_GET]: {
1275
+ timeoutMs: 30_000,
1276
+ persisted: true,
1277
+ maxBytes: 20 * mb,
1278
+ retention: keptUpTo(40 * mb),
1279
+ live: true,
1280
+ normalizeParams: (params) => idParams(params, ['runId']),
1281
+ dependencies: (params) => [
1282
+ { family: 'run', runId: requiredId(params, 'runId') },
1283
+ { family: 'artifacts', runId: requiredId(params, 'runId') },
1284
+ ],
1285
+ },
1286
+ [Methods.FINETUNE_INDEX]: {
1287
+ persisted: true,
1288
+ maxBytes: 2 * mb,
1289
+ retention: keptUpTo(8 * mb),
1290
+ live: true,
1291
+ normalizeParams: (params) => {
1292
+ const value = domainParams(params, ['project']);
1293
+ if (value.project !== undefined)
1294
+ domainId(value.project, 'project');
1295
+ return value;
1296
+ },
1297
+ rereadIntervalMs: { runs: 30_000 },
1298
+ dependencies: () => [{ family: 'runs', scope: 'farm' }],
1299
+ },
1300
+ // Its pressure section probes slots like `resource.pressure.snapshot`.
1301
+ [Methods.MACHINE_PAUSE_STATUS]: {
1302
+ persisted: true,
1303
+ maxBytes: 2 * mb,
1304
+ retention: keptUpTo(8 * mb),
1305
+ live: false,
1306
+ normalizeParams: (params) => idParams(params, ['machine']),
1307
+ dependencies: () => [],
1308
+ },
1309
+ // Toggling admission writes its control file without publishing a key.
1310
+ [Methods.DISPATCH_PRESSURE_ADMISSION_GET]: {
1311
+ persisted: true,
1312
+ maxBytes: 256 * 1024,
1313
+ retention: { maxEntries: 1, maxBytes: 256 * 1024 },
1314
+ live: false,
1315
+ normalizeParams: (params) => domainParams(params, []),
1316
+ dependencies: () => [],
1317
+ },
1318
+ // One turn's diff of one file does not change; a pruned checkpoint reads NOT_FOUND.
1319
+ [Methods.NATIVE_SESSION_TURN_DIFF]: {
1320
+ persisted: true,
1321
+ maxBytes: 5 * mb,
1322
+ retention: { maxEntries: 50, maxBytes: 20 * mb },
1323
+ live: false,
1324
+ normalizeParams: (params) => {
1325
+ const { sequence, path, ...target } = domainParams(params, [
1326
+ 'sessionId',
1327
+ 'executionNodeId',
1328
+ 'worker',
1329
+ 'sequence',
1330
+ 'path',
1331
+ ]);
1332
+ if (!Number.isSafeInteger(sequence) || Number(sequence) < 0)
1333
+ throw new Error('Invalid native turn sequence');
1334
+ if (typeof path !== 'string' || !path)
1335
+ throw new Error('Native turn diff requires a path');
1336
+ validateWorkspacePath(path);
1337
+ return { ...nativeHistoryParams(target), sequence, path };
1338
+ },
1339
+ dependencies: () => [],
1340
+ },
980
1341
  };
981
1342
  /** Advertise only collectors whose owning read and notification contract are enabled. */
982
1343
  export function resourceCollectorReadMethods() {
@@ -1002,10 +1363,44 @@ export function resourceReadTimeout(method) {
1002
1363
  return definition.timeoutMs;
1003
1364
  }
1004
1365
  /** Experimental, portable query factory; mutations and streams are never registered here. */
1005
- export function resourceQuery(method, params = {}, nativeReaderId) {
1366
+ function readDefinition(method, params) {
1006
1367
  const definition = RESOURCE_QUERY_DEFINITIONS[method];
1007
1368
  if (!definition)
1008
1369
  throw new Error(`Unregistered resource read: ${method}`);
1370
+ if ((method !== Methods.GIT_DIFF && method !== Methods.GIT_SHOW) ||
1371
+ !params ||
1372
+ typeof params !== 'object' ||
1373
+ !Reflect.get(params, 'runId') ||
1374
+ Reflect.get(params, 'slotId') ||
1375
+ Reflect.get(params, 'sessionId'))
1376
+ return definition;
1377
+ // A slotless review reads exact retained commits, not a mutable workspace observation.
1378
+ return {
1379
+ ...definition,
1380
+ live: false,
1381
+ requiresObservedRead: false,
1382
+ requiresWorkspaceRead: false,
1383
+ normalizeParams(input) {
1384
+ const value = domainParams(input, method === Methods.GIT_SHOW
1385
+ ? ['slotId', 'runId', 'ref', 'path']
1386
+ : ['slotId', 'runId', 'base', 'head', 'path', 'oldPath']);
1387
+ requiredId(value, 'runId');
1388
+ for (const field of method === Methods.GIT_SHOW ? ['ref', 'path'] : ['base', 'head'])
1389
+ requiredId(value, field);
1390
+ validateWorkspacePath(value.path);
1391
+ validateWorkspacePath(value.oldPath);
1392
+ return { ...value, slotId: '' };
1393
+ },
1394
+ dependencies: () => [],
1395
+ retentionGroups: (value) => [`run:${requiredId(value, 'runId')}`],
1396
+ };
1397
+ }
1398
+ /** Snapshot reads use the ordinary RPC contract, including on gateways predating registration. */
1399
+ export function resourceReadIsLive(method, params) {
1400
+ return readDefinition(method, params).live;
1401
+ }
1402
+ export function resourceQuery(method, params = {}, nativeReaderId) {
1403
+ const definition = readDefinition(method, params);
1009
1404
  const canonical = canonicalResourceJson(definition.normalizeParams ? definition.normalizeParams(params) : (params ?? {}));
1010
1405
  const normalized = JSON.parse(canonical);
1011
1406
  return {
@@ -1038,7 +1433,7 @@ export function resourceQuery(method, params = {}, nativeReaderId) {
1038
1433
  export function resourceDependenciesForRead(method, params, nativeReaderId) {
1039
1434
  if (!Object.hasOwn(RESOURCE_QUERY_DEFINITIONS, method))
1040
1435
  return undefined;
1041
- const definition = RESOURCE_QUERY_DEFINITIONS[method];
1436
+ const definition = readDefinition(method, params);
1042
1437
  return definition.live ? definition.dependencies(params, nativeReaderId) : undefined;
1043
1438
  }
1044
1439
  //# sourceMappingURL=registry.js.map