@cat-factory/kernel 0.324.0 → 0.326.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 (52) hide show
  1. package/dist/domain/environment-reachability.logic.d.ts +131 -0
  2. package/dist/domain/environment-reachability.logic.d.ts.map +1 -0
  3. package/dist/domain/environment-reachability.logic.js +277 -0
  4. package/dist/domain/environment-reachability.logic.js.map +1 -0
  5. package/dist/domain/environment-readiness.logic.d.ts +22 -0
  6. package/dist/domain/environment-readiness.logic.d.ts.map +1 -1
  7. package/dist/domain/environment-readiness.logic.js +35 -10
  8. package/dist/domain/environment-readiness.logic.js.map +1 -1
  9. package/dist/domain/types.d.ts +1 -1
  10. package/dist/domain/types.d.ts.map +1 -1
  11. package/dist/index.d.ts +6 -5
  12. package/dist/index.d.ts.map +1 -1
  13. package/dist/index.js +10 -4
  14. package/dist/index.js.map +1 -1
  15. package/dist/ports/agent-executor.d.ts +35 -1
  16. package/dist/ports/agent-executor.d.ts.map +1 -1
  17. package/dist/ports/agent-executor.js.map +1 -1
  18. package/dist/ports/environment-diagnostics.d.ts +119 -0
  19. package/dist/ports/environment-diagnostics.d.ts.map +1 -0
  20. package/dist/ports/environment-diagnostics.js +2 -0
  21. package/dist/ports/environment-diagnostics.js.map +1 -0
  22. package/dist/ports/environment-investigation.d.ts +132 -0
  23. package/dist/ports/environment-investigation.d.ts.map +1 -0
  24. package/dist/ports/environment-investigation.js +2 -0
  25. package/dist/ports/environment-investigation.js.map +1 -0
  26. package/dist/ports/environment-provider.d.ts +47 -1
  27. package/dist/ports/environment-provider.d.ts.map +1 -1
  28. package/dist/ports/environment-repositories.d.ts +25 -1
  29. package/dist/ports/environment-repositories.d.ts.map +1 -1
  30. package/dist/ports/index.d.ts +4 -1
  31. package/dist/ports/index.d.ts.map +1 -1
  32. package/dist/ports/index.js.map +1 -1
  33. package/dist/ports/route-probe.d.ts +68 -0
  34. package/dist/ports/route-probe.d.ts.map +1 -0
  35. package/dist/ports/route-probe.js +2 -0
  36. package/dist/ports/route-probe.js.map +1 -0
  37. package/dist/ports/runner-transport.d.ts +26 -6
  38. package/dist/ports/runner-transport.d.ts.map +1 -1
  39. package/dist/ports/runner-transport.js.map +1 -1
  40. package/dist/shared/environment-host-bridge.logic.d.ts +100 -6
  41. package/dist/shared/environment-host-bridge.logic.d.ts.map +1 -1
  42. package/dist/shared/environment-host-bridge.logic.js +113 -6
  43. package/dist/shared/environment-host-bridge.logic.js.map +1 -1
  44. package/dist/shared/ip-host.logic.d.ts +16 -0
  45. package/dist/shared/ip-host.logic.d.ts.map +1 -1
  46. package/dist/shared/ip-host.logic.js +52 -0
  47. package/dist/shared/ip-host.logic.js.map +1 -1
  48. package/dist/shared/redact-secrets.logic.d.ts +20 -0
  49. package/dist/shared/redact-secrets.logic.d.ts.map +1 -1
  50. package/dist/shared/redact-secrets.logic.js +46 -0
  51. package/dist/shared/redact-secrets.logic.js.map +1 -1
  52. package/package.json +2 -2
