Core changes: - Add @defgroup/@ingroup to 1791 C2+ contracts (555 files) for HCA 128× pre-training DSA grouping - Add §0.1 Pre-Training Frequency matrix to semantics-core - Add §VIII Attention Architecture rules (ATTN_1-4) with MLA/CSA/HCA/DSA mechanics - Add @defgroup/@ingroup to canonical syntax (§II) and all contract examples Agent prompts (5 files): - Add ZERO-STATE RATIONALE with MLA/CSA/HCA/DSA compression mechanics - Add pre-training note: @RATIONALE/@REJECTED are in-context learned tags - svelte-coder: add missing #region contract, fix Svelte rule violations - python-coder/fullstack-coder: honor function contracts from speckit plan - qa-tester: add attention compliance audit (P3 ATTN_1-4 checks) Skills (6 files): - Translate all axiom_config descriptions to English - Fix doc_dirs to index .opencode/ and .specify/ - Deduplicate 5× complexity_rules → single global_tags catalog - Reduce semantics-svelte 591→485 lines (remove duplicate code blocks) - Fix semantics-testing: 'Short IDs' → 'Short hierarchical IDs' - Fix all examples: flat IDs → hierarchical Domain.Name format - Fix Svelte examples: replace raw Tailwind + <button> with semantic tokens + /ui Speckit workflow (commands + templates): - speckit.plan: add Function-Level Contracts for C3+ with @PRE/@POST/@TEST_EDGE - speckit.plan: add Attention Compliance Gate (ATTN_1-4 before contract generation) - speckit.tasks: add function contract inlining format (constraints in task description) - speckit.specify: load semantics-core for spec density rules - spec-template: add #region contract, @SEMANTICS grouping, hierarchical IDs - ux-reference-template: add #region wrapper - plan-template: add attention gate, @defgroup/@ingroup guidance - tasks-template: add attention audit + rebuild + orphan check tasks - constitution.md: translate to English, add Principle VIII (attention-optimized contracts) Reference modules rewritten (hierarchical IDs + full contracts): - Auth.Jwt: 6 child contracts with @RATIONALE/@REJECTED/@TEST_EDGE - Api.Auth: 5 endpoints with @TEST_EDGE + molecular CoT markers - Migration.Model: @defgroup Migration with 18 @ACTION + 6 @INVARIANT Scripts: - add_defgroup_ingroup.py: zero-risk additive @ingroup migration (1791 insertions) - migrate_hierarchical.py: flat→hierarchical ID dry-run analysis (792 contracts) - merge_prompts.py: merge all prompts/skills/commands into one review file Config: - axiom_config.yaml: 749→395 lines (-47%), English, doc_dirs include prompts - Fix test_datasets.py import collision (rename → test_datasets_routes.py) - Fix test_preview.py: SupersetClient→get_superset_client, AsyncMock, logger f-string
174 lines
5.7 KiB
Python
174 lines
5.7 KiB
Python
# #region DashboardHelpers [C:2] [TYPE Module] [SEMANTICS fastapi, dashboard, api, search, filter]
|
|
# @defgroup Api Module group.
|
|
# @BRIEF Basic helper functions for dashboard route handlers — slug resolution, filter normalization.
|
|
# @LAYER Infrastructure
|
|
# @RELATION DEPENDS_ON -> [SupersetClient]
|
|
# @RELATION DEPENDS_ON -> [AsyncSupersetClient]
|
|
|
|
from typing import Any
|
|
|
|
from fastapi import HTTPException
|
|
|
|
from src.core.async_superset_client import AsyncSupersetClient
|
|
from src.core.superset_client import SupersetClient
|
|
|
|
|
|
# #region _find_dashboard_id_by_slug [C:2] [TYPE Tombstone]
|
|
# @DEPRECATED 2026-06-04 — replaced by _find_dashboard_id_by_slug_async
|
|
# @REPLACED_BY -> [_find_dashboard_id_by_slug_async]
|
|
# @BRIEF Resolve dashboard numeric ID by slug — sync version, dead code.
|
|
# Body removed: SupersetClient methods are now async; this function
|
|
# would raise AttributeError at runtime.
|
|
def _find_dashboard_id_by_slug(
|
|
client: SupersetClient,
|
|
dashboard_slug: str,
|
|
) -> int | None:
|
|
raise RuntimeError(
|
|
"_find_dashboard_id_by_slug is deprecated. "
|
|
"Use _find_dashboard_id_by_slug_async() instead."
|
|
)
|
|
|
|
|
|
# #endregion _find_dashboard_id_by_slug
|
|
|
|
|
|
# #region _resolve_dashboard_id_from_ref [C:2] [TYPE Tombstone]
|
|
# @DEPRECATED 2026-06-04 — replaced by _resolve_dashboard_id_from_ref_async
|
|
# @REPLACED_BY -> [_resolve_dashboard_id_from_ref_async]
|
|
# @BRIEF Resolve dashboard ID from slug-first reference — sync version, dead code.
|
|
# Body removed: SupersetClient methods are now async; this function
|
|
# would raise AttributeError at runtime.
|
|
def _resolve_dashboard_id_from_ref(
|
|
client: SupersetClient,
|
|
dashboard_ref: str,
|
|
) -> int:
|
|
raise RuntimeError(
|
|
"_resolve_dashboard_id_from_ref is deprecated. "
|
|
"Use _resolve_dashboard_id_from_ref_async() instead."
|
|
)
|
|
def _resolve_dashboard_id_from_ref(
|
|
dashboard_ref: str,
|
|
client: SupersetClient,
|
|
) -> int:
|
|
normalized_ref = str(dashboard_ref or "").strip()
|
|
if not normalized_ref:
|
|
raise HTTPException(status_code=404, detail="Dashboard not found")
|
|
|
|
# Slug-first: even if ref looks numeric, try slug first.
|
|
slug_match_id = _find_dashboard_id_by_slug(client, normalized_ref)
|
|
if slug_match_id is not None:
|
|
return slug_match_id
|
|
|
|
if normalized_ref.isdigit():
|
|
return int(normalized_ref)
|
|
|
|
raise HTTPException(status_code=404, detail="Dashboard not found")
|
|
|
|
|
|
# #endregion _resolve_dashboard_id_from_ref
|
|
|
|
|
|
# #region _find_dashboard_id_by_slug_async [C:2] [TYPE Function]
|
|
# @BRIEF Resolve dashboard numeric ID by slug using async Superset list endpoint.
|
|
# @PRE dashboard_slug is non-empty.
|
|
# @POST Returns dashboard ID when found, otherwise None.
|
|
async def _find_dashboard_id_by_slug_async(
|
|
client: AsyncSupersetClient,
|
|
dashboard_slug: str,
|
|
) -> int | None:
|
|
query_variants = [
|
|
{
|
|
"filters": [{"col": "slug", "opr": "eq", "value": dashboard_slug}],
|
|
"page": 0,
|
|
"page_size": 1,
|
|
},
|
|
{
|
|
"filters": [{"col": "slug", "op": "eq", "value": dashboard_slug}],
|
|
"page": 0,
|
|
"page_size": 1,
|
|
},
|
|
]
|
|
|
|
for query in query_variants:
|
|
try:
|
|
_count, dashboards = await client.get_dashboards_page(query=query)
|
|
if dashboards:
|
|
resolved_id = dashboards[0].get("id")
|
|
if resolved_id is not None:
|
|
return int(resolved_id)
|
|
except Exception:
|
|
continue
|
|
|
|
return None
|
|
|
|
|
|
# #endregion _find_dashboard_id_by_slug_async
|
|
|
|
|
|
# #region _resolve_dashboard_id_from_ref_async [C:2] [TYPE Function]
|
|
# @BRIEF Resolve dashboard ID from slug-first reference using async Superset client.
|
|
# @PRE dashboard_ref is provided in route path.
|
|
# @POST Returns valid dashboard ID or raises HTTPException(404).
|
|
async def _resolve_dashboard_id_from_ref_async(
|
|
dashboard_ref: str,
|
|
client: AsyncSupersetClient,
|
|
) -> int:
|
|
normalized_ref = str(dashboard_ref or "").strip()
|
|
if not normalized_ref:
|
|
raise HTTPException(status_code=404, detail="Dashboard not found")
|
|
|
|
slug_match_id = await _find_dashboard_id_by_slug_async(client, normalized_ref)
|
|
if slug_match_id is not None:
|
|
return slug_match_id
|
|
|
|
if normalized_ref.isdigit():
|
|
return int(normalized_ref)
|
|
|
|
raise HTTPException(status_code=404, detail="Dashboard not found")
|
|
|
|
|
|
# #endregion _resolve_dashboard_id_from_ref_async
|
|
|
|
|
|
# #region _normalize_filter_values [C:2] [TYPE Function]
|
|
# @BRIEF Normalize query filter values to lower-cased non-empty tokens.
|
|
# @PRE values may be None or list of strings.
|
|
# @POST Returns trimmed normalized list preserving input order.
|
|
def _normalize_filter_values(values: list[str] | None) -> list[str]:
|
|
if not values:
|
|
return []
|
|
normalized: list[str] = []
|
|
for value in values:
|
|
token = str(value or "").strip().lower()
|
|
if token:
|
|
normalized.append(token)
|
|
return normalized
|
|
|
|
|
|
# #endregion _normalize_filter_values
|
|
|
|
|
|
# #region _dashboard_git_filter_value [C:2] [TYPE Function]
|
|
# @BRIEF Build comparable git status token for dashboards filtering.
|
|
# @PRE dashboard payload may contain git_status or None.
|
|
# @POST Returns one of ok|diff|no_repo|error|pending.
|
|
def _dashboard_git_filter_value(dashboard: dict[str, Any]) -> str:
|
|
git_status = dashboard.get("git_status") or {}
|
|
sync_status = str(git_status.get("sync_status") or "").strip().upper()
|
|
has_repo = git_status.get("has_repo")
|
|
if has_repo is False or sync_status == "NO_REPO":
|
|
return "no_repo"
|
|
if sync_status == "DIFF":
|
|
return "diff"
|
|
if sync_status == "OK":
|
|
return "ok"
|
|
if sync_status == "ERROR":
|
|
return "error"
|
|
return "pending"
|
|
|
|
|
|
# #endregion _dashboard_git_filter_value
|
|
|
|
|
|
# #endregion DashboardHelpers
|