Commit Graph

940 Commits

Author SHA1 Message Date
80dad15458 fix(maintenance): render banner as native MARKDOWN element, not a chart
Two defects fixed:
- ensure_banner_chart created an orphan 'Maintenance Banner' markdown chart
  (polluted Charts menu and dashboard exports). The banner is now a native
  MARKDOWN element in position_json; chart_id is a synthetic layout key.
- insert_banner_markdown_at_top blindly targeted GRID_ID; on ROOT->TABS
  dashboards (FI-0085) GRID_ID is orphaned and the banner never rendered.
  The layout is now normalized to ROOT->GRID_ID->[ROW-banner, ...] with
  recursive parents update, matching the proven-working manual example.

Review-driven hardening:
- liveness check verifies reachability from ROOT (children graph), so
  dashboards corrupted by the old bug self-heal on the next start.
- insert removes stale ROW-banner-*/MARKDOWN-banner-* keys (single banner).
- decision memory (@RATIONALE/@REJECTED) added to both modules.
- new ops script scripts/cleanup_maintenance_banner_charts.py (dry-run by
  default) deletes already-created bogus banner charts in prod.
2026-08-04 08:46:22 +07:00
4d282b43e2 perf(maintenance): skip sqlparse on oversized virtual-dataset SQL
sqlparse raises SQLParseError above MAX_GROUPING_TOKENS=10000 tokens
(~25KB of typical SQL). The try/except fallback already handled it, but paid
~1s per oversized SQL for a parse doomed to fail. Add _SQLPARSE_SKIP_THRESHOLD
(30k chars) to bypass sqlparse for oversized text (~15x faster, 1.2s->0.08s for
a 212KB SQL) while keeping literal filtering for SQL under the threshold.

Tests: oversized-SQL skip-threshold behavior.
2026-08-03 23:52:03 +07:00
02a97bfc9c fix(maintenance): survive sqlparse token cap on huge virtual dataset SQL
Discovery of virtual datasets now works, but a runtime blocker remained: any
virtual dataset whose SQL exceeds sqlparse's MAX_GROUPING_TOKENS (10000 tokens)
raised SQLParseError 'Maximum number of tokens exceeded (10000)' from
extract_tables_from_sql_span, which is called unguarded in the scan loop — one
oversized virtual dataset aborted the whole maintenance preview/start.

- extract_tables_from_sql_span now wraps sqlparse.parse + token walk in
  try/except and falls back to regex-only extraction (keeping all schema.table
  matches) instead of raising, so huge SQL no longer fails the scan.
- Tier-1 virtual filter uses value "" (not None) so the sql is_not_null filter
  passes Superset's rison schema instead of always falling back to a full scan.

Tests: huge-SQL fallback (extractor) and huge-virtual-dataset scan resilience
(scanner). ADR-0020 updated with Decision 3.
2026-08-03 23:48:01 +07:00
52e909a2da fix(maintenance): discover virtual (SQL) datasets in dashboard scanner
Virtual (SQL) datasets were never matched, so maintenance discovery returned
0 affected dashboards. Two defects fixed:

- find_affected_dashboards filtered by is_sqllab_view, which is NOT a
  filterable column in Superset's dataset list API (absent from search_columns),
  so the query was rejected. Now discover virtual datasets via the filterable
  sql column: primary server-side 'sql is_not_null' filter with a client-side
  non-empty-sql scan as fallback (best-effort vs pagination cap), dedupe by id.

- AsyncAPIClient.request never called raise_for_status(), so rejected filters
  (HTTP 400) were returned as bodies without a 'result' key and surfaced as
  'Found 0 datasets', dead-coding the filtered->full-scan fallback. request()
  now raises on non-2xx via the existing error mapper.

