@ai-sdlc/orchestrator 0.5.0 → 0.9.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 (227) hide show
  1. package/dist/action-enforcement.d.ts +26 -0
  2. package/dist/action-enforcement.js +70 -0
  3. package/dist/admission-composite.d.ts +67 -0
  4. package/dist/admission-composite.js +158 -0
  5. package/dist/admission-enrichment.d.ts +142 -0
  6. package/dist/admission-enrichment.js +331 -0
  7. package/dist/admission-hc.d.ts +62 -0
  8. package/dist/admission-hc.js +83 -0
  9. package/dist/admission-score.d.ts +148 -0
  10. package/dist/admission-score.js +237 -0
  11. package/dist/analysis/analyzer.js +3 -2
  12. package/dist/analysis/convention-detector.d.ts +85 -2
  13. package/dist/analysis/convention-detector.js +375 -70
  14. package/dist/analysis/diff-analyzer.d.ts +33 -0
  15. package/dist/analysis/diff-analyzer.js +122 -0
  16. package/dist/analysis/hotspot-analyzer.js +3 -1
  17. package/dist/analysis/index.d.ts +2 -1
  18. package/dist/analysis/index.js +2 -1
  19. package/dist/artifacts/index.d.ts +65 -0
  20. package/dist/artifacts/index.js +142 -0
  21. package/dist/backlog-adapter.d.ts +121 -0
  22. package/dist/backlog-adapter.js +438 -0
  23. package/dist/calibration.d.ts +43 -0
  24. package/dist/calibration.js +76 -0
  25. package/dist/cli/commands/agents.d.ts +24 -0
  26. package/dist/cli/commands/agents.js +66 -1
  27. package/dist/cli/commands/git-remote.d.ts +49 -0
  28. package/dist/cli/commands/git-remote.js +91 -0
  29. package/dist/cli/commands/health.d.ts +4 -0
  30. package/dist/cli/commands/health.js +13 -1
  31. package/dist/cli/commands/init.d.ts +26 -0
  32. package/dist/cli/commands/init.js +164 -22
  33. package/dist/cli/commands/mcp-setup.d.ts +31 -0
  34. package/dist/cli/commands/mcp-setup.js +78 -8
  35. package/dist/cli/formatters/table.js +15 -2
  36. package/dist/cli/index.d.ts +14 -1
  37. package/dist/cli/index.js +81 -20
  38. package/dist/cli/versions.d.ts +57 -0
  39. package/dist/cli/versions.js +128 -0
  40. package/dist/code-area-classifier.d.ts +21 -0
  41. package/dist/code-area-classifier.js +48 -0
  42. package/dist/config.d.ts +33 -1
  43. package/dist/config.js +78 -8
  44. package/dist/cycle-utils.d.ts +51 -0
  45. package/dist/cycle-utils.js +77 -0
  46. package/dist/database/adapters/external.d.ts +24 -0
  47. package/dist/database/adapters/external.js +80 -0
  48. package/dist/database/adapters/neon.d.ts +41 -0
  49. package/dist/database/adapters/neon.js +98 -0
  50. package/dist/database/adapters/pg-snapshot-restore.d.ts +28 -0
  51. package/dist/database/adapters/pg-snapshot-restore.js +68 -0
  52. package/dist/database/adapters/sqlite-copy.d.ts +32 -0
  53. package/dist/database/adapters/sqlite-copy.js +145 -0
  54. package/dist/database/connection-injection.d.ts +35 -0
  55. package/dist/database/connection-injection.js +93 -0
  56. package/dist/database/index.d.ts +12 -0
  57. package/dist/database/index.js +23 -0
  58. package/dist/database/registry.d.ts +13 -0
  59. package/dist/database/registry.js +27 -0
  60. package/dist/database/topology.d.ts +52 -0
  61. package/dist/database/topology.js +44 -0
  62. package/dist/database/types.d.ts +89 -0
  63. package/dist/database/types.js +26 -0
  64. package/dist/defaults.d.ts +5 -0
  65. package/dist/defaults.js +5 -0
  66. package/dist/design-authority.d.ts +40 -0
  67. package/dist/design-authority.js +71 -0
  68. package/dist/design-lookahead.d.ts +64 -0
  69. package/dist/design-lookahead.js +86 -0
  70. package/dist/design-quality-trend.d.ts +87 -0
  71. package/dist/design-quality-trend.js +190 -0
  72. package/dist/design-system-context.d.ts +46 -0
  73. package/dist/design-system-context.js +80 -0
  74. package/dist/design-system-correction-loop.d.ts +64 -0
  75. package/dist/design-system-correction-loop.js +128 -0
  76. package/dist/design-system-metrics.d.ts +61 -0
  77. package/dist/design-system-metrics.js +104 -0
  78. package/dist/design-system-stewardship.d.ts +22 -0
  79. package/dist/design-system-stewardship.js +85 -0
  80. package/dist/design-system-validation.d.ts +37 -0
  81. package/dist/design-system-validation.js +88 -0
  82. package/dist/dispatch/index.d.ts +4 -0
  83. package/dist/dispatch/index.js +4 -0
  84. package/dist/dispatch/merge-gate.d.ts +46 -0
  85. package/dist/dispatch/merge-gate.js +90 -0
  86. package/dist/dispatch/requeue.d.ts +57 -0
  87. package/dist/dispatch/requeue.js +131 -0
  88. package/dist/dispatch/worker-pool.d.ts +62 -0
  89. package/dist/dispatch/worker-pool.js +60 -0
  90. package/dist/execute.d.ts +40 -0
  91. package/dist/execute.js +295 -30
  92. package/dist/fix-ci.js +40 -3
  93. package/dist/fix-review.d.ts +66 -0
  94. package/dist/fix-review.js +448 -0
  95. package/dist/harness/adapters/claude-code.d.ts +29 -0
  96. package/dist/harness/adapters/claude-code.js +191 -0
  97. package/dist/harness/adapters/codex.d.ts +25 -0
  98. package/dist/harness/adapters/codex.js +61 -0
  99. package/dist/harness/independence.d.ts +51 -0
  100. package/dist/harness/independence.js +67 -0
  101. package/dist/harness/index.d.ts +14 -0
  102. package/dist/harness/index.js +20 -0
  103. package/dist/harness/registry.d.ts +17 -0
  104. package/dist/harness/registry.js +31 -0
  105. package/dist/harness/types.d.ts +123 -0
  106. package/dist/harness/types.js +8 -0
  107. package/dist/harness/version-probe.d.ts +14 -0
  108. package/dist/harness/version-probe.js +123 -0
  109. package/dist/index.d.ts +39 -5
  110. package/dist/index.js +48 -3
  111. package/dist/models/classifier.d.ts +76 -0
  112. package/dist/models/classifier.js +221 -0
  113. package/dist/models/index.d.ts +3 -0
  114. package/dist/models/index.js +3 -0
  115. package/dist/models/registry.d.ts +97 -0
  116. package/dist/models/registry.js +173 -0
  117. package/dist/pillar-breakdown.d.ts +63 -0
  118. package/dist/pillar-breakdown.js +153 -0
  119. package/dist/pipeline-cycle-detector.d.ts +70 -0
  120. package/dist/pipeline-cycle-detector.js +111 -0
  121. package/dist/priority.d.ts +7 -76
  122. package/dist/priority.js +18 -5
  123. package/dist/review-meta.d.ts +65 -0
  124. package/dist/review-meta.js +149 -0
  125. package/dist/review.d.ts +35 -0
  126. package/dist/review.js +84 -0
  127. package/dist/runners/claude-code-sdk.d.ts +31 -0
  128. package/dist/runners/claude-code-sdk.js +238 -0
  129. package/dist/runners/claude-code.d.ts +3 -0
  130. package/dist/runners/claude-code.js +319 -73
  131. package/dist/runners/codex.js +4 -1
  132. package/dist/runners/copilot.js +4 -1
  133. package/dist/runners/cursor.js +4 -1
  134. package/dist/runners/git-utils.d.ts +81 -0
  135. package/dist/runners/git-utils.js +201 -0
  136. package/dist/runners/index.d.ts +5 -1
  137. package/dist/runners/index.js +4 -0
  138. package/dist/runners/review-agent.d.ts +67 -0
  139. package/dist/runners/review-agent.js +350 -0
  140. package/dist/runners/runner-registry.js +10 -0
  141. package/dist/runners/sdk-review-runner.d.ts +65 -0
  142. package/dist/runners/sdk-review-runner.js +185 -0
  143. package/dist/runners/security-triage.d.ts +20 -4
  144. package/dist/runners/security-triage.js +42 -14
  145. package/dist/runners/types.d.ts +25 -0
  146. package/dist/runtime/attestations.d.ts +274 -0
  147. package/dist/runtime/attestations.js +460 -0
  148. package/dist/runtime/git-env.d.ts +53 -0
  149. package/dist/runtime/git-env.js +60 -0
  150. package/dist/runtime/index.d.ts +7 -0
  151. package/dist/runtime/index.js +7 -0
  152. package/dist/runtime/parallelism-flag.d.ts +10 -0
  153. package/dist/runtime/parallelism-flag.js +18 -0
  154. package/dist/runtime/port-allocator.d.ts +21 -0
  155. package/dist/runtime/port-allocator.js +66 -0
  156. package/dist/runtime/worktree-pool.d.ts +86 -0
  157. package/dist/runtime/worktree-pool.js +204 -0
  158. package/dist/runtime/worktree.d.ts +25 -0
  159. package/dist/runtime/worktree.js +111 -0
  160. package/dist/sa-scoring/auto-calibrate.d.ts +69 -0
  161. package/dist/sa-scoring/auto-calibrate.js +107 -0
  162. package/dist/sa-scoring/c1-sa2-computable.d.ts +42 -0
  163. package/dist/sa-scoring/c1-sa2-computable.js +59 -0
  164. package/dist/sa-scoring/composite.d.ts +107 -0
  165. package/dist/sa-scoring/composite.js +139 -0
  166. package/dist/sa-scoring/depparse-client.d.ts +79 -0
  167. package/dist/sa-scoring/depparse-client.js +187 -0
  168. package/dist/sa-scoring/did-compiler.d.ts +122 -0
  169. package/dist/sa-scoring/did-compiler.js +286 -0
  170. package/dist/sa-scoring/drift-monitor.d.ts +84 -0
  171. package/dist/sa-scoring/drift-monitor.js +186 -0
  172. package/dist/sa-scoring/exemplar-bank.d.ts +78 -0
  173. package/dist/sa-scoring/exemplar-bank.js +154 -0
  174. package/dist/sa-scoring/feedback-store.d.ts +100 -0
  175. package/dist/sa-scoring/feedback-store.js +156 -0
  176. package/dist/sa-scoring/index.d.ts +71 -0
  177. package/dist/sa-scoring/index.js +158 -0
  178. package/dist/sa-scoring/layer1-deterministic.d.ts +115 -0
  179. package/dist/sa-scoring/layer1-deterministic.js +298 -0
  180. package/dist/sa-scoring/layer2-structural.d.ts +71 -0
  181. package/dist/sa-scoring/layer2-structural.js +151 -0
  182. package/dist/sa-scoring/layer3-llm.d.ts +86 -0
  183. package/dist/sa-scoring/layer3-llm.js +282 -0
  184. package/dist/sa-scoring/rescore-orchestrator.d.ts +52 -0
  185. package/dist/sa-scoring/rescore-orchestrator.js +47 -0
  186. package/dist/scheduling/burn-down.d.ts +27 -0
  187. package/dist/scheduling/burn-down.js +43 -0
  188. package/dist/scheduling/calibration.d.ts +42 -0
  189. package/dist/scheduling/calibration.js +150 -0
  190. package/dist/scheduling/index.d.ts +8 -0
  191. package/dist/scheduling/index.js +8 -0
  192. package/dist/scheduling/ledger.d.ts +59 -0
  193. package/dist/scheduling/ledger.js +216 -0
  194. package/dist/scheduling/off-peak.d.ts +27 -0
  195. package/dist/scheduling/off-peak.js +112 -0
  196. package/dist/scheduling/schedule-decision.d.ts +39 -0
  197. package/dist/scheduling/schedule-decision.js +89 -0
  198. package/dist/scheduling/tier-analysis.d.ts +47 -0
  199. package/dist/scheduling/tier-analysis.js +81 -0
  200. package/dist/scheduling/types.d.ts +140 -0
  201. package/dist/scheduling/types.js +11 -0
  202. package/dist/shared.d.ts +13 -0
  203. package/dist/shared.js +32 -0
  204. package/dist/state/index.d.ts +1 -1
  205. package/dist/state/schema.d.ts +6 -1
  206. package/dist/state/schema.js +276 -1
  207. package/dist/state/store.d.ts +71 -1
  208. package/dist/state/store.js +464 -7
  209. package/dist/state/types.d.ts +174 -0
  210. package/dist/types.d.ts +1 -1
  211. package/dist/validate-agent-output.js +4 -1
  212. package/dist/watch.js +6 -0
  213. package/dist/workflow-patterns/artifact-writer.d.ts +16 -0
  214. package/dist/workflow-patterns/artifact-writer.js +34 -0
  215. package/dist/workflow-patterns/classifiers.d.ts +10 -0
  216. package/dist/workflow-patterns/classifiers.js +72 -0
  217. package/dist/workflow-patterns/detector.d.ts +27 -0
  218. package/dist/workflow-patterns/detector.js +186 -0
  219. package/dist/workflow-patterns/index.d.ts +8 -0
  220. package/dist/workflow-patterns/index.js +7 -0
  221. package/dist/workflow-patterns/proposal-generator.d.ts +15 -0
  222. package/dist/workflow-patterns/proposal-generator.js +183 -0
  223. package/dist/workflow-patterns/telemetry-ingest.d.ts +27 -0
  224. package/dist/workflow-patterns/telemetry-ingest.js +103 -0
  225. package/dist/workflow-patterns/types.d.ts +61 -0
  226. package/dist/workflow-patterns/types.js +11 -0
  227. package/package.json +2 -2
