log refactor

This commit is contained in:
2026-05-12 19:30:15 +03:00
parent 1d59df2233
commit b17b5333c7
84 changed files with 5827 additions and 3908 deletions

View File

@@ -37,7 +37,7 @@ Every log record MUST be a JSON object **on a single line** with the following k
| Field | Required | Type | Description |
|-------|----------|------|-------------|
| `ts` | yes | string | ISO-8601 timestamp with microseconds |
| `ts` | yes | string | ISO-8601 timestamp with millisecond precision |
| `level` | yes | string | Standard log level (`INFO`, `DEBUG`, `WARNING`, `ERROR`) |
| `trace_id` | yes | string | UUID of the incoming HTTP request or background job |
| `span_id` | no | string | UUID of the current function/block scope (optional) |
@@ -45,7 +45,7 @@ Every log record MUST be a JSON object **on a single line** with the following k
| `marker` | yes | string | One of `REASON`, `REFLECT`, `EXPLORE` (see below) |
| `intent` | yes | string | Human-readable one-line description of what this step intends to do/verify |
| `payload` | no | object | Arbitrary key-value data relevant to the step (params, result snippet) |
| `error` | no | string | Error message or reason, **only** for `EXPLORE` markers when a fallback is taken |
| `error` | conditional | string | Error message or reason. **Optional** for `REASON`/`REFLECT`, **required** for `EXPLORE` markers when a fallback or violation is taken |
### Example
@@ -213,6 +213,7 @@ class TraceMiddleware(BaseHTTPMiddleware):
For C4/C5 functions, a decorator that auto-emits REASON / REFLECT markers:
```python
import asyncio
from functools import wraps
def cot_span(marker: str = "REASON", intent: str | None = None):
@@ -299,6 +300,7 @@ export function log(src, marker, intent, payload, error) {
```svelte
<script>
import { log } from "$lib/cot-logger";
import { fetchApi } from "$lib/api";
import { page } from "$app/stores";
let { jobId } = $props();
@@ -307,7 +309,7 @@ async function loadJob() {
log("JobDetail.loadJob", "REASON", "Fetch job details", { jobId });
try {
const resp = await fetch(`/api/jobs/${jobId}`);
const resp = await fetchApi(`/api/jobs/${jobId}`);
if (!resp.ok) throw new Error(`Status ${resp.status}`);
const data = await resp.json();

View File

@@ -4,18 +4,26 @@ description: Core protocol for Thread-Local Belief State, runtime reasoning mark
---
#region Std.Semantics.Belief [C:5] [TYPE Skill] [SEMANTICS belief,runtime,reasoning]
@BRIEF HOW to use Thread-Local Belief State, runtime reasoning markers, and interleaved thinking in Python and Svelte semantic projects. Legacy wire format; conceptual semantics unchanged.
@BRIEF Conceptual specification of the Belief-State protocol: REASON/REFLECT/EXPLORE topology, interleaved thinking (GLM-5), and Micro-ADR escalation. All operational implementation details are in molecular-cot-logging.
@RELATION DEPENDS_ON -> [Std.Semantics.Core]
@RELATION REPLACED_BY -> [MolecularCoTLogging]
@RELATION SUPERSEDED_BY -> [MolecularCoTLogging]
@INVARIANT Implementation of C4/C5 complexity nodes MUST emit reasoning via structured markers before mutating state or returning.
@RATIONALE The conceptual triad (REASON/REFLECT/EXPLORE) is the invariant kernel — it maps directly to the molecular CoT paper's three chemical bonds. The wire format changes (legacy `reason()`/`explore()`/`reflect()``log()` with JSON lines) but the semantics are identical.
@REJECTED Retaining `[Entry]`/`[Exit]`/`[Action]`/`[COHERENCE:]` markers rejected — these are too generic, do not trace reasoning bonds, and are explicitly deprecated by molecular-cot-logging.
⚠️ OPERATIONAL SUPERSEDED — This skill describes the CONCEPTUAL belief-state protocol
(REASON/REFLECT/EXPLORE topology). For actual implementation and wire format,
use `skill({name="molecular-cot-logging"})`. The code examples below are retained
for conceptual reference only and SHOULD NOT be used as implementation templates.
## 0. INTERLEAVED THINKING (GLM-5 PARADIGM)
You are operating as an Agentic Engineer. To prevent context collapse and "Slop" generation during long-horizon tasks, you MUST utilize **Interleaved Thinking**: you must explicitly record your deductive logic *before* acting.
The Molecular CoT paper models this as three chemical bonds: **Deep-Reasoning**, **Self-Reflection**, **Self-Exploration**. Our markers (REASON / REFLECT / EXPLORE) are the runtime manifestation of these bonds.
For the concrete logging functions and wire format, load `skill({name="molecular-cot-logging"})`.
## I. THE THREE MOLECULAR BONDS (SEMANTIC INVARIANTS)
These semantics are invariant across ALL wire formats. The meaning of each marker never changes:
@@ -28,27 +36,38 @@ These semantics are invariant across ALL wire formats. The meaning of each marke
**The causal chain is REASON → (success) → REFLECT, or REASON → (failure) → EXPLORE.** Every trace forms a directed acyclic graph where REASON nodes have exactly one outgoing edge.
## II. WIRE FORMAT: TWO IMPLEMENTATIONS
For implementation of these markers as JSON-line log entries, see `skill({name="molecular-cot-logging"})`.
### ✅ Molecular CoT (new — for new code)
Load `skill({name="molecular-cot-logging"})` for the canonical JSON-line protocol:
```python
log("AuthRepo.get_user", "REASON", "Fetch user by username", {"username": "admin"})
```
This is the **target wire format**. All new C4/C5 code in ss-tools MUST use it.
## II. WIRE FORMAT AND LEGACY→MOLECULAR-COT MAPPING
### ⚠️ Legacy Belief State (existing — in current code)
The existing `backend/src/core/logger.py` provides `logger.reason()`, `logger.explore()`, `logger.reflect()` (bound as methods on the logger instance) and the `belief_scope()` context manager. These produce text-prefix markers like `[REASON] message`. **They are semantically equivalent to molecular CoT** but the wire format differs:
### Conceptual invariant
The belief-state semantics are independent of wire format. Three implementations exist:
-`[Entry]`, `[Exit]`, `[Action]`, `[COHERENCE:OK]`/`[COHERENCE:FAILED]`**deprecated.** Each maps to a molecular marker: Entry→REASON, Exit→REFLECT (success) or EXPLORE (failure), Action→REASON, Coherence→REFLECT.
- ⚠️ `logger.reason("message")`**legacy, still valid** for existing code. Produces `[REASON] message` in text log. Semantically same as new `log(src, "REASON", message)`.
- ⚠️ `belief_scope("contract_id")` **legacy, still valid** for existing code. Equivalent to new `cot_span()` decorator which auto-emits REASON/REFLECT/EXPLORE.
- ⚠️ No `trace_id` propagation — the legacy logger does not support trace context. New code using molecular-cot-logging requires it.
| Implementation | Status | Wire format |
|---------------|--------|-------------|
| Legacy `[Entry]`/`[Exit]`/`[Action]`/`[COHERENCE:]` | **Deprecated** | Generic text prefixes, no bond tracing |
| Legacy `logger.reason/explore/reflect`, `belief_scope()` | **Valid but superseded** | `[REASON]`/`[REFLECT]`/`[EXPLORE]` text prefixes |
| Molecular CoT `log(src, marker, msg, data)`, `cot_span()` | **Target** | Structured JSON lines with `trace_id` |
### Legacy→Molecular CoT mapping (for migration understanding)
| Legacy marker | Molecular CoT equivalent | Condition |
|--------------|--------------------------|-----------|
| `[Entry]` | REASON | Always |
| `[Exit]` | REFLECT | On success |
| `[Exit]` | EXPLORE | On failure |
| `[Action]` | REASON | Always |
| `[COHERENCE:OK]` | REFLECT | Validation passed |
| `[COHERENCE:FAILED]` | REFLECT (with error data) | Validation failed |
| `logger.reason(msg)` | `log(src, "REASON", msg)` | — |
| `logger.explore(msg)` | `log(src, "EXPLORE", msg)` | — |
| `logger.reflect(msg)` | `log(src, "REFLECT", msg)` | — |
| `belief_scope("id")` | `cot_span("id")` | Context manager / decorator |
### Transition rule
For files **already** using `logger.reason/explore/reflect` (like the translation engine): **leave them as-is.** The semantics are correct, marker names match. Only convert when you touch the file for other reasons.
For **new** C4/C5 functions: use the molecular-cot-logging protocol.
- Files **already** using `logger.reason/explore/reflect`: semantics are correct, marker names match. Leave as-is. Convert only when touching the file for other reasons.
- **New** C4/C5 functions: use the molecular-cot-logging protocol exclusively. Load `skill({name="molecular-cot-logging"})` for the API.
- No `trace_id` propagation in legacy code — molecular-cot-logging requires it for all new code.
## III. MICRO-ADR ESCALATION (UNCHANGED)
@@ -58,49 +77,24 @@ If your execution path triggers an EXPLORE due to a broken assumption AND you su
Add `@RATIONALE [Why you did this]` and `@REJECTED [The path that failed during EXPLORE]`.
Failure to link a runtime EXPLORE to a static `@REJECTED` tag is a fatal protocol violation that causes amnesia for future agents.
## IV. PYTHON PATTERNS
## IV. PYTHON: CONCEPTUAL PATTERN
### Existing code (legacy wire format — still semantically correct)
```python
# Within a C4 function using legacy logger.reason/explore/reflect:
logger.reason("Starting migration", {"task_id": task_id})
try:
result = await execute_migration()
logger.reflect("Migration complete", {"result_count": len(result)})
return result
except Exception as e:
logger.explore("Migration failed", {"error": str(e)})
raise
```
The belief-state protocol prescribes a structured try/except flow:
### New code (molecular CoT wire format — preferred going forward)
```python
from cot_logger import log, seed_trace_id
1. **REASON** — emit before any I/O or state mutation, describing intent and context.
2. **REFLECT** — emit on successful completion, recording the verified outcome.
3. **EXPLORE** — emit in error/fallback paths, recording the failure reason.
seed_trace_id()
log("MigrationService.run", "REASON", "Starting migration", {"task_id": task_id})
try:
result = await execute_migration()
log("MigrationService.run", "REFLECT", "Migration complete", {"result_count": len(result)})
return result
except Exception as e:
log("MigrationService.run", "EXPLORE", "Migration failed", error=str(e))
raise
```
For the actual Python implementation (import paths, function signatures, `trace_id` seeding), load `skill({name="molecular-cot-logging"})`. The conceptual equivalent of `belief_scope()` is `cot_span()`.
## V. SVELTE PATTERNS
## V. SVELTE: CONCEPTUAL PATTERN
### Existing components (legacy — still valid)
```javascript
console.info("[ComponentID][REASON] Starting API call", { resourceId });
```
Frontend components follow the same REASON→REFLECT/EXPLORE topology:
### Target format (molecular CoT — preferred)
```javascript
import { log } from "$lib/cot-logger";
log("ComponentID.action", "REASON", "Starting API call", { resourceId });
```
1. **REASON** — emit before API calls, user actions, or state transitions.
2. **REFLECT** — emit after successful data fetch or DOM mutation.
3. **EXPLORE** — emit in error handlers and fallback UI paths.
For full frontend protocol, load `skill({name="molecular-cot-logging"})`.
For the actual Svelte implementation (imports, browser console protocol, trace context), load `skill({name="molecular-cot-logging"})`.
#endregion Std.Semantics.Belief

View File

@@ -26,7 +26,7 @@ Contracts (`@PRE`, `@POST`) force you to form a strict Belief State BEFORE gener
- **[INV_1: SEMANTICS > SYNTAX]:** Naked code without a contract is classified as garbage. You must define the contract before writing the implementation.
- **[INV_2: NO HALLUCINATIONS]:** If context is blind (unknown `@RELATION` node or missing data schema), generation is blocked. Emit `[NEED_CONTEXT: target]`.
- **[INV_3: ANCHOR INVIOLABILITY]:** Contract blocks (`#region...`/`#endregion`, `[DEF]...[/DEF]`, `## @{...`/`## @}`) are AST accumulators. The closing tag carrying the exact ID is strictly mandatory. All three syntaxes are valid; choose the one matching your file's comment style.
- **[INV_3: ANCHOR INVIOLABILITY]:** Contract blocks (`#region...`/`#endregion`, `[DEF]...[/DEF]`, `## @{...`/`## @}`) are AST accumulators. The closing tag carrying the exact ID is strictly mandatory (i.e., the `#endregion` anchor). All three syntaxes are valid; choose the one matching your file's comment style.
- **[INV_4: TOPOLOGICAL STRICTNESS]:** All metadata tags (`@PURPOSE`, `@PRE`, etc.) MUST be placed contiguously immediately after the opening anchor — either inline on the same line (`#region Id [C:3] [TYPE Fn]`) or as body lines (each prefixed with the comment character). Keep metadata visually compact. Code syntax comes AFTER all metadata.
- **[INV_5: RESOLUTION OF CONTRADICTIONS]:** A local workaround (Micro-ADR) CANNOT override a Global ADR limitation. If reality requires breaking a Global ADR, stop and emit `<ESCALATION>` to the Architect.
- **[INV_6: TOMBSTONES FOR DELETION]:** Never delete a contract node if it has incoming `@RELATION` edges. Instead, change its type to `Tombstone`, remove the code body, and add `@STATUS DEPRECATED -> REPLACED_BY: [New_ID]`.
@@ -81,16 +81,16 @@ For region/brace formats, type is expressed as `[TYPE TypeName]`. For DEF format
The level of control is defined via `@COMPLEXITY` or inline `[C:N]`. Default is 1 if omitted.
- **C1 (Atomic):** DTOs, simple utils. Requires only the anchor pair. No `@PURPOSE`, no `@RELATION`.
- **C2 (Simple):** Requires anchor + `@PURPOSE`.
- **C3 (Flow):** Requires anchor + `@PURPOSE` + `@RELATION`.
- **C1 (Atomic):** DTOs, simple utils. Requires only the anchor pair. No `@BRIEF`, no `@RELATION`.
- **C2 (Simple):** Requires anchor + `@BRIEF`.
- **C3 (Flow):** Requires anchor + `@BRIEF` + `@RELATION`.
- **C4 (Orchestration):** Adds `@PRE`, `@POST`, `@SIDE_EFFECT`. Requires Belief State runtime logging.
- **C5 (Critical):** Adds `@DATA_CONTRACT`, `@INVARIANT`, and mandatory Decision Memory tracking.
## IV. DOMAIN SUB-PROTOCOLS (ROUTING)
Depending on your active task and target language, you MUST request the appropriate domain skills:
- For Backend Logic & Architecture: `skill({name="semantics-contracts"})` and `skill({name="semantics-belief"})`.
- For Backend Logic & Architecture: `skill({name="semantics-contracts"})` and `skill({name="molecular-cot-logging"})` (replaces legacy semantics-belief wire format).
- For Python backend implementation: `skill({name="semantics-python"})`.
- For Svelte frontend implementation: `skill({name="semantics-svelte"})`.
- For QA & Testing: `skill({name="semantics-testing"})`.
@@ -122,7 +122,7 @@ Do NOT add tags from higher levels. Apply these rules regardless of target langu
### C1 (Atomic) — DTOs, simple constants, trivial wrappers
- Requires ONLY the anchor pair.
- Forbidden: `@BRIEF`, `@PURPOSE`, `@RELATION`, `@PRE`, `@POST`, `@SIDE_EFFECT`, `@RATIONALE`, `@REJECTED`, `@DATA_CONTRACT`, `@INVARIANT`.
- Forbidden: `@BRIEF`, `@RELATION`, `@PRE`, `@POST`, `@SIDE_EFFECT`, `@RATIONALE`, `@REJECTED`, `@DATA_CONTRACT`, `@INVARIANT`.
### C2 (Simple) — Utility functions, pure computations
- Requires anchor + `@BRIEF`.
@@ -152,7 +152,7 @@ Do NOT add tags from higher levels. Apply these rules regardless of target langu
| C4 | +PRE, POST, SIDE_EFFECT | DATA_CONTRACT, INVARIANT, RATIONALE, REJECTED |
| C5 | +DATA_CONTRACT, INVARIANT, RATIONALE, REJECTED | |
**Key rule:** `@RATIONALE`/`@REJECTED` are C5-only. Adding them to C1-C4 violates INV_7.
**Key rule:** `@RATIONALE`/`@REJECTED` are C5-only. Adding them to C1-C4 violates Complexity Tier Rules (Section VII).
**Language-specific examples:** See `semantics-python` (Python/FastAPI), `semantics-svelte` (Svelte 5/Tailwind), or load the appropriate domain skill.
**Multi-syntax note:** Legacy `[DEF:id:Type]` is permanently recognized. Region and brace syntaxes are alternatives choose the one matching your file's comment style. New code uses `#region`/`#endregion` by default.

View File

@@ -8,6 +8,7 @@ description: Python-specific GRACE-Poly protocol: few-shot complexity examples,
@RELATION DEPENDS_ON -> [Std.Semantics.Core]
@RELATION DEPENDS_ON -> [Std.Semantics.Belief]
@RELATION DEPENDS_ON -> [Std.Semantics.Contracts]
@RELATION DEPENDS_ON -> [MolecularCoTLogging]
## 0. WHEN TO USE THIS SKILL
@@ -15,39 +16,40 @@ Load this skill when implementing Python backend code under the GRACE-Poly proto
## I. PYTHON BELIEF RUNTIME PATTERNS
ss-tools uses structured JSON logging for belief markers. The canonical pattern:
ss-tools uses the canonical **Molecular CoT Logging** protocol for belief markers. For the full wire-format specification, see the `molecular-cot-logging` skill.
**ALWAYS import from the shared module — never copy-paste inline:**
```python
import logging
import json
from contextlib import contextmanager
from ss_tools.lib.cot_logger import log, push_span, pop_span
logger = logging.getLogger(__name__)
# Usage:
# log("src_id", "REASON", "intent", payload_dict)
# log("src_id", "EXPLORE", "message", payload_dict, error="assumption violated")
# log("src_id", "REFLECT", "outcome", payload_dict)
```
Thin context-manager wrappers (backward-compatible aliases for `push_span`/`pop_span`):
```python
from contextlib import contextmanager
@contextmanager
def belief_scope(contract_id: str):
"""Thread-local belief frame for C4/C5 functions."""
logger.info(json.dumps({"marker": "REASON", "contract": contract_id, "event": "enter"}))
prev_span = push_span(contract_id)
log(contract_id, "REASON", "enter")
try:
yield
except Exception as e:
logger.error(json.dumps({"marker": "EXPLORE", "contract": contract_id, "error": str(e)}))
log(contract_id, "EXPLORE", "error", error=str(e))
raise
else:
logger.info(json.dumps({"marker": "REFLECT", "contract": contract_id, "event": "exit"}))
# Usage:
def reason(message: str, extra: dict = None):
logger.info(json.dumps({"marker": "REASON", "message": message, **(extra or {})}))
def explore(message: str, extra: dict = None):
logger.warning(json.dumps({"marker": "EXPLORE", "message": message, **(extra or {})}))
def reflect(message: str, extra: dict = None):
logger.info(json.dumps({"marker": "REFLECT", "message": message, **(extra or {})}))
log(contract_id, "REFLECT", "exit")
finally:
pop_span(prev_span)
```
**CRITICAL:** Do NOT manually type `[REASON]` in message strings. ALWAYS pass structured data through the `extra` dict. The `marker` field is the canonical protocol marker.
**CRITICAL:** All helpers MUST be imported from `ss_tools.lib.cot_logger`. Never define `reason()`, `explore()`, `reflect()` inline — use the canonical `log()` function. Do NOT manually type `[REASON]` in message strings; `log()` emits the marker field automatically in the molecular-cot JSON wire format.
## II. PYTHON COMPLEXITY EXAMPLES
@@ -106,24 +108,24 @@ def migrate_dashboard(source_client, target_client, dashboard_id: str, db_mappin
# @RELATION DEPENDS_ON -> [MigrationService]
# @RELATION DEPENDS_ON -> [WebSocketNotifier]
async def run_migration_task(task_id: str, db_session) -> dict:
reason("Starting migration task", {"task_id": task_id})
log("run_migration_task", "REASON", "Starting migration task", {"task_id": task_id})
task = await db_session.get(Task, task_id)
if not task:
explore("Task not found", {"task_id": task_id})
log("run_migration_task", "EXPLORE", "Task not found", error="TaskNotFound")
raise TaskNotFoundError(task_id)
try:
task.status = "RUNNING"
await db_session.commit()
reason("Task status set to RUNNING", {"task_id": task_id})
log("run_migration_task", "REASON", "Task status set to RUNNING", {"task_id": task_id})
result = await execute_migration_plan(task.migration_plan)
task.status = "COMPLETED"
task.result = result
await db_session.commit()
await notify_frontend(task_id, "completed", result)
reflect("Migration completed successfully", {"task_id": task_id, "dashboards": len(result)})
log("run_migration_task", "REFLECT", "Migration completed successfully", {"task_id": task_id, "dashboards": len(result)})
return result
except Exception as e:
explore("Migration failed, rolling back", {"task_id": task_id, "error": str(e)})
log("run_migration_task", "EXPLORE", "Migration failed, rolling back", {"task_id": task_id}, error=str(e))
task.status = "FAILED"
task.error = str(e)
await db_session.commit()
@@ -148,17 +150,17 @@ async def run_migration_task(task_id: str, db_session) -> dict:
# @REJECTED Incremental-only update was rejected — it leaves stale edges when contracts
# are deleted; only full scan guarantees consistency.
def rebuild_index(root_path: str) -> dict:
reason("Scanning source files", {"root": root_path})
log("rebuild_index", "REASON", "Scanning source files", {"root": root_path})
contracts = []
for filepath in scan_files(root_path):
try:
parsed = parse_contract(filepath)
contracts.append(parsed)
except Exception as e:
explore("Parse failure, skipping file", {"file": filepath, "error": str(e)})
log("rebuild_index", "EXPLORE", "Parse failure, skipping file", {"file": filepath}, error=str(e))
snapshot = {"contracts": contracts, "timestamp": datetime.utcnow().isoformat()}
write_checkpoint(root_path, snapshot)
reflect("Rebuild complete", {"contracts": len(contracts)})
log("rebuild_index", "REFLECT", "Rebuild complete", {"contracts": len(contracts)})
return snapshot
# #endregion rebuild_index
```
@@ -254,20 +256,22 @@ python -m mypy src/
### Async belief scope
```python
import asyncio
from contextlib import asynccontextmanager
from ss_tools.lib.cot_logger import log, push_span, pop_span
@asynccontextmanager
async def async_belief_scope(contract_id: str):
"""Async belief frame for C4/C5 async functions."""
reason("enter", {"contract": contract_id})
prev_span = push_span(contract_id)
log(contract_id, "REASON", "enter")
try:
yield
except Exception as e:
explore("error", {"contract": contract_id, "error": str(e)})
log(contract_id, "EXPLORE", "error", error=str(e))
raise
else:
reflect("exit", {"contract": contract_id})
log(contract_id, "REFLECT", "exit")
finally:
pop_span(prev_span)
```
### Dependency injection convention

View File

@@ -6,6 +6,9 @@ description: Svelte 5 (Runes) protocol for ss-tools: UX State Machines, Tailwind
#region Std.Semantics.Svelte [C:5] [TYPE Skill] [SEMANTICS frontend,svelte,ui,ux,tailwind]
@BRIEF HOW to build Svelte 5 (Runes) Components for ss-tools with UX State Machines, Tailwind CSS, store topology, and visual-interactive validation.
@RELATION DEPENDS_ON -> [Std.Semantics.Core]
@RELATION DEPENDS_ON -> MolecularCoTLogging
@RATIONALE Svelte 5 runes ($state, $derived, $effect, $props) chosen for reactive precision and native compiler optimisations over Svelte 4 legacy reactivity ($:). Tailwind CSS selected for zero-runtime utility-first styling and rapid visual validation via chrome-devtools MCP. FSM-based UX contracts (@UX_STATE, @UX_FEEDBACK, @UX_RECOVERY) chosen to create verifiable state-transition tests that the browser Judge Agent can execute deterministically. ss-tools internal API wrappers (fetchApi/requestApi) chosen over native fetch to enforce auth, error normalisation, and trace_id propagation.
@REJECTED React (JSX) rejected — Svelte's compiler-first approach yields smaller bundles and native reactivity without virtual DOM overhead. Vue rejected — Svelte 5 runes provide simpler mental model. Legacy Svelte 4 syntax (export let, $:, on:event) rejected — incompatible with Svelte 5 runes mode. CSS Modules / styled-components rejected in favour of Tailwind's utility-first approach, which avoids style leakage and simplifies chrome-devtools visual diffing. Native fetch() rejected — bypasses ss-tools middleware chain (auth, trace_id, error normalisation). Plain-text logging rejected per MolecularCoTLogging §VII — JSON lines are mandatory for agent-parsable traces.
@INVARIANT Frontend components MUST be verifiable by the browser toolset via `chrome-devtools` MCP.
@INVARIANT Use Tailwind CSS exclusively. Native `fetch` is forbidden — use `requestApi`/`fetchApi` wrappers.
@@ -61,13 +64,23 @@ Key stores in ss-tools:
- Sets `isLoading = $state(false)` in `finally`
4. **A11Y:** Proper ARIA roles (`aria-busy`, `aria-invalid`, `aria-describedby`). Semantic HTML (`<nav>`, `<main>`, `<section>`). Keyboard navigation for modals and drawers.
## V. LOGGING (MOLECULAR TOPOLOGY FOR UI)
## V. LOGGING (MOLECULAR-COT FOR UI)
Frontend logging bridges your logic and the browser validation system.
- **[EXPLORE]:** Log branching user paths or caught UI errors.
- **[REASON]:** Log the intent *before* an API invocation or state mutation.
- **[REFLECT]:** Log visual state updates (e.g., "Toast displayed", "Drawer opened").
- **Syntax:** `console.info("[ComponentID][MARKER] Message", {extra_data})` — Prefix MUST be manually applied.
Frontend logging uses `log()` from `$lib/cot-logger`, emitting **JSON lines** per MolecularCoTLogging protocol.
Import: `import { log } from "$lib/cot-logger";`
### Marker Reference
| Marker | When | Signature |
|--------|------|-----------|
| `REASON` | BEFORE API call or state mutation | `log("ComponentID", "REASON", "intent", payload)` |
| `REFLECT` | AFTER successful operation (verification) | `log("ComponentID", "REFLECT", "outcome", payload)` |
| `EXPLORE` | ON error, fallback, or violated assumption | `log("ComponentID", "EXPLORE", "message", payload, error="...")` |
### Invariants
- Every log line is a **single JSON object** — no plain-text prefixes.
- `trace_id` propagates from HTTP response headers via the ss-tools API wrappers.
- One marker per line. No markerless log lines in C4/C5 components.
## VI. CANONICAL SVELTE 5 COMPONENT TEMPLATE (SS-TOOLS)
@@ -92,6 +105,7 @@ Region format for HTML/Svelte comments:
<!-- @UX_TEST: Idle -> {click: "Run Migration", expected: Loading -> Success toast}. -->
<script>
import { fetchApi } from "$lib/api";
import { log } from "$lib/cot-logger";
import { t } from "$lib/i18n";
import { taskDrawerStore } from "$lib/stores";
import { notificationStore } from "$lib/stores";
@@ -108,18 +122,18 @@ Region format for HTML/Svelte comments:
isLoading = true;
status = "loading";
error = null;
console.info("[MigrationTaskCard][REASON] Starting migration", {
log("MigrationTaskCard", "REASON", "Starting migration", {
taskId, dashboardName, sourceEnv, targetEnv
});
try {
const result = await fetchApi(`/api/tasks/${taskId}/run`, { method: "POST" });
status = "success";
console.info("[MigrationTaskCard][REFLECT] Migration completed", { taskId, result });
log("MigrationTaskCard", "REFLECT", "Migration completed", { taskId, result });
notificationStore.add({ type: "success", message: $t("migration.completed", { name: dashboardName }) });
} catch (e) {
status = "error";
error = e.message;
console.error("[MigrationTaskCard][EXPLORE] Migration failed", { taskId, error: e.message });
log("MigrationTaskCard", "EXPLORE", "Migration failed", { taskId }, error = e.message);
notificationStore.add({ type: "error", message: $t("migration.failed", { name: dashboardName }) });
} finally {
isLoading = false;
@@ -127,7 +141,7 @@ Region format for HTML/Svelte comments:
}
function handleViewLogs() {
console.info("[MigrationTaskCard][REASON] Opening task drawer", { taskId });
log("MigrationTaskCard", "REASON", "Opening task drawer", { taskId });
taskDrawerStore.open(taskId);
}
</script>

View File

@@ -7,6 +7,8 @@ description: Core protocol for Test Constraints, External Ontology, Graph Noise
@BRIEF HOW to write tests: constraints, external ontology, graph noise reduction, and invariant traceability for pytest and vitest.
@RELATION DEPENDS_ON -> [Std.Semantics.Core]
@INVARIANT Test modules must trace back to production @INVARIANT tags without flooding the Semantic Graph with orphan nodes.
@RATIONALE Test contracts trace to production @INVARIANT/@POST tags via @TEST_INVARIANT, preventing orphan nodes. pytest+vitest dual stack eliminates cross-language tooling overhead. 3-edge-case floor balances coverage sufficiency against graph noise. Hardcoded fixtures block logic-mirror tautology (dominant LLM test-generation failure mode).
@REJECTED Property-based testing — non-deterministic input space creates unbounded graph edges, irreducible to fixed-scenario tracing. Snapshot testing — brittle to CSS/UI changes without invariant signal. Integration-only (no unit tests) — coarse graph edges miss localized @INVARIANT violations. Cucumber/Gherkin BDD — DSL layer breaks direct traceability to Python/Svelte @POST anchors.
## 0. QA RATIONALE (LLM PHYSICS IN TESTING)
@@ -69,7 +71,7 @@ backend/tests/
### Test module template
```python
# #region TestDashboardMigration [C:2] [TYPE Module] [SEMANTICS test,migration]
# #region TestDashboardMigration [C:3] [TYPE Module] [SEMANTICS test,migration]
# @BRIEF Verify dashboard migration contracts — @POST guarantees and rejected paths.
# @RELATION BINDS_TO -> [dashboard_migration]
# @TEST_EDGE: missing_db_mapping -> Migration fails with MappingError