Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
0753156
repair: close audit defects before v0.2.0
erinepshovel-code Sep 11, 2026
3a2f415
repair: align documentation and provenance guards
erinepshovel-code Sep 11, 2026
a7976df
repair: remove stale hmmm and keep legal surface unchanged
erinepshovel-code Sep 11, 2026
fbc3842
repair: preserve handoff scope and public claims
erinepshovel-code Sep 11, 2026
78e397e
repair: make examiner metadata idempotent
erinepshovel-code Sep 11, 2026
c7b2f05
repair: retain numeric msdmd narrative fields
erinepshovel-code Sep 11, 2026
a1681cf
repair: make narrative upsert idempotent and harden CI
erinepshovel-code Sep 11, 2026
1373ea4
fix: treat blank model overrides as unset
erinepshovel-code Sep 11, 2026
e528267
fix: mutate only safe ratio languages
erinepshovel-code Sep 11, 2026
5085f77
fix: close package-script audit gaps
erinepshovel-code Sep 11, 2026
b0b6afa
test: cover repaired audit and examiner boundaries
erinepshovel-code Sep 11, 2026
90c55d7
chore: repin canonical msdmd parser
erinepshovel-code Sep 11, 2026
953765e
chore: align TypeScript parser with canonical msdmd
erinepshovel-code Sep 11, 2026
e82f925
chore: preserve canonical parser bytes
erinepshovel-code Sep 11, 2026
edc29c0
chore: refresh canonical msdmd skill
erinepshovel-code Sep 11, 2026
76fa080
docs: pin merged skill-lib authority
erinepshovel-code Sep 11, 2026
cc2e8ca
docs: record refreshed canonical skill source
erinepshovel-code Sep 11, 2026
4e7c701
fix: consume canonical msdmd entry parser
erinepshovel-code Sep 11, 2026
3d52e9f
fix audit interpreter and path boundaries
erinepshovel-code Sep 11, 2026
3b9162d
package canonical msdmd parser
erinepshovel-code Sep 11, 2026
d307e28
fix evidence packaging and byte hashing
erinepshovel-code Sep 11, 2026
f550ae4
refresh fixture source pin
erinepshovel-code Sep 11, 2026
6fa9725
align apply test with safe adapter boundary
erinepshovel-code Sep 11, 2026
41ffc94
add regressions for audit and evidence boundaries
erinepshovel-code Sep 11, 2026
ea779ed
guard packaged canonical parser provenance
erinepshovel-code Sep 11, 2026
1394efe
verify noneditable wheel parser packaging
erinepshovel-code Sep 11, 2026
3c2f989
Preserve examiner source encodings and resolve interpreter operands
erinepshovel-code Sep 12, 2026
b35b33a
Preserve BOMs across adapters and complete Node option arity
erinepshovel-code Sep 12, 2026
45ecb3f
Handle Node test runner value options and aliases
erinepshovel-code Sep 12, 2026
51c7ef1
Preserve shell quoting, URL entrypoints, and canonical parser bytes
erinepshovel-code Sep 12, 2026
25f65b5
Preserve literal source data and concurrent edits during examination
erinepshovel-code Sep 12, 2026
53e509f
Preserve source inodes and publish without replacing competing edits
erinepshovel-code Sep 12, 2026
363e398
Enforce canonical placement and expose safe source recovery
erinepshovel-code Sep 12, 2026
660d2c8
Keep recovery CLI regressions valid after fixture annotation
erinepshovel-code Sep 12, 2026
751dbd8
Close audit context gaps and preserve source metadata and stale evidence
erinepshovel-code Sep 12, 2026
5b0f03f
Keep unresolved shell expansion contexts out of literal path findings
erinepshovel-code Sep 12, 2026
e065432
Keep literal entrypoints visible around dynamic child arguments
erinepshovel-code Sep 12, 2026
62f863a
Close shell operand and undecodable evidence hash gaps
erinepshovel-code Sep 12, 2026
1b52d08
Restrict assignment tilde expansion to its first separator or colons
erinepshovel-code Sep 12, 2026
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 @@ -3,7 +3,7 @@
This directory contains repo-local copies of canonical skills from
`The-Interdependency/skill-lib`.

Source commit: `c14ee9d500579a4b5d6821f62c9d82ca96e73608`
Source commit: `8de4f12d0f31ff94f41e4a0196c447c0cbe20faf`