@@ -27,6 +27,13 @@ export class StateStore {
27
27
  return new StateStore(pathOrDb);
28
28
  }
29
29
  migrate() {
30
+ // Each migration runs atomically: DDL + schema_version insert in one
31
+ // transaction so a crash mid-migration can't leave the DB in a
32
+ // half-applied state where the version row lies about actual schema.
33
+ const applyMigration = this.db.transaction((migration) => {
34
+ this.db.exec(migration.sql);
35
+ this.db.prepare('INSERT INTO schema_version (version) VALUES (?)').run(migration.version);
36
+ });
30
37
  // Check current schema version
31
38
  try {
32
39
  const row = this.db.prepare('SELECT MAX(version) as v FROM schema_version').get();
@@ -35,16 +42,14 @@ export class StateStore {
35
42
  return;
36
43
  for (const migration of MIGRATIONS) {
37
44
  if (migration.version > (current ?? 0)) {
38
- this.db.exec(migration.sql);
39
- this.db.prepare('INSERT INTO schema_version (version) VALUES (?)').run(migration.version);
45
+ applyMigration(migration);
40
46
  }
41
47
  }
42
48
  }
43
49
  catch {
44
50
  // Table doesn't exist yet — run all migrations
45
51
  for (const migration of MIGRATIONS) {
46
- this.db.exec(migration.sql);
47
- this.db.prepare('INSERT INTO schema_version (version) VALUES (?)').run(migration.version);
52
+ applyMigration(migration);
48
53
  }
49
54
  }
50
55
  }
@@ -316,10 +321,10 @@ export class StateStore {
316
321
  // ── Cost Ledger ────────────────────────────────────────────────
317
322
  saveCostEntry(entry) {
318
323
  const stmt = this.db.prepare(`
319
- INSERT INTO cost_ledger (run_id, agent_name, pipeline_type, model, input_tokens, output_tokens, total_tokens, cost_usd, issue_id, issue_number, pr_number, stage_name, cache_read_tokens)
320
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
324
+ INSERT INTO cost_ledger (run_id, agent_name, pipeline_type, model, model_alias, input_tokens, output_tokens, total_tokens, cost_usd, shadow_cost_usd, issue_id, issue_number, pr_number, stage_name, cache_read_tokens)
325
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
321
326
  `);
322
- const result = stmt.run(entry.runId, entry.agentName, entry.pipelineType, entry.model ?? null, entry.inputTokens ?? 0, entry.outputTokens ?? 0, entry.totalTokens ?? 0, entry.costUsd ?? 0, entry.issueId ?? null, entry.issueNumber ?? null, entry.prNumber ?? null, entry.stageName ?? null, entry.cacheReadTokens ?? 0);
327
+ const result = stmt.run(entry.runId, entry.agentName, entry.pipelineType, entry.model ?? null, entry.modelAlias ?? null, entry.inputTokens ?? 0, entry.outputTokens ?? 0, entry.totalTokens ?? 0, entry.costUsd ?? 0, entry.shadowCostUsd ?? null, entry.issueId ?? null, entry.issueNumber ?? null, entry.prNumber ?? null, entry.stageName ?? null, entry.cacheReadTokens ?? 0);
323
328
  return Number(result.lastInsertRowid);
324
329
  }
325
330
  getCostEntries(opts) {
@@ -361,10 +366,12 @@ export class StateStore {
361
366
  agentName: row.agent_name,
362
367
  pipelineType: row.pipeline_type,
363
368
  model: row.model,
369
+ modelAlias: row.model_alias,
364
370
  inputTokens: row.input_tokens,
365
371
  outputTokens: row.output_tokens,
366
372
  totalTokens: row.total_tokens,
367
373
  costUsd: row.cost_usd,
374
+ shadowCostUsd: row.shadow_cost_usd,
368
375
  issueId: row.issue_id,
369
376
  issueNumber: row.issue_number,
370
377
  prNumber: row.pr_number,
@@ -711,6 +718,456 @@ export class StateStore {
711
718
  getDatabase() {
712
719
  return this.db;
713
720
  }
721
+ // ── Workflow Pattern Detection ─────────────────────────────────────
722
+ saveToolSequenceEvent(event) {
723
+ const stmt = this.db.prepare(`
724
+ INSERT INTO tool_sequence_events (session_id, tool_name, action_canonical, project_path, timestamp)
725
+ VALUES (?, ?, ?, ?, ?)
726
+ `);
727
+ const result = stmt.run(event.sessionId, event.toolName, event.actionCanonical, event.projectPath ?? null, event.timestamp);
728
+ return Number(result.lastInsertRowid);
729
+ }
730
+ saveToolSequenceEvents(events) {
731
+ const stmt = this.db.prepare(`
732
+ INSERT INTO tool_sequence_events (session_id, tool_name, action_canonical, project_path, timestamp)
733
+ VALUES (?, ?, ?, ?, ?)
734
+ `);
735
+ const tx = this.db.transaction((items) => {
736
+ for (const e of items) {
737
+ stmt.run(e.sessionId, e.toolName, e.actionCanonical, e.projectPath ?? null, e.timestamp);
738
+ }
739
+ return items.length;
740
+ });
741
+ return tx(events);
742
+ }
743
+ getToolSequenceEvents(opts) {
744
+ const conditions = [];
745
+ const params = [];
746
+ if (opts?.sessionId) {
747
+ conditions.push('session_id = ?');
748
+ params.push(opts.sessionId);
749
+ }
750
+ if (opts?.since) {
751
+ conditions.push('timestamp >= ?');
752
+ params.push(opts.since);
753
+ }
754
+ const where = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : '';
755
+ const limit = opts?.limit ?? 10000;
756
+ params.push(limit);
757
+ const rows = this.db
758
+ .prepare(`SELECT * FROM tool_sequence_events ${where} ORDER BY timestamp ASC LIMIT ?`)
759
+ .all(...params);
760
+ return rows.map((r) => ({
761
+ id: r.id,
762
+ sessionId: r.session_id,
763
+ toolName: r.tool_name,
764
+ actionCanonical: r.action_canonical,
765
+ projectPath: r.project_path,
766
+ timestamp: r.timestamp,
767
+ ingestedAt: r.ingested_at,
768
+ }));
769
+ }
770
+ saveWorkflowPattern(pattern) {
771
+ const stmt = this.db.prepare(`
772
+ INSERT OR REPLACE INTO workflow_patterns
773
+ (pattern_hash, pattern_type, sequence_json, frequency, session_count, confidence, first_seen, last_seen, status)
774
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
775
+ `);
776
+ const result = stmt.run(pattern.patternHash, pattern.patternType, pattern.sequenceJson, pattern.frequency, pattern.sessionCount, pattern.confidence, pattern.firstSeen ?? null, pattern.lastSeen ?? null, pattern.status);
777
+ return Number(result.lastInsertRowid);
778
+ }
779
+ getWorkflowPatterns(opts) {
780
+ const conditions = [];
781
+ const params = [];
782
+ if (opts?.status) {
783
+ conditions.push('status = ?');
784
+ params.push(opts.status);
785
+ }
786
+ const where = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : '';
787
+ const rows = this.db
788
+ .prepare(`SELECT * FROM workflow_patterns ${where} ORDER BY confidence DESC`)
789
+ .all(...params);
790
+ return rows.map((r) => ({
791
+ id: r.id,
792
+ patternHash: r.pattern_hash,
793
+ patternType: r.pattern_type,
794
+ sequenceJson: r.sequence_json,
795
+ frequency: r.frequency,
796
+ sessionCount: r.session_count,
797
+ confidence: r.confidence,
798
+ firstSeen: r.first_seen,
799
+ lastSeen: r.last_seen,
800
+ status: r.status,
801
+ detectedAt: r.detected_at,
802
+ }));
803
+ }
804
+ savePatternProposal(proposal) {
805
+ const stmt = this.db.prepare(`
806
+ INSERT INTO pattern_proposals
807
+ (pattern_id, proposal_type, artifact_type, artifact_path, draft_content, confidence, status)
808
+ VALUES (?, ?, ?, ?, ?, ?, ?)
809
+ `);
810
+ const result = stmt.run(proposal.patternId, proposal.proposalType, proposal.artifactType, proposal.artifactPath ?? null, proposal.draftContent, proposal.confidence, proposal.status);
811
+ return Number(result.lastInsertRowid);
812
+ }
813
+ getPatternProposals(opts) {
814
+ const conditions = [];
815
+ const params = [];
816
+ if (opts?.status) {
817
+ conditions.push('status = ?');
818
+ params.push(opts.status);
819
+ }
820
+ const where = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : '';
821
+ const rows = this.db
822
+ .prepare(`SELECT * FROM pattern_proposals ${where} ORDER BY confidence DESC`)
823
+ .all(...params);
824
+ return rows.map((r) => ({
825
+ id: r.id,
826
+ patternId: r.pattern_id,
827
+ proposalType: r.proposal_type,
828
+ artifactType: r.artifact_type,
829
+ artifactPath: r.artifact_path,
830
+ draftContent: r.draft_content,
831
+ confidence: r.confidence,
832
+ status: r.status,
833
+ reviewedAt: r.reviewed_at,
834
+ reviewerReason: r.reviewer_reason,
835
+ createdAt: r.created_at,
836
+ }));
837
+ }
838
+ updateProposalStatus(id, status, reason) {
839
+ this.db
840
+ .prepare(`UPDATE pattern_proposals SET status = ?, reviewed_at = datetime('now'), reviewer_reason = ? WHERE id = ?`)
841
+ .run(status, reason ?? null, id);
842
+ }
843
+ // ── Design System Governance (RFC-0006) ───────────────────────────
844
+ insertDesignTokenEvent(record) {
845
+ const result = this.db
846
+ .prepare(`INSERT INTO design_token_events (binding_name, event_type, tokens_affected, diff_json, actor, pipeline_run_id, design_review_decision)
847
+ VALUES (?, ?, ?, ?, ?, ?, ?)`)
848
+ .run(record.bindingName, record.eventType, record.tokensAffected ?? 0, record.diffJson ?? null, record.actor ?? null, record.pipelineRunId ?? null, record.designReviewDecision ?? null);
849
+ return result.lastInsertRowid;
850
+ }
851
+ getDesignTokenEvents(bindingName, limit = 50) {
852
+ return this.db
853
+ .prepare(`SELECT * FROM design_token_events WHERE binding_name = ? ORDER BY created_at DESC LIMIT ?`)
854
+ .all(bindingName, limit);
855
+ }
856
+ insertDesignReviewEvent(record) {
857
+ const result = this.db
858
+ .prepare(`INSERT INTO design_review_events (binding_name, pr_number, component_name, reviewer, decision, categories_json, actionable_notes)
859
+ VALUES (?, ?, ?, ?, ?, ?, ?)`)
860
+ .run(record.bindingName, record.prNumber ?? null, record.componentName ?? null, record.reviewer, record.decision, record.categoriesJson ?? null, record.actionableNotes ?? null);
861
+ return result.lastInsertRowid;
862
+ }
863
+ getDesignReviewEvents(bindingName, limit = 50) {
864
+ return this.db
865
+ .prepare(`SELECT * FROM design_review_events WHERE binding_name = ? ORDER BY created_at DESC LIMIT ?`)
866
+ .all(bindingName, limit);
867
+ }
868
+ insertTokenComplianceSnapshot(record) {
869
+ const result = this.db
870
+ .prepare(`INSERT INTO token_compliance_history (binding_name, coverage_percent, violations_count) VALUES (?, ?, ?)`)
871
+ .run(record.bindingName, record.coveragePercent, record.violationsCount);
872
+ return result.lastInsertRowid;
873
+ }
874
+ getTokenComplianceHistory(bindingName, limit = 50) {
875
+ return this.db
876
+ .prepare(`SELECT * FROM token_compliance_history WHERE binding_name = ? ORDER BY scanned_at DESC LIMIT ?`)
877
+ .all(bindingName, limit);
878
+ }
879
+ insertVisualRegressionResult(record) {
880
+ const result = this.db
881
+ .prepare(`INSERT INTO visual_regression_results (binding_name, story_name, viewport, diff_percentage, approved, approver, baseline_url, current_url)
882
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)`)
883
+ .run(record.bindingName, record.storyName, record.viewport ?? null, record.diffPercentage, record.approved ? 1 : 0, record.approver ?? null, record.baselineUrl ?? null, record.currentUrl ?? null);
884
+ return result.lastInsertRowid;
885
+ }
886
+ getVisualRegressionResults(bindingName, limit = 50) {
887
+ return this.db
888
+ .prepare(`SELECT * FROM visual_regression_results WHERE binding_name = ? ORDER BY created_at DESC LIMIT ?`)
889
+ .all(bindingName, limit);
890
+ }
891
+ insertUsabilitySimulationResult(record) {
892
+ const result = this.db
893
+ .prepare(`INSERT INTO usability_simulation_results (binding_name, story_name, persona_id, task_id, completed, actions_taken, expected_actions, efficiency, findings_json)
894
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`)
895
+ .run(record.bindingName, record.storyName, record.personaId ?? null, record.taskId ?? null, record.completed ? 1 : 0, record.actionsTaken ?? null, record.expectedActions ?? null, record.efficiency ?? null, record.findingsJson ?? null);
896
+ return result.lastInsertRowid;
897
+ }
898
+ getUsabilitySimulationResults(bindingName, limit = 50) {
899
+ return this.db
900
+ .prepare(`SELECT * FROM usability_simulation_results WHERE binding_name = ? ORDER BY created_at DESC LIMIT ?`)
901
+ .all(bindingName, limit);
902
+ }
903
+ // ── PPA Triad Integration (RFC-0008) ─────────────────────────────────
904
+ insertDidCompiledArtifact(record) {
905
+ const result = this.db
906
+ .prepare(`INSERT INTO did_compiled_artifacts (did_name, namespace, source_hash, scope_lists_json, constraint_rules_json, anti_pattern_lists_json, measurable_signals_json, bm25_corpus_blob, principle_corpora_blob)
907
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`)
908
+ .run(record.didName, record.namespace ?? null, record.sourceHash, record.scopeListsJson ?? null, record.constraintRulesJson ?? null, record.antiPatternListsJson ?? null, record.measurableSignalsJson ?? null, record.bm25CorpusBlob ?? null, record.principleCorporaBlob ?? null);
909
+ return Number(result.lastInsertRowid);
910
+ }
911
+ getLatestDidCompiledArtifact(didName) {
912
+ const row = this.db
913
+ .prepare(`SELECT * FROM did_compiled_artifacts WHERE did_name = ? ORDER BY compiled_at DESC, id DESC LIMIT 1`)
914
+ .get(didName);
915
+ return row ? this.mapDidCompiledArtifact(row) : undefined;
916
+ }
917
+ getDidCompiledArtifactByHash(didName, sourceHash) {
918
+ const row = this.db
919
+ .prepare(`SELECT * FROM did_compiled_artifacts WHERE did_name = ? AND source_hash = ? ORDER BY compiled_at DESC, id DESC LIMIT 1`)
920
+ .get(didName, sourceHash);
921
+ return row ? this.mapDidCompiledArtifact(row) : undefined;
922
+ }
923
+ mapDidCompiledArtifact(row) {
924
+ return {
925
+ id: row.id,
926
+ didName: row.did_name,
927
+ namespace: row.namespace,
928
+ sourceHash: row.source_hash,
929
+ scopeListsJson: row.scope_lists_json,
930
+ constraintRulesJson: row.constraint_rules_json,
931
+ antiPatternListsJson: row.anti_pattern_lists_json,
932
+ measurableSignalsJson: row.measurable_signals_json,
933
+ bm25CorpusBlob: row.bm25_corpus_blob,
934
+ principleCorporaBlob: row.principle_corpora_blob,
935
+ compiledAt: row.compiled_at,
936
+ };
937
+ }
938
+ recordDidScoringEvent(record) {
939
+ const result = this.db
940
+ .prepare(`INSERT INTO did_scoring_events (did_name, issue_number, sa_dimension, phase, layer1_result_json, layer2_result_json, layer3_result_json, composite_score, phase_weights_json)
941
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`)
942
+ .run(record.didName, record.issueNumber, record.saDimension, record.phase, record.layer1ResultJson ?? null, record.layer2ResultJson ?? null, record.layer3ResultJson ?? null, record.compositeScore ?? null, record.phaseWeightsJson ?? null);
943
+ return Number(result.lastInsertRowid);
944
+ }
945
+ getDidScoringEvents(opts) {
946
+ const conditions = [];
947
+ const params = [];
948
+ if (opts?.didName) {
949
+ conditions.push('did_name = ?');
950
+ params.push(opts.didName);
951
+ }
952
+ if (opts?.issueNumber !== undefined) {
953
+ conditions.push('issue_number = ?');
954
+ params.push(opts.issueNumber);
955
+ }
956
+ if (opts?.saDimension) {
957
+ conditions.push('sa_dimension = ?');
958
+ params.push(opts.saDimension);
959
+ }
960
+ if (opts?.since) {
961
+ conditions.push('created_at >= ?');
962
+ params.push(opts.since);
963
+ }
964
+ const where = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : '';
965
+ const limit = opts?.limit ?? 100;
966
+ params.push(limit);
967
+ const rows = this.db
968
+ .prepare(`SELECT * FROM did_scoring_events ${where} ORDER BY created_at DESC, id DESC LIMIT ?`)
969
+ .all(...params);
970
+ return rows.map((r) => ({
971
+ id: r.id,
972
+ didName: r.did_name,
973
+ issueNumber: r.issue_number,
974
+ saDimension: r.sa_dimension,
975
+ phase: r.phase,
976
+ layer1ResultJson: r.layer1_result_json,
977
+ layer2ResultJson: r.layer2_result_json,
978
+ layer3ResultJson: r.layer3_result_json,
979
+ compositeScore: r.composite_score,
980
+ phaseWeightsJson: r.phase_weights_json,
981
+ createdAt: r.created_at,
982
+ }));
983
+ }
984
+ recordDidFeedback(record) {
985
+ const result = this.db
986
+ .prepare(`INSERT INTO did_feedback_events (did_name, issue_number, dimension, signal, principal, category, structural_score, llm_score, composite_score, notes)
987
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
988
+ .run(record.didName, record.issueNumber, record.dimension, record.signal, record.principal ?? null, record.category ?? null, record.structuralScore ?? null, record.llmScore ?? null, record.compositeScore ?? null, record.notes ?? null);
989
+ return Number(result.lastInsertRowid);
990
+ }
991
+ getDidFeedbackEvents(opts) {
992
+ const conditions = [];
993
+ const params = [];
994
+ if (opts?.didName) {
995
+ conditions.push('did_name = ?');
996
+ params.push(opts.didName);
997
+ }
998
+ if (opts?.issueNumber !== undefined) {
999
+ conditions.push('issue_number = ?');
1000
+ params.push(opts.issueNumber);
1001
+ }
1002
+ if (opts?.signal) {
1003
+ conditions.push('signal = ?');
1004
+ params.push(opts.signal);
1005
+ }
1006
+ if (opts?.dimension) {
1007
+ conditions.push('dimension = ?');
1008
+ params.push(opts.dimension);
1009
+ }
1010
+ if (opts?.since) {
1011
+ conditions.push('created_at >= ?');
1012
+ params.push(opts.since);
1013
+ }
1014
+ const where = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : '';
1015
+ const limit = opts?.limit ?? 500;
1016
+ params.push(limit);
1017
+ const rows = this.db
1018
+ .prepare(`SELECT * FROM did_feedback_events ${where} ORDER BY created_at DESC, id DESC LIMIT ?`)
1019
+ .all(...params);
1020
+ return rows.map((r) => ({
1021
+ id: r.id,
1022
+ didName: r.did_name,
1023
+ issueNumber: r.issue_number,
1024
+ dimension: r.dimension,
1025
+ signal: r.signal,
1026
+ principal: r.principal,
1027
+ category: r.category,
1028
+ structuralScore: r.structural_score,
1029
+ llmScore: r.llm_score,
1030
+ compositeScore: r.composite_score,
1031
+ notes: r.notes,
1032
+ createdAt: r.created_at,
1033
+ }));
1034
+ }
1035
+ recordDesignChange(record) {
1036
+ const result = this.db
1037
+ .prepare(`INSERT INTO design_change_events (did_name, change_id, change_type, status, payload_json)
1038
+ VALUES (?, ?, ?, ?, ?)`)
1039
+ .run(record.didName, record.changeId, record.changeType, record.status, record.payloadJson);
1040
+ return Number(result.lastInsertRowid);
1041
+ }
1042
+ getDesignChangeEvents(opts) {
1043
+ const conditions = [];
1044
+ const params = [];
1045
+ if (opts?.didName) {
1046
+ conditions.push('did_name = ?');
1047
+ params.push(opts.didName);
1048
+ }
1049
+ if (opts?.changeId) {
1050
+ conditions.push('change_id = ?');
1051
+ params.push(opts.changeId);
1052
+ }
1053
+ const where = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : '';
1054
+ const limit = opts?.limit ?? 100;
1055
+ params.push(limit);
1056
+ const rows = this.db
1057
+ .prepare(`SELECT * FROM design_change_events ${where} ORDER BY emitted_at DESC, id DESC LIMIT ?`)
1058
+ .all(...params);
1059
+ return rows.map((r) => ({
1060
+ id: r.id,
1061
+ didName: r.did_name,
1062
+ changeId: r.change_id,
1063
+ changeType: r.change_type,
1064
+ status: r.status,
1065
+ payloadJson: r.payload_json,
1066
+ emittedAt: r.emitted_at,
1067
+ }));
1068
+ }
1069
+ insertCodeAreaMetrics(record) {
1070
+ const result = this.db
1071
+ .prepare(`INSERT INTO code_area_metrics (code_area, defect_density, churn_rate, pr_rejection_rate, code_acceptance_rate, has_frontend_components, design_metrics_json, data_point_count, window_start, window_end)
1072
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
1073
+ .run(record.codeArea, record.defectDensity ?? null, record.churnRate ?? null, record.prRejectionRate ?? null, record.codeAcceptanceRate ?? null, record.hasFrontendComponents ? 1 : 0, record.designMetricsJson ?? null, record.dataPointCount ?? 0, record.windowStart ?? null, record.windowEnd ?? null);
1074
+ return Number(result.lastInsertRowid);
1075
+ }
1076
+ /**
1077
+ * Get the most recent metrics snapshot for a code area.
1078
+ * `since` filters to rows where `computed_at >= since`.
1079
+ */
1080
+ getCodeAreaMetrics(codeArea, opts) {
1081
+ const conditions = ['code_area = ?'];
1082
+ const params = [codeArea];
1083
+ if (opts?.since) {
1084
+ conditions.push('computed_at >= ?');
1085
+ params.push(opts.since);
1086
+ }
1087
+ const row = this.db
1088
+ .prepare(`SELECT * FROM code_area_metrics WHERE ${conditions.join(' AND ')} ORDER BY computed_at DESC, id DESC LIMIT 1`)
1089
+ .get(...params);
1090
+ return row ? this.mapCodeAreaMetrics(row) : undefined;
1091
+ }
1092
+ getCodeAreaMetricsHistory(codeArea, opts) {
1093
+ const conditions = ['code_area = ?'];
1094
+ const params = [codeArea];
1095
+ if (opts?.since) {
1096
+ conditions.push('computed_at >= ?');
1097
+ params.push(opts.since);
1098
+ }
1099
+ const limit = opts?.limit ?? 100;
1100
+ params.push(limit);
1101
+ const rows = this.db
1102
+ .prepare(`SELECT * FROM code_area_metrics WHERE ${conditions.join(' AND ')} ORDER BY computed_at DESC, id DESC LIMIT ?`)
1103
+ .all(...params);
1104
+ return rows.map((r) => this.mapCodeAreaMetrics(r));
1105
+ }
1106
+ mapCodeAreaMetrics(row) {
1107
+ return {
1108
+ id: row.id,
1109
+ codeArea: row.code_area,
1110
+ defectDensity: row.defect_density,
1111
+ churnRate: row.churn_rate,
1112
+ prRejectionRate: row.pr_rejection_rate,
1113
+ codeAcceptanceRate: row.code_acceptance_rate,
1114
+ hasFrontendComponents: Boolean(row.has_frontend_components),
1115
+ designMetricsJson: row.design_metrics_json,
1116
+ dataPointCount: row.data_point_count,
1117
+ windowStart: row.window_start,
1118
+ windowEnd: row.window_end,
1119
+ computedAt: row.computed_at,
1120
+ };
1121
+ }
1122
+ upsertDesignLookaheadNotification(record) {
1123
+ const result = this.db
1124
+ .prepare(`INSERT INTO design_lookahead_notifications (issue_number, pillar_breakdown_json)
1125
+ VALUES (?, ?)
1126
+ ON CONFLICT(issue_number) DO UPDATE SET
1127
+ last_notified_at = datetime('now'),
1128
+ pillar_breakdown_json = COALESCE(excluded.pillar_breakdown_json, pillar_breakdown_json)`)
1129
+ .run(record.issueNumber, record.pillarBreakdownJson ?? null);
1130
+ return Number(result.lastInsertRowid);
1131
+ }
1132
+ getDesignLookaheadNotification(issueNumber) {
1133
+ const row = this.db
1134
+ .prepare(`SELECT * FROM design_lookahead_notifications WHERE issue_number = ?`)
1135
+ .get(issueNumber);
1136
+ if (!row)
1137
+ return undefined;
1138
+ return {
1139
+ id: row.id,
1140
+ issueNumber: row.issue_number,
1141
+ firstNotifiedAt: row.first_notified_at,
1142
+ lastNotifiedAt: row.last_notified_at,
1143
+ pillarBreakdownJson: row.pillar_breakdown_json,
1144
+ };
1145
+ }
1146
+ // ── SA Phase Weights (RFC-0008 §B.8 AISDLC-66) ──────────────────────
1147
+ upsertSaPhaseWeights(record) {
1148
+ this.db
1149
+ .prepare(`INSERT INTO sa_phase_weights (dimension, w_structural, w_llm, calibrated_at)
1150
+ VALUES (?, ?, ?, datetime('now'))
1151
+ ON CONFLICT(dimension) DO UPDATE SET
1152
+ w_structural = excluded.w_structural,
1153
+ w_llm = excluded.w_llm,
1154
+ calibrated_at = excluded.calibrated_at`)
1155
+ .run(record.dimension, record.wStructural, record.wLlm);
1156
+ }
1157
+ getSaPhaseWeights(dimension) {
1158
+ const row = this.db
1159
+ .prepare(`SELECT * FROM sa_phase_weights WHERE dimension = ?`)
1160
+ .get(dimension);
1161
+ if (!row)
1162
+ return undefined;
1163
+ return {
1164
+ id: row.id,
1165
+ dimension: row.dimension,
1166
+ wStructural: row.w_structural,
1167
+ wLlm: row.w_llm,
1168
+ calibratedAt: row.calibrated_at,
1169
+ };
1170
+ }
714
1171
  close() {
715
1172
  this.db.close();
716
1173
  }