@cat-factory/worker 0.184.0 → 0.185.1
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/infrastructure/repositories/D1RiskPolicyRepository.d.ts +6 -5
- package/dist/infrastructure/repositories/D1RiskPolicyRepository.d.ts.map +1 -1
- package/dist/infrastructure/repositories/D1RiskPolicyRepository.js +59 -21
- package/dist/infrastructure/repositories/D1RiskPolicyRepository.js.map +1 -1
- package/migrations/0090_unattended_risk_policy.sql +62 -0
- package/package.json +18 -18
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import type { RiskPolicyRepository } from '@cat-factory/kernel';
|
|
2
|
-
import type { RiskPolicy } from '@cat-factory/contracts';
|
|
2
|
+
import type { RiskPolicy, RiskPolicyDefaultScope } from '@cat-factory/contracts';
|
|
3
3
|
import type { D1Database } from '@cloudflare/workers-types';
|
|
4
4
|
/**
|
|
5
5
|
* Merge threshold presets, one row per preset in `merge_threshold_presets`
|
|
6
|
-
* (migration 0024). Enforces the single-default invariant
|
|
7
|
-
*
|
|
8
|
-
*
|
|
6
|
+
* (migration 0024, the second default scope added by 0090). Enforces the single-default invariant
|
|
7
|
+
* PER SCOPE: promoting a preset to one of the two defaults demotes every other holder of THAT flag
|
|
8
|
+
* in the workspace, in one statement before the upsert, leaving the other scope alone. Neither
|
|
9
|
+
* scope's default can be removed (the service keeps that rule too).
|
|
9
10
|
*/
|
|
10
11
|
export declare class D1RiskPolicyRepository implements RiskPolicyRepository {
|
|
11
12
|
private readonly db;
|
|
@@ -14,7 +15,7 @@ export declare class D1RiskPolicyRepository implements RiskPolicyRepository {
|
|
|
14
15
|
});
|
|
15
16
|
get(workspaceId: string, id: string): Promise<RiskPolicy | null>;
|
|
16
17
|
list(workspaceId: string): Promise<RiskPolicy[]>;
|
|
17
|
-
getDefault(workspaceId: string): Promise<RiskPolicy | null>;
|
|
18
|
+
getDefault(workspaceId: string, scope: RiskPolicyDefaultScope): Promise<RiskPolicy | null>;
|
|
18
19
|
upsert(workspaceId: string, preset: RiskPolicy): Promise<void>;
|
|
19
20
|
remove(workspaceId: string, id: string): Promise<void>;
|
|
20
21
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"D1RiskPolicyRepository.d.ts","sourceRoot":"","sources":["../../../src/infrastructure/repositories/D1RiskPolicyRepository.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAA;AAC/D,OAAO,KAAK,EAGV,UAAU,
|
|
1
|
+
{"version":3,"file":"D1RiskPolicyRepository.d.ts","sourceRoot":"","sources":["../../../src/infrastructure/repositories/D1RiskPolicyRepository.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAA;AAC/D,OAAO,KAAK,EAGV,UAAU,EACV,sBAAsB,EAKvB,MAAM,wBAAwB,CAAA;AAC/B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAA;AAgF3D;;;;;;GAMG;AACH,qBAAa,sBAAuB,YAAW,oBAAoB;IACjE,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAY;IAE/B,YAAY,EAAE,EAAE,EAAE,EAAE;QAAE,EAAE,EAAE,UAAU,CAAA;KAAE,EAErC;IAEK,GAAG,CAAC,WAAW,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAMrE;IAEK,IAAI,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAQrD;IAEK,UAAU,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,sBAAsB,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAY/F;IAEK,MAAM,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAoGnE;IAEK,MAAM,CAAC,WAAW,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAQ3D;CACF"}
|
|
@@ -30,16 +30,28 @@ function rowToPreset(row) {
|
|
|
30
30
|
submissionClassesByRole: row.submission_classes_by_role
|
|
31
31
|
? JSON.parse(row.submission_classes_by_role)
|
|
32
32
|
: {},
|
|
33
|
+
// The column is NOT NULL DEFAULT 'attended', and the value is narrowed rather than cast for
|
|
34
|
+
// the reason every closed persisted vocabulary is: a row written under a member later retired
|
|
35
|
+
// must not be read back as that member. Anything unrecognised is `attended`, which is the
|
|
36
|
+
// posture that stops for a person — never a licence this row cannot be shown to have granted.
|
|
37
|
+
autonomy: row.autonomy === 'unattended' ? 'unattended' : 'attended',
|
|
33
38
|
isDefault: row.is_default === 1,
|
|
39
|
+
isUnattendedDefault: row.is_unattended_default === 1,
|
|
34
40
|
...(row.version != null ? { version: row.version } : {}),
|
|
35
41
|
createdAt: row.created_at,
|
|
36
42
|
};
|
|
37
43
|
}
|
|
44
|
+
/** The column one default scope is stored in; the ONE place that mapping lives on this facade. */
|
|
45
|
+
const DEFAULT_COLUMN = {
|
|
46
|
+
interactive: 'is_default',
|
|
47
|
+
unattended: 'is_unattended_default',
|
|
48
|
+
};
|
|
38
49
|
/**
|
|
39
50
|
* Merge threshold presets, one row per preset in `merge_threshold_presets`
|
|
40
|
-
* (migration 0024). Enforces the single-default invariant
|
|
41
|
-
*
|
|
42
|
-
*
|
|
51
|
+
* (migration 0024, the second default scope added by 0090). Enforces the single-default invariant
|
|
52
|
+
* PER SCOPE: promoting a preset to one of the two defaults demotes every other holder of THAT flag
|
|
53
|
+
* in the workspace, in one statement before the upsert, leaving the other scope alone. Neither
|
|
54
|
+
* scope's default can be removed (the service keeps that rule too).
|
|
43
55
|
*/
|
|
44
56
|
export class D1RiskPolicyRepository {
|
|
45
57
|
db;
|
|
@@ -60,26 +72,48 @@ export class D1RiskPolicyRepository {
|
|
|
60
72
|
.all();
|
|
61
73
|
return results.map(rowToPreset);
|
|
62
74
|
}
|
|
63
|
-
async getDefault(workspaceId) {
|
|
75
|
+
async getDefault(workspaceId, scope) {
|
|
76
|
+
// The column name is interpolated from a `Record` over a CLOSED picklist, never from a caller
|
|
77
|
+
// string: there is no value of `scope` the type admits that is not one of the two literals.
|
|
64
78
|
const row = await this.db
|
|
65
79
|
.prepare(`SELECT * FROM merge_threshold_presets
|
|
66
|
-
WHERE workspace_id = ? AND
|
|
80
|
+
WHERE workspace_id = ? AND ${DEFAULT_COLUMN[scope]} = 1
|
|
67
81
|
ORDER BY created_at ASC LIMIT 1`)
|
|
68
82
|
.bind(workspaceId)
|
|
69
83
|
.first();
|
|
70
84
|
return row ? rowToPreset(row) : null;
|
|
71
85
|
}
|
|
72
86
|
async upsert(workspaceId, preset) {
|
|
73
|
-
// Promoting this preset to default demotes any other
|
|
74
|
-
// single-default invariant holds.
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
87
|
+
// Promoting this preset to a default demotes any other holder of THAT flag first, so the
|
|
88
|
+
// single-default invariant holds per scope. Separate statements rather than one, because the
|
|
89
|
+
// flags are independent: promoting the unattended default must leave the in-app one alone.
|
|
90
|
+
//
|
|
91
|
+
// ONE `batch`, which D1 runs as a single implicit transaction, mirroring the Drizzle
|
|
92
|
+
// repository's explicit `db.transaction`. Run loose, a demote that committed before a failed
|
|
93
|
+
// INSERT (a D1 error, an isolate eviction between the two awaits) would leave the workspace
|
|
94
|
+
// with NO row holding that flag — `getDefault` then returns null and every run of that scope
|
|
95
|
+
// silently falls to `FALLBACK_RISK_POLICY`, which auto-merges nothing. The two facades claim
|
|
96
|
+
// to be behaviourally identical, and a partial-failure state only one of them can reach is
|
|
97
|
+
// exactly the drift that claim exists to prevent.
|
|
98
|
+
const demotions = [
|
|
99
|
+
...(preset.isDefault
|
|
100
|
+
? [
|
|
101
|
+
this.db
|
|
102
|
+
.prepare(`UPDATE merge_threshold_presets SET is_default = 0
|
|
103
|
+
WHERE workspace_id = ? AND id <> ?`)
|
|
104
|
+
.bind(workspaceId, preset.id),
|
|
105
|
+
]
|
|
106
|
+
: []),
|
|
107
|
+
...(preset.isUnattendedDefault
|
|
108
|
+
? [
|
|
109
|
+
this.db
|
|
110
|
+
.prepare(`UPDATE merge_threshold_presets SET is_unattended_default = 0
|
|
111
|
+
WHERE workspace_id = ? AND id <> ?`)
|
|
112
|
+
.bind(workspaceId, preset.id),
|
|
113
|
+
]
|
|
114
|
+
: []),
|
|
115
|
+
];
|
|
116
|
+
const write = this.db
|
|
83
117
|
.prepare(`INSERT INTO merge_threshold_presets
|
|
84
118
|
(workspace_id, id, name, max_complexity, max_risk, max_impact, ci_max_attempts,
|
|
85
119
|
max_requirement_iterations, max_requirement_concern_allowed,
|
|
@@ -87,8 +121,9 @@ export class D1RiskPolicyRepository {
|
|
|
87
121
|
release_watch_window_minutes, release_max_attempts, human_review_grace_minutes,
|
|
88
122
|
judge_min_score, judge_max_bounces,
|
|
89
123
|
auto_merge_enabled, fork_decision, class_rules, class_rules_by_role, dry_run_roles,
|
|
90
|
-
submission_classes_by_role, version, is_default,
|
|
91
|
-
|
|
124
|
+
submission_classes_by_role, version, autonomy, is_default, is_unattended_default,
|
|
125
|
+
created_at)
|
|
126
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
92
127
|
ON CONFLICT (workspace_id, id) DO UPDATE SET
|
|
93
128
|
name = excluded.name,
|
|
94
129
|
max_complexity = excluded.max_complexity,
|
|
@@ -110,13 +145,16 @@ export class D1RiskPolicyRepository {
|
|
|
110
145
|
dry_run_roles = excluded.dry_run_roles,
|
|
111
146
|
submission_classes_by_role = excluded.submission_classes_by_role,
|
|
112
147
|
version = excluded.version,
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
148
|
+
autonomy = excluded.autonomy,
|
|
149
|
+
is_default = excluded.is_default,
|
|
150
|
+
is_unattended_default = excluded.is_unattended_default`)
|
|
151
|
+
.bind(workspaceId, preset.id, preset.name, preset.maxComplexity, preset.maxRisk, preset.maxImpact, preset.ciMaxAttempts, preset.maxRequirementIterations, preset.maxRequirementConcernAllowed, preset.maxTesterQualityIterations, preset.releaseWatchWindowMinutes, preset.releaseMaxAttempts, preset.humanReviewGraceMinutes, preset.judgeMinScore, preset.judgeMaxBounces, preset.autoMergeEnabled ? 1 : 0, preset.forkDecision ? JSON.stringify(preset.forkDecision) : null, JSON.stringify(preset.classRules ?? {}), JSON.stringify(preset.classRulesByRole ?? {}), JSON.stringify(preset.dryRunRoles ?? []), JSON.stringify(preset.submissionClassesByRole ?? {}), preset.version ?? null, preset.autonomy, preset.isDefault ? 1 : 0, preset.isUnattendedDefault ? 1 : 0, preset.createdAt);
|
|
152
|
+
await this.db.batch([...demotions, write]);
|
|
116
153
|
}
|
|
117
154
|
async remove(workspaceId, id) {
|
|
118
155
|
await this.db
|
|
119
|
-
.prepare(`DELETE FROM merge_threshold_presets
|
|
156
|
+
.prepare(`DELETE FROM merge_threshold_presets
|
|
157
|
+
WHERE workspace_id = ? AND id = ? AND is_default = 0 AND is_unattended_default = 0`)
|
|
120
158
|
.bind(workspaceId, id)
|
|
121
159
|
.run();
|
|
122
160
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"D1RiskPolicyRepository.js","sourceRoot":"","sources":["../../../src/infrastructure/repositories/D1RiskPolicyRepository.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"D1RiskPolicyRepository.js","sourceRoot":"","sources":["../../../src/infrastructure/repositories/D1RiskPolicyRepository.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
-- A workspace's SECOND default risk policy: the one that governs a run nothing is watching (the
|
|
2
|
+
-- public API, a tracker dispatch, a schedule fire), plus the `autonomy` posture that says whether
|
|
3
|
+
-- such a run answers the parks its own automatic loops raise instead of stopping for a person.
|
|
4
|
+
--
|
|
5
|
+
-- Two columns and a backfill, mirrored by the `autonomy` / `is_unattended_default` columns on the
|
|
6
|
+
-- Drizzle `merge_threshold_presets` table.
|
|
7
|
+
--
|
|
8
|
+
-- The BACKFILL is the load-bearing half, because a scope with no default resolves
|
|
9
|
+
-- `FALLBACK_RISK_POLICY`, which auto-merges nothing: shipping the column without filling it would
|
|
10
|
+
-- silently stop every API-started task in every existing workspace from landing. So every existing
|
|
11
|
+
-- library gains the new built-in AND names an unattended default, in the two steps below.
|
|
12
|
+
|
|
13
|
+
ALTER TABLE merge_threshold_presets ADD COLUMN autonomy TEXT NOT NULL DEFAULT 'attended';
|
|
14
|
+
ALTER TABLE merge_threshold_presets ADD COLUMN is_unattended_default INTEGER NOT NULL DEFAULT 0;
|
|
15
|
+
|
|
16
|
+
CREATE INDEX IF NOT EXISTS idx_merge_presets_unattended_default
|
|
17
|
+
ON merge_threshold_presets (workspace_id, is_unattended_default);
|
|
18
|
+
|
|
19
|
+
-- 1. Materialise `mp_unattended` in every workspace that already has a library, CLONED FROM THAT
|
|
20
|
+
-- WORKSPACE'S OWN DEFAULT with the single field this feature is about flipped.
|
|
21
|
+
--
|
|
22
|
+
-- Cloning, rather than writing the catalog's stock values, is what keeps the promise that
|
|
23
|
+
-- landing authority never moves underneath an operator who has already stated theirs. A
|
|
24
|
+
-- built-in is editable IN PLACE, so a row's id says nothing about whether its ceilings are
|
|
25
|
+
-- still the ones we shipped: a workspace that tightened its `Balanced` down to
|
|
26
|
+
-- `maxRisk: 0.1, autoMergeEnabled: 0` keeps `id = 'mp_balanced'`, and seeding stock ceilings
|
|
27
|
+
-- beside it would hand every API-started run a wider licence to land than the operator's own
|
|
28
|
+
-- default grants. Every ceiling, budget and per-role restriction is inherited here
|
|
29
|
+
-- (`dry_run_roles` and `submission_classes_by_role` above all, being the role-scoped landing
|
|
30
|
+
-- authority itself); the ONLY difference from the row it clones is `autonomy`, so all the
|
|
31
|
+
-- workspace gains is a run that stops waiting on a person who is not there.
|
|
32
|
+
--
|
|
33
|
+
-- `INSERT OR IGNORE` rather than an upsert: a workspace that somehow already holds the id keeps
|
|
34
|
+
-- whatever an operator put there.
|
|
35
|
+
INSERT OR IGNORE INTO merge_threshold_presets (
|
|
36
|
+
workspace_id, id, name, max_complexity, max_risk, max_impact, ci_max_attempts,
|
|
37
|
+
max_requirement_iterations, max_requirement_concern_allowed, max_tester_quality_iterations,
|
|
38
|
+
release_watch_window_minutes, release_max_attempts, human_review_grace_minutes,
|
|
39
|
+
judge_min_score, judge_max_bounces, auto_merge_enabled, fork_decision, class_rules,
|
|
40
|
+
class_rules_by_role, dry_run_roles, submission_classes_by_role, version, autonomy,
|
|
41
|
+
is_default, is_unattended_default, created_at
|
|
42
|
+
)
|
|
43
|
+
SELECT
|
|
44
|
+
d.workspace_id, 'mp_unattended', 'Unattended delivery',
|
|
45
|
+
d.max_complexity, d.max_risk, d.max_impact, d.ci_max_attempts,
|
|
46
|
+
d.max_requirement_iterations, d.max_requirement_concern_allowed, d.max_tester_quality_iterations,
|
|
47
|
+
d.release_watch_window_minutes, d.release_max_attempts, d.human_review_grace_minutes,
|
|
48
|
+
d.judge_min_score, d.judge_max_bounces, d.auto_merge_enabled, d.fork_decision, d.class_rules,
|
|
49
|
+
d.class_rules_by_role, d.dry_run_roles, d.submission_classes_by_role, 1, 'unattended',
|
|
50
|
+
0, 1, d.created_at + 1
|
|
51
|
+
FROM merge_threshold_presets d
|
|
52
|
+
WHERE d.is_default = 1;
|
|
53
|
+
|
|
54
|
+
-- 2. A workspace that ALREADY held `mp_unattended` kept its own row above and so never took the
|
|
55
|
+
-- flag with it. Name that row the unattended default, but only where the workspace still has
|
|
56
|
+
-- none, so this can never demote a flag step 1 just set.
|
|
57
|
+
UPDATE merge_threshold_presets
|
|
58
|
+
SET is_unattended_default = 1
|
|
59
|
+
WHERE id = 'mp_unattended'
|
|
60
|
+
AND workspace_id NOT IN (
|
|
61
|
+
SELECT workspace_id FROM merge_threshold_presets WHERE is_unattended_default = 1
|
|
62
|
+
);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cat-factory/worker",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.185.1",
|
|
4
4
|
"description": "Reusable Cloudflare Worker library (Hono + D1) exposing the Agent Architecture Board core: the `createApp()` Hono factory, the default fetch/scheduled/queue handler, and the Durable Object + Workflow classes. Deployments (see deploy/backend) supply the wrangler.toml + config and re-export these.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -43,22 +43,22 @@
|
|
|
43
43
|
"pino": "^10.3.1",
|
|
44
44
|
"valibot": "^1.4.2",
|
|
45
45
|
"workers-ai-provider": "^4.0.0",
|
|
46
|
-
"@cat-factory/agents": "0.126.
|
|
47
|
-
"@cat-factory/
|
|
48
|
-
"@cat-factory/
|
|
49
|
-
"@cat-factory/
|
|
50
|
-
"@cat-factory/
|
|
51
|
-
"@cat-factory/
|
|
52
|
-
"@cat-factory/gitlab": "0.20.
|
|
53
|
-
"@cat-factory/integrations": "0.160.
|
|
54
|
-
"@cat-factory/
|
|
55
|
-
"@cat-factory/
|
|
56
|
-
"@cat-factory/observability-otel": "0.19.
|
|
57
|
-
"@cat-factory/
|
|
58
|
-
"@cat-factory/
|
|
59
|
-
"@cat-factory/
|
|
60
|
-
"@cat-factory/
|
|
61
|
-
"@cat-factory/spend": "0.15.
|
|
46
|
+
"@cat-factory/agents": "0.126.7",
|
|
47
|
+
"@cat-factory/consensus": "0.16.7",
|
|
48
|
+
"@cat-factory/contracts": "0.301.0",
|
|
49
|
+
"@cat-factory/gates": "0.10.38",
|
|
50
|
+
"@cat-factory/caching": "0.20.7",
|
|
51
|
+
"@cat-factory/eks": "0.1.311",
|
|
52
|
+
"@cat-factory/gitlab": "0.20.8",
|
|
53
|
+
"@cat-factory/integrations": "0.160.5",
|
|
54
|
+
"@cat-factory/observability-langfuse": "0.10.82",
|
|
55
|
+
"@cat-factory/kernel": "0.292.1",
|
|
56
|
+
"@cat-factory/observability-otel": "0.19.2",
|
|
57
|
+
"@cat-factory/prompt-fragments": "1.0.62",
|
|
58
|
+
"@cat-factory/provider-cloudflare": "0.7.460",
|
|
59
|
+
"@cat-factory/server": "0.278.1",
|
|
60
|
+
"@cat-factory/orchestration": "0.263.1",
|
|
61
|
+
"@cat-factory/spend": "0.15.80"
|
|
62
62
|
},
|
|
63
63
|
"devDependencies": {
|
|
64
64
|
"@cloudflare/vitest-pool-workers": "^0.20.3",
|
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
"typescript": "7.0.2",
|
|
67
67
|
"vitest": "^4.1.10",
|
|
68
68
|
"wrangler": "^4.120.0",
|
|
69
|
-
"@cat-factory/conformance": "0.
|
|
69
|
+
"@cat-factory/conformance": "0.39.1"
|
|
70
70
|
},
|
|
71
71
|
"scripts": {
|
|
72
72
|
"build": "tsc -b tsconfig.build.json",
|