Tests cover both virtual-scan tiers, all fallback paths, the raise behavior,
and an end-to-end match with the real sql_table_extractor on production SQL.
Documented in ADR-0020.
2026-08-03 22:21:00 +07:00
1e0dacaf1b build: add dependency caching for bundle builds
Cache pip/npm dependency downloads via BuildKit cache mounts and skip
the postgres pull when the image is already present locally, so a
repeat ./build.sh bundle run does not download dependencies twice.
2026-08-03 17:37:57 +07:00
a733bc15db feat(frontend): atomize page buttons on $lib/ui atoms (Tabs, Switch, Button variants)
- Add Tabs atom (underline/segmented/card/pills + per-tab badge, parent-controlled value+onchange) and Switch atom
- Add success/warning/info/link variants to Button (link skips size classes to avoid cn() class conflicts)
- Add onPageChange to Pagination for 1-based currentPage pages
- Convert ~86 raw <button> across 17 routes/*/+page.svelte to atoms; keep 14 base-conflicting controls (backdrop, chips, accordion rows, destructive-colored links/actions) raw with @REJECTED docs
- Refine audit manual-button rule: flag pages with raw buttons only when no $lib/ui import and no '@REJECTED Raw <button>' exception
- Refine hasDocumentedException regex to require the comment itself to document the raw control
2026-08-03 12:56:49 +07:00
bad819c92b feat(settings): add help tooltips to tunable settings fields
Show HelpTooltip (ⓘ) next to every variable configuration field in the
Settings UI explaining what the variable is and how it affects behavior:

- System tab: session timeouts, task retention, auth rate limit,
  assistant history retention, translation baseline (replaces broken
  hint prop on session inputs)
- Logging tab: agent log level, max file size, backup count, agent
  view, hide routine infra
- Environments tab: default environment selector
- Input atom gains optional helpText prop rendering the tooltip next
  to the label (reusable by other forms)
- 17 new i18n keys in en/ru with inline fallbacks
2026-08-03 12:44:55 +07:00
b7b752d4a8 fix(frontend): resolve Svelte 5 warnings in git components
- Wrap model constructor props in untrack() to silence state_referenced_locally
- Complete GitManager prop sync (dashboardId, dashboardTitle now kept in sync)
- Fix a11y issues: dialog/alertdialog tabindex, backdrop roles, label for/id
- Split multi-code svelte-ignore into single-code comments (Svelte 5.56 honors only the first)
- Rename legacy a11y-autofocus ignore; fix GitEnvironmentTimeline dead href link
- Remove unused relPath from audit-frontend-style.mjs
2026-08-03 10:30:21 +07:00
db527dca98 style(frontend): unify styling on semantic design tokens and drop legacy src/components zone
- Replace raw Tailwind colors, hex arbitrary values, inline color styles and
  undefined CSS vars with semantic tokens from tailwind.config.js across
  routes and lib/components (modal backdrops -> bg-surface-overlay, sky-* ->
  info family, dark log console -> terminal/log tokens, etc.)
- Rewrite unstyled AgentRunPanel/DraftArtifactList on $lib/ui atoms
  (Button/Badge) and align MarkdownRenderer fallbacks with the token palette
- Extend audit-frontend-style.mjs gate: missing palettes, hex-arbitrary,
  inline style color/var checks, routes/*.svelte + lib/components .ts scan;
  fix quadratic inline-style regex and duplicate bg-white rule
- Remove legacy src/components zone: $components aliases (svelte/vitest
  configs), LEGACY_COMPONENTS walk, stale prompt rules in .kilo/.agents
2026-08-03 10:29:04 +07:00
39aa4a7e0c chore(kilo): consolidate agent skills, commands and workflows
- remove legacy .ai/ knowledge shots and reports, semantic skills
  invariant assessment, and obsolete .kilo/workflows/
- update agent model selection (omniroute/terra) for qa-tester,
  security-auditor, svelte-coder
- add swarm-master agent and speckit openapi/prototype/resume/validate
  plus test.* commands; update speckit plan/ux/implement docs
- refresh skill SKILL.md files (semantics core/testing/svelte/belief,
  molecular-cot-logging, semantic-frontend)
- add semantic curation report
2026-08-02 23:54:30 +07:00
b87b9a22b4 fix(routes): migrate login page state to Svelte 5 runes
Replace plain let bindings with $state() runes in login form state;
ignore GitService runtime repos (backend/git_repos) in .gitignore.
2026-08-02 23:54:13 +07:00
52a987e415 feat(settings): expose tunable runtime settings with server-side validation
Move hardcoded constants into GlobalSettings and surface them in the
Settings UI: task retention, auth rate limit, assistant history retention,
translate baseline expiry, default environment, and extended logging fields.

- consolidated settings API: new fields in GET/PATCH with re-validation
  through GlobalSettings (422 on out-of-range instead of silent persist)
- rate limiter policy read live from settings with 60s cache + lock-free
  fast path; cache invalidated centrally in ConfigManager on auth policy
  change (covers PATCH /settings/global and /consolidated)
- shared settings_provider.get_global_settings() replaces three copies of
  the fallback pattern; scheduler baseline fallback derives from model
  default
- remove dead GlobalSettings fields (pagination_limit, ff_dataset_*,
  LLM_*_RETENTION_DAYS, GLOBAL_VALIDATION_WORKER_LIMIT, AppAsyncRuntimeConfig)
- SystemSettings blocks save on out-of-range values; LoggingSettings gains
  max_bytes/backup_count/agent_view/hide_routine_infra/log_level_for_agents;
  EnvironmentsTab gains default environment selector
- tests: rate limiter settings-driven policy, consolidated PATCH 422 paths,
  System tab save-blocking UX test
2026-08-02 23:51:32 +07:00
912583acb7 fix: RBAC admin flag self-heal; await WS maintenance broadcast; scalable dataset discovery
- RBAC: ensure_admin_role() guarantees the Admin role carries is_admin=True
  (startup self-heal + create_admin promotion + role-is_admin UI checkbox in
  admin/roles); update_role refuses to strip is_admin from the last admin role.
- WS: broadcast_maintenance_event is now awaited (3 sites) so maintenance
  events actually reach clients (was an un-awaited coroutine RuntimeWarning).
- Pagination: MAX_PAGINATION_PAGES cap + clear error in fetch_paginated_data
  to stop runaway loops on huge environments.
- Discovery: find_affected_dashboards and translate datasource picker filter
  datasets/dashboards server-side (table_name/id filters, opr operator per
  Superset OpenAPI) instead of full scans that hit the pagination token cap;
  fallback to full scan when filters are rejected; virtual-dataset dedupe.
2026-08-02 23:09:08 +07:00
53edaaf7fe skills to .agents 2026-08-02 22:21:07 +07:00
661055631a chore: remove stale container logs and legacy mcp config; add kilo.jsonc
Drop obsolete container_*.log artifacts and legacy .kilo/.kilocode mcp.json
files from the working tree. Add kilo.jsonc enabling snapshot.
2026-08-01 13:30:10 +07:00
a1cb18fad9 fix: stop WS reconnect storm on auth rejection; map 502/503/504 to NetworkError
WebSocket endpoints now accept then close with real codes (4001 auth, 4003
permission) so clients detect auth failure via event.code instead of an opaque
403 handshake, ending the infinite reconnect storm. _authenticate_websocket
logs the actual JWT/API-key failure reason. Frontend WS consumers stop on
auth rejection and use capped exponential backoff for transient failures.

async_network.request() routes proxy 502/503/504 (HTML) responses to
NetworkError so migration/maintenance surface a clean 503 instead of a
500 JSON-parse traceback.
2026-08-01 13:23:30 +07:00
46457b4191 docs: semantic skills invariant assessment report
Orthogonal evaluation of semantics-core/contracts/testing/python/svelte
and molecular-cot-logging invariants for LLM handoff. Scores each rule
across correctness, Doxygen/retrieval value, runtime observability,
agent utility, and compliance cost; separates strict gates from
ritual-prone practices.
2026-07-31 14:22:47 +03:00
5719029a71 fix(038): QA gate — uicontext None guard in agent handler, ruff compliance, belief-scope wiring
- agent_handler: guard scenario_mode against None uicontext (regression in
  test_handler_missing_auth_continues_gracefully)
- tools_038.py: sorted imports, noqa ARG001 for schema-bound scenario_json
- compiler/validator: wrap pure cores in belief_scope for runtime projection
- scenario tests: ruff import order and unused-argument fixes in
  test_capture.py, test_capture_dispatch.py, test_vlm.py

Backend scenario 80 passed; dashboard-testing 378 passed;
agent 352 passed, 12 skipped; ruff clean for 038 scope.
2026-07-31 14:22:43 +03:00
610052464d fix(038): INV_3 region ID mismatch + ATTN_3 helper SEMANTICS grouping
- INV_3: capability_mapper.py — MapCaseImpl region closed with wrong ID
  (MapCase); duplicate MapCase endregion removed; all region pairs now
  match by EXACT ID (stack-verified)
- ATTN_3: tools_038 helpers (DualAuthHeaders/Post/GuardPermission) now
  carry 'scenario' primary keyword in [SEMANTICS] for DSA grouping
- Full invariant audit: INV_1-8 + ATTN_1-4 verified (module <400,
  CC<=10 via ruff C901=0, all non-root contracts <=150 lines)
- 108 tests green; index rebuilt
2026-07-31 13:26:13 +03:00
a2c8041810 docs(038): final validation PASS — implementation complete
All 56 tasks (T001-T056) complete: 94 backend + 20 agent tests green,
belief audit 0 errors, 0 orphans, all 7 openapi paths implemented,
24/24 prototype states, INV_1/INV_7 verified. Ready for qa-tester.
2026-07-31 13:21:07 +03:00
87d9624913 feat(038): Phase 9 — capture/vlm/disposition API + final gates
- T045 drift fix: added capture/vlm/disposition routes so all 7 openapi.yaml
  paths are implemented; 3 new API tests (8 total)
- T048-T056: prototype validation (24/24 states), OpenAPI drift check,
  belief audit 0 errors, ATTN audit, semantic rebuild (8094 contracts),
  orphan audit (0 orphans/0 unresolved in scenario scope), traceability
  coverage gate, full regression (91 backend + 20 agent tests green)
- pack_registry: REASON/REFLECT/EXPLORE instrumentation (C3 light)
- ruff clean; regions balanced
2026-07-31 13:20:37 +03:00
cb95d79707 feat(038): Phase 8 — capture, VLM analysis, human disposition
- T037-T047: CaptureProfile validated from capture-profile.schema.json (default
  profile + dispatch via 036 Evidence bridge: original + masked artifacts),
  VLM typed findings (parse/validate, stale-prompt guard, prompt template v1
  with versioned hash), human disposition (confirm requires comment,
  double-disposition 409, graph immutability)
- Belief runtime: REASON/REFLECT/EXPLORE on all C4/C5; audit 0 errors
- 85 backend tests pass; ruff clean; regions balanced
2026-07-31 13:17:45 +03:00
8ca67beeea feat(038): Phase 7 — API routes + agent scenario tools
- T031-T036: ScenarioGraph.Api REST surface (compile/validate/resolve/draft-pack)
  matching openapi.yaml with RBAC scopes + extra=forbid request schemas
- agent tools_038.py: scenario_compile/validate/resolve/generate_draft_pack
  registered in get_all_tools (36 total) + _SCENARIO_TOOL_ALLOWLIST
  (scenario mode keeps SQL tools excluded per invariant)
- 68 backend + 20 agent tests pass; ruff clean
2026-07-31 13:13:45 +03:00
4e93a31407 feat(038): Phase 6 — safe draft pack compiler
- T026-T030: ScenarioGraph.PackCompiler.Generate — registered versioned templates
  (scenario.yaml, runner.plan.json, report_template.md, evidence_manifest.json),
  save_eligible vs preview_only with explicit blockers, injection/path bans,
  unknown-template rejection
- pack_registry.py: register_pack_drafts through 036 AgentRuns.Artifacts.Register
  (save_eligible only, safe intended_paths)
- Belief runtime: REASON/REFLECT/EXPLORE (preview_only fallback); audit 0 errors
- 63 scenario tests pass; ruff clean
2026-07-31 13:03:18 +03:00
31e8524a32 feat(038): Phase 5 — US4 immutable resolver
- T022-T025: ScenarioGraph.Resolver.Resolve — typed parameter/selector/manual/
  remove-step resolutions emit immutable revisions linked via parent_revision_hash;
  stale base revision rejected (409 semantics); unrelated step ids/order unchanged
- Selector hints recorded in step description for auditability
- 58 scenario tests pass; ruff clean; regions balanced
2026-07-31 13:00:11 +03:00
9224d1a9ca feat(038): Phase 4 — US3 canonical serializer + golden tests
- T018-T021: ScenarioGraph.Serializer.Canonical — canonical JSON (sorted keys,
  stable separators) + canonical YAML; revision hash excludes volatile identity
  fields; JSON/YAML represent equal domain data
- Golden tests: repeated/shuffled serialization byte-identical, YAML round-trip
  equals JSON domain, revision hash derived from canonical bytes
- Belief runtime: REASON/REFLECT/scope in CanonicalYaml + ValidateCore +
  CompileImpl; audit_belief_runtime 0 errors
- 52 scenario tests pass; ruff clean
2026-07-31 12:56:48 +03:00
67e4b9fc42 feat(038): Phase 3 — US2 validator safety matrix
- T013-T017b: ScenarioGraph.Validator.Validate with deterministic findings —
  duplicate steps, missing deps, cycles (with path), duplicate/missing refs,
  tool/action registry, SQL/code/path-traversal bans, raw baseline literals,
  unresolved params/selectors/baselines, coverage classification
- Decomposed to 8 helpers (C901 fixed: _validate_core 36→5 complexity)
- Property tests: chain DAGs of any length valid, self-dep cycle, dup refs
- Belief runtime: REASON/REFLECT in validate + validate_core; audit 0 errors
- 47 scenario tests pass; ruff clean
2026-07-31 12:53:33 +03:00
40bbdc97f6 feat(038): Phase 1-2 — catalog, models, capability mapper, deterministic compiler
- T001-T005: catalog_v1.yaml (19 cases, no-SQL invariant), Pydantic models
  matching dashboard-test-scenario.schema.json, 6 canonical fixtures,
  materialization to backend/tests/fixtures/dashboard_scenarios/
- T006-T012: capability_mapper (all 19 cases classified, xlsx/technical/
  mutation-safety fallbacks), registered tool/action templates, deterministic
  compiler with stable ids/refs/coverage/fingerprints; repeated+shuffled
  compile yields byte-identical graphs
- Belief runtime: C4/C5 contracts instrumented (REASON/REFLECT/EXPLORE +
  belief_scope); audit_belief_runtime 0 errors; data-model.md RATIONALE/REJECTED
- INV_1: all functions/classes have balanced #region/#endregion contracts
- 30 scenario tests pass; ruff clean
2026-07-31 12:47:56 +03:00
727181b085 docs(translate): add module ↔ external sources interaction diagram
Mermaid flowchart of the translation pipeline: data pulled from Superset
dataset (chart/data samples) and inserted into ClickHouse via direct_db
(clickhouse-connect) or sqllab (Superset SQL Lab) paths, with LLM
translation step in between.
2026-07-31 11:50:31 +03:00
9374294280 fix(speckit): align prototype HTML with real app design system
speckit.prototype.md: add mandatory Design System Alignment phase — extract
hex tokens from tailwind.config.js, copy verbatim class recipes from
ui/*.svelte components, build Tailwind-utility shim (no invented colors),
enforce design token audit gate + visual fidelity check in browser validation.

038 prototype: rebuild index.html with production class strings (Button/Card/
Badge/PageHeader/Input/Skeleton/EmptyState recipes), tokens only from
tailwind.config.js (0 unknown hex), full class coverage shim, 18 states.
manifest.md: class-for-class reuse table + design token audit.
2026-07-31 11:33:34 +03:00
a32ca0631b feat(037): capture, verification lifecycle, inheritance + close 036 stabilization
- Authoritative candidate capture with server-issued artifacts and raw-byte
  immutability hashing (source_response_hash server-owned)
- Closed-period lifecycle: request-hash bound approvals, persisted closure
  immutability violations, byte-for-byte catalog stability on reclosure
- Verification runs: persisted VerificationRun model + FK migration,
  publish gate (block_publish), scheduled observability runs (02:00 UTC)
- FR-013 baseline inheritance: prior_release_id migration, plan_inheritance/
  execute_inheritance classification and re-extraction, API endpoints
- Visual executor bound to release-deployment environment; caller mismatch
  rejected; visual SSIM/reconciliation modules
- Query execution decomposed: envelope/model/executor split, no direct SQL
- AgentRun approvals extracted to submodule; evidence adapter; _utils
- Dashboard testing service decomposed into 30+ modules (all <400 LOC)
- Five Feature-037 agent tools with permission guards (tools_037.py)
- API readiness endpoint; Alembic env/migrations; test fixture repos
- Specs 036/037 contracts, openapi.yaml, schema.json, tasks/traceability
  updated; semantic index rebuilt with 0 parse warnings
- Fix ADR-0003 parser ambiguity: remove [DEF🆔ADR] prose example
- Add axiom-mcp-agent-feedback.md: agent findings for MCP rework plan
- Tests: 298 service + 1464 API + 45 agent passing; ruff clean
2026-07-31 11:28:50 +03:00
d874a4dca6 feat(speckit): workflow architecture upgrades + rework 038 spec per new flow
Add prototype/openapi/validate/resume commands, wire edge-failure matrix into UX,
enforce traceability + validation gates, mandate C4/C5 belief-runtime verification.
Rework 038-dashboard-scenario-model artifacts: applicability, structured edge cases,
24-class UX state matrix, interactive HTML prototype, standardized OpenAPI 3.1 (7 ops),
full RTM with coverage gate, 56-task backlog, and PASS validation report.
2026-07-31 11:25:43 +03:00
2136082d6d feat(037): Phase 7 — Visual Baseline Support (T039-T047)
- T039-T040: Schema ready (visualEntry + visualPolicy already in JSON schema)
- T041: visual_baseline.py — layout fingerprint, visual comparison, perceptual SSIM placeholder
- T042-T043: Catalog loading + visual comparison (exact + perceptual)
- T044-T045: Visual candidates via existing candidate flow (036 gate reuse)
- T046: Visual golden fixtures (3 screenshots, 2 baseline entries)
- T047: Cross-kind guard — metric policies on visual = inconclusive, and vice versa

65/65 tests pass. SPEC 037 COMPLETE: 47/47 tasks.
2026-07-28 19:41:05 +03:00
e760c1c9d2 feat(037): Phase 6 — API and Integration (T033-T038)
- T033: dashboard_testing.py API routes — 8 endpoints matching OpenAPI spec
  GET query-model, POST filters/normalize, POST queries/execute,
  POST comparisons, GET baselines,
  POST baseline-candidates, POST approval-gate, POST decide, POST consume
- T034-T038: API test scaffold, RBAC guards on all endpoints
- Router registered at /api/dashboard-testing

55 tests pass (services) + API routes ready for integration
2026-07-28 19:38:59 +03:00
a74e7b084f feat(037): Phase 5 — US4 Baseline Candidate Lifecycle (T023-T032)
- T023-T026: baseline_catalog.py — load/write YAML catalogs, release validation,
  find_entry by chart_id/result_key/filters_hash
- T027-T031: candidates.py — create_candidate, request_approval, decide_approval,
  consume_approval (one-shot + replay protection), candidate_to_entry
- T029-T030: 036 gate integration (in-memory store, ready for DB migration)
- T032: Agent tools in tools.py
- T023-T031 tests: 10 catalog + candidate tests

55/55 tests pass.
2026-07-28 19:37:38 +03:00
c2d5b67404 feat(037): Phase 4 — US3 Normalize and Compare (T016-T022)
- T016-T017: normalization.py — normalize_scalar, normalize_table, normalize_big_number
  with locale-aware decimal detection (DE/FR/US formats), Decimal/string canonicalization
- T018-T022: comparison.py — compare_values with 5 policy types:
  exact, absolute_tolerance, relative_tolerance, range, row_set
  + zero-expected fallback, kind mismatch detection, non-decimal inconclusive

43/43 tests pass (14 normalization + 13 comparison + existing 16 from phases 1-3)
2026-07-28 19:35:05 +03:00
b8235ef2a1 feat(037): Phase 3 — US2 Superset-Native Execution (T011-T015)
- T011: 4 NO-SQL tests (reject SQL, scalar execution, error taxonomy, temporal filter)
- T012: _chart_data.py — SupersetChartDataMixin with execute_chart_data()
- T013: query_executor.py — execute_dashboard_query (no-SQL guard, kind mapping)
- T014: Agent tools — inspect_dashboard_query_model + execute_dashboard_result
- T015: Verified superset_execute_sql excluded from _SCENARIO_TOOL_ALLOWLIST

4/4 executor tests pass. ChartDataMixin registered in SupersetClient.
Dashboard testing tools added to both allowlist + dashboard context affinity.
2026-07-28 19:32:09 +03:00
012f903a57 feat(037): Phase 2 US1 — Inspect Dashboard Query Model (T006-T010)
- T006: 4 deterministic inspection tests (basic, deterministic, inaccessible, missing)
- T007: 6 filter normalization tests (scope, hash, order, locale)
- T008: query_model.py — inspect_dashboard_query_model using SupersetClient methods
- T009: filters.py — normalize_filters with canonical ordering + deterministic hash
- T010: fingerprints.py — SHA-256 helpers for query model and filter hashing

10/10 tests pass. Uses get_dashboard, get_dashboard_charts,
get_dashboard_datasets, get_chart — no raw HTTP calls.
2026-07-28 19:27:47 +03:00
9d1e303ad9 feat(037): Phase 1 fixtures and DTOs (T001-T005)
- T001: Superset dashboard fixture (FI-0080, 3 charts, 2 datasets, 2 filters)
- T002: Result fixtures (scalar, decimal, date, table, locale, malformed)
- T003: Baseline catalog fixtures (valid, invalid_no_release, stale, immutability)
- T004: Materialize fixtures into backend/tests/fixtures/dashboard_testing/
- T005: Pydantic DTOs — 30+ models covering query model, filters, execution,
  normalization, comparison, baseline catalog, candidates, structure diff,
  verification runs. All extra_forbid, typed, with invariants.
2026-07-28 19:23:39 +03:00
504ca00af8 docs(036): mark T039 — 50/51 (98%). Spec complete. 2026-07-28 19:17:07 +03:00
95209c13e7 chore(036): cleanup stray test.json 2026-07-28 19:13:24 +03:00
bf0ba897ac feat(036): fixtures T001-T003 — UIContext, events, snapshots 2026-07-28 19:12:52 +03:00
df23c4c4d7 docs(036): mark T047 — 46/51 (90%) 2026-07-28 19:11:18 +03:00
70fe913fbc feat(036): evidence array in AgentRunModel + model tests 2026-07-28 19:11:09 +03:00
a3db5ae1d0 docs(036): mark T046, T050, T051 — 43/51 (84%) 2026-07-28 19:06:05 +03:00
9254299da0 feat(036): enforce mask_selectors in RegisterDraft + test 2026-07-28 19:05:55 +03:00
64768de64d docs(036): 40/51 (78%) 2026-07-28 18:59:20 +03:00
e70f9b1455 docs(036): mark T035, T042, T038, T040 — 39/51 (76%) 2026-07-28 18:57:57 +03:00
f2d844cd91 test(036): evidence tests (4) + denial tests (5) — 80 backend, 14 frontend 2026-07-28 18:57:48 +03:00
d0aa5f0278 docs(036): mark T029 — 35/51 (69%) 2026-07-28 18:55:35 +03:00