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.
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.
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.
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.
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.
- 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
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
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
- 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.
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.
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.
- 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
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.
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.
- 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