Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Code Generation Plan — quality-repair-runtime

## スコープと追跡元

U2 `quality-repair-runtime`(Issue #2096)のみを実装する。追跡元は USR-02 / USR-05 / USR-08、FR-QRP-001〜013、FR-LMC-010、FR-STP-003〜006、FR-HAR-001〜007、2096-AC01〜18、および Functional / NFR Design の QRP-A/E/P/R 規則である。テスト戦略は `Comprehensive` とし、決定論的 unit test、production coordinator / replay integration、5 harness projection、package / promote drift を同じ Bolt で閉じる。

U1 `loop-monitor-runtime` の generic Monitor、durable repository、Judge port、latch / resume contract を再利用する。quality の obligation / convergence / route 意味論を generic Monitor へ混入させず、harness 別 Core 分岐も作らない。

## 実装手順

- [x] **Step 1 — generic singleton route constraint seam**: U1 Monitor の compiled route 集合から delivery ごとの非空 subset constraint を検証・予約・Judge request へ伝播できるよう最小拡張する。quality 固有語彙は追加しない。(FR-QRP-009〜011、2096-AC09〜10)
- [x] **Step 2 — first-party contribution と activation**: trusted embedded contribution、descriptor exact resolution、`semi/full` 必須、`none` real-human opt-in / default-off、required outputs 初期空集合を pure contract として実装する。(USR-02 / USR-08、FR-QRP-001〜003 / 012、2096-AC01〜05)
- [x] **Step 3 — blocking evidence normalization**: reviewer / blocking sensor / required produce / verification・completion の closed observation を stable obligation、snapshot、resolved / added / retained、canonical fingerprint へ正規化する。advisory sensor と Request Changes は除外し、不完全 evidence は fail-closed にする。(FR-QRP-004〜008 / 013、2096-AC06〜08)
- [x] **Step 4 — bounded quality convergence**: T+1 window、initial / collecting / strict-progress / threshold、fixed-point / churn / regression / undetermined、replan-first と post-replan repair-stalled singleton constraint を pure reducer として実装する。(USR-05、FR-QRP-009〜011、2096-AC09〜11)
- [x] **Step 5 — durable production coordinator**: canonical quality event set、snapshot / progress / replan reservation-before-effect、closed attempt 0/1、local review cycle、generic Monitor delivery / Judge / latch、`REPAIR_STALLED` / suspended status を統合する。(FR-STP-003〜006、2096-AC10〜15)
- [x] **Step 6 — resume / replay / status**: `any-of[evidence-change,human-retry]`、atomic latch clear + new quality epoch + workflow unpark、same-fingerprint short circuit、cross-session replay と safe status envelope を実装する。(USR-05、FR-LMC-010、2096-AC11〜16)
- [x] **Step 7 — Comprehensive tests**: Step 1〜6 の red unit / integration testsを追加し、T-1 Judge 0、初回 T replan、strict progress reset、replan 後 T stalled、Request Changes 非変換、crash / replay / duplicate / cross-scope、latch / resume contract 再利用を検証する。(2096-AC01〜18)
- [x] **Step 8 — 5 harness projection と品質ゲート**: framework core から Claude Code / Codex / Cursor / OpenCode / Kimi Code へ生成し、共通 fixture の byte-equivalent contract、`bun run typecheck`、`bun run lint`、focused tests、`bun scripts/package.ts --check`、`bun run promote:self:check` を検証する。(FR-HAR-001〜007、2096-AC16〜18)

## 非対象

U3〜U5、Intent grant、gate / question 認可、PR / merge、外部 runner / supervisor、Kiro live、外部 Plugin manifest、新 stage、固定総 retry cap、新規 mandatory artifact は実装しない。
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Code Summary — quality-repair-runtime

## 実装結果

U2 `quality-repair-runtime`(Issue #2096)を、U1 `loop-monitor-runtime` の durable delivery / Judge / latch / resume seam を再利用する first-party runtime として実装した。品質固有の obligation、T+1 convergence、replan-first、post-replan `repair-stalled` は専用 reducer に閉じ、generic Monitor には delivery 単位の非空 route subset constraint だけを追加した。

### Core

- `amadeus-quality-repair.ts`: trusted embedded contribution、depth 別 activation、closed evidence normalization、stable obligation / snapshot / delta / fingerprint、T+1 convergence reducer、replan receipt / review-cycle identity を実装した。
- `amadeus-quality-repair-runtime.ts`: quality event と generic Monitor event の atomic transaction、reservation-before-effect、closed attempt 0/1、reconcile-first、`REPAIR_STALLED`、suspended status、human/evidence resume、cross-session replay を実装した。
- `amadeus-quality-repair-replay.ts`: canonical audit transaction の decode / repository / replay を実装した。
- `amadeus-loop-monitor.ts` / `amadeus-loop-monitor-runtime.ts`: compiled route の検証済み subset を予約・Judge request・適用へ伝播し、replan target を post-replan interval の anchor に更新する generic seam を追加した。
- audit event registry に `QUALITY_REPAIR_TRANSACTION_COMMITTED` を追加し、canonical payload の仕様と event count を同期した。
- `docs/reference/12-state-machine.md` と coverage registry / ratchet を U2 の新規 canonical audit event へ同期した。

### 投影

同一 Core bytes を Claude Code、Codex、Cursor、OpenCode、Kimi Code の5ハーネスへ投影した。Kiro live、外部 runner / supervisor、U3〜U5、Intent grant、gate / question authorization は追加していない。

## テスト

- pure unit: contribution / activation、blocking evidence、strict progress / fixed-point / churn / regression / undetermined、replan-first / repair-stalled、Request Changes 除外を検証した。
- integration: T-1 Judge 0、初回 threshold replan、post-replan stalled、atomic resume、same-fingerprint no-op、cross-session replay、attempt 0/1 と attempt 2 不在、latch / resume contract 再利用、canonical serialization を検証した。
- projection: 5ハーネスの quality runtime 3ファイルが Core と byte-identical であることを検証した。
- 品質ゲート: `bun run typecheck`、`bun run lint`、最終 focused 128 tests / 2,185 expects、coverage registry freshness / ratchet、audit emitter / state-machine / audit-format drift、`bun scripts/package.ts --check`、`bun run promote:self:check`、`git diff --check` を通過した。lint は既存 baseline の cognitive-complexity warning のみで error はない。
- `bun run test:ci` は全788ファイルを完走した。初回に U2 由来の event count、test size、audit taxonomy、coverage registry の同期漏れを検出し、すべて修正して上記 focused set で再検証した。古い Bolt base に由来する Pi conductor / package、complexity baseline 等の既存 drift は U2外として残した。

## 設計差分と除外

- 設計上の singleton route を generic runtime で安全に表現するため、U1 の full-set constraint を「compiled route の非空 subset」へ最小限に一般化した。quality 固有語彙は U1 Core へ追加していない。
- U1 依存コミット `89d5afe35` はこの Bolt のローカル前提であり、U2コミットには含めない。
- package / promote 実行で顕在化した、古い base に由来する `amadeus-harness-capability.ts`、`amadeus-harness.ts`、`amadeus-swarm.ts`、`amadeus-utility.ts`、Pi / Kiro 等の既存 drift は U2 の変更ではないため、U2コミット対象から明示的に除外する。

## 残作業

U2の実装残はない。後続は独立した Build and Test / 統合工程で扱う。
5 changes: 3 additions & 2 deletions docs/reference/12-state-machine.md
Original file line number Diff line number Diff line change
Expand Up @@ -395,13 +395,14 @@ The four `SENSOR_*` events are emitted by the sensor dispatcher; `GUARDRAIL_LOAD
| `RULE_LEARNED` | `tools/amadeus-learnings.ts` | The learning gate persisted a kept learning as a dated practice entry to `amadeus/spaces/<space>/memory/{project,team}.md` |
| `SENSOR_PROPOSED` | `tools/amadeus-learnings.ts` | The learning gate scaffolded a project-tier sensor manifest and bound it to the originating stage's `sensors:` frontmatter |

### Loop monitor
### Loop monitor and quality repair

The Loop Monitor commits delivery observations, cycle triggers, Judge reservations and results, closed-route applications, and latch transitions as one canonical event set. The per-clone Replay Index is a repairable projection of this audit source of truth.
The Loop Monitor commits delivery observations, cycle triggers, Judge reservations and results, closed-route applications, and latch transitions as one canonical event set. The Quality Repair runtime commits each quality snapshot, progress, replan, stall, or resume transaction together with its generic Loop Monitor effects. The per-clone Replay Index is a repairable projection of these audit sources of truth.

| Event | Emitter | Trigger |
|---|---|---|
| `LOOP_MONITOR_EVENT_SET_COMMITTED` | `tools/amadeus-loop-monitor-replay.ts` | One atomic Loop Monitor delivery, Judge, or latch transition committed |
| `QUALITY_REPAIR_TRANSACTION_COMMITTED` | `tools/amadeus-quality-repair-replay.ts` | One quality snapshot, progress, replan, stall, or resume transaction and its generic Monitor effects committed atomically |

### Swarm

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ tools read them from. Neither lists the record envelope — every record carries
(the park pair, the practices events) show it in the table as the attribute it
is.

## Event Registry (86 events, 21 categories)
## Event Registry (87 events, 21 categories)

### Workflow Lifecycle (7 events)

Expand Down Expand Up @@ -243,13 +243,14 @@ Emitted by stage-protocol §13 (Learnings Ritual). The runtime-graph compile emi
| `RULE_LEARNED` | The learning gate persisted a kept learning as a practice line under the routed heading in `{project,team}.md` | Stage, Candidate-ID, Destination, Heading, Source | — | `tools/amadeus-learnings.ts persist` |
| `SENSOR_PROPOSED` | The learning gate scaffolded a project-tier sensor manifest and bound it to the originating stage's `sensors:` frontmatter | Stage, Candidate-ID, Sensor ID, Manifest path, Matches, Destinations, Source | — | `tools/amadeus-learnings.ts persist` |

### Loop Monitor (1 event)
### Loop Monitor and Quality Repair (2 events)

The event set is the atomic canonical stream for delivery observation, cycle trigger, Judge reservation/result, closed route application, and latch transitions. The per-clone Replay Index is a repairable secondary projection and never replaces this audit source of truth.

| Event | When | Required | Optional | Emitter |
|-------|------|----------|----------|---------|
| `LOOP_MONITOR_EVENT_SET_COMMITTED` | One atomic Loop Monitor delivery/Judge/latch transition commits | Partition Key, Event Set Id, Event Set | — | `tools/amadeus-loop-monitor-replay.ts` |
| `QUALITY_REPAIR_TRANSACTION_COMMITTED` | One Quality snapshot/progress/replan/stall/resume transaction and its generic Monitor effects commit atomically | Quality Scope Id, Transaction Id, Transaction | — | `tools/amadeus-quality-repair-replay.ts` |

### Swarm (7 events)

Expand Down
15 changes: 12 additions & 3 deletions packages/framework/core/otel/event-registry.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// event-registry.ts — the typed Event Registry (FR-EVT-1).
//
// The canonical half of the registry covers the full 86-event audit
// The canonical half of the registry covers the full 87-event audit
// vocabulary (#1672; VALID_EVENT_TYPES in tools/amadeus-audit.ts) — every
// canonical name maps 1:1 onto the EXISTING v1 audit event vocabulary so the
// current readers understand the records unchanged. The telemetry half
Expand All @@ -14,7 +14,7 @@
// sites (BR-2);
// 2. unit test — tests/unit/event-registry-drift.test.ts asserts the
// four-set equality (state-machine references == canonical registry ==
// exporter accept set == journal reader decode set) with the 86
// exporter accept set == journal reader decode set) with the 87
// cardinality pinned, so vacuous equality fails;
// 3. sensor — sensors/amadeus-event-registry-drift.md runs the same
// extraction at gate time.
Expand Down Expand Up @@ -76,7 +76,7 @@ export type EventDef = {

// The canonical cardinality (#1672). The drift guard pins this so an emptied
// or truncated registry fails instead of passing vacuously.
export const EXPECTED_CANONICAL_COUNT = 86;
export const EXPECTED_CANONICAL_COUNT = 87;

// The OTel semantic-convention span event name produced by recordException().
// Registered as telemetry (FR-EVT-7): it rides the span record, never the
Expand Down Expand Up @@ -206,6 +206,15 @@ export const REGISTERED_EVENTS = [
optionalAttributes: [],
schemaVersion: 1,
},
{
name: "amadeus.quality_repair.transaction.committed",
auditEvent: "QUALITY_REPAIR_TRANSACTION_COMMITTED",
durability: "canonical",
category: "loop-monitor",
requiredAttributes: ["Quality Scope Id", "Transaction Id", "Transaction"],
optionalAttributes: [],
schemaVersion: 1,
},
// --- Phase Lifecycle (4) ---
{
name: "amadeus.phase.started",
Expand Down
2 changes: 2 additions & 0 deletions packages/framework/core/tools/amadeus-audit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ const VALID_EVENT_TYPES = new Set([
// canonical event set; required projections consume its digest after append.
"EXECUTION_EVENT_SET_COMMITTED",
"LOOP_MONITOR_EVENT_SET_COMMITTED",
"QUALITY_REPAIR_TRANSACTION_COMMITTED",
// Session events (hook-owned)
"SESSION_STARTED",
"SESSION_RESUMED",
Expand Down Expand Up @@ -242,6 +243,7 @@ export const EVENT_HEADINGS: Record<string, string> = {
LEGACY_GOAL_MIGRATED: "Legacy Goal Migrated",
EXECUTION_EVENT_SET_COMMITTED: "Execution Event Set Committed",
LOOP_MONITOR_EVENT_SET_COMMITTED: "Loop Monitor Event Set Committed",
QUALITY_REPAIR_TRANSACTION_COMMITTED: "Quality Repair Transaction Committed",
UNIT_POOL_EVENT_SET_COMMITTED: "Unit Pool Event Set Committed",
SESSION_STARTED: "Session Start",
SESSION_RESUMED: "Session Resume",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ function validEvent(value: unknown): value is LoopMonitorEvent {
}
}

function validEventSet(value: unknown): value is LoopMonitorEventSet {
export function validEventSet(value: unknown): value is LoopMonitorEventSet {
return isRecord(value) && typeof value.eventSetId === "string" &&
validPartition(value.partition) && typeof value.partitionKey === "string" &&
value.partitionKey === loopMonitorPartitionKey(value.partition) &&
Expand Down
25 changes: 22 additions & 3 deletions packages/framework/core/tools/amadeus-loop-monitor-runtime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,23 @@ function applyJudgeCompletion(
};
}

function applyRoute(
projection: LoopMonitorRuntimeProjection,
monitor: CompiledLoopMonitor,
event: RuntimeEventOf<"LOOP_ROUTE_APPLIED">,
): LoopMonitorRuntimeProjection {
if (event.targetEvent === null) return { ...projection, lastRouteId: event.routeId };
const cycleIndex = monitor.cycle.indexOf(event.targetEvent);
return {
...projection,
lastRouteId: event.routeId,
lastSemanticEventId: event.targetEvent,
matchedPrefix: cycleIndex < 0 ? 0 : cycleIndex + 1,
cycleCount: 0,
epoch: projection.epoch + 1,
};
}

const RUNTIME_EVENT_HANDLERS = {
LOOP_DELIVERY_OBSERVED: applyObservedDelivery,
LOOP_MONITOR_TRIGGERED: (projection, _monitor, event) =>
Expand All @@ -267,7 +284,7 @@ const RUNTIME_EVENT_HANDLERS = {
LOOP_JUDGE_ATTEMPT_STARTED: (projection, _monitor, event) => applyJudgeAttempt(projection, event),
LOOP_JUDGE_RESULT_OBSERVED: (projection) => projection,
LOOP_JUDGE_COMPLETED: (projection, _monitor, event) => applyJudgeCompletion(projection, event),
LOOP_ROUTE_APPLIED: (projection, _monitor, event) => ({ ...projection, lastRouteId: event.routeId }),
LOOP_ROUTE_APPLIED: (projection, monitor, event) => applyRoute(projection, monitor, event),
LOOP_LATCH_SET: (projection, _monitor, event) => ({ ...projection, latch: event.latch, pendingJudge: null }),
LOOP_LATCH_CLEARED: (projection) => ({ ...projection, latch: null, awaitingHumanReason: null }),
WORKFLOW_UNPARKED: (projection) => projection,
Expand Down Expand Up @@ -317,7 +334,8 @@ function deliveryReplayDecision(
const observed = event.delivery;
if (observed.upstreamEventIdentity === delivery.upstreamEventIdentity) {
return observed.deliveryId === delivery.deliveryId &&
observed.payloadFingerprint === delivery.payloadFingerprint
observed.payloadFingerprint === delivery.payloadFingerprint &&
observed.routeConstraint.fingerprint === delivery.routeConstraint.fingerprint
? "duplicate"
: "identity-conflict";
}
Expand Down Expand Up @@ -347,7 +365,7 @@ function judgeRequest(
judgeInstructionId: monitor.judgeInstruction.id,
evidenceFingerprint: reservation.evidenceFingerprint,
routeConstraintFingerprint: reservation.constraintFingerprint,
allowedRouteIds: [...monitor.routeConstraint.routeIds],
allowedRouteIds: [...reservation.routeConstraint.routeIds],
trace: { ...reservation.trace },
};
}
Expand All @@ -365,6 +383,7 @@ function matchingJudgeResult(
result.evidenceFingerprint === reservation.evidenceFingerprint &&
result.constraintFingerprint === reservation.constraintFingerprint &&
tracesEqual(result.trace, reservation.trace) &&
reservation.routeConstraint.routeIds.includes(result.routeId) &&
routeById(monitor, result.routeId) !== null;
}

Expand Down
Loading
Loading