Skip to content

design: world-time flows from the claim's window (D107) - #362

Closed
fazpu wants to merge 7 commits into
mainfrom
design/temporal-clocks
Closed

design: world-time flows from the claim's window (D107)#362
fazpu wants to merge 7 commits into
mainfrom
design/temporal-clocks

Conversation

@fazpu

@fazpu fazpu commented Sep 3, 2026

Copy link
Copy Markdown
Member

Problem

D106 fixed one instance of a pattern: a stage that has the claim's resolved D41 window available and reasons on the source's date instead. The follow-up audit at 02b79904 found sixteen more, across every plane. The consequential ones: relations' valid_from is never seeded (so valid_at / facts_as_of is a no-op on the relation side, against what /docs/concepts promises); the relation supersession prompt asks the model about "the same period" while showing only document dates; undated supersessions cap at now() (a rebuild on another day yields a different history — breaks D7); the two adjudicators orient undated testimony in opposite directions; testimony_context dedupes identical wording across dates exactly as the adjudicator did before D106; the K fact sheet prints the chat date under "valid since"; aggregate(form="timeline") buckets by ingest year; the answer agent is told to "use timestamps" without being told which; and day-precision windows are zero-width points that intraday as-of queries miss.

What this PR decides (documentation only — no code)

D107 — world-time flows from the claim's window; said-on time is provenance, never validity. One contract instead of seventeen patches:

  • three named clocks (said-on asserted_at; is-about the D41 window; believed ingested_at) and two rules: world-time comes from the is-about window; a missing time stays missing — never now(), and undated never wins an ordering;
  • fact windows seeded by claim kind with a new validity_basis column (world_time / said_on / unknown), widened only earlier by evidence, closed at the successor's is-about start → else said-on as an honest upper bound → else coexist with a recorded reason;
  • one shared ordering comparator for relation supersession, observation staging, and the D90 re-split;
  • the D106 two-clock prompt block (said on / is about, defined) in every temporal prompt: relation supersession, T4 candidates, K writer, answer agent;
  • retrieval dedupe keys include the window; P1 gains is-about filters; timeline by world-time with an undated bucket; profiles rank by window recency, never updated_at;
  • extraction: all four D41 kinds and open taught with examples; half-open precision-derived ends; full-timestamp header; the observation statement carries its resolved date (claim text stays source-faithful, D32);
  • consumer surfaces print a date under a world-time heading only for world_time rows.

The design is written against D41's own boundary: claim windows seed fact windows; the fact window remains the adjudicator's single, monotonic verdict — never a reduction over claim columns.

Files

  • plan/analysis/time_handling_audit.md — the seventeen findings with file:line evidence, six patterns, and a checked-and-sound list.
  • plan/designs/temporal_clocks_design.md — the binding design (clocks, extraction, fact windows, adjudication/retrieval, consumer labels, generations/rebuild/protocol, alternatives, non-goals).
  • decisions.md — D107.
  • plan/plans/temporal_clocks.md — five work packages (WP-T.1 fact windows and closing → T.2 two-clock prompts → T.3 retrieval keys/envelopes → T.4 extraction precision/vocabulary → T.5 consumer labels), each with the findings it closes, generations rolled, and acceptance criteria.
  • Amendment banners on e2_e3_claims_relations_design.md, observations_design.md, registries_design.md, retrieval_design.md, k_layers_design.md, locomo_benchmark_design.md.

What it does not do

No code, schema, generation, or protocol changes; those land per work package with the same-PR docs the CLAUDE.md rule requires. Recurrence and anchor-relative time remain outside the single-interval model (D41).

Contributor agreement

Review

A Codex (gpt-5.6-sol, xhigh) design review will be posted as a comment with a triage.

🤖 Generated with Claude Code

https://claude.ai/code/session_016p9xB9T7VYREuVmohDPKjR

fazpu and others added 2 commits September 3, 2026 14:28
D106 fixed the observation adjudicator reading the wrong clock; the
follow-up audit at 02b7990 found the same confusion in sixteen more
places: relations' valid_from is never seeded (valid_at is a no-op on the
relation side), the relation supersession prompt judges "the same period"
without seeing one, undated supersessions cap at now() (histories depend on
ingest wall-clock), the two adjudicators orient undated testimony in
opposite directions, retrieval dedupes identical text across dates, the K
fact sheet prints chat dates under "valid since", the timeline aggregate
buckets by ingest year, and day-precision windows are zero-width points.

Record the audit (plan/analysis/time_handling_audit.md), decide one contract
(D107 + plan/designs/temporal_clocks_design.md): every stage reads the
claim's resolved D41 window first; said-on time is provenance and at most an
upper bound; a missing time stays missing. Fact windows are seeded by kind
with a validity_basis column, widen only earlier, close at the successor's
world-time start else said-on else coexist; one shared ordering comparator;
the D106 two-clock block in every temporal prompt; window-aware dedupe;
half-open precision ends; all four D41 kinds taught. Sequence it in
plan/plans/temporal_clocks.md and banner the six affected designs.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016p9xB9T7VYREuVmohDPKjR
…nly (D107 review)

Codex's review of the first revision found four mechanisms that contradict
decisions this design must live inside: seeding valid_from from the said-on
date (provenance is not validity), seeding a measurement's end from its
claim (D43 never caps a fixed-period figure), widening the verdict start on
evidence (a reduction over claim columns, D41), and half-open storage
(empties `instant`), plus a merged ordering key that conflated D90's total
processing order with temporal succession.

Replace them: a fact carries an adjudicated verdict window (seeded once by
kind, per-endpoint bases, changed only by recorded verdicts — cap,
extend_start, date_undated, D55) and a derived, non-authoritative occurrence
window that widens with evidence; measurements and events are believed from
their occurrence start and never capped; interval-aware evidence-target
matching for bounded slices under the GiST EXCLUDE; temporal succession
separate from D90 order, requiring world-time starts, else coexist;
precision honoured at comparison time with storage unchanged; statements
canonical and dated labels derived; the full D41 tuple in dedupe keys; the
envelope/operation/protocol roll enumerated. Narrow five audit findings to
what the code shows and add the consumption skill's wrong claims_as_of
definition as 4.18.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016p9xB9T7VYREuVmohDPKjR
@fazpu

fazpu commented Sep 3, 2026

Copy link
Copy Markdown
Member Author

Independent review — round 1 — Codex (gpt-5.6-sol, reasoning xhigh, review-only run against the first revision)

Findings

  1. Blocker — plan/designs/temporal_clocks_design.md §2 and §4.1: said-on is still being used as world-time.

    The design says said-on is “never validity by itself” and that missing is-about time stays missing, but the seeding table assigns valid_from = claims.asserted_at when the claim has no validity window. asserted_at is commonly source_modified_at or published_at (workers/e2.py:599); it is not evidence that the described state began then. Fact filtering interprets valid_from as actual world-time (p9_01_0022_memory_v1_query_space.py:1169-1172, query_engine.py:3696-3734).

    Suggested fix: for unknown is-about time, leave both fact endpoints NULL. Preserve said-on separately as provenance or endpoint-bound metadata; do not overload valid_from.

  2. Blocker — §4.1 contradicts D43’s measurement semantics.

    The table seeds measurement facts with valid_until = claim_valid_until. D43 explicitly says a measurement/fixed-period figure is never capped and “stays open” (decisions.md:1145-1152); the schema repeats that contract (p0_02_0004_claims_observations.py:286-297). A finite end would also remove the fact from facts_current and current profile selection.

    Event semantics are similarly unresolved: a past event’s occurrence window can be finite while the believed historical fact remains current. The design currently treats event, measurement, effective, and proposition windows identically despite calling the policy “by kind.”

    Suggested fix: define separate occurrence/reporting windows and fact-verdict windows. Keep measurement facts open per D43, and explicitly specify whether past events remain current believed facts and how current/profile retrieval treats them.

  3. Blocker — §4.2 violates D41’s single recorded verdict rule.

    “Evidence collapse moves the fact start earlier” is an incremental reduction over claim windows. D41 says the recorded fact window is “never a reduction over claim columns” and is “never reopened by a late-arriving retrospective” (decisions.md:1031-1035). Calling an earlier start monotonic does not resolve that conflict: it still expands an already adjudicated verdict based on later evidence.

    Suggested fix: let the triggering claim seed the verdict once. Later matching evidence should attach without mechanically altering it. Any revision must be an explicit adjudicator verdict with a recorded rationale and D41-compatible retrospective guard; disjoint historical intervals should coexist as distinct slices.

  4. Blocker — §§4.1–4.3 do not redesign matching for bounded historical facts.

    Current relation lookup only considers non-invalidated facts whose end is NULL or later than now() (fact_catalog.py:511-520). Observation exact collapse likewise considers only open candidates (observation_adjudication.py:332-337). Once D107 seeds a fact with a past finite interval, corroborating evidence will not find it: relations can collide with the overlap exclusion constraint (p0_02_0004_claims_observations.py:200-204), while observations can duplicate it.

    The inherited reoccurrence rule is also unsafe for late retrospective data: it uses the maximum previous closed end (fact_catalog.py:867-876), which can push a newly discovered older spell past its own end.

    Suggested fix: specify an interval-aware evidence-target algorithm: overlapping interval attaches without rewriting the verdict; proven disjoint interval creates a distinct slice; unknown timing fails safe. Apply the reoccurrence floor only to a proven chronological successor, not every closed fact.

  5. Blocker — §3’s universal half-open model cannot represent the existing instant kind.

    The database requires an instant to have claim_valid_until = claim_valid_from (p0_02_0004_claims_observations.py:64). Under [from, until), that interval is empty. Current query-space code deliberately uses inclusive ends so equal endpoints remain queryable (p9_01_0022_memory_v1_query_space.py:456), and the D106 disjointness implementation uses closed-interval comparisons (observation_adjudication.py:1410-1424).

    Suggested fix: define a non-empty representation for instants—such as explicit point semantics in overlap predicates—then enumerate every affected query, constraint, exclusion rule, and D106 comparison. Extraction and re-extraction must precede fact reseeding, or the reseed must be repeated after conversion; T4 cannot safely remain independent of T1.

  6. Major — §4.4 conflates deterministic ingest order with temporal succession and is incompatible with D90.

    The proposed key coalesces is-about start and said-on into one scalar, yet also says a world-undated claim is neither predecessor nor successor. For a world-dated 2019 claim and an undated claim said in 2024, the key orders the latter after the former while the rule says it cannot be a successor. That is not a total comparator. D90 requires the exact deterministic total order (asserted_at NULLS LAST, claim_id, statement) and the observation re-split depends on it (decisions.md:3788-3811; observation_adjudication.py:1042-1073).

    Suggested fix: retain a D90-compatible total processing order, and define a separate semantic successor relation for capping. Specify interval ties, overlaps, basis precedence, and missing-world-time behavior explicitly.

  7. Major — §4.3’s said-on fallback is not a generally valid supersession boundary.

    The design claims that by the time a source said the new state held, the old state had ended. That is false for retrospective or undated statements: publication/modification time does not establish contemporaneous validity. It also conflicts with measurement coexistence and with open propositions that lack a resolved start.

    Suggested fix: cap ordinary supersession only at a resolved is-about boundary or an explicit adjudicator conclusion that the statement is contemporaneous. Otherwise coexist. Keep D55’s source-removal boundary separate—it is a source action, not a general temporal inference. Also document the storage/ranking consequences of an unbounded stream of undated coexisting values; the current “at most a duplicate” statement is unsupported.

  8. Major — one validity_basis value cannot describe mixed endpoint provenance.

    A fact can begin at a world-time boundary and later be capped at a said-on upper bound. One row-level enum cannot honestly label both. The design also calls the column nullable while providing unknown, leaving an unexplained fourth state.

    Suggested fix: record provenance per endpoint, such as valid_from_basis and valid_until_basis, or use structured boundary provenance tied to the adjudication. Make the unknown representation unambiguous and specify transitions when an explicit verdict changes a boundary.

  9. Major — §4.5 makes observation identity evidence-dependent and order-dependent.

    The proposed canonical statement includes both a resolved date and the original relative phrase, for example on 2022-09-29 (said 'last week'). D43 treats statement as canonical natural-language identity, and the observations design says it never changes during supersession. Current evidence collapse preserves the first statement (observation_adjudication.py:381-402, 572-600). Two overlapping claims with different precision or wording can collapse into one fact while retaining whichever source-specific date/phrase arrived first.

    Suggested fix: keep the original phrase on the claim. Generate any human-facing dated label deterministically from the adjudicated fact window and precision, with defined refresh semantics, or explicitly amend D43 to define canonical-statement merging.

  10. Major — §5.3 and §7 understate the envelope and protocol migration.

