@cat-factory/orchestration 0.229.0 → 0.231.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/container/dependencies.d.ts +26 -1
- package/dist/container/dependencies.d.ts.map +1 -1
- package/dist/container-content-libraries.d.ts.map +1 -1
- package/dist/container-content-libraries.js +5 -0
- package/dist/container-content-libraries.js.map +1 -1
- package/dist/container.d.ts +11 -1
- package/dist/container.d.ts.map +1 -1
- package/dist/container.js +1 -0
- package/dist/container.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/modules/execution/ExecutionService.d.ts +10 -8
- package/dist/modules/execution/ExecutionService.d.ts.map +1 -1
- package/dist/modules/execution/ExecutionService.js +20 -11
- package/dist/modules/execution/ExecutionService.js.map +1 -1
- package/dist/modules/execution/PrVerificationReportController.d.ts +35 -39
- package/dist/modules/execution/PrVerificationReportController.d.ts.map +1 -1
- package/dist/modules/execution/PrVerificationReportController.js +62 -80
- package/dist/modules/execution/PrVerificationReportController.js.map +1 -1
- package/dist/modules/execution/RunEvidenceLoader.d.ts +79 -0
- package/dist/modules/execution/RunEvidenceLoader.d.ts.map +1 -0
- package/dist/modules/execution/RunEvidenceLoader.js +114 -0
- package/dist/modules/execution/RunEvidenceLoader.js.map +1 -0
- package/dist/modules/execution/RunEvidenceReads.d.ts +53 -0
- package/dist/modules/execution/RunEvidenceReads.d.ts.map +1 -0
- package/dist/modules/execution/RunEvidenceReads.js +57 -0
- package/dist/modules/execution/RunEvidenceReads.js.map +1 -0
- package/dist/modules/execution/ci.logic.d.ts +8 -2
- package/dist/modules/execution/ci.logic.d.ts.map +1 -1
- package/dist/modules/execution/ci.logic.js +8 -4
- package/dist/modules/execution/ci.logic.js.map +1 -1
- package/dist/modules/execution/prReport.logic.d.ts.map +1 -1
- package/dist/modules/execution/prReport.logic.js +53 -45
- package/dist/modules/execution/prReport.logic.js.map +1 -1
- package/dist/modules/execution/prReport.steps.d.ts +4 -0
- package/dist/modules/execution/prReport.steps.d.ts.map +1 -1
- package/dist/modules/execution/prReport.steps.js +6 -6
- package/dist/modules/execution/prReport.steps.js.map +1 -1
- package/dist/modules/execution/runOutcome.boundary.d.ts +11 -0
- package/dist/modules/execution/runOutcome.boundary.d.ts.map +1 -0
- package/dist/modules/execution/runOutcome.boundary.js +163 -0
- package/dist/modules/execution/runOutcome.boundary.js.map +1 -0
- package/dist/modules/observability/retentionPass.d.ts +0 -67
- package/dist/modules/observability/retentionPass.d.ts.map +1 -1
- package/dist/modules/observability/retentionPass.js +1 -70
- package/dist/modules/observability/retentionPass.js.map +1 -1
- package/dist/validation/validateRegistrations.d.ts +38 -1
- package/dist/validation/validateRegistrations.d.ts.map +1 -1
- package/dist/validation/validateRegistrations.js +76 -38
- package/dist/validation/validateRegistrations.js.map +1 -1
- package/package.json +11 -11
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { hostMarkdown } from '@cat-factory/kernel';
|
|
2
|
+
import { selectEvidenceStep } from '@cat-factory/contracts';
|
|
2
3
|
// ---------------------------------------------------------------------------
|
|
3
4
|
// Step selection for the PR verification report: which step of a run a section reports on.
|
|
4
5
|
//
|
|
@@ -16,14 +17,13 @@ import { hostMarkdown } from '@cat-factory/kernel';
|
|
|
16
17
|
* `ci` gate after the coder and another after the tester, say), and the later run is the one
|
|
17
18
|
* that describes the PR head as it stands now. Reporting the first would pin the section to a
|
|
18
19
|
* verdict two steps of work out of date.
|
|
20
|
+
*
|
|
21
|
+
* The rule itself is `selectEvidenceStep` in `@cat-factory/contracts`, shared with the run
|
|
22
|
+
* outcome summary so the two documents cannot quote different sessions of the same run; this is
|
|
23
|
+
* the instance-shaped adapter every call site here already reads through.
|
|
19
24
|
*/
|
|
20
25
|
export function findStep(instance, matches, hasEvidence) {
|
|
21
|
-
|
|
22
|
-
for (let i = matching.length - 1; i >= 0; i--) {
|
|
23
|
-
if (hasEvidence(matching[i]))
|
|
24
|
-
return matching[i];
|
|
25
|
-
}
|
|
26
|
-
return matching[0];
|
|
26
|
+
return selectEvidenceStep(instance.steps, matches, hasEvidence);
|
|
27
27
|
}
|
|
28
28
|
/**
|
|
29
29
|
* Render an ABSENT section's note: the ONE line every section emits in place of its evidence.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prReport.steps.js","sourceRoot":"","sources":["../../../src/modules/execution/prReport.steps.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;
|
|
1
|
+
{"version":3,"file":"prReport.steps.js","sourceRoot":"","sources":["../../../src/modules/execution/prReport.steps.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAClD,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAA;AAE3D,8EAA8E;AAC9E,2FAA2F;AAC3F,EAAE;AACF,6FAA6F;AAC7F,+FAA+F;AAC/F,gGAAgG;AAChG,oCAAoC;AACpC,8EAA8E;AAE9E;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,QAAQ,CACtB,QAA2B,EAC3B,OAAwC,EACxC,WAA4C;IAE5C,OAAO,kBAAkB,CAAC,QAAQ,CAAC,KAAK,EAAE,OAAO,EAAE,WAAW,CAAC,CAAA;AACjE,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,UAAU,CAAC,IAA+B;IACxD,OAAO,IAAI,YAAY,CAAC,KAAK,CAAC,IAAI,IAAI,eAAe,CAAC,GAAG,CAAA;AAC3D,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { RunOutcome } from '@cat-factory/contracts';
|
|
2
|
+
/**
|
|
3
|
+
* The outcome summary as a public response body: scrubbed, clamped, bounded, and honest about
|
|
4
|
+
* every drop.
|
|
5
|
+
*
|
|
6
|
+
* Rebuilt field by field rather than spread over the composed value, so a section added to
|
|
7
|
+
* {@link RunOutcome} fails THIS build until someone has decided what its boundary treatment is.
|
|
8
|
+
* A spread would have carried it out unscrubbed and compiled.
|
|
9
|
+
*/
|
|
10
|
+
export declare function boundOutcomeForApi(outcome: RunOutcome): RunOutcome;
|
|
11
|
+
//# sourceMappingURL=runOutcome.boundary.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runOutcome.boundary.d.ts","sourceRoot":"","sources":["../../../src/modules/execution/runOutcome.boundary.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAMV,UAAU,EACX,MAAM,wBAAwB,CAAA;AA2J/B;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,UAAU,GAAG,UAAU,CAwBlE"}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import { redactSecrets } from '@cat-factory/kernel';
|
|
2
|
+
// ---------------------------------------------------------------------------
|
|
3
|
+
// The BOUNDARY treatment for the run outcome summary on its way out over
|
|
4
|
+
// `GET /api/v1/runs/:runId/outcome`.
|
|
5
|
+
//
|
|
6
|
+
// `composeRunOutcome` lives in `@cat-factory/contracts` because the SPA composes the same
|
|
7
|
+
// reduction live off its own store, and it is deliberately un-scrubbed and un-clamped for the
|
|
8
|
+
// same reason `run-evidence.ts` says its join is: handing the SPA escaped entities and elided
|
|
9
|
+
// prose would degrade the surface that renders into a DOM for a member who is already inside the
|
|
10
|
+
// workspace. What crosses the wire to an API key is a different exposure, and it is the one the
|
|
11
|
+
// verification report has always treated as such: the same tester summary, the same per-verdict
|
|
12
|
+
// evidence and the same spec titles are scrubbed and clamped on their way onto a pull request
|
|
13
|
+
// body and out of `GET /api/v1/runs/:runId/report`. Serving them verbatim beside that endpoint
|
|
14
|
+
// would have made the weaker of the two the one an integration reads.
|
|
15
|
+
//
|
|
16
|
+
// Two things happen here, in this order, and the order is the point:
|
|
17
|
+
//
|
|
18
|
+
// 1. **Scrub, at COMPOSE time, before any truncation** (the repo-wide rule): a model routinely
|
|
19
|
+
// echoes a request URL or an auth header into its prose, and clamping first would leave half
|
|
20
|
+
// a token in the payload with nothing to say it had been cut.
|
|
21
|
+
// 2. **BOUND what is unbounded**, recording every drop in `truncations`. A response whose size
|
|
22
|
+
// is set by how much a model chose to write is not a contract a consumer can hold; a
|
|
23
|
+
// response that says what it withheld is.
|
|
24
|
+
//
|
|
25
|
+
// Nothing here decides anything. Every count in the payload is computed over the WHOLE join
|
|
26
|
+
// before this function sees it, so a bounded rendering still reports the true totals: the caps
|
|
27
|
+
// touch what is SHOWN, never what is COUNTED.
|
|
28
|
+
// ---------------------------------------------------------------------------
|
|
29
|
+
/**
|
|
30
|
+
* How much of one free-text field survives. Sized for a field a person reads whole (a tester's
|
|
31
|
+
* observation against one requirement, its session summary), not for a transcript: a producer
|
|
32
|
+
* that wrote more than this has written a document, and the endpoint that serves documents is
|
|
33
|
+
* `/report`.
|
|
34
|
+
*/
|
|
35
|
+
const MAX_TEXT_CHARS = 2_000;
|
|
36
|
+
/**
|
|
37
|
+
* How many requirement rows one response carries. Above any real service's `spec/` (the largest
|
|
38
|
+
* in this repo's own fixtures is two orders below it), so the cap is a ceiling on a pathological
|
|
39
|
+
* case rather than a routine truncation, and `truncations` names it on the runs that hit it.
|
|
40
|
+
*/
|
|
41
|
+
const MAX_REQUIREMENT_ENTRIES = 500;
|
|
42
|
+
/** How many tester areas and concerns one response carries. Same reasoning as the rows. */
|
|
43
|
+
const MAX_TESTER_LIST = 200;
|
|
44
|
+
/** Scrub, then clamp. Null in, null out: an absent value is not an empty one. */
|
|
45
|
+
function text(value) {
|
|
46
|
+
const scrubbed = redactSecrets(value) ?? null;
|
|
47
|
+
if (scrubbed == null)
|
|
48
|
+
return null;
|
|
49
|
+
return scrubbed.length <= MAX_TEXT_CHARS ? scrubbed : `${scrubbed.slice(0, MAX_TEXT_CHARS - 1)}…`;
|
|
50
|
+
}
|
|
51
|
+
/** The same treatment where the field is non-nullable. */
|
|
52
|
+
function required(value) {
|
|
53
|
+
return text(value) ?? '';
|
|
54
|
+
}
|
|
55
|
+
/** The ONE shape a truncation note takes, matching the verification report's own vocabulary. */
|
|
56
|
+
function note(label, kept, total, detail) {
|
|
57
|
+
return `${label}: showing ${kept} of ${total}${detail ? ` (${detail})` : ''}`;
|
|
58
|
+
}
|
|
59
|
+
/** Cap a list, recording what it dropped. */
|
|
60
|
+
function cap(items, label, truncations, max, detail) {
|
|
61
|
+
if (items.length <= max)
|
|
62
|
+
return [...items];
|
|
63
|
+
truncations.push(note(label, max, items.length, detail));
|
|
64
|
+
return items.slice(0, max);
|
|
65
|
+
}
|
|
66
|
+
function boundRequirement(entry) {
|
|
67
|
+
return {
|
|
68
|
+
id: required(entry.id),
|
|
69
|
+
title: text(entry.title),
|
|
70
|
+
verdict: entry.verdict,
|
|
71
|
+
detail: text(entry.detail),
|
|
72
|
+
state: entry.state,
|
|
73
|
+
regression: entry.regression,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
function boundRequirements(requirements, truncations) {
|
|
77
|
+
if (requirements.status === 'absent')
|
|
78
|
+
return requirements;
|
|
79
|
+
return {
|
|
80
|
+
status: 'reported',
|
|
81
|
+
spec: requirements.spec,
|
|
82
|
+
met: requirements.met,
|
|
83
|
+
notMet: requirements.notMet,
|
|
84
|
+
notCovered: requirements.notCovered,
|
|
85
|
+
regressions: requirements.regressions,
|
|
86
|
+
total: requirements.total,
|
|
87
|
+
unmatchedVerdicts: requirements.unmatchedVerdicts,
|
|
88
|
+
// The rows arrive ordered by SEVERITY, so a cap keeps the regressions and failures and drops
|
|
89
|
+
// the least severe tail. Said in the note, because a reader who assumed the spec's own order
|
|
90
|
+
// would conclude the missing requirements were never ruled on.
|
|
91
|
+
entries: cap(requirements.entries, 'requirements.entries', truncations, MAX_REQUIREMENT_ENTRIES, 'ordered by severity, so the rows dropped are the least severe').map(boundRequirement),
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
function boundConcern(concern) {
|
|
95
|
+
return { title: required(concern.title), severity: concern.severity };
|
|
96
|
+
}
|
|
97
|
+
function boundTests(tests, truncations) {
|
|
98
|
+
if (tests.status === 'absent')
|
|
99
|
+
return tests;
|
|
100
|
+
return {
|
|
101
|
+
status: 'reported',
|
|
102
|
+
verdict: tests.verdict,
|
|
103
|
+
summary: text(tests.summary),
|
|
104
|
+
abortReason: text(tests.abortReason),
|
|
105
|
+
areas: cap(tests.areas, 'tests.areas', truncations, MAX_TESTER_LIST).map(required),
|
|
106
|
+
passed: tests.passed,
|
|
107
|
+
failed: tests.failed,
|
|
108
|
+
skipped: tests.skipped,
|
|
109
|
+
concerns: cap(tests.concerns, 'tests.concerns', truncations, MAX_TESTER_LIST).map(boundConcern),
|
|
110
|
+
// The environment is a closed shape of platform-recorded identifiers, not model prose.
|
|
111
|
+
environment: tests.environment,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
function boundVisuals(visuals) {
|
|
115
|
+
if (visuals.status === 'absent') {
|
|
116
|
+
return { status: 'absent', gap: visuals.gap, detail: text(visuals.detail) };
|
|
117
|
+
}
|
|
118
|
+
return {
|
|
119
|
+
status: 'reported',
|
|
120
|
+
source: visuals.source,
|
|
121
|
+
phase: visuals.phase,
|
|
122
|
+
// Bounded by the capture path, which caps how many views one run may store.
|
|
123
|
+
views: visuals.views.map((view) => ({
|
|
124
|
+
view: required(view.view),
|
|
125
|
+
artifactId: view.artifactId,
|
|
126
|
+
referenceArtifactId: view.referenceArtifactId,
|
|
127
|
+
})),
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* The outcome summary as a public response body: scrubbed, clamped, bounded, and honest about
|
|
132
|
+
* every drop.
|
|
133
|
+
*
|
|
134
|
+
* Rebuilt field by field rather than spread over the composed value, so a section added to
|
|
135
|
+
* {@link RunOutcome} fails THIS build until someone has decided what its boundary treatment is.
|
|
136
|
+
* A spread would have carried it out unscrubbed and compiled.
|
|
137
|
+
*/
|
|
138
|
+
export function boundOutcomeForApi(outcome) {
|
|
139
|
+
const truncations = [...outcome.truncations];
|
|
140
|
+
return {
|
|
141
|
+
version: outcome.version,
|
|
142
|
+
disposition: outcome.disposition,
|
|
143
|
+
title: required(outcome.title),
|
|
144
|
+
ask: text(outcome.ask),
|
|
145
|
+
pullRequests: outcome.pullRequests.map((pr) => ({
|
|
146
|
+
url: required(pr.url),
|
|
147
|
+
number: pr.number,
|
|
148
|
+
branch: text(pr.branch),
|
|
149
|
+
repo: text(pr.repo),
|
|
150
|
+
})),
|
|
151
|
+
requirements: boundRequirements(outcome.requirements, truncations),
|
|
152
|
+
tests: boundTests(outcome.tests, truncations),
|
|
153
|
+
visuals: boundVisuals(outcome.visuals),
|
|
154
|
+
// A closed vocabulary of enum members and one nullable enum: nothing here is authored text.
|
|
155
|
+
checks: outcome.checks.map((check) => ({
|
|
156
|
+
kind: check.kind,
|
|
157
|
+
state: check.state,
|
|
158
|
+
reproduction: check.reproduction,
|
|
159
|
+
})),
|
|
160
|
+
truncations,
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
//# sourceMappingURL=runOutcome.boundary.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runOutcome.boundary.js","sourceRoot":"","sources":["../../../src/modules/execution/runOutcome.boundary.ts"],"names":[],"mappings":"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"}
|
|
@@ -45,73 +45,6 @@ export declare function createRetentionPass(logger?: Logger): RetentionPass;
|
|
|
45
45
|
* history. Shared by both facades so the two cannot drift on how much they heal.
|
|
46
46
|
*/
|
|
47
47
|
export declare const RUN_DAY_ROLLUP_LOOKBACK_MS: number;
|
|
48
|
-
/** How far back a steady-state spend-rollup pass recomputes, for the reason above. */
|
|
49
|
-
export declare const SPEND_DAY_ROLLUP_LOOKBACK_MS: number;
|
|
50
|
-
/**
|
|
51
|
-
* The most a SINGLE spend-rollup pass will aggregate. The catch-up walk below can ask for an
|
|
52
|
-
* arbitrarily wide window (a deployment that has never rolled up, a sweep down for a week),
|
|
53
|
-
* and one unbounded `GROUP BY` over a busy deployment's whole ledger is how a cron pass turns
|
|
54
|
-
* into a row-limit error on D1 or a long-running query on Postgres, which would then fail on
|
|
55
|
-
* every subsequent pass too, since the window only widens.
|
|
56
|
-
*/
|
|
57
|
-
export declare const SPEND_DAY_ROLLUP_MAX_SPAN_MS: number;
|
|
58
|
-
/**
|
|
59
|
-
* How far back the FIRST pass on a deployment reaches. The rollup serves the 90-day report
|
|
60
|
-
* window, so a rollup that started at "today" would under-report that window for a quarter
|
|
61
|
-
* while looking complete: the ledger holds the data, and the reader has no way to see that
|
|
62
|
-
* the newer store simply had not been asked yet. Older history than this is deliberately not
|
|
63
|
-
* backfilled: `rolledUpThrough` states where the durable record begins.
|
|
64
|
-
*
|
|
65
|
-
* It also serves as the FLOOR under a resumed pass when the ledger has no retention window of
|
|
66
|
-
* its own to derive one from. See {@link spendRollupWindow}.
|
|
67
|
-
*/
|
|
68
|
-
export declare const SPEND_DAY_ROLLUP_BACKFILL_MS: number;
|
|
69
|
-
/** One spend-rollup pass's window, plus whatever it had to give up on to produce it. */
|
|
70
|
-
export interface SpendRollupWindow {
|
|
71
|
-
from: number;
|
|
72
|
-
to: number;
|
|
73
|
-
/**
|
|
74
|
-
* The span the catch-up horizon dropped, or null when the walk covers everything the last
|
|
75
|
-
* pass left. NON-NULL IS A PERMANENT DATA GAP, not a deferral: nothing re-offers these days
|
|
76
|
-
* to a later pass, and the watermark advances past them. Whoever calls this must SAY so:
|
|
77
|
-
* `through_day` is a high-water mark and cannot represent a hole, so the log line is the
|
|
78
|
-
* only place the hole is ever named.
|
|
79
|
-
*/
|
|
80
|
-
skipped: {
|
|
81
|
-
from: number;
|
|
82
|
-
to: number;
|
|
83
|
-
} | null;
|
|
84
|
-
}
|
|
85
|
-
/**
|
|
86
|
-
* The window one spend-rollup pass should materialise, given what the last pass covered and
|
|
87
|
-
* how long the LEDGER it folds is retained.
|
|
88
|
-
*
|
|
89
|
-
* Unlike the run rollup, which recomputes a fixed trailing lookback, this one walks FORWARD
|
|
90
|
-
* from the sweep's own watermark. The difference is that a gap here is permanent: nothing
|
|
91
|
-
* else retains the attribution the rollup is folding, so a day the sweep skipped while it was
|
|
92
|
-
* down is a day whose TCO history is simply missing, forever. Resuming from the watermark
|
|
93
|
-
* turns "the sweep was down for a week" into a few catch-up passes instead.
|
|
94
|
-
*
|
|
95
|
-
* Which is why the catch-up horizon is derived from `ledgerRetentionMs` rather than reusing
|
|
96
|
-
* the backfill constant. The two answer different questions and only look alike. The backfill
|
|
97
|
-
* bounds a FIRST pass, where the choice is how much history to adopt and 90 days is a
|
|
98
|
-
* judgement call. A resumed pass has no such choice: every day between the watermark and now
|
|
99
|
-
* is a day this deployment has already committed to recording, and the ledger still HOLDS it
|
|
100
|
-
* (the prune runs in this same sweep, so a sweep that was down pruned nothing either). A
|
|
101
|
-
* horizon shorter than the ledger's own retention would step over those days while they were
|
|
102
|
-
* still readable, which is losing data that was there for the asking. Past the ledger's
|
|
103
|
-
* retention there is genuinely nothing left to fold, so that is where the walk stops, and the
|
|
104
|
-
* pathological watermark the horizon exists to contain (hand-edited, restored from a backup,
|
|
105
|
-
* epoch-zero) is still contained.
|
|
106
|
-
*
|
|
107
|
-
* Pure so both facades share it (and so the walk is unit-testable without a database): the
|
|
108
|
-
* caller reads the watermark, calls this, materialises `[from, to)`, and reports `skipped`.
|
|
109
|
-
*
|
|
110
|
-
* @param ledgerRetentionMs how long `token_usage` is kept; 0 or less means the ledger is
|
|
111
|
-
* never pruned, in which case there is no retention edge to derive a horizon from and the
|
|
112
|
-
* backfill constant is the floor.
|
|
113
|
-
*/
|
|
114
|
-
export declare function spendRollupWindow(throughDay: number | null, now: number, ledgerRetentionMs: number): SpendRollupWindow;
|
|
115
48
|
/**
|
|
116
49
|
* One sweep's spend-rollup step, shared by both facades: read the watermark, walk the window,
|
|
117
50
|
* materialise it, and NAME any span the catch-up horizon had to give up on.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"retentionPass.d.ts","sourceRoot":"","sources":["../../../src/modules/observability/retentionPass.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"retentionPass.d.ts","sourceRoot":"","sources":["../../../src/modules/observability/retentionPass.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,MAAM,EACX,KAAK,qBAAqB,EAG3B,MAAM,qBAAqB,CAAA;AAiB5B,0FAA0F;AAC1F,MAAM,WAAW,aAAa;IAC5B;;;;OAIG;IACH,KAAK,CACH,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,EAChB,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,GACvC,OAAO,CAAC,MAAM,CAAC,CAAA;IAClB;;;OAGG;IACH,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;IAClE;;;;;;;;;OASG;IACH,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;IACzE;;;OAGG;IACH,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,CAAA;CAC1B;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,aAAa,CAyBlE;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,0BAA0B,QAAuB,CAAA;AAE9D;;;;;;;;;;;;GAYG;AACH,wBAAsB,sBAAsB,CAC1C,IAAI,EAAE,aAAa,EACnB,UAAU,EAAE,IAAI,CAAC,qBAAqB,EAAE,iBAAiB,GAAG,sBAAsB,CAAC,EACnF,GAAG,EAAE,MAAM,EACX,iBAAiB,EAAE,MAAM,EACzB,MAAM,CAAC,EAAE,MAAM,GACd,OAAO,CAAC,MAAM,CAAC,CAwBjB"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { describeError } from '@cat-factory/kernel';
|
|
1
|
+
import { describeError, spendRollupWindow, } from '@cat-factory/kernel';
|
|
2
2
|
/**
|
|
3
3
|
* Start one isolated retention pass. Create a new one per sweep (the {@link RetentionPass.failed}
|
|
4
4
|
* list is per-pass state), then read `failed` after the last table.
|
|
@@ -40,75 +40,6 @@ export function createRetentionPass(logger) {
|
|
|
40
40
|
* history. Shared by both facades so the two cannot drift on how much they heal.
|
|
41
41
|
*/
|
|
42
42
|
export const RUN_DAY_ROLLUP_LOOKBACK_MS = 3 * 24 * 60 * 60_000;
|
|
43
|
-
/** How far back a steady-state spend-rollup pass recomputes, for the reason above. */
|
|
44
|
-
export const SPEND_DAY_ROLLUP_LOOKBACK_MS = 3 * 24 * 60 * 60_000;
|
|
45
|
-
/**
|
|
46
|
-
* The most a SINGLE spend-rollup pass will aggregate. The catch-up walk below can ask for an
|
|
47
|
-
* arbitrarily wide window (a deployment that has never rolled up, a sweep down for a week),
|
|
48
|
-
* and one unbounded `GROUP BY` over a busy deployment's whole ledger is how a cron pass turns
|
|
49
|
-
* into a row-limit error on D1 or a long-running query on Postgres, which would then fail on
|
|
50
|
-
* every subsequent pass too, since the window only widens.
|
|
51
|
-
*/
|
|
52
|
-
export const SPEND_DAY_ROLLUP_MAX_SPAN_MS = 30 * 24 * 60 * 60_000;
|
|
53
|
-
/**
|
|
54
|
-
* How far back the FIRST pass on a deployment reaches. The rollup serves the 90-day report
|
|
55
|
-
* window, so a rollup that started at "today" would under-report that window for a quarter
|
|
56
|
-
* while looking complete: the ledger holds the data, and the reader has no way to see that
|
|
57
|
-
* the newer store simply had not been asked yet. Older history than this is deliberately not
|
|
58
|
-
* backfilled: `rolledUpThrough` states where the durable record begins.
|
|
59
|
-
*
|
|
60
|
-
* It also serves as the FLOOR under a resumed pass when the ledger has no retention window of
|
|
61
|
-
* its own to derive one from. See {@link spendRollupWindow}.
|
|
62
|
-
*/
|
|
63
|
-
export const SPEND_DAY_ROLLUP_BACKFILL_MS = 90 * 24 * 60 * 60_000;
|
|
64
|
-
/**
|
|
65
|
-
* The window one spend-rollup pass should materialise, given what the last pass covered and
|
|
66
|
-
* how long the LEDGER it folds is retained.
|
|
67
|
-
*
|
|
68
|
-
* Unlike the run rollup, which recomputes a fixed trailing lookback, this one walks FORWARD
|
|
69
|
-
* from the sweep's own watermark. The difference is that a gap here is permanent: nothing
|
|
70
|
-
* else retains the attribution the rollup is folding, so a day the sweep skipped while it was
|
|
71
|
-
* down is a day whose TCO history is simply missing, forever. Resuming from the watermark
|
|
72
|
-
* turns "the sweep was down for a week" into a few catch-up passes instead.
|
|
73
|
-
*
|
|
74
|
-
* Which is why the catch-up horizon is derived from `ledgerRetentionMs` rather than reusing
|
|
75
|
-
* the backfill constant. The two answer different questions and only look alike. The backfill
|
|
76
|
-
* bounds a FIRST pass, where the choice is how much history to adopt and 90 days is a
|
|
77
|
-
* judgement call. A resumed pass has no such choice: every day between the watermark and now
|
|
78
|
-
* is a day this deployment has already committed to recording, and the ledger still HOLDS it
|
|
79
|
-
* (the prune runs in this same sweep, so a sweep that was down pruned nothing either). A
|
|
80
|
-
* horizon shorter than the ledger's own retention would step over those days while they were
|
|
81
|
-
* still readable, which is losing data that was there for the asking. Past the ledger's
|
|
82
|
-
* retention there is genuinely nothing left to fold, so that is where the walk stops, and the
|
|
83
|
-
* pathological watermark the horizon exists to contain (hand-edited, restored from a backup,
|
|
84
|
-
* epoch-zero) is still contained.
|
|
85
|
-
*
|
|
86
|
-
* Pure so both facades share it (and so the walk is unit-testable without a database): the
|
|
87
|
-
* caller reads the watermark, calls this, materialises `[from, to)`, and reports `skipped`.
|
|
88
|
-
*
|
|
89
|
-
* @param ledgerRetentionMs how long `token_usage` is kept; 0 or less means the ledger is
|
|
90
|
-
* never pruned, in which case there is no retention edge to derive a horizon from and the
|
|
91
|
-
* backfill constant is the floor.
|
|
92
|
-
*/
|
|
93
|
-
export function spendRollupWindow(throughDay, now, ledgerRetentionMs) {
|
|
94
|
-
// A `null` watermark is "no pass has ever completed", not "start from now": see the
|
|
95
|
-
// backfill constant. Once there IS one, the steady-state lookback still applies on top of
|
|
96
|
-
// it, so a day that was still accruing when it was covered gets recomputed rather than
|
|
97
|
-
// frozen half-counted.
|
|
98
|
-
const resume = throughDay == null
|
|
99
|
-
? now - SPEND_DAY_ROLLUP_BACKFILL_MS
|
|
100
|
-
: Math.min(throughDay, now - SPEND_DAY_ROLLUP_LOOKBACK_MS);
|
|
101
|
-
const horizon = now - Math.max(ledgerRetentionMs, SPEND_DAY_ROLLUP_BACKFILL_MS);
|
|
102
|
-
// Never walk back past the horizon, and never aggregate more than one pass's worth in one
|
|
103
|
-
// query. A first pass is bounded by its own backfill choice, so only a RESUMED one can be
|
|
104
|
-
// cut here, and only that one has days it was already committed to.
|
|
105
|
-
const from = Math.max(resume, horizon);
|
|
106
|
-
return {
|
|
107
|
-
from,
|
|
108
|
-
to: Math.min(now, from + SPEND_DAY_ROLLUP_MAX_SPAN_MS),
|
|
109
|
-
skipped: throughDay != null && resume < horizon ? { from: resume, to: horizon } : null,
|
|
110
|
-
};
|
|
111
|
-
}
|
|
112
43
|
/**
|
|
113
44
|
* One sweep's spend-rollup step, shared by both facades: read the watermark, walk the window,
|
|
114
45
|
* materialise it, and NAME any span the catch-up horizon had to give up on.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"retentionPass.js","sourceRoot":"","sources":["../../../src/modules/observability/retentionPass.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"retentionPass.js","sourceRoot":"","sources":["../../../src/modules/observability/retentionPass.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,aAAa,EACb,iBAAiB,GAClB,MAAM,qBAAqB,CAAA;AAqD5B;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CAAC,MAAe;IACjD,MAAM,MAAM,GAAa,EAAE,CAAA;IAC3B,MAAM,OAAO,GAAG,KAAK,EAAE,KAAa,EAAE,GAA0B,EAAmB,EAAE;QACnF,IAAI,CAAC;YACH,OAAO,MAAM,GAAG,EAAE,CAAA;QACpB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;YAClB,yFAAyF;YACzF,uFAAuF;YACvF,6DAA6D;YAC7D,MAAM,EAAE,IAAI,CAAC,0DAA0D,EAAE;gBACvE,KAAK,EAAE,WAAW;gBAClB,KAAK;gBACL,GAAG,aAAa,CAAC,KAAK,CAAC;aACxB,CAAC,CAAA;YACF,OAAO,CAAC,CAAA;QACV,CAAC;IACH,CAAC,CAAA;IACD,OAAO;QACL,KAAK,EAAE,CAAC,KAAK,EAAE,QAAQ,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,CACnC,QAAQ,IAAI,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,GAAG,GAAG,QAAQ,CAAC,CAAC;QAChF,MAAM,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC;QAC3C,WAAW,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC;QACpD,MAAM;KACP,CAAA;AACH,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,MAAM,CAAA;AAE9D;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAC1C,IAAmB,EACnB,UAAmF,EACnF,GAAW,EACX,iBAAyB,EACzB,MAAe;IAEf,OAAO,MAAM,IAAI,CAAC,WAAW,CAAC,YAAY,EAAE,KAAK,IAAI,EAAE;QACrD,MAAM,SAAS,GAAG,MAAM,UAAU,CAAC,oBAAoB,EAAE,CAAA;QACzD,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,OAAO,EAAE,GAAG,iBAAiB,CAAC,SAAS,EAAE,GAAG,EAAE,iBAAiB,CAAC,CAAA;QAClF,IAAI,OAAO,EAAE,CAAC;YACZ,wFAAwF;YACxF,qFAAqF;YACrF,wFAAwF;YACxF,oDAAoD;YACpD,MAAM,EAAE,IAAI,CACV,0EAA0E;gBACxE,wCAAwC,EAC1C;gBACE,KAAK,EAAE,WAAW;gBAClB,KAAK,EAAE,YAAY;gBACnB,WAAW,EAAE,OAAO,CAAC,IAAI;gBACzB,SAAS,EAAE,OAAO,CAAC,EAAE;gBACrB,WAAW,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,GAAG,EAAE,GAAG,MAAM,CAAC,CAAC;gBACzE,SAAS;aACV,CACF,CAAA;QACH,CAAC;QACD,OAAO,MAAM,UAAU,CAAC,eAAe,CAAC,IAAI,EAAE,EAAE,CAAC,CAAA;IACnD,CAAC,CAAC,CAAA;AACJ,CAAC"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { AgentKindRegistry } from '@cat-factory/agents';
|
|
2
|
-
import type { BinaryGeneratorRegistry, FoundationalServiceRegistry, GateRegistry, InitiativePresetRegistry, PipelineRegistry, PromptFragmentRegistry, PromptFragmentSource, TaskTypeRegistry } from '@cat-factory/kernel';
|
|
2
|
+
import type { BinaryGeneratorRegistry, DeploymentDocumentResolver, FoundationalServiceRegistry, GateRegistry, InitiativePresetRegistry, PipelineRegistry, PromptFragmentRegistry, PromptFragmentSource, TaskTypeRegistry } from '@cat-factory/kernel';
|
|
3
3
|
/** A single problem found during validation. `error` aborts boot; `warn` is logged only. */
|
|
4
4
|
export interface RegistrationProblem {
|
|
5
5
|
severity: 'error' | 'warn';
|
|
@@ -87,6 +87,15 @@ export interface ValidatedRegistries {
|
|
|
87
87
|
* never arrives.
|
|
88
88
|
*/
|
|
89
89
|
promptFragments?: PromptFragmentSource;
|
|
90
|
+
/**
|
|
91
|
+
* How this deployment reads its OWN documents, or absent when it configured none.
|
|
92
|
+
*
|
|
93
|
+
* What turns the `documentRef` check below from a blanket refusal into a real one: a
|
|
94
|
+
* code-registered fragment may name a living document exactly when the deployment can resolve
|
|
95
|
+
* it, and only this can say whether it can. Named as the CONTAINER names it, like every other
|
|
96
|
+
* member here.
|
|
97
|
+
*/
|
|
98
|
+
deploymentDocumentResolver?: DeploymentDocumentResolver;
|
|
90
99
|
}
|
|
91
100
|
/** Options for {@link collectRegistrationProblems} / {@link validateRegistrations}. */
|
|
92
101
|
export interface ValidateRegistrationsOptions {
|
|
@@ -109,6 +118,30 @@ export interface ValidateRegistrationsOptions {
|
|
|
109
118
|
* (errors still throw).
|
|
110
119
|
*/
|
|
111
120
|
onWarn?: (problem: RegistrationProblem) => void;
|
|
121
|
+
/**
|
|
122
|
+
* Raise a `warn` to an ERROR: return `true` and the problem joins the aggregated boot failure
|
|
123
|
+
* instead of the log.
|
|
124
|
+
*
|
|
125
|
+
* The severities here are set by ONE bar: boot ERRORS on what is fully knowable from a
|
|
126
|
+
* registration and WARNS only where it structurally cannot see the answer (ADR 0040). That bar is
|
|
127
|
+
* about what the PLATFORM can know, and for one warn in particular the DEPLOYMENT knows more.
|
|
128
|
+
* `task_type_unknown_fragment` fires for two causes it cannot separate: a typo in a code-owned id,
|
|
129
|
+
* and an account/workspace-tier id that merges per workspace at run time and is invisible at boot.
|
|
130
|
+
* A deployment whose operations reference only fragments it registers itself knows the second
|
|
131
|
+
* cause cannot apply to it, and for that deployment the warn names a real defect: part of an
|
|
132
|
+
* operation's standing guidance silently never enters a run, and for a `conditionalFragmentIds`
|
|
133
|
+
* entry it goes missing only for the cases matching the condition.
|
|
134
|
+
*
|
|
135
|
+
* So the SEVERITY is platform judgement and the DISPOSITION is deployment policy, which is the
|
|
136
|
+
* split this hook exists to express. It takes the whole problem rather than a list of codes on
|
|
137
|
+
* purpose: a deployment can escalate one code, a prefix, or everything, and a warn added later is
|
|
138
|
+
* covered by a predicate that never mentioned it.
|
|
139
|
+
*
|
|
140
|
+
* Escalated problems are collected and thrown TOGETHER with the genuine errors, so a boot failure
|
|
141
|
+
* still names every problem at once. A predicate that throws is a bug in the predicate and
|
|
142
|
+
* propagates unchanged, rather than being swallowed into a warn about warnings.
|
|
143
|
+
*/
|
|
144
|
+
escalateWarning?: (problem: RegistrationProblem) => boolean;
|
|
112
145
|
}
|
|
113
146
|
/**
|
|
114
147
|
* Collect every registration problem (does not throw). Useful for tests and for callers that
|
|
@@ -119,6 +152,10 @@ export declare function collectRegistrationProblems(opts: ValidateRegistrationsO
|
|
|
119
152
|
* Validate the registered extensions, throwing an aggregated error on any `error`-severity
|
|
120
153
|
* problem and logging `warn`-severity ones. Call once at facade boot, after every `register*`
|
|
121
154
|
* import side effect + provider wiring, before serving requests.
|
|
155
|
+
*
|
|
156
|
+
* A deployment may raise selected warnings to errors with
|
|
157
|
+
* {@link ValidateRegistrationsOptions.escalateWarning}; an escalated problem is thrown with the
|
|
158
|
+
* errors and is NOT also logged, so one problem produces one report.
|
|
122
159
|
*/
|
|
123
160
|
export declare function validateRegistrations(opts: ValidateRegistrationsOptions): void;
|
|
124
161
|
/** Run {@link validateRegistrations} at most once per process. Safe to call from a per-request build. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validateRegistrations.d.ts","sourceRoot":"","sources":["../../src/validation/validateRegistrations.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;AAE5D,OAAO,KAAK,EAEV,uBAAuB,EACvB,2BAA2B,EAC3B,YAAY,EACZ,wBAAwB,EAGxB,gBAAgB,EAChB,sBAAsB,EACtB,oBAAoB,EACpB,gBAAgB,EACjB,MAAM,qBAAqB,CAAA;
|
|
1
|
+
{"version":3,"file":"validateRegistrations.d.ts","sourceRoot":"","sources":["../../src/validation/validateRegistrations.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;AAE5D,OAAO,KAAK,EAEV,uBAAuB,EACvB,0BAA0B,EAC1B,2BAA2B,EAC3B,YAAY,EACZ,wBAAwB,EAGxB,gBAAgB,EAChB,sBAAsB,EACtB,oBAAoB,EACpB,gBAAgB,EACjB,MAAM,qBAAqB,CAAA;AAgE5B,4FAA4F;AAC5F,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,OAAO,GAAG,MAAM,CAAA;IAC1B,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;CAChB;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,mBAAmB;IAClC;;;OAGG;IACH,iBAAiB,EAAE,iBAAiB,CAAA;IACpC;;;;OAIG;IACH,YAAY,EAAE,YAAY,CAAA;IAC1B;;;;;;OAMG;IACH,gBAAgB,CAAC,EAAE,gBAAgB,CAAA;IACnC;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,gBAAgB,CAAA;IACnC;;;;;OAKG;IACH,wBAAwB,CAAC,EAAE,wBAAwB,CAAA;IACnD;;;;;;OAMG;IACH,2BAA2B,CAAC,EAAE,2BAA2B,CAAA;IACzD;;;;;;OAMG;IACH,uBAAuB,CAAC,EAAE,uBAAuB,CAAA;IACjD;;;;;OAKG;IACH,sBAAsB,CAAC,EAAE,sBAAsB,CAAA;IAC/C;;;;;;;;;OASG;IACH,eAAe,CAAC,EAAE,oBAAoB,CAAA;IACtC;;;;;;;OAOG;IACH,0BAA0B,CAAC,EAAE,0BAA0B,CAAA;CACxD;AAED,uFAAuF;AACvF,MAAM,WAAW,4BAA4B;IAC3C,+EAA+E;IAC/E,UAAU,EAAE,mBAAmB,CAAA;IAC/B,qGAAqG;IACrG,kBAAkB,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAA;IACxC,qGAAqG;IACrG,kBAAkB,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAA;IACxC;;;;;OAKG;IACH,eAAe,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAA;IACrC;;;;OAIG;IACH,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,mBAAmB,KAAK,IAAI,CAAA;IAC/C;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACH,eAAe,CAAC,EAAE,CAAC,OAAO,EAAE,mBAAmB,KAAK,OAAO,CAAA;CAC5D;AAED;;;GAGG;AACH,wBAAgB,2BAA2B,CACzC,IAAI,EAAE,4BAA4B,GACjC,mBAAmB,EAAE,CA4FvB;AA+kCD;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,4BAA4B,GAAG,IAAI,CAuB9E;AAOD,yGAAyG;AACzG,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,4BAA4B,GAAG,IAAI,CASlF;AAED,uFAAuF;AACvF,wBAAgB,gCAAgC,IAAI,IAAI,CAEvD"}
|