diff --git a/.agents/skills/README.md b/.agents/skills/README.md index 3b7a25f..b5af888 100644 --- a/.agents/skills/README.md +++ b/.agents/skills/README.md @@ -1,6 +1,53 @@ -# Canonical skill-lib snapshot +# Local agent skills -Source: The-Interdependency/skill-lib -Commit: 8dfb974ea0cee72e4412f9d2c8b597a8930a4d57 +This directory contains repo-local copies of canonical skills from +`The-Interdependency/skill-lib`. -These directories are repo-local consumers. Canonical doctrine remains in skill-lib. +Source commit: `c14ee9d500579a4b5d6821f62c9d82ca96e73608` + +Repo-local copies are not the source of truth. Edit `skill-lib` first, +then propagate from the canonical source. + +Installed skills: + +- `a0p-instancing/` +- `action-calibration/` +- `agent-instantiation/` +- `canon/` +- `cap-build/` +- `char-compress/` +- `data-visualization/` +- `deps-build/` +- `distributed-publication/` +- `doc-build/` +- `domain-claims/` +- `epac-selection-display/` +- `explore-data/` +- `fresh-making/` +- `gonol-build/` +- `interdependent-work-graph/` +- `llms-build/` +- `loop-eng/` +- `manifest/` +- `meta/` +- `meta-module-build/` +- `msdmd/` +- `owner-build/` +- `plain-lens/` +- `project-incubation-graduation/` +- `ratios/` +- `repo-audit-repair/` +- `risk-boundary-build/` +- `skill-build/` +- `skill-usage/` +- `sql-queries/` +- `ssh-automation/` +- `statistical-analysis/` +- `test-build/` +- `the-interdependency/` +- `thought-lens/` +- `typed-meta-frontend/` +- `ucns-option-selection/` +- `validate-data/` +- `visitor-intro/` +- `vm-mcp/` diff --git a/.agents/skills/msdmd/SKILL.md b/.agents/skills/msdmd/SKILL.md index 15f49d6..ffa10c4 100644 --- a/.agents/skills/msdmd/SKILL.md +++ b/.agents/skills/msdmd/SKILL.md @@ -48,10 +48,16 @@ claims to prove those obligations. See - **Fence**: `=== ===` opens, `=== END ===` closes. Block name is uppercase snake_case (e.g. `CONTRACTS`, `CHECKS`, `DOCS`, `CAPABILITIES`, `OWNERS`). -- **Comment marker**: whatever is idiomatic for the file's language. - `#` for Python / Ruby / Elixir / shell. `//` for TS / JS / Rust / Go / - Java / C / C++ / Swift. `--` for SQL / Lua / Haskell. The marker - appears at the start of every line inside the block. +- **Comment marker**: whatever is idiomatic for the file's language. The + reference parsers auto-detect these line-comment families by extension: + `#` for Python, Ruby, Elixir, shell, Perl, R, Julia, PowerShell, Tcl, and + Raku; `//` for TypeScript/JavaScript, Rust, Go, Java, C, C++ (including + `.c+`, `.c++`, `.cxx`, and header variants), Swift, Kotlin, C#, + Objective-C++, Scala, Dart, Zig, Groovy, and PHP; `--` for SQL, Lua, + Haskell, Ada, VHDL, and Lean; `%` for Erlang and Prolog; `;` for + Clojure/Lisp/Scheme/Racket; `!` for Fortran; `'` for Visual Basic; and + `*>` for COBOL. The marker appears at the start of every line in the block. + `COMMENT_MARKERS` in both universal parsers is the exact extension registry. - **Entry boundary**: every entry begins with `id:`. The id must be unique within its block and stable across refactors (so it can be referenced from external tooling). @@ -138,6 +144,17 @@ A reference implementation in pure stdlib Python lives at Both commit to zero non-stdlib dependencies so you can copy them into any project. +Extension detection refuses ambiguous suffixes rather than sniffing content. +For example, `.m` can mean Objective-C or MATLAB/Octave and therefore has no +automatic marker. A caller that already knows the language may still call +`parse_text` / `parseText` with an explicit marker. Languages that cannot carry +the msdmd shape as repeated line comments need a future versioned syntax +extension; they are not approximated with an invalid fence. + +The paired RATIOS helper preserves the interpreter boundary: a non-empty +line-1 shebang may precede opening RATIOS, which must then occupy line 2 with no +gap. See [`ratios/SKILL.md`](../ratios/SKILL.md) for the complete seal contract. + ## Repo collection point and visualizer Every consuming repo SHOULD maintain one repo-level collection point named @@ -219,9 +236,9 @@ Implementation rules every runner MUST follow: 1. **Walk the source tree** under a configurable root, skipping conventional non-source paths (`__pycache__`, `node_modules`, `.git`, build outputs, the runner's own test directory). -2. **Detect comment marker by extension**, not by content sniffing. - `.py / .rb / .ex / .sh → #`. `.ts / .js / .tsx / .jsx / .rs / .go / - .java / .c / .cpp / .swift → //`. `.sql / .lua / .hs → --`. +2. **Detect comment marker by extension**, not by content sniffing. Consume the + parser's `COMMENT_MARKERS` registry rather than maintaining a runner-local + language list. Python and TypeScript registries must remain identical. 3. **Parse all matching blocks** in each file. Multiple blocks of the same type concatenate; entries from different blocks are distinguishable only by id, not by source block. diff --git a/.agents/skills/msdmd/collection.ts b/.agents/skills/msdmd/collection.ts index 697dca2..00195df 100644 --- a/.agents/skills/msdmd/collection.ts +++ b/.agents/skills/msdmd/collection.ts @@ -1,4 +1,4 @@ -// ratios: loc_comments=67:0 imports_exports=0:0 calls_definitions=1:0 +// ratios: loc_comments=hmmm imports_exports=hmmm calls_definitions=hmmm /** * Shared TypeScript shapes for repo-level msdmd collection points. * @@ -72,4 +72,4 @@ export interface MsdmdCollection { export function defineMsdmdCollection(collection: MsdmdCollection): MsdmdCollection { return collection; } -// ratios: loc_comments=67:0 imports_exports=0:0 calls_definitions=1:0 +// ratios: loc_comments=hmmm imports_exports=hmmm calls_definitions=hmmm diff --git a/.agents/skills/msdmd/parsers/universal.py b/.agents/skills/msdmd/parsers/universal.py index 7bc86bf..204f533 100644 --- a/.agents/skills/msdmd/parsers/universal.py +++ b/.agents/skills/msdmd/parsers/universal.py @@ -1,4 +1,4 @@ -# ratios: loc_comments=128:49 imports_exports=4:7 calls_definitions=51:10 +# ratios: loc_comments=161:57 imports_exports=4:7 calls_definitions=55:10 """Universal msdmd parser — pure stdlib. Implements the parser contract from ``msdmd/SKILL.md``: extracts every @@ -7,6 +7,8 @@ Comment marker is auto-detected by file extension. The block syntax itself is identical across languages; only the per-line marker changes. +``COMMENT_MARKERS`` is public so runners can distinguish parser support +from their narrower language-specific execution or metric coverage. Public API: @@ -15,12 +17,13 @@ walk_tree(root, block_name, *, skip=None, extensions=None) -> tuple[annotated, untested] RATIOS is the one msdmd declaration that is *not* a fenced block — it is a -single comment line carried on a file's first and last non-blank lines. The -reader for it lives here too, as a sanctioned extension rather than a fork: +single comment line carried on a file's opening and closing source boundaries. +A valid interpreter shebang owns literal line 1, so the opening RATIOS line is +literal line 2 in that case. The reader lives here as a sanctioned extension: parse_ratios(text, marker="#") -> list[dict] parse_ratios_file(path) -> list[dict] - ratios_placement(text, marker="#") -> tuple[first_ok, last_ok] + ratios_placement(text, marker="#") -> tuple[opening_ok, closing_ok] This module has zero non-stdlib dependencies and is safe to copy verbatim into any project that wants msdmd support. @@ -30,13 +33,39 @@ from pathlib import Path from typing import Iterable -# extension → comment marker -_MARKERS: dict[str, str] = { - ".py": "#", ".rb": "#", ".ex": "#", ".exs": "#", ".sh": "#", - ".ts": "//", ".tsx": "//", ".js": "//", ".jsx": "//", ".mjs": "//", - ".rs": "//", ".go": "//", ".java": "//", ".c": "//", ".cpp": "//", - ".cc": "//", ".h": "//", ".hpp": "//", ".swift": "//", ".kt": "//", +# extension → line-comment marker. Keep this registry entry-for-entry equivalent +# to universal.ts; tests fail if either parser gains or loses an extension alone. +COMMENT_MARKERS: dict[str, str] = { + ".py": "#", ".pyw": "#", ".pyi": "#", + ".rb": "#", ".rake": "#", ".gemspec": "#", + ".ex": "#", ".exs": "#", + ".sh": "#", ".bash": "#", ".zsh": "#", ".fish": "#", + ".pl": "#", ".pm": "#", ".t": "#", + ".r": "#", ".jl": "#", + ".ps1": "#", ".psm1": "#", ".tcl": "#", + ".raku": "#", ".rakumod": "#", + ".ts": "//", ".tsx": "//", ".mts": "//", ".cts": "//", + ".js": "//", ".jsx": "//", ".mjs": "//", ".cjs": "//", + ".rs": "//", ".go": "//", ".java": "//", + ".c": "//", ".cc": "//", ".cp": "//", ".cpp": "//", + ".cxx": "//", ".c+": "//", ".c++": "//", + ".h": "//", ".hh": "//", ".hp": "//", ".hpp": "//", + ".hxx": "//", ".h+": "//", ".h++": "//", + ".tcc": "//", ".ipp": "//", ".inl": "//", + ".swift": "//", ".kt": "//", ".kts": "//", ".cs": "//", + ".mm": "//", ".scala": "//", ".dart": "//", ".zig": "//", + ".groovy": "//", ".gradle": "//", ".php": "//", ".sql": "--", ".lua": "--", ".hs": "--", + ".adb": "--", ".ads": "--", ".vhd": "--", ".vhdl": "--", + ".lean": "--", + ".erl": "%", ".hrl": "%", ".prolog": "%", + ".clj": ";", ".cljs": ";", ".cljc": ";", ".bb": ";", + ".lisp": ";", ".lsp": ";", ".cl": ";", + ".scm": ";", ".ss": ";", ".rkt": ";", + ".f": "!", ".for": "!", ".f90": "!", ".f95": "!", + ".f03": "!", ".f08": "!", + ".vb": "'", ".vbs": "'", + ".cob": "*>", ".cbl": "*>", } _DEFAULT_SKIP = ( @@ -48,7 +77,7 @@ def marker_for(path: Path) -> str | None: """Return the comment marker for a file path, or None if unsupported.""" - return _MARKERS.get(path.suffix.lower()) + return COMMENT_MARKERS.get(path.suffix.lower()) def _block_regex(block_name: str, marker: str) -> re.Pattern[str]: @@ -124,7 +153,7 @@ def walk_tree( ext_set = ( set(e.lower() if e.startswith(".") else "." + e.lower() for e in extensions) if extensions is not None - else set(_MARKERS.keys()) + else set(COMMENT_MARKERS.keys()) ) def iter_source_files(path: Path) -> Iterable[Path]: @@ -155,8 +184,9 @@ def iter_source_files(path: Path) -> Iterable[Path]: # --- RATIOS single-line declaration (msdmd extension) -------------------- # Unlike every other declaration, RATIOS is not fenced. It is a single -# comment line carrying the three canonical ratios, placed on the file's -# first and last non-blank lines: +# comment line carrying the three canonical ratios at the opening source +# boundary and last non-blank line. A valid line-1 shebang moves the opening +# boundary to literal line 2: # ratios: loc_comments=N:M imports_exports=N:M calls_definitions=N:M RATIO_IDS = ("loc_comments", "imports_exports", "calls_definitions") _RATIOS_TOKEN_RE = re.compile(r"(?P[a-z_]+)=(?P\S+)") @@ -171,9 +201,9 @@ def parse_ratios(text: str, marker: str = "#") -> list[dict]: RATIOS is not a fenced block: it is one comment line of the form `` ratios: loc_comments=N:M imports_exports=N:M calls_definitions=N:M`` - placed on the file's first and last non-blank lines. Returns one flat - ``{"id", "value"}`` dict per (declaration line x ratio token) so a drift - gate can verify every occurrence. + placed at the file's opening and closing source boundaries. Returns one + flat ``{"id", "value"}`` dict per (declaration line x ratio token) so a + drift gate can verify every occurrence. """ line_re = _ratios_line_re(marker) out: list[dict] = [] @@ -198,17 +228,29 @@ def parse_ratios_file(path: Path) -> list[dict]: def ratios_placement(text: str, marker: str = "#") -> tuple[bool, bool]: - """Return ``(first_line_has_ratios, last_non_blank_line_has_ratios)``.""" + """Return ``(opening_ratios_ok, closing_ratios_ok)``. + + A non-empty ``#!`` interpreter directive may occupy literal line 1. It is + the only accepted preamble and RATIOS must immediately follow it. + """ line_re = _ratios_line_re(marker) lines = text.splitlines() if not lines: return (False, False) - first_ok = bool(line_re.match(lines[0].rstrip())) + has_shebang = lines[0].startswith("#!") and bool(lines[0][2:].strip()) + opening_index = 1 if has_shebang else 0 + opening_ok = ( + len(lines) > opening_index + and bool(line_re.match(lines[opening_index].rstrip())) + ) + if opening_index == 0 and len(lines) > 1: + displaced = lines[1].startswith("#!") and bool(lines[1][2:].strip()) + opening_ok = opening_ok and not displaced last_ok = False for raw in reversed(lines): if raw.strip() == "": continue last_ok = bool(line_re.match(raw.rstrip())) break - return (first_ok, last_ok) -# ratios: loc_comments=128:49 imports_exports=4:7 calls_definitions=51:10 + return (opening_ok, last_ok) +# ratios: loc_comments=161:57 imports_exports=4:7 calls_definitions=55:10 diff --git a/.agents/skills/msdmd/parsers/universal.ts b/.agents/skills/msdmd/parsers/universal.ts index 2db076f..141f46c 100644 --- a/.agents/skills/msdmd/parsers/universal.ts +++ b/.agents/skills/msdmd/parsers/universal.ts @@ -1,4 +1,4 @@ -// ratios: loc_comments=176:0 imports_exports=2:0 calls_definitions=53:0 +// ratios: loc_comments=hmmm imports_exports=hmmm calls_definitions=hmmm /** * Universal msdmd parser — pure Node stdlib (fs, path). * @@ -9,12 +9,13 @@ * * Comment marker auto-detected by file extension. The block syntax * itself is identical across languages; only the per-line marker - * changes. + * changes. COMMENT_MARKERS is public so runners can keep their narrower + * language-specific execution or metric coverage separate. * * RATIOS is the one msdmd declaration that is not a fenced block — it is a - * single comment line on a file's first and last non-blank lines. Its reader - * (parseRatios / parseRatiosFile / ratiosPlacement) lives here too, as a - * sanctioned extension rather than a fork. + * single comment line on a file's opening and closing source boundaries. A + * valid interpreter shebang owns literal line 1, moving opening RATIOS to + * literal line 2. Its reader lives here as a sanctioned extension. * * Zero non-stdlib dependencies. Safe to copy verbatim into any * Node/Deno/Bun project that wants msdmd support. @@ -24,12 +25,39 @@ import { join, extname } from "node:path"; export type Entry = Record; -const MARKERS: Record = { - ".py": "#", ".rb": "#", ".ex": "#", ".exs": "#", ".sh": "#", - ".ts": "//", ".tsx": "//", ".js": "//", ".jsx": "//", ".mjs": "//", - ".rs": "//", ".go": "//", ".java": "//", ".c": "//", ".cpp": "//", - ".cc": "//", ".h": "//", ".hpp": "//", ".swift": "//", ".kt": "//", +// Keep this registry entry-for-entry equivalent to universal.py; tests fail if +// either parser gains or loses an extension alone. +export const COMMENT_MARKERS: Record = { + ".py": "#", ".pyw": "#", ".pyi": "#", + ".rb": "#", ".rake": "#", ".gemspec": "#", + ".ex": "#", ".exs": "#", + ".sh": "#", ".bash": "#", ".zsh": "#", ".fish": "#", + ".pl": "#", ".pm": "#", ".t": "#", + ".r": "#", ".jl": "#", + ".ps1": "#", ".psm1": "#", ".tcl": "#", + ".raku": "#", ".rakumod": "#", + ".ts": "//", ".tsx": "//", ".mts": "//", ".cts": "//", + ".js": "//", ".jsx": "//", ".mjs": "//", ".cjs": "//", + ".rs": "//", ".go": "//", ".java": "//", + ".c": "//", ".cc": "//", ".cp": "//", ".cpp": "//", + ".cxx": "//", ".c+": "//", ".c++": "//", + ".h": "//", ".hh": "//", ".hp": "//", ".hpp": "//", + ".hxx": "//", ".h+": "//", ".h++": "//", + ".tcc": "//", ".ipp": "//", ".inl": "//", + ".swift": "//", ".kt": "//", ".kts": "//", ".cs": "//", + ".mm": "//", ".scala": "//", ".dart": "//", ".zig": "//", + ".groovy": "//", ".gradle": "//", ".php": "//", ".sql": "--", ".lua": "--", ".hs": "--", + ".adb": "--", ".ads": "--", ".vhd": "--", ".vhdl": "--", + ".lean": "--", + ".erl": "%", ".hrl": "%", ".prolog": "%", + ".clj": ";", ".cljs": ";", ".cljc": ";", ".bb": ";", + ".lisp": ";", ".lsp": ";", ".cl": ";", + ".scm": ";", ".ss": ";", ".rkt": ";", + ".f": "!", ".for": "!", ".f90": "!", ".f95": "!", + ".f03": "!", ".f08": "!", + ".vb": "'", ".vbs": "'", + ".cob": "*>", ".cbl": "*>", }; const DEFAULT_SKIP = new Set([ @@ -43,7 +71,7 @@ function escapeRegex(s: string): string { } export function markerFor(path: string): string | null { - return MARKERS[extname(path).toLowerCase()] ?? null; + return COMMENT_MARKERS[extname(path).toLowerCase()] ?? null; } export function parseText( @@ -104,7 +132,7 @@ export function walkTree( ): { annotated: Array<[string, Entry[]]>; untested: string[] } { const skip = opts.skip ?? DEFAULT_SKIP; const extensions = - opts.extensions ?? new Set(Object.keys(MARKERS)); + opts.extensions ?? new Set(Object.keys(COMMENT_MARKERS)); const annotated: Array<[string, Entry[]]> = []; const untested: string[] = []; @@ -145,8 +173,9 @@ export function walkTree( // --- RATIOS single-line declaration (msdmd extension) -------------------- // Unlike every other declaration, RATIOS is not fenced. It is a single -// comment line carrying the three canonical ratios, placed on the file's -// first and last non-blank lines: +// comment line carrying the three canonical ratios at the opening source +// boundary and last non-blank line. A valid line-1 shebang moves the opening +// boundary to literal line 2: // ratios: loc_comments=N:M imports_exports=N:M calls_definitions=N:M export const RATIO_IDS = ["loc_comments", "imports_exports", "calls_definitions"] as const; @@ -184,13 +213,22 @@ export function ratiosPlacement(text: string, marker: string = "#"): [boolean, b const lineRe = ratiosLineRe(marker); const lines = text.split("\n"); if (lines.length === 0) return [false, false]; - const firstOk = lineRe.test(lines[0].replace(/\s+$/, "")); + const hasShebang = lines[0].startsWith("#!") && lines[0].slice(2).trim().length > 0; + const openingIndex = hasShebang ? 1 : 0; + const openingOk = + lines.length > openingIndex && + lineRe.test(lines[openingIndex].replace(/\s+$/, "")); + const displacedShebang = + openingIndex === 0 && + lines.length > 1 && + lines[1].startsWith("#!") && + lines[1].slice(2).trim().length > 0; let lastOk = false; for (let i = lines.length - 1; i >= 0; i--) { if (lines[i].trim() === "") continue; lastOk = lineRe.test(lines[i].replace(/\s+$/, "")); break; } - return [firstOk, lastOk]; + return [openingOk && !displacedShebang, lastOk]; } -// ratios: loc_comments=176:0 imports_exports=2:0 calls_definitions=53:0 +// ratios: loc_comments=hmmm imports_exports=hmmm calls_definitions=hmmm diff --git a/.agents/skills/ratios/SKILL.md b/.agents/skills/ratios/SKILL.md index cf2b7cd..076181c 100644 --- a/.agents/skills/ratios/SKILL.md +++ b/.agents/skills/ratios/SKILL.md @@ -1,6 +1,6 @@ --- name: ratios -description: Self-declaring module composition ratios on msdmd — a single comment line on a file's first and last line (never a fenced block). The canonical seal is `The-Interdependency/a0`'s compact positional `N:M C:D I:O` annotation (code:comment · consumed:declared · fan-in:fan-out), computed by a0's `scripts/annotate.py`; the named `loc_comments=… imports_exports=… calls_definitions=…` line is a portable, per-file adaptation for standalone libraries, verified by the stdlib `ratios_check.py` (drift/misplacement failures, visible gaps). JSON/Markdown are out of scope. Load this when recording a module's composition ratios, when authoring or extending the ratio registry, or when wiring ratio verification into CI. +description: Self-declaring module composition ratios on msdmd — one comment line at a file's opening and closing source boundaries (never a fenced block), with a valid interpreter shebang allowed before the opening seal. The canonical seal is `The-Interdependency/a0`'s compact positional `N:M C:D I:O` annotation (code:comment · consumed:declared · fan-in:fan-out), computed by a0's `scripts/annotate.py`; the named `loc_comments=… imports_exports=… calls_definitions=…` line is a portable, per-file adaptation for standalone libraries, verified by the stdlib `ratios_check.py` (drift/misplacement failures, visible gaps). JSON/Markdown are out of scope. Load this when recording a module's composition ratios, when authoring or extending the ratio registry, or when wiring ratio verification into CI. --- # ratios — Module composition ratios on msdmd @@ -23,14 +23,19 @@ the file is a build failure, not a stale comment nobody noticed. `The-Interdependency/a0` is the **canonical origin** of the ratios seal — the convention every other form adapts, not the other way round. a0 stamps three -composition metrics on the first and last line of every Python / TypeScript -file, written and verified by its own `scripts/annotate.py`: +composition metrics at the opening and closing source boundaries of every +Python / TypeScript file, written and verified by its own `scripts/annotate.py`: ```text # N:M C:D I:O (Python) // N:M C:D I:O (TypeScript / TSX) ``` +Ordinary modules put the opening seal on literal line 1. Directly executable +scripts reserve literal line 1 for a non-empty `#!` interpreter directive and +put the opening seal immediately on literal line 2. The matching closing seal +is the last non-blank line in both cases. + | pair | meaning | how computed | |---|---|---| | `N:M` | code lines : comment+docstring lines (internal density; `N` budget ≤ 400) | per-file | @@ -73,16 +78,17 @@ are per-file stand-ins for the surface/graph intent of `C:D` and `I:O`. Repos already stamped in this form (skill-lib, aimmh, edcmbone, pcna, pcta, ptca, pcea) remain valid and are **not** required to reconvert. -Both forms keep one seal discipline: a single line on the file's first and last -non-blank line, with nothing above it. +Both forms keep one seal discipline: a single line at the opening and closing +source boundaries. Nothing may precede the opening seal except one valid +interpreter shebang on literal line 1. -### The single line, and the first/last rule +### The single line and shebang-safe boundary rule RATIOS is the one msdmd declaration that is **not a fenced block**. It applies to executable/source files with a language comment marker (`#`, `//`, or `--`), not to JSON, Markdown, or other data/documentation files. In covered source -files it is a single comment line carrying all three ratios, placed on the -file's **literal first line and its last non-blank line**: +files it is a single comment line carrying all three ratios, placed at the +opening boundary and repeated on the file's last non-blank line: ```python # ratios: loc_comments=128:49 imports_exports=4:7 calls_definitions=51:10 @@ -91,6 +97,20 @@ file's **literal first line and its last non-blank line**: # ratios: loc_comments=128:49 imports_exports=4:7 calls_definitions=51:10 ``` +For a directly executable script: + +```bash +#!/usr/bin/env bash +# ratios: loc_comments=40:12 imports_exports=0:0 calls_definitions=0:0 +... +# ratios: loc_comments=40:12 imports_exports=0:0 calls_definitions=0:0 +``` + +The shebang exception is structural, not a general license for preambles: it +must be non-empty, occupy literal line 1, and be followed immediately by the +opening seal. Blank lines, encoding headers, copyright comments, or other text +before the seal fail placement. + The form is: ```text @@ -101,10 +121,10 @@ The form is: - The three ids are fixed: `loc_comments`, `imports_exports`, `calls_definitions`. Each carries an `A:B` value, or `hmmm` if the ratio is declared-but-not-yet-resolved. -- The same line opens and closes the file. The file is a self-measuring - object; its boundary lines carry the measurement, opening and closing. +- The same line opens and closes the file. Without a shebang the opening seal + is literal line 1; with a valid shebang it is literal line 2. - Scope: executable source files only. `json` and `.md` files are out of - scope for first/last-line RATIOS bookends. + scope for RATIOS boundary seals. There is no fenced `# === RATIOS === … # === END RATIOS ===` block. An earlier draft of this skill described one; that was wrong. Tooling reads the single @@ -126,7 +146,7 @@ a fork (`msdmd/parsers/universal.py`): from msdmd.parsers.universal import parse_ratios, ratios_placement, RATIO_IDS parse_ratios(text, marker) # -> [{"id": "loc_comments", "value": "128:49"}, ...] -ratios_placement(text, marker) # -> (first_line_ok, last_non_blank_line_ok) +ratios_placement(text, marker) # -> (opening_ok, closing_ok) ``` `parse_ratios` returns one flat `{"id", "value"}` dict per (declaration line × @@ -144,7 +164,7 @@ registry. A computer is a pure function `file_text -> "A:B"`. The runner: measurement; - compares the recomputed value to the recorded value; - on mismatch, emits a **drift** error and exits non-zero; -- on a declaration that is not on both the first and last line, emits a +- on a declaration that is not on both source boundaries, emits a **misplaced** error and exits non-zero; - on `value: hmmm`, reports a living continuation (pending), never a failure — the transition out of `hmmm` is the owner's decision; @@ -152,10 +172,13 @@ registry. A computer is a pure function `file_text -> "A:B"`. The runner: unverifiable (informational), so unknown ratios stay visible rather than silently trusted. -Covered source files with no `ratios:` line surface as coverage gaps, exactly -as in the build checker. JSON, Markdown, and other files with no supported -source comment marker are skipped rather than reported as gaps. The gap list is -informational unless `--strict`. +The bundled named-form computers currently implement Python syntax. Python +files without `ratios:` surface as coverage gaps; other parser-supported +languages do not become false gaps merely because msdmd learned their comment +marker. If a non-Python file already carries a named seal, the runner checks +its placement and reports its values as visible-but-unverifiable until a +language-aware computer is registered. JSON, Markdown, and unsupported files +remain out of scope. The Python gap list is informational unless `--strict`. ## The three ratios @@ -252,9 +275,9 @@ as gaps is expected, not a bug. It is a single `ratios:` line; the block form was a mistake. - Recording a ratio by hand instead of recomputing it. The point is that the file measures itself; a hand-typed value is a contract that drifts. -- Placing the line anywhere but the file's first and last line. The first/last - placement is the convention; a mid-file `ratios:` line defeats the - at-a-glance reading and fails the placement gate. +- Placing anything before opening RATIOS except a valid line-1 shebang, or + leaving a gap between that shebang and the opening seal. Either breaks the + source-boundary invariant and fails placement. - Counting a `ratios:` line in its own ratio. Always self-exclude. - Inventing ratio ids whose computer does not exist and recording a number for them. If there's no computer, the value cannot be verified — record @@ -265,16 +288,17 @@ as gaps is expected, not a bug. ## Completion criteria -A run is complete when every covered executable/source file carries a correctly placed `ratios:` -line on its first and last line, the registry's three computers -(`loc_comments`, `imports_exports`, `calls_definitions`) recompute each -recorded value with no drift, and any unresolved ratio is recorded as `hmmm` -rather than guessed. +A run is complete when every computer-covered source file carries a correctly +placed opening RATIOS line (literal line 1, or line 2 immediately after a valid +line-1 shebang), an identical closing line on the last non-blank line, the +registry's three computers (`loc_comments`, `imports_exports`, +`calls_definitions`) recompute each recorded value with no drift, and any +unresolved ratio is recorded as `hmmm` rather than guessed. hmmm -- the reference computers implement the Python counting rules; language-aware - computers for TypeScript/other markers are a documented extension point, not - yet implemented in `ratios_check.py` +- language-aware named-form computers for TypeScript and other parser-supported + languages remain an extension point; the runner now exposes them as outside + computer scope instead of applying Python semantics - whether ratios verification joins CI beside the other msdmd checks - calls_definitions: whether lambda assignments count as definitions - imports_exports: whether re-exported names from `__init__.py` aggregate diff --git a/.agents/skills/ratios/annotate_index.py b/.agents/skills/ratios/annotate_index.py index e4d7e59..8a88945 100644 --- a/.agents/skills/ratios/annotate_index.py +++ b/.agents/skills/ratios/annotate_index.py @@ -1,4 +1,4 @@ -# ratios: loc_comments=232:33 imports_exports=7:4 calls_definitions=83:14 +# ratios: loc_comments=264:34 imports_exports=7:4 calls_definitions=99:17 """Portable computer for the canonical ratios seal — a0's `N:M C:D I:O`. This is the shared, stdlib port of `The-Interdependency/a0`'s @@ -59,12 +59,30 @@ def _is_seal(line: str, ext: str) -> bool: return bool((_ANN_PY if ext == ".py" else _ANN_TS).match(s)) +def _has_valid_shebang(lines: list[str]) -> bool: + """Return whether literal line 1 is a non-empty interpreter directive.""" + return bool(lines and lines[0].startswith("#!") and lines[0][2:].strip()) + + +def _opening_index(lines: list[str]) -> int: + return 1 if _has_valid_shebang(lines) else 0 + + +def _last_nonblank_index(lines: list[str]) -> int | None: + for index in range(len(lines) - 1, -1, -1): + if lines[index].strip(): + return index + return None + + def _strip_seal(lines: list[str], ext: str) -> list[str]: w = lines[:] - if w and _is_seal(w[0], ext): - w = w[1:] - if w and _is_seal(w[-1], ext): - w = w[:-1] + opening = _opening_index(w) + if len(w) > opening and _is_seal(w[opening], ext): + del w[opening] + closing = _last_nonblank_index(w) + if closing is not None and _is_seal(w[closing], ext): + del w[closing] return w @@ -289,18 +307,39 @@ def main(argv: list[str] | None = None) -> int: lines = path.read_text(encoding="utf-8").splitlines() except OSError: continue - have = lines[0].strip() if lines else "" - placed_ok = bool(lines) and _is_seal(lines[0], ext) and _is_seal(lines[-1], ext) + opening = _opening_index(lines) + closing = _last_nonblank_index(lines) + have = lines[opening].strip() if len(lines) > opening else "" + close = lines[closing].strip() if closing is not None else "" + placed_ok = ( + len(lines) > opening + and _is_seal(lines[opening], ext) + and closing is not None + and _is_seal(lines[closing], ext) + and not ( + opening == 0 + and len(lines) > 1 + and lines[1].startswith("#!") + and bool(lines[1][2:].strip()) + ) + ) if write: working = _strip_seal(lines, ext) - new = "\n".join([want] + working + [want]) + "\n" + if _has_valid_shebang(working): + new_lines = [working[0], want, *working[1:], want] + else: + new_lines = [want, *working, want] + new = "\n".join(new_lines) + "\n" if new != path.read_text(encoding="utf-8"): path.write_text(new, encoding="utf-8") print(f" stamped {path.relative_to(root)} [{want}]") else: - if not placed_ok or have != want: + if not placed_ok or have != want or close != want: drift += 1 - print(f" DRIFT {path.relative_to(root)}: have '{have}' want '{want}'") + print( + f" DRIFT {path.relative_to(root)}: " + f"opening '{have}' closing '{close}' want '{want}'" + ) if check: print(f"annotate_index: {len(files)} files, {drift} drift/misplaced") return 1 if drift else 0 @@ -309,4 +348,4 @@ def main(argv: list[str] | None = None) -> int: if __name__ == "__main__": raise SystemExit(main()) -# ratios: loc_comments=232:33 imports_exports=7:4 calls_definitions=83:14 +# ratios: loc_comments=264:34 imports_exports=7:4 calls_definitions=99:17 diff --git a/.agents/skills/ratios/ratios_check.py b/.agents/skills/ratios/ratios_check.py index 12f470e..59eafe0 100644 --- a/.agents/skills/ratios/ratios_check.py +++ b/.agents/skills/ratios/ratios_check.py @@ -1,18 +1,21 @@ -# ratios: loc_comments=190:27 imports_exports=6:7 calls_definitions=78:10 +# ratios: loc_comments=218:33 imports_exports=6:7 calls_definitions=86:10 """ratios skill executor — recompute the canonical ratios and gate on drift. Reference runner for the ``ratios`` skill. It reads the single-line RATIOS declaration (`` ratios: loc_comments=N:M imports_exports=N:M -calls_definitions=N:M``) from a file's first and last non-blank lines, +calls_definitions=N:M``) from a file's opening and closing source boundaries, recomputes each ratio from the source, and fails on: * drift — a recorded ratio no longer matches what the source computes; - * misplaced — a RATIOS declaration not on both the first and last line; - * gaps — (only under ``--strict``) source files with no RATIOS at all. + * misplaced — a RATIOS declaration not on both source boundaries; + * gaps — (only under ``--strict``) computer-supported files with no + RATIOS at all. ``value: hmmm`` is reported as pending, never a failure. A recorded id with no registered computer is reported as unverifiable (informational). Pure stdlib; the single-line reader is reused from the msdmd universal parser, not forked. +The bundled computers are Python-specific. Parser support for another language +does not silently opt that language into Python metric semantics. Usage: python ratios_check.py path/to/module.py # verify one file @@ -148,6 +151,11 @@ def compute_calls_definitions(text: str) -> str: "calls_definitions": compute_calls_definitions, } +# The named-form computers above use Python imports, definitions, docstrings, +# and call syntax. Other parser-supported languages remain discoverable without +# becoming false strict-mode gaps or receiving Python-shaped verification. +COMPUTER_EXTENSIONS = {".py"} + def _iter_source(root: Path): """Yield every source file under ``root`` with a known comment marker.""" @@ -167,13 +175,36 @@ def _verify_file(path: Path, base: Path, rep: dict) -> None: text = path.read_text(encoding="utf-8", errors="ignore") entries = parse_ratios(text, marker) if not entries: - rep["gaps"].append(rel) + if path.suffix.lower() in COMPUTER_EXTENSIONS: + rep["gaps"].append(rel) + else: + rep["outside_computer_scope"].append(rel) return rep["covered"] += 1 - first_ok, last_ok = ratios_placement(text, marker) - if not (first_ok and last_ok): - rep["misplaced"].append({"file": rel, "first_line": first_ok, "last_line": last_ok}) + opening_ok, closing_ok = ratios_placement(text, marker) + if not (opening_ok and closing_ok): + rep["misplaced"].append( + {"file": rel, "opening": opening_ok, "closing": closing_ok} + ) + + if path.suffix.lower() not in COMPUTER_EXTENSIONS: + for entry in entries: + value = (entry.get("value") or "").strip() + if value == "hmmm": + rep["pending"].append( + {"file": rel, "id": entry.get("id", ""), "reason": "language computer unavailable"} + ) + continue + rep["unverifiable"].append( + { + "file": rel, + "id": entry.get("id", ""), + "value": value, + "reason": f"no named-form computer for {path.suffix.lower()}", + } + ) + return for entry in entries: cid = entry.get("id", "") @@ -202,7 +233,7 @@ def run(target: Path) -> dict: rep: dict = { "skill": "ratios", "root": str(target), "scanned": 0, "covered": 0, "gaps": [], "drift": [], "misplaced": [], "pending": [], - "verified": [], "unverifiable": [], + "verified": [], "unverifiable": [], "outside_computer_scope": [], } if target.is_file(): rep["scanned"] = 1 @@ -215,6 +246,7 @@ def run(target: Path) -> dict: rep["drift_count"] = len(rep["drift"]) rep["misplaced_count"] = len(rep["misplaced"]) rep["pending_count"] = len(rep["pending"]) + rep["outside_computer_scope_count"] = len(rep["outside_computer_scope"]) rep["verified_count"] = len(rep["verified"]) return rep @@ -226,6 +258,7 @@ def summary(rep: dict) -> str: f"{rep['verified_count']} verified . {rep['drift_count']} drift . " f"{rep['misplaced_count']} misplaced . " f"{rep['pending_count']} hmmm . {len(rep['unverifiable'])} unverifiable" + f" . {rep['outside_computer_scope_count']} outside-computer-scope" ) @@ -242,7 +275,10 @@ def main(argv: list[str] | None = None) -> int: for d in rep["drift"][:30]: print(f" drift: {d['file']} :: {d['id']}: recorded {d['recorded']} != computed {d['computed']}") for m in rep["misplaced"][:30]: - print(f" misplaced: {m['file']}: first_line={m['first_line']} last_line={m['last_line']}") + print( + f" misplaced: {m['file']}: " + f"opening={m['opening']} closing={m['closing']}" + ) if strict: for g in rep["gaps"][:30]: print(f" gap: {g}") @@ -253,4 +289,4 @@ def main(argv: list[str] | None = None) -> int: if __name__ == "__main__": raise SystemExit(main()) -# ratios: loc_comments=190:27 imports_exports=6:7 calls_definitions=78:10 +# ratios: loc_comments=218:33 imports_exports=6:7 calls_definitions=86:10 diff --git a/.agents/skills/vm-mcp/install.sh b/.agents/skills/vm-mcp/install.sh index 545f68c..c0bb487 100644 --- a/.agents/skills/vm-mcp/install.sh +++ b/.agents/skills/vm-mcp/install.sh @@ -1,5 +1,5 @@ -# ratios: loc_comments=115:18 imports_exports=0:0 calls_definitions=2:0 #!/usr/bin/env bash +# ratios: loc_comments=hmmm imports_exports=hmmm calls_definitions=hmmm set -euo pipefail # Install canonical vm-mcp on a Linux VM. @@ -148,4 +148,4 @@ else printf ' root broker: disabled\n' fi systemctl --no-pager --full status vm-mcp.service | sed -n '1,14p' -# ratios: loc_comments=115:18 imports_exports=0:0 calls_definitions=2:0 +# ratios: loc_comments=hmmm imports_exports=hmmm calls_definitions=hmmm