@cat-factory/orchestration 0.141.0 → 0.143.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 (78) hide show
  1. package/dist/container/dependencies.d.ts +8 -1
  2. package/dist/container/dependencies.d.ts.map +1 -1
  3. package/dist/container/engine-collaborators.d.ts +4 -4
  4. package/dist/container/engine-dependent-modules.d.ts +8 -1
  5. package/dist/container/engine-dependent-modules.d.ts.map +1 -1
  6. package/dist/container/engine-dependent-modules.js +9 -2
  7. package/dist/container/engine-dependent-modules.js.map +1 -1
  8. package/dist/container/module-shapes.d.ts +127 -0
  9. package/dist/container/module-shapes.d.ts.map +1 -0
  10. package/dist/container/module-shapes.js +2 -0
  11. package/dist/container/module-shapes.js.map +1 -0
  12. package/dist/container/modules.d.ts +16 -2
  13. package/dist/container/modules.d.ts.map +1 -1
  14. package/dist/container/modules.js +32 -1
  15. package/dist/container/modules.js.map +1 -1
  16. package/dist/container.d.ts +5 -118
  17. package/dist/container.d.ts.map +1 -1
  18. package/dist/container.js +8 -21
  19. package/dist/container.js.map +1 -1
  20. package/dist/index.d.ts +2 -1
  21. package/dist/index.d.ts.map +1 -1
  22. package/dist/index.js +1 -0
  23. package/dist/index.js.map +1 -1
  24. package/dist/modules/execution/AgentContextBuilder.d.ts +15 -1
  25. package/dist/modules/execution/AgentContextBuilder.d.ts.map +1 -1
  26. package/dist/modules/execution/AgentContextBuilder.js +27 -1
  27. package/dist/modules/execution/AgentContextBuilder.js.map +1 -1
  28. package/dist/modules/execution/ExecutionService.d.ts +22 -30
  29. package/dist/modules/execution/ExecutionService.d.ts.map +1 -1
  30. package/dist/modules/execution/ExecutionService.js +51 -54
  31. package/dist/modules/execution/ExecutionService.js.map +1 -1
  32. package/dist/modules/execution/ExecutionServiceDependencies.d.ts +9 -0
  33. package/dist/modules/execution/ExecutionServiceDependencies.d.ts.map +1 -1
  34. package/dist/modules/execution/MergeResolver.d.ts +18 -1
  35. package/dist/modules/execution/MergeResolver.d.ts.map +1 -1
  36. package/dist/modules/execution/MergeResolver.js +70 -17
  37. package/dist/modules/execution/MergeResolver.js.map +1 -1
  38. package/dist/modules/execution/PollCompletionController.d.ts.map +1 -1
  39. package/dist/modules/execution/PollCompletionController.js +6 -0
  40. package/dist/modules/execution/PollCompletionController.js.map +1 -1
  41. package/dist/modules/execution/RunDispatcher.d.ts.map +1 -1
  42. package/dist/modules/execution/RunDispatcher.js +10 -0
  43. package/dist/modules/execution/RunDispatcher.js.map +1 -1
  44. package/dist/modules/execution/RunMergePolicy.d.ts +59 -0
  45. package/dist/modules/execution/RunMergePolicy.d.ts.map +1 -0
  46. package/dist/modules/execution/RunMergePolicy.js +85 -0
  47. package/dist/modules/execution/RunMergePolicy.js.map +1 -0
  48. package/dist/modules/execution/RunStateMachine.d.ts +9 -0
  49. package/dist/modules/execution/RunStateMachine.d.ts.map +1 -1
  50. package/dist/modules/execution/RunStateMachine.js +11 -0
  51. package/dist/modules/execution/RunStateMachine.js.map +1 -1
  52. package/dist/modules/execution/StepGraph.d.ts.map +1 -1
  53. package/dist/modules/execution/StepGraph.js +5 -0
  54. package/dist/modules/execution/StepGraph.js.map +1 -1
  55. package/dist/modules/execution/policy-types.d.ts +37 -0
  56. package/dist/modules/execution/policy-types.d.ts.map +1 -0
  57. package/dist/modules/execution/policy-types.js +2 -0
  58. package/dist/modules/execution/policy-types.js.map +1 -0
  59. package/dist/modules/execution/reproductionProof.logic.d.ts +101 -0
  60. package/dist/modules/execution/reproductionProof.logic.d.ts.map +1 -0
  61. package/dist/modules/execution/reproductionProof.logic.js +264 -0
  62. package/dist/modules/execution/reproductionProof.logic.js.map +1 -0
  63. package/dist/modules/execution/run-context-admission.d.ts +25 -0
  64. package/dist/modules/execution/run-context-admission.d.ts.map +1 -0
  65. package/dist/modules/execution/run-context-admission.js +54 -0
  66. package/dist/modules/execution/run-context-admission.js.map +1 -0
  67. package/dist/modules/merge/MergeTrackRecordService.d.ts +133 -0
  68. package/dist/modules/merge/MergeTrackRecordService.d.ts.map +1 -0
  69. package/dist/modules/merge/MergeTrackRecordService.js +191 -0
  70. package/dist/modules/merge/MergeTrackRecordService.js.map +1 -0
  71. package/dist/modules/merge/RiskPolicyService.d.ts.map +1 -1
  72. package/dist/modules/merge/RiskPolicyService.js +5 -0
  73. package/dist/modules/merge/RiskPolicyService.js.map +1 -1
  74. package/dist/modules/merge/externalMergeObserver.d.ts +27 -0
  75. package/dist/modules/merge/externalMergeObserver.d.ts.map +1 -0
  76. package/dist/modules/merge/externalMergeObserver.js +40 -0
  77. package/dist/modules/merge/externalMergeObserver.js.map +1 -0
  78. package/package.json +11 -11
