@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.
Files changed (53) hide show
  1. package/dist/container/dependencies.d.ts +26 -1
  2. package/dist/container/dependencies.d.ts.map +1 -1
  3. package/dist/container-content-libraries.d.ts.map +1 -1
  4. package/dist/container-content-libraries.js +5 -0
  5. package/dist/container-content-libraries.js.map +1 -1
  6. package/dist/container.d.ts +11 -1
  7. package/dist/container.d.ts.map +1 -1
  8. package/dist/container.js +1 -0
  9. package/dist/container.js.map +1 -1
  10. package/dist/index.d.ts +1 -1
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js +1 -1
  13. package/dist/index.js.map +1 -1
  14. package/dist/modules/execution/ExecutionService.d.ts +10 -8
  15. package/dist/modules/execution/ExecutionService.d.ts.map +1 -1
  16. package/dist/modules/execution/ExecutionService.js +20 -11
  17. package/dist/modules/execution/ExecutionService.js.map +1 -1
  18. package/dist/modules/execution/PrVerificationReportController.d.ts +35 -39
  19. package/dist/modules/execution/PrVerificationReportController.d.ts.map +1 -1
  20. package/dist/modules/execution/PrVerificationReportController.js +62 -80
  21. package/dist/modules/execution/PrVerificationReportController.js.map +1 -1
  22. package/dist/modules/execution/RunEvidenceLoader.d.ts +79 -0
  23. package/dist/modules/execution/RunEvidenceLoader.d.ts.map +1 -0
  24. package/dist/modules/execution/RunEvidenceLoader.js +114 -0
  25. package/dist/modules/execution/RunEvidenceLoader.js.map +1 -0
  26. package/dist/modules/execution/RunEvidenceReads.d.ts +53 -0
  27. package/dist/modules/execution/RunEvidenceReads.d.ts.map +1 -0
  28. package/dist/modules/execution/RunEvidenceReads.js +57 -0
  29. package/dist/modules/execution/RunEvidenceReads.js.map +1 -0
  30. package/dist/modules/execution/ci.logic.d.ts +8 -2
  31. package/dist/modules/execution/ci.logic.d.ts.map +1 -1
  32. package/dist/modules/execution/ci.logic.js +8 -4
  33. package/dist/modules/execution/ci.logic.js.map +1 -1
  34. package/dist/modules/execution/prReport.logic.d.ts.map +1 -1
  35. package/dist/modules/execution/prReport.logic.js +53 -45
  36. package/dist/modules/execution/prReport.logic.js.map +1 -1
  37. package/dist/modules/execution/prReport.steps.d.ts +4 -0
  38. package/dist/modules/execution/prReport.steps.d.ts.map +1 -1
  39. package/dist/modules/execution/prReport.steps.js +6 -6
  40. package/dist/modules/execution/prReport.steps.js.map +1 -1
  41. package/dist/modules/execution/runOutcome.boundary.d.ts +11 -0
  42. package/dist/modules/execution/runOutcome.boundary.d.ts.map +1 -0
  43. package/dist/modules/execution/runOutcome.boundary.js +163 -0
  44. package/dist/modules/execution/runOutcome.boundary.js.map +1 -0
  45. package/dist/modules/observability/retentionPass.d.ts +0 -67
  46. package/dist/modules/observability/retentionPass.d.ts.map +1 -1
  47. package/dist/modules/observability/retentionPass.js +1 -70
  48. package/dist/modules/observability/retentionPass.js.map +1 -1
  49. package/dist/validation/validateRegistrations.d.ts +38 -1
  50. package/dist/validation/validateRegistrations.d.ts.map +1 -1
  51. package/dist/validation/validateRegistrations.js +76 -38
  52. package/dist/validation/validateRegistrations.js.map +1 -1
  53. 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
