@cat-factory/orchestration 0.275.0 → 0.276.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.
|
@@ -7,18 +7,21 @@ import type { RegistrationProblem } from './validateRegistrations.js';
|
|
|
7
7
|
* Its own module rather than more of `validateRegistrations.ts` because the section is a cohesive
|
|
8
8
|
* concern with a growing rule set, and its host had reached the file-size ratchet.
|
|
9
9
|
*
|
|
10
|
-
* Boot is the only place these can be caught
|
|
11
|
-
*
|
|
12
|
-
* malformed definition or an unparseable contract becomes an
|
|
13
|
-
* no operations, a credential key that is not a valid
|
|
14
|
-
* harness's env validation and reappears as an
|
|
15
|
-
* puts that credential on the wire from inside
|
|
16
|
-
* discover and names nothing that points back at
|
|
10
|
+
* Boot is the only place these can be caught for a deployment that registers in its own code.
|
|
11
|
+
* There is no write boundary that ever refused them, and every failure below is silent at run time
|
|
12
|
+
* in the same expensive way: a malformed definition or an unparseable contract becomes an
|
|
13
|
+
* integration the brief describes with no operations, a credential key that is not a valid
|
|
14
|
+
* environment-variable name is dropped by the harness's env validation and reappears as an
|
|
15
|
+
* unexplained 401 mid-run, and a cleartext endpoint puts that credential on the wire from inside
|
|
16
|
+
* the run container. Each of those costs a run to discover and names nothing that points back at
|
|
17
|
+
* the registration.
|
|
17
18
|
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
19
|
+
* The RULES are kernel's (`binaryGeneratorDetailIssues` / `binaryGeneratorInjectionCollisions`),
|
|
20
|
+
* not this module's, and that split is what makes them reusable: a definitions package
|
|
21
|
+
* (`@cat-factory/binary-generators`, and a deployment's own) runs the same functions at authoring
|
|
22
|
+
* time, so a definition that would fail this boot fails a test first. What stays here is the boot
|
|
23
|
+
* TAXONOMY: which severity each fault carries, and that a definition failing its parse is not
|
|
24
|
+
* asked the questions the parse just called meaningless.
|
|
22
25
|
*/
|
|
23
26
|
export declare function checkBinaryGenerators(registry: BinaryGeneratorRegistry | undefined): RegistrationProblem[];
|
|
24
27
|
//# sourceMappingURL=validateBinaryGenerators.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validateBinaryGenerators.d.ts","sourceRoot":"","sources":["../../src/validation/validateBinaryGenerators.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,qBAAqB,CAAA;
|
|
1
|
+
{"version":3,"file":"validateBinaryGenerators.d.ts","sourceRoot":"","sources":["../../src/validation/validateBinaryGenerators.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,qBAAqB,CAAA;AAWlE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAA;AAErE;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,uBAAuB,GAAG,SAAS,GAC5C,mBAAmB,EAAE,CAuBvB"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { binaryGeneratorDetailIssues, binaryGeneratorInjectionCollisions, } from '@cat-factory/kernel';
|
|
2
|
+
import { binaryGeneratorDefinitionIssues, } from '@cat-factory/contracts';
|
|
3
3
|
/**
|
|
4
4
|
* Section 9 of `collectRegistrationProblems`: every generative binary integration a deployment
|
|
5
5
|
* registers must be a definition the platform can actually dispatch against.
|
|
@@ -7,18 +7,21 @@ import { binaryAcceptsWithoutCapability, binaryCredentialInjectionName, binaryGe
|
|
|
7
7
|
* Its own module rather than more of `validateRegistrations.ts` because the section is a cohesive
|
|
8
8
|
* concern with a growing rule set, and its host had reached the file-size ratchet.
|
|
9
9
|
*
|
|
10
|
-
* Boot is the only place these can be caught
|
|
11
|
-
*
|
|
12
|
-
* malformed definition or an unparseable contract becomes an
|
|
13
|
-
* no operations, a credential key that is not a valid
|
|
14
|
-
* harness's env validation and reappears as an
|
|
15
|
-
* puts that credential on the wire from inside
|
|
16
|
-
* discover and names nothing that points back at
|
|
10
|
+
* Boot is the only place these can be caught for a deployment that registers in its own code.
|
|
11
|
+
* There is no write boundary that ever refused them, and every failure below is silent at run time
|
|
12
|
+
* in the same expensive way: a malformed definition or an unparseable contract becomes an
|
|
13
|
+
* integration the brief describes with no operations, a credential key that is not a valid
|
|
14
|
+
* environment-variable name is dropped by the harness's env validation and reappears as an
|
|
15
|
+
* unexplained 401 mid-run, and a cleartext endpoint puts that credential on the wire from inside
|
|
16
|
+
* the run container. Each of those costs a run to discover and names nothing that points back at
|
|
17
|
+
* the registration.
|
|
17
18
|
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
19
|
+
* The RULES are kernel's (`binaryGeneratorDetailIssues` / `binaryGeneratorInjectionCollisions`),
|
|
20
|
+
* not this module's, and that split is what makes them reusable: a definitions package
|
|
21
|
+
* (`@cat-factory/binary-generators`, and a deployment's own) runs the same functions at authoring
|
|
22
|
+
* time, so a definition that would fail this boot fails a test first. What stays here is the boot
|
|
23
|
+
* TAXONOMY: which severity each fault carries, and that a definition failing its parse is not
|
|
24
|
+
* asked the questions the parse just called meaningless.
|
|
22
25
|
*/
|
|
23
26
|
export function checkBinaryGenerators(registry) {
|
|
24
27
|
const problems = [];
|
|
@@ -38,139 +41,20 @@ export function checkBinaryGenerators(registry) {
|
|
|
38
41
|
continue;
|
|
39
42
|
}
|
|
40
43
|
valid.push(definition);
|
|
41
|
-
problems.push(...
|
|
44
|
+
problems.push(...asProblems(binaryGeneratorDetailIssues(definition)));
|
|
42
45
|
}
|
|
43
|
-
|
|
46
|
+
// Only definitions that PARSED are compared: a malformed one has already been reported, and
|
|
47
|
+
// reading its credentials here would restate that fault as a second, more confusing one.
|
|
48
|
+
problems.push(...asProblems(binaryGeneratorInjectionCollisions(valid)));
|
|
44
49
|
return problems;
|
|
45
50
|
}
|
|
46
51
|
/**
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
* same name is legitimate and common, because one vendor behind an image endpoint and a music
|
|
52
|
-
* endpoint is one account: what makes that case safe is that both look the value up under the SAME
|
|
53
|
-
* key, so whichever integration is resolved first sets the variable to exactly what the other
|
|
54
|
-
* wanted. Different keys behind one name is the opposite, and there is no arbitration that makes
|
|
55
|
-
* it right. Serving the first claimant sets the variable the second integration's brief tells the
|
|
56
|
-
* agent to read, so the agent authenticates one vendor with another's key; withholding it (what
|
|
57
|
-
* dispatch does, since a mothership node validates nothing) costs both integrations every run.
|
|
58
|
-
*
|
|
59
|
-
* Neither outcome is what the deployment meant, and the remedy is one `envName` on one definition,
|
|
60
|
-
* which is why this is an error at boot rather than a warning nobody acts on. Only definitions
|
|
61
|
-
* that PARSED are compared: a malformed one has already been reported, and reading its credentials
|
|
62
|
-
* here would restate that fault as a second, more confusing one.
|
|
52
|
+
* Every rule in that module is an ERROR at boot, and each of them says why in its own doc: the
|
|
53
|
+
* deployment either starts having disabled an integration it paid for, or starts with a credential
|
|
54
|
+
* on a cleartext wire. A warning would be a line an operator reads once per boot and stops seeing,
|
|
55
|
+
* for faults whose remedy is one edit in the deployment's own code.
|
|
63
56
|
*/
|
|
64
|
-
function
|
|
65
|
-
|
|
66
|
-
// wrote, because `ACME_KEY` and `acme_key` are one variable wherever the environment is
|
|
67
|
-
// case-insensitive and two everywhere else: the pair collides on exactly the platform where the
|
|
68
|
-
// operator has the least chance of noticing.
|
|
69
|
-
const claims = new Map();
|
|
70
|
-
for (const definition of definitions) {
|
|
71
|
-
for (const credential of definition.credentials ?? []) {
|
|
72
|
-
const claim = claims.get(comparableCredentialInjectionName(credential)) ?? {
|
|
73
|
-
spelling: binaryCredentialInjectionName(credential),
|
|
74
|
-
byKey: new Map(),
|
|
75
|
-
};
|
|
76
|
-
claim.byKey.set(credential.key, [...(claim.byKey.get(credential.key) ?? []), definition.id]);
|
|
77
|
-
claims.set(comparableCredentialInjectionName(credential), claim);
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
const problems = [];
|
|
81
|
-
for (const [, { spelling: envName, byKey }] of claims) {
|
|
82
|
-
if (byKey.size < 2)
|
|
83
|
-
continue;
|
|
84
|
-
const described = [...byKey]
|
|
85
|
-
.map(([key, ids]) => `"${key}" (${ids.join(', ')})`)
|
|
86
|
-
.sort()
|
|
87
|
-
.join(' and ');
|
|
88
|
-
problems.push({
|
|
89
|
-
severity: 'error',
|
|
90
|
-
code: 'binary_generator_injection_name_collision',
|
|
91
|
-
message: `Generative binary integrations disagree about environment variable "${envName}": it is ` +
|
|
92
|
-
`declared for lookup keys ${described}. One variable cannot hold both values, so an agent ` +
|
|
93
|
-
`told to read it for one integration would authenticate with the other's credential. Give ` +
|
|
94
|
-
`one of them a distinct \`envName\`, or point both at the same lookup key if they really ` +
|
|
95
|
-
`share an account.`,
|
|
96
|
-
});
|
|
97
|
-
}
|
|
98
|
-
return problems;
|
|
99
|
-
}
|
|
100
|
-
/** The per-definition checks a valid PARSE cannot make: the endpoint, contracts, media types. */
|
|
101
|
-
function checkBinaryGeneratorDetails(definition) {
|
|
102
|
-
const problems = [];
|
|
103
|
-
const invalid = (code, message) => {
|
|
104
|
-
problems.push({ severity: 'error', code, message });
|
|
105
|
-
};
|
|
106
|
-
// The same rule an HTTP tool server's URL is held to, and for the same reason the helper
|
|
107
|
-
// states: a declared credential rides this request, so cleartext off loopback puts it on the
|
|
108
|
-
// wire. (The helper is MCP-named because that was its first caller; the rule is not.)
|
|
109
|
-
if (definition.endpoint && !isAllowedMcpHttpUrl(definition.endpoint)) {
|
|
110
|
-
invalid('insecure_binary_generator_endpoint', `Generative binary integration "${definition.id}" has endpoint "${definition.endpoint}". Its ` +
|
|
111
|
-
`credential is sent with every request, so the endpoint must be https (plain http is ` +
|
|
112
|
-
`accepted only on loopback).`);
|
|
113
|
-
}
|
|
114
|
-
for (const problem of validateFoundationalDefinition({ contracts: definition.contracts })) {
|
|
115
|
-
invalid('binary_generator_invalid', `Generative binary integration "${definition.id}": ${describeFoundationalProblem(problem)}`);
|
|
116
|
-
}
|
|
117
|
-
const declared = new Set(definition.modalities);
|
|
118
|
-
for (const mediaType of definition.mediaTypes ?? []) {
|
|
119
|
-
const consistent = modalitiesOfMediaType(mediaType);
|
|
120
|
-
// An UNRECOGNISED media type is not a fault: the platform's classifier is not a registry of
|
|
121
|
-
// every format that exists, and refusing one would make registering a new codec impossible.
|
|
122
|
-
// A recognised one that CONTRADICTS the declaration is, because both drive selection.
|
|
123
|
-
//
|
|
124
|
-
// Contradiction is an empty INTERSECTION, not an absent member, and for 3D that is the whole
|
|
125
|
-
// difference: a `.glb` is consistent with both `3d-model` and `3d-scene` because the container
|
|
126
|
-
// does not record which it holds, so requiring every member would refuse a scene generator
|
|
127
|
-
// for declaring the only format it can emit.
|
|
128
|
-
if (consistent.length > 0 && !consistent.some((modality) => declared.has(modality))) {
|
|
129
|
-
const names = consistent.join('/');
|
|
130
|
-
invalid('binary_generator_modality_mismatch', `Generative binary integration "${definition.id}" declares media type "${mediaType}" ` +
|
|
131
|
-
`(${names}) but lists none of those among its modalities ` +
|
|
132
|
-
`(${definition.modalities.join(', ')}). A step selecting it for ${names} would be ` +
|
|
133
|
-
`refused, and one selecting it for the listed modalities would be told it can emit this.`);
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
// The transport's one rule that needs more than the definition: whether the named CLI actually
|
|
137
|
-
// carries a generation tool. Here rather than in the contracts schema because kernel owns both
|
|
138
|
-
// the harness list and which of them generate, and contracts (which kernel imports) can see
|
|
139
|
-
// neither.
|
|
140
|
-
//
|
|
141
|
-
// Judged against the GENERATING harnesses rather than every harness this build runs, because the
|
|
142
|
-
// two failures are indistinguishable downstream and both are silent: a definition naming `pi` or
|
|
143
|
-
// `claude-code` passes every structural check, admission resolves the step's model to that same
|
|
144
|
-
// CLI and admits it, the dispatch sets the generation flag, the runner ignores it, and the
|
|
145
|
-
// agent's brief tells it to collect output from a staging directory nothing created. The run
|
|
146
|
-
// then reports a model or vendor problem for what is one string in the deployment's own code.
|
|
147
|
-
//
|
|
148
|
-
// An error rather than a warning, and an early one, for that reason: boot validation is the only
|
|
149
|
-
// place this is cheap to fix.
|
|
150
|
-
if (definition.harness && !harnessServesBinaryGeneration(definition.harness)) {
|
|
151
|
-
const known = isHarnessKind(definition.harness);
|
|
152
|
-
invalid('binary_generator_unknown_harness', `Generative binary integration "${definition.id}" is served by harness ` +
|
|
153
|
-
`"${definition.harness}", which ` +
|
|
154
|
-
(known
|
|
155
|
-
? `this build runs but which carries no built-in generation tool`
|
|
156
|
-
: `is not one this build runs`) +
|
|
157
|
-
`. Only ${BINARY_GENERATING_HARNESSES.join(', ')} can serve a harness-transport ` +
|
|
158
|
-
`integration; a step selecting this one would dispatch and produce nothing.`);
|
|
159
|
-
}
|
|
160
|
-
// The same fault one axis finer: a declaration whose two halves contradict each other, where
|
|
161
|
-
// every reader believes a different half. An `accepts` set states which values the endpoint
|
|
162
|
-
// takes for an option its `capabilities` say it cannot be asked for at all, so the brief
|
|
163
|
-
// renders the set as fact while admission refuses every step that asks, and the value rule
|
|
164
|
-
// (judged over the capability's declarers) never sees the set at all. The accurate half is
|
|
165
|
-
// unreachable, which makes this an error rather than a warning: the remedy is one capability
|
|
166
|
-
// on one definition, and the deployment has already written down that the endpoint has it.
|
|
167
|
-
for (const { option, capability } of binaryAcceptsWithoutCapability(definition)) {
|
|
168
|
-
invalid('binary_generator_accepts_without_capability', `Generative binary integration "${definition.id}" states the values it accepts for ` +
|
|
169
|
-
`\`${option}\` but does not declare the "${capability}" capability that option needs. ` +
|
|
170
|
-
`A step asking for it is refused as unsupported, so the accepted set is never consulted ` +
|
|
171
|
-
`while the agent's brief states it. Declare "${capability}", or drop the set if the ` +
|
|
172
|
-
`endpoint genuinely takes no such parameter.`);
|
|
173
|
-
}
|
|
174
|
-
return problems;
|
|
57
|
+
function asProblems(issues) {
|
|
58
|
+
return issues.map((issue) => ({ severity: 'error', code: issue.code, message: issue.message }));
|
|
175
59
|
}
|
|
176
60
|
//# sourceMappingURL=validateBinaryGenerators.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validateBinaryGenerators.js","sourceRoot":"","sources":["../../src/validation/validateBinaryGenerators.ts"],"names":[],"mappings":"AACA,OAAO,EACL,2BAA2B,EAC3B,
|
|
1
|
+
{"version":3,"file":"validateBinaryGenerators.js","sourceRoot":"","sources":["../../src/validation/validateBinaryGenerators.ts"],"names":[],"mappings":"AACA,OAAO,EACL,2BAA2B,EAC3B,kCAAkC,GACnC,MAAM,qBAAqB,CAAA;AAC5B,OAAO,EAEL,+BAA+B,GAChC,MAAM,wBAAwB,CAAA;AAK/B;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,UAAU,qBAAqB,CACnC,QAA6C;IAE7C,MAAM,QAAQ,GAA0B,EAAE,CAAA;IAC1C,IAAI,CAAC,QAAQ;QAAE,OAAO,QAAQ,CAAA;IAC9B,MAAM,KAAK,GAAgC,EAAE,CAAA;IAC7C,KAAK,MAAM,UAAU,IAAI,QAAQ,CAAC,GAAG,EAAE,EAAE,CAAC;QACxC,MAAM,MAAM,GAAG,+BAA+B,CAAC,UAAU,CAAC,CAAA;QAC1D,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACtB,QAAQ,CAAC,IAAI,CAAC;gBACZ,QAAQ,EAAE,OAAO;gBACjB,IAAI,EAAE,0BAA0B;gBAChC,OAAO,EAAE,kCAAkC,UAAU,CAAC,EAAE,gCAAgC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;aAC5G,CAAC,CAAA;YACF,uFAAuF;YACvF,sCAAsC;YACtC,SAAQ;QACV,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAA;QACtB,QAAQ,CAAC,IAAI,CAAC,GAAG,UAAU,CAAC,2BAA2B,CAAC,UAAU,CAAC,CAAC,CAAC,CAAA;IACvE,CAAC;IACD,4FAA4F;IAC5F,yFAAyF;IACzF,QAAQ,CAAC,IAAI,CAAC,GAAG,UAAU,CAAC,kCAAkC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;IACvE,OAAO,QAAQ,CAAA;AACjB,CAAC;AAED;;;;;GAKG;AACH,SAAS,UAAU,CAAC,MAAoD;IACtE,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAA;AACjG,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cat-factory/orchestration",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.276.0",
|
|
4
4
|
"description": "Delivery-workflow engine for the Agent Architecture Board (execution, bootstrap, pipelines, board, boardScan, requirements, and composition root).",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -25,20 +25,20 @@
|
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
27
|
"ai": "^7.0.64",
|
|
28
|
-
"@cat-factory/agents": "0.133.
|
|
29
|
-
"@cat-factory/caching": "0.20.
|
|
30
|
-
"@cat-factory/contracts": "0.
|
|
31
|
-
"@cat-factory/integrations": "0.164.
|
|
32
|
-
"@cat-factory/kernel": "0.
|
|
33
|
-
"@cat-factory/prompt-fragments": "1.0.
|
|
34
|
-
"@cat-factory/sandbox": "0.11.
|
|
35
|
-
"@cat-factory/spend": "0.15.
|
|
36
|
-
"@cat-factory/workspaces": "0.28.
|
|
28
|
+
"@cat-factory/agents": "0.133.1",
|
|
29
|
+
"@cat-factory/caching": "0.20.26",
|
|
30
|
+
"@cat-factory/contracts": "0.317.0",
|
|
31
|
+
"@cat-factory/integrations": "0.164.1",
|
|
32
|
+
"@cat-factory/kernel": "0.305.0",
|
|
33
|
+
"@cat-factory/prompt-fragments": "1.0.81",
|
|
34
|
+
"@cat-factory/sandbox": "0.11.158",
|
|
35
|
+
"@cat-factory/spend": "0.15.99",
|
|
36
|
+
"@cat-factory/workspaces": "0.28.14"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
39
|
"typescript": "7.0.2",
|
|
40
40
|
"vitest": "^4.1.10",
|
|
41
|
-
"@cat-factory/sandbox-fixtures": "0.7.
|
|
41
|
+
"@cat-factory/sandbox-fixtures": "0.7.359"
|
|
42
42
|
},
|
|
43
43
|
"scripts": {
|
|
44
44
|
"build": "tsc -b tsconfig.build.json",
|