Migrate owned cadence declaration to published contract

Assistant: codex
Assistant-Model: gpt-6.1-sol
Assistant-Session: 01a1029d-2c93-7500-a0e0-e3e089668b29
This commit is contained in:
tegwick 2026-10-03 22:59:46 +02:00
parent 3abb576821
commit 931e0b3249
4 changed files with 289 additions and 52 deletions

View file

@ -1,38 +1,196 @@
# Source-side emission cadence for load-bearing approval evidence.
# Statute §9.6; detection surface GH-WP-0002-T04.
schema_version: "0.1"
source: approval-engine
kind: load-bearing
form: heartbeat-or-reconciliation
rate_monitoring: forbidden
heartbeat:
class: heartbeat
interval: 24h
assertion: nothing-to-report
missing: finding
reconciliation:
compare:
local: committed outbox counts per class
remote: "audit-core event counts where source=approval-engine"
divergence: finding
undrained_local: lag-not-divergence
lag_bound:
outbox_depth: 100
outbox_age: 1h
exceed: finding
classes:
issuance:
action: approval.issuance
use:
action: approval.use
note: "Public CAS consumption under GH-DEC-2026-003."
supersession:
action: approval.supersession
revocation:
action: approval.revocation
heartbeat:
action: approval.heartbeat
{
"schema_version": "0.1",
"declaration_id": "approval-engine-emission-cadence-v0.1",
"source": "approval-engine",
"sources": [
{
"source_id": "approval-engine:issuance",
"source_system": "approval-engine",
"event_class": "issuance",
"form": "heartbeat-or-reconciliation",
"reconciliation": {
"compare_local": "committed outbox issuance counts for the same tenant and bounded window; drained counts exclude pending lag",
"compare_observed": "audit-core accepted action=approval.issuance counts for source=approval-engine, tenant=tenant:platform and identical since/until bounds",
"divergence": "finding",
"undrained_local": "lag-not-divergence"
},
"extensions": {
"netkingdom": {
"evidence_class": "load-bearing",
"rate_monitoring": "forbidden"
},
"approval-engine": {
"action": "approval.issuance"
}
},
"heartbeat": {
"event_class": "audit-core.heartbeat",
"interval_seconds": 86400,
"assertion": "nothing-to-report",
"missing": "finding",
"extensions": {
"approval-engine": {
"asserted_class": "issuance",
"requested_observer_max_gap_seconds": 172800,
"observer_registration_status": "pending"
}
}
}
},
{
"source_id": "approval-engine:use",
"source_system": "approval-engine",
"event_class": "use",
"form": "heartbeat-or-reconciliation",
"reconciliation": {
"compare_local": "committed outbox use counts for the same tenant and bounded window; drained counts exclude pending lag",
"compare_observed": "audit-core accepted action=approval.use counts for source=approval-engine, tenant=tenant:platform and identical since/until bounds",
"divergence": "finding",
"undrained_local": "lag-not-divergence"
},
"extensions": {
"netkingdom": {
"evidence_class": "load-bearing",
"rate_monitoring": "forbidden"
},
"approval-engine": {
"action": "approval.use"
}
},
"heartbeat": {
"event_class": "audit-core.heartbeat",
"interval_seconds": 86400,
"assertion": "nothing-to-report",
"missing": "finding",
"extensions": {
"approval-engine": {
"asserted_class": "use",
"requested_observer_max_gap_seconds": 172800,
"observer_registration_status": "pending"
}
}
}
},
{
"source_id": "approval-engine:supersession",
"source_system": "approval-engine",
"event_class": "supersession",
"form": "heartbeat-or-reconciliation",
"reconciliation": {
"compare_local": "committed outbox supersession counts for the same tenant and bounded window; drained counts exclude pending lag",
"compare_observed": "audit-core accepted action=approval.supersession counts for source=approval-engine, tenant=tenant:platform and identical since/until bounds",
"divergence": "finding",
"undrained_local": "lag-not-divergence"
},
"extensions": {
"netkingdom": {
"evidence_class": "load-bearing",
"rate_monitoring": "forbidden"
},
"approval-engine": {
"action": "approval.supersession"
}
},
"heartbeat": {
"event_class": "audit-core.heartbeat",
"interval_seconds": 86400,
"assertion": "nothing-to-report",
"missing": "finding",
"extensions": {
"approval-engine": {
"asserted_class": "supersession",
"requested_observer_max_gap_seconds": 172800,
"observer_registration_status": "pending"
}
}
}
},
{
"source_id": "approval-engine:revocation",
"source_system": "approval-engine",
"event_class": "revocation",
"form": "heartbeat-or-reconciliation",
"reconciliation": {
"compare_local": "committed outbox revocation counts for the same tenant and bounded window; drained counts exclude pending lag",
"compare_observed": "audit-core accepted action=approval.revocation counts for source=approval-engine, tenant=tenant:platform and identical since/until bounds",
"divergence": "finding",
"undrained_local": "lag-not-divergence"
},
"extensions": {
"netkingdom": {
"evidence_class": "load-bearing",
"rate_monitoring": "forbidden"
},
"approval-engine": {
"action": "approval.revocation"
}
},
"heartbeat": {
"event_class": "audit-core.heartbeat",
"interval_seconds": 86400,
"assertion": "nothing-to-report",
"missing": "finding",
"extensions": {
"approval-engine": {
"asserted_class": "revocation",
"requested_observer_max_gap_seconds": 172800,
"observer_registration_status": "pending"
}
}
}
},
{
"source_id": "approval-engine:heartbeat",
"source_system": "approval-engine",
"event_class": "heartbeat",
"form": "heartbeat-or-reconciliation",
"reconciliation": {
"compare_local": "committed outbox heartbeat counts for the same tenant and bounded window; drained counts exclude pending lag",
"compare_observed": "audit-core accepted action=audit-core.heartbeat counts for source=approval-engine, tenant=tenant:platform and identical since/until bounds",
"divergence": "finding",
"undrained_local": "lag-not-divergence"
},
"extensions": {
"netkingdom": {
"evidence_class": "load-bearing",
"rate_monitoring": "forbidden"
},
"approval-engine": {
"action": "audit-core.heartbeat"
}
}
}
],
"extensions": {
"approval-engine": {
"lag_bound": {
"outbox_depth": 100,
"outbox_age_seconds": 3600,
"exceed": "finding",
"enforcement_status": "observer-delivery-pending"
},
"inventory": {
"load_bearing": [
"issuance",
"use",
"supersession",
"revocation",
"heartbeat"
],
"rare_load_bearing": [
"issuance",
"use",
"supersession",
"revocation"
],
"attributive": []
},
"contract": {
"owner": "info-tech-canon",
"document_version": "0.2.0",
"status": "candidate",
"schema_sha256": "6d52692eb1e4d1325e0d6062d95acded98beddaae5bcfe24c6f0e91f1b6be6ae"
}
}
}
}

