@cat-factory/orchestration 0.239.0 → 0.241.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 (104) hide show
  1. package/dist/container/dependencies.d.ts +24 -1
  2. package/dist/container/dependencies.d.ts.map +1 -1
  3. package/dist/container/module-shapes.d.ts +8 -0
  4. package/dist/container/module-shapes.d.ts.map +1 -1
  5. package/dist/container/modules.d.ts.map +1 -1
  6. package/dist/container/modules.js +9 -2
  7. package/dist/container/modules.js.map +1 -1
  8. package/dist/container/runtime.d.ts +1 -0
  9. package/dist/container/runtime.d.ts.map +1 -1
  10. package/dist/container/runtime.js +7 -1
  11. package/dist/container/runtime.js.map +1 -1
  12. package/dist/container.d.ts +9 -1
  13. package/dist/container.d.ts.map +1 -1
  14. package/dist/container.js +2 -1
  15. package/dist/container.js.map +1 -1
  16. package/dist/index.d.ts +1 -0
  17. package/dist/index.d.ts.map +1 -1
  18. package/dist/index.js +4 -0
  19. package/dist/index.js.map +1 -1
  20. package/dist/modules/artifacts/artifactRetention.d.ts +11 -4
  21. package/dist/modules/artifacts/artifactRetention.d.ts.map +1 -1
  22. package/dist/modules/artifacts/artifactRetention.js +11 -4
  23. package/dist/modules/artifacts/artifactRetention.js.map +1 -1
  24. package/dist/modules/execution/AgentDispatchController.d.ts.map +1 -1
  25. package/dist/modules/execution/AgentDispatchController.js +11 -17
  26. package/dist/modules/execution/AgentDispatchController.js.map +1 -1
  27. package/dist/modules/execution/CompanionController.d.ts.map +1 -1
  28. package/dist/modules/execution/CompanionController.js +5 -22
  29. package/dist/modules/execution/CompanionController.js.map +1 -1
  30. package/dist/modules/execution/DeployerStepController.d.ts.map +1 -1
  31. package/dist/modules/execution/DeployerStepController.js +2 -4
  32. package/dist/modules/execution/DeployerStepController.js.map +1 -1
  33. package/dist/modules/execution/ExecutionService.d.ts.map +1 -1
  34. package/dist/modules/execution/ExecutionService.js +2 -1
  35. package/dist/modules/execution/ExecutionService.js.map +1 -1
  36. package/dist/modules/execution/FollowUpGateController.js +3 -3
  37. package/dist/modules/execution/FollowUpGateController.js.map +1 -1
  38. package/dist/modules/execution/ForkDecisionController.d.ts.map +1 -1
  39. package/dist/modules/execution/ForkDecisionController.js +1 -2
  40. package/dist/modules/execution/ForkDecisionController.js.map +1 -1
  41. package/dist/modules/execution/GateHelperDispatcher.d.ts.map +1 -1
  42. package/dist/modules/execution/GateHelperDispatcher.js +1 -2
  43. package/dist/modules/execution/GateHelperDispatcher.js.map +1 -1
  44. package/dist/modules/execution/GateStepController.d.ts.map +1 -1
  45. package/dist/modules/execution/GateStepController.js +1 -2
  46. package/dist/modules/execution/GateStepController.js.map +1 -1
  47. package/dist/modules/execution/HumanTestController.d.ts.map +1 -1
  48. package/dist/modules/execution/HumanTestController.js +7 -32
  49. package/dist/modules/execution/HumanTestController.js.map +1 -1
  50. package/dist/modules/execution/InterviewGateController.d.ts.map +1 -1
  51. package/dist/modules/execution/InterviewGateController.js +2 -21
  52. package/dist/modules/execution/InterviewGateController.js.map +1 -1
  53. package/dist/modules/execution/JudgeStepController.d.ts.map +1 -1
  54. package/dist/modules/execution/JudgeStepController.js +1 -2
  55. package/dist/modules/execution/JudgeStepController.js.map +1 -1
  56. package/dist/modules/execution/OneShotStepController.d.ts.map +1 -1
  57. package/dist/modules/execution/OneShotStepController.js +1 -2
  58. package/dist/modules/execution/OneShotStepController.js.map +1 -1
  59. package/dist/modules/execution/PollRunningController.d.ts.map +1 -1
  60. package/dist/modules/execution/PollRunningController.js +2 -4
  61. package/dist/modules/execution/PollRunningController.js.map +1 -1
  62. package/dist/modules/execution/RalphController.d.ts.map +1 -1
  63. package/dist/modules/execution/RalphController.js +5 -9
  64. package/dist/modules/execution/RalphController.js.map +1 -1
  65. package/dist/modules/execution/ReviewGateController.d.ts.map +1 -1
  66. package/dist/modules/execution/ReviewGateController.js +2 -20
  67. package/dist/modules/execution/ReviewGateController.js.map +1 -1
  68. package/dist/modules/execution/RunDispatcher.d.ts.map +1 -1
  69. package/dist/modules/execution/RunDispatcher.js +11 -54
  70. package/dist/modules/execution/RunDispatcher.js.map +1 -1
  71. package/dist/modules/execution/RunStateMachine.d.ts +49 -0
  72. package/dist/modules/execution/RunStateMachine.d.ts.map +1 -1
  73. package/dist/modules/execution/RunStateMachine.js +84 -0
  74. package/dist/modules/execution/RunStateMachine.js.map +1 -1
  75. package/dist/modules/execution/TesterController.d.ts.map +1 -1
  76. package/dist/modules/execution/TesterController.js +9 -21
  77. package/dist/modules/execution/TesterController.js.map +1 -1
  78. package/dist/modules/execution/VisualConfirmationController.d.ts +20 -4
  79. package/dist/modules/execution/VisualConfirmationController.d.ts.map +1 -1
  80. package/dist/modules/execution/VisualConfirmationController.js +83 -45
  81. package/dist/modules/execution/VisualConfirmationController.js.map +1 -1
  82. package/dist/modules/execution/gate-window-controllers.d.ts +2 -0
  83. package/dist/modules/execution/gate-window-controllers.d.ts.map +1 -1
  84. package/dist/modules/execution/gate-window-controllers.js +2 -1
  85. package/dist/modules/execution/gate-window-controllers.js.map +1 -1
  86. package/dist/modules/execution/step-fold.logic.d.ts +24 -0
  87. package/dist/modules/execution/step-fold.logic.d.ts.map +1 -1
  88. package/dist/modules/execution/step-fold.logic.js +29 -0
  89. package/dist/modules/execution/step-fold.logic.js.map +1 -1
  90. package/dist/modules/execution/stepPreamble.d.ts.map +1 -1
  91. package/dist/modules/execution/stepPreamble.js +2 -4
  92. package/dist/modules/execution/stepPreamble.js.map +1 -1
  93. package/dist/modules/execution/visual-confirm-design-references.d.ts +85 -0
  94. package/dist/modules/execution/visual-confirm-design-references.d.ts.map +1 -0
  95. package/dist/modules/execution/visual-confirm-design-references.js +229 -0
  96. package/dist/modules/execution/visual-confirm-design-references.js.map +1 -0
  97. package/dist/modules/notifications/NotificationService.d.ts.map +1 -1
  98. package/dist/modules/notifications/NotificationService.js +15 -9
  99. package/dist/modules/notifications/NotificationService.js.map +1 -1
  100. package/dist/modules/notifications/NotificationSettingsService.d.ts +28 -0
  101. package/dist/modules/notifications/NotificationSettingsService.d.ts.map +1 -0
  102. package/dist/modules/notifications/NotificationSettingsService.js +50 -0
  103. package/dist/modules/notifications/NotificationSettingsService.js.map +1 -0
  104. package/package.json +11 -11