- const matching = instance.steps.filter(matches);
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;AAElD,8EAA8E;AAC9E,2FAA2F;AAC3F,EAAE;AACF,6FAA6F;AAC7F,+FAA+F;AAC/F,gGAAgG;AAChG,oCAAoC;AACpC,8EAA8E;AAE9E;;;;;;;;;GASG;AACH,MAAM,UAAU,QAAQ,CACtB,QAA2B,EAC3B,OAAwC,EACxC,WAA4C;IAE5C,MAAM,QAAQ,GAAG,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;IAC/C,KAAK,IAAI,CAAC,GAAG,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QAC9C,IAAI,WAAW,CAAC,QAAQ,CAAC,CAAC,CAAE,CAAC;YAAE,OAAO,QAAQ,CAAC,CAAC,CAAC,CAAA;IACnD,CAAC;IACD,OAAO,QAAQ,CAAC,CAAC,CAAC,CAAA;AACpB,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"}
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":"AAQA,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAEnD,8EAA8E;AAC9E,yEAAyE;AACzE,qCAAqC;AACrC,EAAE;AACF,0FAA0F;AAC1F,8FAA8F;AAC9F,8FAA8F;AAC9F,iGAAiG;AACjG,gGAAgG;AAChG,gGAAgG;AAChG,8FAA8F;AAC9F,+FAA+F;AAC/F,sEAAsE;AACtE,EAAE;AACF,qEAAqE;AACrE,EAAE;AACF,gGAAgG;AAChG,iGAAiG;AACjG,kEAAkE;AAClE,gGAAgG;AAChG,yFAAyF;AACzF,8CAA8C;AAC9C,EAAE;AACF,4FAA4F;AAC5F,+FAA+F;AAC/F,8CAA8C;AAC9C,8EAA8E;AAE9E;;;;;GAKG;AACH,MAAM,cAAc,GAAG,KAAK,CAAA;AAE5B;;;;GAIG;AACH,MAAM,uBAAuB,GAAG,GAAG,CAAA;AAEnC,2FAA2F;AAC3F,MAAM,eAAe,GAAG,GAAG,CAAA;AAE3B,iFAAiF;AACjF,SAAS,IAAI,CAAC,KAAoB;IAChC,MAAM,QAAQ,GAAG,aAAa,CAAC,KAAK,CAAC,IAAI,IAAI,CAAA;IAC7C,IAAI,QAAQ,IAAI,IAAI;QAAE,OAAO,IAAI,CAAA;IACjC,OAAO,QAAQ,CAAC,MAAM,IAAI,cAAc,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,cAAc,GAAG,CAAC,CAAC,GAAG,CAAA;AACnG,CAAC;AAED,0DAA0D;AAC1D,SAAS,QAAQ,CAAC,KAAa;IAC7B,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAA;AAC1B,CAAC;AAED,gGAAgG;AAChG,SAAS,IAAI,CAAC,KAAa,EAAE,IAAY,EAAE,KAAa,EAAE,MAAe;IACvE,OAAO,GAAG,KAAK,aAAa,IAAI,OAAO,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC,KAAK,MAAM,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAA;AAC/E,CAAC;AAED,6CAA6C;AAC7C,SAAS,GAAG,CACV,KAAmB,EACnB,KAAa,EACb,WAAqB,EACrB,GAAW,EACX,MAAe;IAEf,IAAI,KAAK,CAAC,MAAM,IAAI,GAAG;QAAE,OAAO,CAAC,GAAG,KAAK,CAAC,CAAA;IAC1C,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,GAAG,EAAE,KAAK,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;IACxD,OAAO,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAA;AAC5B,CAAC;AAED,SAAS,gBAAgB,CAAC,KAAyB;IACjD,OAAO;QACL,EAAE,EAAE,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QACtB,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC;QACxB,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC;QAC1B,KAAK,EAAE,KAAK,CAAC,KAAK;QAClB,UAAU,EAAE,KAAK,CAAC,UAAU;KAC7B,CAAA;AACH,CAAC;AAED,SAAS,iBAAiB,CACxB,YAAiC,EACjC,WAAqB;IAErB,IAAI,YAAY,CAAC,MAAM,KAAK,QAAQ;QAAE,OAAO,YAAY,CAAA;IACzD,OAAO;QACL,MAAM,EAAE,UAAU;QAClB,IAAI,EAAE,YAAY,CAAC,IAAI;QACvB,GAAG,EAAE,YAAY,CAAC,GAAG;QACrB,MAAM,EAAE,YAAY,CAAC,MAAM;QAC3B,UAAU,EAAE,YAAY,CAAC,UAAU;QACnC,WAAW,EAAE,YAAY,CAAC,WAAW;QACrC,KAAK,EAAE,YAAY,CAAC,KAAK;QACzB,iBAAiB,EAAE,YAAY,CAAC,iBAAiB;QACjD,6FAA6F;QAC7F,6FAA6F;QAC7F,+DAA+D;QAC/D,OAAO,EAAE,GAAG,CACV,YAAY,CAAC,OAAO,EACpB,sBAAsB,EACtB,WAAW,EACX,uBAAuB,EACvB,+DAA+D,CAChE,CAAC,GAAG,CAAC,gBAAgB,CAAC;KACxB,CAAA;AACH,CAAC;AAED,SAAS,YAAY,CAAC,OAAuB;IAC3C,OAAO,EAAE,KAAK,EAAE,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,CAAA;AACvE,CAAC;AAED,SAAS,UAAU,CAAC,KAAmB,EAAE,WAAqB;IAC5D,IAAI,KAAK,CAAC,MAAM,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAA;IAC3C,OAAO;QACL,MAAM,EAAE,UAAU;QAClB,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC;QAC5B,WAAW,EAAE,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC;QACpC,KAAK,EAAE,GAAG,CAAC,KAAK,CAAC,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,eAAe,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC;QAClF,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,QAAQ,EAAE,GAAG,CAAC,KAAK,CAAC,QAAQ,EAAE,gBAAgB,EAAE,WAAW,EAAE,eAAe,CAAC,CAAC,GAAG,CAAC,YAAY,CAAC;QAC/F,uFAAuF;QACvF,WAAW,EAAE,KAAK,CAAC,WAAW;KAC/B,CAAA;AACH,CAAC;AAED,SAAS,YAAY,CAAC,OAAuB;IAC3C,IAAI,OAAO,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;QAChC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAA;IAC7E,CAAC;IACD,OAAO;QACL,MAAM,EAAE,UAAU;QAClB,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,4EAA4E;QAC5E,KAAK,EAAE,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;YAClC,IAAI,EAAE,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC;YACzB,UAAU,EAAE,IAAI,CAAC,UAAU;YAC3B,mBAAmB,EAAE,IAAI,CAAC,mBAAmB;SAC9C,CAAC,CAAC;KACJ,CAAA;AACH,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,kBAAkB,CAAC,OAAmB;IACpD,MAAM,WAAW,GAAa,CAAC,GAAG,OAAO,CAAC,WAAW,CAAC,CAAA;IACtD,OAAO;QACL,OAAO,EAAE,OAAO,CAAC,OAAO;QACxB,WAAW,EAAE,OAAO,CAAC,WAAW;QAChC,KAAK,EAAE,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC;QAC9B,GAAG,EAAE,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC;QACtB,YAAY,EAAE,OAAO,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;YAC9C,GAAG,EAAE,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC;YACrB,MAAM,EAAE,EAAE,CAAC,MAAM;YACjB,MAAM,EAAE,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC;YACvB,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC;SACpB,CAAC,CAAC;QACH,YAAY,EAAE,iBAAiB,CAAC,OAAO,CAAC,YAAY,EAAE,WAAW,CAAC;QAClE,KAAK,EAAE,UAAU,CAAC,OAAO,CAAC,KAAK,EAAE,WAAW,CAAC;QAC7C,OAAO,EAAE,YAAY,CAAC,OAAO,CAAC,OAAO,CAAC;QACtC,4FAA4F;QAC5F,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;YACrC,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,KAAK,EAAE,KAAK,CAAC,KAAK;YAClB,YAAY,EAAE,KAAK,CAAC,YAAY;SACjC,CAAC,CAAC;QACH,WAAW;KACZ,CAAA;AACH,CAAC"}
@@ -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,EAAE,KAAK,MAAM,EAAE,KAAK,qBAAqB,EAAiB,MAAM,qBAAqB,CAAA;AAiB5F,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,sFAAsF;AACtF,eAAO,MAAM,4BAA4B,QAAuB,CAAA;AAEhE;;;;;;GAMG;AACH,eAAO,MAAM,4BAA4B,QAAwB,CAAA;AAEjE;;;;;;;;;GASG;AACH,eAAO,MAAM,4BAA4B,QAAwB,CAAA;AAEjE,wFAAwF;AACxF,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAA;IACZ,EAAE,EAAE,MAAM,CAAA;IACV;;;;;;OAMG;IACH,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAA;CAC7C;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAgB,iBAAiB,CAC/B,UAAU,EAAE,MAAM,GAAG,IAAI,EACzB,GAAG,EAAE,MAAM,EACX,iBAAiB,EAAE,MAAM,GACxB,iBAAiB,CAmBnB;AAED;;;;;;;;;;;;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
+ {"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":"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"}
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;AA+D5B,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;CACvC;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;CAChD;AAED;;;GAGG;AACH,wBAAgB,2BAA2B,CACzC,IAAI,EAAE,4BAA4B,GACjC,mBAAmB,EAAE,CA4FvB;AA6jCD;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,4BAA4B,GAAG,IAAI,CAY9E;AAOD,yGAAyG;AACzG,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,4BAA4B,GAAG,IAAI,CASlF;AAED,uFAAuF;AACvF,wBAAgB,gCAAgC,IAAI,IAAI,CAEvD"}
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"}