build: derive coordination receiver from staged owner sources
Assistant: codex Assistant-Model: gpt-6-astra Assistant-Session: 01a15374-f59f-7a31-86d2-d23b5d2ed181
This commit is contained in:
parent
4c7f32adc7
commit
bde143e030
9 changed files with 284 additions and 22 deletions
|
|
@ -3,6 +3,8 @@ CUSTODIAN_SOURCE ?= /home/worsch/the-custodian
|
||||||
GENERATED_REPO_SLUG ?= net-kingdom
|
GENERATED_REPO_SLUG ?= net-kingdom
|
||||||
.PHONY: generated-work-records generated-work-records-check
|
.PHONY: generated-work-records generated-work-records-check
|
||||||
generated-work-records:
|
generated-work-records:
|
||||||
|
python3 tools/coordination-frame/staged.py --repo .
|
||||||
python3 "$(CUSTODIAN_SOURCE)/scripts/generate_staged_work_records.py" --repo . --repo-slug "$(GENERATED_REPO_SLUG)"
|
python3 "$(CUSTODIAN_SOURCE)/scripts/generate_staged_work_records.py" --repo . --repo-slug "$(GENERATED_REPO_SLUG)"
|
||||||
generated-work-records-check:
|
generated-work-records-check:
|
||||||
|
python3 tools/coordination-frame/staged.py --repo . --check
|
||||||
python3 "$(CUSTODIAN_SOURCE)/scripts/generate_staged_work_records.py" --repo . --repo-slug "$(GENERATED_REPO_SLUG)" --check
|
python3 "$(CUSTODIAN_SOURCE)/scripts/generate_staged_work_records.py" --repo . --repo-slug "$(GENERATED_REPO_SLUG)" --check
|
||||||
|
|
|
||||||
6
Makefile
6
Makefile
|
|
@ -401,3 +401,9 @@ generated-work-records:
|
||||||
$(MAKE) --no-print-directory -f .generated-work-records.mk generated-work-records
|
$(MAKE) --no-print-directory -f .generated-work-records.mk generated-work-records
|
||||||
generated-work-records-check:
|
generated-work-records-check:
|
||||||
$(MAKE) --no-print-directory -f .generated-work-records.mk generated-work-records-check
|
$(MAKE) --no-print-directory -f .generated-work-records.mk generated-work-records-check
|
||||||
|
|
||||||
|
.PHONY: coordination-frame-staged coordination-frame-staged-check
|
||||||
|
coordination-frame-staged:
|
||||||
|
python3 tools/coordination-frame/staged.py --repo .
|
||||||
|
coordination-frame-staged-check:
|
||||||
|
python3 tools/coordination-frame/staged.py --repo . --check
|
||||||
|
|
|
||||||
10
SCOPE.md
10
SCOPE.md
|
|
@ -244,3 +244,13 @@ WORK-RECORDS.md with the selected source paths. Existing generated-only guards
|
||||||
and exact-scope secret scans remain in place. This is repository maintenance,
|
and exact-scope secret scans remain in place. This is repository maintenance,
|
||||||
not a runtime service, authorization decision, deployment or publication.
|
not a runtime service, authorization decision, deployment or publication.
|
||||||
Other index generators and hub-derived briefs retain their owner boundaries.
|
Other index generators and hub-derived briefs retain their owner boundaries.
|
||||||
|
|
||||||
|
## Coordination receiver generation — 2026-10-19
|
||||||
|
|
||||||
|
The shared opt-in commit recipe now compiles the local proposed Approval Engine
|
||||||
|
receiver from staged NetKingdom/coordination-engine/approval-engine sources,
|
||||||
|
then renders WORK-RECORDS. Dedicated Make generation/check targets preserve
|
||||||
|
unstaged authored work and refuse receiver conflicts or alternate-index writes.
|
||||||
|
Only the local receiver is staged; sibling sources and runtime registries are
|
||||||
|
untouched. Missing owner source checkouts fail closed. Multi-owner binding
|
||||||
|
publication and actual receiver activation retain their existing owner gates.
|
||||||
|
|
|
||||||
|
|
@ -160,6 +160,7 @@
|
||||||
| task | NK-WP-0035-T04 | progress | — | workplans/NK-WP-0035-emission-cadence-security-profile.md |
|
| task | NK-WP-0035-T04 | progress | — | workplans/NK-WP-0035-emission-cadence-security-profile.md |
|
||||||
| task | NK-WP-0035-T05 | done | — | workplans/NK-WP-0035-emission-cadence-security-profile.md |
|
| task | NK-WP-0035-T05 | done | — | workplans/NK-WP-0035-emission-cadence-security-profile.md |
|
||||||
| task | NK-WP-0035-T06 | done | — | workplans/NK-WP-0035-emission-cadence-security-profile.md |
|
| task | NK-WP-0035-T06 | done | — | workplans/NK-WP-0035-emission-cadence-security-profile.md |
|
||||||
|
| task | NK-WP-0035-T07 | done | — | workplans/NK-WP-0035-emission-cadence-security-profile.md |
|
||||||
| task | NK-WP-0036-T01 | done | — | workplans/NK-WP-0036-restore-user-portal-client-registration.md |
|
| task | NK-WP-0036-T01 | done | — | workplans/NK-WP-0036-restore-user-portal-client-registration.md |
|
||||||
| task | NK-WP-0036-T02 | done | — | workplans/NK-WP-0036-restore-user-portal-client-registration.md |
|
| task | NK-WP-0036-T02 | done | — | workplans/NK-WP-0036-restore-user-portal-client-registration.md |
|
||||||
| task | NK-WP-0036-T03 | done | — | workplans/NK-WP-0036-restore-user-portal-client-registration.md |
|
| task | NK-WP-0036-T03 | done | — | workplans/NK-WP-0036-restore-user-portal-client-registration.md |
|
||||||
|
|
|
||||||
|
|
@ -40,3 +40,25 @@ This is the first rollout of a shared coordination setting. Other ecosystem
|
||||||
coordination consumers must adopt explicit frame multipliers through their own
|
coordination consumers must adopt explicit frame multipliers through their own
|
||||||
configuration. Transport polling, security validity and credential leases are
|
configuration. Transport polling, security validity and credential leases are
|
||||||
not silently rescaled by a coordination setting.
|
not silently rescaled by a coordination setting.
|
||||||
|
|
||||||
|
## Staged local receiver generation
|
||||||
|
|
||||||
|
`make coordination-frame-staged` compiles and stages only the NetKingdom receiver
|
||||||
|
JSON from Git-index snapshots of its renderer, coordination-engine's frame/API
|
||||||
|
and approval-engine's cadence. It never edits those sibling checkouts. Unstaged
|
||||||
|
owner source edits are excluded, and unstaged receiver edits, missing/conflicted
|
||||||
|
or symlink inputs and alternate-index writes are refused. Stage the reviewed
|
||||||
|
adapter before its first run. `make coordination-frame-staged-check` is read-only.
|
||||||
|
|
||||||
|
The existing opt-in pre-commit recipe runs this adapter before WORK-RECORDS
|
||||||
|
rendering and the existing configured scanner. Missing sibling source checkouts
|
||||||
|
fail closed. Full multi-owner `render.py --write` remains an explicit preparation
|
||||||
|
command and is never run against real sibling worktrees by the commit hook.
|
||||||
|
`render.py --receiver-only` limits rendering to the one local proposed receiver;
|
||||||
|
none of these commands activate the receiver or publish runtime changes.
|
||||||
|
|
||||||
|
For a partial commit, generate from the selected staged sources first and include
|
||||||
|
the receiver with those sources; `git commit --only` cannot generate missing
|
||||||
|
changes into its temporary index. Cross-repo owner commits still need their own
|
||||||
|
review and publication; local index snapshots are source evidence, not release
|
||||||
|
or operational acceptance.
|
||||||
|
|
|
||||||
|
|
@ -69,7 +69,27 @@ def bind_frame_annotation(text, digest, metadata_prefix):
|
||||||
return updated
|
return updated
|
||||||
|
|
||||||
|
|
||||||
def compile_bindings(workspace: Path):
|
def receiver_binding(frame, provenance, approval_text):
|
||||||
|
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(approval_text.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,
|
||||||
|
}
|
||||||
|
return json.dumps(receiver, indent=2) + "\n"
|
||||||
|
|
||||||
|
|
||||||
|
def compile_bindings(workspace: Path, *, receiver_only=False):
|
||||||
frame = owner_frame(workspace)
|
frame = owner_frame(workspace)
|
||||||
digest = hashlib.sha256((workspace / FRAME_REF).read_bytes()).hexdigest()
|
digest = hashlib.sha256((workspace / FRAME_REF).read_bytes()).hexdigest()
|
||||||
provenance = {
|
provenance = {
|
||||||
|
|
@ -97,6 +117,9 @@ def compile_bindings(workspace: Path):
|
||||||
ext["effective_deadline_seconds"] = frame.seconds(3)
|
ext["effective_deadline_seconds"] = frame.seconds(3)
|
||||||
approval["extensions"].setdefault("netkingdom", {})["coordination_frame"] = provenance
|
approval["extensions"].setdefault("netkingdom", {})["coordination_frame"] = provenance
|
||||||
outputs[approval_path] = json.dumps(approval, indent=2) + "\n"
|
outputs[approval_path] = json.dumps(approval, indent=2) + "\n"
|
||||||
|
if receiver_only:
|
||||||
|
path = workspace / "net-kingdom/generated/coordination-frame/approval-engine-receiver.json"
|
||||||
|
return frame, {path: receiver_binding(frame, provenance, outputs[approval_path])}
|
||||||
|
|
||||||
qonto_path = workspace / "qonto-assistant/specs/audit-emission-cadence.yaml"
|
qonto_path = workspace / "qonto-assistant/specs/audit-emission-cadence.yaml"
|
||||||
qonto = yaml.safe_load(qonto_path.read_text())
|
qonto = yaml.safe_load(qonto_path.read_text())
|
||||||
|
|
@ -160,37 +183,20 @@ def compile_bindings(workspace: Path):
|
||||||
fixture["extensions"].setdefault("netkingdom", {})["coordination_frame"] = provenance
|
fixture["extensions"].setdefault("netkingdom", {})["coordination_frame"] = provenance
|
||||||
outputs[fixture_path] = json.dumps(fixture, indent=2) + "\n"
|
outputs[fixture_path] = json.dumps(fixture, indent=2) + "\n"
|
||||||
|
|
||||||
receiver = {
|
outputs[workspace / "net-kingdom/generated/coordination-frame/approval-engine-receiver.json"] = receiver_binding(frame, provenance, outputs[approval_path])
|
||||||
"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
|
return frame, outputs
|
||||||
|
|
||||||
|
|
||||||
def main(argv=None):
|
def main(argv=None):
|
||||||
parser = argparse.ArgumentParser(description=__doc__)
|
parser = argparse.ArgumentParser(description=__doc__)
|
||||||
parser.add_argument("--workspace", type=Path, default=ROOT.parent)
|
parser.add_argument("--workspace", type=Path, default=ROOT.parent)
|
||||||
|
parser.add_argument("--receiver-only", action="store_true")
|
||||||
mode = parser.add_mutually_exclusive_group()
|
mode = parser.add_mutually_exclusive_group()
|
||||||
mode.add_argument("--check", action="store_true")
|
mode.add_argument("--check", action="store_true")
|
||||||
mode.add_argument("--write", action="store_true")
|
mode.add_argument("--write", action="store_true")
|
||||||
args = parser.parse_args(argv)
|
args = parser.parse_args(argv)
|
||||||
try:
|
try:
|
||||||
frame, outputs = compile_bindings(args.workspace)
|
frame, outputs = compile_bindings(args.workspace, receiver_only=args.receiver_only)
|
||||||
changed = {
|
changed = {
|
||||||
p: text for p, text in outputs.items() if not p.exists() or p.read_text() != text
|
p: text for p, text in outputs.items() if not p.exists() or p.read_text() != text
|
||||||
}
|
}
|
||||||
|
|
|
||||||
100
tools/coordination-frame/staged.py
Normal file
100
tools/coordination-frame/staged.py
Normal file
|
|
@ -0,0 +1,100 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Stage only the local receiver from indexed owner sources; never mutate siblings."""
|
||||||
|
import argparse
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
from pathlib import Path
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import tempfile
|
||||||
|
|
||||||
|
OUTPUT = 'generated/coordination-frame/approval-engine-receiver.json'
|
||||||
|
SELF = 'tools/coordination-frame/staged.py'
|
||||||
|
INPUTS = {
|
||||||
|
'net-kingdom': ['tools/coordination-frame/render.py'],
|
||||||
|
'coordination-engine': ['config/coordination-frame.json', 'src/coordination_engine/timing.py'],
|
||||||
|
'approval-engine': ['cadence.yaml'],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def git(repo, *args, default_index=False):
|
||||||
|
env = dict(os.environ)
|
||||||
|
if default_index:
|
||||||
|
env.pop("GIT_INDEX_FILE", None)
|
||||||
|
return subprocess.check_output(['git', '-C', str(repo), *args], stderr=subprocess.PIPE, env=env)
|
||||||
|
|
||||||
|
|
||||||
|
def indexed(repo, path, *, default_index=False):
|
||||||
|
rows = git(repo, 'ls-files', '--stage', '--', path, default_index=default_index).decode().splitlines()
|
||||||
|
if len(rows) != 1:
|
||||||
|
raise ValueError('missing or conflicted source: ' + path)
|
||||||
|
metadata, name = rows[0].split('\t', 1)
|
||||||
|
mode, oid, stage = metadata.split()
|
||||||
|
if stage != '0' or mode not in ('100644', '100755') or name != path:
|
||||||
|
raise ValueError('nonregular or conflicted source: ' + path)
|
||||||
|
return git(repo, 'cat-file', 'blob', oid, default_index=default_index)
|
||||||
|
|
||||||
|
|
||||||
|
def generate(repo, *, check=False):
|
||||||
|
repo = Path(repo).resolve()
|
||||||
|
workspace = repo.parent
|
||||||
|
if Path(git(repo, 'rev-parse', '--show-toplevel').decode().strip()).resolve() != repo:
|
||||||
|
raise ValueError('repository root required')
|
||||||
|
if (repo / SELF).is_symlink() or (repo / SELF).read_bytes() != indexed(repo, SELF):
|
||||||
|
raise ValueError('stage the reviewed adapter before executing it')
|
||||||
|
target = repo / OUTPUT
|
||||||
|
if any(p.is_symlink() for p in (target, *target.parents)):
|
||||||
|
raise ValueError('redirected receiver output refused')
|
||||||
|
prior = indexed(repo, OUTPUT)
|
||||||
|
if target.read_bytes() != prior:
|
||||||
|
raise ValueError('unstaged receiver edits; preserve or reconcile first')
|
||||||
|
sources = []
|
||||||
|
with tempfile.TemporaryDirectory(prefix='coordination-staged-') as directory:
|
||||||
|
snapshot = Path(directory)
|
||||||
|
for slug, paths in INPUTS.items():
|
||||||
|
source_repo = repo if slug == 'net-kingdom' else workspace / slug
|
||||||
|
if Path(git(source_repo, 'rev-parse', '--show-toplevel').decode().strip()).resolve() != source_repo.resolve():
|
||||||
|
raise ValueError('owner repository root required')
|
||||||
|
for path in paths:
|
||||||
|
dest = snapshot / slug / path
|
||||||
|
dest.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
content = indexed(source_repo, path, default_index=source_repo != repo)
|
||||||
|
sources.append((source_repo, path, content))
|
||||||
|
dest.write_bytes(content)
|
||||||
|
subprocess.run([sys.executable, str(snapshot/'net-kingdom/tools/coordination-frame/render.py'),
|
||||||
|
'--workspace', str(snapshot), '--receiver-only', '--write'],
|
||||||
|
check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||||
|
result = (snapshot/'net-kingdom'/OUTPUT).read_bytes()
|
||||||
|
if any(indexed(owner, name, default_index=owner != repo) != content
|
||||||
|
for owner, name, content in sources):
|
||||||
|
raise ValueError("owner index changed during compilation")
|
||||||
|
if result == prior:
|
||||||
|
return False
|
||||||
|
if check:
|
||||||
|
raise ValueError('staged receiver drift; run make coordination-frame-staged')
|
||||||
|
default_index = Path(git(repo, 'rev-parse', '--git-path', 'index', default_index=True).decode().strip())
|
||||||
|
if not default_index.is_absolute():
|
||||||
|
default_index = repo/default_index
|
||||||
|
active_index = Path(os.environ.get('GIT_INDEX_FILE', str(default_index)))
|
||||||
|
if not active_index.is_absolute():
|
||||||
|
active_index = repo/active_index
|
||||||
|
if active_index.resolve() != default_index.resolve():
|
||||||
|
raise ValueError('alternate-index mutation refused; generate before commit --only')
|
||||||
|
# Optimistic check: refuse if a source/index update raced compilation.
|
||||||
|
if indexed(repo, OUTPUT) != prior or target.read_bytes() != prior:
|
||||||
|
raise ValueError('receiver changed during compilation')
|
||||||
|
target.write_bytes(result)
|
||||||
|
git(repo, 'add', '--', OUTPUT)
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
parser = argparse.ArgumentParser(description=__doc__)
|
||||||
|
parser.add_argument('--repo', type=Path, default=Path.cwd())
|
||||||
|
parser.add_argument('--check', action='store_true')
|
||||||
|
args = parser.parse_args()
|
||||||
|
try:
|
||||||
|
changed = generate(args.repo, check=args.check)
|
||||||
|
except (OSError, ValueError, subprocess.SubprocessError) as exc:
|
||||||
|
parser.exit(1, 'Coordination generation refused: ' + str(exc) + '\n')
|
||||||
|
print(json.dumps({'receiver_changed': changed, 'sibling_writes': False, 'live_operations': False}))
|
||||||
85
tools/coordination-frame/tests/test_staged.py
Normal file
85
tools/coordination-frame/tests/test_staged.py
Normal file
|
|
@ -0,0 +1,85 @@
|
||||||
|
import importlib.util
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
from pathlib import Path
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
ROOT = Path(__file__).resolve().parents[3]
|
||||||
|
SPEC = importlib.util.spec_from_file_location('staged_frame', ROOT/'tools/coordination-frame/staged.py')
|
||||||
|
staged = importlib.util.module_from_spec(SPEC)
|
||||||
|
SPEC.loader.exec_module(staged)
|
||||||
|
|
||||||
|
|
||||||
|
def git(repo, *args):
|
||||||
|
return subprocess.check_output(['git','-C',str(repo),*args])
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def repos(tmp_path):
|
||||||
|
workspace = ROOT.parent
|
||||||
|
for slug, names in staged.INPUTS.items():
|
||||||
|
repo=tmp_path/slug;repo.mkdir()
|
||||||
|
git(repo,'init','-q')
|
||||||
|
for name in names:
|
||||||
|
dest=repo/name;dest.parent.mkdir(parents=True,exist_ok=True)
|
||||||
|
dest.write_bytes((workspace/slug/name).read_bytes())
|
||||||
|
repo=tmp_path/'net-kingdom'
|
||||||
|
for name in (staged.SELF,staged.OUTPUT):
|
||||||
|
dest=repo/name;dest.parent.mkdir(parents=True,exist_ok=True)
|
||||||
|
dest.write_bytes((ROOT/name).read_bytes())
|
||||||
|
for slug in staged.INPUTS:git(tmp_path/slug,'add','.')
|
||||||
|
return tmp_path,repo
|
||||||
|
|
||||||
|
|
||||||
|
def test_receiver_only_ignores_unstaged_sibling_source(repos):
|
||||||
|
workspace,repo=repos
|
||||||
|
path=workspace/'coordination-engine/config/coordination-frame.json'
|
||||||
|
original=path.read_bytes();path.write_text('uncommitted invalid source')
|
||||||
|
assert staged.generate(repo) is False
|
||||||
|
assert path.read_text()=='uncommitted invalid source'
|
||||||
|
assert git(workspace/'coordination-engine','show',':config/coordination-frame.json')==original
|
||||||
|
|
||||||
|
|
||||||
|
def test_staged_frame_change_only_updates_local_receiver(repos):
|
||||||
|
workspace,repo=repos
|
||||||
|
path=workspace/'coordination-engine/config/coordination-frame.json'
|
||||||
|
data=json.loads(path.read_text());data['frame_seconds']=600;path.write_text(json.dumps(data))
|
||||||
|
git(path.parents[1],'add','config/coordination-frame.json')
|
||||||
|
approval=workspace/'approval-engine/cadence.yaml';before=approval.read_bytes()
|
||||||
|
with pytest.raises(ValueError,match='drift'):staged.generate(repo,check=True)
|
||||||
|
assert staged.generate(repo)
|
||||||
|
result=json.loads((repo/staged.OUTPUT).read_text())
|
||||||
|
assert result['effective_deadline_seconds']==1800
|
||||||
|
assert approval.read_bytes()==before
|
||||||
|
assert staged.generate(repo,check=True) is False
|
||||||
|
|
||||||
|
|
||||||
|
def test_unstaged_receiver_preserved(repos):
|
||||||
|
_,repo=repos;p=repo/staged.OUTPUT;p.write_text('local edit')
|
||||||
|
with pytest.raises(ValueError,match='unstaged receiver'):staged.generate(repo)
|
||||||
|
assert p.read_text()=='local edit'
|
||||||
|
|
||||||
|
|
||||||
|
def test_unstaged_adapter_refused(repos):
|
||||||
|
_,repo=repos;p=repo/staged.SELF;p.write_text(p.read_text()+'\n# local edit\n')
|
||||||
|
with pytest.raises(ValueError,match='stage the reviewed'):staged.generate(repo)
|
||||||
|
|
||||||
|
|
||||||
|
def test_symlink_source_refused(repos):
|
||||||
|
workspace,repo=repos;p=workspace/'approval-engine/cadence.yaml';p.unlink();p.symlink_to('/etc/passwd')
|
||||||
|
git(p.parent,'add','cadence.yaml')
|
||||||
|
with pytest.raises(ValueError,match='nonregular'):staged.generate(repo)
|
||||||
|
|
||||||
|
|
||||||
|
def test_alternate_index_write_refused_and_sibling_default_index_used(repos,monkeypatch):
|
||||||
|
workspace,repo=repos
|
||||||
|
path=workspace/'coordination-engine/config/coordination-frame.json'
|
||||||
|
data=json.loads(path.read_text());data['frame_seconds']=600;path.write_text(json.dumps(data))
|
||||||
|
git(path.parents[1],'add','config/coordination-frame.json')
|
||||||
|
alternate=repo/'.git/partial-index';alternate.write_bytes((repo/'.git/index').read_bytes())
|
||||||
|
before=(repo/staged.OUTPUT).read_bytes()
|
||||||
|
monkeypatch.setenv('GIT_INDEX_FILE',str(alternate))
|
||||||
|
with pytest.raises(ValueError,match='alternate-index mutation'):staged.generate(repo)
|
||||||
|
assert (repo/staged.OUTPUT).read_bytes()==before
|
||||||
|
|
@ -10,7 +10,7 @@ owner: codex
|
||||||
topic_slug: netkingdom
|
topic_slug: netkingdom
|
||||||
planning_priority: P1
|
planning_priority: P1
|
||||||
created: "2026-09-04"
|
created: "2026-09-04"
|
||||||
updated: "2026-10-15"
|
updated: "2026-10-19"
|
||||||
related:
|
related:
|
||||||
- GH-DEC-2026-004
|
- GH-DEC-2026-004
|
||||||
- canon/standards/security-layer-model_v0.7.md
|
- canon/standards/security-layer-model_v0.7.md
|
||||||
|
|
@ -417,3 +417,33 @@ and collector implementation are no longer missing. Remaining work is actual
|
||||||
elapsed-time capture, independent source/receiver correlation and observer
|
elapsed-time capture, independent source/receiver correlation and observer
|
||||||
acceptance. Local-identity remains explicitly incompatible, with no completeness
|
acceptance. Local-identity remains explicitly incompatible, with no completeness
|
||||||
claim. Detailed state: [owner acceptance plan](../docs/evidence/2026-10-15-cadence-adoption/owner-acceptance-plan.json).
|
claim. Detailed state: [owner acceptance plan](../docs/evidence/2026-10-15-cadence-adoption/owner-acceptance-plan.json).
|
||||||
|
|
||||||
|
## Automate staged receiver derivation without sibling mutations
|
||||||
|
|
||||||
|
```task
|
||||||
|
id: NK-WP-0035-T07
|
||||||
|
status: done
|
||||||
|
priority: medium
|
||||||
|
```
|
||||||
|
|
||||||
|
Completed source/fixture work 2026-10-19 for CUST-WP-0079-T05. The existing
|
||||||
|
coordination-frame compiler now has a receiver-only mode, and its staged
|
||||||
|
adapter compiles indexed NetKingdom renderer, coordination-engine frame/API and
|
||||||
|
approval-engine cadence inputs in an isolated temporary snapshot. Only the
|
||||||
|
local proposed receiver is written/staged. Dedicated Make targets and the
|
||||||
|
existing shared opt-in pre-commit recipe invoke this path; authored sibling
|
||||||
|
files and unstaged source edits are untouched. Missing/conflicted/nonregular
|
||||||
|
inputs, an unstaged receiver/adapter, changed input snapshots and required
|
||||||
|
alternate-index mutations refuse. The existing guard/scanner remain intact.
|
||||||
|
|
||||||
|
Eleven focused tests pass, including partial source staging, namespaced sibling
|
||||||
|
index isolation, receiver edit preservation and alternate-index refusal.
|
||||||
|
The first alternate-index test found that Git's default index query itself
|
||||||
|
honored GIT_INDEX_FILE; corrected the query and retained its regression. This
|
||||||
|
is a refined implementation, not an unchanged execution-success claim.
|
||||||
|
|
||||||
|
T06 retains ownership of the full multi-consumer frame compiler. T07 owns only
|
||||||
|
the staged local receiver automation introduced here. T04 retains registry,
|
||||||
|
collector and operational lifecycle/observer acceptance; neither this task nor
|
||||||
|
its tests claim runtime activation or a clean week of fleet commit history.
|
||||||
|
See tools/coordination-frame/README.md for commands and source boundaries.
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue