@kognai/orchestrator-core 0.1.3 → 0.2.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.
@@ -36,6 +36,7 @@ const engine_agents_1 = require("./engine-agents");
36
36
  const engine_coding_agent_1 = require("./engine-coding-agent");
37
37
  const engine_loaders_1 = require("./engine-loaders");
38
38
  const orchestrate_engine_1 = require("./orchestrate-engine");
39
+ const build_triage_1 = require("./build-triage");
39
40
  class Orchestrator {
40
41
  spawnGate;
41
42
  ceo;
@@ -44,6 +45,11 @@ class Orchestrator {
44
45
  supervisor2;
45
46
  agents = new Map();
46
47
  tasks = [];
48
+ // TICKET-234: ceremony-depth path for this run. 'regulated' = full ceremony
49
+ // (default, safe); 'fast' = coder → single-supervisor → QA safety floor only.
50
+ // Set in run() by classifyBuildPath after tasks load. Defaults to regulated.
51
+ buildPath = 'regulated';
52
+ triage = null;
47
53
  stats = { tasksExecuted: 0, approved: 0, rejected: 0, totalTokens: 0, conflicts: 0, escalations: 0 };
48
54
  // Per-task structured run records — written to swarm run report at end of sprint
49
55
  taskRuns = [];
@@ -219,6 +225,13 @@ class Orchestrator {
219
225
  // Normalize priority: sprint JSON may omit it
220
226
  if (!task.priority)
221
227
  task.priority = 'medium';
228
+ // Normalize status: sprint JSON may omit it. Without a status the task is
229
+ // silently skipped in Phase 2 (`if (task.status !== 'pending') continue`),
230
+ // so the full ceremony runs but executes 0 tasks. Default a MISSING status
231
+ // to 'pending'; explicit terminal states (done/skipped/rejected/approved)
232
+ // are preserved so re-runs don't re-execute finished work.
233
+ if (!task.status)
234
+ task.status = 'pending';
222
235
  // Fix: task_target used as file path (e.g., 'scripts/lib/foo.ts') must be cleared
223
236
  // so it doesn't confuse the routing switch which expects: local|cloud-code|cloud-exec|cloud-post
224
237
  const VALID_ROUTING_TARGETS = ['local', 'cloud-code', 'cloud-exec', 'cloud-post'];
@@ -404,17 +417,23 @@ ONLY output the JSON array. No markdown, no explanation.`;
404
417
  monotask_state_machine_1.MonotaskSM.release(subtask.agent, subtask.id, `no files: ${inferred.slice(0, 60)}`);
405
418
  return false;
406
419
  }
407
- // Dual supervisor review
408
- const [review1, review2] = await Promise.all([
409
- this.supervisor.reviewTask(subtask, result.files),
410
- this.supervisor2.reviewTask(subtask, result.files),
411
- ]);
412
- const dualResult = await (0, engine_agents_1.reconcileSupervisorReviews)(review1, review2, subtask, this.ceo);
413
- const review = dualResult.finalReview;
414
- if (!dualResult.consensus)
415
- this.stats.conflicts++;
416
- if (dualResult.escalatedToCEO)
417
- this.stats.escalations++;
420
+ // Supervisor review. TICKET-234: fast track → single supervisor; regulated → dual.
421
+ let review;
422
+ if (this.buildPath === 'fast') {
423
+ review = await this.supervisor.reviewTask(subtask, result.files);
424
+ }
425
+ else {
426
+ const [review1, review2] = await Promise.all([
427
+ this.supervisor.reviewTask(subtask, result.files),
428
+ this.supervisor2.reviewTask(subtask, result.files),
429
+ ]);
430
+ const dualResult = await (0, engine_agents_1.reconcileSupervisorReviews)(review1, review2, subtask, this.ceo);
431
+ review = dualResult.finalReview;
432
+ if (!dualResult.consensus)
433
+ this.stats.conflicts++;
434
+ if (dualResult.escalatedToCEO)
435
+ this.stats.escalations++;
436
+ }
418
437
  lastReview = review;
419
438
  // TICKET-214: instrument SUB-TASK attempts. The MAIN task loop already taps KSL +
420
439
  // records reputation, but the split sub-task loop did neither — so split sprints
@@ -787,18 +806,28 @@ ONLY output the JSON array. No markdown, no explanation.`;
787
806
  return;
788
807
  }
789
808
  (0, engine_primitives_1.log)(engine_primitives_1.c.gray, ` [QA-gate] PASS — ${qaResult.reason}`);
790
- // Dual Supervisor review (DeepSeek/ClawRouter + Haiku in parallel)
809
+ // Supervisor review. TICKET-234: fast track runs ONE supervisor (no dual
810
+ // review / reconcile / CEO escalation); regulated runs the dual-supervisor
811
+ // ceremony. The QA gate above already enforced the safety floor
812
+ // (typecheck/compile/no-secrets) on both paths.
791
813
  task.status = 'review';
792
- const [review1, review2] = await Promise.all([
793
- this.supervisor.reviewTask(task, result.files),
794
- this.supervisor2.reviewTask(task, result.files),
795
- ]);
796
- const dualResult = await (0, engine_agents_1.reconcileSupervisorReviews)(review1, review2, task, this.ceo);
797
- const review = dualResult.finalReview;
798
- if (!dualResult.consensus)
799
- this.stats.conflicts++;
800
- if (dualResult.escalatedToCEO)
801
- this.stats.escalations++;
814
+ let review;
815
+ if (this.buildPath === 'fast') {
816
+ review = await this.supervisor.reviewTask(task, result.files);
817
+ (0, engine_primitives_1.log)(engine_primitives_1.c.gray, ' [fast-track] single-supervisor review (dual-supervisor skipped)');
818
+ }
819
+ else {
820
+ const [review1, review2] = await Promise.all([
821
+ this.supervisor.reviewTask(task, result.files),
822
+ this.supervisor2.reviewTask(task, result.files),
823
+ ]);
824
+ const dualResult = await (0, engine_agents_1.reconcileSupervisorReviews)(review1, review2, task, this.ceo);
825
+ review = dualResult.finalReview;
826
+ if (!dualResult.consensus)
827
+ this.stats.conflicts++;
828
+ if (dualResult.escalatedToCEO)
829
+ this.stats.escalations++;
830
+ }
802
831
  lastReview = review;
803
832
  task.output = { files: result.files, commit: '', model: result.model, review };
804
833
  // CTO-006 telemetry-blackout hotfix (2026-05-29, Slice A of TICKET-135):
@@ -1050,6 +1079,28 @@ ONLY output the JSON array. No markdown, no explanation.`;
1050
1079
  await mc.disconnect().catch(() => { });
1051
1080
  return;
1052
1081
  }
1082
+ // ── BUILD TRIAGE — TICKET-234 (ceremony-depth routing) ─────────────────
1083
+ // Classify the build BEFORE the swarm ceremony: simple, non-sensitive,
1084
+ // single-file builds take the FAST path (single-supervisor + QA safety
1085
+ // floor, no CTO/CEO post-sprint ceremony, no templates); everything
1086
+ // sensitive/sovereign/complex/ambiguous takes the REGULATED full ceremony.
1087
+ // Pure heuristic — negligible cost vs the ceremony it gates. SOVEREIGN_MODE
1088
+ // always forces regulated: a sovereign build is regulated by definition.
1089
+ {
1090
+ const triageSprint = JSON.parse((0, fs_1.readFileSync)(process.argv[2] || 'sprints/current.json', 'utf-8'));
1091
+ this.triage = (0, build_triage_1.classifyBuildPath)(triageSprint, this.tasks);
1092
+ if (engine_primitives_1.SOVEREIGN_MODE && this.triage.path === 'fast') {
1093
+ this.triage = { ...this.triage, path: 'regulated', reason: 'sovereign mode → regulated by definition', triggers: [...this.triage.triggers, 'sovereign:mode'], sovereign: true };
1094
+ }
1095
+ this.buildPath = this.triage.path;
1096
+ (0, build_triage_1.logBuildTriage)(_evtSprintId, this.triage);
1097
+ const col = this.buildPath === 'fast' ? engine_primitives_1.c.green : engine_primitives_1.c.magenta;
1098
+ (0, engine_primitives_1.log)(col, `\n--- Build Triage: ${this.buildPath.toUpperCase()} ---`);
1099
+ (0, engine_primitives_1.log)(engine_primitives_1.c.gray, ` ${this.triage.reason}`);
1100
+ (0, engine_primitives_1.log)(engine_primitives_1.c.gray, ` complexity=${this.triage.complexity} tasks=${this.triage.taskCount} code-files=${this.triage.codeFileCount}${this.triage.triggers.length ? ` · triggers: ${this.triage.triggers.join(', ')}` : ''}`);
1101
+ if (this.buildPath === 'fast')
1102
+ (0, engine_primitives_1.log)(engine_primitives_1.c.gray, ' Fast track: single-supervisor + QA safety floor; skipping dual-supervisor, CTO/CEO post-sprint ceremony, and templates.');
1103
+ }
1053
1104
  // ── CTO APPROVAL GATE — Exec Protocol §17 ──────────────────────────────
1054
1105
  // Every autonomous sprint must be approved by the CTO agent before execution.
1055
1106
  // Human-submitted sprints (source: 'human') are auto-approved.
@@ -1100,8 +1151,14 @@ ONLY output the JSON array. No markdown, no explanation.`;
1100
1151
  }
1101
1152
  // ── End CTO Gate ────────────────────────────────────────────────────────
1102
1153
  // 2. CEO initial assessment (B.14: once per sprint, not once per conflict)
1103
- (0, engine_primitives_1.log)(engine_primitives_1.c.magenta, '\n--- Phase 1: CEO Initial Assessment ---');
1104
- await this.ceo.reviewSprintProgress(this.tasks);
1154
+ // TICKET-234: regulated path only the fast track skips the CEO ceremony.
1155
+ if (this.buildPath === 'regulated') {
1156
+ (0, engine_primitives_1.log)(engine_primitives_1.c.magenta, '\n--- Phase 1: CEO Initial Assessment ---');
1157
+ await this.ceo.reviewSprintProgress(this.tasks);
1158
+ }
1159
+ else {
1160
+ (0, engine_primitives_1.log)(engine_primitives_1.c.gray, '\n--- Phase 1: CEO Initial Assessment — SKIPPED (fast track) ---');
1161
+ }
1105
1162
  const _ceoIntentDone = true; // flag for Phase 5: only re-run if ≥2 rejected
1106
1163
  // 3. Execute coding tasks with review loop
1107
1164
  (0, engine_primitives_1.log)(engine_primitives_1.c.blue, '\n--- Phase 2: Sprint Execution ---');
@@ -1220,79 +1277,91 @@ ONLY output the JSON array. No markdown, no explanation.`;
1220
1277
  }
1221
1278
  }
1222
1279
  // 4. CTO data-driven analysis + CMO reports
1223
- (0, engine_primitives_1.log)(engine_primitives_1.c.cyan, '\n--- Phase 3: CTO Data-Driven Analysis + CMO Reports ---');
1280
+ // TICKET-234: Phases 3–6 (CTO/CEO governance ceremony + agent minting +
1281
+ // daily report) run on the REGULATED path only. Fast track ships after the
1282
+ // per-task review + QA safety floor; the financial telemetry below (wallet
1283
+ // burn + budget freeze/warning) still runs on both paths.
1224
1284
  let ctoReport = { summary: '', proposals: [], metrics_reviewed: [] };
1225
1285
  let ctoDecisions = '';
1226
1286
  let cmoReports = '';
1227
- try {
1228
- ctoReport = await this.cto.analyze();
1229
- // Load CMO reports (produced independently by Manus AI runner)
1230
- cmoReports = (0, engine_loaders_1.loadCMOReports)();
1231
- if (cmoReports) {
1232
- (0, engine_primitives_1.log)(engine_primitives_1.c.magenta, ' CMO reports found — will include in CEO review');
1233
- }
1234
- else {
1235
- (0, engine_primitives_1.log)(engine_primitives_1.c.gray, ' No CMO reports available yet');
1236
- }
1237
- // Load CTO tech-watch reports (produced independently by run-cto-techwatch.ts)
1238
- const ctoTechWatch = (0, engine_loaders_1.loadCTOTechWatchReports)();
1239
- if (ctoTechWatch) {
1240
- (0, engine_primitives_1.log)(engine_primitives_1.c.cyan, ' CTO tech-watch reports found — will include in CEO review');
1241
- cmoReports = cmoReports ? cmoReports + '\n\n' + ctoTechWatch : ctoTechWatch;
1242
- }
1243
- else {
1244
- (0, engine_primitives_1.log)(engine_primitives_1.c.gray, ' No CTO tech-watch reports available yet');
1245
- }
1246
- // Load Grok intelligence feed (Grok AI monitors X/Twitter for OpenClaw news)
1247
- const grokFeed = (0, engine_loaders_1.loadGrokFeed)();
1248
- if (grokFeed) {
1249
- (0, engine_primitives_1.log)(engine_primitives_1.c.magenta, ' Grok intelligence feed found — will include in CEO review');
1250
- cmoReports = cmoReports ? cmoReports + '\n\n' + grokFeed : grokFeed;
1251
- }
1252
- else {
1253
- (0, engine_primitives_1.log)(engine_primitives_1.c.gray, ' No Grok feed reports available');
1254
- }
1255
- // Load Owner Directives (highest priority — always included)
1256
- const ownerDirectives = (0, engine_loaders_1.loadOwnerDirectives)();
1257
- if (ownerDirectives) {
1258
- (0, engine_primitives_1.log)(engine_primitives_1.c.magenta, " Owner directives found — will include in CEO review (highest priority)");
1259
- cmoReports = ownerDirectives + (cmoReports ? "\n\n" + cmoReports : "");
1260
- }
1261
- // 5. CEO reviews CTO proposals + CMO reports
1262
- if (ctoReport.proposals.length > 0 || cmoReports) {
1263
- (0, engine_primitives_1.log)(engine_primitives_1.c.magenta, '\n--- Phase 4: CEO Reviews CTO Proposals + CMO Reports ---');
1264
- ctoDecisions = await this.ceo.reviewCTOProposals(ctoReport);
1265
- // Persist CEO decisions for CTO feedback loop + approved proposals tracking
1266
- (0, orchestrate_engine_1.persistCEODecisions)(ctoDecisions, ctoReport);
1267
- // Handle approved new_agent proposals
1268
- const agentCreator = new engine_agents_1.AgentCreator(this.spawnGate);
1269
- for (const proposal of ctoReport.proposals) {
1270
- if (proposal.category === 'new_agent' && proposal.agent_spec) {
1271
- // Check if CEO approved this specific proposal
1272
- if (ctoDecisions.includes(proposal.id) && ctoDecisions.toUpperCase().includes('APPROVED')) {
1273
- (0, engine_primitives_1.log)(engine_primitives_1.c.green, `\n 🤖 CEO approved new agent: ${proposal.agent_spec.name}`);
1274
- agentCreator.createAgent(proposal.agent_spec);
1275
- (0, engine_primitives_1.log)(engine_primitives_1.c.green, ` Agent will be loaded on next orchestrator run.`);
1276
- }
1277
- else {
1278
- (0, engine_primitives_1.log)(engine_primitives_1.c.yellow, ` CEO did not approve agent: ${proposal.agent_spec.name}`);
1287
+ if (this.buildPath === 'regulated') {
1288
+ (0, engine_primitives_1.log)(engine_primitives_1.c.cyan, '\n--- Phase 3: CTO Data-Driven Analysis + CMO Reports ---');
1289
+ try {
1290
+ ctoReport = await this.cto.analyze();
1291
+ // Load CMO reports (produced independently by Manus AI runner)
1292
+ cmoReports = (0, engine_loaders_1.loadCMOReports)();
1293
+ if (cmoReports) {
1294
+ (0, engine_primitives_1.log)(engine_primitives_1.c.magenta, ' CMO reports found — will include in CEO review');
1295
+ }
1296
+ else {
1297
+ (0, engine_primitives_1.log)(engine_primitives_1.c.gray, ' No CMO reports available yet');
1298
+ }
1299
+ // Load CTO tech-watch reports (produced independently by run-cto-techwatch.ts)
1300
+ const ctoTechWatch = (0, engine_loaders_1.loadCTOTechWatchReports)();
1301
+ if (ctoTechWatch) {
1302
+ (0, engine_primitives_1.log)(engine_primitives_1.c.cyan, ' CTO tech-watch reports found — will include in CEO review');
1303
+ cmoReports = cmoReports ? cmoReports + '\n\n' + ctoTechWatch : ctoTechWatch;
1304
+ }
1305
+ else {
1306
+ (0, engine_primitives_1.log)(engine_primitives_1.c.gray, ' No CTO tech-watch reports available yet');
1307
+ }
1308
+ // Load Grok intelligence feed (Grok AI monitors X/Twitter for OpenClaw news)
1309
+ const grokFeed = (0, engine_loaders_1.loadGrokFeed)();
1310
+ if (grokFeed) {
1311
+ (0, engine_primitives_1.log)(engine_primitives_1.c.magenta, ' Grok intelligence feed found — will include in CEO review');
1312
+ cmoReports = cmoReports ? cmoReports + '\n\n' + grokFeed : grokFeed;
1313
+ }
1314
+ else {
1315
+ (0, engine_primitives_1.log)(engine_primitives_1.c.gray, ' No Grok feed reports available');
1316
+ }
1317
+ // Load Owner Directives (highest priority — always included)
1318
+ const ownerDirectives = (0, engine_loaders_1.loadOwnerDirectives)();
1319
+ if (ownerDirectives) {
1320
+ (0, engine_primitives_1.log)(engine_primitives_1.c.magenta, " Owner directives found — will include in CEO review (highest priority)");
1321
+ cmoReports = ownerDirectives + (cmoReports ? "\n\n" + cmoReports : "");
1322
+ }
1323
+ // 5. CEO reviews CTO proposals + CMO reports
1324
+ if (ctoReport.proposals.length > 0 || cmoReports) {
1325
+ (0, engine_primitives_1.log)(engine_primitives_1.c.magenta, '\n--- Phase 4: CEO Reviews CTO Proposals + CMO Reports ---');
1326
+ ctoDecisions = await this.ceo.reviewCTOProposals(ctoReport);
1327
+ // Persist CEO decisions for CTO feedback loop + approved proposals tracking
1328
+ (0, orchestrate_engine_1.persistCEODecisions)(ctoDecisions, ctoReport);
1329
+ // Handle approved new_agent proposals
1330
+ const agentCreator = new engine_agents_1.AgentCreator(this.spawnGate);
1331
+ for (const proposal of ctoReport.proposals) {
1332
+ if (proposal.category === 'new_agent' && proposal.agent_spec) {
1333
+ // Check if CEO approved this specific proposal
1334
+ if (ctoDecisions.includes(proposal.id) && ctoDecisions.toUpperCase().includes('APPROVED')) {
1335
+ (0, engine_primitives_1.log)(engine_primitives_1.c.green, `\n 🤖 CEO approved new agent: ${proposal.agent_spec.name}`);
1336
+ agentCreator.createAgent(proposal.agent_spec);
1337
+ (0, engine_primitives_1.log)(engine_primitives_1.c.green, ` Agent will be loaded on next orchestrator run.`);
1338
+ }
1339
+ else {
1340
+ (0, engine_primitives_1.log)(engine_primitives_1.c.yellow, ` CEO did not approve agent: ${proposal.agent_spec.name}`);
1341
+ }
1279
1342
  }
1280
1343
  }
1281
1344
  }
1345
+ else {
1346
+ (0, engine_primitives_1.log)(engine_primitives_1.c.cyan, ' No proposals from CTO — stack is current and optimized');
1347
+ ctoDecisions = 'No proposals to review.';
1348
+ }
1282
1349
  }
1283
- else {
1284
- (0, engine_primitives_1.log)(engine_primitives_1.c.cyan, ' No proposals from CTO stack is current and optimized');
1285
- ctoDecisions = 'No proposals to review.';
1350
+ catch (error) {
1351
+ (0, engine_primitives_1.log)(engine_primitives_1.c.yellow, ` CTO/CEO review cycle skipped: ${error.message}`);
1352
+ ctoDecisions = 'CTO analysis was not performed this run.';
1286
1353
  }
1287
1354
  }
1288
- catch (error) {
1289
- (0, engine_primitives_1.log)(engine_primitives_1.c.yellow, ` CTO/CEO review cycle skipped: ${error.message}`);
1290
- ctoDecisions = 'CTO analysis was not performed this run.';
1355
+ else {
1356
+ (0, engine_primitives_1.log)(engine_primitives_1.c.gray, '\n--- Phases 3–4: CTO/CEO Governance Ceremony SKIPPED (fast track) ---');
1291
1357
  }
1292
1358
  // 6. CEO final assessment — B.14: only runs if ≥2 tasks rejected (skips if sprint went well)
1293
1359
  const rejectedCount = this.tasks.filter(t => t.status === 'rejected').length;
1294
1360
  (0, engine_primitives_1.log)(engine_primitives_1.c.magenta, '\n--- Phase 5: CEO Final Assessment ---');
1295
- if (rejectedCount >= 2) {
1361
+ if (this.buildPath === 'fast') {
1362
+ (0, engine_primitives_1.log)(engine_primitives_1.c.gray, ' Fast track — skipping CEO final assessment');
1363
+ }
1364
+ else if (rejectedCount >= 2) {
1296
1365
  (0, engine_primitives_1.log)(engine_primitives_1.c.magenta, ` ${rejectedCount} tasks rejected — CEO reviewing...`);
1297
1366
  await this.ceo.reviewSprintProgress(this.tasks);
1298
1367
  }
@@ -1309,63 +1378,68 @@ ONLY output the JSON array. No markdown, no explanation.`;
1309
1378
  (0, event_bus_publisher_1.publishBudgetWarning)(_evtSprintId, _ws.burnPct, _ws.spentThisMonth, _ws.monthlyBudget).catch(() => { });
1310
1379
  }
