Commit Graph

1169 Commits

Author SHA1 Message Date
fc8a9bf45d feat(maintenance): support insecure TLS mode 2026-09-10 13:46:11 +03:00
9d2e856e3f fix(maintenance): make example scripts ASCII-only 2026-09-10 12:29:30 +03:00
e1dcf7cf90 fix(maintenance): INV_7 routes decomposition, UX contract-drift repair, RBAC/L2 test gaps closed
- decompose _routes.py (947 lines) into a 27-line facade + 5 handler modules (events/preview/start/end/settings), all <=400; extract _chart_layout from _chart_manager (441->381+78); contract IDs preserved verbatim, 9 routes registered in original order
- close RBAC FR-015 invariant gap: tests/api/test_maintenance_routes_rbac.py — 403 denied + 401 unauth on all 9 endpoints with exact guards (root cause of the blind spot: conftest MaintenanceRouteEnv overrode permission closures with lambda: None)
- repair 4 UX contract drifts: EventsTable empty-state + expandedEventIds invariant aligned to implementation (backend terminal-events expansion is intended per MaintenanceEventStateStatuses @POST); Badge phantom loading state removed (INV_9); SettingsPanel fields disabled during Saving implemented per contract
- add 34 L2 component tests (EventsTable/Badge/SettingsPanel) covering declared @UX_STATE/@UX_TEST/@UX_RECOVERY
- split oversized test files (709/686/624 -> all <=520, collected counts identical)
- test hygiene: RootTransaction is_active guard removes SAWarning in shared postgres fixture; AsyncMock create_task coroutine leak fixed in scheduler tests (zero RuntimeWarnings)
- examples/maintenance actualized against current API: optional environment_id with PROD fan-out (batch response), 422 no-PROD-target, GET events/{id}/dashboards, settings field list

Verified: isolated worktree (HEAD + this diff) 729 backend tests passed; frontend 109 passed; ruff clean; anchors balanced; index rebuilt (0 warnings)
2026-09-10 10:57:18 +03:00
1b9cb2b352 fix(migration): compare only obtainable fields in dry-run diff + archive key mapping
- archive_parser: canonical compare-field specs (position->position_json), presence-checked `fields`, shared normalization; keep backward-compat signature
- dry_run_orchestrator: intersection-based object diff — no false "update" on 6.x LIST exposure; 4.1.2 create-only limitation documented and pinned
- translate: unshadow fastapi.status in job list route (ValueError now 400) + unskip regression test
- tests: real-container migration plugin PARTIAL_SUCCESS/dry-run e2e, Superset LIST column-exposure characterization, translate malformed-LLM e2e + pg_e2e split (<800-line cap), dict_snapshot_hash DATABASE_URL poisoning fix, dead BINDS_TO/edge repairs
2026-09-08 06:09:25 +03:00
9c1a1e093c feat(mcp): Phase 2d field-run remediation — ADR-0024 agent-run surface, derived capabilities, disposition clarity
Source: live external MCP run against ss-prod Sales Dashboard (docs/2026-09-07-sales-prod-mcp-run.md) proved the initial-bootstrap chain externally unreachable: register_draft_pack requires a principal-owned AgentRun but no MCP operation created one after the chat decommission; the vertical E2E masked the gap with a raw-ORM prerequisite seed.

T029i: MCP create_agent_run/get_agent_run (mcp_server/tools_agent_run.py) over Services.AgentRuns.Service.Create — REST-parity EXECUTE/READ permissions, human-only, server-pinned UIContext, idempotency-key replay; catalog 2.1.0->2.2.0; MCPX-FR-027 external-reachability invariant pinned; initial-scenario E2E converted to the fully external chain (zero non-MCP seeding); strict-xfail pin flipped as designed, unmarked and hardened (E2E-EXT-001 CLOSED).

T029k: ScenarioGraph.CapabilityAuthority — truthful capability facts derived from the authoritative DashboardQueryModel (mutation-context capabilities never derived), derived-wins merge over caller declarations, single choke point wired into MCP inspect_scenario / inspect_dashboard_context and REST api_compile_scenario; CAP-001 classification-fix test on the sales-shape fixture (B02-B04/T01-T03 automated, C04-C06 unsupported, unsafe-mutation cases legitimately human).

T029l: disposition vocabulary clarity — RU/EN labels name the persisted outcome (confirm->passed), confirm restyled bg-destructive->bg-primary, decide_checkpoint description carries the immutable outcome table; lifecycle mapping and API vocabulary unchanged (DISP-001 CLOSED).

Decision memory: ADR-0024 (IMPLEMENTED, 4 rejected alternatives incl. no-AgentRun boundary and implicit auto-create) + README registry; 050 MCPX-FR-027/028/029 + release-gate rows + Clarifications session 2026-09-07; 038/044/045 field-run amendments -> IMPLEMENTED; WORKSTATE checkpoints (plan round + execution round).

Pre-existing HEAD regressions surfaced by the first full-suite rerun since 4d5ef6be/58c5ae39 and fixed: (1) stale SC-007 resource pin — canonical identifier is the post-redirect /mcp/ (code + twin pin aligned since the batches; test_mcp_client_flow_http pin updated with rationale); (2) app-lifespan tests re-entered the run-once StreamableHTTPSessionManager module singleton — autouse fresh-transport-app fixture (production lifespan runs once per process; singleton stays correct there).

