feat(semantic): curator-driven protocol hardening — decision memory + relation repair

- Add @RATIONALE/@REJECTED to 103+ C4/C5 contracts across backend core, services, API routes, and frontend models
- Fix 109 unresolved @RELATION edges (Auth.*, SupersetClient.*, AgentChat.*, ADR cross-refs)
- Add 13 @ingroup tags for DSA/HCA attention grouping
- Repair 29 stale graph edges via index rebuild
- Update .kilo agent prompts and skills for GRACE-Poly v2.6 compliance
- Git integration: merge routes, branch lifecycle, remote providers, UX components
- 0 broken anchor pairs, index rebuilt with 0 parse warnings
This commit is contained in:
2026-07-02 08:53:19 +03:00
parent 87ac90bb8d
commit db998ce085
144 changed files with 10111 additions and 762 deletions

View File

@@ -10,6 +10,11 @@
# @SIDE_EFFECT Starts background scheduler and binds network ports for HTTP/WS traffic.
# @DATA_CONTRACT [HTTP Request | WS Message] -> [HTTP Response | JSON Log Stream]
# @RATIONALE Duplicate @RELATION and @INVARIANT lines removed from header. Import sorting unified via ruff isort (I) rule across src/ — 139 fixes applied.
# @REJECTED Monolithic route registration in app.py was rejected — route groups are now modular
# in separate router modules under api/routes/ to keep AppModule focused on middleware,
# lifespan, and WebSocket endpoint wiring. Embedding lifespan logic directly in module
# scope was rejected — the asynccontextmanager pattern ensures clean startup/shutdown
# lifecycle without module-level race conditions.
import asyncio
from contextlib import asynccontextmanager
@@ -384,7 +389,7 @@ async def log_requests(request: Request, call_next):
# @BRIEF Register all FastAPI route groups exposed by the application entrypoint.
# @RELATION DEPENDS_ON -> [FastAPI_App]
# @RELATION DEPENDS_ON -> [Route_Group_Contracts]
# @RELATION DEPENDS_ON -> [AuthApi]
# @RELATION DEPENDS_ON -> [Api.Auth]
# @RELATION DEPENDS_ON -> [AdminApi]
# @RELATION DEPENDS_ON -> [PluginsRouter]
# @RELATION DEPENDS_ON -> [TasksRouter]
@@ -432,7 +437,7 @@ app.include_router(maintenance.maintenance_router)
# @BRIEF Authenticate a WebSocket connection via JWT or API key from query param `token`.
# @PRE websocket is a live Starlette WebSocket before accept().
# @POST Returns True if token is valid, logs reason; returns False if rejected.
# @RELATION DEPENDS_ON -> [AuthJwtModule]
# @RELATION DEPENDS_ON -> [Auth.Jwt]
# @RELATION DEPENDS_ON -> [APIKeyModel]
# @SIDE_EFFECT Performs DB read to validate API key hash.
async def _authenticate_websocket(websocket: WebSocket, endpoint_name: str) -> bool:
@@ -506,6 +511,14 @@ async def _authenticate_websocket(websocket: WebSocket, endpoint_name: str) -> b
# @DATA_CONTRACT [task_id: str, source: str, level: str] -> [JSON log entry objects]
# @INVARIANT Every accepted WebSocket subscription is unsubscribed exactly once even when streaming fails or the client disconnects.
# @UX_STATE Connecting -> Streaming -> (Disconnected)
# @RATIONALE Uses asyncio.wait with two queues (log + status) to multiplex task logs and status
# updates over a single WebSocket connection — eliminates the need for the client to
# open a second socket or poll /api/tasks for status changes. Server-side source and
# level filters reduce bandwidth by discarding irrelevant log entries before transmission.
# @REJECTED Separate WebSocket connections for logs vs status was rejected — doubles connection
# overhead and complicates client-side synchronization. Client-side filtering was rejected
# — sends unnecessary data over the network when the server can discard early. Polling
# /api/tasks for status changes was rejected — introduces latency and load.
#
# @TEST_CONTRACT WebSocketLogStreamApi ->
# {
@@ -725,6 +738,13 @@ async def websocket_endpoint(
# @RELATION CALLS -> [TaskManagerPackage]
# @PRE WebSocket must be authenticated via `token` query param.
# @POST WebSocket streams task status events until disconnect.
# @RATIONALE Push-based global task event stream replaces per-task status polling — a single
# WebSocket delivers status changes for all tasks, enabling real-time dashboards and
# notification UIs without repeated /api/tasks queries.
# @REJECTED Per-task WebSocket subscriptions was rejected — the task-manager already publishes
# global events, so subscribing per-task duplicates the subscription overhead.
# Polling /api/tasks was rejected — introduces latency, load on the DB, and
# misses events between polls.
@app.websocket("/ws/task-events")
async def task_events_websocket(websocket: WebSocket):
"""
@@ -773,6 +793,12 @@ async def task_events_websocket(websocket: WebSocket):
# @RELATION CALLS -> [TaskManagerPackage]
# @PRE WebSocket must be authenticated via `token` query param.
# @POST WebSocket streams maintenance events until disconnect.
# @RATIONALE Push-based maintenance event notification replaces polling /api/maintenance/events —
# maintenance windows are time-sensitive (banner visibility, creation/ending); push
# ensures sub-second delivery without DB load from polling.
# @REJECTED Polling /api/maintenance/events was rejected — maintenance state changes are
# infrequent but time-critical; polling wastes resources during long idle periods
# and still incurs latency.
@app.websocket("/ws/maintenance/events")
async def maintenance_events_websocket(websocket: WebSocket):
"""