@cat-factory/contracts 0.335.0 → 0.337.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/debug-api.d.ts +1 -1
- package/dist/entities.d.ts +14 -0
- package/dist/entities.d.ts.map +1 -1
- package/dist/entities.js +8 -0
- package/dist/entities.js.map +1 -1
- package/dist/environment-investigation.d.ts +212 -0
- package/dist/environment-investigation.d.ts.map +1 -0
- package/dist/environment-investigation.js +258 -0
- package/dist/environment-investigation.js.map +1 -0
- package/dist/environment-reachability.d.ts +246 -0
- package/dist/environment-reachability.d.ts.map +1 -0
- package/dist/environment-reachability.js +248 -0
- package/dist/environment-reachability.js.map +1 -0
- package/dist/environments.d.ts +282 -1
- package/dist/environments.d.ts.map +1 -1
- package/dist/environments.js +41 -0
- package/dist/environments.js.map +1 -1
- package/dist/execution.d.ts +38 -0
- package/dist/execution.d.ts.map +1 -1
- package/dist/execution.js +15 -0
- package/dist/execution.js.map +1 -1
- package/dist/frontend.d.ts +52 -1
- package/dist/frontend.d.ts.map +1 -1
- package/dist/frontend.js +69 -9
- package/dist/frontend.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/provisioning-logs.d.ts +12 -5
- package/dist/provisioning-logs.d.ts.map +1 -1
- package/dist/provisioning-logs.js +10 -2
- package/dist/provisioning-logs.js.map +1 -1
- package/dist/requests.d.ts +2 -0
- package/dist/requests.d.ts.map +1 -1
- package/dist/routes/agent-runs.d.ts +8 -0
- package/dist/routes/agent-runs.d.ts.map +1 -1
- package/dist/routes/bug-hunt.d.ts +8 -0
- package/dist/routes/bug-hunt.d.ts.map +1 -1
- package/dist/routes/debug-api.d.ts +1 -1
- package/dist/routes/environmentUserHandlers.d.ts +6 -0
- package/dist/routes/environmentUserHandlers.d.ts.map +1 -1
- package/dist/routes/environments.d.ts +110 -0
- package/dist/routes/environments.d.ts.map +1 -1
- package/dist/routes/execution.d.ts +40 -0
- package/dist/routes/execution.d.ts.map +1 -1
- package/dist/routes/human-review.d.ts +4 -0
- package/dist/routes/human-review.d.ts.map +1 -1
- package/dist/routes/human-test.d.ts +20 -0
- package/dist/routes/human-test.d.ts.map +1 -1
- package/dist/routes/pipelines.d.ts +8 -0
- package/dist/routes/pipelines.d.ts.map +1 -1
- package/dist/routes/provisioning-logs.d.ts +1 -1
- package/dist/routes/public-evidence.d.ts +1 -0
- package/dist/routes/public-evidence.d.ts.map +1 -1
- package/dist/routes/visual-confirm.d.ts +12 -0
- package/dist/routes/visual-confirm.d.ts.map +1 -1
- package/dist/routes/workspaces.d.ts +10 -0
- package/dist/routes/workspaces.d.ts.map +1 -1
- package/dist/run-evidence.d.ts +8 -0
- package/dist/run-evidence.d.ts.map +1 -1
- package/dist/run-evidence.js +5 -1
- package/dist/run-evidence.js.map +1 -1
- package/dist/run-outcome.d.ts +58 -3
- package/dist/run-outcome.d.ts.map +1 -1
- package/dist/run-outcome.js +40 -3
- package/dist/run-outcome.js.map +1 -1
- package/dist/snapshot.d.ts +5 -0
- package/dist/snapshot.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
import * as v from 'valibot';
|
|
2
|
+
// ---------------------------------------------------------------------------
|
|
3
|
+
// ENVIRONMENT INVESTIGATION: the vocabulary of what the platform does when an environment never
|
|
4
|
+
// becomes usable and no checkout edit can help.
|
|
5
|
+
//
|
|
6
|
+
// The sibling of `deploy-fix.ts`, and deliberately its opposite half. The `deploy-fixer` runs
|
|
7
|
+
// only for `manifest_invalid`: a document the checkout owns and got wrong. Everything else a
|
|
8
|
+
// provisioning failure can be (a VM that went offline under a deploy job that reported success, a
|
|
9
|
+
// load balancer with no healthy target, a DNS record that was never published) lives entirely in
|
|
10
|
+
// the provider, and the conclusion the platform drew from "a code fixer cannot help here" used to
|
|
11
|
+
// be "nobody can help here": the run died at the tester with a report correctly saying a human had
|
|
12
|
+
// to look. What actually follows is that a DIFFERENT investigator is needed, one whose evidence is
|
|
13
|
+
// the provider rather than the repository.
|
|
14
|
+
//
|
|
15
|
+
// The division of labour is the one CLAUDE.md states for every model-in-the-loop decision: the
|
|
16
|
+
// model JUDGES (which layer is at fault, on which evidence) and the platform COMPUTES (which
|
|
17
|
+
// action it is allowed to take, whether it takes it, and, always, whether the environment came
|
|
18
|
+
// up afterwards). The verdict is never the proof. The re-probe is.
|
|
19
|
+
//
|
|
20
|
+
// Tracker: `docs/initiatives/environment-investigation.md`.
|
|
21
|
+
// ---------------------------------------------------------------------------
|
|
22
|
+
// Every schema below that ends up INSIDE a pipeline step is declared as an explicit interface and
|
|
23
|
+
// annotated `v.GenericSchema<unknown, T>` rather than inferred with `v.InferOutput`, the shape
|
|
24
|
+
// `binaryGenerationOptionsSchema` already uses. The investigation state nests four object levels
|
|
25
|
+
// under `PipelineStep` (step → state → attempt → verdict → evidence), which is deep enough that
|
|
26
|
+
// inferring it tips `tsc` into "type instantiation is excessively deep" in a consumer several
|
|
27
|
+
// packages away. It was first seen in `WorkspaceService`, which is nowhere near this file and gives a
|
|
28
|
+
// reader nothing to go on. `unknown` on the input side is what a parser accepts anyway.
|
|
29
|
+
/** The inline engine kind the investigation runs under (model resolution + spend attribution). */
|
|
30
|
+
export const ENVIRONMENT_INVESTIGATOR_AGENT_KIND = 'environment-investigator';
|
|
31
|
+
/**
|
|
32
|
+
* WHERE the fault the investigator found lives, which is the one thing its report has to settle:
|
|
33
|
+
* every reader (the run's recorded failure, an operator, a later retry) does something different
|
|
34
|
+
* per layer, and today they all get the same "the environment did not come up".
|
|
35
|
+
*
|
|
36
|
+
* - `provider`: the infrastructure the platform asked for is broken or was never delivered. A
|
|
37
|
+
* VM that went offline, a balancer with no healthy target, a DNS record never published, a
|
|
38
|
+
* quota refusal. The platform can sometimes retry into it and can never fix it.
|
|
39
|
+
* - `platform`: cat-factory itself got it wrong. A readiness ceiling that expired on an
|
|
40
|
+
* environment still legitimately converging, a URL published before it resolved, a poll that
|
|
41
|
+
* read a field the provider does not populate.
|
|
42
|
+
* - `deployment`: the description the run deployed is at fault, but NOT in a way the
|
|
43
|
+
* `manifest_invalid` classifier caught (a workload that starts and crashes, an image the
|
|
44
|
+
* cluster cannot pull). Distinct from `provider` because the fix is a commit; distinct from the
|
|
45
|
+
* deploy-fixer's admission because the finding is a HYPOTHESIS and does not itself dispatch a
|
|
46
|
+
* container against a checkout.
|
|
47
|
+
* - `unknown`: the evidence did not settle it. A first-class answer, never a default dressed up
|
|
48
|
+
* as one: "we could not tell" and "the provider is broken" send different people to different
|
|
49
|
+
* places, and collapsing them is how an operator ends up debugging a healthy cluster.
|
|
50
|
+
*/
|
|
51
|
+
export const environmentFaultLayerSchema = v.picklist([
|
|
52
|
+
'provider',
|
|
53
|
+
'platform',
|
|
54
|
+
'deployment',
|
|
55
|
+
'unknown',
|
|
56
|
+
]);
|
|
57
|
+
/**
|
|
58
|
+
* What the platform may DO about it, as a closed vocabulary the model picks from and the engine
|
|
59
|
+
* executes. The model never acts: it names one of these and the engine decides whether this
|
|
60
|
+
* deployment, this provider and this budget allow it.
|
|
61
|
+
*
|
|
62
|
+
* - `stop`: nothing here is retryable. The run fails with the investigator's named cause instead
|
|
63
|
+
* of a tester's guess, which is the whole point of the second outcome.
|
|
64
|
+
* - `wait`: the environment is converging and the ceiling was simply too tight for it. Extends
|
|
65
|
+
* the readiness wait ONCE, by the ceiling again.
|
|
66
|
+
* - `restart`: restart the workload in place, without rebuilding anything around it. The one
|
|
67
|
+
* action that needs the provider to implement `EnvironmentDiagnostics.remediate`.
|
|
68
|
+
* - `reprovision`: stand it up again over the same target. Idempotent for every provider whose
|
|
69
|
+
* provision is an apply; the existing environment is left in place.
|
|
70
|
+
* - `recreate`: tear the environment down first, then stand it up again. For a target whose own
|
|
71
|
+
* state is what is wrong, where re-applying over it would reproduce the fault.
|
|
72
|
+
*/
|
|
73
|
+
export const environmentRemediationActionSchema = v.picklist([
|
|
74
|
+
'stop',
|
|
75
|
+
'wait',
|
|
76
|
+
'restart',
|
|
77
|
+
'reprovision',
|
|
78
|
+
'recreate',
|
|
79
|
+
]);
|
|
80
|
+
/**
|
|
81
|
+
* Whether an action needs the provider to implement the optional remediation capability.
|
|
82
|
+
*
|
|
83
|
+
* An exhaustive `Record` rather than a membership test, for the reason
|
|
84
|
+
* `REPO_FIXABLE_ENVIRONMENT_FAILURES` is one: the default a new action would silently inherit is
|
|
85
|
+
* wrong in both directions. `false` on an action no provider can perform makes the engine promise
|
|
86
|
+
* something and do nothing; `true` on one the platform owns outright (tearing an environment down
|
|
87
|
+
* and standing it up again are `EnvironmentProvider` methods every provider already has) withholds
|
|
88
|
+
* the only remedy available from every provider that never implemented diagnostics.
|
|
89
|
+
*/
|
|
90
|
+
const REMEDIATION_NEEDS_PROVIDER_SUPPORT = {
|
|
91
|
+
stop: false,
|
|
92
|
+
wait: false,
|
|
93
|
+
restart: true,
|
|
94
|
+
reprovision: false,
|
|
95
|
+
recreate: false,
|
|
96
|
+
};
|
|
97
|
+
/** See {@link REMEDIATION_NEEDS_PROVIDER_SUPPORT}. */
|
|
98
|
+
export function remediationNeedsProviderSupport(action) {
|
|
99
|
+
return REMEDIATION_NEEDS_PROVIDER_SUPPORT[action];
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Narrow an arbitrary string to a member, DERIVED from the picklist's own options so adding one
|
|
103
|
+
* needs no second edit here. Used wherever a PERSISTED action is read back: the vocabulary is
|
|
104
|
+
* closed and stored on a run's step, so a member retired later is still in the database, and a
|
|
105
|
+
* reader that assumed the type was total would splice `undefined` into the very message whose job
|
|
106
|
+
* is to name what a human must re-pick (CLAUDE.md's closed-vocabulary rule).
|
|
107
|
+
*/
|
|
108
|
+
export function isEnvironmentRemediationAction(value) {
|
|
109
|
+
if (!value)
|
|
110
|
+
return false;
|
|
111
|
+
return environmentRemediationActionSchema.options.includes(value);
|
|
112
|
+
}
|
|
113
|
+
/** Compile-time totality guard for {@link describeRemediationAction}. */
|
|
114
|
+
function unrecognisedRemediation(action) {
|
|
115
|
+
return `an unrecognised remediation (${JSON.stringify(action)})`;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* One-line description of a stored action, for an operator-facing message. Total against the TYPE
|
|
119
|
+
* through the `never` helper (adding a member fails the build) and honest about the DATA: a value
|
|
120
|
+
* that is no longer a member is named as retired rather than guessed onto a current one, because
|
|
121
|
+
* nothing knows which one was meant.
|
|
122
|
+
*/
|
|
123
|
+
export function describeRemediationAction(action) {
|
|
124
|
+
if (!isEnvironmentRemediationAction(action)) {
|
|
125
|
+
return `a remediation this deployment no longer offers (${JSON.stringify(action)})`;
|
|
126
|
+
}
|
|
127
|
+
switch (action) {
|
|
128
|
+
case 'stop':
|
|
129
|
+
return 'stop and report the cause';
|
|
130
|
+
case 'wait':
|
|
131
|
+
return 'keep waiting for the environment to converge';
|
|
132
|
+
case 'restart':
|
|
133
|
+
return 'restart the workload in place';
|
|
134
|
+
case 'reprovision':
|
|
135
|
+
return 'provision the environment again';
|
|
136
|
+
case 'recreate':
|
|
137
|
+
return 'tear the environment down and provision it again';
|
|
138
|
+
default:
|
|
139
|
+
return unrecognisedRemediation(action);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
export const environmentEvidenceItemSchema = v.object({
|
|
143
|
+
source: v.pipe(v.string(), v.maxLength(120)),
|
|
144
|
+
statement: v.pipe(v.string(), v.maxLength(1000)),
|
|
145
|
+
});
|
|
146
|
+
export const environmentInvestigationVerdictSchema = v.object({
|
|
147
|
+
faultLayer: environmentFaultLayerSchema,
|
|
148
|
+
summary: v.pipe(v.string(), v.maxLength(4000)),
|
|
149
|
+
evidence: v.array(environmentEvidenceItemSchema),
|
|
150
|
+
action: environmentRemediationActionSchema,
|
|
151
|
+
actionRationale: v.pipe(v.string(), v.maxLength(1000)),
|
|
152
|
+
});
|
|
153
|
+
/** At most this many cited facts survive coercion; past it the model is padding, not evidencing. */
|
|
154
|
+
const MAX_EVIDENCE_ITEMS = 20;
|
|
155
|
+
function isFaultLayer(value) {
|
|
156
|
+
return (typeof value === 'string' &&
|
|
157
|
+
environmentFaultLayerSchema.options.includes(value));
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Trim a prose field to `max` characters INCLUSIVE of the ellipsis that states the drop.
|
|
161
|
+
*
|
|
162
|
+
* The ellipsis counts against the budget rather than riding on top of it, because `max` is the
|
|
163
|
+
* same number the schema beside it declares as `v.maxLength`: a coercion that answered `max + 1`
|
|
164
|
+
* produced a value its own validator then rejected, on a field persisted to `step
|
|
165
|
+
* .environmentInvestigation` and served through `executionInstanceSchema`, whose lengths are
|
|
166
|
+
* published into the OpenAPI spec and the four SDKs.
|
|
167
|
+
*/
|
|
168
|
+
function coerceText(value, max) {
|
|
169
|
+
if (typeof value !== 'string')
|
|
170
|
+
return undefined;
|
|
171
|
+
const trimmed = value.trim();
|
|
172
|
+
if (!trimmed)
|
|
173
|
+
return undefined;
|
|
174
|
+
return trimmed.length <= max ? trimmed : `${trimmed.slice(0, max - 1)}…`;
|
|
175
|
+
}
|
|
176
|
+
function coerceEvidence(value) {
|
|
177
|
+
if (!Array.isArray(value))
|
|
178
|
+
return [];
|
|
179
|
+
const items = [];
|
|
180
|
+
for (const entry of value) {
|
|
181
|
+
if (items.length >= MAX_EVIDENCE_ITEMS)
|
|
182
|
+
break;
|
|
183
|
+
if (!entry || typeof entry !== 'object')
|
|
184
|
+
continue;
|
|
185
|
+
const record = entry;
|
|
186
|
+
const statement = coerceText(record.statement, 1000);
|
|
187
|
+
if (!statement)
|
|
188
|
+
continue;
|
|
189
|
+
items.push({ source: coerceText(record.source, 120) ?? 'unattributed', statement });
|
|
190
|
+
}
|
|
191
|
+
return items;
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Read a model reply into a verdict, LENIENTLY in the fields that are prose and STRICTLY in the
|
|
195
|
+
* two that are decisions.
|
|
196
|
+
*
|
|
197
|
+
* A fault layer or an action the model invented is not coerced onto a neighbour: both drop to the
|
|
198
|
+
* value meaning "this did not settle anything" (`unknown` / `stop`), because the action is the one
|
|
199
|
+
* field where a generous reading spends real infrastructure on a guess. The prose fields degrade
|
|
200
|
+
* field-by-field instead of discarding the whole verdict, since a report whose `evidence` array is
|
|
201
|
+
* malformed still names a cause worth putting on the record.
|
|
202
|
+
*
|
|
203
|
+
* Returns null when there is no object at all. The caller then records the investigation as FAILED,
|
|
204
|
+
* which is not the same as a verdict of `stop` and must never read like one.
|
|
205
|
+
*/
|
|
206
|
+
export function coerceEnvironmentInvestigationVerdict(raw) {
|
|
207
|
+
if (!raw || typeof raw !== 'object' || Array.isArray(raw))
|
|
208
|
+
return null;
|
|
209
|
+
const value = raw;
|
|
210
|
+
const action = typeof value.action === 'string' ? value.action : undefined;
|
|
211
|
+
return {
|
|
212
|
+
faultLayer: isFaultLayer(value.faultLayer) ? value.faultLayer : 'unknown',
|
|
213
|
+
summary: coerceText(value.summary, 4000) ?? '',
|
|
214
|
+
evidence: coerceEvidence(value.evidence),
|
|
215
|
+
action: isEnvironmentRemediationAction(action) ? action : 'stop',
|
|
216
|
+
actionRationale: coerceText(value.actionRationale, 1000) ?? '',
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* How many investigation rounds a `deployer` step gets. Two, for the reason the deploy-fixer's
|
|
221
|
+
* budget is two: the first round has the whole evidence bag and the provider's own account, and a
|
|
222
|
+
* second covers a remedy that was right about the layer and wrong about the action. A third round
|
|
223
|
+
* against an environment that has twice refused to come up is not converging, and each round costs
|
|
224
|
+
* an LLM call plus real infrastructure work.
|
|
225
|
+
*/
|
|
226
|
+
export const DEFAULT_ENVIRONMENT_INVESTIGATION_MAX_ATTEMPTS = 2;
|
|
227
|
+
/** Bounds on the per-step budget: `0` disables the loop, 5 is the ceiling. */
|
|
228
|
+
export const environmentInvestigationAttemptsSchema = v.pipe(v.number(), v.integer(), v.minValue(0), v.maxValue(5));
|
|
229
|
+
export const environmentInvestigationConfigSchema = v.object({
|
|
230
|
+
enabled: v.optional(v.boolean()),
|
|
231
|
+
maxAttempts: v.optional(environmentInvestigationAttemptsSchema),
|
|
232
|
+
allowRemediation: v.optional(v.boolean()),
|
|
233
|
+
});
|
|
234
|
+
export const environmentInvestigationAttemptSchema = v.object({
|
|
235
|
+
attempt: v.number(),
|
|
236
|
+
at: v.number(),
|
|
237
|
+
outcome: v.picklist(['reported', 'remediated', 'failed']),
|
|
238
|
+
reason: v.optional(v.nullable(v.string())),
|
|
239
|
+
error: v.string(),
|
|
240
|
+
verdict: v.optional(v.nullable(environmentInvestigationVerdictSchema)),
|
|
241
|
+
ranAction: v.optional(v.nullable(v.string())),
|
|
242
|
+
withheld: v.optional(v.nullable(v.string())),
|
|
243
|
+
failure: v.optional(v.nullable(v.string())),
|
|
244
|
+
});
|
|
245
|
+
/**
|
|
246
|
+
* How many readiness-ceiling extensions a `wait` verdict may win, across the whole step. One: a
|
|
247
|
+
* second would let a model postpone a run indefinitely, one ceiling at a time.
|
|
248
|
+
*/
|
|
249
|
+
export const MAX_ENVIRONMENT_WAIT_EXTENSIONS = 1;
|
|
250
|
+
export const environmentInvestigationStateSchema = v.object({
|
|
251
|
+
attempts: v.number(),
|
|
252
|
+
maxAttempts: v.number(),
|
|
253
|
+
frameId: v.string(),
|
|
254
|
+
environmentId: v.optional(v.nullable(v.string())),
|
|
255
|
+
waitExtensions: v.optional(v.nullable(v.number())),
|
|
256
|
+
attemptLog: v.optional(v.nullable(v.array(environmentInvestigationAttemptSchema))),
|
|
257
|
+
});
|
|
258
|
+
//# sourceMappingURL=environment-investigation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"environment-investigation.js","sourceRoot":"","sources":["../src/environment-investigation.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
import * as v from 'valibot';
|
|
2
|
+
/**
|
|
3
|
+
* One address a provider states will carry traffic for its environment's URL host.
|
|
4
|
+
*
|
|
5
|
+
* The motivating shape is an org running per-PR preview environments whose per-environment DNS
|
|
6
|
+
* record lives in an internal view while the load balancers fronting it are ordinary names and
|
|
7
|
+
* the ingress routes on the `Host` header. The address exists and a container's egress reaches
|
|
8
|
+
* it. The only missing thing is a name-to-address mapping, which is exactly what a hosts-file
|
|
9
|
+
* entry (or a Kubernetes `hostAliases` entry) is.
|
|
10
|
+
*
|
|
11
|
+
* `label` is for the human reading a diagnostic ("internal ALB", "public ALB"), never for
|
|
12
|
+
* matching: the platform picks by PROBING, never by name.
|
|
13
|
+
*/
|
|
14
|
+
export declare const environmentAddressSchema: v.ObjectSchema<{
|
|
15
|
+
/** An IP literal. Never a name: a name would just be the lookup that already failed. */
|
|
16
|
+
readonly address: v.StringSchema<undefined>;
|
|
17
|
+
/** What this address IS, for the diagnostic. Never load-bearing. */
|
|
18
|
+
readonly label: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
|
|
19
|
+
}, undefined>;
|
|
20
|
+
export type EnvironmentAddress = v.InferOutput<typeof environmentAddressSchema>;
|
|
21
|
+
/**
|
|
22
|
+
* Why a `ready` environment could not be reached, at the layer the platform can observe.
|
|
23
|
+
*
|
|
24
|
+
* Separate members rather than one "unreachable" because they need different reactions and name
|
|
25
|
+
* different owners: `name_unresolved` with candidates that also failed is an environment nobody
|
|
26
|
+
* can reach, `no_candidate` is a PROVIDER that never told us where the thing lives, and
|
|
27
|
+
* `connection_refused` is a route that carries to a box with nothing listening, which is the
|
|
28
|
+
* deployed workload rather than the network.
|
|
29
|
+
*
|
|
30
|
+
* - `no_candidate` the environment carries no URL, or one with no host to probe. There
|
|
31
|
+
* was nothing to try, which is not the same as trying and failing.
|
|
32
|
+
* - `name_unresolved` the URL's host resolved nowhere, and no stated address carried either.
|
|
33
|
+
* - `no_route` something resolved and the connect never completed (timeout,
|
|
34
|
+
* host/network unreachable). The expensive failure: a lookup that
|
|
35
|
+
* worked followed by a connect that hangs.
|
|
36
|
+
* - `connection_refused` the route carries and nothing is listening on the port.
|
|
37
|
+
* - `address_refused` the provider stated an address the platform will not dial: loopback,
|
|
38
|
+
* link-local/vendor metadata, or a non-canonical literal. Recorded as an
|
|
39
|
+
* attempt rather than dropped, because a refused input is an omission the
|
|
40
|
+
* operator has to be able to see.
|
|
41
|
+
* - `probe_failed` the probe itself errored in a way it could not classify. Kept apart
|
|
42
|
+
* from the three above so "we could not tell" never renders as a
|
|
43
|
+
* verdict about the environment.
|
|
44
|
+
*/
|
|
45
|
+
export declare const environmentUnreachableReasonSchema: v.PicklistSchema<["no_candidate", "name_unresolved", "no_route", "connection_refused", "address_refused", "probe_failed"], undefined>;
|
|
46
|
+
export type EnvironmentUnreachableReason = v.InferOutput<typeof environmentUnreachableReasonSchema>;
|
|
47
|
+
/** One target the proof tried, in the order it was tried, and what came back. */
|
|
48
|
+
export declare const environmentRouteAttemptSchema: v.ObjectSchema<{
|
|
49
|
+
/** `host:port` for the name itself, `host@address:port` for a stated address. */
|
|
50
|
+
readonly target: v.StringSchema<undefined>;
|
|
51
|
+
/** `carried`, or the {@link EnvironmentUnreachableReason} that target produced. */
|
|
52
|
+
readonly outcome: v.StringSchema<undefined>;
|
|
53
|
+
/**
|
|
54
|
+
* What the probe said when it could not classify its own failure, capped for a rendered
|
|
55
|
+
* surface. The ONLY field carrying WHY a `probe_failed` attempt failed.
|
|
56
|
+
*
|
|
57
|
+
* Kept because `probe_failed` names no layer by design, so without this an operator reading a
|
|
58
|
+
* proof cannot tell a TLS or resolver fault from a runtime restriction from a bug in the probe:
|
|
59
|
+
* the three need different fixes and the reason renders identically for all of them. Absent for
|
|
60
|
+
* every other outcome, which is already self-describing.
|
|
61
|
+
*/
|
|
62
|
+
readonly detail: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
|
|
63
|
+
}, undefined>;
|
|
64
|
+
export type EnvironmentRouteAttempt = v.InferOutput<typeof environmentRouteAttemptSchema>;
|
|
65
|
+
/**
|
|
66
|
+
* What the platform PROVED about reaching an environment, once, at the moment it went `ready`.
|
|
67
|
+
*
|
|
68
|
+
* `state` splits along TWO axes and both are load-bearing. `reached` and `not_reached` are
|
|
69
|
+
* verdicts about the ENVIRONMENT, and only `not_reached` fails a deployer frame. `inconclusive`
|
|
70
|
+
* and `unproved` are verdicts about the PLATFORM, and neither may ever fail anything: collapsing
|
|
71
|
+
* either into `not_reached` turns a diagnostic into a second way for a healthy deploy to die,
|
|
72
|
+
* which is the one failure mode this whole module must not introduce, and collapsing either into
|
|
73
|
+
* `reached` hands a tester the unbacked claim it exists to retire.
|
|
74
|
+
*
|
|
75
|
+
* - `inconclusive` the platform LOOKED and established nothing either way: a probe that
|
|
76
|
+
* errored in a way it could not classify, or an environment with no address to
|
|
77
|
+
* dial. Narrated, because "we could not tell" is exactly the fact that stops an
|
|
78
|
+
* agent concluding the environment is dead.
|
|
79
|
+
* - `unproved` nothing was wired to open a socket, so nothing was tried. SILENT (see
|
|
80
|
+
* {@link reachabilityNote}): it is the standing state of every deployment with
|
|
81
|
+
* no prober, and a line on every prompt is a line nobody reads on the one
|
|
82
|
+
* prompt where it matters.
|
|
83
|
+
*/
|
|
84
|
+
export declare const environmentRouteProofSchema: v.ObjectSchema<{
|
|
85
|
+
readonly state: v.PicklistSchema<["reached", "not_reached", "inconclusive", "unproved"], undefined>;
|
|
86
|
+
/**
|
|
87
|
+
* The stated address that CARRIED, or null when the URL's own name carried (the ordinary case)
|
|
88
|
+
* and when nothing carried at all. Read `state` to tell those two apart.
|
|
89
|
+
*
|
|
90
|
+
* This is the field a container bridge is built from, which is why the proof publishes the
|
|
91
|
+
* candidate that carried rather than the first that resolved: a bridge built from an unproved
|
|
92
|
+
* address is recorded as successfully applied while the tester still fails, and the evidence
|
|
93
|
+
* then points further from the cause than no bridge at all did.
|
|
94
|
+
*/
|
|
95
|
+
readonly via: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
96
|
+
/**
|
|
97
|
+
* The {@link EnvironmentUnreachableReason} when `state` is `not_reached` or `inconclusive`,
|
|
98
|
+
* else null. An open string on the wire so a stored proof written by an older build never fails
|
|
99
|
+
* to parse; readers that branch on it treat an unknown value as "not one of the cases I handle".
|
|
100
|
+
*/
|
|
101
|
+
readonly reason: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
102
|
+
/** Every target tried, in order. Recorded whether or not one carried. */
|
|
103
|
+
readonly attempts: v.ArraySchema<v.ObjectSchema<{
|
|
104
|
+
/** `host:port` for the name itself, `host@address:port` for a stated address. */
|
|
105
|
+
readonly target: v.StringSchema<undefined>;
|
|
106
|
+
/** `carried`, or the {@link EnvironmentUnreachableReason} that target produced. */
|
|
107
|
+
readonly outcome: v.StringSchema<undefined>;
|
|
108
|
+
/**
|
|
109
|
+
* What the probe said when it could not classify its own failure, capped for a rendered
|
|
110
|
+
* surface. The ONLY field carrying WHY a `probe_failed` attempt failed.
|
|
111
|
+
*
|
|
112
|
+
* Kept because `probe_failed` names no layer by design, so without this an operator reading a
|
|
113
|
+
* proof cannot tell a TLS or resolver fault from a runtime restriction from a bug in the probe:
|
|
114
|
+
* the three need different fixes and the reason renders identically for all of them. Absent for
|
|
115
|
+
* every other outcome, which is already self-describing.
|
|
116
|
+
*/
|
|
117
|
+
readonly detail: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
|
|
118
|
+
}, undefined>, undefined>;
|
|
119
|
+
/** When the proof ran (epoch ms). */
|
|
120
|
+
readonly checkedAt: v.NumberSchema<undefined>;
|
|
121
|
+
}, undefined>;
|
|
122
|
+
export type EnvironmentRouteProof = v.InferOutput<typeof environmentRouteProofSchema>;
|
|
123
|
+
/**
|
|
124
|
+
* Everything the platform knows about ADDRESSING an environment, beside the one string it knows
|
|
125
|
+
* about naming it.
|
|
126
|
+
*
|
|
127
|
+
* Two halves because they come from two places and one of them is a claim: `candidates` is what
|
|
128
|
+
* the PROVIDER said, `proof` is what the platform TRIED. Keeping the claim after the proof runs
|
|
129
|
+
* is deliberate: an operator debugging a dead environment wants to see which addresses were
|
|
130
|
+
* offered as well as which were reached, and a re-probe on a later poll re-reads the same claim.
|
|
131
|
+
*/
|
|
132
|
+
export declare const environmentReachabilitySchema: v.ObjectSchema<{
|
|
133
|
+
/** Addresses the provider states carry traffic for the URL's host, in ITS preference order. */
|
|
134
|
+
readonly candidates: v.ArraySchema<v.ObjectSchema<{
|
|
135
|
+
/** An IP literal. Never a name: a name would just be the lookup that already failed. */
|
|
136
|
+
readonly address: v.StringSchema<undefined>;
|
|
137
|
+
/** What this address IS, for the diagnostic. Never load-bearing. */
|
|
138
|
+
readonly label: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
|
|
139
|
+
}, undefined>, undefined>;
|
|
140
|
+
/** What proving found, or null when nothing has probed this environment yet. */
|
|
141
|
+
readonly proof: v.NullableSchema<v.ObjectSchema<{
|
|
142
|
+
readonly state: v.PicklistSchema<["reached", "not_reached", "inconclusive", "unproved"], undefined>;
|
|
143
|
+
/**
|
|
144
|
+
* The stated address that CARRIED, or null when the URL's own name carried (the ordinary case)
|
|
145
|
+
* and when nothing carried at all. Read `state` to tell those two apart.
|
|
146
|
+
*
|
|
147
|
+
* This is the field a container bridge is built from, which is why the proof publishes the
|
|
148
|
+
* candidate that carried rather than the first that resolved: a bridge built from an unproved
|
|
149
|
+
* address is recorded as successfully applied while the tester still fails, and the evidence
|
|
150
|
+
* then points further from the cause than no bridge at all did.
|
|
151
|
+
*/
|
|
152
|
+
readonly via: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
153
|
+
/**
|
|
154
|
+
* The {@link EnvironmentUnreachableReason} when `state` is `not_reached` or `inconclusive`,
|
|
155
|
+
* else null. An open string on the wire so a stored proof written by an older build never fails
|
|
156
|
+
* to parse; readers that branch on it treat an unknown value as "not one of the cases I handle".
|
|
157
|
+
*/
|
|
158
|
+
readonly reason: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
159
|
+
/** Every target tried, in order. Recorded whether or not one carried. */
|
|
160
|
+
readonly attempts: v.ArraySchema<v.ObjectSchema<{
|
|
161
|
+
/** `host:port` for the name itself, `host@address:port` for a stated address. */
|
|
162
|
+
readonly target: v.StringSchema<undefined>;
|
|
163
|
+
/** `carried`, or the {@link EnvironmentUnreachableReason} that target produced. */
|
|
164
|
+
readonly outcome: v.StringSchema<undefined>;
|
|
165
|
+
/**
|
|
166
|
+
* What the probe said when it could not classify its own failure, capped for a rendered
|
|
167
|
+
* surface. The ONLY field carrying WHY a `probe_failed` attempt failed.
|
|
168
|
+
*
|
|
169
|
+
* Kept because `probe_failed` names no layer by design, so without this an operator reading a
|
|
170
|
+
* proof cannot tell a TLS or resolver fault from a runtime restriction from a bug in the probe:
|
|
171
|
+
* the three need different fixes and the reason renders identically for all of them. Absent for
|
|
172
|
+
* every other outcome, which is already self-describing.
|
|
173
|
+
*/
|
|
174
|
+
readonly detail: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
|
|
175
|
+
}, undefined>, undefined>;
|
|
176
|
+
/** When the proof ran (epoch ms). */
|
|
177
|
+
readonly checkedAt: v.NumberSchema<undefined>;
|
|
178
|
+
}, undefined>, undefined>;
|
|
179
|
+
}, undefined>;
|
|
180
|
+
export type EnvironmentReachability = v.InferOutput<typeof environmentReachabilitySchema>;
|
|
181
|
+
/**
|
|
182
|
+
* The reachability facts an agent (or a container dispatch) is handed for ONE environment it is
|
|
183
|
+
* being pointed at.
|
|
184
|
+
*
|
|
185
|
+
* A flattened projection rather than the stored shape, because the reader's question is narrower
|
|
186
|
+
* than the operator's: it needs the address it may dial and the layer that failed, not the
|
|
187
|
+
* provider's full candidate list. `state: 'reached'` with no `address` means the name itself
|
|
188
|
+
* carried, which is the case that needs no narration at all.
|
|
189
|
+
*/
|
|
190
|
+
export interface EnvironmentReachabilityNote {
|
|
191
|
+
/**
|
|
192
|
+
* Deliberately NOT the proof's full state union: an `unproved` note is unrepresentable, because
|
|
193
|
+
* the projection withholds it (see {@link reachabilityNote}). A reader that branched on
|
|
194
|
+
* `'unproved'` here would be writing a case its input can never hold.
|
|
195
|
+
*/
|
|
196
|
+
state: Exclude<EnvironmentRouteProof['state'], 'unproved'>;
|
|
197
|
+
/** The address that carried, when the name did not. */
|
|
198
|
+
address?: string;
|
|
199
|
+
reason?: string;
|
|
200
|
+
/** What a `probe_failed` attempt said, when one did. See the attempt's own `detail`. */
|
|
201
|
+
detail?: string;
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Project a stored {@link EnvironmentReachability} onto the note an agent or a dispatch reads, or
|
|
205
|
+
* undefined when there is nothing to say.
|
|
206
|
+
*
|
|
207
|
+
* Undefined in two cases, and they are the same fact from two directions: no proof has been
|
|
208
|
+
* written, and a proof recording that nothing was WIRED to probe. "Nothing has looked" is the
|
|
209
|
+
* ordinary state of an environment mid-provision AND the permanent state of a deployment with no
|
|
210
|
+
* prober, so narrating it would put an unverified-reachability warning on every prompt of such a
|
|
211
|
+
* deployment and train a reader to skip the section that matters. The row still records the
|
|
212
|
+
* `unproved` proof, because when the probe ran is a fact an operator reads off the environment.
|
|
213
|
+
*/
|
|
214
|
+
export declare function reachabilityNote(reachability: EnvironmentReachability | null | undefined): EnvironmentReachabilityNote | undefined;
|
|
215
|
+
/** Where an environment URL is dialled: its host, the port, and the scheme it names. */
|
|
216
|
+
export interface EnvironmentCoordinates {
|
|
217
|
+
host: string;
|
|
218
|
+
/** Explicit from the URL, else the scheme default (443/80), else null: nothing to dial. */
|
|
219
|
+
port: number | null;
|
|
220
|
+
/** URL scheme without the trailing colon (e.g. `https`). */
|
|
221
|
+
scheme: string;
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Derive the coordinates of an environment URL, or null when there is no URL or it does not parse.
|
|
225
|
+
*
|
|
226
|
+
* ONE deriver, here rather than beside either of its two readers, because they have to agree about
|
|
227
|
+
* the same string and the divergence is not cosmetic: the route proof DIALS what this returns and
|
|
228
|
+
* the Tester prompt states it to the agent as the environment's Host / Port / Scheme. Two parsers
|
|
229
|
+
* mean an agent told to dial coordinates the platform never probed, and the copies this replaced
|
|
230
|
+
* had already diverged on the one case that mattered (an unknown scheme became port `0` in one and
|
|
231
|
+
* `null` in the other, and `0` is what routed a non-http URL into a failed deploy).
|
|
232
|
+
*
|
|
233
|
+
* The parse is hand-rolled because contracts compiles against `lib: ["ES2022"]` with no DOM and no
|
|
234
|
+
* Node types, so `URL` is unavailable here exactly as it is in kernel, and this is the one package
|
|
235
|
+
* both readers can see. The three things a naive split gets wrong are handled: userinfo (whose
|
|
236
|
+
* password may itself contain `@`, so the LAST one separates it from the host), a bracketed IPv6
|
|
237
|
+
* literal (kept bracketed, which is what `URL.hostname` also returns), and an explicit port, where
|
|
238
|
+
* a MALFORMED one answers null rather than being dropped so a garbled URL cannot be silently
|
|
239
|
+
* dialled on the scheme default. Deliberately not attempted: IDNA/punycode and percent-decoding,
|
|
240
|
+
* neither of which an environment URL from a provider needs.
|
|
241
|
+
*
|
|
242
|
+
* An unknown scheme yields `port: null` (there is no default to invent), which every caller reads
|
|
243
|
+
* as "nothing to dial".
|
|
244
|
+
*/
|
|
245
|
+
export declare function deriveEnvironmentCoordinates(url: string | null | undefined): EnvironmentCoordinates | null;
|
|
246
|
+
//# sourceMappingURL=environment-reachability.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"environment-reachability.d.ts","sourceRoot":"","sources":["../src/environment-reachability.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,CAAC,MAAM,SAAS,CAAA;AAE5B;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,wBAAwB;IACnC,wFAAwF;;IAExF,oEAAoE;;aAEpE,CAAA;AACF,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,WAAW,CAAC,OAAO,wBAAwB,CAAC,CAAA;AAE/E;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,eAAO,MAAM,kCAAkC,uIAO7C,CAAA;AACF,MAAM,MAAM,4BAA4B,GAAG,CAAC,CAAC,WAAW,CAAC,OAAO,kCAAkC,CAAC,CAAA;AAEnG,iFAAiF;AACjF,eAAO,MAAM,6BAA6B;IACxC,iFAAiF;;IAEjF,mFAAmF;;IAEnF;;;;;;;;OAQG;;aAEH,CAAA;AACF,MAAM,MAAM,uBAAuB,GAAG,CAAC,CAAC,WAAW,CAAC,OAAO,6BAA6B,CAAC,CAAA;AAEzF;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,2BAA2B;;IAEtC;;;;;;;;OAQG;;IAEH;;;;OAIG;;IAEH,yEAAyE;;QAtDzE,iFAAiF;;QAEjF,mFAAmF;;QAEnF;;;;;;;;WAQG;;;IA4CH,qCAAqC;;aAErC,CAAA;AACF,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,WAAW,CAAC,OAAO,2BAA2B,CAAC,CAAA;AAErF;;;;;;;;GAQG;AACH,eAAO,MAAM,6BAA6B;IACxC,+FAA+F;;QAlH/F,wFAAwF;;QAExF,oEAAoE;;;IAkHpE,gFAAgF;;;QAnChF;;;;;;;;WAQG;;QAEH;;;;WAIG;;QAEH,yEAAyE;;YAtDzE,iFAAiF;;YAEjF,mFAAmF;;YAEnF;;;;;;;;eAQG;;;QA4CH,qCAAqC;;;aAmBrC,CAAA;AACF,MAAM,MAAM,uBAAuB,GAAG,CAAC,CAAC,WAAW,CAAC,OAAO,6BAA6B,CAAC,CAAA;AAEzF;;;;;;;;GAQG;AACH,MAAM,WAAW,2BAA2B;IAC1C;;;;OAIG;IACH,KAAK,EAAE,OAAO,CAAC,qBAAqB,CAAC,OAAO,CAAC,EAAE,UAAU,CAAC,CAAA;IAC1D,uDAAuD;IACvD,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,wFAAwF;IACxF,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAC9B,YAAY,EAAE,uBAAuB,GAAG,IAAI,GAAG,SAAS,GACvD,2BAA2B,GAAG,SAAS,CAUzC;AAED,wFAAwF;AACxF,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,MAAM,CAAA;IACZ,2FAA2F;IAC3F,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IACnB,4DAA4D;IAC5D,MAAM,EAAE,MAAM,CAAA;CACf;AAKD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,4BAA4B,CAC1C,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAC7B,sBAAsB,GAAG,IAAI,CAW/B"}
|