Adding basis only to Validity does not make every consumer able to distinguish it. GraphEdge has flat validity fields without basis (model/envelope.py:378-393); K-layer input has its own fact model (model/knowledge.py:479-494); the memory-v1 views use explicit column lists. Moreover, Validity participates in the shared generated envelope schema used by assured operations (spine/assured_operations.py:204-209). The open-query design requires changed fields or selection semantics to increment the affected operation version.

Suggested fix: enumerate all read models, views, graph results, K-layer loaders, generated SDK/OpenAPI artifacts, operation versions, manifest fingerprints, and protocol fingerprints. Resolve the contradiction between §7’s single whole-change LoCoMo roll and T2/T3/T4 each claiming a protocol consequence.

  1. Major — §5.2’s dedupe key still loses load-bearing temporal distinctions.

(normalized text, kind, from, until) omits claim_valid_precision, even though D41 treats precision as an honesty marker. For unknown windows it falls back to text alone, preserving the current failure mode where grouping retains one representative row and only the other claim IDs (query_engine.py:3388-3404). Distinct assertions made at different times can therefore be collapsed before the model sees their said-on clocks.

Suggested fix: include the complete D41 window tuple, including precision. For missing is-about time, either include asserted-at/source identity or keep claims separate; alternatively, make grouped results preserve every member’s temporal metadata.

  1. Major — several audit findings need correction before they can serve as D107’s rationale.
  • Finding 4.2 calls valid_at a no-op and says it returns the current employer. Relation lookup does filter valid_until > as_of (query_engine.py:3696-3697); the actual defect is that missing/incorrect starts cannot exclude facts before their true beginning, so current and historical facts may both appear.
  • Finding 4.6 says a relation’s only surviving timestamp is ingested_at, but fact_context includes representative evidence with asserted_at and claim windows (query_engine.py:778-867). This is true only of the direct relation result itself.
  • Finding 4.12 overlooks the existing P1 FactTime selector (adapters/postgres_p1.py:1449-1492). Claim search lacks equivalent is-about filtering, but fact search is not wholly time-blind.
  • Finding 4.13 says touching windows are treated as non-overlapping; _windows_disjoint uses strict <, so equal endpoints currently count as overlapping.
  • Finding 4.14’s “point or not at all” result is speculative. The supported kinds are exposed structurally, but the prompt does not teach their semantics.

Suggested fix: narrow these claims to the behavior directly established by the cited code and update D107’s context accordingly. Clarify whether §5.4 extends the existing P1 time selector or introduces a distinct filter vocabulary with explicit overlap/unknown semantics.

  1. Major — the audit and implementation plan omit the public consumption skill’s incorrect clock contract.

core/consumption_skill.py:191-194 describes claims_as_of as what sources asserted by a past system time, while D41 defines it over source world-time. The skill teaches fact validity versus ingestion but not the said-on/is-about distinction (:202-210). Under D60, that skill is part of the complete agent-facing library surface.

Suggested fix: add this defect to the audit and add a work-package acceptance item to update and regenerate the consumption skill with the three-clock model, the corrected claims_as_of definition, and basis-aware rendering.

  1. Minor — the corpus contains contradictory amendment and sequencing language.

The observations banner says evidence can widen only to is-about time and “never to said-on time,” while central §4.2 permits said-on widening. The LoCoMo banner says the protocol rolls “when implemented,” and §6 says “Until the fact layer is re-seeded”; both put transition/deferral language inside design documents contrary to CLAUDE.md Rule 2. The LoCoMo banner says merely “Accepted,” while the other banners identify D107 as binding. T4 is called independent in the plan despite T1 depending on converted claim endpoints. D107’s references to “D43 §3/§4” do not identify actual sections in decisions.md.

Suggested fix: make every banner match the binding rule, move rollout wording into plan/plans/temporal_clocks.md, express the real package dependency, and replace ambiguous D43 references with exact decision/design anchors.

Verified

  • Audit 4.1 holds: exact-text answer/testimony grouping keys only by normalized text and exposes one representative member, losing differing temporal metadata.
  • Audit 4.2’s core schema observation holds: first relation insertion does not seed valid_from from the claim window.
  • Audit 4.3 holds: the relation-supersession prompt receives labels, evidence, and asserted-at timestamps, but not the D41 validity interval.
  • Audit 4.4 holds: relation supersession, observation supersession, and lifecycle capping all silently fall back to database now().
  • Audit 4.5 holds: E3 is not shown claim windows, while E2 forbids embedding dates in claim text; observation labels/statements therefore lack a reliable resolved date.
  • Audit 4.6’s core prompt ambiguity holds: the benchmark prompt says to use timestamps without distinguishing said-on, is-about, and believed time.
  • Audit 4.7 holds: knowledge fact-sheet ordering uses valid_from, but the rendered rows do not show the corresponding time.
  • Audit 4.8 holds: K-writer claim inputs contain no asserted-at or validity-window fields.
  • Audit 4.9 holds: timeline ordering coalesces valid_from with ingested_at, mixing world-time and belief-time.
  • Audit 4.10 and 4.11 hold: current adjudication ordering is asserted-at based, and successor selection disagrees on missing-time treatment.
  • Audit 4.15–4.17 hold: temporal headers lose time-of-day, profiles omit fact windows while ranking by update time, and retrospective widening currently exists only inside one adjudication pass.
  • The audit’s checked-and-sound claims hold for E2 parsing/validation, D106’s open-end and fail-safe overlap behavior, D41 fields in evidence envelopes, believed-time plumbing, query-space exposure of claim validity, D55’s shape discipline, and adjudication transcripts.
  • The three-clock taxonomy itself is compatible with D41, D49, and D106. Adding non-authoritative boundary-provenance metadata is also compatible with D41 if it cannot independently mutate the verdict.
  • No D60/D61 library-boundary violation was found; the proposal remains provider-neutral and inside the public engine surface.

Merge verdict: not mergeable as written. The first required change is to reconcile the fact-window model with D41, D43, and the missing-time rule: remove said-on seeding as valid_from, preserve measurement/event semantics, and replace mechanical evidence widening with an explicit single-verdict adjudication model. The half-open instant representation and bounded-history matching algorithm must then be specified before the rollout and protocol plan can be considered implementable.

@fazpu

fazpu commented Sep 3, 2026

Copy link
Copy Markdown
Member Author

Review triage — round 1 (Codex), dispositions applied in 5065ef7

Codex's verdict on the first revision was "not mergeable as written", and it was right on the substance: four mechanisms in the first cut contradicted decisions this design must live inside. The revision replaces them rather than patching wording. Every finding was re-read against the cited code before acting.

# Finding (Codex) Verified Disposition
1 Seeding valid_from from the said-on date writes provenance into a world-time column and contradicts the design's own Rule 2 Yes Fixed (design change). Unknown window → NULL/unknown; said-on is never a boundary. validity_basis no longer has a said_on value.
2 Seeding a measurement's valid_until from its claim contradicts D43's no-cap rule; events treated like states Yes — schema comment and D43 Fixed (design change). A fact now carries two windows: the adjudicated verdict window (measurements and events believed from their occurrence start onward, never capped) and a derived, non-authoritative occurrence window (the claim's period / event day). §3 explains why two.
3 Mechanical "widen earlier on evidence" is a reduction over claim columns (D41) Yes Fixed. Evidence attachment never changes a verdict; the occurrence window (non-authoritative) widens. A state's start moves earlier only by a recorded, deterministic extend_start verdict with rationale and the retrospective guard (§4.3).
4 Bounded historical slices can't be found by the open-only evidence-target lookup; EXCLUDE collisions; reoccurrence floor unsafe for late-discovered older spells Yes — _SELECT_RELATION open-only; GiST EXCLUDE on (key, tstzrange) Fixed. §4.2 specifies interval-aware matching: overlapping → attach; disjoint → new slice; unknown-timing → single open slice else most recent, never a second unbounded slice; the reoccurrence floor applies only to a proven chronological successor.
5 Universal half-open storage empties instant (until = from by CHECK) and breaks the closed-interval comparisons Yes — CHECK at p0_02_0004_claims_facts_evidence.py:64 Fixed (design change). Storage and CHECKs unchanged; one comparison-time overlap function derives precision-aware effective ends (day → whole day; instant a point; open +∞). No migration, no re-extraction; T.4 stays independent (§5, WP-T.0).
6 The coalesced ordering key conflated D90's total processing order with temporal succession and was not a total comparator Yes — D90 §5.5 / _is_later_in_total_order Fixed. D90's processing order is unchanged; temporal succession is a separate relation requiring world_time starts on both sides (§4.4).
7 Said-on as a cap upper bound is invalid for retrospectives/undated statements; "at most a duplicate" unsupported Yes Fixed. Caps only at a world_time successor start, else coexist with a recorded reason; D55 keeps source_removed and closes on belief-time when unknown. The duplicate-growth residual is stated honestly with its lever and a reported metric (§4.4).
8 One row-level validity_basis can't describe mixed endpoint provenance; nullable + unknown ambiguity Yes Fixed. Per-endpoint valid_from_basis / valid_until_basis, NOT NULL DEFAULT 'unknown', values world_time / verdict / source_removed / unknown.
9 Writing the resolved date into the observation statement makes identity evidence- and order-dependent (D43) Yes Fixed. Statements stay canonical; dated labels are derived from statement + occurrence window + precision and refreshed with it (§4.5).
10 Envelope/protocol migration understated (GraphEdge, K fact model, memory_v1 views, generated SDK/OpenAPI, operation versions; T2/T3/T4 vs "one roll") Yes Fixed. §7 enumerates the read models and names fact_context@3 / answer_context@3; §8 states each landed package rolls the protocol, packages released together roll once; the plan lists surfaces per package.
11 Dedupe key omitted precision; unknown-window fallback keeps the failure mode Yes Fixed. Key is the full D41 tuple incl. precision, or (text, asserted_at) when unknown; grouped rows carry every member's times (§7).
12 Audit overstatements: 4.2 (valid_at does filter ends), 4.6 (fact_context carries evidence times), 4.12 (P1 has a FactTime selector), 4.13 (equal endpoints do overlap), 4.14 (speculative) Yes, all five Fixed. Each narrowed to what the code establishes; D107's context updated to match.
13 Consumption skill defines claims_as_of as a system-time query (D41 says world-time) — missed by the audit Yes — consumption_skill.py:191-194 Fixed. Added as finding 4.18; WP-T.3 regenerates the skill with the three clocks and the corrected definition.
14 Contradictory banners; transition/deferral wording in design docs; "Accepted" vs "Binding"; T4 dependency; vague "D43 §3/§4" references Yes Fixed. All six banners rewritten to the revised rules; rollout wording moved to plan/plans/temporal_clocks.md; the LoCoMo banner is binding; T.4 is genuinely independent now that storage is unchanged; references point at observations_design.md sections.

A second Codex round runs against the revision.

…on, canonical bounds (D107 round 2)

Codex's second review showed revision two still broke on its own terms:
matching every fact by verdict-window overlap makes an occurrence's open
window overlap every later occurrence (recreating the D106 collapse and
colliding with the relations EXCLUDE); an automatic extend_start is min()
over claim columns (D41); "+ one unit" over-expands normalised year ends
and fact windows had no precision; the D90 re-split compared asserted_at to
a world-time cap; succession between dated states only lost D106's
dated-resignation-ends-undated-state case; and "current" was undefined for
finite future ends.

Give every fact a temporal kind (state / occurrence / undated): states are
identified by verdict-window overlap under the existing EXCLUDE restricted
to states; occurrences by occurrence-window overlap under their own
exclusion, so recurring events are distinct rows on both planes; undated
rows collapse by key (relations) or wording (observations). Seed once from
the D90-first claim (recorded), never revise automatically — discrepancies
become review items. Store fact windows canonical half-open from one
canonical_bounds function (year 2022 -> [2022-01-01, 2023-01-01); instant
a non-empty point) and canonicalise claim comparisons through the same
function; claim storage unchanged. Succession caps at any world-time
instant the successor supplies, including an ending occurrence. Re-split
by occurrence start. One evaluated-at current predicate with an expiry
sweep. Enumerate the shared-envelope version rolls (resolve_entity@2,
testimony_context@2, fact_context@3, answer_context@3) and the
stop-drain-migrate-rebuild-readiness cutover. Add the open-query
confirmation surface as audit 4.19; narrow 4.5 and 4.15; banner the D90
design.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016p9xB9T7VYREuVmohDPKjR
@fazpu

fazpu commented Sep 3, 2026

Copy link
Copy Markdown
Member Author

Independent review — round 2 — Codex (gpt-5.6-sol, reasoning xhigh, review-only run against the second revision)

  1. blocker — plan/designs/temporal_clocks_design.md §§4.1–4.2 — no-cap occurrence facts cannot use verdict-window overlap as identity. The design seeds every event or measurement as [occurrence start, ∞) and then says evidence attaches when its occurrence window overlaps the existing verdict window. Consequently, every later occurrence overlaps the first occurrence forever. Two visits in January and October therefore collapse instead of becoming distinct occurrences—the exact D106 failure this PR is meant to prevent. For relations, attempting a separate row would also violate the existing EXCLUDE ... tstzrange(valid_from, valid_until) WITH && constraint in p0_02_0004_claims_facts_evidence.py, because two open verdict ranges overlap. For observations, the text does not establish whether D106 runs before §4.2, and §4.2’s unconditional undated attachment also conflicts with D106’s dated-event/undated non-collapse rule. Suggested fix: define the ordering between semantic identity, D106 compatibility, and slice selection; persist enough temporal shape to match occurrence facts against occurs_*, not their open verdict windows; and redesign the relation constraint so distinct event occurrences can coexist while states retain overlap exclusion.

  2. blocker — plan/designs/temporal_clocks_design.md §4.3 and D107 item 3 — extend_start is still the D41-forbidden reduction over evidence. The revision says the rule is “deterministic over the evidence set (the earliest evidenced start wins).” That is exactly min(claim_valid_from) over supporting claim columns. Writing a transcript row does not turn that reduction into an adjudicated semantic verdict. It also directly contradicts D41’s requirements that the verdict be “never a reduction over claim columns” and that a late retrospective cannot move an adjudicated window (decisions.md D41). A retrospective added later would move valid_from earlier and rewrite what facts_as_of says about prior world time. The basis transition is also unspecified: setting it to verdict would make the fact ineligible for §4.4 succession, while leaving it world_time would misstate how the endpoint was obtained. Suggested fix: remove automatic earliest-evidence widening and leave evidence aggregation solely in occurs_*. If start revision is genuinely required, define a non-reductive adjudication rule, explicitly amend D41’s retrospective guard, record the seed/revision claim and basis atomically, and specify replay behavior.

  3. blocker — plan/designs/temporal_clocks_design.md §§3 and 5 — comparison-time precision is not implementable consistently with the proposed fact schema or the existing constraint. The verdict window has no precision column, yet bounded state verdicts are copied from inclusive claim bounds and then queried through half-open fact predicates. A year ending at stored 2018-12-31 00:00 would therefore exclude almost all of December 31 from valid_at; the engine cannot recover the seed precision from valid_from_basis. The GiST constraint likewise continues to compare raw half-open tstzrange values, so it can disagree with the proposed precision-aware matcher. There are two additional mathematical errors in §5:

    • claim_valid_until + one unit” over-expands normalized month/quarter/year bounds. The current extractor stores 2022 as 2022-01-01 through 2022-12-31; adding one year to the end reaches December 2023, not January 2023.
    • Giving an instant an effective exclusive end equal to its start makes the stated strict predicate false even against the same instant. “Points compared inclusively” is an unstated second predicate, not an implementation of the formula shown.

    Suggested fix: specify a canonical interval conversion for every precision, including point-vs-range cases; retain verdict precision or canonical effective bounds independently of the evidence-derived occurrence window; and make every fact query and the relation EXCLUDE constraint consume the same canonical representation. Keeping claim storage unchanged is compatible with this, but keeping fact range semantics unchanged is not.

  4. blocker — plan/designs/temporal_clocks_design.md §4.4 versus plan/designs/e3_entity_obs_flush_fanout_design.md §5.5.3 — the D90 re-split still mutates truth by said-on order. D107 separates total processing order from temporal succession, but the still-binding D90 design requires a capped observation to re-materialize attached evidence when asserted_at > T (§5.5.3). That is not merely processing order; it determines fact slices. Under D107, T is a world-time boundary, so comparing a claim’s said-on timestamp to it crosses clocks and can recreate the wrong spell for a late retrospective. This design is not among the six amended banners. Suggested fix: amend D90’s binding design explicitly. Re-split eligibility must use a compatible state claim’s occurrence start relative to the world-time cap, while asserted_at remains only the total work order; undated evidence must follow the chosen coexistence rule. Add the staggered-unit acceptance case with said-on and is-about orders deliberately reversed.

  5. major — D107 §4.4 and the observations amendment conflict with D106’s mixed-kind supersession contract. D106 explicitly says a dated resignation may supersede an undated “is CEO” state (decisions.md D106 item 2). The revised design instead requires both facts to be states with world_time starts and says an unknown-timed fact is never capped. A resignation is an event, and the CEO state has no start, so the D106 case is now impossible. Yet the observations banner says “The D106 rung is unchanged,” and D107’s amendment paragraph does not say this D106 rule is withdrawn. Suggested fix: either preserve D106 by allowing an explicitly matched ending event’s world-time occurrence to cap a state—even one with an unknown start—or explicitly amend D106, explain the loss, and change the banner and tests.

  6. major — plan/designs/temporal_clocks_design.md §§3, 7 — “current” membership after finite seeding is undefined for existing open-only consumers. The code intentionally uses valid_until IS NULL for entity profiles (profile_refresher.py), source-removal eligibility, and some K routing. After D107, a state may have a finite future end and still be current today, but those paths will omit it. Changing them to wall-clock predicates introduces the refresh-at-expiry problem the profile code comment explicitly warns about. The design changes ranking and display but never decides membership or expiry scheduling. Suggested fix: define one fixed-evaluation “current fact” predicate for every consumer, enumerate all open-only call sites, and specify how cached profiles/K pages refresh when a finite endpoint passes without a new evidence write. State separately whether events and measurements are included as enduring believed facts.

  7. major — plan/designs/temporal_clocks_design.md §7 — the assured-operation rolls do not cover the actual contract changes. “Grouped rows keep every member’s times” cannot be represented by the current EvidenceResult, which has one representative timestamp plus only grouped_claim_ids (model/envelope.py). Adding member records changes testimony_context, despite §7 saying its shape is unchanged. Moreover, all Envelope-returning operations derive their result schema from the same global Envelope.model_json_schema() (assured_operations.py); extending Validity therefore changes the descriptors for resolve_entity and testimony_context as well as fact_context. Suggested fix: define the grouped-member schema and roll testimony_context plus its answer_context parent; either roll every operation whose shared result schema changes or split the result schemas by grain. Enumerate the resulting descriptor, manifest, OpenAPI/SDK, and protocol fingerprints.

  8. major — plan/designs/temporal_clocks_design.md §8 — the migration/rebuild contract permits a mixed-authority store. New basis columns default to unknown, so pre-D107 rows with non-null, said-on-derived windows would immediately be interpreted inconsistently: readers still filter on the old timestamps, consumers suppress them as unknown-basis, and succession refuses them. Only the observation flush inherits an explicit stop-drain-rebuild statement; there is no coordinated cutover for relation normalization, both adjudicators, readers, P1, K, or stored canonical facts. “Re-seeded from the claim rows” is also underspecified where several claims support a fact and no seed claim is recorded; choosing the minimum would recreate finding 2. Suggested fix: specify a stop/drain/migrate/rebuild/readiness boundary that prevents mixed old/new fact semantics, persist or transcript the seed claim, and define rollback/failure behavior. Also correct “four columns on each fact table”: two basis columns plus three occurrence columns is five.

  9. major — the audit missed temporal information dropped by the open-query P1 confirmation surface. query_sandbox/nomination.py confirms claim search rows with asserted_at, claim_valid_from, and claim_valid_until but omits claim_valid_precision and claim_valid_kind; fact search rows omit verdict and occurrence time entirely. Thus an agent cannot distinguish a point, coarse period, open interval, or unknown from this public search path, even after the proposed filters are added. This is a material missed instance of P1/P4 and is absent from WP-T.3. Suggested fix: add it to the audit and design, return the complete D41 tuple for claim results and bases/occurrence for fact results, and include its query-space manifest/fingerprint roll.

  10. major — plan/plans/temporal_clocks.md WP-T.4 has an impossible acceptance case under the retained schema. The test requires two same-day sessions to resolve “this morning” to different instants. The D41 precision enum has no hour or part-of-day interval, and “this morning” does not identify an instant merely because the source header includes a timestamp. This also makes audit finding 4.15’s specific “this morning” consequence overstated: retaining time of day fixes expressions such as “three hours ago,” but not the expressivity gap for “this morning.” Suggested fix: either add an hour/part-of-day precision and its normalization rules, or change the example and acceptance test to an expression that supports an exact offset-derived instant.

  11. minor — plan/analysis/time_handling_audit.md §4.5 — “E3 never sees the resolved window” is overstated after D106. The normalizer prompt and statement-minting path do omit the window, and the claimed consumer consequence is correct. But the observation adjudicator invoked by E3 already loads claim_valid_kind/from/until, as the audit’s own “checked and sound” section acknowledges. Suggested fix: retitle this finding to say that normalization and canonical label construction do not propagate the resolved window, rather than all of E3.

Verified

  • Audit findings 4.1–4.4 and 4.6–4.8 match the cited code: exact-text-only testimony grouping, unseeded relation starts, the relation prompt’s missing D41 fields, said-on/now() caps, ambiguous answer-agent clocks, misleading K columns/order, and date-free K writer claims are all present. Finding 4.5’s consequence holds subject to finding 11’s narrower wording.
  • Findings 4.9–4.14 and 4.16–4.18 also hold: timeline ingest fallback, source-time observation order, opposite undated ordering, missing P1 is-about filters, coarse precision point storage, incomplete extraction instruction, date-free/updated_at-ranked profiles, observation start widening from asserted_at, and the incorrect consumption-skill definition.
  • The audit’s parse/validation gate, claims_as_of use of D41 columns, evidence-grain D41 fields, separate belief-time plumbing, D55 shape distinction, and append-only adjudication transcripts are correctly described.
  • The revised text genuinely removes said-on seeding and now() supersession boundaries, keeps missing time missing, preserves D43 no-cap semantics for measurements and extends them explicitly to events, retains canonical statements with derived labels, and does not adopt universal half-open claim storage.
  • It states the full D41 tuple in testimony dedupe, separates the new succession relation from D90’s total processing order at the D107 level, enumerates the main generation/surface/protocol rolls, and introduces no D60/D61 boundary violation or prohibited design-phase/MVP hedge.
  • Writing resolved dates only into derived labels avoids the D32/D43 identity problem from round one; evidence collapse can refresh the label without mutating the canonical statement.

Merge verdict: REQUEST CHANGES. The PR is not mergeable because the revised temporal identity model cannot represent recurring no-cap events under its own matching rule and the existing GiST constraint, extend_start remains the D41-prohibited claim reduction, and precision cannot consistently govern fact windows or the EXCLUDE constraint. Fix those three mechanics first, then reconcile D90 re-splitting and D106 mixed-kind termination, and finally close the current-surface, versioning, and cutover gaps before treating the design as binding.

@fazpu

fazpu commented Sep 3, 2026

Copy link
Copy Markdown
Member Author

Review triage — round 2 (Codex), dispositions applied in 3ec25a2

Round two's verdict was again "request changes", and the three mechanical blockers were real: revision two's identity rule could not represent recurring occurrences, its extend_start was still a reduction over claim columns, and its precision handling was wrong twice over. Revision three changes the model rather than the wording.

# Finding (Codex) Verified Disposition
1 Occurrence facts seeded [start, ∞) and matched by verdict-window overlap → every later occurrence overlaps the first (the D106 failure at the fact layer); relations EXCLUDE rejects a second open range Yes Fixed (design change). Every fact carries a temporal_kind. States are identified by verdict-window overlap under the EXCLUDE restricted to states; occurrences are identified by occurrence-window overlap under their own exclusion on occurs_*, so a January and an October visit are two rows on both planes; undated rows collapse by key/wording. Matching order (block → kind identity → D106/D4 ladder) is stated (§4.2).
2 extend_start = min(claim_valid_from) — the D41-forbidden reduction; basis transition unspecified Yes Fixed. No automatic verdict revision exists. Discrepancies (evidence earlier than the verdict start; dated evidence on an undated slice) become review items; only a recorded review verdict (basis verdict), a cap, or D55 changes a window, and none reopens a closed end (§4.3). Succession accepts bases world_time and verdict.
3 Comparison-time precision inconsistent with fact windows and the EXCLUDE; "+ one unit" over-expands normalised ends; instant predicate contradiction Yes — 2022-12-31 + 1 year = 2023-12-31 Fixed (design change). One canonical_bounds function: [from, date_trunc(unit, until) + unit) for coarse precisions, [t, t+1µs) for instants, unbounded for open. Fact windows are stored canonical at seeding, so every existing fact predicate and the EXCLUDE read consistent half-open bounds; claim comparisons canonicalise at query time; claim storage unchanged (§5).
4 D90 §5.5.3 re-split compares asserted_at to a world-time cap; the D90 design was not amended Yes Fixed. Re-split eligibility uses the attached state claim's canonical occurrence start against T; asserted_at remains work order only; undated evidence is never re-split; the D90 design carries a D107 banner and the plan adds the reversed-order acceptance case (§4.5).
5 Succession restricted to two dated states made D106's dated-resignation-ends-undated-"is CEO" case impossible Yes — D106 item 2 Fixed. A state is capped at any world-time instant its successor supplies — a successor state's start or a matched ending occurrence's start; the predecessor's start basis is irrelevant (§4.4). D106 preserved; the observations banner says so.
6 "Current" undefined for finite future ends; open-only consumers; refresh-at-expiry problem Yes — profile_refresher comment Fixed. One evaluated-at predicate (§7.1) for every open-only site; cached profiles/K pages include the earliest future end in their input hash and an expiry sweep refreshes them; occurrences/undated always current.
7 Grouped-member times need an EvidenceResult change (so testimony_context rolls); shared Envelope schema rolls every envelope operation Yes Fixed. EvidenceResult.grouped_members defined; resolve_entity@2, testimony_context@2, fact_context@3, answer_context@3 all roll, with manifests/OpenAPI/SDK/protocol (§7.3).
8 Migration permits a mixed-authority store; seed claim unrecorded; column count wrong Yes Fixed. seed_claim_id recorded; the seed is the D90-first claim (identical to a fresh ingest, so rebuild = replay); stop → drain → migrate → rebuild → readiness gate refusing older fact generations; rollback = restore (§9). Column list corrected.
9 Open-query confirmation surface drops precision/kind on claims and all time on facts — missed by the audit Yes — nomination.py:323-327 Fixed. Audit 4.19; design §7.3; WP-T.3.
10 "this morning" cannot resolve to distinct instants (no part-of-day precision); 4.15 overstated Yes Fixed. Example and acceptance use an offset expression ("three hours ago"); part-of-day expressions named as an expressivity boundary (§6, §11); 4.15 narrowed.
11 4.5 title overstates (the adjudicator does load windows post-D106) Yes Fixed. Retitled to normalisation and label construction.

A third Codex round runs against 3ec25a2.

…lace conversion (D107 round 3)

Codex's third review: an occurrence exclusion constraint contradicts
adjudicated identity (two same-day visits, or a union that grows into a
neighbour); kind-routed matching made D106's ending-event cap unreachable
and had no chronological guard; "review item" named no verdict schema; a
replay rebuild erases D55 history and can re-pick seeds; belief-time leaked
into a world-time endpoint; aggregates and predicate absence never evaluate
valid_until; canonical bounds kept raw starts and had no SQL form.

Drop the occurrence exclusion — occurrence identity is adjudicated under
the per-key lock with overlap as a candidate filter. Define two candidate
sets (same-kind for evidence; state-ending occurrences for supersede/
contradict only) and a chronological guard. Amend D24 with a
temporal_window review kind and its append-only, reversible verdict schema,
invariants and replay order. Convert in place from the recorded add
adjudication's triggering claim (fact ids and D55 history preserved,
shadow-first, resumable). Retraction with unknown source time closes only
the belief interval from the persisted reconciliation instant. Canonical
bounds truncate both ends and ship as memory_v1.canonical_bounds with a
claims_canonical view. One evaluated-at current predicate everywhere,
including aggregate/absence, with a durable expiry schedule. Audit 4.20
(aggregates) and 4.21 (claims_as_of example) added; protocol rolls listed
per package; the D90 §5.5.3 rule rewritten.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016p9xB9T7VYREuVmohDPKjR
@fazpu

