Skip to content

Global Model Update

Show how a source change that adds a material effect is reflected in the global Shape model, and how that update can still fail policy checks for the right reason.

Before (passes): the store only grants append.

module audit
resource AuditEvent : AppendOnly
component AuditStore {
owns AuditEvent
grants Append<AuditEvent>
}

After (fails): purge is declared with HardDelete grant and effect.

module audit
resource AuditEvent : AppendOnly
component AuditStore {
owns AuditEvent
grants Append<AuditEvent>
grants HardDelete<AuditEvent>
fn purgeOldEvents
source ts("src/audit/purge.ts#purgeOldEvents")
effects complete {
HardDelete<AuditEvent>
evidence ts("src/audit/purge.ts#purgeOldEvents")
}
}

Before:

Terminal window
shp check path/to/before.shape
Shape check passed.

After:

Terminal window
shp check path/to/after.shape
error: forbidden effect
AuditStore.purgeOldEvents emits HardDelete<AuditEvent>.
AuditEvent has trait AppendOnly.
AppendOnly forbids final HardDelete<AuditEvent>.
evidence: ts("src/audit/purge.ts#purgeOldEvents")

The closely related fail fixture is fixtures/fail/append_only_hard_delete/audit.shape.

Updating the global model is required when architecture claims change, but an accurate claim can still be illegal under resource policy. Final forbids reject the purge effect even when the grant and evidence are explicit.

To land a purge, the architecture decision must change (for example, stop treating the resource as append-only), or the behavior must not be claimed against that resource.