Skip to content

Commit d526f28

Browse files
5000Stadiaclaude
andcommitted
INGESTION-FIDELITY-V2: the standing-property contract
Evidence-gated on Construct's emberroad2 rebuild (16 of 81 unstamped_timed rows were standing personal properties authored timed-but-unstamped; bin-B re-ask table). Spec GREEN Cx r3; implementation GREEN after one RED round (containment-only rider gate, docs conflation excised, Oracle 6 as written). Two orthogonal contracts, never conflated: valid time (timeless = true across the world's WHOLE history; absence of a narrated onset never licenses backward-forever projection) and durability (a standing class may coexist with valid_from). Each defect row exits the audit bin by its own contract - age by STAMPING (mutable, time-relative, stays STATE), kinship of origin by CLASS (declared structural -> deterministic CONSTITUTIVE), acquired standing facts by CLASS with valid time at the earliest supported point. - ingest.py: both extract TIME clauses rewritten (whole-history rule, facts-of-origin bucket, dated-onset exception, earliest-supported stamp, age-never-timeless); merged_self_edge receipt reason - a containment edge whose raw ids differ but resolve to one identity head post-same_as receipts distinctly with both raw ids retained (merge footprint vs authored bug); containment-only, merged lateral loops keep the original reason. - classify.py: the enduring-baseline preference line (prefer CONSTITUTIVE/ DISPOSITIONAL over STATE for traits/capabilities/continuing roles; temporary or time-relative stays STATE); EVENT safety, asymmetric defaults, review floor untouched. - No engine kinship vocabulary: the child->parent attribute_default recipe (father/mother structural) ships in PLAYBOOK + ADOPTION; father_of stays a separate opt-in inverse, never a canonicalization target. - Audit bin: zero code change (the STATE/EVENT-only contract already existed); regression pins strengthened (DISPOSITIONAL exits, STATE stays, stamped rows never enter). - tests/test_ingestion_fidelity_v2.py: 11 oracles incl. the scripted per-row battery and the lateral-boundary pin. - Background-homonym coreference contract: parked forever with cause (4 residual fixture groups, all unvouched, none load-bearing, replay-proved harmless). - evals/corpora/: emberroad2 fixture provenance (binary gitignored). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 34dd028 commit d526f28

10 files changed

Lines changed: 602 additions & 11 deletions

File tree