fazpu commented Sep 3, 2026

Copy link
Copy Markdown
Member Author

Independent review — round 3 — Codex (gpt-5.6-sol, reasoning xhigh, review-only run against the third revision)

  1. Blocker — plan/designs/temporal_clocks_design.md §4.2 “Matching and identity”; decisions.md D107 §4.2: The occurrence exclusion constraint contradicts the adjudication rules. The design first says overlapping occurrence windows proceed through the D4/D106 ladder, where the outcome can still be new, but then requires an exclusion constraint preventing the same (subject, predicate, object) from having overlapping occurrence ranges. Two genuinely distinct recurring occurrences can overlap after precision canonicalization—for example, two visits on the same day when one or both claims have day precision. An existing occurrence’s evidence-union range can also expand until it overlaps another row, making a previously legal update fail. D106 deliberately sends overlapping event windows through semantic adjudication; overlap alone does not establish event identity. Suggested fix: remove the occurrence overlap exclusion and serialize adjudication using the same advisory-lock mechanism used for observations, or add a durable occurrence-group identity that distinguishes events independently of their possibly overlapping ranges. Specify insert and range-expansion collision handling, with acceptance cases for same-triple recurring events, coarse/fine precision overlap, and a union expansion bridging two existing occurrences.

  2. Blocker — plan/designs/temporal_clocks_design.md §§4.2 and 4.4; decisions.md D106 and D107: Temporal-kind routing, succession, and D106’s ending-occurrence rule are not mutually implementable as written. Section 4.2 says temporal-kind identity is applied before the ladder and that occurrences compare only with occurrence facts. Section 4.4 nevertheless requires an ending occurrence to be “ladder-matched as superseding a state” and cap it at the occurrence start. D106’s dated-resignation/undated-CEO case depends on precisely that cross-kind comparison. The design also gives no chronological guard preventing a purported successor boundary at or before the predecessor’s known start, which could produce an invalid or backwards state interval. Suggested fix: define two separate candidate sets: same-kind candidates eligible for evidence attachment, and cross-kind state-ending candidates eligible only for succession or contradiction. Explicitly require a cap boundary later than a known predecessor start; otherwise route the result to contradiction, coexistence, or review rather than writing an invalid interval. Cover both relation and observation paths.

  3. Blocker — plan/designs/temporal_clocks_design.md §4.3 “Review-only revision” and §9; decisions.md D24 and D107: “Create a D24 review item” does not define a review mechanism capable of implementing the promised behavior. D24’s queue is for merge/split/type-conflict review, and the current review enums and handlers have no temporal-window verdict. D24 also requires reviewer actions to be append-only, reversible provenance records. D107 instead says a reviewer may move valid_from or the occurrence date, but does not define the durable verdict record, stable target identity, old and new bounds, reversal, authorization, invariant checks, or ordering relative to caps and retractions. Section 9’s instruction to replay review verdicts therefore has no executable replay contract. Suggested fix: explicitly amend D24 and define a temporal_window review-item/verdict schema containing the logical fact target or stable fact ID, seed claim, old/new canonical bounds and bases, reviewer provenance, supersession/reversal linkage, monotonicity checks, and idempotent replay order.

  4. Blocker — plan/designs/temporal_clocks_design.md §§4.1 and 9 “Cutover”; decisions.md D41, D55, and D107: The proposed rebuild is neither history-preserving nor guaranteed to reproduce live verdicts. Section 9 rebuilds from “current-testimony claims” and replaces fact rows. D55 retains historical claims and allows history-visible facts with no current support; replaying only current testimony can erase those historical facts and their adjudication history. Fact IDs are also provenance handles referenced by evidence, review payloads, and downstream K-layer citations, including real foreign keys, so replacing or regrouping rows needs an explicit identity migration.

    Seed preservation is also unresolved. Suppose fact A was seeded by a claim asserted in 2024. A late claim asserted in 2023 overlaps A and attaches without revising A’s seed, as D107 requires. A fresh global D90 replay processes the 2023 claim first and selects it as the new seed, changing the verdict. Recording seed_claim_id does not solve this if the rebuild discards the old row before grouping. Suggested fix: define the authoritative migration input as the complete surviving testimony and currency/adjudication transcript, preserve existing seed decisions before regrouping, provide an old-to-new fact-ID map, migrate every evidence/review/K reference, and specify crash-safe shadow rebuild, validation, atomic swap, rollback, and idempotent resume. Alternatively, use an in-place conversion that preserves stable fact identities.

  5. Major — plan/designs/temporal_clocks_design.md §4.4 “Retraction”; decisions.md D55 and D107: The unknown-source-time removal rule still conflates world time with belief time. The text says a state with no source removal time “closes on belief-time (invalidated_at) rather than now(),” while assigning source_removed as an endpoint basis. If invalidated_at is copied into valid_until, that violates D107’s rule that belief time never supplies world time. If only invalidated_at is set, then the world-time state did not close and source_removed is not a truthful valid_until_basis. The current invalidation paths derive invalidated_at from database time, so a later rebuild would also get a different instant unless the original event is persisted. Suggested fix: when source time is absent, leave the world-time verdict end unknown and terminate only the belief interval using a persisted reconciliation/removal-event timestamp. Do not label a world-time endpoint source_removed unless the source supplied that endpoint, and replay the recorded belief instant rather than evaluating the clock again.

  6. Major — plan/designs/temporal_clocks_design.md §7.1 “Current”; plan/analysis/time_handling_audit.md findings list; src/rememberstack/query_engine.py aggregate queries around _AGG_COUNT, _AGG_GROUP_PREDICATES, _AGG_GROUP_OBJECTS, and _AGG_PREDICATE_ABSENCE: The audit and migration scope miss current-fact consumers that never tested valid_until IS NULL. The aggregate paths select “live” relations using only invalidated_at; the predicate-absence query likewise checks for no live relation without evaluating valid_until. After D107, an expired relation can therefore continue to count and can incorrectly block an absence answer. This conflicts with D49’s requirement that current fact-grain answers be validity-filtered.

    The expiry sweep is also under-specified: “queue regeneration when the earliest end passes” defines no durable schedule, idempotency key, fixed evaluation instant, restart catch-up, or stale-read bound. Merely including the earliest end in a hash does not change the hash when wall time crosses that end. Suggested fix: add the aggregate/absence paths to the audit and require every current fact read to use the shared evaluated-at predicate. Define a durable, indexed expiry schedule keyed by fact/page, endpoint, and generation; carry the boundary instant as evaluation time; specify D12 idempotency and crash catch-up; and retain a read-time predicate as the correctness backstop.

  7. Major — plan/designs/temporal_clocks_design.md §5 “Canonical bounds”; examples/claims_as_of.sql; src/rememberstack/open_query_prose.py: canonical_bounds is incomplete at both ends of the interface.

    • For bounded precision it truncates or extends the end but retains the raw start. D41 validation permits timestamp values carrying day/month precision without requiring alignment, so a day-precision claim starting at noon would become [noon, next-day midnight) rather than the represented calendar day.
    • Strict half-open overlap does not define how an inclusive claims_as_of(from,to) request is converted. The current contract permits from == to; converting that directly to [t,t) produces an empty query rather than a point-in-time query.
    • Open SQL examples and prose still compare stored claim endpoints directly with inclusive predicates. They cannot automatically use an application-only comparison helper. The shipped claims_as_of example’s “unknown” count also combines precision='unknown' with a non-null-bound comparison, so D41’s checks make that count permanently zero—an additional audit omission.

    Suggested fix: define calendar and timezone behavior and canonicalize the start with date_trunc(unit, from) or enforce aligned stored inputs. Specify point and inclusive-range query conversion separately. Expose one immutable SQL canonicalization function or canonical comparison view through memory_v1, then update saved examples, open-query prose, catalog metadata, and tests for adjacent boundaries, equality queries, non-aligned bounded inputs, and existing claim rows.

  8. Minor — plan/plans/temporal_clocks.md WP-T.0 and WP-T.5; plan/designs/temporal_clocks_design.md §8: Package-level fingerprint consequences are inconsistent with the design’s own behavioral changes. WP-T.0 says no assured-operation or protocol surfaces change even though canonical comparison changes claims_as_of results. WP-T.5 similarly omits a protocol consequence despite changing P1 selection, labels, profile ranking, and answer inputs. These are observable protocol semantics even if the JSON field shape is unchanged. Suggested fix: either make the cutover atomic under one protocol generation or list the affected protocol/generation rolls in each package whose result semantics change.

  9. Minor — amendment banners and audit wording: Several cold-read inconsistencies remain.

    • plan/analysis/time_handling_audit.md §5 says every confirmation query selects all D41 fields, while §4.19 correctly records that the open-query confirmation omits kind and precision. Narrow the §5 assertion to EvidenceResult hydration or explicitly identify the exception.
    • plan/designs/registries_design.md’s amendment banner points the relation prompt change to temporal design §6, but the prompt contract is in §7.2.
    • plan/designs/e3_claim_lineage_fanout.md retains underlying text saying the D90 re-split uses asserted_at and that temporal ordering is not redefined there. The D107 banner overrides it, but leaving directly contradictory normative text below an amendment banner is not cold-readable. Rewrite the affected subsection or point to the exact replacement rule.

