log refactor
This commit is contained in:
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user