@derwinjs/db 0.6.0 → 0.8.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 (52) hide show
  1. package/dist/budget-gate.d.ts +43 -0
  2. package/dist/budget-gate.d.ts.map +1 -0
  3. package/dist/budget-gate.js +110 -0
  4. package/dist/budget-gate.js.map +1 -0
  5. package/dist/classification-override-store.d.ts +24 -0
  6. package/dist/classification-override-store.d.ts.map +1 -0
  7. package/dist/classification-override-store.js +131 -0
  8. package/dist/classification-override-store.js.map +1 -0
  9. package/dist/drift-detector.d.ts +63 -0
  10. package/dist/drift-detector.d.ts.map +1 -0
  11. package/dist/drift-detector.js +0 -0
  12. package/dist/drift-detector.js.map +1 -0
  13. package/dist/freeze-window-evaluator.d.ts +62 -0
  14. package/dist/freeze-window-evaluator.d.ts.map +1 -0
  15. package/dist/freeze-window-evaluator.js +236 -0
  16. package/dist/freeze-window-evaluator.js.map +1 -0
  17. package/dist/index.d.ts +8 -0
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/index.js +8 -0
  20. package/dist/index.js.map +1 -1
  21. package/dist/kill-switch-evaluator.d.ts +68 -0
  22. package/dist/kill-switch-evaluator.d.ts.map +1 -0
  23. package/dist/kill-switch-evaluator.js +389 -0
  24. package/dist/kill-switch-evaluator.js.map +1 -0
  25. package/dist/path-tier-resolver.d.ts +47 -0
  26. package/dist/path-tier-resolver.d.ts.map +1 -0
  27. package/dist/path-tier-resolver.js +177 -0
  28. package/dist/path-tier-resolver.js.map +1 -0
  29. package/dist/rag-retriever.d.ts.map +1 -1
  30. package/dist/rag-retriever.js +38 -0
  31. package/dist/rag-retriever.js.map +1 -1
  32. package/dist/regression-detector.d.ts +45 -0
  33. package/dist/regression-detector.d.ts.map +1 -0
  34. package/dist/regression-detector.js +78 -0
  35. package/dist/regression-detector.js.map +1 -0
  36. package/dist/trust-threshold-config-store.d.ts +20 -0
  37. package/dist/trust-threshold-config-store.d.ts.map +1 -0
  38. package/dist/trust-threshold-config-store.js +88 -0
  39. package/dist/trust-threshold-config-store.js.map +1 -0
  40. package/package.json +3 -3
  41. package/prisma/migrations/20260507120000_sprint8_policy_governance/migration.sql +58 -0
  42. package/prisma/migrations/20260507120100_sprint8_phase2_thresholds_and_freeze/migration.sql +33 -0
  43. package/prisma/migrations/20260507120200_sprint8_phase3_budget_cap/migration.sql +21 -0
  44. package/prisma/migrations/20260507120300_sprint8_phase4_kill_switches/migration.sql +74 -0
  45. package/prisma/schema.prisma +183 -11
  46. package/prisma-client/edge.js +96 -19
  47. package/prisma-client/index-browser.js +93 -16
  48. package/prisma-client/index.d.ts +10997 -3426
  49. package/prisma-client/index.js +96 -19
  50. package/prisma-client/package.json +1 -1
  51. package/prisma-client/schema.prisma +183 -11
  52. package/prisma-client/wasm.js +93 -16
@@ -122,6 +122,30 @@ export function createPrismaRAGRetriever(config) {
122
122
  }
123
123
  return { id };
124
124
  },
125
+ async updateOutcomeQuality(input) {
126
+ validateUpdateOutcomeQualityInput(input);
127
+ // Pattern D — tenant isolation. The WHERE clause scopes by both
128
+ // projectId AND fixAttemptId so a Sprint 7 Phase 5 update cannot
129
+ // bleed across tenants even if the caller mis-routes a fixAttemptId.
130
+ // Cross-tenant or missing-row → updateMany returns count=0; surface
131
+ // that as `{ updated: 0 }` per the contract (no throw).
132
+ //
133
+ // We deliberately use the typed `updateMany` (not raw SQL) because:
134
+ // (a) the `embedding` column is Unsupported but we're not touching
135
+ // it — we only set `outcomeQuality` (Float, fully typed); and
136
+ // (b) `updateMany` returns the affected-row count, which we need to
137
+ // hand back to the orchestrator for the audit trail.
138
+ const result = await prisma.rAGCorpus.updateMany({
139
+ where: {
140
+ projectId: input.projectId,
141
+ fixAttemptId: input.fixAttemptId,
142
+ },
143
+ data: {
144
+ outcomeQuality: input.outcomeQuality,
145
+ },
146
+ });
147
+ return { updated: result.count };
148
+ },
125
149
  };