Verified

  • Audit §4.1 correctly identifies text-only claim grouping: the grouping key excludes asserted and is-about time, while EvidenceResult carries those fields.
  • Audit §4.2 correctly identifies relation facts initially receiving no world-time start even though world-time retrieval filters use fact validity.
  • Audit §4.3 correctly identifies that relation supersession prompts receive claim text and asserted time but not the D41 is-about window.
  • Audit §4.4 correctly identifies coalesce(boundary, now()) in relation, observation, and lifecycle closing paths.
  • Audit §4.5 correctly identifies that observation normalization sees claim text but not resolved structured temporal fields.
  • Audit §4.6 correctly identifies that the LoCoMo answer prompt mentions timestamps without distinguishing said-on, is-about, and believed clocks.
  • Audit §4.7 correctly identifies K-layer “valid since” and history ordering as using unsuitable fact fields.
  • Audit §4.8 correctly identifies that K-writer candidates and models omit temporal fields.
  • Seeding a verdict once from a recorded claim is compatible with D41 in principle. The non-authoritative occurrence evidence union and endpoint-basis provenance do not themselves create a second verdict, provided database checks prevent them from mutating the authoritative window.
  • Deriving observation labels from the verdict window while preserving the canonical statement is compatible with D32 and D43.
  • The revised D90 re-split rule now uses occurrence start rather than asserted time at the binding D107 level.
  • The undated-relation rule preserves D106’s core protection by never attaching an undated relation directly to an occurrence.
  • The shared Envelope schema justifies rolling all four assured-operation descriptors, and the window-bearing dedupe-key change is correctly assigned a protocol roll.
  • The stop/drain/readiness intent prevents mixed old/new reads, and the design contains no substantive phase/MVP-style deferral or D60/D61 boundary violation.

Merge verdict: Not mergeable. Revision three resolves several round-two conceptual problems—especially automatic verdict widening, explicit temporal kinds, occurrence-plane separation, world-time D90 re-splitting, and evaluated-at current semantics—but the occurrence exclusion cannot represent adjudicated recurring events, D106 cross-kind succession is contradicted by the matching rules, and neither temporal review nor the rebuild has a durable history-preserving replay model. Fix those three blockers first; then close the removal-clock, canonical-boundary, and expiry-consumer gaps before approval.

@fazpu

fazpu commented Sep 3, 2026

Copy link
Copy Markdown
Member Author

Review triage — round 3 (Codex), dispositions applied in be67e65

Round three confirmed the direction (temporal kinds, occurrence-plane separation, no automatic widening, world-time re-split, evaluated-at current) and blocked on four implementability gaps. All four are closed by mechanism, not wording.

# Finding (Codex) Verified Disposition
1 An occurrence EXCLUDE on occurs_* contradicts adjudicated identity (two same-day visits; a union expansion bridging a neighbour) Yes Fixed (design change). No occurrence exclusion. Overlap is a candidate filter; identity is the D4/D106 ladder's verdict under the per-key advisory lock; overlapping occurrence rows are legal; union expansion never merges. Acceptance cases added (§4.2).
2 Kind-routed matching made D106's ending-occurrence cap unreachable; no chronological guard Yes Fixed. Two candidate sets — same-kind (evidence/contradict/new) and state-ending occurrences (supersede/contradict only) — plus a guard: a cap must be later than the predecessor's known start, else contradict/coexist + review item (§4.2, §4.4). Both planes.
3 "D24 review item" named no verdict mechanism Yes — D24 is a cluster queue with merge/not-merge verdicts Fixed. D24 amended: a temporal_window review kind with an append-only, reversible verdict record (target, seed, old/new canonical bounds + bases, provenance, reversal linkage), invariants, and idempotent replay after caps/retractions (§4.3).
4 Replay rebuild erases D55 history, replaces referenced fact ids, and can re-pick seeds Yes Fixed (design change). In-place conversion: seed_claim_id := the recorded add adjudication's triggering_claim_id (already written on both planes — the claim that actually created the row), windows by kind, existing caps kept, shadow-first, validated, resumable; fact ids and D55 history preserved; re-adjudicating old identity decisions is an operator-chosen fresh rebuild (§9).
5 Unknown-source-time retraction copied belief-time into a world-time end labelled source_removed Yes Fixed. The world-time end stays unknown; only invalidated_at closes, from the persisted reconciliation instant (rebuild-stable); source_removed only when the source supplied the time (§4.4).
6 Aggregate/absence queries never evaluate valid_until; expiry sweep under-specified Yes — _AGG_COUNT, _AGG_PREDICATE_ABSENCE Fixed. Audit 4.20; the evaluated-at predicate on every current read incl. aggregates; a durable, indexed, D12-idempotent fact_expiry_schedule with restart catch-up and the read-time predicate as backstop (§7.1).
7 canonical_bounds kept raw starts; inclusive request conversion undefined; no SQL form for saved examples/open SQL; the example's unknown count is permanently zero Yes Fixed. Both ends truncated to the unit in UTC; (t, t) → point query; memory_v1.canonical_bounds + claims_canonical view; example fixed (audit 4.21; §5).
8 T.0 / T.5 change observable semantics without a protocol roll Yes Fixed. Rule stated (§8): any package whose result semantics change rolls the protocol; the plan lists it per package.
9 Audit §5 overstated; registries banner section ref; D90 design's normative text contradicted its banner Yes Fixed. §5 narrowed to EvidenceResult hydration with 4.19 as the exception; banner ref → §7.2; D90 §5.5.3's "Required" paragraph rewritten to the world-clock rule.

A fourth Codex round runs against be67e65.

…nt contradiction restored (D107 round 4)

Codex's fourth review: relation add adjudications never recorded a
creator claim, so exact legacy seed recovery was false; keeping legacy caps
preserved the said-on/now() ends D107 removes; the current predicate had no
lower bound (a 2030 fact current in 2026) and no activation scheduling;
an overlap-only candidate filter dropped D106's disjoint-date contradiction;
state-ending candidates limited to open states could not shorten a
finite-ended state; the relation write path attached evidence before any
verdict; the review verdict schema lacked identity, idempotency key and a
reconciled reversal rule; fact checks allowed empty half-open states; D55
withdrawal erased historical occurrence windows; D55's observation close is
shape-blind; stale round-three mechanics remained in banners.

