@cat-factory/server 0.253.0 → 0.254.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.
- package/dist/app.d.ts.map +1 -1
- package/dist/app.js +6 -0
- package/dist/app.js.map +1 -1
- package/dist/modules/artifacts/ArtifactController.d.ts.map +1 -1
- package/dist/modules/artifacts/ArtifactController.js +48 -3
- package/dist/modules/artifacts/ArtifactController.js.map +1 -1
- package/dist/modules/artifacts/HarnessArtifactController.d.ts.map +1 -1
- package/dist/modules/artifacts/HarnessArtifactController.js +29 -28
- package/dist/modules/artifacts/HarnessArtifactController.js.map +1 -1
- package/dist/modules/artifacts/artifactSetCap.d.ts +31 -0
- package/dist/modules/artifacts/artifactSetCap.d.ts.map +1 -0
- package/dist/modules/artifacts/artifactSetCap.js +47 -0
- package/dist/modules/artifacts/artifactSetCap.js.map +1 -0
- package/dist/modules/publicApi/PublicApiController.d.ts.map +1 -1
- package/dist/modules/publicApi/PublicApiController.js +16 -33
- package/dist/modules/publicApi/PublicApiController.js.map +1 -1
- package/dist/modules/publicApi/PublicBoardController.d.ts +4 -0
- package/dist/modules/publicApi/PublicBoardController.d.ts.map +1 -0
- package/dist/modules/publicApi/PublicBoardController.js +241 -0
- package/dist/modules/publicApi/PublicBoardController.js.map +1 -0
- package/dist/modules/publicApi/PublicEvidenceController.d.ts.map +1 -1
- package/dist/modules/publicApi/PublicEvidenceController.js +43 -5
- package/dist/modules/publicApi/PublicEvidenceController.js.map +1 -1
- package/dist/modules/publicApi/boardProjection.d.ts +6 -0
- package/dist/modules/publicApi/boardProjection.d.ts.map +1 -0
- package/dist/modules/publicApi/boardProjection.js +39 -0
- package/dist/modules/publicApi/boardProjection.js.map +1 -0
- package/dist/modules/publicApi/decisions/projection.d.ts +16 -7
- package/dist/modules/publicApi/decisions/projection.d.ts.map +1 -1
- package/dist/modules/publicApi/decisions/projection.js +23 -15
- package/dist/modules/publicApi/decisions/projection.js.map +1 -1
- package/dist/modules/publicApi/documentAttachment.d.ts +10 -2
- package/dist/modules/publicApi/documentAttachment.d.ts.map +1 -1
- package/dist/modules/publicApi/documentAttachment.js +1 -1
- package/dist/modules/publicApi/documentAttachment.js.map +1 -1
- package/dist/modules/publicApi/openapiDocument.generated.d.ts +1 -1
- package/dist/modules/publicApi/openapiDocument.generated.d.ts.map +1 -1
- package/dist/modules/publicApi/openapiDocument.generated.js +1 -1
- package/dist/modules/publicApi/openapiDocument.generated.js.map +1 -1
- package/dist/modules/publicApi/publicApiAdmission.d.ts +56 -47
- package/dist/modules/publicApi/publicApiAdmission.d.ts.map +1 -1
- package/dist/modules/publicApi/publicApiAdmission.js +51 -51
- package/dist/modules/publicApi/publicApiAdmission.js.map +1 -1
- package/dist/modules/publicApi/publicApiStream.d.ts +29 -1
- package/dist/modules/publicApi/publicApiStream.d.ts.map +1 -1
- package/dist/modules/publicApi/publicApiStream.js +45 -0
- package/dist/modules/publicApi/publicApiStream.js.map +1 -1
- package/dist/persistence/rpc-allowlist.d.ts.map +1 -1
- package/dist/persistence/rpc-allowlist.js +1 -0
- package/dist/persistence/rpc-allowlist.js.map +1 -1
- package/package.json +8 -8
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"openapiDocument.generated.js","sourceRoot":"","sources":["../../../src/modules/publicApi/openapiDocument.generated.ts"],"names":[],"mappings":"AAAA,qFAAqF;AACrF,EAAE;AACF,0FAA0F;AAC1F,8FAA8F;AAC9F,8FAA8F;AAC9F,8EAA8E;AAE9E,MAAM,CAAC,MAAM,YAAY,GAAG,
|
|
1
|
+
{"version":3,"file":"openapiDocument.generated.js","sourceRoot":"","sources":["../../../src/modules/publicApi/openapiDocument.generated.ts"],"names":[],"mappings":"AAAA,qFAAqF;AACrF,EAAE;AACF,0FAA0F;AAC1F,8FAA8F;AAC9F,8FAA8F;AAC9F,8EAA8E;AAE9E,MAAM,CAAC,MAAM,YAAY,GAAG,ys2dAAys2d,CAAA"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type AgentKindRegistry } from '@cat-factory/agents';
|
|
2
|
-
import {
|
|
2
|
+
import type { GateRegistry } from '@cat-factory/kernel';
|
|
3
3
|
/**
|
|
4
4
|
* Inline agent kinds that PARK a run on a human/gate decision. This MUST list every
|
|
5
5
|
* inline-and-parking kind: the two review gates AND the two brainstorm dialogues (all four set the
|
|
@@ -42,8 +42,7 @@ export declare const INPUT_GATE_PARK_SURFACE = "input-gate";
|
|
|
42
42
|
*
|
|
43
43
|
* A FOURTH mechanism, read off the step kind's `interview-gate` TRAIT rather than a list of
|
|
44
44
|
* interviewer kinds, which is what makes a deployment's OWN registered interviewer visible to
|
|
45
|
-
* admission with no edit here
|
|
46
|
-
* documents. Being visible HERE is not the same as being answerable: the decision surface needs the
|
|
45
|
+
* admission with no edit here. Being visible HERE is not the same as being answerable: the decision surface needs the
|
|
47
46
|
* gate's controller wired too (`ExecutionService.interviewGateFor`), and a kind registered without
|
|
48
47
|
* one is admitted as a park and 503s when answered. That order is the safe one (the refusal
|
|
49
48
|
* over-counts rather than under-counts), but it is why the two checks are not one.
|
|
@@ -58,40 +57,30 @@ export declare const INPUT_GATE_PARK_SURFACE = "input-gate";
|
|
|
58
57
|
*/
|
|
59
58
|
export declare const INTERVIEW_PARK_SURFACE = "interview";
|
|
60
59
|
/**
|
|
61
|
-
*
|
|
62
|
-
* surface this module enumerates is reachable from one place.
|
|
60
|
+
* Whether a polling-GATE kind parks the run on a human, read off the gate's OWN registration.
|
|
63
61
|
*
|
|
64
|
-
* A third
|
|
65
|
-
* because it is a third
|
|
66
|
-
* approval flag riding an ordinary step, but a gate step whose
|
|
67
|
-
* (`pollExhaustion: 'rearm'`) because it is waiting on a person. `human-review` is the
|
|
62
|
+
* A third mechanism beside {@link PARKING_INLINE_KINDS} and {@link APPROVAL_GATE_PARK_SURFACE},
|
|
63
|
+
* because it is a third KIND of thing: not an inline review that sets the run `blocked`, and not
|
|
64
|
+
* an approval flag riding an ordinary step, but a gate step whose poll loop never times out
|
|
65
|
+
* (`pollExhaustion: 'rearm'`) because it is waiting on a person. `human-review` is the built-in
|
|
68
66
|
* that qualifies, and it is why `pl_full` (the shipped Adaptive build preset, which carries a
|
|
69
67
|
* risk-gated `human-review`) is a parking pipeline.
|
|
70
68
|
*
|
|
71
|
-
* Missing it was a real hole rather than a theoretical one: `human-review` is not
|
|
72
|
-
* `/api/v1/runs/:runId/decisions` at all, so a plain `write` key could start the
|
|
73
|
-
* board preset and have it park forever on the one surface with no public
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
* through the public `GateRegistry` seam
|
|
77
|
-
* admitted for a
|
|
78
|
-
*
|
|
79
|
-
*
|
|
80
|
-
*
|
|
81
|
-
*
|
|
82
|
-
*
|
|
83
|
-
*
|
|
84
|
-
* Note what the neighbouring surfaces do NOT share this limit: {@link INTERVIEW_PARK_SURFACE} is
|
|
85
|
-
* read off an AGENT KIND's trait, and follow-up triage would be readable off the pipeline's own
|
|
86
|
-
* per-step toggles (it has no constant here because it is deliberately not enumerated, see
|
|
87
|
-
* {@link parkSurfacesOf}), both of which a deployment's own registrations flow through, so a custom
|
|
88
|
-
* interviewer is seen here and a custom wait gate is not. Closing the gap means a gate declaring
|
|
89
|
-
* `pollExhaustion` at REGISTRATION time rather than only on the built definition; that is a change
|
|
90
|
-
* to the registry seam, and its shape is recorded in
|
|
91
|
-
* `backend/docs/adr/0043-public-decision-surface.md` rather than smuggled in behind a park-surface
|
|
92
|
-
* slice.
|
|
69
|
+
* Missing it entirely was a real hole rather than a theoretical one: `human-review` is not
|
|
70
|
+
* answerable through `/api/v1/runs/:runId/decisions` at all, so a plain `write` key could start the
|
|
71
|
+
* platform's flagship board preset and have it park forever on the one surface with no public
|
|
72
|
+
* answer path. It was first closed with a hand-kept constant in `@cat-factory/contracts` naming the
|
|
73
|
+
* SHIPPED human-wait gates, pinned by a drift guard, which left the same hole open one level down:
|
|
74
|
+
* a gate a DEPLOYMENT registered through the public `GateRegistry` seam was invisible to the rule,
|
|
75
|
+
* admitted for a `write` key, and then parked with nothing here able to name it.
|
|
76
|
+
*
|
|
77
|
+
* Reading the registration closes that, and it is the shape ADR 0043 recorded rather than a
|
|
78
|
+
* shortcut: `pollExhaustion` is DECLARED at registration, so answering costs a map lookup and
|
|
79
|
+
* standing a fake engine context up per admission call (the thing that made this unreadable
|
|
80
|
+
* before) never enters into it. Every mechanism this module enumerates now derives from a
|
|
81
|
+
* declaration a deployment's own registrations flow through.
|
|
93
82
|
*/
|
|
94
|
-
export
|
|
83
|
+
export declare function isHumanWaitGate(kind: string, gates: GateRegistry): boolean;
|
|
95
84
|
/**
|
|
96
85
|
* The route that frees an abandoned park, per public START surface. Named here rather than inlined
|
|
97
86
|
* at each call site because {@link parkingRefusalMessage} puts one of them in front of an operator:
|
|
@@ -133,13 +122,36 @@ export interface AdmissiblePipelineShape {
|
|
|
133
122
|
* container work or a GitHub write through the jobs surface, whatever its scope.
|
|
134
123
|
*/
|
|
135
124
|
export declare function isInlineOnlyPipeline(pipeline: AdmissiblePipelineShape, registry: AgentKindRegistry): boolean;
|
|
125
|
+
/**
|
|
126
|
+
* The two app-owned registries every park question is answered against, passed as one object so a
|
|
127
|
+
* call site cannot supply them in the wrong order, and so adding a third mechanism that reads a
|
|
128
|
+
* third registry is one edit rather than one per function in this chain.
|
|
129
|
+
*/
|
|
130
|
+
export interface AdmissionRegistries {
|
|
131
|
+
/** Decides traits (the interview gate) and whether a step runs inline. */
|
|
132
|
+
agentKinds: AgentKindRegistry;
|
|
133
|
+
/** Decides what a spent poll budget means for a gate kind, which is what {@link isHumanWaitGate} reads. */
|
|
134
|
+
gates: GateRegistry;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Read the two registries off whatever carries them (the request container, an engine
|
|
138
|
+
* `CoreDependencies`), so a call site names the container once instead of spelling the pairing out
|
|
139
|
+
* at each of the four places that ask a park question.
|
|
140
|
+
*
|
|
141
|
+
* Structurally typed rather than taking `ServerContainer`, which keeps this module what it is: pure,
|
|
142
|
+
* runtime-neutral policy with no HTTP or container dependency, unit-testable from two registries.
|
|
143
|
+
*/
|
|
144
|
+
export declare function admissionRegistries(source: {
|
|
145
|
+
agentKindRegistry: AgentKindRegistry;
|
|
146
|
+
gateRegistry: GateRegistry;
|
|
147
|
+
}): AdmissionRegistries;
|
|
136
148
|
/**
|
|
137
149
|
* Whether a pipeline can PARK the run on a human decision: an approval gate on an enabled step, one
|
|
138
|
-
* of the {@link PARKING_INLINE_KINDS} review/brainstorm kinds, or
|
|
139
|
-
* {@link
|
|
140
|
-
*
|
|
150
|
+
* of the {@link PARKING_INLINE_KINDS} review/brainstorm kinds, or a gate that waits on a person
|
|
151
|
+
* with no deadline ({@link isHumanWaitGate}). Parking is not a defect: it is the clarification
|
|
152
|
+
* loop. It just needs an answerer, which is what the `decide` scope asserts.
|
|
141
153
|
*/
|
|
142
|
-
export declare function canParkOnHuman(pipeline: AdmissiblePipelineShape,
|
|
154
|
+
export declare function canParkOnHuman(pipeline: AdmissiblePipelineShape, registries: AdmissionRegistries): boolean;
|
|
143
155
|
/**
|
|
144
156
|
* Every park surface an ENABLED step of `pipeline` can put the run on, in step order and deduped.
|
|
145
157
|
* Four mechanisms, each a separate check because each parks for a different reason:
|
|
@@ -147,7 +159,7 @@ export declare function canParkOnHuman(pipeline: AdmissiblePipelineShape, regist
|
|
|
147
159
|
* 1. an approval gate flag on the step ({@link APPROVAL_GATE_PARK_SURFACE});
|
|
148
160
|
* 2. the step's own kind being an inline review/brainstorm ({@link PARKING_INLINE_KINDS});
|
|
149
161
|
* 3. the step's own kind being a polling gate that waits on a human with no deadline
|
|
150
|
-
* ({@link
|
|
162
|
+
* ({@link isHumanWaitGate});
|
|
151
163
|
* 4. the step's own kind carrying the `interview-gate` TRAIT ({@link INTERVIEW_PARK_SURFACE}).
|
|
152
164
|
*
|
|
153
165
|
* This is the single enumeration {@link canParkOnHuman} derives its boolean from, so the predicate
|
|
@@ -156,18 +168,15 @@ export declare function canParkOnHuman(pipeline: AdmissiblePipelineShape, regist
|
|
|
156
168
|
* Case 4 arrived after the first three had shipped, which is the lesson the human-wait gates
|
|
157
169
|
* already taught repeating itself: an enumeration written against the park mechanisms somebody
|
|
158
170
|
* thought of misses the ones they did not, so ask what each entry is DERIVED from. Cases 2, 3 and 4
|
|
159
|
-
* each derive from a declaration
|
|
160
|
-
* registered trait) rather than from a hand-kept list of
|
|
161
|
-
* be derivable too.
|
|
171
|
+
* each derive from a declaration a deployment's own registrations flow through (a kind list, a
|
|
172
|
+
* gate's registered `pollExhaustion`, a registered trait) rather than from a hand-kept list of
|
|
173
|
+
* pipelines. Whatever is added next should be derivable too.
|
|
162
174
|
*
|
|
163
|
-
*
|
|
175
|
+
* TWO THINGS ARE DELIBERATELY NOT HERE, and they are absent for two different reasons:
|
|
164
176
|
*
|
|
165
177
|
* - A park raised dynamically mid-run (an agent-raised decision, a judge `park` disposition) is
|
|
166
178
|
* not knowable from the step chain at start time, so the rule cannot see it and does not pretend
|
|
167
179
|
* to. ADR 0032.
|
|
168
|
-
* - An unbounded human-wait gate a DEPLOYMENT registered itself cannot be read at request time;
|
|
169
|
-
* see the note on {@link HUMAN_WAIT_GATE_KINDS}. It is the only mechanism here a deployment's own
|
|
170
|
-
* registration escapes: a custom interviewer carries the trait case 4 reads and IS seen.
|
|
171
180
|
* - FOLLOW-UP TRIAGE is knowable (the companion is seeded on a Coder step unless the pipeline's
|
|
172
181
|
* per-step `followUps` toggle turns it off) and is deliberately left out anyway, because
|
|
173
182
|
* counting it would refuse a plain `write` key EVERY board pipeline that builds anything: the
|
|
@@ -180,7 +189,7 @@ export declare function canParkOnHuman(pipeline: AdmissiblePipelineShape, regist
|
|
|
180
189
|
* Recorded in `backend/docs/adr/0043-public-decision-surface.md` so it is not re-proposed as
|
|
181
190
|
* an oversight.
|
|
182
191
|
*/
|
|
183
|
-
export declare function parkSurfacesOf(pipeline: AdmissiblePipelineShape,
|
|
192
|
+
export declare function parkSurfacesOf(pipeline: AdmissiblePipelineShape, registries: AdmissionRegistries): string[];
|
|
184
193
|
/**
|
|
185
194
|
* The message behind the `pipeline_requires_decide_scope` refusal, built from the pipeline's ACTUAL
|
|
186
195
|
* park surfaces.
|
|
@@ -217,7 +226,7 @@ export declare function parkingRefusalMessage(surfaces: string[], options: {
|
|
|
217
226
|
* `true` refuses runs that were never going to park. Required means a new start surface has to
|
|
218
227
|
* answer the question rather than inherit somebody else's answer.
|
|
219
228
|
*/
|
|
220
|
-
export declare function publicRunParkSurfaces(pipeline: AdmissiblePipelineShape,
|
|
229
|
+
export declare function publicRunParkSurfaces(pipeline: AdmissiblePipelineShape, registries: AdmissionRegistries, options: {
|
|
221
230
|
inputGateBlocks: boolean;
|
|
222
231
|
}): string[];
|
|
223
232
|
/**
|
|
@@ -226,5 +235,5 @@ export declare function publicRunParkSurfaces(pipeline: AdmissiblePipelineShape,
|
|
|
226
235
|
* can drive such a pipeline end to end with no follow-up. A parking pipeline is still admissible
|
|
227
236
|
* for a `decide`-scoped key (see {@link PARKING_INLINE_KINDS}), it simply needs answering.
|
|
228
237
|
*/
|
|
229
|
-
export declare function isHeadlessInlinePipeline(pipeline: AdmissiblePipelineShape,
|
|
238
|
+
export declare function isHeadlessInlinePipeline(pipeline: AdmissiblePipelineShape, registries: AdmissionRegistries): boolean;
|
|
230
239
|
//# sourceMappingURL=publicApiAdmission.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"publicApiAdmission.d.ts","sourceRoot":"","sources":["../../../src/modules/publicApi/publicApiAdmission.ts"],"names":[],"mappings":"AAaA,OAAO,EACL,KAAK,iBAAiB,EAQvB,MAAM,qBAAqB,CAAA;AAC5B,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"publicApiAdmission.d.ts","sourceRoot":"","sources":["../../../src/modules/publicApi/publicApiAdmission.ts"],"names":[],"mappings":"AAaA,OAAO,EACL,KAAK,iBAAiB,EAQvB,MAAM,qBAAqB,CAAA;AAC5B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAEvD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,oBAAoB,aAK/B,CAAA;AAEF;;;;GAIG;AACH,eAAO,MAAM,0BAA0B,kBAAkB,CAAA;AAEzD;;;;;;;GAOG;AACH,eAAO,MAAM,uBAAuB,eAAe,CAAA;AAEnD;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,sBAAsB,cAAc,CAAA;AAEjD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,GAAG,OAAO,CAE1E;AAED;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB,iCAAiC,CAAA;AACpE,eAAO,MAAM,qBAAqB,oCAAoC,CAAA;AAEtE;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,iCAAiC,aAQ5C,CAAA;AAEF,iGAAiG;AACjG,MAAM,WAAW,uBAAuB;IACtC,UAAU,EAAE,MAAM,EAAE,CAAA;IACpB,6FAA6F;IAC7F,OAAO,CAAC,EAAE,OAAO,EAAE,CAAA;IACnB,+DAA+D;IAC/D,KAAK,CAAC,EAAE,OAAO,EAAE,CAAA;CAClB;AASD;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,uBAAuB,EACjC,QAAQ,EAAE,iBAAiB,GAC1B,OAAO,CAIT;AAED;;;;GAIG;AACH,MAAM,WAAW,mBAAmB;IAClC,0EAA0E;IAC1E,UAAU,EAAE,iBAAiB,CAAA;IAC7B,2GAA2G;IAC3G,KAAK,EAAE,YAAY,CAAA;CACpB;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE;IAC1C,iBAAiB,EAAE,iBAAiB,CAAA;IACpC,YAAY,EAAE,YAAY,CAAA;CAC3B,GAAG,mBAAmB,CAEtB;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,uBAAuB,EACjC,UAAU,EAAE,mBAAmB,GAC9B,OAAO,CAET;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,uBAAuB,EACjC,UAAU,EAAE,mBAAmB,GAC9B,MAAM,EAAE,CAYV;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE;IAAE,UAAU,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAgBjG;AAED;;;;;;;;;GASG;AACH,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,uBAAuB,EACjC,UAAU,EAAE,mBAAmB,EAC/B,OAAO,EAAE;IAAE,eAAe,EAAE,OAAO,CAAA;CAAE,GACpC,MAAM,EAAE,CAKV;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,CACtC,QAAQ,EAAE,uBAAuB,EACjC,UAAU,EAAE,mBAAmB,GAC9B,OAAO,CAIT"}
|
|
@@ -11,7 +11,6 @@
|
|
|
11
11
|
//
|
|
12
12
|
// See backend/docs/adr/0047-headless-clarification-loop.md (D1).
|
|
13
13
|
import { ARCHITECTURE_BRAINSTORM_AGENT_KIND, CLARITY_REVIEW_AGENT_KIND, hasTrait, INTERVIEW_GATE_TRAIT, isInlineModelStep, REQUIREMENTS_BRAINSTORM_AGENT_KIND, REQUIREMENTS_REVIEW_AGENT_KIND, } from '@cat-factory/agents';
|
|
14
|
-
import { HUMAN_WAIT_GATE_KINDS } from '@cat-factory/contracts';
|
|
15
14
|
/**
|
|
16
15
|
* Inline agent kinds that PARK a run on a human/gate decision. This MUST list every
|
|
17
16
|
* inline-and-parking kind: the two review gates AND the two brainstorm dialogues (all four set the
|
|
@@ -59,8 +58,7 @@ export const INPUT_GATE_PARK_SURFACE = 'input-gate';
|
|
|
59
58
|
*
|
|
60
59
|
* A FOURTH mechanism, read off the step kind's `interview-gate` TRAIT rather than a list of
|
|
61
60
|
* interviewer kinds, which is what makes a deployment's OWN registered interviewer visible to
|
|
62
|
-
* admission with no edit here
|
|
63
|
-
* documents. Being visible HERE is not the same as being answerable: the decision surface needs the
|
|
61
|
+
* admission with no edit here. Being visible HERE is not the same as being answerable: the decision surface needs the
|
|
64
62
|
* gate's controller wired too (`ExecutionService.interviewGateFor`), and a kind registered without
|
|
65
63
|
* one is admitted as a park and 503s when answered. That order is the safe one (the refusal
|
|
66
64
|
* over-counts rather than under-counts), but it is why the two checks are not one.
|
|
@@ -75,40 +73,32 @@ export const INPUT_GATE_PARK_SURFACE = 'input-gate';
|
|
|
75
73
|
*/
|
|
76
74
|
export const INTERVIEW_PARK_SURFACE = 'interview';
|
|
77
75
|
/**
|
|
78
|
-
*
|
|
79
|
-
* surface this module enumerates is reachable from one place.
|
|
76
|
+
* Whether a polling-GATE kind parks the run on a human, read off the gate's OWN registration.
|
|
80
77
|
*
|
|
81
|
-
* A third
|
|
82
|
-
* because it is a third
|
|
83
|
-
* approval flag riding an ordinary step, but a gate step whose
|
|
84
|
-
* (`pollExhaustion: 'rearm'`) because it is waiting on a person. `human-review` is the
|
|
78
|
+
* A third mechanism beside {@link PARKING_INLINE_KINDS} and {@link APPROVAL_GATE_PARK_SURFACE},
|
|
79
|
+
* because it is a third KIND of thing: not an inline review that sets the run `blocked`, and not
|
|
80
|
+
* an approval flag riding an ordinary step, but a gate step whose poll loop never times out
|
|
81
|
+
* (`pollExhaustion: 'rearm'`) because it is waiting on a person. `human-review` is the built-in
|
|
85
82
|
* that qualifies, and it is why `pl_full` (the shipped Adaptive build preset, which carries a
|
|
86
83
|
* risk-gated `human-review`) is a parking pipeline.
|
|
87
84
|
*
|
|
88
|
-
* Missing it was a real hole rather than a theoretical one: `human-review` is not
|
|
89
|
-
* `/api/v1/runs/:runId/decisions` at all, so a plain `write` key could start the
|
|
90
|
-
* board preset and have it park forever on the one surface with no public
|
|
85
|
+
* Missing it entirely was a real hole rather than a theoretical one: `human-review` is not
|
|
86
|
+
* answerable through `/api/v1/runs/:runId/decisions` at all, so a plain `write` key could start the
|
|
87
|
+
* platform's flagship board preset and have it park forever on the one surface with no public
|
|
88
|
+
* answer path. It was first closed with a hand-kept constant in `@cat-factory/contracts` naming the
|
|
89
|
+
* SHIPPED human-wait gates, pinned by a drift guard, which left the same hole open one level down:
|
|
90
|
+
* a gate a DEPLOYMENT registered through the public `GateRegistry` seam was invisible to the rule,
|
|
91
|
+
* admitted for a `write` key, and then parked with nothing here able to name it.
|
|
91
92
|
*
|
|
92
|
-
*
|
|
93
|
-
*
|
|
94
|
-
*
|
|
95
|
-
*
|
|
96
|
-
*
|
|
97
|
-
* context up per admission call to interrogate a static declaration would be a shortcut, not a
|
|
98
|
-
* design. So the deployment that registered the gate owns the answer to it, in whatever surface
|
|
99
|
-
* it registered it for, and the run reports `parked: true` with an empty decision list until then.
|
|
100
|
-
*
|
|
101
|
-
* Note what the neighbouring surfaces do NOT share this limit: {@link INTERVIEW_PARK_SURFACE} is
|
|
102
|
-
* read off an AGENT KIND's trait, and follow-up triage would be readable off the pipeline's own
|
|
103
|
-
* per-step toggles (it has no constant here because it is deliberately not enumerated, see
|
|
104
|
-
* {@link parkSurfacesOf}), both of which a deployment's own registrations flow through, so a custom
|
|
105
|
-
* interviewer is seen here and a custom wait gate is not. Closing the gap means a gate declaring
|
|
106
|
-
* `pollExhaustion` at REGISTRATION time rather than only on the built definition; that is a change
|
|
107
|
-
* to the registry seam, and its shape is recorded in
|
|
108
|
-
* `backend/docs/adr/0043-public-decision-surface.md` rather than smuggled in behind a park-surface
|
|
109
|
-
* slice.
|
|
93
|
+
* Reading the registration closes that, and it is the shape ADR 0043 recorded rather than a
|
|
94
|
+
* shortcut: `pollExhaustion` is DECLARED at registration, so answering costs a map lookup and
|
|
95
|
+
* standing a fake engine context up per admission call (the thing that made this unreadable
|
|
96
|
+
* before) never enters into it. Every mechanism this module enumerates now derives from a
|
|
97
|
+
* declaration a deployment's own registrations flow through.
|
|
110
98
|
*/
|
|
111
|
-
export
|
|
99
|
+
export function isHumanWaitGate(kind, gates) {
|
|
100
|
+
return gates.pollExhaustion(kind) === 'rearm';
|
|
101
|
+
}
|
|
112
102
|
/**
|
|
113
103
|
* The route that frees an abandoned park, per public START surface. Named here rather than inlined
|
|
114
104
|
* at each call site because {@link parkingRefusalMessage} puts one of them in front of an operator:
|
|
@@ -161,14 +151,25 @@ export function isInlineOnlyPipeline(pipeline, registry) {
|
|
|
161
151
|
return false;
|
|
162
152
|
return enabled.every(({ kind }) => isInlineModelStep(kind, registry));
|
|
163
153
|
}
|
|
154
|
+
/**
|
|
155
|
+
* Read the two registries off whatever carries them (the request container, an engine
|
|
156
|
+
* `CoreDependencies`), so a call site names the container once instead of spelling the pairing out
|
|
157
|
+
* at each of the four places that ask a park question.
|
|
158
|
+
*
|
|
159
|
+
* Structurally typed rather than taking `ServerContainer`, which keeps this module what it is: pure,
|
|
160
|
+
* runtime-neutral policy with no HTTP or container dependency, unit-testable from two registries.
|
|
161
|
+
*/
|
|
162
|
+
export function admissionRegistries(source) {
|
|
163
|
+
return { agentKinds: source.agentKindRegistry, gates: source.gateRegistry };
|
|
164
|
+
}
|
|
164
165
|
/**
|
|
165
166
|
* Whether a pipeline can PARK the run on a human decision: an approval gate on an enabled step, one
|
|
166
|
-
* of the {@link PARKING_INLINE_KINDS} review/brainstorm kinds, or
|
|
167
|
-
* {@link
|
|
168
|
-
*
|
|
167
|
+
* of the {@link PARKING_INLINE_KINDS} review/brainstorm kinds, or a gate that waits on a person
|
|
168
|
+
* with no deadline ({@link isHumanWaitGate}). Parking is not a defect: it is the clarification
|
|
169
|
+
* loop. It just needs an answerer, which is what the `decide` scope asserts.
|
|
169
170
|
*/
|
|
170
|
-
export function canParkOnHuman(pipeline,
|
|
171
|
-
return parkSurfacesOf(pipeline,
|
|
171
|
+
export function canParkOnHuman(pipeline, registries) {
|
|
172
|
+
return parkSurfacesOf(pipeline, registries).length > 0;
|
|
172
173
|
}
|
|
173
174
|
/**
|
|
174
175
|
* Every park surface an ENABLED step of `pipeline` can put the run on, in step order and deduped.
|
|
@@ -177,7 +178,7 @@ export function canParkOnHuman(pipeline, registry) {
|
|
|
177
178
|
* 1. an approval gate flag on the step ({@link APPROVAL_GATE_PARK_SURFACE});
|
|
178
179
|
* 2. the step's own kind being an inline review/brainstorm ({@link PARKING_INLINE_KINDS});
|
|
179
180
|
* 3. the step's own kind being a polling gate that waits on a human with no deadline
|
|
180
|
-
* ({@link
|
|
181
|
+
* ({@link isHumanWaitGate});
|
|
181
182
|
* 4. the step's own kind carrying the `interview-gate` TRAIT ({@link INTERVIEW_PARK_SURFACE}).
|
|
182
183
|
*
|
|
183
184
|
* This is the single enumeration {@link canParkOnHuman} derives its boolean from, so the predicate
|
|
@@ -186,18 +187,15 @@ export function canParkOnHuman(pipeline, registry) {
|
|
|
186
187
|
* Case 4 arrived after the first three had shipped, which is the lesson the human-wait gates
|
|
187
188
|
* already taught repeating itself: an enumeration written against the park mechanisms somebody
|
|
188
189
|
* thought of misses the ones they did not, so ask what each entry is DERIVED from. Cases 2, 3 and 4
|
|
189
|
-
* each derive from a declaration
|
|
190
|
-
* registered trait) rather than from a hand-kept list of
|
|
191
|
-
* be derivable too.
|
|
190
|
+
* each derive from a declaration a deployment's own registrations flow through (a kind list, a
|
|
191
|
+
* gate's registered `pollExhaustion`, a registered trait) rather than from a hand-kept list of
|
|
192
|
+
* pipelines. Whatever is added next should be derivable too.
|
|
192
193
|
*
|
|
193
|
-
*
|
|
194
|
+
* TWO THINGS ARE DELIBERATELY NOT HERE, and they are absent for two different reasons:
|
|
194
195
|
*
|
|
195
196
|
* - A park raised dynamically mid-run (an agent-raised decision, a judge `park` disposition) is
|
|
196
197
|
* not knowable from the step chain at start time, so the rule cannot see it and does not pretend
|
|
197
198
|
* to. ADR 0032.
|
|
198
|
-
* - An unbounded human-wait gate a DEPLOYMENT registered itself cannot be read at request time;
|
|
199
|
-
* see the note on {@link HUMAN_WAIT_GATE_KINDS}. It is the only mechanism here a deployment's own
|
|
200
|
-
* registration escapes: a custom interviewer carries the trait case 4 reads and IS seen.
|
|
201
199
|
* - FOLLOW-UP TRIAGE is knowable (the companion is seeded on a Coder step unless the pipeline's
|
|
202
200
|
* per-step `followUps` toggle turns it off) and is deliberately left out anyway, because
|
|
203
201
|
* counting it would refuse a plain `write` key EVERY board pipeline that builds anything: the
|
|
@@ -210,15 +208,17 @@ export function canParkOnHuman(pipeline, registry) {
|
|
|
210
208
|
* Recorded in `backend/docs/adr/0043-public-decision-surface.md` so it is not re-proposed as
|
|
211
209
|
* an oversight.
|
|
212
210
|
*/
|
|
213
|
-
export function parkSurfacesOf(pipeline,
|
|
211
|
+
export function parkSurfacesOf(pipeline, registries) {
|
|
214
212
|
const surfaces = new Set();
|
|
215
213
|
for (const { kind, i } of enabledSteps(pipeline)) {
|
|
216
214
|
if (pipeline.gates?.[i])
|
|
217
215
|
surfaces.add(APPROVAL_GATE_PARK_SURFACE);
|
|
218
|
-
if (PARKING_INLINE_KINDS.has(kind) ||
|
|
216
|
+
if (PARKING_INLINE_KINDS.has(kind) || isHumanWaitGate(kind, registries.gates)) {
|
|
219
217
|
surfaces.add(kind);
|
|
220
|
-
|
|
218
|
+
}
|
|
219
|
+
if (hasTrait(kind, INTERVIEW_GATE_TRAIT, registries.agentKinds)) {
|
|
221
220
|
surfaces.add(INTERVIEW_PARK_SURFACE);
|
|
221
|
+
}
|
|
222
222
|
}
|
|
223
223
|
return [...surfaces];
|
|
224
224
|
}
|
|
@@ -268,8 +268,8 @@ export function parkingRefusalMessage(surfaces, options) {
|
|
|
268
268
|
* `true` refuses runs that were never going to park. Required means a new start surface has to
|
|
269
269
|
* answer the question rather than inherit somebody else's answer.
|
|
270
270
|
*/
|
|
271
|
-
export function publicRunParkSurfaces(pipeline,
|
|
272
|
-
const surfaces = parkSurfacesOf(pipeline,
|
|
271
|
+
export function publicRunParkSurfaces(pipeline, registries, options) {
|
|
272
|
+
const surfaces = parkSurfacesOf(pipeline, registries);
|
|
273
273
|
// Prepended: the gate parks BEFORE the first dispatch, so if it is going to hold this run it
|
|
274
274
|
// holds it before any of the pipeline's own park surfaces are reached.
|
|
275
275
|
return options.inputGateBlocks ? [INPUT_GATE_PARK_SURFACE, ...surfaces] : surfaces;
|
|
@@ -280,7 +280,7 @@ export function publicRunParkSurfaces(pipeline, registry, options) {
|
|
|
280
280
|
* can drive such a pipeline end to end with no follow-up. A parking pipeline is still admissible
|
|
281
281
|
* for a `decide`-scoped key (see {@link PARKING_INLINE_KINDS}), it simply needs answering.
|
|
282
282
|
*/
|
|
283
|
-
export function isHeadlessInlinePipeline(pipeline,
|
|
284
|
-
return isInlineOnlyPipeline(pipeline,
|
|
283
|
+
export function isHeadlessInlinePipeline(pipeline, registries) {
|
|
284
|
+
return (isInlineOnlyPipeline(pipeline, registries.agentKinds) && !canParkOnHuman(pipeline, registries));
|
|
285
285
|
}
|
|
286
286
|
//# sourceMappingURL=publicApiAdmission.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"publicApiAdmission.js","sourceRoot":"","sources":["../../../src/modules/publicApi/publicApiAdmission.ts"],"names":[],"mappings":"AAAA,sFAAsF;AACtF,0FAA0F;AAC1F,mCAAmC;AACnC,EAAE;AACF,iGAAiG;AACjG,mGAAmG;AACnG,mGAAmG;AACnG,mGAAmG;AACnG,sFAAsF;AACtF,mCAAmC;AACnC,EAAE;AACF,iEAAiE;AAEjE,OAAO,EAEL,kCAAkC,EAClC,yBAAyB,EACzB,QAAQ,EACR,oBAAoB,EACpB,iBAAiB,EACjB,kCAAkC,EAClC,8BAA8B,GAC/B,MAAM,qBAAqB,CAAA;
|
|
1
|
+
{"version":3,"file":"publicApiAdmission.js","sourceRoot":"","sources":["../../../src/modules/publicApi/publicApiAdmission.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ExecutionStatus } from '@cat-factory/contracts';
|
|
1
|
+
import type { ExecutionStatus, PublicRun } from '@cat-factory/contracts';
|
|
2
2
|
/**
|
|
3
3
|
* Whether a run is PARKED: waiting on a human decision and unable to move until one is answered.
|
|
4
4
|
*
|
|
@@ -21,4 +21,32 @@ export declare function createParkAnnouncer(): {
|
|
|
21
21
|
/** Feed each poll's status; true exactly on the tick a NEW park should be announced. */
|
|
22
22
|
shouldAnnounce: (status: ExecutionStatus) => boolean;
|
|
23
23
|
};
|
|
24
|
+
/**
|
|
25
|
+
* Per-step character cap on the deliverable a STREAM frame carries, applied to `output` and to
|
|
26
|
+
* `data`'s serialized size alike.
|
|
27
|
+
*
|
|
28
|
+
* Sized as a preview a caller can act on (recognise the shape of the deliverable, decide whether
|
|
29
|
+
* to fetch the rest) rather than as a budget for the deliverable itself, and deliberately smaller
|
|
30
|
+
* than the run detail's own 8,000-char sibling (`MAX_HISTORY_OUTPUT_CHARS`, which bounds the same
|
|
31
|
+
* class of content for the same reason): this cap is paid once per step per FRAME, where that one
|
|
32
|
+
* is paid once per step.
|
|
33
|
+
*/
|
|
34
|
+
export declare const STREAM_DELIVERABLE_PREVIEW_CHARS = 2000;
|
|
35
|
+
/**
|
|
36
|
+
* Reduce a run for an SSE frame: clip each step's oversized `output` to a preview, withhold an
|
|
37
|
+
* oversized `data`, and mark every step the reduction touched.
|
|
38
|
+
*
|
|
39
|
+
* The stream re-sends the whole run on every change, so an unreduced frame repeats every output
|
|
40
|
+
* the run has produced so far and the traffic grows with the SQUARE of the pipeline's length. The
|
|
41
|
+
* point read (`GET /api/v1/tasks/{taskId}/run`) serves both fields whole and is what a caller
|
|
42
|
+
* reads for the deliverable; this keeps the progress channel a progress channel.
|
|
43
|
+
*
|
|
44
|
+
* Only what EXCEEDS the cap is touched. A step whose deliverable already fits — which is the
|
|
45
|
+
* ordinary case for the structured `data` a fork choice or an estimate carries — rides the stream
|
|
46
|
+
* unchanged and unflagged, so `truncated` means exactly "something was left out of this frame"
|
|
47
|
+
* rather than "this frame came from the stream". That is the whole reason the flag exists: a
|
|
48
|
+
* clipped preview that did not say so is indexed by a caller as the step's output, and its tail is
|
|
49
|
+
* then absent in a way that reads as never written.
|
|
50
|
+
*/
|
|
51
|
+
export declare function reduceRunForStream(run: PublicRun): PublicRun;
|
|
24
52
|
//# sourceMappingURL=publicApiStream.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"publicApiStream.d.ts","sourceRoot":"","sources":["../../../src/modules/publicApi/publicApiStream.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAA;
|
|
1
|
+
{"version":3,"file":"publicApiStream.d.ts","sourceRoot":"","sources":["../../../src/modules/publicApi/publicApiStream.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,SAAS,EAAiB,MAAM,wBAAwB,CAAA;AAUvF;;;;;;GAMG;AACH,wBAAgB,QAAQ,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAEzD;AAED;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,IAAI;IACrC,wFAAwF;IACxF,cAAc,EAAE,CAAC,MAAM,EAAE,eAAe,KAAK,OAAO,CAAA;CACrD,CAaA;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,gCAAgC,OAAQ,CAAA;AAErD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,SAAS,GAAG,SAAS,CAE5D"}
|
|
@@ -40,4 +40,49 @@ export function createParkAnnouncer() {
|
|
|
40
40
|
},
|
|
41
41
|
};
|
|
42
42
|
}
|
|
43
|
+
/**
|
|
44
|
+
* Per-step character cap on the deliverable a STREAM frame carries, applied to `output` and to
|
|
45
|
+
* `data`'s serialized size alike.
|
|
46
|
+
*
|
|
47
|
+
* Sized as a preview a caller can act on (recognise the shape of the deliverable, decide whether
|
|
48
|
+
* to fetch the rest) rather than as a budget for the deliverable itself, and deliberately smaller
|
|
49
|
+
* than the run detail's own 8,000-char sibling (`MAX_HISTORY_OUTPUT_CHARS`, which bounds the same
|
|
50
|
+
* class of content for the same reason): this cap is paid once per step per FRAME, where that one
|
|
51
|
+
* is paid once per step.
|
|
52
|
+
*/
|
|
53
|
+
export const STREAM_DELIVERABLE_PREVIEW_CHARS = 2_000;
|
|
54
|
+
/**
|
|
55
|
+
* Reduce a run for an SSE frame: clip each step's oversized `output` to a preview, withhold an
|
|
56
|
+
* oversized `data`, and mark every step the reduction touched.
|
|
57
|
+
*
|
|
58
|
+
* The stream re-sends the whole run on every change, so an unreduced frame repeats every output
|
|
59
|
+
* the run has produced so far and the traffic grows with the SQUARE of the pipeline's length. The
|
|
60
|
+
* point read (`GET /api/v1/tasks/{taskId}/run`) serves both fields whole and is what a caller
|
|
61
|
+
* reads for the deliverable; this keeps the progress channel a progress channel.
|
|
62
|
+
*
|
|
63
|
+
* Only what EXCEEDS the cap is touched. A step whose deliverable already fits — which is the
|
|
64
|
+
* ordinary case for the structured `data` a fork choice or an estimate carries — rides the stream
|
|
65
|
+
* unchanged and unflagged, so `truncated` means exactly "something was left out of this frame"
|
|
66
|
+
* rather than "this frame came from the stream". That is the whole reason the flag exists: a
|
|
67
|
+
* clipped preview that did not say so is indexed by a caller as the step's output, and its tail is
|
|
68
|
+
* then absent in a way that reads as never written.
|
|
69
|
+
*/
|
|
70
|
+
export function reduceRunForStream(run) {
|
|
71
|
+
return { ...run, steps: run.steps.map(reduceStepForStream) };
|
|
72
|
+
}
|
|
73
|
+
function reduceStepForStream(step) {
|
|
74
|
+
const output = step.output;
|
|
75
|
+
const clipped = output !== null && output.length > STREAM_DELIVERABLE_PREVIEW_CHARS;
|
|
76
|
+
// Measured, not assumed: `data` is whatever the step's agent kind produced, so its size is a
|
|
77
|
+
// property of the deployment's kinds rather than of this contract.
|
|
78
|
+
const withheld = step.data != null && JSON.stringify(step.data).length > STREAM_DELIVERABLE_PREVIEW_CHARS;
|
|
79
|
+
if (!clipped && !withheld)
|
|
80
|
+
return step;
|
|
81
|
+
return {
|
|
82
|
+
...step,
|
|
83
|
+
output: clipped && output !== null ? output.slice(0, STREAM_DELIVERABLE_PREVIEW_CHARS) : output,
|
|
84
|
+
data: withheld ? null : step.data,
|
|
85
|
+
truncated: true,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
43
88
|
//# sourceMappingURL=publicApiStream.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"publicApiStream.js","sourceRoot":"","sources":["../../../src/modules/publicApi/publicApiStream.ts"],"names":[],"mappings":"AAEA,6FAA6F;AAC7F,kGAAkG;AAClG,mGAAmG;AACnG,6FAA6F;AAC7F,EAAE;AACF,kGAAkG;AAClG,4DAA4D;AAE5D;;;;;;GAMG;AACH,MAAM,UAAU,QAAQ,CAAC,MAAuB;IAC9C,OAAO,MAAM,KAAK,SAAS,CAAA;AAC7B,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,mBAAmB;IAIjC,IAAI,SAAS,GAAG,KAAK,CAAA;IACrB,OAAO;QACL,cAAc,CAAC,MAAuB;YACpC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;gBACtB,SAAS,GAAG,KAAK,CAAA;gBACjB,OAAO,KAAK,CAAA;YACd,CAAC;YACD,IAAI,SAAS;gBAAE,OAAO,KAAK,CAAA;YAC3B,SAAS,GAAG,IAAI,CAAA;YAChB,OAAO,IAAI,CAAA;QACb,CAAC;KACF,CAAA;AACH,CAAC"}
|
|
1
|
+
{"version":3,"file":"publicApiStream.js","sourceRoot":"","sources":["../../../src/modules/publicApi/publicApiStream.ts"],"names":[],"mappings":"AAEA,6FAA6F;AAC7F,kGAAkG;AAClG,mGAAmG;AACnG,6FAA6F;AAC7F,EAAE;AACF,kGAAkG;AAClG,4DAA4D;AAE5D;;;;;;GAMG;AACH,MAAM,UAAU,QAAQ,CAAC,MAAuB;IAC9C,OAAO,MAAM,KAAK,SAAS,CAAA;AAC7B,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,mBAAmB;IAIjC,IAAI,SAAS,GAAG,KAAK,CAAA;IACrB,OAAO;QACL,cAAc,CAAC,MAAuB;YACpC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;gBACtB,SAAS,GAAG,KAAK,CAAA;gBACjB,OAAO,KAAK,CAAA;YACd,CAAC;YACD,IAAI,SAAS;gBAAE,OAAO,KAAK,CAAA;YAC3B,SAAS,GAAG,IAAI,CAAA;YAChB,OAAO,IAAI,CAAA;QACb,CAAC;KACF,CAAA;AACH,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,gCAAgC,GAAG,KAAK,CAAA;AAErD;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,kBAAkB,CAAC,GAAc;IAC/C,OAAO,EAAE,GAAG,GAAG,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,mBAAmB,CAAC,EAAE,CAAA;AAC9D,CAAC;AAED,SAAS,mBAAmB,CAAC,IAAmB;IAC9C,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAA;IAC1B,MAAM,OAAO,GAAG,MAAM,KAAK,IAAI,IAAI,MAAM,CAAC,MAAM,GAAG,gCAAgC,CAAA;IACnF,6FAA6F;IAC7F,mEAAmE;IACnE,MAAM,QAAQ,GACZ,IAAI,CAAC,IAAI,IAAI,IAAI,IAAI,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,GAAG,gCAAgC,CAAA;IAC1F,IAAI,CAAC,OAAO,IAAI,CAAC,QAAQ;QAAE,OAAO,IAAI,CAAA;IACtC,OAAO;QACL,GAAG,IAAI;QACP,MAAM,EAAE,OAAO,IAAI,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,gCAAgC,CAAC,CAAC,CAAC,CAAC,MAAM;QAC/F,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI;QACjC,SAAS,EAAE,IAAI;KAChB,CAAA;AACH,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rpc-allowlist.d.ts","sourceRoot":"","sources":["../../src/persistence/rpc-allowlist.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,UAAU,CAAA;AAgBtD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,eAAO,MAAM,0BAA0B,EAAE,
|
|
1
|
+
{"version":3,"file":"rpc-allowlist.d.ts","sourceRoot":"","sources":["../../src/persistence/rpc-allowlist.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,UAAU,CAAA;AAgBtD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,eAAO,MAAM,0BAA0B,EAAE,sBAmxCxC,CAAA;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,oCAAoC,YAC/C,yBAAyB,EACzB,gCAAgC,EAChC,4BAA4B,EAC5B,yBAAyB,EACzB,2BAA2B,EAC3B,kCAAkC,CAC1B,CAAA;AAEV,yEAAyE;AACzE,MAAM,MAAM,+BAA+B,GAAG,CAAC,OAAO,oCAAoC,CAAC,CAAC,MAAM,CAAC,CAAA"}
|
|
@@ -1094,6 +1094,7 @@ export const REMOTE_PERSISTENCE_METHODS = {
|
|
|
1094
1094
|
listByExecution: { scope: { kind: 'workspace', arg: 0 } },
|
|
1095
1095
|
countByExecution: { scope: { kind: 'workspace', arg: 0 } },
|
|
1096
1096
|
listByBlock: { scope: { kind: 'workspace', arg: 0 } },
|
|
1097
|
+
countByBlock: { scope: { kind: 'workspace', arg: 0 } },
|
|
1097
1098
|
// The document reclaim's two halves: an import running on a node retains a design source's
|
|
1098
1099
|
// rendered frames and replaces the previous revision's, so both have to reach the mothership's
|
|
1099
1100
|
// store or a local import would silently retain nothing. Same `workspace` rule as the reads
|