@ai-sdlc/orchestrator 0.6.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 (203) hide show
  1. package/dist/admission-composite.d.ts +67 -0
  2. package/dist/admission-composite.js +158 -0
  3. package/dist/admission-enrichment.d.ts +142 -0
  4. package/dist/admission-enrichment.js +331 -0
  5. package/dist/admission-hc.d.ts +62 -0
  6. package/dist/admission-hc.js +83 -0
  7. package/dist/admission-score.d.ts +95 -5
  8. package/dist/admission-score.js +84 -11
  9. package/dist/analysis/analyzer.js +3 -2
  10. package/dist/analysis/convention-detector.d.ts +85 -2
  11. package/dist/analysis/convention-detector.js +375 -70
  12. package/dist/analysis/diff-analyzer.d.ts +33 -0
  13. package/dist/analysis/diff-analyzer.js +122 -0
  14. package/dist/analysis/hotspot-analyzer.js +3 -1
  15. package/dist/analysis/index.d.ts +2 -1
  16. package/dist/analysis/index.js +2 -1
  17. package/dist/artifacts/index.d.ts +65 -0
  18. package/dist/artifacts/index.js +142 -0
  19. package/dist/backlog-adapter.d.ts +121 -0
  20. package/dist/backlog-adapter.js +438 -0
  21. package/dist/calibration.d.ts +43 -0
  22. package/dist/calibration.js +76 -0
  23. package/dist/cli/commands/agents.d.ts +24 -0
  24. package/dist/cli/commands/agents.js +66 -1
  25. package/dist/cli/commands/git-remote.d.ts +49 -0
  26. package/dist/cli/commands/git-remote.js +91 -0
  27. package/dist/cli/commands/health.d.ts +4 -0
  28. package/dist/cli/commands/health.js +13 -1
  29. package/dist/cli/commands/init.d.ts +26 -0
  30. package/dist/cli/commands/init.js +164 -22
  31. package/dist/cli/commands/mcp-setup.d.ts +31 -0
  32. package/dist/cli/commands/mcp-setup.js +78 -8
  33. package/dist/cli/formatters/table.js +15 -2
  34. package/dist/cli/index.d.ts +14 -1
  35. package/dist/cli/index.js +81 -20
  36. package/dist/cli/versions.d.ts +57 -0
  37. package/dist/cli/versions.js +128 -0
  38. package/dist/code-area-classifier.d.ts +21 -0
  39. package/dist/code-area-classifier.js +48 -0
  40. package/dist/config.d.ts +33 -1
  41. package/dist/config.js +78 -8
  42. package/dist/database/adapters/external.d.ts +24 -0
  43. package/dist/database/adapters/external.js +80 -0
  44. package/dist/database/adapters/neon.d.ts +41 -0
  45. package/dist/database/adapters/neon.js +98 -0
  46. package/dist/database/adapters/pg-snapshot-restore.d.ts +28 -0
  47. package/dist/database/adapters/pg-snapshot-restore.js +68 -0
  48. package/dist/database/adapters/sqlite-copy.d.ts +32 -0
  49. package/dist/database/adapters/sqlite-copy.js +145 -0
  50. package/dist/database/connection-injection.d.ts +35 -0
  51. package/dist/database/connection-injection.js +93 -0
  52. package/dist/database/index.d.ts +12 -0
  53. package/dist/database/index.js +23 -0
  54. package/dist/database/registry.d.ts +13 -0
  55. package/dist/database/registry.js +27 -0
  56. package/dist/database/topology.d.ts +52 -0
  57. package/dist/database/topology.js +44 -0
  58. package/dist/database/types.d.ts +89 -0
  59. package/dist/database/types.js +26 -0
  60. package/dist/design-authority.d.ts +40 -0
  61. package/dist/design-authority.js +71 -0
  62. package/dist/design-lookahead.d.ts +64 -0
  63. package/dist/design-lookahead.js +86 -0
  64. package/dist/design-quality-trend.d.ts +87 -0
  65. package/dist/design-quality-trend.js +190 -0
  66. package/dist/design-system-context.d.ts +46 -0
  67. package/dist/design-system-context.js +80 -0
  68. package/dist/design-system-correction-loop.d.ts +64 -0
  69. package/dist/design-system-correction-loop.js +128 -0
  70. package/dist/design-system-metrics.d.ts +61 -0
  71. package/dist/design-system-metrics.js +104 -0
  72. package/dist/design-system-stewardship.d.ts +22 -0
  73. package/dist/design-system-stewardship.js +85 -0
  74. package/dist/design-system-validation.d.ts +37 -0
  75. package/dist/design-system-validation.js +88 -0
  76. package/dist/dispatch/index.d.ts +4 -0
  77. package/dist/dispatch/index.js +4 -0
  78. package/dist/dispatch/merge-gate.d.ts +46 -0
  79. package/dist/dispatch/merge-gate.js +90 -0
  80. package/dist/dispatch/requeue.d.ts +57 -0
  81. package/dist/dispatch/requeue.js +131 -0
  82. package/dist/dispatch/worker-pool.d.ts +62 -0
  83. package/dist/dispatch/worker-pool.js +60 -0
  84. package/dist/execute.d.ts +40 -0
  85. package/dist/execute.js +185 -15
  86. package/dist/fix-ci.js +8 -1
  87. package/dist/fix-review.js +8 -1
  88. package/dist/harness/adapters/claude-code.d.ts +29 -0
  89. package/dist/harness/adapters/claude-code.js +191 -0
  90. package/dist/harness/adapters/codex.d.ts +25 -0
  91. package/dist/harness/adapters/codex.js +61 -0
  92. package/dist/harness/independence.d.ts +51 -0
  93. package/dist/harness/independence.js +67 -0
  94. package/dist/harness/index.d.ts +14 -0
  95. package/dist/harness/index.js +20 -0
  96. package/dist/harness/registry.d.ts +17 -0
  97. package/dist/harness/registry.js +31 -0
  98. package/dist/harness/types.d.ts +123 -0
  99. package/dist/harness/types.js +8 -0
  100. package/dist/harness/version-probe.d.ts +14 -0
  101. package/dist/harness/version-probe.js +123 -0
  102. package/dist/index.d.ts +30 -4
  103. package/dist/index.js +35 -2
  104. package/dist/models/classifier.d.ts +76 -0
  105. package/dist/models/classifier.js +221 -0
  106. package/dist/models/index.d.ts +3 -0
  107. package/dist/models/index.js +3 -0
  108. package/dist/models/registry.d.ts +97 -0
  109. package/dist/models/registry.js +173 -0
  110. package/dist/pillar-breakdown.d.ts +63 -0
  111. package/dist/pillar-breakdown.js +153 -0
  112. package/dist/priority.d.ts +5 -0
  113. package/dist/priority.js +18 -5
  114. package/dist/review-meta.d.ts +65 -0
  115. package/dist/review-meta.js +149 -0
  116. package/dist/review.d.ts +4 -0
  117. package/dist/review.js +12 -2
  118. package/dist/runners/claude-code-sdk.d.ts +31 -0
  119. package/dist/runners/claude-code-sdk.js +238 -0
  120. package/dist/runners/claude-code.d.ts +3 -0
  121. package/dist/runners/claude-code.js +30 -66
  122. package/dist/runners/codex.js +4 -1
  123. package/dist/runners/copilot.js +4 -1
  124. package/dist/runners/cursor.js +4 -1
  125. package/dist/runners/git-utils.d.ts +81 -0
  126. package/dist/runners/git-utils.js +201 -0
  127. package/dist/runners/index.d.ts +3 -0
  128. package/dist/runners/index.js +3 -0
  129. package/dist/runners/review-agent.d.ts +20 -0
  130. package/dist/runners/review-agent.js +171 -41
  131. package/dist/runners/runner-registry.js +10 -0
  132. package/dist/runners/sdk-review-runner.d.ts +65 -0
  133. package/dist/runners/sdk-review-runner.js +185 -0
  134. package/dist/runners/security-triage.d.ts +20 -4
  135. package/dist/runners/security-triage.js +39 -15
  136. package/dist/runners/types.d.ts +6 -0
  137. package/dist/runtime/attestations.d.ts +274 -0
  138. package/dist/runtime/attestations.js +460 -0
  139. package/dist/runtime/git-env.d.ts +53 -0
  140. package/dist/runtime/git-env.js +60 -0
  141. package/dist/runtime/index.d.ts +7 -0
  142. package/dist/runtime/index.js +7 -0
  143. package/dist/runtime/parallelism-flag.d.ts +10 -0
  144. package/dist/runtime/parallelism-flag.js +18 -0
  145. package/dist/runtime/port-allocator.d.ts +21 -0
  146. package/dist/runtime/port-allocator.js +66 -0
  147. package/dist/runtime/worktree-pool.d.ts +86 -0
  148. package/dist/runtime/worktree-pool.js +204 -0
  149. package/dist/runtime/worktree.d.ts +25 -0
  150. package/dist/runtime/worktree.js +111 -0
  151. package/dist/sa-scoring/auto-calibrate.d.ts +69 -0
  152. package/dist/sa-scoring/auto-calibrate.js +107 -0
  153. package/dist/sa-scoring/c1-sa2-computable.d.ts +42 -0
  154. package/dist/sa-scoring/c1-sa2-computable.js +59 -0
  155. package/dist/sa-scoring/composite.d.ts +107 -0
  156. package/dist/sa-scoring/composite.js +139 -0
  157. package/dist/sa-scoring/depparse-client.d.ts +79 -0
  158. package/dist/sa-scoring/depparse-client.js +187 -0
  159. package/dist/sa-scoring/did-compiler.d.ts +122 -0
  160. package/dist/sa-scoring/did-compiler.js +286 -0
  161. package/dist/sa-scoring/drift-monitor.d.ts +84 -0
  162. package/dist/sa-scoring/drift-monitor.js +186 -0
  163. package/dist/sa-scoring/exemplar-bank.d.ts +78 -0
  164. package/dist/sa-scoring/exemplar-bank.js +154 -0
  165. package/dist/sa-scoring/feedback-store.d.ts +100 -0
  166. package/dist/sa-scoring/feedback-store.js +156 -0
  167. package/dist/sa-scoring/index.d.ts +71 -0
  168. package/dist/sa-scoring/index.js +158 -0
  169. package/dist/sa-scoring/layer1-deterministic.d.ts +115 -0
  170. package/dist/sa-scoring/layer1-deterministic.js +298 -0
  171. package/dist/sa-scoring/layer2-structural.d.ts +71 -0
  172. package/dist/sa-scoring/layer2-structural.js +151 -0
  173. package/dist/sa-scoring/layer3-llm.d.ts +86 -0
  174. package/dist/sa-scoring/layer3-llm.js +282 -0
  175. package/dist/sa-scoring/rescore-orchestrator.d.ts +52 -0
  176. package/dist/sa-scoring/rescore-orchestrator.js +47 -0
  177. package/dist/scheduling/burn-down.d.ts +27 -0
  178. package/dist/scheduling/burn-down.js +43 -0
  179. package/dist/scheduling/calibration.d.ts +42 -0
  180. package/dist/scheduling/calibration.js +150 -0
  181. package/dist/scheduling/index.d.ts +8 -0
  182. package/dist/scheduling/index.js +8 -0
  183. package/dist/scheduling/ledger.d.ts +59 -0
  184. package/dist/scheduling/ledger.js +216 -0
  185. package/dist/scheduling/off-peak.d.ts +27 -0
  186. package/dist/scheduling/off-peak.js +112 -0
  187. package/dist/scheduling/schedule-decision.d.ts +39 -0
  188. package/dist/scheduling/schedule-decision.js +89 -0
  189. package/dist/scheduling/tier-analysis.d.ts +47 -0
  190. package/dist/scheduling/tier-analysis.js +81 -0
  191. package/dist/scheduling/types.d.ts +140 -0
  192. package/dist/scheduling/types.js +11 -0
  193. package/dist/shared.d.ts +13 -0
  194. package/dist/shared.js +32 -0
  195. package/dist/state/schema.d.ts +5 -1
  196. package/dist/state/schema.js +223 -1
  197. package/dist/state/store.d.ts +55 -1
  198. package/dist/state/store.js +342 -7
  199. package/dist/state/types.d.ts +139 -0
  200. package/dist/types.d.ts +1 -1
  201. package/dist/validate-agent-output.js +4 -1
  202. package/dist/watch.js +6 -0
  203. package/package.json +2 -2
