Adopt shared hourly coordination frame and prepare guarded runtime patches
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 2s

Assistant: codex
Assistant-Model: gpt-6-astra
Assistant-Session: 01a13eab-1e6a-7b33-9c37-372e90ada3a2
This commit is contained in:
tegwick 2026-10-15 20:45:06 +02:00
parent a83691398e
commit 2d0681f361
15 changed files with 860 additions and 70 deletions

View file

@ -26,6 +26,7 @@ If yes to any of the above, don't add it here.
| CP-NK-004 | KeyCape OIDC hostname | `kc.coulomb.social` | `sso-mfa/k8s/keycape/ingress.yaml`, `sso-mfa/k8s/authelia/configmap.yaml`, `sso-mfa/k8s/keycape/create-secrets.sh` |
| CP-NK-005 | Authelia login portal hostname | `auth.coulomb.social` | `sso-mfa/k8s/authelia/ingress.yaml`, `sso-mfa/k8s/authelia/configmap.yaml` |
| CP-NK-006 | LLDAP admin web UI hostname | `lldap.coulomb.social` | `sso-mfa/k8s/lldap/ingress.yaml` |
| CP-NK-007 | Ecosystem coordination frame | `f = 1h` | `coordination-engine/config/coordination-frame.json` (owner source) |
---
@ -144,3 +145,18 @@ to the parent domain (`coulomb.social`) so the cookie is valid across both
is IP-restricted by the `lldap-admin-allowlist` Traefik Middleware (VPN/office
CIDRs only). The LDAP port (3890) is cluster-internal only and never exposed
via Ingress.
## CP-NK-007 — Ecosystem coordination frame
**Owner:** coordination-engine. **Initial setting:** `frame_seconds: 3600`.
Founder decision 2026-10-15: pace long-term coordination in hourly rather than
daily frames. This is an operator-selected pace, not a topology-derived value.
The canonical file is `coordination-engine/config/coordination-frame.json`;
NetKingdom keeps no independent editable copy.
Cadence adopters derive heartbeat f, receiver wait 2f and effective deadline
3f (including Audit Core's existing 1.5 grace). Change f once, then run
`tools/coordination-frame/render.py --write` and `--check`. Generated owner
artifacts carry the source digest. Runtime owners deploy reviewed artifacts;
source regeneration is not deployment or estate-wide timer adoption.

View file

@ -159,3 +159,16 @@ This profile can become accepted only when:
checked with owner-authored class inventories; and
- `kings-guard` has been given the canonical coordinates so its handover draft
can become historical.
## Coordination-frame configuration — 2026-10-15
Source owners may derive their cadence timing from the ecosystem coordination
frame at `coordination-engine/config/coordination-frame.json`. The operator's
current frame is f=1h; the first adopter mapping is heartbeat f, receiver wait
2f, and effective missing-heartbeat deadline 3f after the receiver's 1.5 grace.
Namespaced frame provenance accompanies the derived numeric declaration values.
Changing the frame requires regenerating the source/receiver settings together
and separately deploying them through owner change control. It changes neither
source classification nor the heartbeat-plus-reconciliation requirement, and
a compiled configuration is not evidence of operating emission or observation.

View file

@ -0,0 +1,29 @@
[
{
"op": "test",
"path": "/metadata/uid",
"value": "8b44c901-024f-4472-a822-2fd07aa2be5f"
},
{
"op": "test",
"path": "/metadata/resourceVersion",
"value": "75292270"
},
{
"op": "add",
"path": "/spec/template/metadata/annotations",
"value": {
"coordination.coulomb.social/frame-sha256": "d15e092387f128ffdfd00b9815707a05ff77c5bb0ba4d9a428fbc37b8c440b67"
}
},
{
"op": "add",
"path": "/spec/template/spec/containers/0/args/-",
"value": "--heartbeat-seconds"
},
{
"op": "add",
"path": "/spec/template/spec/containers/0/args/-",
"value": "3600"
}
]

View file

@ -0,0 +1,18 @@
{
"workplan_id": "04685f94-1991-5e62-80d2-5669913e99fc",
"id": "1ac5a70f-082e-4d8f-9ac8-59e4c175da02",
"topic_id": null,
"title": "Use a configurable ecosystem coordination frame, initially one hour",
"description": "Founder directs one base duration frame for ecosystem coordination timelines and deadlines. Set f=1h now, with waits expressed as 2f and 3f rather than independent day constants. First cadence adoption: heartbeat f, registered receiver wait 2f, existing 1.5 grace yields effective 3f.",
"decision_type": "made",
"status": "resolved",
"rationale": "Small team is moving quickly; long-term coordination currently needs an hourly rather than daily pace. Owner-reviewed adoption retains timing formulas and frame provenance. This records the configuration decision, not an approval of an unspecified live rollout.",
"decided_by": "Bernd Worsch (founder), explicit session instruction",
"decided_at": "2026-10-15T18:05:48.234679Z",
"deadline": null,
"escalation_note": null,
"superseded_by": null,
"created_at": "2026-10-15T18:05:49.826919Z",
"updated_at": "2026-10-15T18:05:49.826919Z",
"workstream_id": "04685f94-1991-5e62-80d2-5669913e99fc"
}

View file

@ -0,0 +1,47 @@
{
"decision_id": "1ac5a70f-082e-4d8f-9ac8-59e4c175da02",
"config": {
"ref": "coordination-engine/config/coordination-frame.json",
"sha256": "d15e092387f128ffdfd00b9815707a05ff77c5bb0ba4d9a428fbc37b8c440b67",
"frame_seconds": 3600,
"heartbeat_frames": 1,
"registered_wait_frames": 2,
"effective_deadline_frames": 3,
"decision_id": "1ac5a70f-082e-4d8f-9ac8-59e4c175da02"
},
"tests": {
"coordination_engine": {
"passed": 73,
"skipped": 1
},
"coordination_frame_and_profile": {
"passed": 32
},
"approval_engine": {
"passed": 271
},
"qonto_assistant": {
"passed": 91
},
"rapp_qonto": {
"passed": 25
},
"kings_guard": {
"passed": 128
}
},
"compiler_check": "no drift",
"source_assessments": "source-assessments-f1h.json",
"manifest_preservation": "semantic comparison against committed manifests proves only heartbeat settings and frame digest annotations changed; image/identity/secrets/routing/scaling preserved",
"deployment_applied": false,
"registry_applied": false,
"independent_live_observer_proved": false,
"source_commits": {
"coordination-engine": "f658556690f3f6b7efe9c95a445222019182e402",
"approval-engine": "a786b061da4d7730c0827cf4919ab9206aed6d3e",
"qonto-assistant": "5eb7e86f7a5fccf8bb8c40bd991e32bb9ae440c9",
"rapp-qonto": "51de093b4431fc7cc569be84bc20cbff7aa6a4d5",
"kings-guard": "164a4cdaf12e7a450ac225f7a645e769a3e76f40"
},
"runtime_preflight": "Both timing-only patches passed server dry-run on verified railiance01; nothing applied"
}

View file

@ -4,6 +4,99 @@
"profile_status": "proposed",
"live_observer_proved": false,
"source_files": {
"approval_source": {
"path": "../approval-engine/cadence.yaml",
"sha256": "cc58c8d53ebf50acf540d73b7607d579942bda7734c3e8722108e9c9204af655"
},
"qonto_source": {
"path": "../qonto-assistant/specs/audit-emission-cadence.yaml",
"sha256": "adedbe06e04c38812057db97364557644157eb5f72f16adebb6f7beec1587005"
},
"generic_schema": {
"path": "../info-tech-canon/infospace/schemas/emission-cadence.schema.yaml",
"sha256": "6d52692eb1e4d1325e0d6062d95acded98beddaae5bcfe24c6f0e91f1b6be6ae"
},
"bearer_revocation_receipt": {
"path": "../audit-core/docs/evidence/2026-09-15-sender-bearer-revocation.json",
"sha256": "8da798005611711f4a3da969597a3763e6c02e41013df5227b0434dc328b6fb3"
},
"qonto_historical_capture": {
"path": "../rapp-qonto/evidence/live/2026-09-05-audit-rollout.json",
"sha256": "1cad71fe93ab2a9f7d5dbc99b9aada47c212a7e43813a86ea91f52639e163be9"
}
},
"approval_engine_registration_proposal": {
"status": "not-applied; founder selected configurable f=1h",
"sender": "approval-engine",
"source": "approval-engine",
"tenant": "tenant:platform",
"preserve": [
"tokens",
"secret_policy=redact",
"may_write=true",
"may_read=false",
"existing other senders and registry fields"
],
"emission_cadence": "Import exact source-owned cadence.yaml at the pinned digest; never use a draft/fallback schema",
"class_mapping": {
"issuance": "approval.issuance",
"use": "approval.use",
"supersession": "approval.supersession",
"revocation": "approval.revocation",
"heartbeat": "audit-core.heartbeat"
},
"heartbeat_transport": "audit-core.heartbeat",
"covered_class_field": "data.class",
"source_interval_seconds": 3600,
"source_requested_bound_seconds": 7200,
"receiver_grace_factor": 1.5,
"live_steps": [
"Verify generated one-hour frame bindings, current runtime/source pins and separately approved rollout scope",
"Review exact protected-registry metadata-only patch preserving credentials and all unrelated entries",
"Founder approves exact runtime change; use governed owner custody with contained session and CAS/readback",
"Receiver reload under owner change gate; prove actual per-class registration and class-isolated heartbeats",
"Emit/drain actual lifecycle transitions under owner-scoped authority; correlate occurrence, acknowledgment and receiver acceptance windows including lag and duplicates",
"Independent readback/count comparison and missing-class/lag findings; retain value-safe receipts"
],
"existing_revocation_proof": "2026-09-15 T1 accepted 202, dropped T1 refused 401, incumbent T0 accepted 202; do not repeat unchanged synthetic proof as if absent",
"effective_deadline_seconds": 10800,
"coordination_frame": {
"ref": "coordination-engine/config/coordination-frame.json",
"sha256": "d15e092387f128ffdfd00b9815707a05ff77c5bb0ba4d9a428fbc37b8c440b67",
"frame_seconds": 3600,
"heartbeat_frames": 1,
"registered_wait_frames": 2,
"effective_deadline_frames": 3,
"decision_id": "1ac5a70f-082e-4d8f-9ac8-59e4c175da02"
}
},
"qonto": {
"required_owner": "rapp-qonto",
"missing": "Actual stdout collector/sender source/image/config and governed delivery lane",
"authoritative_workload_tenant": "tenant:friendly:binky (rapp-qonto binding; collector mapping still needs source/receiver review)",
"receiver_commitment": "AUDIT-WP-0013-T05",
"receiver_instance_filter": "Implemented in AUDIT-WP-0013-T04; reviewed release and native proof still required",
"source_coordination": "QONTO-WP-0006-T02",
"observer_acceptance": "KG-WP-0005-T03 then QONTO-WP-0006-T03",
"historical_receipt_limit": "Source-path capture with startup and deny; not independent collector/feed acceptance",
"source_interval_seconds": 3600,
"runtime_status": "source settings prepared; not deployed in this session"
},
"local_identity": {
"status": "explicit incompatibility retained",
"expected_findings": [
"rare-heartbeat-missing:revoke-token",
"rare-heartbeat-missing:serve/token.token_issued"
],
"completeness_claimed": false
},
"observer_fix": {
"defect": "Shared heartbeat event type could mask silence of another covered class",
"change": "Require explicit covered_event_classes as well as matching transport class; retain source/adapter coverage, not inferred traffic/count keys",
"old_regression": "False COMPLETE for unscoped audit-core.heartbeat across issuance/revocation",
"deployment_or_live_acceptance": false
},
"source_files_before_frame": {
"approval_source": {
"path": "../approval-engine/cadence.yaml",
"sha256": "0389be492628e2df0d84a70755c92aaf4a749bc64fbf2772e0c3301c3e1fe5ed"
@ -25,73 +118,13 @@
"sha256": "1cad71fe93ab2a9f7d5dbc99b9aada47c212a7e43813a86ea91f52639e163be9"
}
},
"approval_engine_registration_proposal": {
"status": "not-applied; owner deadline decision pending",
"sender": "approval-engine",
"source": "approval-engine",
"tenant": "tenant:platform",
"preserve": [
"tokens",
"secret_policy=redact",
"may_write=true",
"may_read=false",
"existing other senders and registry fields"
],
"emission_cadence": "Import exact source-owned cadence.yaml at the pinned digest; never use a draft/fallback schema",
"class_mapping": {
"issuance": "approval.issuance",
"use": "approval.use",
"supersession": "approval.supersession",
"revocation": "approval.revocation",
"heartbeat": "audit-core.heartbeat"
},
"heartbeat_transport": "audit-core.heartbeat",
"covered_class_field": "data.class",
"source_interval_seconds": 86400,
"source_requested_bound_seconds": 172800,
"receiver_grace_factor": 1.5,
"deadline_options": [
{
"effective_seconds": 172800,
"registration_seconds": 115200
},
{
"effective_seconds": 259200,
"registration_seconds": 172800
}
],
"live_steps": [
"Owner confirms effective heartbeat deadline and current runtime/source pin",
"Review exact protected-registry metadata-only patch preserving credentials and all unrelated entries",
"Founder approves exact runtime change; use governed owner custody with contained session and CAS/readback",
"Receiver reload under owner change gate; prove actual per-class registration and class-isolated heartbeats",
"Emit/drain actual lifecycle transitions under owner-scoped authority; correlate occurrence, acknowledgment and receiver acceptance windows including lag and duplicates",
"Independent readback/count comparison and missing-class/lag findings; retain value-safe receipts"
],
"existing_revocation_proof": "2026-09-15 T1 accepted 202, dropped T1 refused 401, incumbent T0 accepted 202; do not repeat unchanged synthetic proof as if absent"
},
"qonto": {
"required_owner": "rapp-qonto",
"missing": "Actual stdout collector/sender source/image/config and governed delivery lane",
"authoritative_workload_tenant": "tenant:friendly:binky (rapp-qonto binding; collector mapping still needs source/receiver review)",
"receiver_commitment": "AUDIT-WP-0013-T05",
"receiver_instance_filter": "Implemented in AUDIT-WP-0013-T04; reviewed release and native proof still required",
"source_coordination": "QONTO-WP-0006-T02",
"observer_acceptance": "KG-WP-0005-T03 then QONTO-WP-0006-T03",
"historical_receipt_limit": "Source-path capture with startup and deny; not independent collector/feed acceptance"
},
"local_identity": {
"status": "explicit incompatibility retained",
"expected_findings": [
"rare-heartbeat-missing:revoke-token",
"rare-heartbeat-missing:serve/token.token_issued"
],
"completeness_claimed": false
},
"observer_fix": {
"defect": "Shared heartbeat event type could mask silence of another covered class",
"change": "Require explicit covered_event_classes as well as matching transport class; retain source/adapter coverage, not inferred traffic/count keys",
"old_regression": "False COMPLETE for unscoped audit-core.heartbeat across issuance/revocation",
"deployment_or_live_acceptance": false
"coordination_frame": {
"ref": "coordination-engine/config/coordination-frame.json",
"sha256": "d15e092387f128ffdfd00b9815707a05ff77c5bb0ba4d9a428fbc37b8c440b67",
"frame_seconds": 3600,
"heartbeat_frames": 1,
"registered_wait_frames": 2,
"effective_deadline_frames": 3,
"decision_id": "1ac5a70f-082e-4d8f-9ac8-59e4c175da02"
}
}

View file

@ -0,0 +1,37 @@
[
{
"op": "test",
"path": "/metadata/uid",
"value": "a665e1d0-3ada-4b27-ac56-a8d452499003"
},
{
"op": "test",
"path": "/metadata/resourceVersion",
"value": "57092911"
},
{
"op": "add",
"path": "/spec/template/metadata/annotations/coordination.coulomb.social~1frame-sha256",
"value": "d15e092387f128ffdfd00b9815707a05ff77c5bb0ba4d9a428fbc37b8c440b67"
},
{
"op": "replace",
"path": "/spec/template/spec/containers/0/env/0/value",
"value": "3600"
},
{
"op": "add",
"path": "/spec/traffic",
"value": [
{
"revisionName": "rapp-qonto-00009",
"percent": 100
},
{
"latestRevision": true,
"percent": 0,
"tag": "frame-preview"
}
]
}
]

View file

@ -0,0 +1,18 @@
{
"approval-engine": {
"patch": "approval-engine-frame-runtime-patch.json",
"server_dry_run_exit": 0,
"resource_uid": "8b44c901-024f-4472-a822-2fd07aa2be5f",
"resource_version": "75292270",
"additional_owner_step": "OnDelete requires separately approved controlled restart of approval-engine-0; image and storage schema stay unchanged",
"live_mutations": false
},
"rapp-qonto": {
"patch": "rapp-qonto-frame-runtime-patch.json",
"server_dry_run_exit": 0,
"resource_uid": "a665e1d0-3ada-4b27-ac56-a8d452499003",
"resource_version": "57092911",
"additional_owner_step": "Keep all traffic on the current Ready revision while creating zero-percent frame-preview candidate; promote only after owner verification",
"live_mutations": false
}
}

View file

@ -0,0 +1,34 @@
{
"live_mutations": false,
"cluster_uid": "a553c742-0115-43d4-99a4-a5ca56fe0786",
"resources": {
"approval-engine": {
"available": true,
"kind": "statefulset",
"namespace": "approval-engine",
"uid": "8b44c901-024f-4472-a822-2fd07aa2be5f",
"resource_version": "75292270",
"image": "forgejo.coulomb.social/coulomb/approval-engine@sha256:251941a5cb2724b57cc32cff6b693b1ab0be695bee4f56f02d51961189c0fa49",
"heartbeat_argument_seconds": [],
"heartbeat_environment_seconds": [],
"frame_digest": null,
"status_ready": 1,
"rollout_strategy": "OnDelete"
},
"rapp-qonto": {
"available": true,
"kind": "ksvc",
"namespace": "rapp-qonto",
"uid": "a665e1d0-3ada-4b27-ac56-a8d452499003",
"resource_version": "57092911",
"image": "forgejo.coulomb.social/coulomb/rapp-qonto@sha256:2e42b5e665a19ffa3b3ae8109a8aab64f5485329f72810be063263ff5086cb3f",
"heartbeat_argument_seconds": [],
"heartbeat_environment_seconds": [
"86400"
],
"frame_digest": null,
"status_ready": "rapp-qonto-00009",
"rollout_strategy": null
}
}
}

View file

@ -0,0 +1,92 @@
{
"live_observer_proved": false,
"reports": {
"approval-engine": {
"assessment_scope": "supplied-inventory",
"conformant": true,
"contract_schema": "../info-tech-canon/infospace/schemas/emission-cadence.schema.yaml",
"contract_valid": true,
"declaration": "../approval-engine/cadence.yaml",
"findings": [],
"inventory": {
"attributive": [],
"load_bearing": [
"heartbeat"
],
"rare_load_bearing": [
"issuance",
"revocation",
"supersession",
"use"
]
},
"profile": "netkingdom-emission-cadence-security-profile-v0.1",
"profile_assessed": true,
"summary": {
"must": 0,
"should": 0
}
},
"local-identity": {
"assessment_scope": "supplied-inventory",
"conformant": false,
"contract_schema": "../info-tech-canon/infospace/schemas/emission-cadence.schema.yaml",
"contract_valid": true,
"declaration": "local-identity/emission-cadence.yaml",
"findings": [
{
"code": "rare-heartbeat-missing",
"event_class": "revoke-token",
"level": "MUST",
"message": "rare load-bearing evidence requires a positive heartbeat"
},
{
"code": "rare-heartbeat-missing",
"event_class": "serve/token.token_issued",
"level": "MUST",
"message": "rare load-bearing evidence requires a positive heartbeat"
}
],
"inventory": {
"attributive": [],
"load_bearing": [],
"rare_load_bearing": [
"revoke-token",
"serve/token.token_issued"
]
},
"profile": "netkingdom-emission-cadence-security-profile-v0.1",
"profile_assessed": true,
"summary": {
"must": 2,
"should": 0
}
},
"qonto-assistant": {
"assessment_scope": "supplied-inventory",
"conformant": true,
"contract_schema": "../info-tech-canon/infospace/schemas/emission-cadence.schema.yaml",
"contract_valid": true,
"declaration": "../qonto-assistant/specs/audit-emission-cadence.yaml",
"findings": [],
"inventory": {
"attributive": [
"audit.allow"
],
"load_bearing": [
"audit.deny",
"audit.heartbeat"
],
"rare_load_bearing": [
"audit.deny"
]
},
"profile": "netkingdom-emission-cadence-security-profile-v0.1",
"profile_assessed": true,
"summary": {
"must": 0,
"should": 0
}
}
}
}

View file

@ -0,0 +1,26 @@
{
"status": "proposed-not-applied",
"coordination_frame": {
"ref": "coordination-engine/config/coordination-frame.json",
"sha256": "d15e092387f128ffdfd00b9815707a05ff77c5bb0ba4d9a428fbc37b8c440b67",
"frame_seconds": 3600,
"heartbeat_frames": 1,
"registered_wait_frames": 2,
"effective_deadline_frames": 3
},
"sender": "approval-engine",
"source": "approval-engine",
"tenant": "tenant:platform",
"may_read": false,
"emission_cadence_ref": "approval-engine/cadence.yaml",
"emission_cadence_sha256": "cc58c8d53ebf50acf540d73b7607d579942bda7734c3e8722108e9c9204af655",
"heartbeat_classes": {
"issuance": 7200,
"use": 7200,
"supersession": 7200,
"revocation": 7200
},
"receiver_grace_factor": 1.5,
"effective_deadline_seconds": 10800,
"preserve_existing_credentials_and_other_registry_fields": true
}

View file

@ -0,0 +1,42 @@
# Coordination-frame bindings
The ecosystem frame is owned by coordination-engine at
`coordination-engine/config/coordination-frame.json`. Its initial value is
`frame_seconds: 3600`, selected by the founder on 2026-10-15. Change that one
setting to change the pace. The owner API validates positive integer frames
and derives timezone-bound deadlines; this tool imports that API, with no
fallback config or duplicated reader.
For cadence adoption the formulas are heartbeat **f**, registered receiver
wait **2f**, and effective missing-heartbeat deadline **3f** after Audit Core's
existing 1.5 grace. At f=1h those are 3600, 7200 and 10800 seconds. A return
to f=24h produces 24h/48h/72h through the same formulas.
From net-kingdom:
```sh
python3 tools/coordination-frame/render.py # read-only source plan
python3 tools/coordination-frame/render.py --check # fail on derived-file drift
python3 tools/coordination-frame/render.py --write # regenerate source artifacts
python3 -m pytest -q tools/coordination-frame/tests
```
`--write` changes only the listed source files. It prepares Approval Engine
and Qonto declarations, generated Python defaults, both deployment heartbeat
settings, and a non-secret proposed Approval Engine receiver registration.
The compiler preserves image pins, identity, secret references, other source
classifications and the lack of a completeness claim. Each generated consumer
records the frame source and SHA-256. Runtime consumers import their generated
values rather than opening an adjacent coordination-engine checkout.
Check generated artifacts after changing the frame, review/commit each owner
source, then use the owner's approved release and registry procedures. This
tool performs no login, credential operation, registry update or deployment.
It cannot replace a source collector or provide operational observer evidence.
All five binding tests require the sibling owner checkouts and explicitly skip
when they are unavailable; no substitute owner contract is used.
This is the first rollout of a shared coordination setting. Other ecosystem
coordination consumers must adopt explicit frame multipliers through their own
configuration. Transport polling, security validity and credential leases are
not silently rescaled by a coordination setting.

View file

@ -0,0 +1,214 @@
#!/usr/bin/env python3
"""Compile owner-reviewed cadence bindings from the ecosystem coordination frame."""
from __future__ import annotations
import argparse
import hashlib
import importlib.util
import json
import re
import sys
from pathlib import Path
import yaml
ROOT = Path(__file__).resolve().parents[2]
FRAME_REF = "coordination-engine/config/coordination-frame.json"
def owner_frame(workspace: Path):
source = workspace / "coordination-engine/src/coordination_engine/timing.py"
spec = importlib.util.spec_from_file_location("coordination_frame_owner", source)
if spec is None or spec.loader is None:
raise ValueError("coordination-engine frame API is required; no fallback")
module = importlib.util.module_from_spec(spec)
sys.modules[spec.name] = module
spec.loader.exec_module(module)
return module.load_frame(workspace / FRAME_REF)
def generated_module(frame, digest):
return (
'"""Generated cadence timings; regenerate with NetKingdom coordination-frame tool."""\n'
f"# Source: {FRAME_REF}\n"
f'FRAME_CONFIG_SHA256 = "{digest}"\n'
f"FRAME_SECONDS = {frame.frame_seconds}\n"
f"RECEIVER_WAIT_SECONDS = {frame.seconds(2)}\n"
f"EFFECTIVE_DEADLINE_SECONDS = {frame.seconds(3)}\n"
)
def bind_frame_annotation(text, digest, metadata_prefix):
key = "coordination.coulomb.social/frame-sha256"
pattern = r"(?m)^(\s*" + re.escape(key) + r": )[^\n]+"
if re.search(pattern, text):
updated, count = re.subn(pattern, lambda match: match[1] + json.dumps(digest), text)
else:
replacement = (
metadata_prefix
+ "annotations:\n"
+ " " * (len(metadata_prefix.splitlines()[-1]) + 2)
+ key
+ ": "
+ json.dumps(digest)
+ "\n"
)
# metadata_prefix ends with the indentation for annotations. Existing
# annotation maps retain their contents; otherwise insert a new map.
if metadata_prefix + "annotations:\n" in text:
updated = text.replace(metadata_prefix + "annotations:\n", replacement, 1)
count = 1
else:
updated = text.replace(
metadata_prefix, replacement + metadata_prefix.rsplit("\n", 1)[-1], 1
)
count = int(updated != text)
if count != 1:
raise ValueError("expected one runtime frame provenance binding")
return updated
def compile_bindings(workspace: Path):
frame = owner_frame(workspace)
digest = hashlib.sha256((workspace / FRAME_REF).read_bytes()).hexdigest()
provenance = {
"ref": FRAME_REF,
"sha256": digest,
"frame_seconds": frame.frame_seconds,
"heartbeat_frames": 1,
"registered_wait_frames": 2,
"effective_deadline_frames": 3,
}
outputs = {}
for relative in (
"approval-engine/approval_engine/coordination.py",
"qonto-assistant/src/qonto_assistant/coordination.py",
):
outputs[workspace / relative] = generated_module(frame, digest)
approval_path = workspace / "approval-engine/cadence.yaml"
approval = json.loads(approval_path.read_text())
for entry in approval["sources"]:
if "heartbeat" in entry:
beat = entry["heartbeat"]
beat["interval_seconds"] = frame.frame_seconds
ext = beat["extensions"]["approval-engine"]
ext["requested_observer_max_gap_seconds"] = frame.seconds(2)
ext["effective_deadline_seconds"] = frame.seconds(3)
approval["extensions"].setdefault("netkingdom", {})["coordination_frame"] = provenance
outputs[approval_path] = json.dumps(approval, indent=2) + "\n"
qonto_path = workspace / "qonto-assistant/specs/audit-emission-cadence.yaml"
qonto = yaml.safe_load(qonto_path.read_text())
for entry in qonto["sources"]:
if "heartbeat" in entry:
entry["heartbeat"]["interval"] = f"PT{frame.frame_seconds}S"
heartbeat = qonto["extensions"]["qonto-assistant"]["heartbeat"]
heartbeat["interval"] = f"PT{frame.frame_seconds}S"
heartbeat["default_interval_seconds"] = frame.frame_seconds
qonto["extensions"]["netkingdom"]["coordination_frame"] = provenance
outputs[qonto_path] = (
"# Source-owned cadence; coordination timings generated from "
+ FRAME_REF
+ "\n"
+ yaml.safe_dump(qonto, sort_keys=False)
)
deploy_path = workspace / "approval-engine/deploy/approval-engine.yaml"
deploy = deploy_path.read_text()
if re.search(r"^\s+- --heartbeat-seconds\s*$", deploy, re.M):
deploy, count = re.subn(
r"(?m)^(\s+- --heartbeat-seconds\n\s+- )[^\n]+",
lambda m: m[1] + json.dumps(str(frame.frame_seconds)),
deploy,
)
else:
# Explicit runtime arg also works with the already pinned image; no image
# pin, storage migration, authority or unrelated deployment change here.
deploy, count = re.subn(
r"(?m)^(\s+)- --audit-url$",
lambda m: (
f'{m[1]}- --heartbeat-seconds\n{m[1]}- "{frame.frame_seconds}"\n{m[1]}- --audit-url'
),
deploy,
)
if count != 1:
raise ValueError("expected one Approval Engine heartbeat argument binding")
outputs[deploy_path] = bind_frame_annotation(
deploy, digest, " template:\n metadata:\n "
)
deploy_path = workspace / "rapp-qonto/runtime/knative/service.yaml"
deploy, count = re.subn(
r"(?m)(name: QONTO_AUDIT_HEARTBEAT_INTERVAL_SECONDS\n\s+value: )[^\n]+",
lambda m: m[1] + json.dumps(str(frame.frame_seconds)),
deploy_path.read_text(),
)
if count != 1:
raise ValueError("expected one Qonto heartbeat environment binding")
outputs[deploy_path] = bind_frame_annotation(
deploy, digest, " template:\n metadata:\n "
)
fixture_path = (
workspace / "kings-guard/src/kings_guard/fixtures/qonto_assistant_source_cadence.json"
)
fixture = json.loads(fixture_path.read_text())
for entry in fixture["sources"]:
if "heartbeat" in entry:
entry["heartbeat"]["interval_seconds"] = frame.frame_seconds
fixture["extensions"].setdefault("netkingdom", {})["coordination_frame"] = provenance
outputs[fixture_path] = json.dumps(fixture, indent=2) + "\n"
receiver = {
"status": "proposed-not-applied",
"coordination_frame": provenance,
"sender": "approval-engine",
"source": "approval-engine",
"tenant": "tenant:platform",
"may_read": False,
"emission_cadence_ref": "approval-engine/cadence.yaml",
"emission_cadence_sha256": hashlib.sha256(outputs[approval_path].encode()).hexdigest(),
"heartbeat_classes": {
name: frame.seconds(2) for name in ("issuance", "use", "supersession", "revocation")
},
"receiver_grace_factor": 1.5,
"effective_deadline_seconds": frame.seconds(3),
"preserve_existing_credentials_and_other_registry_fields": True,
}
outputs[
workspace / "net-kingdom/generated/coordination-frame/approval-engine-receiver.json"
] = json.dumps(receiver, indent=2) + "\n"
return frame, outputs
def main(argv=None):
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--workspace", type=Path, default=ROOT.parent)
mode = parser.add_mutually_exclusive_group()
mode.add_argument("--check", action="store_true")
mode.add_argument("--write", action="store_true")
args = parser.parse_args(argv)
try:
frame, outputs = compile_bindings(args.workspace)
changed = {
p: text for p, text in outputs.items() if not p.exists() or p.read_text() != text
}
if args.write:
for path, text in changed.items():
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text(text)
report = {
"frame": frame.as_dict(),
"mode": "write" if args.write else "check" if args.check else "plan",
"changed": [str(p.relative_to(args.workspace)) for p in changed],
"live_operations": False,
}
print(json.dumps(report, indent=2, sort_keys=True))
return 1 if args.check and changed else 0
except (OSError, ValueError, KeyError, TypeError) as exc:
parser.error(str(exc))
if __name__ == "__main__":
raise SystemExit(main())

View file

@ -0,0 +1,127 @@
import hashlib
import importlib.util
import json
import shutil
from pathlib import Path
import pytest
import yaml
SCRIPT = Path(__file__).resolve().parents[1] / "render.py"
SPEC = importlib.util.spec_from_file_location("frame_renderer", SCRIPT)
renderer = importlib.util.module_from_spec(SPEC)
SPEC.loader.exec_module(renderer)
WORKSPACE = SCRIPT.parents[3]
@pytest.fixture
def workspace(tmp_path):
required = (
"coordination-engine/config/coordination-frame.json",
"coordination-engine/src/coordination_engine/timing.py",
"approval-engine/cadence.yaml",
"approval-engine/deploy/approval-engine.yaml",
"qonto-assistant/specs/audit-emission-cadence.yaml",
"rapp-qonto/runtime/knative/service.yaml",
"kings-guard/src/kings_guard/fixtures/qonto_assistant_source_cadence.json",
)
if any(not (WORKSPACE / name).is_file() for name in required):
pytest.skip("sibling owner sources required; no fallback frame or contract")
for name in (
"coordination-engine/config/coordination-frame.json",
"coordination-engine/src/coordination_engine/timing.py",
"approval-engine/cadence.yaml",
"approval-engine/deploy/approval-engine.yaml",
"qonto-assistant/specs/audit-emission-cadence.yaml",
"rapp-qonto/runtime/knative/service.yaml",
"kings-guard/src/kings_guard/fixtures/qonto_assistant_source_cadence.json",
):
path = tmp_path / name
path.parent.mkdir(parents=True, exist_ok=True)
shutil.copyfile(WORKSPACE / name, path)
return tmp_path
@pytest.mark.parametrize("frame_seconds", [600, 3600, 86400])
def test_one_frame_edit_rescales_sources_runtime_and_receiver(workspace, frame_seconds):
config = workspace / renderer.FRAME_REF
config.write_text(
json.dumps({"schema_version": "coordination-frame/v1", "frame_seconds": frame_seconds})
)
_, outputs = renderer.compile_bindings(workspace)
approval = json.loads(outputs[workspace / "approval-engine/cadence.yaml"])
qonto = yaml.safe_load(outputs[workspace / "qonto-assistant/specs/audit-emission-cadence.yaml"])
for entry in approval["sources"]:
if "heartbeat" in entry:
assert entry["heartbeat"]["interval_seconds"] == frame_seconds
extension = entry["heartbeat"]["extensions"]["approval-engine"]
assert extension["requested_observer_max_gap_seconds"] == 2 * frame_seconds
assert extension["effective_deadline_seconds"] == 3 * frame_seconds
for entry in qonto["sources"]:
assert entry["heartbeat"]["interval"] == f"PT{frame_seconds}S"
observer = json.loads(
outputs[
workspace / "kings-guard/src/kings_guard/fixtures/qonto_assistant_source_cadence.json"
]
)
assert observer["sources"][0]["heartbeat"]["interval_seconds"] == frame_seconds
receiver = json.loads(
outputs[
workspace / "net-kingdom/generated/coordination-frame/approval-engine-receiver.json"
]
)
assert set(receiver["heartbeat_classes"].values()) == {2 * frame_seconds}
assert receiver["effective_deadline_seconds"] == 3 * frame_seconds
assert receiver["may_read"] is False
assert receiver["status"] == "proposed-not-applied"
for name in (
"approval-engine/approval_engine/coordination.py",
"qonto-assistant/src/qonto_assistant/coordination.py",
):
assert f"FRAME_SECONDS = {frame_seconds}\n" in outputs[workspace / name]
deploy = yaml.safe_load_all(outputs[workspace / "approval-engine/deploy/approval-engine.yaml"])
workload = next(item for item in deploy if item["kind"] == "StatefulSet")
expected_digest = hashlib.sha256(config.read_bytes()).hexdigest()
assert (
workload["spec"]["template"]["metadata"]["annotations"][
"coordination.coulomb.social/frame-sha256"
]
== expected_digest
)
args = workload["spec"]["template"]["spec"]["containers"][0]["args"]
assert args[args.index("--heartbeat-seconds") + 1] == str(frame_seconds)
service = yaml.safe_load(outputs[workspace / "rapp-qonto/runtime/knative/service.yaml"])
assert (
service["spec"]["template"]["metadata"]["annotations"][
"coordination.coulomb.social/frame-sha256"
]
== expected_digest
)
env = service["spec"]["template"]["spec"]["containers"][0]["env"]
assert next(
item["value"] for item in env if item["name"] == "QONTO_AUDIT_HEARTBEAT_INTERVAL_SECONDS"
) == str(frame_seconds)
def test_render_is_read_only_and_write_is_idempotent_with_drift_detection(workspace, capsys):
before = {path: path.read_bytes() for path in workspace.rglob("*") if path.is_file()}
assert renderer.main(["--workspace", str(workspace)]) == 0
assert all(path.read_bytes() == data for path, data in before.items())
assert renderer.main(["--workspace", str(workspace), "--check"]) == 1
assert renderer.main(["--workspace", str(workspace), "--write"]) == 0
assert renderer.main(["--workspace", str(workspace), "--check"]) == 0
receiver = workspace / "net-kingdom/generated/coordination-frame/approval-engine-receiver.json"
data = json.loads(receiver.read_text())
data["heartbeat_classes"]["revocation"] = 999999
receiver.write_text(json.dumps(data))
assert renderer.main(["--workspace", str(workspace), "--check"]) == 1
def test_invalid_frame_does_not_partially_rewrite_sources(workspace):
config = workspace / renderer.FRAME_REF
config.write_text('{"schema_version":"coordination-frame/v1","frame_seconds":0}')
before = {path: path.read_bytes() for path in workspace.rglob("*") if path.is_file()}
with pytest.raises(SystemExit):
renderer.main(["--workspace", str(workspace), "--write"])
assert all(path.read_bytes() == data for path, data in before.items())

View file

@ -5,7 +5,7 @@ title: "Publish the NetKingdom emission-cadence security profile"
domain: infotech
repo: net-kingdom
status: blocked
flavor: residual
flavor: implementation
owner: codex
topic_slug: netkingdom
planning_priority: P1
@ -90,7 +90,7 @@ Python compilation and `git diff --check` pass.
id: NK-WP-0035-T04
status: wait
blocked_on: message-from:approval-engine
blocking_reason: "Approval Engine effective heartbeat deadline needs owner choice (48h requested; receiver applies 1.5 grace), followed by approved cadence registry/runtime acceptance and lifecycle reconciliation. Qonto needs an actual rapp-qonto collector and AUDIT-WP-0013-T05 sender admission before KG-WP-0005-T03 operational observation. Existing bearer-revocation proof is delivered; local-identity incompatibility remains explicit."
blocking_reason: "Founder chose configurable frame f=1h: source heartbeat f, receiver wait 2f, effective deadline 3f. Generated source/runtime bindings await approved deployment and registry admission plus actual lifecycle reconciliation. Qonto still needs an actual rapp-qonto collector and AUDIT-WP-0013-T05 sender admission before KG-WP-0005-T03 observation. Existing bearer-revocation proof is delivered; local-identity incompatibility remains explicit."
priority: high
state_hub_task_id: "e3fbc8b8-00d5-57ce-ba0c-19b58044c950"
```
@ -276,3 +276,47 @@ Knowledge: Emergent 0.2.6, digest
`8d1d6a9d4d07fec7b619618de7dfe2be2254c1790f85f4198c7fe19db9751c02`;
start/evidence source guidance directly reviewed, withheld/orientation-only
receipt retained. This supplies no operational authority.
## Introduce a configurable ecosystem coordination frame
```task
id: NK-WP-0035-T06
status: done
priority: high
```
Founder direction in this sitting supersedes the binary 48h/72h question:
long-term ecosystem coordination uses one configurable base frame, initially
**f=1h**, with waits of **2f** and **3f**. Decision:
`1ac5a70f-082e-4d8f-9ac8-59e4c175da02`.
Authoritative config is `coordination-engine/config/coordination-frame.json`.
The coordination-engine API validates it and derives durations / deadlines.
NetKingdom's compiler derives source declarations, consumer Python defaults,
Approval Engine's deployment heartbeat argument, Qonto's deployment environment
setting, and the proposed receiver metadata, retaining the frame digest.
Heartbeat is f=3600s; registered wait is 2f=7200s; the receiver's 1.5 grace
makes the effective deadline 3f=10800s. The formulas also reproduce the old
24h/48h/72h cadence when f is set to 24h.
This is source-level adoption of the setting, not proof that the deployed
processes have changed pace or that every ecosystem timer has adopted it.
Runtime release/registry receipts remain T04. Credential and approval validity,
worker leases and transport retry timers are separate owner contracts.
[Configuration and regeneration](../tools/coordination-frame/README.md).
T06 source acceptance: **73 coordination-engine tests passed, one live test
skipped; 32 compiler/profile tests; 271 Approval Engine; 91 Qonto; 25 package;
128 King's Guard tests passed**. The compiler's --check has no drift. Changing
f to 10 minutes or 24 hours in isolated test workspaces rescales source,
receiver and observer bindings together. Prepared manifests preserve image,
identity, secret, routing and scaling fields apart from the timing values and
frame-digest annotations. [Frame validation](../docs/evidence/2026-10-15-cadence-adoption/coordination-frame-validation.json).
The earlier 48h/72h question is resolved by the explicit configurable-frame
decision. No further deadline selection is waiting on the founder. T04 still
requires actual approved rollout/registration, missing Qonto collector/admission,
and operational lifecycle/observer acceptance. The profile remains proposed;
this workplan is now **5/6 source tasks done**, with T04's operational gate open.