Record the seed atomically on both planes going forward; convert legacy
relations under a `legacy` basis with migration adjudications; recompute
recoverable legacy caps, remove caps from converted occurrences, turn D55
fallback caps into belief-time closes, and route the rest to
`legacy_unknown_boundary` review items readiness reports. Use the full
containment current predicate everywhere with activation and expiry
scheduling. Keep nomination as today and bound verdicts by temporal
relation (disjoint: new or contradict). Include finite-ended states in the
state-ending set with a guard on both bounds. Stage relation writes until
an idempotent verdict. Define temporal_window_verdicts concretely with
reversal as the documented exception. Require non-empty states; derive
occurrence windows over all attached evidence; route D55 by temporal kind
(audit 4.22). Align every banner.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016p9xB9T7VYREuVmohDPKjR
@fazpu

fazpu commented Sep 3, 2026

Copy link
Copy Markdown
Member Author

Independent review — round 4 — Codex (gpt-5.6-sol, reasoning xhigh, review-only run against the fourth revision)

Findings

  1. blocker — plan/designs/temporal_clocks_design.md §9 / D107 item 10: the promised legacy seed is not recorded. The conversion requires seed_claim_id := triggering_claim_id from the fact’s add adjudication and says it is “present on both planes.” That is false for relations. src/rememberstack/spine/supersession.py::_INSERT_ADJUDICATION inserts no triggering_claim_id, and SupersessionAdjudicator._record does not accept one. FactCatalog.upsert_relation creates the relation and attaches evidence before that later add verdict. Even observation triggers are not universal because src/rememberstack/spine/forget.py:1193-1204 explicitly clears them during hard forget. Therefore an in-place converter cannot recover the claim that actually created every existing fact without re-picking—the exact behavior revision four rejects. Fix: define a total legacy conversion policy: atomically record the creator claim for all new facts; make seed_claim_id nullable/scrubbable for hard forget; preserve legacy verdict endpoints when the creator is unknowable and append a migration verdict identifying that condition. Do not claim exact seed recovery from legacy add rows.

  2. blocker — plan/designs/temporal_clocks_design.md §9 and D107 consequences: conversion preserves the wrong pre-D107 boundaries. Section 9 says every existing supersession/retraction cap is retained and relabelled verdict/source_removed. But the audited code sets those ends from said-on or wall time:

    -- supersession.py:503-510
    SET valid_until = coalesce(:boundary_asserted, now())
    
    -- lifecycle.py:929-936
    SET valid_until = coalesce(CAST(:boundary AS timestamptz), now())

    Keeping these values leaves audit finding 4.4 unfixed in every upgraded store, while D107 simultaneously claims said-on is never a boundary and unknown-source retraction leaves world-time unknown. It also preserves caps on rows converted to occurrence, contradicting the new no-cap rule. Fix: specify conversion per recorded cap: recompute recoverable supersession ends from the successor’s canonical world-time; convert unknown-source D55 fallback caps into belief-time invalidation at the persisted reconciliation event; handle occurrence caps according to the new no-cap rule; and route genuinely unrecoverable boundaries to an explicit legacy-unknown verdict before readiness succeeds. Record any migration-only correction needed to remove a previously invalid now() endpoint.

  3. blocker — plan/designs/temporal_clocks_design.md §7.1 / D107 item 5: the new “current” predicate omits the lower bound. It defines current as only:

    invalidated_at IS NULL AND (valid_until IS NULL OR valid_until > E)
    

    A state or occurrence beginning in 2030 is therefore “current” in 2026. This regresses the existing canonical contract: memory_v1.facts_current at p9_01_0022_memory_v1_query_space.py:1167-1172 checks ingested_at <= E, valid_from <= E, and valid_until > E; _FACT_CONTEXT_TIME_PREDICATE does likewise. The expiry schedule compounds the defect by scheduling future ends only: once the predicate is corrected, cached artifacts excluded before a future valid_from have no activation event that makes them appear. Fix: bind current to full interval containment—ingested_at <= E, not invalidated, valid_from IS NULL OR valid_from <= E, and valid_until IS NULL OR valid_until > E—and schedule both future starts and future ends for cached profiles/K pages. Add a future-start acceptance case.

  4. blocker — plan/designs/temporal_clocks_design.md §4.2: “Disjoint windows are always new” contradicts D106. D106 explicitly requires disjoint dated-event pairs to remain eligible for contradict when two sources name the same occurrence but dispute its date (decisions.md:4913-4918); the existing observation design repeats that rule at observations_design.md:171-175. Revision four’s overlap-only candidate filter silently eliminates that path. Fix: preserve a bounded semantic/name-based candidate path for possible same-occurrence date disputes. Disjoint pairs may only resolve to new or contradict; they must never become evidence or supersede.

  5. blocker — plan/designs/temporal_clocks_design.md §§4.1–4.4: ending occurrences cannot correct bounded states. A state seeded from a bounded effective_period is stored with a finite end, but the cross-kind state-ending set contains only “open state slices.” Thus a 2027 resignation is never compared with “CEO 2025–2030”; it is neither same-kind nor in the state-ending set, so the state remains valid through 2030. Fix: include non-invalidated state slices whose interval extends beyond the occurrence boundary, whether their end is null or finite. Apply the chronological guard to the start and require the new boundary to shorten the existing end; otherwise record coexistence/contradiction as appropriate.

  6. major — plan/designs/temporal_clocks_design.md §4.2: the relation write path needed for adjudicated occurrence identity is unspecified. Today FactCatalog.upsert_relation mechanically finds a live (subject,predicate,object) row and attaches evidence (fact_catalog.py:39-105) before relation supersession runs; the later relation ladder treats the same redirected object as an exact no-op (supersession.py:169-178). That path necessarily collapses two same-triple visits before the new overlap-and-ladder rule can decide new. Merely saying matching occurs under a per-key lock does not define where the claim waits, how retries replay the identity verdict, or how D88’s concurrent normalizers avoid duplicate occurrence rows now that no constraint exists. Fix: specify the relation staging/apply transaction: the claim must remain unattached until candidate selection and verdict replay complete under the exact block lock; new inserts a fact plus add verdict and evidence atomically, while evidence attaches atomically. Define a durable idempotency key keyed by triggering claim and adjudicator generation.

  7. major — plan/designs/temporal_clocks_design.md §4.3: the temporal_window verdict schema is still not executable as written. The listed identity is target_fact_id plus temporal_kind, but D49 fact identity is (fact_kind, fact_id); temporal_kind does not distinguish the relations and observations tables. The field list also omits the verdict_id later used for idempotency and does not name the append-only domain table or its link to review_queue. More importantly, “a reversal restores the prior bounds” conflicts with both stated invariants: reversing an earlier-start verdict moves the start later, and reversing a newly closed end reopens it. Fix: define the concrete verdict relation with at least verdict_id, review_id, target_fact_kind, target_fact_id, old/new bounds and bases, actor/provenance, and reversal linkage. Then explicitly reconcile D24 reversibility with D41 monotonicity—either make human reversal a documented exception, or implement reversal by a compensating slice/verdict that does not reopen the existing slice.

  8. major — plan/designs/temporal_clocks_design.md §§4.3, 4.4, 9: half-open fact invariants are not carried into the database schema. Existing relation and observation checks allow valid_until = valid_from (p0_02_0004_claims_facts_evidence.py:198,313). In a half-open model that is an empty fact; tstzrange(t,t) is empty and can also bypass the overlap exclusion. Section 9 does not replace these checks, and D55 retraction is not covered by §4.4’s chronological guard. Fix: migrate both fact tables to a conditional non-empty check for states with two known endpoints, and apply the same boundary > known start guard to every cap source, including D55. Route invalid boundaries to belief invalidation or review rather than storing an empty world interval.

  9. major — plan/designs/temporal_clocks_design.md §§3 and 9: D55 historical occurrences lose their resolved time. occurs_* is defined as the union of only current-testimony evidence and is recomputed when evidence is withdrawn. A D55 sole-support removal therefore clears the occurrence window exactly when the design says the historical fact and its identity must be preserved. For an invalidated “last week” event or measurement, the fact survives but its derived date/precision and derived label disappear. Fix: define historical occurrence retention explicitly—either derive from all surviving attached evidence, or freeze the last non-empty adjudicated occurrence metadata when belief closes. Hard forget may then recompute from surviving evidence, but ordinary D55 currency withdrawal must not erase the historical world-time.

  10. major — plan/analysis/time_handling_audit.md §5 “Checked and sound”: the D55 assessment is wrong. The audit says D55 shape discipline is sound because “relations cap … observations use invalidated_at; only the now() fallback is wrong.” D55 and evidence_lifecycle_design.md:153-165 require effective-state observations to cap world-time and only measurements to use invalidated_at. The audited implementation’s close_observations (lifecycle.py:438-468) invalidates every observation without performing that per-shape judgment. Fix: promote this to a finding and make D107’s new temporal_kind route D55 state observations to a guarded source-time cap and occurrences/measurements to belief invalidation.

  11. major — the binding amendment corpus still contains superseded round-three mechanics. e2_e3_claims_relations_design.md:8-9 says occurrences match “under a separate exclusion,” directly contradicting revision four’s no-occurrence-exclusion decision. e3_entity_obs_flush_fanout_design.md:251-258 correctly forbids asserted_at in the re-split, but lines 264-265 immediately say implementation may walk evidence asserted_at. D107’s consequences at decisions.md:5145-5146 still call the upgrade a “fact-layer rebuild,” while §9 and D107 item 10 require in-place conversion and explicitly reject replay rebuild. Fix: rewrite these binding passages to the revision-four rules; also change “Two independent … reviews” followed by first/second/third at decisions.md:5120-5128, and reconcile “nineteen local patches” with the twenty-one-finding corpus.

  12. minor — plan/analysis/time_handling_audit.md §4.13 overstates one precision consequence. The zero-width day/month/year defect is real, as is the day-precision-versus-instant miss. But two genuinely instant-precision events at different times on the same day should be disjoint; the fact that “the day contains both” does not make their non-overlap erroneous under D106. Fix: narrow the example to coarse bounded precision and coarse-versus-instant comparisons, unless the text explicitly says both timestamps name the same disputed occurrence.

Verified

  • Audit findings 4.1–4.8 are otherwise supported at 02b79904: testimony grouping keys only on normalized text; first relation starts are unseeded; relation supersession sees only said-on; caps use said-on/now(); observation labels retain unresolved relative wording; the answer prompt does not define the clocks; the K sheet labels/sorts on the wrong fact time; and the K writer claim model/query omit all temporal fields.
  • Findings 4.9–4.12, 4.14–4.20, and the core of 4.13/4.21 also hold: the timeline falls back to ingest time, observation apply order is said-on, the adjudicators orient null times differently, P1 lacks is-about filters, E2 lacks kind examples and a full timestamp header, T4 ranks by updated_at, observation evidence collapse widens from asserted_at, the consumption skill misdefines claims_as_of, confirmation omits kind/precision, aggregate/absence ignore validity ends, and the saved unknown count is structurally zero.
  • Seeding a verdict once from one recorded claim is compatible with D41; it is not a reduction over many claim columns. Likewise, endpoint bases are provenance on the same verdict row, not a second validity authority. A separately disclosed evidence-derived occurrence window can remain non-authoritative.
  • Keeping D90’s said-on total processing order while using only world-time for succession is coherent with D88/D90, and “undated never wins temporal succession” is coherent with NULLS LAST as a work-order rule.
  • The bounded-precision canonical formulas truncate both ends correctly, preserve non-empty instants, and give adjacent half-open units the intended behavior. Shipping the SQL function and claims_canonical view addresses the saved-query/open-SQL consistency problem.
  • Keeping canonical observation statements unchanged and deriving dated labels is consistent with D32 and D43; it avoids arrival-order-dependent identity.
  • The D49 additions, assured-operation version rolls, generated manifest/OpenAPI/SDK consequences, and per-package LoCoMo protocol rolls are stated. The design also contains no new phase/MVP hedge or D60/D61 boundary violation.

