@cat-factory/kernel 0.308.0 → 0.309.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/dist/domain/binary-generator-registration.d.ts +1 -18
  2. package/dist/domain/binary-generator-registration.d.ts.map +1 -1
  3. package/dist/domain/binary-generator-registration.js +1 -53
  4. package/dist/domain/binary-generator-registration.js.map +1 -1
  5. package/dist/domain/binary-generators.js +3 -3
  6. package/dist/domain/binary-generators.js.map +1 -1
  7. package/dist/domain/binary-outputs.d.ts.map +1 -1
  8. package/dist/domain/binary-outputs.js +26 -1
  9. package/dist/domain/binary-outputs.js.map +1 -1
  10. package/dist/domain/define-pipeline.d.ts +75 -0
  11. package/dist/domain/define-pipeline.d.ts.map +1 -0
  12. package/dist/domain/define-pipeline.js +48 -0
  13. package/dist/domain/define-pipeline.js.map +1 -0
  14. package/dist/domain/foundational-service-registry.d.ts +7 -1
  15. package/dist/domain/foundational-service-registry.d.ts.map +1 -1
  16. package/dist/domain/foundational-service-registry.js +4 -0
  17. package/dist/domain/foundational-service-registry.js.map +1 -1
  18. package/dist/domain/foundational-services.d.ts +67 -1
  19. package/dist/domain/foundational-services.d.ts.map +1 -1
  20. package/dist/domain/foundational-services.js +58 -1
  21. package/dist/domain/foundational-services.js.map +1 -1
  22. package/dist/domain/seed.d.ts.map +1 -1
  23. package/dist/domain/seed.js +2 -42
  24. package/dist/domain/seed.js.map +1 -1
  25. package/dist/index.d.ts +4 -2
  26. package/dist/index.d.ts.map +1 -1
  27. package/dist/index.js +6 -2
  28. package/dist/index.js.map +1 -1
  29. package/dist/ports/agent-definition.d.ts +17 -4
  30. package/dist/ports/agent-definition.d.ts.map +1 -1
  31. package/dist/ports/agent-executor.d.ts +20 -0
  32. package/dist/ports/agent-executor.d.ts.map +1 -1
  33. package/dist/ports/agent-executor.js.map +1 -1
  34. package/dist/ports/agent-tools.d.ts +14 -0
  35. package/dist/ports/agent-tools.d.ts.map +1 -1
  36. package/dist/ports/index.d.ts +2 -1
  37. package/dist/ports/index.d.ts.map +1 -1
  38. package/dist/ports/index.js +1 -1
  39. package/dist/ports/index.js.map +1 -1
  40. package/dist/ports/runner-transport.d.ts +67 -34
  41. package/dist/ports/runner-transport.d.ts.map +1 -1
  42. package/dist/ports/runner-transport.js +85 -33
  43. package/dist/ports/runner-transport.js.map +1 -1
  44. package/package.json +2 -2
@@ -1,4 +1,5 @@
1
- import { UnavailableError } from '../domain/errors.js';
1
+ import { isImageVariantName, isPlatformImageVariant, PLATFORM_IMAGE_VARIANTS, } from '@cat-factory/contracts';
2
+ import { UnavailableError, ValidationError } from '../domain/errors.js';
2
3
  /**
3
4
  * The one-line `error` a transport reports beside `evicted` when the job's container/runner is
4
5
  * simply GONE — the poll found no such job. Owned here rather than copied per transport because
@@ -23,35 +24,46 @@ export const CONTAINER_EVICTION_ERROR = 'Job not found (container evicted or cra
23
24
  * killed its container each time and reported infrastructure churn.
24
25
  */
25
26
  export const HARNESS_SHUTDOWN_ERROR = 'The executor-harness shut down while this job was still running';
