Capture current source, content data, tests, asset licenses, and original-specification traceability. Original implementation remains incomplete. The accepted matching UI generation passed 154 suites and 12,253 checks, with eight rendered staff-contract screens reviewed. Latest native Windows and full-original acceptance remain outstanding.
86 lines
6.0 KiB
Python
86 lines
6.0 KiB
Python
#!/usr/bin/env python3
|
||
"""Capture current registration evidence; successful export is not acceptance."""
|
||
import argparse
|
||
from collections import Counter
|
||
import hashlib
|
||
import json
|
||
import os
|
||
from pathlib import Path
|
||
import re
|
||
import subprocess
|
||
|
||
ROOT = Path(__file__).resolve().parents[1]
|
||
MAPPING = 'docs/plans/original-completion-2026-09-29/execution/original_facility_mapping.json'
|
||
BASELINE = 'docs/plans/original-completion-2026-09-29/execution/baseline-fetched-2026-09-29.txt'
|
||
|
||
def manifest():
|
||
paths = [ROOT / MAPPING, ROOT / BASELINE, ROOT / 'tools/capture_facility_audit.gd', Path(__file__)]
|
||
for directory in ('autoload', 'scripts', 'scenes', 'data'):
|
||
paths.extend(p for p in (ROOT / directory).rglob('*') if p.suffix in ('.gd', '.tres', '.tscn', '.json'))
|
||
return {str(p.relative_to(ROOT)): hashlib.sha256(p.read_bytes()).hexdigest() for p in sorted(set(paths))}
|
||
|
||
def main():
|
||
parser = argparse.ArgumentParser(description=__doc__)
|
||
parser.add_argument('--godot', default='godot')
|
||
parser.add_argument('--output', required=True)
|
||
args = parser.parse_args()
|
||
out = Path(args.output).resolve()
|
||
out.mkdir(parents=True, exist_ok=True)
|
||
def save(name, value):
|
||
(out / name).write_text(json.dumps(value, ensure_ascii=False, indent=2) + '\n')
|
||
before = manifest()
|
||
save('source-start.json', before)
|
||
env = dict(os.environ, THE_TREE_FACILITY_AUDIT_PATH=str(out / 'runtime-facilities.json'))
|
||
with (out / 'export.log').open('w') as log:
|
||
result = subprocess.run([args.godot, '--headless', '--path', str(ROOT), '--script', 'res://tools/capture_facility_audit.gd'], env=env, stdout=log, stderr=subprocess.STDOUT, timeout=120)
|
||
after = manifest()
|
||
changes = [p for p in sorted(before.keys() | after.keys()) if before.get(p) != after.get(p)]
|
||
save('source-end.json', after)
|
||
save('source-change.json', changes)
|
||
if result.returncode or changes:
|
||
raise SystemExit('Audit capture failed or source changed; inspect logs.')
|
||
data = json.loads((out / 'runtime-facilities.json').read_text())
|
||
mapping = json.loads((ROOT / MAPPING).read_text())
|
||
rows = data['original_facilities']
|
||
if len(rows) != 30 or len({r['name'] for r in rows}) != 30 or [r['name'] for r in rows] != [r['name'] for r in mapping]:
|
||
raise SystemExit('Original mapping coverage is invalid.')
|
||
counts = Counter()
|
||
mismatches = []
|
||
for row in rows:
|
||
definition = row['definition']
|
||
row['registration_status'] = ('normal' if row['runtime_registered'] and row['palette_listed'] else 'definition_only' if definition else 'missing')
|
||
counts[row['registration_status']] += 1
|
||
row['full_acceptance'] = 'unproven'
|
||
if definition:
|
||
expected = [int(x) for x in row['original_size'].split('x')]
|
||
layer = re.match(r'FRONT|BACK', row['original_layer_zone']).group()
|
||
if definition['footprint'] != expected or definition['layer'] != layer:
|
||
mismatches.append(row['name'])
|
||
extra = sorted(set(data['normal_registry_ids']) - {r['definition_id'] for r in rows})
|
||
unspecified = [r['name'] for r in rows if r['definition'] and r['definition']['customer_capacity'] < 0]
|
||
summary = dict(original_count=30, registration_counts=dict(counts), normal_catalog_count=len(data['normal_registry_ids']), non_original_registry_ids=extra,
|
||
dimension_or_layer_mismatches=mismatches, customer_limit_unset=unspecified,
|
||
all_original_acceptance=False, scope='Registration and loaded definition values only. Not operation, save migration, assets, Windows or whole-spec acceptance.')
|
||
save('summary.json', summary)
|
||
save('classified-facilities.json', rows)
|
||
labels = {'normal': '通常登録・パレット掲載', 'definition_only': '定義のみ', 'missing': '対応定義なし'}
|
||
lines = ['# 原本30施設・現行登録監査', '',
|
||
f"通常登録 {counts['normal']}、定義のみ {counts['definition_only']}、対応定義なし {counts['missing']}。通常登録全{len(data['normal_registry_ids'])}件のうち原本30施設以外は{len(extra)}件。",
|
||
'', '登録状態と読込済み定義の監査。実営業・保存移行・完成資産・Windows・全要件の受入完了は証明しない。', '',
|
||
f'対応定義の寸法・層の不一致: {len(mismatches)}件。人数専用上限が未設定: {len(unspecified)}件。capacityから人数値を転記していない。高層・背面・騒音・サービス条件は別途受入が必要。', '',
|
||
'| 原本 | 施設 | ID | 登録 | 寸法 / 層 / ゾーン | 顧客人数上限 |', '|---|---|---|---|---|---|']
|
||
for r in rows:
|
||
d = r['definition']
|
||
geometry = f"{d['footprint'][0]}×{d['footprint'][1]} / {d['layer']} / {d['zone']}" if d else '未定義'
|
||
limit = str(d['customer_capacity']) if d and d['customer_capacity'] >= 0 else '未設定'
|
||
lines.append(f"| {r['section']} | {r['name']} | {r['definition_id'] or '—'} | {labels[r['registration_status']]} | {geometry} | {limit} |")
|
||
lines += ['', '## 未接続施設', '', '対応定義なし: ' + '、'.join(r['name'] for r in rows if r['registration_status']=='missing') + '。', '',
|
||
'定義のみ: ' + '、'.join(r['name'] for r in rows if r['registration_status']=='definition_only') + '。', '',
|
||
'## 次の受入', '', '未定義施設は寸法・層だけでなく経済値、人数、業務、通常操作、保存を接続する。登録済み施設は未設定人数とサービス属性、営業時間・停止・経路・客/職員行動を個別検証する。施設追加のたびにこの監査を再実行する。', '',
|
||
'再現: `python3 tools/run_facility_audit.py --godot /opt/homebrew/bin/godot --output artifacts/facility-audit-current-2026-09-29`。原本SHA・入力ソースSHA・取得中の変更なしは同ディレクトリのsource-start/end/change.jsonを参照。', '']
|
||
(out / 'REPORT.md').write_text('\n'.join(lines))
|
||
print(json.dumps(summary, ensure_ascii=False))
|
||
|
||
if __name__ == '__main__':
|
||
main()
|