Files
inter-hub/contracts/core/append-only-events-v1.md
Bernd Worsch b5d73aa18b
Some checks failed
Test / test (push) Has been cancelled
feat(WP-0009): IHF GAAF Compliance Foundation — type registries, extension manifests, architectural contracts
Implements IHUB-WP-0009: closes four GAAF-2026 gaps before domain hub work begins.
- TypeRegistry helper + controllers/views (hub_kind, hub_capability_manifest)
- HubCapabilityManifest entity with validation and registry linkage
- ARCHITECTURE-LAYERS.md + CI-enforced boundary contracts
- Alembic migration 1743724800, fitness tests (Test/Architecture/)
- GAAF spec, Operational Architecture spec, domain hub extension guide
- Updates to CLAUDE.md, SCOPE.md, Schema.sql, Routes, FrontController, Types

state_hub_sync: pending (tunnel was STALE at completion time; run fix-consistency)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-31 21:17:39 +00:00

2.9 KiB

Append-Only Events Contract

Name: append-only-events Version: 1.0 Date: 2026-03-31 Status: Active Layer: Core Immutable: Yes — this invariant is permanent and cannot be relaxed


Purpose

Interaction events and outcome signals are the primary observational record of the IHF. Their integrity as an append-only log is a foundational invariant: governance, traceability, and antifragility all depend on the fact that the historical record cannot be silently rewritten.


Invariant

The following tables are append-only:

Table Trigger (no update) Trigger (no delete)
interaction_events interaction_events_no_update interaction_events_no_delete
outcome_signals outcome_signals_no_update outcome_signals_no_delete

No row in either table may be modified or deleted after insertion. This invariant is enforced at the PostgreSQL level by BEFORE UPDATE and BEFORE DELETE triggers that raise exceptions. It cannot be bypassed by application code.


Enforcement

-- Implemented in Application/Schema.sql
CREATE TRIGGER interaction_events_no_update
    BEFORE UPDATE ON interaction_events
    FOR EACH ROW EXECUTE FUNCTION prevent_interaction_event_mutation();

CREATE TRIGGER interaction_events_no_delete
    BEFORE DELETE ON interaction_events
    FOR EACH ROW EXECUTE FUNCTION prevent_interaction_event_mutation();

-- Same pattern for outcome_signals

The trigger function raises:

"interaction_events is append-only: UPDATE and DELETE are not permitted"

Correction Policy

Erroneous events must not be corrected by modifying the original row. The correct approach is to insert a new event:

{
  "event_type": "retracted",
  "metadata": {
    "retracted_event_id": "<uuid of original event>",
    "reason": "incorrect actor attribution"
  }
}

The original event remains in the table. Downstream analysis should treat retracted events as markers that exclude the referenced event from calculations.


Failure Mode

Any attempt to UPDATE or DELETE a row in interaction_events or outcome_signals raises a PostgreSQL exception with SQLSTATE P0001. The calling transaction is aborted. No partial mutation is possible.


Scope

This contract applies only to interaction_events and outcome_signals.

Other append-oriented tables (triage_states, widget_ownerships, stewardship_roles) use the same conceptual pattern (soft expiry instead of update, no hard delete) but are not covered by DB-trigger enforcement. Their append semantics are enforced by application-layer controller conventions.


Implementation Reference

  • Functions: prevent_interaction_event_mutation(), prevent_outcome_signal_mutation() in Application/Schema.sql
  • The architectural fitness function Test/Architecture/LayerBoundarySpec.hs (Test 1) verifies these trigger names are present in the schema