27
+ // The reserved-name half of the vocabulary lives on the WIRE (`@cat-factory/contracts`), because
28
+ // a runner backend's variant map is edited in the SPA and an agent kind's declaration is written
29
+ // by a deployment: both must be held to one list of names the platform has already claimed.
30
+ export { PLATFORM_IMAGE_VARIANTS, isPlatformImageVariant, isImageVariantName };
26
31
  /**
27
- * The {@link RunnerImageVariant} vocabulary as DATA, so a reader can narrow a string against it
28
- * rather than cast. Kept beside the type it enumerates and typed as the member list, so adding a
29
- * variant to the union without adding it here fails to compile.
32
+ * The `default:` arm of a backend's exhaustive switch over {@link PlatformImageVariant}: it takes
33
+ * `never`, so publishing a fourth platform image fails the BUILD in every backend until each
34
+ * decides what to do with it, and it still refuses honestly at RUN time for the case the type
35
+ * cannot see, a value an older job body or a stored step still carries after this build retired it.
36
+ *
37
+ * The compile-time half is the load-bearing one, because the alternative is silent in the worst
38
+ * direction: a backend that fell through would run the job on its default image, and nothing
39
+ * downstream can say what the variant was supposed to carry. The DEPLOYMENT-owned half of the
40
+ * vocabulary is open and gets {@link deploymentImageVariantMessage} instead; this arm is only ever
41
+ * reached by a name the platform itself claimed.
30
42
  */
