Skip to content

feat: mission control + flight recorder operator cockpit#2044

Merged
Aureliolo merged 17 commits into
mainfrom
feat/1981-mission-control-flight-recorder
May 22, 2026
Merged

feat: mission control + flight recorder operator cockpit#2044
Aureliolo merged 17 commits into
mainfrom
feat/1981-mission-control-flight-recorder

Conversation

@Aureliolo
Copy link
Copy Markdown
Owner

Closes #1981.

Summary

Operator cockpit for the SynthOrg runtime: watch the company work live, identify a stuck or runaway agent and intervene, replay any completed run step-by-step.

What this adds

Persistence (dual-backend, conformance-tested)

  • FlightRecorderFrame append-only frame store: SQLite + Postgres repos, yoyo revisions, canonical schema.sql for both backends, FakeFlightRecorderFrameRepository mirrored into the api test fixture.

Engine

  • Pluggable FlightRecorderSink (default-on, fail-soft, off the per-turn hot path) wired into AgentEngine._run_and_finalize: every agent run records redacted per-turn frames.
  • CockpitService aggregates live activity (who/what + cost + turn count) and flags stuck / runaway agents from operator-tunable thresholds.
  • FlightRecorderService serves the scrubber timeline and a seek(turn N) ascending-prefix reconstruction with cumulative cost, frame-authoritative.
  • Pluggable SteeringDirective protocol with a SafeDefaultSteeringDirective that posts an INFO_REQUEST interrupt for hint / redirect (visible queued artefact, never silent no-op).
  • InterventionKind enum on core/enums.py; cockpit settings namespace with 8 knobs; observability/events/cockpit.py event constants.

API

  • /cockpit Litestar controller: snapshot, flight-recorder frames + seek, four guarded interventions (pause / kill / hint / redirect), 503-gated via AppState.
  • Boot wiring via _try_wire_cockpit after persistence connects; ENFORCED ghost-wiring manifest lines for CockpitService, FlightRecorderService, build_steering_directive, build_flight_recorder_sink.
  • CHANNEL_COCKPIT appended to the WS allowlist.

MCP

  • New cockpit domain: 3 read tools (live activity, frames, seek) and 4 admin tools (pause / kill / hint / redirect) that call require_admin_guardrails as their lexically-first call. Tool-count plan bumped to 226.

Web dashboard

  • /mission-control route (sidebar nav, Radio icon).
  • Live cockpit: KPI row (Active / Spend / Stuck / Runaway), per-agent rows with status indicator (text + colour + ARIA), pause / kill / hint controls, snapshot polling + WS liveness on cockpit | tasks | agents | budget channels.
  • Flight Recorder: new shared Timeline scrubber primitive (+ stories), transport (prev / next / play / pause / speed), per-turn frame detail.
  • Zustand mission-control store (mutation pattern: try / catch + toast + sentinel; callers do not wrap), useMissionControlData hook (polling + WS + cleanup), api/endpoints/cockpit.ts, MSW handlers, regenerated DTOs.
  • Shared statusBgClass util so Timeline + LiveCockpit + FlightRecorder all map status → colour the same way.

Test plan

  • Unit: tests/unit/engine/{cockpit,flight_recording,intervention}/, tests/unit/api/controllers/test_cockpit.py, web Timeline / page / store tests.
  • Integration: tests/unit/engine/flight_recording/test_engine_recording.py proves AgentEngine.run() auto-records replayable frames through the real hook.
  • Conformance: tests/conformance/persistence/test_flight_recorder_repository.py over SQLite + Postgres.
  • E2E acceptance: tests/e2e/test_cockpit_mission_control_e2e.py exercises detect → intervene → replay against the real services.

All pre-push gates green locally (ruff, mypy on affected, pytest unit on affected, ESLint, ghost-wiring, currency-aggregation, MCP guardrails, frozen-model extra="forbid", typed-boundary, dto-types-ts-in-sync, schema-drift, schema.sql vs revisions, no-review-origin, dead-API-endpoint, convention-gate inventory).

Review coverage

Six core pre-PR review agents ran on the diff: code-reviewer, conventions-enforcer, frontend-reviewer, persistence-reviewer, test-quality-reviewer, issue-resolution-verifier. 13 valid findings addressed (immutability via fresh dict construction in repo deserialization, accessible status indicator + Hint context, named frame type, _MAX_SEEK_FRAMES: Final[int], useMemo for scrubber projections, shared status-colour util, store reset in test teardown, richer MSW defaults, as const satisfies typing). One code-reviewer finding (except A, B: claimed as Py2) dismissed as false positive: PEP 758 in 3.14 allows it and the conventions-enforcer confirmed the project standard. Issue-resolution-verifier: PASS, all #1981 criteria RESOLVED.