@@ -0,0 +1,85 @@
1
+ import type { BinaryArtifactRecord, BinaryArtifactStore, DocumentRecord, DocumentRepository } from '@cat-factory/kernel';
2
+ import type { DocumentRenderStatus, VisualConfirmDesignGapReason, VisualConfirmDesignReferences } from '@cat-factory/contracts';
3
+ /**
4
+ * How many design-rendered views one gallery may carry, across every design a task links.
5
+ *
6
+ * A per-document render cap already bounds each design (Figma rasterises the first frames of a
7
+ * file, not all of them), and this bounds their SUM: a task linking four designs would otherwise
8
+ * push a couple of captured screenshots off the bottom of a page of mocks nobody asked to review
9
+ * here. Whatever it excludes is COUNTED and stated, never quietly trimmed.
10
+ */
11
+ export declare const MAX_DESIGN_REFERENCE_VIEWS = 12;
12
+ /** One design-rendered frame, keyed by the view name it pairs on. */
13
+ export interface DesignReference {
14
+ view: string;
15
+ artifactId: string;
16
+ }
17
+ /** The fold's product: what to show, and what to say about what is missing. */
18
+ export interface DesignReferenceFold {
19
+ references: DesignReference[];
20
+ summary: VisualConfirmDesignReferences;
21
+ }
22
+ /** The document fields the fold reads; a `DocumentRecord` structurally satisfies it. */
23
+ export interface DesignDocumentSummary {
24
+ source: DocumentRecord['source'];
25
+ externalId: string;
26
+ title: string;
27
+ renderStatus: DocumentRenderStatus | null;
28
+ }
29
+ /**
30
+ * Why a linked design contributed less than its whole set of frames, or null when it contributed
31
+ * everything it has.
32
+ *
33
+ * Reads the stored `renderStatus` AND what the artifact store actually holds, because the two can
34
+ * disagree in the one direction that matters: a row CLAIMING retention over an empty shelf (an
35
+ * account that re-pointed its blob backend, a reclaim that outran its re-import) would otherwise
36
+ * describe a gallery that is not there. `partial` is such a claim just as `stored` is, and left to
37
+ * speak for itself it tells the reviewer "only part of its frames were retained" above nothing at
38
+ * all, which reads as a design that is merely short rather than one that is absent, and sends them
39
+ * looking for the frames that did survive.
40
+ *
41
+ * So the two claiming statuses are checked against what is held, and the three that already say
42
+ * nothing was kept (`failed` / `none` / `storage_unavailable`) stand as they are: each names a
43
+ * DIFFERENT cause of the same empty shelf, and collapsing them would throw the cause away.
44
+ */
45
+ export declare function designGapReason(renderStatus: DocumentRenderStatus | null, heldImages: number): VisualConfirmDesignGapReason | null;
46
+ /**
47
+ * Fold a task's design documents and their retained renders into the gate's reference set.
48
+ *
49
+ * Four rules, each of which the obvious shape gets wrong:
50
+ *
51
+ * A view name claimed by TWO designs is qualified with its design's label on BOTH sides, never
52
+ * just the second. This is the same rule slice 1 applied to a frame name repeated across pages
53
+ * within one file: leaving the first occurrence bare hands the plain name to whichever document
54
+ * happened to be read first, so re-ordering the links would silently re-point a reviewed view at
55
+ * a different screen. The cost is that neither qualified name matches a screenshot captured as
56
+ * plain "Checkout", which is correct: nothing knows which of two designs that capture is of.
57
+ *
58
+ * Within ONE design, the NEWEST render for a view wins. The artifact reads are ordered oldest
59
+ * first, so a later assignment overriding an earlier one is the rule, not an accident.
60
+ *
61
+ * The cap counts VIEWS, not artifacts, and is applied after the per-view reduction: capping the
62
+ * raw rows first would spend the budget on frames a later revision had already replaced. It is
63
+ * SHARED across the linked designs rather than consumed in read order (see {@link allocate}), and
64
+ * what it cuts is named per design, not just totalled.
65
+ *
66
+ * Emission stays in document order with each design's own frames contiguous: the allocation
67
+ * decides how many slots each design gets, never how the gallery reads.
68
+ */
69
+ export declare function foldDesignReferences(documents: readonly DesignDocumentSummary[], artifacts: readonly BinaryArtifactRecord[], cap?: number): DesignReferenceFold;
70
+ /**
71
+ * Read the task's linked DESIGN documents and their retained renders, then fold them.
72
+ *
73
+ * Returns null when the task links no design at all, which is a different fact from a design that
74
+ * gave nothing: the first has nothing to state and the second is exactly what the summary exists
75
+ * to say. Two reads regardless of how many designs are attached (the batched
76
+ * {@link BinaryArtifactStore.listByDocuments}), because this runs on the driver path of every run
77
+ * whose pipeline carries the gate.
78
+ *
79
+ * The documents are read LIVE at gather time rather than off the run's recorded context, for the
80
+ * same reason the hand-uploaded references are: `recapture` exists so a person can attach a
81
+ * missing reference mid-review and see it, and a design linked while the gate is parked is that
82
+ * same act.
83
+ */
84
+ export declare function resolveDesignReferences(documentRepository: DocumentRepository | undefined, store: BinaryArtifactStore | null, workspaceId: string, blockId: string): Promise<DesignReferenceFold | null>;
85
+ //# sourceMappingURL=visual-confirm-design-references.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"visual-confirm-design-references.d.ts","sourceRoot":"","sources":["../../../src/modules/execution/visual-confirm-design-references.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,oBAAoB,EACpB,mBAAmB,EAEnB,cAAc,EACd,kBAAkB,EACnB,MAAM,qBAAqB,CAAA;AAC5B,OAAO,KAAK,EACV,oBAAoB,EAEpB,4BAA4B,EAC5B,6BAA6B,EAC9B,MAAM,wBAAwB,CAAA;AAc/B;;;;;;;GAOG;AACH,eAAO,MAAM,0BAA0B,KAAK,CAAA;AAE5C,qEAAqE;AACrE,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAA;IACZ,UAAU,EAAE,MAAM,CAAA;CACnB;AAED,+EAA+E;AAC/E,MAAM,WAAW,mBAAmB;IAClC,UAAU,EAAE,eAAe,EAAE,CAAA;IAC7B,OAAO,EAAE,6BAA6B,CAAA;CACvC;AAED,wFAAwF;AACxF,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,cAAc,CAAC,QAAQ,CAAC,CAAA;IAChC,UAAU,EAAE,MAAM,CAAA;IAClB,KAAK,EAAE,MAAM,CAAA;IACb,YAAY,EAAE,oBAAoB,GAAG,IAAI,CAAA;CAC1C;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,eAAe,CAC7B,YAAY,EAAE,oBAAoB,GAAG,IAAI,EACzC,UAAU,EAAE,MAAM,GACjB,4BAA4B,GAAG,IAAI,CAoBrC;AAiED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,SAAS,qBAAqB,EAAE,EAC3C,SAAS,EAAE,SAAS,oBAAoB,EAAE,EAC1C,GAAG,SAA6B,GAC/B,mBAAmB,CAmErB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,uBAAuB,CAC3C,kBAAkB,EAAE,kBAAkB,GAAG,SAAS,EAClD,KAAK,EAAE,mBAAmB,GAAG,IAAI,EACjC,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,mBAAmB,GAAG,IAAI,CAAC,CAiBrC"}
@@ -0,0 +1,229 @@
1
+ import { isDesignSource } from '@cat-factory/contracts';
2
+ // ---------------------------------------------------------------------------
3
+ // The visual-confirmation gate's DESIGN-ORIGIN reference half: the rendered frames an import
4
+ // retained for the designs a task links, folded into the gate's gallery beside the images a
5
+ // person uploaded by hand.
6
+ //
7
+ // Its own module rather than more methods on `VisualConfirmationController` because the fold is
8
+ // pure and the interesting part: which frame wins a view, what a name collision across two
9
+ // designs means, and which of five ways a design can contribute nothing the reviewer is looking
10
+ // at. The controller keeps the one impure step (two reads) and hands the rest here.
11
+ // ---------------------------------------------------------------------------
12
+ /**
13
+ * How many design-rendered views one gallery may carry, across every design a task links.
14
+ *
15
+ * A per-document render cap already bounds each design (Figma rasterises the first frames of a
16
+ * file, not all of them), and this bounds their SUM: a task linking four designs would otherwise
17
+ * push a couple of captured screenshots off the bottom of a page of mocks nobody asked to review
18
+ * here. Whatever it excludes is COUNTED and stated, never quietly trimmed.
19
+ */
20
+ export const MAX_DESIGN_REFERENCE_VIEWS = 12;
21
+ /**
22
+ * Why a linked design contributed less than its whole set of frames, or null when it contributed
23
+ * everything it has.
24
+ *
25
+ * Reads the stored `renderStatus` AND what the artifact store actually holds, because the two can
26
+ * disagree in the one direction that matters: a row CLAIMING retention over an empty shelf (an
27
+ * account that re-pointed its blob backend, a reclaim that outran its re-import) would otherwise
28
+ * describe a gallery that is not there. `partial` is such a claim just as `stored` is, and left to
29
+ * speak for itself it tells the reviewer "only part of its frames were retained" above nothing at
30
+ * all, which reads as a design that is merely short rather than one that is absent, and sends them
31
+ * looking for the frames that did survive.
32
+ *
33
+ * So the two claiming statuses are checked against what is held, and the three that already say
34
+ * nothing was kept (`failed` / `none` / `storage_unavailable`) stand as they are: each names a
35
+ * DIFFERENT cause of the same empty shelf, and collapsing them would throw the cause away.
36
+ */
37
+ export function designGapReason(renderStatus, heldImages) {
38
+ switch (renderStatus) {
39
+ case 'stored':
40
+ return heldImages > 0 ? null : 'not_retained';
41
+ case 'partial':
42
+ return heldImages > 0 ? 'partial' : 'not_retained';
43
+ case 'failed':
44
+ return 'failed';
45
+ case 'none':
46
+ return 'none';
47
+ case 'storage_unavailable':
48
+ return 'storage_unavailable';
49
+ case null:
50
+ // No render outcome was ever recorded for this document. Two causes the gate cannot tell
51
+ // apart (a source that rasterises nothing, a document imported before renders were kept),
52
+ // and one answer covers both honestly; a re-import is what distinguishes them.
53
+ return heldImages > 0 ? null : 'not_retained';
54
+ default:
55
+ return exhaustiveRenderStatus(renderStatus);
56
+ }
57
+ }
58
+ /**
59
+ * The compile-time totality guard: a new {@link DocumentRenderStatus} member fails the build here
60
+ * rather than silently becoming "this design is complete".
61
+ */
62
+ function exhaustiveRenderStatus(status) {
63
+ void status;
64
+ return 'not_retained';
65
+ }
66
+ /** The stable key both sides of the join use: a document's own source identity. */
67
+ function documentKey(ref) {
68
+ return `${ref.source}::${ref.externalId}`;
69
+ }
70
+ /**
71
+ * A per-document display label that is UNIQUE within this fold, used to qualify a view name two
72
+ * designs both claim. Titles alone are not unique (two boards can import files named "Checkout
73
+ * flow"), so a shared title falls back to carrying the source id.
74
+ */
75
+ function documentLabels(documents) {
76
+ const byTitle = new Map();
77
+ for (const document of documents) {
78
+ byTitle.set(document.title, (byTitle.get(document.title) ?? 0) + 1);
79
+ }
80
+ const labels = new Map();
81
+ for (const document of documents) {
82
+ const shared = (byTitle.get(document.title) ?? 0) > 1;
83
+ labels.set(documentKey(document), shared ? `${document.title} ${document.externalId}` : document.title);
84
+ }
85
+ return labels;
86
+ }
87
+ /**
88
+ * Share a bounded budget of gallery slots across the designs competing for it, one slot at a time
89
+ * in turn, and answer how many each may take.
90
+ *
91
+ * The budget is shared, so how it is SPLIT is a decision, and taking the first `cap` views in read
92
+ * order is the one shape that answers it worst: reads come back oldest-first, so the design linked
93
+ * longest ago fills the gallery and a design linked this morning contributes nothing, its absence
94
+ * indistinguishable to the reviewer from a design with no frames. Round-robin instead: every
95
+ * design is represented before any design gets a second slot, a design with fewer frames than its
96
+ * share leaves the rest to the others, and the split does not move when the links are re-ordered.
97
+ */
98
+ function allocate(counts, cap) {
99
+ const taken = counts.map(() => 0);
100
+ let remaining = Math.max(0, cap);
101
+ for (let round = 0; remaining > 0; round += 1) {
102
+ let servedThisRound = false;
103
+ for (let i = 0; i < counts.length && remaining > 0; i += 1) {
104
+ if (round >= counts[i])
105
+ continue;
106
+ taken[i] += 1;
107
+ remaining -= 1;
108
+ servedThisRound = true;
109
+ }
110
+ // Nobody had a frame left at this depth, so nobody will at any greater one.
111
+ if (!servedThisRound)
112
+ break;
113
+ }
114
+ return taken;
115
+ }
116
+ /**
117
+ * Fold a task's design documents and their retained renders into the gate's reference set.
118
+ *
119
+ * Four rules, each of which the obvious shape gets wrong:
120
+ *
121
+ * A view name claimed by TWO designs is qualified with its design's label on BOTH sides, never
122
+ * just the second. This is the same rule slice 1 applied to a frame name repeated across pages
123
+ * within one file: leaving the first occurrence bare hands the plain name to whichever document
124
+ * happened to be read first, so re-ordering the links would silently re-point a reviewed view at
125
+ * a different screen. The cost is that neither qualified name matches a screenshot captured as
126
+ * plain "Checkout", which is correct: nothing knows which of two designs that capture is of.
127
+ *
128
+ * Within ONE design, the NEWEST render for a view wins. The artifact reads are ordered oldest
129
+ * first, so a later assignment overriding an earlier one is the rule, not an accident.
130
+ *
131
+ * The cap counts VIEWS, not artifacts, and is applied after the per-view reduction: capping the
132
+ * raw rows first would spend the budget on frames a later revision had already replaced. It is
133
+ * SHARED across the linked designs rather than consumed in read order (see {@link allocate}), and
134
+ * what it cuts is named per design, not just totalled.
135
+ *
136
+ * Emission stays in document order with each design's own frames contiguous: the allocation
137
+ * decides how many slots each design gets, never how the gallery reads.
138
+ */
139
+ export function foldDesignReferences(documents, artifacts, cap = MAX_DESIGN_REFERENCE_VIEWS) {
140
+ // One entry per document IDENTITY, in first-linked order. A repeated link is one design: counted
141
+ // twice it would take two shares of the budget, state its gap twice, and make its own title look
142
+ // shared to the qualifier below, which would then qualify every one of its views against itself.
143
+ const known = new Map(documents.map((document) => [documentKey(document), document]));
144
+ const unique = [...known.values()];
145
+ const renders = artifacts.filter((record) => record.kind === 'reference' && record.document && known.has(documentKey(record.document)));
146
+ // Which documents claim each raw view name: the collision test the qualification below runs on.
147
+ const claimants = new Map();
148
+ for (const record of renders) {
149
+ const view = record.view;
150
+ if (!view)
151
+ continue;
152
+ const key = documentKey(record.document);
153
+ const held = claimants.get(view);
154
+ if (held)
155
+ held.add(key);
156
+ else
157
+ claimants.set(view, new Set([key]));
158
+ }
159
+ const labels = documentLabels(unique);
160
+ const byDocument = new Map(unique.map((document) => [documentKey(document), new Map()]));
161
+ const heldPerDocument = new Map();
162
+ for (const record of renders) {
163
+ // A render with no view has no pairing key, so it can only ever be shown against nothing.
164
+ // Counted for its document (it IS retained) but not rendered as a pair.
165
+ const key = documentKey(record.document);
166
+ heldPerDocument.set(key, (heldPerDocument.get(key) ?? 0) + 1);
167
+ if (!record.view)
168
+ continue;
169
+ const contested = (claimants.get(record.view)?.size ?? 0) > 1;
170
+ const view = contested ? `${record.view} (${labels.get(key) ?? key})` : record.view;
171
+ byDocument.get(key).set(view, record.id);
172
+ }
173
+ const offered = unique.map((document) => [...byDocument.get(documentKey(document)).entries()]);
174
+ const taken = allocate(offered.map((views) => views.length), cap);
175
+ const references = offered.flatMap((views, index) => views.slice(0, taken[index]).map(([view, artifactId]) => ({ view, artifactId })));
176
+ const gaps = [];
177
+ let dropped = 0;
178
+ unique.forEach((document, index) => {
179
+ const cut = offered[index].length - taken[index];
180
+ dropped += cut;
181
+ const reason = designGapReason(document.renderStatus, heldPerDocument.get(documentKey(document)) ?? 0);
182
+ // The two ways a design falls short are independent, so one entry carries both: a design can
183
+ // be short at its source, short at the gallery ceiling, or both at once.
184
+ if (reason || cut > 0) {
185
+ gaps.push({ title: document.title, reason, ...(cut > 0 ? { dropped: cut } : {}) });
186
+ }
187
+ });
188
+ return {
189
+ references,
190
+ summary: {
191
+ documents: unique.length,
192
+ images: references.length,
193
+ ...(dropped > 0 ? { dropped } : {}),
194
+ ...(gaps.length ? { gaps } : {}),
195
+ },
196
+ };
197
+ }
198
+ /**
199
+ * Read the task's linked DESIGN documents and their retained renders, then fold them.
200
+ *
201
+ * Returns null when the task links no design at all, which is a different fact from a design that
202
+ * gave nothing: the first has nothing to state and the second is exactly what the summary exists
203
+ * to say. Two reads regardless of how many designs are attached (the batched
204
+ * {@link BinaryArtifactStore.listByDocuments}), because this runs on the driver path of every run
205
+ * whose pipeline carries the gate.
206
+ *
207
+ * The documents are read LIVE at gather time rather than off the run's recorded context, for the
208
+ * same reason the hand-uploaded references are: `recapture` exists so a person can attach a
209
+ * missing reference mid-review and see it, and a design linked while the gate is parked is that
210
+ * same act.
211
+ */
212
+ export async function resolveDesignReferences(documentRepository, store, workspaceId, blockId) {
213
+ if (!documentRepository || !store)
214
+ return null;
215
+ const linked = await documentRepository.listByBlock(workspaceId, blockId);
216
+ const designs = linked
217
+ .filter((document) => isDesignSource(document.source))
218
+ .map((document) => ({
219
+ source: document.source,
220
+ externalId: document.externalId,
221
+ title: document.title,
222
+ renderStatus: document.renderStatus,
223
+ }));
224
+ if (!designs.length)
225
+ return null;
226
+ const artifacts = await store.listByDocuments(workspaceId, designs.map((document) => ({ source: document.source, externalId: document.externalId })));
227
+ return foldDesignReferences(designs, artifacts);
228
+ }
229
+ //# sourceMappingURL=visual-confirm-design-references.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"visual-confirm-design-references.js","sourceRoot":"","sources":["../../../src/modules/execution/visual-confirm-design-references.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"NotificationService.d.ts","sourceRoot":"","sources":["../../../src/modules/notifications/NotificationService.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,KAAK,EACL,WAAW,EACX,YAAY,EACZ,mBAAmB,EACnB,sBAAsB,EACtB,gBAAgB,EAChB,sBAAsB,EACtB,yBAAyB,EAC1B,MAAM,qBAAqB,CAAA;AAE5B,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAA;AAE9D,MAAM,WAAW,+BAA+B;IAC9C,sBAAsB,EAAE,sBAAsB,CAAA;IAC9C,mBAAmB,EAAE,mBAAmB,CAAA;IACxC,WAAW,EAAE,WAAW,CAAA;IACxB,KAAK,EAAE,KAAK,CAAA;IACZ;;;;;OAKG;IACH,OAAO,CAAC,EAAE,mBAAmB,CAAA;CAC9B;AAED;;;;;;;;GAQG;AACH,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAwB;IACtD,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAqB;IACzD,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAa;IACzC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAO;IAC7B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAqB;IAE9C,YAAY,IAAI,EAAE,+BAA+B,EAMhD;IAED;;;;;;;;;;OAUG;IACG,KAAK,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,sBAAsB,GAAG,OAAO,CAAC,YAAY,CAAC,CA0CrF;IAED,yFAAyF;IACzF,OAAO,CAAC,cAAc;IAetB;;;;;;;;;;;OAWG;IACG,GAAG,CACP,WAAW,EAAE,MAAM,EACnB,EAAE,EAAE,MAAM,EACV,UAAU,EAAE,CAAC,YAAY,EAAE,YAAY,KAAK,OAAO,CAAC,IAAI,CAAC,GACxD,OAAO,CAAC,YAAY,CAAC,CA0BvB;IAED,kFAAkF;IAC5E,OAAO,CACX,WAAW,EAAE,MAAM,EACnB,EAAE,EAAE,MAAM,EACV,MAAM,EAAE,yBAAyB,GAChC,OAAO,CAAC,YAAY,CAAC,CAYvB;IAED,2EAA2E;IACrE,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CAE3D;IAED;;;;;OAKG;IACG,cAAc,CAClB,YAAY,EAAE,MAAM,EAAE,EACtB,IAAI,EAAE,gBAAgB,GACrB,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,CAEpC;IAED;;;;OAIG;IACG,gBAAgB,CACpB,YAAY,EAAE,MAAM,EAAE,EACtB,IAAI,EAAE,gBAAgB,GACrB,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,CAEpC;IAED;;;;;;;OAOG;IACG,WAAW,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAW3F;IAED;;;;;;;;;OASG;IACG,oBAAoB,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAiB9E;IAED;;;;;;;;OAQG;IACG,aAAa,CAAC,WAAW,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAQ1F;IAED,4CAA4C;IACtC,GAAG,CAAC,WAAW,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAEvE;IAED,mFAAmF;YACrE,OAAO;CAQtB"}
1
+ {"version":3,"file":"NotificationService.d.ts","sourceRoot":"","sources":["../../../src/modules/notifications/NotificationService.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,KAAK,EACL,WAAW,EACX,YAAY,EACZ,mBAAmB,EAEnB,sBAAsB,EACtB,gBAAgB,EAChB,sBAAsB,EACtB,yBAAyB,EAC1B,MAAM,qBAAqB,CAAA;AAE5B,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAA;AAE9D,MAAM,WAAW,+BAA+B;IAC9C,sBAAsB,EAAE,sBAAsB,CAAA;IAC9C,mBAAmB,EAAE,mBAAmB,CAAA;IACxC,WAAW,EAAE,WAAW,CAAA;IACxB,KAAK,EAAE,KAAK,CAAA;IACZ;;;;;OAKG;IACH,OAAO,CAAC,EAAE,mBAAmB,CAAA;CAC9B;AAED;;;;;;;;GAQG;AACH,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAwB;IACtD,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAqB;IACzD,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAa;IACzC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAO;IAC7B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAqB;IAE9C,YAAY,IAAI,EAAE,+BAA+B,EAMhD;IAED;;;;;;;;;;OAUG;IACG,KAAK,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,sBAAsB,GAAG,OAAO,CAAC,YAAY,CAAC,CA0CrF;IAED,yFAAyF;IACzF,OAAO,CAAC,cAAc;IAetB;;;;;;;;;;;OAWG;IACG,GAAG,CACP,WAAW,EAAE,MAAM,EACnB,EAAE,EAAE,MAAM,EACV,UAAU,EAAE,CAAC,YAAY,EAAE,YAAY,KAAK,OAAO,CAAC,IAAI,CAAC,GACxD,OAAO,CAAC,YAAY,CAAC,CA6BvB;IAED,kFAAkF;IAC5E,OAAO,CACX,WAAW,EAAE,MAAM,EACnB,EAAE,EAAE,MAAM,EACV,MAAM,EAAE,yBAAyB,GAChC,OAAO,CAAC,YAAY,CAAC,CAYvB;IAED,2EAA2E;IACrE,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CAE3D;IAED;;;;;OAKG;IACG,cAAc,CAClB,YAAY,EAAE,MAAM,EAAE,EACtB,IAAI,EAAE,gBAAgB,GACrB,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,CAEpC;IAED;;;;OAIG;IACG,gBAAgB,CACpB,YAAY,EAAE,MAAM,EAAE,EACtB,IAAI,EAAE,gBAAgB,GACrB,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,CAEpC;IAED;;;;;;;OAOG;IACG,WAAW,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAW3F;IAED;;;;;;;;;OASG;IACG,oBAAoB,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAiB9E;IAED;;;;;;;;OAQG;IACG,aAAa,CAAC,WAAW,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAW1F;IAED,4CAA4C;IACtC,GAAG,CAAC,WAAW,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAEvE;IAED,mFAAmF;YACrE,OAAO;CAYtB"}
@@ -72,7 +72,7 @@ export class NotificationService {
72
72
  await this.notifications.upsert(workspaceId, notification);
73
73
  }
74
74
  if (!existing || this.contentChanged(existing, notification)) {
75
- await this.deliver(workspaceId, persisted);
75
+ await this.deliver(workspaceId, persisted, 'raised');
76
76
  }
77
77
  return persisted;
78
78
  }
