net-kingdom/tools/contract-tests/excerpt.py
tegwick c63aa398d6 NK-WP-0058-T08 worker protocol and excerpt tool; T06 window watch (row O5), first use of the protocol
T08: .claude/rules/worker-protocol.md (imported by CLAUDE.md, pointed to from AGENTS.md) and
tools/contract-tests/excerpt.py: name the rows, hand every worker one excerpt, one owner per step, check
with the excerpt's tests. A test requires every table row to have details and a contract test (found O4).
T06: bounded-executor/window_watch.py flags or closes the write role when no run Job is active or recent;
stub tests; in the image. Built from the excerpt for O5, E1, C1, E8, E9, R2.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 943911@bnt-lap001
Assistant-Session: fc322940-1c8e-4bed-ab39-86cec99f23a0
2026-11-06 01:36:09 +01:00

62 lines
2.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
"""Contract excerpt for a worker on a cross-repo change (NK-WP-0058-T08). Read-only.
python3 tools/contract-tests/excerpt.py E1 C5 O1 # rows of docs/bounded-execution-contract-table.md
Prints, for each row: its line in the table (owner and source of truth, consumer, mark), its detail sections (names,
paths, roles, payloads, exit codes, and the one owning script or file per step), and the contract tests that cover
it. A worker gets this excerpt before starting and checks its result with those tests and `make contract-test`.
An unknown row fails: a new interface gets its row in the table first.
"""
import re
import sys
from pathlib import Path
TABLE = Path(__file__).resolve().parents[2] / 'docs/bounded-execution-contract-table.md'
ROW = re.compile(r'^[EROCF]\d+$')
def ids_in(text):
"""Row ids named in a cell or heading, with ranges like O2–O4 expanded."""
found = set()
for first, last in re.findall(r'\b([EROCF]\d+)\s*[–-]\s*([EROCF]\d+)\b', text):
if first[0] == last[0]:
found |= {f'{first[0]}{n}' for n in range(int(first[1:]), int(last[1:]) + 1)}
return found | set(re.findall(r'\b[EROCF]\d+\b', text))
def sections(text):
"""(heading, body) for each ### section."""
parts = re.split(r'^(### .+)$', text, flags=re.M)
return [(parts[i], parts[i + 1].split('\n## ')[0]) for i in range(1, len(parts) - 1, 2)]
def excerpt(row_ids, text=None):
text = text if text is not None else TABLE.read_text()
out = []
for row in row_ids:
if not ROW.match(row):
raise SystemExit(f'not a row id: {row}')
line = next((l for l in text.splitlines() if l.startswith(f'| {row} |')), None)
if line is None:
raise SystemExit(f'{row}: no such row; add the interface to the table first')
out += [f'## {row}', '', line, '']
for heading, body in sections(text):
if row in ids_in(heading.split(':')[0]):
out += [heading, body.strip(), '']
coverage = [l for l in text[text.index('### Coverage by row'):].splitlines()
if l.startswith('| ') and not l.startswith('| Row') and row in ids_in(l.split('|')[1])]
out += ['**Contract tests:**', *(coverage or ['none recorded: add one with the change']), '']
return '\n'.join(out)
def main(argv=None):
rows = argv if argv is not None else sys.argv[1:]
if not rows:
raise SystemExit(__doc__)
print(excerpt(rows))
return 0
if __name__ == '__main__':
sys.exit(main())