Repo-local copies are not the source of truth. Edit `skill-lib` first,
then propagate from the canonical source.
Expand Down
4 changes: 3 additions & 1 deletion .agents/skills/msdmd/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,9 @@ claims to prove those obligations. See
referenced from external tooling).
- **Field lines**: indented one level beneath the id (two spaces of
visible indent inside the comment). Field names are lowercase
snake_case followed by `:` and a value.
snake_case followed by `:` and a value. Digits are allowed after the first
character, so `evidence_sha256` is valid; the first character must be a
lowercase letter or underscore.
- **Multiple blocks per file**: a module may declare more than one
block, of the same or different types. The parser concatenates
entries.
Expand Down
6 changes: 3 additions & 3 deletions .agents/skills/msdmd/parsers/universal.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ def parse_text(text: str, block_name: str, marker: str = "#") -> list[dict]:
block_re = _block_regex(block_name, marker)
m = re.escape(marker)
id_re = re.compile(rf"^\s*{m}\s*id:\s*(?P<id>\S+)\s*$")
field_re = re.compile(rf"^\s*{m}\s+(?P<key>[a-z_]+):\s*(?P<val>.+?)\s*$")
field_re = re.compile(rf"^\s*{m}\s+(?P<key>[a-z_][a-z0-9_]*):\s*(?P<val>.+?)\s*$")

entries: list[dict] = []
for block in block_re.finditer(text):
Expand Down Expand Up @@ -189,7 +189,7 @@ def iter_source_files(path: Path) -> Iterable[Path]:
# boundary to literal line 2:
# <marker> 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<key>[a-z_]+)=(?P<val>\S+)")
_RATIOS_TOKEN_RE = re.compile(r"(?P<key>[a-z_][a-z0-9_]*)=(?P<val>\S+)")


def _ratios_line_re(marker: str) -> re.Pattern[str]:
Expand Down Expand Up @@ -253,4 +253,4 @@ def ratios_placement(text: str, marker: str = "#") -> tuple[bool, bool]:
last_ok = bool(line_re.match(raw.rstrip()))
break
return (opening_ok, last_ok)
# ratios: loc_comments=161:57 imports_exports=4:7 calls_definitions=55:10
# ratios: loc_comments=161:57 imports_exports=4:7 calls_definitions=55:10
4 changes: 2 additions & 2 deletions .agents/skills/msdmd/parsers/universal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ export function parseText(
"gm",
);
const idRe = new RegExp(`^\\s*${m}\\s*id:\\s*(\\S+)\\s*$`);
const fieldRe = new RegExp(`^\\s*${m}\\s+([a-z_]+):\\s*(.+?)\\s*$`);
const fieldRe = new RegExp(`^\\s*${m}\\s+([a-z_][a-z0-9_]*):\\s*(.+?)\\s*$`);