Also fixed one unrelated pre-existing test-isolation bug surfaced by the full-suite gate (tests/unit/observability/audit_chain/test_audit_chain.py: mocked executor submit was dropping its coroutine arg, leaking an un-awaited coroutine into pytest's unraisable-exception capture and tainting downstream tests on the same xdist worker).

Aureliolo added 14 commits May 22, 2026 20:09
Persistence: append-only FlightRecorderFrame repo (sqlite+postgres, new yoyo revision), wired into both backends + fake. Engine: pluggable recorder sink records per-turn frames after each agent run (off the hot path, fail-soft). Services: FlightRecorderService (frame-authoritative get/seek), CockpitService (live activity + stuck/runaway heuristics), SafeDefaultSteeringDirective (hint/redirect via INFO_REQUEST interrupt). Adds InterventionKind enum, cockpit settings namespace + events module.
Adds /cockpit controller (live snapshot, flight-recorder frames + seek, pause/kill/hint/redirect interventions) registered in BASE_CONTROLLERS and 503-gated via AppState. Wires CockpitService/FlightRecorderService/SteeringDirective at boot via _try_wire_cockpit. Appends CHANNEL_COCKPIT, AppState cockpit seams, ENFORCED ghost-manifest lines, and regenerated TS DTOs. CockpitService takes thresholds at call time (controller resolves settings) to stay free of a wire-time resolver dependency. Controller + service unit tests.
Adds /mission-control route + sidebar nav. Live tab: KPI row, agent activity rows with pause/kill/hint/redirect interventions, stuck/runaway flags, REST snapshot polling + WS liveness on the cockpit/tasks/agents/budget channels. Flight Recorder tab: new Timeline scrubber primitive (+ stories), transport controls + speed, per-turn frame detail. Adds cockpit endpoints, Zustand store (mutation pattern), useMissionControlData hook, MSW handlers, WS cockpit channel, and AgentActivity.execution_id (regenerated DTOs). Timeline + page + store tests.
Adds meta/mcp/domains/cockpit.py + handlers/cockpit.py: read tools (get_live_activity, get_flight_recorder_frames, seek_flight_recorder) and admin intervention tools (pause/kill/hint/redirect) that call require_admin_guardrails() and route through the same cockpit/flight-recorder/steering/task services as the REST controller. Registered in the domain + handler aggregators; tool-count plan bumped 216 -> 223.
allow_inf_nan=False on cockpit controller models; build_frames split under the 50-line limit; drop unused FlightRecorder playingRef; add AgentEngine auto-recording integration test proving run() records replayable frames through the real hook (closes the sim-harness validation gap).
test_channels expects CHANNEL_COCKPIT; protocol-compliance fake backend gains flight_recorder_frames; MCP hint/redirect handlers call require_admin_guardrails as their lexically-first call (gate compliance).
RUNTIME_PREFIXES excludes persistence/, so the flight-recorder repos (reached through the persistence backend like every other repo) cannot and should not be manifest-ENFORCED. The four genuine runtime services/builders (CockpitService, FlightRecorderService, build_steering_directive, build_flight_recorder_sink) remain enforced.
Adds cockpit to test_events expected discovery + VALID_SETTINGS_NAMESPACES; introduces _sum_costs helper carrying the currency-aggregation lint-allow marker in both cockpit and flight_recording services.
Persistence: avoid mutating row dict before validation in sqlite/postgres flight_recorder_repo. Service: type _MAX_SEEK_FRAMES as Final[int]. Web: extract shared statusBgClass into @/utils/status-color; add aria-label on AgentRow status dot; tie Hint InputField to the agent via aria-describedby; import FlightRecorderFrame for FrameDetail prop; memoize ordered + timelineFrames; tighten TAB_OPTIONS typing; seed richer MSW defaults; reset mission-control store in afterEach in both web tests.
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 22, 2026

Dependency Review

✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.

Scanned Files

None

@gemini-code-assist
Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces a comprehensive 'Mission Control' cockpit for the SynthOrg runtime. It provides operators with the ability to monitor live agent activity, detect stuck or runaway agents, perform interventions (pause, kill, hint, redirect), and replay completed agent runs turn-by-turn using a new flight recorder system.

Highlights

  • Persistence: Added a FlightRecorderFrame append-only store with SQLite and Postgres support to enable persistent frame storage.
  • Engine: Implemented a pluggable FlightRecorderSink and CockpitService to aggregate live activity and record agent turns.
  • API: Added a new /cockpit Litestar controller for live snapshots, frame seeking, and operator interventions.
  • Web Dashboard: Introduced a new /mission-control route with a live cockpit view and a timeline scrubber for replaying agent runs.
  • MCP: Exposed new cockpit domain tools for live activity monitoring and administrative interventions.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize the Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counterproductive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 22, 2026

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI (base), Organization UI (inherited)

Review profile: ASSERTIVE

Plan: Pro

Run ID: 7651faa8-c214-47cf-b136-b6435f90ebd7

📥 Commits

Reviewing files that changed from the base of the PR and between a6f8b64 and 729febe.

📒 Files selected for processing (6)
  • src/synthorg/engine/flight_recording/service.py
  • src/synthorg/persistence/flight_recorder_protocol.py
  • src/synthorg/persistence/postgres/flight_recorder_repo.py
  • src/synthorg/persistence/sqlite/flight_recorder_repo.py
  • tests/unit/api/fakes.py
  • web/src/stores/mission-control.ts
📜 Recent review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (13)
  • GitHub Check: Build Backend
  • GitHub Check: Build Web Assets (melange)
  • GitHub Check: Lighthouse Dashboard
  • GitHub Check: CodSpeed Python benchmarks
  • GitHub Check: CodSpeed Web benchmarks
  • GitHub Check: Test Integration
  • GitHub Check: Test E2E
  • GitHub Check: Dashboard Test
  • GitHub Check: Test Unit
  • GitHub Check: Test Conformance (SQLite)
  • GitHub Check: Build Preview
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (9)
**/*.{py,ts,tsx,jsx,md}

📄 CodeRabbit inference engine (CLAUDE.md)

No region/currency/locale privileged; use metric units; British English per docs/reference/regional-defaults.md

Files:

  • tests/unit/api/fakes.py
  • src/synthorg/persistence/flight_recorder_protocol.py
  • web/src/stores/mission-control.ts
  • src/synthorg/engine/flight_recording/service.py
  • src/synthorg/persistence/postgres/flight_recorder_repo.py
  • src/synthorg/persistence/sqlite/flight_recorder_repo.py
tests/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

tests/**/*.py: Timeout/slow failures = source-code regression; never edit tests/baselines/unit_timing.json or any scripts/*_baseline.{txt,json} / scripts/_*_baseline.py; both families PreToolUse-blocked; per-invocation bypass requires explicit approval (ALLOW_BASELINE_GROWTH=1 git commit)
Test markers: @pytest.mark.{unit,integration,e2e,slow}; async auto; timeout 30s global; coverage 80% min
xdist -n 8 --dist=loadfile auto-applied via pyproject addopts; Windows unit tests use WindowsSelectorEventLoopPolicy; subprocess tests override back
Test doubles: FakeClock for Clock seam, mock_of[T](**overrides) for typed-boundary substitutions, SimpleNamespace for attribute-bags; bare MagicMock at typed boundary blocked by scripts/check_mock_spec.py
Hypothesis: 10 deterministic CI examples; failures are real bugs (fix + add @example(...)); never skip/xfail flaky tests; fix fundamentally

Files:

  • tests/unit/api/fakes.py

⚙️ CodeRabbit configuration file

Test files do not require Google-style docstrings on classes or functions -- ruff D rules are only enforced on src/. A bare @settings() decorator with no arguments on Hypothesis property tests is a no-op and should not be suggested -- the HYPOTHESIS_PROFILE env var controls example counts via registered profiles, which @given() honors automatically.

Files:

  • tests/unit/api/fakes.py
src/synthorg/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

src/synthorg/**/*.py: Only src/synthorg/persistence/ may import sqlite/psycopg or emit raw SQL; new repository protocols inherit from generic categories in persistence/_generics.py; bespoke methods permitted only under ADR-0001 D7
Configuration Precedence: DB > env > code default via SettingsService/ConfigResolver (Cat-1) or env > code default (Cat-2, read_only_post_init); Cat-3 bootstrap secrets pure env; YAML is ingestion format only, not precedence tier; no os.environ.get outside startup
No hardcoded numeric values; numerics live in settings/definitions/; allowlist only 0/1/-1, HTTP codes, hex masks, powers-of-2, and module-level annotated named constants (NAME: int|float|Final); enforced by scripts/check_no_magic_numbers.py
Comments document WHY only; no reviewer citations, issue back-refs, or migration framing; enforced by check_no_review_origin_in_code.py + check_no_migration_framing.py
No from __future__ import annotations (Python 3.14 has PEP 649); use PEP 758 except: except A, B: no parens unless binding
Type hints on public functions; mypy strict; Google-style docstrings; line length 88; functions <50 lines; files <800 lines
Errors follow <Domain><Condition>Error pattern from DomainError; never inherit Exception/RuntimeError directly; enforced by check_domain_error_hierarchy.py
Pydantic v2 frozen + extra="forbid" on every frozen model project-wide; gate check_frozen_model_extra_forbid.py; @computed_field auto-exempt; per-line # lint-allow: frozen-extra-forbid -- <reason> for extra="allow"/"ignore" boundaries; use @computed_field for derived; use NotBlankStr for identifiers
Args models at every system boundary; parse_typed() for every external dict ingestion; enforced by check_boundary_typed.py
Immutability: use model_copy(update=...) or copy.deepcopy(); deepcopy at system boundaries
Async: use asyncio.TaskGroup for fan-out/fan-in; helpers catch Exception (re-raise MemoryError/`RecursionError...

Files:

  • src/synthorg/persistence/flight_recorder_protocol.py
  • src/synthorg/engine/flight_recording/service.py
  • src/synthorg/persistence/postgres/flight_recorder_repo.py
  • src/synthorg/persistence/sqlite/flight_recorder_repo.py
src/synthorg/persistence/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

src/synthorg/persistence/**/*.py: Repository CRUD: save(entity), get(id), delete(id) -> bool, list_items(...), query(...) returning tuples
Datetime in persistence: use parse_iso_utc / format_iso_utc from persistence._shared (reject naive); use normalize_utc for already-typed

Files:

  • src/synthorg/persistence/flight_recorder_protocol.py
  • src/synthorg/persistence/postgres/flight_recorder_repo.py
  • src/synthorg/persistence/sqlite/flight_recorder_repo.py
src/**/*.py

⚙️ CodeRabbit configuration file

This project uses Python 3.14+ with PEP 758 except syntax: "except A, B:" (comma-separated, no parentheses) is correct and mandatory -- do NOT flag it as a typo or suggest parenthesized form. The "except builtins.MemoryError, RecursionError: raise" pattern is intentional project convention for system-error propagation. When evaluating the 50-line function limit, count only the function body excluding the signature lines, decorators, and docstring. Functions 1-5 lines over due to docstrings or multi-line signatures should not be flagged. Do not suggest extracting single-use helper functions called exactly once -- this reduces readability without improving maintainability.

Files:

  • src/synthorg/persistence/flight_recorder_protocol.py
  • src/synthorg/engine/flight_recording/service.py
  • src/synthorg/persistence/postgres/flight_recorder_repo.py
  • src/synthorg/persistence/sqlite/flight_recorder_repo.py
web/src/**/*.{js,jsx,ts,tsx,mts}

📄 CodeRabbit inference engine (web/CLAUDE.md)

web/src/**/*.{js,jsx,ts,tsx,mts}: Always use createLogger from @/lib/logger; never bare console.warn/console.error/console.debug in application code. Variable name must always be log. Only logger.ts itself may use bare console methods. Use log.debug() (DEV-only, stripped in production), log.warn(), log.error().
Pass dynamic/untrusted values as separate args to logger calls (not interpolated into the message string) so they go through sanitizeArg
Attacker-controlled fields inside structured objects must be wrapped in sanitizeForLog() before embedding in log calls
Error-code constants (MANDATORY): import ErrorCode and ErrorCategory from @/api/types/errors (re-exported from the generated web/src/api/types/error-codes.gen.ts). Discriminate on ErrorCode.<NAME>, never on raw integer literals.
Use @eslint-react/web-api-no-leaked-fetch to detect fetch() in effects without AbortController cleanup

Files:

  • web/src/stores/mission-control.ts
web/src/stores/**/*.ts

📄 CodeRabbit inference engine (web/CLAUDE.md)

web/src/stores/**/*.ts: List reads (fetch*) must set error: string | null on the store instead of toasting
Test teardown (MANDATORY): any new store that schedules timers or attaches event listeners must expose an equivalent cleanup hook and register it in the global afterEach. The global afterEach in web/src/test-setup.tsx already calls useToastStore.getState().dismissAll(), cancelPendingPersist(), and useThemeStore.getState().teardown().

Files:

  • web/src/stores/mission-control.ts
web/src/{api/endpoints,stores}/**/*.ts

📄 CodeRabbit inference engine (web/CLAUDE.md)

Cursor pagination (MANDATORY): list endpoints must use opaque cursor-based paging via PaginationMeta. Stores must keep nextCursor + hasMore in state (not offset arithmetic) and early-return when !hasMore || !nextCursor. Display counts must come from data.length.

Files:

  • web/src/stores/mission-control.ts
web/src/**/*.{ts,tsx,mts}

📄 CodeRabbit inference engine (web/CLAUDE.md)

web/src/**/*.{ts,tsx,mts}: Use @typescript-eslint/no-floating-promises to forbid unawaited promises so async work cannot survive the test that scheduled it and trip the active-handle gate
Use @typescript-eslint/no-misused-promises (with checksVoidReturn: { attributes: false }) to forbid passing async functions where the callsite ignores the returned promise. React 19 async event handlers stay allowed via the attributes: false exemption.

Files:

  • web/src/stores/mission-control.ts
🧠 Learnings (3)
📚 Learning: 2026-05-05T09:04:46.195Z
Learnt from: Aureliolo
Repo: Aureliolo/synthorg PR: 1760
File: scripts/_dual_backend_parity_lib.py:215-216
Timestamp: 2026-05-05T09:04:46.195Z
Learning: This repository targets Python 3.14+ and follows PEP 758. Therefore, reviewer tooling should NOT treat unparenthesized multi-exception `except` clauses written without an `as` clause (e.g., `except MemoryError, RecursionError:`) as syntax errors. Only flag `except`-clause problems when they are genuinely invalid for Python 3.14+.

Applied to files:

  • tests/unit/api/fakes.py
  • src/synthorg/persistence/flight_recorder_protocol.py
  • src/synthorg/engine/flight_recording/service.py
  • src/synthorg/persistence/postgres/flight_recorder_repo.py
  • src/synthorg/persistence/sqlite/flight_recorder_repo.py
📚 Learning: 2026-05-21T22:55:20.496Z
Learnt from: Aureliolo
Repo: Aureliolo/synthorg PR: 2035
File: src/synthorg/meta/toolsmith/models.py:114-114
Timestamp: 2026-05-21T22:55:20.496Z
Learning: In this repo’s “magic number” review standard, the existing gate in `scripts/check_no_magic_numbers.py` intentionally does NOT flag numeric literals used as raw call-site arguments. So, do not flag numeric literals passed as keyword arguments to Pydantic `Field()` (e.g., `Field(ge=0, le=100)` / `Field(ge=1, le=50)`)—this is an established idiom. Only treat numeric literals as “magic numbers” when they occur in the locations the gate checks (module-level assignments and function/method parameter defaults).

Applied to files:

  • tests/unit/api/fakes.py
  • src/synthorg/persistence/flight_recorder_protocol.py
  • src/synthorg/engine/flight_recording/service.py
  • src/synthorg/persistence/postgres/flight_recorder_repo.py
  • src/synthorg/persistence/sqlite/flight_recorder_repo.py
📚 Learning: 2026-05-21T22:55:09.289Z
Learnt from: Aureliolo
Repo: Aureliolo/synthorg PR: 2035
File: src/synthorg/meta/toolsmith/config.py:29-30
Timestamp: 2026-05-21T22:55:09.289Z
Learning: For this repo’s Pydantic configuration idiom, do not treat numeric literals passed directly as arguments to `pydantic.Field(...)` as “magic numbers” during review. This includes call-site usages like `Field(default=0.2, ge=0.0, le=1.0)` (e.g., in config models such as `ToolAuthoringConfig`, `ToolValidationConfig`, `ToolsmithConfig`). Do not request extracting those `Field(...)` numeric arguments into named constants, since the repo’s `scripts/check_no_magic_numbers.py` intentionally excludes call-site `Field(...)` numerics and relies on `Field(...)` as the canonical way to express these constraints/defaults.

Applied to files:

  • src/synthorg/persistence/flight_recorder_protocol.py
  • src/synthorg/engine/flight_recording/service.py
  • src/synthorg/persistence/postgres/flight_recorder_repo.py
  • src/synthorg/persistence/sqlite/flight_recorder_repo.py
🔇 Additional comments (8)
tests/unit/api/fakes.py (1)

591-603: LGTM!

src/synthorg/persistence/flight_recorder_protocol.py (2)

117-125: LGTM!


143-156: LGTM!

web/src/stores/mission-control.ts (2)

96-103: LGTM!

Also applies to: 111-111


129-136: LGTM!

Also applies to: 144-144

src/synthorg/engine/flight_recording/service.py (1)

128-133: LGTM!

src/synthorg/persistence/postgres/flight_recorder_repo.py (1)

171-175: LGTM!

src/synthorg/persistence/sqlite/flight_recorder_repo.py (1)

175-179: LGTM!


Walkthrough

Adds cockpit live snapshot and interventions, integrates a flight recorder capturing agent turns, persists frames in Postgres/SQLite, and provides a replay/seek service. App state and startup wire cockpit/recorder/steering; REST controller and MCP tools expose snapshot, frames, seek, and interventions. Adds observability events and cockpit settings. AgentEngine records frames via a pluggable sink. Web app introduces a Mission Control page (Live and Flight Recorder tabs), a Timeline component, Zustand store and hook, routes/nav, and MSW mocks. Extensive unit/e2e tests cover repositories, services, engine recording, controller, steering, MCP surface, and UI.

Suggested labels

scope:web

@Aureliolo Aureliolo temporarily deployed to cloudflare-preview May 22, 2026 18:19 — with GitHub Actions Inactive
@codspeed-hq
Copy link
Copy Markdown

codspeed-hq Bot commented May 22, 2026

Merging this PR will not alter performance

✅ 54 untouched benchmarks


Comparing feat/1981-mission-control-flight-recorder (729febe) with main (f81a5ac)

Open in CodSpeed

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces the Mission Control Cockpit, providing live agent activity monitoring, flight-recorder replay, and operator intervention capabilities. The implementation includes backend services, persistence for Postgres and SQLite, REST and MCP interfaces, and a React-based frontend. Review feedback highlights performance concerns regarding N+1 queries and inefficient individual inserts, as well as logic errors in turn-to-message correlation for resumed tasks and incomplete prefix reconstruction in the flight-recorder seek functionality.

Comment thread src/synthorg/engine/cockpit/service.py Outdated
Comment on lines +129 to +136
for status in _ACTIVE_STATUSES:
tasks, _ = await self._task_engine.list_tasks(status=status)
activities.extend(
[
await self._build_activity(task, stuck_cutoff, runaway_pct)
for task in tasks
]
)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

This loop introduces an N+1 query pattern because _build_activity performs a repository query for every active task. With many active tasks, this will significantly degrade the performance of the mission control dashboard. Additionally, the cost calculation in _build_activity is incorrect for tasks with more than 1000 turns: since the frame query is limited to 1000 records and the repository returns them newest-first, the resulting sum will only reflect the cost of the most recent 1000 turns. Consider adding an optimized aggregation method to the repository (e.g., get_stats_by_task) that returns the total cost, turn count, and latest timestamp in a single query using SQL SUM and MAX functions.

Comment on lines +164 to +168
response=(
assistant_messages[index].content
if index < len(assistant_messages)
else None
),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Correlating turns with assistant messages using the loop index is incorrect for resumed tasks. execution_result.turns only contains turns from the current run, while execution_result.context.conversation contains the full history. If a task is resumed at turn 5, index 0 will incorrectly pick the first assistant message in the history instead of the 5th. Using turn.turn_number - 1 as the index into assistant_messages would correctly target the message corresponding to the turn, assuming a 1:1 mapping.

Suggested change
response=(
assistant_messages[index].content
if index < len(assistant_messages)
else None
),
response=(
assistant_messages[turn.turn_number - 1].content
if (turn.turn_number - 1) < len(assistant_messages)
else None
),

Comment on lines +88 to +94
frames = await self._repository.query(
FlightRecorderFrameFilterSpec(
execution_id=NotBlankStr(execution_id),
turn_index_min=1,
turn_index_max=turn_index,
),
limit=_MAX_SEEK_FRAMES,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

There is a logic error in the seek method when an execution's turn count exceeds _MAX_SEEK_FRAMES. Because the repository query method returns frames newest-first (descending turn index), the limit will cause the query to return the latest 1000 frames within the requested range (turns 1 to turn_index). For a run at turn 1500, this returns turns 501 to 1500. The resulting ReplaySeekView will be missing the beginning of the run (turns 1 to 500), which contradicts the docstring and the expected behavior of a scrubber reconstruction. To fix this, the repository protocol should be extended to support sort order, or the service should handle prefix reconstruction more robustly.

Comment on lines +70 to +82
recorded = 0
for frame in frames:
try:
await self._repository.append(frame)
recorded += 1
except Exception as exc:
logger.warning(
FLIGHT_RECORDER_RECORD_FAILED,
execution_id=frame.execution_id,
turn_index=frame.turn_index,
error_type=type(exc).__name__,
error=safe_error_description(exc),
)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The record_frames method is inefficient as it performs individual inserts in a loop. In both the Postgres and SQLite repository implementations, each call to append opens a new connection and transaction. For agent runs with many turns, this adds significant overhead to the finalization phase. It is recommended to add a batch insertion method (e.g., append_many) to the FlightRecorderFrameRepository protocol and use it here to persist all frames in a single transaction.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 19

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/synthorg/api/controllers/cockpit.py`:
- Around line 110-112: Add input validation at the controller boundary in
cockpit.py for the parameters limit, offset, and turn_index: ensure limit is a
positive integer and capped (use DEFAULT_PAGE_SIZE as the max), offset is >= 0,
and turn_index (when present) is >= 0 (and within any domain-specific max if
applicable). If a value is out of bounds, return a 4xx immediately (e.g., raise
fastapi.HTTPException(status_code=400) or return an ApiResponse error) instead
of passing invalid values into repository queries; add these guards in the
controller function that returns ApiResponse[FlightRecorderFramesResponse]
(validate the parameters named limit, offset, turn_index) and apply the same
checks to the similar controller block around lines 127-133.
- Around line 222-227: The steering text is operator-provided and must be
wrapped as untrusted content before being passed to SteeringDirective.steer;
import and call wrap_untrusted from engine.prompt_safety on data.text and pass
the wrapped value in details (e.g., details={"text": wrap_untrusted(data.text)})
when invoking app_state.steering_directive.steer to satisfy SEC-1 requirements.

In `@src/synthorg/api/state.py`:
- Around line 1592-1600: The log always emits transition="attached" in
set_cockpit_services even when no-op or replacement occurs; update
set_cockpit_services to compute the correct transition by comparing existing
self._cockpit_service (and related self._flight_recorder_service /
self._steering_directive) to the incoming
cockpit_service/flight_recorder_service/steering_directive: use "noop" when
nothing changed, "attached" when there was no prior service, and "replaced" when
an existing service is being swapped, then pass that transition value into the
logger.info(API_APP_STARTUP, service="cockpit_services", transition=transition)
call.

In `@src/synthorg/engine/agent_engine.py`:
- Around line 681-689: Wrap the frame construction and recording block in a
defensive try/except inside the _execute method so that build_frames(...) and
await self._flight_recorder_sink.record_frames(frames) cannot turn a successful
run into a failure; specifically, call build_frames and record_frames inside a
try, re-raise MemoryError and RecursionError unchanged, and for any other
Exception catch it, log the exception (using the existing logger in this class)
and return/exit the method early to preserve the existing fail-soft post-run
behavior.

In `@src/synthorg/engine/cockpit/service.py`:
- Around line 129-136: The loop is awaiting _build_activity sequentially for
each task, causing latency; refactor to fan-out/fan-in using asyncio.TaskGroup:
for each status from _ACTIVE_STATUSES call
self._task_engine.list_tasks(status=status) as before but then create an
asyncio.TaskGroup, spawn a task for each task that awaits
self._build_activity(task, stuck_cutoff, runaway_pct) (referencing
_build_activity and _task_engine) and collect results (gather successful
activities), then extend activities with the completed results; ensure you
handle task exceptions per the project's policy (cancel/propagate or log) inside
the TaskGroup and preserve original ordering if required.

In `@src/synthorg/engine/flight_recording/service.py`:
- Around line 88-114: The seek() implementation in service.py quietly truncates
results when turn_index > _MAX_SEEK_FRAMES by limiting the repository query to
_MAX_SEEK_FRAMES and still returning a normal ReplaySeekView, so change seek()
to detect when the requested turn_index exceeds the cap (compare turn_index to
_MAX_SEEK_FRAMES before/after the query) and fail fast or mark truncation:
either raise a clear exception (e.g., ValueError/CustomException) indicating the
seek limit was exceeded, or add a truncation flag on the ReplaySeekView (e.g.,
truncated=True) and populate it so callers can detect partial reconstruction;
update all usages of ReplaySeekView accordingly and ensure logging
(FLIGHT_RECORDER_SEEK) records the truncation or the error.

In `@src/synthorg/engine/flight_recording/sink.py`:
- Around line 75-82: In PersistenceFlightRecorderSink.record_frames,
special-case and re-raise system errors before the broad except Exception block:
add an early except (MemoryError, RecursionError) as sys_exc: raise sys_exc to
ensure these are not swallowed, then proceed with the existing except Exception
as exc: logger.warning(...) handling; reference the method name record_frames
and the existing logger.warning/FLIGHT_RECORDER_RECORD_FAILED call to locate
where to insert the re-raise.

In `@src/synthorg/engine/intervention/steering.py`:
- Around line 106-121: The operator-provided text is being stored directly into
the Interrupt.question (and similar fields) without the SEC-1 wrapper; import
and call wrap_untrusted from engine.prompt_safety on the raw text before
creating the Interrupt in steer/steering.py (the block that constructs Interrupt
with id, type, session_id, agent_id, question, context_snippet). Replace usages
of the raw text (e.g., the value passed to question and any other untrusted
fields like context_snippet) with the wrapped result (then feed that wrapped
string into NotBlankStr) so all untrusted content is SEC-1 wrapped prior to
queueing.

In `@src/synthorg/persistence/flight_recorder_protocol.py`:
- Around line 139-140: Update purge_before to require a timezone-aware datetime
and normalize it to UTC before using: import normalize_utc (and/or parse_iso_utc
if you decide to accept strings) from persistence._shared, change the
contract/docstring of purge_before to state the threshold must be timezone-aware
(ISO UTC), and call normalize_utc(threshold) at the start of the method (or
parse_iso_utc for string inputs) so naive datetimes are rejected/normalized
consistently before any backend purge logic; keep the return type int and raise
a clear ValueError if a naive datetime is passed.

In
`@src/synthorg/persistence/sqlite/revisions/20260522000002_flight_recorder.sql`:
- Around line 20-21: The index idx_frf_execution_turn on flight_recorder_frames
is non-unique, allowing duplicate (execution_id, turn_index) rows; change this
index to a UNIQUE index on columns execution_id and turn_index in the migration
that creates idx_frf_execution_turn (so seek/replay is deterministic) and mirror
the same UNIQUE constraint/update in schema.sql so drift checks remain green.

In `@tests/unit/engine/intervention/test_steering.py`:
- Around line 36-48: The test test_redirect_also_queues_interrupt currently only
asserts outcome.applied and outcome.artifact_id but doesn't verify persistence;
update the test to read from the InterruptStore (the same InterruptStore
instance created at the top) after calling SafeDefaultSteeringDirective.steer
and assert that a redirect interrupt exists for execution_id "exec-1" (e.g.,
verify store contains an interrupt with kind InterventionKind.REDIRECT and
matching execution_id/agent_id/details), ensuring the directive actually wrote
the interrupt to the store.

In `@tests/unit/persistence/test_protocol.py`:
- Around line 438-453: TestProtocolCompliance is missing an assertion that the
new flight_recorder_frames accessor conforms to the flight-recorder repository
protocol: add a protocol-conformance check similar to the other repository
accessors by creating or using _FakeFlightRecorderRepository and asserting that
the subject.flight_recorder_frames implements the same protocol used elsewhere
in TestProtocolCompliance (mirror assertions for other accessors so drift is
detected); reference _FakeFlightRecorderRepository, flight_recorder_frames, and
TestProtocolCompliance to locate and add this check.

In `@web/src/api/endpoints/cockpit.ts`:
- Around line 20-27: getFlightRecorderFrames currently accepts offset-based
params ({ limit, offset }) which must be replaced with opaque cursor pagination
and return/consume PaginationMeta; update the function signature
getFlightRecorderFrames(executionId: string, params?: { cursor?: string; limit?:
number }) and ensure the API call sends { params } with cursor and limit instead
of offset, and that the returned FlightRecorderFramesResponse (and any
ApiResponse wrapper handling) uses PaginationMeta for paging metadata so the
client/store flow gets the opaque cursor and next/previous info consistently.

In `@web/src/components/ui/timeline.tsx`:
- Around line 38-52: The keyboard handler onKeyDown can call onSeek with indexes
that may be out-of-range if currentIndex is stale after frames shrink; update
every key branch in onKeyDown (ArrowRight, ArrowLeft, Home, End) to clamp the
computed target into the valid range [0, lastIndex] before calling onSeek (e.g.,
compute target then set target = Math.max(0, Math.min(lastIndex, target))). This
change should be applied inside the onKeyDown function to ensure all key paths
use the same clamping logic and avoid invalid seeks.

In `@web/src/hooks/useMissionControlData.ts`:
- Around line 58-66: The WS handlers in the bindings created inside useMemo call
fetchSnapshot() on every event which can cause overlapping requests; change the
handler (the object built for COCKPIT_CHANNELS) to coalesce bursts by tracking a
shared timer/ref (e.g., pendingFetchTimerRef or lastWsUpdateAtRef) and
scheduling a single delayed call to
useMissionControlStore.getState().fetchSnapshot() within a short debounce window
(e.g., 50–200ms), clearing any previous timer when new events arrive so only one
fetch is triggered per burst; keep the lastWsUpdateAtRef update but ensure
fetchSnapshot is invoked from the debounced/queued function rather than directly
in the handler.

In `@web/src/router/index.tsx`:
- Line 170: Replace the hardcoded route string in the routes registration with
the route constant to prevent drift: in the routes array entry that currently
uses path: 'mission-control' (component: MissionControlPage), change it to use
path: ROUTES.MISSION_CONTROL so the route registration derives from the shared
ROUTES constant used elsewhere.

In `@web/src/stores/mission-control.ts`:
- Around line 78-85: The fetchFrames handler leaves previous frames in state if
loading a new execution fails; update fetchFrames so when initiating a load you
also clear stale frames (e.g., set frames to null or an empty array) along with
framesLoading, framesError, and framesExecutionId, and ensure on error you do
not retain old frames (keep frames cleared) while on success you set frames =
response.frames; refer to the fetchFrames function and the state keys frames,
framesLoading, framesError, and framesExecutionId.

In `@web/src/utils/constants.ts`:
- Line 188: The new display label "cockpit" was added but the NAMESPACE_ORDER
constant still omits 'cockpit', preventing it from being surfaced; update the
NAMESPACE_ORDER array to include 'cockpit' in the desired ordering so it appears
in Settings (locate the NAMESPACE_ORDER symbol in web/src/utils/constants.ts and
insert 'cockpit' at the appropriate position consistent with other namespace
names and the file's ordering contract).

In `@web/src/utils/status-color.ts`:
- Around line 8-23: The STATUS_BG map and statusBgClass currently use plain
string types allowing typos; replace them to use the generated TaskStatus union:
change STATUS_BG's type to Partial<Record<TaskStatus, string>> (or
Record<TaskStatus, string> if you can authoritatively cover every status) and
change statusBgClass to accept status: TaskStatus (i.e., export function
statusBgClass(status: TaskStatus): string). Keep the fallback lookup
(STATUS_BG[status] ?? 'bg-text-secondary') unchanged; import or reference the
generated TaskStatus type where STATUS_BG and statusBgClass are declared.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI (base), Organization UI (inherited)

Review profile: ASSERTIVE

Plan: Pro

Run ID: 82a8a440-145f-4c20-a08b-aecb3d30f9cc

📥 Commits

Reviewing files that changed from the base of the PR and between f81a5ac and d07e9a6.

📒 Files selected for processing (77)
  • scripts/_ghost_wiring_manifest.txt
  • src/synthorg/api/app.py
  • src/synthorg/api/channels.py
  • src/synthorg/api/controllers/__init__.py
  • src/synthorg/api/controllers/cockpit.py
  • src/synthorg/api/state.py
  • src/synthorg/core/enums.py
  • src/synthorg/engine/agent_engine.py
  • src/synthorg/engine/cockpit/__init__.py
  • src/synthorg/engine/cockpit/service.py
  • src/synthorg/engine/flight_recording/__init__.py
  • src/synthorg/engine/flight_recording/service.py
  • src/synthorg/engine/flight_recording/sink.py
  • src/synthorg/engine/intervention/__init__.py
  • src/synthorg/engine/intervention/steering.py
  • src/synthorg/meta/mcp/domains/__init__.py
  • src/synthorg/meta/mcp/domains/cockpit.py
  • src/synthorg/meta/mcp/handlers/__init__.py
  • src/synthorg/meta/mcp/handlers/cockpit.py
  • src/synthorg/observability/events/cockpit.py
  • src/synthorg/observability/events/persistence.py
  • src/synthorg/observability/prometheus_labels.py
  • src/synthorg/persistence/flight_recorder_protocol.py
  • src/synthorg/persistence/postgres/backend.py
  • src/synthorg/persistence/postgres/flight_recorder_repo.py
  • src/synthorg/persistence/postgres/revisions/20260522000002_flight_recorder.sql
  • src/synthorg/persistence/postgres/schema.sql
  • src/synthorg/persistence/protocol.py
  • src/synthorg/persistence/sqlite/__init__.py
  • src/synthorg/persistence/sqlite/_backend_accessors.py
  • src/synthorg/persistence/sqlite/backend.py
  • src/synthorg/persistence/sqlite/flight_recorder_repo.py
  • src/synthorg/persistence/sqlite/revisions/20260522000002_flight_recorder.sql
  • src/synthorg/persistence/sqlite/schema.sql
  • src/synthorg/settings/definitions/__init__.py
  • src/synthorg/settings/definitions/cockpit.py
  • src/synthorg/settings/enums.py
  • src/synthorg/workers/runtime_builder.py
  • tests/conformance/persistence/test_flight_recorder_repository.py
  • tests/e2e/test_cockpit_mission_control_e2e.py
  • tests/unit/api/controllers/test_cockpit.py
  • tests/unit/api/fakes.py
  • tests/unit/api/fakes_backend.py
  • tests/unit/api/test_channels.py
  • tests/unit/engine/cockpit/test_cockpit_service.py
  • tests/unit/engine/flight_recording/test_engine_recording.py
  • tests/unit/engine/flight_recording/test_flight_recorder_service.py
  • tests/unit/engine/flight_recording/test_sink.py
  • tests/unit/engine/intervention/test_steering.py
  • tests/unit/meta/mcp/test_all_handlers_wired.py
  • tests/unit/observability/audit_chain/test_audit_chain.py
  • tests/unit/observability/test_events.py
  • tests/unit/persistence/test_protocol.py
  • web/src/__tests__/components/ui/timeline.test.tsx
  • web/src/__tests__/pages/MissionControlPage.test.tsx
  • web/src/__tests__/stores/mission-control.test.ts
  • web/src/api/endpoints/cockpit.ts
  • web/src/api/types/dtos.gen.ts
  • web/src/api/types/enum-values.gen.ts
  • web/src/api/types/openapi.gen.ts
  • web/src/api/types/websocket.ts
  • web/src/components/layout/Sidebar.tsx
  • web/src/components/ui/timeline.stories.tsx
  • web/src/components/ui/timeline.tsx
  • web/src/hooks/useMissionControlData.ts
  • web/src/mocks/handlers/cockpit.ts
  • web/src/mocks/handlers/index.ts
  • web/src/pages/MissionControlPage.tsx
  • web/src/pages/mission-control/FlightRecorder.tsx
  • web/src/pages/mission-control/LiveCockpit.tsx
  • web/src/pages/settings/utils.ts
  • web/src/router/index.tsx
  • web/src/router/route-titles.ts
  • web/src/router/routes.ts
  • web/src/stores/mission-control.ts
  • web/src/utils/constants.ts
  • web/src/utils/status-color.ts
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (13)
  • GitHub Check: Deploy Preview
  • GitHub Check: Build Backend
  • GitHub Check: Build Web Assets (melange)
  • GitHub Check: CodSpeed Web benchmarks
  • GitHub Check: CodSpeed Python benchmarks
  • GitHub Check: Test Unit
  • GitHub Check: Dashboard Test
  • GitHub Check: Test Integration
  • GitHub Check: Test Conformance (SQLite)
  • GitHub Check: Test E2E
  • GitHub Check: Lighthouse Dashboard
  • GitHub Check: Analyze (python)
  • GitHub Check: Analyze (javascript-typescript)
🧰 Additional context used
📓 Path-based instructions (21)
web/src/**/*.{js,jsx,ts,tsx,mts}

📄 CodeRabbit inference engine (web/CLAUDE.md)

web/src/**/*.{js,jsx,ts,tsx,mts}: Always use createLogger from @/lib/logger; never bare console.warn/console.error/console.debug in application code. Variable name must always be log. Only logger.ts itself may use bare console methods. Use log.debug() (DEV-only, stripped in production), log.warn(), log.error().
Pass dynamic/untrusted values as separate args to logger calls (not interpolated into the message string) so they go through sanitizeArg
Attacker-controlled fields inside structured objects must be wrapped in sanitizeForLog() before embedding in log calls
Error-code constants (MANDATORY): import ErrorCode and ErrorCategory from @/api/types/errors (re-exported from the generated web/src/api/types/error-codes.gen.ts). Discriminate on ErrorCode.<NAME>, never on raw integer literals.
Use @eslint-react/web-api-no-leaked-fetch to detect fetch() in effects without AbortController cleanup

Files:

  • web/src/utils/status-color.ts
  • web/src/utils/constants.ts
  • web/src/router/index.tsx
  • web/src/__tests__/stores/mission-control.test.ts
  • web/src/api/endpoints/cockpit.ts
  • web/src/__tests__/components/ui/timeline.test.tsx
  • web/src/pages/MissionControlPage.tsx
  • web/src/components/ui/timeline.tsx
  • web/src/router/route-titles.ts
  • web/src/api/types/enum-values.gen.ts
  • web/src/__tests__/pages/MissionControlPage.test.tsx
  • web/src/components/ui/timeline.stories.tsx
  • web/src/api/types/websocket.ts
  • web/src/pages/settings/utils.ts
  • web/src/components/layout/Sidebar.tsx
  • web/src/router/routes.ts
  • web/src/mocks/handlers/index.ts
  • web/src/mocks/handlers/cockpit.ts
  • web/src/hooks/useMissionControlData.ts
  • web/src/pages/mission-control/LiveCockpit.tsx
  • web/src/pages/mission-control/FlightRecorder.tsx
  • web/src/stores/mission-control.ts
  • web/src/api/types/dtos.gen.ts
  • web/src/api/types/openapi.gen.ts
web/src/{components,utils}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (web/CLAUDE.md)

NEVER write getXIcon(value): LucideIcon factories called inside JSX bodies. Export a <XIcon value={...} /> wrapper that does the lookup via createElement inside the wrapper body. Wrapper components live in their own file, not alongside utility exports.

Files:

  • web/src/utils/status-color.ts
  • web/src/utils/constants.ts
  • web/src/components/ui/timeline.tsx
  • web/src/components/ui/timeline.stories.tsx
  • web/src/components/layout/Sidebar.tsx
web/src/**/*.{ts,tsx,mts}

📄 CodeRabbit inference engine (web/CLAUDE.md)

web/src/**/*.{ts,tsx,mts}: Use @typescript-eslint/no-floating-promises to forbid unawaited promises so async work cannot survive the test that scheduled it and trip the active-handle gate
Use @typescript-eslint/no-misused-promises (with checksVoidReturn: { attributes: false }) to forbid passing async functions where the callsite ignores the returned promise. React 19 async event handlers stay allowed via the attributes: false exemption.

Files:

  • web/src/utils/status-color.ts
  • web/src/utils/constants.ts
  • web/src/router/index.tsx
  • web/src/__tests__/stores/mission-control.test.ts
  • web/src/api/endpoints/cockpit.ts
  • web/src/__tests__/components/ui/timeline.test.tsx
  • web/src/pages/MissionControlPage.tsx
  • web/src/components/ui/timeline.tsx
  • web/src/router/route-titles.ts
  • web/src/api/types/enum-values.gen.ts
  • web/src/__tests__/pages/MissionControlPage.test.tsx
  • web/src/components/ui/timeline.stories.tsx
  • web/src/api/types/websocket.ts
  • web/src/pages/settings/utils.ts
  • web/src/components/layout/Sidebar.tsx
  • web/src/router/routes.ts
  • web/src/mocks/handlers/index.ts
  • web/src/mocks/handlers/cockpit.ts
  • web/src/hooks/useMissionControlData.ts
  • web/src/pages/mission-control/LiveCockpit.tsx
  • web/src/pages/mission-control/FlightRecorder.tsx
  • web/src/stores/mission-control.ts
  • web/src/api/types/dtos.gen.ts
  • web/src/api/types/openapi.gen.ts
**/*.{py,ts,tsx,jsx,md}

📄 CodeRabbit inference engine (CLAUDE.md)

No region/currency/locale privileged; use metric units; British English per docs/reference/regional-defaults.md

Files:

  • web/src/utils/status-color.ts
  • src/synthorg/engine/intervention/__init__.py
  • tests/unit/engine/flight_recording/test_engine_recording.py
  • web/src/utils/constants.ts
  • web/src/router/index.tsx
  • web/src/__tests__/stores/mission-control.test.ts
  • tests/unit/observability/test_events.py
  • web/src/api/endpoints/cockpit.ts
  • web/src/__tests__/components/ui/timeline.test.tsx
  • src/synthorg/engine/flight_recording/__init__.py
  • web/src/pages/MissionControlPage.tsx
  • src/synthorg/engine/intervention/steering.py
  • web/src/components/ui/timeline.tsx
  • src/synthorg/persistence/sqlite/__init__.py
  • web/src/router/route-titles.ts
  • src/synthorg/persistence/sqlite/backend.py
  • web/src/api/types/enum-values.gen.ts
  • web/src/__tests__/pages/MissionControlPage.test.tsx
  • web/src/components/ui/timeline.stories.tsx
  • web/src/api/types/websocket.ts
  • src/synthorg/observability/prometheus_labels.py
  • src/synthorg/engine/cockpit/__init__.py
  • src/synthorg/api/controllers/__init__.py
  • web/src/pages/settings/utils.ts
  • src/synthorg/api/channels.py
  • web/src/components/layout/Sidebar.tsx
  • web/src/router/routes.ts
  • tests/unit/observability/audit_chain/test_audit_chain.py
  • src/synthorg/settings/enums.py
  • web/src/mocks/handlers/index.ts
  • src/synthorg/meta/mcp/domains/__init__.py
  • src/synthorg/api/app.py
  • tests/unit/api/test_channels.py
  • web/src/mocks/handlers/cockpit.ts
  • web/src/hooks/useMissionControlData.ts
  • src/synthorg/observability/events/persistence.py
  • src/synthorg/core/enums.py
  • src/synthorg/meta/mcp/handlers/__init__.py
  • src/synthorg/meta/mcp/domains/cockpit.py
  • tests/unit/persistence/test_protocol.py
  • tests/unit/meta/mcp/test_all_handlers_wired.py
  • tests/unit/engine/intervention/test_steering.py
  • web/src/pages/mission-control/LiveCockpit.tsx
  • src/synthorg/settings/definitions/__init__.py
  • tests/e2e/test_cockpit_mission_control_e2e.py
  • src/synthorg/observability/events/cockpit.py
  • tests/conformance/persistence/test_flight_recorder_repository.py
  • src/synthorg/engine/flight_recording/service.py
  • src/synthorg/api/state.py
  • src/synthorg/persistence/postgres/backend.py
  • src/synthorg/persistence/sqlite/flight_recorder_repo.py
  • src/synthorg/engine/flight_recording/sink.py
  • tests/unit/api/controllers/test_cockpit.py
  • src/synthorg/persistence/protocol.py
  • src/synthorg/engine/cockpit/service.py
  • src/synthorg/engine/agent_engine.py
  • tests/unit/engine/cockpit/test_cockpit_service.py
  • tests/unit/api/fakes_backend.py
  • src/synthorg/persistence/sqlite/_backend_accessors.py
  • src/synthorg/workers/runtime_builder.py
  • src/synthorg/persistence/flight_recorder_protocol.py
  • src/synthorg/settings/definitions/cockpit.py
  • tests/unit/api/fakes.py
  • tests/unit/engine/flight_recording/test_sink.py
  • src/synthorg/persistence/postgres/flight_recorder_repo.py
  • web/src/pages/mission-control/FlightRecorder.tsx
  • tests/unit/engine/flight_recording/test_flight_recorder_service.py
  • web/src/stores/mission-control.ts
  • src/synthorg/api/controllers/cockpit.py
  • src/synthorg/meta/mcp/handlers/cockpit.py
  • web/src/api/types/dtos.gen.ts
  • web/src/api/types/openapi.gen.ts
src/synthorg/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

src/synthorg/**/*.py: Only src/synthorg/persistence/ may import sqlite/psycopg or emit raw SQL; new repository protocols inherit from generic categories in persistence/_generics.py; bespoke methods permitted only under ADR-0001 D7
Configuration Precedence: DB > env > code default via SettingsService/ConfigResolver (Cat-1) or env > code default (Cat-2, read_only_post_init); Cat-3 bootstrap secrets pure env; YAML is ingestion format only, not precedence tier; no os.environ.get outside startup
No hardcoded numeric values; numerics live in settings/definitions/; allowlist only 0/1/-1, HTTP codes, hex masks, powers-of-2, and module-level annotated named constants (NAME: int|float|Final); enforced by scripts/check_no_magic_numbers.py
Comments document WHY only; no reviewer citations, issue back-refs, or migration framing; enforced by check_no_review_origin_in_code.py + check_no_migration_framing.py
No from __future__ import annotations (Python 3.14 has PEP 649); use PEP 758 except: except A, B: no parens unless binding
Type hints on public functions; mypy strict; Google-style docstrings; line length 88; functions <50 lines; files <800 lines
Errors follow <Domain><Condition>Error pattern from DomainError; never inherit Exception/RuntimeError directly; enforced by check_domain_error_hierarchy.py
Pydantic v2 frozen + extra="forbid" on every frozen model project-wide; gate check_frozen_model_extra_forbid.py; @computed_field auto-exempt; per-line # lint-allow: frozen-extra-forbid -- <reason> for extra="allow"/"ignore" boundaries; use @computed_field for derived; use NotBlankStr for identifiers
Args models at every system boundary; parse_typed() for every external dict ingestion; enforced by check_boundary_typed.py
Immutability: use model_copy(update=...) or copy.deepcopy(); deepcopy at system boundaries
Async: use asyncio.TaskGroup for fan-out/fan-in; helpers catch Exception (re-raise MemoryError/`RecursionError...

Files:

  • src/synthorg/engine/intervention/__init__.py
  • src/synthorg/engine/flight_recording/__init__.py
  • src/synthorg/engine/intervention/steering.py
  • src/synthorg/persistence/sqlite/__init__.py
  • src/synthorg/persistence/sqlite/backend.py
  • src/synthorg/observability/prometheus_labels.py
  • src/synthorg/engine/cockpit/__init__.py
  • src/synthorg/api/controllers/__init__.py
  • src/synthorg/api/channels.py
  • src/synthorg/settings/enums.py
  • src/synthorg/meta/mcp/domains/__init__.py
  • src/synthorg/api/app.py
  • src/synthorg/observability/events/persistence.py
  • src/synthorg/core/enums.py
  • src/synthorg/meta/mcp/handlers/__init__.py
  • src/synthorg/meta/mcp/domains/cockpit.py
  • src/synthorg/settings/definitions/__init__.py
  • src/synthorg/observability/events/cockpit.py
  • src/synthorg/engine/flight_recording/service.py
  • src/synthorg/api/state.py
  • src/synthorg/persistence/postgres/backend.py
  • src/synthorg/persistence/sqlite/flight_recorder_repo.py
  • src/synthorg/engine/flight_recording/sink.py
  • src/synthorg/persistence/protocol.py
  • src/synthorg/engine/cockpit/service.py
  • src/synthorg/engine/agent_engine.py
  • src/synthorg/persistence/sqlite/_backend_accessors.py
  • src/synthorg/workers/runtime_builder.py
  • src/synthorg/persistence/flight_recorder_protocol.py
  • src/synthorg/settings/definitions/cockpit.py
  • src/synthorg/persistence/postgres/flight_recorder_repo.py
  • src/synthorg/api/controllers/cockpit.py
  • src/synthorg/meta/mcp/handlers/cockpit.py
src/**/*.py

⚙️ CodeRabbit configuration file

This project uses Python 3.14+ with PEP 758 except syntax: "except A, B:" (comma-separated, no parentheses) is correct and mandatory -- do NOT flag it as a typo or suggest parenthesized form. The "except builtins.MemoryError, RecursionError: raise" pattern is intentional project convention for system-error propagation. When evaluating the 50-line function limit, count only the function body excluding the signature lines, decorators, and docstring. Functions 1-5 lines over due to docstrings or multi-line signatures should not be flagged. Do not suggest extracting single-use helper functions called exactly once -- this reduces readability without improving maintainability.

Files:

  • src/synthorg/engine/intervention/__init__.py
  • src/synthorg/engine/flight_recording/__init__.py
  • src/synthorg/engine/intervention/steering.py
  • src/synthorg/persistence/sqlite/__init__.py
  • src/synthorg/persistence/sqlite/backend.py
  • src/synthorg/observability/prometheus_labels.py
  • src/synthorg/engine/cockpit/__init__.py
  • src/synthorg/api/controllers/__init__.py
  • src/synthorg/api/channels.py
  • src/synthorg/settings/enums.py
  • src/synthorg/meta/mcp/domains/__init__.py
  • src/synthorg/api/app.py
  • src/synthorg/observability/events/persistence.py
  • src/synthorg/core/enums.py
  • src/synthorg/meta/mcp/handlers/__init__.py
  • src/synthorg/meta/mcp/domains/cockpit.py
  • src/synthorg/settings/definitions/__init__.py
  • src/synthorg/observability/events/cockpit.py
  • src/synthorg/engine/flight_recording/service.py
  • src/synthorg/api/state.py
  • src/synthorg/persistence/postgres/backend.py
  • src/synthorg/persistence/sqlite/flight_recorder_repo.py
  • src/synthorg/engine/flight_recording/sink.py
  • src/synthorg/persistence/protocol.py
  • src/synthorg/engine/cockpit/service.py
  • src/synthorg/engine/agent_engine.py
  • src/synthorg/persistence/sqlite/_backend_accessors.py
  • src/synthorg/workers/runtime_builder.py
  • src/synthorg/persistence/flight_recorder_protocol.py
  • src/synthorg/settings/definitions/cockpit.py
  • src/synthorg/persistence/postgres/flight_recorder_repo.py
  • src/synthorg/api/controllers/cockpit.py
  • src/synthorg/meta/mcp/handlers/cockpit.py
tests/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

tests/**/*.py: Timeout/slow failures = source-code regression; never edit tests/baselines/unit_timing.json or any scripts/*_baseline.{txt,json} / scripts/_*_baseline.py; both families PreToolUse-blocked; per-invocation bypass requires explicit approval (ALLOW_BASELINE_GROWTH=1 git commit)
Test markers: @pytest.mark.{unit,integration,e2e,slow}; async auto; timeout 30s global; coverage 80% min
xdist -n 8 --dist=loadfile auto-applied via pyproject addopts; Windows unit tests use WindowsSelectorEventLoopPolicy; subprocess tests override back
Test doubles: FakeClock for Clock seam, mock_of[T](**overrides) for typed-boundary substitutions, SimpleNamespace for attribute-bags; bare MagicMock at typed boundary blocked by scripts/check_mock_spec.py
Hypothesis: 10 deterministic CI examples; failures are real bugs (fix + add @example(...)); never skip/xfail flaky tests; fix fundamentally

Files:

  • tests/unit/engine/flight_recording/test_engine_recording.py
  • tests/unit/observability/test_events.py
  • tests/unit/observability/audit_chain/test_audit_chain.py
  • tests/unit/api/test_channels.py
  • tests/unit/persistence/test_protocol.py
  • tests/unit/meta/mcp/test_all_handlers_wired.py
  • tests/unit/engine/intervention/test_steering.py
  • tests/e2e/test_cockpit_mission_control_e2e.py
  • tests/conformance/persistence/test_flight_recorder_repository.py
  • tests/unit/api/controllers/test_cockpit.py
  • tests/unit/engine/cockpit/test_cockpit_service.py
  • tests/unit/api/fakes_backend.py
  • tests/unit/api/fakes.py
  • tests/unit/engine/flight_recording/test_sink.py
  • tests/unit/engine/flight_recording/test_flight_recorder_service.py

⚙️ CodeRabbit configuration file

Test files do not require Google-style docstrings on classes or functions -- ruff D rules are only enforced on src/. A bare @settings() decorator with no arguments on Hypothesis property tests is a no-op and should not be suggested -- the HYPOTHESIS_PROFILE env var controls example counts via registered profiles, which @given() honors automatically.

Files:

  • tests/unit/engine/flight_recording/test_engine_recording.py
  • tests/unit/observability/test_events.py
  • tests/unit/observability/audit_chain/test_audit_chain.py
  • tests/unit/api/test_channels.py
  • tests/unit/persistence/test_protocol.py
  • tests/unit/meta/mcp/test_all_handlers_wired.py
  • tests/unit/engine/intervention/test_steering.py
  • tests/e2e/test_cockpit_mission_control_e2e.py
  • tests/conformance/persistence/test_flight_recorder_repository.py
  • tests/unit/api/controllers/test_cockpit.py
  • tests/unit/engine/cockpit/test_cockpit_service.py
  • tests/unit/api/fakes_backend.py
  • tests/unit/api/fakes.py
  • tests/unit/engine/flight_recording/test_sink.py
  • tests/unit/engine/flight_recording/test_flight_recorder_service.py
web/src/utils/constants.ts

📄 CodeRabbit inference engine (web/CLAUDE.md)

WS wire protocol (MANDATORY): the client-server contract lives in web/src/utils/constants.ts (WS_PROTOCOL_VERSION, WS_MAX_MESSAGE_SIZE, WS_HEARTBEAT_INTERVAL_MS, WS_PONG_TIMEOUT_MS, LOG_SANITIZE_MAX_LENGTH) and MUST stay in lockstep with src/synthorg/api/ws_models.py / src/synthorg/api/controllers/ws.py. Bump the protocol version on both sides together for breaking payload changes.

Files:

  • web/src/utils/constants.ts
web/src/**/*.{jsx,tsx}

📄 CodeRabbit inference engine (web/CLAUDE.md)

web/src/**/*.{jsx,tsx}: Use @eslint-react/no-leaked-conditional-rendering to catch the {count && <Foo />} bug where 0 renders verbatim. For ReactNode | undefined props use {value != null && value !== false && <jsx>}; for compound truthiness use Boolean(...).
Use @eslint-react/globals to restrict window / document / localStorage / etc. inside render. Hoist offenders into a useCallback event handler, a useEffect, or a useSyncExternalStore-backed hook.

Reuse web/src/components/ui/ design tokens in Web Dashboard Design System; detail in web/CLAUDE.md

Files:

  • web/src/router/index.tsx
  • web/src/__tests__/components/ui/timeline.test.tsx
  • web/src/pages/MissionControlPage.tsx
  • web/src/components/ui/timeline.tsx
  • web/src/__tests__/pages/MissionControlPage.test.tsx
  • web/src/components/ui/timeline.stories.tsx
  • web/src/components/layout/Sidebar.tsx
  • web/src/pages/mission-control/LiveCockpit.tsx
  • web/src/pages/mission-control/FlightRecorder.tsx
web/src/{stores,**/*.test.{ts,tsx}}

📄 CodeRabbit inference engine (web/CLAUDE.md)

Active-handle gate (MANDATORY): every unit test runs under web/test-infra/active-handle-tracker.ts, which fails any test that leaks an event-loop-holding resource. A new store that schedules timers / attaches listeners MUST expose a teardown hook and register it in the global afterEach; otherwise the gate fails the first test that triggers the schedule.

Files:

  • web/src/__tests__/stores/mission-control.test.ts
  • web/src/__tests__/components/ui/timeline.test.tsx
  • web/src/__tests__/pages/MissionControlPage.test.tsx
web/src/{api/endpoints,stores}/**/*.ts

📄 CodeRabbit inference engine (web/CLAUDE.md)

Cursor pagination (MANDATORY): list endpoints must use opaque cursor-based paging via PaginationMeta. Stores must keep nextCursor + hasMore in state (not offset arithmetic) and early-return when !hasMore || !nextCursor. Display counts must come from data.length.

Files:

  • web/src/api/endpoints/cockpit.ts
  • web/src/stores/mission-control.ts
web/src/api/endpoints/**/*.ts

📄 CodeRabbit inference engine (web/CLAUDE.md)

Health / readiness endpoints (MANDATORY): getLiveness() is always 200 while the process is alive; getReadiness() is 200 healthy / 503 unavailable (binary 'ok' | 'unavailable' outcome, no tri-state). Any new caller must handle the 503 path explicitly.

Files:

  • web/src/api/endpoints/cockpit.ts
web/src/components/ui/**/*.{ts,tsx}

📄 CodeRabbit inference engine (web/CLAUDE.md)

web/src/components/ui/**/*.{ts,tsx}: ALWAYS reuse existing components from web/src/components/ui/ before creating new ones. NEVER hardcode hex colors, font-family declarations, pixel spacing, Motion transition durations, BCP 47 locale literals ('en-US'), or currency symbols / codes; use design tokens, @/lib/motion presets, the helpers in @/utils/format, and DEFAULT_CURRENCY from @/utils/currencies.
Every new shared component lives in web/src/components/ui/ with a sibling .stories.tsx covering all states (default, hover, loading, error, empty, disabled where applicable)
Component Props interface name must be <ComponentName>Props and must be exported from the same file (e.g. AgentCardProps in agent-card.tsx). This makes the contract greppable and lets callers extend the props without re-typing the shape.
Base UI primitives must compose Portal + Backdrop + Popup explicitly, use the render prop for polymorphism, and rely on animation state attributes (data-[open], data-[closed]) rather than the older data-[state=open] form.
Base UI primitives are imported directly from @base-ui/react/<subpath> and use the native render prop for polymorphism; the local <Slot> helper is reserved for <Button asChild> only

Files:

  • web/src/components/ui/timeline.tsx
  • web/src/components/ui/timeline.stories.tsx
web/src/{components,hooks}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (web/CLAUDE.md)

NEVER read window.innerWidth / window.innerHeight directly in a render body or useMemo; use useViewportSize() from @/hooks/useViewportSize instead

Files:

  • web/src/components/ui/timeline.tsx
  • web/src/components/ui/timeline.stories.tsx
  • web/src/components/layout/Sidebar.tsx
  • web/src/hooks/useMissionControlData.ts
src/synthorg/persistence/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

src/synthorg/persistence/**/*.py: Repository CRUD: save(entity), get(id), delete(id) -> bool, list_items(...), query(...) returning tuples
Datetime in persistence: use parse_iso_utc / format_iso_utc from persistence._shared (reject naive); use normalize_utc for already-typed

Files:

  • src/synthorg/persistence/sqlite/__init__.py
  • src/synthorg/persistence/sqlite/backend.py
  • src/synthorg/persistence/postgres/backend.py
  • src/synthorg/persistence/sqlite/flight_recorder_repo.py
  • src/synthorg/persistence/protocol.py
  • src/synthorg/persistence/sqlite/_backend_accessors.py
  • src/synthorg/persistence/flight_recorder_protocol.py
  • src/synthorg/persistence/postgres/flight_recorder_repo.py
web/src/api/types/**/*.gen.ts

📄 CodeRabbit inference engine (web/CLAUDE.md)

Generated DTO types (MANDATORY): NEVER hand-edit web/src/api/types/*.gen.ts. Regenerate with uv run python scripts/generate_dto_types_ts.py. Import DTOs via the barrel (import type { AgentConfig } from '@/api/types').

Files:

  • web/src/api/types/enum-values.gen.ts
  • web/src/api/types/dtos.gen.ts
  • web/src/api/types/openapi.gen.ts
web/src/**/*.stories.{ts,tsx}

📄 CodeRabbit inference engine (web/CLAUDE.md)

Storybook 10 is ESM-only; essentials are built into core, but @storybook/addon-docs is now separate; imports moved to storybook/test and storybook/actions

Files:

  • web/src/components/ui/timeline.stories.tsx
web/src/mocks/handlers/**/*.ts

📄 CodeRabbit inference engine (web/CLAUDE.md)

web/src/mocks/handlers/**/*.ts: MSW handlers (MANDATORY): web/src/mocks/handlers/ must mirror web/src/api/endpoints/*.ts 1:1 with a default happy-path handler for every exported endpoint. Use onUnhandledRequest: 'error' in test setup; tests override per-case via server.use(...), never vi.mock('@/api/endpoints/*').
Use typed envelope helpers (successFor, paginatedFor, voidSuccess) to keep MSW handlers in lockstep with endpoint return types

Files:

  • web/src/mocks/handlers/index.ts
  • web/src/mocks/handlers/cockpit.ts
src/synthorg/meta/mcp/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

MCP: Define ToolHandler + args_model; call require_admin_guardrails() on admin tools; route through service layers per mcp-handler-contract.md

Files:

  • src/synthorg/meta/mcp/domains/__init__.py
  • src/synthorg/meta/mcp/handlers/__init__.py
  • src/synthorg/meta/mcp/domains/cockpit.py
  • src/synthorg/meta/mcp/handlers/cockpit.py
tests/conformance/persistence/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

Dual-backend conformance: tests/conformance/persistence/ consumes backend fixture (SQLite + Postgres); enforced by check_dual_backend_test_parity.py

Files:

  • tests/conformance/persistence/test_flight_recorder_repository.py
web/src/stores/**/*.ts

📄 CodeRabbit inference engine (web/CLAUDE.md)

web/src/stores/**/*.ts: List reads (fetch*) must set error: string | null on the store instead of toasting
Test teardown (MANDATORY): any new store that schedules timers or attaches event listeners must expose an equivalent cleanup hook and register it in the global afterEach. The global afterEach in web/src/test-setup.tsx already calls useToastStore.getState().dismissAll(), cancelPendingPersist(), and useThemeStore.getState().teardown().

Files:

  • web/src/stores/mission-control.ts
🧠 Learnings (5)
📚 Learning: 2026-05-05T09:04:46.195Z
Learnt from: Aureliolo
Repo: Aureliolo/synthorg PR: 1760
File: scripts/_dual_backend_parity_lib.py:215-216
Timestamp: 2026-05-05T09:04:46.195Z
Learning: This repository targets Python 3.14+ and follows PEP 758. Therefore, reviewer tooling should NOT treat unparenthesized multi-exception `except` clauses written without an `as` clause (e.g., `except MemoryError, RecursionError:`) as syntax errors. Only flag `except`-clause problems when they are genuinely invalid for Python 3.14+.

Applied to files:

  • src/synthorg/engine/intervention/__init__.py
  • tests/unit/engine/flight_recording/test_engine_recording.py
  • tests/unit/observability/test_events.py
  • src/synthorg/engine/flight_recording/__init__.py
  • src/synthorg/engine/intervention/steering.py
  • src/synthorg/persistence/sqlite/__init__.py
  • src/synthorg/persistence/sqlite/backend.py
  • src/synthorg/observability/prometheus_labels.py
  • src/synthorg/engine/cockpit/__init__.py
  • src/synthorg/api/controllers/__init__.py
  • src/synthorg/api/channels.py
  • tests/unit/observability/audit_chain/test_audit_chain.py
  • src/synthorg/settings/enums.py
  • src/synthorg/meta/mcp/domains/__init__.py
  • src/synthorg/api/app.py
  • tests/unit/api/test_channels.py
  • src/synthorg/observability/events/persistence.py
  • src/synthorg/core/enums.py
  • src/synthorg/meta/mcp/handlers/__init__.py
  • src/synthorg/meta/mcp/domains/cockpit.py
  • tests/unit/persistence/test_protocol.py
  • tests/unit/meta/mcp/test_all_handlers_wired.py
  • tests/unit/engine/intervention/test_steering.py
  • src/synthorg/settings/definitions/__init__.py
  • tests/e2e/test_cockpit_mission_control_e2e.py
  • src/synthorg/observability/events/cockpit.py
  • tests/conformance/persistence/test_flight_recorder_repository.py
  • src/synthorg/engine/flight_recording/service.py
  • src/synthorg/api/state.py
  • src/synthorg/persistence/postgres/backend.py
  • src/synthorg/persistence/sqlite/flight_recorder_repo.py
  • src/synthorg/engine/flight_recording/sink.py
  • tests/unit/api/controllers/test_cockpit.py
  • src/synthorg/persistence/protocol.py
  • src/synthorg/engine/cockpit/service.py
  • src/synthorg/engine/agent_engine.py
  • tests/unit/engine/cockpit/test_cockpit_service.py
  • tests/unit/api/fakes_backend.py
  • src/synthorg/persistence/sqlite/_backend_accessors.py
  • src/synthorg/workers/runtime_builder.py
  • src/synthorg/persistence/flight_recorder_protocol.py
  • src/synthorg/settings/definitions/cockpit.py
  • tests/unit/api/fakes.py
  • tests/unit/engine/flight_recording/test_sink.py
  • src/synthorg/persistence/postgres/flight_recorder_repo.py
  • tests/unit/engine/flight_recording/test_flight_recorder_service.py
  • src/synthorg/api/controllers/cockpit.py
  • src/synthorg/meta/mcp/handlers/cockpit.py
📚 Learning: 2026-05-21T22:55:20.496Z
Learnt from: Aureliolo
Repo: Aureliolo/synthorg PR: 2035
File: src/synthorg/meta/toolsmith/models.py:114-114
Timestamp: 2026-05-21T22:55:20.496Z
Learning: In this repo’s “magic number” review standard, the existing gate in `scripts/check_no_magic_numbers.py` intentionally does NOT flag numeric literals used as raw call-site arguments. So, do not flag numeric literals passed as keyword arguments to Pydantic `Field()` (e.g., `Field(ge=0, le=100)` / `Field(ge=1, le=50)`)—this is an established idiom. Only treat numeric literals as “magic numbers” when they occur in the locations the gate checks (module-level assignments and function/method parameter defaults).

Applied to files:

  • src/synthorg/engine/intervention/__init__.py
  • tests/unit/engine/flight_recording/test_engine_recording.py
  • tests/unit/observability/test_events.py
  • src/synthorg/engine/flight_recording/__init__.py
  • src/synthorg/engine/intervention/steering.py
  • src/synthorg/persistence/sqlite/__init__.py
  • src/synthorg/persistence/sqlite/backend.py
  • src/synthorg/observability/prometheus_labels.py
  • src/synthorg/engine/cockpit/__init__.py
  • src/synthorg/api/controllers/__init__.py
  • src/synthorg/api/channels.py
  • tests/unit/observability/audit_chain/test_audit_chain.py
  • src/synthorg/settings/enums.py
  • src/synthorg/meta/mcp/domains/__init__.py
  • src/synthorg/api/app.py
  • tests/unit/api/test_channels.py
  • src/synthorg/observability/events/persistence.py
  • src/synthorg/core/enums.py
  • src/synthorg/meta/mcp/handlers/__init__.py
  • src/synthorg/meta/mcp/domains/cockpit.py
  • tests/unit/persistence/test_protocol.py
  • tests/unit/meta/mcp/test_all_handlers_wired.py
  • tests/unit/engine/intervention/test_steering.py
  • src/synthorg/settings/definitions/__init__.py
  • tests/e2e/test_cockpit_mission_control_e2e.py
  • src/synthorg/observability/events/cockpit.py
  • tests/conformance/persistence/test_flight_recorder_repository.py
  • src/synthorg/engine/flight_recording/service.py
  • src/synthorg/api/state.py
  • src/synthorg/persistence/postgres/backend.py
  • src/synthorg/persistence/sqlite/flight_recorder_repo.py
  • src/synthorg/engine/flight_recording/sink.py
  • tests/unit/api/controllers/test_cockpit.py
  • src/synthorg/persistence/protocol.py
  • src/synthorg/engine/cockpit/service.py
  • src/synthorg/engine/agent_engine.py
  • tests/unit/engine/cockpit/test_cockpit_service.py
  • tests/unit/api/fakes_backend.py
  • src/synthorg/persistence/sqlite/_backend_accessors.py
  • src/synthorg/workers/runtime_builder.py
  • src/synthorg/persistence/flight_recorder_protocol.py
  • src/synthorg/settings/definitions/cockpit.py
  • tests/unit/api/fakes.py
  • tests/unit/engine/flight_recording/test_sink.py
  • src/synthorg/persistence/postgres/flight_recorder_repo.py
  • tests/unit/engine/flight_recording/test_flight_recorder_service.py
  • src/synthorg/api/controllers/cockpit.py
  • src/synthorg/meta/mcp/handlers/cockpit.py
📚 Learning: 2026-05-21T22:55:09.289Z
Learnt from: Aureliolo
Repo: Aureliolo/synthorg PR: 2035
File: src/synthorg/meta/toolsmith/config.py:29-30
Timestamp: 2026-05-21T22:55:09.289Z
Learning: For this repo’s Pydantic configuration idiom, do not treat numeric literals passed directly as arguments to `pydantic.Field(...)` as “magic numbers” during review. This includes call-site usages like `Field(default=0.2, ge=0.0, le=1.0)` (e.g., in config models such as `ToolAuthoringConfig`, `ToolValidationConfig`, `ToolsmithConfig`). Do not request extracting those `Field(...)` numeric arguments into named constants, since the repo’s `scripts/check_no_magic_numbers.py` intentionally excludes call-site `Field(...)` numerics and relies on `Field(...)` as the canonical way to express these constraints/defaults.

Applied to files:

  • src/synthorg/engine/intervention/__init__.py
  • src/synthorg/engine/flight_recording/__init__.py
  • src/synthorg/engine/intervention/steering.py
  • src/synthorg/persistence/sqlite/__init__.py
  • src/synthorg/persistence/sqlite/backend.py
  • src/synthorg/observability/prometheus_labels.py
  • src/synthorg/engine/cockpit/__init__.py
  • src/synthorg/api/controllers/__init__.py
  • src/synthorg/api/channels.py
  • src/synthorg/settings/enums.py
  • src/synthorg/meta/mcp/domains/__init__.py
  • src/synthorg/api/app.py
  • src/synthorg/observability/events/persistence.py
  • src/synthorg/core/enums.py
  • src/synthorg/meta/mcp/handlers/__init__.py
  • src/synthorg/meta/mcp/domains/cockpit.py
  • src/synthorg/settings/definitions/__init__.py
  • src/synthorg/observability/events/cockpit.py
  • src/synthorg/engine/flight_recording/service.py
  • src/synthorg/api/state.py
  • src/synthorg/persistence/postgres/backend.py
  • src/synthorg/persistence/sqlite/flight_recorder_repo.py
  • src/synthorg/engine/flight_recording/sink.py
  • src/synthorg/persistence/protocol.py
  • src/synthorg/engine/cockpit/service.py
  • src/synthorg/engine/agent_engine.py
  • src/synthorg/persistence/sqlite/_backend_accessors.py
  • src/synthorg/workers/runtime_builder.py
  • src/synthorg/persistence/flight_recorder_protocol.py
  • src/synthorg/settings/definitions/cockpit.py
  • src/synthorg/persistence/postgres/flight_recorder_repo.py
  • src/synthorg/api/controllers/cockpit.py
  • src/synthorg/meta/mcp/handlers/cockpit.py
📚 Learning: 2026-05-17T11:45:11.839Z
Learnt from: Aureliolo
Repo: Aureliolo/synthorg PR: 1952
File: src/synthorg/settings/definitions/api.py:594-638
Timestamp: 2026-05-17T11:45:11.839Z
Learning: In SynthOrg (Aureliolo/synthorg) pre-alpha, apply the strict no-backward-compat policy: any setting-key rename must be fully completed in the same change/PR with all repo callers updated, and you should not keep legacy aliases or compatibility fallbacks. When reviewing, do not flag a setting-key rename as a breaking upgrade hazard if the rename is repo-wide and fully implemented within the same PR.

Applied to files:

  • src/synthorg/settings/enums.py
  • src/synthorg/settings/definitions/__init__.py
  • src/synthorg/settings/definitions/cockpit.py
📚 Learning: 2026-05-17T11:45:11.839Z
Learnt from: Aureliolo
Repo: Aureliolo/synthorg PR: 1952
File: src/synthorg/settings/definitions/api.py:594-638
Timestamp: 2026-05-17T11:45:11.839Z
Learning: In this repository, SynthOrg is pre-alpha and uses a strict no-backward-compat policy for setting-key renames. When reviewing code under src/synthorg/settings, do NOT flag a setting-key rename as an “upgrade-safety” issue if the rename is complete/atomic in the same PR: all callers/usages of the old key are updated simultaneously, and the PR does not keep any legacy aliases, compatibility fallbacks, or migration/rollback paths for the old key.

Applied to files:

  • src/synthorg/settings/enums.py
  • src/synthorg/settings/definitions/__init__.py
  • src/synthorg/settings/definitions/cockpit.py
🪛 OpenGrep (1.21.0)
src/synthorg/persistence/sqlite/flight_recorder_repo.py

[ERROR] 68-76: SQL query built via f-string passed to execute()/executemany(). Use parameterized queries with placeholders instead.

(coderabbit.sql-injection.python-fstring-execute)

src/synthorg/persistence/postgres/flight_recorder_repo.py

[ERROR] 61-70: SQL query built via f-string passed to execute()/executemany(). Use parameterized queries with placeholders instead.

(coderabbit.sql-injection.python-fstring-execute)

🔇 Additional comments (61)
scripts/_ghost_wiring_manifest.txt (1)

106-109: LGTM!

src/synthorg/core/enums.py (1)

1000-1013: LGTM!

src/synthorg/persistence/flight_recorder_protocol.py (1)

1-137: LGTM!

src/synthorg/persistence/protocol.py (1)

75-77: LGTM!

Also applies to: 404-407

src/synthorg/settings/enums.py (1)

38-38: LGTM!

src/synthorg/settings/definitions/__init__.py (1)

13-13: LGTM!

Also applies to: 42-42

src/synthorg/settings/definitions/cockpit.py (1)

1-155: LGTM!

src/synthorg/observability/prometheus_labels.py (1)

289-289: LGTM!

src/synthorg/engine/intervention/__init__.py (1)

1-15: LGTM!

src/synthorg/observability/events/cockpit.py (1)

1-21: LGTM!

src/synthorg/observability/events/persistence.py (1)

62-75: LGTM!

src/synthorg/persistence/postgres/backend.py (1)

74-76: LGTM!

Also applies to: 231-233, 338-338, 407-407, 479-479, 695-701

src/synthorg/persistence/postgres/flight_recorder_repo.py (1)

1-200: LGTM!

src/synthorg/persistence/postgres/revisions/20260522000002_flight_recorder.sql (1)

1-25: LGTM!

src/synthorg/persistence/postgres/schema.sql (1)

376-400: LGTM!

src/synthorg/persistence/sqlite/__init__.py (1)

13-15: LGTM!

Also applies to: 30-30

src/synthorg/persistence/sqlite/_backend_accessors.py (1)

63-65: LGTM!

Also applies to: 153-153, 300-307

src/synthorg/persistence/sqlite/backend.py (1)

73-75: LGTM!

Also applies to: 243-243, 318-318, 537-540

src/synthorg/persistence/sqlite/flight_recorder_repo.py (1)

1-210: LGTM!

tests/conformance/persistence/test_flight_recorder_repository.py (1)

1-163: LGTM!

tests/e2e/test_cockpit_mission_control_e2e.py (1)

1-110: LGTM!

tests/unit/api/controllers/test_cockpit.py (1)

1-161: LGTM!

tests/unit/api/fakes.py (1)

35-38: LGTM!

Also applies to: 517-562

tests/unit/api/fakes_backend.py (1)

37-37: LGTM!

Also applies to: 641-641, 807-810

tests/unit/api/test_channels.py (1)

13-13: LGTM!

Also applies to: 80-80

tests/unit/engine/cockpit/test_cockpit_service.py (1)

1-135: LGTM!

tests/unit/engine/flight_recording/test_engine_recording.py (1)

1-92: LGTM!

tests/unit/engine/flight_recording/test_flight_recorder_service.py (1)

1-66: LGTM!

tests/unit/engine/flight_recording/test_sink.py (1)

1-212: LGTM!

tests/unit/engine/intervention/test_steering.py (1)

1-35: LGTM!

Also applies to: 49-83

tests/unit/meta/mcp/test_all_handlers_wired.py (1)

214-221: LGTM!

tests/unit/observability/audit_chain/test_audit_chain.py (1)

457-457: LGTM!

Also applies to: 470-480

tests/unit/observability/test_events.py (1)

355-357: LGTM!

web/src/api/endpoints/cockpit.ts (1)

13-17: LGTM!

Also applies to: 31-84

web/src/api/types/dtos.gen.ts (1)

18-18: LGTM!

Also applies to: 65-65, 70-70, 90-90, 106-106, 262-263, 284-284, 288-288, 373-373, 418-418, 469-470

web/src/api/types/enum-values.gen.ts (1)

387-394: LGTM!

Also applies to: 659-659

web/src/api/types/openapi.gen.ts (1)

1275-17030: LGTM!

web/src/api/types/websocket.ts (1)

14-22: LGTM!

web/src/pages/MissionControlPage.tsx (1)

15-45: LGTM!

web/src/pages/mission-control/FlightRecorder.tsx (1)

28-155: LGTM!

Also applies to: 157-197

web/src/pages/mission-control/LiveCockpit.tsx (1)

31-116: LGTM!

Also applies to: 118-160

web/src/pages/settings/utils.ts (1)

18-45: LGTM!

web/src/mocks/handlers/cockpit.ts (1)

16-106: LGTM!

web/src/router/route-titles.ts (1)

48-48: LGTM!

web/src/router/routes.ts (1)

12-12: LGTM!

web/src/components/layout/Sidebar.tsx (1)

19-19: LGTM!

Also applies to: 229-229

web/src/components/ui/timeline.stories.tsx (1)

1-43: LGTM!

web/src/mocks/handlers/index.ts (1)

73-73: LGTM!

Also applies to: 127-127, 178-178

web/src/__tests__/components/ui/timeline.test.tsx (1)

1-45: LGTM!

web/src/__tests__/pages/MissionControlPage.test.tsx (1)

1-86: LGTM!

web/src/__tests__/stores/mission-control.test.ts (1)

1-55: LGTM!

src/synthorg/engine/cockpit/__init__.py (1)

3-13: LGTM!

src/synthorg/api/app.py (1)

300-353: LGTM!

Also applies to: 1302-1304

src/synthorg/api/channels.py (1)

39-39: LGTM!

Also applies to: 64-64

src/synthorg/api/controllers/__init__.py (1)

27-27: LGTM!

Also applies to: 172-172

src/synthorg/meta/mcp/domains/__init__.py (1)

11-11: LGTM!

Also applies to: 42-42

src/synthorg/meta/mcp/domains/cockpit.py (1)

1-89: LGTM!

src/synthorg/meta/mcp/handlers/__init__.py (1)

14-14: LGTM!

Also applies to: 49-49

src/synthorg/meta/mcp/handlers/cockpit.py (1)

1-264: LGTM!

src/synthorg/engine/flight_recording/__init__.py (1)

1-24: LGTM!

src/synthorg/workers/runtime_builder.py (1)

34-37: LGTM!

Also applies to: 94-97, 396-417, 429-430, 469-470, 730-740

Comment thread src/synthorg/api/controllers/cockpit.py Outdated
Comment thread src/synthorg/api/controllers/cockpit.py
Comment thread src/synthorg/api/state.py
Comment thread src/synthorg/engine/agent_engine.py Outdated
Comment thread src/synthorg/engine/cockpit/service.py Outdated
Comment thread web/src/hooks/useMissionControlData.ts
Comment thread web/src/router/index.tsx Outdated
Comment thread web/src/stores/mission-control.ts
Comment thread web/src/utils/constants.ts
Comment thread web/src/utils/status-color.ts Outdated
Aureliolo added 2 commits May 22, 2026 21:03
CI fixes (2):
- tests/e2e/test_cockpit_mission_control_e2e.py: construct real Task
  instead of mock_of[Task] (Pydantic v2 fields are not autospec attrs).
- tests/integration/mcp/test_tool_surface.py: bump tool count assertion
  from 219 to 226 to reflect new cockpit MCP tools.

Reviewer feedback (4 gemini, 19 coderabbit):

Persistence (protocol + sqlite + postgres + fakes + conformance):
- Add FlightRecorderFrameAggregate + get_aggregate() bespoke method
  (ADR-0001 D7) so cockpit activity and seek can sum cost / max turn
  in one SQL pass instead of N+1 across active tasks.
- Add append_many() bespoke method so flight-recorder finalisation lands
  as one batched transaction instead of N round-trips.
- Make idx_frf_execution_turn UNIQUE (sqlite + postgres revisions and
  schema.sql) so seek/replay is deterministic.
- purge_before now takes AwareDatetime (was plain datetime), rejecting
  naive values at the contract boundary.

Engine:
- engine/cockpit/service: _build_activity now consumes get_aggregate;
  fan-out across tasks via asyncio.TaskGroup keeps snapshot latency
  bounded by the slowest aggregate query, not the sum.
- engine/flight_recording/sink: PersistenceFlightRecorderSink uses
  append_many; re-raises MemoryError/RecursionError before generic
  Exception catch; build_frames correlates assistant message by
  turn.turn_number - 1 (was loop index), fixing resumed-run drift.
- engine/flight_recording/service: ReplaySeekView gains a truncated
  flag; cumulative_cost now comes from the unbounded SQL aggregate so
  it stays accurate when the windowed frames are capped.
- engine/agent_engine: guard build_frames + record_frames in try/except
  so a construction fault cannot turn a successful run into a failure.
- engine/intervention/steering: wrap operator text via wrap_untrusted
  (SEC-1) before persisting the steering interrupt.

API:
- api/controllers/cockpit: /frames switches to opaque cursor pagination
  (PaginatedResponse FlightRecorderFrame); turn_index path param now
  validated ge=1 at the Litestar boundary; /interventions/hint and
  /interventions/redirect wrap operator text via wrap_untrusted (SEC-1).
- api/state: set_cockpit_services emits accurate transition value
  (noop / attached / replaced) instead of always attached.

Web (regenerated DTO + manual updates):
- web/src/api/endpoints/cockpit.ts: getFlightRecorderFrames returns
  PaginatedResult, takes PaginationParams.
- web/src/stores/mission-control.ts: fetchFrames clears stale state
  synchronously; nextCursor + hasMore tracked; fetchMoreFrames appends.
- web/src/components/ui/timeline.tsx: clamp keyboard seek targets to
  [0, lastIndex] on every key path so a stale currentIndex cannot
  produce an out-of-range seek.
- web/src/hooks/useMissionControlData.ts: coalesce burst-y WS-triggered
  snapshot refreshes via a single in-flight ref.
- web/src/router/index.tsx: derive mission-control path from
  ROUTES.MISSION_CONTROL constant.
- web/src/utils/constants.ts: add cockpit to NAMESPACE_ORDER so the
  namespace surfaces in Settings.
- web/src/utils/status-color.ts: type STATUS_BG against generated
  TaskStatus union for compile-time safety on status drift.

Tests:
- tests/unit/api/fakes.py: FakeFlightRecorderFrameRepository mirrors
  the new protocol methods + UNIQUE-turn invariant.
- tests/unit/persistence/test_protocol.py: _FakeFlightRecorderRepository
  mirrors the new protocol; conformance assertion added.
- tests/conformance/persistence/test_flight_recorder_repository.py:
  dual-backend coverage for append_many, get_aggregate, unique-turn.
- tests/unit/api/controllers/test_cockpit.py: frames response shape
  updated for PaginatedResponse.
- tests/unit/engine/intervention/test_steering.py: assert redirect
  interrupt is persisted; hint test accepts wrap_untrusted envelope.
@Aureliolo
Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 22, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/synthorg/engine/flight_recording/service.py`:
- Around line 127-129: The current code computes truncated using the requested
turn_index which can be misleading; change the logic in the block using
self._repository.get_aggregate(filter_spec) to derive truncated from the
aggregate's actual data (e.g., use aggregate.max_turn_index or similar field
returned by get_aggregate) rather than turn_index or only _MAX_SEEK_FRAMES, so
set truncated = aggregate.max_turn_index > _MAX_SEEK_FRAMES (or compare
aggregate.max_turn_index to the requested window) and leave cumulative =
aggregate.total_cost as-is.

In `@tests/unit/api/fakes.py`:
- Around line 591-604: The current selection of latest frame uses
candidates_sorted = sorted(candidates, key=lambda f: (f.turn_index,
f.timestamp), reverse=True) which prioritizes turn_index over actual time,
causing latest_timestamp/latest_execution_id in FlightRecorderFrameAggregate to
sometimes be older; change the selection to pick the frame with the greatest
timestamp (tie-break by turn_index) instead — e.g. compute latest =
max(candidates, key=lambda f: (f.timestamp, f.turn_index)) and then use
latest.timestamp and latest.execution_id when building
FlightRecorderFrameAggregate, keeping total_cost and max_turn_index calculations
unchanged.

In `@web/src/stores/mission-control.ts`:
- Around line 97-103: The async fetch in fetchFrames/fetchMoreFrames can apply
stale results after executionId changes; to fix, record a per-request identifier
(e.g., capture executionId or an incrementing framesRequestId from the store) at
the start of the async call and compare it right before calling set(...) so you
only mutate frames when the captured id matches the current store value; apply
the same guard around the getFlightRecorderFrames response handling in both
fetchFrames and fetchMoreFrames (use the symbols fetchFrames, fetchMoreFrames,
getFlightRecorderFrames, executionId, framesNextCursor/framesHasMore to locate
the spots).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI (base), Organization UI (inherited)

Review profile: ASSERTIVE

Plan: Pro

Run ID: 9628f0a6-0393-47e0-b95c-38a2bcc99c61

📥 Commits

Reviewing files that changed from the base of the PR and between d07e9a6 and a6f8b64.

📒 Files selected for processing (31)
  • src/synthorg/api/controllers/cockpit.py
  • src/synthorg/api/state.py
  • src/synthorg/engine/agent_engine.py
  • src/synthorg/engine/cockpit/service.py
  • src/synthorg/engine/flight_recording/service.py
  • src/synthorg/engine/flight_recording/sink.py
  • src/synthorg/engine/intervention/steering.py
  • src/synthorg/persistence/flight_recorder_protocol.py
  • src/synthorg/persistence/postgres/flight_recorder_repo.py
  • src/synthorg/persistence/postgres/revisions/20260522000002_flight_recorder.sql
  • src/synthorg/persistence/postgres/schema.sql
  • src/synthorg/persistence/sqlite/flight_recorder_repo.py
  • src/synthorg/persistence/sqlite/revisions/20260522000002_flight_recorder.sql
  • src/synthorg/persistence/sqlite/schema.sql
  • tests/conformance/persistence/test_flight_recorder_repository.py
  • tests/e2e/test_cockpit_mission_control_e2e.py
  • tests/integration/mcp/test_tool_surface.py
  • tests/unit/api/controllers/test_cockpit.py
  • tests/unit/api/fakes.py
  • tests/unit/engine/intervention/test_steering.py
  • tests/unit/persistence/test_protocol.py
  • web/src/api/endpoints/cockpit.ts
  • web/src/api/types/dtos.gen.ts
  • web/src/api/types/openapi.gen.ts
  • web/src/components/ui/timeline.tsx
  • web/src/hooks/useMissionControlData.ts
  • web/src/mocks/handlers/cockpit.ts
  • web/src/router/index.tsx
  • web/src/stores/mission-control.ts
  • web/src/utils/constants.ts
  • web/src/utils/status-color.ts
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Test Integration
  • GitHub Check: Test Unit
🧰 Additional context used
📓 Path-based instructions (18)
web/src/**/*.{js,jsx,ts,tsx,mts}

📄 CodeRabbit inference engine (web/CLAUDE.md)

web/src/**/*.{js,jsx,ts,tsx,mts}: Always use createLogger from @/lib/logger; never bare console.warn/console.error/console.debug in application code. Variable name must always be log. Only logger.ts itself may use bare console methods. Use log.debug() (DEV-only, stripped in production), log.warn(), log.error().
Pass dynamic/untrusted values as separate args to logger calls (not interpolated into the message string) so they go through sanitizeArg
Attacker-controlled fields inside structured objects must be wrapped in sanitizeForLog() before embedding in log calls
Error-code constants (MANDATORY): import ErrorCode and ErrorCategory from @/api/types/errors (re-exported from the generated web/src/api/types/error-codes.gen.ts). Discriminate on ErrorCode.<NAME>, never on raw integer literals.
Use @eslint-react/web-api-no-leaked-fetch to detect fetch() in effects without AbortController cleanup

Files:

  • web/src/router/index.tsx
  • web/src/utils/constants.ts
  • web/src/mocks/handlers/cockpit.ts
  • web/src/utils/status-color.ts
  • web/src/api/endpoints/cockpit.ts
  • web/src/components/ui/timeline.tsx
  • web/src/hooks/useMissionControlData.ts
  • web/src/api/types/dtos.gen.ts
  • web/src/stores/mission-control.ts
  • web/src/api/types/openapi.gen.ts
web/src/**/*.{jsx,tsx}

📄 CodeRabbit inference engine (web/CLAUDE.md)

web/src/**/*.{jsx,tsx}: Use @eslint-react/no-leaked-conditional-rendering to catch the {count && <Foo />} bug where 0 renders verbatim. For ReactNode | undefined props use {value != null && value !== false && <jsx>}; for compound truthiness use Boolean(...).
Use @eslint-react/globals to restrict window / document / localStorage / etc. inside render. Hoist offenders into a useCallback event handler, a useEffect, or a useSyncExternalStore-backed hook.

Reuse web/src/components/ui/ design tokens in Web Dashboard Design System; detail in web/CLAUDE.md

Files:

  • web/src/router/index.tsx
  • web/src/components/ui/timeline.tsx
web/src/**/*.{ts,tsx,mts}

📄 CodeRabbit inference engine (web/CLAUDE.md)

web/src/**/*.{ts,tsx,mts}: Use @typescript-eslint/no-floating-promises to forbid unawaited promises so async work cannot survive the test that scheduled it and trip the active-handle gate
Use @typescript-eslint/no-misused-promises (with checksVoidReturn: { attributes: false }) to forbid passing async functions where the callsite ignores the returned promise. React 19 async event handlers stay allowed via the attributes: false exemption.

Files:

  • web/src/router/index.tsx
  • web/src/utils/constants.ts
  • web/src/mocks/handlers/cockpit.ts
  • web/src/utils/status-color.ts
  • web/src/api/endpoints/cockpit.ts
  • web/src/components/ui/timeline.tsx
  • web/src/hooks/useMissionControlData.ts
  • web/src/api/types/dtos.gen.ts
  • web/src/stores/mission-control.ts
  • web/src/api/types/openapi.gen.ts
**/*.{py,ts,tsx,jsx,md}

📄 CodeRabbit inference engine (CLAUDE.md)

No region/currency/locale privileged; use metric units; British English per docs/reference/regional-defaults.md

Files:

  • web/src/router/index.tsx
  • web/src/utils/constants.ts
  • web/src/mocks/handlers/cockpit.ts
  • web/src/utils/status-color.ts
  • src/synthorg/engine/intervention/steering.py
  • web/src/api/endpoints/cockpit.ts
  • tests/unit/persistence/test_protocol.py
  • web/src/components/ui/timeline.tsx
  • tests/integration/mcp/test_tool_surface.py
  • tests/unit/api/fakes.py
  • tests/unit/engine/intervention/test_steering.py
  • tests/e2e/test_cockpit_mission_control_e2e.py
  • web/src/hooks/useMissionControlData.ts
  • src/synthorg/api/state.py
  • src/synthorg/persistence/flight_recorder_protocol.py
  • src/synthorg/engine/flight_recording/service.py
  • src/synthorg/engine/agent_engine.py
  • src/synthorg/engine/flight_recording/sink.py
  • src/synthorg/engine/cockpit/service.py
  • src/synthorg/persistence/postgres/flight_recorder_repo.py
  • web/src/api/types/dtos.gen.ts
  • tests/unit/api/controllers/test_cockpit.py
  • tests/conformance/persistence/test_flight_recorder_repository.py
  • web/src/stores/mission-control.ts
  • src/synthorg/api/controllers/cockpit.py
  • src/synthorg/persistence/sqlite/flight_recorder_repo.py
  • web/src/api/types/openapi.gen.ts
web/src/utils/constants.ts

📄 CodeRabbit inference engine (web/CLAUDE.md)

WS wire protocol (MANDATORY): the client-server contract lives in web/src/utils/constants.ts (WS_PROTOCOL_VERSION, WS_MAX_MESSAGE_SIZE, WS_HEARTBEAT_INTERVAL_MS, WS_PONG_TIMEOUT_MS, LOG_SANITIZE_MAX_LENGTH) and MUST stay in lockstep with src/synthorg/api/ws_models.py / src/synthorg/api/controllers/ws.py. Bump the protocol version on both sides together for breaking payload changes.

Files:

  • web/src/utils/constants.ts
web/src/{components,utils}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (web/CLAUDE.md)

NEVER write getXIcon(value): LucideIcon factories called inside JSX bodies. Export a <XIcon value={...} /> wrapper that does the lookup via createElement inside the wrapper body. Wrapper components live in their own file, not alongside utility exports.

Files:

  • web/src/utils/constants.ts
  • web/src/utils/status-color.ts
  • web/src/components/ui/timeline.tsx
web/src/mocks/handlers/**/*.ts

📄 CodeRabbit inference engine (web/CLAUDE.md)

web/src/mocks/handlers/**/*.ts: MSW handlers (MANDATORY): web/src/mocks/handlers/ must mirror web/src/api/endpoints/*.ts 1:1 with a default happy-path handler for every exported endpoint. Use onUnhandledRequest: 'error' in test setup; tests override per-case via server.use(...), never vi.mock('@/api/endpoints/*').
Use typed envelope helpers (successFor, paginatedFor, voidSuccess) to keep MSW handlers in lockstep with endpoint return types

Files:

  • web/src/mocks/handlers/cockpit.ts
src/synthorg/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

src/synthorg/**/*.py: Only src/synthorg/persistence/ may import sqlite/psycopg or emit raw SQL; new repository protocols inherit from generic categories in persistence/_generics.py; bespoke methods permitted only under ADR-0001 D7
Configuration Precedence: DB > env > code default via SettingsService/ConfigResolver (Cat-1) or env > code default (Cat-2, read_only_post_init); Cat-3 bootstrap secrets pure env; YAML is ingestion format only, not precedence tier; no os.environ.get outside startup
No hardcoded numeric values; numerics live in settings/definitions/; allowlist only 0/1/-1, HTTP codes, hex masks, powers-of-2, and module-level annotated named constants (NAME: int|float|Final); enforced by scripts/check_no_magic_numbers.py
Comments document WHY only; no reviewer citations, issue back-refs, or migration framing; enforced by check_no_review_origin_in_code.py + check_no_migration_framing.py
No from __future__ import annotations (Python 3.14 has PEP 649); use PEP 758 except: except A, B: no parens unless binding
Type hints on public functions; mypy strict; Google-style docstrings; line length 88; functions <50 lines; files <800 lines
Errors follow <Domain><Condition>Error pattern from DomainError; never inherit Exception/RuntimeError directly; enforced by check_domain_error_hierarchy.py
Pydantic v2 frozen + extra="forbid" on every frozen model project-wide; gate check_frozen_model_extra_forbid.py; @computed_field auto-exempt; per-line # lint-allow: frozen-extra-forbid -- <reason> for extra="allow"/"ignore" boundaries; use @computed_field for derived; use NotBlankStr for identifiers
Args models at every system boundary; parse_typed() for every external dict ingestion; enforced by check_boundary_typed.py
Immutability: use model_copy(update=...) or copy.deepcopy(); deepcopy at system boundaries
Async: use asyncio.TaskGroup for fan-out/fan-in; helpers catch Exception (re-raise MemoryError/`RecursionError...

Files:

  • src/synthorg/engine/intervention/steering.py
  • src/synthorg/api/state.py
  • src/synthorg/persistence/flight_recorder_protocol.py
  • src/synthorg/engine/flight_recording/service.py
  • src/synthorg/engine/agent_engine.py
  • src/synthorg/engine/flight_recording/sink.py
  • src/synthorg/engine/cockpit/service.py
  • src/synthorg/persistence/postgres/flight_recorder_repo.py
  • src/synthorg/api/controllers/cockpit.py
  • src/synthorg/persistence/sqlite/flight_recorder_repo.py
src/**/*.py

⚙️ CodeRabbit configuration file

This project uses Python 3.14+ with PEP 758 except syntax: "except A, B:" (comma-separated, no parentheses) is correct and mandatory -- do NOT flag it as a typo or suggest parenthesized form. The "except builtins.MemoryError, RecursionError: raise" pattern is intentional project convention for system-error propagation. When evaluating the 50-line function limit, count only the function body excluding the signature lines, decorators, and docstring. Functions 1-5 lines over due to docstrings or multi-line signatures should not be flagged. Do not suggest extracting single-use helper functions called exactly once -- this reduces readability without improving maintainability.

Files:

  • src/synthorg/engine/intervention/steering.py
  • src/synthorg/api/state.py
  • src/synthorg/persistence/flight_recorder_protocol.py
  • src/synthorg/engine/flight_recording/service.py
  • src/synthorg/engine/agent_engine.py
  • src/synthorg/engine/flight_recording/sink.py
  • src/synthorg/engine/cockpit/service.py
  • src/synthorg/persistence/postgres/flight_recorder_repo.py
  • src/synthorg/api/controllers/cockpit.py
  • src/synthorg/persistence/sqlite/flight_recorder_repo.py
web/src/{api/endpoints,stores}/**/*.ts

📄 CodeRabbit inference engine (web/CLAUDE.md)

Cursor pagination (MANDATORY): list endpoints must use opaque cursor-based paging via PaginationMeta. Stores must keep nextCursor + hasMore in state (not offset arithmetic) and early-return when !hasMore || !nextCursor. Display counts must come from data.length.

Files:

  • web/src/api/endpoints/cockpit.ts
  • web/src/stores/mission-control.ts
web/src/api/endpoints/**/*.ts

📄 CodeRabbit inference engine (web/CLAUDE.md)

Health / readiness endpoints (MANDATORY): getLiveness() is always 200 while the process is alive; getReadiness() is 200 healthy / 503 unavailable (binary 'ok' | 'unavailable' outcome, no tri-state). Any new caller must handle the 503 path explicitly.

Files:

  • web/src/api/endpoints/cockpit.ts
tests/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

tests/**/*.py: Timeout/slow failures = source-code regression; never edit tests/baselines/unit_timing.json or any scripts/*_baseline.{txt,json} / scripts/_*_baseline.py; both families PreToolUse-blocked; per-invocation bypass requires explicit approval (ALLOW_BASELINE_GROWTH=1 git commit)
Test markers: @pytest.mark.{unit,integration,e2e,slow}; async auto; timeout 30s global; coverage 80% min
xdist -n 8 --dist=loadfile auto-applied via pyproject addopts; Windows unit tests use WindowsSelectorEventLoopPolicy; subprocess tests override back
Test doubles: FakeClock for Clock seam, mock_of[T](**overrides) for typed-boundary substitutions, SimpleNamespace for attribute-bags; bare MagicMock at typed boundary blocked by scripts/check_mock_spec.py
Hypothesis: 10 deterministic CI examples; failures are real bugs (fix + add @example(...)); never skip/xfail flaky tests; fix fundamentally

Files:

  • tests/unit/persistence/test_protocol.py
  • tests/integration/mcp/test_tool_surface.py
  • tests/unit/api/fakes.py
  • tests/unit/engine/intervention/test_steering.py
  • tests/e2e/test_cockpit_mission_control_e2e.py
  • tests/unit/api/controllers/test_cockpit.py
  • tests/conformance/persistence/test_flight_recorder_repository.py

⚙️ CodeRabbit configuration file

Test files do not require Google-style docstrings on classes or functions -- ruff D rules are only enforced on src/. A bare @settings() decorator with no arguments on Hypothesis property tests is a no-op and should not be suggested -- the HYPOTHESIS_PROFILE env var controls example counts via registered profiles, which @given() honors automatically.

Files:

  • tests/unit/persistence/test_protocol.py
  • tests/integration/mcp/test_tool_surface.py
  • tests/unit/api/fakes.py
  • tests/unit/engine/intervention/test_steering.py
  • tests/e2e/test_cockpit_mission_control_e2e.py
  • tests/unit/api/controllers/test_cockpit.py
  • tests/conformance/persistence/test_flight_recorder_repository.py
web/src/components/ui/**/*.{ts,tsx}

📄 CodeRabbit inference engine (web/CLAUDE.md)

web/src/components/ui/**/*.{ts,tsx}: ALWAYS reuse existing components from web/src/components/ui/ before creating new ones. NEVER hardcode hex colors, font-family declarations, pixel spacing, Motion transition durations, BCP 47 locale literals ('en-US'), or currency symbols / codes; use design tokens, @/lib/motion presets, the helpers in @/utils/format, and DEFAULT_CURRENCY from @/utils/currencies.
Every new shared component lives in web/src/components/ui/ with a sibling .stories.tsx covering all states (default, hover, loading, error, empty, disabled where applicable)
Component Props interface name must be <ComponentName>Props and must be exported from the same file (e.g. AgentCardProps in agent-card.tsx). This makes the contract greppable and lets callers extend the props without re-typing the shape.
Base UI primitives must compose Portal + Backdrop + Popup explicitly, use the render prop for polymorphism, and rely on animation state attributes (data-[open], data-[closed]) rather than the older data-[state=open] form.
Base UI primitives are imported directly from @base-ui/react/<subpath> and use the native render prop for polymorphism; the local <Slot> helper is reserved for <Button asChild> only

Files:

  • web/src/components/ui/timeline.tsx
web/src/{components,hooks}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (web/CLAUDE.md)

NEVER read window.innerWidth / window.innerHeight directly in a render body or useMemo; use useViewportSize() from @/hooks/useViewportSize instead

Files:

  • web/src/components/ui/timeline.tsx
  • web/src/hooks/useMissionControlData.ts
src/synthorg/persistence/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

src/synthorg/persistence/**/*.py: Repository CRUD: save(entity), get(id), delete(id) -> bool, list_items(...), query(...) returning tuples
Datetime in persistence: use parse_iso_utc / format_iso_utc from persistence._shared (reject naive); use normalize_utc for already-typed

Files:

  • src/synthorg/persistence/flight_recorder_protocol.py
  • src/synthorg/persistence/postgres/flight_recorder_repo.py
  • src/synthorg/persistence/sqlite/flight_recorder_repo.py
web/src/api/types/**/*.gen.ts

📄 CodeRabbit inference engine (web/CLAUDE.md)

Generated DTO types (MANDATORY): NEVER hand-edit web/src/api/types/*.gen.ts. Regenerate with uv run python scripts/generate_dto_types_ts.py. Import DTOs via the barrel (import type { AgentConfig } from '@/api/types').

Files:

  • web/src/api/types/dtos.gen.ts
  • web/src/api/types/openapi.gen.ts
tests/conformance/persistence/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

Dual-backend conformance: tests/conformance/persistence/ consumes backend fixture (SQLite + Postgres); enforced by check_dual_backend_test_parity.py

Files:

  • tests/conformance/persistence/test_flight_recorder_repository.py
web/src/stores/**/*.ts

📄 CodeRabbit inference engine (web/CLAUDE.md)

web/src/stores/**/*.ts: List reads (fetch*) must set error: string | null on the store instead of toasting
Test teardown (MANDATORY): any new store that schedules timers or attaches event listeners must expose an equivalent cleanup hook and register it in the global afterEach. The global afterEach in web/src/test-setup.tsx already calls useToastStore.getState().dismissAll(), cancelPendingPersist(), and useThemeStore.getState().teardown().

Files:

  • web/src/stores/mission-control.ts
🧠 Learnings (3)
📚 Learning: 2026-05-05T09:04:46.195Z
Learnt from: Aureliolo
Repo: Aureliolo/synthorg PR: 1760
File: scripts/_dual_backend_parity_lib.py:215-216
Timestamp: 2026-05-05T09:04:46.195Z
Learning: This repository targets Python 3.14+ and follows PEP 758. Therefore, reviewer tooling should NOT treat unparenthesized multi-exception `except` clauses written without an `as` clause (e.g., `except MemoryError, RecursionError:`) as syntax errors. Only flag `except`-clause problems when they are genuinely invalid for Python 3.14+.

Applied to files:

  • src/synthorg/engine/intervention/steering.py
  • tests/unit/persistence/test_protocol.py
  • tests/integration/mcp/test_tool_surface.py
  • tests/unit/api/fakes.py
  • tests/unit/engine/intervention/test_steering.py
  • tests/e2e/test_cockpit_mission_control_e2e.py
  • src/synthorg/api/state.py
  • src/synthorg/persistence/flight_recorder_protocol.py
  • src/synthorg/engine/flight_recording/service.py
  • src/synthorg/engine/agent_engine.py
  • src/synthorg/engine/flight_recording/sink.py
  • src/synthorg/engine/cockpit/service.py
  • src/synthorg/persistence/postgres/flight_recorder_repo.py
  • tests/unit/api/controllers/test_cockpit.py
  • tests/conformance/persistence/test_flight_recorder_repository.py
  • src/synthorg/api/controllers/cockpit.py
  • src/synthorg/persistence/sqlite/flight_recorder_repo.py
📚 Learning: 2026-05-21T22:55:20.496Z
Learnt from: Aureliolo
Repo: Aureliolo/synthorg PR: 2035
File: src/synthorg/meta/toolsmith/models.py:114-114
Timestamp: 2026-05-21T22:55:20.496Z
Learning: In this repo’s “magic number” review standard, the existing gate in `scripts/check_no_magic_numbers.py` intentionally does NOT flag numeric literals used as raw call-site arguments. So, do not flag numeric literals passed as keyword arguments to Pydantic `Field()` (e.g., `Field(ge=0, le=100)` / `Field(ge=1, le=50)`)—this is an established idiom. Only treat numeric literals as “magic numbers” when they occur in the locations the gate checks (module-level assignments and function/method parameter defaults).

Applied to files:

  • src/synthorg/engine/intervention/steering.py
  • tests/unit/persistence/test_protocol.py
  • tests/integration/mcp/test_tool_surface.py
  • tests/unit/api/fakes.py
  • tests/unit/engine/intervention/test_steering.py
  • tests/e2e/test_cockpit_mission_control_e2e.py
  • src/synthorg/api/state.py
  • src/synthorg/persistence/flight_recorder_protocol.py
  • src/synthorg/engine/flight_recording/service.py
  • src/synthorg/engine/agent_engine.py
  • src/synthorg/engine/flight_recording/sink.py
  • src/synthorg/engine/cockpit/service.py
  • src/synthorg/persistence/postgres/flight_recorder_repo.py
  • tests/unit/api/controllers/test_cockpit.py
  • tests/conformance/persistence/test_flight_recorder_repository.py
  • src/synthorg/api/controllers/cockpit.py
  • src/synthorg/persistence/sqlite/flight_recorder_repo.py
📚 Learning: 2026-05-21T22:55:09.289Z
Learnt from: Aureliolo
Repo: Aureliolo/synthorg PR: 2035
File: src/synthorg/meta/toolsmith/config.py:29-30
Timestamp: 2026-05-21T22:55:09.289Z
Learning: For this repo’s Pydantic configuration idiom, do not treat numeric literals passed directly as arguments to `pydantic.Field(...)` as “magic numbers” during review. This includes call-site usages like `Field(default=0.2, ge=0.0, le=1.0)` (e.g., in config models such as `ToolAuthoringConfig`, `ToolValidationConfig`, `ToolsmithConfig`). Do not request extracting those `Field(...)` numeric arguments into named constants, since the repo’s `scripts/check_no_magic_numbers.py` intentionally excludes call-site `Field(...)` numerics and relies on `Field(...)` as the canonical way to express these constraints/defaults.

Applied to files:

  • src/synthorg/engine/intervention/steering.py
  • src/synthorg/api/state.py
  • src/synthorg/persistence/flight_recorder_protocol.py
  • src/synthorg/engine/flight_recording/service.py
  • src/synthorg/engine/agent_engine.py
  • src/synthorg/engine/flight_recording/sink.py
  • src/synthorg/engine/cockpit/service.py
  • src/synthorg/persistence/postgres/flight_recorder_repo.py
  • src/synthorg/api/controllers/cockpit.py
  • src/synthorg/persistence/sqlite/flight_recorder_repo.py
🔇 Additional comments (33)
web/src/router/index.tsx (1)

170-170: LGTM!

src/synthorg/persistence/sqlite/revisions/20260522000002_flight_recorder.sql (1)

20-24: LGTM!

web/src/utils/constants.ts (1)

144-144: LGTM!

src/synthorg/persistence/postgres/schema.sql (1)

395-396: LGTM!

web/src/mocks/handlers/cockpit.ts (1)

14-14: LGTM!

Also applies to: 61-70, 84-84

web/src/utils/status-color.ts (1)

8-20: LGTM!

Also applies to: 33-35

src/synthorg/engine/intervention/steering.py (1)

24-24: LGTM!

Also applies to: 114-118, 126-126

web/src/api/endpoints/cockpit.ts (1)

2-2: LGTM!

Also applies to: 9-16, 24-41

src/synthorg/persistence/sqlite/schema.sql (1)

381-385: LGTM!

tests/unit/persistence/test_protocol.py (1)

26-26: LGTM!

Also applies to: 443-445, 455-461, 1471-1482

src/synthorg/persistence/postgres/revisions/20260522000002_flight_recorder.sql (1)

20-24: LGTM!

web/src/components/ui/timeline.tsx (1)

40-49: LGTM!

tests/integration/mcp/test_tool_surface.py (1)

398-402: LGTM!

tests/unit/engine/intervention/test_steering.py (1)

34-40: LGTM!

Also applies to: 54-58

tests/e2e/test_cockpit_mission_control_e2e.py (1)

17-18: LGTM!

Also applies to: 68-82

web/src/hooks/useMissionControlData.ts (1)

42-60: LGTM!

Also applies to: 79-79, 82-82

src/synthorg/api/state.py (1)

1590-1612: LGTM!

Also applies to: 1619-1619

src/synthorg/persistence/flight_recorder_protocol.py (1)

25-26: LGTM!

Also applies to: 113-153, 164-170, 173-175, 179-188, 200-214, 216-223

src/synthorg/engine/agent_engine.py (1)

36-36: LGTM!

Also applies to: 41-41, 675-706

src/synthorg/engine/flight_recording/sink.py (1)

9-9: LGTM!

Also applies to: 13-17, 69-69, 73-103, 158-164, 183-183, 192-207

src/synthorg/engine/cockpit/service.py (1)

9-9: LGTM!

Also applies to: 119-122, 131-141, 170-178, 180-186

src/synthorg/persistence/postgres/flight_recorder_repo.py (1)

13-13: LGTM!

Also applies to: 16-16, 29-29, 44-50, 67-67, 88-126, 138-138, 143-143, 149-149, 161-207, 209-220, 233-262

web/src/api/types/dtos.gen.ts (1)

333-333: LGTM!

tests/unit/api/controllers/test_cockpit.py (1)

84-90: LGTM!

tests/conformance/persistence/test_flight_recorder_repository.py (1)

164-246: LGTM!

src/synthorg/api/controllers/cockpit.py (1)

110-141: LGTM!

Also applies to: 148-148, 252-252

src/synthorg/persistence/sqlite/flight_recorder_repo.py (1)

95-133: LGTM!

Also applies to: 165-211, 213-224, 239-261

web/src/api/types/openapi.gen.ts (6)

10122-10136: LGTM!


11407-11411: LGTM!


11417-11428: LGTM!


16826-16830: LGTM!


16846-16846: LGTM!


16864-16865: LGTM!

Comment thread src/synthorg/engine/flight_recording/service.py Outdated
Comment thread tests/unit/api/fakes.py Outdated
Comment thread web/src/stores/mission-control.ts
CodeRabbit re-reviewed the round-1 push (review 4348377208, 3
actionable comments on HEAD a6f8b64). All three valid.

Engine:
- engine/flight_recording/service.seek: ``truncated`` now derives from
  ``aggregate.max_turn_index > _MAX_SEEK_FRAMES`` (the actual recorded
  max turn) instead of the operator-supplied ``turn_index``. A scrubber
  that seeks to turn 2000 in a run that only recorded 50 frames is NOT
  truncated, even though 2000 > _MAX_SEEK_FRAMES.

Persistence (sqlite + postgres + protocol + fake parity):
- ``FlightRecorderFrameAggregate.latest_timestamp`` /
  ``latest_execution_id`` now come from the row ordered by
  ``(timestamp DESC, turn_index DESC)`` instead of ``(turn_index DESC,
  timestamp DESC)``. Ordering by timestamp first matches the semantic
  meaning of "latest activity": a frame at turn 5 written 30s after
  turn 6 (clock skew, resumed-run interleaving) is the *more recent*
  activity even if turn 6 has a higher index. Applied to both
  ``SELECT timestamp / execution_id ORDER BY ...`` subqueries in
  sqlite + postgres, the in-memory fake's selection, and the protocol
  docstring.

Web:
- web/src/stores/mission-control.ts: ``fetchFrames`` and
  ``fetchMoreFrames`` now capture the requesting executionId in a
  local before awaiting and re-check ``get().framesExecutionId`` before
  every ``set(...)`` call. A user who loads execution A then quickly
  loads execution B will never see B's timeline polluted with a stale
  A page that lands after the switch.
@codecov
Copy link
Copy Markdown

codecov Bot commented May 22, 2026

Codecov Report

❌ Patch coverage is 86.85567% with 102 lines in your changes missing coverage. Please review.
✅ Project coverage is 85.04%. Comparing base (f81a5ac) to head (729febe).
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
src/synthorg/meta/mcp/handlers/cockpit.py 72.95% 32 Missing and 1 partial ⚠️
...ynthorg/persistence/sqlite/flight_recorder_repo.py 80.39% 18 Missing and 2 partials ⚠️
...thorg/persistence/postgres/flight_recorder_repo.py 81.05% 17 Missing and 1 partial ⚠️
src/synthorg/api/controllers/cockpit.py 88.76% 10 Missing ⚠️
src/synthorg/api/app.py 68.42% 5 Missing and 1 partial ⚠️
src/synthorg/api/state.py 83.78% 5 Missing and 1 partial ⚠️
src/synthorg/engine/agent_engine.py 68.75% 4 Missing and 1 partial ⚠️
src/synthorg/engine/flight_recording/sink.py 89.74% 2 Missing and 2 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2044      +/-   ##
==========================================
+ Coverage   85.03%   85.04%   +0.01%     
==========================================
  Files        2193     2208      +15     
  Lines      127351   128126     +775     
  Branches    10579    10613      +34     
==========================================
+ Hits       108288   108967     +679     
- Misses      16397    16486      +89     
- Partials     2666     2673       +7     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@Aureliolo Aureliolo merged commit 1c2660b into main May 22, 2026
82 checks passed
@Aureliolo Aureliolo deleted the feat/1981-mission-control-flight-recorder branch May 22, 2026 20:00
@Aureliolo Aureliolo temporarily deployed to cloudflare-preview May 22, 2026 20:00 — with GitHub Actions Inactive
Aureliolo added a commit that referenced this pull request May 22, 2026
main merged #2044 (mission-control + flight-recorder) which added the
cockpit MCP domain, cockpit settings namespace, and its own generated
types. Rebasing this charter PR on top required:

- Keeping both charter and cockpit imports in the MCP domain / handler
  aggregators and the SettingNamespace enum.
- Bumping the pinned tool-count assertions to 231 (219 baseline +
  7 cockpit + 5 charter) in test_tool_surface and test_all_handlers_wired.
- Regenerating web/src/api/types/{dtos,enum-values,openapi}.gen.ts so
  both the cockpit and charter DTO additions are reflected (the
  generator is the single source of truth; the rebase conflict markers
  inside the .gen.ts files were resolved by accepting cockpit then
  regenerating to produce the union).
Aureliolo pushed a commit that referenced this pull request May 24, 2026
<!-- HIGHLIGHTS_START -->
## Highlights

> _AI-generated summary (model: `openai/gpt-4.1-mini` via GitHub
Models). Commit-based changelog below._

### What you'll notice
- New brownfield codebase intake mode supports merger and acquisition
scenarios.
- Added deep CEO interview feature to improve project charter creation.
- Introduced mission control and flight recorder operator cockpit for
better operational oversight.
- Research mode added for enhanced exploratory work.
- Runtime services now log safety-spine state at boot for clearer
diagnostics.

### What's new
- Research mode feature enables deeper data exploration.
- CEO interview integration helps shape project charters.
- Mission control and flight recorder cockpit introduced for operational
tracking.

### Under the hood
- Improved codebase modularity with module-size gates and lint
tightening.
- Added __init__.py to 21 test directories for better test discovery.
- Promoted six transitive dependencies to direct dependencies for
clarity.
- Split codespell ignore list into vocabulary and source renames.
- Decomposed oversized web utilities, hooks, and libraries for
maintainability.
- Enhanced CI with Lychee link checker integration and retry logic for
cosign signing.
- Sharded unit and integration tests and added Postgres service
container in CI.
- Updated infrastructure and web dependencies; maintained lock files.

<!-- HIGHLIGHTS_END -->

:robot: I have created a release *beep* *boop*
---


##
[0.8.8](v0.8.7...v0.8.8)
(2026-05-24)


### Features

* brownfield codebase intake (merger/acquisition entry mode)
([#2042](#2042))
([e287621](e287621)),
closes [#1975](#1975)
* deep CEO interview to project charter
([#2045](#2045))
([904f2fb](904f2fb))
* mission control + flight recorder operator cockpit
([#2044](#2044))
([1c2660b](1c2660b))
* research mode
([#2041](#2041))
([f81a5ac](f81a5ac)),
closes [#1989](#1989)
* surface safety-spine state in runtime-services boot log (closes
[#2096](#2096))
([#2097](#2097))
([f187b31](f187b31))


### Refactoring

* add __init__.py to 21 leaf test directories (INP001)
([#2081](#2081))
([2592118](2592118)),
closes [#2064](#2064)
* codebase modularity (1/4) - module-size gates + lint tightening +
tools ([#2078](#2078))
([556fbd9](556fbd9)),
closes [#2047](#2047)
[#2040](#2040)
* promote 6 transitive deps to direct deps
([#2083](#2083))
([adedc6a](adedc6a))
* split codespell ignore-words-list into vocab + source renames
([#2085](#2085))
([917d98a](917d98a)),
closes [#2074](#2074)
* **web:** PR A foundation, decompose oversized utils/hooks/lib
([#2092](#2092))
([#2098](#2098))
([aedbba5](aedbba5))


### CI/CD

* exclude slsa.dev from lychee (transient timeout on canonical badge)
([#2090](#2090))
([346c51d](346c51d))
* fix paths-filter shallow-clone race and scorecard allowlist
([#2089](#2089))
([7cd7ce8](7cd7ce8))
* refresh .test_durations.{unit,integration}
([#2087](#2087))
([ddf2d86](ddf2d86))
* retry cosign sign on transient GHCR/Rekor failures
([#2100](#2100))
([da9422a](da9422a))
* shard test-unit + test-integration, sysmon coverage, Postgres service
container ([#2080](#2080))
([0768787](0768787))
* wire Lychee link-checker (workflow + installer + pre-push hook)
([#2084](#2084))
([1c0694a](1c0694a))


### Maintenance

* Lock file maintenance
([#2086](#2086))
([a78810a](a78810a))
* Update Infrastructure dependencies
([#2055](#2055))
([041ad8b](041ad8b))
* Update Web dependencies
([#2054](#2054))
([4d57b9a](4d57b9a))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

---------

Co-authored-by: synthorg-repo-bot[bot] <279117679+synthorg-repo-bot[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Mission control + flight recorder

1 participant