Gates: full backend suite 11357 passed / 243 skipped / 1 xpassed / 0 failed (first green full run since the batches); MCP+catalog slice 70 passed; capability slice 67 passed; frontend vitest 3507 passed (206 files), lint 0 errors (364 baseline warnings), build OK; ruff/compileall clean; anchors balanced; scoped git diff --check clean. INV_7 watch: tools_scenario.py 508 LOC and routes scenario.py 442 LOC flagged for the next decomposition pass (new code lives in new modules 155/236 LOC).

OPEN: T029m / E2E-EXT-002 — live-stand replay of the sales scenario through the full external chain. Not included (foreign uncommitted workstream): translate/migration integration tests, _job_routes.py, .kilo/agent-manager.json, specs-036-050-20260907-111314.md.
2026-09-07 16:52:38 +03:00
58c5ae39cb feat(scenario): server-owned handle pipeline T029d–h + MCP bootstrap/automation + UI launch/approval
Backend (Phase 2c, closes ADR-0023):
- T029b/c: 9 automation MCP tools (REST-parity RBAC, scheduler registration, idempotency), migration 0018; fresh-DB MCP E2E.
- Guard BOOTSTRAP_REVISION_NOT_RUNNABLE in derive_runner_plan (provenance-only revisions never queue a vacuous zero-step PASS); demoted to defense-in-depth after materialization landed.
- T029d: CompiledScenarioHandle/ValidationResultHandle/DraftPackHandle (immutable, owner-bound, content-addressed canonical-bytes store), migrations 0019/0021; minting at REST compile/validate/resolve/draft-pack boundaries; single consumption under SELECT...FOR UPDATE + populate_existing, proven on PostgreSQL (Testcontainers).
- T029e: handle-first create_scenario/create_initial materialize canonical graph_snapshot (+ server-owned action_registry identity) in-transaction; OutboxEvent + RevisionMaterialization (0020) with idempotent worker wired into the scheduler poll loop (30s tick).
- T029f: MCP register_draft_pack write tool; bootstrap accepts only stored handle ids (transitional compile:{run}:{digest} removed); legacy REST POST /scenarios/{id}/revisions retired -> 410; catalog 2.0.0 (pinned-major ritual); ActionRegistry 038.2.0 — generate_report reclassified non-mutating (local draft write), register_artifact/row_edit/bulk_edit stay mutating.
- T029h (hybrid C+X1): inspect_dashboard_context MCP tool (live DashboardQueryModel resolver); context_authority evaluation — server recomputes client-context fingerprint (claimed values ignored), sentinel fingerprints never verify, unreachable env fails open to unverified, live-env mismatches reject typed with zero rows; marker persists on DraftPackHandle, materializes into graph_snapshot; PROD start refuses explicit non-verified (CONTEXT_AUTHORITY_REQUIRED_FOR_PROD); validator recursively rejects query_context/SQL smuggling in dashboard_context; catalog 2.1.0. 043 editor path provably inherits the marker.

Frontend:
- D2: scenario detail route scenarios/[id] — first production host of RunConfigurationPanel (typed 044 launch + Idempotency-Key + redirect to run monitor); ROUTES.scenarioDetail SSOT; registry index links to detail (launch stays off the index).
- D4: ApprovalDecisionPanel + RunMonitorModel.decideApproval — PROD gates decidable from the web UI (run-detail aside on pending_approval).
- Pre-existing suite repairs: oauth-consent raw goto -> ROUTES.login(); InvestigationModels stale dispose signature; settings mcp_oauth_* bind:value undefined crash (backend defaults 15/30/90).
- i18n: approval_* + scenario_detail_* keys in en+ru.

Specs/docs (amendments 2026-09-06/07):
- 038: PackCompiler.Generate contract corrected (pure manifest); ServerOwnedPipeline handle-persistence amendment; verification-program reconciliation (implemented vs PROPOSED IR entities).
- 042: synchronous graph materialization + outbox scope; CreateInitial amendments; RevisionChain @REJECTED for raw client graph_snapshot.
- 050: stage-table implementation-status note, handle-rules status, T029–T029h evidence; WORKSTATE checkpoints; ADR-0023 -> IMPLEMENTED.

Gates: backend full regression 3360 passed (+ PostgreSQL integration green), alembic single head 0021; frontend vitest 3506 passed, lint 0 errors, build OK.
2026-09-07 11:26:34 +03:00
4d5ef6bed0 feat: dashboard-testing UX remediation + admin MCP governance + i18n sweep
- UX audit Fix 1-5: actionable MCP HandoffSurface (endpoint/discovery/onboarding), reachable
  approval loop (sidebar section + waiting-for-me badge), honest MCP entry labels, ROUTES SSOT
  for dashboard-testing/load-testing (+ link-integrity coverage)
- scenario registry hub (/dashboard-testing/scenarios) built on ScenarioRegistryModel
- admin MCP governance: read-only GET /api/admin/mcp/catalog (catalog x roles + DCR clients) +
  /admin/mcp page/model/api + ROUTES.admin.mcp + sidebar entry
