@fourier-labs/harbour-contracts 0.5.0 → 0.6.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/gen-ts/ai-governance-decision.d.ts +2 -2
- package/dist/gen-ts/ai-policy-snapshot.d.ts +5 -269
- package/dist/gen-ts/ai-runtime-contract.d.ts +1 -1
- package/dist/gen-ts/ai-transform-event.d.ts +2 -21
- package/dist/gen-ts/ai-transform-result.d.ts +1 -1
- package/dist/gen-ts/ai-verification-evidence.d.ts +1 -1
- package/dist/gen-ts/data-grant.d.ts +1 -1
- package/dist/gen-ts/error-category-registry.d.ts +5 -0
- package/dist/gen-ts/error-category-registry.js +10 -0
- package/dist/gen-ts/index.d.ts +1 -0
- package/dist/gen-ts/index.js +1 -0
- package/dist/gen-ts/kvs-routing-entry.d.ts +19 -5
- package/dist/gen-ts/promotion-request.d.ts +23 -0
- package/dist/gen-ts/transform-report.d.ts +102 -0
- package/dist/gen-ts/transform-report.js +3 -0
- package/package.json +1 -1
- package/schema/error-category.enum.json +6 -1
- package/schema/kvs-routing-entry.schema.json +28 -8
- package/schema/promotion-request.schema.json +38 -0
- package/schema/transform-report.schema.json +204 -0
|
@@ -42,7 +42,7 @@ export type AiInterceptionPlanEntry = {
|
|
|
42
42
|
* @minItems 1
|
|
43
43
|
* @maxItems 32
|
|
44
44
|
*/
|
|
45
|
-
allowedSyntaxKinds:
|
|
45
|
+
allowedSyntaxKinds: AiDecisionIdentifier[];
|
|
46
46
|
configurationMappingId?: AiDecisionIdentifier;
|
|
47
47
|
configurationMappingVersion?: string;
|
|
48
48
|
transformId?: AiDecisionIdentifier;
|
|
@@ -70,5 +70,5 @@ export interface AiDecisionRuntimeContract {
|
|
|
70
70
|
* @minItems 1
|
|
71
71
|
* @maxItems 2
|
|
72
72
|
*/
|
|
73
|
-
requiredStrategies:
|
|
73
|
+
requiredStrategies: ('deployment_injection' | 'deterministic_adapter')[];
|
|
74
74
|
}
|
|
@@ -33,7 +33,7 @@ export type AiPolicyEmbeddedJsonSchema = {
|
|
|
33
33
|
* @minItems 1
|
|
34
34
|
* @maxItems 64
|
|
35
35
|
*/
|
|
36
|
-
enum?:
|
|
36
|
+
enum?: (string | number | boolean | null)[];
|
|
37
37
|
minimum?: number;
|
|
38
38
|
maximum?: number;
|
|
39
39
|
minLength?: number;
|
|
@@ -93,7 +93,7 @@ export interface AiPolicyModel {
|
|
|
93
93
|
* @minItems 1
|
|
94
94
|
* @maxItems 2
|
|
95
95
|
*/
|
|
96
|
-
capabilities:
|
|
96
|
+
capabilities: ('generation' | 'embeddings')[];
|
|
97
97
|
approved: boolean;
|
|
98
98
|
pricing: AiPolicyPricing;
|
|
99
99
|
}
|
|
@@ -110,139 +110,7 @@ export interface AiPolicyRoute {
|
|
|
110
110
|
* @minItems 1
|
|
111
111
|
* @maxItems 16
|
|
112
112
|
*/
|
|
113
|
-
targets:
|
|
114
|
-
AiPolicyRouteTarget,
|
|
115
|
-
AiPolicyRouteTarget,
|
|
116
|
-
AiPolicyRouteTarget,
|
|
117
|
-
AiPolicyRouteTarget,
|
|
118
|
-
AiPolicyRouteTarget,
|
|
119
|
-
AiPolicyRouteTarget
|
|
120
|
-
] | [
|
|
121
|
-
AiPolicyRouteTarget,
|
|
122
|
-
AiPolicyRouteTarget,
|
|
123
|
-
AiPolicyRouteTarget,
|
|
124
|
-
AiPolicyRouteTarget,
|
|
125
|
-
AiPolicyRouteTarget,
|
|
126
|
-
AiPolicyRouteTarget,
|
|
127
|
-
AiPolicyRouteTarget
|
|
128
|
-
] | [
|
|
129
|
-
AiPolicyRouteTarget,
|
|
130
|
-
AiPolicyRouteTarget,
|
|
131
|
-
AiPolicyRouteTarget,
|
|
132
|
-
AiPolicyRouteTarget,
|
|
133
|
-
AiPolicyRouteTarget,
|
|
134
|
-
AiPolicyRouteTarget,
|
|
135
|
-
AiPolicyRouteTarget,
|
|
136
|
-
AiPolicyRouteTarget
|
|
137
|
-
] | [
|
|
138
|
-
AiPolicyRouteTarget,
|
|
139
|
-
AiPolicyRouteTarget,
|
|
140
|
-
AiPolicyRouteTarget,
|
|
141
|
-
AiPolicyRouteTarget,
|
|
142
|
-
AiPolicyRouteTarget,
|
|
143
|
-
AiPolicyRouteTarget,
|
|
144
|
-
AiPolicyRouteTarget,
|
|
145
|
-
AiPolicyRouteTarget,
|
|
146
|
-
AiPolicyRouteTarget
|
|
147
|
-
] | [
|
|
148
|
-
AiPolicyRouteTarget,
|
|
149
|
-
AiPolicyRouteTarget,
|
|
150
|
-
AiPolicyRouteTarget,
|
|
151
|
-
AiPolicyRouteTarget,
|
|
152
|
-
AiPolicyRouteTarget,
|
|
153
|
-
AiPolicyRouteTarget,
|
|
154
|
-
AiPolicyRouteTarget,
|
|
155
|
-
AiPolicyRouteTarget,
|
|
156
|
-
AiPolicyRouteTarget,
|
|
157
|
-
AiPolicyRouteTarget
|
|
158
|
-
] | [
|
|
159
|
-
AiPolicyRouteTarget,
|
|
160
|
-
AiPolicyRouteTarget,
|
|
161
|
-
AiPolicyRouteTarget,
|
|
162
|
-
AiPolicyRouteTarget,
|
|
163
|
-
AiPolicyRouteTarget,
|
|
164
|
-
AiPolicyRouteTarget,
|
|
165
|
-
AiPolicyRouteTarget,
|
|
166
|
-
AiPolicyRouteTarget,
|
|
167
|
-
AiPolicyRouteTarget,
|
|
168
|
-
AiPolicyRouteTarget,
|
|
169
|
-
AiPolicyRouteTarget
|
|
170
|
-
] | [
|
|
171
|
-
AiPolicyRouteTarget,
|
|
172
|
-
AiPolicyRouteTarget,
|
|
173
|
-
AiPolicyRouteTarget,
|
|
174
|
-
AiPolicyRouteTarget,
|
|
175
|
-
AiPolicyRouteTarget,
|
|
176
|
-
AiPolicyRouteTarget,
|
|
177
|
-
AiPolicyRouteTarget,
|
|
178
|
-
AiPolicyRouteTarget,
|
|
179
|
-
AiPolicyRouteTarget,
|
|
180
|
-
AiPolicyRouteTarget,
|
|
181
|
-
AiPolicyRouteTarget,
|
|
182
|
-
AiPolicyRouteTarget
|
|
183
|
-
] | [
|
|
184
|
-
AiPolicyRouteTarget,
|
|
185
|
-
AiPolicyRouteTarget,
|
|
186
|
-
AiPolicyRouteTarget,
|
|
187
|
-
AiPolicyRouteTarget,
|
|
188
|
-
AiPolicyRouteTarget,
|
|
189
|
-
AiPolicyRouteTarget,
|
|
190
|
-
AiPolicyRouteTarget,
|
|
191
|
-
AiPolicyRouteTarget,
|
|
192
|
-
AiPolicyRouteTarget,
|
|
193
|
-
AiPolicyRouteTarget,
|
|
194
|
-
AiPolicyRouteTarget,
|
|
195
|
-
AiPolicyRouteTarget,
|
|
196
|
-
AiPolicyRouteTarget
|
|
197
|
-
] | [
|
|
198
|
-
AiPolicyRouteTarget,
|
|
199
|
-
AiPolicyRouteTarget,
|
|
200
|
-
AiPolicyRouteTarget,
|
|
201
|
-
AiPolicyRouteTarget,
|
|
202
|
-
AiPolicyRouteTarget,
|
|
203
|
-
AiPolicyRouteTarget,
|
|
204
|
-
AiPolicyRouteTarget,
|
|
205
|
-
AiPolicyRouteTarget,
|
|
206
|
-
AiPolicyRouteTarget,
|
|
207
|
-
AiPolicyRouteTarget,
|
|
208
|
-
AiPolicyRouteTarget,
|
|
209
|
-
AiPolicyRouteTarget,
|
|
210
|
-
AiPolicyRouteTarget,
|
|
211
|
-
AiPolicyRouteTarget
|
|
212
|
-
] | [
|
|
213
|
-
AiPolicyRouteTarget,
|
|
214
|
-
AiPolicyRouteTarget,
|
|
215
|
-
AiPolicyRouteTarget,
|
|
216
|
-
AiPolicyRouteTarget,
|
|
217
|
-
AiPolicyRouteTarget,
|
|
218
|
-
AiPolicyRouteTarget,
|
|
219
|
-
AiPolicyRouteTarget,
|
|
220
|
-
AiPolicyRouteTarget,
|
|
221
|
-
AiPolicyRouteTarget,
|
|
222
|
-
AiPolicyRouteTarget,
|
|
223
|
-
AiPolicyRouteTarget,
|
|
224
|
-
AiPolicyRouteTarget,
|
|
225
|
-
AiPolicyRouteTarget,
|
|
226
|
-
AiPolicyRouteTarget,
|
|
227
|
-
AiPolicyRouteTarget
|
|
228
|
-
] | [
|
|
229
|
-
AiPolicyRouteTarget,
|
|
230
|
-
AiPolicyRouteTarget,
|
|
231
|
-
AiPolicyRouteTarget,
|
|
232
|
-
AiPolicyRouteTarget,
|
|
233
|
-
AiPolicyRouteTarget,
|
|
234
|
-
AiPolicyRouteTarget,
|
|
235
|
-
AiPolicyRouteTarget,
|
|
236
|
-
AiPolicyRouteTarget,
|
|
237
|
-
AiPolicyRouteTarget,
|
|
238
|
-
AiPolicyRouteTarget,
|
|
239
|
-
AiPolicyRouteTarget,
|
|
240
|
-
AiPolicyRouteTarget,
|
|
241
|
-
AiPolicyRouteTarget,
|
|
242
|
-
AiPolicyRouteTarget,
|
|
243
|
-
AiPolicyRouteTarget,
|
|
244
|
-
AiPolicyRouteTarget
|
|
245
|
-
];
|
|
113
|
+
targets: AiPolicyRouteTarget[];
|
|
246
114
|
retryCount: number;
|
|
247
115
|
timeoutMs: number;
|
|
248
116
|
}
|
|
@@ -275,7 +143,7 @@ export interface AiPolicyGuardrailParameters {
|
|
|
275
143
|
* @minItems 1
|
|
276
144
|
* @maxItems 64
|
|
277
145
|
*/
|
|
278
|
-
allowedTools?:
|
|
146
|
+
allowedTools?: string[];
|
|
279
147
|
jsonSchema?: AiPolicyEmbeddedJsonSchema;
|
|
280
148
|
jsonSchemaRef?: AiPolicyDigest;
|
|
281
149
|
}
|
|
@@ -293,137 +161,5 @@ export interface AiPolicyRetention {
|
|
|
293
161
|
/**
|
|
294
162
|
* @maxItems 16
|
|
295
163
|
*/
|
|
296
|
-
revealRoles:
|
|
297
|
-
AiPolicyIdentifier,
|
|
298
|
-
AiPolicyIdentifier,
|
|
299
|
-
AiPolicyIdentifier,
|
|
300
|
-
AiPolicyIdentifier,
|
|
301
|
-
AiPolicyIdentifier,
|
|
302
|
-
AiPolicyIdentifier
|
|
303
|
-
] | [
|
|
304
|
-
AiPolicyIdentifier,
|
|
305
|
-
AiPolicyIdentifier,
|
|
306
|
-
AiPolicyIdentifier,
|
|
307
|
-
AiPolicyIdentifier,
|
|
308
|
-
AiPolicyIdentifier,
|
|
309
|
-
AiPolicyIdentifier,
|
|
310
|
-
AiPolicyIdentifier
|
|
311
|
-
] | [
|
|
312
|
-
AiPolicyIdentifier,
|
|
313
|
-
AiPolicyIdentifier,
|
|
314
|
-
AiPolicyIdentifier,
|
|
315
|
-
AiPolicyIdentifier,
|
|
316
|
-
AiPolicyIdentifier,
|
|
317
|
-
AiPolicyIdentifier,
|
|
318
|
-
AiPolicyIdentifier,
|
|
319
|
-
AiPolicyIdentifier
|
|
320
|
-
] | [
|
|
321
|
-
AiPolicyIdentifier,
|
|
322
|
-
AiPolicyIdentifier,
|
|
323
|
-
AiPolicyIdentifier,
|
|
324
|
-
AiPolicyIdentifier,
|
|
325
|
-
AiPolicyIdentifier,
|
|
326
|
-
AiPolicyIdentifier,
|
|
327
|
-
AiPolicyIdentifier,
|
|
328
|
-
AiPolicyIdentifier,
|
|
329
|
-
AiPolicyIdentifier
|
|
330
|
-
] | [
|
|
331
|
-
AiPolicyIdentifier,
|
|
332
|
-
AiPolicyIdentifier,
|
|
333
|
-
AiPolicyIdentifier,
|
|
334
|
-
AiPolicyIdentifier,
|
|
335
|
-
AiPolicyIdentifier,
|
|
336
|
-
AiPolicyIdentifier,
|
|
337
|
-
AiPolicyIdentifier,
|
|
338
|
-
AiPolicyIdentifier,
|
|
339
|
-
AiPolicyIdentifier,
|
|
340
|
-
AiPolicyIdentifier
|
|
341
|
-
] | [
|
|
342
|
-
AiPolicyIdentifier,
|
|
343
|
-
AiPolicyIdentifier,
|
|
344
|
-
AiPolicyIdentifier,
|
|
345
|
-
AiPolicyIdentifier,
|
|
346
|
-
AiPolicyIdentifier,
|
|
347
|
-
AiPolicyIdentifier,
|
|
348
|
-
AiPolicyIdentifier,
|
|
349
|
-
AiPolicyIdentifier,
|
|
350
|
-
AiPolicyIdentifier,
|
|
351
|
-
AiPolicyIdentifier,
|
|
352
|
-
AiPolicyIdentifier
|
|
353
|
-
] | [
|
|
354
|
-
AiPolicyIdentifier,
|
|
355
|
-
AiPolicyIdentifier,
|
|
356
|
-
AiPolicyIdentifier,
|
|
357
|
-
AiPolicyIdentifier,
|
|
358
|
-
AiPolicyIdentifier,
|
|
359
|
-
AiPolicyIdentifier,
|
|
360
|
-
AiPolicyIdentifier,
|
|
361
|
-
AiPolicyIdentifier,
|
|
362
|
-
AiPolicyIdentifier,
|
|
363
|
-
AiPolicyIdentifier,
|
|
364
|
-
AiPolicyIdentifier,
|
|
365
|
-
AiPolicyIdentifier
|
|
366
|
-
] | [
|
|
367
|
-
AiPolicyIdentifier,
|
|
368
|
-
AiPolicyIdentifier,
|
|
369
|
-
AiPolicyIdentifier,
|
|
370
|
-
AiPolicyIdentifier,
|
|
371
|
-
AiPolicyIdentifier,
|
|
372
|
-
AiPolicyIdentifier,
|
|
373
|
-
AiPolicyIdentifier,
|
|
374
|
-
AiPolicyIdentifier,
|
|
375
|
-
AiPolicyIdentifier,
|
|
376
|
-
AiPolicyIdentifier,
|
|
377
|
-
AiPolicyIdentifier,
|
|
378
|
-
AiPolicyIdentifier,
|
|
379
|
-
AiPolicyIdentifier
|
|
380
|
-
] | [
|
|
381
|
-
AiPolicyIdentifier,
|
|
382
|
-
AiPolicyIdentifier,
|
|
383
|
-
AiPolicyIdentifier,
|
|
384
|
-
AiPolicyIdentifier,
|
|
385
|
-
AiPolicyIdentifier,
|
|
386
|
-
AiPolicyIdentifier,
|
|
387
|
-
AiPolicyIdentifier,
|
|
388
|
-
AiPolicyIdentifier,
|
|
389
|
-
AiPolicyIdentifier,
|
|
390
|
-
AiPolicyIdentifier,
|
|
391
|
-
AiPolicyIdentifier,
|
|
392
|
-
AiPolicyIdentifier,
|
|
393
|
-
AiPolicyIdentifier,
|
|
394
|
-
AiPolicyIdentifier
|
|
395
|
-
] | [
|
|
396
|
-
AiPolicyIdentifier,
|
|
397
|
-
AiPolicyIdentifier,
|
|
398
|
-
AiPolicyIdentifier,
|
|
399
|
-
AiPolicyIdentifier,
|
|
400
|
-
AiPolicyIdentifier,
|
|
401
|
-
AiPolicyIdentifier,
|
|
402
|
-
AiPolicyIdentifier,
|
|
403
|
-
AiPolicyIdentifier,
|
|
404
|
-
AiPolicyIdentifier,
|
|
405
|
-
AiPolicyIdentifier,
|
|
406
|
-
AiPolicyIdentifier,
|
|
407
|
-
AiPolicyIdentifier,
|
|
408
|
-
AiPolicyIdentifier,
|
|
409
|
-
AiPolicyIdentifier,
|
|
410
|
-
AiPolicyIdentifier
|
|
411
|
-
] | [
|
|
412
|
-
AiPolicyIdentifier,
|
|
413
|
-
AiPolicyIdentifier,
|
|
414
|
-
AiPolicyIdentifier,
|
|
415
|
-
AiPolicyIdentifier,
|
|
416
|
-
AiPolicyIdentifier,
|
|
417
|
-
AiPolicyIdentifier,
|
|
418
|
-
AiPolicyIdentifier,
|
|
419
|
-
AiPolicyIdentifier,
|
|
420
|
-
AiPolicyIdentifier,
|
|
421
|
-
AiPolicyIdentifier,
|
|
422
|
-
AiPolicyIdentifier,
|
|
423
|
-
AiPolicyIdentifier,
|
|
424
|
-
AiPolicyIdentifier,
|
|
425
|
-
AiPolicyIdentifier,
|
|
426
|
-
AiPolicyIdentifier,
|
|
427
|
-
AiPolicyIdentifier
|
|
428
|
-
];
|
|
164
|
+
revealRoles: AiPolicyIdentifier[];
|
|
429
165
|
}
|
|
@@ -23,5 +23,5 @@ export interface AiRuntimeContract {
|
|
|
23
23
|
* @minItems 1
|
|
24
24
|
* @maxItems 2
|
|
25
25
|
*/
|
|
26
|
-
requiredStrategies:
|
|
26
|
+
requiredStrategies: ('deployment_injection' | 'deterministic_adapter')[];
|
|
27
27
|
}
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
export type AiTransformIdentifier = string;
|
|
2
2
|
export type AiTransformDigest = string;
|
|
3
3
|
export type AiTransformPlanEntry = {
|
|
4
|
-
[k: string]: unknown;
|
|
5
|
-
} & {
|
|
6
4
|
callSiteFingerprint: AiTransformDigest;
|
|
7
5
|
sourcePath: string;
|
|
8
6
|
expectedSourceFileSha256: AiTransformDigest;
|
|
@@ -15,24 +13,7 @@ export type AiTransformPlanEntry = {
|
|
|
15
13
|
* @minItems 1
|
|
16
14
|
* @maxItems 32
|
|
17
15
|
*/
|
|
18
|
-
allowedSyntaxKinds:
|
|
19
|
-
runtimeShimName?: string;
|
|
20
|
-
runtimeShimVersion?: string;
|
|
21
|
-
runtimeShimDigest?: AiTransformDigest;
|
|
22
|
-
} & {
|
|
23
|
-
callSiteFingerprint: AiTransformDigest;
|
|
24
|
-
sourcePath: string;
|
|
25
|
-
expectedSourceFileSha256: AiTransformDigest;
|
|
26
|
-
strategy: 'deployment_injection' | 'deterministic_adapter';
|
|
27
|
-
configurationMappingId?: AiTransformIdentifier;
|
|
28
|
-
configurationMappingVersion?: string;
|
|
29
|
-
transformId?: AiTransformIdentifier;
|
|
30
|
-
transformVersion?: string;
|
|
31
|
-
/**
|
|
32
|
-
* @minItems 1
|
|
33
|
-
* @maxItems 32
|
|
34
|
-
*/
|
|
35
|
-
allowedSyntaxKinds: [AiTransformIdentifier, ...AiTransformIdentifier[]];
|
|
16
|
+
allowedSyntaxKinds: AiTransformIdentifier[];
|
|
36
17
|
runtimeShimName?: string;
|
|
37
18
|
runtimeShimVersion?: string;
|
|
38
19
|
runtimeShimDigest?: AiTransformDigest;
|
|
@@ -56,7 +37,7 @@ export interface AiTransformEvent {
|
|
|
56
37
|
* @minItems 1
|
|
57
38
|
* @maxItems 1000
|
|
58
39
|
*/
|
|
59
|
-
entries:
|
|
40
|
+
entries: AiTransformPlanEntry[];
|
|
60
41
|
}
|
|
61
42
|
export interface AiTransformWorkspace {
|
|
62
43
|
bucket: string;
|
|
@@ -27,7 +27,7 @@ export interface AiVerificationEvidence {
|
|
|
27
27
|
* @minItems 1
|
|
28
28
|
* @maxItems 32
|
|
29
29
|
*/
|
|
30
|
-
endpointChecks:
|
|
30
|
+
endpointChecks: AiVerificationEndpointCheck[];
|
|
31
31
|
providerCredentialsAbsent: true;
|
|
32
32
|
smokeTraceId: string;
|
|
33
33
|
evidenceDigest: AiVerificationDigest;
|
|
@@ -4,6 +4,8 @@ export declare const ErrorCategories: {
|
|
|
4
4
|
readonly IntakeAttestationMissing: "intake.attestation-missing";
|
|
5
5
|
readonly IntakeMultiAppRepo: "intake.multi-app-repo";
|
|
6
6
|
readonly SecretsUnresolvable: "secrets.unresolvable";
|
|
7
|
+
readonly SecretsReferenceUnresolvable: "secrets.reference-unresolvable";
|
|
8
|
+
readonly SecretsPlaceholderUnresolved: "secrets.placeholder-unresolved";
|
|
7
9
|
readonly SecretsLeakedInArtifact: "secrets.leaked-in-artifact";
|
|
8
10
|
readonly StorageSqliteMisclassified: "storage.sqlite-misclassified";
|
|
9
11
|
readonly StorageMappingDrift: "storage.mapping-drift";
|
|
@@ -12,6 +14,8 @@ export declare const ErrorCategories: {
|
|
|
12
14
|
readonly FrontendEnvInlinedUnfixable: "frontend.env-inlined-unfixable";
|
|
13
15
|
readonly BuildRecipeFailed: "build.recipe-failed";
|
|
14
16
|
readonly BuildImageTooLarge: "build.image-too-large";
|
|
17
|
+
readonly BrowserProbeFailed: "browser.probe-failed";
|
|
18
|
+
readonly BrowserProbeUnavailable: "browser.probe-unavailable";
|
|
15
19
|
readonly VerifySmokeFailed: "verify.smoke-failed";
|
|
16
20
|
readonly VerifyCharacterizationDiverged: "verify.characterization-diverged";
|
|
17
21
|
readonly VerifyMigrationFromZeroFailed: "verify.migration-from-zero-failed";
|
|
@@ -27,6 +31,7 @@ export declare const ErrorCategories: {
|
|
|
27
31
|
readonly AdmissionAppNotRegistered: "admission.app-not-registered";
|
|
28
32
|
readonly DeployCommitNotOnBranch: "deploy.commit-not-on-branch";
|
|
29
33
|
readonly DeployQueuePublicationFailed: "deploy.queue-publication-failed";
|
|
34
|
+
readonly SourceBranchMoved: "source.branch-moved";
|
|
30
35
|
readonly PromotionPreviewNotPromotable: "promotion.preview-not-promotable";
|
|
31
36
|
readonly PromotionProductionBranchMoved: "promotion.production-branch-moved";
|
|
32
37
|
readonly PromotionSourceTreeMismatch: "promotion.source-tree-mismatch";
|
|
@@ -6,6 +6,8 @@ export const ErrorCategories = {
|
|
|
6
6
|
IntakeAttestationMissing: "intake.attestation-missing",
|
|
7
7
|
IntakeMultiAppRepo: "intake.multi-app-repo",
|
|
8
8
|
SecretsUnresolvable: "secrets.unresolvable",
|
|
9
|
+
SecretsReferenceUnresolvable: "secrets.reference-unresolvable",
|
|
10
|
+
SecretsPlaceholderUnresolved: "secrets.placeholder-unresolved",
|
|
9
11
|
SecretsLeakedInArtifact: "secrets.leaked-in-artifact",
|
|
10
12
|
StorageSqliteMisclassified: "storage.sqlite-misclassified",
|
|
11
13
|
StorageMappingDrift: "storage.mapping-drift",
|
|
@@ -14,6 +16,8 @@ export const ErrorCategories = {
|
|
|
14
16
|
FrontendEnvInlinedUnfixable: "frontend.env-inlined-unfixable",
|
|
15
17
|
BuildRecipeFailed: "build.recipe-failed",
|
|
16
18
|
BuildImageTooLarge: "build.image-too-large",
|
|
19
|
+
BrowserProbeFailed: "browser.probe-failed",
|
|
20
|
+
BrowserProbeUnavailable: "browser.probe-unavailable",
|
|
17
21
|
VerifySmokeFailed: "verify.smoke-failed",
|
|
18
22
|
VerifyCharacterizationDiverged: "verify.characterization-diverged",
|
|
19
23
|
VerifyMigrationFromZeroFailed: "verify.migration-from-zero-failed",
|
|
@@ -29,6 +33,7 @@ export const ErrorCategories = {
|
|
|
29
33
|
AdmissionAppNotRegistered: "admission.app-not-registered",
|
|
30
34
|
DeployCommitNotOnBranch: "deploy.commit-not-on-branch",
|
|
31
35
|
DeployQueuePublicationFailed: "deploy.queue-publication-failed",
|
|
36
|
+
SourceBranchMoved: "source.branch-moved",
|
|
32
37
|
PromotionPreviewNotPromotable: "promotion.preview-not-promotable",
|
|
33
38
|
PromotionProductionBranchMoved: "promotion.production-branch-moved",
|
|
34
39
|
PromotionSourceTreeMismatch: "promotion.source-tree-mismatch",
|
|
@@ -44,6 +49,8 @@ const retryableExact = {
|
|
|
44
49
|
"intake.attestation-missing": false,
|
|
45
50
|
"intake.multi-app-repo": false,
|
|
46
51
|
"secrets.unresolvable": false,
|
|
52
|
+
"secrets.reference-unresolvable": false,
|
|
53
|
+
"secrets.placeholder-unresolved": false,
|
|
47
54
|
"secrets.leaked-in-artifact": false,
|
|
48
55
|
"storage.sqlite-misclassified": false,
|
|
49
56
|
"storage.mapping-drift": false,
|
|
@@ -52,6 +59,8 @@ const retryableExact = {
|
|
|
52
59
|
"frontend.env-inlined-unfixable": false,
|
|
53
60
|
"build.recipe-failed": false,
|
|
54
61
|
"build.image-too-large": false,
|
|
62
|
+
"browser.probe-failed": true,
|
|
63
|
+
"browser.probe-unavailable": false,
|
|
55
64
|
"verify.smoke-failed": false,
|
|
56
65
|
"verify.characterization-diverged": false,
|
|
57
66
|
"verify.migration-from-zero-failed": false,
|
|
@@ -67,6 +76,7 @@ const retryableExact = {
|
|
|
67
76
|
"admission.app-not-registered": false,
|
|
68
77
|
"deploy.commit-not-on-branch": false,
|
|
69
78
|
"deploy.queue-publication-failed": true,
|
|
79
|
+
"source.branch-moved": false,
|
|
70
80
|
"promotion.preview-not-promotable": false,
|
|
71
81
|
"promotion.production-branch-moved": false,
|
|
72
82
|
"promotion.source-tree-mismatch": false,
|
package/dist/gen-ts/index.d.ts
CHANGED
|
@@ -28,5 +28,6 @@ export * from './kvs-routing-entry.js';
|
|
|
28
28
|
export * from './promotion-request.js';
|
|
29
29
|
export * from './promotion-response.js';
|
|
30
30
|
export * from './secret-reference.js';
|
|
31
|
+
export * from './transform-report.js';
|
|
31
32
|
export * from './version-state-machine.js';
|
|
32
33
|
export * from './version-state.js';
|
package/dist/gen-ts/index.js
CHANGED
|
@@ -30,5 +30,6 @@ export * from './kvs-routing-entry.js';
|
|
|
30
30
|
export * from './promotion-request.js';
|
|
31
31
|
export * from './promotion-response.js';
|
|
32
32
|
export * from './secret-reference.js';
|
|
33
|
+
export * from './transform-report.js';
|
|
33
34
|
export * from './version-state-machine.js';
|
|
34
35
|
export * from './version-state.js';
|
|
@@ -1,13 +1,27 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Value stored in the CloudFront KeyValueStore
|
|
2
|
+
* Value stored in the CloudFront KeyValueStore and read by the viewer-request router on EVERY request. Keyed by `<org>.<app>` — the tenant-qualified app identity, not a host header; slugs are lowercase DNS-label-shaped and cannot contain dots, so the single dot is an unambiguous separator. Two constraints cannot be expressed in JSON Schema and are enforced in the router: the TOTAL length of all `staticAssetPrefixes` must not exceed 512 bytes, and the array must be empty when `routeMode` is `static`. Written by cutover; a request whose entry fails any of these rules is refused at the edge rather than routed on a guess.
|
|
3
3
|
*/
|
|
4
4
|
export interface KvsRoutingEntry {
|
|
5
5
|
/**
|
|
6
|
-
*
|
|
6
|
+
* Immutable prefix of the LIVE version's static output: `builds/<org>/<app>/<64-hex-digest>`, with no trailing slash. The digest is what makes a cutover safe — the router rewrites matching requests to this prefix before the cache lookup, so it is also the edge cache key, and a new version therefore cannot serve the previous version's cached bytes.
|
|
7
7
|
*/
|
|
8
|
-
|
|
8
|
+
staticPath: string;
|
|
9
9
|
/**
|
|
10
|
-
*
|
|
10
|
+
* Whether the app has an application runtime. REQUIRED: an entry without it is refused with 503 rather than guessed at. In `server` mode a path under a declared `staticAssetPrefixes` entry is served from S3 and everything else goes to `apiDomain`; in `static` mode every path is served from S3.
|
|
11
11
|
*/
|
|
12
|
-
|
|
12
|
+
routeMode: 'server' | 'static';
|
|
13
|
+
/**
|
|
14
|
+
* The version's monotonic sequence number within its lane. Cutover uses it to keep writes one-way: an entry is only replaced by a strictly higher ordinal, so a delayed or replayed write cannot move an app backwards.
|
|
15
|
+
*/
|
|
16
|
+
ordinal: number;
|
|
17
|
+
/**
|
|
18
|
+
* The app runtime's AWS_IAM-protected Lambda Function URL host. Required in `server` mode and omitted entirely for a static-only app. The router refuses any other domain shape, so this cannot be pointed at an arbitrary origin.
|
|
19
|
+
*/
|
|
20
|
+
apiDomain?: string;
|
|
21
|
+
/**
|
|
22
|
+
* Build-derived prefixes that a `server` app serves from its immutable S3 output rather than from its runtime, e.g. `_next/static/`. Derived from verified build output, never from framework names. Must be strictly ascending, must total at most 512 bytes, and must be absent or empty in `static` mode — the last two are enforced in the router because JSON Schema cannot express them. Omitted when empty: a server app with public build output and no prefixes serves every asset from its Lambda, which is a build-plan defect rather than a routing one.
|
|
23
|
+
*
|
|
24
|
+
* @maxItems 16
|
|
25
|
+
*/
|
|
26
|
+
staticAssetPrefixes?: string[];
|
|
13
27
|
}
|
|
@@ -14,4 +14,27 @@ export interface PromotionRequest {
|
|
|
14
14
|
* Durable caller-generated key. Identical replays return the original production version; reuse with a changed request is rejected.
|
|
15
15
|
*/
|
|
16
16
|
idempotencyKey: string;
|
|
17
|
+
environmentBindings?: PromotionRequestEnvironmentBindings;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Optional secret bindings for the production version. Additive: promotions without it remain valid, and a deployment plane that ignores the field behaves exactly as before. Named environmentBindings to match deploy-request.schema.json, whose preview counterpart this mirrors.
|
|
21
|
+
*/
|
|
22
|
+
export interface PromotionRequestEnvironmentBindings {
|
|
23
|
+
/**
|
|
24
|
+
* Secret bindings for the production version. An empty array is meaningful: it says the caller looked and the app declares no secrets.
|
|
25
|
+
*/
|
|
26
|
+
bindings: PromotionRequestSecretBinding[];
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* One secret binding. Unlike the preview counterpart there is no `value` member and `secretRef` is required, so a plain literal is unrepresentable on the promotion path rather than merely refused by the handler. The secretRef pattern admits only the app-secret shape, which is what keeps a promotion from naming a tenant integration credential.
|
|
30
|
+
*/
|
|
31
|
+
export interface PromotionRequestSecretBinding {
|
|
32
|
+
/**
|
|
33
|
+
* Environment-variable name the app reads.
|
|
34
|
+
*/
|
|
35
|
+
name: string;
|
|
36
|
+
/**
|
|
37
|
+
* Governance reference the deployment plane resolves. The value never appears in the request, in this schema, or in any record derived from it.
|
|
38
|
+
*/
|
|
39
|
+
secretRef: string;
|
|
17
40
|
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structured output an agent must return from one Harbour transformation attempt. Handed to the agent as its output schema, then decoded and semantically re-validated by the control plane, which remains the authority. The enum on applied_playbooks.items is the one dynamic part: the adapter injects the names of the playbooks supplied for that invocation before writing the document, so the model is structurally prevented from naming a playbook it was not given. Application-secret handling was removed platform-wide, so this document carries no redactions and no secrets fields.
|
|
3
|
+
*/
|
|
4
|
+
export interface TransformReport {
|
|
5
|
+
/**
|
|
6
|
+
* @minItems 1
|
|
7
|
+
*/
|
|
8
|
+
applied_playbooks: string[];
|
|
9
|
+
static_rebuild_required: boolean;
|
|
10
|
+
analysis: {
|
|
11
|
+
deployable: boolean;
|
|
12
|
+
needsTransformation: boolean;
|
|
13
|
+
/**
|
|
14
|
+
* @maxItems 64
|
|
15
|
+
*/
|
|
16
|
+
blockers: string[];
|
|
17
|
+
/**
|
|
18
|
+
* @minItems 1
|
|
19
|
+
* @maxItems 1024
|
|
20
|
+
*/
|
|
21
|
+
surfaces: string[];
|
|
22
|
+
/**
|
|
23
|
+
* @maxItems 1024
|
|
24
|
+
*/
|
|
25
|
+
evidence: {
|
|
26
|
+
path: string;
|
|
27
|
+
line: number;
|
|
28
|
+
reason: string;
|
|
29
|
+
}[];
|
|
30
|
+
};
|
|
31
|
+
database: {
|
|
32
|
+
mode: 'none' | 'sql' | 'unsupported';
|
|
33
|
+
changeType: 'none' | 'code_only' | 'schema_only' | 'code_and_schema';
|
|
34
|
+
requiresCodeChanges: boolean;
|
|
35
|
+
requiresSchemaMigration: boolean;
|
|
36
|
+
desiredSchemaPath: string;
|
|
37
|
+
/**
|
|
38
|
+
* @maxItems 128
|
|
39
|
+
*/
|
|
40
|
+
migrationPaths: string[];
|
|
41
|
+
/**
|
|
42
|
+
* @maxItems 512
|
|
43
|
+
*/
|
|
44
|
+
changedFiles: string[];
|
|
45
|
+
/**
|
|
46
|
+
* @maxItems 128
|
|
47
|
+
*/
|
|
48
|
+
evidence: {
|
|
49
|
+
path: string;
|
|
50
|
+
line: number;
|
|
51
|
+
reason: string;
|
|
52
|
+
}[];
|
|
53
|
+
/**
|
|
54
|
+
* @maxItems 64
|
|
55
|
+
*/
|
|
56
|
+
unsupportedFeatures: string[];
|
|
57
|
+
};
|
|
58
|
+
application: {
|
|
59
|
+
runtime: string;
|
|
60
|
+
buildKind: 'container' | 'static';
|
|
61
|
+
topology: 'static' | 'backend' | 'frontend_and_backend';
|
|
62
|
+
entrypoint: string;
|
|
63
|
+
build: {
|
|
64
|
+
/**
|
|
65
|
+
* @minItems 1
|
|
66
|
+
* @maxItems 64
|
|
67
|
+
*/
|
|
68
|
+
installCommand: string[];
|
|
69
|
+
/**
|
|
70
|
+
* @minItems 1
|
|
71
|
+
* @maxItems 64
|
|
72
|
+
*/
|
|
73
|
+
buildCommand: string[];
|
|
74
|
+
/**
|
|
75
|
+
* @minItems 1
|
|
76
|
+
* @maxItems 16
|
|
77
|
+
*/
|
|
78
|
+
outputs: {
|
|
79
|
+
path: string;
|
|
80
|
+
kind: 'public' | 'backend';
|
|
81
|
+
route: string;
|
|
82
|
+
}[];
|
|
83
|
+
};
|
|
84
|
+
basePath: {
|
|
85
|
+
required: boolean;
|
|
86
|
+
environmentVariable: 'HARBOUR_BASE_PATH';
|
|
87
|
+
};
|
|
88
|
+
/**
|
|
89
|
+
* @minItems 1
|
|
90
|
+
* @maxItems 64
|
|
91
|
+
*/
|
|
92
|
+
evidence: {
|
|
93
|
+
path: string;
|
|
94
|
+
line: number;
|
|
95
|
+
reason: string;
|
|
96
|
+
}[];
|
|
97
|
+
/**
|
|
98
|
+
* @maxItems 64
|
|
99
|
+
*/
|
|
100
|
+
unsupportedFeatures: string[];
|
|
101
|
+
};
|
|
102
|
+
}
|
package/package.json
CHANGED
|
@@ -16,7 +16,9 @@
|
|
|
16
16
|
{ "id": "intake.unsupported-runtime", "retryable": false, "description": "Detected runtime has no Harbour build recipe." },
|
|
17
17
|
{ "id": "intake.attestation-missing", "retryable": false, "description": "Required auth attestation absent." },
|
|
18
18
|
{ "id": "intake.multi-app-repo", "retryable": false, "description": "Repo contains more than one deployable app." },
|
|
19
|
-
{ "id": "secrets.unresolvable", "retryable": false, "description": "
|
|
19
|
+
{ "id": "secrets.unresolvable", "retryable": false, "retired": true, "description": "RETIRED 2026-08-08 and no longer emittable: the secret-materializer stack, its reconciler and the secret-reference playbook were all removed, so nothing can reach this state. Kept rather than deleted because historical failure records still carry it and a dropped id would decode to nothing. Do not emit in new code." },
|
|
20
|
+
{ "id": "secrets.reference-unresolvable", "retryable": false, "description": "A governance secret reference supplied on the deploy request could not be resolved to a stored value — the secret does not exist, the read was denied, or the secretref:// URI is malformed. Not retryable: no amount of waiting produces the value, a human must set it (or fix the reference) before the deploy can proceed." },
|
|
21
|
+
{ "id": "secrets.placeholder-unresolved", "retryable": false, "description": "The built workspace still contains a ${HARBOUR_REDACTED_<KEY>} substitution placeholder after transformation, meaning the transform never converted it into a runtime secret lookup and the artifact would ship a literal placeholder where a secret belongs. Not retryable: the workspace is already built, so the same input yields the same placeholder until the transform is corrected." },
|
|
20
22
|
{ "id": "secrets.leaked-in-artifact", "retryable": false, "description": "Artifact secret scan found a plaintext secret in the built image (belt-and-suspenders)." },
|
|
21
23
|
{ "id": "storage.sqlite-misclassified", "retryable": false, "description": "SQLite usage not resolvable to a managed binding." },
|
|
22
24
|
{ "id": "storage.unsupported-engine", "retryable": false, "family": true, "description": "Storage engine with no Harbour mapping; concrete token names the engine, e.g. storage.unsupported-engine.mongodb." },
|
|
@@ -27,6 +29,8 @@
|
|
|
27
29
|
{ "id": "frontend.env-inlined-unfixable", "retryable": false, "description": "Client code inlined build-time env/self-URLs in a way transformation cannot rewrite." },
|
|
28
30
|
{ "id": "build.recipe-failed", "retryable": false, "description": "The Harbour build recipe failed for the detected runtime." },
|
|
29
31
|
{ "id": "build.image-too-large", "retryable": false, "description": "Built image exceeded the size limit." },
|
|
32
|
+
{ "id": "browser.probe-failed", "retryable": true, "description": "The app built and produced its declared outputs, but the browser probe found it does not serve them — typically assets emitted at the root instead of under the app base path. Retryable because it is fed back to the transform agent, which is the component that can fix it; the merged job retries in-loop and the state machine retries the job. Distinct from build.recipe-failed, which means the build itself did not succeed: here it did." },
|
|
33
|
+
{ "id": "browser.probe-unavailable", "retryable": false, "description": "The browser probe could not reach a verdict — Chromium crashed or disconnected, or it wrote no result document. Says nothing about the app, so it is NOT fed back to the agent: retrying would spend agent budget on something the agent cannot influence, and that budget is currently the only cost control in the system (control-plane-infra ADR 0007). Replaces the uncategorized.browser-probe token the merged job emitted while this entry did not exist." },
|
|
30
34
|
{ "id": "verify.smoke-failed", "retryable": false, "description": "Candidate smoke/health check failed (boot, routes, storage, secret refs, response shape)." },
|
|
31
35
|
{ "id": "verify.characterization-diverged", "retryable": false, "description": "Post-MVP: recorded req/res replay diverged beyond thresholds." },
|
|
32
36
|
{ "id": "verify.migration-from-zero-failed", "retryable": false, "description": "Post-MVP: from-zero migration chain failed on scratch DB." },
|
|
@@ -42,6 +46,7 @@
|
|
|
42
46
|
{ "id": "admission.app-not-registered", "retryable": false, "description": "Admission rejected: the app directory does not know this app, so there is no sourceRef to fetch a commit from. Fails closed rather than creating the app on demand — a deploy request must not become an app-creation side effect, or app naming stops being a reviewed act. Non-retryable: the directory is authoritative, so retrying cannot make an unknown app known." },
|
|
43
47
|
{ "id": "deploy.commit-not-on-branch", "retryable": false, "description": "Admission rejected: the deploy request's commit is not reachable from the app's branch." },
|
|
44
48
|
{ "id": "deploy.queue-publication-failed", "retryable": true, "description": "The version was created but its version-qualified SQS message definitively could not be published. The lane is released when this version still owns it; submitting a new deployment is safe." },
|
|
49
|
+
{ "id": "source.branch-moved", "retryable": false, "description": "The app branch head moved while the transformed commit was being published, so the publish would have raced another push. Non-retryable at this version: the deploy request named a commit and the branch now points elsewhere, so a retry would deploy something the requester did not ask for. Submitting a new deployment for the new head is the recovery." },
|
|
45
50
|
{ "id": "promotion.preview-not-promotable", "retryable": false, "description": "The referenced preview is missing, belongs to another route, is not LIVE, or lacks immutable artifact and source-tree evidence." },
|
|
46
51
|
{ "id": "promotion.production-branch-moved", "retryable": false, "description": "The requested production commit is not the current configured production branch head." },
|
|
47
52
|
{ "id": "promotion.source-tree-mismatch", "retryable": false, "description": "The production commit root Git tree identity differs from the referenced preview tree identity." },
|
|
@@ -2,20 +2,40 @@
|
|
|
2
2
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
3
|
"$id": "https://schemas.harbour.dev/kvs-routing-entry.schema.json",
|
|
4
4
|
"title": "KvsRoutingEntry",
|
|
5
|
-
"description": "Value stored in the CloudFront KeyValueStore
|
|
5
|
+
"description": "Value stored in the CloudFront KeyValueStore and read by the viewer-request router on EVERY request. Keyed by `<org>.<app>` — the tenant-qualified app identity, not a host header; slugs are lowercase DNS-label-shaped and cannot contain dots, so the single dot is an unambiguous separator. Two constraints cannot be expressed in JSON Schema and are enforced in the router: the TOTAL length of all `staticAssetPrefixes` must not exceed 512 bytes, and the array must be empty when `routeMode` is `static`. Written by cutover; a request whose entry fails any of these rules is refused at the edge rather than routed on a guess.",
|
|
6
6
|
"type": "object",
|
|
7
7
|
"additionalProperties": false,
|
|
8
|
-
"required": ["
|
|
8
|
+
"required": ["staticPath", "routeMode", "ordinal"],
|
|
9
9
|
"properties": {
|
|
10
|
-
"
|
|
10
|
+
"staticPath": {
|
|
11
11
|
"type": "string",
|
|
12
|
-
"
|
|
13
|
-
"description": "
|
|
12
|
+
"pattern": "^builds/[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?/[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?/[0-9a-f]{64}$",
|
|
13
|
+
"description": "Immutable prefix of the LIVE version's static output: `builds/<org>/<app>/<64-hex-digest>`, with no trailing slash. The digest is what makes a cutover safe — the router rewrites matching requests to this prefix before the cache lookup, so it is also the edge cache key, and a new version therefore cannot serve the previous version's cached bytes."
|
|
14
14
|
},
|
|
15
|
-
"
|
|
15
|
+
"routeMode": {
|
|
16
16
|
"type": "string",
|
|
17
|
-
"
|
|
18
|
-
"description": "
|
|
17
|
+
"enum": ["server", "static"],
|
|
18
|
+
"description": "Whether the app has an application runtime. REQUIRED: an entry without it is refused with 503 rather than guessed at. In `server` mode a path under a declared `staticAssetPrefixes` entry is served from S3 and everything else goes to `apiDomain`; in `static` mode every path is served from S3."
|
|
19
|
+
},
|
|
20
|
+
"ordinal": {
|
|
21
|
+
"type": "integer",
|
|
22
|
+
"minimum": 1,
|
|
23
|
+
"description": "The version's monotonic sequence number within its lane. Cutover uses it to keep writes one-way: an entry is only replaced by a strictly higher ordinal, so a delayed or replayed write cannot move an app backwards."
|
|
24
|
+
},
|
|
25
|
+
"apiDomain": {
|
|
26
|
+
"type": "string",
|
|
27
|
+
"pattern": "^[a-z0-9-]+\\.lambda-url\\.[a-z0-9-]+\\.on\\.aws$",
|
|
28
|
+
"description": "The app runtime's AWS_IAM-protected Lambda Function URL host. Required in `server` mode and omitted entirely for a static-only app. The router refuses any other domain shape, so this cannot be pointed at an arbitrary origin."
|
|
29
|
+
},
|
|
30
|
+
"staticAssetPrefixes": {
|
|
31
|
+
"type": "array",
|
|
32
|
+
"maxItems": 16,
|
|
33
|
+
"uniqueItems": true,
|
|
34
|
+
"description": "Build-derived prefixes that a `server` app serves from its immutable S3 output rather than from its runtime, e.g. `_next/static/`. Derived from verified build output, never from framework names. Must be strictly ascending, must total at most 512 bytes, and must be absent or empty in `static` mode — the last two are enforced in the router because JSON Schema cannot express them. Omitted when empty: a server app with public build output and no prefixes serves every asset from its Lambda, which is a build-plan defect rather than a routing one.",
|
|
35
|
+
"items": {
|
|
36
|
+
"type": "string",
|
|
37
|
+
"pattern": "^[A-Za-z0-9_-]+(?:/[A-Za-z0-9_-]+)*/$"
|
|
38
|
+
}
|
|
19
39
|
}
|
|
20
40
|
}
|
|
21
41
|
}
|
|
@@ -21,6 +21,44 @@
|
|
|
21
21
|
"type": "string",
|
|
22
22
|
"pattern": "^[A-Za-z0-9][A-Za-z0-9._:-]{7,127}$",
|
|
23
23
|
"description": "Durable caller-generated key. Identical replays return the original production version; reuse with a changed request is rejected."
|
|
24
|
+
},
|
|
25
|
+
"environmentBindings": {
|
|
26
|
+
"$ref": "#/definitions/PromotionRequestEnvironmentBindings"
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
"definitions": {
|
|
30
|
+
"PromotionRequestEnvironmentBindings": {
|
|
31
|
+
"type": "object",
|
|
32
|
+
"additionalProperties": false,
|
|
33
|
+
"required": ["bindings"],
|
|
34
|
+
"properties": {
|
|
35
|
+
"bindings": {
|
|
36
|
+
"type": "array",
|
|
37
|
+
"items": {
|
|
38
|
+
"$ref": "#/definitions/PromotionRequestSecretBinding"
|
|
39
|
+
},
|
|
40
|
+
"description": "Secret bindings for the production version. An empty array is meaningful: it says the caller looked and the app declares no secrets."
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
"description": "Optional secret bindings for the production version. Additive: promotions without it remain valid, and a deployment plane that ignores the field behaves exactly as before. Named environmentBindings to match deploy-request.schema.json, whose preview counterpart this mirrors."
|
|
44
|
+
},
|
|
45
|
+
"PromotionRequestSecretBinding": {
|
|
46
|
+
"type": "object",
|
|
47
|
+
"additionalProperties": false,
|
|
48
|
+
"required": ["name", "secretRef"],
|
|
49
|
+
"properties": {
|
|
50
|
+
"name": {
|
|
51
|
+
"type": "string",
|
|
52
|
+
"pattern": "^[A-Z][A-Z0-9_]{0,127}$",
|
|
53
|
+
"description": "Environment-variable name the app reads."
|
|
54
|
+
},
|
|
55
|
+
"secretRef": {
|
|
56
|
+
"type": "string",
|
|
57
|
+
"pattern": "^secretref://tenant/[A-Za-z0-9._-]+/app/[A-Za-z0-9._-]+/secret/[A-Z][A-Z0-9_]{0,127}$",
|
|
58
|
+
"description": "Governance reference the deployment plane resolves. The value never appears in the request, in this schema, or in any record derived from it."
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
"description": "One secret binding. Unlike the preview counterpart there is no `value` member and `secretRef` is required, so a plain literal is unrepresentable on the promotion path rather than merely refused by the handler. The secretRef pattern admits only the app-secret shape, which is what keeps a promotion from naming a tenant integration credential."
|
|
24
62
|
}
|
|
25
63
|
}
|
|
26
64
|
}
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"$id": "https://schemas.harbour.dev/transform-report.schema.json",
|
|
4
|
+
"title": "TransformReport",
|
|
5
|
+
"description": "Structured output an agent must return from one Harbour transformation attempt. Handed to the agent as its output schema, then decoded and semantically re-validated by the control plane, which remains the authority. The enum on applied_playbooks.items is the one dynamic part: the adapter injects the names of the playbooks supplied for that invocation before writing the document, so the model is structurally prevented from naming a playbook it was not given. Application-secret handling was removed platform-wide, so this document carries no redactions and no secrets fields.",
|
|
6
|
+
"x-go-embed": true,
|
|
7
|
+
"type": "object",
|
|
8
|
+
"additionalProperties": false,
|
|
9
|
+
"required": [
|
|
10
|
+
"applied_playbooks",
|
|
11
|
+
"static_rebuild_required",
|
|
12
|
+
"analysis",
|
|
13
|
+
"database",
|
|
14
|
+
"application"
|
|
15
|
+
],
|
|
16
|
+
"properties": {
|
|
17
|
+
"applied_playbooks": {
|
|
18
|
+
"type": "array",
|
|
19
|
+
"minItems": 1,
|
|
20
|
+
"items": { "type": "string", "minLength": 1 }
|
|
21
|
+
},
|
|
22
|
+
"static_rebuild_required": { "type": "boolean" },
|
|
23
|
+
"analysis": {
|
|
24
|
+
"type": "object",
|
|
25
|
+
"additionalProperties": false,
|
|
26
|
+
"required": ["deployable", "needsTransformation", "blockers", "surfaces", "evidence"],
|
|
27
|
+
"properties": {
|
|
28
|
+
"deployable": { "type": "boolean" },
|
|
29
|
+
"needsTransformation": { "type": "boolean" },
|
|
30
|
+
"blockers": {
|
|
31
|
+
"type": "array",
|
|
32
|
+
"maxItems": 64,
|
|
33
|
+
"items": { "type": "string", "minLength": 1, "maxLength": 1024 }
|
|
34
|
+
},
|
|
35
|
+
"surfaces": {
|
|
36
|
+
"type": "array",
|
|
37
|
+
"minItems": 1,
|
|
38
|
+
"maxItems": 1024,
|
|
39
|
+
"items": { "type": "string", "minLength": 1, "maxLength": 512 }
|
|
40
|
+
},
|
|
41
|
+
"evidence": {
|
|
42
|
+
"type": "array",
|
|
43
|
+
"maxItems": 1024,
|
|
44
|
+
"items": {
|
|
45
|
+
"type": "object",
|
|
46
|
+
"additionalProperties": false,
|
|
47
|
+
"required": ["path", "line", "reason"],
|
|
48
|
+
"properties": {
|
|
49
|
+
"path": { "type": "string", "minLength": 1, "maxLength": 512 },
|
|
50
|
+
"line": { "type": "integer", "minimum": 1 },
|
|
51
|
+
"reason": { "type": "string", "minLength": 1, "maxLength": 1024 }
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
"database": {
|
|
58
|
+
"type": "object",
|
|
59
|
+
"additionalProperties": false,
|
|
60
|
+
"required": [
|
|
61
|
+
"mode",
|
|
62
|
+
"changeType",
|
|
63
|
+
"requiresCodeChanges",
|
|
64
|
+
"requiresSchemaMigration",
|
|
65
|
+
"desiredSchemaPath",
|
|
66
|
+
"migrationPaths",
|
|
67
|
+
"changedFiles",
|
|
68
|
+
"evidence",
|
|
69
|
+
"unsupportedFeatures"
|
|
70
|
+
],
|
|
71
|
+
"properties": {
|
|
72
|
+
"mode": { "type": "string", "enum": ["none", "sql", "unsupported"] },
|
|
73
|
+
"changeType": {
|
|
74
|
+
"type": "string",
|
|
75
|
+
"enum": ["none", "code_only", "schema_only", "code_and_schema"]
|
|
76
|
+
},
|
|
77
|
+
"requiresCodeChanges": { "type": "boolean" },
|
|
78
|
+
"requiresSchemaMigration": { "type": "boolean" },
|
|
79
|
+
"desiredSchemaPath": { "type": "string", "maxLength": 512 },
|
|
80
|
+
"migrationPaths": {
|
|
81
|
+
"type": "array",
|
|
82
|
+
"maxItems": 128,
|
|
83
|
+
"items": { "type": "string", "minLength": 1, "maxLength": 512 }
|
|
84
|
+
},
|
|
85
|
+
"changedFiles": {
|
|
86
|
+
"type": "array",
|
|
87
|
+
"maxItems": 512,
|
|
88
|
+
"items": { "type": "string", "minLength": 1, "maxLength": 512 }
|
|
89
|
+
},
|
|
90
|
+
"evidence": {
|
|
91
|
+
"type": "array",
|
|
92
|
+
"maxItems": 128,
|
|
93
|
+
"items": {
|
|
94
|
+
"type": "object",
|
|
95
|
+
"additionalProperties": false,
|
|
96
|
+
"required": ["path", "line", "reason"],
|
|
97
|
+
"properties": {
|
|
98
|
+
"path": { "type": "string", "minLength": 1, "maxLength": 512 },
|
|
99
|
+
"line": { "type": "integer", "minimum": 1 },
|
|
100
|
+
"reason": { "type": "string", "minLength": 1, "maxLength": 1024 }
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
},
|
|
104
|
+
"unsupportedFeatures": {
|
|
105
|
+
"type": "array",
|
|
106
|
+
"maxItems": 64,
|
|
107
|
+
"items": { "type": "string", "minLength": 1, "maxLength": 512 }
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
},
|
|
111
|
+
"application": {
|
|
112
|
+
"type": "object",
|
|
113
|
+
"additionalProperties": false,
|
|
114
|
+
"required": [
|
|
115
|
+
"runtime",
|
|
116
|
+
"buildKind",
|
|
117
|
+
"topology",
|
|
118
|
+
"entrypoint",
|
|
119
|
+
"build",
|
|
120
|
+
"basePath",
|
|
121
|
+
"evidence",
|
|
122
|
+
"unsupportedFeatures"
|
|
123
|
+
],
|
|
124
|
+
"properties": {
|
|
125
|
+
"runtime": {
|
|
126
|
+
"type": "string",
|
|
127
|
+
"pattern": "^(?:nodejs|python)[0-9]+(?:\\.[0-9]+)?$"
|
|
128
|
+
},
|
|
129
|
+
"buildKind": { "type": "string", "enum": ["container", "static"] },
|
|
130
|
+
"topology": {
|
|
131
|
+
"type": "string",
|
|
132
|
+
"enum": ["static", "backend", "frontend_and_backend"]
|
|
133
|
+
},
|
|
134
|
+
"entrypoint": { "type": "string", "minLength": 1, "maxLength": 1024 },
|
|
135
|
+
"build": {
|
|
136
|
+
"type": "object",
|
|
137
|
+
"additionalProperties": false,
|
|
138
|
+
"required": ["installCommand", "buildCommand", "outputs"],
|
|
139
|
+
"properties": {
|
|
140
|
+
"installCommand": {
|
|
141
|
+
"type": "array",
|
|
142
|
+
"minItems": 1,
|
|
143
|
+
"maxItems": 64,
|
|
144
|
+
"items": { "type": "string", "minLength": 1, "maxLength": 1024 }
|
|
145
|
+
},
|
|
146
|
+
"buildCommand": {
|
|
147
|
+
"type": "array",
|
|
148
|
+
"minItems": 1,
|
|
149
|
+
"maxItems": 64,
|
|
150
|
+
"items": { "type": "string", "minLength": 1, "maxLength": 1024 }
|
|
151
|
+
},
|
|
152
|
+
"outputs": {
|
|
153
|
+
"type": "array",
|
|
154
|
+
"minItems": 1,
|
|
155
|
+
"maxItems": 16,
|
|
156
|
+
"items": {
|
|
157
|
+
"type": "object",
|
|
158
|
+
"additionalProperties": false,
|
|
159
|
+
"required": ["path", "kind", "route"],
|
|
160
|
+
"properties": {
|
|
161
|
+
"path": { "type": "string", "minLength": 1, "maxLength": 512 },
|
|
162
|
+
"kind": { "type": "string", "enum": ["public", "backend"] },
|
|
163
|
+
"route": {
|
|
164
|
+
"type": "string",
|
|
165
|
+
"pattern": "^(?:/\\*|/[A-Za-z0-9_-]+(?:/[A-Za-z0-9_-]+)*/\\*)$"
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
},
|
|
172
|
+
"basePath": {
|
|
173
|
+
"type": "object",
|
|
174
|
+
"additionalProperties": false,
|
|
175
|
+
"required": ["required", "environmentVariable"],
|
|
176
|
+
"properties": {
|
|
177
|
+
"required": { "type": "boolean" },
|
|
178
|
+
"environmentVariable": { "type": "string", "enum": ["HARBOUR_BASE_PATH"] }
|
|
179
|
+
}
|
|
180
|
+
},
|
|
181
|
+
"evidence": {
|
|
182
|
+
"type": "array",
|
|
183
|
+
"minItems": 1,
|
|
184
|
+
"maxItems": 64,
|
|
185
|
+
"items": {
|
|
186
|
+
"type": "object",
|
|
187
|
+
"additionalProperties": false,
|
|
188
|
+
"required": ["path", "line", "reason"],
|
|
189
|
+
"properties": {
|
|
190
|
+
"path": { "type": "string", "minLength": 1, "maxLength": 512 },
|
|
191
|
+
"line": { "type": "integer", "minimum": 1 },
|
|
192
|
+
"reason": { "type": "string", "minLength": 1, "maxLength": 1024 }
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
},
|
|
196
|
+
"unsupportedFeatures": {
|
|
197
|
+
"type": "array",
|
|
198
|
+
"maxItems": 64,
|
|
199
|
+
"items": { "type": "string", "minLength": 1, "maxLength": 512 }
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|