Merge verdict: request changes. Revision four resolves the conceptual D41 reduction problem, removes occurrence exclusion in the primary design, separates work order from world-time succession, and chooses the right identity-preserving direction for cutover, but it is not yet implementable or internally consistent. First fix the conversion contract—legacy relations have no recorded creator claim and legacy ends are exactly the said-on/now() values D107 is meant to eliminate—then correct the full current predicate/activation schedule and restore D106’s disjoint-date contradiction path. After that, make the relation occurrence transaction and temporal_window verdict schema concrete and align every binding amendment.

@fazpu

fazpu commented Sep 3, 2026

Copy link
Copy Markdown
Member Author

Review triage — round 4 (Codex), dispositions applied in b5311ec

Round four affirmed the direction (verified: seed-once is D41-compatible, bases are provenance not authority, canonical formulas correct, D90 order vs succession coherent, derived labels D32/D43-safe, version rolls stated) and blocked on conversion and predicate details. One of its findings caught a factual error of mine: relation add adjudications carry no triggering_claim_id (I had asserted "both planes"), so legacy relation seeds are unrecoverable. Every disposition is a mechanism, not a rewording.

# Finding (Codex) Verified Disposition
1 Legacy relation seeds are not recorded; observation seeds can be scrubbed by hard forget Yes — _INSERT_ADJUDICATION in supersession.py has no triggering claim Fixed. Seeds are recorded atomically on both planes going forward (seed_claim_id + relation add rows gain triggering_claim_id); seed_claim_id nullable/scrubbable; legacy relations (and scrubbed observations) convert under basis legacy with kind derived from unanimous evidence else undated, each as a recorded migration adjudication. No claim of exact recovery remains (§9).
2 Keeping legacy caps preserves the said-on/now() ends D107 removes; occurrence rows kept caps Yes Fixed. Per recorded cap: recoverable supersede caps recomputed at the successor's world-time start; caps on converted occurrences removed; D55 fallback caps → belief-time close at the persisted reconciliation instant; unrecoverable → legacy_unknown_boundary review items that readiness reports before promotion (§9).
3 Current predicate lacked the lower bound and ingested_at; only expiries scheduled Yes — _FACT_CONTEXT_TIME_PREDICATE / facts_current Fixed. Full containment predicate (§7.1); both activation and expiry instants scheduled and hashed; future-start acceptance case added.
4 "Disjoint windows are always new" dropped D106's disjoint-date contradict Yes — D106 item 1 Fixed. Nomination is unchanged (block + similarity residue, never an overlap filter); the temporal relation bounds the verdict — disjoint: new or contradict, never evidence/supersede (§4.2).
5 State-ending candidates limited to open states; a 2027 resignation could not shorten "CEO 2025–2030" Yes Fixed. Non-invalidated states whose interval extends beyond the boundary, open or finite; guard requires the boundary strictly inside the known window; the cap shortens the end (§4.2, §4.4).
6 Relation write path attaches evidence before any verdict; no idempotency/concurrency contract Yes — upsert_relation Fixed. Relation claims are staged unattached until the verdict under the block lock; new inserts fact + add adjudication + evidence atomically; verdicts idempotent on (triggering_claim_id, adjudicator generation); the exact-no-op short-circuit limited to state/undated triples (§4.2).
7 temporal_window verdict schema not executable; reversal contradicted the invariants Yes Fixed. Concrete temporal_window_verdicts relation (verdict_id, review_id, D49 fact identity, seed, old/new bounds+bases, actor, reverses_verdict_id); reversal is the documented exception (human verdicts over human verdicts), evidence never moves a window (§4.3).
8 Fact checks allow valid_until = valid_from (empty in half-open form); D55 outside the guard Yes Fixed. Non-empty check for states with two known endpoints; the chronological guard applies to every cap source including D55 (§4.1, §4.4).
9 D55 withdrawal erased historical occurrence windows Yes Fixed. occurs_* unions all attached evidence, current or withdrawn; hard forget recomputes from survivors (§3).
10 Audit's D55 "sound" assessment wrong — close_observations is shape-blind Yes — its own docstring Fixed. Audit 4.22; D55 routed by temporal kind (§4.4); §5 bullet narrowed to relations.
11 Stale round-three mechanics in banners; "rebuild" wording; review-count wording Yes Fixed. e2_e3 banner, the D90 design's implementation note, D107 consequences and context rewritten.
12 4.13 example overstated for two instant events Yes Fixed. Narrowed to coarse-vs-instant and adjacent-day cases.

A fifth Codex round runs against b5311ec.

…pen items (D107 round 5)

Codex's fifth review: mapping a NULL claim kind to an `undated` temporal
kind conflated shape with datedness, so "is CEO" with no start was
uncappable and D106's ending-event case was lost again; the verdict matrix
omitted supersede for states; the observations banner still carried the
withdrawn overlap-filter wording; relation_adjudications already has
triggering_claim_id (populate, not add); adjudication_outcome has no
`migrate` value; a D55 cap refused by the guard left a zombie fact; three
audit sentences overstated; one section reference was wrong. It also named
four contracts beyond this design's scope: deterministic relation seeding
under D88 concurrency, locked compare-and-swap review application,
cached-artifact staleness, and the D74 hard-forget inventory.

Kinds are now shape only (state / occurrence / unknown) with bounds known
or unknown independently; a state with unknown bounds can be ended; only
an undated successor cannot supply a boundary; the guard is stated
mechanically; states may supersede within the matrix; D55 closes belief
time fail-closed whenever the world-time cap is unknown or refused; schema
wording corrected and a postgres_schema_design amendment required; §4.3
gains the CAS precondition, order key and item uniqueness; a new §12
records the four open contracts and WP-T.1 is gated on them.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016p9xB9T7VYREuVmohDPKjR
@fazpu

fazpu commented Sep 3, 2026

Copy link
Copy Markdown
Member Author

Independent review — round 5 — Codex (gpt-5.6-sol, reasoning xhigh, review-only run against the fifth revision)

  1. blocker — the temporal-kind/verdict matrix cannot perform the succession that D106 and D107 require.
    Location: plan/designs/temporal_clocks_design.md §§2, 4.1–4.4; plan/plans/temporal_clocks.md WP-T.1; decisions.md D106 rule 2 and D107 items 3–4.
    What is wrong: claim_valid_kind = NULL is mapped to temporal_kind = 'undated', conflating “the source gave no date” with the semantic shape of the fact. Rule 2 then says an undated fact “is never capped,” and §4.2 lets an incoming occurrence end only a state candidate. Therefore a dated resignation cannot end an undated “is CEO” fact, despite D106, D107, the observations banner, and WP-T.1 explicitly requiring that result. Independently, §4.2 says same-kind candidates are eligible only for evidence, contradict, or new; its overlapping row also omits supersede. That makes §4.4’s “successor state’s verdict start” cap unreachable for ordinary state-to-state changes.
    Evidence: D106 says a dated resignation may end an undated state. The new design says both “an undated fact … is never capped” (§2) and “a dated resignation ends an ‘is CEO’ state whose own start may be unknown” (§4.4).
    Suggested fix: Separate semantic shape from datedness—for example, fact_shape = state | occurrence | unknown, with bounds/bases independently known or unknown—or otherwise permit state with unknown bounds. Define the matrix explicitly so overlapping successor states may supersede, a dated ending occurrence can cap an unknown-start state, and only an undated successor is barred from supplying a boundary. Express the guard mechanically as (start IS NULL OR T > start) AND (end IS NULL OR T < end), then align D107, both design banners, and WP-T.1.

  2. blocker — relation seed selection remains nondeterministic under D88 concurrency.
    Location: plan/designs/temporal_clocks_design.md §§4.1–4.2; decisions.md D88; plan/designs/e3_claim_level_normalize_fanout_design.md §§5.3–5.5.
    What is wrong: §4.1 promises that both planes use “the first claim … in D90 processing order,” but D90 orders only the post-barrier observation flush. D88 still has concurrent claim jobs execute upsert relations for this claim, and its decision says “Relation evidence attach is commutative under concurrency.” The new staged relation paragraph does not define a durable staging table, a barrier handoff, or a globally ordered per-block drain. A per-key lock serializes whichever worker arrives first; it does not make that winner the first claim in the specified total order. Atomic seed_claim_id/triggering_claim_id recording therefore records a race rather than removing it, and different schedules can choose different seed windows and occurrence identities.
    Suggested fix: Specify a durable, claim-idempotent relation staging relation and a post-barrier/global per-block drain ordered by the chosen total key, including cross-version single-flight behavior analogous to D90. The fact row, add adjudication, and evidence link can then be atomic for the deterministic head claim. Amend D88 and e3_claim_level_normalize_fanout_design.md; its existing “commutative relation upsert” contract is no longer true.

  3. blocker — the new temporal review verdict is not replay-safe or reversal-safe.
    Location: plan/designs/temporal_clocks_design.md §4.3; decisions.md D24 amendment.
    What is wrong: The proposed relation is concrete enough to name fields but not enough to define a correct state transition:

    • The design raises review for an unknown window becoming dated, yet ordinary verdicts allow a start to move “earlier, never later.” It does not define how NULL/unknown → known satisfies that invariant.
    • A reversal “restores the prior bounds and bases exactly.” If a supersession cap or D55 retraction landed after the original review verdict, that restoration can overwrite or reopen the later close.
    • There is no compare-and-swap requirement that the current bounds still equal the verdict’s old_* values, nor a per-fact locking rule for review versus ingestion/retraction writes.
    • decided_at alone is not a total replay order, and no idempotent uniqueness key is given for repeatedly generating the same discrepancy review item.

    These gaps violate D7 replay determinism and can undo D41’s monotonic fact verdict.
    Suggested fix: Define application under the fact lock with an explicit fact revision or exact old_* precondition; stale verdicts must remain unapplied and return to review. Use a total sequence or (decided_at, verdict_id) plus dependency validation. A reversal should compensate only endpoints changed by the referenced verdict while preserving intervening caps/retractions. Define basis-sensitive unknown → known transitions and a unique review-item fingerprint.

  4. major — a binding amendment banner still contains the withdrawn round-four overlap filter.
    Location: plan/designs/observations_design.md D107 banner, lines 9–12; plan/designs/temporal_clocks_design.md §§4.2 and 10.
    What is wrong: The observations banner says “overlapping windows are a candidate filter the D106 rung judges.” The primary design says nomination is “never an overlap filter,” and §10 explicitly records overlap filtering as withdrawn because it loses D106’s disjoint-date contradiction path. Both texts are marked binding, so the round-four blocker is not resolved across the corpus.
    Suggested fix: Rewrite the banner to say the entity block and similarity ordering nominate candidates regardless of temporal overlap; the temporal relation only bounds the eventual verdict.

  5. major — the migration and authoritative schema contracts are incomplete and contain executable inaccuracies.
    Location: plan/designs/temporal_clocks_design.md §9; plan/plans/temporal_clocks.md WP-T.1; plan/designs/postgres_schema_design.md §§0, 4, 9, 9.A, 13; src/rememberstack/spine/migrations/versions/p0_02_0001_extensions_enums.py:87-93; p0_02_0004_claims_facts_evidence.py:257-270.
    What is wrong: postgres_schema_design.md declares itself the complete specification of every table, enum, key, and deletion rule, but has no D107 amendment. Specific inconsistencies already visible from the current schema are:

    • triggering_claim_id already exists on relation_adjudications; the change is to populate it on relation add writes, not add a column.
    • §9 requires adjudication outcome = migrate, but adjudication_outcome has no migrate, and adjudication_method has no migration method.
    • valid_until set to unknown” is not a valid timestamp operation; it must be NULL with valid_until_basis = 'unknown'.
    • The new basis/kind enum or check types, review-queue integration, keys/FKs, and full DDL for temporal_window_verdicts and fact_expiry_schedule are not specified in the document that claims to own them.

    Suggested fix: Add a D107 schema amendment or update the affected schema sections fully. Enumerate every enum alteration, constraint, tenancy key, index, FK/logical-FK, migration adjudication method/outcome, and review status/result linkage. Correct WP-T.1 to “populate the existing relation-adjudication column.”

  6. major — activation/expiry scheduling does not yet guarantee correctness for cached profiles and K pages.
    Location: plan/designs/temporal_clocks_design.md §7.1.
    What is wrong: The schedule is derived from future boundaries “among their inputs,” but a future fact excluded by the current predicate is not necessarily an artifact input, so its activation may never be scheduled. More importantly, the claimed “read-time predicate” backstop applies to live fact reads, not already-rendered profile text or a static K page. A late sweep can therefore serve a not-yet-refreshed artifact containing an expired fact. Rebuilding at the old boundary instant also fails when multiple boundaries passed during downtime.
    Suggested fix: Define how future facts become artifact dependencies before activation, update schedule rows transactionally whenever a fact boundary/routing relation changes, and regenerate using the current evaluation instant after draining/coalescing all due boundaries. Give cached artifacts a checked valid_through/stale state that prevents them from being presented as current when refresh is late, or narrow the guarantee and expose the staleness through D49.

  7. major — a D55 cap rejected by the chronological guard has no fail-closed belief transition.
    Location: plan/designs/temporal_clocks_design.md §4.4; decisions.md D55.
    What is wrong: Every cap, including D55, is rejected unless its boundary is strictly inside the known state window. The design closes belief time only when source time is unknown. If source time is known but at/before the state start, the cap is refused and merely sent to review; a future-starting, zero-supported fact can later activate because invalidated_at remains null. D55 explicitly rejects leaving a sole-support removal as a zombie fact.
    Suggested fix: When a D55 world-time cap cannot pass the guard, still close belief time at the persisted reconciliation instant—or mark the fact in a fail-closed withdrawn state excluded by every current predicate—while sending only the disputed world-time endpoint to review.

  8. major — D107’s new source-bearing fields and tables are not integrated into hard-forget.
    Location: plan/designs/temporal_clocks_design.md §§3, 4.3, 9; plan/designs/hard_forget_design.md §4; plan/designs/postgres_schema_design.md §13.2; decisions.md D74.
    What is wrong: The design says facts.seed_claim_id is scrubbed and occurs_* recomputed, but temporal_window_verdicts also stores seed_claim_id, actor/rationale, and before/after data; temporal review payloads and migration-adjudication features can also retain forgotten identifiers or source-derived text. D74 requires every new source-bearing field to be classified in the explicit scrub/residual inventory.
    Suggested fix: Amend the hard-forget inventory and canary matrix for the new fact columns, review queue payloads, temporal verdict relation, migration adjudications, schedules, derived labels, and embeddings. Specify delete-versus-null-versus-recompute behavior for each.

  9. minor — several audit consequences are overstated even though the underlying defects are real.
    Location: plan/analysis/time_handling_audit.md §§4.7, 4.9, 4.22.
    What is wrong: §4.7 says relation valid_from is “always empty,” and §4.9 says the relation timeline is “entirely ingest time,” but fact_catalog.py:78-87 seeds a re-occurring relation from _LATEST_CLOSED_UNTIL; first spells are unstamped, not every relation. Section 4.22 says invalidating a withdrawn observation records it as “never believed,” but invalidated_at ends transaction time: belief-as-of before that timestamp still returns it. The real defect is that no state world-time end is recorded and the removal is classified as invalidation.
    Suggested fix: Narrow those sentences while preserving the findings: “first/new spells lack the source window,” “most relation timeline entries fall back to ingest time,” and “the state gets a belief-time invalidation instead of the required world-time close.”

  10. nit — one section reference is wrong.
    Location: plan/designs/temporal_clocks_design.md header, lines 5–6.
    What is wrong: It says §11 records what each review round withdrew; that material is in §10, while §11 is Non-goals.
    Suggested fix: Change §11 to §10.

