@straiffi/archon 1.10.9 → 1.10.12
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/client/assets/ActivityView-BFn_Nhj4.js +1 -0
- package/dist/client/assets/GitHubActionsDialog-iZD86Yju.js +1 -0
- package/dist/client/assets/VerificationDialog-CqKE8t1d.js +4 -0
- package/dist/client/assets/{architectureDiagram-3BPJPVTR-BAIGV9Mj.js → architectureDiagram-3BPJPVTR-C8KefY67.js} +1 -1
- package/dist/client/assets/{blockDiagram-GPEHLZMM-B-5v5jSZ.js → blockDiagram-GPEHLZMM-BO2Q_Osr.js} +1 -1
- package/dist/client/assets/{c4Diagram-AAUBKEIU-C6wU415o.js → c4Diagram-AAUBKEIU-DGPkhbrK.js} +1 -1
- package/dist/client/assets/channel-DXKn3TOv.js +1 -0
- package/dist/client/assets/{chunk-2J33WTMH-COmvX2tP.js → chunk-2J33WTMH-Dtb7Xu8C.js} +1 -1
- package/dist/client/assets/{chunk-3OPIFGDE-BlANptdY.js → chunk-3OPIFGDE-Bnf4GbOF.js} +1 -1
- package/dist/client/assets/{chunk-5ZQYHXKU-ETyA2_GU.js → chunk-5ZQYHXKU-BWGid3g7.js} +1 -1
- package/dist/client/assets/{chunk-727SXJPM-D5-DudwF.js → chunk-727SXJPM-ScA8IRGP.js} +1 -1
- package/dist/client/assets/{chunk-AQP2D5EJ-k1AJ4sA3.js → chunk-AQP2D5EJ-Bygg04Ip.js} +1 -1
- package/dist/client/assets/{chunk-CSCIHK7Q-jfksXwY9.js → chunk-CSCIHK7Q-CxdDDtfN.js} +1 -1
- package/dist/client/assets/{chunk-KSCS5N6A-CHj0FDj9.js → chunk-KSCS5N6A-BgpZFsB5.js} +1 -1
- package/dist/client/assets/{chunk-L5ZTLDWV-1ODGxXhG.js → chunk-L5ZTLDWV-CKSew0OL.js} +1 -1
- package/dist/client/assets/{chunk-LZXEDZCA-Bgh9X2W0.js → chunk-LZXEDZCA-DVG9Rx0K.js} +2 -2
- package/dist/client/assets/{chunk-ND2GUHAM-DDkb3sp4.js → chunk-ND2GUHAM-CHBqNmuF.js} +1 -1
- package/dist/client/assets/{chunk-NZK2D7GU-B6B8PZ_-.js → chunk-NZK2D7GU-DvZYWn7V.js} +1 -1
- package/dist/client/assets/{chunk-O5CBEL6O-DhiUIFgj.js → chunk-O5CBEL6O-BL7lRTSe.js} +1 -1
- package/dist/client/assets/{chunk-WU5MYG2G-Dzd0fbP3.js → chunk-WU5MYG2G-C-il2wHZ.js} +1 -1
- package/dist/client/assets/classDiagram-4FO5ZUOK-U0fU20hT.js +1 -0
- package/dist/client/assets/classDiagram-v2-Q7XG4LA2-C6bQNSxL.js +1 -0
- package/dist/client/assets/{dagre-BM42HDAG-DoNDMCXI.js → dagre-BM42HDAG-B00l5tLi.js} +1 -1
- package/dist/client/assets/{diagram-2AECGRRQ-ETDXSa5q.js → diagram-2AECGRRQ-Tum6g1_5.js} +1 -1
- package/dist/client/assets/{diagram-5GNKFQAL-CgTUep7e.js → diagram-5GNKFQAL-BK1GX5jc.js} +1 -1
- package/dist/client/assets/{diagram-KO2AKTUF-BKTx2iRe.js → diagram-KO2AKTUF-BrzmD5NB.js} +1 -1
- package/dist/client/assets/{diagram-LMA3HP47-9iEiScHT.js → diagram-LMA3HP47-BhrlgXiJ.js} +1 -1
- package/dist/client/assets/{diagram-OG6HWLK6-UIZRh7Qa.js → diagram-OG6HWLK6-K-fWsJ3a.js} +1 -1
- package/dist/client/assets/{erDiagram-TEJ5UH35-BpNJmJva.js → erDiagram-TEJ5UH35-Der6PjHE.js} +1 -1
- package/dist/client/assets/{flowDiagram-I6XJVG4X-C-rK0XZ1.js → flowDiagram-I6XJVG4X-BVWgGhXe.js} +1 -1
- package/dist/client/assets/{ganttDiagram-6RSMTGT7-DWyfPvv_.js → ganttDiagram-6RSMTGT7-DcoZ5ggj.js} +1 -1
- package/dist/client/assets/{gitGraphDiagram-PVQCEYII-x71bzdc_.js → gitGraphDiagram-PVQCEYII-BhhbMTBu.js} +1 -1
- package/dist/client/assets/index-B6BltHSr.css +2 -0
- package/dist/client/assets/index-CFOYm3j9.js +276 -0
- package/dist/client/assets/{infoDiagram-5YYISTIA-CbRus0Xu.js → infoDiagram-5YYISTIA-Lwc-agyc.js} +1 -1
- package/dist/client/assets/{ishikawaDiagram-YF4QCWOH-DvaMHrgN.js → ishikawaDiagram-YF4QCWOH-B95U1Xcl.js} +1 -1
- package/dist/client/assets/{journeyDiagram-JHISSGLW-BQBu4YGn.js → journeyDiagram-JHISSGLW-xFpigy5D.js} +1 -1
- package/dist/client/assets/{kanban-definition-UN3LZRKU-8rU-U7L1.js → kanban-definition-UN3LZRKU-D3mudQnR.js} +1 -1
- package/dist/client/assets/{line-CSZnwjLA.js → line-DtTL3ZI2.js} +1 -1
- package/dist/client/assets/{mermaid-parser.core-CTOl2slE.js → mermaid-parser.core-Dau7K6zV.js} +1 -1
- package/dist/client/assets/{mermaid.core-B9gr0Vqf.js → mermaid.core-B8qtvATu.js} +3 -3
- package/dist/client/assets/{mindmap-definition-RKZ34NQL-But1_PWQ.js → mindmap-definition-RKZ34NQL-Cus04Yq3.js} +1 -1
- package/dist/client/assets/{pieDiagram-4H26LBE5-CnlVmfSG.js → pieDiagram-4H26LBE5-BCMGpBnn.js} +1 -1
- package/dist/client/assets/{quadrantDiagram-W4KKPZXB-Dww1ZGuR.js → quadrantDiagram-W4KKPZXB-CAmOr-PJ.js} +1 -1
- package/dist/client/assets/{requirementDiagram-4Y6WPE33-CNf_loe8.js → requirementDiagram-4Y6WPE33-kisD3jc4.js} +1 -1
- package/dist/client/assets/{sankeyDiagram-5OEKKPKP-DBhi37Jj.js → sankeyDiagram-5OEKKPKP-CsCedmM0.js} +1 -1
- package/dist/client/assets/{sequenceDiagram-3UESZ5HK-B64hb4E4.js → sequenceDiagram-3UESZ5HK-B-dAi954.js} +1 -1
- package/dist/client/assets/{stateDiagram-AJRCARHV-DcS6oB-S.js → stateDiagram-AJRCARHV-X0BnedIW.js} +1 -1
- package/dist/client/assets/stateDiagram-v2-BHNVJYJU-6B8YH8Y2.js +1 -0
- package/dist/client/assets/{timeline-definition-PNZ67QCA-Dq-4tXfh.js → timeline-definition-PNZ67QCA-DfFoSjhr.js} +1 -1
- package/dist/client/assets/{vennDiagram-CIIHVFJN-CeDklSE_.js → vennDiagram-CIIHVFJN-CKSCBwhG.js} +1 -1
- package/dist/client/assets/{wardleyDiagram-YWT4CUSO-D2cJISMm.js → wardleyDiagram-YWT4CUSO-DNIBQmHO.js} +1 -1
- package/dist/client/assets/{xychartDiagram-2RQKCTM6-CBF-tTpF.js → xychartDiagram-2RQKCTM6-FvB55TQN.js} +1 -1
- package/dist/client/index.html +2 -2
- package/dist/server/db.js +368 -5
- package/dist/server/db.js.map +1 -1
- package/dist/server/index.js +194 -250
- package/dist/server/index.js.map +1 -1
- package/dist/server/lib/agentRuns.js +14 -1
- package/dist/server/lib/agentRuns.js.map +1 -1
- package/dist/server/lib/automationLoopProjection.js +55 -12
- package/dist/server/lib/automationLoopProjection.js.map +1 -1
- package/dist/server/lib/automationProgression.js +2 -5
- package/dist/server/lib/automationProgression.js.map +1 -1
- package/dist/server/lib/automationResumeDecision.js +19 -1
- package/dist/server/lib/automationResumeDecision.js.map +1 -1
- package/dist/server/lib/buildControlEligibility.js +4 -0
- package/dist/server/lib/buildControlEligibility.js.map +1 -0
- package/dist/server/lib/buildExecutionAdmission.js +76 -0
- package/dist/server/lib/buildExecutionAdmission.js.map +1 -0
- package/dist/server/lib/buildSequenceResume.js +79 -0
- package/dist/server/lib/buildSequenceResume.js.map +1 -0
- package/dist/server/lib/buildWorkload.js +11 -0
- package/dist/server/lib/buildWorkload.js.map +1 -0
- package/dist/server/lib/checkAutoFixDetails.js +36 -1
- package/dist/server/lib/checkAutoFixDetails.js.map +1 -1
- package/dist/server/lib/executionEnvironmentReconciliation.js +15 -2
- package/dist/server/lib/executionEnvironmentReconciliation.js.map +1 -1
- package/dist/server/lib/executionEnvironments.js +15 -0
- package/dist/server/lib/executionEnvironments.js.map +1 -1
- package/dist/server/lib/executionRetry.js +13 -1
- package/dist/server/lib/executionRetry.js.map +1 -1
- package/dist/server/lib/executionRunAuthority.js +2 -2
- package/dist/server/lib/executionRunAuthority.js.map +1 -1
- package/dist/server/lib/executionTargets.js +7 -4
- package/dist/server/lib/executionTargets.js.map +1 -1
- package/dist/server/lib/executionTimeline.js +8 -13
- package/dist/server/lib/executionTimeline.js.map +1 -1
- package/dist/server/lib/executionTimelineHierarchy.js +83 -0
- package/dist/server/lib/executionTimelineHierarchy.js.map +1 -0
- package/dist/server/lib/failedBuildSequenceRecovery.js +133 -0
- package/dist/server/lib/failedBuildSequenceRecovery.js.map +1 -0
- package/dist/server/lib/hostRunSession.js +62 -0
- package/dist/server/lib/hostRunSession.js.map +1 -0
- package/dist/server/lib/hostServiceRecovery.js +159 -0
- package/dist/server/lib/hostServiceRecovery.js.map +1 -0
- package/dist/server/lib/hostServiceRunProvider.js +32 -0
- package/dist/server/lib/hostServiceRunProvider.js.map +1 -0
- package/dist/server/lib/mobileAccess.js +6 -2
- package/dist/server/lib/mobileAccess.js.map +1 -1
- package/dist/server/lib/projectAutoConfig.js +5 -2
- package/dist/server/lib/projectAutoConfig.js.map +1 -1
- package/dist/server/lib/projectTargets.js +16 -2
- package/dist/server/lib/projectTargets.js.map +1 -1
- package/dist/server/lib/projects.js +25 -1
- package/dist/server/lib/projects.js.map +1 -1
- package/dist/server/lib/reviewFindingReconciliation.js +9 -2
- package/dist/server/lib/reviewFindingReconciliation.js.map +1 -1
- package/dist/server/lib/reviewFindings.js +82 -21
- package/dist/server/lib/reviewFindings.js.map +1 -1
- package/dist/server/lib/reviewRepairAssessmentRecords.js +41 -0
- package/dist/server/lib/reviewRepairAssessmentRecords.js.map +1 -0
- package/dist/server/lib/reviewRepairCompletion.js +78 -18
- package/dist/server/lib/reviewRepairCompletion.js.map +1 -1
- package/dist/server/lib/reviewRepairIterationRecords.js +4 -2
- package/dist/server/lib/reviewRepairIterationRecords.js.map +1 -1
- package/dist/server/lib/reviewRepairIterations.js +8 -2
- package/dist/server/lib/reviewRepairIterations.js.map +1 -1
- package/dist/server/lib/reviewRepairProgress.js +177 -0
- package/dist/server/lib/reviewRepairProgress.js.map +1 -0
- package/dist/server/lib/reviewRepairReconciliation.js +119 -140
- package/dist/server/lib/reviewRepairReconciliation.js.map +1 -1
- package/dist/server/lib/reviewRepairResumeOverride.js +55 -0
- package/dist/server/lib/reviewRepairResumeOverride.js.map +1 -0
- package/dist/server/lib/run.js +541 -504
- package/dist/server/lib/run.js.map +1 -1
- package/dist/server/lib/runProcessIdentity.js +71 -0
- package/dist/server/lib/runProcessIdentity.js.map +1 -0
- package/dist/server/lib/runProcesses.js +273 -0
- package/dist/server/lib/runProcesses.js.map +1 -0
- package/dist/server/lib/runServices.js +223 -0
- package/dist/server/lib/runServices.js.map +1 -0
- package/dist/server/lib/runSessionLifecycle.js +77 -0
- package/dist/server/lib/runSessionLifecycle.js.map +1 -0
- package/dist/server/lib/runStatus.js +8 -0
- package/dist/server/lib/runStatus.js.map +1 -0
- package/dist/server/lib/serviceRunCleanup.js +70 -0
- package/dist/server/lib/serviceRunCleanup.js.map +1 -0
- package/dist/server/lib/serviceRuns.js +458 -19
- package/dist/server/lib/serviceRuns.js.map +1 -1
- package/dist/server/lib/ticketAutomation.js +4 -27
- package/dist/server/lib/ticketAutomation.js.map +1 -1
- package/dist/server/lib/ticketRunOperations.js +103 -34
- package/dist/server/lib/ticketRunOperations.js.map +1 -1
- package/dist/server/lib/tickets.js +0 -13
- package/dist/server/lib/tickets.js.map +1 -1
- package/dist/server/lib/types.js.map +1 -1
- package/dist/server/workers/build.js +44 -69
- package/dist/server/workers/build.js.map +1 -1
- package/dist/server/workers/plan.js +0 -7
- package/dist/server/workers/plan.js.map +1 -1
- package/dist/server/workers/review.js +95 -146
- package/dist/server/workers/review.js.map +1 -1
- package/package.json +1 -1
- package/dist/client/assets/ActivityView-CKvbDXeA.js +0 -1
- package/dist/client/assets/GitHubActionsDialog-Dzo0vtak.js +0 -1
- package/dist/client/assets/VerificationDialog-BJnOitrJ.js +0 -4
- package/dist/client/assets/channel-5mIy7nm1.js +0 -1
- package/dist/client/assets/classDiagram-4FO5ZUOK-BiQ-X2Sg.js +0 -1
- package/dist/client/assets/classDiagram-v2-Q7XG4LA2-CF-wCYW-.js +0 -1
- package/dist/client/assets/index-CIAO5aE_.css +0 -2
- package/dist/client/assets/index-nCGyalrn.js +0 -276
- package/dist/client/assets/stateDiagram-v2-BHNVJYJU-PWeeL0tR.js +0 -1
- package/dist/server/lib/automationDeliveryDecision.js +0 -34
- package/dist/server/lib/automationDeliveryDecision.js.map +0 -1
package/dist/server/db.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import Database from 'better-sqlite3';
|
|
2
|
-
import { createHash } from 'crypto';
|
|
2
|
+
import { createHash, randomUUID } from 'crypto';
|
|
3
3
|
import { parseCheckDefinitionsJsonStrict, parseLegacyTestCommandsJsonStrict, projectCheckDefinitionsToTestCommands, } from './lib/checkDefinitions.js';
|
|
4
4
|
import { ensureParentDirectory, resolveArchonDbPath } from './lib/runtimePaths.js';
|
|
5
5
|
import { TRANSCRIPT_RUN_TEXT_LIMIT_BYTES, truncateUtf8 } from './lib/transcriptRuns.js';
|
|
@@ -183,6 +183,46 @@ ensureColumn('projects', 'spec_aware_code_review_enabled', 'INTEGER NOT NULL DEF
|
|
|
183
183
|
ensureColumn('projects', 'deletion_started_at', 'DATETIME');
|
|
184
184
|
ensureColumn('projects', 'deletion_claim_id', 'TEXT');
|
|
185
185
|
ensureColumn('projects', 'deletion_cleanup_started_at', 'DATETIME');
|
|
186
|
+
ensureColumn('projects', 'run_services', 'TEXT');
|
|
187
|
+
db.transaction(() => {
|
|
188
|
+
const projects = db.prepare('SELECT id, run_services FROM projects WHERE run_services IS NOT NULL').all();
|
|
189
|
+
const update = db.prepare('UPDATE projects SET run_services = ? WHERE id = ?');
|
|
190
|
+
for (const project of projects) {
|
|
191
|
+
let services;
|
|
192
|
+
try {
|
|
193
|
+
services = JSON.parse(project.run_services);
|
|
194
|
+
}
|
|
195
|
+
catch {
|
|
196
|
+
continue;
|
|
197
|
+
}
|
|
198
|
+
// Leave malformed legacy configuration intact rather than partially rewriting it.
|
|
199
|
+
if (!Array.isArray(services) || services.some(service => !service || typeof service !== 'object' || Array.isArray(service))) {
|
|
200
|
+
continue;
|
|
201
|
+
}
|
|
202
|
+
const entries = services;
|
|
203
|
+
const validId = (id) => typeof id === 'string' && id.trim().length > 0 && id === id.trim();
|
|
204
|
+
const reserved = new Set(entries.map(service => service.id).filter(validId));
|
|
205
|
+
const seen = new Set();
|
|
206
|
+
let changed = false;
|
|
207
|
+
for (const service of entries) {
|
|
208
|
+
if (validId(service.id) && !seen.has(service.id)) {
|
|
209
|
+
seen.add(service.id);
|
|
210
|
+
continue;
|
|
211
|
+
}
|
|
212
|
+
let id;
|
|
213
|
+
do {
|
|
214
|
+
id = randomUUID();
|
|
215
|
+
} while (reserved.has(id));
|
|
216
|
+
reserved.add(id);
|
|
217
|
+
seen.add(id);
|
|
218
|
+
service.id = id;
|
|
219
|
+
changed = true;
|
|
220
|
+
}
|
|
221
|
+
if (changed) {
|
|
222
|
+
update.run(JSON.stringify(entries), project.id);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}).immediate();
|
|
186
226
|
const backfillAgentModelMaps = () => {
|
|
187
227
|
db.transaction(() => {
|
|
188
228
|
db.exec(`
|
|
@@ -2655,6 +2695,15 @@ db.exec(`
|
|
|
2655
2695
|
service_snapshot_json TEXT NOT NULL,
|
|
2656
2696
|
placement_json TEXT,
|
|
2657
2697
|
interruption_scope TEXT,
|
|
2698
|
+
intended_status TEXT,
|
|
2699
|
+
intended_event_type TEXT,
|
|
2700
|
+
intended_message TEXT,
|
|
2701
|
+
cleanup_claim_id TEXT,
|
|
2702
|
+
cleanup_claimed_at DATETIME,
|
|
2703
|
+
cleanup_attempts INTEGER NOT NULL DEFAULT 0,
|
|
2704
|
+
cleanup_retry_at DATETIME,
|
|
2705
|
+
cleanup_error_message TEXT,
|
|
2706
|
+
force_released_at DATETIME,
|
|
2658
2707
|
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
2659
2708
|
started_at DATETIME,
|
|
2660
2709
|
completed_at DATETIME,
|
|
@@ -2672,7 +2721,11 @@ db.exec(`
|
|
|
2672
2721
|
CHECK (environment_revision IS NULL OR environment_revision >= 1),
|
|
2673
2722
|
CHECK (length(CAST(service_snapshot_json AS BLOB)) BETWEEN 2 AND 16384),
|
|
2674
2723
|
CHECK (placement_json IS NULL OR length(CAST(placement_json AS BLOB)) BETWEEN 2 AND 16384),
|
|
2675
|
-
CHECK (interruption_scope IS NULL OR interruption_scope IN ('local_processes', 'whole_environment'))
|
|
2724
|
+
CHECK (interruption_scope IS NULL OR interruption_scope IN ('local_processes', 'whole_environment')),
|
|
2725
|
+
CHECK (intended_status IS NULL OR intended_status IN ('completed', 'failed', 'cancelled', 'interrupted')),
|
|
2726
|
+
CHECK ((cleanup_claim_id IS NULL) = (cleanup_claimed_at IS NULL)),
|
|
2727
|
+
CHECK (cleanup_attempts >= 0),
|
|
2728
|
+
CHECK (cleanup_error_message IS NULL OR length(cleanup_error_message) <= 4000)
|
|
2676
2729
|
);
|
|
2677
2730
|
|
|
2678
2731
|
CREATE UNIQUE INDEX IF NOT EXISTS idx_active_service_run_context
|
|
@@ -2682,6 +2735,15 @@ db.exec(`
|
|
|
2682
2735
|
CREATE INDEX IF NOT EXISTS idx_service_run_profile
|
|
2683
2736
|
ON service_run_details(project_id, execution_profile_revision_id, created_at);
|
|
2684
2737
|
`);
|
|
2738
|
+
ensureColumn('service_run_details', 'intended_status', 'TEXT');
|
|
2739
|
+
ensureColumn('service_run_details', 'intended_event_type', 'TEXT');
|
|
2740
|
+
ensureColumn('service_run_details', 'intended_message', 'TEXT');
|
|
2741
|
+
ensureColumn('service_run_details', 'cleanup_claim_id', 'TEXT');
|
|
2742
|
+
ensureColumn('service_run_details', 'cleanup_claimed_at', 'DATETIME');
|
|
2743
|
+
ensureColumn('service_run_details', 'cleanup_attempts', 'INTEGER NOT NULL DEFAULT 0');
|
|
2744
|
+
ensureColumn('service_run_details', 'cleanup_retry_at', 'DATETIME');
|
|
2745
|
+
ensureColumn('service_run_details', 'cleanup_error_message', 'TEXT');
|
|
2746
|
+
ensureColumn('service_run_details', 'force_released_at', 'DATETIME');
|
|
2685
2747
|
const executionEnvironmentStates = "'queued', 'preparing', 'ready', 'running', 'stopped', 'retiring', 'cleanup_pending', 'retired', 'failed', 'unavailable'";
|
|
2686
2748
|
db.exec(`
|
|
2687
2749
|
CREATE TABLE IF NOT EXISTS execution_environments (
|
|
@@ -2892,6 +2954,195 @@ ensureColumn('execution_environments', 'operation_claimed_at', 'DATETIME');
|
|
|
2892
2954
|
ensureColumn('execution_environment_run_bindings', 'execution_profile_fingerprint', 'TEXT');
|
|
2893
2955
|
ensureColumn('execution_environment_run_bindings', 'authority_json', 'TEXT');
|
|
2894
2956
|
ensureColumn('execution_environment_run_bindings', 'placement_json', 'TEXT');
|
|
2957
|
+
db.exec('DROP TRIGGER IF EXISTS protect_service_project_target');
|
|
2958
|
+
db.exec(`
|
|
2959
|
+
CREATE VIEW IF NOT EXISTS active_project_service_authorities AS
|
|
2960
|
+
SELECT run.id AS execution_run_id, run.project_id
|
|
2961
|
+
FROM execution_runs run
|
|
2962
|
+
WHERE run.kind = 'service' AND (
|
|
2963
|
+
run.status NOT IN ('completed', 'failed', 'cancelled', 'interrupted')
|
|
2964
|
+
OR EXISTS (SELECT 1 FROM service_run_details details
|
|
2965
|
+
WHERE details.execution_run_id = run.id AND details.completed_at IS NULL)
|
|
2966
|
+
OR EXISTS (SELECT 1 FROM execution_environment_run_bindings binding
|
|
2967
|
+
WHERE binding.execution_run_id = run.id AND binding.relationship = 'execution'
|
|
2968
|
+
AND binding.released_at IS NULL)
|
|
2969
|
+
);
|
|
2970
|
+
|
|
2971
|
+
CREATE TRIGGER IF NOT EXISTS admit_project_service_run
|
|
2972
|
+
BEFORE INSERT ON execution_runs WHEN NEW.kind = 'service'
|
|
2973
|
+
BEGIN
|
|
2974
|
+
SELECT RAISE(ABORT, 'Project is being deleted') WHERE EXISTS (
|
|
2975
|
+
SELECT 1 FROM projects WHERE id = NEW.project_id AND deletion_started_at IS NOT NULL);
|
|
2976
|
+
SELECT RAISE(ABORT, 'Project already has active service authority') WHERE EXISTS (
|
|
2977
|
+
SELECT 1 FROM active_project_service_authorities WHERE project_id = NEW.project_id);
|
|
2978
|
+
END;
|
|
2979
|
+
|
|
2980
|
+
CREATE TRIGGER IF NOT EXISTS admit_project_service_details
|
|
2981
|
+
BEFORE INSERT ON service_run_details
|
|
2982
|
+
BEGIN
|
|
2983
|
+
SELECT RAISE(ABORT, 'New service authority must be unfinished') WHERE NEW.completed_at IS NOT NULL;
|
|
2984
|
+
SELECT RAISE(ABORT, 'Service profile fingerprint does not match') WHERE NOT EXISTS (
|
|
2985
|
+
SELECT 1 FROM execution_profile_revisions WHERE id = NEW.execution_profile_revision_id
|
|
2986
|
+
AND project_id = NEW.project_id AND fingerprint = NEW.execution_profile_fingerprint);
|
|
2987
|
+
SELECT RAISE(ABORT, 'Service details require an active service run') WHERE NOT EXISTS (
|
|
2988
|
+
SELECT 1 FROM execution_runs WHERE id = NEW.execution_run_id AND project_id = NEW.project_id
|
|
2989
|
+
AND kind = 'service' AND status NOT IN ('completed', 'failed', 'cancelled', 'interrupted'));
|
|
2990
|
+
SELECT RAISE(ABORT, 'Project is being deleted') WHERE EXISTS (
|
|
2991
|
+
SELECT 1 FROM projects WHERE id = NEW.project_id AND deletion_started_at IS NOT NULL);
|
|
2992
|
+
SELECT RAISE(ABORT, 'Project already has active service authority') WHERE EXISTS (
|
|
2993
|
+
SELECT 1 FROM active_project_service_authorities WHERE project_id = NEW.project_id
|
|
2994
|
+
AND execution_run_id <> NEW.execution_run_id);
|
|
2995
|
+
END;
|
|
2996
|
+
|
|
2997
|
+
CREATE TRIGGER IF NOT EXISTS preserve_service_detail_identity
|
|
2998
|
+
BEFORE UPDATE ON service_run_details
|
|
2999
|
+
WHEN NEW.execution_run_id IS NOT OLD.execution_run_id OR NEW.project_id IS NOT OLD.project_id
|
|
3000
|
+
OR NEW.context_key IS NOT OLD.context_key OR NEW.target_kind IS NOT OLD.target_kind
|
|
3001
|
+
OR NEW.target_key IS NOT OLD.target_key OR NEW.target_workspace_path IS NOT OLD.target_workspace_path
|
|
3002
|
+
OR NEW.execution_profile_revision_id IS NOT OLD.execution_profile_revision_id
|
|
3003
|
+
OR NEW.execution_profile_fingerprint IS NOT OLD.execution_profile_fingerprint
|
|
3004
|
+
OR NEW.service_snapshot_json IS NOT OLD.service_snapshot_json
|
|
3005
|
+
OR (OLD.completed_at IS NOT NULL AND NEW.completed_at IS NOT OLD.completed_at)
|
|
3006
|
+
BEGIN
|
|
3007
|
+
SELECT RAISE(ABORT, 'Service run authority is immutable');
|
|
3008
|
+
END;
|
|
3009
|
+
|
|
3010
|
+
CREATE TRIGGER IF NOT EXISTS protect_service_run_identity
|
|
3011
|
+
BEFORE UPDATE OF id, kind, project_id ON execution_runs
|
|
3012
|
+
WHEN (OLD.kind = 'service' OR NEW.kind = 'service') AND (
|
|
3013
|
+
NEW.id IS NOT OLD.id OR NEW.kind IS NOT OLD.kind OR NEW.project_id IS NOT OLD.project_id)
|
|
3014
|
+
BEGIN
|
|
3015
|
+
SELECT RAISE(ABORT, 'Service run authority is immutable');
|
|
3016
|
+
END;
|
|
3017
|
+
|
|
3018
|
+
CREATE TRIGGER IF NOT EXISTS protect_service_run_reactivation
|
|
3019
|
+
BEFORE UPDATE OF status ON execution_runs
|
|
3020
|
+
WHEN OLD.kind = 'service' AND OLD.status IN ('completed', 'failed', 'cancelled', 'interrupted')
|
|
3021
|
+
AND NEW.status NOT IN ('completed', 'failed', 'cancelled', 'interrupted')
|
|
3022
|
+
BEGIN
|
|
3023
|
+
SELECT RAISE(ABORT, 'Terminal service run cannot be reactivated');
|
|
3024
|
+
END;
|
|
3025
|
+
|
|
3026
|
+
CREATE TRIGGER IF NOT EXISTS admit_service_execution_binding
|
|
3027
|
+
BEFORE INSERT ON execution_environment_run_bindings
|
|
3028
|
+
WHEN NEW.relationship = 'execution' AND NEW.released_at IS NULL AND EXISTS (
|
|
3029
|
+
SELECT 1 FROM execution_runs WHERE id = NEW.execution_run_id AND kind = 'service')
|
|
3030
|
+
BEGIN
|
|
3031
|
+
SELECT RAISE(ABORT, 'Service binding requires unfinished authority') WHERE NOT EXISTS (
|
|
3032
|
+
SELECT 1 FROM service_run_details details JOIN execution_runs run ON run.id = details.execution_run_id
|
|
3033
|
+
JOIN projects project ON project.id = details.project_id
|
|
3034
|
+
WHERE details.execution_run_id = NEW.execution_run_id AND details.project_id = NEW.project_id
|
|
3035
|
+
AND details.completed_at IS NULL AND project.deletion_started_at IS NULL
|
|
3036
|
+
AND run.status NOT IN ('completed', 'failed', 'cancelled', 'interrupted'));
|
|
3037
|
+
SELECT RAISE(ABORT, 'Project already has active service authority') WHERE EXISTS (
|
|
3038
|
+
SELECT 1 FROM active_project_service_authorities WHERE project_id = NEW.project_id
|
|
3039
|
+
AND execution_run_id <> NEW.execution_run_id);
|
|
3040
|
+
END;
|
|
3041
|
+
|
|
3042
|
+
CREATE TRIGGER IF NOT EXISTS protect_service_binding_reactivation
|
|
3043
|
+
BEFORE UPDATE OF released_at ON execution_environment_run_bindings
|
|
3044
|
+
WHEN OLD.relationship = 'execution' AND OLD.released_at IS NOT NULL AND NEW.released_at IS NULL
|
|
3045
|
+
AND EXISTS (SELECT 1 FROM execution_runs WHERE id = OLD.execution_run_id AND kind = 'service')
|
|
3046
|
+
BEGIN
|
|
3047
|
+
SELECT RAISE(ABORT, 'Released service binding cannot be reactivated');
|
|
3048
|
+
END;
|
|
3049
|
+
|
|
3050
|
+
CREATE TRIGGER IF NOT EXISTS protect_service_binding_deletion
|
|
3051
|
+
BEFORE DELETE ON execution_environment_run_bindings
|
|
3052
|
+
WHEN OLD.relationship = 'execution' AND OLD.released_at IS NULL
|
|
3053
|
+
AND EXISTS (SELECT 1 FROM execution_runs WHERE id = OLD.execution_run_id AND kind = 'service')
|
|
3054
|
+
BEGIN
|
|
3055
|
+
SELECT RAISE(ABORT, 'Service execution binding is unreleased');
|
|
3056
|
+
END;
|
|
3057
|
+
|
|
3058
|
+
CREATE TRIGGER IF NOT EXISTS protect_service_completion
|
|
3059
|
+
BEFORE UPDATE OF completed_at ON service_run_details
|
|
3060
|
+
WHEN NEW.completed_at IS NOT NULL AND EXISTS (
|
|
3061
|
+
SELECT 1 FROM execution_environment_run_bindings WHERE execution_run_id = OLD.execution_run_id
|
|
3062
|
+
AND relationship = 'execution' AND released_at IS NULL)
|
|
3063
|
+
BEGIN
|
|
3064
|
+
SELECT RAISE(ABORT, 'Service execution binding is unreleased');
|
|
3065
|
+
END;
|
|
3066
|
+
|
|
3067
|
+
CREATE TRIGGER IF NOT EXISTS require_terminal_service_completion
|
|
3068
|
+
BEFORE UPDATE OF completed_at ON service_run_details
|
|
3069
|
+
WHEN NEW.completed_at IS NOT NULL AND EXISTS (
|
|
3070
|
+
SELECT 1 FROM execution_runs WHERE id = OLD.execution_run_id
|
|
3071
|
+
AND status NOT IN ('completed', 'failed', 'cancelled', 'interrupted'))
|
|
3072
|
+
BEGIN
|
|
3073
|
+
SELECT RAISE(ABORT, 'Service run must be terminal before completing details');
|
|
3074
|
+
END;
|
|
3075
|
+
|
|
3076
|
+
CREATE TRIGGER IF NOT EXISTS protect_service_detail_deletion
|
|
3077
|
+
BEFORE DELETE ON service_run_details
|
|
3078
|
+
WHEN EXISTS (SELECT 1 FROM active_project_service_authorities WHERE execution_run_id = OLD.execution_run_id)
|
|
3079
|
+
BEGIN
|
|
3080
|
+
SELECT RAISE(ABORT, 'Service run authority is active');
|
|
3081
|
+
END;
|
|
3082
|
+
|
|
3083
|
+
CREATE TRIGGER IF NOT EXISTS protect_service_run_deletion
|
|
3084
|
+
BEFORE DELETE ON execution_runs
|
|
3085
|
+
WHEN EXISTS (SELECT 1 FROM active_project_service_authorities WHERE execution_run_id = OLD.id)
|
|
3086
|
+
BEGIN
|
|
3087
|
+
SELECT RAISE(ABORT, 'Service run authority is active');
|
|
3088
|
+
END;
|
|
3089
|
+
|
|
3090
|
+
CREATE TRIGGER IF NOT EXISTS protect_service_ticket_deletion
|
|
3091
|
+
BEFORE DELETE ON tickets
|
|
3092
|
+
WHEN EXISTS (
|
|
3093
|
+
SELECT 1 FROM active_project_service_authorities active
|
|
3094
|
+
JOIN execution_runs run ON run.id = active.execution_run_id
|
|
3095
|
+
WHERE run.source_kind = 'ticket' AND run.source_id = OLD.id)
|
|
3096
|
+
BEGIN
|
|
3097
|
+
SELECT RAISE(ABORT, 'Ticket has active service authority');
|
|
3098
|
+
END;
|
|
3099
|
+
|
|
3100
|
+
CREATE TRIGGER IF NOT EXISTS protect_service_ticket_target
|
|
3101
|
+
BEFORE UPDATE OF project_id, worktree_bundle_id ON tickets
|
|
3102
|
+
WHEN (NEW.project_id IS NOT OLD.project_id OR NEW.worktree_bundle_id IS NOT OLD.worktree_bundle_id)
|
|
3103
|
+
AND EXISTS (
|
|
3104
|
+
SELECT 1 FROM active_project_service_authorities active
|
|
3105
|
+
JOIN execution_runs run ON run.id = active.execution_run_id
|
|
3106
|
+
WHERE run.source_kind = 'ticket' AND run.source_id = OLD.id)
|
|
3107
|
+
BEGIN
|
|
3108
|
+
SELECT RAISE(ABORT, 'Ticket has active service authority');
|
|
3109
|
+
END;
|
|
3110
|
+
|
|
3111
|
+
CREATE TRIGGER IF NOT EXISTS protect_service_project_deletion_claim
|
|
3112
|
+
BEFORE UPDATE OF deletion_started_at ON projects
|
|
3113
|
+
WHEN NEW.deletion_started_at IS NOT NULL AND EXISTS (
|
|
3114
|
+
SELECT 1 FROM active_project_service_authorities WHERE project_id = OLD.id)
|
|
3115
|
+
BEGIN
|
|
3116
|
+
SELECT RAISE(ABORT, 'Project has active service authority');
|
|
3117
|
+
END;
|
|
3118
|
+
|
|
3119
|
+
CREATE TRIGGER IF NOT EXISTS protect_service_project_deletion
|
|
3120
|
+
BEFORE DELETE ON projects
|
|
3121
|
+
WHEN EXISTS (SELECT 1 FROM active_project_service_authorities WHERE project_id = OLD.id)
|
|
3122
|
+
BEGIN
|
|
3123
|
+
SELECT RAISE(ABORT, 'Project has active service authority');
|
|
3124
|
+
END;
|
|
3125
|
+
|
|
3126
|
+
CREATE TRIGGER IF NOT EXISTS protect_service_project_target
|
|
3127
|
+
BEFORE UPDATE OF active_target_kind, active_target_bundle_id ON projects
|
|
3128
|
+
WHEN EXISTS (
|
|
3129
|
+
SELECT 1 FROM active_project_service_authorities active
|
|
3130
|
+
JOIN execution_runs run ON run.id = active.execution_run_id
|
|
3131
|
+
WHERE active.project_id = OLD.id AND (run.source_kind IS NULL OR run.source_kind <> 'ticket'))
|
|
3132
|
+
OR OLD.deletion_started_at IS NOT NULL
|
|
3133
|
+
BEGIN
|
|
3134
|
+
SELECT RAISE(ABORT, 'Cannot change project target while service authority or deletion is active');
|
|
3135
|
+
END;
|
|
3136
|
+
|
|
3137
|
+
CREATE TRIGGER IF NOT EXISTS protect_service_project_repo_path
|
|
3138
|
+
BEFORE UPDATE OF repo_path ON projects
|
|
3139
|
+
WHEN NEW.repo_path IS NOT OLD.repo_path AND (
|
|
3140
|
+
EXISTS (SELECT 1 FROM active_project_service_authorities WHERE project_id = OLD.id)
|
|
3141
|
+
OR OLD.deletion_started_at IS NOT NULL)
|
|
3142
|
+
BEGIN
|
|
3143
|
+
SELECT RAISE(ABORT, 'Cannot change project repository while service authority or deletion is active');
|
|
3144
|
+
END;
|
|
3145
|
+
`);
|
|
2895
3146
|
db.exec(`
|
|
2896
3147
|
CREATE TABLE IF NOT EXISTS execution_run_authorities (
|
|
2897
3148
|
execution_run_id TEXT NOT NULL,
|
|
@@ -5176,6 +5427,67 @@ db.exec(`
|
|
|
5176
5427
|
FOREIGN KEY (review_run_id) REFERENCES review_runs(id) ON DELETE CASCADE
|
|
5177
5428
|
)
|
|
5178
5429
|
`);
|
|
5430
|
+
ensureColumn('review_runs', 'output_provenance', `TEXT CHECK (output_provenance IS NULL OR output_provenance IN ('structured_primary', 'structured_transcript', 'subagent_aggregation', 'markdown_fallback', 'parse_failed'))`);
|
|
5431
|
+
ensureColumn('review_runs', 'evaluator_fingerprint', `TEXT CHECK (evaluator_fingerprint IS NULL OR (length(evaluator_fingerprint) = 64 AND evaluator_fingerprint NOT GLOB '*[^0-9a-f]*'))`);
|
|
5432
|
+
// Historical identity survives deletion of the source ticket; writes are validated below.
|
|
5433
|
+
ensureColumn('review_findings', 'predecessor_finding_id', 'TEXT');
|
|
5434
|
+
ensureColumn('review_findings', 'evaluator_fingerprint', `TEXT CHECK (evaluator_fingerprint IS NULL OR (length(evaluator_fingerprint) = 64 AND evaluator_fingerprint NOT GLOB '*[^0-9a-f]*'))`);
|
|
5435
|
+
ensureColumn('review_findings', 'output_provenance', `TEXT CHECK (output_provenance IS NULL OR output_provenance IN ('structured_primary', 'structured_transcript', 'subagent_aggregation', 'markdown_fallback', 'parse_failed'))`);
|
|
5436
|
+
db.exec(`
|
|
5437
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_review_finding_predecessor
|
|
5438
|
+
ON review_findings(review_run_id, predecessor_finding_id) WHERE predecessor_finding_id IS NOT NULL;
|
|
5439
|
+
CREATE TRIGGER IF NOT EXISTS preserve_review_finding_predecessor
|
|
5440
|
+
BEFORE UPDATE OF predecessor_finding_id ON review_findings
|
|
5441
|
+
WHEN NEW.predecessor_finding_id IS NOT OLD.predecessor_finding_id
|
|
5442
|
+
BEGIN
|
|
5443
|
+
SELECT RAISE(ABORT, 'Review finding predecessor is immutable');
|
|
5444
|
+
END;
|
|
5445
|
+
CREATE TRIGGER IF NOT EXISTS preserve_review_finding_lineage_owner
|
|
5446
|
+
BEFORE UPDATE OF review_run_id ON review_findings
|
|
5447
|
+
WHEN NEW.review_run_id IS NOT OLD.review_run_id AND EXISTS (
|
|
5448
|
+
SELECT 1 FROM review_findings WHERE predecessor_finding_id = OLD.id
|
|
5449
|
+
)
|
|
5450
|
+
BEGIN
|
|
5451
|
+
SELECT RAISE(ABORT, 'Review finding lineage ownership is immutable');
|
|
5452
|
+
END;
|
|
5453
|
+
CREATE TRIGGER IF NOT EXISTS preserve_review_run_lineage_owner
|
|
5454
|
+
BEFORE UPDATE OF ticket_id, project_id, worktree_bundle_id, status ON review_runs
|
|
5455
|
+
WHEN (NEW.ticket_id IS NOT OLD.ticket_id OR NEW.project_id IS NOT OLD.project_id
|
|
5456
|
+
OR NEW.worktree_bundle_id IS NOT OLD.worktree_bundle_id OR NEW.status IS NOT OLD.status)
|
|
5457
|
+
AND EXISTS (
|
|
5458
|
+
SELECT 1 FROM review_findings predecessor
|
|
5459
|
+
JOIN review_findings successor ON successor.predecessor_finding_id = predecessor.id
|
|
5460
|
+
WHERE predecessor.review_run_id = OLD.id
|
|
5461
|
+
OR (successor.review_run_id = OLD.id AND (
|
|
5462
|
+
NEW.ticket_id IS NOT OLD.ticket_id OR NEW.project_id IS NOT OLD.project_id
|
|
5463
|
+
OR NEW.worktree_bundle_id IS NOT OLD.worktree_bundle_id
|
|
5464
|
+
))
|
|
5465
|
+
)
|
|
5466
|
+
BEGIN
|
|
5467
|
+
SELECT RAISE(ABORT, 'Review run lineage ownership is immutable');
|
|
5468
|
+
END;
|
|
5469
|
+
`);
|
|
5470
|
+
for (const operation of ['INSERT', 'UPDATE']) {
|
|
5471
|
+
db.exec(`
|
|
5472
|
+
DROP TRIGGER IF EXISTS validate_review_finding_predecessor_${operation.toLowerCase()};
|
|
5473
|
+
CREATE TRIGGER validate_review_finding_predecessor_${operation.toLowerCase()}
|
|
5474
|
+
BEFORE ${operation} ON review_findings
|
|
5475
|
+
WHEN NEW.predecessor_finding_id IS NOT NULL
|
|
5476
|
+
BEGIN
|
|
5477
|
+
SELECT RAISE(ABORT, 'Invalid review finding predecessor') WHERE NOT EXISTS (
|
|
5478
|
+
SELECT 1 FROM review_findings predecessor
|
|
5479
|
+
JOIN review_runs prior ON prior.id = predecessor.review_run_id
|
|
5480
|
+
JOIN review_runs current ON current.id = NEW.review_run_id
|
|
5481
|
+
WHERE predecessor.id = NEW.predecessor_finding_id
|
|
5482
|
+
AND prior.id <> current.id
|
|
5483
|
+
AND prior.status = 'completed'
|
|
5484
|
+
AND prior.project_id IS current.project_id
|
|
5485
|
+
AND prior.worktree_bundle_id IS current.worktree_bundle_id
|
|
5486
|
+
AND (current.worktree_bundle_id IS NOT NULL OR prior.ticket_id = current.ticket_id)
|
|
5487
|
+
);
|
|
5488
|
+
END;
|
|
5489
|
+
`);
|
|
5490
|
+
}
|
|
5179
5491
|
db.exec(`
|
|
5180
5492
|
CREATE TABLE IF NOT EXISTS bundle_pull_requests (
|
|
5181
5493
|
id TEXT PRIMARY KEY,
|
|
@@ -5215,7 +5527,6 @@ db.exec(`
|
|
|
5215
5527
|
automation_paused_code TEXT,
|
|
5216
5528
|
automation_paused_reason TEXT,
|
|
5217
5529
|
automation_paused_at DATETIME,
|
|
5218
|
-
automation_delivery_ready_stage_run_id TEXT,
|
|
5219
5530
|
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
5220
5531
|
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
5221
5532
|
PRIMARY KEY (project_id, worktree_bundle_id),
|
|
@@ -5231,7 +5542,6 @@ ensureColumn('bundle_automation_state', 'automation_progression_run_id', 'TEXT')
|
|
|
5231
5542
|
ensureColumn('bundle_automation_state', 'automation_paused_stage_run_id', 'TEXT');
|
|
5232
5543
|
ensureColumn('bundle_automation_state', 'automation_paused_boundary_purpose', 'TEXT');
|
|
5233
5544
|
ensureColumn('bundle_automation_state', 'automation_pause_reason_code', 'TEXT');
|
|
5234
|
-
ensureColumn('bundle_automation_state', 'automation_delivery_ready_stage_run_id', 'TEXT');
|
|
5235
5545
|
db.exec('DROP TRIGGER IF EXISTS validate_review_repair_result_update');
|
|
5236
5546
|
db.exec('DROP TRIGGER IF EXISTS validate_review_repair_gate_update');
|
|
5237
5547
|
db.exec('DROP TRIGGER IF EXISTS validate_review_repair_gate_evaluation_update');
|
|
@@ -5693,9 +6003,19 @@ db.exec(`
|
|
|
5693
6003
|
SELECT RAISE(ABORT, 'Invalid review repair verification lineage');
|
|
5694
6004
|
END;
|
|
5695
6005
|
|
|
5696
|
-
|
|
6006
|
+
DROP TRIGGER IF EXISTS validate_review_repair_result_update;
|
|
6007
|
+
CREATE TRIGGER validate_review_repair_result_update
|
|
5697
6008
|
BEFORE UPDATE OF resulting_review_run_id ON review_repair_iterations
|
|
5698
6009
|
WHEN (OLD.resulting_review_run_id IS NOT NULL AND NEW.resulting_review_run_id IS NULL
|
|
6010
|
+
AND NOT (
|
|
6011
|
+
OLD.phase = 'paused' AND OLD.outcome IS 'paused' AND OLD.stop_reason IS 'stale_evidence'
|
|
6012
|
+
AND NEW.phase = 'gate_pending' AND NEW.outcome IS NULL AND NEW.stop_reason IS NULL
|
|
6013
|
+
AND NEW.resulting_review_execution_run_id IS NULL AND NEW.resulting_blocking_count IS NULL
|
|
6014
|
+
AND NEW.gate_batch_run_id IS NULL AND NEW.gate_source_batch_run_id IS NULL
|
|
6015
|
+
AND NEW.gate_evaluation_id IS NULL AND NEW.workspace_evidence_json IS NULL
|
|
6016
|
+
AND NEW.gate_active_at IS NULL AND NEW.verification_pending_at IS NULL
|
|
6017
|
+
AND NEW.verification_active_at IS NULL
|
|
6018
|
+
)
|
|
5699
6019
|
AND NOT (OLD.resulting_review_execution_run_id <> NEW.resulting_review_execution_run_id
|
|
5700
6020
|
AND EXISTS (
|
|
5701
6021
|
SELECT 1 FROM review_runs prior_result
|
|
@@ -5941,6 +6261,49 @@ db.exec('CREATE INDEX IF NOT EXISTS idx_chat_sessions_project_updated_at ON chat
|
|
|
5941
6261
|
db.exec('CREATE INDEX IF NOT EXISTS idx_chat_messages_session_created_at ON chat_messages(chat_session_id, created_at)');
|
|
5942
6262
|
db.exec('CREATE UNIQUE INDEX IF NOT EXISTS idx_ticket_stage_changes_ticket_stage ON ticket_stage_changes(ticket_id, stage)');
|
|
5943
6263
|
db.exec('CREATE INDEX IF NOT EXISTS idx_ticket_stage_changes_bundle_stage_success ON ticket_stage_changes(project_id, worktree_bundle_id, stage, success_revision)');
|
|
6264
|
+
ensureColumn('review_repair_iterations', 'progress_assessment_json', `TEXT CHECK (progress_assessment_json IS NULL OR CASE WHEN json_valid(progress_assessment_json) THEN json_type(progress_assessment_json) = 'object' AND length(CAST(progress_assessment_json AS BLOB)) BETWEEN 2 AND 16384 ELSE 0 END)`);
|
|
6265
|
+
db.exec(`
|
|
6266
|
+
CREATE TRIGGER IF NOT EXISTS validate_review_repair_assessment_insert
|
|
6267
|
+
BEFORE INSERT ON review_repair_iterations
|
|
6268
|
+
WHEN NEW.progress_assessment_json IS NOT NULL
|
|
6269
|
+
BEGIN
|
|
6270
|
+
SELECT RAISE(ABORT, 'Review repair assessment requires existing verification evidence');
|
|
6271
|
+
END;
|
|
6272
|
+
|
|
6273
|
+
CREATE TRIGGER IF NOT EXISTS validate_review_repair_assessment_update
|
|
6274
|
+
BEFORE UPDATE ON review_repair_iterations
|
|
6275
|
+
WHEN (OLD.progress_assessment_json IS NULL AND NEW.progress_assessment_json IS NOT NULL AND (
|
|
6276
|
+
OLD.phase <> 'verification_active' OR NEW.phase <> 'verification_active'
|
|
6277
|
+
OR OLD.resulting_review_execution_run_id IS NULL OR OLD.resulting_review_run_id IS NULL
|
|
6278
|
+
OR NEW.resulting_review_execution_run_id IS NOT OLD.resulting_review_execution_run_id
|
|
6279
|
+
OR NEW.resulting_review_run_id IS NOT OLD.resulting_review_run_id
|
|
6280
|
+
)) OR (OLD.progress_assessment_json IS NOT NULL AND (
|
|
6281
|
+
NEW.progress_assessment_json IS NOT OLD.progress_assessment_json
|
|
6282
|
+
OR NEW.resulting_review_execution_run_id IS NOT OLD.resulting_review_execution_run_id
|
|
6283
|
+
OR NEW.resulting_review_run_id IS NOT OLD.resulting_review_run_id
|
|
6284
|
+
) AND NOT (
|
|
6285
|
+
OLD.phase = 'paused' AND OLD.outcome IS 'paused' AND OLD.stop_reason IS 'stale_evidence'
|
|
6286
|
+
AND NEW.phase = 'gate_pending' AND NEW.outcome IS NULL AND NEW.stop_reason IS NULL
|
|
6287
|
+
AND NEW.progress_assessment_json IS NULL
|
|
6288
|
+
AND NEW.resulting_review_execution_run_id IS NULL AND NEW.resulting_review_run_id IS NULL
|
|
6289
|
+
AND NEW.resulting_blocking_count IS NULL AND NEW.gate_batch_run_id IS NULL
|
|
6290
|
+
AND NEW.gate_source_batch_run_id IS NULL AND NEW.gate_evaluation_id IS NULL
|
|
6291
|
+
AND NEW.workspace_evidence_json IS NULL AND NEW.gate_active_at IS NULL
|
|
6292
|
+
AND NEW.verification_pending_at IS NULL AND NEW.verification_active_at IS NULL
|
|
6293
|
+
))
|
|
6294
|
+
BEGIN
|
|
6295
|
+
SELECT RAISE(ABORT, 'Invalid or immutable Review repair progress assessment');
|
|
6296
|
+
END;
|
|
6297
|
+
|
|
6298
|
+
CREATE TRIGGER IF NOT EXISTS prevent_review_repair_no_progress_resume
|
|
6299
|
+
BEFORE UPDATE ON review_repair_iterations
|
|
6300
|
+
WHEN OLD.phase = 'paused' AND OLD.stop_reason = 'no_progress'
|
|
6301
|
+
AND NEW.phase <> 'terminal'
|
|
6302
|
+
AND (NEW.phase <> 'paused' OR NEW.stop_reason IS NOT 'no_progress')
|
|
6303
|
+
BEGIN
|
|
6304
|
+
SELECT RAISE(ABORT, 'Review repair no_progress requires an explicit successor iteration');
|
|
6305
|
+
END;
|
|
6306
|
+
`);
|
|
5944
6307
|
db.exec('CREATE INDEX IF NOT EXISTS idx_review_runs_ticket_created_at ON review_runs(ticket_id, created_at)');
|
|
5945
6308
|
db.exec('CREATE INDEX IF NOT EXISTS idx_review_runs_bundle_created_at ON review_runs(project_id, worktree_bundle_id, created_at)');
|
|
5946
6309
|
db.exec('CREATE INDEX IF NOT EXISTS idx_review_findings_review_run_ordinal ON review_findings(review_run_id, ordinal)');
|