@@ -122,10 +122,13 @@ export class NotificationService {
122
122
  // it and this revert can't lose an escalation.
123
123
  const reopened = { ...claimed, status: 'open', resolvedAt: null };
124
124
  await this.notifications.upsert(workspaceId, reopened);
125
- await this.deliver(workspaceId, reopened);
125
+ // `refreshed`, not `raised`: the human is at the screen they just acted from, and the card
126
+ // was already alerted on when it was raised. Re-interrupting the whole board because a
127
+ // merge call 500ed states a new decision that nobody has to make.
128
+ await this.deliver(workspaceId, reopened, 'refreshed');
126
129
  throw err;
127
130
  }
128
- await this.deliver(workspaceId, claimed);
131
+ await this.deliver(workspaceId, claimed, 'settled');
129
132
  return claimed;
130
133
  }
131
134
  /** Resolve a notification (the human acted on it or dismissed it). Idempotent. */
@@ -140,7 +143,7 @@ export class NotificationService {
140
143
  resolvedAt: this.clock.now(),
141
144
  };
142
145
  await this.notifications.upsert(workspaceId, resolved);
143
- await this.deliver(workspaceId, resolved);
146
+ await this.deliver(workspaceId, resolved, 'settled');
144
147
  return resolved;
145
148
  }