View file

@ -24,7 +24,7 @@ becomes a missing positive rather than a quiet month.
| Interval | 24 hours (SHOULD also be emittable on demand) |
| Assertion | `nothing-to-report` |
| Counts | `{issuance, use, supersession, revocation}` of committed outbox rows |
| Missing heartbeat | **finding** |
| Missing heartbeat | **finding** after the requested 172800s receiver bound; registration pending |
### Reconciliation
@ -38,7 +38,7 @@ accepted event counts for `source=approval-engine` and the corresponding
| `use` | `approval.use` |
| `supersession` | `approval.supersession` |
| `revocation` | `approval.revocation` |
| `heartbeat` | `approval.heartbeat` |
| `heartbeat` | `audit-core.heartbeat` |
Undrained local rows are this engine's lag, not yet a divergence. A row
with `drained_at` set that `audit-core` does not hold is the omission
@ -46,7 +46,7 @@ case §9.6 names.
## What is a finding
- No heartbeat arrives for more than one interval.
- No per-class heartbeat arrives beyond the requested 48h receiver bound (24h emission interval).
- `audit-core` count for a class is less than this engine's drained count
for that class.
- Outbox depth or age exceeds the lag bound in `cadence.yaml` (drain stuck).
@ -59,3 +59,55 @@ Atomicity prevents accidental omission (crash between mutation and emit).
Cadence and reconciliation **detect** adversarial omission after the fact.
Nothing in the model prevents a compromised source from suppressing. That
residual is stated, not closed.
## Imported declaration and source inventory — 2026-10-03
`cadence.yaml` now uses InfoTechCanon's published candidate 0.2.0 contract,
schema 0.1, rather than the historical flattened draft. The source-owned
inventory is `extensions.approval-engine.inventory`: issuance, use,
supersession and revocation are rare load-bearing transitions; heartbeat is
the load-bearing delivery control, reconciled without a recursive heartbeat.
No evidence classification or emission interval has been relaxed.
The implementation emits four atomic `audit-core.heartbeat` events, asserting
the four transition classes through `data.class`; it does not emit
`approval.heartbeat`. Production CLI defaults to 86400s. The receiver request
in `audit-source-registration.md` remains 172800s; it is not a live admission
receipt. Lag depth 100 and age 3600s remain declared bounds, with observer
enforcement pending. Repository conformance does not prove stream completeness.
Live closure stays in APPROVAL-WP-0002-T04: audit-core/platform must bind exact
sender `approval-engine`, tenant `tenant:platform`, explicit redact policy,
the already delivered protected credential/native custody (2026-09-11),
authenticated ingest and all four heartbeat class registrations.
Synthetic native accepted/duplicate, read-refusal and independent archive
readback already passed in the platform receipts
`docs/evidence/2026-09-11-factory-native-producers.json` and
`docs/evidence/2026-09-11-factory-native-readback.json`; these do not prove
deployed service or lifecycle transaction emission. Remaining acceptance
requires service admission, actual lifecycle drain and bearer revocation,
same-window drained-versus-accepted reconciliation, startup heartbeat and
missing-class/lag findings. Existing AUDIT-WP-0009 detection code is reused;
neither a second observer nor new receiver APIs are required.
Orientation: Emergent Knowledge 0.2.5, digest
`9e186dbd6f2d5eb455bca24db4b03cd866c63c4e94660430dd15f2ca9856215f`,
start/evidence cards verified-files, orientation-only.
Validation: full owner suite 169 passed. Imported owner schema SHA-256
`6d52692eb1e4d1325e0d6062d95acded98beddaae5bcfe24c6f0e91f1b6be6ae`
and NetKingdom profile returned contract_valid/profile_assessed/conformant true
with zero findings for the authoritative inventory above. Reproduce from
net-kingdom with:
```bash
uv run tools/emission-cadence-profile/emission_cadence_profile.py \
--contract-schema ../info-tech-canon/infospace/schemas/emission-cadence.schema.yaml \
--load-bearing heartbeat \
--rare-load-bearing issuance --rare-load-bearing use \
--rare-load-bearing supersession --rare-load-bearing revocation \
../approval-engine/cadence.yaml
```
This supplies an owner-authored instance to NK-WP-0035; it does not accept the
proposed NetKingdom profile or claim receiver admission/observed cadence.