@@ -0,0 +1,93 @@
1
+ /**
2
+ * Connection-string injection per RFC §15.6. The agent sees the per-worktree branch
3
+ * via the same env-var name (`DATABASE_URL` etc.) the application expects. Adapters
4
+ * provide the rewritten string; this module derives optional component env vars
5
+ * (PGHOST, PGDATABASE, etc.) from it.
6
+ */
7
+ /**
8
+ * Build the env-var overlay for a single (handle, pool) pair. The agent's process
9
+ * env is the orchestrator's env merged with this overlay.
10
+ *
11
+ * Component derivation supports postgres:// connection strings — for non-Postgres
12
+ * URLs (e.g., sqlite file paths), additionalEnvs is silently ignored.
13
+ */
14
+ export function buildInjectionOverrides(handle, pool) {
15
+ const overrides = {};
16
+ overrides[pool.injection.targetEnv] = handle.connectionString;
17
+ if (pool.injection.additionalEnvs && pool.injection.additionalEnvs.length > 0) {
18
+ const components = parsePostgresUrl(handle.connectionString);
19
+ if (components) {
20
+ for (const envName of pool.injection.additionalEnvs) {
21
+ const mapped = mapEnvNameToComponent(envName, components);
22
+ if (mapped !== null)
23
+ overrides[envName] = mapped;
24
+ }
25
+ }
26
+ }
27
+ return overrides;
28
+ }
29
+ export function parsePostgresUrl(url) {
30
+ // postgres://[user[:password]@]host[:port][/database][?...]
31
+ // Also handles postgresql:// scheme.
32
+ try {
33
+ const parsed = new URL(url);
34
+ if (!/^postgres(?:ql)?:$/.test(parsed.protocol))
35
+ return null;
36
+ return {
37
+ host: parsed.hostname,
38
+ port: parsed.port || '5432',
39
+ database: parsed.pathname.replace(/^\//, ''),
40
+ user: decodeURIComponent(parsed.username),
41
+ password: decodeURIComponent(parsed.password),
42
+ };
43
+ }
44
+ catch {
45
+ return null;
46
+ }
47
+ }
48
+ function mapEnvNameToComponent(name, c) {
49
+ const upper = name.toUpperCase();
50
+ switch (upper) {
51
+ case 'PGHOST':
52
+ case 'POSTGRES_HOST':
53
+ case 'DB_HOST':
54
+ return c.host;
55
+ case 'PGPORT':
56
+ case 'POSTGRES_PORT':
57
+ case 'DB_PORT':
58
+ return c.port;
59
+ case 'PGDATABASE':
60
+ case 'POSTGRES_DB':
61
+ case 'DB_NAME':
62
+ return c.database;
63
+ case 'PGUSER':
64
+ case 'POSTGRES_USER':
65
+ case 'DB_USER':
66
+ return c.user;
67
+ case 'PGPASSWORD':
68
+ case 'POSTGRES_PASSWORD':
69
+ case 'DB_PASSWORD':
70
+ return c.password;
71
+ default:
72
+ return null;
73
+ }
74
+ }
75
+ /**
76
+ * Mask a connection string for safe logging. Replaces the password segment with
77
+ * `****`. Per RFC §15.1 the connection string itself MUST NEVER appear in any
78
+ * observability output — this helper exists for adapter error messages where
79
+ * the URL form might leak.
80
+ */
81
+ export function maskConnectionString(url) {
82
+ try {
83
+ const parsed = new URL(url);
84
+ if (parsed.password) {
85
+ parsed.password = '****';
86
+ }
87
+ return parsed.toString();
88
+ }
89
+ catch {
90
+ return '<unparseable connection string>';
91
+ }
92
+ }
93
+ //# sourceMappingURL=connection-injection.js.map
@@ -0,0 +1,12 @@
1
+ export * from './types.js';
2
+ export { DatabaseAdapterRegistry, UnknownDatabaseAdapterError } from './registry.js';
3
+ export { buildInjectionOverrides, parsePostgresUrl, maskConnectionString, type InjectedEnvOverrides, } from './connection-injection.js';
4
+ export { enforceTopologyGuard, buildMigrationDivergedEvent, type KnownInFlightBranches, type MigrationDivergedEvent, } from './topology.js';
5
+ export { SqliteCopyAdapter, type SqliteCopyAdapterDeps } from './adapters/sqlite-copy.js';
6
+ export { NeonAdapter, type NeonAdapterDeps } from './adapters/neon.js';
7
+ export { PgSnapshotRestoreAdapter, type PgSnapshotRestoreAdapterDeps, } from './adapters/pg-snapshot-restore.js';
8
+ export { ExternalAdapter, type ExternalAdapterDeps } from './adapters/external.js';
9
+ import { DatabaseAdapterRegistry } from './registry.js';
10
+ /** Pre-populated registry with the four shipped v1 adapters. */
11
+ export declare function createDefaultDatabaseAdapterRegistry(): DatabaseAdapterRegistry;
12
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,23 @@
1
+ export * from './types.js';
2
+ export { DatabaseAdapterRegistry, UnknownDatabaseAdapterError } from './registry.js';
3
+ export { buildInjectionOverrides, parsePostgresUrl, maskConnectionString, } from './connection-injection.js';
4
+ export { enforceTopologyGuard, buildMigrationDivergedEvent, } from './topology.js';
5
+ export { SqliteCopyAdapter } from './adapters/sqlite-copy.js';
6
+ export { NeonAdapter } from './adapters/neon.js';
7
+ export { PgSnapshotRestoreAdapter, } from './adapters/pg-snapshot-restore.js';
8
+ export { ExternalAdapter } from './adapters/external.js';
9
+ import { DatabaseAdapterRegistry } from './registry.js';
10
+ import { SqliteCopyAdapter } from './adapters/sqlite-copy.js';
11
+ import { NeonAdapter } from './adapters/neon.js';
12
+ import { PgSnapshotRestoreAdapter } from './adapters/pg-snapshot-restore.js';
13
+ import { ExternalAdapter } from './adapters/external.js';
14
+ /** Pre-populated registry with the four shipped v1 adapters. */
15
+ export function createDefaultDatabaseAdapterRegistry() {
16
+ const reg = new DatabaseAdapterRegistry();
17
+ reg.register(new SqliteCopyAdapter());
18
+ reg.register(new NeonAdapter());
19
+ reg.register(new PgSnapshotRestoreAdapter());
20
+ reg.register(new ExternalAdapter());
21
+ return reg;
22
+ }
23
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,13 @@
1
+ import type { DatabaseAdapterName, DatabaseBranchAdapter } from './types.js';
2
+ export declare class UnknownDatabaseAdapterError extends Error {
3
+ readonly name: string;
4
+ constructor(name: string);
5
+ }
6
+ export declare class DatabaseAdapterRegistry {
7
+ private readonly adapters;
8
+ register(adapter: DatabaseBranchAdapter): void;
9
+ get(name: string): DatabaseBranchAdapter;
10
+ has(name: string): boolean;
11
+ list(): DatabaseAdapterName[];
12
+ }
13
+ //# sourceMappingURL=registry.d.ts.map
@@ -0,0 +1,27 @@
1
+ export class UnknownDatabaseAdapterError extends Error {
2
+ name;
3
+ constructor(name) {
4
+ super(`Unknown DatabaseBranchAdapter: ${name}`);
5
+ this.name = name;
6
+ this.name = 'UnknownDatabaseAdapterError';
7
+ }
8
+ }
9
+ export class DatabaseAdapterRegistry {
10
+ adapters = new Map();
11
+ register(adapter) {
12
+ this.adapters.set(adapter.name, adapter);
13
+ }
14
+ get(name) {
15
+ const a = this.adapters.get(name);
16
+ if (!a)
17
+ throw new UnknownDatabaseAdapterError(name);
18
+ return a;
19
+ }
20
+ has(name) {
21
+ return this.adapters.has(name);
22
+ }
23
+ list() {
24
+ return Array.from(this.adapters.keys());
25
+ }
26
+ }
27
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Branch topology guard per RFC §15.5.1 (Q15 resolution). Defaults `allowBranchFromBranch`
3
+ * to false, refusing to allocate a branch whose upstream is itself an in-flight feature
4
+ * branch. Eliminates MigrationDiverged for ~95% of pipelines that don't need stacked PRs.
5
+ */
6
+ import { type ResolvedDatabaseBranchPool } from './types.js';
7
+ export interface KnownInFlightBranches {
8
+ /** Branch names currently allocated as DatabaseBranch handles in this pool. */
9
+ inFlightBranchNames: Set<string>;
10
+ /** Stable upstream branch names the operator considers safe to branch from. */
11
+ stableUpstreams: Set<string>;
12
+ }
13
+ /**
14
+ * Validate a branchFrom request against the topology guard. Throws
15
+ * BranchTopologyForbiddenError if the upstream is an in-flight branch and
16
+ * `allowBranchFromBranch` is false.
17
+ */
18
+ export declare function enforceTopologyGuard(pool: ResolvedDatabaseBranchPool, state: KnownInFlightBranches): void;
19
+ /**
20
+ * MigrationDiverged event payload per RFC §15.5.1. Emitted by the orchestrator when a
21
+ * branch with active children is reclaimed (parent PR abandoned).
22
+ */
23
+ export interface MigrationDivergedEvent {
24
+ type: 'MigrationDiverged';
25
+ reclaimedBranch: {
26
+ branchKey: string;
27
+ reason: 'pr-abandoned' | 'manual-reclaim' | 'ttl-expired';
28
+ issueId?: string;
29
+ };
30
+ divergentChildren: Array<{
31
+ branchKey: string;
32
+ issueId?: string;
33
+ lastActivity: string;
34
+ }>;
35
+ interpretation: string;
36
+ recommendation: string;
37
+ }
38
+ /**
39
+ * Build a MigrationDiverged event from the parent reclaim + a snapshot of children.
40
+ * The orchestrator emits this through its event stream; the operator triages per
41
+ * the runbook. NO auto-action.
42
+ */
43
+ export declare function buildMigrationDivergedEvent(parent: {
44
+ branchKey: string;
45
+ reason: 'pr-abandoned' | 'manual-reclaim' | 'ttl-expired';
46
+ issueId?: string;
47
+ }, children: Array<{
48
+ branchKey: string;
49
+ issueId?: string;
50
+ lastActivity: Date;
51
+ }>): MigrationDivergedEvent;
52
+ //# sourceMappingURL=topology.d.ts.map
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Branch topology guard per RFC §15.5.1 (Q15 resolution). Defaults `allowBranchFromBranch`
3
+ * to false, refusing to allocate a branch whose upstream is itself an in-flight feature
4
+ * branch. Eliminates MigrationDiverged for ~95% of pipelines that don't need stacked PRs.
5
+ */
6
+ import { BranchTopologyForbiddenError } from './types.js';
7
+ /**
8
+ * Validate a branchFrom request against the topology guard. Throws
9
+ * BranchTopologyForbiddenError if the upstream is an in-flight branch and
10
+ * `allowBranchFromBranch` is false.
11
+ */
12
+ export function enforceTopologyGuard(pool, state) {
13
+ const branchFrom = pool.upstream.branchFrom;
14
+ if (!branchFrom)
15
+ return;
16
+ // Always allowed when the upstream is a declared stable branch.
17
+ if (state.stableUpstreams.has(branchFrom))
18
+ return;
19
+ if (state.inFlightBranchNames.has(branchFrom)) {
20
+ if (pool.allowBranchFromBranch !== true) {
21
+ throw new BranchTopologyForbiddenError(`DatabaseBranchPool '${pool.name}' attempted to branch from in-flight branch '${branchFrom}'; ` +
22
+ `set allowBranchFromBranch: true to opt in to chained branching (and accept MigrationDiverged risk).`, pool.name);
23
+ }
24
+ }
25
+ }
26
+ /**
27
+ * Build a MigrationDiverged event from the parent reclaim + a snapshot of children.
28
+ * The orchestrator emits this through its event stream; the operator triages per
29
+ * the runbook. NO auto-action.
30
+ */
31
+ export function buildMigrationDivergedEvent(parent, children) {
32
+ return {
33
+ type: 'MigrationDiverged',
34
+ reclaimedBranch: parent,
35
+ divergentChildren: children.map((c) => ({
36
+ branchKey: c.branchKey,
37
+ issueId: c.issueId,
38
+ lastActivity: c.lastActivity.toISOString(),
39
+ })),
40
+ interpretation: 'child branches inherit a migration that no longer exists in any merged code. Their PRs may pass tests but break on merge to main.',
41
+ recommendation: 'operator triage: rebase children onto current upstream, accept divergence, or reclaim children. The orchestrator does NOT auto-rebase or auto-reclaim.',
42
+ };
43
+ }
44
+ //# sourceMappingURL=topology.js.map
@@ -0,0 +1,89 @@
1
+ /**
2
+ * DatabaseBranchAdapter framework per RFC-0010 §15. Each adapter abstracts a database
3
+ * branching mechanism; the orchestrator allocates a branch per worktree, injects the
4
+ * branch's connection string into the agent's environment, and reclaims on PR merge.
5
+ */
6
+ export type DatabaseAdapterName = 'sqlite-copy' | 'neon' | 'pg-snapshot-restore' | 'supabase' | 'external';
7
+ export interface DatabaseBranchCapabilities {
8
+ branchCreationLatencyP50Ms: number;
9
+ maxBranches: number;
10
+ supportsMigrations: boolean;
11
+ supportsReadOnlyBranches: boolean;
12
+ supportsBranchFromBranch: boolean;
13
+ multiDatabase: boolean;
14
+ costModel: 'per-branch-storage' | 'per-snapshot' | 'free';
15
+ }
16
+ export interface DatabaseBranchHandle {
17
+ /** Stable key derived from the worktree branch name. */
18
+ branchKey: string;
19
+ /**
20
+ * Connection URL the agent will use. NEVER logged in cleartext per RFC §15.1
21
+ * (security review property — adapters MUST mask credentials in any error returned).
22
+ */
23
+ connectionString: string;
24
+ createdAt: Date;
25
+ /** Upstream branch the handle was derived from. */
26
+ upstream: string;
27
+ upstreamCommitId?: string;
28
+ /** Adapter-specific metadata (Neon: branch_id; pg-snapshot-restore: snapshot id). */
29
+ metadata: Record<string, string>;
30
+ }
31
+ export interface ResolvedDatabaseBranchPool {
32
+ name: string;
33
+ adapter: DatabaseAdapterName;
34
+ upstream: {
35
+ connectionStringEnv: string;
36
+ branchFrom?: string;
37
+ };
38
+ injection: {
39
+ targetEnv: string;
40
+ additionalEnvs?: string[];
41
+ };
42
+ lifecycle?: {
43
+ createOn?: 'worktree-allocation' | 'first-write-stage';
44
+ reclaimOn?: 'pr-merge' | 'worktree-reclaim' | 'manual';
45
+ maxConcurrent?: number;
46
+ branchTtl?: string;
47
+ abandonAfter?: string;
48
+ warmPoolSize?: number;
49
+ };
50
+ allowBranchFromBranch?: boolean;
51
+ migrations?: {
52
+ runOnBranchCreate?: boolean;
53
+ migrationCommand?: string;
54
+ migrationCwd?: string;
55
+ };
56
+ credentials?: Record<string, unknown>;
57
+ }
58
+ export type ValidationResult = {
59
+ ok: true;
60
+ } | {
61
+ ok: false;
62
+ error: string;
63
+ };
64
+ export interface DatabaseBranchAdapter {
65
+ readonly name: DatabaseAdapterName;
66
+ readonly capabilities: DatabaseBranchCapabilities;
67
+ /** Pipeline-load validation; checks credentials + adapter-specific config. */
68
+ validate(pool: ResolvedDatabaseBranchPool): Promise<ValidationResult>;
69
+ /** Provision a new branch from the pool's upstream. */
70
+ allocate(pool: ResolvedDatabaseBranchPool, branchKey: string): Promise<DatabaseBranchHandle>;
71
+ /** Destroy a branch and free its quota slot. */
72
+ reclaim(handle: DatabaseBranchHandle): Promise<void>;
73
+ /** Enumerate currently active branches (for stale-branch sweep on startup). */
74
+ list(pool: ResolvedDatabaseBranchPool): Promise<DatabaseBranchHandle[]>;
75
+ /** Cheap liveness probe. */
76
+ isAvailable(pool: ResolvedDatabaseBranchPool): Promise<boolean>;
77
+ }
78
+ export declare class DatabaseBranchAdapterError extends Error {
79
+ readonly adapter: DatabaseAdapterName;
80
+ readonly branchKey?: string | undefined;
81
+ readonly cause?: unknown | undefined;
82
+ constructor(message: string, adapter: DatabaseAdapterName, branchKey?: string | undefined, cause?: unknown | undefined);
83
+ }
84
+ export declare class BranchTopologyForbiddenError extends Error {
85
+ readonly poolName: string;
86
+ constructor(message: string, poolName: string);
87
+ }
88
+ export type DatabaseAccess = 'none' | 'read' | 'write' | 'migrate';
89
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1,26 @@
1
+ /**
2
+ * DatabaseBranchAdapter framework per RFC-0010 §15. Each adapter abstracts a database
3
+ * branching mechanism; the orchestrator allocates a branch per worktree, injects the
4
+ * branch's connection string into the agent's environment, and reclaims on PR merge.
5
+ */
6
+ export class DatabaseBranchAdapterError extends Error {
7
+ adapter;
8
+ branchKey;
9
+ cause;
10
+ constructor(message, adapter, branchKey, cause) {
11
+ super(message);
12
+ this.adapter = adapter;
13
+ this.branchKey = branchKey;
14
+ this.cause = cause;
15
+ this.name = 'DatabaseBranchAdapterError';
16
+ }
17
+ }
18
+ export class BranchTopologyForbiddenError extends Error {
19
+ poolName;
20
+ constructor(message, poolName) {
21
+ super(message);
22
+ this.poolName = poolName;
23
+ this.name = 'BranchTopologyForbiddenError';
24
+ }
25
+ }
26
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1,40 @@
1
+ /**
2
+ * C5 — Design authority signal detection (RFC-0008 §A.5).
3
+ *
4
+ * Determines whether the issue's author or any commenter is listed as a
5
+ * `designAuthority` principal on the resolved DesignSystemBinding, and
6
+ * parses the explicit signal type from issue labels (preferred) or
7
+ * structured comment markers.
8
+ */
9
+ import type { DesignSystemBinding } from '@ai-sdlc/reference';
10
+ import type { DesignAuthoritySignalType } from './admission-score.js';
11
+ export interface CheckDesignAuthorityInput {
12
+ /** GitHub login of the issue author. */
13
+ authorLogin?: string;
14
+ /** GitHub logins of anyone who commented on the issue. */
15
+ commenterLogins?: readonly string[];
16
+ /** Labels attached to the issue — used to parse the signal type. */
17
+ labels: readonly string[];
18
+ }
19
+ export interface DesignAuthoritySignalResult {
20
+ isDesignAuthority: boolean;
21
+ signalType: DesignAuthoritySignalType;
22
+ }
23
+ /**
24
+ * Determine whether the issue author or any commenter is a
25
+ * designAuthority principal, and resolve the signal type from labels.
26
+ * Returns `{ isDesignAuthority: false, signalType: 'unspecified' }`
27
+ * when no DSB is present.
28
+ */
29
+ export declare function checkDesignAuthority(input: CheckDesignAuthorityInput, binding: DesignSystemBinding | undefined): DesignAuthoritySignalResult;
30
+ /**
31
+ * Resolve the design-signal type from issue labels.
32
+ *
33
+ * Priority order mirrors the RFC's weighting (positive signals first),
34
+ * so an issue tagged with both a positive and a negative label resolves
35
+ * to the positive one. This is deliberate: design authorities shouldn't
36
+ * dual-tag in practice, but if they do, we don't want to default to the
37
+ * punitive path.
38
+ */
39
+ export declare function parseDesignSignalType(labels: readonly string[]): DesignAuthoritySignalType;
40
+ //# sourceMappingURL=design-authority.d.ts.map
@@ -0,0 +1,71 @@
1
+ /**
2
+ * C5 — Design authority signal detection (RFC-0008 §A.5).
3
+ *
4
+ * Determines whether the issue's author or any commenter is listed as a
5
+ * `designAuthority` principal on the resolved DesignSystemBinding, and
6
+ * parses the explicit signal type from issue labels (preferred) or
7
+ * structured comment markers.
8
+ */
9
+ /**
10
+ * Label-encoded design signal types. Short, stable slugs keep GitHub
11
+ * label names readable; the map below converts them to the
12
+ * `DesignAuthoritySignalType` used downstream.
13
+ */
14
+ const LABEL_TO_SIGNAL = Object.freeze({
15
+ 'design/advances-coherence': 'advances-design-coherence',
16
+ 'design/fills-gap': 'fills-catalog-gap',
17
+ 'design/fragments-catalog': 'fragments-component-catalog',
18
+ 'design/misaligned-brand': 'misaligned-with-brand',
19
+ });
20
+ /**
21
+ * Determine whether the issue author or any commenter is a
22
+ * designAuthority principal, and resolve the signal type from labels.
23
+ * Returns `{ isDesignAuthority: false, signalType: 'unspecified' }`
24
+ * when no DSB is present.
25
+ */
26
+ export function checkDesignAuthority(input, binding) {
27
+ const principals = binding?.spec.stewardship.designAuthority.principals ?? [];
28
+ const authorityParticipants = collectAuthorityParticipants(input, principals);
29
+ const isDesignAuthority = authorityParticipants.length > 0;
30
+ const signalType = parseDesignSignalType(input.labels);
31
+ return { isDesignAuthority, signalType };
32
+ }
33
+ function collectAuthorityParticipants(input, principals) {
34
+ if (principals.length === 0)
35
+ return [];
36
+ const principalSet = new Set(principals.map((p) => p.toLowerCase()));
37
+ const participants = [];
38
+ if (input.authorLogin && principalSet.has(input.authorLogin.toLowerCase())) {
39
+ participants.push(input.authorLogin);
40
+ }
41
+ for (const c of input.commenterLogins ?? []) {
42
+ if (principalSet.has(c.toLowerCase()))
43
+ participants.push(c);
44
+ }
45
+ return participants;
46
+ }
47
+ /**
48
+ * Resolve the design-signal type from issue labels.
49
+ *
50
+ * Priority order mirrors the RFC's weighting (positive signals first),
51
+ * so an issue tagged with both a positive and a negative label resolves
52
+ * to the positive one. This is deliberate: design authorities shouldn't
53
+ * dual-tag in practice, but if they do, we don't want to default to the
54
+ * punitive path.
55
+ */
56
+ export function parseDesignSignalType(labels) {
57
+ const priority = [
58
+ 'advances-design-coherence',
59
+ 'fills-catalog-gap',
60
+ 'fragments-component-catalog',
61
+ 'misaligned-with-brand',
62
+ ];
63
+ const lowered = labels.map((l) => l.toLowerCase());
64
+ for (const target of priority) {
65
+ const label = Object.entries(LABEL_TO_SIGNAL).find(([, v]) => v === target)?.[0];
66
+ if (label && lowered.includes(label))
67
+ return target;
68
+ }
69
+ return 'unspecified';
70
+ }
71
+ //# sourceMappingURL=design-authority.js.map
@@ -0,0 +1,64 @@
1
+ /**
2
+ * C7 — Design Lookahead Notification (RFC-0008 §11 + Amendment 6).
3
+ *
4
+ * Fires a notification when a backlog item has:
5
+ * 1. Stayed in the top-10 of the prioritized backlog for ≥48h
6
+ * (OQ-7 stability threshold against priority churn)
7
+ * 2. Design-system impact (any of: frontend code area, catalog gaps,
8
+ * or `PRODUCT_HIGH_DESIGN_LOW` tension flag)
9
+ * 3. Not been notified within the last 7 days
10
+ * (dedupe via `design_lookahead_notifications` table)
11
+ *
12
+ * The payload is the full `PillarBreakdown` plus gap and tension
13
+ * information — design reviewers need the structured context to decide
14
+ * whether to unblock, reprioritize, or flag the item.
15
+ */
16
+ import type { StateStore } from './state/store.js';
17
+ import type { PillarBreakdown, TensionFlag } from './pillar-breakdown.js';
18
+ export interface DesignLookaheadConfig {
19
+ /** Min time an issue must have been in top-N to qualify. Default 48h. */
20
+ stabilityThresholdMs: number;
21
+ /** Min time since last notification before re-notifying. Default 7d. */
22
+ dedupeExpiryMs: number;
23
+ /** Cutoff for "top" (ignored when `items` is already pre-filtered). */
24
+ topN: number;
25
+ }
26
+ export declare const DEFAULT_LOOKAHEAD_CONFIG: DesignLookaheadConfig;
27
+ export interface BacklogItem {
28
+ issueNumber: number;
29
+ /** Composite score that placed this item in top-N. */
30
+ composite: number;
31
+ /** Pillar breakdown from the admission composite. */
32
+ pillarBreakdown: PillarBreakdown;
33
+ /** When the item first entered the top-N (ISO timestamp). */
34
+ enteredTop10At?: string;
35
+ /** Whether the code area has frontend components (C3 classifier). */
36
+ hasFrontendComponents?: boolean;
37
+ /** Catalog gaps surfaced during enrichment (C2). */
38
+ catalogGaps?: string[];
39
+ }
40
+ export type DesignImpactReason = 'frontend-components' | 'catalog-gaps' | 'product-design-tension';
41
+ export interface DesignLookaheadNotification {
42
+ type: 'DesignLookaheadNotification';
43
+ issueNumber: number;
44
+ notifiedAt: string;
45
+ /** Reasons this item was flagged (ordered as detected). */
46
+ reasons: DesignImpactReason[];
47
+ pillarBreakdown: PillarBreakdown;
48
+ catalogGaps: string[];
49
+ tensionFlags: TensionFlag[];
50
+ }
51
+ export declare function detectDesignImpactReasons(item: BacklogItem): DesignImpactReason[];
52
+ export interface DesignLookaheadDetectorDeps {
53
+ stateStore: StateStore;
54
+ now?: () => number;
55
+ config?: Partial<DesignLookaheadConfig>;
56
+ }
57
+ /**
58
+ * Run one scheduler tick. `items` should already be the top-N backlog
59
+ * items in descending composite order; caller is responsible for
60
+ * tracking `enteredTop10At` across ticks. Returns the notifications
61
+ * to emit + persist for this tick.
62
+ */
63
+ export declare function detectDesignLookaheadNotifications(items: readonly BacklogItem[], deps: DesignLookaheadDetectorDeps): DesignLookaheadNotification[];
64
+ //# sourceMappingURL=design-lookahead.d.ts.map
@@ -0,0 +1,86 @@
1
+ /**
2
+ * C7 — Design Lookahead Notification (RFC-0008 §11 + Amendment 6).
3
+ *
4
+ * Fires a notification when a backlog item has:
5
+ * 1. Stayed in the top-10 of the prioritized backlog for ≥48h
6
+ * (OQ-7 stability threshold against priority churn)
7
+ * 2. Design-system impact (any of: frontend code area, catalog gaps,
8
+ * or `PRODUCT_HIGH_DESIGN_LOW` tension flag)
9
+ * 3. Not been notified within the last 7 days
10
+ * (dedupe via `design_lookahead_notifications` table)
11
+ *
12
+ * The payload is the full `PillarBreakdown` plus gap and tension
13
+ * information — design reviewers need the structured context to decide
14
+ * whether to unblock, reprioritize, or flag the item.
15
+ */
16
+ // ── Thresholds ─────────────────────────────────────────────────────────
17
+ const DEFAULT_STABILITY_MS = 48 * 60 * 60 * 1000;
18
+ const DEFAULT_DEDUPE_EXPIRY_MS = 7 * 24 * 60 * 60 * 1000;
19
+ const DEFAULT_TOP_N = 10;
20
+ export const DEFAULT_LOOKAHEAD_CONFIG = {
21
+ stabilityThresholdMs: DEFAULT_STABILITY_MS,
22
+ dedupeExpiryMs: DEFAULT_DEDUPE_EXPIRY_MS,
23
+ topN: DEFAULT_TOP_N,
24
+ };
25
+ // ── Impact detection ───────────────────────────────────────────────────
26
+ export function detectDesignImpactReasons(item) {
27
+ const reasons = [];
28
+ if (item.hasFrontendComponents)
29
+ reasons.push('frontend-components');
30
+ if ((item.catalogGaps ?? []).length > 0)
31
+ reasons.push('catalog-gaps');
32
+ if (item.pillarBreakdown.tensions.some((t) => t.type === 'PRODUCT_HIGH_DESIGN_LOW')) {
33
+ reasons.push('product-design-tension');
34
+ }
35
+ return reasons;
36
+ }
37
+ /**
38
+ * Run one scheduler tick. `items` should already be the top-N backlog
39
+ * items in descending composite order; caller is responsible for
40
+ * tracking `enteredTop10At` across ticks. Returns the notifications
41
+ * to emit + persist for this tick.
42
+ */
43
+ export function detectDesignLookaheadNotifications(items, deps) {
44
+ const config = { ...DEFAULT_LOOKAHEAD_CONFIG, ...deps.config };
45
+ const nowMs = (deps.now ?? (() => Date.now()))();
46
+ const topItems = items.slice(0, config.topN);
47
+ const emissions = [];
48
+ for (const item of topItems) {
49
+ // 1. Stability check — must have been in top-N ≥ stabilityThresholdMs.
50
+ if (!item.enteredTop10At)
51
+ continue;
52
+ const enteredMs = Date.parse(item.enteredTop10At);
53
+ if (Number.isNaN(enteredMs))
54
+ continue;
55
+ if (nowMs - enteredMs < config.stabilityThresholdMs)
56
+ continue;
57
+ // 2. Design-system impact.
58
+ const reasons = detectDesignImpactReasons(item);
59
+ if (reasons.length === 0)
60
+ continue;
61
+ // 3. Dedupe via notification table.
62
+ const existing = deps.stateStore.getDesignLookaheadNotification(item.issueNumber);
63
+ if (existing?.lastNotifiedAt) {
64
+ const lastMs = Date.parse(existing.lastNotifiedAt);
65
+ if (!Number.isNaN(lastMs) && nowMs - lastMs < config.dedupeExpiryMs)
66
+ continue;
67
+ }
68
+ // 4. Emit + record.
69
+ const notification = {
70
+ type: 'DesignLookaheadNotification',
71
+ issueNumber: item.issueNumber,
72
+ notifiedAt: new Date(nowMs).toISOString(),
73
+ reasons,
74
+ pillarBreakdown: item.pillarBreakdown,
75
+ catalogGaps: item.catalogGaps ?? [],
76
+ tensionFlags: item.pillarBreakdown.tensions,
77
+ };
78
+ emissions.push(notification);
79
+ deps.stateStore.upsertDesignLookaheadNotification({
80
+ issueNumber: item.issueNumber,
81
+ pillarBreakdownJson: JSON.stringify(item.pillarBreakdown),
82
+ });
83
+ }
84
+ return emissions;
85
+ }
86
+ //# sourceMappingURL=design-lookahead.js.map