const entries: Entry[] = [];
let match: RegExpExecArray | null;
Expand Down Expand Up @@ -185,7 +185,7 @@ function ratiosLineRe(marker: string): RegExp {

export function parseRatios(text: string, marker: string = "#"): Entry[] {
const lineRe = ratiosLineRe(marker);
const tokenRe = /([a-z_]+)=(\S+)/g;
const tokenRe = /([a-z_][a-z0-9_]*)=(\S+)/g;
const out: Entry[] = [];
for (const raw of text.split("\n")) {
const lm = lineRe.exec(raw.replace(/\s+$/, ""));
Expand Down
7 changes: 7 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# This file intentionally exists as an example only. Real credentials belong in
# your local .env (ignored) or process environment.
OPENAI_API_KEY=
OPENAI_MODEL=
Comment thread
erinepshovel-code marked this conversation as resolved.
ANTHROPIC_API_KEY=
ANTHROPIC_MODEL=
# Base URL overrides are process-environment-only and are not read from .env.
19 changes: 16 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,16 +1,29 @@
name: ci
on: [push, pull_request]
permissions:
contents: read
jobs:
test:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: ['3.11', '3.12']
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
- uses: actions/checkout@v7
with:
python-version: '3.12'
persist-credentials: false
- uses: actions/setup-python@v7
Comment thread
erinepshovel-code marked this conversation as resolved.
with:
python-version: ${{ matrix.python-version }}
- run: |
python -m venv .venv
. .venv/bin/activate
python -m pip install -e .
python -m unittest discover -s tests
python -m pubskill_lib.audit examples/neglected-repo --out /tmp/findings.json
python -m pip wheel . --no-deps -w /tmp/pubskill-wheel
python -m venv /tmp/pubskill-wheel-venv
/tmp/pubskill-wheel-venv/bin/python -m pip install --no-deps /tmp/pubskill-wheel/pubskill_lib-*.whl
cd /tmp
/tmp/pubskill-wheel-venv/bin/python -c "from pubskill_lib import evidence; assert evidence._comment_markers()['.py'] == '#'"
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,8 @@
__pycache__/
*.pyc
*.egg-info/
.env
.env.*
!.env.example

.examiner-originals-*/
41 changes: 26 additions & 15 deletions HANDOFF.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,18 @@ VM contract: `HANDOFF.vm.md`

A stranger clones this repository, runs the commands in README.md, and gets a findings file for `examples/neglected-repo`.

That is `v0.2.0`. Nothing else is the first tag. A VM receipt is not a tag.
That is the `v0.2.0` release gate. A VM receipt is not a tag, and an implementation on `main` is not a published release.

## Current closure

- The clean-checkout gate runs in GitHub CI on Python 3.11 and 3.12.
- `v0.2.0` remains unpublished until the repaired head is merged and the tag is explicitly created.
- Provider base-URL overrides are operator configuration: they may come from the process environment, never from a repository `.env` file.

## Non-goals for this handoff

- Do not port the full skill-lib catalog.
- Do not implement `--fix-one` until inspect works (that is `v0.3.0`).
- Do not add `--fix-one` to v0.2; remote execution and repair require later versioned work.
- Do not host a SaaS.
- Do not rewrite msdmd.
- Do not add Way / UCNS / energy text to README.
Expand Down Expand Up @@ -123,19 +129,20 @@ python -m pubskill_lib.audit PATH --out findings.json

v0.2 inspect only:

- read README / pyproject / package.json / lockfiles / `.github/workflows/*`
- read README, `pyproject.toml`, `package.json`, and `.github/workflows/*`
- record identity if `.git` exists, else `hmmm`
- flag README links to missing local files
- flag workflows that claim tests but only `echo`
- flag missing advertised scripts
- flag README links to missing local files or paths that escape the repository
- flag workflows that claim tests but only `echo`/no-op
- flag Python console scripts whose modules are missing
- flag direct local `package.json` script targets invoked by node/python/bash/sh when the referenced file is missing or escapes the repository
- do not install target deps
- do not run target tests

Exit 0 if the tool ran. Do not exit nonzero just because the target repo is sick. Exit nonzero for tool/schema failures.

## Step D — fixture

`examples/neglected-repo` must contain at least three evidenced defects the CLI will see without `--run`:
`examples/neglected-repo` must contain at least three evidenced defects the CLI will see without execution:

1. README references a file that does not exist
2. CI workflow named like tests that does not invoke a test runner
Expand All @@ -155,7 +162,7 @@ Compare on `id`, `class`, and `surface`.

Optional if time or disk is scarce. Prefer A–D first.

From skill-lib at the SOURCE.md SHA, copy only `msdmd` and `repo-audit-repair` into `.agents/skills/` and write `.agents/skills/README.md` with the SHA. Do not copy the rest of skill-lib.
From skill-lib at the SOURCE.md SHA, copy only `msdmd` and `repo-audit-repair` into `.agents/skills/` and write `.agents/skills/README.md` with the same SHA. Do not copy the rest of skill-lib.

## Step F — tests in this repo

Expand All @@ -165,20 +172,24 @@ python -m unittest discover -s tests
python -m pubskill_lib.audit examples/neglected-repo --out /tmp/out.json
```

A `.github/workflows/ci.yml` may be added. The VM does not push it unless `PUSH=1`.
CI runs this gate on Python 3.11 and 3.12. The VM does not push unless `PUSH=1`.

## Step G — close the public door

Not a VM default. Requires `PUSH=1`.

1. Rewrite README status table: inspect ships.
2. Tag `v0.2.0`.
3. Add this repo to skill-lib consumer list only with `WRITE_CANON=1`.
1. Merge only a head that passes the full gate and required review.
2. Create tag `v0.2.0` explicitly from the accepted release commit.
3. Claim the release as shipped only after the tag exists.
4. Add this repo to skill-lib consumer list only with `WRITE_CANON=1`.

## Done / not done

Done: clean clone → install → unittest → audit fixture → findings.json.
Done at a verified release head: clean clone → install → unittest → audit fixture → findings.json.

Not done: stars, SaaS, full catalog, remote execution/repair, architectural-drift theater, selling VERIFIED on the zip.

Not done: stars, SaaS, full catalog, architectural-drift theater, selling VERIFIED on the zip.
## hmmm

hmmm — if the fixture expected file was authored by hand and never produced by the CLI, the utility is still fake.
- Remote URL inspection, remote commit selection, target execution, and repair semantics remain outside v0.2 until separately specified.
- The fixture is continuously checked against live CLI output on `id`, `class`, and `surface`; provenance of its original byte-for-byte generation is not retained.
96 changes: 61 additions & 35 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,17 @@

Public distribution of [skill-lib](https://github.com/The-Interdependency/skill-lib).

Clone this repo when you want a command that inspects a repository and writes findings. The full catalog, org doctrine, and unfinished skills stay in skill-lib. This repo is the subset a stranger can run.
Clone this repo when you want a command that inspects a local repository and writes findings. The full catalog, org doctrine, and unfinished skills stay in skill-lib. This repo is the subset a stranger can run.

## Status

The inspect CLI ships. Clone, run, get findings.
The inspect CLI implementation passes the repository gate; the `v0.2.0` release tag is not published yet.

| Claim | State |
|---|---|
| Canon | `The-Interdependency/skill-lib` |
| This repo | distribution + public CLI + fixtures |
| Clone / run / findings | **shipped** — `v0.2` inspect; see `HANDOFF.md` |
| Clone / run / findings | **implementation ready** — release pending |
| VM populate | `HANDOFF.vm.md` |
| Source pin | `SOURCE.md` |

Expand All @@ -29,60 +29,86 @@ python -m unittest discover -s tests
python -m pubskill_lib.audit examples/neglected-repo --out /tmp/findings.json
```

Those commands are the definition of done for the first utility tag (`v0.2.0`). They run on a clean clone.
Those commands are the definition of done for the first utility tag (`v0.2.0`). They run in GitHub CI from a clean checkout; publish the tag only after the release gate is explicitly completed.

## What this will do
## Inspect CLI

Inspect one repository path or URL at a named commit and write:
`v0.2` inspects one **local repository path** without executing the target repository:

- identity (remote, commit, dirty state, declared instructions)
- claimed gates vs files that exist
- obvious dependency and docs drift
- findings classified as `defect`, `environment`, `external`, `policy`, or `hmmm`
```bash
python -m pubskill_lib.audit PATH --out findings.json
```

`--run` is opt-in. `verified` is stamped only on a finding whose gate was re-run.
It writes:

## What this will not do
- identity when the target contains `.git` (remote, commit, dirty state)
- README links to missing local files or paths that escape the repository
- obvious test-workflow no-ops
- Python `pyproject.toml` console scripts whose modules are missing
- direct local `package.json` script targets whose referenced files are missing or escape the repository
- findings classified as `defect`, `environment`, `external`, `policy`, or `hmmm`

The inspector does **not** yet clone URLs, select remote commits, execute target tests, or repair the target. Those are later capabilities and must not be inferred from the schema.

- audit the whole internet
- execute private CI secrets by default
- rewrite a repo unless `--fix-one` is explicit and bounded
- carry The Interdependent Way, UCNS, or org liturgy on the first screen
Direct script inspection handles interpreter flags and their arguments, such as
`python -W ignore app.py`, `node --require preload.js app.js`, and
`bash -o errexit build.sh`. Shell expansion and indirect launcher commands remain
outside this static inspection contract.

## Repository examiner (BYOK)

The inspect CLI is the first consumer of a repository evidence engine. A
documentation generator builds on that same evidence substrate:
A separate documentation examiner builds on the repository evidence substrate:

```bash
python -m pubskill_lib.examine --repo /path/to/repo --json # dry run
python -m pubskill_lib.examine --repo /path/to/repo --apply --narrate # write + assemble
python -m pubskill_lib.examine --repo /path/to/repo --json
python -m pubskill_lib.examine --repo /path/to/repo --apply --narrate
```

With `--apply`, the examiner inventories actual code, writes a descriptive
`NARRATIVE` msdmd block into each supported source file (never a `CONTRACT`,
`CHECK`, `CAPABILITY`, or other normative declaration), maintains
shebang-first RATIOS placement, and assembles `docs/examiner/EXAMINER.md`
from the discovered module graph. Narratives are evidence-bound to the source
hash that produced them; changed source without a re-narrate is marked stale.
The tool never leaves the repository boundary it was pointed at.
With `--apply`, the examiner inventories actual code, writes descriptive `NARRATIVE` msdmd blocks into supported source files, maintains source-boundary RATIOS placement, and assembles `docs/examiner/EXAMINER.md`. Narratives are evidence-bound to the source hash that produced them; changed source without a re-narrate is marked stale. The tool never writes outside the repository boundary it was pointed at.

BYOK credentials come from the environment or a `.env` file and are never
printed:
BYOK credentials may come from the process environment or a `.env` file. `.env` files are ignored by this repository. To prevent a target repository from redirecting an operator credential, provider base-URL overrides are accepted only from the process environment, not from `.env`:

```text
OPENAI_API_KEY / OPENAI_BASE_URL / OPENAI_MODEL
ANTHROPIC_API_KEY / ANTHROPIC_BASE_URL / ANTHROPIC_MODEL
OPENAI_API_KEY / OPENAI_MODEL
ANTHROPIC_API_KEY / ANTHROPIC_MODEL
OPENAI_BASE_URL / ANTHROPIC_BASE_URL # process environment only
```

Multiple providers are attempted sequentially (fallback). Languages without
a shipped ratio computer keep `hmmm` values; unsupported languages are
skipped and reported as `hmmm`, never guessed.
Multiple configured providers are attempted sequentially as fallback. Unsupported or not-faithfully-computable metrics remain `hmmm`; they are not guessed.

UTF-8 byte-order marks are preserved during source mutation. Files whose protected
coding cookies conflict with the pinned canonical RATIOS placement are left intact
and reported as `hmmm`; this consumer cannot expand canonical placement rules.
If generated prose cannot be encoded in the source encoding, the file is also
left intact with `hmmm`. Existing narratives remain
available in assembled documentation even when a file has no safe mutation adapter.

## License

MPL-2.0, same as skill-lib. Changes to MPL-covered files must be published.

## Canon

Do not add skills here first. Add them in skill-lib, mark them `runnable`, pin the SHA in `SOURCE.md`, then propagate.
Do not add skills here first. Add them in skill-lib, mark them appropriately, pin the SHA in `SOURCE.md`, then propagate the public slice.

Source updates preserve the original inode in a private `.examiner-originals-*`
directory beside the file, recorded under `preserved_sources` in the apply report.
These recovery directories are excluded from examiner inventory and should not be
committed. The required hard-link operations are probed before source is moved.
Publication briefly withdraws the old name, then creates the updated
name only if it remains absent; it never replaces a competing live file. A
collision or observed write to the retained original records `hmmm`. Already-open
writers can still change the retained original after the operation; stop editors
and generators before applying, then inspect recovery files before removing them.
This protocol preserves bytes; it does not claim a transactional edit shared with
uncooperative writers or uninterrupted availability to concurrent readers.

Source publication currently requires Linux inode metadata support. Ownership,
permission bits, ACL/xattr/security-label bytes are copied and compared before
publication; an unavailable operation leaves the source intact with `hmmm`.
The generated volume uses a new source inventory after application, so preserved
concurrent edits can mark their older narratives stale.
Direct-script audit is intentionally bounded: unsupported commands, malformed
quoting, shell expansions/control syntax, and working-directory transitions remain
visible as `hmmm`. Later commands after an unresolved shell context inherit that
uncertainty; the tool does not guess their working directory or entrypoint.
8 changes: 4 additions & 4 deletions SOURCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ Canon: https://github.com/The-Interdependency/skill-lib

| Field | Value |
|---|---|
| Pinned SHA | `be72da66a112d0632fd25480c1f51b6e69db4976` |
| Pinned date | 2026-09-04 |
| Pin meaning | last observed skill-lib `main` when pubskill-lib was created |
| Runnable subset | `msdmd` (runnable), `repo-audit-repair` (contract) — set in skill-lib `skills.json` after the pin |
| Pinned SHA | `8de4f12d0f31ff94f41e4a0196c447c0cbe20faf` |
| Pinned date | 2026-09-11 |
| Pin meaning | exact canonical source used for the vendored public skill slice |
| Runnable subset | `msdmd` (runnable), `repo-audit-repair` (contract) |

Update this file in the same commit that propagates vendored skills.

Expand Down
13 changes: 3 additions & 10 deletions examples/neglected-repo/expected-findings.json
Original file line number Diff line number Diff line change
@@ -1,19 +1,14 @@
{
"schema_version": 1,
"tool": "pubskill-lib",
"source_pin": "be72da66a112d0632fd25480c1f51b6e69db4976",
"source_pin": "8de4f12d0f31ff94f41e4a0196c447c0cbe20faf",
"target": {
"path": "examples/neglected-repo",
"commit": "hmmm",
"remote": "hmmm",
"dirty": false
},
"surfaces": [
"identity",
"docs",
"ci",
"deps"
],
"surfaces": ["identity", "docs", "ci", "deps"],
"findings": [
{
"id": "F001",
Expand Down Expand Up @@ -43,7 +38,5 @@
"verified": false
}
],
"hmmm": [
"target has no .git directory; identity unresolved"
]
"hmmm": ["target has no .git directory; identity unresolved"]
}
Loading