View file

@ -1,5 +1,9 @@
import json
from pathlib import Path
from approval_engine.audit import audit_envelope
from approval_engine.store import EVENT_CLASSES, HEARTBEAT_CLASSES
ROOT = Path(__file__).resolve().parents[1]
@ -8,15 +12,26 @@ def test_layer_yaml_cadence_declared():
assert "cadence_status: declared" in text
assert "cadence_form: heartbeat-or-reconciliation" in text
assert "cadence: cadence.yaml" in text
assert "cadence_status: undeclared" not in text
def test_cadence_yaml_forbids_rate_monitoring():
text = (ROOT / "cadence.yaml").read_text()
assert "kind: load-bearing" in text
assert "form: heartbeat-or-reconciliation" in text
assert "rate_monitoring: forbidden" in text
assert "missing: finding" in text
assert "divergence: finding" in text
for cls in ("issuance", "use", "supersession", "revocation", "heartbeat"):
assert f"{cls}:" in text
def test_cadence_inventory_matches_durable_emitter(engine):
declaration = json.loads((ROOT / "cadence.yaml").read_text())
inventory = declaration["extensions"]["approval-engine"]["inventory"]
assert set(inventory["load_bearing"]) == set(EVENT_CLASSES)
assert set(inventory["rare_load_bearing"]) == set(HEARTBEAT_CLASSES)
entries = {entry["event_class"]: entry for entry in declaration["sources"]}
assert set(entries) == set(EVENT_CLASSES)
engine.emit_heartbeat()
observed = {audit_envelope(row["payload"])["data"]["class"]:
audit_envelope(row["payload"]) for row in engine.undrained()}
assert set(observed) == set(HEARTBEAT_CLASSES)
for cls in HEARTBEAT_CLASSES:
beat = entries[cls]["heartbeat"]
assert beat["event_class"] == observed[cls]["type"] == "audit-core.heartbeat"
assert beat["assertion"] == observed[cls]["data"]["assertion"]
assert beat["extensions"]["approval-engine"]["asserted_class"] == cls
assert beat["interval_seconds"] == 86400
assert beat["extensions"]["approval-engine"]["requested_observer_max_gap_seconds"] == 172800
assert entries[cls]["extensions"]["netkingdom"]["rate_monitoring"] == "forbidden"
assert entries[cls]["reconciliation"]["undrained_local"] == "lag-not-divergence"
assert "heartbeat" not in entries["heartbeat"] # transport control has no recursive heartbeat

