fix(packs/register): remove bare '.' closings + ratify gate refuses them

The widened 100-pack tour surfaced four packs whose closings bucket
included a bare '.' entry: assertive_v1, blunt_v1, dry_v1, and
mathematical_v1. Seeded variation selects from buckets uniformly, so
roughly 1/N of turns would emit a '..'-style surface artefact
(e.g. 'Truth is what is true..') when '.' was selected and appended
to a surface CORE's deterministic realizer already terminated with
'.'.

This commit:
  * Strips the bare '.' entry from the four affected packs' closings.
    The remaining entries (e.g. ' — qed.', ' — that's it.', '') all
    carry their own leading separator, so concatenation produces a
    clean surface.
  * Re-runs scripts/ratify_register_packs.py to re-seal each pack's
    mastery_report.json with a fresh pack_source_sha256 and
    self_seal_sha256 — these companion files are part of the diff
    because pack content changed.
  * Adds _validate_discourse_markers_shape() to
    scripts/ratify_register_packs.py as defense in depth. The new
    R4-tier gate refuses any closing entry whose first character is
    bare sentence-final punctuation ('.', '!', '?', ';', ':') or an
    alphanumeric — both classes would produce concatenation artefacts.
    Ellipsis ('...', '…') is explicitly exempt as a legitimate
    stylistic ending.

Verified:
  * core eval cognition byte-identical (the eval runs unregistered)
  * tests/test_cognition_eval_register_matrix.py: 801 passed in 5:23
    (100 registers × 8 projection invariants + meta-test), confirming
    the closing fix did not perturb ADR-0072 trace_hash invariance
    or any per-case projection.
  * Hand-verification across {assertive,blunt,dry,mathematical}_v1
    × 4 prompts = 16 surfaces: 0 remaining double-period artefacts.
  * Re-running ratify against a re-introduced bad closing produces
    SystemExit with the new gate's diagnostic message.

mathematical_v1 now reads beautifully under "What is light?":
  "Lemma:  Light is visible medium that reveals truth. — qed."
This commit is contained in:
Shay 2026-05-21 06:57:43 -07:00
parent 483c66dc5f
commit ae38412e93
9 changed files with 77 additions and 22 deletions

View file

@ -3,7 +3,7 @@
"version": "1.0.0", "version": "1.0.0",
"description": "Assertive register — declarative markers, no hedging.", "description": "Assertive register — declarative markers, no hedging.",
"schema_version": "1.0.0", "schema_version": "1.0.0",
"mastery_report_sha256": "44750505a1fce4eaadf47a4fe5a22c8d3d53d41957f5d161797a539dc9258844", "mastery_report_sha256": "785f079aad5e2492ed7d054716ed2ecf897622230bd2cc96d419cf0ebe9cc9f5",
"display_name": "Assertive", "display_name": "Assertive",
"depth_preference": "standard", "depth_preference": "standard",
"realizer_overrides": { "realizer_overrides": {
@ -19,8 +19,7 @@
], ],
"transitions": [], "transitions": [],
"closings": [ "closings": [
"", ""
"."
] ]
} }
} }

View file

@ -3,7 +3,7 @@
"depth_preference": "standard", "depth_preference": "standard",
"discourse_markers_empty": false, "discourse_markers_empty": false,
"marker_bucket_sizes": { "marker_bucket_sizes": {
"closings": 2, "closings": 1,
"openings": 4, "openings": 4,
"transitions": 0 "transitions": 0
}, },
@ -16,10 +16,10 @@
}, },
"failure_reasons": [], "failure_reasons": [],
"issued_at": "2026-05-20T00:00:00Z", "issued_at": "2026-05-20T00:00:00Z",
"pack_source_sha256": "a6d1c49aee2ef5222c7e4481ddb968b40be4eb13cae6eaa14ad140a1a60ec128", "pack_source_sha256": "f542dae9062ee981018846517da65c6480200138e029df7254669b5b0a9dfc44",
"ratification_method": "seeded_variation_replay_equivalence", "ratification_method": "seeded_variation_replay_equivalence",
"ratified": true, "ratified": true,
"register_id": "assertive_v1", "register_id": "assertive_v1",
"report_sha256": "44750505a1fce4eaadf47a4fe5a22c8d3d53d41957f5d161797a539dc9258844", "report_sha256": "785f079aad5e2492ed7d054716ed2ecf897622230bd2cc96d419cf0ebe9cc9f5",
"schema_version": "1.0.0" "schema_version": "1.0.0"
} }

View file