146
149
  /** All open notifications for the workspace (for the inbox + snapshot). */
@@ -182,7 +185,7 @@ export class NotificationService {
182
185
  resolvedAt: this.clock.now(),
183
186
  };
184
187
  await this.notifications.upsert(workspaceId, resolved);
185
- await this.deliver(workspaceId, resolved);
188
+ await this.deliver(workspaceId, resolved, 'settled');
186
189
  return resolved;
187
190
  }
188
191
  /**
@@ -211,7 +214,7 @@ export class NotificationService {
211
214
  resolvedAt: this.clock.now(),
212
215
  };
213
216
  await this.notifications.upsert(workspaceId, resolved);
214
- await this.deliver(workspaceId, resolved);
217
+ await this.deliver(workspaceId, resolved, 'settled');
215
218
  }
216
219
  }
217
220
  /**
@@ -228,7 +231,10 @@ export class NotificationService {
228
231
  // escalated row is then re-delivered so the inbox re-renders it red in real time.
229
232
  const escalated = await this.notifications.escalateStaleOpen(workspaceId, now - thresholdMs);
230
233
  for (const n of escalated) {
231
- await this.deliver(workspaceId, n);
234
+ // `refreshed`: the colour change is for the boards already holding the card, not a second
235
+ // ask. It is also what keeps this loop free of per-card routing and email reads: an alert
236
+ // transport and the routing gate both stand down before touching a store.
237
+ await this.deliver(workspaceId, n, 'refreshed');
232
238
  }
233
239
  return escalated.length;
234
240
  }
@@ -237,11 +243,11 @@ export class NotificationService {
237
243
  return this.notifications.get(workspaceId, id);
238
244
  }
239
245
  /** Best-effort delivery to the channel — a failure must never break the caller. */