126
150
  }
127
151
  // ─── Helpers ─────────────────────────────────────────────────────────────
@@ -147,6 +171,20 @@ function validateFindSimilarInput(input) {
147
171
  throw new RAGRetrieverError('invalid_embedding_length', `queryEmbedding must be ${String(EMBEDDING_DIM)}-dim, got ${actual}`);
148
172
  }
149
173
  }
174
+ function validateUpdateOutcomeQualityInput(input) {
175
+ if (typeof input.projectId !== 'string' || !input.projectId.trim()) {
176
+ throw new RAGRetrieverError('invalid_input', 'projectId is required');
177
+ }
178
+ if (typeof input.fixAttemptId !== 'string' || !input.fixAttemptId.trim()) {
179
+ throw new RAGRetrieverError('invalid_input', 'fixAttemptId is required');
180
+ }
181
+ if (typeof input.outcomeQuality !== 'number' ||
182
+ Number.isNaN(input.outcomeQuality) ||
183
+ input.outcomeQuality < 0 ||
184
+ input.outcomeQuality > 1) {
185
+ throw new RAGRetrieverError('invalid_input', 'outcomeQuality must be in [0, 1]');
186
+ }
187
+ }
150
188
  function validatePersistInput(input) {
151
189
  if (typeof input.projectId !== 'string' || !input.projectId.trim()) {
152
190
  throw new RAGRetrieverError('invalid_input', 'projectId is required');
@@ -1 +1 @@
1
- {"version":3,"file":"rag-retriever.js","sourceRoot":"","sources":["../src/rag-retriever.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"rag-retriever.js","sourceRoot":"","sources":["../src/rag-retriever.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Default RegressionDetector — QAP-Sprint7 Phase 3 / QAP-071.
3
+ *
4
+ * Stock implementation of the SDK RegressionDetector callback type
5
+ * (packages/sdk/src/types/regression-detector.ts). Wires `QATicketStore.listQATickets`
6
+ * with (classification, surface, ageHours, status) filters to find newly-opened
7
+ * tickets matching the original ticket's classification + surface within
8
+ * `withinDays` of `sinceMergedAt`. Returns true iff at least one such ticket
9
+ * exists (excluding the original ticket itself).
10
+ *
11
+ * Why a callback factory in @derwinjs/db rather than a stateful adapter:
12
+ * The RegressionDetector contract is intentionally a function type — not
13
+ * every consumer reads QA tickets to decide regression. A telemetry-driven
14
+ * Datadog/OpenTelemetry impl would query metrics instead. This file provides
15
+ * the *default* QATicketStore-backed callback that runPostVerify wires when
16
+ * the consumer opts into Derwin's standard regression-detection rule.
17
+ *
18
+ * Tenant isolation: the projectId argument from the callback flows directly
19
+ * into ticketStore.getQATicket and ticketStore.listQATickets, both of which
20
+ * are tenant-scoped per QAP-018B. No cross-project leakage is possible at
21
+ * this layer.
22
+ *
23
+ * Failure semantics: the callback never throws. Defense-in-depth — if the
24
+ * original ticket cannot be resolved (missing or cross-tenant), return false
25
+ * (no original means no regression context). This mirrors the orchestrator's
26
+ * "regression detection MUST NOT abort the post-verify path" rule. The
27
+ * upstream caller (runPostVerify) additionally wraps the call in try/catch
28
+ * for the same defensive posture.
29
+ */
30
+ import type { QATicketStore, RegressionDetector } from '@derwinjs/sdk';
31
+ export interface PrismaRegressionDetectorConfig {
32
+ /**
33
+ * QATicketStore instance — the same instance the rest of the platform uses,
34
+ * so the lookups respect the same tenant scope and DB connection pool.
35
+ */
36
+ ticketStore: QATicketStore;
37
+ }
38
+ /**
39
+ * Build a RegressionDetector backed by QATicketStore.listQATickets.
40
+ *
41
+ * The returned callback is invoked by runPostVerify when post-verify reports
42
+ * failure signals after a merge — see packages/core/src/orchestrator/run-post-verify.ts.
43
+ */
44
+ export declare function createPrismaRegressionDetector(config: PrismaRegressionDetectorConfig): RegressionDetector;
45
+ //# sourceMappingURL=regression-detector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"regression-detector.d.ts","sourceRoot":"","sources":["../src/regression-detector.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAIvE,MAAM,WAAW,8BAA8B;IAC7C;;;OAGG;IACH,WAAW,EAAE,aAAa,CAAC;CAC5B;AAQD;;;;;GAKG;AACH,wBAAgB,8BAA8B,CAC5C,MAAM,EAAE,8BAA8B,GACrC,kBAAkB,CAyCpB"}
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Default RegressionDetector — QAP-Sprint7 Phase 3 / QAP-071.
3
+ *
4
+ * Stock implementation of the SDK RegressionDetector callback type
5
+ * (packages/sdk/src/types/regression-detector.ts). Wires `QATicketStore.listQATickets`
6
+ * with (classification, surface, ageHours, status) filters to find newly-opened
7
+ * tickets matching the original ticket's classification + surface within
8
+ * `withinDays` of `sinceMergedAt`. Returns true iff at least one such ticket
9
+ * exists (excluding the original ticket itself).
10
+ *
11
+ * Why a callback factory in @derwinjs/db rather than a stateful adapter:
12
+ * The RegressionDetector contract is intentionally a function type — not
13
+ * every consumer reads QA tickets to decide regression. A telemetry-driven
14
+ * Datadog/OpenTelemetry impl would query metrics instead. This file provides
15
+ * the *default* QATicketStore-backed callback that runPostVerify wires when
16
+ * the consumer opts into Derwin's standard regression-detection rule.
17
+ *
18
+ * Tenant isolation: the projectId argument from the callback flows directly
19
+ * into ticketStore.getQATicket and ticketStore.listQATickets, both of which
20
+ * are tenant-scoped per QAP-018B. No cross-project leakage is possible at
21
+ * this layer.
22
+ *
23
+ * Failure semantics: the callback never throws. Defense-in-depth — if the
24
+ * original ticket cannot be resolved (missing or cross-tenant), return false
25
+ * (no original means no regression context). This mirrors the orchestrator's
26
+ * "regression detection MUST NOT abort the post-verify path" rule. The
27
+ * upstream caller (runPostVerify) additionally wraps the call in try/catch
28
+ * for the same defensive posture.
29
+ */
30
+ // ─── Constants ────────────────────────────────────────────────────────────
31
+ const HOURS_PER_DAY = 24;
32
+ // ─── Factory ─────────────────────────────────────────────────────────────
33
+ /**
34
+ * Build a RegressionDetector backed by QATicketStore.listQATickets.
35
+ *
36
+ * The returned callback is invoked by runPostVerify when post-verify reports
37
+ * failure signals after a merge — see packages/core/src/orchestrator/run-post-verify.ts.
38
+ */
39
+ export function createPrismaRegressionDetector(config) {
40
+ const { ticketStore } = config;
41
+ return async ({ projectId, qaTicketId, sinceMergedAt, withinDays }) => {
42
+ // (1) Fetch the original ticket. Both not-found and cross-tenant
43
+ // collisions return null per the QATicketStore contract — either way,
44
+ // returning false here is the correct defensive answer (no original →
45
+ // no regression context to evaluate).
46
+ const original = await ticketStore.getQATicket({ id: qaTicketId, projectId });
47
+ if (original === null) {
48
+ return false;
49
+ }
50
+ // (2) List candidate regression tickets via the store's existing filter
51
+ // shape. We narrow on (classification, surface) to scope to the same
52
+ // failure family, on ageHoursMax = withinDays * 24 to bound the search
53
+ // window, and on status: 'OPEN' so already-resolved historical tickets
54
+ // don't generate false positives. ageHoursMin: 0 is the floor.
55
+ const candidates = await ticketStore.listQATickets({
56
+ projectId,
57
+ classification: original.classification,
58
+ surface: original.surface,
59
+ ageHoursMin: 0,
60
+ ageHoursMax: withinDays * HOURS_PER_DAY,
61
+ status: 'OPEN',
62
+ });
63
+ // (3) Paranoia filter — listQATickets uses age (relative to "now"), not
64
+ // an absolute timestamp, and the original's age might place IT inside
65
+ // the window too. We exclude (a) tickets created at or before the merge
66
+ // moment and (b) the original ticket itself. The combination means:
67
+ // only tickets opened strictly AFTER the merge that are NOT the original
68
+ // count as regressions.
69
+ const mergedAtMs = sinceMergedAt.getTime();
70
+ const matches = candidates.tickets.filter((t) => {
71
+ if (t.id === qaTicketId)
72
+ return false;
73
+ return t.createdAt.getTime() > mergedAtMs;
74
+ });
75
+ return matches.length > 0;
76
+ };
77
+ }
78
+ //# sourceMappingURL=regression-detector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"regression-detector.js","sourceRoot":"","sources":["../src/regression-detector.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAcH,6EAA6E;AAE7E,MAAM,aAAa,GAAG,EAAE,CAAC;AAEzB,4EAA4E;AAE5E;;;;;GAKG;AACH,MAAM,UAAU,8BAA8B,CAC5C,MAAsC;IAEtC,MAAM,EAAE,WAAW,EAAE,GAAG,MAAM,CAAC;IAE/B,OAAO,KAAK,EAAE,EAAE,SAAS,EAAE,UAAU,EAAE,aAAa,EAAE,UAAU,EAAE,EAAE,EAAE;QACpE,iEAAiE;QACjE,sEAAsE;QACtE,sEAAsE;QACtE,sCAAsC;QACtC,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAC,WAAW,CAAC,EAAE,EAAE,EAAE,UAAU,EAAE,SAAS,EAAE,CAAC,CAAC;QAC9E,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;YACtB,OAAO,KAAK,CAAC;QACf,CAAC;QAED,wEAAwE;QACxE,qEAAqE;QACrE,uEAAuE;QACvE,uEAAuE;QACvE,+DAA+D;QAC/D,MAAM,UAAU,GAAG,MAAM,WAAW,CAAC,aAAa,CAAC;YACjD,SAAS;YACT,cAAc,EAAE,QAAQ,CAAC,cAAc;YACvC,OAAO,EAAE,QAAQ,CAAC,OAAO;YACzB,WAAW,EAAE,CAAC;YACd,WAAW,EAAE,UAAU,GAAG,aAAa;YACvC,MAAM,EAAE,MAAM;SACf,CAAC,CAAC;QAEH,wEAAwE;QACxE,sEAAsE;QACtE,wEAAwE;QACxE,oEAAoE;QACpE,yEAAyE;QACzE,wBAAwB;QACxB,MAAM,UAAU,GAAG,aAAa,CAAC,OAAO,EAAE,CAAC;QAC3C,MAAM,OAAO,GAAG,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE;YAC9C,IAAI,CAAC,CAAC,EAAE,KAAK,UAAU;gBAAE,OAAO,KAAK,CAAC;YACtC,OAAO,CAAC,CAAC,SAAS,CAAC,OAAO,EAAE,GAAG,UAAU,CAAC;QAC5C,CAAC,CAAC,CAAC;QAEH,OAAO,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC;IAC5B,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * createPrismaTrustThresholdConfigStore — Prisma-backed implementation of
3
+ * the SDK TrustThresholdConfigStore contract introduced by QAP-082.
4
+ *
5
+ * Sprint 8 Phase 2 (Policy Governance). The config is stored as a JSON
6
+ * column on Project.trustThresholds. Null in storage means "use defaults".
7
+ *
8
+ * Tenant isolation: every method scopes by projectId. Pattern D applies —
9
+ * unknown / wrong-project lookups return DEFAULT_TRUST_THRESHOLDS rather
10
+ * than throwing or leaking existence (defense-in-depth against tenant
11
+ * enumeration).
12
+ */
13
+ import type { PrismaClient } from './prisma.js';
14
+ import { type TrustThresholdConfigStore } from '@derwinjs/sdk';
15
+ export interface PrismaTrustThresholdConfigStoreConfig {
16
+ /** Generated Prisma client. Pass an instance per process. */
17
+ prisma: PrismaClient;
18
+ }
19
+ export declare function createPrismaTrustThresholdConfigStore(config: PrismaTrustThresholdConfigStoreConfig): TrustThresholdConfigStore;
20
+ //# sourceMappingURL=trust-threshold-config-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trust-threshold-config-store.d.ts","sourceRoot":"","sources":["../src/trust-threshold-config-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAIL,KAAK,yBAAyB,EAC/B,MAAM,eAAe,CAAC;AAIvB,MAAM,WAAW,qCAAqC;IACpD,6DAA6D;IAC7D,MAAM,EAAE,YAAY,CAAC;CACtB;AA8DD,wBAAgB,qCAAqC,CACnD,MAAM,EAAE,qCAAqC,GAC5C,yBAAyB,CA4B3B"}
@@ -0,0 +1,88 @@
1
+ /**
2
+ * createPrismaTrustThresholdConfigStore — Prisma-backed implementation of
3
+ * the SDK TrustThresholdConfigStore contract introduced by QAP-082.
4
+ *
5
+ * Sprint 8 Phase 2 (Policy Governance). The config is stored as a JSON
6
+ * column on Project.trustThresholds. Null in storage means "use defaults".
7
+ *
8
+ * Tenant isolation: every method scopes by projectId. Pattern D applies —
9
+ * unknown / wrong-project lookups return DEFAULT_TRUST_THRESHOLDS rather
10
+ * than throwing or leaking existence (defense-in-depth against tenant
11
+ * enumeration).
12
+ */
13
+ import { DEFAULT_TRUST_THRESHOLDS, TrustThresholdConfigError, } from '@derwinjs/sdk';
14
+ // ─── Validation ──────────────────────────────────────────────────────────
15
+ /**
16
+ * Each threshold must be a finite integer in [0, 100]. We accept floats
17
+ * because the JSON column can store them, but the dispatcher's comparison
18
+ * is integer-percent semantically; reject NaN / Infinity / out-of-range.
19
+ */
20
+ function validateConfig(config) {
21
+ for (const [key, value] of [
22
+ ['low', config.low],
23
+ ['medium', config.medium],
24
+ ['high', config.high],
25
+ ]) {
26
+ if (typeof value !== 'number' || !Number.isFinite(value)) {
27
+ throw new TrustThresholdConfigError('invalid_input', `TrustThresholdConfig: ${key} must be a finite number (got ${String(value)})`);
28
+ }
29
+ if (value < 0 || value > 100) {
30
+ throw new TrustThresholdConfigError('invalid_input', `TrustThresholdConfig: ${key} must be in [0, 100] (got ${String(value)})`);
31
+ }
32
+ }
33
+ }
34
+ /**
35
+ * Best-effort coercion of an unknown JSON value into a TrustThresholdConfig.
36
+ * Returns null if the shape is wrong — caller falls back to defaults. We
37
+ * intentionally do not throw here: defense-in-depth so a corrupted row
38
+ * doesn't cascade into a runtime error.
39
+ */
40
+ function tryParseConfig(value) {
41
+ if (value !== null &&
42
+ typeof value === 'object' &&
43
+ !Array.isArray(value) &&
44
+ 'low' in value &&
45
+ 'medium' in value &&
46
+ 'high' in value) {
47
+ const v = value;
48
+ if (typeof v.low === 'number' &&
49
+ typeof v.medium === 'number' &&
50
+ typeof v.high === 'number' &&
51
+ Number.isFinite(v.low) &&
52
+ Number.isFinite(v.medium) &&
53
+ Number.isFinite(v.high)) {
54
+ return { low: v.low, medium: v.medium, high: v.high };
55
+ }
56
+ }
57
+ return null;
58
+ }
59
+ // ─── Factory ─────────────────────────────────────────────────────────────
60
+ export function createPrismaTrustThresholdConfigStore(config) {
61
+ const { prisma } = config;
62
+ return {
63
+ async getConfig(input) {
64
+ const project = await prisma.project.findUnique({
65
+ where: { id: input.projectId },
66
+ select: { trustThresholds: true },
67
+ });
68
+ if (project === null)
69
+ return { ...DEFAULT_TRUST_THRESHOLDS };
70
+ const parsed = tryParseConfig(project.trustThresholds);
71
+ return parsed ?? { ...DEFAULT_TRUST_THRESHOLDS };
72
+ },
73
+ async setConfig(input) {
74
+ validateConfig(input.config);
75
+ await prisma.project.update({
76
+ where: { id: input.projectId },
77
+ data: {
78
+ trustThresholds: {
79
+ low: input.config.low,
80
+ medium: input.config.medium,
81
+ high: input.config.high,
82
+ },
83
+ },
84
+ });
85
+ },
86
+ };
87
+ }
88
+ //# sourceMappingURL=trust-threshold-config-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trust-threshold-config-store.js","sourceRoot":"","sources":["../src/trust-threshold-config-store.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@derwinjs/db",
3
- "version": "0.6.0",
3
+ "version": "0.8.0",
4
4
  "description": "Prisma schema + migrations for Derwin's own Postgres. 14 models, project-namespaced. Per ADR-0005. Ships its own generated Prisma client (multi-platform binaries) for cross-consumer compatibility.",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "type": "module",
@@ -33,8 +33,8 @@
33
33
  },
34
34
  "dependencies": {
35
35
  "@prisma/client": "^5.22.0",
36
- "@derwinjs/core": "0.6.0",
37
- "@derwinjs/sdk": "0.6.0"
36
+ "@derwinjs/core": "0.8.0",
37
+ "@derwinjs/sdk": "0.8.0"
38
38
  },
39
39
  "devDependencies": {
40
40
  "@vitest/coverage-v8": "^2.1.9",
@@ -0,0 +1,58 @@
1
+ -- Sprint 8 (QAP-080..081) — Policy governance: path-tier rules + classification override table.
2
+ --
3
+ -- Promotes Policy.pathRules / Policy.classificationOverrides JSON columns to
4
+ -- first-class tables so the policy-editor UI (Sprint 9 / QAP-088) can render,
5
+ -- reorder, and audit them as discrete rows. The legacy JSON fields on Policy
6
+ -- stay for back-compat with QAP-013's createPrismaFixPolicy until Sprint 9
7
+ -- migrates the read path.
8
+ --
9
+ -- Idempotent (IF NOT EXISTS) — safe to re-run on environments where the
10
+ -- enum or tables already exist.
11
+
12
+ -- 1. Project.defaultTier — fallback tier when no PathTierRule matches.
13
+ ALTER TABLE "derwin"."projects"
14
+ ADD COLUMN IF NOT EXISTS "defaultTier" "derwin"."RiskTier" NOT NULL DEFAULT 'LOW';
15
+
16
+ -- 2. OverrideMode enum.
17
+ DO $$ BEGIN
18
+ CREATE TYPE "derwin"."OverrideMode" AS ENUM ('BLOCK_AUTO_FIX', 'FORCE_ESCALATION', 'DOWNGRADE_TIER');
19
+ EXCEPTION
20
+ WHEN duplicate_object THEN NULL;
21
+ END $$;
22
+
23
+ -- 3. PathTierRule.
24
+ CREATE TABLE IF NOT EXISTS "derwin"."path_tier_rules" (
25
+ "id" TEXT PRIMARY KEY,
26
+ "projectId" TEXT NOT NULL,
27
+ "pattern" TEXT NOT NULL,
28
+ "tier" "derwin"."RiskTier" NOT NULL,
29
+ "priority" INTEGER NOT NULL,
30
+ "reason" TEXT,
31
+ "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
32
+ "updatedAt" TIMESTAMP(3) NOT NULL,
33
+ CONSTRAINT "path_tier_rules_projectId_fkey"
34
+ FOREIGN KEY ("projectId") REFERENCES "derwin"."projects"("id")
35
+ ON DELETE CASCADE ON UPDATE CASCADE
36
+ );
37
+
38
+ CREATE INDEX IF NOT EXISTS "path_tier_rules_projectId_priority_idx"
39
+ ON "derwin"."path_tier_rules" ("projectId", "priority");
40
+
41
+ -- 4. ClassificationOverride.
42
+ CREATE TABLE IF NOT EXISTS "derwin"."classification_overrides" (
43
+ "id" TEXT PRIMARY KEY,
44
+ "projectId" TEXT NOT NULL,
45
+ "classification" TEXT NOT NULL,
46
+ "surface" TEXT,
47
+ "overrideMode" "derwin"."OverrideMode" NOT NULL,
48
+ "downgradeTier" "derwin"."RiskTier",
49
+ "reason" TEXT NOT NULL,
50
+ "createdBy" TEXT NOT NULL,
51
+ "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
52
+ CONSTRAINT "classification_overrides_projectId_fkey"
53
+ FOREIGN KEY ("projectId") REFERENCES "derwin"."projects"("id")
54
+ ON DELETE CASCADE ON UPDATE CASCADE
55
+ );
56
+
57
+ CREATE INDEX IF NOT EXISTS "classification_overrides_projectId_classification_surface_idx"
58
+ ON "derwin"."classification_overrides" ("projectId", "classification", "surface");
@@ -0,0 +1,33 @@
1
+ -- Sprint 8 Phase 2 (QAP-082..083) — Trust threshold config + freeze windows.
2
+ --
3
+ -- Phase 1 (20260507120000_sprint8_policy_governance) added PathTierRule,
4
+ -- ClassificationOverride, and Project.defaultTier. Phase 2 layers on:
5
+ -- 1. Project.trustThresholds JSONB — per-tier minimum trustPercent for
6
+ -- auto-fix dispatch. Null → use SDK defaults ({low:60, medium:80, high:95}).
7
+ -- 2. freeze_windows table — operator-defined recurring dispatch freeze
8
+ -- windows. Cron-driven, 5-field, no seconds.
9
+ --
10
+ -- Idempotent (IF NOT EXISTS). Safe to re-run on environments where Phase 1
11
+ -- already landed but Phase 2 didn't.
12
+
13
+ -- 1. Project.trustThresholds — JSONB, nullable.
14
+ ALTER TABLE "derwin"."projects"
15
+ ADD COLUMN IF NOT EXISTS "trustThresholds" JSONB;
16
+
17
+ -- 2. FreezeWindow.
18
+ CREATE TABLE IF NOT EXISTS "derwin"."freeze_windows" (
19
+ "id" TEXT PRIMARY KEY,
20
+ "projectId" TEXT NOT NULL,
21
+ "cronExpression" TEXT NOT NULL,
22
+ "durationMinutes" INTEGER NOT NULL,
23
+ "label" TEXT NOT NULL,
24
+ "blocksDispatch" BOOLEAN NOT NULL DEFAULT TRUE,
25
+ "enabled" BOOLEAN NOT NULL DEFAULT TRUE,
26
+ "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
27
+ CONSTRAINT "freeze_windows_projectId_fkey"
28
+ FOREIGN KEY ("projectId") REFERENCES "derwin"."projects"("id")
29
+ ON DELETE CASCADE ON UPDATE CASCADE
30
+ );
31
+
32
+ CREATE INDEX IF NOT EXISTS "freeze_windows_projectId_enabled_idx"
33
+ ON "derwin"."freeze_windows" ("projectId", "enabled");
@@ -0,0 +1,21 @@
1
+ -- Sprint 8 Phase 3 (QAP-084) — Per-project budget cap + soft-warn pct.
2
+ --
3
+ -- Adds the budget-gate columns the BudgetGate contract reads:
4
+ -- 1. Project.monthlyBudgetUsd — DOUBLE PRECISION, nullable. Null = NO_CAP.
5
+ -- 2. Project.budgetSoftWarnPct — DOUBLE PRECISION, default 0.8 (80%).
6
+ --
7
+ -- The dispatcher consults a BudgetGate before runFixCycle and refuses new
8
+ -- auto-fix dispatches when month-to-date spend / monthlyBudgetUsd >= 1.0.
9
+ -- Soft-warn (>= budgetSoftWarnPct, < 1.0) is observable but non-blocking;
10
+ -- hard-stop (>= 1.0) blocks. NO_CAP (monthlyBudgetUsd IS NULL) is the
11
+ -- pre-Phase-3 default and preserves legacy behavior for projects that have
12
+ -- not opted into explicit USD caps.
13
+ --
14
+ -- Idempotent (IF NOT EXISTS). Safe to re-run on environments where Phase 1
15
+ -- and Phase 2 have already landed but Phase 3 has not.
16
+
17
+ ALTER TABLE "derwin"."projects"
18
+ ADD COLUMN IF NOT EXISTS "monthlyBudgetUsd" DOUBLE PRECISION;
19
+
20
+ ALTER TABLE "derwin"."projects"
21
+ ADD COLUMN IF NOT EXISTS "budgetSoftWarnPct" DOUBLE PRECISION NOT NULL DEFAULT 0.8;
@@ -0,0 +1,74 @@
1
+ -- Sprint 8 Phase 4 (QAP-085 / QAP-086 / QAP-087) — Three kill switches.
2
+ --
3
+ -- Adds the schema the KillSwitchEvaluator contract reads/writes:
4
+ -- 1. Project.killSwitchConfig — JSONB, nullable. Per-project threshold
5
+ -- overrides; null → use SDK defaults.
6
+ -- 2. KillSwitchType enum — three trigger discriminators.
7
+ -- 3. KillSwitchScope enum — three granularity discriminators.
8
+ -- 4. kill_switch_states table — history-preserving log of every trip.
9
+ --
10
+ -- The dispatcher consults a KillSwitchEvaluator before runFixCycle and
11
+ -- refuses to dispatch when any matching engaged switch is present:
12
+ -- - PROJECT or PLATFORM-scope switches block before ticket fetch.
13
+ -- - CLASSIFICATION-scope switches block after ticket fetch when the
14
+ -- ticket's classification + surface match the engaged switch's tuple.
15
+ --
16
+ -- History semantics: a new trip inserts a new row; an unblock flips
17
+ -- engaged → false on the existing row; subsequent re-trips on the same
18
+ -- tuple insert another row. This preserves the audit trail.
19
+ --
20
+ -- Idempotent (IF NOT EXISTS / DO ... EXCEPTION). Safe to re-run on
21
+ -- environments where Phase 1 / Phase 2 / Phase 3 already landed but
22
+ -- Phase 4 has not.
23
+
24
+ -- 1. Project.killSwitchConfig — JSONB, nullable.
25
+ ALTER TABLE "derwin"."projects"
26
+ ADD COLUMN IF NOT EXISTS "killSwitchConfig" JSONB;
27
+
28
+ -- 2. KillSwitchType enum.
29
+ DO $$ BEGIN
30
+ CREATE TYPE "derwin"."KillSwitchType" AS ENUM (
31
+ 'SUCCESS_RATE_DROP',
32
+ 'CONSECUTIVE_FAILURE',
33
+ 'REGRESSION_CASCADE'
34
+ );
35
+ EXCEPTION
36
+ WHEN duplicate_object THEN NULL;
37
+ END $$;
38
+
39
+ -- 3. KillSwitchScope enum.
40
+ DO $$ BEGIN
41
+ CREATE TYPE "derwin"."KillSwitchScope" AS ENUM (
42
+ 'CLASSIFICATION',
43
+ 'PROJECT',
44
+ 'PLATFORM'
45
+ );
46
+ EXCEPTION
47
+ WHEN duplicate_object THEN NULL;
48
+ END $$;
49
+
50
+ -- 4. KillSwitchState table.
51
+ CREATE TABLE IF NOT EXISTS "derwin"."kill_switch_states" (
52
+ "id" TEXT PRIMARY KEY,
53
+ "projectId" TEXT,
54
+ "classification" TEXT,
55
+ "surface" TEXT,
56
+ "type" "derwin"."KillSwitchType" NOT NULL,
57
+ "scope" "derwin"."KillSwitchScope" NOT NULL,
58
+ "engaged" BOOLEAN NOT NULL DEFAULT TRUE,
59
+ "engagedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
60
+ "unblockedAt" TIMESTAMP(3),
61
+ "unblockedBy" TEXT,
62
+ "reason" TEXT NOT NULL,
63
+ "triggerMetrics" JSONB NOT NULL,
64
+ "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
65
+ CONSTRAINT "kill_switch_states_projectId_fkey"
66
+ FOREIGN KEY ("projectId") REFERENCES "derwin"."projects"("id")
67
+ ON DELETE CASCADE ON UPDATE CASCADE
68
+ );
69
+
70
+ CREATE INDEX IF NOT EXISTS "kill_switch_states_projectId_engaged_idx"
71
+ ON "derwin"."kill_switch_states" ("projectId", "engaged");
72
+
73
+ CREATE INDEX IF NOT EXISTS "kill_switch_states_type_scope_engaged_idx"
74
+ ON "derwin"."kill_switch_states" ("type", "scope", "engaged");