@cat-factory/orchestration 0.225.0 → 0.228.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 +23 -1
- package/dist/container/dependencies.d.ts.map +1 -1
- package/dist/container/foundation.d.ts.map +1 -1
- package/dist/container/foundation.js +17 -6
- package/dist/container/foundation.js.map +1 -1
- package/dist/container/modules.js +2 -2
- package/dist/container/modules.js.map +1 -1
- package/dist/container/platform-modules.d.ts.map +1 -1
- package/dist/container/platform-modules.js +1 -0
- package/dist/container/platform-modules.js.map +1 -1
- package/dist/container.d.ts +21 -8
- package/dist/container.d.ts.map +1 -1
- package/dist/container.js +4 -1
- 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/board/BoardService.d.ts +22 -9
- package/dist/modules/board/BoardService.d.ts.map +1 -1
- package/dist/modules/board/BoardService.js +42 -106
- package/dist/modules/board/BoardService.js.map +1 -1
- package/dist/modules/board/publicBoardReads.d.ts +3 -3
- package/dist/modules/board/publicBoardReads.d.ts.map +1 -1
- package/dist/modules/board/publicBoardReads.js.map +1 -1
- package/dist/modules/board/reparentWrite.d.ts +43 -0
- package/dist/modules/board/reparentWrite.d.ts.map +1 -0
- package/dist/modules/board/reparentWrite.js +126 -0
- package/dist/modules/board/reparentWrite.js.map +1 -0
- package/dist/modules/board/riskPolicySelectionGuard.d.ts +45 -4
- package/dist/modules/board/riskPolicySelectionGuard.d.ts.map +1 -1
- package/dist/modules/board/riskPolicySelectionGuard.js +84 -20
- package/dist/modules/board/riskPolicySelectionGuard.js.map +1 -1
- package/dist/modules/boardScan/BoardScanService.js +6 -6
- package/dist/modules/boardScan/BoardScanService.js.map +1 -1
- package/dist/modules/execution/ExecutionServiceDependencies.d.ts +2 -1
- package/dist/modules/execution/ExecutionServiceDependencies.d.ts.map +1 -1
- package/dist/modules/execution/MergeResolver.d.ts +3 -3
- package/dist/modules/execution/MergeResolver.d.ts.map +1 -1
- package/dist/modules/execution/MergeResolver.js +76 -34
- package/dist/modules/execution/MergeResolver.js.map +1 -1
- package/dist/modules/execution/PostMergeBoardController.d.ts.map +1 -1
- package/dist/modules/execution/PostMergeBoardController.js +6 -1
- package/dist/modules/execution/PostMergeBoardController.js.map +1 -1
- package/dist/modules/execution/RunMergePolicy.d.ts +3 -2
- package/dist/modules/execution/RunMergePolicy.d.ts.map +1 -1
- package/dist/modules/execution/RunMergePolicy.js +1 -1
- package/dist/modules/execution/RunMergePolicy.js.map +1 -1
- package/dist/modules/execution/StepGraph.d.ts.map +1 -1
- package/dist/modules/execution/StepGraph.js +20 -0
- package/dist/modules/execution/StepGraph.js.map +1 -1
- package/dist/modules/execution/policy-types.d.ts +5 -4
- package/dist/modules/execution/policy-types.d.ts.map +1 -1
- package/dist/modules/merge/RiskPolicyService.d.ts +22 -11
- package/dist/modules/merge/RiskPolicyService.d.ts.map +1 -1
- package/dist/modules/merge/RiskPolicyService.js +27 -48
- package/dist/modules/merge/RiskPolicyService.js.map +1 -1
- package/dist/modules/merge/riskPolicyResolution.d.ts +36 -4
- package/dist/modules/merge/riskPolicyResolution.d.ts.map +1 -1
- package/dist/modules/merge/riskPolicyResolution.js +36 -8
- package/dist/modules/merge/riskPolicyResolution.js.map +1 -1
- package/dist/modules/observability/retentionPass.d.ts +82 -1
- package/dist/modules/observability/retentionPass.d.ts.map +1 -1
- package/dist/modules/observability/retentionPass.js +104 -0
- package/dist/modules/observability/retentionPass.js.map +1 -1
- package/dist/modules/reports/ReportsService.d.ts +29 -6
- package/dist/modules/reports/ReportsService.d.ts.map +1 -1
- package/dist/modules/reports/ReportsService.js +64 -18
- package/dist/modules/reports/ReportsService.js.map +1 -1
- package/dist/modules/reports/reports.logic.d.ts +16 -2
- package/dist/modules/reports/reports.logic.d.ts.map +1 -1
- package/dist/modules/reports/reports.logic.js +26 -5
- package/dist/modules/reports/reports.logic.js.map +1 -1
- package/package.json +11 -11
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RiskPolicyService.js","sourceRoot":"","sources":["../../../src/modules/merge/RiskPolicyService.ts"],"names":[],"mappings":"AAWA,OAAO,EACL,WAAW,EACX,aAAa,EACb,gBAAgB,EAChB,gBAAgB,EAChB,eAAe,GAChB,MAAM,qBAAqB,CAAA;
|
|
1
|
+
{"version":3,"file":"RiskPolicyService.js","sourceRoot":"","sources":["../../../src/modules/merge/RiskPolicyService.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,8 +1,22 @@
|
|
|
1
1
|
import type { GroupCacheHandle, RiskPolicy, RiskPolicyCacheValue } from '@cat-factory/kernel';
|
|
2
2
|
import type { RiskPolicyRepository } from '@cat-factory/kernel';
|
|
3
3
|
import type { ResolvedRunRiskPolicy } from '../execution/policy-types.js';
|
|
4
|
-
/**
|
|
5
|
-
|
|
4
|
+
/**
|
|
5
|
+
* WHICH row a resolution wants: the id the task pinned, or the workspace's default.
|
|
6
|
+
*
|
|
7
|
+
* A discriminated target rather than the cache key string it used to be. The key spelling is one
|
|
8
|
+
* reader's encoding, and picking the id back out of it (`key.slice('picked:'.length)`) is the
|
|
9
|
+
* shape that reads as correct until someone renames a prefix; a second reader that answers off a
|
|
10
|
+
* preloaded library needs the id, not the key.
|
|
11
|
+
*/
|
|
12
|
+
export type RiskPolicyTarget = {
|
|
13
|
+
kind: 'picked';
|
|
14
|
+
id: string;
|
|
15
|
+
} | {
|
|
16
|
+
kind: 'default';
|
|
17
|
+
};
|
|
18
|
+
/** Reads one preset row, possibly through a cache slice or a preloaded library. */
|
|
19
|
+
export type RiskPolicyRead = (target: RiskPolicyTarget, load: () => Promise<RiskPolicy | null>) => Promise<RiskPolicy | null>;
|
|
6
20
|
/** Read straight from the repository, for the paths with no cache slice wired to read through. */
|
|
7
21
|
export declare const directRiskPolicyRead: RiskPolicyRead;
|
|
8
22
|
/**
|
|
@@ -12,12 +26,30 @@ export declare const directRiskPolicyRead: RiskPolicyRead;
|
|
|
12
26
|
* exactly as an uncached read would. That is what the `RiskPolicyCacheValue` wrapper is for.
|
|
13
27
|
*/
|
|
14
28
|
export declare function cachedRiskPolicyRead(cache: GroupCacheHandle<RiskPolicyCacheValue> | undefined, workspaceId: string): RiskPolicyRead;
|
|
29
|
+
/**
|
|
30
|
+
* Answer every resolution in one workspace out of its library, already read in full.
|
|
31
|
+
*
|
|
32
|
+
* For the caller that resolves MANY ids in the same workspace at once (the board's preset guard,
|
|
33
|
+
* judging every block in a moved subtree), where the per-id shape is the banned N+1: one point
|
|
34
|
+
* read per pin plus the workspace default re-read once per pin. A preset library is a handful of
|
|
35
|
+
* rows a workspace admin maintains by hand, so reading it whole is one query whatever the subtree
|
|
36
|
+
* holds, and the workspace default stops being a repeated round trip.
|
|
37
|
+
*
|
|
38
|
+
* `load` is never called: the library IS the answer, and a miss (a pinned id that no longer exists,
|
|
39
|
+
* a workspace with no default seeded) is a real null that falls through to the same place an
|
|
40
|
+
* uncached read's null would, which is {@link FALLBACK_RISK_POLICY}.
|
|
41
|
+
*/
|
|
42
|
+
export declare function preloadedRiskPolicyRead(library: readonly RiskPolicy[]): RiskPolicyRead;
|
|
15
43
|
/**
|
|
16
44
|
* Resolve the preset governing `riskPolicyId` in a workspace.
|
|
17
45
|
*
|
|
18
46
|
* An ABSENT repository is not a hole to guard: with no preset library there is nothing for a task
|
|
19
|
-
* to point at, so every task in the deployment is governed by {@link
|
|
20
|
-
* role layer is empty and therefore holds nobody to anything
|
|
47
|
+
* to point at, so every task in the deployment is governed by {@link FALLBACK_RISK_POLICY}, whose
|
|
48
|
+
* role layer is empty and therefore holds nobody to anything, and which auto-merges nothing, so
|
|
49
|
+
* the deployment that configured no policy lands no PR without a human.
|
|
50
|
+
*
|
|
51
|
+
* A wired repository answers from a library the board was seeded with at CREATION, so reaching
|
|
52
|
+
* the fallback is a deployment-level fact rather than a question of who had read what first.
|
|
21
53
|
*/
|
|
22
54
|
export declare function resolveRiskPolicy(input: {
|
|
23
55
|
repository: RiskPolicyRepository | undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"riskPolicyResolution.d.ts","sourceRoot":"","sources":["../../../src/modules/merge/riskPolicyResolution.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,UAAU,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAA;AAC7F,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAA;AAE/D,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAA;AAkBzE,
|
|
1
|
+
{"version":3,"file":"riskPolicyResolution.d.ts","sourceRoot":"","sources":["../../../src/modules/merge/riskPolicyResolution.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,UAAU,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAA;AAC7F,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAA;AAE/D,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAA;AAkBzE;;;;;;;GAOG;AACH,MAAM,MAAM,gBAAgB,GAAG;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,CAAA;AAEnF,mFAAmF;AACnF,MAAM,MAAM,cAAc,GAAG,CAC3B,MAAM,EAAE,gBAAgB,EACxB,IAAI,EAAE,MAAM,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,KACnC,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAAA;AAE/B,kGAAkG;AAClG,eAAO,MAAM,oBAAoB,EAAE,cAA0C,CAAA;AAO7E;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,gBAAgB,CAAC,oBAAoB,CAAC,GAAG,SAAS,EACzD,WAAW,EAAE,MAAM,GAClB,cAAc,CAKhB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,SAAS,UAAU,EAAE,GAAG,cAAc,CAKtF;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,iBAAiB,CAAC,KAAK,EAAE;IAC7C,UAAU,EAAE,oBAAoB,GAAG,SAAS,CAAA;IAC5C,WAAW,EAAE,MAAM,CAAA;IACnB,YAAY,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAA;IACvC,IAAI,CAAC,EAAE,cAAc,CAAA;CACtB,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAcjC"}
|
|
@@ -1,6 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { FALLBACK_RISK_POLICY } from '@cat-factory/kernel';
|
|
2
2
|
/** Read straight from the repository, for the paths with no cache slice wired to read through. */
|
|
3
|
-
export const directRiskPolicyRead = (
|
|
3
|
+
export const directRiskPolicyRead = (_target, load) => load();
|
|
4
|
+
/** The cache key one target resolves under; the ONE place that spelling lives. */
|
|
5
|
+
function cacheKeyOf(target) {
|
|
6
|
+
return target.kind === 'picked' ? `picked:${target.id}` : 'default';
|
|
7
|
+
}
|
|
4
8
|
/**
|
|
5
9
|
* Read through the `AppCaches.riskPolicy` slice, grouped by workspace (one preset write drops the
|
|
6
10
|
* whole library) and keyed per resolved id, so a task's pick and the workspace default cache
|
|
@@ -10,25 +14,49 @@ export const directRiskPolicyRead = (_key, load) => load();
|
|
|
10
14
|
export function cachedRiskPolicyRead(cache, workspaceId) {
|
|
11
15
|
if (!cache)
|
|
12
16
|
return directRiskPolicyRead;
|
|
13
|
-
return async (
|
|
17
|
+
return async (target, load) => (await cache.get(cacheKeyOf(target), workspaceId, async () => ({ policy: await load() })))
|
|
18
|
+
.policy;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Answer every resolution in one workspace out of its library, already read in full.
|
|
22
|
+
*
|
|
23
|
+
* For the caller that resolves MANY ids in the same workspace at once (the board's preset guard,
|
|
24
|
+
* judging every block in a moved subtree), where the per-id shape is the banned N+1: one point
|
|
25
|
+
* read per pin plus the workspace default re-read once per pin. A preset library is a handful of
|
|
26
|
+
* rows a workspace admin maintains by hand, so reading it whole is one query whatever the subtree
|
|
27
|
+
* holds, and the workspace default stops being a repeated round trip.
|
|
28
|
+
*
|
|
29
|
+
* `load` is never called: the library IS the answer, and a miss (a pinned id that no longer exists,
|
|
30
|
+
* a workspace with no default seeded) is a real null that falls through to the same place an
|
|
31
|
+
* uncached read's null would, which is {@link FALLBACK_RISK_POLICY}.
|
|
32
|
+
*/
|
|
33
|
+
export function preloadedRiskPolicyRead(library) {
|
|
34
|
+
const byId = new Map(library.map((preset) => [preset.id, preset]));
|
|
35
|
+
const workspaceDefault = library.find((preset) => preset.isDefault) ?? null;
|
|
36
|
+
return (target) => Promise.resolve(target.kind === 'picked' ? (byId.get(target.id) ?? null) : workspaceDefault);
|
|
14
37
|
}
|
|
15
38
|
/**
|
|
16
39
|
* Resolve the preset governing `riskPolicyId` in a workspace.
|
|
17
40
|
*
|
|
18
41
|
* An ABSENT repository is not a hole to guard: with no preset library there is nothing for a task
|
|
19
|
-
* to point at, so every task in the deployment is governed by {@link
|
|
20
|
-
* role layer is empty and therefore holds nobody to anything
|
|
42
|
+
* to point at, so every task in the deployment is governed by {@link FALLBACK_RISK_POLICY}, whose
|
|
43
|
+
* role layer is empty and therefore holds nobody to anything, and which auto-merges nothing, so
|
|
44
|
+
* the deployment that configured no policy lands no PR without a human.
|
|
45
|
+
*
|
|
46
|
+
* A wired repository answers from a library the board was seeded with at CREATION, so reaching
|
|
47
|
+
* the fallback is a deployment-level fact rather than a question of who had read what first.
|
|
21
48
|
*/
|
|
22
49
|
export async function resolveRiskPolicy(input) {
|
|
23
50
|
const { repository, workspaceId, riskPolicyId } = input;
|
|
24
51
|
if (!repository)
|
|
25
|
-
return
|
|
52
|
+
return FALLBACK_RISK_POLICY;
|
|
26
53
|
const read = input.read ?? directRiskPolicyRead;
|
|
27
54
|
if (riskPolicyId) {
|
|
28
|
-
const picked = await read(
|
|
55
|
+
const picked = await read({ kind: 'picked', id: riskPolicyId }, () => repository.get(workspaceId, riskPolicyId));
|
|
29
56
|
if (picked)
|
|
30
57
|
return picked;
|
|
31
58
|
}
|
|
32
|
-
return (await read('default', () => repository.getDefault(workspaceId))) ??
|
|
59
|
+
return ((await read({ kind: 'default' }, () => repository.getDefault(workspaceId))) ??
|
|
60
|
+
FALLBACK_RISK_POLICY);
|
|
33
61
|
}
|
|
34
62
|
//# sourceMappingURL=riskPolicyResolution.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"riskPolicyResolution.js","sourceRoot":"","sources":["../../../src/modules/merge/riskPolicyResolution.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"riskPolicyResolution.js","sourceRoot":"","sources":["../../../src/modules/merge/riskPolicyResolution.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAA;AAmC1D,kGAAkG;AAClG,MAAM,CAAC,MAAM,oBAAoB,GAAmB,CAAC,OAAO,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,CAAA;AAE7E,kFAAkF;AAClF,SAAS,UAAU,CAAC,MAAwB;IAC1C,OAAO,MAAM,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,UAAU,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAA;AACrE,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,oBAAoB,CAClC,KAAyD,EACzD,WAAmB;IAEnB,IAAI,CAAC,KAAK;QAAE,OAAO,oBAAoB,CAAA;IACvC,OAAO,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,CAC5B,CAAC,MAAM,KAAK,CAAC,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC;SACvF,MAAM,CAAA;AACb,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,uBAAuB,CAAC,OAA8B;IACpE,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC,CAAC,CAAA;IAClE,MAAM,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,IAAI,CAAA;IAC3E,OAAO,CAAC,MAAM,EAAE,EAAE,CAChB,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAA;AAChG,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,KAKvC;IACC,MAAM,EAAE,UAAU,EAAE,WAAW,EAAE,YAAY,EAAE,GAAG,KAAK,CAAA;IACvD,IAAI,CAAC,UAAU;QAAE,OAAO,oBAAoB,CAAA;IAC5C,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,IAAI,oBAAoB,CAAA;IAC/C,IAAI,YAAY,EAAE,CAAC;QACjB,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,YAAY,EAAE,EAAE,GAAG,EAAE,CACnE,UAAU,CAAC,GAAG,CAAC,WAAW,EAAE,YAAY,CAAC,CAC1C,CAAA;QACD,IAAI,MAAM;YAAE,OAAO,MAAM,CAAA;IAC3B,CAAC;IACD,OAAO,CACL,CAAC,MAAM,IAAI,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,GAAG,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC,CAAC;QAC3E,oBAAoB,CACrB,CAAA;AACH,CAAC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type Logger } from '@cat-factory/kernel';
|
|
1
|
+
import { type Logger, type SpendRollupRepository } from '@cat-factory/kernel';
|
|
2
2
|
/** One pass's isolation state: the per-table runner plus the names it could not prune. */
|
|
3
3
|
export interface RetentionPass {
|
|
4
4
|
/**
|
|
@@ -45,4 +45,85 @@ 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
|
+
/**
|
|
116
|
+
* One sweep's spend-rollup step, shared by both facades: read the watermark, walk the window,
|
|
117
|
+
* materialise it, and NAME any span the catch-up horizon had to give up on.
|
|
118
|
+
*
|
|
119
|
+
* It is one function rather than four lines repeated per facade because the reporting half is
|
|
120
|
+
* the half that goes missing. Materialising is obvious and both facades would write it; the
|
|
121
|
+
* warning is what turns a permanent hole in the durable record from an invisible event into an
|
|
122
|
+
* operator-visible one, and a hole nobody logs is indistinguishable from a quarter nobody
|
|
123
|
+
* spent anything in, which is the exact failure this whole table exists to prevent.
|
|
124
|
+
*
|
|
125
|
+
* Runs INSIDE {@link RetentionPass.materialize}, so a throw here is isolated and named like
|
|
126
|
+
* any other table's, and the ledger prune that follows it in the sweep still runs.
|
|
127
|
+
*/
|
|
128
|
+
export declare function materializeSpendRollup(pass: RetentionPass, repository: Pick<SpendRollupRepository, 'rollupSpendDays' | 'spendRollupWatermark'>, now: number, ledgerRetentionMs: number, logger?: Logger): Promise<number>;
|
|
48
129
|
//# sourceMappingURL=retentionPass.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"retentionPass.d.ts","sourceRoot":"","sources":["../../../src/modules/observability/retentionPass.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,MAAM,EAAiB,MAAM,qBAAqB,CAAA;
|
|
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"}
|
|
@@ -40,4 +40,108 @@ 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
|
+
/**
|
|
113
|
+
* One sweep's spend-rollup step, shared by both facades: read the watermark, walk the window,
|
|
114
|
+
* materialise it, and NAME any span the catch-up horizon had to give up on.
|
|
115
|
+
*
|
|
116
|
+
* It is one function rather than four lines repeated per facade because the reporting half is
|
|
117
|
+
* the half that goes missing. Materialising is obvious and both facades would write it; the
|
|
118
|
+
* warning is what turns a permanent hole in the durable record from an invisible event into an
|
|
119
|
+
* operator-visible one, and a hole nobody logs is indistinguishable from a quarter nobody
|
|
120
|
+
* spent anything in, which is the exact failure this whole table exists to prevent.
|
|
121
|
+
*
|
|
122
|
+
* Runs INSIDE {@link RetentionPass.materialize}, so a throw here is isolated and named like
|
|
123
|
+
* any other table's, and the ledger prune that follows it in the sweep still runs.
|
|
124
|
+
*/
|
|
125
|
+
export async function materializeSpendRollup(pass, repository, now, ledgerRetentionMs, logger) {
|
|
126
|
+
return await pass.materialize('spend_days', async () => {
|
|
127
|
+
const watermark = await repository.spendRollupWatermark();
|
|
128
|
+
const { from, to, skipped } = spendRollupWindow(watermark, now, ledgerRetentionMs);
|
|
129
|
+
if (skipped) {
|
|
130
|
+
// WARN rather than error: the pass itself is healthy and everything from `from` on will
|
|
131
|
+
// be recorded. What is lost is bounded and already gone, so this is the one and only
|
|
132
|
+
// notice it gets. `through_day` is a high-water mark and will advance straight over the
|
|
133
|
+
// hole, so nothing downstream can restate it later.
|
|
134
|
+
logger?.warn('retention: the durable spend rollup skipped days it can no longer fold; ' +
|
|
135
|
+
'that attribution is permanently absent', {
|
|
136
|
+
scope: 'retention',
|
|
137
|
+
table: 'spend_days',
|
|
138
|
+
skippedFrom: skipped.from,
|
|
139
|
+
skippedTo: skipped.to,
|
|
140
|
+
skippedDays: Math.round((skipped.to - skipped.from) / (24 * 60 * 60_000)),
|
|
141
|
+
watermark,
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
return await repository.rollupSpendDays(from, to);
|
|
145
|
+
});
|
|
146
|
+
}
|
|
43
147
|
//# sourceMappingURL=retentionPass.js.map
|
|
@@ -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":"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"}
|
|
@@ -1,7 +1,15 @@
|
|
|
1
1
|
import type { ReportWindow, ReportsView } from '@cat-factory/contracts';
|
|
2
|
-
import type { Clock, ReportsRepository } from '@cat-factory/kernel';
|
|
2
|
+
import type { Clock, ReportsRepository, SpendRollupRepository } from '@cat-factory/kernel';
|
|
3
3
|
export interface ReportsServiceDependencies {
|
|
4
4
|
reportsRepository: ReportsRepository;
|
|
5
|
+
/**
|
|
6
|
+
* The durable cost-attribution rollup, which serves the long windows. Optional so a facade
|
|
7
|
+
* that has not wired it (or a unit test) falls back to the ledger for every window rather
|
|
8
|
+
* than losing the two long ones: the ledger holds ~13 months, so the fallback is accurate
|
|
9
|
+
* until retention reaches it, and the projection still SAYS `ledger` so nothing reads as
|
|
10
|
+
* durable that is not.
|
|
11
|
+
*/
|
|
12
|
+
spendRollupRepository?: SpendRollupRepository;
|
|
5
13
|
clock: Clock;
|
|
6
14
|
/**
|
|
7
15
|
* The deployment's spend currency (the base pricing table's), so the SPA formats every
|
|
@@ -12,20 +20,35 @@ export interface ReportsServiceDependencies {
|
|
|
12
20
|
currency: string;
|
|
13
21
|
}
|
|
14
22
|
/**
|
|
15
|
-
* Cross-cutting usage analytics: composes the rollups behind {@link ReportsRepository}
|
|
16
|
-
* into the Reports view: spend sliced by model, agent kind,
|
|
17
|
-
* spend and run activity sliced by workspace / service /
|
|
18
|
-
* time window.
|
|
19
|
-
* against, answered by a grouped query rather than a
|
|
23
|
+
* Cross-cutting usage analytics: composes the rollups behind {@link ReportsRepository} and
|
|
24
|
+
* {@link SpendRollupRepository} into the Reports view: spend sliced by model, agent kind,
|
|
25
|
+
* repository, tracker ticket and run, spend and run activity sliced by workspace / service /
|
|
26
|
+
* task type, and a spend trend, over a time window. Run, repository and ticket are the TCO
|
|
27
|
+
* axes: what an organisation budgets against, answered by a grouped query rather than a
|
|
28
|
+
* hand-written join against the database.
|
|
20
29
|
*
|
|
21
30
|
* The dual of {@link PlatformObservabilityService}: that answers "is the deployment
|
|
22
31
|
* healthy", this answers "where are the money and the work going". Every breakdown is one
|
|
23
32
|
* SQL GROUP BY, and they are independent aggregates run in parallel — NOT an N+1. The
|
|
24
33
|
* reshaping (totals fold, trend zero-fill) is the pure logic in `reports.logic.ts`.
|
|
34
|
+
*
|
|
35
|
+
* Two stores answer the spend half, routed by window exactly as the operator dashboard routes
|
|
36
|
+
* its own: `24h`/`7d` scan the `token_usage` ledger live, `30d`/`90d` read the durable
|
|
37
|
+
* `spend_days` rollup, which carries each run's board shape frozen at spend time and is never
|
|
38
|
+
* pruned. The projection reports which answered (`source`) and, on the rollup path, how far
|
|
39
|
+
* the sweep has covered (`rolledUpThrough`), because an un-materialised rollup and an idle
|
|
40
|
+
* quarter produce the same empty breakdown and are opposite facts.
|
|
25
41
|
*/
|
|
26
42
|
export declare class ReportsService {
|
|
27
43
|
private readonly deps;
|
|
28
44
|
constructor(deps: ReportsServiceDependencies);
|
|
29
45
|
summarize(accountId: string, window: ReportWindow, workspaceId?: string | null): Promise<ReportsView>;
|
|
46
|
+
/**
|
|
47
|
+
* Bind the window's spend reads to the store that serves them, and report which one that
|
|
48
|
+
* turned out to be. The window PREFERS the rollup on the long windows; an unwired rollup
|
|
49
|
+
* repository degrades to the ledger, and the returned `source` says so rather than
|
|
50
|
+
* labelling ledger numbers as durable ones.
|
|
51
|
+
*/
|
|
52
|
+
private spendSource;
|
|
30
53
|
}
|
|
31
54
|
//# sourceMappingURL=ReportsService.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ReportsService.d.ts","sourceRoot":"","sources":["../../../src/modules/reports/ReportsService.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"ReportsService.d.ts","sourceRoot":"","sources":["../../../src/modules/reports/ReportsService.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAGV,YAAY,EACZ,WAAW,EACZ,MAAM,wBAAwB,CAAA;AAC/B,OAAO,KAAK,EACV,KAAK,EAKL,iBAAiB,EACjB,qBAAqB,EACtB,MAAM,qBAAqB,CAAA;AAsB5B,MAAM,WAAW,0BAA0B;IACzC,iBAAiB,EAAE,iBAAiB,CAAA;IACpC;;;;;;OAMG;IACH,qBAAqB,CAAC,EAAE,qBAAqB,CAAA;IAC7C,KAAK,EAAE,KAAK,CAAA;IACZ;;;;;OAKG;IACH,QAAQ,EAAE,MAAM,CAAA;CACjB;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBAAa,cAAc;IACb,OAAO,CAAC,QAAQ,CAAC,IAAI;IAAjC,YAA6B,IAAI,EAAE,0BAA0B,EAAI;IAE3D,SAAS,CACb,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,YAAY,EACpB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,GAC1B,OAAO,CAAC,WAAW,CAAC,CAsEtB;IAED;;;;;OAKG;IACH,OAAO,CAAC,WAAW;CA6BpB"}
|
|
@@ -1,15 +1,23 @@
|
|
|
1
1
|
import { REPORT_WINDOWS, alignWindowStart, buildSpendTrend, foldTotals, toActivityRow, toSpendRow, } from './reports.logic.js';
|
|
2
2
|
/**
|
|
3
|
-
* Cross-cutting usage analytics: composes the rollups behind {@link ReportsRepository}
|
|
4
|
-
* into the Reports view: spend sliced by model, agent kind,
|
|
5
|
-
* spend and run activity sliced by workspace / service /
|
|
6
|
-
* time window.
|
|
7
|
-
* against, answered by a grouped query rather than a
|
|
3
|
+
* Cross-cutting usage analytics: composes the rollups behind {@link ReportsRepository} and
|
|
4
|
+
* {@link SpendRollupRepository} into the Reports view: spend sliced by model, agent kind,
|
|
5
|
+
* repository, tracker ticket and run, spend and run activity sliced by workspace / service /
|
|
6
|
+
* task type, and a spend trend, over a time window. Run, repository and ticket are the TCO
|
|
7
|
+
* axes: what an organisation budgets against, answered by a grouped query rather than a
|
|
8
|
+
* hand-written join against the database.
|
|
8
9
|
*
|
|
9
10
|
* The dual of {@link PlatformObservabilityService}: that answers "is the deployment
|
|
10
11
|
* healthy", this answers "where are the money and the work going". Every breakdown is one
|
|
11
12
|
* SQL GROUP BY, and they are independent aggregates run in parallel — NOT an N+1. The
|
|
12
13
|
* reshaping (totals fold, trend zero-fill) is the pure logic in `reports.logic.ts`.
|
|
14
|
+
*
|
|
15
|
+
* Two stores answer the spend half, routed by window exactly as the operator dashboard routes
|
|
16
|
+
* its own: `24h`/`7d` scan the `token_usage` ledger live, `30d`/`90d` read the durable
|
|
17
|
+
* `spend_days` rollup, which carries each run's board shape frozen at spend time and is never
|
|
18
|
+
* pruned. The projection reports which answered (`source`) and, on the rollup path, how far
|
|
19
|
+
* the sweep has covered (`rolledUpThrough`), because an un-materialised rollup and an idle
|
|
20
|
+
* quarter produce the same empty breakdown and are opposite facts.
|
|
13
21
|
*/
|
|
14
22
|
export class ReportsService {
|
|
15
23
|
deps;
|
|
@@ -17,27 +25,31 @@ export class ReportsService {
|
|
|
17
25
|
this.deps = deps;
|
|
18
26
|
}
|
|
19
27
|
async summarize(accountId, window, workspaceId) {
|
|
20
|
-
const { windowMs, bucketMs } = REPORT_WINDOWS[window];
|
|
28
|
+
const { windowMs, bucketMs, source: preferred } = REPORT_WINDOWS[window];
|
|
21
29
|
const until = this.deps.clock.now();
|
|
22
30
|
// Snapped to a bucket edge so the trend's leading column is a COMPLETE bucket; every
|
|
23
31
|
// breakdown and the totals aggregate over the same snapped window, so the tiles and the
|
|
24
|
-
// chart can never describe different spans.
|
|
32
|
+
// chart can never describe different spans. It is also what keeps a rollup-backed window
|
|
33
|
+
// on whole UTC days. See `alignWindowStart`.
|
|
25
34
|
const since = alignWindowStart(until, windowMs, bucketMs);
|
|
26
35
|
const scope = { accountId, workspaceId: workspaceId ?? null };
|
|
27
36
|
const range = { since, until };
|
|
28
37
|
const repo = this.deps.reportsRepository;
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
38
|
+
const { source, spend } = this.spendSource(preferred);
|
|
39
|
+
const [byModel, byAgentKind, spendByWorkspace, spendByService, spendByRepo, spendByTaskType, spendByTicket, spendByRun, activityByWorkspace, activityByService, activityByTaskType, trend, rolledUpThrough,] = await Promise.all([
|
|
40
|
+
spend.byDimension(scope, 'model', range),
|
|
41
|
+
spend.byDimension(scope, 'agentKind', range),
|
|
42
|
+
spend.byDimension(scope, 'workspace', range),
|
|
43
|
+
spend.byDimension(scope, 'service', range),
|
|
44
|
+
spend.byDimension(scope, 'repo', range),
|
|
45
|
+
spend.byDimension(scope, 'taskType', range),
|
|
46
|
+
spend.byDimension(scope, 'ticket', range),
|
|
47
|
+
spend.byDimension(scope, 'run', range),
|
|
37
48
|
repo.activityByDimension(scope, 'workspace', range),
|
|
38
49
|
repo.activityByDimension(scope, 'service', range),
|
|
39
50
|
repo.activityByDimension(scope, 'taskType', range),
|
|
40
|
-
|
|
51
|
+
spend.trend(scope, range, bucketMs),
|
|
52
|
+
spend.watermark(),
|
|
41
53
|
]);
|
|
42
54
|
const spendByModel = byModel.map(toSpendRow);
|
|
43
55
|
return {
|
|
@@ -46,8 +58,10 @@ export class ReportsService {
|
|
|
46
58
|
since,
|
|
47
59
|
workspaceId: workspaceId ?? null,
|
|
48
60
|
currency: this.deps.currency,
|
|
49
|
-
|
|
50
|
-
|
|
61
|
+
source,
|
|
62
|
+
rolledUpThrough,
|
|
63
|
+
// Every spend breakdown partitions the same rows, so the totals fold from
|
|
64
|
+
// whichever one is at hand rather than costing another query.
|
|
51
65
|
totals: foldTotals(spendByModel),
|
|
52
66
|
spend: {
|
|
53
67
|
byModel: spendByModel,
|
|
@@ -57,6 +71,7 @@ export class ReportsService {
|
|
|
57
71
|
byRepo: spendByRepo.map(toSpendRow),
|
|
58
72
|
byTaskType: spendByTaskType.map(toSpendRow),
|
|
59
73
|
byTicket: spendByTicket.map(toSpendRow),
|
|
74
|
+
byRun: spendByRun.map(toSpendRow),
|
|
60
75
|
},
|
|
61
76
|
activity: {
|
|
62
77
|
byWorkspace: activityByWorkspace.map(toActivityRow),
|
|
@@ -66,5 +81,36 @@ export class ReportsService {
|
|
|
66
81
|
trend: { bucketMs, points: buildSpendTrend(trend, since, until, bucketMs) },
|
|
67
82
|
};
|
|
68
83
|
}
|
|
84
|
+
/**
|
|
85
|
+
* Bind the window's spend reads to the store that serves them, and report which one that
|
|
86
|
+
* turned out to be. The window PREFERS the rollup on the long windows; an unwired rollup
|
|
87
|
+
* repository degrades to the ledger, and the returned `source` says so rather than
|
|
88
|
+
* labelling ledger numbers as durable ones.
|
|
89
|
+
*/
|
|
90
|
+
spendSource(preferred) {
|
|
91
|
+
const rollup = this.deps.spendRollupRepository;
|
|
92
|
+
if (preferred === 'daily-rollup' && rollup) {
|
|
93
|
+
return {
|
|
94
|
+
source: 'daily-rollup',
|
|
95
|
+
spend: {
|
|
96
|
+
byDimension: (scope, dimension, range) => rollup.spendByDimension(scope, dimension, range),
|
|
97
|
+
trend: (scope, range, bucketMs) => rollup.spendTrend(scope, range, bucketMs),
|
|
98
|
+
watermark: () => rollup.spendRollupWatermark(),
|
|
99
|
+
},
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
const repo = this.deps.reportsRepository;
|
|
103
|
+
return {
|
|
104
|
+
source: 'ledger',
|
|
105
|
+
spend: {
|
|
106
|
+
byDimension: (scope, dimension, range) => repo.spendByDimension(scope, dimension, range),
|
|
107
|
+
trend: (scope, range, bucketMs) => repo.spendTrend(scope, range, bucketMs),
|
|
108
|
+
// Null, not a stale watermark: there is no rollup in this path, so there is nothing
|
|
109
|
+
// about it that could be behind, and reporting one would invite the reader to believe
|
|
110
|
+
// the ledger numbers were bounded by it.
|
|
111
|
+
watermark: () => Promise.resolve(null),
|
|
112
|
+
},
|
|
113
|
+
};
|
|
114
|
+
}
|
|
69
115
|
}
|
|
70
116
|
//# sourceMappingURL=ReportsService.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ReportsService.js","sourceRoot":"","sources":["../../../src/modules/reports/ReportsService.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ReportsService.js","sourceRoot":"","sources":["../../../src/modules/reports/ReportsService.ts"],"names":[],"mappings":"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"}
|