‎.gitignore‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,4 @@ evals/results/**/*.world
1313
evals/results/**/staging/
1414
dist/
1515
build/
16+
evals/corpora/*.world*

‎docs/ADOPTION.md‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,14 @@ p.fidelity_audit(frame="canon", as_of=None) -> {name_collisions, unstamped_timed
339339
# repair by it: reject() genuine homonyms (harth person<->place), adjudicate_deferred/retype
340340
# true same-kind splits. summary.name_collisions counts LIVE groups only (the tracked number).
341341
# unstamped_timed = classified STATE/EVENT rows with no valid_from (off the time spine).
342+
# Rows the sidecar judges CONSTITUTIVE/DISPOSITIONAL sit OUTSIDE this STATE/EVENT-only
343+
# bin; their valid-time correctness is a separate extraction contract (acquired standing
344+
# facts — occupation, scars, learned skills — still carry valid_from at the earliest
345+
# supported point; durability never licenses backward-forever projection).
346+
# Kinship-of-origin recipe (INGESTION-FIDELITY-V2): declare child->parent vocabulary
347+
# structural (attribute_default returning {"structural": True} for "father"/"mother")
348+
# -> deterministic CONSTITUTIVE, no model call; father_of (inverse) is a separate
349+
# opt-in attribute, never a canonicalization of father.
342350
# orphan_entities = unanchored obj:/person:. open_conflicts = the truth-maintenance flags.
343351
# The engine SURFACES gaps keyed by entity; the HOST joins arc/cast severity and drives
344352
# targeted re-extraction of the flagged spans (membrane: engine never repairs).

‎docs/INGESTION-PLAYBOOK.md‎

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,25 @@ do. The load-bearing instructions, in order of damage when absent:
4343
knowledge transfer, causality) and say "every one the text describes."
4444
With the equally explicit negative: never an edge the text doesn't
4545
support — proximity is not connectivity.
46-
5. **Scope `timeless` to a whitelist.** *(Run-1 failure, minor.)* "timeless
47-
= permanent facts" produced timeless STATE rows (a dead man's status, a
48-
meter's location). Whitelist instead: identity and structure only (kind,
49-
names, fixed adjacency); everything that holds-at-a-time gets stamped.
46+
5. **Scope `timeless` to a whitelist.** *(Run-1 failure, minor; widened by
47+
INGESTION-FIDELITY-V2.)* "timeless = permanent facts" produced timeless
48+
STATE rows (a dead man's status, a meter's location). Whitelist instead:
49+
what holds across the world's **whole history** — identity/structure
50+
(kind, names, fixed adjacency) and facts of origin (kinship of origin,
51+
innate traits). Everything acquired or mutable gets `valid_from`: the
52+
dated onset if the text gives one, else the **earliest supported point**
53+
(the entity's introduction / the scene cursor). Time-relative quantities
54+
(age) are cursor-stamped state, never timeless; standing-but-acquired
55+
properties (occupation, scars, learned skills) are stamped at their
56+
earliest supported time — their *durability* is the classifier's to
57+
judge (standing class ≠ timeless valid time; the two are orthogonal).
58+
**Kinship-of-origin recipe:** declare your canonical child→parent
59+
vocabulary structural at construction —
60+
`attribute_default=lambda a: {"structural": True} if a in ("father",
61+
"mother") else None` — and those rows classify CONSTITUTIVE
62+
deterministically (no model call). The inverse `father_of`/`mother_of`
63+
(subject IS father of value) is a separate attribute you declare only if
64+
you accept that form; it is never a canonicalization of `father`.
5065
6. **The never-invent floor and the texture negative hold well.** *(Run-1
5166
success.)* "Extract only what the text supports; atmosphere is not an
5267
assertion" produced zero phantom contents in two sealed containers and

‎docs/LEXICON.md‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,11 @@ The working vocabulary for pattern-buffer. One name per concept, used identicall
4747
| **`typing_conflicts()`** | Read-only surfacing of typing-slip candidates (SHAPE-FIX-V1): same-anchor cross-kind pairs carrying the **slip signature** (an outgoing-bare spurious twin beside a structurally real entity). `reconcile()` never re-proposes hard-blocked pairs, so without this read the slips are invisible; the host adjudicates each with `retype()`. | Plain. |
4848
| **durable-contradiction veto** | The kind-check generalized to every standing fact (SHAPE-FIX-V1): two entities whose shared, present, **durable** (CONSTITUTIVE/DISPOSITIONAL) attributes hold contradictory folded values are probably two things — auto-merge soft-declines to a proposal (a retrieval lead and a defense apprentice don't fuse on a shared first name). STATE differences (mood, position) never trigger it. Surfaces as decline code `durable_contradiction`. | Plain. |
4949
| **malformed-id gate / phantom suppression** | The ingest defenses (SHAPE-FIX-V1) that kill non-diegetic entities at the source: an id violating the grammar (`person:/you`) is **skipped** with a typed `malformed_id` receipt, never normalized (that would manufacture the phantom well-formed); the extractor suppresses narrative-voice entities (the narrator is not a person); and **`pov`** (a validated viewpoint entity id) binds the full scoped deictic family (singular I/me/my/mine/myself + addressed you/your/yours exclusively; plural we/us/our/ours inclusively, never exclusive ownership) to the protagonist instead of minting a new person. Runs after the authority gate, so a violation still raises. | Plain. |
50+
| **`merged_self_edge`** | The skip-receipt reason distinguishing a MERGE footprint from an authored bug (INGESTION-FIDELITY-V2 §D): a containment edge whose raw subject and value differ but resolve to one identity head post-`same_as` receipts `merged_self_edge` (both raw ids retained — actionable diagnosis); an authored self-edge keeps the original cycle reason. Gate behavior identical — the row never enters. | Plain. |
5051
| **`entities()` / `facts()`** | The two **frame-bounded** roster/scan reads (BOUNDED-READS-V1). `entities(frame, prefix=)` lists the entity ids a frame carries; `facts(frame, …)` returns that frame's visible rows as `Fact` dicts for **audited scans** (receipt trails, knowledge digests), never folds. `frame` is **required** on both — a prefix-only enumeration would leak cross-frame entity existence (the §6 absence discipline applied to enumeration). | Plain. |
5152
| **build session** | The porcelain build lifecycle (BUILD-SESSION-V1): `begin_build(at=)` enters defer-classification mode, `seal_build(scope=)` runs one classification pass at the end (`"session"` rows or `"all"` log), `abort_build()`/`World.close()` restore the toggle and classify nothing. `with p.build():` is the context-manager sugar. A host-workflow concept living on the porcelain — the engine's classifier stays ignorant of it. | Plain (build/seal a scenario). |
5253
| **`axis_heads()`** | The log's two-axis high-water mark (AXIS-HEAD-V1): `asserted_head` (the seq head) and `valid_head` (`MAX(valid_from)` over **all** rows, all frames — the entry-epoch read). A coordinate scalar, never content: no entity/attribute/value/frame crosses (distinct from `horizon`, the play/read cutoff). | Plain. |
53-
| **`fidelity_audit()` / `name_collisions`** | The structural ingestion-fidelity read (INGESTION-FIDELITY-V1): derives where a freshly-built log is incomplete — **`name_collisions`** (distinct ids sharing a name/alias, each pair annotated `correlated`/`hard_blocked`/`typing_slip`/`auto_declined`/`unlinked` — the coreference-fragmentation metric, the tracked number driven down), `unstamped_timed` (classified STATE/EVENT off the time spine), `orphan_entities` (unanchored `obj:`/`person:`), `open_conflicts`. Composes the shipped identity per-pair predicates over a frame/as-of-scoped candidate set; membrane-clean (derive-don't-store, zero writes). The engine **surfaces** gaps; the host joins arc/cast **severity** (host meaning, never engine) and drives targeted re-extraction. | Plain (a build/QA audit). |
54+
| **`fidelity_audit()` / `name_collisions`** | The structural ingestion-fidelity read (INGESTION-FIDELITY-V1): derives where a freshly-built log is incomplete — **`name_collisions`** (distinct ids sharing a name/alias, each pair annotated `correlated`/`hard_blocked`/`typing_slip`/`auto_declined`/`unlinked` — the coreference-fragmentation metric, the tracked number driven down), `unstamped_timed` (classified STATE/EVENT off the time spine — rows the sidecar judges CONSTITUTIVE/DISPOSITIONAL sit outside this STATE/EVENT-only bin; their valid-time correctness is a separate extraction contract — acquired standing facts still carry `valid_from`; INGESTION-FIDELITY-V2), `orphan_entities` (unanchored `obj:`/`person:`), `open_conflicts`. Composes the shipped identity per-pair predicates over a frame/as-of-scoped candidate set; membrane-clean (derive-don't-store, zero writes). The engine **surfaces** gaps; the host joins arc/cast **severity** (host meaning, never engine) and drives targeted re-extraction. | Plain (a build/QA audit). |
5455
| **porcelain** | The frozen, typed, JSON-serializable host contract (`porcelain-v0.1`; `world.porcelain`) — the verb set a host integrates against, **additive-only** from the tag (params gain defaults, verbs are added; nothing renamed/removed/re-typed). The operation algebra (§12) is the engine's internal surface; the porcelain is the public one. A reach below it signals a missing verb, not a missing capability. | Plain (plumbing vs. porcelain — the exposed fixtures over the internal pipes). |
5556
| **`Scene cursor`** | The ingest-time "where is the narrated action happening" pose. The largest single precision multiplier in ingestion. | Heritage: lidar pose estimation, not Trek. |
5657
| **`arch`** | The operator's inspection CLI: dump the buffer, query as-of, audit provenance — without touching the world. | Trek: "Computer, arch!" — the operator's control interface inside the simulation. Allowed in code as a tool nickname, not an API symbol. |

‎evals/corpora/README.md‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# evals/corpora — external world fixtures (binaries not committed)
2+
3+
- **emberroad2.world** (+ `emberroad2.meta.json`) — Construct's 2026-07-10
4+
emberroad rebuild through the current pipeline (live fidelity seal,
5+
frame-partitioned gates, deixis family). `world_id = w:emberroad2`.
6+
Source of truth: `/home/k/Newproject/worlds/`; regenerate on the Construct
7+
side (HD owns the build). Reference audit at copy time:
8+
`name_collisions: 4 (27 total), unstamped_timed: 81, orphan_entities: 24,
9+
open_conflicts: 0` — the INGESTION-FIDELITY-V2 ruling's evidence base
10+
(feeder letter `<57c75397-7675-497b-9608-7d91e4375c05@agentpost.local>`).

‎evals/corpora/emberroad2.meta.json‎

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
{
2+
"title": "The Ember That Burned Cold",
3+
"protagonist": "person:brother_caldus",
4+
"theme": "True inheritance is not the crown you can claim, but the burden you choose to carry and lay down for the living.",
5+
"stance": "fiction",
6+
"mode": "pure",
7+
"style": "Grim northern medieval folk-fantasy in a mountain borderland: spare, ash-cold, road-worn prose with monkish dread, hearthside superstition, iron-and-snow imagery, and the solemn cadence of an old tale being whispered beside dying embers.",
8+
"scenario_mode": "win_loss",
9+
"arc_scope": [
10+
"person:brother_caldus",
11+
"person:caldus",
12+
"person:lysa"
13+
],
14+
"main_arc": "arc:main",
15+
"arc_ids": [
16+
"arc:main"
17+
],
18+
"entry_epoch": 1001000.0,
19+
"seeded_frames": [
20+
"person:brother_caldus",
21+
"person:caldus",
22+
"person:elian",
23+
"person:horned_figure",
24+
"person:lysa"
25+
],
26+
"endless": false,
27+
"opening_as_of": 1001000.0,
28+
"next_source_as_of": 2000000.0,
29+
"source_step": 1000000.0,
30+
"goal_statement": "See your story through to its end.",
31+
"intro": "In the northern border mountains, where snow closes the passes and old saints are carved into roadside stones, you are the one left carrying a crown no living head should wear. A dying monk of Saint Orven\u2019s Step has put the east road before you, and every hearth, shrine, and black pine hollow remembers that some inheritances bite deeper than iron. What waits in these heights is not only a claim of blood, but the weight of what you choose to bear for the living, and what you must one day lay down.",
32+
"genre": "gothic fantasy pilgrimage",
33+
"premise": "After Saint Orven\u2019s Step has been reduced to \u201cwhat remains of it,\u201d Brother Caldus, a monk marked by a wooden sun-disc, charges a traveler to carry a crown east by the old pilgrim path. The path is an inherited religious duty: it gives people guides, rules, and sacred signs, but it also forbids anyone from wearing the crown and turns inheritance into a burden that must be carried for the living.",
34+
"game_type": [
35+
"political_intrigue",
36+
"social_drama_relationship_web"
37+
],
38+
"death_policy": "mortal",
39+
"death_policy_reason": "a gothic fantasy pilgrimage with political intrigue still centers a dangerous quest rather than a death-shielded social genre"
40+
}

0 commit comments

Comments
 (0)