← Files APODICTIC Development EditorARCHIVED FILE
scripts/calibration_honesty.py
22.8 KB · Nov 9, 2026 · 00:53 UTC
#!/usr/bin/env python3
"""calibration-honesty — an uncalibrated SETEC band must never be rendered to a reader as a verdict.
`validate.sh calibration-honesty <run_folder|files...> [--strict]` shells out here. Both consumer
decision-audit surfaces — `narrative_decision_audit` (StoryScope) and `argument_decision_audit`
(ArgScope) — ship `handoff: experimental` with an envelope `aggregate.verdict_band: "uncalibrated"` and
`thresholds: {low: null, high: null}`. The consumer-side discipline (surface the band as PROVENANCE
only, never as a calibrated verdict) was enforced ENTIRELY in prose (the two audit docs' anti-verdict
sections + four pass-dependencies.md rows). No mechanical check existed that a decision-audit's
human-facing rendering doesn't present the uncalibrated band as calibrated. This is that check: the
house `claim-surface-asserts-it -> enforce-it` posture applied to a claim the audits already make.
WHAT IT CHECKS (D1). The guard scans the reader-facing editorial letter WHOLE (D2 — region-scoping was a
false foundation: the only per-audit sectioner scopes appendix bodies only, decision-audit findings land
in the unscoped synthesis body, and the canonical fixture carries no decision-audit region), per
PARAGRAPH (blank-line-delimited scan unit). A paragraph is flagged only when a CLAIM SHAPE matches AND no
QUALIFIER is co-present in that same paragraph. Bare token presence ("band", "threshold", "verdict")
never fires on its own — that is what keeps the mandated clean-path boilerplate and the vendored bundle
labels safe (they carry a qualifier or lack a claim shape).
CS1 band-placement "the manuscript scores in the AI-elevated band" — a subject + a placement verb +
`in/into/within/at` + `band`. The verdict form, no qualifier.
CS2 calibrated-verdict "calibrated verdict/band/score", or a bare `verdict:` / `verdict =` assertion.
CS3 threshold claim "sits above the threshold" / "threshold of 0.4" — on a thresholds-null surface,
a comparative + `the/a/its threshold|cut-off`, or a numeric threshold.
CS4 aggregate-verdict "the aggregate score confirms/proves/establishes/demonstrates …" — the score
promoted to a verdict.
SEVERITY (D4 — the honest class). This is an OPEN natural-language co-presence check, not a closed
literal scan, so its house class is content_advisory W1 (prescriptive drift) / stance-consistency F4:
WARN by default, ERROR only under --strict. Failure direction is toward NOT firing (a missed leak is
recoverable by the human reader who owns the reading; a false ERROR blocks a run on prose the doc itself
mandates). The HONEST CLAIM (stated here and in the validator's help): the guard closes the ENUMERATED
claim shapes when unqualified; it does NOT claim to close every way prose can imply calibration. Residual
semantic leakage that no vocabulary list can close is presented to a human. Layered mechanism + human
terminus, not a proof.
Override: a per-instance prose override `<!-- override: calibration-honesty — <why> -->`, detected via
the shared `override_marker` SSoT (code-span-stripped, boundary-matched — M5), never a bare substring.
OWNERSHIP (D5 — one new arm; the three-way boundary, disclaimed not latent).
* `severity-floor` (letter_checks) owns whole-letter verdict-band-vs-flags honesty for the
SUBMISSION-READINESS vocabulary (`_HIGH_VERDICT_RE` = Strong Fit | publishable as-is | Highest Band
| Excellent Fit), policed against flag volume. NAMED OVERLAP + DISCLAIMER: both validators scan
letter-wide verdict-adjacent vocabulary; the two vocabularies are and must remain DISJOINT — no CS
pattern matches the four readiness tokens (the readiness-disjointness self-test asserts a legal
readiness sentence does not fire calibration-honesty), and calibration-honesty never reads flag
counts.
* `honesty_check` (softness-check / deficit-lock) owns locked-severity delivery. It says nothing about
calibration bands.
* `calibration-honesty` (this arm) owns per-audit calibration-PROVENANCE rendering — an uncalibrated
SETEC band presented as calibrated. It never reads severities, never gates tiers, never touches the
§4e propagation logic.
CROSS-SURFACE (D6). The guard covers BOTH decision-audits and is surface-agnostic: nothing keys on the
audit name, so a future uncalibrated `handoff: experimental` consumer surface inherits it by
construction.
VOCABULARY HOME. The severity-token SSoT (`severity_vocab.SEVERITY_TOKEN_RE`, M8) is the Must/Should/
Could-Fix leak token — a DIFFERENT vocabulary that this guard does not use (it reads calibration-band
prose, not editorial-severity prose). The CS shapes, qualifier set, and allowlist are THIS guard's OWN
new vocabulary and live here; M8 does not apply (no `(?:Must|Should|Could)` alternation is re-compiled).
See docs/calibration-honesty.md.
calibration_honesty.py calibration-honesty <run_folder|files...> [--strict]
calibration_honesty.py --self-test
Exit: 0 clean / WARN-only, 1 ERROR (WARN under --strict), 2 usage / no artifact.
"""
import glob
import os
import re
import sys
from override_marker import has_override, strip_code_spans # SSoT: code-span-stripped, boundary-matched
_OVERRIDE_SLUG = "calibration-honesty"
# The editorial letter — scanned whole (D2). Newest wins on a run-folder resolution.
_LETTER_GLOBS = ("*_Core_DE_Synthesis_*.md", "*_Full_DE_Synthesis_*.md")
# ------------------------------------------------------------------ CS family (D1)
# CS1 — band-placement claim: a subject, a placement verb, in/into/within/at, then `band` within a short
# same-line window. The `\bband\b` requirement is what keeps "scores high on structural_streamlining"
# (the :157 "fair" summary — no `band` token) and the bundle labels safe.
_CS1 = re.compile(
r"(?:manuscript|document|essay|story|draft|work|text|chapter|prose|argument|op-ed|it|this)\b"
r"[^.!?\n]{0,60}?"
r"\b(?:scores?|falls?|lands?|sits?|places?|rates?|comes?\s+out|is)\s+"
r"(?:in|into|within|at)\s+(?:the\s+|a\s+|an\s+)?"
r"[^.!?\n]{0,40}?\bband\b",
re.IGNORECASE)
# CS2 — calibrated / verdict assertion (two patterns).
_CS2 = (
re.compile(r"\bcalibrated\s+(?:verdict|band|score|result|threshold)s?\b", re.IGNORECASE),
# `verdict:` / `verdict =` — a rendered verdict field. DELIBERATELY case-SENSITIVE (no IGNORECASE):
# a capitalized `**Verdict:**` / `## Readiness Verdict:` is a submission-readiness/severity-floor
# heading (severity-floor's turf, D5) and legitimately out-of-scope for the calibration-band check;
# only a lower-case decision-audit `verdict:` field is CS2's target. IGNORECASE here would false-fire
# on every readiness verdict heading. See the `**Verdict:**`-shaped negative fixture in run_self_test.
re.compile(r"\bverdict\s*[:=]"),
)
# CS3 — threshold claim on a thresholds-null surface (two patterns).
_CS3 = (
re.compile(r"\b(?:above|below|exceeds?|crosses?|meets?|over|under|past)\s+"
r"(?:the|a|its)\s+(?:threshold|cut-?off)\b", re.IGNORECASE),
re.compile(r"\bthreshold\s+(?:of|at)\s+[-+]?\d"),
)
# CS4 — aggregate-as-verdict.
_CS4 = re.compile(
r"\baggregate(?:\s+|[-_])?score\b[^.!?\n]{0,80}"
r"\b(?:verdict|confirms?|proves?|establishes?|demonstrates?)\b",
re.IGNORECASE)
# D5 disjointness: the SUBMISSION-READINESS vocabulary is severity-floor's (`_HIGH_VERDICT_RE`), and the
# two vocabularies must remain DISJOINT. One readiness token — "Highest Band" — carries the `band` noun
# CS1 keys on, so a CS1 match whose ONLY band anchor is a readiness phrase is severity-floor's turf, not
# ours; excise those matches. (The other three readiness tokens carry no `band`/threshold/verdict shape,
# so no other CS rule can reach them.) Kept in lockstep with letter_checks._HIGH_VERDICT_RE by the
# readiness-disjointness self-test.
_READINESS_BAND_RE = re.compile(r"\b(?:Highest|Strong|Top|Excellent|Publishable)\s+Band\b", re.IGNORECASE)
def _cs1_hits(text):
"""CS1 matches on `text`, minus any whose `band` anchor is a submission-readiness phrase
("Highest Band") — that is severity-floor's vocabulary (D5). A CS1 hit counts only if a NON-readiness
`band` occurrence backs it: strip the readiness-band phrases and re-test."""
if not _CS1.search(text):
return False
stripped = _READINESS_BAND_RE.sub("", text)
return bool(_CS1.search(stripped))
# (label, matcher) — a matcher is a compiled RE, a tuple of them (any match fires), or a callable.
_CS_RULES = (
("CS1 band-placement", _cs1_hits),
("CS2 calibrated-verdict", _CS2),
("CS3 threshold-claim", _CS3),
("CS4 aggregate-as-verdict", _CS4),
)
# ------------------------------------------------------------------ qualifier set (D1)
# Case-folded substring: co-presence in the SAME paragraph quenches the flag. Enumerated in full.
_QUALIFIERS = (
"uncalibrated", "provenance only", "provenance-only", "not a verdict", "never a verdict",
"no thresholds", "ships uncalibrated", "advisory", "does not license", "does_not_license",
"experimental", "directional reference",
)
def _matches(matcher, text):
if isinstance(matcher, tuple):
return any(pat.search(text) for pat in matcher)
if callable(matcher) and not hasattr(matcher, "search"):
return bool(matcher(text)) # a predicate (e.g. _cs1_hits)
return bool(matcher.search(text))
def _qualified(para_lower):
"""True if any qualifier substring is co-present in the (already lower-cased) paragraph."""
return any(q in para_lower for q in _QUALIFIERS)
def _read(path):
try:
with open(path, encoding="utf-8") as fh:
return fh.read()
except (OSError, UnicodeDecodeError):
return None
def _paragraphs(text):
"""Blank-line-delimited scan units. HTML comments (override markers, apodictic blocks) are stripped
from the SCANNED copy so an override marker's own text can't trip a CS pattern, but the raw paragraph
is retained for the override lookup (which needs the marker) and for the report quote."""
# Split on one-or-more blank lines (whitespace-only lines count as blank).
return [p for p in re.split(r"\n[ \t]*\n", text or "") if p.strip()]
_HTML_COMMENT_RE = re.compile(r"<!--.*?-->", re.DOTALL)
def scan(text, strict=False):
"""Run the calibration-honesty scan over an editorial letter. Returns (code, lines).
Whole-letter, per paragraph. A paragraph fires at most ONE WARN (the first CS rule to match on the
unqualified, override-free paragraph); the WARN names the rule and quotes the offending paragraph."""
lines, warns = [], []
paras = _paragraphs(text)
for para in paras:
# Reader-facing prose only: strip HTML comments AND code spans before pattern-matching, so an
# override marker or a fenced code example never trips a CS shape (the boilerplate/label safety
# relies on the qualifier co-presence, but a marker quoting a CS phrase must not self-fire).
scan_text = strip_code_spans(_HTML_COMMENT_RE.sub("", para))
para_lower = scan_text.lower()
if _qualified(para_lower):
continue # a co-present qualifier quenches every CS rule in this paragraph
for label, matcher in _CS_RULES:
if not _matches(matcher, scan_text):
continue
# A per-instance prose override silences THIS paragraph (M5: code-span-stripped, boundary-
# matched via the shared SSoT — a suffixed slug / a backtick'd marker is not honored).
if has_override(para, _OVERRIDE_SLUG):
break
# Quote the reader-facing prose (HTML comments stripped) so the report isn't polluted by
# markers/meta-comments; the match was on scan_text anyway.
quote = " ".join(_HTML_COMMENT_RE.sub("", para).split())
if len(quote) > 160:
quote = quote[:157] + "..."
warns.append("%s: an uncalibrated SETEC band is rendered as a verdict, with no "
"uncalibrated/provenance-only/advisory qualifier in the paragraph — \"%s\""
% (label, quote))
break # one WARN per paragraph
lines.append("calibration-honesty: %d paragraph(s) scanned" % len(paras))
for w in warns:
lines.append(" %s: %s" % ("ERROR (--strict)" if strict else "WARN", w))
if strict and warns:
lines.append("calibration-honesty: FAIL (%d strict warn(s))" % len(warns))
return 1, lines
if warns:
lines.append("WARN: calibration-honesty: %d unqualified calibration-band claim(s) — the guard "
"closes the enumerated claim shapes; a human reader owns residual leakage" % len(warns))
else:
lines.append("calibration-honesty: PASS (no unqualified calibration-band verdict claim)")
return 0, lines
# ------------------------------------------------------------------ resolution
def _newest(paths):
return max(paths, key=os.path.getmtime) if paths else None
def resolve(paths):
"""A single directory resolves to the newest editorial-letter glob; explicit files are checked in
order (first that reads). No block-membership probe — the letter is unstructured synthesis prose."""
if len(paths) == 1 and os.path.isdir(paths[0]):
cands = []
for g in _LETTER_GLOBS:
cands.extend(glob.glob(os.path.join(paths[0], g)))
return _newest(cands)
for p in paths:
if os.path.isfile(p) and _read(p) is not None:
return p
return None
def run(paths, strict=False):
path = resolve(paths)
if not path:
return 2, ["calibration-honesty: no editorial letter found (need a *_Core_DE_Synthesis_*.md / "
"*_Full_DE_Synthesis_*.md or an explicit letter file) — nothing to check"]
text = _read(path)
if text is None:
return 2, ["calibration-honesty: cannot read %s" % path]
return scan(text, strict=strict)
# ------------------------------------------------------------------ self-test
def run_self_test():
rc = {"v": 0}
def chk(name, cond):
print(" %s: %s" % (name, "OK" if cond else "FAIL"))
if not cond:
rc["v"] = 1
def warns_of(text, strict=False):
# Only the per-paragraph finding lines (two-space indent + WARN:/ERROR (--strict):), NOT the
# trailing WARN summary line (which also carries "WARN").
return [ln for ln in scan(text, strict=strict)[1]
if ln.startswith(" WARN:") or ln.startswith(" ERROR (--strict):")]
# non-UTF8 read degrades to None, never a traceback (the 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)
# Fixture 1 — clean provenance-only rendering (PASS): band stated WITH a qualifier co-present.
chk("fx1_clean_provenance_pass",
scan("aggregate score -0.84; verdict band uncalibrated, provenance only")[0] == 0
and warns_of("aggregate score -0.84; verdict band uncalibrated, provenance only") == [])
# Fixture 2 — CS1 band-placement (WARN default; ERROR --strict): no qualifier in the paragraph.
F2 = "the manuscript scores in the AI-elevated band"
chk("fx2_cs1_warn_default", scan(F2)[0] == 0 and any("CS1" in w for w in warns_of(F2)))
chk("fx2_cs1_strict_fails", scan(F2, strict=True)[0] == 1)
# Fixture 3 — CS3 threshold claim on a thresholds-null surface.
F3 = "the story sits above the threshold"
chk("fx3_cs3_warn_default", scan(F3)[0] == 0 and any("CS3" in w for w in warns_of(F3)))
chk("fx3_cs3_strict_fails", scan(F3, strict=True)[0] == 1)
chk("fx3b_cs3_numeric", any("CS3" in w for w in warns_of("crossed a threshold of 0.42 in the run")))
# Fixture 4 — CS4 aggregate-as-verdict.
F4 = "the aggregate score confirms the draft is AI-patterned"
chk("fx4_cs4_warn_default", scan(F4)[0] == 0 and any("CS4" in w for w in warns_of(F4)))
chk("fx4_cs4_strict_fails", scan(F4, strict=True)[0] == 1)
# CS2 — calibrated/verdict assertion (both patterns).
chk("cs2_calibrated_band", any("CS2" in w for w in warns_of("this is a calibrated band for the work")))
chk("cs2_verdict_field", any("CS2" in w for w in warns_of("verdict: AI-elevated")))
# Fixture 5 — allowlist negatives (PASS, zero flags). Each must NOT fire.
# (a) the bundle-label literals (narrative-decision-audit.md:88 + argument-decision-audit.md:89,92)
for label in ('"AI-elevated: Structural streamlining"',
'"B1 — Structural arc (paragraph-role transitions)"',
'"B2 — Discourse-mode mix"'):
chk("fx5_bundle_label_clean::%s" % label[:22], warns_of(label) == [])
# (b) the three mandated boilerplate sentences (D1: :165 / :185 / :177)
for boiler in ("Word count vs. bounds; verdict band `uncalibrated`; calibration status literature_anchored.",
"The surface ships uncalibrated, with no thresholds and an `uncalibrated` verdict band.",
"It is *not* a threshold, *not* a verdict, *not* shipped per-signal."):
chk("fx5_boilerplate_clean::%s" % boiler[:22], warns_of(boiler) == [])
# (c) the :157 "fair" summary sentence — CS1 needs `band`, which this lacks
chk("fx5_fair_summary_clean",
warns_of("this story scores high on sensory_embodied_performativity and structural_streamlining") == [])
# Fixture 6 — override respected (PASS): a flagged paragraph with the override marker is quiet; a
# suffixed-slug decoy and a code-span-quoted marker are NOT honored (M5 via override_marker).
OV = "<!-- override: %s — SETEC's own docstring quoted verbatim -->" % _OVERRIDE_SLUG
chk("fx6_override_silences",
warns_of("the manuscript scores in the AI-elevated band\n%s" % OV) == [])
chk("fx6_suffixed_slug_decoy_not_honored",
any("CS1" in w for w in warns_of(
"the manuscript scores in the AI-elevated band\n"
"<!-- override: %s-but-not-really — decoy -->" % _OVERRIDE_SLUG)))
chk("fx6_codespan_marker_not_honored",
any("CS1" in w for w in warns_of(
"the manuscript scores in the AI-elevated band\n`%s`" % OV)))
# Fixture 7 — readiness-verdict disjointness (PASS): a severity-floor-legal readiness sentence fires
# NOTHING. The D5 boundary proof — no CS pattern may match the four _HIGH_VERDICT_RE readiness tokens.
for ready in ("Strong Fit; publishable as-is after the Must-Fix items are addressed.",
"This lands in the Highest Band for submission readiness.",
"Excellent Fit for the target market."):
chk("fx7_readiness_disjoint::%s" % ready[:20], warns_of(ready) == [])
# Fixture 7b — capitalized verdict headings stay CLEAN (records CS2's deliberate case-sensitivity):
# a `**Verdict:**` / `## Readiness Verdict:` heading is a readiness/severity-floor field, out-of-scope
# for the calibration-band check. CS2's `verdict:` arm is case-sensitive by design so these do NOT fire
# (IGNORECASE would false-fire on every readiness verdict heading). If someone "fixes" the case, this
# fixture fails — the intended tripwire.
for cap_verdict in ("**Verdict:** Excellent Fit for the target market.",
"## Readiness Verdict: publishable as-is."):
chk("fx7b_capital_verdict_clean::%s" % cap_verdict[:22], warns_of(cap_verdict) == [])
# Fixture 8 — cross-contamination (PASS+WARN, attributed): one letter with a CLEAN narrative-decision
# paragraph AND a VIOLATING argument-decision paragraph. Exactly one WARN, attributed to the violating
# paragraph (quoted); the clean one not false-fired.
F8 = (
"## Narrative-Decision (StoryScope)\n\n"
"StoryScope aggregate score -0.84; verdict band uncalibrated, provenance only — the structural "
"signals lean AI-elevated, but this is not a verdict.\n\n"
"## Argument-Decision (ArgScope)\n\n"
"the op-ed scores in the AI-elevated band, confirming the piece is machine-drafted."
)
w8 = warns_of(F8)
chk("fx8_exactly_one_warn", len(w8) == 1)
chk("fx8_attributed_to_violation", w8 and "op-ed scores in the AI-elevated band" in w8[0])
chk("fx8_clean_narrative_not_fired", not any("StoryScope aggregate" in w for w in w8))
chk("fx8_strict_fails", scan(F8, strict=True)[0] == 1)
# A paragraph with NO decision-audit content simply has no CS match (the unconditional whole-letter
# scan is safe because the CS family is specific).
chk("no_cs_match_clean",
warns_of("Chapter 3 needs a stronger midpoint reversal; the reader loses the thread here.") == [])
# editorial-threshold prose (Open Q2): CS3 requires `the/a/its threshold|cut-off` after a comparative,
# so "above the threshold where a beta round helps" DOES match the shape — but it is quenched only if a
# qualifier is present. Without decision-audit context it can false-fire; the override is the relief
# valve. We assert the SHAPE narrowness: a bare comparative with no `threshold`/`cut-off` noun is clean.
chk("editorial_no_threshold_noun_clean",
warns_of("the draft is above average for a debut in this category") == [])
# resolution: glob (newest), explicit file, no-artifact exit 2.
import shutil
import tempfile
d = tempfile.mkdtemp()
try:
p = os.path.join(d, "Proj_Core_DE_Synthesis_run.md")
with open(p, "w", encoding="utf-8", newline="") as fh:
fh.write("# Editorial Letter\n\nverdict band uncalibrated, provenance only.\n")
chk("run_folder_resolution", run([d])[0] == 0)
chk("explicit_file_resolution", run([p])[0] == 0)
chk("no_artifact_exit2", run([os.path.join(d, "nope.md")])[0] == 2)
# a run folder with a VIOLATING letter fails under --strict
pv = os.path.join(d, "Proj_Full_DE_Synthesis_run.md")
with open(pv, "w", encoding="utf-8", newline="") as fh:
fh.write("# Letter\n\nthe manuscript scores in the AI-elevated band\n")
# Order fixture mtimes so the newest-glob resolver exercises the violating letter.
os.utime(p, (1700000000, 1700000000))
os.utime(pv, (1700000002, 1700000002))
chk("run_folder_violation_strict_fails", run([d], strict=True)[0] == 1)
finally:
shutil.rmtree(d, ignore_errors=True)
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 != "calibration-honesty"]
strict = "--strict" in args
paths = [a for a in args if not a.startswith("--")]
if not paths:
print("Usage: calibration_honesty.py calibration-honesty <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: dee8e3a310d08dfa1810d490fe549a7416ccc7692dc3da6302f8d8fbbcb5ab2e