hall-of-helix/scripts/export-pqrst.py
tegwick 7d70cd3ad4 Add read-only PQRST evidence export from pinned entries
Assistant: codex
Assistant-Model: gpt-6-astra
Assistant-Session: 01a0e759-301a-78b1-bbc1-040ef094b12d
2026-09-28 11:54:26 +02:00

55 lines
2.2 KiB
Python

#!/usr/bin/env python3
"""Export hall entry evidence as JSONL, without changing or grading seats.
Usage: python3 export-pqrst.py /path/to/hall-of-helix [--revision HEAD]
Only committed entries at the resolved revision are read. Every entry is emitted,
including missing/malformed PQRST sections. Raw text is retained for review.
"""
import argparse
import hashlib
import json
import re
import subprocess
from pathlib import Path
def git(repo, *args):
return subprocess.check_output(['git', '-C', str(repo), *args])
def export(repo, revision):
commit = git(repo, 'rev-parse', '--verify', revision + '^{commit}').decode().strip()
paths = git(repo, 'ls-tree', '-r', '--name-only', '-z', commit, '--', 'entries/')
for name in sorted(p.decode() for p in paths.split(b'\0') if p.endswith(b'.md')):
raw = git(repo, 'show', f'{commit}:{name}')
text = raw.decode('utf-8')
fm = re.match(r'\A---\n(.*?)\n---(?:\n|$)', text, re.S)
body = text[fm.end():] if fm else text
sections = re.findall(r'^## PQRST estimate\s*\n(.*?)(?=^## |\Z)', body, re.M | re.S | re.I)
blocks = []
for section in sections:
for match in re.finditer(r'^```[^\n]*\n(PQRST-Estimate\n.*?)^```[ \t]*$', section, re.M | re.S):
record = match.group(1)
fields = {}
for field in re.finditer(r'^([A-Za-z][A-Za-z ]*):[ \t]*(.*?)(?=^[A-Za-z][A-Za-z ]*:|\Z)', record, re.M | re.S):
fields.setdefault(field.group(1), []).append(field.group(2).strip())
blocks.append({'raw': record, 'fields': fields})
yield {
'source_commit': commit, 'path': name,
'sha256': hashlib.sha256(raw).hexdigest(),
'frontmatter_raw': fm.group(1) if fm else None,
'pqrst_sections': sections, 'blocks': blocks,
}
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('repo', type=Path)
parser.add_argument('--revision', default='HEAD')
args = parser.parse_args()
for record in export(args.repo, args.revision):
print(json.dumps(record, ensure_ascii=False))
if __name__ == '__main__':
main()