@@ -0,0 +1,131 @@
1
+ import type { EnvironmentAddress, EnvironmentRouteAttempt, EnvironmentRouteProof, EnvironmentUnreachableReason } from '@cat-factory/contracts';
2
+ import type { RouteProbeOutcome, RouteProbeRequest } from '../ports/route-probe.js';
3
+ /** How long one target gets before it counts as a route that does not carry. */
4
+ export declare const ROUTE_PROBE_TIMEOUT_MS = 4000;
5
+ /**
6
+ * How many stated addresses a proof will try, on top of the name itself.
7
+ *
8
+ * Bounded because the list is provider-supplied and the proof runs inside the deployer's settle
9
+ * path: an unbounded list is an unbounded stall on a run that is otherwise ready to proceed. Four
10
+ * covers the shape this exists for (an internal and a public balancer per environment, with room
11
+ * for a second availability zone) and the consumer measured live balancers answering in 34ms to
12
+ * 162ms, so the ceiling is well under a second of ordinary cost.
13
+ */
14
+ export declare const MAX_PROBED_ADDRESSES = 4;
15
+ /**
16
+ * One target a proof will try, in the order the proof will try it.
17
+ *
18
+ * A discriminated union rather than a dial target with a "skip me" flag, because the refused
19
+ * member carries NO {@link RouteProbeRequest}: an address the platform will not dial must be
20
+ * structurally undialable by whoever iterates this list, not merely marked. Handing out a request
21
+ * beside a boolean is how the next caller opens the socket anyway.
22
+ */
23
+ export type RouteProbeTarget =
24
+ /** Open a socket to this. `address` is null when the target dials the URL's own name. */
25
+ {
26
+ kind: 'dial';
27
+ request: RouteProbeRequest;
28
+ address: string | null;
29
+ label: string;
30
+ }
31
+ /** RECORD this and dial nothing: a stated address {@link isBridgeableAddress} refuses. */
32
+ | {
33
+ kind: 'refused';
34
+ address: string;
35
+ label: string;
36
+ reason: EnvironmentUnreachableReason;
37
+ };
38
+ /**
39
+ * The targets a proof tries for one environment, in order: the URL's own name first, then each
40
+ * stated address in the PROVIDER'S preference order.
41
+ *
42
+ * The name goes first because it is the answer that needs no bridge, and a deployment where it
43
+ * works must not start paying for `--add-host` entries and the warm-pool evictions they cost. The
44
+ * addresses keep the provider's order because the provider is the only thing that knows which of
45
+ * its balancers is the one it wants used; the platform decides only which one CARRIED.
46
+ *
47
+ * **A stated address is dialled only if a bridge could NAME it.** The rule is
48
+ * `isBridgeableAddress`, and applying it HERE rather than only at bridge-build time is the whole
49
+ * safety property of the probe: `addresses` is provider-authored data, so without it the
50
+ * orchestrator opens sockets wherever a manifest says and records the results on a row a workspace
51
+ * can read back, which is a liveness oracle against the deployment's own private network. The
52
+ * refusal costs nothing real either, because an address no bridge may name is an address no
53
+ * container could be pointed at, so proving it would prove something unusable. Refused addresses
54
+ * are RECORDED (`kind: 'refused'`) rather than dropped: a shortened list nobody is told about is
55
+ * how a provider's bad address becomes an unexplained `name_unresolved`.
56
+ *
57
+ * Empty when there is no host or port to dial, which the caller reads as `no_candidate`: an
58
+ * environment with no URL was never going to be reached, and that is a different fact from one
59
+ * that was tried and failed.
60
+ */
61
+ export declare function planRouteProbes(host: string | null | undefined, port: number | null | undefined, candidates?: readonly EnvironmentAddress[], timeoutMs?: number): RouteProbeTarget[];
62
+ /**
63
+ * Record one DIALLED attempt for the proof's log, whether it carried or not.
64
+ *
65
+ * `detail` rides along for the one outcome that names no layer: `probe_failed` says "we could not
66
+ * tell", and the probe's own message is then the only thing that distinguishes a resolver fault
67
+ * from a runtime restriction from a bug here. Capped rather than dropped or passed whole, because
68
+ * it lands in an operator's failure prose and in an agent's prompt.
69
+ */
70
+ export declare function recordRouteAttempt(target: Extract<RouteProbeTarget, {
71
+ kind: 'dial';
72
+ }>, outcome: RouteProbeOutcome): EnvironmentRouteAttempt;
73
+ /** Record a target the platform REFUSED to dial, so the omission is on the proof rather than lost. */
74
+ export declare function recordRefusedAttempt(target: Extract<RouteProbeTarget, {
75
+ kind: 'refused';
76
+ }>): EnvironmentRouteAttempt;
77
+ /**
78
+ * Fold a completed set of attempts into the proof that is stored and narrated.
79
+ *
80
+ * Three outcomes, and which one this returns is the most consequential line in the feature,
81
+ * because only `not_reached` fails a deployer frame:
82
+ *
83
+ * - **`reached`** as soon as any attempt carried, publishing the target that did.
84
+ * - **`inconclusive`** when nothing carried AND some attempt left a route unruled-out: a probe
85
+ * that could not classify its own failure, or nothing to try at all. A workerd connect message
86
+ * matching none of that facade's markers, or a Node errno outside the mapped five, arrives
87
+ * here, and reading either as a verdict about the environment is how a diagnostic becomes a
88
+ * second way for a healthy deploy to die. The reason names the attempt that left it unknown.
89
+ * - **`not_reached`** only when EVERY attempt established something and none of them carried.
90
+ * The reported reason is then the FIRST attempt's, which is always the name, so a reader is
91
+ * told what happened to the address they were given rather than what happened to the last
92
+ * balancer in someone's preference list. The attempt log carries the rest, in order.
93
+ */
94
+ export declare function reduceRouteProof(attempts: readonly EnvironmentRouteAttempt[], carriedVia: string | null, checkedAt: number): EnvironmentRouteProof;
95
+ /**
96
+ * The operator-facing sentence for an environment nothing could reach, with every target tried.
97
+ *
98
+ * States the LAYER rather than a verdict about the application, because they are different faults
99
+ * with different owners and the whole point of proving the route is to stop reporting one as the
100
+ * other. The attempt list is included verbatim, each attempt carrying its `detail` where it has
101
+ * one: a reader who wants to reproduce the finding needs the exact targets, the reason alone names
102
+ * none of them, and a `probe_failed` with its detail stripped is a sentence saying only that
103
+ * something went wrong somewhere.
104
+ */
105
+ export declare function describeUnreachableEnvironment(url: string | null, proof: EnvironmentRouteProof): string;
106
+ /**
107
+ * The operator-facing sentence for a proof that established nothing either way, with every target
108
+ * tried.
109
+ *
110
+ * Its own describer rather than a branch inside {@link describeUnreachableEnvironment}, because
111
+ * every clause differs: this one may not say "unreachable", must not name a layer as the fault,
112
+ * and exists to be readable beside a run that CONTINUED. Nothing settles on it; it is what the
113
+ * deployer logs and what the environment surface shows so an inconclusive proof is visible rather
114
+ * than merely harmless.
115
+ */
116
+ export declare function describeInconclusiveRoute(url: string | null, proof: EnvironmentRouteProof): string;
117
+ /**
118
+ * The proof recorded when nothing was wired to open a socket.
119
+ *
120
+ * Its own constructor rather than a `not_reached` with a special reason, because the two are
121
+ * verdicts about different things: `not_reached` is about the environment and fails the frame,
122
+ * `unproved` is about the deployment and must never fail anything. A facade that cannot probe is
123
+ * a facade that behaves exactly as it did before this existed.
124
+ *
125
+ * Distinct from `inconclusive` too, which is the probe having RUN and established nothing. Both
126
+ * are admissions rather than verdicts, and the difference is who is told: an inconclusive proof is
127
+ * narrated to the agent that has to interpret a connection failure, an unproved one is withheld
128
+ * from every prompt (`reachabilityNote`) because it is the standing state of the deployment.
129
+ */
130
+ export declare function unprovedRoute(checkedAt: number): EnvironmentRouteProof;
131
+ //# sourceMappingURL=environment-reachability.logic.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"environment-reachability.logic.d.ts","sourceRoot":"","sources":["../../src/domain/environment-reachability.logic.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EACV,kBAAkB,EAClB,uBAAuB,EACvB,qBAAqB,EACrB,4BAA4B,EAC7B,MAAM,wBAAwB,CAAA;AAE/B,OAAO,KAAK,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAA;AAMnF,gFAAgF;AAChF,eAAO,MAAM,sBAAsB,OAAO,CAAA;AAE1C;;;;;;;;GAQG;AACH,eAAO,MAAM,oBAAoB,IAAI,CAAA;AAErC;;;;;;;GAOG;AACH,MAAM,MAAM,gBAAgB;AAC1B,yFAAyF;AACvF;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,iBAAiB,CAAC;IAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE;AACrF,0FAA0F;GACxF;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,4BAA4B,CAAA;CAAE,CAAA;AAE7F;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAC/B,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAC/B,UAAU,GAAE,SAAS,kBAAkB,EAAO,EAC9C,SAAS,GAAE,MAA+B,GACzC,gBAAgB,EAAE,CA4BpB;AA8BD;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,OAAO,CAAC,gBAAgB,EAAE;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,EACnD,OAAO,EAAE,iBAAiB,GACzB,uBAAuB,CAQzB;AAED,sGAAsG;AACtG,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,OAAO,CAAC,gBAAgB,EAAE;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,CAAC,GACrD,uBAAuB,CAEzB;AAwCD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,SAAS,uBAAuB,EAAE,EAC5C,UAAU,EAAE,MAAM,GAAG,IAAI,EACzB,SAAS,EAAE,MAAM,GAChB,qBAAqB,CA6BvB;AAcD;;;;;;;;;GASG;AACH,wBAAgB,8BAA8B,CAC5C,GAAG,EAAE,MAAM,GAAG,IAAI,EAClB,KAAK,EAAE,qBAAqB,GAC3B,MAAM,CAKR;AAED;;;;;;;;;GASG;AACH,wBAAgB,yBAAyB,CACvC,GAAG,EAAE,MAAM,GAAG,IAAI,EAClB,KAAK,EAAE,qBAAqB,GAC3B,MAAM,CAKR;AAaD;;;;;;;;;;;;GAYG;AACH,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,qBAAqB,CAEtE"}
@@ -0,0 +1,277 @@
1
+ // Proving that a `ready` environment can be reached: what to try, in what order, and what the
2
+ // answers add up to.
3
+ //
4
+ // The rule lives here rather than in the provisioning service because two layers act on the
5
+ // result and neither may re-derive it: the DEPLOYER settles a frame on the verdict, and the
6
+ // container transports build a host bridge out of the address that carried. A second derivation
7
+ // is how the platform would come to record a bridge as applied against an address nothing ever
8
+ // reached, which is strictly worse evidence than no bridge at all.
9
+ //
10
+ // Deliberately not a gate. `docs/initiatives/deployment-failure-remediation.md` withdrew a
11
+ // `deploy-health` gate that would have probed the environment handle, on the grounds that the
12
+ // deployer owns provisioning through to a terminal verdict, and this is that verdict getting one
13
+ // more fact behind it.
14
+ import { environmentUnreachableReasonSchema } from '@cat-factory/contracts';
15
+ import { isBridgeableAddress } from '../shared/environment-host-bridge.logic.js';
16
+ /** How much of a probe's own error message is kept on the attempt it explains. */
17
+ const MAX_PROBE_DETAIL_CHARS = 200;
18
+ /** How long one target gets before it counts as a route that does not carry. */
19
+ export const ROUTE_PROBE_TIMEOUT_MS = 4000;
20
+ /**
21
+ * How many stated addresses a proof will try, on top of the name itself.
22
+ *
23
+ * Bounded because the list is provider-supplied and the proof runs inside the deployer's settle
24
+ * path: an unbounded list is an unbounded stall on a run that is otherwise ready to proceed. Four
25
+ * covers the shape this exists for (an internal and a public balancer per environment, with room
26
+ * for a second availability zone) and the consumer measured live balancers answering in 34ms to
27
+ * 162ms, so the ceiling is well under a second of ordinary cost.
28
+ */
29
+ export const MAX_PROBED_ADDRESSES = 4;
30
+ /**
31
+ * The targets a proof tries for one environment, in order: the URL's own name first, then each
32
+ * stated address in the PROVIDER'S preference order.
33
+ *
34
+ * The name goes first because it is the answer that needs no bridge, and a deployment where it
35
+ * works must not start paying for `--add-host` entries and the warm-pool evictions they cost. The
36
+ * addresses keep the provider's order because the provider is the only thing that knows which of
37
+ * its balancers is the one it wants used; the platform decides only which one CARRIED.
38
+ *
39
+ * **A stated address is dialled only if a bridge could NAME it.** The rule is
40
+ * `isBridgeableAddress`, and applying it HERE rather than only at bridge-build time is the whole
41
+ * safety property of the probe: `addresses` is provider-authored data, so without it the
42
+ * orchestrator opens sockets wherever a manifest says and records the results on a row a workspace
43
+ * can read back, which is a liveness oracle against the deployment's own private network. The
44
+ * refusal costs nothing real either, because an address no bridge may name is an address no
45
+ * container could be pointed at, so proving it would prove something unusable. Refused addresses
46
+ * are RECORDED (`kind: 'refused'`) rather than dropped: a shortened list nobody is told about is
47
+ * how a provider's bad address becomes an unexplained `name_unresolved`.
48
+ *
49
+ * Empty when there is no host or port to dial, which the caller reads as `no_candidate`: an
50
+ * environment with no URL was never going to be reached, and that is a different fact from one
51
+ * that was tried and failed.
52
+ */
53
+ export function planRouteProbes(host, port, candidates = [], timeoutMs = ROUTE_PROBE_TIMEOUT_MS) {
54
+ if (!host || !port)
55
+ return [];
56
+ const targets = [
57
+ { kind: 'dial', request: { host, port, timeoutMs }, address: null, label: `${host}:${port}` },
58
+ ];
59
+ const seen = new Set();
60
+ let dialable = 0;
61
+ let refused = 0;
62
+ for (const candidate of candidates) {
63
+ const address = candidate.address.trim();
64
+ if (!address || seen.has(address))
65
+ continue;
66
+ seen.add(address);
67
+ const label = `${host}@${address}:${port}`;
68
+ // Bounded separately, and by `continue` rather than `break`, so a manifest listing four
69
+ // refused addresses ahead of a good one still gets the good one dialled. A refusal costs no
70
+ // I/O; the dial budget is what the deployer's settle path is actually waiting on.
71
+ if (!isBridgeableAddress(address)) {
72
+ if (refused < MAX_PROBED_ADDRESSES) {
73
+ refused += 1;
74
+ targets.push({ kind: 'refused', address, label, reason: 'address_refused' });
75
+ }
76
+ continue;
77
+ }
78
+ if (dialable >= MAX_PROBED_ADDRESSES)
79
+ continue;
80
+ dialable += 1;
81
+ targets.push({ kind: 'dial', request: { host, address, port, timeoutMs }, address, label });
82
+ }
83
+ return targets;
84
+ }
85
+ /**
86
+ * The user-facing reason one probe outcome states, for the target it was tried against.
87
+ *
88
+ * A NAME that does not resolve and an ADDRESS that does not resolve are not the same event, and
89
+ * only the first can happen: an address is dialled, never looked up. A resolver answering
90
+ * `unresolved` for a literal is a probe malfunction, so it is reported as `probe_failed` rather
91
+ * than as a claim about DNS that would send a reader to the wrong zone.
92
+ */
93
+ function reasonFor(outcome, address) {
94
+ switch (outcome.state) {
95
+ case 'carried':
96
+ // Never reached: `recordRouteAttempt` answers `carried` before asking. Present so the
97
+ // switch stays total against the port's union.
98
+ return 'probe_failed';
99
+ case 'unresolved':
100
+ return address === null ? 'name_unresolved' : 'probe_failed';
101
+ case 'no_route':
102
+ return 'no_route';
103
+ case 'refused':
104
+ return 'connection_refused';
105
+ case 'failed':
106
+ return 'probe_failed';
107
+ }
108
+ }
109
+ /**
110
+ * Record one DIALLED attempt for the proof's log, whether it carried or not.
111
+ *
112
+ * `detail` rides along for the one outcome that names no layer: `probe_failed` says "we could not
113
+ * tell", and the probe's own message is then the only thing that distinguishes a resolver fault
114
+ * from a runtime restriction from a bug here. Capped rather than dropped or passed whole, because
115
+ * it lands in an operator's failure prose and in an agent's prompt.
116
+ */
117
+ export function recordRouteAttempt(target, outcome) {
118
+ if (outcome.state === 'carried')
119
+ return { target: target.label, outcome: 'carried' };
120
+ const detail = outcome.state === 'failed' ? outcome.detail.trim() : '';
121
+ return {
122
+ target: target.label,
123
+ outcome: reasonFor(outcome, target.address),
124
+ ...(detail ? { detail: detail.slice(0, MAX_PROBE_DETAIL_CHARS) } : {}),
125
+ };
126
+ }
127
+ /** Record a target the platform REFUSED to dial, so the omission is on the proof rather than lost. */
128
+ export function recordRefusedAttempt(target) {
129
+ return { target: target.label, outcome: target.reason };
130
+ }
131
+ /**
132
+ * Whether one attempt's outcome leaves a route the platform never actually RULED OUT.
133
+ *
134
+ * The rule that decides whether a proof is a verdict about the environment or an admission about
135
+ * the platform, and it lives here because two layers read the answer and neither may re-derive it:
136
+ * the deployer fails a frame on the first and must never fail one on the second. `probe_failed`
137
+ * names no layer by construction, so an attempt that produced it establishes nothing; every other
138
+ * outcome does establish something, `address_refused` included, since an address no bridge may
139
+ * name is one no container could have been pointed at either way.
140
+ */
141
+ const LEAVES_ROUTE_UNKNOWN = {
142
+ no_candidate: true,
143
+ name_unresolved: false,
144
+ no_route: false,
145
+ connection_refused: false,
146
+ address_refused: false,
147
+ probe_failed: true,
148
+ };
149
+ /**
150
+ * Read an attempt's stored outcome as a known reason, or undefined.
151
+ *
152
+ * Derived from the picklist's own options rather than a hand-listed set, so adding a member fails
153
+ * the `Record` above until it has picked a side. An outcome this build does not know (a proof
154
+ * written by a newer one) is treated as leaving the route unknown, which is the disposition that
155
+ * cannot turn an unreadable value into a failed deploy.
156
+ */
157
+ function knownReason(outcome) {
158
+ return environmentUnreachableReasonSchema.options.includes(outcome)
159
+ ? outcome
160
+ : undefined;
161
+ }
162
+ function leavesRouteUnknown(outcome) {
163
+ const reason = knownReason(outcome);
164
+ return reason === undefined || LEAVES_ROUTE_UNKNOWN[reason];
165
+ }
166
+ /**
167
+ * Fold a completed set of attempts into the proof that is stored and narrated.
168
+ *
169
+ * Three outcomes, and which one this returns is the most consequential line in the feature,
170
+ * because only `not_reached` fails a deployer frame:
171
+ *
172
+ * - **`reached`** as soon as any attempt carried, publishing the target that did.
173
+ * - **`inconclusive`** when nothing carried AND some attempt left a route unruled-out: a probe
174
+ * that could not classify its own failure, or nothing to try at all. A workerd connect message
175
+ * matching none of that facade's markers, or a Node errno outside the mapped five, arrives
176
+ * here, and reading either as a verdict about the environment is how a diagnostic becomes a
177
+ * second way for a healthy deploy to die. The reason names the attempt that left it unknown.
178
+ * - **`not_reached`** only when EVERY attempt established something and none of them carried.
179
+ * The reported reason is then the FIRST attempt's, which is always the name, so a reader is
180
+ * told what happened to the address they were given rather than what happened to the last
181
+ * balancer in someone's preference list. The attempt log carries the rest, in order.
182
+ */
183
+ export function reduceRouteProof(attempts, carriedVia, checkedAt) {
184
+ if (attempts.some((attempt) => attempt.outcome === 'carried'))
185
+ return { state: 'reached', via: carriedVia, reason: null, attempts: [...attempts], checkedAt };
186
+ if (attempts.length === 0) {
187
+ return {
188
+ state: 'inconclusive',
189
+ via: null,
190
+ reason: 'no_candidate',
191
+ attempts: [],
192
+ checkedAt,
193
+ };
194
+ }
195
+ const unknown = attempts.find((attempt) => leavesRouteUnknown(attempt.outcome));
196
+ if (unknown) {
197
+ return {
198
+ state: 'inconclusive',
199
+ via: null,
200
+ reason: unknown.outcome,
201
+ attempts: [...attempts],
202
+ checkedAt,
203
+ };
204
+ }
205
+ return {
206
+ state: 'not_reached',
207
+ via: null,
208
+ reason: attempts[0]?.outcome ?? 'probe_failed',
209
+ attempts: [...attempts],
210
+ checkedAt,
211
+ };
212
+ }
213
+ /** What each unreachable reason means for whoever has to fix it, in one clause. */
214
+ const UNREACHABLE_CAUSES = {
215
+ no_candidate: 'the environment carries no address to try, so nothing could be dialled',
216
+ name_unresolved: 'its hostname resolves nowhere from this deployment, and no address the provider stated for it carried either',
217
+ no_route: 'nothing answered within the probe window, so no route reaches it',
218
+ connection_refused: 'the route reaches it and nothing is listening on that port',
219
+ address_refused: 'every address its provider stated is one no host bridge may name (loopback, link-local or vendor metadata, or a non-canonical literal), so none could be dialled',
220
+ probe_failed: 'the probe could not complete, so nothing was established either way',
221
+ };
222
+ /**
223
+ * The operator-facing sentence for an environment nothing could reach, with every target tried.
224
+ *
225
+ * States the LAYER rather than a verdict about the application, because they are different faults
226
+ * with different owners and the whole point of proving the route is to stop reporting one as the
227
+ * other. The attempt list is included verbatim, each attempt carrying its `detail` where it has
228
+ * one: a reader who wants to reproduce the finding needs the exact targets, the reason alone names
229
+ * none of them, and a `probe_failed` with its detail stripped is a sentence saying only that
230
+ * something went wrong somewhere.
231
+ */
232
+ export function describeUnreachableEnvironment(url, proof) {
233
+ const reason = proof.reason;
234
+ const cause = (reason && UNREACHABLE_CAUSES[reason]) || UNREACHABLE_CAUSES.probe_failed;
235
+ const where = url ? `The environment at ${url} is unreachable` : 'The environment is unreachable';
236
+ return `${where}: ${cause}.${describeRouteAttempts(proof)}`;
237
+ }
238
+ /**
239
+ * The operator-facing sentence for a proof that established nothing either way, with every target
240
+ * tried.
241
+ *
242
+ * Its own describer rather than a branch inside {@link describeUnreachableEnvironment}, because
243
+ * every clause differs: this one may not say "unreachable", must not name a layer as the fault,
244
+ * and exists to be readable beside a run that CONTINUED. Nothing settles on it; it is what the
245
+ * deployer logs and what the environment surface shows so an inconclusive proof is visible rather
246
+ * than merely harmless.
247
+ */
248
+ export function describeInconclusiveRoute(url, proof) {
249
+ const reason = proof.reason;
250
+ const cause = (reason && UNREACHABLE_CAUSES[reason]) || UNREACHABLE_CAUSES.probe_failed;
251
+ const where = url ? `The route to the environment at ${url}` : 'The route to the environment';
252
+ return `${where} could not be established either way: ${cause}.${describeRouteAttempts(proof)}`;
253
+ }
254
+ /** ` Tried: <target> (<outcome>: <detail>), ….`, or empty when nothing was tried. */
255
+ function describeRouteAttempts(proof) {
256
+ const tried = proof.attempts
257
+ .map((attempt) => `${attempt.target} (${attempt.outcome}${attempt.detail ? `: ${attempt.detail}` : ''})`)
258
+ .join(', ');
259
+ return tried ? ` Tried: ${tried}.` : '';
260
+ }
261
+ /**
262
+ * The proof recorded when nothing was wired to open a socket.
263
+ *
264
+ * Its own constructor rather than a `not_reached` with a special reason, because the two are
265
+ * verdicts about different things: `not_reached` is about the environment and fails the frame,
266
+ * `unproved` is about the deployment and must never fail anything. A facade that cannot probe is
267
+ * a facade that behaves exactly as it did before this existed.
268
+ *
269
+ * Distinct from `inconclusive` too, which is the probe having RUN and established nothing. Both
270
+ * are admissions rather than verdicts, and the difference is who is told: an inconclusive proof is
271
+ * narrated to the agent that has to interpret a connection failure, an unproved one is withheld
272
+ * from every prompt (`reachabilityNote`) because it is the standing state of the deployment.
273
+ */
274
+ export function unprovedRoute(checkedAt) {
275
+ return { state: 'unproved', via: null, reason: null, attempts: [], checkedAt };
276
+ }
277
+ //# sourceMappingURL=environment-reachability.logic.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"environment-reachability.logic.js","sourceRoot":"","sources":["../../src/domain/environment-reachability.logic.ts"],"names":[],"mappings":"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"}
@@ -37,6 +37,13 @@ export interface EnvironmentReadinessInput {
37
37
  status: EnvironmentStatus;
38
38
  /** The provider's own last error, when it recorded one; used verbatim in a `failed` verdict. */
39
39
  lastError?: string | null;
40
+ /**
41
+ * The provider's own account of a state it has not left yet, when it gave one. It is the only
42
+ * channel that survives a `provisioning` poll, because `lastError` is persisted on `failed`
43
+ * alone (see `ProvisionedEnvironment.statusNote`). It is what lets a `timed_out` verdict name
44
+ * the state the environment was stuck in rather than only how long it was stuck.
45
+ */
46
+ statusNote?: string | null;
40
47
  }