1311
1380
  catch { /* wallet state unavailable */ }
1312
- // 6b. CTO autonomous post-sprint analysis (runs after EVERY sprint)
1313
- (0, engine_primitives_1.log)(engine_primitives_1.c.cyan, '\n--- Phase 5b: CTO Post-Sprint Analysis (Autonomous) ---');
1381
+ // 6b. CTO autonomous post-sprint analysis regulated path only (TICKET-234)
1314
1382
  let postSprintReport = '';
1315
- try {
1316
- postSprintReport = await this.cto.postSprintAnalysis(this.tasks, this.stats);
1317
- (0, engine_primitives_1.log)(engine_primitives_1.c.cyan, ' Post-sprint analysis saved to reports/cto/');
1318
- // Extract proposals from post-sprint analysis and feed into CEO review
1319
- const jsonMatch = postSprintReport.match(/```json\s*([\s\S]*?)```/);
1320
- if (jsonMatch) {
1321
- try {
1322
- const parsed = JSON.parse(jsonMatch[1].trim());
1323
- const postSprintProposals = parsed.proposals || [];
1324
- if (postSprintProposals.length > 0) {
1325
- (0, engine_primitives_1.log)(engine_primitives_1.c.cyan, ` Found ${postSprintProposals.length} proposals sending to CEO for autonomous review`);
1326
- // Build CTOReport for CEO review
1327
- const postSprintCTOReport = {
1328
- summary: parsed.summary || 'Post-sprint analysis proposals',
1329
- proposals: postSprintProposals.map((p) => ({
1330
- id: p.id,
1331
- title: p.title,
1332
- category: p.category,
1333
- description: p.description,
1334
- estimated_impact: p.estimated_impact || '',
1335
- risk_level: p.risk_level || 'medium',
1336
- implementation_steps: p.implementation_steps || [],
1337
- })),
1338
- metrics_reviewed: ['sprint_results', 'failure_patterns', 'trend_analysis'],
1339
- };
1340
- // Phase 5c: CEO autonomously reviews post-sprint proposals
1341
- (0, engine_primitives_1.log)(engine_primitives_1.c.magenta, '\n--- Phase 5c: CEO Reviews Post-Sprint Proposals (Autonomous) ---');
1342
- const postSprintDecisions = await this.ceo.reviewCTOProposals(postSprintCTOReport);
1343
- // Persist CEO decisions + update approved-proposals tracker
1344
- (0, orchestrate_engine_1.persistCEODecisions)(postSprintDecisions, postSprintCTOReport);
1345
- (0, engine_primitives_1.log)(engine_primitives_1.c.magenta, ' CEO post-sprint proposal review complete');
1383
+ if (this.buildPath === 'regulated') {
1384
+ (0, engine_primitives_1.log)(engine_primitives_1.c.cyan, '\n--- Phase 5b: CTO Post-Sprint Analysis (Autonomous) ---');
1385
+ try {
1386
+ postSprintReport = await this.cto.postSprintAnalysis(this.tasks, this.stats);
1387
+ (0, engine_primitives_1.log)(engine_primitives_1.c.cyan, ' Post-sprint analysis saved to reports/cto/');
1388
+ // Extract proposals from post-sprint analysis and feed into CEO review
1389
+ const jsonMatch = postSprintReport.match(/```json\s*([\s\S]*?)```/);
1390
+ if (jsonMatch) {
1391
+ try {
1392
+ const parsed = JSON.parse(jsonMatch[1].trim());
1393
+ const postSprintProposals = parsed.proposals || [];
1394
+ if (postSprintProposals.length > 0) {
1395
+ (0, engine_primitives_1.log)(engine_primitives_1.c.cyan, ` Found ${postSprintProposals.length} proposals — sending to CEO for autonomous review`);
1396
+ // Build CTOReport for CEO review
1397
+ const postSprintCTOReport = {
1398
+ summary: parsed.summary || 'Post-sprint analysis proposals',
1399
+ proposals: postSprintProposals.map((p) => ({
1400
+ id: p.id,
1401
+ title: p.title,
1402
+ category: p.category,
1403
+ description: p.description,
1404
+ estimated_impact: p.estimated_impact || '',
1405
+ risk_level: p.risk_level || 'medium',
1406
+ implementation_steps: p.implementation_steps || [],
1407
+ })),
1408
+ metrics_reviewed: ['sprint_results', 'failure_patterns', 'trend_analysis'],
1409
+ };
1410
+ // Phase 5c: CEO autonomously reviews post-sprint proposals
1411
+ (0, engine_primitives_1.log)(engine_primitives_1.c.magenta, '\n--- Phase 5c: CEO Reviews Post-Sprint Proposals (Autonomous) ---');
1412
+ const postSprintDecisions = await this.ceo.reviewCTOProposals(postSprintCTOReport);
1413
+ // Persist CEO decisions + update approved-proposals tracker
1414
+ (0, orchestrate_engine_1.persistCEODecisions)(postSprintDecisions, postSprintCTOReport);
1415
+ (0, engine_primitives_1.log)(engine_primitives_1.c.magenta, ' CEO post-sprint proposal review complete');
1416
+ }
1417
+ else {
1418
+ (0, engine_primitives_1.log)(engine_primitives_1.c.cyan, ' No proposals in post-sprint analysis');
1419
+ }
1346
1420
  }
1347
- else {
1348
- (0, engine_primitives_1.log)(engine_primitives_1.c.cyan, ' No proposals in post-sprint analysis');
1421
+ catch (parseErr) {
1422
+ (0, engine_primitives_1.log)(engine_primitives_1.c.yellow, ` Could not parse post-sprint proposals JSON: ${parseErr.message}`);
1349
1423
  }
1350
1424
  }
1351
- catch (parseErr) {
1352
- (0, engine_primitives_1.log)(engine_primitives_1.c.yellow, ` Could not parse post-sprint proposals JSON: ${parseErr.message}`);
1353
- }
1354
1425
  }
1426
+ catch (error) {
1427
+ (0, engine_primitives_1.log)(engine_primitives_1.c.yellow, ` Post-sprint analysis skipped: ${error.message}`);
1428
+ }
1429
+ // 7. CEO generates daily report
1430
+ (0, engine_primitives_1.log)(engine_primitives_1.c.magenta, '\n--- Phase 6: Daily Report Generation ---');
1431
+ const ctoReportStr = `Summary: ${ctoReport.summary}\nProposals: ${ctoReport.proposals.length}\n${ctoReport.proposals.map(p => `- [${p.category}] ${p.title} (${p.risk_level})`).join('\n')}`;
1432
+ const grokSection = (0, engine_loaders_1.loadGrokFeed)();
1433
+ const cmoSection = cmoReports
1434
+ ? '\n\n## CMO Activity (Manus AI)\n' + cmoReports.substring(0, 2000)
1435
+ : '\n\nCMO: No reports available this cycle.';
1436
+ const grokForReport = grokSection ? '\n\n## Grok Intelligence Feed\nGrok AI reports available — included in CTO/CEO analysis.' : '\n\nGrok: No feed reports this cycle.';
1437
+ const postSprintSection = postSprintReport ? '\n\n## CTO Post-Sprint Analysis\n' + postSprintReport.substring(0, 2000) : '';
1438
+ await this.ceo.generateDailyReport(this.tasks, this.stats, ctoReportStr + cmoSection + grokForReport + postSprintSection, ctoDecisions);
1355
1439
  }
1356
- catch (error) {
1357
- (0, engine_primitives_1.log)(engine_primitives_1.c.yellow, ` Post-sprint analysis skipped: ${error.message}`);
1440
+ else {
1441
+ (0, engine_primitives_1.log)(engine_primitives_1.c.gray, '\n--- Phases 5b–6: Post-Sprint Ceremony + Daily Report — SKIPPED (fast track) ---');
1358
1442
  }
1359
- // 7. CEO generates daily report
1360
- (0, engine_primitives_1.log)(engine_primitives_1.c.magenta, '\n--- Phase 6: Daily Report Generation ---');
1361
- const ctoReportStr = `Summary: ${ctoReport.summary}\nProposals: ${ctoReport.proposals.length}\n${ctoReport.proposals.map(p => `- [${p.category}] ${p.title} (${p.risk_level})`).join('\n')}`;
1362
- const grokSection = (0, engine_loaders_1.loadGrokFeed)();
1363
- const cmoSection = cmoReports
1364
- ? '\n\n## CMO Activity (Manus AI)\n' + cmoReports.substring(0, 2000)
1365
- : '\n\nCMO: No reports available this cycle.';
1366
- const grokForReport = grokSection ? '\n\n## Grok Intelligence Feed\nGrok AI reports available — included in CTO/CEO analysis.' : '\n\nGrok: No feed reports this cycle.';
1367
- const postSprintSection = postSprintReport ? '\n\n## CTO Post-Sprint Analysis\n' + postSprintReport.substring(0, 2000) : '';
1368
- await this.ceo.generateDailyReport(this.tasks, this.stats, ctoReportStr + cmoSection + grokForReport + postSprintSection, ctoDecisions);
1369
1443
  // 8. Save updated sprint state
1370
1444
  const sprintFile = process.argv[2] || 'sprints/current.json';
1371
1445
  (0, fs_1.writeFileSync)(sprintFile, JSON.stringify({ tasks: this.tasks }, null, 2));
@@ -1412,6 +1486,8 @@ ONLY output the JSON array. No markdown, no explanation.`;
1412
1486
  git_head_before: gitHeadBefore,
1413
1487
  git_head_after: gitHeadAfter,
1414
1488
  sovereign_mode: engine_primitives_1.SOVEREIGN_MODE,
1489
+ build_path: this.buildPath, // TICKET-234: 'regulated' | 'fast'
1490
+ triage: this.triage, // TICKET-234: classifier reason + triggers
1415
1491
  summary: {
1416
1492
  total_tasks: this.tasks.length,
1417
1493
  done: this.tasks.filter(t => t.status === 'done').length,
@@ -17,6 +17,7 @@
17
17
  * 1. KSL record (spawn_request + spawn_decision)
18
18
  * 2. Voxight market intelligence signal (spawn classification = demand signal)
19
19
  */
20
+ import { type CitizenOwner, type CitizenRecord } from './citizenship';
20
21
  /** All possible classifications for a spawn request. */
21
22
  export type SpawnClass = 'UTILITY' | 'SPECIALIST' | 'CITIZEN' | 'EXTERNAL' | 'PRIME';
22
23
  export type GovernancePath = 'auto' | 'ceo_review' | 'cto_review' | 'founder_required' | 'blocked';
@@ -95,6 +96,39 @@ export declare function issueSpawnDecision(req: SpawnRequest, analysis: SpawnAna
95
96
  * if (!decision.approved) throw new Error(`Spawn blocked: ${decision.rejection_reason}`);
96
97
  */
97
98
  export declare function sovereignSpawn(req: SpawnRequest): SpawnDecision;
99
+ /**
100
+ * Derive a new citizen's lineage owner from the spawn requester's DID, so the
101
+ * spawned citizen inherits the requester's identity:
102
+ * - `did:external:{org}:…` → external org (AMD-23 airlock)
103
+ * - `did:kognai:citizen:{wallet}` → the requester is a user's citizen forming
104
+ * a swarm → sub-agents belong to that SCS
105
+ * (scs id = the founder wallet)
106
+ * - `did:kognai:scs:{scsId}:…` → same SCS (a swarm growing itself)
107
+ * - `did:kognai:{company}:…` → that company (invoica/voxight/kreativ/…)
108
+ * - anything else (founder / legacy `did:kognai:{agent}`) → kognai company.
109
+ *
110
+ * NB: the FIRST agent of a wallet (the citizen-journey 1-per-wallet citizen) is
111
+ * minted with `owner: { kind:'user', id: wallet }` by the join flow, not here —
112
+ * deriveOwner is for spawns *requested by* an existing citizen.
113
+ */
114
+ export declare function deriveOwner(requester_did: string): CitizenOwner;
115
+ /**
116
+ * The single canonical citizen-spawn entry point: governance gate (SAF) →
117
+ * identity issuance (mintCitizen with the requester-derived owner). Every new
118
+ * citizen — product, external, user, or SCS sub-agent — should be born here.
119
+ *
120
+ * Returns the governance decision plus the minted citizen (when approved). The
121
+ * caller still writes citizen.yaml via renderCitizenYaml(citizen). The initial
122
+ * ACP (`decision.initial_acp_score`) should be persisted to the score registry
123
+ * by the caller/wiring step (see TICKET-335).
124
+ */
125
+ export declare function spawnCitizen(req: SpawnRequest, opts?: {
126
+ agent_name?: string;
127
+ now?: Date;
128
+ }): {
129
+ decision: SpawnDecision;
130
+ citizen?: CitizenRecord;
131
+ };
98
132
  /**
99
133
  * Emergency bypass — Founder only. Overrides all gates including health and
100
134
  * constitutional conditional findings. Logs prominently to KSL.