@opensip-cli/contracts 0.1.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/LICENSE +202 -0
- package/NOTICE +8 -0
- package/README.md +31 -0
- package/dist/__tests__/exit-codes.test.d.ts +2 -0
- package/dist/__tests__/exit-codes.test.d.ts.map +1 -0
- package/dist/__tests__/exit-codes.test.js +185 -0
- package/dist/__tests__/exit-codes.test.js.map +1 -0
- package/dist/__tests__/manifest-reexport.test.d.ts +6 -0
- package/dist/__tests__/manifest-reexport.test.d.ts.map +1 -0
- package/dist/__tests__/manifest-reexport.test.js +38 -0
- package/dist/__tests__/manifest-reexport.test.js.map +1 -0
- package/dist/__tests__/types-only.test.d.ts +10 -0
- package/dist/__tests__/types-only.test.d.ts.map +1 -0
- package/dist/__tests__/types-only.test.js +49 -0
- package/dist/__tests__/types-only.test.js.map +1 -0
- package/dist/cli-flags.d.ts +56 -0
- package/dist/cli-flags.d.ts.map +1 -0
- package/dist/cli-flags.js +85 -0
- package/dist/cli-flags.js.map +1 -0
- package/dist/cli-flags.test.d.ts +2 -0
- package/dist/cli-flags.test.d.ts.map +1 -0
- package/dist/cli-flags.test.js +51 -0
- package/dist/cli-flags.test.js.map +1 -0
- package/dist/command-outcome.d.ts +87 -0
- package/dist/command-outcome.d.ts.map +1 -0
- package/dist/command-outcome.js +32 -0
- package/dist/command-outcome.js.map +1 -0
- package/dist/command-outcome.test.d.ts +10 -0
- package/dist/command-outcome.test.d.ts.map +1 -0
- package/dist/command-outcome.test.js +68 -0
- package/dist/command-outcome.test.js.map +1 -0
- package/dist/command-results.d.ts +501 -0
- package/dist/command-results.d.ts.map +1 -0
- package/dist/command-results.js +14 -0
- package/dist/command-results.js.map +1 -0
- package/dist/exit-codes.d.ts +44 -0
- package/dist/exit-codes.d.ts.map +1 -0
- package/dist/exit-codes.js +186 -0
- package/dist/exit-codes.js.map +1 -0
- package/dist/graph-catalog.d.ts +143 -0
- package/dist/graph-catalog.d.ts.map +1 -0
- package/dist/graph-catalog.js +13 -0
- package/dist/graph-catalog.js.map +1 -0
- package/dist/index.d.ts +62 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +56 -0
- package/dist/index.js.map +1 -0
- package/dist/recipe-default.d.ts +53 -0
- package/dist/recipe-default.d.ts.map +1 -0
- package/dist/recipe-default.js +55 -0
- package/dist/recipe-default.js.map +1 -0
- package/dist/recipe-default.test.d.ts +2 -0
- package/dist/recipe-default.test.d.ts.map +1 -0
- package/dist/recipe-default.test.js +32 -0
- package/dist/recipe-default.test.js.map +1 -0
- package/dist/score.d.ts +26 -0
- package/dist/score.d.ts.map +1 -0
- package/dist/score.js +25 -0
- package/dist/score.js.map +1 -0
- package/dist/score.test.d.ts +2 -0
- package/dist/score.test.d.ts.map +1 -0
- package/dist/score.test.js +22 -0
- package/dist/score.test.js.map +1 -0
- package/dist/session-types.d.ts +132 -0
- package/dist/session-types.d.ts.map +1 -0
- package/dist/session-types.js +11 -0
- package/dist/session-types.js.map +1 -0
- package/dist/signal-envelope.d.ts +118 -0
- package/dist/signal-envelope.d.ts.map +1 -0
- package/dist/signal-envelope.js +84 -0
- package/dist/signal-envelope.js.map +1 -0
- package/dist/signal-envelope.test.d.ts +2 -0
- package/dist/signal-envelope.test.d.ts.map +1 -0
- package/dist/signal-envelope.test.js +168 -0
- package/dist/signal-envelope.test.js.map +1 -0
- package/dist/types.d.ts +78 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/dist/verbose-detail.d.ts +26 -0
- package/dist/verbose-detail.d.ts.map +1 -0
- package/dist/verbose-detail.js +75 -0
- package/dist/verbose-detail.js.map +1 -0
- package/dist/verbose-detail.test.d.ts +2 -0
- package/dist/verbose-detail.test.d.ts.map +1 -0
- package/dist/verbose-detail.test.js +53 -0
- package/dist/verbose-detail.test.js.map +1 -0
- package/dist/verdict-envelope.test.d.ts +8 -0
- package/dist/verdict-envelope.test.d.ts.map +1 -0
- package/dist/verdict-envelope.test.js +67 -0
- package/dist/verdict-envelope.test.js.map +1 -0
- package/package.json +56 -0
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { BUILTIN_DEFAULT_RECIPE, resolveToolRecipeName } from './recipe-default.js';
|
|
3
|
+
describe('resolveToolRecipeName (ADR-0022 precedence + tolerance)', () => {
|
|
4
|
+
it('explicit --recipe wins over every config source and is strict', () => {
|
|
5
|
+
expect(resolveToolRecipeName({
|
|
6
|
+
explicit: 'backend',
|
|
7
|
+
toolRecipe: 'graph-core',
|
|
8
|
+
})).toEqual({ name: 'backend', source: 'flag', tolerant: false });
|
|
9
|
+
});
|
|
10
|
+
it('falls to <tool>.recipe when no flag, and is tolerant', () => {
|
|
11
|
+
expect(resolveToolRecipeName({ toolRecipe: 'graph-core' })).toEqual({
|
|
12
|
+
name: 'graph-core',
|
|
13
|
+
source: 'tool-config',
|
|
14
|
+
tolerant: true,
|
|
15
|
+
});
|
|
16
|
+
});
|
|
17
|
+
it('returns the builtin default when nothing is configured', () => {
|
|
18
|
+
expect(resolveToolRecipeName({})).toEqual({
|
|
19
|
+
name: BUILTIN_DEFAULT_RECIPE,
|
|
20
|
+
source: 'builtin',
|
|
21
|
+
tolerant: true,
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
it('treats empty-string config values as unset (precedence skips them)', () => {
|
|
25
|
+
expect(resolveToolRecipeName({ explicit: '', toolRecipe: '' })).toEqual({
|
|
26
|
+
name: BUILTIN_DEFAULT_RECIPE,
|
|
27
|
+
source: 'builtin',
|
|
28
|
+
tolerant: true,
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
//# sourceMappingURL=recipe-default.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recipe-default.test.js","sourceRoot":"","sources":["../src/recipe-default.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAE9C,OAAO,EAAE,sBAAsB,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAEpF,QAAQ,CAAC,yDAAyD,EAAE,GAAG,EAAE;IACvE,EAAE,CAAC,+DAA+D,EAAE,GAAG,EAAE;QACvE,MAAM,CACJ,qBAAqB,CAAC;YACpB,QAAQ,EAAE,SAAS;YACnB,UAAU,EAAE,YAAY;SACzB,CAAC,CACH,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC;IAClE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sDAAsD,EAAE,GAAG,EAAE;QAC9D,MAAM,CAAC,qBAAqB,CAAC,EAAE,UAAU,EAAE,YAAY,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC;YAClE,IAAI,EAAE,YAAY;YAClB,MAAM,EAAE,aAAa;YACrB,QAAQ,EAAE,IAAI;SACf,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wDAAwD,EAAE,GAAG,EAAE;QAChE,MAAM,CAAC,qBAAqB,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC;YACxC,IAAI,EAAE,sBAAsB;YAC5B,MAAM,EAAE,SAAS;YACjB,QAAQ,EAAE,IAAI;SACf,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oEAAoE,EAAE,GAAG,EAAE;QAC5E,MAAM,CAAC,qBAAqB,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC;YACtE,IAAI,EAAE,sBAAsB;YAC5B,MAAM,EAAE,SAAS;YACjB,QAAQ,EAAE,IAAI;SACf,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
package/dist/score.d.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical pass rate for a run.
|
|
3
|
+
*
|
|
4
|
+
* `score` is a shared field on the run verdict (`SignalEnvelope.verdict`)
|
|
5
|
+
* and `StoredSession` that the dashboard renders as the "PASS RATE" column.
|
|
6
|
+
* It has ONE meaning across every tool: the percentage of units that passed.
|
|
7
|
+
*
|
|
8
|
+
* A unit passes when it has no error-severity signals — warnings alone
|
|
9
|
+
* do not fail a unit. So a warnings-only run
|
|
10
|
+
* scores 100, consistent with the WARN-but-passing status the dashboard
|
|
11
|
+
* shows for it. An empty run (no checks) also scores 100, matching the
|
|
12
|
+
* fitness gate-baseline convention so `--gate-compare` does not report a
|
|
13
|
+
* phantom regression on an empty recipe.
|
|
14
|
+
*
|
|
15
|
+
* This lives in contracts — the layer below every tool — because the
|
|
16
|
+
* formula must be identical everywhere `score` is produced. Each tool
|
|
17
|
+
* previously rolled its own: fitness used passed/total, but graph used a
|
|
18
|
+
* findings-count penalty (`100 - findings`), which disagreed with its own
|
|
19
|
+
* passed/total summary and rendered 0% for warnings-only runs. Route all
|
|
20
|
+
* score computation through here so they cannot drift again.
|
|
21
|
+
*/
|
|
22
|
+
export declare function passRate(summary: {
|
|
23
|
+
readonly total: number;
|
|
24
|
+
readonly passed: number;
|
|
25
|
+
}): number;
|
|
26
|
+
//# sourceMappingURL=score.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"score.d.ts","sourceRoot":"","sources":["../src/score.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,QAAQ,CAAC,OAAO,EAAE;IAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAE7F"}
|
package/dist/score.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical pass rate for a run.
|
|
3
|
+
*
|
|
4
|
+
* `score` is a shared field on the run verdict (`SignalEnvelope.verdict`)
|
|
5
|
+
* and `StoredSession` that the dashboard renders as the "PASS RATE" column.
|
|
6
|
+
* It has ONE meaning across every tool: the percentage of units that passed.
|
|
7
|
+
*
|
|
8
|
+
* A unit passes when it has no error-severity signals — warnings alone
|
|
9
|
+
* do not fail a unit. So a warnings-only run
|
|
10
|
+
* scores 100, consistent with the WARN-but-passing status the dashboard
|
|
11
|
+
* shows for it. An empty run (no checks) also scores 100, matching the
|
|
12
|
+
* fitness gate-baseline convention so `--gate-compare` does not report a
|
|
13
|
+
* phantom regression on an empty recipe.
|
|
14
|
+
*
|
|
15
|
+
* This lives in contracts — the layer below every tool — because the
|
|
16
|
+
* formula must be identical everywhere `score` is produced. Each tool
|
|
17
|
+
* previously rolled its own: fitness used passed/total, but graph used a
|
|
18
|
+
* findings-count penalty (`100 - findings`), which disagreed with its own
|
|
19
|
+
* passed/total summary and rendered 0% for warnings-only runs. Route all
|
|
20
|
+
* score computation through here so they cannot drift again.
|
|
21
|
+
*/
|
|
22
|
+
export function passRate(summary) {
|
|
23
|
+
return summary.total > 0 ? Math.round((summary.passed / summary.total) * 100) : 100;
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=score.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"score.js","sourceRoot":"","sources":["../src/score.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,UAAU,QAAQ,CAAC,OAA4D;IACnF,OAAO,OAAO,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;AACtF,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"score.test.d.ts","sourceRoot":"","sources":["../src/score.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { passRate } from './score.js';
|
|
3
|
+
describe('passRate', () => {
|
|
4
|
+
it('is the rounded passed/total percentage', () => {
|
|
5
|
+
expect(passRate({ total: 4, passed: 4 })).toBe(100);
|
|
6
|
+
expect(passRate({ total: 4, passed: 1 })).toBe(25);
|
|
7
|
+
expect(passRate({ total: 2, passed: 1 })).toBe(50);
|
|
8
|
+
});
|
|
9
|
+
it('rounds to the nearest integer', () => {
|
|
10
|
+
expect(passRate({ total: 3, passed: 1 })).toBe(33);
|
|
11
|
+
expect(passRate({ total: 3, passed: 2 })).toBe(67);
|
|
12
|
+
});
|
|
13
|
+
it('is 100 for an empty run (no checks) — matches the gate-baseline convention', () => {
|
|
14
|
+
expect(passRate({ total: 0, passed: 0 })).toBe(100);
|
|
15
|
+
});
|
|
16
|
+
it('does not penalize warnings: all-passed scores 100 regardless of finding volume', () => {
|
|
17
|
+
// The graph regression: every check passed (warnings only), so the
|
|
18
|
+
// pass rate is 100 even though the run had many findings.
|
|
19
|
+
expect(passRate({ total: 1, passed: 1 })).toBe(100);
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
//# sourceMappingURL=score.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"score.test.js","sourceRoot":"","sources":["../src/score.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAE9C,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEtC,QAAQ,CAAC,UAAU,EAAE,GAAG,EAAE;IACxB,EAAE,CAAC,wCAAwC,EAAE,GAAG,EAAE;QAChD,MAAM,CAAC,QAAQ,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACpD,MAAM,CAAC,QAAQ,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACnD,MAAM,CAAC,QAAQ,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACrD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+BAA+B,EAAE,GAAG,EAAE;QACvC,MAAM,CAAC,QAAQ,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACnD,MAAM,CAAC,QAAQ,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACrD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4EAA4E,EAAE,GAAG,EAAE;QACpF,MAAM,CAAC,QAAQ,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACtD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gFAAgF,EAAE,GAAG,EAAE;QACxF,mEAAmE;QACnE,0DAA0D;QAC1D,MAAM,CAAC,QAAQ,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACtD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session persistence contract type.
|
|
3
|
+
*
|
|
4
|
+
* `StoredSession` is the cross-tool shape every tool's session row shares.
|
|
5
|
+
* The runtime (SessionRepo, schema, id/filename helpers) lives in
|
|
6
|
+
* @opensip-cli/session-store; this type stays in contracts as the shared
|
|
7
|
+
* surface tools and the dashboard agree on (audit 2026-05-29, contracts
|
|
8
|
+
* split).
|
|
9
|
+
*/
|
|
10
|
+
import type { SignalEnvelope } from './signal-envelope.js';
|
|
11
|
+
import type { ToolShortId } from '@opensip-cli/core';
|
|
12
|
+
/**
|
|
13
|
+
* A persisted tool-run session.
|
|
14
|
+
*
|
|
15
|
+
* Holds only **generic** columns every tool shares — score, pass/fail,
|
|
16
|
+
* lifecycle timing, host metrics, provenance. Per-session detail is
|
|
17
|
+
* tool-specific and lives in the opaque {@link StoredSession.payload}:
|
|
18
|
+
* `contracts` holds ZERO tool vocabulary. Each tool owns the shape of its own
|
|
19
|
+
* payload; the dashboard, as the presentation owner, reads the payload and
|
|
20
|
+
* renders it — the same producer/consumer split used for `GraphCatalog`.
|
|
21
|
+
*
|
|
22
|
+
* ## Host-owned run lifecycle timing (host-owned-run-timing)
|
|
23
|
+
*
|
|
24
|
+
* - `startedAt` is the wall-clock start of the user-initiated tool run,
|
|
25
|
+
* captured by the host run-lifecycle plane *after* the per-run `RunScope`
|
|
26
|
+
* exists and *before* any tool-owned setup / handler / live-renderer work.
|
|
27
|
+
* - `completedAt` is the wall-clock instant the tool handler / live renderer
|
|
28
|
+
* returned its completion data to the host, *before* host persistence,
|
|
29
|
+
* render, egress, or report side effects.
|
|
30
|
+
* - `durationMs` is the canonical tool-invocation duration (monotonic
|
|
31
|
+
* elapsed between the two boundaries), **not** TTY-busy time.
|
|
32
|
+
*
|
|
33
|
+
* All three are stamped exclusively by the host run-lifecycle plane from a
|
|
34
|
+
* single `RunLifecycle`. Tools never capture `new Date()` / `Date.now()` /
|
|
35
|
+
* `performance.now()` for these fields and never supply them — they return a
|
|
36
|
+
* `ToolSessionContribution` (verdict/score/recipe/payload) and the host owns
|
|
37
|
+
* the timing. See the clock taxonomy in the spec / session docs.
|
|
38
|
+
*
|
|
39
|
+
* `hostMetrics` (when present) explains *host-side* overhead — TTY occupancy,
|
|
40
|
+
* render, persist, egress, total command time — separately from the canonical
|
|
41
|
+
* `durationMs`. It is a hydrated projection of the sibling host-metrics record
|
|
42
|
+
* keyed by session id, not necessarily a column on the `sessions` table.
|
|
43
|
+
*/
|
|
44
|
+
export interface StoredSession {
|
|
45
|
+
readonly id: string;
|
|
46
|
+
readonly tool: ToolShortId;
|
|
47
|
+
/** Wall-clock start of the tool run (host run-lifecycle plane). */
|
|
48
|
+
readonly startedAt: string;
|
|
49
|
+
/** Wall-clock completion of the tool run (when the tool returned to the host). */
|
|
50
|
+
readonly completedAt: string;
|
|
51
|
+
readonly cwd: string;
|
|
52
|
+
readonly recipe?: string;
|
|
53
|
+
readonly score: number;
|
|
54
|
+
readonly passed: boolean;
|
|
55
|
+
/** Canonical tool-invocation duration (monotonic), not TTY-busy time. */
|
|
56
|
+
readonly durationMs: number;
|
|
57
|
+
/**
|
|
58
|
+
* Host-side overhead metrics for this run, hydrated from the sibling
|
|
59
|
+
* host-metrics record. Absent when no metrics were captured. These are NOT
|
|
60
|
+
* a replacement for `durationMs` — they answer "where did host-side cost
|
|
61
|
+
* accumulate", not "how long did the tool take".
|
|
62
|
+
*/
|
|
63
|
+
readonly hostMetrics?: StoredSessionHostMetrics;
|
|
64
|
+
/**
|
|
65
|
+
* Tool-owned opaque per-session detail. `contracts` treats this as
|
|
66
|
+
* `unknown` and never inspects it; the producing tool owns and validates
|
|
67
|
+
* its shape. Absent for tools that persist no detail.
|
|
68
|
+
*
|
|
69
|
+
* ## Inner payload versioning convention
|
|
70
|
+
*
|
|
71
|
+
* All tools (first-party and third-party) MUST stamp new payloads they
|
|
72
|
+
* persist with a top-level numeric `"__version": N` (double-underscore
|
|
73
|
+
* prefix signals infrastructure, not user data). Start at `1` for the
|
|
74
|
+
* current shape.
|
|
75
|
+
*
|
|
76
|
+
* The host (contracts / session-store / datastore) stays ignorant of tool
|
|
77
|
+
* shapes — only the producing tool owns the semantics of its version.
|
|
78
|
+
* The structural decoder tolerates legacy payloads (missing `__version`
|
|
79
|
+
* treated as v1 / legacy with `fidelity: 'projection'`).
|
|
80
|
+
*
|
|
81
|
+
* Example of a versioned tool payload (illustrative v1):
|
|
82
|
+
* ```json
|
|
83
|
+
* {
|
|
84
|
+
* "__version": 1,
|
|
85
|
+
* "summary": { "total": 42, "passed": 40, "failed": 2, "errors": 1, "warnings": 1 },
|
|
86
|
+
* "checks": [ ... ]
|
|
87
|
+
* }
|
|
88
|
+
* ```
|
|
89
|
+
*
|
|
90
|
+
* - Additive / optional fields: safe, no version bump required.
|
|
91
|
+
* - Breaking (remove/rename/ reinterpret required field, change shapes
|
|
92
|
+
* that replay code depends on): bump `__version` + follow documented
|
|
93
|
+
* deprecation window (see extending guide and ADR-0050).
|
|
94
|
+
*/
|
|
95
|
+
readonly payload?: unknown;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Host-side overhead metrics for a single tool run, captured on separate
|
|
99
|
+
* clocks from the canonical `durationMs` (host-owned-run-timing §5.3/§5.4).
|
|
100
|
+
*
|
|
101
|
+
* Stored in a sibling host-metrics record keyed by session id (so render /
|
|
102
|
+
* egress metrics — known only *after* the initial session write — can be
|
|
103
|
+
* upserted without rewriting the session row) and hydrated back onto
|
|
104
|
+
* {@link StoredSession.hostMetrics} for readers. Every field is optional: a
|
|
105
|
+
* given run only populates the metrics observable for its path (e.g.
|
|
106
|
+
* `ttyBusyMs` only for live/TTY runs).
|
|
107
|
+
*/
|
|
108
|
+
export interface StoredSessionHostMetrics {
|
|
109
|
+
/** Time the interactive TTY was occupied by the live view. */
|
|
110
|
+
readonly ttyBusyMs?: number;
|
|
111
|
+
/** Time spent rendering the final static/live completion output. */
|
|
112
|
+
readonly renderMs?: number;
|
|
113
|
+
/** Time spent writing the session row + payload. */
|
|
114
|
+
readonly persistMs?: number;
|
|
115
|
+
/** Time spent in host-owned post-run signal/report delivery. */
|
|
116
|
+
readonly egressMs?: number;
|
|
117
|
+
/** Elapsed time for the full command action, including host pre/post work. */
|
|
118
|
+
readonly totalCommandMs?: number;
|
|
119
|
+
}
|
|
120
|
+
/** A tool-owned replay of a stored session projection. */
|
|
121
|
+
export interface ToolSessionReplay<R = unknown> {
|
|
122
|
+
/** Human-renderable result for the shared CLI render seam. */
|
|
123
|
+
readonly result: R;
|
|
124
|
+
/** Machine-readable reconstructed envelope emitted by `sessions show --json`. */
|
|
125
|
+
readonly envelope: SignalEnvelope;
|
|
126
|
+
/**
|
|
127
|
+
* Stored sessions currently persist dashboard/detail projections, not the full
|
|
128
|
+
* live run envelope. This marker makes that explicit for machine consumers.
|
|
129
|
+
*/
|
|
130
|
+
readonly fidelity: 'projection';
|
|
131
|
+
}
|
|
132
|
+
//# sourceMappingURL=session-types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-types.d.ts","sourceRoot":"","sources":["../src/session-types.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAC3B,mEAAmE;IACnE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,kFAAkF;IAClF,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,yEAAyE;IACzE,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B;;;;;OAKG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,wBAAwB,CAAC;IAChD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA8BG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED;;;;;;;;;;GAUG;AACH,MAAM,WAAW,wBAAwB;IACvC,8DAA8D;IAC9D,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,oEAAoE;IACpE,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,oDAAoD;IACpD,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,gEAAgE;IAChE,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,8EAA8E;IAC9E,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;CAClC;AAED,0DAA0D;AAC1D,MAAM,WAAW,iBAAiB,CAAC,CAAC,GAAG,OAAO;IAC5C,8DAA8D;IAC9D,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;IACnB,iFAAiF;IACjF,QAAQ,CAAC,QAAQ,EAAE,cAAc,CAAC;IAClC;;;OAGG;IACH,QAAQ,CAAC,QAAQ,EAAE,YAAY,CAAC;CACjC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session persistence contract type.
|
|
3
|
+
*
|
|
4
|
+
* `StoredSession` is the cross-tool shape every tool's session row shares.
|
|
5
|
+
* The runtime (SessionRepo, schema, id/filename helpers) lives in
|
|
6
|
+
* @opensip-cli/session-store; this type stays in contracts as the shared
|
|
7
|
+
* surface tools and the dashboard agree on (audit 2026-05-29, contracts
|
|
8
|
+
* split).
|
|
9
|
+
*/
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=session-types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-types.js","sourceRoot":"","sources":["../src/session-types.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import type { FingerprintStrategy, Signal, ToolShortId, VerdictPolicy } from '@opensip-cli/core';
|
|
2
|
+
/**
|
|
3
|
+
* Run-level verdict header. `passed` ⇔ "no `critical`/`high` signals";
|
|
4
|
+
* `score` is the canonical {@link passRate} over `summary`.
|
|
5
|
+
*/
|
|
6
|
+
export interface RunVerdict {
|
|
7
|
+
readonly score: number;
|
|
8
|
+
readonly passed: boolean;
|
|
9
|
+
readonly summary: {
|
|
10
|
+
readonly total: number;
|
|
11
|
+
readonly passed: number;
|
|
12
|
+
readonly failed: number;
|
|
13
|
+
readonly errors: number;
|
|
14
|
+
readonly warnings: number;
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Per-unit fact sidecar. A "unit" is the neutral umbrella over a fit check, a
|
|
19
|
+
* graph rule, and a sim scenario (ADR-0011). Carries ONLY what a flat
|
|
20
|
+
* `Signal[]` cannot express: that a unit ran, whether it errored, and timing.
|
|
21
|
+
* `passed` ⇔ "that unit emitted no `critical`/`high` signals".
|
|
22
|
+
*/
|
|
23
|
+
export interface UnitResult {
|
|
24
|
+
readonly slug: string;
|
|
25
|
+
readonly passed: boolean;
|
|
26
|
+
readonly violationCount?: number;
|
|
27
|
+
readonly durationMs: number;
|
|
28
|
+
readonly error?: string;
|
|
29
|
+
/**
|
|
30
|
+
* Files the unit validated/scanned this run (fitness's "Validated" column).
|
|
31
|
+
* A per-unit fact a flat `Signal[]` cannot express — a check that scanned
|
|
32
|
+
* 450 files and emitted 0 signals still has `filesValidated: 450`. Optional:
|
|
33
|
+
* graph rules / sim scenarios do not scan files and omit it (the terminal
|
|
34
|
+
* table renders the column blank for those tools). `itemType` names the
|
|
35
|
+
* scanned noun (`files` / `packages` / …) for the column label.
|
|
36
|
+
*/
|
|
37
|
+
readonly filesValidated?: number;
|
|
38
|
+
readonly itemType?: string;
|
|
39
|
+
/**
|
|
40
|
+
* Findings suppressed by an inline `@fitness-ignore` directive this run
|
|
41
|
+
* (fitness's "Ignores" column). Like {@link filesValidated}, a per-unit fact
|
|
42
|
+
* not recoverable from the (post-suppression) signal list; optional and
|
|
43
|
+
* omitted by tools without a suppression mechanism.
|
|
44
|
+
*/
|
|
45
|
+
readonly ignoredCount?: number;
|
|
46
|
+
}
|
|
47
|
+
/** The one tool-run output envelope. The `CommandResult` payload every tool returns. */
|
|
48
|
+
export interface SignalEnvelope {
|
|
49
|
+
readonly schemaVersion: 2;
|
|
50
|
+
readonly tool: ToolShortId;
|
|
51
|
+
readonly recipe?: string;
|
|
52
|
+
readonly runId: string;
|
|
53
|
+
readonly createdAt: string;
|
|
54
|
+
readonly verdict: RunVerdict;
|
|
55
|
+
readonly units: readonly UnitResult[];
|
|
56
|
+
readonly signals: readonly Signal[];
|
|
57
|
+
/** Graph-only edge-fidelity marker, carried over from CliOutput.resolutionMode. */
|
|
58
|
+
readonly resolutionMode?: 'exact' | 'fast';
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Input to {@link buildSignalEnvelope}. `signals` are already the wire
|
|
62
|
+
* currency; `units` carry the per-unit ran/errored/timing facts. `runId` and
|
|
63
|
+
* `createdAt` are supplied by the caller (formatter-purity contract: no
|
|
64
|
+
* `Date.now()`/`randomUUID` in this layer, so tests stay deterministic).
|
|
65
|
+
*/
|
|
66
|
+
export interface BuildEnvelopeInput {
|
|
67
|
+
readonly tool: ToolShortId;
|
|
68
|
+
readonly recipe?: string;
|
|
69
|
+
readonly runId: string;
|
|
70
|
+
readonly createdAt: string;
|
|
71
|
+
readonly units: readonly UnitResult[];
|
|
72
|
+
readonly signals: readonly Signal[];
|
|
73
|
+
readonly resolutionMode?: 'exact' | 'fast';
|
|
74
|
+
/**
|
|
75
|
+
* The tool's resolved findings policy (ADR-0035). `verdict.passed` is computed
|
|
76
|
+
* from `(errors, warnings)` against this — replacing the old `errors === 0`.
|
|
77
|
+
*/
|
|
78
|
+
readonly policy: VerdictPolicy;
|
|
79
|
+
/**
|
|
80
|
+
* `true` when the run faulted OUTSIDE its units — e.g. fit's plugin-load
|
|
81
|
+
* errors, which occur before any unit exists. Unit-level faults are derived
|
|
82
|
+
* from `UnitResult.error` and need not be passed here. A faulted run always
|
|
83
|
+
* FAILs, independent of the findings policy (a crash ≠ "0 errors found").
|
|
84
|
+
*/
|
|
85
|
+
readonly runFaulted: boolean;
|
|
86
|
+
/**
|
|
87
|
+
* The tool's baseline-identity strategy (ADR-0036). {@link buildSignalEnvelope}
|
|
88
|
+
* stamps `Signal.fingerprint` with it at construction, so every envelope
|
|
89
|
+
* reaches the host seams (gate save/compare, cloud, SARIF) already stamped —
|
|
90
|
+
* the "tool forgot to stamp" failure class cannot occur for an envelope built
|
|
91
|
+
* here. Omitted ⇒ {@link defaultFingerprintStrategy} (`ruleId|filePath|line|col`),
|
|
92
|
+
* which is exactly the documented inheritance for a tool that declares no
|
|
93
|
+
* `Tool.fingerprintStrategy`. Stamping is idempotent: a signal that already
|
|
94
|
+
* carries a non-empty `fingerprint` is preserved byte-for-byte, so a tool may
|
|
95
|
+
* still stamp earlier (e.g. at `createSignal`) without double-hashing.
|
|
96
|
+
*/
|
|
97
|
+
readonly fingerprintStrategy?: FingerprintStrategy;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Assemble a {@link SignalEnvelope} from a run's units + signals.
|
|
101
|
+
*
|
|
102
|
+
* Centralises the verdict/summary computation so all three tools agree on
|
|
103
|
+
* "`passed` ⇔ no critical/high" and the score definition. Pure: no IO, no
|
|
104
|
+
* clock, no id generation — `runId`/`createdAt` arrive on the input.
|
|
105
|
+
*
|
|
106
|
+
* - `summary.total/passed/failed` come from `units` (units are what "ran").
|
|
107
|
+
* - `summary.errors/warnings` come from `signals` (critical|high → error,
|
|
108
|
+
* else warning).
|
|
109
|
+
* - `score = passRate(summary)`.
|
|
110
|
+
* - `verdict.passed` (ADR-0035) ⇔ the run did not fault, no unit errored, AND
|
|
111
|
+
* the error/warning counts pass the tool's findings `policy`. This is the
|
|
112
|
+
* single verdict that drives both the exit code and the headline.
|
|
113
|
+
* - Every signal is fingerprint-stamped (ADR-0036) with
|
|
114
|
+
* `input.fingerprintStrategy` (host default when omitted; idempotent for
|
|
115
|
+
* pre-stamped signals), so the built envelope is gate-ready by construction.
|
|
116
|
+
*/
|
|
117
|
+
export declare function buildSignalEnvelope(input: BuildEnvelopeInput): SignalEnvelope;
|
|
118
|
+
//# sourceMappingURL=signal-envelope.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"signal-envelope.d.ts","sourceRoot":"","sources":["../src/signal-envelope.ts"],"names":[],"mappings":"AA+BA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAEjG;;;GAGG;AACH,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE;QAChB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;QACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;QACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;QACxB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;KAC3B,CAAC;CACH;AAED;;;;;GAKG;AACH,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB;;;;;;;OAOG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B;;;;;OAKG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;CAChC;AAED,wFAAwF;AACxF,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,aAAa,EAAE,CAAC,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAC3B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAC;IAC7B,QAAQ,CAAC,KAAK,EAAE,SAAS,UAAU,EAAE,CAAC;IACtC,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,mFAAmF;IACnF,QAAQ,CAAC,cAAc,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;CAC5C;AAED;;;;;GAKG;AACH,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAC3B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,KAAK,EAAE,SAAS,UAAU,EAAE,CAAC;IACtC,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,QAAQ,CAAC,cAAc,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IAC3C;;;OAGG;IACH,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC;IAC/B;;;;;OAKG;IACH,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;IAC7B;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,mBAAmB,CAAC,EAAE,mBAAmB,CAAC;CACpD;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,kBAAkB,GAAG,cAAc,CA+C7E"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SignalEnvelope — the universal tool-run output currency (ADR-0011).
|
|
3
|
+
*
|
|
4
|
+
* Every tool run yields one envelope: the flat `Signal[]` a run produced
|
|
5
|
+
* (the same currency the cloud egresses via {@link SignalBatch}, ADR-0008)
|
|
6
|
+
* plus run identity (`tool`, `recipe`, `runId`, `createdAt`), a `verdict`
|
|
7
|
+
* header, and a `units[]` sidecar (so "ran, errored, 0 signals" is expressible
|
|
8
|
+
* — a flat signal list cannot carry per-unit ran/errored/timing facts). On the
|
|
9
|
+
* CLI wire this envelope rides under `.envelope` of a `CommandOutcome`
|
|
10
|
+
* (ADR-0024), so a `--json` consumer reads `jq '.envelope.verdict.passed'` /
|
|
11
|
+
* `.envelope.verdict.score`.
|
|
12
|
+
*
|
|
13
|
+
* This is intentionally close to {@link SignalBatch} (the cloud egress shape):
|
|
14
|
+
* the cloud sink ships the signals as-is, adding `repo` identity and dropping
|
|
15
|
+
* `verdict`/`units`. It lives in `contracts` — the tool↔runner contract layer —
|
|
16
|
+
* because it is the `CommandResult` payload every tool returns and the
|
|
17
|
+
* composition root consumes.
|
|
18
|
+
*
|
|
19
|
+
* `schemaVersion` is the output-contract version, independent of any package
|
|
20
|
+
* version. It is `2`, succeeding the implicit `CliOutput` "1.0" husk this
|
|
21
|
+
* envelope replaces.
|
|
22
|
+
*/
|
|
23
|
+
import { defaultFingerprintStrategy, policyPasses, SeverityPolicy, stampFingerprints, } from '@opensip-cli/core';
|
|
24
|
+
import { passRate } from './score.js';
|
|
25
|
+
/**
|
|
26
|
+
* Assemble a {@link SignalEnvelope} from a run's units + signals.
|
|
27
|
+
*
|
|
28
|
+
* Centralises the verdict/summary computation so all three tools agree on
|
|
29
|
+
* "`passed` ⇔ no critical/high" and the score definition. Pure: no IO, no
|
|
30
|
+
* clock, no id generation — `runId`/`createdAt` arrive on the input.
|
|
31
|
+
*
|
|
32
|
+
* - `summary.total/passed/failed` come from `units` (units are what "ran").
|
|
33
|
+
* - `summary.errors/warnings` come from `signals` (critical|high → error,
|
|
34
|
+
* else warning).
|
|
35
|
+
* - `score = passRate(summary)`.
|
|
36
|
+
* - `verdict.passed` (ADR-0035) ⇔ the run did not fault, no unit errored, AND
|
|
37
|
+
* the error/warning counts pass the tool's findings `policy`. This is the
|
|
38
|
+
* single verdict that drives both the exit code and the headline.
|
|
39
|
+
* - Every signal is fingerprint-stamped (ADR-0036) with
|
|
40
|
+
* `input.fingerprintStrategy` (host default when omitted; idempotent for
|
|
41
|
+
* pre-stamped signals), so the built envelope is gate-ready by construction.
|
|
42
|
+
*/
|
|
43
|
+
export function buildSignalEnvelope(input) {
|
|
44
|
+
const total = input.units.length;
|
|
45
|
+
const passed = input.units.filter((u) => u.passed).length;
|
|
46
|
+
const failed = total - passed;
|
|
47
|
+
// ADR-0036: fingerprints are an envelope-construction concern. Stamping here
|
|
48
|
+
// (tool strategy, host default when none) guarantees every built envelope is
|
|
49
|
+
// gate-ready, instead of trusting each tool to remember a post-hoc stamp that
|
|
50
|
+
// would otherwise only fail at the first `--gate-save`.
|
|
51
|
+
const signals = stampFingerprints(input.signals, input.fingerprintStrategy ?? defaultFingerprintStrategy);
|
|
52
|
+
let errors = 0;
|
|
53
|
+
let warnings = 0;
|
|
54
|
+
for (const signal of signals) {
|
|
55
|
+
// The gate's error/warning split is the central policy predicate (§5.9), one
|
|
56
|
+
// source of truth shared with the verdict / terminal table / SARIF level.
|
|
57
|
+
if (SeverityPolicy.isError(signal.severity))
|
|
58
|
+
errors += 1;
|
|
59
|
+
else
|
|
60
|
+
warnings += 1;
|
|
61
|
+
}
|
|
62
|
+
const summary = { total, passed, failed, errors, warnings };
|
|
63
|
+
// A unit that errored (a check that threw / timed out) is a fault, not a
|
|
64
|
+
// finding — it FAILs the run regardless of the findings policy. Pre-unit
|
|
65
|
+
// faults (e.g. fit plugin-load) arrive on `runFaulted` since no unit exists.
|
|
66
|
+
const unitFaulted = input.units.some((u) => u.error !== undefined);
|
|
67
|
+
const verdict = {
|
|
68
|
+
score: passRate(summary),
|
|
69
|
+
passed: !input.runFaulted && !unitFaulted && policyPasses({ errors, warnings }, input.policy),
|
|
70
|
+
summary,
|
|
71
|
+
};
|
|
72
|
+
return {
|
|
73
|
+
schemaVersion: 2,
|
|
74
|
+
tool: input.tool,
|
|
75
|
+
recipe: input.recipe,
|
|
76
|
+
runId: input.runId,
|
|
77
|
+
createdAt: input.createdAt,
|
|
78
|
+
verdict,
|
|
79
|
+
units: input.units,
|
|
80
|
+
signals,
|
|
81
|
+
resolutionMode: input.resolutionMode,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=signal-envelope.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"signal-envelope.js","sourceRoot":"","sources":["../src/signal-envelope.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,OAAO,EACL,0BAA0B,EAC1B,YAAY,EACZ,cAAc,EACd,iBAAiB,GAClB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAyGtC;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,mBAAmB,CAAC,KAAyB;IAC3D,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC;IACjC,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC;IAC1D,MAAM,MAAM,GAAG,KAAK,GAAG,MAAM,CAAC;IAE9B,6EAA6E;IAC7E,6EAA6E;IAC7E,8EAA8E;IAC9E,wDAAwD;IACxD,MAAM,OAAO,GAAG,iBAAiB,CAC/B,KAAK,CAAC,OAAO,EACb,KAAK,CAAC,mBAAmB,IAAI,0BAA0B,CACxD,CAAC;IAEF,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,IAAI,QAAQ,GAAG,CAAC,CAAC;IACjB,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,6EAA6E;QAC7E,0EAA0E;QAC1E,IAAI,cAAc,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC;YAAE,MAAM,IAAI,CAAC,CAAC;;YACpD,QAAQ,IAAI,CAAC,CAAC;IACrB,CAAC;IAED,MAAM,OAAO,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;IAE5D,yEAAyE;IACzE,yEAAyE;IACzE,6EAA6E;IAC7E,MAAM,WAAW,GAAG,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC;IAEnE,MAAM,OAAO,GAAe;QAC1B,KAAK,EAAE,QAAQ,CAAC,OAAO,CAAC;QACxB,MAAM,EAAE,CAAC,KAAK,CAAC,UAAU,IAAI,CAAC,WAAW,IAAI,YAAY,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,KAAK,CAAC,MAAM,CAAC;QAC7F,OAAO;KACR,CAAC;IAEF,OAAO;QACL,aAAa,EAAE,CAAC;QAChB,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,KAAK,EAAE,KAAK,CAAC,KAAK;QAClB,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,OAAO;QACP,KAAK,EAAE,KAAK,CAAC,KAAK;QAClB,OAAO;QACP,cAAc,EAAE,KAAK,CAAC,cAAc;KACrC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"signal-envelope.test.d.ts","sourceRoot":"","sources":["../src/signal-envelope.test.ts"],"names":[],"mappings":""}
|