@ -3,7 +3,7 @@
"version": "1.0.0", "version": "1.0.0",
"description": "Blunt register — short, sharp, no qualification.", "description": "Blunt register — short, sharp, no qualification.",
"schema_version": "1.0.0", "schema_version": "1.0.0",
"mastery_report_sha256": "2925ce07bd132a235296098d135ad46f171efc46f2cead69b06f52d309661d33", "mastery_report_sha256": "0c435910a295c7cade443cccfd175c90f0302cc90f0c5a6c613ef62c190462ed",
"display_name": "Blunt", "display_name": "Blunt",
"depth_preference": "terse", "depth_preference": "terse",
"realizer_overrides": { "realizer_overrides": {
@ -21,8 +21,7 @@
], ],
"transitions": [], "transitions": [],
"closings": [ "closings": [
"", ""
"."
] ]
} }
} }

View file

@ -3,7 +3,7 @@
"depth_preference": "terse", "depth_preference": "terse",
"discourse_markers_empty": false, "discourse_markers_empty": false,
"marker_bucket_sizes": { "marker_bucket_sizes": {
"closings": 2, "closings": 1,
"openings": 4, "openings": 4,
"transitions": 0 "transitions": 0
}, },
@ -18,10 +18,10 @@
}, },
"failure_reasons": [], "failure_reasons": [],
"issued_at": "2026-05-20T00:00:00Z", "issued_at": "2026-05-20T00:00:00Z",
"pack_source_sha256": "71a9bc92336de59c4014777e5d3e36bdece30c6519e21f7fd8df984f7847309f", "pack_source_sha256": "6f148b6f90971ff4be82d8fa22001d890e2f8c98ac8f6caa4f453328ba1eabcd",
"ratification_method": "seeded_variation_replay_equivalence", "ratification_method": "seeded_variation_replay_equivalence",
"ratified": true, "ratified": true,
"register_id": "blunt_v1", "register_id": "blunt_v1",
"report_sha256": "2925ce07bd132a235296098d135ad46f171efc46f2cead69b06f52d309661d33", "report_sha256": "0c435910a295c7cade443cccfd175c90f0302cc90f0c5a6c613ef62c190462ed",
"schema_version": "1.0.0" "schema_version": "1.0.0"
} }

View file

@ -3,7 +3,7 @@
"version": "1.0.0", "version": "1.0.0",
"description": "Dry register — understated, factual.", "description": "Dry register — understated, factual.",
"schema_version": "1.0.0", "schema_version": "1.0.0",
"mastery_report_sha256": "1f3232b4eb99d6df156de3f34c5e8fe24f8453ac04a59bb3bd41553ffc5b169a", "mastery_report_sha256": "6f413313c0cc42bae47dfb3f1273d429006c0b4405a48764ad6aac8d69da3ebc",
"display_name": "Dry", "display_name": "Dry",
"depth_preference": "standard", "depth_preference": "standard",
"realizer_overrides": { "realizer_overrides": {
@ -19,7 +19,6 @@
"transitions": [], "transitions": [],
"closings": [ "closings": [
"", "",
".",
" — that's it." " — that's it."
] ]
} }

View file

@ -3,7 +3,7 @@
"depth_preference": "standard", "depth_preference": "standard",
"discourse_markers_empty": false, "discourse_markers_empty": false,
"marker_bucket_sizes": { "marker_bucket_sizes": {
"closings": 3, "closings": 2,
"openings": 3, "openings": 3,
"transitions": 0 "transitions": 0
}, },
@ -16,10 +16,10 @@
}, },
"failure_reasons": [], "failure_reasons": [],
"issued_at": "2026-05-20T00:00:00Z", "issued_at": "2026-05-20T00:00:00Z",
"pack_source_sha256": "eccd21f4b00102526fc22d28bac38e091dbda30a408848ac6f42bbfc16716bfb", "pack_source_sha256": "0db49fb251edc60106c04ca75b3422b4661a26e8e1ac17cd9ef2c7973f6617c8",
"ratification_method": "seeded_variation_replay_equivalence", "ratification_method": "seeded_variation_replay_equivalence",
"ratified": true, "ratified": true,
"register_id": "dry_v1", "register_id": "dry_v1",
"report_sha256": "1f3232b4eb99d6df156de3f34c5e8fe24f8453ac04a59bb3bd41553ffc5b169a", "report_sha256": "6f413313c0cc42bae47dfb3f1273d429006c0b4405a48764ad6aac8d69da3ebc",
"schema_version": "1.0.0" "schema_version": "1.0.0"
} }

View file

@ -3,7 +3,7 @@
"version": "1.0.0", "version": "1.0.0",
"description": "Mathematical register — proof-cadence.", "description": "Mathematical register — proof-cadence.",
"schema_version": "1.0.0", "schema_version": "1.0.0",
"mastery_report_sha256": "04e9a09cce4e599781b2d4994383cebf4f6529391f58005a84e69363494508c2", "mastery_report_sha256": "b85e2505fe647aa474b599cfa447c3677ad92c7c305d34ae63c97c8b5ba82fb6",
"display_name": "Mathematical", "display_name": "Mathematical",
"depth_preference": "standard", "depth_preference": "standard",
"realizer_overrides": { "realizer_overrides": {
@ -21,7 +21,6 @@
"transitions": [], "transitions": [],
"closings": [ "closings": [
"", "",
".",
" — qed." " — qed."
] ]
} }

