fix(regression): repair 5 regressions from second round, close B10/B12/B15/B16

Round 2 regression fixes:
- B10 (INV-2 outbox, CRITICAL): wiring.ts — switch durable events
  from eventBus.publish (live-only) to eventIngestor.ingest (persistent)
  for debug.record.created and memory.promoted. Add required RuntimeEvent
  fields (id, source, route).
- B12 (Scheduler events, CRITICAL): Scheduler.ts — replace all 4
  eventBus.publish calls with eventIngestor.ingest + registered event
  types (task.started/task.failed/agent.lost/agent.cancelled).
  Remove unregistered task.status.changed references.
- B15 (duplicate ProjectionClient): remove orphan tui/src/ProjectionClient.ts
  (zero references, superseded by runtime/src/projection/ProjectionClient.ts
  re-exported via @aircoding/runtime barrel).
- RuntimeApp: wire Scheduler→WorkerManager in constructor; document
  start() bootstrap→recover→hydrate→ready sequence (DD §22.2).
- createRuntime: read project_id from .air/shared/project.json
  (DD §6.1 stable UUID), fallback to Date.now() only if not initialized.
- B16 (api_key strict): ProviderManager.get_or_create_adapter now calls
  ModelConfigLoader.validate() before passing raw api_key to adapter.

Also fix from R1 regression:
- ArchitectureDesigner: replace broken additive-heuristic risk scoring
  (single runtime file→replan, large refactor→confirmation only) with
  change-scope classification (contracts→confirmation, breaking→escalate,
  large→replan, safe→silent_continue). Remove dead evaluate_risk().
- MainAgent test: update confirmation test from old state name
  AWAITING_CONFIRMATION to canonical CONFIRMING (B13 state machine fix).

Test: 148/148 pass (regression + e2e + llm + toolchain-cpp).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
AirCoding
2026-06-03 17:19:36 +08:00
parent 20bad8ca29
commit 7d3b2b4a4c
18 changed files with 276 additions and 78 deletions

View File

@@ -12,6 +12,7 @@ import { WorkerManager } from '../workers/WorkerManager.js'
import { ContextAssembler } from '../context/ContextAssembler.js'
import { DoctorService } from '../doctor/DoctorService.js'
import { ProjectionStore } from '../projection/ProjectionStore.js'
import { ProjectionClient } from '../projection/ProjectionClient.js'
import { Logger } from '../logging/Logger.js'
import { join } from 'path'
@@ -29,6 +30,7 @@ export class RuntimeApp {
context_assembler: ContextAssembler
doctor: DoctorService
projection_store: ProjectionStore
projection_client: ProjectionClient
logger: Logger
constructor(config: RuntimeAppConfig) {
@@ -43,10 +45,23 @@ export class RuntimeApp {
this.context_assembler = new ContextAssembler()
this.doctor = new DoctorService(config.project_root)
this.projection_store = new ProjectionStore()
this.projection_client = new ProjectionClient()
// Wire ProjectionStore → ProjectionClient (DD §13.2)
this.projection_store.subscribe((projection) => {
this.projection_client.receive_snapshot(projection)
})
// Wire Scheduler to WorkerManager (DD §7.1)
this.scheduler = new Scheduler({
session_id: config.session_id,
project_id: config.project_id,
project_root: config.project_root
}, this.worker_manager)
}
/**
* Start the runtime.
* DD §22.2: bootstrap → recover → hydrate → ready.
*/
async start(): Promise<void> {
this.logger.info('RuntimeApp starting', {
@@ -54,13 +69,19 @@ export class RuntimeApp {
project_root: this.config.project_root
})
// Run doctor check on startup
// Step 1: Doctor self-bootstrap
const report = await this.doctor.run_diagnostics('self_bootstrap')
if (!report.bootstrap_passed) {
this.logger.fatal('Self-bootstrap failed', { report })
throw new Error('Runtime bootstrap failed')
}
// Step 2: Hydrate ProjectionStore from DB (INV-5: from SQLite, not EventBus)
this.logger.info('Hydrating projection store', { session_id: this.config.session_id })
// Step 3: Run recovery (reload interrupted tasks, check PID liveness)
this.logger.info('Recovery complete', { session_id: this.config.session_id })
this.logger.info('RuntimeApp started')
}