Skip to content

feat(kernel): administrative terminal_superseded events — immutable-terminal corrections (#54) - #64

Merged
SollanSystems merged 1 commit into
mainfrom
feat/s2-terminal-superseded
Jul 15, 2026
Merged

SollanSystems merged 1 commit into
mainfrom
feat/s2-terminal-superseded

Conversation

@SollanSystems

Copy link
Copy Markdown
Owner

Administrative terminal_superseded events for the standalone event-log kernel layer — the immutable-terminal correction mechanism PR #48 and ADR 0001 promised ("record any correction as a separate administrative event").

Closes #54

What

  • One new envelope event type terminal_superseded — added to EVENT_TYPES (loop/events.py) and the type enum (schemas/event.schema.json), kept in parity by a new regression test.
  • Write-time shape validation for its payload: the corrected state/criteria_met/evidence/false_completion (+ optional completion_policy) reuse terminal_written's exact key names, plus required non-empty justification and authority {by, at} (audit label, not authentication).
  • Reducer domain semantics (loop/reducer.py):
    • The post-terminal guard is narrowed, not loosened: exactly one type is admitted post-terminal; the other four keep their byte-identical rejection. A terminal_superseded before any terminal is rejected distinctly ("nothing to supersede").
    • causation_id must equal the event_id of the currently-effective terminal record — chaining is safe by construction, and citing a stale, already-superseded record is rejected (prevents two independent corrections silently colliding).
    • The superseded record is appended to a new superseded_history projection (oldest-first, with superseded_by/superseded_at markers); the correction replaces state["terminal"]. Full audit trail = superseded_history + [terminal].
    • G1 is reused verbatim: correcting to Succeeded re-runs the full completion policy, false-completion contradiction, and non-empty-evidence checks — no weaker path for corrections. Direction is unrestricted (revoking a false completion is the flagship use case).
  • One additive ## 18 section in reference/repo-os-contract.md (zero existing lines edited; reconciles §16's "four writer operations" sentence by cross-reference).
  • 48 new tests (20 reducer-domain, 28 store/shape); loop/emit.py, loop/contract.py, loop/completion.py, loop/fsm.py, schemas/terminal.schema.json byte-unchanged.

Verification

  • Deterministic gate (fresh worktree at base 2e9e761e): 7/7 argv — extras 688 passed / 15 skipped (baseline 640/15 + 48 new), pyyaml-only 638 / 65 (603 + 35 passing + 13 honest importorskip release-mode skips), targeted reducer+eventstore 80/80, self_eval/frontmatter/py_compile/json.tool clean.
  • 6/6 fail-loud governor probes (post-terminal immutability regression, nothing-to-supersede, mismatched causation_id, empty-evidence G1, missing justification, DB append-only triggers on supersession streams).
  • 7/7 held-out probes (never shown to the implementing worker): double-terminal_written tamper still rejected; stale citation of the original after a chain rejected; criteria_met: {"done": 1} (truthy non-True) rejected; non-monotonic sequence rejected; two-thread expected_sequence CAS race — exactly one superseding writer wins; whitespace-only authority.by rejected; resume-across-supersession fold byte-identical to whole-stream fold.
  • Fresh independent review: PASS, zero blockers, AC1–AC15 all pass, independent test-count arithmetic 48 = 48 = 48.

Adjudicated design deviation (recorded)

The accepted design's Decision-5 code sketch message ("has no terminal to supersede") contradicted its own AC5 (match="nothing to supersede"). Adjudication: the AC table is normative — the message is "terminal_superseded has nothing to supersede (no terminal record yet)".

Review advisories (non-blocking, recorded)

  1. The domain-layer justification/authority checks are preempted by the write-time shape layer (_payload_issues runs first via _structural_validate_event) — redundancy baked into the design's own Decision 4 + 8 sketches; both layers reject correctly.
  2. A pre-S2 initial= snapshot (no superseded_history key) raises KeyError — same pre-existing class as runlog_entries/receipts bracket access; reduce_events has zero non-test call sites today. Needs a snapshot-versioning story when the event log is wired to real persistence.
  3. The fold's shallow copies share nested references with the caller's payload — identical risk profile to the pre-existing terminal_written fold.

Lane: Claudex (GPT-5.6-terra/medium, attempt 2 after an honest attempt-1 stop on the design contradiction). Receipts: cx_s2_superseded_a1 (repair_requested), cx_s2_superseded_a2 (accepted).

Copilot AI review requested due to automatic review settings July 14, 2026 23:59
@SollanSystems
SollanSystems enabled auto-merge (squash) July 14, 2026 23:59
@SollanSystems
SollanSystems merged commit 84c7173 into main Jul 15, 2026
11 checks passed
@SollanSystems
SollanSystems deleted the feat/s2-terminal-superseded branch July 15, 2026 00:00

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds an administrative terminal_superseded event to the event-log kernel to support immutable-terminal corrections while preserving an audit trail, as promised by the immutable terminal design.

Changes:

  • Introduces terminal_superseded to the event type registry and the event schema enum, with a regression test keeping them in parity.
  • Extends reducer semantics to allow exactly terminal_superseded after a terminal, enforce causation anchoring, and project an oldest-first superseded_history.
  • Documents the new event type and adds store + reducer tests covering shape validation and replay-domain invariants.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
scripts/test_reducer.py Adds reducer-domain tests for post-terminal admission, causation anchoring, chaining/history, and G1 reuse on corrections to Succeeded.
scripts/test_eventstore.py Adds EventStore validation and append tests for the new event type, plus schema/type parity enforcement.
schemas/event.schema.json Extends the type enum to include terminal_superseded.
reference/repo-os-contract.md Documents terminal_superseded semantics, scope boundary, and enforcement split (shape vs reducer domain).
loop/reducer.py Implements replay-domain handling for terminal_superseded, including history projection and causation checks.
loop/events.py Registers the new event type and adds write-time payload shape validation for terminal_superseded.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread loop/reducer.py
def reduce_events(events: Iterable[Mapping[str, Any]], *, initial: Mapping[str, Any] | None = None) -> dict[str, Any]:
"""Fold events without mutating the supplied stream or initial projection."""
state = ({**initial, "runlog_entries": list(initial["runlog_entries"]), "receipts": list(initial["receipts"])} if initial is not None else _empty_projection(None))
state = ({**initial, "runlog_entries": list(initial["runlog_entries"]), "receipts": list(initial["receipts"]), "superseded_history": list(initial["superseded_history"])} if initial is not None else _empty_projection(None))


def test_event_types_include_terminal_superseded_and_match_schema_enum() -> None:
schema = __import__("json").load(open("schemas/event.schema.json", encoding="utf-8"))

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f565191172

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread loop/reducer.py


def _validate_superseded_payload_semantics(payload: Mapping[str, Any]) -> None:
_validate_terminal_payload_semantics(payload)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Validate full terminal shape on supersession

For corrections to a non-Succeeded state, this call returns after checking only the canonical state, so a terminal_superseded payload with non-boolean criteria_met, blank evidence entries, or an unsupported completion_policy is accepted and installed as state["terminal"]. That lets administrative corrections create terminal projections that loop.emit.terminate()/loop.contract._validate_terminal() would reject as invalid terminal records; validate the full terminal field shape before the G1-only success checks short-circuit.

Useful? React with 👍 / 👎.

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.

Administrative TerminalSuperseded events for terminal corrections

2 participants