Verified

  • Audit 4.1 is correct: _group_claim_evidence keys only on normalized text, while group_exact_text=True is used by testimony retrieval; grouped members’ individual temporal fields disappear.

  • Audit 4.2 is correct in its load-bearing form: first relation spells are not seeded from claim_valid_*; the only current non-null start source is a prior closed spell’s end.

  • Audit 4.3 is correct: the relation prompt and both evidence laterals expose claim_text and asserted_at, not the D41 tuple, while asking about the “same period.”

  • Audit 4.4 is correct: relation supersession, observation supersession, and D55 relation closure use said-on boundaries and/or now() fallbacks.

  • Audit 4.5 is correct: the E3 normalizer sees no D41 tuple, and observation statement/label creation has no resolved-date input, so relative wording can reach fact consumers unanchored.

  • Audit 4.6 is correct: the benchmark prompt merely says “Use timestamps” and does not define said-on, is-about, and believed time.

  • Audit 4.7’s core is correct: K sheets render and order by fact valid_from, which today is unstamped for first relations and said-on for observations; only the “always” wording needs narrowing.

  • Audit 4.8 is correct: _SELECT_WRITER_CLAIMS and KnowledgeWriterClaim carry no assertion or D41 dates.

  • The broader searches over asserted_at, claim_valid_*, valid_from, valid_until, ingested_at, and now() did not reveal another distinct material pre-D107 clock-conflation class omitted from the 22 findings.

  • The round-four legacy blocker is directionally resolved: relations no longer claim exact seed recovery; unrecoverable rows use legacy, migrations record adjudications, legacy caps are recomputed/removed/belief-closed/review-routed, and readiness reports unresolved boundaries.

  • The primary design now contains the correct full current predicate, future activation as well as expiry, finite-ended state-ending candidates, a non-empty state check, occurrence windows over withdrawn evidence, and D55 routing by temporal kind.

  • The canonical half-open formulas, point-query conversion, unchanged claim storage, D90 processing-order/world-succession separation, source-faithful statements with derived dated labels, D49 operation rolls, and protocol/generation consequences are sound.

  • valid_*_basis is provenance, not a second validity authority: it does not supply or independently revise an endpoint. Seed-once remains compatible with D41 in principle once deterministic seed selection and review replay are specified.

  • The new design introduces no D60/D61 boundary violation and no prohibited phase/MVP hedge; sequencing is correctly isolated in plan/plans/temporal_clocks.md.

Merge verdict: Not mergeable in revision five. The first required change is to repair the fact-shape/verdict matrix so state-to-state supersession and D106’s dated-ending-event/undated-state case are actually reachable. Next, define deterministic post-barrier relation staging/seed selection and make temporal review application/reversal a locked, totally ordered, stale-safe state transition. The schema, cache scheduling, D55 fallback, hard-forget inventory, and conflicting amendment banner must then be aligned before D107 is implementable and internally consistent.

@fazpu

fazpu commented Sep 3, 2026

Copy link
Copy Markdown
Member Author

Review triage — round 5 (Codex), dispositions in 77c4a77 — and four items left open on purpose

Round five's verified list now covers the predicate, activation/expiry, canonical formulas, the D90/succession separation, D49 rolls, the legacy-conversion direction, D55 by kind, and a repo-wide search that found no further clock-conflation class beyond the 22 findings. Its blockers split into defects in the text (fixed) and contracts that reach into adjacent decisions (recorded as open in a new §12 and gating WP-T.1, pending the operator's call).

# Finding (Codex) Verified Disposition
1 NULL kind → undated conflated shape with datedness; "undated never capped" made D106's dated-resignation-ends-undated-CEO case unreachable; the matrix omitted supersede for states Yes Fixed (design change). Temporal kind is shape only (state / occurrence / unknown), bounds known or unknown independently; a state with unknown bounds can be ended; only an undated successor cannot supply a boundary; the guard is stated mechanically; the matrix includes supersede for states in the disjoint-later, overlapping and mixed-incoming-dated rows (§2, §3, §4.1, §4.2, §4.4).
2 Relation seed selection is a race under D88's commutative concurrent upserts; a per-key lock serialises arrival, not the total order Yes — D88 Open (§12.1). Requires a durable relation staging relation and a post-barrier per-block drain, amending D88 and e3_claim_level_normalize_fanout_design.md. Recorded as a gating spike for WP-T.1.
3 Review verdicts not replay/reversal-safe: no CAS, no total order, reversal may reopen later caps, unknown→known unaddressed, no item uniqueness Yes Partly fixed, remainder open (§12.2). §4.3 now requires compare-and-swap on old_* under the fact lock (stale → back to review), (decided_at, verdict_id) order, per-fact discrepancy fingerprint uniqueness, and defines NULL → known as the one permitted "later" start move. The locking rule against ingestion/retraction writes and the compensating-reversal algorithm are recorded as open.
4 Observations banner still carried the withdrawn overlap-filter wording Yes Fixed. Banner rewritten: nomination unchanged regardless of overlap; the temporal relation only bounds the verdict.
5 Schema inaccuracies: triggering_claim_id already exists on relation adjudications; no migrate outcome/method; "set to unknown" is not a timestamp op; postgres_schema_design.md lacks an amendment Yes Fixed in text; DDL amendment required. Wording corrected (populate the existing column; NULL + basis unknown; migrate/migration enum values named); the design now requires the matching postgres_schema_design.md D107 amendment with full DDL before WP-T.1.
6 Activation/expiry scheduling cannot guarantee correctness for already-rendered artifacts; future facts not yet inputs; downtime coalescing Yes Open (§12.3). Recorded with the required pieces (dependency tracking for not-yet-active facts, transactional schedule maintenance, drain-and-coalesce with the current instant, a checked stale state or D49-disclosed staleness).
7 A D55 cap refused by the guard left a zombie fact (belief interval never closed) Yes Fixed. D55 is fail-closed: whenever the world-time cap is unknown or refused, invalidated_at is set from the persisted reconciliation instant and the disputed endpoint goes to review (§4.4).
8 New source-bearing fields not in the D74 hard-forget inventory Yes Open (§12.4). Each new field/table listed for delete/null/recompute classification in hard_forget_design.md §4 and the canary matrix.
9 Audit 4.7 / 4.9 / 4.22 overstated Yes Fixed. Narrowed to "first spells lack the window", "most relation timeline entries fall back to ingest time", "belief-time invalidation where a world-time close is required".
10 Header referenced §11 for withdrawn mechanics Yes Fixed (§10).

The four open items are decisions that widen D107 into D88, D24's application semantics, K/profile caching, and D74; whether to resolve them inside this PR or as gating spikes before WP-T.1 is the operator's call and is left explicit in the design rather than papered over.

…rom WP-T.1

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016p9xB9T7VYREuVmohDPKjR
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant