@crewhaus/canary-controller 0.1.8 → 0.2.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/index.d.ts +23 -1
- package/dist/index.js +36 -3
- package/package.json +5 -5
package/dist/index.d.ts
CHANGED
|
@@ -20,8 +20,30 @@ export type RegressionGate = (input: {
|
|
|
20
20
|
readonly verdict: "pass" | "fail";
|
|
21
21
|
readonly reason?: string;
|
|
22
22
|
}>;
|
|
23
|
-
/**
|
|
23
|
+
/**
|
|
24
|
+
* EXPLICIT always-pass stub. NOT the wired production default anymore
|
|
25
|
+
* (item 29): the CLI builds a real gate via {@link makeRegressionGate} that
|
|
26
|
+
* evals both versions and runs `regression-runner`'s `gate()`. Kept only for
|
|
27
|
+
* tests, `--dry-run`, and manual promotions that deliberately skip the eval
|
|
28
|
+
* gate.
|
|
29
|
+
*/
|
|
24
30
|
export declare const PASSING_GATE: RegressionGate;
|
|
31
|
+
/**
|
|
32
|
+
* Build a real {@link RegressionGate} from a caller-supplied per-step
|
|
33
|
+
* evaluator. The evaluator is the seam that keeps canary-controller
|
|
34
|
+
* dependency-inverted: it evals BOTH versions and returns the comparison
|
|
35
|
+
* verdict (in the CLI it runs two `eval-runner` passes and feeds the two
|
|
36
|
+
* `EvalRunSummary` results into `regression-runner.gate()`). Any throw from
|
|
37
|
+
* the evaluator is surfaced as a `fail` verdict so a broken eval never
|
|
38
|
+
* silently promotes a candidate — the controller then auto-rolls-back.
|
|
39
|
+
*/
|
|
40
|
+
export declare function makeRegressionGate(evaluate: (input: {
|
|
41
|
+
readonly fromVersion: string;
|
|
42
|
+
readonly toVersion: string;
|
|
43
|
+
}) => Promise<{
|
|
44
|
+
readonly verdict: "pass" | "fail";
|
|
45
|
+
readonly reason?: string;
|
|
46
|
+
}>): RegressionGate;
|
|
25
47
|
export type CanaryConfig = {
|
|
26
48
|
readonly name: string;
|
|
27
49
|
/** Currently-pinned version (control). */
|
package/dist/index.js
CHANGED
|
@@ -6,8 +6,15 @@
|
|
|
6
6
|
*
|
|
7
7
|
* After `evalIntervalMs` elapses, runs an eval-spec against both versions
|
|
8
8
|
* in parallel and gates promotion on `regression-runner` (Section 29 —
|
|
9
|
-
*
|
|
10
|
-
*
|
|
9
|
+
* `gate(baseline, candidate)` over two `EvalRunSummary` results).
|
|
10
|
+
*
|
|
11
|
+
* The real gate is wired by the caller (item 29 — `crewhaus deploy canary`):
|
|
12
|
+
* canary-controller stays dependency-inverted (it does NOT import
|
|
13
|
+
* `regression-runner`/`eval-runner`, keeping this a leaf package). Callers
|
|
14
|
+
* build a `RegressionGate` with {@link makeRegressionGate}, injecting the
|
|
15
|
+
* per-step "eval both versions, then compare" closure. {@link PASSING_GATE}
|
|
16
|
+
* is retained ONLY as an explicit always-pass stub for tests and manual
|
|
17
|
+
* dry-runs — it is no longer the wired production default.
|
|
11
18
|
*
|
|
12
19
|
* Without an eval gate (manual mode), the controller waits for an
|
|
13
20
|
* explicit `crewhaus deploy promote` call.
|
|
@@ -20,8 +27,34 @@ export class CanaryError extends CrewhausError {
|
|
|
20
27
|
super("config", message, cause);
|
|
21
28
|
}
|
|
22
29
|
}
|
|
23
|
-
/**
|
|
30
|
+
/**
|
|
31
|
+
* EXPLICIT always-pass stub. NOT the wired production default anymore
|
|
32
|
+
* (item 29): the CLI builds a real gate via {@link makeRegressionGate} that
|
|
33
|
+
* evals both versions and runs `regression-runner`'s `gate()`. Kept only for
|
|
34
|
+
* tests, `--dry-run`, and manual promotions that deliberately skip the eval
|
|
35
|
+
* gate.
|
|
36
|
+
*/
|
|
24
37
|
export const PASSING_GATE = async () => ({ verdict: "pass" });
|
|
38
|
+
/**
|
|
39
|
+
* Build a real {@link RegressionGate} from a caller-supplied per-step
|
|
40
|
+
* evaluator. The evaluator is the seam that keeps canary-controller
|
|
41
|
+
* dependency-inverted: it evals BOTH versions and returns the comparison
|
|
42
|
+
* verdict (in the CLI it runs two `eval-runner` passes and feeds the two
|
|
43
|
+
* `EvalRunSummary` results into `regression-runner.gate()`). Any throw from
|
|
44
|
+
* the evaluator is surfaced as a `fail` verdict so a broken eval never
|
|
45
|
+
* silently promotes a candidate — the controller then auto-rolls-back.
|
|
46
|
+
*/
|
|
47
|
+
export function makeRegressionGate(evaluate) {
|
|
48
|
+
return async (input) => {
|
|
49
|
+
try {
|
|
50
|
+
return await evaluate(input);
|
|
51
|
+
}
|
|
52
|
+
catch (err) {
|
|
53
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
54
|
+
return { verdict: "fail", reason: `eval gate errored: ${message}` };
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
}
|
|
25
58
|
export function createCanaryController(opts) {
|
|
26
59
|
return {
|
|
27
60
|
route(config, requestId) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@crewhaus/canary-controller",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Percent-of-traffic rollout with eval-gated promotion. Hash-routes requests across two pinned versions and auto-rolls-back on regression.",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -15,10 +15,10 @@
|
|
|
15
15
|
"test": "bun test src"
|
|
16
16
|
},
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"@crewhaus/audit-log": "0.
|
|
19
|
-
"@crewhaus/deployment-controller": "0.
|
|
20
|
-
"@crewhaus/errors": "0.
|
|
21
|
-
"@crewhaus/spec-registry": "0.
|
|
18
|
+
"@crewhaus/audit-log": "0.2.0",
|
|
19
|
+
"@crewhaus/deployment-controller": "0.2.0",
|
|
20
|
+
"@crewhaus/errors": "0.2.0",
|
|
21
|
+
"@crewhaus/spec-registry": "0.2.0"
|
|
22
22
|
},
|
|
23
23
|
"license": "Apache-2.0",
|
|
24
24
|
"author": {
|