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>
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()inApplication/Schema.sql - The architectural fitness function
Test/Architecture/LayerBoundarySpec.hs(Test 1) verifies these trigger names are present in the schema