41
48
  /**
42
49
  * Human-readable elapsed time for a readiness verdict's message, in the coarsest unit that
@@ -44,6 +51,21 @@ export interface EnvironmentReadinessInput {
44
51
  * operator is quoted a duration rather than a millisecond count.
45
52
  */
46
53
  export declare function describeWaitedFor(ms: number): string;
54
+ /**
55
+ * How an environment that has stopped at a status it will never leave for `ready` is explained to
56
+ * a person: `failed` / `expired` / `tearing_down` / `torn_down`. Shared, because every reader that
57
+ * has to give up on such an environment owes the same account, and the two that stated it
58
+ * separately disagreed about it.
59
+ *
60
+ * The provider's own error is the whole message where it recorded one, because on these statuses
61
+ * that error IS the verdict. With none, the state is NAMED and the last note is APPENDED rather
62
+ * than substituted, and both halves of that matter. Naming the state is what separates "the
63
+ * provider refused it" from "something tore it down under the run", which send an operator to
64
+ * different places. Appending rather than substituting is because a bare note reads as the reason
65
+ * the environment ended up here, which nothing here knows: a `torn_down` row's note describes the
66
+ * spin-up it was in the middle of, not who tore it down.
67
+ */
68
+ export declare function describeTerminalEnvironment(env: EnvironmentReadinessInput): string;
47
69
  /**
48
70
  * Judge one readiness poll: the environment as the provider just reported it, against how long
49
71
  * the step has been waiting.
@@ -1 +1 @@
1
- {"version":3,"file":"environment-readiness.logic.d.ts","sourceRoot":"","sources":["../../src/domain/environment-readiness.logic.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAkBnD;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,4BAA4B,QAAiB,CAAA;AAE1D;;;;;GAKG;AACH,MAAM,MAAM,oBAAoB,GAC5B;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,GACjB;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GACtC;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACjC;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAA;AAExC,iEAAiE;AACjE,MAAM,WAAW,yBAAyB;IACxC,MAAM,EAAE,iBAAiB,CAAA;IACzB,gGAAgG;IAChG,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAC1B;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAOpD;AAED;;;;;;;;;GASG;AACH,wBAAgB,yBAAyB,CACvC,GAAG,EAAE,yBAAyB,EAC9B,QAAQ,EAAE,MAAM,EAChB,SAAS,GAAE,MAAqC,GAC/C,oBAAoB,CAwBtB"}
1
+ {"version":3,"file":"environment-readiness.logic.d.ts","sourceRoot":"","sources":["../../src/domain/environment-readiness.logic.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAkBnD;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,4BAA4B,QAAiB,CAAA;AAE1D;;;;;GAKG;AACH,MAAM,MAAM,oBAAoB,GAC5B;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,GACjB;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GACtC;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACjC;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAA;AAExC,iEAAiE;AACjE,MAAM,WAAW,yBAAyB;IACxC,MAAM,EAAE,iBAAiB,CAAA;IACzB,gGAAgG;IAChG,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB;;;;;OAKG;IACH,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAC3B;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAOpD;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,2BAA2B,CAAC,GAAG,EAAE,yBAAyB,GAAG,MAAM,CAQlF;AAED;;;;;;;;;GASG;AACH,wBAAgB,yBAAyB,CACvC,GAAG,EAAE,yBAAyB,EAC9B,QAAQ,EAAE,MAAM,EAChB,SAAS,GAAE,MAAqC,GAC/C,oBAAoB,CA0BtB"}
@@ -41,6 +41,28 @@ export function describeWaitedFor(ms) {
41
41
  const seconds = Math.max(1, Math.round(ms / 1000));
42
42
  return `${seconds} second${seconds === 1 ? '' : 's'}`;
43
43
  }
44
+ /**
45
+ * How an environment that has stopped at a status it will never leave for `ready` is explained to
46
+ * a person: `failed` / `expired` / `tearing_down` / `torn_down`. Shared, because every reader that
47
+ * has to give up on such an environment owes the same account, and the two that stated it
48
+ * separately disagreed about it.
49
+ *
50
+ * The provider's own error is the whole message where it recorded one, because on these statuses
51
+ * that error IS the verdict. With none, the state is NAMED and the last note is APPENDED rather
52
+ * than substituted, and both halves of that matter. Naming the state is what separates "the
53
+ * provider refused it" from "something tore it down under the run", which send an operator to
54
+ * different places. Appending rather than substituting is because a bare note reads as the reason
55
+ * the environment ended up here, which nothing here knows: a `torn_down` row's note describes the
56
+ * spin-up it was in the middle of, not who tore it down.
57
+ */
58
+ export function describeTerminalEnvironment(env) {
59
+ const failure = env.lastError?.trim();
60
+ if (failure)
61
+ return failure;
62
+ const note = env.statusNote?.trim();
63
+ return (`Environment provisioning did not complete (status: ${env.status}).` +
64
+ (note ? ` Last provider note: ${note}` : ''));
65
+ }
44
66
  /**
45
67
  * Judge one readiness poll: the environment as the provider just reported it, against how long
46
68
  * the step has been waiting.
@@ -54,23 +76,26 @@ export function describeWaitedFor(ms) {
54
76
  export function judgeEnvironmentReadiness(env, waitedMs, timeoutMs = ENVIRONMENT_READY_TIMEOUT_MS) {
55
77
  if (env.status === 'ready')
56
78
  return { kind: 'ready' };
79
+ const failure = env.lastError?.trim();
80
+ const note = env.statusNote?.trim();
81
+ // `failed` / `expired` / `tearing_down` / `torn_down`: none of these becomes `ready` on its own,
82
+ // so waiting out the deadline would only delay the same answer.
57
83
  if (env.status !== 'provisioning') {
58
- // `failed` / `expired` / `tearing_down` / `torn_down`: none of these becomes `ready` on its
59
- // own, so waiting out the deadline would only delay the same answer. Name the state, because
60
- // "the provider refused it" and "something tore it down under the run" send an operator to
61
- // different places.
62
- return {
63
- kind: 'failed',
64
- error: env.lastError?.trim() ||
65
- `Environment provisioning did not complete (status: ${env.status}).`,
66
- };
84
+ return { kind: 'failed', error: describeTerminalEnvironment(env) };
67
85
  }
68
86
  if (waitedMs >= timeoutMs) {
69
87
  return {
70
88
  kind: 'timed_out',
71
89
  error: `Environment was still provisioning after ${describeWaitedFor(waitedMs)}` +
72
90
  ` (readiness ceiling ${describeWaitedFor(timeoutMs)}).` +
73
- (env.lastError?.trim() ? ` Last provider error: ${env.lastError.trim()}` : ''),
91
+ // BOTH, where a caller carries both, each under its own label and the fault FIRST. A
92
+ // recorded fault outranks a note on every reader (it is the more specific claim, and the
93
+ // only one of the two that is a fault), and dropping either would be the misattribution
94
+ // this pair exists to avoid: the note is the one channel a `provisioning` provider had,
95
+ // since that is exactly the status `lastError` is nulled on, so a caller reaching here
96
+ // with a fault as well carries it from an earlier poll and it is not superseded.
97
+ (failure ? ` Last provider error: ${failure}` : '') +
98
+ (note ? ` Last provider note: ${note}` : ''),
74
99
  };
75
100
  }
76
101
  return { kind: 'waiting', elapsedMs: waitedMs };
@@ -1 +1 @@
1
- {"version":3,"file":"environment-readiness.logic.js","sourceRoot":"","sources":["../../src/domain/environment-readiness.logic.ts"],"names":[],"mappings":"AAEA,8EAA8E;AAC9E,2FAA2F;AAC3F,8EAA8E;AAC9E,EAAE;AACF,8FAA8F;AAC9F,6FAA6F;AAC7F,gGAAgG;AAChG,8FAA8F;AAC9F,+FAA+F;AAC/F,6BAA6B;AAC7B,EAAE;AACF,4FAA4F;AAC5F,+FAA+F;AAC/F,6DAA6D;AAC7D,8EAA8E;AAE9E;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,MAAM,4BAA4B,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAA;AAqB1D;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAAC,EAAU;IAC1C,IAAI,EAAE,IAAI,MAAM,EAAE,CAAC;QACjB,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,GAAG,MAAM,CAAC,CAAA;QACvC,OAAO,GAAG,OAAO,UAAU,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAA;IACvD,CAAC;IACD,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,EAAE,GAAG,IAAI,CAAC,CAAC,CAAA;IAClD,OAAO,GAAG,OAAO,UAAU,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAA;AACvD,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,yBAAyB,CACvC,GAA8B,EAC9B,QAAgB,EAChB,SAAS,GAAW,4BAA4B;IAEhD,IAAI,GAAG,CAAC,MAAM,KAAK,OAAO;QAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAA;IACpD,IAAI,GAAG,CAAC,MAAM,KAAK,cAAc,EAAE,CAAC;QAClC,4FAA4F;QAC5F,6FAA6F;QAC7F,2FAA2F;QAC3F,oBAAoB;QACpB,OAAO;YACL,IAAI,EAAE,QAAQ;YACd,KAAK,EACH,GAAG,CAAC,SAAS,EAAE,IAAI,EAAE;gBACrB,sDAAsD,GAAG,CAAC,MAAM,IAAI;SACvE,CAAA;IACH,CAAC;IACD,IAAI,QAAQ,IAAI,SAAS,EAAE,CAAC;QAC1B,OAAO;YACL,IAAI,EAAE,WAAW;YACjB,KAAK,EACH,4CAA4C,iBAAiB,CAAC,QAAQ,CAAC,EAAE;gBACzE,uBAAuB,iBAAiB,CAAC,SAAS,CAAC,IAAI;gBACvD,CAAC,GAAG,CAAC,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,yBAAyB,GAAG,CAAC,SAAS,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACjF,CAAA;IACH,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAA;AACjD,CAAC"}
1
+ {"version":3,"file":"environment-readiness.logic.js","sourceRoot":"","sources":["../../src/domain/environment-readiness.logic.ts"],"names":[],"mappings":"AAEA,8EAA8E;AAC9E,2FAA2F;AAC3F,8EAA8E;AAC9E,EAAE;AACF,8FAA8F;AAC9F,6FAA6F;AAC7F,gGAAgG;AAChG,8FAA8F;AAC9F,+FAA+F;AAC/F,6BAA6B;AAC7B,EAAE;AACF,4FAA4F;AAC5F,+FAA+F;AAC/F,6DAA6D;AAC7D,8EAA8E;AAE9E;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,MAAM,4BAA4B,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAA;AA4B1D;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAAC,EAAU;IAC1C,IAAI,EAAE,IAAI,MAAM,EAAE,CAAC;QACjB,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,GAAG,MAAM,CAAC,CAAA;QACvC,OAAO,GAAG,OAAO,UAAU,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAA;IACvD,CAAC;IACD,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,EAAE,GAAG,IAAI,CAAC,CAAC,CAAA;IAClD,OAAO,GAAG,OAAO,UAAU,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAA;AACvD,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,2BAA2B,CAAC,GAA8B;IACxE,MAAM,OAAO,GAAG,GAAG,CAAC,SAAS,EAAE,IAAI,EAAE,CAAA;IACrC,IAAI,OAAO;QAAE,OAAO,OAAO,CAAA;IAC3B,MAAM,IAAI,GAAG,GAAG,CAAC,UAAU,EAAE,IAAI,EAAE,CAAA;IACnC,OAAO,CACL,sDAAsD,GAAG,CAAC,MAAM,IAAI;QACpE,CAAC,IAAI,CAAC,CAAC,CAAC,wBAAwB,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAC7C,CAAA;AACH,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,yBAAyB,CACvC,GAA8B,EAC9B,QAAgB,EAChB,SAAS,GAAW,4BAA4B;IAEhD,IAAI,GAAG,CAAC,MAAM,KAAK,OAAO;QAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAA;IACpD,MAAM,OAAO,GAAG,GAAG,CAAC,SAAS,EAAE,IAAI,EAAE,CAAA;IACrC,MAAM,IAAI,GAAG,GAAG,CAAC,UAAU,EAAE,IAAI,EAAE,CAAA;IACnC,iGAAiG;IACjG,gEAAgE;IAChE,IAAI,GAAG,CAAC,MAAM,KAAK,cAAc,EAAE,CAAC;QAClC,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,2BAA2B,CAAC,GAAG,CAAC,EAAE,CAAA;IACpE,CAAC;IACD,IAAI,QAAQ,IAAI,SAAS,EAAE,CAAC;QAC1B,OAAO;YACL,IAAI,EAAE,WAAW;YACjB,KAAK,EACH,4CAA4C,iBAAiB,CAAC,QAAQ,CAAC,EAAE;gBACzE,uBAAuB,iBAAiB,CAAC,SAAS,CAAC,IAAI;gBACvD,qFAAqF;gBACrF,yFAAyF;gBACzF,wFAAwF;gBACxF,wFAAwF;gBACxF,uFAAuF;gBACvF,iFAAiF;gBACjF,CAAC,OAAO,CAAC,CAAC,CAAC,yBAAyB,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACnD,CAAC,IAAI,CAAC,CAAC,CAAC,wBAAwB,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC/C,CAAA;IACH,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAA;AACjD,CAAC"}
@@ -1,4 +1,4 @@
1
- export type { AgentKind, AgentState, AgentFailure, AgentFailureKind, AgentRunKind, ModelFamily, ModelFamilyPolicy, ModelPolicyMode, AccountRegion, ModelFamilyPolicyPreset, Block, BlockLevel, BlockStatus, BlockType, TaskType, CreateTaskType, TaskTypeFields, CustomTaskType, TaskTypePresentation, TaskTypeFieldDescriptor, TaskTypeFieldType, TaskTypeFieldOption, DescriptorField, DescriptorFieldType, DescriptorFieldOption, DescriptorFieldShowWhen, DescriptorFieldValue, DescriptorFieldValues, DocKind, Decision, EnvConfigRepairJob, EnvConfigRepairStatus, EnvironmentTestRun, EnvironmentTestStage, EnvironmentTestStatus, ExecutionInstance, ExecutionStatus, IntakeOrigin, InputGateIssue, InputGateIssueCode, InputGateMode, InputGateSeverity, InputGateStatus, RunInputGate, ResolveInputGateChoice, ResolveInputGateRequest, Pipeline, PipelineAvailability, PipelineStep, Position, PriorStepOutput, PromptFragment, PullRequestRef, PeerPullRequest, ReferenceRepo, AprioriBranch, SpendStatus, StepApproval, StepReviewComment, ReviewCommentSeverity, StepSubtasks, WebSearchAvailability, WebSearchProvider, Workspace, WorkspaceSnapshot, FragmentOwnerKind, FragmentTier, CreatePromptFragmentInput, CreateDocumentFragmentInput, UpdatePromptFragmentInput, FragmentSource, LinkFragmentSourceInput, FragmentSyncResult, FragmentSourceStatus, ResolvedFragment, ResolvedFragmentCatalog, Account, AccountType, AccountRole, AccountMember, CreateAccountInput, AddMemberInput, WorkspaceRole, WorkspacePermission, WorkspaceAccessMode, WorkspaceMember, Service, WorkspaceMount, MountServiceInput, UpdateMountInput, GitHubBranch, GitHubCheckRun, GitHubCommit, GitHubConnection, GitHubInstallationOption, GitHubAvailableRepo, GitHubIssue, GitHubIssueState, GitHubPullRequest, GitHubPullRequestState, OpenedPullRequest, GitHubRepo, RepoTreeEntry, SetRepoMonorepoInput, CommitFilesInput, LinkReposInput, OpenPullRequestInput, MergePullRequestInput, ProviderConfigFieldType, ProviderConfigField, ProviderDescriptor, ConnectionTestResult, ConnectionWarning, ConnectionWarningCode, UserSecretKind, UserSecretStatus, StoreUserSecretInput, TestUserSecretInput, UserSecretDescriptor, DocumentSourceKind, DocumentOrigin, DocumentLinkRole, DocumentRenderStatus, DocumentSourceDescriptor, CredentialField, DocumentConnection, SourceDocument, DocumentSearchResult, DocumentBoardPlan, PlanFrame, PlanModule, PlanTask, TaskSourceKind, TaskSourceDescriptor, TaskSourceState, TaskSourceDiagnostic, TaskSourceDiagnosticStatus, TaskConnection, TaskComment, TaskDependencyLink, SourceTask, TaskSearchResult, IssueIntakePredicate, TrackerBoard, BugCandidate, BugHuntAnalysis, BugHuntAnalysisStatus, BugHuntCandidate, BugHuntConfidence, BugHuntResult, RunBugHuntInput, EnvironmentSecretRef, EnvironmentAuthScheme, EnvironmentHttpMethod, EnvironmentRequestTemplate, EnvironmentStatus, TeardownConfirmation, EnvironmentAccessScheme, EnvironmentAccessMapping, EnvironmentResponseMapping, EnvironmentManifest, EnvironmentBackendConfig, EnvironmentBackendKind, KubernetesEnvironmentConfig, KubernetesConnectionConfig, KubernetesManifestSource, KubernetesUrlSource, KubernetesRenderer, KubernetesImageOverride, KubernetesHelmRelease, KubernetesHelmSet, KubernetesSecretEntry, KubernetesSecretInjection, KubernetesProvisionConfig, CloudflareEnvironmentConfig, CloudflareConnectionConfig, ProvisionType, EnvironmentFailureReason, InfraEngine, ManifestId, ServiceProvisioning, StackRecipe, RecipeStep, RecipeStepKind, RecipeHealthGate, RecipeEnvFile, PreflightCheckId, PreflightParams, PreflightRef, PreflightStatus, PreflightResult, FrontendConfig, FrontendBackendBinding, FrontendBackendSource, ResolvedFrontendBinding, LiveEnvHandle, ServiceConnection, KubernetesEngineConfig, InfraHandlerConfig, CustomManifestType, CustomManifestTypeSource, UpsertCustomManifestTypeInput, EnvironmentAccessHandle, EnvironmentHandle, EnvironmentConnection, TestEnvironmentConnectionInput, TestEnvironmentHandlerInput, ValidateEnvironmentRepoInput, BootstrapEnvironmentRepoInput, BootstrapRepoResult, TestSecretRef, TestSecretEntry, ServiceTestSecretsView, UpsertServiceTestSecretsInput, ProvisioningSubsystem, ProvisioningOperation, ProvisioningOutcome, ProvisioningLogEntry, RunnerPoolSecretRef, RunnerPoolAuthScheme, RunnerPoolRequestTemplate, RunnerJobState, RunnerPoolResponseMapping, RunnerPoolManifest, RunnerPoolConnection, TestRunnerPoolConnectionInput, RunnerBackendConfig, RunnerBackendKind, KubernetesRunnerConfig, KubernetesResourceQuantities, ReferenceArchitecture, CreateReferenceArchitectureInput, UpdateReferenceArchitectureInput, BootstrapStatus, BootstrapFailure, BootstrapFailureKind, BootstrapJob, BootstrapRepoInput, BlueprintModule, BlueprintService, BlueprintSource, BoardScanSpawnResult, ReviewItemCategory, ReviewItemSeverity, ReviewItemStatus, RequirementReviewItem, RequirementReviewStatus, RequirementReview, DocInterviewQa, DocInterviewStatus, DocInterviewSession, AnswerDocInterviewInput, KaizenGradingStatus, KaizenGrading, KaizenVerifiedCombo, KaizenOverview, KaizenRunGradings, RecommendationStatus, RequirementRecommendation, ReplyReviewItemInput, UpdateReviewItemStatusInput, IncorporateRequirementsInput, RequestRecommendationItem, RequestRecommendationsInput, ReRequestRecommendationInput, ResolveRequirementsExceededInput, ResolveRequirementsExceededChoice, FollowUpItemKind, FollowUpItemStatus, FollowUpResolution, FollowUpItem, FollowUpsStepState, AnswerFollowUpInput, StreamedFollowUp, ForkOption, ForkChatMessage, ForkDecisionStatus, ForkChoice, ForkDecisionStepState, ForkChatRequestInput, ChooseForkInput, ForkProposal, BinaryCandidate, BinaryCandidateComparison, BinaryCandidateChoice, BinaryCandidateKeep, BinaryCandidateNoChoiceReason, BinaryCandidateStatus, BinaryCandidateStepState, KeepBinaryCandidatesInput, BinaryGeneratorCapability, BinaryGenerationOptions, BinaryAssetRef, BinaryReferenceImage, JudgeFindingSeverity, JudgeFinding, JudgeVerdict, JudgeDisposition, JudgeStatus, JudgeRound, JudgeStepState, JudgeModelPin, JudgeModelPinStatus, ResolveJudgeInput, PrReviewSeverity, PrReviewCategory, PrReviewSlice, PrReviewSliceReview, PrReviewFinding, PrReviewFindingChallenge, PrReviewStatus, PrReviewResolution, PrReviewStepState, PrReviewPostReport, PrReviewPostFailure, PrReviewAgentOutput, PrReviewChallengeOutput, ResolvePrReviewInput, ChallengePrReviewFindingInput, ClarityReviewItem, ClarityReviewStatus, ClarityReview, ReplyClarityItemInput, UpdateClarityItemStatusInput, IncorporateClarityInput, ResolveClarityExceededInput, ResolveClarityExceededChoice, BrainstormStage, BrainstormItem, BrainstormStatus, BrainstormSession, ReplyBrainstormItemInput, UpdateBrainstormItemStatusInput, IncorporateBrainstormInput, ResolveBrainstormExceededInput, ResolveBrainstormExceededChoice, IterationCapChoice, ResolveIterationCapInput, RequirementPriority, RequirementKind,
1
+ export type { AgentKind, AgentState, AgentFailure, AgentFailureKind, AgentRunKind, ModelFamily, ModelFamilyPolicy, ModelPolicyMode, AccountRegion, ModelFamilyPolicyPreset, Block, BlockLevel, BlockStatus, BlockType, TaskType, CreateTaskType, TaskTypeFields, CustomTaskType, TaskTypePresentation, TaskTypeFieldDescriptor, TaskTypeFieldType, TaskTypeFieldOption, DescriptorField, DescriptorFieldType, DescriptorFieldOption, DescriptorFieldShowWhen, DescriptorFieldValue, DescriptorFieldValues, DocKind, Decision, EnvConfigRepairJob, EnvConfigRepairStatus, EnvironmentTestRun, EnvironmentTestStage, EnvironmentTestStatus, ExecutionInstance, ExecutionStatus, IntakeOrigin, InputGateIssue, InputGateIssueCode, InputGateMode, InputGateSeverity, InputGateStatus, RunInputGate, ResolveInputGateChoice, ResolveInputGateRequest, Pipeline, PipelineAvailability, PipelineStep, Position, PriorStepOutput, PromptFragment, PullRequestRef, PeerPullRequest, ReferenceRepo, AprioriBranch, SpendStatus, StepApproval, StepReviewComment, ReviewCommentSeverity, StepSubtasks, WebSearchAvailability, WebSearchProvider, Workspace, WorkspaceSnapshot, FragmentOwnerKind, FragmentTier, CreatePromptFragmentInput, CreateDocumentFragmentInput, UpdatePromptFragmentInput, FragmentSource, LinkFragmentSourceInput, FragmentSyncResult, FragmentSourceStatus, ResolvedFragment, ResolvedFragmentCatalog, Account, AccountType, AccountRole, AccountMember, CreateAccountInput, AddMemberInput, WorkspaceRole, WorkspacePermission, WorkspaceAccessMode, WorkspaceMember, Service, WorkspaceMount, MountServiceInput, UpdateMountInput, GitHubBranch, GitHubCheckRun, GitHubCommit, GitHubConnection, GitHubInstallationOption, GitHubAvailableRepo, GitHubIssue, GitHubIssueState, GitHubPullRequest, GitHubPullRequestState, OpenedPullRequest, GitHubRepo, RepoTreeEntry, SetRepoMonorepoInput, CommitFilesInput, LinkReposInput, OpenPullRequestInput, MergePullRequestInput, ProviderConfigFieldType, ProviderConfigField, ProviderDescriptor, ConnectionTestResult, ConnectionWarning, ConnectionWarningCode, UserSecretKind, UserSecretStatus, StoreUserSecretInput, TestUserSecretInput, UserSecretDescriptor, DocumentSourceKind, DocumentOrigin, DocumentLinkRole, DocumentRenderStatus, DocumentSourceDescriptor, CredentialField, DocumentConnection, SourceDocument, DocumentSearchResult, DocumentBoardPlan, PlanFrame, PlanModule, PlanTask, TaskSourceKind, TaskSourceDescriptor, TaskSourceState, TaskSourceDiagnostic, TaskSourceDiagnosticStatus, TaskConnection, TaskComment, TaskDependencyLink, SourceTask, TaskSearchResult, IssueIntakePredicate, TrackerBoard, BugCandidate, BugHuntAnalysis, BugHuntAnalysisStatus, BugHuntCandidate, BugHuntConfidence, BugHuntResult, RunBugHuntInput, EnvironmentSecretRef, EnvironmentAuthScheme, EnvironmentHttpMethod, EnvironmentRequestTemplate, EnvironmentStatus, TeardownConfirmation, EnvironmentAccessScheme, EnvironmentAccessMapping, EnvironmentResponseMapping, EnvironmentManifest, EnvironmentBackendConfig, EnvironmentBackendKind, KubernetesEnvironmentConfig, KubernetesConnectionConfig, KubernetesManifestSource, KubernetesUrlSource, KubernetesRenderer, KubernetesImageOverride, KubernetesHelmRelease, KubernetesHelmSet, KubernetesSecretEntry, KubernetesSecretInjection, KubernetesProvisionConfig, CloudflareEnvironmentConfig, CloudflareConnectionConfig, ProvisionType, EnvironmentFailureReason, InfraEngine, ManifestId, ServiceProvisioning, StackRecipe, RecipeStep, RecipeStepKind, RecipeHealthGate, RecipeEnvFile, PreflightCheckId, PreflightParams, PreflightRef, PreflightStatus, PreflightResult, FrontendConfig, FrontendBackendBinding, FrontendBackendSource, ResolvedFrontendBinding, LiveEnvHandle, ServiceConnection, KubernetesEngineConfig, InfraHandlerConfig, CustomManifestType, CustomManifestTypeSource, UpsertCustomManifestTypeInput, EnvironmentAccessHandle, EnvironmentHandle, EnvironmentAddress, EnvironmentReachability, EnvironmentReachabilityNote, EnvironmentRouteAttempt, EnvironmentRouteProof, EnvironmentUnreachableReason, EnvironmentConnection, TestEnvironmentConnectionInput, TestEnvironmentHandlerInput, ValidateEnvironmentRepoInput, BootstrapEnvironmentRepoInput, BootstrapRepoResult, TestSecretRef, TestSecretEntry, ServiceTestSecretsView, UpsertServiceTestSecretsInput, ProvisioningSubsystem, ProvisioningOperation, ProvisioningOutcome, ProvisioningLogEntry, RunnerPoolSecretRef, RunnerPoolAuthScheme, RunnerPoolRequestTemplate, RunnerJobState, RunnerPoolResponseMapping, RunnerPoolManifest, RunnerPoolConnection, TestRunnerPoolConnectionInput, RunnerBackendConfig, RunnerBackendKind, KubernetesRunnerConfig, KubernetesResourceQuantities, ReferenceArchitecture, CreateReferenceArchitectureInput, UpdateReferenceArchitectureInput, BootstrapStatus, BootstrapFailure, BootstrapFailureKind, BootstrapJob, BootstrapRepoInput, BlueprintModule, BlueprintService, BlueprintSource, BoardScanSpawnResult, ReviewItemCategory, ReviewItemSeverity, ReviewItemStatus, RequirementReviewItem, RequirementReviewStatus, RequirementReview, DocInterviewQa, DocInterviewStatus, DocInterviewSession, AnswerDocInterviewInput, KaizenGradingStatus, KaizenGrading, KaizenVerifiedCombo, KaizenOverview, KaizenRunGradings, RecommendationStatus, RequirementRecommendation, ReplyReviewItemInput, UpdateReviewItemStatusInput, IncorporateRequirementsInput, RequestRecommendationItem, RequestRecommendationsInput, ReRequestRecommendationInput, ResolveRequirementsExceededInput, ResolveRequirementsExceededChoice, FollowUpItemKind, FollowUpItemStatus, FollowUpResolution, FollowUpItem, FollowUpsStepState, AnswerFollowUpInput, StreamedFollowUp, ForkOption, ForkChatMessage, ForkDecisionStatus, ForkChoice, ForkDecisionStepState, ForkChatRequestInput, ChooseForkInput, ForkProposal, BinaryCandidate, BinaryCandidateComparison, BinaryCandidateChoice, BinaryCandidateKeep, BinaryCandidateNoChoiceReason, BinaryCandidateStatus, BinaryCandidateStepState, KeepBinaryCandidatesInput, BinaryGeneratorCapability, BinaryGenerationOptions, BinaryAssetRef, BinaryReferenceImage, JudgeFindingSeverity, JudgeFinding, JudgeVerdict, JudgeDisposition, JudgeStatus, JudgeRound, JudgeStepState, JudgeModelPin, JudgeModelPinStatus, ResolveJudgeInput, PrReviewSeverity, PrReviewCategory, PrReviewSlice, PrReviewSliceReview, PrReviewFinding, PrReviewFindingChallenge, PrReviewStatus, PrReviewResolution, PrReviewStepState, PrReviewPostReport, PrReviewPostFailure, PrReviewAgentOutput, PrReviewChallengeOutput, ResolvePrReviewInput, ChallengePrReviewFindingInput, ClarityReviewItem, ClarityReviewStatus, ClarityReview, ReplyClarityItemInput, UpdateClarityItemStatusInput, IncorporateClarityInput, ResolveClarityExceededInput, ResolveClarityExceededChoice, BrainstormStage, BrainstormItem, BrainstormStatus, BrainstormSession, ReplyBrainstormItemInput, UpdateBrainstormItemStatusInput, IncorporateBrainstormInput, ResolveBrainstormExceededInput, ResolveBrainstormExceededChoice, IterationCapChoice, ResolveIterationCapInput, RequirementPriority, RequirementKind,
2
2
  /** Implementation state: agreed-but-not-built vs observed-to-hold. */
