inter-hub-haskell/contracts/core/append-only-events-v1.md

122 lines
3.6 KiB
Markdown
Raw Normal View History

# 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
```sql
-- 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:
```json
{
"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.
---
feat(WP-0013): IHF Phase 12 — Platform Memory and Continuous Learning Closes the long-range feedback loop: outcome signals now enrich the full traceability chain and feed back into routing, triage, and AI proposals. Schema (T01): - outcome_correlations (CHECK correlation_type) - pattern_performance_records - adaptive_threshold_configs - institutional_knowledge_entries (GIN tsvector FTS) - learning_insights (CHECK insight_type) - ALTER TABLE decision_records + requirement_candidates: outcome_summary JSONB - AFTER INSERT trigger trg_enrich_lineage on outcome_signals - contracts/core/ updated (outcome-summary-columns-v1, append-only addendum) Correlation engine (T02): - Application/Helper/CorrelationEngine.hs: pure annotation→outcome SQL - Web/Controller/OutcomeCorrelations.hs: ComputeCorrelationsAction + index Pattern performance (T03): - Web/Controller/PatternPerformance.hs: ComputePatternPerformanceAction Adaptive thresholds (T04): - Web/Controller/AdaptiveThresholds.hs: CalibrateThresholdsAction - Application/Helper/FrictionScore.hs: applyAdaptiveWeights Institutional knowledge (T05): - DistilDecisionAction in DecisionRecords controller - Web/Controller/InstitutionalKnowledge.hs: QueryKnowledgeBaseAction Lineage enrichment (T06): - Web/Controller/LineageEnrichment.hs: EnrichLineageAction (batch backfill) - enrich_lineage_on_outcome_batch() PL/pgSQL helper in migration Learning dashboard (T07): - Web/Controller/LearningDashboard.hs: 5-panel autoRefresh view - "Learning" nav link in FrontController API v2 learning endpoints (T08): - GET /api/v2/outcome-correlations, /pattern-performance, /knowledge-base/{id} - OpenAPI schemas: OutcomeCorrelation, PatternPerformanceRecord, InstitutionalKnowledgeEntry GAAF scorecard + docs (T09): - Core 3.8→3.9, Functional 3.6→3.8, overall 3.61→3.68 - CLAUDE.md: IHF v0.2 complete, no active workplan Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-01 23:14:15 +00:00
## Phase 12 Addendum — Lineage Enrichment Trigger
**Added in Phase 12 (IHUB-WP-0013 T06):** `outcome_signals` now has an
`AFTER INSERT` trigger `trg_enrich_lineage` that calls
`enrich_lineage_on_outcome()`.
This trigger:
- Is **AFTER INSERT only** — it never fires on UPDATE or DELETE.
- Does **not modify `outcome_signals`** — it only enriches upstream records
(`decision_records.outcome_summary`, `requirement_candidates.outcome_summary`).
- Is consistent with the append-only invariant: the `outcome_signals` row
itself remains immutable after insertion.
---
## Implementation Reference
- Functions: `prevent_interaction_event_mutation()`,
`prevent_outcome_signal_mutation()` in `Application/Schema.sql`
feat(WP-0013): IHF Phase 12 — Platform Memory and Continuous Learning Closes the long-range feedback loop: outcome signals now enrich the full traceability chain and feed back into routing, triage, and AI proposals. Schema (T01): - outcome_correlations (CHECK correlation_type) - pattern_performance_records - adaptive_threshold_configs - institutional_knowledge_entries (GIN tsvector FTS) - learning_insights (CHECK insight_type) - ALTER TABLE decision_records + requirement_candidates: outcome_summary JSONB - AFTER INSERT trigger trg_enrich_lineage on outcome_signals - contracts/core/ updated (outcome-summary-columns-v1, append-only addendum) Correlation engine (T02): - Application/Helper/CorrelationEngine.hs: pure annotation→outcome SQL - Web/Controller/OutcomeCorrelations.hs: ComputeCorrelationsAction + index Pattern performance (T03): - Web/Controller/PatternPerformance.hs: ComputePatternPerformanceAction Adaptive thresholds (T04): - Web/Controller/AdaptiveThresholds.hs: CalibrateThresholdsAction - Application/Helper/FrictionScore.hs: applyAdaptiveWeights Institutional knowledge (T05): - DistilDecisionAction in DecisionRecords controller - Web/Controller/InstitutionalKnowledge.hs: QueryKnowledgeBaseAction Lineage enrichment (T06): - Web/Controller/LineageEnrichment.hs: EnrichLineageAction (batch backfill) - enrich_lineage_on_outcome_batch() PL/pgSQL helper in migration Learning dashboard (T07): - Web/Controller/LearningDashboard.hs: 5-panel autoRefresh view - "Learning" nav link in FrontController API v2 learning endpoints (T08): - GET /api/v2/outcome-correlations, /pattern-performance, /knowledge-base/{id} - OpenAPI schemas: OutcomeCorrelation, PatternPerformanceRecord, InstitutionalKnowledgeEntry GAAF scorecard + docs (T09): - Core 3.8→3.9, Functional 3.6→3.8, overall 3.61→3.68 - CLAUDE.md: IHF v0.2 complete, no active workplan Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-01 23:14:15 +00:00
- Phase 12: `enrich_lineage_on_outcome()` — AFTER INSERT trigger on
`outcome_signals`; enriches non-append-only columns on upstream tables only
- The architectural fitness function `Test/Architecture/LayerBoundarySpec.hs`
(Test 1) verifies these trigger names are present in the schema