#!/usr/bin/env python3 """Merge peergos-for-compliance subjects.json into catalog/pfc-derived.json. Each row has from/to/in/out/encryption/reject/dead/timeout/filter. """ from __future__ import annotations import json from pathlib import Path ROOT = Path(__file__).resolve().parents[1] PFC = Path("/Users/marchon/research/peergos-for-compliance/schemas/subjects.json") OUT = ROOT / "catalog" / "pfc-derived.json" TIMEOUT = { "request-reply": 5.0, "queue": 4.0, "pub": 0.0, "core": 5.0, } FOR = { "verae.sm.send": "Deliver a passthrough secure message (dest in the clear, body ciphertext)", "verae.sm.dead": "Dead-letter failed service requests", "verae.sm.error": "Emit a Network Error Bundle (ct_sender + ct_system)", "verae.sm.log.summary": "Central log summaries (codes only, never ciphertext)", "verae.admin.config.sign": "Sign a configuration payload (Ed25519 wrapper)", "verae.admin.history.append": "Append prev + new + unified diff to admin-history cube", "verae.storage.pin": "Pin object bytes via IPFS pin API / Kubo localhost", "verae.storage.replicate": "Replicate bytes to min_ok replica ingest subjects", "verae.pfc.health": "Loopback health for PFC services", "verae.inspect.open": "Start k-of-n inspect; log-before-reveal", } def timeout_for(pattern: str, name: str) -> float: if name.startswith("verae.storage.pin"): return 30.0 return TIMEOUT.get(pattern or "request-reply", 5.0) def filter_for(name: str) -> str: if name.startswith("verae.sm."): return "passthrough dest/subject clear; reject missing to, empty ct, plaintext body, body-like log fields" if name.startswith("verae.inspect."): return "k-of-n officers; author cannot be officer; TOTP session; log-before-reveal" if name.startswith("verae.admin."): return "unsigned wrappers rejected; empty actor rejected" if name.startswith("verae.storage."): return "Kubo localhost only; no WAN 5001; hash must match bytes" return "unknown subject rejected; required payload fields; no verae.llm.turn.>; no plaintext PHI" def main() -> None: src = json.loads(PFC.read_text()) rows = [] for s in src.get("subjects") or []: name = s["name"] pattern = s.get("pattern") or "request-reply" owner = s.get("owner") or "unknown" rows.append( { "name": name, "pattern": pattern, "for": FOR.get(name, "PFC/Verae subject — see peergos-for-compliance/docs/nats-addresses.md"), "from": ["pfc-py-admin", "sm-leaf", "connectors", "pfc-repl", "pfc-ipfs"], "to": [owner], "in": {"fields": s.get("payload") or []}, "out": "ack or service JSON (never recipient mail plaintext on error subjects)", "encryption": "passthrough dest-in-clear; body pfc-lab-xor or NPE; Pattern A apps never publish", "reject": ["unknown subject", "missing required fields", "plaintext PHI", "verae.llm.turn.>"], "dead": "verae.sm.dead" if name.startswith("verae.sm.") else "none", "timeout_sec": timeout_for(pattern, name), "filter": filter_for(name), "git": "https://git.georgelambert.org/marchon/peergos-for-compliance", } ) OUT.write_text(json.dumps({"version": src.get("version"), "endpoints": rows}, indent=2) + "\n") print("wrote", OUT, "n=", len(rows)) if __name__ == "__main__": main()