Skip to content
This repository was archived by the owner on Jul 29, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .agents/skills/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Installed skills:
- `meta-module-build/` — metadata-first module scaffolding
- `new-retain-old/` — safe replacement workflow that preserves the old implementation while creating a new active path
- `manifest/` — living-spec generator for `CLAUDE.md` (vendored from
`The-Interdependency/skill-lib@6f36340`). Generates the mechanical facts
`The-Interdependency/skill-lib@05ee7aa`). Generates the mechanical facts
block in `CLAUDE.md` from `backend/pyproject.toml` + the tree; the
`manifest drift check` workflow runs `generate.py --check` in CI. Refresh with
`python .agents/skills/manifest/generate.py --pyproject backend/pyproject.toml --write`.
Expand Down
35 changes: 23 additions & 12 deletions .agents/skills/doctrine/msdmd-checks.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,27 +55,38 @@ beneath it:
CONTRACTS fields: `id`, `given`, `then`, `class`
(doctrine | evidence | safety | security).

CHECKS fields, all consumed: `id`, `proves`, `call`, `requires`
(runner refuses to execute on hosts missing them), `timeout` (runner
sets the active subprocess bound per check), `mutates` and `cleanup`
(danger documentation read by humans deciding when a check may run).
CHECKS fields — every one has a consumer, whether the runner or the
operator: `id`, `proves`, `call`, `requires` (runner refuses to execute
on hosts missing them), `timeout` (runner sets the active subprocess
bound per check) — these four are **runner-consumed** — plus `mutates`
and `cleanup`, which are **operator-consumed**: the danger documentation
a human reads to decide when a check may run. Operator-consumed is
consumed; it is not decoration.

## The field-entry rule

A field enters the schema in the same change that makes a runner
consume it, not before. Declared-but-unread metadata is F6 —
A field enters the schema in the same change that gives it a consumer —
a runner mode that reads it, or a documented operator decision it feeds
— not before. Metadata read by *neither* runner nor operator is F6 —
decorative preservation — and is treated as a defect, not diligence.
(`determinism` and `level` are currently out for exactly this reason;
they enter when a runner mode reads them. Note that `determinism` is
self-reported until a runner measures it by repeated execution.)
(`mutates`/`cleanup` clear this bar as operator-consumed. `determinism`
and `level` do not yet: nothing reads them, so they stay out until a
runner mode does. Note that `determinism` is self-reported until a
runner measures it by repeated execution.)

## call: resolution

The only sanctioned form is `self::fn` — a callable defined in the
The only sanctioned form is `self::fn` — a function defined in the
file that declares the check. Dotted import paths are refused by the
audit: Python imports execute module top level, and **an audit that
executes is not an audit**. The `self::` form is also rename-immune;
copies and uploads reconcile identically.
executes is not an audit**. A no-exec audit therefore resolves `self::fn`
against the file's **parsed** `def`/`async def` names (read the source,
walk the AST) — never by importing the module or inspecting loaded
callables. (The reference `tests/test_repo_loto.py` reads `globals()`
only because its audit runs *as* that module, so the definitions are
already in scope; a central audit walking many files must parse.) The
`self::` form is also rename-immune; copies and uploads reconcile
identically.

## audit

Expand Down
31 changes: 24 additions & 7 deletions .agents/skills/test-build/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,19 +139,36 @@ A check function:
## Authoring an audit

Audit is the cheapest runner mode: reconcile declarations without
executing checks. A Python audit for `self::fn` checks can avoid import
side effects entirely:
executing checks. Resolve `self::fn` against the declaring file's
**parsed** function definitions — never by importing it or reading
loaded callables, since import executes module top level and an audit
that executes is not an audit:

```python
def resolve_self_call(spec: str, namespace: dict) -> object:
import ast

def defined_functions(source_path: str) -> set[str]:
tree = ast.parse(open(source_path, encoding="utf-8").read())
return {
node.name
for node in ast.walk(tree)
if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef))
}

def resolve_self_call(spec: str, defined: set[str]) -> str:
if not spec.startswith("self::"):
raise LookupError(f"only self::fn resolves without execution: {spec}")
fn = namespace.get(spec[len("self::"):])
if not callable(fn):
raise LookupError(f"not callable: {spec}")
return fn
name = spec[len("self::"):]
if name not in defined:
raise LookupError(f"self:: target not defined in file: {spec}")
return name
```

(The bundled `tests/test_repo_loto.py` reads `globals()` instead — it
can, because its audit runs *as* that module, so its own `def`s are
already in scope. A central audit walking other test files has no such
shortcut and must parse, as above.)

An audit MUST report, at minimum:

```text
Expand Down
Loading
Loading