31
- export const RUNNER_IMAGE_VARIANTS = ['default', 'ui', 'deploy'];
32
- /** Whether a string names a variant THIS build can serve. */
33
- export function isRunnerImageVariant(value) {
34
- return value != null && RUNNER_IMAGE_VARIANTS.includes(value);
43
+ export function unservablePlatformImageVariant(variant) {
44
+ throw new UnavailableError(`This step declared the '${String(variant)}' executor image, which this backend does not ` +
45
+ 'serve. It is a platform image this build does not know: re-pick the executor image on the ' +
46
+ "agent kind's registration.", RUNNER_IMAGE_UNWIRED_REASON, { image: String(variant) });
35
47
  }
36
48
  /**
37
- * The `details.reason` every backend carries on the `UnavailableError` it raises for a
38
- * declared image variant it cannot serve. ONE constant because it is a machine-readable wire
39
- * vocabulary the SPA and the run record branch on, and each backend refuses in its own file: as
40
- * a per-file string literal a typo in one produces a reason nothing recognises and no typecheck
41
- * fails.
42
- */
43
- export const RUNNER_IMAGE_UNWIRED_REASON = 'runner_image_unwired';
44
- /**
45
- * The `default:` arm of a backend's exhaustive switch over {@link RunnerImageVariant}: it takes
46
- * `never`, so adding a member to the union fails the BUILD until that backend decides what to do
47
- * with it, and it still refuses honestly at RUN time for the case the type cannot see — a value
48
- * this build retired that an older row or an older job body still carries.
49
+ * The refusal a DEPLOYMENT-named image variant earns when the resolved runner backend maps it to
50
+ * nothing, with the per-backend knob named by the caller.
51
+ *
52
+ * One message, in kernel, because three backends refuse it and an operator reading three
53
+ * wordings for one misconfiguration learns three things instead of one. The platform's own
54
+ * variants keep their bespoke messages: the platform knows what `ui` is FOR, so it can say what
55
+ * a deployment loses by leaving it unwired and what to do instead, and this one cannot say
56
+ * anything about a variant it has never heard of beyond where the mapping goes.
49
57
  */
50
- export function unservableImageVariant(variant) {
51
- throw new UnavailableError(`This step declared the '${String(variant)}' executor image, which this backend does not ` +
52
- 'serve. It is not a variant this build knows: re-pick the executor image on the agent ' +
53
- "kind's registration.", RUNNER_IMAGE_UNWIRED_REASON, { image: String(variant) });
58
+ export function deploymentImageVariantMessage(variant, setting) {
59
+ return (`This step's agent kind declares the "${variant}" executor image, which this deployment's ` +
60
+ `runner backend maps to no image. Add "${variant}" to ${setting}, or drop the kind's ` +
61
+ `\`image\` declaration if the default harness image is enough: running the default instead ` +
62
+ `would produce a job without whatever "${variant}" carries, and a step reporting a missing ` +
63
+ `result with nothing naming the cause.`);
54
64
  }
65
+ /** The `details.reason` every unwired-image refusal carries, whoever raises it. */
66
+ export const RUNNER_IMAGE_UNWIRED_REASON = 'runner_image_unwired';
55
67
  /**
56
68
  * The container identity a ref addresses on a per-run container backend: the run id for the
57
69
  * default image, qualified by the variant for anything else.
@@ -62,18 +74,58 @@ export function unservableImageVariant(variant) {
62
74
  * a reap from a cron all land on the same container with nothing passed between them.
63
75
  */
64
76
  export function containerKeyForRef(ref) {
65
- return ref.image && ref.image !== 'default' ? `${ref.image}:${ref.runId}` : ref.runId;
77
+ const key = ref.image && ref.image !== 'default' ? `${ref.image}:${ref.runId}` : ref.runId;
78
+ // The two must be EXACT inverses, and the PRODUCER is the only side that can check it:
79
+ // `parseContainerKey` reads keys with no ref in hand, so it cannot tell a run id that merely
80
+ // LOOKS variant-qualified from one that is (see its own doc for why the test it makes is a shape
81
+ // and not a lookup). Checking here converts the one input class that would break the inverse into
82
+ // a refused dispatch that NAMES the cause, instead of a key the reaper later maps to no run and
83
+ // kills a live container for.
84
+ //
85
+ // Unreachable for every run-id scheme the platform mints today (all `[A-Za-z0-9_-]`, which cannot
86
+ // contain the separator), which is exactly why this is a guard and not an escaping scheme: the
87
+ // invariant the pair rests on is "a run id carries no `:`", and it was previously assumed rather
88
+ // than stated anywhere. A future scheme that wants one has to pick a different separator, and this
89
+ // is where it finds out: at the first dispatch, in one place, rather than as a sweep deleting
90
+ // containers weeks later.
91
+ const parsed = parseContainerKey(key);
92
+ if (parsed.runId !== ref.runId || (parsed.image ?? 'default') !== (ref.image || 'default')) {
93
+ throw new ValidationError(`Cannot address a container for run "${ref.runId}"${ref.image ? ` on the "${ref.image}" executor image` : ''}: ` +
94
+ `the container key "${key}" does not read back as the run and image it was built from, so ` +
95
+ `every reader of it (the dispatch, the poll, the orphan sweep) would disagree about which ` +
96
+ `run owns the container. A run id may not put a variant-shaped segment before a ":", and a ` +
97
+ `variant name must be a lower-kebab slug.`, {
98
+ reason: 'container_key_not_reversible',
99
+ runId: ref.runId,
100
+ ...(ref.image ? { image: ref.image } : {}),
101
+ });
102
+ }
103
+ return key;
66
104
  }
67
105
  /**
68
106
  * The parts a container key encodes, the exact inverse of {@link containerKeyForRef}.
69
107
  *
70
- * The prefix is stripped ONLY when it names a variant this build knows. A bare
71
- * "everything before the first colon is a variant" split is lossy in the direction that
72
- * destroys data: a key carrying a colon for any OTHER reason (a job-id scheme, an
73
- * operator-created label) would be truncated to a run id that matches no run, and the orphan
74
- * sweep below then kills a live container for being unrecognised the very misread this
75
- * inverse exists to prevent. An unrecognised prefix therefore answers "the whole key is the
76
- * run id", which at worst leaves a container for the next sweep.
108
+ * The prefix is stripped ONLY when it is SHAPED like a variant name. A bare "everything before
109
+ * the first colon is a variant" split is lossy in the direction that destroys data: a key
110
+ * carrying a colon for any OTHER reason (a job-id scheme, an operator-created label) would be
111
+ * truncated to a run id that matches no run, and the orphan sweep below then kills a live
112
+ * container for being unrecognised, the very misread this inverse exists to prevent. A prefix
113
+ * that is not variant-shaped therefore answers "the whole key is the run id", which at worst
114
+ * leaves a container for the next sweep.
115
+ *
116
+ * SHAPE rather than membership, because variant names are open: a deployment's own is a slug
117
+ * only its runner backend can map, and this function is read by a reaper that holds no backend
118
+ * config. The rule is the one every declaring boundary already enforces (`checkAgentImageVariants`
119
+ * at boot, the backends' variant-map schemas), so a prefix this rejects is one no registration
120
+ * could have produced.
121
+ *
122
+ * What that leaves is a prefix which IS slug-shaped and was never a variant. Open names make that
123
+ * case unknowable HERE, so it is not decided here: {@link containerKeyForRef} refuses to mint a key
124
+ * this function would read back differently, which is what makes the pair exact rather than merely
125
+ * careful. Every key the inventory holds was written by that producer, so a prefix reaching this
126
+ * point and passing the shape test came from a variant a registration declared. The split of
127
+ * responsibility is the point: the reader refuses anything UNSHAPED, and the writer refuses
128
+ * anything AMBIGUOUS, because only one of them holds the ref to compare against.
77
129
  */
78
130
  export function parseContainerKey(containerKey) {
79
131
  const separator = containerKey.indexOf(':');
@@ -82,7 +134,7 @@ export function parseContainerKey(containerKey) {
82
134
  const prefix = containerKey.slice(0, separator);
83
135
  // `default` is never a prefix (`containerKeyForRef` emits the bare run id for it), so a key
84
136
  // spelling it out is not one this function produced and is left whole.
85
- if (prefix === 'default' || !isRunnerImageVariant(prefix))
137
+ if (prefix === 'default' || !isImageVariantName(prefix))
86
138
  return { runId: containerKey };
87
139
  return { runId: containerKey.slice(separator + 1), image: prefix };
88
140
  }
@@ -1 +1 @@
1
- {"version":3,"file":"runner-transport.js","sourceRoot":"","sources":["../../src/ports/runner-transport.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAA;AA6CtD;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG,8CAA8C,CAAA;AAEtF;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,MAAM,sBAAsB,GACjC,iEAAiE,CAAA;AA4NnE;;;;GAIG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAkC,CAAC,SAAS,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAA;AAE/F,6DAA6D;AAC7D,MAAM,UAAU,oBAAoB,CAClC,KAAgC;IAEhC,OAAO,KAAK,IAAI,IAAI,IAAK,qBAA2C,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAA;AACtF,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,2BAA2B,GAAG,sBAAsB,CAAA;AAEjE;;;;;GAKG;AACH,MAAM,UAAU,sBAAsB,CAAC,OAAc;IACnD,MAAM,IAAI,gBAAgB,CACxB,2BAA2B,MAAM,CAAC,OAAO,CAAC,gDAAgD;QACxF,uFAAuF;QACvF,sBAAsB,EACxB,2BAA2B,EAC3B,EAAE,KAAK,EAAE,MAAM,CAAC,OAAO,CAAC,EAAE,CAC3B,CAAA;AACH,CAAC;AAuUD;;;;;;;;GAQG;AACH,MAAM,UAAU,kBAAkB,CAAC,GAAiB;IAClD,OAAO,GAAG,CAAC,KAAK,IAAI,GAAG,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,KAAK,IAAI,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAA;AACvF,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,iBAAiB,CAAC,YAAoB;IAIpD,MAAM,SAAS,GAAG,YAAY,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;IAC3C,IAAI,SAAS,IAAI,CAAC;QAAE,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,CAAA;IAClD,MAAM,MAAM,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,CAAC,CAAA;IAC/C,4FAA4F;IAC5F,uEAAuE;IACvE,IAAI,MAAM,KAAK,SAAS,IAAI,CAAC,oBAAoB,CAAC,MAAM,CAAC;QAAE,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,CAAA;IACzF,OAAO,EAAE,KAAK,EAAE,YAAY,CAAC,KAAK,CAAC,SAAS,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,CAAA;AACpE,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,qBAAqB,CAAC,YAAoB;IACxD,OAAO,iBAAiB,CAAC,YAAY,CAAC,CAAC,KAAK,CAAA;AAC9C,CAAC"}
1
+ {"version":3,"file":"runner-transport.js","sourceRoot":"","sources":["../../src/ports/runner-transport.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cat-factory/kernel",
3
- "version": "0.308.0",
3
+ "version": "0.309.0",
4
4
  "description": "Shared vocabulary, pure logic, and port interfaces for the Agent Architecture Board.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -26,7 +26,7 @@
26
26
  "dependencies": {
27
27
  "ai": "^7.0.64",
28
28
  "yaml": "^2.9.0",
29
- "@cat-factory/contracts": "0.318.0"
29
+ "@cat-factory/contracts": "0.319.0"
30
30
  },
31
31
  "devDependencies": {
32
32
  "@stryker-mutator/core": "9.6.1",