--- name: molecular-cot-logging description: Structured logging protocol for agent-driven development, based on molecular Long CoT bonds (REASON/REFLECT/EXPLORE). Replaces legacy Entry/Exit/Coherence markers. Python + Svelte. --- #region Std.Semantics.MolecularCoTLogging [C:5] [TYPE Skill] [SEMANTICS reasoning,runtime,logging,agentic] @BRIEF Structured logging protocol for agent-driven development, based on molecular Long CoT bonds (Deep-Reasoning, Self-Reflection, Self-Exploration). Replaces legacy Entry/Exit/Coherence markers. Wire format is specified here; the Python implementation lives in `ss_tools.shared.cot_logger`. @RELATION DEPENDS_ON -> [Std.Semantics.Core] @RELATION DISPATCHES -> [Std.Semantics.Python] @RELATION DISPATCHES -> [Std.Semantics.Svelte] @RATIONALE Long CoT chains need stabilisation through explicit reasoning bonds. The three-marker system (REASON/REFLECT/EXPLORE) maps directly to the molecular CoT paper and produces machine-readable execution traces that LLM agents can parse, analyse, and use for fine-tuning (MoLE-Syn bond distributions). Without structured markers, agent-generated code exhibits invisible failures: a function returns `None` instead of raising — the agent's attention never sees it because there's no log; a fallback path activates silently — no EXPLORE marker, no trace. JSON-line format ensures every log entry is a self-contained, parseable unit that survives log rotation, aggregation, and agent parsing — unlike plain-text logs that require regex heuristics. @REJECTED Legacy Entry/Exit/Action/Coherence markers rejected — they are too generic, do not map to reasoning structure, and prevent traceability graph analysis. Plain-text logging rejected — JSON lines are mandatory for agent parsing. Unstructured printf-style logging rejected — agents cannot reliably extract structured fields (trace_id, marker, intent) from free-form text, making automated diagnosis impossible. cot_span decorator rejected — replaced by belief_scope context manager + logger.reason/reflect/explore which gives more granular intent control per logical branch. @DATA_CONTRACT LogEntry -> { ts: str, level: str, trace_id: str, span_id?: str, src: str, marker: REASON|REFLECT|EXPLORE, intent: str, payload?: object, error?: str } @INVARIANT Every log line MUST carry exactly one valid marker (REASON | REFLECT | EXPLORE). No markerless log lines in C4/C5 code. @INVARIANT trace_id MUST propagate via ContextVar across async boundaries. Every incoming request or background job seeds a new trace_id. ## Purpose Enable **transparent agent-driven development** by producing machine-readable execution traces that directly reflect the reasoning structure of the code. Every log line becomes an edge in a traceability graph that an LLM agent can parse, analyse, and optionally use for fine-tuning (via MoLE-Syn-like bond distributions). ## Core principles (from the Molecular CoT paper) Long CoT chains are stabilised by three "chemical bonds": | Bond | Marker | Function | |------|--------|----------| | **Deep-Reasoning** | `REASON` | Extends the logical backbone | | **Self-Reflection** | `REFLECT` | Folds back to validate or correct previous steps | | **Self-Exploration** | `EXPLORE` | Branches into alternatives when an assumption fails | Our logs annotate every semantically meaningful step with exactly one of these markers. ## I. Log Entry Specification Every log record MUST be a JSON object **on a single line** with the following keys: | Field | Required | Type | Description | |-------|----------|------|-------------| | `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) | | `src` | yes | string | Qualified function name, e.g. `AuthRepository.get_user_by_username` | | `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` | conditional | string | Error message or reason. **Optional** for `REASON`/`REFLECT`, **required** for `EXPLORE` markers when a fallback or violation is taken | ### Example ```json {"ts":"2026-05-12T14:31:39.577","level":"INFO","trace_id":"d874a1b2-...","span_id":"...","src":"AuthRepository.get_user_by_username","marker":"REASON","intent":"Fetch user by username","payload":{"username":"admin"}} ``` ## II. Semantic Marker Usage ### REASON (Deep-Reasoning) - **When**: BEFORE an operation that extends the logical chain (DB query, API call, computation). - **Level**: `INFO` by default, `DEBUG` for high-frequency loops. - **`intent`**: Describes what the code is about to do. - **`payload`**: Input parameters, context values. - **Effect**: This is the primary "deep-reasoning" step that forms the backbone of the trace. ```python log("AuthRepository.get_user_by_username", "REASON", "Fetch user by username", {"username": username}) ``` ### REFLECT (Self-Reflection) - **When**: AFTER an operation to **verify the outcome** or check invariants. - **Level**: `INFO` on success, `WARNING` if invariants partially degrade. - **`intent`**: Describes what is being verified. - **`payload`**: Result summary, status codes, row counts. - **Effect**: Folds the logical chain back on itself — the agent sees cause + effect in two adjacent lines. ```python log("AuthRepository.get_user_by_username", "REFLECT", "User found", {"found": user is not None, "user_id": user.id if user else None}) ``` ### EXPLORE (Self-Exploration) - **When**: An expected condition is **violated** and the code enters a fallback, error handler, or alternative path. - **Level**: `WARNING` for recoverable fallbacks, `ERROR` for unrecoverable failures. - **`intent`**: Describes what assumption failed. - **`payload`**: Relevant state at the branch point. - **`error`**: **Required.** Explain what assumption was violated. - **Effect**: Creates a branch in the trace — a future agent can see why the happy path was not taken. ```python log("AuthRepository.get_user_by_username", "EXPLORE", "User not found, returning None", {"username": username}, error="User does not exist in database") ``` ### Quick Reference | Situation | Marker | Level | `error` field | |-----------|--------|-------|---------------| | About to execute DB query | `REASON` | INFO | — | | DB query returned results | `REFLECT` | INFO | — | | DB query returned empty set (happy path) | `REFLECT` | INFO | — | | DB query failed, fallback to cache | `EXPLORE` | WARNING | required | | About to call external API | `REASON` | INFO | — | | API responded 200 | `REFLECT` | INFO | — | | API responded 5xx, retrying | `EXPLORE` | WARNING | required | | API exhausted retries | `EXPLORE` | ERROR | required | | Precondition check fails (e.g., not found) | `EXPLORE` | WARNING | required | | State validation passes | `REFLECT` | INFO | — | | Decomposing a complex loop iteration | `REASON` | DEBUG | — | **Never use** generic tags like `Entry`, `Exit`, `Action`, `Coherence:OK/FAIL`. Those are replaced entirely by the molecular bond markers. ## III. Trace Propagation (Python) **SSOT implementation:** `shared/src/ss_tools/shared/cot_logger.py` (`ss_tools.shared.cot_logger`). Backend facade: `src.core.logger`. Do not copy the logger into skills or call sites. ```python from ss_tools.shared.cot_logger import log, seed_trace_id, get_trace_id, push_span, pop_span # Backend: # from src.core.logger import log, belief_scope, logger ``` `log()`, `seed_trace_id()`, `push_span()` / `pop_span()`, and ContextVar propagation are defined in that module. If the wire format in §I disagrees with the module, **the module wins** and this skill must be updated. ### FastAPI middleware (trace seeding) ```python from starlette.middleware.base import BaseHTTPMiddleware class TraceMiddleware(BaseHTTPMiddleware): async def dispatch(self, request, call_next): seed_trace_id() response = await call_next(request) return response ``` ## IV. Svelte / Frontend Pattern The frontend implementation lives at `frontend/src/lib/cot-logger.ts` (installed as `$lib/cot-logger`). ### API ```typescript function log( src: string, // e.g. "MigrationModel.executeMigration" marker: LogMarker, // "REASON" | "REFLECT" | "EXPLORE" intent: string, // human-readable one-liner payload?: Record, // params, result snippet error?: string, // required for EXPLORE ): void; ``` ### Import ```typescript import { log, setTraceId, getTraceId } from "$lib/cot-logger"; ``` ### Usage in a Svelte component ```svelte ``` ### trace_id Propagation The trace ID is set automatically when the backend returns it. Call `setTraceId(id)` manually if needed: ```typescript import { setTraceId } from "$lib/cot-logger"; import { requestApi } from "$lib/api"; const res = await requestApi("/api/endpoint"); if (res.trace_id) setTraceId(res.trace_id); ``` ## V. CLI / Stdout Reader (for humans) To make JSON lines readable in development: ```bash # Pretty-print the last 50 CoT lines tail -50 app.log | python3 -c " import sys, json for line in sys.stdin: line = line.strip() if not line: continue rec = json.loads(line) m = rec.get('marker','?') icon = {'REASON':'→','REFLECT':'✓','EXPLORE':'⚠'}.get(m, '·') err = f\" | {rec['error']}\" if 'error' in rec else '' pay = f\" | {rec.get('payload','')}\" if 'payload' in rec else '' print(f\"{icon} {rec['level']:7} {rec['src']} — {rec['intent']}{pay}{err}\") " ``` ## VI. Anti-patterns | ❌ Don't | ✅ Do | |----------|-------| | `COHERENCE:OK` on happy path | `REFLECT` with verification summary | | `Action: something` | `REASON` with intent | | `Entry` / `Exit` | REASON at entry, REFLECT at exit | | Wrapping EVERY line with a marker | Only log semantically meaningful steps | | Plain-text log lines | Always JSON lines | | `marker` without `intent` | Every marker has a human-readable `intent` | | Logging raw passwords or tokens in `payload` | Always sanitise sensitive data | | Spread markers across multiple modules without trace_id | Always propagate `trace_id` | #endregion Std.Semantics.MolecularCoTLogging