Files
troupe-standup/wizard-work/quill/draft_compliance_report.py
volt 54451e4f6d volt: quill draft-compliance artifact grades its own tree (Q142)
The 2026-10-31 artifact hardcoded an absolute home path in both the scanner
and the 'independent verifier', so a clone's CHECK graded the host tree (a
clone whose committed TSV held one garbage line still reported on the host's
79-row TSV). The two copies also carried different rule lists -- the generator
rejected true/false, the verifier did not -- and the TSV's comment line was
emitted by neither script's stdout.

- draft_compliance_rule.py: the bare-command rule, stated once, 11 cases
- generator: paths from __file__, artifact excluded from its own population,
  deterministic output (comment + header + rows)
- verifier: own re-derivation, both directions, grades the report's six counts,
  rc 0/1/2, --selftest one control + eight mutants + rule-agreement + no-host-path
- CHECK: four legs (selftest, rederive, byte-identical regeneration, copy-parity)
- report: measured numbers (79 drafts, 14/14/11, 68 failing, 3 non-bare)
2026-10-31 23:58:23 +00:00

71 lines
2.4 KiB
Python

#!/usr/bin/env python3
"""Generate the draft-compliance TSV for the .md drafts in this directory.
The lane directory is derived from THIS FILE's location, never from a host path,
so a clone grades its own tree. `--lane` exists for a fixture tree; `--out`
writes the TSV instead of stdout, and the output is deterministic: the same tree
produces the same bytes, comment line and header included.
The artifact itself (`draft-compliance-report-2026-10-31.md`) is NOT a row: the
report publishes the table, it is not a draft in it. That exclusion is what makes
the population 79 rather than 80 -- the 2026-10-31 report's prose said 79 while
its TSV carried 80 rows, and the missing row was the report counting itself.
Rule, columns and the artifact name live in `draft_compliance_rule.py`; the
verifier re-derives this table from the files with its own code.
"""
import argparse
import os
import sys
HERE = os.path.dirname(os.path.abspath(__file__))
sys.path.insert(0, HERE)
import draft_compliance_rule as rule # noqa: E402
def scan(lane):
rows = []
for name in sorted(os.listdir(lane)):
if not name.endswith(".md") or name == rule.ARTIFACT_MD:
continue
path = os.path.join(lane, name)
if not os.path.isfile(path):
continue
with open(path, "r", encoding="utf-8", errors="replace") as f:
text = f.read()
rows.append(rule.row_for(name, text))
return rows
def main(argv=None):
ap = argparse.ArgumentParser(
description="Generate the draft-compliance TSV for this lane's .md drafts.")
ap.add_argument("--lane", default=HERE,
help="directory of .md drafts (default: this file's dir)")
ap.add_argument("--out", default=None,
help="write the TSV here instead of stdout")
a = ap.parse_args(argv)
if not os.path.isdir(a.lane):
print("cannot read lane directory: %s" % a.lane, file=sys.stderr)
return 2
rows = scan(a.lane)
lines = ["# measured %d markdown files" % len(rows),
"\t".join(rule.COLUMNS)]
lines.extend("\t".join(r) for r in rows)
body = "\n".join(lines) + "\n"
if a.out:
with open(a.out, "w", encoding="utf-8", newline="\n") as f:
f.write(body)
print("wrote %s (%d rows)" % (a.out, len(rows)), file=sys.stderr)
else:
sys.stdout.write(body)
return 0
if __name__ == "__main__":
raise SystemExit(main())