- full i18n sweep of dashboard-testing routes and scenario-* component trees (ru/en)
- accumulated workspace: MCP OAuth/DCR, automation idempotency migration, docker/nginx, specs
2026-09-05 20:16:26 +03:00
3d78569235 fix(logging): enforce single JSON protocol on console — uvicorn takeover + library noise demotion
uvicorn/uvicorn.error adopt the shared CotJsonFormatter handlers (own plain-text handlers replaced, propagate=False); uvicorn.access silenced by default — middleware JSON framing already narrates every non-polling request, and the plain 'INFO: host - GET ...' access lines were the duplicate-console-format source under run.sh. LoggingConfig.uvicorn_access_log=True restores access output as JSON, never plain text.

Unmarked library records map deterministically in CotJsonFormatter: ERROR+ -> EXPLORE with exc_info traceback captured into the error field (<=1000 chars), below -> REASON. Explicit marker always wins.

httpx/httpcore demoted to WARNING via LoggingConfig.http_client_log_level ('HTTP Request: ...' per outbound Superset call is polling-amplified noise; our CoT layer narrates those requests). Git NO_REPO branch: 10 interpolated REASON lines per batch poll -> one invariant-intent DEBUG line with payload{dashboard_id,result} (ADR-0021 intent-invariance).

Tests: uvicorn takeover x3, httpx demotion x2, formatter marker mapping x3 — logger/formatter suites green (42), ruff clean. NOT included (entangled with a parallel session's WIP in the same files, stays in working tree): app.py POST-batch framing suppression + its middleware test, and the Run Center runaway-fetch-loop fix + regression test.
2026-09-05 10:09:49 +03:00
65121cac6b feat(logging): self-diagnosing EXPLORE + shared/ absorption + belief analytics (ADR-0021/0022)
T0: absorb shared/ into backend — cot_logger→src/core, CotJsonFormatter→src/core/cot_formatter.py, _llm_http/_llm_health/ssl→src/core/utils; imports rewritten (26 prod + tests, patch targets); run.sh/backend.Dockerfile/requirements/.axiom source_dirs/semantic_health/AGENTS/INSTALL cleaned; ADR-0022 supersedes ADR-0015; fixed latent CI defects (ss_tools ImportError, record.message in logger tests, same-name test-module collision).

ADR-0021 wire enrichment (additive): contract_id/claim/error_code/loc fields; _contract_id ContextVar + resolve_contract_id (explicit > belief_scope > declared-src mirror, derived src never mirrors); EXPLORE auto-loc via single frame walk; facade error auto-fill; 2KB payload cap with payload_truncated/payload_bytes markers; migrated 85 error="CODE" sites to error_code= (12 files); pilot editor/load.py; superset preview payload-bomb inlined bodies removed.

Analytics SSOT src/core/log_stats.py (bond transition matrix, orphan-EXPLORE ratio, REFLECT pairing, intent families, coverage, insufficient-sample flag); pretty_cot.py --stats/--digest/--trajectory/--story over one engine; log_gap_service three-tier ground-truth triangulation (FAILED w/o EXPLORE etc.) + GET /api/reports/log-stats|task-log-gaps (polling-suppressed); scripts/cot_audit.py CLI; enriched fields persisted into task_logs.payload for tier queries.

Frontend: ReportsAnalyticsModel + AnalyticsStatsPanel (Logs tab) + TaskGapPanel and per-row T1/T2/T3 gap badges (Tasks tab); cot-logger.ts ADR-0021 opts; i18n en/ru. Scheduler console spam fixed: apscheduler logger demoted to WARNING via LoggingConfig.scheduler_log_level. .axiom belief patterns -> $OBJ.* (alias undercount). molecular-cot-logging skill updated (fields, decision rules, tie-break, CLI) and synced.

Reviewed orthogonally: F1 cot_span contract pollution, F2 cap boundary accounting, F3 digest over-dedup, F4 trace-state bound, F5 tier metadata — fixed with regression tests. Validation: backend 11287 passed + ruff + compileall; frontend 3446 passed + lint + build; CLI smoke on live app.log.
2026-09-04 20:56:41 +03:00
34a6507fa3 chore(semantics): Axiom live re-review — curator pass 46 edges (unresolved 446→401) + MCP happy-path UX audit
Closure-gate re-review of rounds 1-5 with the Axiom index live (full rebuild 10534 contracts): remediation matrix all CLOSED, SC-001..SC-009 walkthrough carried current executable pins, verdict recorded in specs/WORKSTATE-043-047.md.

Curator pass (comment-only, zero runtime change; every target verified against the live index before retargeting): mcp_server zone 6 edges fixed (Services.AgentAuthoringWorkspace.Service, McpServer.Package→McpServer, phantom SupersetClient.DashboardWrite → three verified Core.DashboardsWrite/Datasets contracts, AgentSuperset.SqlFormat) — scoped audit now 0 unresolved; plus 35 historical retargets (scenario chain → function-level contracts, Superset-client alias/path forms → Core.Init.SupersetClientModule, Models.User→Models.Auth.User ×5, ExecuteEnvelope→ExecuteQueryEnvelope ×6, GitService/Deployment/StructureSnapshot/DashboardTesting.Core, client_registry python-path forms) and 11 malformed multi-target translate-plugin lines split into individual @RELATION lines with verified IDs. Workspace unresolved relations 446→401; remainder classified and queued (logging-SSOT zone owned by the concurrent shared→backend migration, function-shaped targets, legacy single-# regions).

UX audit (read-only, findings + prioritized fix plan persisted in WORKSTATE): MCP happy path for a BI analyst scores 2/5 — CRITICAL: handoff surface gives no endpoint URL/discovery/client onboarding; approval loop (/dashboard-testing/runs WaitingForMeView, HumanCheckpointPanel) unreachable via navigation (absent from ROUTES.ts and sidebar). HIGH: AI/Ассистент buttons promise chat but land on a decommission stub; no MCP settings/status surface anywhere. MEDIUM: dashboard-testing/load-testing routes bypass the ROUTES SSOT.
2026-09-04 20:41:38 +03:00
96f6965845 feat(agents): inject semantic nav map (root.map) into agent context
- .kilo/kilo.jsonc: instructions=["docs/api/nav/root.map"] — the
  semantic module digest (doc-gen --nav) is auto-injected into the
  starting context of every agent session (~14 KB: areas, per-module
  purpose/kw/deps, collapsed tests).
- AGENTS.md: documented the L0->L3 navigation protocol (root.map ->
  <Name>.map -> nodes/<Contract>.md -> source via FILE:line), nav_id.map
  fallback, and the re-read/regenerate freshness rule (the injected map
  is a session-start snapshot).
- .kilo/setup-script: generate docs/api/nav for fresh Agent Manager
  worktrees (gitignored artifact; uses $REPO_PATH/../axiom-mcp binary,
  cold index build ~60s, graceful skip when the binary is missing).

Requires ../axiom-mcp doc-gen with the semantic root (see axiom-mcp
"feat(docs): semantic module digest root.map" commit); regenerate via
`make docs-nav`.
2026-09-04 17:39:31 +03:00
4c57789218 fix(mcp): closure-gate remediation rounds 2-5 — unified CoT logging, server.py decomposition, 050 P2 queue closed
Round 2 — P1 MCL + GRACE:
- logger intent-drop repaired across 182 call sites; logging unified repo-wide on the
  intent-first facade (211 direct SSOT log() sites migrated); facade level= support;
  molecular-cot-logging skill synced with the module (.agents -> .kilo).
- EXPLORE/REASON-REFLECT gaps closed: poll-dispatch failure path, exploration fail-closed
  choke point in _finish(), 9 silent mcp_ops_dispatch adapters.
- INV_6: dead agent/app.py edge removed (_llm_health); specs 033/035/036/039 sweep ->
  0 dead edges (5 retargeted to live IDs, 15 tombstoned with successors).
- INV_9 dedupes (TaskDrawer BINDS_TO, vestigial assistantOffset, duplicated @SIDE_EFFECT);
  INV_1: migrations 0014-0016 anchored, exploration_sandbox module-region span fixed.
- Full-suite defect root-caused: leaked DI singleton mocks from test_dependencies_unit ->
  autouse restore fixture + get_session_idle_timeout_minutes hardening (int validation,
  EXPLORE fallback SESSION_POLICY_CONFIG_INVALID).
- Executable pins: tests/test_core/test_logger_wire_format.py (wire fields, misuse proof,
  repo-wide AST sweeps over both forbidden shapes).

Round 3 — server.py decomposition EXECUTED per the binding gate plan
(specs/050-mcp-interface/plans/server-decomposition-gate.md, execution log included):
- 1571 -> 177 LOC: scenario_inputs.py (268), auth.py (238, single _access_token_context
  site), rbac_server.py (393), tools_authoring.py (367), tools_scenario.py (373).
- Addendum E: pre-existing ops_tools.py INV_7 offender split 420 -> 215 + tools_review.py (253).
- Contract IDs frozen, import surface frozen, registration order frozen; monkeypatch seams
  relocated to owning modules (recorded); zero behavior diff.

Round 4 — P2 queue closed:
- Story 5 AC2: HandoffSurface copyable prompt parameterized with dashboard context
  (/agent route forwards objectType/objectId/objectName/envId/route/intent; i18n
  handoff_context_label ru/en; contract + render tests).
- E6 / MCPX-FR-007a: McpTransportGuard enforces server-owned JSON-depth bound (typed
  400 json_depth_exceeded pre-dispatch, iterative fail-closed walker) and per-session
  sliding-window rate limit (typed 429 rate_limited + standard Retry-After); rejections
  create no mutable state. Limits live in McpServerConfiguration.
- SC-005 remnants CLOSED: /api/assistant router unmounted (package retained as MCP parity
  provenance, header records rationale); /api/agent/llm-config REMOVED with in-place
  Tombstone + dead strict service DI deleted; assistant.ts deleted (inbound edge removed
  first); SystemSettings assistant-retention UI + 16 i18n keys removed; .env.example
  7860/GRADIO vars removed (zero consumers verified repo-wide).
- SC-004 + SC-009: exact RBAC catalog pins (admin 47 / analyst 21 / viewer 15 derived from
  the live catalog); mid-flow role revocation hides tools in the next tools/list AND denies
  cached-catalog calls by name on the same identity-only token; mid-flow grant exposes the
  approvals surface without new consent.
- Browser cookie-consent decision recorded (tasks.md T008): not built in 050.

Round 5 — last 050 task + FR-010:
- T008b: Core.EndpointLocality deny-by-default perimeter guard for LLM/VLM provider base_url
  at the create/update choke points (private ranges, enterprise DNS suffixes, all-private
  resolution; fail closed; anti-substring-spoofing; empty URL denied); typed 400
  endpoint_not_local:<reason> pre-persistence; EXPLORE audit line on every denial; env
  escape hatches documented (INSTALL.md "Локальный периметр").
- MCPX-FR-010: MCP_CATALOG_VERSION published as serverInfo.version at initialize;
  deprecated/deprecation_note on McpToolDefinition; [DEPRECATED] marker at the single
  list_tools choke point (entry stays listed/callable one minor cycle); deliberate
  major-bump ritual pinned by test.

Evidence: full backend suite 11243 passed / 240 skipped / 1 xpassed / 0 failed;
frontend vitest 3435 passed / lint 0 errors; MCP slice 103; locality slice 107;
anchor+AST sweeps ALL BALANCED over 138 touched files; 050 tasks.md fully [x] with proof.
2026-09-04 13:07:08 +03:00
a0450b33a9 fix(mcp): closure-gate remediation round 1 (P0) — checkpoint tools, client_credentials, gate shape-unwrap, SC-007 HTTP flows
FR-019 (was a false [x]): MCP list_checkpoints + decide_checkpoint over the
044 CAS lifecycle (server-resolved pending checkpoint, decision_version CAS,
continue_after_human_decision, typed conflict/not_found); catalog scenario:RUN
and service_allowed=False — automation has no path to checkpoints.
tests/test_mcp_checkpoints.py: 3 passed.

FR-013/SC-007: client_credentials grant for machine clients — confidential DCR
(one-time client_secret, sha256-only via migration 0017_oauth_client_secret
with idempotent guard), signed identity-only service-principal tokens
(principal_type=service, aud=mcp, no refresh), McpTokenVerifier service
short-circuit, AS metadata grants/auth-methods, INSTALL.md §MCP-client docs.
tests/test_mcp_client_flow_http.py: full scripted-client flows over real HTTP
(machine: discovery→DCR→client_credentials→/mcp initialize→tools/list→call;
user: DCR→PKCE S256 authorize via Bearer web session→exchange→/mcp live-RBAC
listing). 2 passed; oauth suite 10 passed.

PRODUCTION DEFECTS fixed en route: call_tool argument-inspection gates parsed
only the FLAT shape while FastMCP delivers {"request": {...}} —
start_scenario_run was uncallable over MCP and the PROD-SQL terminal denial was
bypassable by the wrapped shape. Both gates now unwrap via _gate_arguments;
regression pinned by flat x wrapped PROD matrix (6 combos).

E2E-AUTH-001..003 release-gate rows closed with evidence: T028 chain gained
propose_test_plan (single-trace 001); T023 extended with post-activation
start_scenario_run on the canonical runner-shaped fixture graph, asserting the
queued run pins promoted revision_id + content_hash (003); 002 already proven.

Record honesty: tasks.md T025/T008/T008b/T032 downgraded at review time;
T025+T008 re-closed with executable evidence; T032/T008b/T005a remain open in
the round-2 queue (recorded in WORKSTATE checkpoint with the full P1/P2 list:
MCL intent repair, dispatch/sandbox EXPLORE traces, INV_6 tombstones,
SC-005 remnants, FR-010 versioning, depth/rate limits).

Evidence: combined MCP slice 95 passed; alembic single head 0017; ruff and
compileall clean; anchors balanced in all touched files.
2026-09-03 13:02:57 +03:00
ddbfe00fc5 fix(semantics): round 3 — zero parse warnings via relation/canonical fixes, MCP parser patches
- All schema parse warnings NOW ZERO (unclosed, def_deprecated, invalid_enum,
  unknown_tag, invalid_predicate, invalid_tier: 0).
- Redirect 42 dead @RELATION targets to existing contracts (Core.Database.*→
  DatabaseModule, User→Models.Auth.User, create_task→Core.Manager.TaskManager,
  AuthMiddleware→Dependencies.AppDependencies, AuthRepository→Core.Repository.*,
  _handle_deploy_helpers→Api.RepoLifecycleRoutes, etc.).
- Config: add NAMESPACE/SEE (Doxygen-native), TYPE empty-enum (suppress JSDoc
  @type false positives), remove *.html exclude (prototype contracts now
  indexable), extend LAYER enum.
- Plan doc: record round-3 results (2066→1171, -43%).

MCP parser fixes (axiom-mcp sibling repo):
- comments.rs: detect block-comment terminator BEFORE stripping leading '*'
  (bare '*/' close line no longer stays open → 20 Svelte __unclosed__ cleared).
- parser.rs line 249: only comment-normalized lines carry GRACE anchors
  (payload.unwrap_or('') instead of .unwrap_or(raw_line)) → string-literal
  '#region' misreads + prose [DEF:] false positives cleared.
2026-09-03 09:09:21 +03:00
731aaaa8df feat(mcp): 050 unified MCP interface — parity tools, durable gates, authoring E2E, assistant decommission
044 provider runtime completion (pre-staged workstream): capacity/operator
stores, provider ops/protocol/reconciler/dispatch revalidation, exploration
sandbox runtime, alembic 0014-0016, live canary evidence (browser provider
6/6 against the live stand).

050 Phases 0-2: RBAC FastMCP server with a 45-tool explicit catalog,
OAuth/DCR transport guards with bounded bodies, per-call provenance
(McpToolInvocationRecord), durable ActionApprovalGate + CAS decide +
leased/fenced poller, authoring workspace ops, bounded-response discipline,
hidden-vs-gated matrices.

Parity domains (T012-T014): gated git/deploy/migration/backup/llm tools with
reviewed dispatch adapters in explicit poll chains; Superset reads/writes with
a dedicated plugin:superset_sql risk class (terminal PROD denial via the
canonical execution-policy criterion, hardened danger-SQL guard covering
INTO/CALL/SET/REFRESH/file primitives/multi-statement); baseline 037 tools
over the shared REST-surface services.

Evidence (T016/T023/T028): REST-vs-MCP field parity on shared 037 fixtures;
vertical E2E from tools/list through registry revision activation with real
scenario:EDIT RBAC; sandbox-to-revision promotion E2E with unsafe-payload and
caller-digest rejection; dispatcher soak (three poll cycles, exactly-once).

Orthogonal QA+security audit hardening: enforced response_limit fail-closed
envelope, poisoned-exploration fail-closed (EXPLORATION_TARGET_UNRESOLVED),
sha256 exploration evidence digests, actor-UUID task ownership, is_active
guard on baseline consume, 038 resolver description=None selector fix.

Phase 3/4 decommission: HandoffSurface behind the MCP_DECOMMISSION flag,
then unconditional removal — agent/ service tree, chat components/models/
stores/types, gradio proxies (vite + nginx), agent service in run.sh,
docker-compose profiles, build.sh bundles; /agent renders the handoff only.
Docs: AGENTS.md/INSTALL.md two-service rewrite; 036-047 drift amendments
marked done; WORKSTATE checkpoints with all evidence.

Suites: backend 11199 passed / 240 skipped / 1 xpassed; frontend 3454 passed
(197 files), lint 0 errors, build OK; browser E2E login+handoff 6/6 twice on
the isolated compose stack (no 7860); ruff/compileall clean.

Misc: gitignore hardening (tmp/, tool model cache); E2E selector repairs
(nav strict-mode, invalid-credentials passthrough detail).
2026-09-03 07:37:14 +03:00
341d54399a fix(semantics): repair GRACE-Poly anchors, relations, and metadata
Repair broken/unclosed semantic-protocol markup across the codebase:

- INV_3 region pairing: restore 87 bare '# #endregion' (6 test_structure_*
  files) and 321 bare '// #endregion' (13 frontend test files) with their
  matching IDs; hand-fix 26 Python + 12 frontend + 2 E2E files with
  mismatched/missing/premature/duplicate closes; fully migrate
  test_orthogonal_fixes.py from single- to double-hash anchors.
  Workspace-wide stack-pair scan now passes 6569 code files with 0 problems.
- Relations: normalize legacy predicates USES/CONTAINS/BELONGS_TO to
  canonical DEPENDS_ON/BINDS_TO (28 edits).
- Metadata: normalize @LAYER and [TYPE] enum values to the canonical
  vocabulary (App->Application, lib->Infra, Service/Route/Checklist/
  Declaration/Decorator/Functions -> Module/Function/Block, etc.).
- Config: extend tags.LAYER.enum; fix tools.py prose '#region' phantom that
  broke anchor nesting.
- Remove dead scratch scripts backend/_convert_defs.py, _batch_convert_defs.py.

Index refresh: contract count 9576 -> 10821; schema_unclosed_anchor
1179 -> 729 (remaining 729 are markdown legacy [DEF:]/brace anchors, a
separate migration phase).
2026-09-01 12:24:42 +03:00
7a14a4d947 feat: add MCP authoring workspace foundations 2026-08-28 19:01:42 +03:00
e14524d22a fix: resolve test and lint gate failures 2026-08-26 18:56:57 +03:00
0415a2ed7d chore: accumulate uncommitted workspace changes 2026-08-26 17:03:22 +03:00
c4ccfcc9fd fix(migration): dual-mode recovery logging + regression tests for PR-0160 incident
The composite-key recovery branch crashed with TypeError depending on execution
mode: TaskLogger requires metadata=, app CoT logger requires extra=. The earlier
metadata= fix repaired task-context runs but broke context-less runs (6 existing
tests confirmed).

- add _emit_task_log: inspect-based kwarg selection per logger backend
  (@REJECTED TypeError-catch: masks genuine logging failures)
- add test_migration_recovery_regression.py with a REAL TaskLogger (mocks
  silently accepted the wrong kwarg, which is why the prod bug was never
  caught): recovery success phases started/sync/retry_import/completed,
  context-less mode, invalid mutation-server coercion to target,
  retry-failure entry fields, NO_MATCHES short-circuit
2026-08-26 13:37:27 +03:00
e3754b0931 sync skills 2026-08-26 13:13:02 +03:00
6cfd9135bb fix: resolve production log errors — profile, datasets, migration recovery, mapper validation, reencrypt
- AuthRepository: add missing save_user_dashboard_preference (PATCH
  /api/profile/preferences returned 500)
- DatasetItem.schema_name nullable — GET /api/datasets no longer 503s on
  Superset datasets with null schema
- migration: TaskLogger calls used extra= kwarg which raised TypeError and
  killed the composite-key recovery branch, leaving the target server
  unrepaired after failed dashboard imports (e.g. PR-0160); switched to
  metadata=
- maintenance settings: lazy-create singleton with IntegrityError race guard
  instead of permanent 404
- mapper upload-xlsx: structured 400 detail (expected vs actual columns);
  MapperTool shows inline error panel instead of toast; i18n ru/en
- connection_service: eager re-encryption of legacy plaintext passwords in
  get_connection; returns a copy so live config never holds plaintext
- check_target_schema: log exception type/repr/traceback (was empty error)
- scheduler/maintenance auto-end: skip empty-tick INFO logs; suppress HTTP
  framing for GET polling endpoints
- reencrypt script: repair broken merge artifact, JSON-serialize payload on
  save, fix failed-count arithmetic
2026-08-26 12:50:03 +03:00
8a3bba139e fix(database): auto-reset orphaned Alembic revisions 2026-08-25 16:06:14 +03:00
4b9619e229 refactor(deploy): standardize enterprise environment file 2026-08-25 15:30:10 +03:00
a2ede492b7 fix(database): reset any legacy Alembic revision 2026-08-25 15:21:42 +03:00
e80c954b37 fix(build): defer bundle secrets to deployment 2026-08-25 12:24:51 +03:00
5bc1b62bd0 refactor: unify initialization and reset migration baseline 2026-08-25 11:42:31 +03:00
cfb13d9a69 chore(agents): migrate command definitions 2026-08-24 17:02:22 +03:00
9fb37a7e9d fix(settings): normalize empty validation policy lists 2026-08-24 17:02:15 +03:00
c1222eb906 feat(scenarios): add SQL evidence and bounded transforms 2026-08-24 17:02:06 +03:00
0c895cf416 feat(logging): unify canonical task CoT events 2026-08-24 17:00:17 +03:00
511219e3e0 fix(git): remove guided tour 2026-08-24 16:01:03 +03:00
fa4a75ce1e feat(frontend): unify Superset Tools visual system 2026-08-24 14:16:35 +03:00
2043f25d3a docs(scenarios): define production provider contracts 2026-08-24 12:34:02 +03:00
1a5c14739e feat(auth): refresh login experience 2026-08-21 16:17:23 +03:00
ffa4d6a85b feat(scenarios): implement execution engine contracts 2026-08-21 16:15:40 +03:00
adbea9db18 fix(translate): fail-closed source handling, double insert, retry recount, scheduler races, LLM parse safety, and improved BI-analyst error UX 2026-08-20 17:34:39 +03:00
63a839e3b0 fix(translate): fail closed on missing source and silent run success
Stop preview/env fallbacks when a configured datasource is gone, skip the
duplicate final insert after streaming, and surface retry/scheduler/LLM
edge cases as FAILED instead of COMPLETED.
2026-08-20 15:37:16 +03:00
585a00c537 semantic-curation: fix anchors, metadata, and relations across backend + specs
- Replace legacy @PURPOSE with @BRIEF across 241 files
- Add missing [C:N] complexity tiers to function contracts in core modules
- Fix tombstone contracts: add @STATUS DEPRECATED to 5 deprecated anchors
- Resolve 7 unresolved @RELATION edges in executor.py (DictionaryManager, TranslationPreview, etc.)
- Fix flat hierarchical IDs in 4 test files (22 test functions)
- Fix invalid tags/relations in logger.py (@ADR, @CONSEQUENCES, DISABLED_BY)
- Rebuild semantic index: 9,576 contracts, 4,742 edges, 0 parse warnings
2026-08-20 11:45:15 +03:00
82a519a347 feat(scenarios): complete editor execution and analytics 2026-08-20 11:32:26 +03:00
455a56856f fix(agent): report THREAD_REPAIRED as lifecycle error code
The send-path repair branch set _request_result but not
_request_error_code, so the AGENT_REQUEST_FAILED lifecycle event fell back
to the misleading 'agent lifecycle failure'. Set THREAD_REPAIRED so logs
and middleware show the real outcome.
2026-08-19 20:14:50 +03:00
a619c0afb2 fix(agent): use async aupdate_state for checkpoint repair
The repair paths (send-path _repair_pending_tool_calls and resume fallback)
called graph.update_state — the SYNC method — which internally invokes
AsyncPostgresSaver.get_tuple() and raises InvalidStateError ('Synchronous
calls to AsyncPostgresSaver are only allowed from a different thread').
The repair therefore always failed (surfacing as 'Event loop is closed' +
a dangling aget_tuple coroutine) and broken threads stayed broken.

Switch both repair sites to agent.aupdate_state (async checkpointer
interface) and align the mocked agent in tests. Verified live: aupdate_state
repaired the broken checkpoint of conversation 69651ca1 (pending calls → 0).
2026-08-19 20:08:52 +03:00
7cc3297f1e fix(agent): recover broken threads and lazily create scenario runs
Two recurring failures from live logs (conversations 69651ca1 / a8c0dff8):

1. A checkpoint whose AI messages carry tool_calls without ToolMessages
   (run crashed after the LLM emitted a call) makes every send raise
   INVALID_CHAT_HISTORY with no recovery. The send path now repairs the
   thread via _repair_pending_tool_calls: pending calls are answered with
   synthetic error ToolMessages (THREAD_REPAIRED) so the user can retry.

2. Scenario tools scheduled from plain chat (no build_dashboard_test_scenario
   UI intent) had no durable AgentRun, so the resume fallback refused with
   SCENARIO_RUN_REQUIRED. _ensure_scenario_run now lazily creates the run
   from the tool args (dashboard_context from scenario_json for
   validate/resolve), mirroring the UIContextV2 scenario contract.
2026-08-19 20:02:12 +03:00
614f675f64 fix(agent): detect truncated scenario JSON for clear retry feedback
Observed in a live checkpoint: the pending scenario_validate tool call
carried a scenario_json that the LLM stream cut mid-document (ended
inside the unclosed outer object, len 3837). _parse_json_value failed
with a generic 'Could not extract JSON value' that neither the operator
nor the LLM could act on. Add _looks_truncated (unbalanced structure /
unterminated string at end) and report 'truncated/incomplete JSON' with
input length, so the model regenerates the full document.
2026-08-19 19:52:16 +03:00
9b0350b3b0 fix(agent): send search param instead of ignored q to /api/dashboards
The backend route binds the search query to `search`; a bare `q` param is
not bound, so search_dashboards and prefetch_dashboards silently returned
the unfiltered catalog (e.g. query 'Sales' listed all 11 dashboards).
Switch both to `search` and update the URL-contract test.
2026-08-19 19:31:32 +03:00
e291ba757f fix(agent): full-catalog dashboard search and working LLM retry
- search_dashboards: call /api/dashboards with page_context=other and
  page_size=100 so the profile 'My Dashboards Only' filter can no longer
  hide the whole catalog; parse available_total/effective_profile_filter
  and report hidden-by-filter instead of a false 'no dashboards' answer
- prefetch_dashboards: same full-catalog context; fix dead code where
  data=resp.json() sat after return '' inside the error branch, making
  every 200 response raise NameError and the prefetch always return ''
- llm-status: ?force=1 bypasses the 30s health cache so the 'Retry now'
  button performs a fresh probe instead of re-reading the stale status;
  frontend keeps a single retry interval (previously stacked intervals
  decayed the countdown faster than 1/s and fired duplicate probes)
- tests: agent tool/prefetch, backend route bypass + force param,
  frontend retry/force coverage
2026-08-19 19:21:00 +03:00
615f3ccd25 fix: graceful fallback when Superset rejects changed_on_dttm filter during incremental sync 2026-08-19 17:38:35 +03:00
488a8f349b test(backend): raise coverage to 95%+ statements and branches (97.8%/95.0%)
- ~60 new/extended test files across api, core, plugins, services, schemas:
  routes, superset clients, task_manager, lineage, git, translate,
  dashboard-testing, load-testing, migration, llm_analysis, scheduler, ssl
- .coveragerc: enable branch coverage; exclude src/__tests__ (test files)
  and src/scripts (CLI/ops tools) from the denominator
- bug fixes found while testing:
  * settings: PUT /settings/reports registered under duplicated prefix
  * schemas/lineage: FleetReportDTO missing run_status (route always 500)
  * dashboard_testing/baseline_inheritance: visual entry read wrong field
  * superset_client/_databases: logger extra name shadowed LogRecord attr
  * routes/datasets: _yaml_string_paths recursion without yield from
  * translate/sql_generator: restore explicit-type timestamp contract
  * baseline_catalog: remove unreachable dashboard_id fallback
- conftest fixes: pytest_plugins to rootdir conftest (pytest 9), test
  filename collision, TMPDIR-safe integration fixtures
2026-08-19 17:14:32 +03:00
dd9df0fc5e feat(env-widget): dashboard stats widget with per-env counts, health probe and profile-filter reference info
- Replace the global env <select> in TopNavbar with an expandable
  EnvironmentStatsWidget showing per-env total/mine/published/drafts
  and health status (latency, unreachable), preserving env switching.
- Add GET /api/environments/stats: per-env counts (profile-actor matched)
  + lightweight health probe, gathered concurrently with an 8s probe
  timeout and a process-local TTL cache (30s, coalescing) so the full
  Superset dashboard catalog is not re-fetched on every dropdown open.
- Add available_total to GET /api/dashboards so grids can show how many
  dashboards exist when the profile-default filter hides everything.
- Share ProfileFilterBanner across the dashboards hub and validation
  task form: 'showing X of Y' reference info + explicit Show all /
  Restore filter actions.
- Russian plural forms for dashboard counts (pluralRu helper) and
  compact 'Опубл.' label; i18n keys en/ru.
- Ignore :memory:test_* SQLite test artifacts and drop them from the index.
- Tests: env stats endpoint (incl. caching), widget, model fallback,
  plural helper, api client, integration.
2026-08-19 14:40:14 +03:00
a571ff8175 fix(search): global search queries with envId and bypasses profile filter
- handleSearchInput now receives the selected envId, so the debounced
  search actually fires API requests instead of hitting the !envId guard
  and clearing results immediately.
- The dashboard section of the global search sends page_context=other,
  apply_profile_default=false, override_show_all=true (same pattern as
  DashboardHubModel.loadDashboardSearchOptions), so the "show only my
  dashboards" profile filter no longer zeroes out dashboards that lack
  owner metadata.
- Updated unit tests: debounce now asserts API calls + profile-off flags.
2026-08-19 11:00:33 +03:00