View file

@ -9,7 +9,7 @@ flavor: residual
owner: codex
topic_slug: netkingdom
created: "2026-09-01"
updated: "2026-09-27"
updated: "2026-10-03"
reviewed_at: "2026-09-01"
reviewed_against_commit: "ebce5abb276c01ab29ce2526f3b8abb332dc9e90"
reviewed_note: >-
@ -546,6 +546,7 @@ id: APPROVAL-WP-0002-T04
status: wait
flavor: residual
priority: high
blocking_reason: "Source declaration migrated and emitter mapping verified; sender/native custody delivered 2026-09-11; await canonical receiver declaration and heartbeat class admission, service admission and actual lifecycle outbox/cadence proof plus bearer revocation (synthetic accepted/duplicate/read-refusal/readback already verified 2026-09-11), exact-window reconciliation and observed per-class heartbeat/lag findings. Existing AUDIT-WP-0009 observer implementation is reused."
state_hub_task_id: "777a5cf5-c1db-5e07-8de6-ab109db5ccdc"
```
@ -793,3 +794,14 @@ has exhausted its own reachable surface until an external owner responds;
inbox items received since the 2026-09-10 update (KeyCape/glas-harness/
flex-auth/gate-house/grok) are status requests or informational and do not
supply the missing owner answers. No new task or workplan opened.
## Cadence owner adoption — 2026-10-03
Migrated cadence.yaml to the owner-published InfoTechCanon candidate envelope
and published the source-owned class inventory. Tests compare the declaration
against actual atomic heartbeat outbox envelopes, fixing the historical
approval.heartbeat alias while preserving the 86400s emission and requested
172800s detection bound. Lag enforcement and receiver registration remain
explicitly pending. See docs/emission-cadence.md for the bounded owner acceptance
requirements; T04 stays wait, and this workplan stays blocked. Source validation
does not admit a workload or close its real delivery proof.