@@ -0,0 +1,54 @@
1
+ /**
2
+ * The engine's context-building + run-admission pair: the {@link AgentContextBuilder} every
3
+ * dispatch composes its prompt through, and the {@link RunAdmission} preflight family
4
+ * (`assert*`) that start / retry / restart all gate on.
5
+ *
6
+ * Extracted verbatim from the {@link ExecutionService} constructor (which had grown past the
7
+ * per-function line budget — docs/initiatives/lint-complexity-size-ratchet.md) following the
8
+ * same sibling-factory pattern as `gate-window-controllers.ts`: ONE deps object of values the
9
+ * constructor already had in hand, and the two collaborators returned together because admission
10
+ * is built ON the context builder — they are one seam, not two. Behaviour-neutral.
11
+ */
12
+ import { AgentContextBuilder } from './AgentContextBuilder.js';
13
+ import { RunAdmission } from './RunAdmission.js';
14
+ export function buildRunContextAndAdmission(deps) {
15
+ const contextBuilder = new AgentContextBuilder({
16
+ workspaceRepository: deps.workspaceRepository,
17
+ blockRepository: deps.blockRepository,
18
+ accountRepository: deps.accountRepository,
19
+ agentKindRegistry: deps.agentKindRegistry,
20
+ initiativePresetRegistry: deps.initiativePresetRegistry,
21
+ documents: deps.documentRepository,
22
+ documentUrlResolver: deps.documentUrlResolver,
23
+ tasks: deps.taskRepository,
24
+ requirementReviews: deps.requirementReviewRepository,
25
+ docInterviews: deps.docInterviewRepository,
26
+ clarityReviews: deps.clarityReviewRepository,
27
+ brainstormSessions: deps.brainstormSessionRepository,
28
+ initiatives: deps.initiativeRepository,
29
+ environmentProvisioning: deps.environmentProvisioning,
30
+ resolveTestSecretRefs: deps.resolveTestSecretRefs,
31
+ resolveValidationChecks: deps.resolveValidationChecks,
32
+ fragmentResolver: deps.fragmentResolver,
33
+ skillResolver: deps.skillResolver,
34
+ });
35
+ // The run-admission preflights (the shared start/retry/restart `assert*` gate family).
36
+ // The admission-only seams are forwarded here rather than stored on the engine.
37
+ const admission = new RunAdmission({
38
+ workspaceRepository: deps.workspaceRepository,
39
+ blockRepository: deps.blockRepository,
40
+ executionRepository: deps.executionRepository,
41
+ contextBuilder,
42
+ agentKindRegistry: deps.agentKindRegistry,
43
+ spend: deps.spendService,
44
+ environmentProvisioning: deps.environmentProvisioning,
45
+ workspaceSettingsService: deps.workspaceSettingsService,
46
+ resolveBinaryArtifactStore: deps.resolveBinaryArtifactStore,
47
+ resolveProviderCapabilities: deps.resolveProviderCapabilities,
48
+ inlineHarnessRef: deps.inlineHarnessRef,
49
+ resolveWorkspaceModelDefault: deps.resolveWorkspaceModelDefault,
50
+ assertAgentBackendConfigured: deps.assertAgentBackendConfigured,
51
+ });
52
+ return { contextBuilder, admission };
53
+ }
54
+ //# sourceMappingURL=run-context-admission.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-context-admission.js","sourceRoot":"","sources":["../../../src/modules/execution/run-context-admission.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAA;AAC9D,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAsChD,MAAM,UAAU,2BAA2B,CAAC,IAA6B;IAIvE,MAAM,cAAc,GAAG,IAAI,mBAAmB,CAAC;QAC7C,mBAAmB,EAAE,IAAI,CAAC,mBAAmB;QAC7C,eAAe,EAAE,IAAI,CAAC,eAAe;QACrC,iBAAiB,EAAE,IAAI,CAAC,iBAAiB;QACzC,iBAAiB,EAAE,IAAI,CAAC,iBAAiB;QACzC,wBAAwB,EAAE,IAAI,CAAC,wBAAwB;QACvD,SAAS,EAAE,IAAI,CAAC,kBAAkB;QAClC,mBAAmB,EAAE,IAAI,CAAC,mBAAmB;QAC7C,KAAK,EAAE,IAAI,CAAC,cAAc;QAC1B,kBAAkB,EAAE,IAAI,CAAC,2BAA2B;QACpD,aAAa,EAAE,IAAI,CAAC,sBAAsB;QAC1C,cAAc,EAAE,IAAI,CAAC,uBAAuB;QAC5C,kBAAkB,EAAE,IAAI,CAAC,2BAA2B;QACpD,WAAW,EAAE,IAAI,CAAC,oBAAoB;QACtC,uBAAuB,EAAE,IAAI,CAAC,uBAAuB;QACrD,qBAAqB,EAAE,IAAI,CAAC,qBAAqB;QACjD,uBAAuB,EAAE,IAAI,CAAC,uBAAuB;QACrD,gBAAgB,EAAE,IAAI,CAAC,gBAAgB;QACvC,aAAa,EAAE,IAAI,CAAC,aAAa;KAClC,CAAC,CAAA;IACF,uFAAuF;IACvF,gFAAgF;IAChF,MAAM,SAAS,GAAG,IAAI,YAAY,CAAC;QACjC,mBAAmB,EAAE,IAAI,CAAC,mBAAmB;QAC7C,eAAe,EAAE,IAAI,CAAC,eAAe;QACrC,mBAAmB,EAAE,IAAI,CAAC,mBAAmB;QAC7C,cAAc;QACd,iBAAiB,EAAE,IAAI,CAAC,iBAAiB;QACzC,KAAK,EAAE,IAAI,CAAC,YAAY;QACxB,uBAAuB,EAAE,IAAI,CAAC,uBAAuB;QACrD,wBAAwB,EAAE,IAAI,CAAC,wBAAwB;QACvD,0BAA0B,EAAE,IAAI,CAAC,0BAA0B;QAC3D,2BAA2B,EAAE,IAAI,CAAC,2BAA2B;QAC7D,gBAAgB,EAAE,IAAI,CAAC,gBAAgB;QACvC,4BAA4B,EAAE,IAAI,CAAC,4BAA4B;QAC/D,4BAA4B,EAAE,IAAI,CAAC,4BAA4B;KAChE,CAAC,CAAA;IACF,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,CAAA;AACtC,CAAC"}
@@ -0,0 +1,133 @@
1
+ import type { Block, ChangeClass, Clock, MergeAssessment, MergeClassRollup, MergeTrackDecision, MergeTrackRecord, MergeTrackRecordRepository, ResolveRunRepoContext, ReviewEffort, VcsProvider, WorkspaceRepository } from '@cat-factory/kernel';
2
+ /** The repo identity a record carries, in the provider-neutral VCS vocabulary. */
3
+ export interface MergeTrackRepoRef {
4
+ repoId?: string | null;
5
+ provider?: VcsProvider | null;
6
+ }
7
+ /** Everything the merge path knows at the moment a merger step's decision is made. */
8
+ export interface RecordMergeDecisionInput {
9
+ block: Block;
10
+ executionId: string;
11
+ decision: MergeTrackDecision;
12
+ /** The merger's scores, when it produced a parseable assessment. */
13
+ assessment?: MergeAssessment | null;
14
+ /** The preset the decision was made against (its id is absent for the built-in fallback). */
15
+ riskPolicyId?: string | null;
16
+ riskPolicyName?: string | null;
17
+ /**
18
+ * The pre-computed classification, when the caller already ran it (the merge resolver needs
19
+ * the class BEFORE it decides, so it classifies first and passes the result down rather than
20
+ * paying for a second VCS call). It carries the run's repo identity too, so the record is
21
+ * attributable without a second resolution — see {@link RunClassification}.
22
+ */
23
+ classification?: RunClassification;
24
+ /** Explicit override for the repo identity; normally it rides `classification`. */
25
+ repo?: MergeTrackRepoRef;
26
+ }
27
+ /**
28
+ * What classifying a run's pull request yields: the change class, how many files it covered,
29
+ * and WHICH REPO the PR belongs to.
30
+ *
31
+ * The repo identity is not incidental — it is the key external-merge attribution looks a record
32
+ * up by (`getByPullRequest(repoId, prNumber)`), because a webhook delivery knows only
33
+ * `(repoId, prNumber)`. It is captured here because `classify` already resolves the run's repo
34
+ * context to read the changed files, so recording it costs nothing extra; resolving it later
35
+ * would be a second walk of the same linkage.
36
+ */
37
+ export interface RunClassification {
38
+ changeClass: ChangeClass;
39
+ fileCount: number;
40
+ repoId?: string | null;
41
+ provider?: VcsProvider | null;
42
+ }
43
+ export interface MergeTrackRecordServiceDependencies {
44
+ mergeTrackRecordRepository: MergeTrackRecordRepository;
45
+ workspaceRepository: WorkspaceRepository;
46
+ clock: Clock;
47
+ /**
48
+ * Resolve the run's repo so the changed-file list can be read (`RepoFiles.listChangedFiles`).
49
+ * Absent (tests / no VCS connected) ⇒ classification yields `unknown`, which never matches a
50
+ * per-class rule, so the merge policy falls back to the score thresholds untouched.
51
+ */
52
+ resolveRunRepoContext?: ResolveRunRepoContext;
53
+ }
54
+ /**
55
+ * The merge TRACK RECORD: one persisted row per merge decision carrying the run's
56
+ * deterministic change class, the merger's scores, what happened, and the reviewer-effort tag a
57
+ * human left — plus the per-class rollups that justify widening a preset's per-class rule.
58
+ *
59
+ * Every write here is a **best-effort side channel of the merge path**: `classify` and
60
+ * `recordDecision` swallow their own failures and return a degraded-but-valid result, because a
61
+ * classification or persistence fault must NEVER block or fail a merge. The read paths
62
+ * (`rollups`, `tag`) are ordinary request-scoped operations and do throw.
63
+ *
64
+ * Full design: `docs/initiatives/merge-track-record.md`.
65
+ */
66
+ export declare class MergeTrackRecordService {
67
+ private readonly deps;
68
+ constructor(deps: MergeTrackRecordServiceDependencies);
69
+ /**
70
+ * Classify a block's pull request from the files it changed — ONE VCS call, then the pure
71
+ * `classifyChangedFiles` precedence rule (highest-ranked class present wins).
72
+ *
73
+ * Returns `unknown` (never throws) when there is no repo context, the bound client cannot
74
+ * enumerate a PR's files, the block has no PR number, or the call fails. `unknown` is inert by
75
+ * design: `resolveMergeClassRule` never matches it, so a transient VCS outage can neither
76
+ * widen nor tighten the merge policy.
77
+ */
78
+ classify(workspaceId: string, block: Block): Promise<RunClassification>;
79
+ /**
80
+ * Record a merger step's decision. Idempotent by construction: the id is derived from the
81
+ * run (`mtr_<executionId>`) and the insert is first-write-wins, so the durable driver
82
+ * re-resolving a step whose merge already landed cannot duplicate the row — nor clobber an
83
+ * effort tag a human has since added.
84
+ *
85
+ * Returns the stored record, or null when nothing could be written (no repository, or the
86
+ * write threw). Callers treat null as "no record" and carry on: the merge is what matters.
87
+ */
88
+ recordDecision(workspaceId: string, input: RecordMergeDecisionInput): Promise<MergeTrackRecord | null>;
89
+ /**
90
+ * Settle a record that was left `pending_review` once a human resolved it — merged it through
91
+ * cat-factory, merged it on the provider, or declined. Optionally tags the review effort in
92
+ * the same write (the merge card's one-tap confirm-and-tag).
93
+ *
94
+ * Best-effort and silent: a run with no record (classification never ran, or the merge came
95
+ * from a pipeline with no `merger` step) is simply skipped. Returns the record's id when one
96
+ * was updated, so a caller can put it on a notification payload.
97
+ *
98
+ * Only a still-`pending_review` record is SETTLED here, mirroring {@link recordExternalMerge}:
99
+ * a landed PR must never be re-decided by a late action on a stale card. The concrete case is
100
+ * a PR merged on the provider (recorded `external_merged`) whose merge-review card is then
101
+ * dismissed — without this guard that dismissal would rewrite a merged PR as `rejected` and
102
+ * corrupt the very rollup the record exists to produce. A later EFFORT TAG is still applied,
103
+ * because tagging is orthogonal to the decision and is welcome whenever it arrives.
104
+ */
105
+ resolveDecision(workspaceId: string, executionId: string, decision: Exclude<MergeTrackDecision, 'pending_review'>, reviewEffort?: ReviewEffort | null): Promise<string | null>;
106
+ /**
107
+ * Attribute an EXTERNAL merge: a human merged a PR directly on the VCS provider, bypassing
108
+ * cat-factory's merge card. Looks the record up by `(repoId, prNumber)` — which a merger-step
109
+ * record already carries — so no unindexed scan of the blocks' JSON PR column is needed, and
110
+ * the feature is correctly scoped to PRs cat-factory opened and was waiting on.
111
+ *
112
+ * Returns the settled record when this delivery is the one that flipped it (so the caller
113
+ * raises exactly ONE tag-request nudge), and null when there is nothing to attribute or the
114
+ * record was already resolved — webhook deliveries are re-sent, so this must be idempotent.
115
+ */
116
+ recordExternalMerge(workspaceId: string, repoId: string, prNumber: number): Promise<MergeTrackRecord | null>;
117
+ /** A record by id (for the tag surface and the notification card's context). */
118
+ get(workspaceId: string, id: string): Promise<MergeTrackRecord | null>;
119
+ /** The most recent record for a block — the seam the block-scoped merge controls tag through. */
120
+ getLatestByBlock(workspaceId: string, blockId: string): Promise<MergeTrackRecord | null>;
121
+ /**
122
+ * Tag (or clear) how much review effort a human spent. Unlike the write paths above this is a
123
+ * deliberate user action, so an unknown id is a real 404 rather than a silent skip.
124
+ */
125
+ tag(workspaceId: string, id: string, reviewEffort: ReviewEffort | null): Promise<MergeTrackRecord>;
126
+ /**
127
+ * Per-change-class rollups for the workspace: ONE SQL aggregate, then every class the query
128
+ * returned nothing for is filled in as an empty rollup so the caller always gets the full,
129
+ * stably-ordered set (the preset editor renders a row per class whether or not it has data).
130
+ */
131
+ rollups(workspaceId: string): Promise<MergeClassRollup[]>;
132
+ }
133
+ //# sourceMappingURL=MergeTrackRecordService.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MergeTrackRecordService.d.ts","sourceRoot":"","sources":["../../../src/modules/merge/MergeTrackRecordService.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,191 @@
1
+ import { CHANGE_CLASSES, emptyMergeClassRollup } from '@cat-factory/contracts';
2
+ import { assertFound, classifyChangedFiles, requireWorkspace } from '@cat-factory/kernel';
3
+ /**
4
+ * The merge TRACK RECORD: one persisted row per merge decision carrying the run's
5
+ * deterministic change class, the merger's scores, what happened, and the reviewer-effort tag a
6
+ * human left — plus the per-class rollups that justify widening a preset's per-class rule.
7
+ *
8
+ * Every write here is a **best-effort side channel of the merge path**: `classify` and
9
+ * `recordDecision` swallow their own failures and return a degraded-but-valid result, because a
10
+ * classification or persistence fault must NEVER block or fail a merge. The read paths
11
+ * (`rollups`, `tag`) are ordinary request-scoped operations and do throw.
12
+ *
13
+ * Full design: `docs/initiatives/merge-track-record.md`.
14
+ */
15
+ export class MergeTrackRecordService {
16
+ deps;
17
+ constructor(deps) {
18
+ this.deps = deps;
19
+ }
20
+ /**
21
+ * Classify a block's pull request from the files it changed — ONE VCS call, then the pure
22
+ * `classifyChangedFiles` precedence rule (highest-ranked class present wins).
23
+ *
24
+ * Returns `unknown` (never throws) when there is no repo context, the bound client cannot
25
+ * enumerate a PR's files, the block has no PR number, or the call fails. `unknown` is inert by
26
+ * design: `resolveMergeClassRule` never matches it, so a transient VCS outage can neither
27
+ * widen nor tighten the merge policy.
28
+ */
29
+ async classify(workspaceId, block) {
30
+ const absent = { changeClass: 'unknown', fileCount: 0 };
31
+ const prNumber = block.pullRequest?.number;
32
+ if (prNumber == null)
33
+ return absent;
34
+ try {
35
+ const ctx = await this.deps.resolveRunRepoContext?.(workspaceId, block.id);
36
+ if (!ctx)
37
+ return absent;
38
+ // Capture the repo identity even when the changed-file list is unreadable: the class then
39
+ // degrades to `unknown` (inert by design), but the record stays ATTRIBUTABLE, so a PR later
40
+ // merged on the provider is still matched by `(repoId, prNumber)`.
41
+ const repo = { repoId: ctx.repoId, provider: ctx.provider ?? null };
42
+ const files = await ctx.repo.listChangedFiles?.(prNumber);
43
+ if (!files)
44
+ return { ...absent, ...repo };
45
+ return { ...classifyChangedFiles(files.map((f) => f.path)), ...repo };
46
+ }
47
+ catch {
48
+ return absent;
49
+ }
50
+ }
51
+ /**
52
+ * Record a merger step's decision. Idempotent by construction: the id is derived from the
53
+ * run (`mtr_<executionId>`) and the insert is first-write-wins, so the durable driver
54
+ * re-resolving a step whose merge already landed cannot duplicate the row — nor clobber an
55
+ * effort tag a human has since added.
56
+ *
57
+ * Returns the stored record, or null when nothing could be written (no repository, or the
58
+ * write threw). Callers treat null as "no record" and carry on: the merge is what matters.
59
+ */
60
+ async recordDecision(workspaceId, input) {
61
+ try {
62
+ const now = this.deps.clock.now();
63
+ const classification = input.classification ?? (await this.classify(workspaceId, input.block));
64
+ const terminal = input.decision !== 'pending_review';
65
+ const record = {
66
+ id: `mtr_${input.executionId}`,
67
+ blockId: input.block.id,
68
+ executionId: input.executionId,
69
+ changeClass: classification.changeClass,
70
+ changedFileCount: classification.fileCount > 0 ? classification.fileCount : null,
71
+ complexity: input.assessment?.complexity ?? null,
72
+ risk: input.assessment?.risk ?? null,
73
+ impact: input.assessment?.impact ?? null,
74
+ riskPolicyId: input.riskPolicyId ?? null,
75
+ riskPolicyName: input.riskPolicyName ?? null,
76
+ decision: input.decision,
77
+ reviewEffort: null,
78
+ prNumber: input.block.pullRequest?.number ?? null,
79
+ prUrl: input.block.pullRequest?.url ?? null,
80
+ repoId: input.repo?.repoId ?? classification.repoId ?? null,
81
+ provider: input.repo?.provider ?? classification.provider ?? null,
82
+ createdAt: now,
83
+ resolvedAt: terminal ? now : null,
84
+ taggedAt: null,
85
+ };
86
+ return await this.deps.mergeTrackRecordRepository.insertIfAbsent(workspaceId, record);
87
+ }
88
+ catch {
89
+ return null;
90
+ }
91
+ }
92
+ /**
93
+ * Settle a record that was left `pending_review` once a human resolved it — merged it through
94
+ * cat-factory, merged it on the provider, or declined. Optionally tags the review effort in
95
+ * the same write (the merge card's one-tap confirm-and-tag).
96
+ *
97
+ * Best-effort and silent: a run with no record (classification never ran, or the merge came
98
+ * from a pipeline with no `merger` step) is simply skipped. Returns the record's id when one
99
+ * was updated, so a caller can put it on a notification payload.
100
+ *
101
+ * Only a still-`pending_review` record is SETTLED here, mirroring {@link recordExternalMerge}:
102
+ * a landed PR must never be re-decided by a late action on a stale card. The concrete case is
103
+ * a PR merged on the provider (recorded `external_merged`) whose merge-review card is then
104
+ * dismissed — without this guard that dismissal would rewrite a merged PR as `rejected` and
105
+ * corrupt the very rollup the record exists to produce. A later EFFORT TAG is still applied,
106
+ * because tagging is orthogonal to the decision and is welcome whenever it arrives.
107
+ */
108
+ async resolveDecision(workspaceId, executionId, decision, reviewEffort) {
109
+ try {
110
+ const existing = await this.deps.mergeTrackRecordRepository.getByExecution(workspaceId, executionId);
111
+ if (!existing)
112
+ return null;
113
+ const now = this.deps.clock.now();
114
+ const settled = existing.decision !== 'pending_review';
115
+ const tag = reviewEffort !== undefined ? { reviewEffort, taggedAt: reviewEffort ? now : null } : {};
116
+ if (settled && Object.keys(tag).length === 0)
117
+ return existing.id;
118
+ await this.deps.mergeTrackRecordRepository.patch(workspaceId, existing.id, {
119
+ // An already-terminal decision stands; only the tag is folded in.
120
+ ...(settled ? {} : { decision, resolvedAt: now }),
121
+ ...tag,
122
+ });
123
+ return existing.id;
124
+ }
125
+ catch {
126
+ return null;
127
+ }
128
+ }
129
+ /**
130
+ * Attribute an EXTERNAL merge: a human merged a PR directly on the VCS provider, bypassing
131
+ * cat-factory's merge card. Looks the record up by `(repoId, prNumber)` — which a merger-step
132
+ * record already carries — so no unindexed scan of the blocks' JSON PR column is needed, and
133
+ * the feature is correctly scoped to PRs cat-factory opened and was waiting on.
134
+ *
135
+ * Returns the settled record when this delivery is the one that flipped it (so the caller
136
+ * raises exactly ONE tag-request nudge), and null when there is nothing to attribute or the
137
+ * record was already resolved — webhook deliveries are re-sent, so this must be idempotent.
138
+ */
139
+ async recordExternalMerge(workspaceId, repoId, prNumber) {
140
+ try {
141
+ const existing = await this.deps.mergeTrackRecordRepository.getByPullRequest(workspaceId, repoId, prNumber);
142
+ // Only a still-pending record is attributable. An already-resolved one either merged
143
+ // through cat-factory (this delivery is the echo of our own merge) or was already
144
+ // attributed by an earlier redelivery.
145
+ if (!existing || existing.decision !== 'pending_review')
146
+ return null;
147
+ const now = this.deps.clock.now();
148
+ await this.deps.mergeTrackRecordRepository.patch(workspaceId, existing.id, {
149
+ decision: 'external_merged',
150
+ resolvedAt: now,
151
+ });
152
+ return { ...existing, decision: 'external_merged', resolvedAt: now };
153
+ }
154
+ catch {
155
+ return null;
156
+ }
157
+ }
158
+ /** A record by id (for the tag surface and the notification card's context). */
159
+ async get(workspaceId, id) {
160
+ await requireWorkspace(this.deps.workspaceRepository, workspaceId);
161
+ return this.deps.mergeTrackRecordRepository.get(workspaceId, id);
162
+ }
163
+ /** The most recent record for a block — the seam the block-scoped merge controls tag through. */
164
+ async getLatestByBlock(workspaceId, blockId) {
165
+ await requireWorkspace(this.deps.workspaceRepository, workspaceId);
166
+ return this.deps.mergeTrackRecordRepository.getLatestByBlock(workspaceId, blockId);
167
+ }
168
+ /**
169
+ * Tag (or clear) how much review effort a human spent. Unlike the write paths above this is a
170
+ * deliberate user action, so an unknown id is a real 404 rather than a silent skip.
171
+ */
172
+ async tag(workspaceId, id, reviewEffort) {
173
+ await requireWorkspace(this.deps.workspaceRepository, workspaceId);
174
+ const existing = assertFound(await this.deps.mergeTrackRecordRepository.get(workspaceId, id), 'MergeTrackRecord', id);
175
+ const taggedAt = reviewEffort ? this.deps.clock.now() : null;
176
+ await this.deps.mergeTrackRecordRepository.patch(workspaceId, id, { reviewEffort, taggedAt });
177
+ return { ...existing, reviewEffort, taggedAt };
178
+ }
179
+ /**
180
+ * Per-change-class rollups for the workspace: ONE SQL aggregate, then every class the query
181
+ * returned nothing for is filled in as an empty rollup so the caller always gets the full,
182
+ * stably-ordered set (the preset editor renders a row per class whether or not it has data).
183
+ */
184
+ async rollups(workspaceId) {
185
+ await requireWorkspace(this.deps.workspaceRepository, workspaceId);
186
+ const rows = await this.deps.mergeTrackRecordRepository.rollupByClass(workspaceId);
187
+ const byClass = new Map(rows.map((r) => [r.changeClass, r]));
188
+ return CHANGE_CLASSES.map((c) => byClass.get(c) ?? emptyMergeClassRollup(c));
189
+ }
190
+ }
191
+ //# sourceMappingURL=MergeTrackRecordService.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MergeTrackRecordService.js","sourceRoot":"","sources":["../../../src/modules/merge/MergeTrackRecordService.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"RiskPolicyService.d.ts","sourceRoot":"","sources":["../../../src/modules/merge/RiskPolicyService.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,KAAK,EACL,qBAAqB,EACrB,gBAAgB,EAChB,WAAW,EACX,oBAAoB,EACpB,UAAU,EACV,oBAAoB,EACpB,qBAAqB,EACrB,mBAAmB,EACpB,MAAM,qBAAqB,CAAA;AAU5B,MAAM,WAAW,6BAA6B;IAC5C,oBAAoB,EAAE,oBAAoB,CAAA;IAC1C,mBAAmB,EAAE,mBAAmB,CAAA;IACxC,WAAW,EAAE,WAAW,CAAA;IACxB,KAAK,EAAE,KAAK,CAAA;IACZ;;;;OAIG;IACH,eAAe,CAAC,EAAE,gBAAgB,CAAC,oBAAoB,CAAC,CAAA;CACzD;AAED;;;;;;;;GAQG;AACH,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAsB;IAC9C,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,KAAK,CAAC,CAAwC;IAE/D,YAAY,IAAI,EAAE,6BAA6B,EAM9C;IAED;;;;OAIG;YACW,UAAU;IAIxB,kFAAkF;IAC5E,IAAI,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAIrD;IAED,uFAAuF;IACjF,MAAM,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,qBAAqB,GAAG,OAAO,CAAC,UAAU,CAAC,CAyBnF;IAED,+EAA+E;IACzE,MAAM,CAAC,WAAW,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,qBAAqB,GAAG,OAAO,CAAC,UAAU,CAAC,CAsC/F;IAED,6DAA6D;IACvD,MAAM,CAAC,WAAW,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAQ3D;IAED;;;;;;;;;;;OAWG;IACG,MAAM,CAAC,WAAW,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAuBjE;IAED,sFAAsF;YACxE,YAAY;IAiB1B,2FAA2F;IAC3F,OAAO,CAAC,QAAQ;CAoBjB"}
1
+ {"version":3,"file":"RiskPolicyService.d.ts","sourceRoot":"","sources":["../../../src/modules/merge/RiskPolicyService.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,KAAK,EACL,qBAAqB,EACrB,gBAAgB,EAChB,WAAW,EACX,oBAAoB,EACpB,UAAU,EACV,oBAAoB,EACpB,qBAAqB,EACrB,mBAAmB,EACpB,MAAM,qBAAqB,CAAA;AAU5B,MAAM,WAAW,6BAA6B;IAC5C,oBAAoB,EAAE,oBAAoB,CAAA;IAC1C,mBAAmB,EAAE,mBAAmB,CAAA;IACxC,WAAW,EAAE,WAAW,CAAA;IACxB,KAAK,EAAE,KAAK,CAAA;IACZ;;;;OAIG;IACH,eAAe,CAAC,EAAE,gBAAgB,CAAC,oBAAoB,CAAC,CAAA;CACzD;AAED;;;;;;;;GAQG;AACH,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAsB;IAC9C,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,KAAK,CAAC,CAAwC;IAE/D,YAAY,IAAI,EAAE,6BAA6B,EAM9C;IAED;;;;OAIG;YACW,UAAU;IAIxB,kFAAkF;IAC5E,IAAI,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAIrD;IAED,uFAAuF;IACjF,MAAM,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,qBAAqB,GAAG,OAAO,CAAC,UAAU,CAAC,CA0BnF;IAED,+EAA+E;IACzE,MAAM,CAAC,WAAW,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,qBAAqB,GAAG,OAAO,CAAC,UAAU,CAAC,CAyC/F;IAED,6DAA6D;IACvD,MAAM,CAAC,WAAW,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAQ3D;IAED;;;;;;;;;;;OAWG;IACG,MAAM,CAAC,WAAW,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAuBjE;IAED,sFAAsF;YACxE,YAAY;IAiB1B,2FAA2F;IAC3F,OAAO,CAAC,QAAQ;CAqBjB"}
@@ -54,6 +54,7 @@ export class RiskPolicyService {
54
54
  humanReviewGraceMinutes: input.humanReviewGraceMinutes,
55
55
  autoMergeEnabled: input.autoMergeEnabled,
56
56
  forkDecision: input.forkDecision ?? null,
57
+ classRules: input.classRules,
57
58
  // The very first preset must be the default; otherwise honour the request.
58
59
  isDefault: existing.length === 0 ? true : input.isDefault,
59
60
  createdAt: this.clock.now(),
@@ -96,6 +97,9 @@ export class RiskPolicyService {
96
97
  : {}),
97
98
  ...(patch.autoMergeEnabled !== undefined ? { autoMergeEnabled: patch.autoMergeEnabled } : {}),
98
99
  ...(patch.forkDecision !== undefined ? { forkDecision: patch.forkDecision } : {}),
100
+ // Replaces the whole map rather than merging, so clearing a class's rule is a plain
101
+ // omission from the submitted set (there is no "delete this one key" wire shape).
102
+ ...(patch.classRules !== undefined ? { classRules: patch.classRules } : {}),
99
103
  ...(patch.isDefault !== undefined ? { isDefault: patch.isDefault } : {}),
100
104
  };
101
105
  await this.presets.upsert(workspaceId, updated);
@@ -181,6 +185,7 @@ export class RiskPolicyService {
181
185
  humanReviewGraceMinutes: seed.humanReviewGraceMinutes,
182
186
  autoMergeEnabled: seed.autoMergeEnabled,
183
187
  forkDecision: seed.forkDecision,
188
+ classRules: seed.classRules,
184
189
  isDefault: seed.isDefault,
185
190
  version: seed.version,
186
191
  };
@@ -1 +1 @@
1
- {"version":3,"file":"RiskPolicyService.js","sourceRoot":"","sources":["../../../src/modules/merge/RiskPolicyService.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"RiskPolicyService.js","sourceRoot":"","sources":["../../../src/modules/merge/RiskPolicyService.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ import type { MergeTrackRecordService } from './MergeTrackRecordService.js';
2
+ import type { NotificationService } from '../notifications/NotificationService.js';
3
+ export interface ExternalMergeObserverDeps {
4
+ trackRecord: MergeTrackRecordService;
5
+ /** Absent ⇒ the record is still attributed, just without the tag-request nudge. */
6
+ notifications?: NotificationService;
7
+ }
8
+ /**
9
+ * Build the observer the GitHub/GitLab webhook ingest calls when a pull request is merged
10
+ * OUTSIDE cat-factory — a human clicking merge on the provider rather than acting on the
11
+ * merge-review card. Two things follow:
12
+ *
13
+ * 1. The run's merge track record is attributed `external_merged` (it would otherwise sit at
14
+ * `pending_review` forever, overstating the class's un-decided share).
15
+ * 2. A `merge_tag_request` card asks for the one-tap reviewer-effort tag that the merge card
16
+ * would have collected. It is a NUDGE: dismissible, gates nothing, and the record stays
17
+ * perfectly valid untagged.
18
+ *
19
+ * `recordExternalMerge` returns a record ONLY on the delivery that actually flipped it, so a
20
+ * webhook redelivery — or the echo of cat-factory's own merge — raises no duplicate card.
21
+ *
22
+ * Lives in orchestration (not integrations) because it spans the track record and the
23
+ * notification inbox; the webhook service itself sees only a narrow
24
+ * `(workspaceId, repoId, prNumber)` callback and knows nothing about either.
25
+ */
26
+ export declare function makeExternalMergeObserver(deps: ExternalMergeObserverDeps): (workspaceId: string, repoId: string, prNumber: number) => Promise<void>;
27
+ //# sourceMappingURL=externalMergeObserver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"externalMergeObserver.d.ts","sourceRoot":"","sources":["../../../src/modules/merge/externalMergeObserver.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAA;AAC3E,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,yCAAyC,CAAA;AAElF,MAAM,WAAW,yBAAyB;IACxC,WAAW,EAAE,uBAAuB,CAAA;IACpC,mFAAmF;IACnF,aAAa,CAAC,EAAE,mBAAmB,CAAA;CACpC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,yBAAyB,CACvC,IAAI,EAAE,yBAAyB,GAC9B,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAoB1E"}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Build the observer the GitHub/GitLab webhook ingest calls when a pull request is merged
3
+ * OUTSIDE cat-factory — a human clicking merge on the provider rather than acting on the
4
+ * merge-review card. Two things follow:
5
+ *
6
+ * 1. The run's merge track record is attributed `external_merged` (it would otherwise sit at
7
+ * `pending_review` forever, overstating the class's un-decided share).
8
+ * 2. A `merge_tag_request` card asks for the one-tap reviewer-effort tag that the merge card
9
+ * would have collected. It is a NUDGE: dismissible, gates nothing, and the record stays
10
+ * perfectly valid untagged.
11
+ *
12
+ * `recordExternalMerge` returns a record ONLY on the delivery that actually flipped it, so a
13
+ * webhook redelivery — or the echo of cat-factory's own merge — raises no duplicate card.
14
+ *
15
+ * Lives in orchestration (not integrations) because it spans the track record and the
16
+ * notification inbox; the webhook service itself sees only a narrow
17
+ * `(workspaceId, repoId, prNumber)` callback and knows nothing about either.
18
+ */
19
+ export function makeExternalMergeObserver(deps) {
20
+ return async (workspaceId, repoId, prNumber) => {
21
+ const record = await deps.trackRecord.recordExternalMerge(workspaceId, repoId, prNumber);
22
+ if (!record)
23
+ return;
24
+ await deps.notifications?.raise(workspaceId, {
25
+ type: 'merge_tag_request',
26
+ blockId: record.blockId,
27
+ executionId: record.executionId,
28
+ title: 'How much review did that PR need?',
29
+ body: `This PR was merged directly on the provider, so its review effort was not recorded. ` +
30
+ `One tap tells the merge policy how much review a ${record.changeClass} change actually ` +
31
+ `needed — or dismiss this card.`,
32
+ payload: {
33
+ ...(record.prUrl ? { prUrl: record.prUrl } : {}),
34
+ ...(record.changeClass !== 'unknown' ? { changeClass: record.changeClass } : {}),
35
+ mergeTrackRecordId: record.id,
36
+ },
37
+ });
38
+ };
39
+ }
40
+ //# sourceMappingURL=externalMergeObserver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"externalMergeObserver.js","sourceRoot":"","sources":["../../../src/modules/merge/externalMergeObserver.ts"],"names":[],"mappings":"AASA;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,yBAAyB,CACvC,IAA+B;IAE/B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE;QAC7C,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,mBAAmB,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAA;QACxF,IAAI,CAAC,MAAM;YAAE,OAAM;QACnB,MAAM,IAAI,CAAC,aAAa,EAAE,KAAK,CAAC,WAAW,EAAE;YAC3C,IAAI,EAAE,mBAAmB;YACzB,OAAO,EAAE,MAAM,CAAC,OAAO;YACvB,WAAW,EAAE,MAAM,CAAC,WAAW;YAC/B,KAAK,EAAE,mCAAmC;YAC1C,IAAI,EACF,sFAAsF;gBACtF,oDAAoD,MAAM,CAAC,WAAW,mBAAmB;gBACzF,gCAAgC;YAClC,OAAO,EAAE;gBACP,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBAChD,GAAG,CAAC,MAAM,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,MAAM,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBAChF,kBAAkB,EAAE,MAAM,CAAC,EAAE;aAC9B;SACF,CAAC,CAAA;IACJ,CAAC,CAAA;AACH,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cat-factory/orchestration",
3
- "version": "0.141.0",
3
+ "version": "0.143.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.35",
28
- "@cat-factory/agents": "0.69.9",
29
- "@cat-factory/caching": "0.10.42",
30
- "@cat-factory/contracts": "0.166.0",
31
- "@cat-factory/integrations": "0.99.0",
32
- "@cat-factory/kernel": "0.160.0",
33
- "@cat-factory/prompt-fragments": "0.14.14",
34
- "@cat-factory/sandbox": "0.9.147",
35
- "@cat-factory/spend": "0.12.86",
36
- "@cat-factory/workspaces": "0.18.2"
28
+ "@cat-factory/agents": "0.70.0",
29
+ "@cat-factory/caching": "0.10.44",
30
+ "@cat-factory/contracts": "0.168.0",
31
+ "@cat-factory/integrations": "0.100.1",
32
+ "@cat-factory/kernel": "0.162.0",
33
+ "@cat-factory/prompt-fragments": "0.14.16",
34
+ "@cat-factory/sandbox": "0.9.149",
35
+ "@cat-factory/spend": "0.12.88",
36
+ "@cat-factory/workspaces": "0.18.4"
37
37
  },
38
38
  "devDependencies": {
39
39
  "typescript": "7.0.2",
40
40
  "vitest": "^4.1.10",
41
- "@cat-factory/sandbox-fixtures": "0.7.197"
41
+ "@cat-factory/sandbox-fixtures": "0.7.199"
42
42
  },
43
43
  "scripts": {
44
44
  "build": "tsc -b tsconfig.build.json",