View file

@ -3,7 +3,7 @@
"depth_preference": "standard", "depth_preference": "standard",
"discourse_markers_empty": false, "discourse_markers_empty": false,
"marker_bucket_sizes": { "marker_bucket_sizes": {
"closings": 3, "closings": 2,
"openings": 4, "openings": 4,
"transitions": 0 "transitions": 0
}, },
@ -17,10 +17,10 @@
}, },
"failure_reasons": [], "failure_reasons": [],
"issued_at": "2026-05-20T00:00:00Z", "issued_at": "2026-05-20T00:00:00Z",
"pack_source_sha256": "f7885f683ad806730ede0ce1a0a4f3d2503ead583719f055949e2a1ccdad281e", "pack_source_sha256": "59be9a46ca10a612aa201fcb3736d1791505b9fea5add9b40ac5e57e21f84028",
"ratification_method": "seeded_variation_replay_equivalence", "ratification_method": "seeded_variation_replay_equivalence",
"ratified": true, "ratified": true,
"register_id": "mathematical_v1", "register_id": "mathematical_v1",
"report_sha256": "04e9a09cce4e599781b2d4994383cebf4f6529391f58005a84e69363494508c2", "report_sha256": "b85e2505fe647aa474b599cfa447c3677ad92c7c305d34ae63c97c8b5ba82fb6",
"schema_version": "1.0.0" "schema_version": "1.0.0"
} }

View file

@ -266,6 +266,64 @@ def _validate_per_intent_block(
) )
_BARE_SENTENCE_FINAL_PUNCT: frozenset[str] = frozenset(".!?;:")
"""Closing entries beginning with one of these characters concatenate
directly onto a surface that already ends in ``.`` (CORE's deterministic
realizer always emits a trailing period) and produce double-punctuation
artefacts like ``true..``. Ellipsis (``...`` / ````) is exempt that
is a legitimate stylistic ending in its own right.
"""
def _validate_discourse_markers_shape(pack: dict, register_id: str) -> None:
"""Reject discourse-marker shapes that would produce surface
artefacts when concatenated to a sentence-final surface.
Catches the class of authoring bug discovered during the 100-pack
widened tour: a bare ``"."`` closing yields ``..`` when seeded
variation picks it. Defense in depth pack authors should not
have to remember the realizer's trailing-period convention.
Rules (closings only openings always lead the surface with a
space separator inserted by the composer):
* ``""`` is always legal (no-op closing)
* Entries starting with bare ``.``, ``!``, ``?``, ``;``, ``:``
are refused they double-punctuate. Ellipsis (``"..."`` /
``""``) is exempt and remains legal.
* Entries starting with an alphanumeric character are refused
they would join with no separator, e.g. ``"true.holds."``.
"""
markers = pack.get("discourse_markers", {})
if not isinstance(markers, dict):
return # shape-only — schema validator owns dict-vs-not
closings = markers.get("closings", [])
if not isinstance(closings, list):
return
for entry in closings:
if not isinstance(entry, str) or entry == "":
continue
first = entry[0]
if entry.startswith(("...", "")):
continue
if first in _BARE_SENTENCE_FINAL_PUNCT:
raise SystemExit(
f"R4 gate refuses {register_id!r}: discourse_markers."
f"closings[{entry!r}] starts with bare sentence-final "
f"punctuation. CORE's realizer always emits a trailing "
f"'.', so {entry!r} concatenates to '..'-style "
f"artefacts. Either drop the entry or prefix it with a "
f"separator (e.g. ' — note.')."
)
if first.isalnum():
raise SystemExit(
f"R4 gate refuses {register_id!r}: discourse_markers."
f"closings[{entry!r}] starts with an alphanumeric "
f"character. Closings concatenate directly to the "
f"surface — prefix with a space or punctuation "
f"separator (e.g. ' note.' or ' — note.')."
)
def _markers_have_content(pack: dict) -> bool: def _markers_have_content(pack: dict) -> bool:
"""True iff openings or closings has at least one entry (R4 needs """True iff openings or closings has at least one entry (R4 needs
one of these populated for a marker-using ratification). one of these populated for a marker-using ratification).
@ -301,6 +359,7 @@ def _ratify_one(pack_path: Path, register_id: str) -> tuple[dict, dict[str, Any]
# must have at least one of openings/closings populated. Null # must have at least one of openings/closings populated. Null
# registers pass trivially. # registers pass trivially.
_validate_overrides_known_keys(pack, register_id) _validate_overrides_known_keys(pack, register_id)
_validate_discourse_markers_shape(pack, register_id)
null_register = _is_null_register(pack) null_register = _is_null_register(pack)
overrides = pack.get("realizer_overrides", {}) or {} overrides = pack.get("realizer_overrides", {}) or {}