@cat-factory/server 0.253.0 → 0.255.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 (58) hide show
  1. package/dist/agents/containerAgentBody.d.ts.map +1 -1
  2. package/dist/agents/containerAgentBody.js +30 -0
  3. package/dist/agents/containerAgentBody.js.map +1 -1
  4. package/dist/agents/harnessContract.d.ts +2 -0
  5. package/dist/agents/harnessContract.d.ts.map +1 -1
  6. package/dist/agents/harnessContract.js +3 -1
  7. package/dist/agents/harnessContract.js.map +1 -1
  8. package/dist/app.d.ts.map +1 -1
  9. package/dist/app.js +10 -2
  10. package/dist/app.js.map +1 -1
  11. package/dist/modules/artifacts/ArtifactController.d.ts.map +1 -1
  12. package/dist/modules/artifacts/ArtifactController.js +48 -3
  13. package/dist/modules/artifacts/ArtifactController.js.map +1 -1
  14. package/dist/modules/artifacts/HarnessArtifactController.d.ts.map +1 -1
  15. package/dist/modules/artifacts/HarnessArtifactController.js +99 -55
  16. package/dist/modules/artifacts/HarnessArtifactController.js.map +1 -1
  17. package/dist/modules/artifacts/artifactSetCap.d.ts +31 -0
  18. package/dist/modules/artifacts/artifactSetCap.d.ts.map +1 -0
  19. package/dist/modules/artifacts/artifactSetCap.js +47 -0
  20. package/dist/modules/artifacts/artifactSetCap.js.map +1 -0
  21. package/dist/modules/publicApi/PublicApiController.d.ts.map +1 -1
  22. package/dist/modules/publicApi/PublicApiController.js +16 -33
  23. package/dist/modules/publicApi/PublicApiController.js.map +1 -1
  24. package/dist/modules/publicApi/PublicBoardController.d.ts +4 -0
  25. package/dist/modules/publicApi/PublicBoardController.d.ts.map +1 -0
  26. package/dist/modules/publicApi/PublicBoardController.js +241 -0
  27. package/dist/modules/publicApi/PublicBoardController.js.map +1 -0
  28. package/dist/modules/publicApi/PublicEvidenceController.d.ts.map +1 -1
  29. package/dist/modules/publicApi/PublicEvidenceController.js +43 -5
  30. package/dist/modules/publicApi/PublicEvidenceController.js.map +1 -1
  31. package/dist/modules/publicApi/boardProjection.d.ts +6 -0
  32. package/dist/modules/publicApi/boardProjection.d.ts.map +1 -0
  33. package/dist/modules/publicApi/boardProjection.js +39 -0
  34. package/dist/modules/publicApi/boardProjection.js.map +1 -0
  35. package/dist/modules/publicApi/decisions/projection.d.ts +16 -7
  36. package/dist/modules/publicApi/decisions/projection.d.ts.map +1 -1
  37. package/dist/modules/publicApi/decisions/projection.js +23 -15
  38. package/dist/modules/publicApi/decisions/projection.js.map +1 -1
  39. package/dist/modules/publicApi/documentAttachment.d.ts +10 -2
  40. package/dist/modules/publicApi/documentAttachment.d.ts.map +1 -1
  41. package/dist/modules/publicApi/documentAttachment.js +1 -1
  42. package/dist/modules/publicApi/documentAttachment.js.map +1 -1
  43. package/dist/modules/publicApi/openapiDocument.generated.d.ts +1 -1
  44. package/dist/modules/publicApi/openapiDocument.generated.d.ts.map +1 -1
  45. package/dist/modules/publicApi/openapiDocument.generated.js +1 -1
  46. package/dist/modules/publicApi/openapiDocument.generated.js.map +1 -1
  47. package/dist/modules/publicApi/publicApiAdmission.d.ts +56 -47
  48. package/dist/modules/publicApi/publicApiAdmission.d.ts.map +1 -1
  49. package/dist/modules/publicApi/publicApiAdmission.js +51 -51
  50. package/dist/modules/publicApi/publicApiAdmission.js.map +1 -1
  51. package/dist/modules/publicApi/publicApiStream.d.ts +29 -1
  52. package/dist/modules/publicApi/publicApiStream.d.ts.map +1 -1
  53. package/dist/modules/publicApi/publicApiStream.js +45 -0
  54. package/dist/modules/publicApi/publicApiStream.js.map +1 -1
  55. package/dist/persistence/rpc-allowlist.d.ts.map +1 -1
  56. package/dist/persistence/rpc-allowlist.js +1 -0
  57. package/dist/persistence/rpc-allowlist.js.map +1 -1
  58. 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,y9pcAAy9pc,CAAA"}
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 { HUMAN_WAIT_GATE_KINDS } from '@cat-factory/contracts';
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, the opposite of the wait-gate gap {@link HUMAN_WAIT_GATE_KINDS}
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
- * POLLING-GATE kinds that park on a human, re-exported from `@cat-factory/contracts` so every park
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 category beside {@link PARKING_INLINE_KINDS} and {@link APPROVAL_GATE_PARK_SURFACE},
65
- * because it is a third MECHANISM: not an inline review that sets the run `blocked`, and not an
66
- * approval flag riding an ordinary step, but a gate step whose own poll loop never times out
67
- * (`pollExhaustion: 'rearm'`) because it is waiting on a person. `human-review` is the one built-in
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 answerable through
72
- * `/api/v1/runs/:runId/decisions` at all, so a plain `write` key could start the platform's flagship
73
- * board preset and have it park forever on the one surface with no public answer path.
74
- *
75
- * ONLY BUILT-IN GATES ARE IN IT, and a deployment that registers its own unbounded-wait gate
76
- * through the public `GateRegistry` seam is therefore INVISIBLE to this check: such a pipeline is
77
- * admitted for a plain `write` key and then parks with nothing here able to name it. That is a
78
- * limit of what a request-time check can read, not an oversight: a gate's `pollExhaustion` is
79
- * declared inside the object its FACTORY builds from an engine context, and standing a fake
80
- * context up per admission call to interrogate a static declaration would be a shortcut, not a
81
- * design. So the deployment that registered the gate owns the answer to it, in whatever surface
82
- * it registered it for, and the run reports `parked: true` with an empty decision list until then.
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 { HUMAN_WAIT_GATE_KINDS };
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 one of the
139
- * {@link HUMAN_WAIT_GATE_KINDS} unbounded-wait gates. Parking is not a defect: it is the
140
- * clarification loop. It just needs an answerer, which is what the `decide` scope asserts.
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, registry: AgentKindRegistry): boolean;
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 HUMAN_WAIT_GATE_KINDS});
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 (a kind list, a `pollExhaustion` value pinned by a drift guard, a
160
- * registered trait) rather than from a hand-kept list of pipelines. Whatever is added next should
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
- * THREE THINGS ARE DELIBERATELY NOT HERE, and they are absent for three different reasons:
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, registry: AgentKindRegistry): string[];
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, registry: AgentKindRegistry, options: {
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, registry: AgentKindRegistry): boolean;
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,qBAAqB,EAAE,MAAM,wBAAwB,CAAA;AAE9D;;;;;;;;;;;;;;;;;;;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;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,sBAAsB,cAAc,CAAA;AAEjD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,OAAO,EAAE,qBAAqB,EAAE,CAAA;AAEhC;;;;;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;;;;;GAKG;AACH,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,uBAAuB,EACjC,QAAQ,EAAE,iBAAiB,GAC1B,OAAO,CAET;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,uBAAuB,EACjC,QAAQ,EAAE,iBAAiB,GAC1B,MAAM,EAAE,CAQV;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,QAAQ,EAAE,iBAAiB,EAC3B,OAAO,EAAE;IAAE,eAAe,EAAE,OAAO,CAAA;CAAE,GACpC,MAAM,EAAE,CAKV;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,CACtC,QAAQ,EAAE,uBAAuB,EACjC,QAAQ,EAAE,iBAAiB,GAC1B,OAAO,CAET"}
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, the opposite of the wait-gate gap {@link HUMAN_WAIT_GATE_KINDS}
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
- * POLLING-GATE kinds that park on a human, re-exported from `@cat-factory/contracts` so every park
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 category beside {@link PARKING_INLINE_KINDS} and {@link APPROVAL_GATE_PARK_SURFACE},
82
- * because it is a third MECHANISM: not an inline review that sets the run `blocked`, and not an
83
- * approval flag riding an ordinary step, but a gate step whose own poll loop never times out
84
- * (`pollExhaustion: 'rearm'`) because it is waiting on a person. `human-review` is the one built-in
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 answerable through
89
- * `/api/v1/runs/:runId/decisions` at all, so a plain `write` key could start the platform's flagship
90
- * board preset and have it park forever on the one surface with no public answer path.
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
- * ONLY BUILT-IN GATES ARE IN IT, and a deployment that registers its own unbounded-wait gate
93
- * through the public `GateRegistry` seam is therefore INVISIBLE to this check: such a pipeline is
94
- * admitted for a plain `write` key and then parks with nothing here able to name it. That is a
95
- * limit of what a request-time check can read, not an oversight: a gate's `pollExhaustion` is
96
- * declared inside the object its FACTORY builds from an engine context, and standing a fake
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 { HUMAN_WAIT_GATE_KINDS };
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 one of the
167
- * {@link HUMAN_WAIT_GATE_KINDS} unbounded-wait gates. Parking is not a defect: it is the
168
- * clarification loop. It just needs an answerer, which is what the `decide` scope asserts.
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, registry) {
171
- return parkSurfacesOf(pipeline, registry).length > 0;
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 HUMAN_WAIT_GATE_KINDS});
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 (a kind list, a `pollExhaustion` value pinned by a drift guard, a
190
- * registered trait) rather than from a hand-kept list of pipelines. Whatever is added next should
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
- * THREE THINGS ARE DELIBERATELY NOT HERE, and they are absent for three different reasons:
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, registry) {
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) || HUMAN_WAIT_GATE_KINDS.has(kind))
216
+ if (PARKING_INLINE_KINDS.has(kind) || isHumanWaitGate(kind, registries.gates)) {
219
217
  surfaces.add(kind);
220
- if (hasTrait(kind, INTERVIEW_GATE_TRAIT, registry))
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, registry, options) {
272
- const surfaces = parkSurfacesOf(pipeline, registry);
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, registry) {
284
- return isInlineOnlyPipeline(pipeline, registry) && !canParkOnHuman(pipeline, registry);
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":"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"}
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;AAG5B;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,IAAI,GAAG,CAAS;IAClD,8BAA8B;IAC9B,yBAAyB;IACzB,kCAAkC;IAClC,kCAAkC;CACnC,CAAC,CAAA;AAEF;;;;GAIG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAG,eAAe,CAAA;AAEzD;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG,YAAY,CAAA;AAEnD;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,WAAW,CAAA;AAEjD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,UAAU,eAAe,CAAC,IAAY,EAAE,KAAmB;IAC/D,OAAO,KAAK,CAAC,cAAc,CAAC,IAAI,CAAC,KAAK,OAAO,CAAA;AAC/C,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,8BAA8B,CAAA;AACpE,MAAM,CAAC,MAAM,qBAAqB,GAAG,iCAAiC,CAAA;AAEtE;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,CAAC,MAAM,iCAAiC,GAAG,IAAI,GAAG,CAAS;IAC/D,8BAA8B;IAC9B,yBAAyB;IACzB,kCAAkC;IAClC,kCAAkC;IAClC,uBAAuB;IACvB,0BAA0B;IAC1B,sBAAsB;CACvB,CAAC,CAAA;AAWF,mGAAmG;AACnG,SAAS,YAAY,CAAC,QAAiC;IACrD,OAAO,QAAQ,CAAC,UAAU;SACvB,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC;SAC/B,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC,CAAA;AACvD,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,oBAAoB,CAClC,QAAiC,EACjC,QAA2B;IAE3B,MAAM,OAAO,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAA;IACtC,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,KAAK,CAAA;IACtC,OAAO,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,iBAAiB,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAA;AACvE,CAAC;AAcD;;;;;;;GAOG;AACH,MAAM,UAAU,mBAAmB,CAAC,MAGnC;IACC,OAAO,EAAE,UAAU,EAAE,MAAM,CAAC,iBAAiB,EAAE,KAAK,EAAE,MAAM,CAAC,YAAY,EAAE,CAAA;AAC7E,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAC5B,QAAiC,EACjC,UAA+B;IAE/B,OAAO,cAAc,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC,MAAM,GAAG,CAAC,CAAA;AACxD,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,MAAM,UAAU,cAAc,CAC5B,QAAiC,EACjC,UAA+B;IAE/B,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAU,CAAA;IAClC,KAAK,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,YAAY,CAAC,QAAQ,CAAC,EAAE,CAAC;QACjD,IAAI,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;YAAE,QAAQ,CAAC,GAAG,CAAC,0BAA0B,CAAC,CAAA;QACjE,IAAI,oBAAoB,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,eAAe,CAAC,IAAI,EAAE,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;YAC9E,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;QACpB,CAAC;QACD,IAAI,QAAQ,CAAC,IAAI,EAAE,oBAAoB,EAAE,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;YAChE,QAAQ,CAAC,GAAG,CAAC,sBAAsB,CAAC,CAAA;QACtC,CAAC;IACH,CAAC;IACD,OAAO,CAAC,GAAG,QAAQ,CAAC,CAAA;AACtB,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,UAAU,qBAAqB,CAAC,QAAkB,EAAE,OAA+B;IACvF,MAAM,EAAE,UAAU,EAAE,GAAG,OAAO,CAAA;IAC9B,MAAM,UAAU,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,iCAAiC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAA;IACnF,MAAM,YAAY,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,iCAAiC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAA;IACtF,MAAM,KAAK,GAAG,CAAC,+CAA+C,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IACtF,KAAK,CAAC,IAAI,CACR,UAAU,CAAC,MAAM,GAAG,CAAC;QACnB,CAAC,CAAC,wDAAwD,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,yCAAyC;QACxH,CAAC,CAAC,yCAAyC,CAC9C,CAAA;IACD,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC5B,KAAK,CAAC,IAAI,CACR,6CAA6C,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,iFAAiF,UAAU,GAAG,CACnK,CAAA;IACH,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;AACxB,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,qBAAqB,CACnC,QAAiC,EACjC,UAA+B,EAC/B,OAAqC;IAErC,MAAM,QAAQ,GAAG,cAAc,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAA;IACrD,6FAA6F;IAC7F,uEAAuE;IACvE,OAAO,OAAO,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,uBAAuB,EAAE,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAA;AACpF,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,wBAAwB,CACtC,QAAiC,EACjC,UAA+B;IAE/B,OAAO,CACL,oBAAoB,CAAC,QAAQ,EAAE,UAAU,CAAC,UAAU,CAAC,IAAI,CAAC,cAAc,CAAC,QAAQ,EAAE,UAAU,CAAC,CAC/F,CAAA;AACH,CAAC"}
@@ -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;AAU7D;;;;;;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"}
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,sBAkxCxC,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"}
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