← Files APODICTIC Development EditorARCHIVED FILE
scripts/promise_contract.py
33.4 KB · Nov 9, 2026 · 00:53 UTC
#!/usr/bin/env python3
"""promise-contract — Promise-Contract Fidelity: does the pitch keep the promise the book makes?
`validate.sh promise-contract <run_folder|files>` shells out here. APODICTIC's foundational move is
contract inference; this module points it at the author's own marketing COPY. It diagnoses the gap
between the persisted pitch (query / synopsis / blurb / logline) and the inferred Contract — emphasis
distortion, reveal leak, over/under-promise, cross-document inconsistency — and never drafts the
replacement copy (the Firewall: diagnose the copy, never write it). It CONSUMES Shelf & Positioning
(genre / comp / tone) rather than re-deriving it; this module owns only the document-fidelity layer.
Findings are apodictic.finding.v1 blocks with origin PCF (id F-PCF-NN). Each PCF flag is a two-sided
GAP, so it must cite both sides via a namespaced evidence-ref convention scoped to PCF findings:
copy:<copy_type>¶<n> a span in the persisted pitch copy (e.g. copy:query¶2)
contract:<FIELD> a Contract field (e.g. contract:CONTROLLING IDEA, contract:READER PROMISE)
ms:<locus> a manuscript locus (e.g. ms:Ch 9)
The persisted pitch copy is apodictic.pitch_copy.v1 (a first-class durable input, NOT a runtime
paste); persisting it is what makes the firewall guard (W1) a substring check and the form gate (P3)
mechanical.
P1 two-sided gap every F-PCF-NN finding carries >=1 copy: ref AND >=1 contract:/ms: ref. A
one-sided "gap" is an unsupported assertion — the signature integrity check.
P2 copy persisted an apodictic.pitch_copy.v1 input exists and every document declares a valid
& typed copy_type. Flags are form-calibrated; an undeclared/absent copy makes
PCF2/PCF5 ungovernable.
P3 reveal-leak a PCF2 finding's copy: ref must NOT point at a synopsis. A synopsis discloses
form gate by design, so a PCF2 raised against one is a calibration error and fails.
W1 drafted-copy a multi-sentence quoted block in the report that is NOT a verbatim substring
leak (firewall) of the persisted pitch copy => authored replacement copy (the Firewall
leak). Concrete substring check, not a vibe heuristic. Advisory; ERROR --strict.
Override (per id): <!-- override: drafted-copy PCF-NN — <rationale> -->.
W2 market-prediction a PCF finding matching the prohibited sales-prediction phrase set ("won't
drift (#14) sell", "agents will pass", "no market for", "unmarketable", "won't find
an audience"). Keeps the module on the fidelity side of the §Not Planned line.
Advisory; ERROR --strict. Override: <!-- override: market-prediction PCF-NN — … -->.
severity is the editorial Must/Should/Could scale, where severity = fidelity risk (how badly promise
and book diverge), never market outcome. Reuses apodictic_artifacts (block grammar + schema engine).
Each artifact is optional; an empty/absent one is a no-op. See docs/promise-contract-audit.md.
promise_contract.py promise-contract <run_folder|files...> [--strict]
promise_contract.py --self-test
Exit: 0 clean / WARN-only, 1 ERROR (or WARN under --strict), 2 usage.
"""
import glob
import os
import re
import sys
from override_marker import override_targets, override_payloads # SSoT: code-span-stripped override scan
try:
import apodictic_artifacts as art
except ImportError:
art = None
def _has_block(text, btype):
"""True if `text` carries a real apodictic:<btype> block (a parsed carrier, not a prose mention).
Classifying on parsed blocks — not a raw substring — keeps a file that merely *names* the marker
in prose from being misrouted/skipped (the 2026-06-20 resolver-hardening sweep). Gated by
validate.sh validator-conventions (M2)."""
if art is None:
return ("apodictic:%s" % btype) in (text or "")
return any(bt == btype for bt, _o, _e in art.parse_blocks(text or ""))
_PITCH_SCHEMA_ID = "apodictic.pitch_copy.v1"
_FINDING_SCHEMA_ID = "apodictic.finding.v1"
_PITCH_GLOB = "*_Pitch_Copy_*.md"
_ORIGIN = "PCF"
# A well-formed PCF finding id: F-PCF-NN. The short form used in override markers is PCF-NN.
_PCF_ID_RE = re.compile(r"^F-PCF-[0-9]{2,}$")
# PCF-ORIGIN attribution (looser than the well-formed id): any F-PCF-* claims this module, so a
# malformed digit count (F-PCF-1) is still attributed to PCF and caught by the schema pattern (P1),
# rather than silently dropped by the origin filter.
_PCF_ORIGIN_RE = re.compile(r"^F-PCF-", re.IGNORECASE)
# Map an F-PCF-NN finding id to its short PCF-NN override token.
_SHORT_RE = re.compile(r"^F-(PCF-[0-9]+)$")
# Namespaced evidence-ref convention (PCF-scoped). A ref is prefix-typed; optional whitespace after
# the colon is tolerated (the ref is also .strip()ed in _ref_kind) so a stray space can't drop a real
# two-sided ref into the unknown bucket and falsely fail P1.
# copy:<copy_type>¶<n> — the FULL grammar: a copy_type AND a non-empty paragraph locus (¶<n>, range
# ok). A locus-less `copy:query`, a malformed `copy:query-does-not-exist` (no ¶), or a bare `copy:`
# names no span and must NOT satisfy P1's copy side; the captured copy_type is then checked for
# membership in the PERSISTED copy in check() (a `copy:<absent-type>¶n` is dangling). (Codex P1.)
_COPY_REF_RE = re.compile(r"^copy:\s*([A-Za-z]+)\s*¶\s*[0-9]+(?:\s*-\s*[0-9]+)?\s*$", re.IGNORECASE)
# contract:/ms: must carry a NON-EMPTY target (a field name / a locus). A bare `contract:` or `ms:`
# (or whitespace-only) names no side and must NOT satisfy the two-sided P1 check (Codex P1, 2026-06-19).
_CONTRACT_REF_RE = re.compile(r"^contract:\s*\S", re.IGNORECASE)
_MS_REF_RE = re.compile(r"^ms:\s*\S", re.IGNORECASE)
# Override markers naming a finding's short id ("<!-- override: market-prediction PCF-01 — ... -->")
# route through the shared override_marker SSoT — code spans stripped, slug boundary-matched.
# W1's drafted-copy override is SNIPPET-keyed, not id-keyed: a report's leaked quote isn't
# attributable to one finding id, so the override quotes a snippet of the leaked text and silences
# ONLY a leak that snippet matches — "<!-- override: drafted-copy <snippet> — <rationale> -->".
# This stops one override from blanket-silencing the firewall and stops an override for absent text
# from silencing a real leak.
# The drafted-copy snippet is the free-text PAYLOAD of a `drafted-copy` marker; it is read via the
# shared override_marker SSoT (override_payloads) so a backtick'd example is not honored.
# HTML comments (incl. the apodictic:* blocks and the override markers) are stripped before the W1
# prose scan, so the persisted-copy blocks and impl notes are not themselves mistaken for report prose.
_HTML_COMMENT_RE = re.compile(r"<!--.*?-->", re.DOTALL)
# W2 — the prohibited sales-prediction phrase set (the #14 boundary guard). Concrete, not a vibe set.
_MARKET_RE = re.compile(
r"won'?t\s+sell"
r"|agents?\s+will\s+pass"
r"|no\s+market\s+for"
r"|unmarketable"
r"|won'?t\s+find\s+an\s+audience",
re.IGNORECASE)
def _read(path):
try:
with open(path, encoding="utf-8") as fh:
return fh.read()
except (OSError, UnicodeDecodeError):
return None
def _overrides(text, slug):
"""The set of PCF-NN ids overridden for `slug` — via the shared SSoT, so a marker quoted inside a
code span is not honored as a live directive."""
return {t[0] for t in override_targets(text, slug, r"(PCF-[0-9]+)")}
def _drafted_override_snippets(text):
"""Snippets from `<!-- override: drafted-copy <snippet> — <rationale> -->` markers (W1). The
captured group is split on the em-/en-/hyphen rationale separator and de-quoted; a leak is
silenced only when one of these snippets is a substring of (or contains) the leaked block."""
out = []
for payload in override_payloads(text or "", "drafted-copy"):
snip = re.split(r"\s+[—–-]\s+", payload, 1)[0].strip().strip('"“”')
if snip:
out.append(snip)
return out
def _short(fid):
m = _SHORT_RE.match(fid or "")
return m.group(1) if m else (fid or "")
def parse_pitch(text):
"""[(obj_or_None, schema_errs, index), ...] for each apodictic:pitch_copy block."""
items = []
if not text or art is None:
return items
schema = art.load_schema(_PITCH_SCHEMA_ID)
idx = 0
for btype, obj, jerr in art.parse_blocks(text):
if btype != "pitch_copy":
continue
idx += 1
where = "pitch_copy #%d" % idx
if jerr:
items.append((None, ["%s: invalid JSON — %s" % (where, jerr)], idx))
continue
items.append((obj, art.validate_obj(obj, schema, where), idx))
return items
def parse_findings(text):
"""[(obj_or_None, schema_errs, index), ...] for each apodictic:finding block with origin PCF."""
items = []
if not text or art is None:
return items
schema = art.load_schema(_FINDING_SCHEMA_ID)
idx = 0
for btype, obj, jerr in art.parse_blocks(text):
if btype != "finding":
continue
# PCF owns only PCF-origin findings; another origin's finding in the same corpus is ignored.
# Attribution is by the F-PCF- prefix (loose), so a malformed PCF id is still validated (P1).
if isinstance(obj, dict) and not _PCF_ORIGIN_RE.match(str(obj.get("id") or "")):
continue # non-PCF-origin finding ignored; a non-dict payload falls through to validate_obj (P1)
if jerr:
# A malformed finding JSON can't be attributed to an origin; skip rather than mis-claim it.
continue
idx += 1
where = "finding %s" % (obj.get("id") if isinstance(obj, dict) else "#%d" % idx)
items.append((obj, art.validate_obj(obj, schema, where), idx))
return items
def _ref_kind(ref):
"""Classify a namespaced evidence-ref. Returns ('copy', copy_type) | ('contract', None) |
('ms', None) | (None, None)."""
s = str(ref or "").strip()
m = _COPY_REF_RE.match(s)
if m:
return "copy", m.group(1).lower()
if _CONTRACT_REF_RE.match(s):
return "contract", None
if _MS_REF_RE.match(s):
return "ms", None
return None, None
def _is_pcf2(obj):
"""A PCF2 (reveal leak) finding — identified by the flag DECLARED at the head of its mechanism
(the "PCFn <name>: …" convention), not a mere mention of PCF2 elsewhere in the prose. A PCF1/PCF4
finding may contrast itself against PCF2 ("…distinct from PCF2 reveal leak…") while legitimately
citing a synopsis ref; anchoring to the leading flag stops that from tripping the P3 form gate."""
return bool(re.match(r"\s*PCF2\b", obj.get("mechanism") or ""))
# Multi-sentence quoted-block detection for W1. A "quoted block" is a run inside straight or curly
# double quotes whose content holds >=2 sentence terminators — i.e. authored multi-sentence prose, the
# shape a drafted replacement query/blurb takes. A single quoted phrase (a label, a cited span) is not.
_QUOTED_BLOCK_RE = re.compile(r"[\"“]([^\"“”]{2,}?)[\"”]", re.DOTALL)
_SENT_TERM_RE = re.compile(r"[.!?](?:\s|$)")
def _multi_sentence_quotes(report_text):
"""Multi-sentence quoted blocks in report prose (HTML comments/blocks stripped first)."""
visible = _HTML_COMMENT_RE.sub("", report_text or "")
out = []
for m in _QUOTED_BLOCK_RE.finditer(visible):
body = m.group(1).strip()
if len(_SENT_TERM_RE.findall(body)) >= 2:
out.append(body)
return out
def check(pitch_text, report_text, strict=False):
"""Run the Promise-Contract Fidelity checks. Returns (code, lines).
pitch_text — the persisted pitch-copy corpus (apodictic.pitch_copy.v1 blocks).
report_text — the findings / report corpus (apodictic.finding.v1 F-PCF blocks + report prose).
(For a single combined file the two are the same text; resolution passes them in.)
"""
lines, errs, warns = [], [], []
pitch_items = parse_pitch(pitch_text)
findings = parse_findings(report_text)
if not pitch_items and not findings:
return 0, ["promise-contract: no pitch_copy blocks or F-PCF findings found — nothing to check"]
# ---- pitch copy validity (feeds P2) ----
for _obj, schema_errs, _idx in pitch_items:
for e in schema_errs:
errs.append("P2 invalid pitch copy: %s" % e)
valid_pitch = [obj for obj, schema_errs, _idx in pitch_items
if obj is not None and not schema_errs]
copy_types = {obj.get("copy_type") for obj in valid_pitch}
# The verbatim corpus W1 checks the report's quoted blocks against.
persisted_text = "\n".join(obj.get("text") or "" for obj in valid_pitch)
# ---- finding validity (feeds P1/P3) ----
for _obj, schema_errs, _idx in findings:
for e in schema_errs:
errs.append("P1 invalid finding: %s" % e)
valid_findings = [obj for obj, schema_errs, _idx in findings
if obj is not None and not schema_errs]
# ---- P2 — an apodictic.pitch_copy.v1 input exists and every doc declares a valid copy_type ----
# (Schema validity already covers copy_type membership; P2 also requires the input to EXIST when
# there are PCF findings to govern — a finding with no persisted copy is ungovernable.)
if valid_findings and not valid_pitch:
errs.append("P2 pitch copy not persisted: F-PCF findings exist but no valid "
"apodictic.pitch_copy.v1 input was found — PCF2/PCF5 are ungovernable without it")
# ---- P1 — two-sided gap: each F-PCF finding cites >=1 copy: ref AND >=1 contract:/ms: ref ----
for obj in valid_findings:
fid = obj.get("id")
refs = obj.get("evidence_refs") or []
has_copy = False # a well-formed copy: ref that links to PERSISTED copy
saw_copy_ref = False # any well-formed copy: ref (incl. one naming an absent copy_type)
has_contract_or_ms = False
for r in refs:
kind, ct = _ref_kind(r)
if kind == "copy":
saw_copy_ref = True
# A copy: ref is evidence only when it names a copy_type ACTUALLY persisted; a
# fabricated `copy:<absent-type>¶n` must not satisfy the two-sided gate with no copy
# behind it (Codex P1, 2026-06-19). When NO copy is persisted at all, P2 owns that
# error — don't also dangling-flag every ref here.
if copy_types and ct not in copy_types:
errs.append("P1 dangling copy ref: %s cites %r but no persisted "
"apodictic.pitch_copy.v1 document declares copy_type %r — a copy: ref "
"must name a span of persisted copy" % (fid, r, ct))
else:
has_copy = True
elif kind in ("contract", "ms"):
has_contract_or_ms = True
if not (has_copy and has_contract_or_ms):
missing = []
# a dangling copy ref is already reported above; only call the copy side "missing" when NO
# copy: ref was cited at all (else the message would contradict the dangling-ref error).
if not has_copy and not saw_copy_ref:
missing.append("a copy: ref")
if not has_contract_or_ms:
missing.append("a contract:/ms: ref")
if missing:
errs.append("P1 one-sided gap: %s is missing %s — a PCF flag is a two-sided gap and "
"must cite both the copy side and the contract/manuscript side "
"(namespaced refs)" % (fid, " and ".join(missing)))
# ---- P3 — reveal-leak form gate: a PCF2 finding's copy: ref must not point at a synopsis ----
for obj in valid_findings:
if not _is_pcf2(obj):
continue
for r in obj.get("evidence_refs") or []:
kind, ct = _ref_kind(r)
if kind == "copy" and ct == "synopsis":
errs.append("P3 reveal-leak miscalibration: %s is a PCF2 (reveal leak) but its copy "
"ref %r points at a synopsis — a synopsis discloses by design, so PCF2 "
"never fires on one" % (obj.get("id"), r))
break
# ---- W1 — drafted-copy leak (the Firewall): a multi-sentence quoted block in the report that is
# NOT a verbatim substring of the persisted pitch copy is authored replacement copy. Overrides are
# SNIPPET-keyed (see _drafted_override_snippets): a leak is silenced only by an override whose
# snippet matches THAT leak — so one override can't blanket-silence the firewall, and an override
# for absent text silences nothing. Skipped when no pitch is persisted (P2 already fails, and every
# quote would otherwise "leak" against an empty corpus — spurious noise on top of the P2 error).
if valid_pitch:
override_snips = _drafted_override_snippets(report_text)
for q in _multi_sentence_quotes(report_text):
if q in persisted_text:
continue
if any(s and (s in q or q in s) for s in override_snips):
continue
preview = (q[:60] + "…") if len(q) > 60 else q
warns.append("W1 drafted-copy leak: a multi-sentence quoted block in the report is not a "
"verbatim substring of the persisted pitch copy (authored replacement copy "
"— the Firewall): \"%s\"" % preview)
# ---- W2 — market-prediction drift: a PCF finding matching the prohibited phrase set ----
market_overrides = _overrides(report_text, "market-prediction")
for obj in valid_findings:
fid = obj.get("id")
short = _short(fid)
blob = "%s %s %s" % (obj.get("mechanism") or "", obj.get("fix_class") or "",
obj.get("risk_if_fixed") or "")
if _MARKET_RE.search(blob) and short not in market_overrides:
warns.append("W2 market-prediction drift: %s predicts a sales / market outcome (the #14 "
"boundary) — severity is fidelity risk, never market outcome; describe the "
"promise↔book gap, don't forecast the market" % fid)
# ---- Report ----
lines.append("promise-contract: %d pitch doc(s), %d F-PCF finding(s)%s" % (
len(valid_pitch), len(valid_findings),
"" if len(valid_pitch) == len(pitch_items) and len(valid_findings) == len(findings)
else " (%d/%d pitch, %d/%d findings well-formed)"
% (len(valid_pitch), len(pitch_items), len(valid_findings), len(findings))))
for obj in valid_pitch:
lines.append(" %-6s copy_type=%s" % (obj.get("id"), obj.get("copy_type")))
for obj in valid_findings:
lines.append(" %-9s severity=%s" % (obj.get("id"), obj.get("severity")))
if copy_types:
lines.append(" copy types present: %s" % ", ".join(sorted(t for t in copy_types if t)))
for e in errs:
lines.append(" ERROR: %s" % e)
for w in warns:
lines.append(" %s: %s" % ("ERROR (--strict)" if strict else "WARN", w))
if errs or (strict and warns):
lines.append("promise-contract: FAIL (%d error(s)%s)"
% (len(errs), ", %d strict warn(s)" % len(warns) if (strict and warns) else ""))
return 1, lines
if warns:
lines.append("WARN: promise-contract: %d advisory gap(s) — see W1/W2 above" % len(warns))
else:
lines.append("promise-contract: PASS (two-sided gap + copy typing + reveal form gate + "
"firewall/scope guards)")
return 0, lines
# ---------------------------------------------------------------- resolution
def _newest(paths):
return max(paths, key=os.path.getmtime) if paths else None
def resolve(paths):
"""Resolve (pitch_text, report_text) from a run folder or explicit files.
A run folder: pitch copy = newest *_Pitch_Copy_*.md (newest-wins on the glob); report = the whole
folder concatenated (so F-PCF findings in a letter/ledger are seen alongside the persisted copy).
Explicit files: each is read; a file carrying apodictic:pitch_copy contributes to the pitch corpus,
and every file contributes to the report corpus (a single combined file is both).
"""
if len(paths) == 1 and os.path.isdir(paths[0]):
d = paths[0]
pitch_path = _newest(glob.glob(os.path.join(d, _PITCH_GLOB)))
pitch_text = _read(pitch_path) if pitch_path else ""
report_parts = []
for p in sorted(glob.glob(os.path.join(d, "*.md"))):
t = _read(p)
if t is not None:
report_parts.append(t)
return (pitch_text or ""), "\n".join(report_parts)
pitch_parts, report_parts, found = [], [], False
for p in paths:
t = _read(p)
if t is None:
continue
found = True
report_parts.append(t)
if _has_block(t, "pitch_copy"):
pitch_parts.append(t)
if not found:
return None, None
return "\n".join(pitch_parts), "\n".join(report_parts)
def run(paths, strict=False):
pitch_text, report_text = resolve(paths)
if pitch_text is None and report_text is None:
return 2, ["promise-contract: no readable artifact found (need a run folder, a "
"*_Pitch_Copy_*.md, or files with apodictic:pitch_copy / F-PCF finding blocks)"]
return check(pitch_text, report_text, strict=strict)
# ---------------------------------------------------------------- self-test
def run_self_test():
import json as _j
rc = {"v": 0}
def chk(name, cond):
print(" %s: %s" % (name, "OK" if cond else "FAIL"))
if not cond:
rc["v"] = 1
# non-UTF8 artifact: _read must degrade to the unreadable path (None), never
# a traceback (the disposition_check adjacent-exception class, swept repo-wide)
import tempfile as _tf
_fd, _nu = _tf.mkstemp(suffix=".md")
with os.fdopen(_fd, "wb") as _fh:
_fh.write(b"\xff\xfenot utf-8\xff")
chk("non_utf8_read_returns_none", _read(_nu) is None)
os.unlink(_nu)
def pitch(pid="PC-01", ctype="query", text="A grieving cartographer maps a city that keeps "
"redrawing itself."):
obj = {"schema": _PITCH_SCHEMA_ID, "id": pid, "copy_type": ctype, "text": text}
return "<!-- apodictic:pitch_copy\n%s\n-->" % _j.dumps(obj)
def finding(fid="F-PCF-01", mech="PCF1 emphasis distortion: the query leads with a minor subplot",
refs=None, sev="Should-Fix", fix="bring the copy back to the kept promise",
risk="the lead reframes the book", conf="HIGH"):
if refs is None:
refs = ["copy:query¶1", "contract:CONTROLLING IDEA"]
obj = {"schema": _FINDING_SCHEMA_ID, "id": fid, "mechanism": mech, "severity": sev,
"confidence": conf, "evidence_refs": refs, "fix_class": fix, "risk_if_fixed": risk}
return "<!-- apodictic:finding\n%s\n-->" % _j.dumps(obj)
def C(pitch_text, report_text=None, strict=False):
return check(pitch_text, pitch_text if report_text is None else report_text, strict=strict)
# clean: one typed pitch + one two-sided PCF finding
chk("clean_basic", C(pitch() + "\n" + finding())[0] == 0)
# P1 — one-sided gap (copy-only) => ERROR; (contract-only) => ERROR; both sides => clean
chk("p1_copy_only_fails",
C(pitch() + "\n" + finding(refs=["copy:query¶1"]))[0] == 1)
chk("p1_contract_only_fails",
C(pitch() + "\n" + finding(refs=["contract:READER PROMISE"]))[0] == 1)
chk("p1_ms_satisfies_second_side",
C(pitch() + "\n" + finding(refs=["copy:query¶2", "ms:Ch 9"]))[0] == 0)
# stray whitespace (leading space; space after the colon) must not drop a real two-sided ref
chk("p1_whitespace_ref_ok",
C(pitch() + "\n" + finding(refs=[" copy:query¶1", "contract: CONTROLLING IDEA"]))[0] == 0)
code, ls = C(pitch() + "\n" + finding(refs=["copy:query¶1"]))
chk("p1_message", any("P1 one-sided gap" in ln for ln in ls))
# P1 — schema-invalid finding (empty refs, bad id) is an ERROR
chk("p1_empty_refs_fails", C(pitch() + "\n" + finding(refs=[]))[0] == 1)
chk("p1_bad_id_fails", C(pitch() + "\n" + finding(fid="F-PCF-1"))[0] == 1)
# P1 — a ref with the right prefix but an EMPTY target (bare `contract:`, `ms:`) names no side and
# must NOT satisfy two-sidedness (Codex P1) — this finding is then one-sided -> ERROR.
chk("p1_empty_target_contract_fails",
C(pitch() + "\n" + finding(refs=["copy:query¶1", "contract:"]))[0] == 1)
chk("p1_empty_target_ms_fails",
C(pitch() + "\n" + finding(refs=["copy:query¶1", "ms: "]))[0] == 1)
# P1 — a copy: ref must carry the FULL grammar (a ¶<n> locus) AND name a PERSISTED copy_type. A
# locus-less `copy:query`, a malformed `copy:query-does-not-exist` (no ¶), or a well-formed ref
# naming an absent copy_type is NO evidence and must not satisfy the two-sided gate even when a
# contract:/ms: ref is present (Codex P1, 2026-06-19 — the copy-side half of the gap).
chk("p1_copy_ref_without_locus_fails",
C(pitch() + "\n" + finding(refs=["copy:query", "contract:CONTROLLING IDEA"]))[0] == 1)
chk("p1_copy_ref_malformed_no_locus_fails",
C(pitch() + "\n" + finding(refs=["copy:query-does-not-exist", "contract:READER PROMISE"]))[0] == 1)
code, ls = C(pitch() + "\n" + finding(refs=["copy:synopsis¶2", "contract:CONTROLLING IDEA"]))
chk("p1_copy_ref_absent_copytype_fails", code == 1)
chk("p1_dangling_copy_ref_message", any("P1 dangling copy ref" in ln for ln in ls))
# P2 — a finding with no persisted pitch copy => ERROR; pitch present => clean
code, ls = C(finding()) # finding alone, no pitch_copy block
chk("p2_no_copy_fails", code == 1 and any("P2 pitch copy not persisted" in ln for ln in ls))
chk("p2_copy_present_ok", C(pitch() + "\n" + finding())[0] == 0)
# P2 — invalid copy_type (bad enum) fails schema
chk("p2_bad_copy_type_fails", C(pitch(ctype="tagline") + "\n" + finding())[0] == 1)
chk("p2_bad_pitch_id_fails", C(pitch(pid="PC-1") + "\n" + finding())[0] == 1)
# P2 — empty / whitespace-only pitch text is not real copy and must fail the schema (Codex P1)
chk("p2_empty_text_fails", C(pitch(text="") + "\n" + finding())[0] == 1)
chk("p2_whitespace_text_fails", C(pitch(text=" ") + "\n" + finding())[0] == 1)
# P3 — a PCF2 whose copy ref is a synopsis => ERROR; the same PCF2 against a query => clean;
# a NON-PCF2 finding citing a synopsis (the disclosing-synopsis negative) => clean.
pcf2_syn = finding(fid="F-PCF-02", mech="PCF2 reveal leak: discloses the ending",
refs=["copy:synopsis¶3", "contract:ENDING TYPE"])
pcf2_query = finding(fid="F-PCF-02", mech="PCF2 reveal leak: the blurb discloses the twist",
refs=["copy:query¶3", "contract:ENDING TYPE"])
chk("p3_pcf2_on_synopsis_fails",
C(pitch(ctype="synopsis") + "\n" + pcf2_syn)[0] == 1)
code, ls = C(pitch(ctype="synopsis") + "\n" + pcf2_syn)
chk("p3_message", any("P3 reveal-leak miscalibration" in ln for ln in ls))
chk("p3_pcf2_on_query_ok",
C(pitch(ctype="query") + "\n" + pcf2_query)[0] == 0)
# the P3 NEGATIVE assertion: a disclosing synopsis with a NON-PCF2 finding must NOT raise P3
non_pcf2_syn = finding(fid="F-PCF-03", mech="PCF4 under-sell: the synopsis omits the kept promise",
refs=["copy:synopsis¶1", "contract:CONTROLLING IDEA"])
chk("p3_disclosing_synopsis_no_false_positive",
C(pitch(ctype="synopsis") + "\n" + non_pcf2_syn)[0] == 0)
# a NON-PCF2 finding that merely MENTIONS "PCF2" in prose (and cites a synopsis) must NOT trip P3
sibling = finding(fid="F-PCF-05",
mech="PCF1 emphasis distortion (distinct from PCF2 reveal leak): the synopsis "
"leads with a subplot the book backgrounds",
refs=["copy:synopsis¶1", "contract:READER PROMISE"])
chk("p3_sibling_mention_no_false_positive",
C(pitch(ctype="synopsis") + "\n" + sibling)[0] == 0)
# W1 — a multi-sentence quoted block NOT in the persisted copy => advisory; ERROR --strict; a
# multi-sentence quote that IS a verbatim substring => clean; override silences.
persisted = "A grieving cartographer maps a city that keeps redrawing itself. She learns the map is her own grief."
report_leak = (pitch(text=persisted) + "\n" + finding()
+ "\n\nConsider this instead: \"A bold thriller about a cartographer. "
+ "Everyone will love it.\"\n")
code, ls = C(report_leak)
chk("w1_leak_advisory", code == 0 and any("W1 drafted-copy leak" in ln for ln in ls))
chk("w1_leak_strict_fails", C(report_leak, strict=True)[0] == 1)
# quoting the author's OWN copy verbatim (a multi-sentence substring of persisted) is clean
report_quote = (pitch(text=persisted) + "\n" + finding()
+ "\n\nThe query says: \"" + persisted + "\"\n")
chk("w1_verbatim_quote_clean",
not any("W1" in ln for ln in C(report_quote)[1]))
# a single-sentence quoted phrase is not a multi-sentence block => no W1
report_single = (pitch(text=persisted) + "\n" + finding()
+ "\n\nThe phrase \"a bold thriller\" overstates the genre.\n")
chk("w1_single_phrase_clean",
not any("W1" in ln for ln in C(report_single)[1]))
# a snippet-keyed override silences ONLY the leak it matches; a non-matching snippet silences none
ov = "<!-- override: drafted-copy A bold thriller about a cartographer — author drafted this herself -->\n"
chk("w1_override_snippet_silences",
not any("W1" in ln for ln in C(ov + report_leak)[1]))
ov_nomatch = "<!-- override: drafted-copy something unrelated entirely — n/a -->\n"
chk("w1_override_nonmatching_no_silence",
any("W1" in ln for ln in C(ov_nomatch + report_leak)[1]))
# Codex P2 (PR #148 review): a live drafted-copy snippet that CONTAINS a backtick code span is
# returned INTACT (override_payloads no longer blanks payload backticks); a marker quoted inside a
# code span still yields nothing.
chk("w1_backtick_snippet_preserved",
_drafted_override_snippets("<!-- override: drafted-copy a `b c` d — why -->") == ["a `b c` d"])
chk("w1_inline_decoy_yields_no_snippet",
_drafted_override_snippets("Use `<!-- override: drafted-copy x -->` here.") == [])
# W2 — a PCF finding predicting a market outcome => advisory; ERROR --strict; override silences;
# a fidelity-only finding is clean.
market = finding(mech="PCF1 emphasis: the query leads with the subplot; agents will pass on this",
refs=["copy:query¶1", "contract:READER PROMISE"])
code, ls = C(pitch() + "\n" + market)
chk("w2_market_advisory", code == 0 and any("W2 market-prediction drift" in ln for ln in ls))
chk("w2_market_strict_fails", C(pitch() + "\n" + market, strict=True)[0] == 1)
chk("w2_each_phrase_fires", all(
any("W2" in ln for ln in C(pitch() + "\n" + finding(
mech="PCF3 over-promise: %s" % phrase,
refs=["copy:query¶1", "ms:Ch 1"]))[1])
for phrase in ("won't sell", "no market for this", "unmarketable", "won't find an audience")))
ov2 = "<!-- override: market-prediction PCF-01 — quoting the author's own Pass-11 prediction -->\n"
chk("w2_override", not any("W2" in ln for ln in C(ov2 + pitch() + "\n" + market)[1]))
chk("w2_fidelity_only_clean", not any("W2" in ln for ln in C(pitch() + "\n" + finding())[1]))
# no blocks => no-op
chk("no_blocks_noop", C("# Notes\nnothing structured\n")[0] == 0)
# run-folder + explicit-file + missing-artifact resolution
import tempfile
import shutil
d = tempfile.mkdtemp()
try:
pc = os.path.join(d, "Proj_Pitch_Copy_run.md")
with open(pc, "w", encoding="utf-8", newline="") as fh:
fh.write("# Pitch Copy\n" + pitch() + "\n")
ltr = os.path.join(d, "Proj_Editorial_Letter_run.md")
with open(ltr, "w", encoding="utf-8", newline="") as fh:
fh.write("# Promise-Contract Findings\n" + finding() + "\n")
chk("run_folder_resolution", run([d])[0] == 0)
chk("explicit_files_resolution", run([pc, ltr])[0] == 0)
chk("missing_artifact_usage", run([os.path.join(d, "nope.md")])[0] == 2)
# run-folder: pitch present but P1 one-sided finding still fails
bad = os.path.join(d, "Proj_Bad_Letter_run.md")
with open(bad, "w", encoding="utf-8", newline="") as fh:
fh.write(finding(fid="F-PCF-09", refs=["copy:query¶1"]) + "\n")
chk("run_folder_p1_fails", run([d])[0] == 1)
finally:
shutil.rmtree(d, ignore_errors=True)
# regression: a non-dict finding payload must not crash parse_findings (2026-06-20 sweep)
chk("crash_nondict_finding", C(pitch() + "\n" + '<!-- apodictic:finding\n[1,2,3]\n-->')[0] == 1)
print("Self-test: PASS" if rc["v"] == 0 else "Self-test: FAIL")
return rc["v"]
def main(argv):
if "--self-test" in argv:
return run_self_test()
args = [a for a in argv[1:] if a != "promise-contract"]
strict = "--strict" in args
paths = [a for a in args if not a.startswith("--")]
if not paths:
print("Usage: promise_contract.py promise-contract <run_folder|files...> [--strict] | --self-test")
return 2
code, lines = run(paths, strict=strict)
for ln in lines:
print(ln)
return code
if __name__ == "__main__":
sys.exit(main(sys.argv))
SHA-256: 81da7f18c8895d71e0e33714710658aedb7ed73602df8070d4d39b9bbdacb982