3
3
  RequirementState, AcceptanceCriterion, RequirementItem, DomainRule, RequirementGroup, SpecModule, SpecDoc, CompanionAssessment, CompanionVerdict, DeployFixConfig, DeployFixState, DeployFixAttempt, GateStepState, GateFailingCheck, GateAttempt, RalphStepState, RalphVerdict, RalphAttempt, ValidationCheck, ValidationCheckOutcome, ValidationReport, ResolvedValidationChecks, ServiceValidationConfig, UpsertServiceValidationConfigInput, ReproductionProofMode, ResolvedReproduction, ReproductionStatus, ReproductionPhaseOutcome, ReproductionReport, HumanTestStepState, HumanTestEnvironment, HumanTestRound, RequestHumanTestFixInput, VisualConfirmStepState, VisualConfirmPair, VisualConfirmReferenceOrigin, VisualConfirmDesignGap, VisualConfirmDesignGapReason, VisualConfirmDesignReferences, VisualConfirmRound, MergeAssessment, MergeAxis, MergeDecision, MergeDecisionThresholds, MergeClassRule, MergeClassRules, ClassRulesByRole, SubmissionClassesByRole, RunMode, ChangeClass, ReviewEffort, MergeTrackDecision, MergeTrackRecord, MergeClassRollup, ReviewEffortDistribution, TagReviewEffortInput, PrVerificationReport, PrReportScope, PrReportOwnPullRequest, PrReportSectionStatus, PrReportStep, PrReportIssue, PrReportJudge, PrReportFollowUp, PrReportFollowUps, PrReportRun, PrReportCheck, PrReportCi, PrReportTestOutcome, PrReportTestConcern, PrReportTests, PrReportContext, PrReportContextDocument, PrReportValidation, PrReportValidationCommand, PrReportReproduction, PrReportReproductionPhase, PrReportEnvironment, PrReportEnvironments, PrReportEnvironmentTimeline, PrReportTimelineGap, PrReportEnvironmentEvidence, PrReportEvidenceArtifact, PrReportRequirement, PrReportRequirements, PrReportMerge, PrReportObservability, RiskPolicy, RequirementConcernLevel, CreateRiskPolicyInput, UpdateRiskPolicyInput, CloneRiskPolicyInput, RiskPolicyTier, RiskPolicyLibraryEntry, RiskPolicySuppression, RunAutonomy, RunDefaultScope, ComposeFileRef, ComposeSource, ComposeSourceKind, SharedStack, SharedStackStatus, CreateSharedStackInput, UpdateSharedStackInput, DetectSharedStackInput, SharedStackRecommendation, ConsensusStrategy, ConsensusParticipant, ConsensusGating, StepGating, ConsensusStepConfig, ConsensusGroup, CreateConsensusGroupInput, UpdateConsensusGroupInput, TaskEstimate, TaskEstimateBasis, SupersededTaskEstimate, ConsensusScore, ConsensusContribution, ConsensusRound, ConsensusSessionStatus, ConsensusSession, AgentConfigOption, AgentConfigDescriptor, AgentConfigCatalog, AgentConfigValues, TestReport, TestOutcome, TestConcern, TestConcernSeverity, RequirementVerdict, RequirementVerdictStatus, TesterQualityConfig, StepOptions, StepGateConfig, GateApproverPolicy, GateApprovalRecord, CloudProvider, InstanceSize, UpdateAccountInput, ModelFlavor, ModelPreset, CreateModelPresetInput, UpdateModelPresetInput, AgentPromptRevision, AgentPromptDetail, AgentPromptSummary, SaveAgentPromptInput, PromoteAgentPromptInput, WorkspaceAgentSettings, UpdateWorkspaceAgentSettingsInput, ServiceFragmentDefaults, SetServiceFragmentDefaultsInput, Notification, NotificationType, NotificationStatus, NotificationSeverity, NotificationPayload, ResolveNotificationAction, NotificationDeliveryChannel, NotificationChannelOverrides, NotificationRoutingMatrix, NotificationSettings, UpdateNotificationSettingsInput, WorkspaceSettings, UpdateWorkspaceSettingsInput, TaskLimitMode, TaskLimitPerType, UserSettings, UpdateUserSettingsInput, TutorialProgress, TutorialDecision, UpdateTutorialProgressInput, TutorialEvent, RecordTutorialEventInput, SlackConnection, SlackRoute, SlackNotificationSettings, SlackMemberMappingEntry, SlackMemberRole, SlackMemberMapping, SlackChannel, ConnectSlackByTokenInput, UpdateSlackSettingsInput, UpdateSlackMemberMappingInput, ScheduleTemplate, Recurrence, IssueIntakeConfig, PipelineSchedule, ScheduleRun, CreateScheduleInput, UpdateScheduleInput, TrackerKind, TrackerSettings, PutTrackerSettingsInput, WritebackOverride, LlmCallActivity, SandboxPromptOrigin, SandboxPromptVersion, SandboxFixtureKind, SandboxRepoRef, SandboxFixtureObjective, SandboxFixture, SandboxExperimentStatus, SandboxMatrix, SandboxExperiment, SandboxRunStatus, SandboxTokenUsage, SandboxRun, SandboxGradeDimension, SandboxObjectiveResult, SandboxGrade, Initiative, InitiativeStatus, InitiativeItem, InitiativeItemStatus, InitiativePhase, InitiativeEstimate, InitiativePipelineRule, InitiativeExecutionPolicy, InitiativeDecision, InitiativeDeviation, InitiativeFollowUp, InitiativeQa, InitiativeQaStatus, InitiativeInterviewState, InitiativePlanDraft, InitiativeDraftItem, InitiativeVersion, CreateInitiativeInput, AnswerInitiativeQuestionInput, PromoteInitiativeFollowUpInput, UpdateInitiativeItemInput, UpdateInitiativePolicyInput, AccountSettingsConfig, ContentStorageConfig, FigmaOAuthSecret, LinearOAuthSecret, S3CredentialsSecret, SlackOAuthSecret, WebSearchSecret, } from '@cat-factory/contracts';
4
4
  /**