Establish InterfaceCanon with Statehub integration and FIAM-derived model

Assistant: codex
Assistant-Model: gpt-6-astra
Assistant-Session: 01a087be-d842-7252-81be-2105c4279c87
This commit is contained in:
tegwick 2026-09-09 22:05:18 +02:00
parent af74f742de
commit ee0df5c931
21 changed files with 937 additions and 2 deletions

60
tools/check.py Normal file
View file

@ -0,0 +1,60 @@
"""Check document references, work-record identity, and immutable source provenance."""
import argparse
import hashlib
import json
from pathlib import Path
import re
import subprocess
ROOT = Path(__file__).resolve().parents[1]
parser = argparse.ArgumentParser()
parser.add_argument('--require-sources', action='store_true')
args = parser.parse_args()
errors = []
for path in ROOT.rglob('*.md'):
if '.git' in path.parts:
continue
for link in re.findall(r'\[[^\]]*\]\(([^)]+)\)', path.read_text()):
if '://' in link or link.startswith('#'):
continue
target = link.split('#')[0]
if target and not (path.parent / target).exists():
errors.append(f'{path.relative_to(ROOT)}: missing link {target}')
ids = set()
for path in sorted((ROOT / 'workplans').glob('*.md')):
text = path.read_text()
for identifier in re.findall(r'^id: (INTERFACE-WP-[^\s]+)$', text, re.M):
if identifier in ids:
errors.append(f'duplicate work-record id: {identifier}')
ids.add(identifier)
for status in re.findall(r'^status: (\S+)$', text, re.M):
if status not in {'proposed', 'ready', 'active', 'blocked', 'backlog', 'finished', 'archived', 'wait', 'todo', 'progress', 'done', 'cancel'}:
errors.append(f'{path.name}: invalid status {status}')
for path in [ROOT / 'canon.yaml', ROOT / 'infospace/interfaces/federation.yaml']:
for target in re.findall(r'^\s*(?:path|manifest): (\S+)$', path.read_text(), re.M):
if target == 'infospace/schemas/interface-card.schema.yaml':
continue # Explicitly owned upstream.
if not (ROOT / target).is_file():
errors.append(f'{path.name}: missing artifact {target}')
for path in sorted((ROOT / 'infospace').rglob('*.json')):
manifest = json.loads(path.read_text())
revision = manifest['source_commit']
if not re.fullmatch('[0-9a-f]{40}', revision):
errors.append(f'{path}: invalid source commit')
source = ROOT.parent / manifest['source_repository']
records = manifest.get('sources', manifest.get('imports', []))
if not records:
errors.append(f'{path}: empty source manifest')
for record in records:
if not re.fullmatch('[0-9a-f]{64}', record['sha256']):
errors.append(f'{path}: invalid SHA-256')
if not (source / '.git').exists():
if args.require_sources:
errors.append(f'missing source checkout: {source}')
continue
result = subprocess.run(['git', '-C', str(source), 'show', f'{revision}:{record["path"]}'], capture_output=True)
if result.returncode or hashlib.sha256(result.stdout).hexdigest() != record['sha256']:
errors.append(f'{path.name}: source integrity failure for {record["path"]}')
if errors:
raise SystemExit('\n'.join(errors))
print(f'PASS: document links, artifact paths, {len(ids)} work-record IDs, and available pinned Git sources')