240
- async deliver(workspaceId, notification) {
246
+ async deliver(workspaceId, notification, reason) {
241
247
  if (!this.channel)
242
248
  return;
243
249
  try {
244
- await this.channel.deliver(workspaceId, notification);
250
+ await this.channel.deliver(workspaceId, notification, reason);
245
251
  }
246
252
  catch {
247
253
  // The row is persisted; delivery is an optimisation. Swallow channel errors.
@@ -1 +1 @@
1
- {"version":3,"file":"NotificationService.js","sourceRoot":"","sources":["../../../src/modules/notifications/NotificationService.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"NotificationService.js","sourceRoot":"","sources":["../../../src/modules/notifications/NotificationService.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAA;AAiBnE;;;;;;;;GAQG;AACH,MAAM,OAAO,mBAAmB;IACb,aAAa,CAAwB;IACrC,mBAAmB,CAAqB;IACxC,WAAW,CAAa;IACxB,KAAK,CAAO;IACZ,OAAO,CAAsB;IAE9C,YAAY,IAAqC;QAC/C,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC,sBAAsB,CAAA;QAChD,IAAI,CAAC,mBAAmB,GAAG,IAAI,CAAC,mBAAmB,CAAA;QACnD,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,WAAW,CAAA;QACnC,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAA;QACvB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAA;IAC7B,CAAC;IAED;;;;;;;;;;OAUG;IACH,KAAK,CAAC,KAAK,CAAC,WAAmB,EAAE,KAA6B;QAC5D,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO;YAC5B,CAAC,CAAC,MAAM,IAAI,CAAC,aAAa,CAAC,eAAe,CAAC,WAAW,EAAE,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,IAAI,CAAC;YAClF,CAAC,CAAC,oFAAoF;gBACpF,iFAAiF;gBACjF,6EAA6E;gBAC7E,MAAM,IAAI,CAAC,aAAa,CAAC,cAAc,CAAC,WAAW,EAAE,KAAK,CAAC,IAAI,CAAC,CAAA;QACpE,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,CAAA;QAC5B,MAAM,YAAY,GAAiB;YACjC,EAAE,EAAE,QAAQ,EAAE,EAAE,IAAI,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC;YAChD,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,MAAM,EAAE,MAAM;YACd,mFAAmF;YACnF,6EAA6E;YAC7E,QAAQ,EAAE,QAAQ,EAAE,QAAQ,IAAI,QAAQ;YACxC,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,WAAW,EAAE,KAAK,CAAC,WAAW;YAC9B,KAAK,EAAE,KAAK,CAAC,KAAK;YAClB,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,OAAO,EAAE,KAAK,CAAC,OAAO,IAAI,IAAI;YAC9B,SAAS,EAAE,QAAQ,EAAE,SAAS,IAAI,GAAG;YACrC,UAAU,EAAE,IAAI;SACjB,CAAA;QACD,mFAAmF;QACnF,oFAAoF;QACpF,8EAA8E;QAC9E,yEAAyE;QACzE,EAAE;QACF,sFAAsF;QACtF,uFAAuF;QACvF,sFAAsF;QACtF,mFAAmF;QACnF,IAAI,SAAS,GAAG,YAAY,CAAA;QAC5B,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;YAClB,SAAS,GAAG,MAAM,IAAI,CAAC,aAAa,CAAC,kBAAkB,CAAC,WAAW,EAAE,YAAY,CAAC,CAAA;QACpF,CAAC;aAAM,CAAC;YACN,MAAM,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,WAAW,EAAE,YAAY,CAAC,CAAA;QAC5D,CAAC;QACD,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,cAAc,CAAC,QAAQ,EAAE,YAAY,CAAC,EAAE,CAAC;YAC7D,MAAM,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAA;QACtD,CAAC;QACD,OAAO,SAAS,CAAA;IAClB,CAAC;IAED,yFAAyF;IACjF,cAAc,CAAC,IAAkB,EAAE,IAAkB;QAC3D,OAAO,CACL,IAAI,CAAC,KAAK,KAAK,IAAI,CAAC,KAAK;YACzB,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC,IAAI;YACvB,IAAI,CAAC,QAAQ,KAAK,IAAI,CAAC,QAAQ;YAC/B,IAAI,CAAC,MAAM,KAAK,IAAI,CAAC,MAAM;YAC3B,uFAAuF;YACvF,wFAAwF;YACxF,0FAA0F;YAC1F,kDAAkD;YAClD,IAAI,CAAC,WAAW,KAAK,IAAI,CAAC,WAAW;YACrC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,CAC9E,CAAA;IACH,CAAC;IAED;;;;;;;;;;;OAWG;IACH,KAAK,CAAC,GAAG,CACP,WAAmB,EACnB,EAAU,EACV,UAAyD;QAEzD,MAAM,gBAAgB,CAAC,IAAI,CAAC,mBAAmB,EAAE,WAAW,CAAC,CAAA;QAC7D,MAAM,QAAQ,GAAG,WAAW,CAAC,MAAM,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,WAAW,EAAE,EAAE,CAAC,EAAE,cAAc,EAAE,EAAE,CAAC,CAAA;QAC/F,4FAA4F;QAC5F,IAAI,QAAQ,CAAC,MAAM,KAAK,MAAM;YAAE,OAAO,QAAQ,CAAA;QAE/C,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,aAAa,CAAC,cAAc,CAAC,WAAW,EAAE,EAAE,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAA;QAC1F,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,0FAA0F;YAC1F,uDAAuD;YACvD,OAAO,WAAW,CAAC,MAAM,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,WAAW,EAAE,EAAE,CAAC,EAAE,cAAc,EAAE,EAAE,CAAC,CAAA;QACvF,CAAC;QAED,IAAI,CAAC;YACH,MAAM,UAAU,CAAC,OAAO,CAAC,CAAA;QAC3B,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,yFAAyF;YACzF,2FAA2F;YAC3F,+CAA+C;YAC/C,MAAM,QAAQ,GAAiB,EAAE,GAAG,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,CAAA;YAC/E,MAAM,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAA;YACtD,2FAA2F;YAC3F,uFAAuF;YACvF,kEAAkE;YAClE,MAAM,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,QAAQ,EAAE,WAAW,CAAC,CAAA;YACtD,MAAM,GAAG,CAAA;QACX,CAAC;QACD,MAAM,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,OAAO,EAAE,SAAS,CAAC,CAAA;QACnD,OAAO,OAAO,CAAA;IAChB,CAAC;IAED,kFAAkF;IAClF,KAAK,CAAC,OAAO,CACX,WAAmB,EACnB,EAAU,EACV,MAAiC;QAEjC,MAAM,gBAAgB,CAAC,IAAI,CAAC,mBAAmB,EAAE,WAAW,CAAC,CAAA;QAC7D,MAAM,QAAQ,GAAG,WAAW,CAAC,MAAM,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,WAAW,EAAE,EAAE,CAAC,EAAE,cAAc,EAAE,EAAE,CAAC,CAAA;QAC/F,IAAI,QAAQ,CAAC,MAAM,KAAK,MAAM;YAAE,OAAO,QAAQ,CAAA;QAC/C,MAAM,QAAQ,GAAiB;YAC7B,GAAG,QAAQ;YACX,MAAM,EAAE,MAAM,KAAK,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,WAAW;YAChD,UAAU,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE;SAC7B,CAAA;QACD,MAAM,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAA;QACtD,MAAM,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAA;QACpD,OAAO,QAAQ,CAAA;IACjB,CAAC;IAED,2EAA2E;IAC3E,KAAK,CAAC,QAAQ,CAAC,WAAmB;QAChC,OAAO,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAA;IACjD,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,cAAc,CAClB,YAAsB,EACtB,IAAsB;QAEtB,OAAO,IAAI,CAAC,aAAa,CAAC,cAAc,CAAC,YAAY,EAAE,IAAI,CAAC,CAAA;IAC9D,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,gBAAgB,CACpB,YAAsB,EACtB,IAAsB;QAEtB,OAAO,IAAI,CAAC,aAAa,CAAC,gBAAgB,CAAC,YAAY,EAAE,IAAI,CAAC,CAAA;IAChE,CAAC;IAED;;;;;;;OAOG;IACH,KAAK,CAAC,WAAW,CAAC,WAAmB,EAAE,IAAsB;QAC3D,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,aAAa,CAAC,cAAc,CAAC,WAAW,EAAE,IAAI,CAAC,CAAA;QAC3E,IAAI,CAAC,QAAQ;YAAE,OAAO,IAAI,CAAA;QAC1B,MAAM,QAAQ,GAAiB;YAC7B,GAAG,QAAQ;YACX,MAAM,EAAE,WAAW;YACnB,UAAU,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE;SAC7B,CAAA;QACD,MAAM,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAA;QACtD,MAAM,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAA;QACpD,OAAO,QAAQ,CAAA;IACjB,CAAC;IAED;;;;;;;;;OASG;IACH,KAAK,CAAC,oBAAoB,CAAC,WAAmB,EAAE,OAAe;QAC7D,KAAK,MAAM,IAAI,IAAI;YACjB,mBAAmB;YACnB,kBAAkB;YAClB,uBAAuB;YACvB,iBAAiB;SACT,EAAE,CAAC;YACX,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,aAAa,CAAC,eAAe,CAAC,WAAW,EAAE,OAAO,EAAE,IAAI,CAAC,CAAA;YACrF,IAAI,CAAC,QAAQ;gBAAE,SAAQ;YACvB,MAAM,QAAQ,GAAiB;gBAC7B,GAAG,QAAQ;gBACX,MAAM,EAAE,WAAW;gBACnB,UAAU,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE;aAC7B,CAAA;YACD,MAAM,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAA;YACtD,MAAM,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAA;QACtD,CAAC;IACH,CAAC;IAED;;;;;;;;OAQG;IACH,KAAK,CAAC,aAAa,CAAC,WAAmB,EAAE,WAAmB,EAAE,GAAW;QACvE,gFAAgF;QAChF,kFAAkF;QAClF,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,aAAa,CAAC,iBAAiB,CAAC,WAAW,EAAE,GAAG,GAAG,WAAW,CAAC,CAAA;QAC5F,KAAK,MAAM,CAAC,IAAI,SAAS,EAAE,CAAC;YAC1B,0FAA0F;YAC1F,0FAA0F;YAC1F,0EAA0E;YAC1E,MAAM,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,EAAE,WAAW,CAAC,CAAA;QACjD,CAAC;QACD,OAAO,SAAS,CAAC,MAAM,CAAA;IACzB,CAAC;IAED,4CAA4C;IAC5C,KAAK,CAAC,GAAG,CAAC,WAAmB,EAAE,EAAU;QACvC,OAAO,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,WAAW,EAAE,EAAE,CAAC,CAAA;IAChD,CAAC;IAED,mFAAmF;IAC3E,KAAK,CAAC,OAAO,CACnB,WAAmB,EACnB,YAA0B,EAC1B,MAAkC;QAElC,IAAI,CAAC,IAAI,CAAC,OAAO;YAAE,OAAM;QACzB,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,WAAW,EAAE,YAAY,EAAE,MAAM,CAAC,CAAA;QAC/D,CAAC;QAAC,MAAM,CAAC;YACP,6EAA6E;QAC/E,CAAC;IACH,CAAC;CACF"}
@@ -0,0 +1,28 @@
1
+ import { type NotificationSettings } from '@cat-factory/contracts';
2
+ import type { Clock, NotificationDeliveryChannel, NotificationRouter, NotificationRoutingMatrix, NotificationSettingsRepository, NotificationType } from '@cat-factory/kernel';
3
+ export interface NotificationSettingsServiceDependencies {
4
+ notificationSettingsRepository: NotificationSettingsRepository;
5
+ clock: Clock;
6
+ }
7
+ export declare class NotificationSettingsService implements NotificationRouter {
8
+ private readonly deps;
9
+ constructor(deps: NotificationSettingsServiceDependencies);
10
+ /** A workspace's settings; the empty matrix (everything on its default) when unconfigured. */
11
+ get(workspaceId: string): Promise<NotificationSettings>;
12
+ /** Replace a workspace's routing overrides (a full replace, like the Slack routing write). */
13
+ update(workspaceId: string, matrix: NotificationRoutingMatrix): Promise<NotificationSettings>;
14
+ /**
15
+ * The routing decision, for one delivery. One point read per notification per routed
16
+ * channel: notifications are raised at human scale (a run parks, a gate gives up), so
17
+ * this is not on any hot path, and a cached copy would answer with a mute the operator
18
+ * had already lifted.
19
+ */
20
+ isRouted(workspaceId: string, type: NotificationType, channel: NotificationDeliveryChannel): Promise<boolean>;
21
+ /**
22
+ * Decode a stored matrix. The cell-by-cell tolerance (a retired type costs its own override
23
+ * and nothing else) lives in `@cat-factory/contracts` beside the resolution it feeds, so the
24
+ * settings UI decoding the same row reaches the same answer.
25
+ */
26
+ private parseMatrix;
27
+ }
28
+ //# sourceMappingURL=NotificationSettingsService.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NotificationSettingsService.d.ts","sourceRoot":"","sources":["../../../src/modules/notifications/NotificationSettingsService.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,oBAAoB,EAC1B,MAAM,wBAAwB,CAAA;AAC/B,OAAO,KAAK,EACV,KAAK,EACL,2BAA2B,EAC3B,kBAAkB,EAClB,yBAAyB,EACzB,8BAA8B,EAC9B,gBAAgB,EACjB,MAAM,qBAAqB,CAAA;AAW5B,MAAM,WAAW,uCAAuC;IACtD,8BAA8B,EAAE,8BAA8B,CAAA;IAC9D,KAAK,EAAE,KAAK,CAAA;CACb;AAED,qBAAa,2BAA4B,YAAW,kBAAkB;IACxD,OAAO,CAAC,QAAQ,CAAC,IAAI;IAAjC,YAA6B,IAAI,EAAE,uCAAuC,EAAI;IAE9E,8FAA8F;IACxF,GAAG,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAI5D;IAED,8FAA8F;IACxF,MAAM,CACV,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,yBAAyB,GAChC,OAAO,CAAC,oBAAoB,CAAC,CAQ/B;IAED;;;;;OAKG;IACG,QAAQ,CACZ,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,gBAAgB,EACtB,OAAO,EAAE,2BAA2B,GACnC,OAAO,CAAC,OAAO,CAAC,CAGlB;IAED;;;;OAIG;IACH,OAAO,CAAC,WAAW;CASpB"}
@@ -0,0 +1,50 @@
1
+ import { decodeNotificationRoutingMatrix, isNotificationRouted, } from '@cat-factory/contracts';
2
+ export class NotificationSettingsService {
3
+ deps;
4
+ constructor(deps) {
5
+ this.deps = deps;
6
+ }
7
+ /** A workspace's settings; the empty matrix (everything on its default) when unconfigured. */
8
+ async get(workspaceId) {
9
+ const record = await this.deps.notificationSettingsRepository.getByWorkspace(workspaceId);
10
+ if (!record)
11
+ return { matrix: {}, updatedAt: 0 };
12
+ return { matrix: this.parseMatrix(record.matrixJson), updatedAt: record.updatedAt };
13
+ }
14
+ /** Replace a workspace's routing overrides (a full replace, like the Slack routing write). */
15
+ async update(workspaceId, matrix) {
16
+ const updatedAt = this.deps.clock.now();
17
+ await this.deps.notificationSettingsRepository.upsert({
18
+ workspaceId,
19
+ matrixJson: JSON.stringify(matrix),
20
+ updatedAt,
21
+ });
22
+ return { matrix, updatedAt };
23
+ }
24
+ /**
25
+ * The routing decision, for one delivery. One point read per notification per routed
26
+ * channel: notifications are raised at human scale (a run parks, a gate gives up), so
27
+ * this is not on any hot path, and a cached copy would answer with a mute the operator
28
+ * had already lifted.
29
+ */
30
+ async isRouted(workspaceId, type, channel) {
31
+ const { matrix } = await this.get(workspaceId);
32
+ return isNotificationRouted(matrix, type, channel);
33
+ }
34
+ /**
35
+ * Decode a stored matrix. The cell-by-cell tolerance (a retired type costs its own override
36
+ * and nothing else) lives in `@cat-factory/contracts` beside the resolution it feeds, so the
37
+ * settings UI decoding the same row reaches the same answer.
38
+ */
39
+ parseMatrix(matrixJson) {
40
+ try {
41
+ return decodeNotificationRoutingMatrix(JSON.parse(matrixJson));
42
+ }
43
+ catch {
44
+ // A corrupt row is, for routing, the same state as an unconfigured one: every cell falls
45
+ // back to its shipped default. Throwing here would run on the delivery path.
46
+ return {};
47
+ }
48
+ }
49
+ }
50
+ //# sourceMappingURL=NotificationSettingsService.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NotificationSettingsService.js","sourceRoot":"","sources":["../../../src/modules/notifications/NotificationSettingsService.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,+BAA+B,EAC/B,oBAAoB,GAErB,MAAM,wBAAwB,CAAA;AAwB/B,MAAM,OAAO,2BAA2B;IACT,IAAI;IAAjC,YAA6B,IAA6C;oBAA7C,IAAI;IAA4C,CAAC;IAE9E,8FAA8F;IAC9F,KAAK,CAAC,GAAG,CAAC,WAAmB;QAC3B,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,8BAA8B,CAAC,cAAc,CAAC,WAAW,CAAC,CAAA;QACzF,IAAI,CAAC,MAAM;YAAE,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,SAAS,EAAE,CAAC,EAAE,CAAA;QAChD,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,SAAS,EAAE,MAAM,CAAC,SAAS,EAAE,CAAA;IACrF,CAAC;IAED,8FAA8F;IAC9F,KAAK,CAAC,MAAM,CACV,WAAmB,EACnB,MAAiC;QAEjC,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,CAAA;QACvC,MAAM,IAAI,CAAC,IAAI,CAAC,8BAA8B,CAAC,MAAM,CAAC;YACpD,WAAW;YACX,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC;YAClC,SAAS;SACV,CAAC,CAAA;QACF,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,CAAA;IAC9B,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,QAAQ,CACZ,WAAmB,EACnB,IAAsB,EACtB,OAAoC;QAEpC,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,CAAA;QAC9C,OAAO,oBAAoB,CAAC,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC,CAAA;IACpD,CAAC;IAED;;;;OAIG;IACK,WAAW,CAAC,UAAkB;QACpC,IAAI,CAAC;YACH,OAAO,+BAA+B,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAA;QAChE,CAAC;QAAC,MAAM,CAAC;YACP,yFAAyF;YACzF,6EAA6E;YAC7E,OAAO,EAAE,CAAA;QACX,CAAC;IACH,CAAC;CACF"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cat-factory/orchestration",
3
- "version": "0.239.0",
3
+ "version": "0.241.0",
4
4
  "description": "Delivery-workflow engine for the Agent Architecture Board (execution, bootstrap, pipelines, board, boardScan, requirements, and composition root).",
5
5
  "repository": {
6
6
  "type": "git",
@@ -25,20 +25,20 @@
25
25
  },
26
26
  "dependencies": {
27
27
  "ai": "^7.0.51",
28
- "@cat-factory/agents": "0.117.11",
29
- "@cat-factory/caching": "0.18.12",
30
- "@cat-factory/contracts": "0.273.0",
31
- "@cat-factory/integrations": "0.149.0",
32
- "@cat-factory/kernel": "0.271.0",
33
- "@cat-factory/prompt-fragments": "1.0.21",
34
- "@cat-factory/sandbox": "0.11.98",
35
- "@cat-factory/spend": "0.15.39",
36
- "@cat-factory/workspaces": "0.26.11"
28
+ "@cat-factory/agents": "0.118.0",
29
+ "@cat-factory/caching": "0.18.14",
30
+ "@cat-factory/contracts": "0.275.0",
31
+ "@cat-factory/integrations": "0.151.0",
32
+ "@cat-factory/kernel": "0.273.0",
33
+ "@cat-factory/prompt-fragments": "1.0.23",
34
+ "@cat-factory/sandbox": "0.11.100",
35
+ "@cat-factory/spend": "0.15.41",
36
+ "@cat-factory/workspaces": "0.26.13"
37
37
  },
38
38
  "devDependencies": {
39
39
  "typescript": "7.0.2",
40
40
  "vitest": "^4.1.10",
41
- "@cat-factory/sandbox-fixtures": "0.7.308"
41
+ "@cat-factory/sandbox-fixtures": "0.7.310"
42
42
  },
43
43
  "scripts": {
44
44
  "build": "tsc -b tsconfig.build.json",