Complete G7 reciprocal canon interfaces and source-review evidence

Assistant: codex
Assistant-Model: gpt-6-astra
Assistant-Session: 01a070b5-4994-7271-bd8b-7c3dbcedec4b
This commit is contained in:
tegwick 2026-09-06 01:04:34 +02:00
parent 942d345cb5
commit 49b03943c8
8 changed files with 373 additions and 5 deletions

View file

@ -16,8 +16,8 @@
| task | CFED-WP-0001-T05 | done | — | workplans/CFED-WP-0001-foundation.md |
| task | CFED-WP-0001-T06 | done | — | workplans/CFED-WP-0001-foundation.md |
| task | CFED-WP-0001-T07 | done | — | workplans/CFED-WP-0001-foundation.md |
| task | CFED-WP-0001-T08 | todo | — | workplans/CFED-WP-0001-foundation.md |
| task | CFED-WP-0001-T09 | wait | — | workplans/CFED-WP-0001-foundation.md |
| task | CFED-WP-0001-T08 | done | — | workplans/CFED-WP-0001-foundation.md |
| task | CFED-WP-0001-T09 | todo | — | workplans/CFED-WP-0001-foundation.md |
| task | CFED-WP-0001-T10 | wait | — | workplans/CFED-WP-0001-foundation.md |
| task | CFED-WP-0001-T11 | done | — | workplans/CFED-WP-0001-foundation.md |
| task | CFED-WP-0001-T12 | done | — | workplans/CFED-WP-0001-foundation.md |

View file

@ -44,7 +44,10 @@ for row in manifest['imports']:
text = historical.decode()
if text.startswith('---\n'):
upstream_fm = yaml.safe_load(text.split('---')[1])
upstream_owned = set(upstream_fm['owned_concepts'])
upstream_owned = set(upstream_fm.get('owned_concepts', []))
# Organization frontmatter records only its incremental social extension.
# Include explicit legacy definitions, never bare imported anchors.
upstream_owned.update(re.findall(r'^(?:An? )?\*\*(.+?)\*\* is\b', text, re.M))
else:
upstream_owned = set(re.findall(r'^## \d+\.\d+[a-z]? (.+)$', text, re.M))
assert set(row['concepts']) <= upstream_owned, set(row['concepts']) - upstream_owned

View file

@ -0,0 +1,15 @@
{
"gate": "G7",
"result": "pass",
"cards": 3,
"reciprocal_peer_links": 6,
"import_edges": 6,
"ledger_concepts_and_seed_covered": 59,
"imported_concepts": 25,
"historical_and_current_import_blobs_checked": 8,
"source_commit": "372f671eef861e3f180eb5f9fc2fbd8c479ef8b7",
"upstream_changes_since_review": [],
"navigation_links_checked": 27,
"custodian_domain_concepts": 0,
"family": "seeded-not-authored"
}

View file

@ -0,0 +1,100 @@
# G7 — Reciprocal canon interfaces, 2026-09-06
CFED-WP-0001-T08 publishes three repository-owned cards:
- [InfoTechCanon](../../../info-tech-canon/infospace/interfaces/federation.yaml), implemented by [INFO-WP-0025](../../../info-tech-canon/workplans/INFO-WP-0025-federation-interface.md).
- [CommerceCanon](../../../commerce-canon/infospace/interfaces/federation.yaml), implemented by [COMMERCE-WP-0004](../../../commerce-canon/workplans/COMMERCE-WP-0004-federation-interface.md).
- [Custodian canon](../../../the-custodian/canon/interfaces/federation.yaml), implemented by [THE-WP-0001](../../../the-custodian/workplans/THE-WP-0001-federation-interface.md).
The cards follow InfoTechCanonCore §24 and its existing JSON Schema. They name
source authority, imports, available exports, source-of-truth boundaries,
limitations, and both peer cards. Card shape uses the schema's string consumer
and array canon_surfaces; richer Core fields are additive. This does not claim
a new standardized runtime exchange protocol or repair every older card template.
Six reciprocal peer links and six actual import edges are checked: each domain
canon imports accepted CUST-ADR-006 governance; Commerce also imports four
InfoTech models. A reciprocal navigation link does not invent a reverse semantic
import. Custodian exports accepted federation governance, owns no domain
semantics, and leaves the accepted ADR unchanged.
Exports cover all 58 ledger domain concepts and the separately classified Family
seed. Non-canonical convenience terms remain in model resolution guidance, not
new canonical roots. Community/Household remain the draft social extension;
Family remains seeded-not-authored. No stable model promotion or consumer
adoption is asserted.
## Explicit upstream review
Commerce retains its [original import manifest](../../../commerce-canon/infospace/models/counterparty/import-history/2026-09-05-imports.json)
byte-for-byte against published Commerce revision
`bc67e1f25b140ecb60d1439de984f8361acabc32` (SHA-256
`60a6c5187f1e208dcf763913d4d6a98840bc934d238f25d660c8ff3b5ea241d9`).
The [review record](../../../commerce-canon/infospace/models/counterparty/import-review-2026-09-06.md)
advances the upstream source from `361c944325934ccdb190470baf6f55440b6b486e` to
`372f671eef861e3f180eb5f9fc2fbd8c479ef8b7`. Only the organization source changed:
the social-collective extension and incremental ownership metadata. All 25
imported concepts remain the same. Current kernel references acknowledge the
completed extension and Family seed without adopting either as a new Counterparty
import. Eight source blobs verify both revisions and their hashes.
The T06 reproducer now recognizes explicit legacy definitions alongside
incremental frontmatter; bare retained import anchors never establish ownership.
No historical workplan, ADR, original research or frozen assimilation source was
rewritten.
## Validation
[Machine-readable result](2026-09-06-interface-cards.json) records G7 pass.
Reproduce from this repository with adjacent canon checkouts:
```bash
python3 tools/validate_interfaces.py --workspace ..
python3 -m unittest discover -s tools -p 'test*.py'
python3 tools/validate_ownership.py --source-repo ../commerce-canon
python3 tools/validate_corpus.py --commerce-repo ../commerce-canon --info-tech-repo ../info-tech-canon
python3 docs/evidence/2026-09-05-counterparty-validate.py --commerce-repo ../commerce-canon --info-tech-repo ../info-tech-canon
make -C ../info-tech-canon check
```
- Three schema-valid cards; six reciprocal peer links; 59 ledger concept/seed
assignments covered; 25 imports from four models; zero source drift.
- Six G7 rejection tests check missing reciprocity, duplicate Evidence ownership,
Family model promotion, Custodian domain claims, invalid schema shape and
undeclared imports. Seven existing ownership tests also pass (13 total).
- InfoTechCanon: 46 tests pass, generated discovery surfaces current, canon
validation and small-saas proof pass. 81 artifacts, 14 models and one Family
seed; the interface adds one discoverable artifact and no model. Existing
exact reciprocal model-import cycle review remains in force.
- Counterparty: 18 owned concepts, 25 imports and 53 protected files unchanged.
- Corpus: 45 unchanged originals, 69 snapshots, 153 exact fragments and 479 links
still verify. Ownership ledger has zero unowned or multiply owned targets.
G7 is complete after publishing these revisions. CFED-WP-0001-T09 retains the
fleet reference sweep and REUSE-WP-0021 dependency; T10 retains residual review.
## State Hub synchronization limitation and live handoff
InfoTech and Commerce native records synchronized successfully. Custodian also
created THE-WP-0001 and its two completed tasks, but its repository-wide checker
reported 13 historical assessment failures: ten missing archived CUST-WP-0054
task bindings, missing archived CUST-WP-0057/0058 workplan bindings, and one
active retired ad-hoc orphan. Prefix warnings expose the explicit AGENTS file
convention disagreeing with header/database prefixes (THE/CUST and INFO/ITC).
Live [CUST-IN-0017](../../../the-custodian/intakes.md), origin residual from
THE-WP-0001, owns triage and evidence-backed disposition. Archived records and
accepted ADR were preserved. G7 passes; a clean whole-Custodian State Hub
assessment is not claimed. Decision: `689eeb84-8b46-4dae-be5d-baa8e654f6ee`.
## Publication
- InfoTechCanon implementation `28c624b`, synchronized index `9e89a19`.
- CommerceCanon implementation `482fc1d`, repository-manager verified publication
and primary projection `1ac87592904be384dd1230e9b4ad5c9c10cc5da3`.
- Custodian interface and live residual `1df777b`.
- CUST-IN-0017 indexed as `01a073cf-51ca-7fa7-a432-658ba3718382`.
All native interface workplans are finished and their tasks are done. Project
T08 is done; T09 is ready to execute, with T10 still waiting on final residual
review. Overall foundation progress is 11/13 tasks.

View file

@ -71,3 +71,6 @@ The [corpus distribution ledger](corpus-distribution.json) records T07's frozen
research destinations and exact shared fragments. Reproduce G6 with
`python3 tools/validate_corpus.py --commerce-repo ../commerce-canon --info-tech-repo ../info-tech-canon`
from the project root. Historical source assertions are not current definitions.
[Reciprocal interface evidence](../docs/evidence/2026-09-06-interface-cards.md)
records the three published canon cards and explicit upstream import review (G7).

60
tools/test_interfaces.py Normal file
View file

@ -0,0 +1,60 @@
"""Regression checks for G7 rejection paths; run beside the three canon checkouts."""
from pathlib import Path
import unittest
from unittest.mock import patch
import yaml
import jsonschema
from validate_interfaces import validate
WORKSPACE = Path(__file__).resolve().parents[2]
READ_TEXT = Path.read_text
class InterfaceGateTests(unittest.TestCase):
def reject_card(self, repo, mutate, message, error=ValueError):
suffix = 'canon/interfaces/federation.yaml' if repo == 'the-custodian' else 'infospace/interfaces/federation.yaml'
target = WORKSPACE / repo / suffix
def read(path, *args, **kwargs):
content = READ_TEXT(path, *args, **kwargs)
if path == target:
card = yaml.safe_load(content)
mutate(card)
return yaml.safe_dump(card)
return content
with patch.object(Path, 'read_text', read):
with self.assertRaisesRegex(error, message):
validate(WORKSPACE)
def test_missing_reciprocal_peer_is_rejected(self):
self.reject_card('info-tech-canon', lambda c: c['peers'].pop(), 'peer coverage')
def test_duplicate_evidence_owner_is_rejected(self):
self.reject_card('commerce-canon', lambda c: c['exports'][0]['concepts'].append('Evidence'),
'Duplicate domain owner: Evidence')
def test_family_model_promotion_is_rejected(self):
def promote(card):
entry = next(e for e in card['exports'] if e['artifact'] == 'family-area')
entry['kind'] = 'domain-model'
self.reject_card('info-tech-canon', promote, 'Family promoted')
def test_custodian_domain_claim_is_rejected(self):
self.reject_card('the-custodian', lambda c: c['exports'][0]['concepts'].append('Evidence'),
'Governance claims domain semantics')
def test_invalid_schema_shape_is_rejected(self):
self.reject_card('info-tech-canon', lambda c: c.update(consumer={'repo': 'info-tech-canon'}),
"is not of type 'string'", jsonschema.ValidationError)
def test_import_exceeding_export_is_rejected(self):
def extend(card):
card['imports'][1]['concepts'].append('Undeclared concept')
self.reject_card('commerce-canon', extend, 'Import exceeds export')
if __name__ == '__main__':
unittest.main()

View file

@ -0,0 +1,176 @@
"""Check G7 federation cards, reciprocal contracts, ownership and review provenance.
Run from a project checkout beside the three canons. Requires PyYAML/jsonschema.
Repository-qualified card paths resolve below --workspace, never below the card.
"""
from __future__ import annotations
import argparse
import hashlib
import json
from pathlib import Path
import re
import subprocess
import jsonschema
import yaml
CARD_PATHS = {
'info-tech-canon': 'infospace/interfaces/federation.yaml',
'commerce-canon': 'infospace/interfaces/federation.yaml',
'the-custodian': 'canon/interfaces/federation.yaml',
}
def require(condition, message):
if not condition:
raise ValueError(message)
def sha(data):
return hashlib.sha256(data).hexdigest()
def git_blob(repo, commit, path):
require(bool(re.fullmatch(r'[0-9a-f]{40}', commit)), 'Source must use a full Git commit')
return subprocess.check_output(['git', 'show', f'{commit}:{path}'], cwd=repo)
def declared_concepts(text):
"""Support complete metadata and older explicit prose definitions.
A section heading alone cannot establish ownership: transferred concepts
deliberately keep their old anchors as imports.
"""
fm = yaml.safe_load(text.split('---', 2)[1]) if text.startswith('---\n') else {}
return set(fm.get('owned_concepts', [])) | set(
re.findall(r'^(?:An? )?\*\*(.+?)\*\* is\b', text, re.M)
)
def validate(workspace):
project = Path(__file__).resolve().parents[1]
schema_path = 'infospace/schemas/interface-card.schema.yaml'
schema = yaml.safe_load((workspace / 'info-tech-canon' / schema_path).read_text())
jsonschema.Draft202012Validator.check_schema(schema)
cards = {repo: yaml.safe_load((workspace / repo / path).read_text())
for repo, path in CARD_PATHS.items()}
ledger = json.loads((project / 'ledger/concept-ownership.json').read_text())
targets = [t for e in ledger['entries'] for t in e['targets'] if t['kind'] in {'concept', 'seed'}]
targets += ledger['additional_required_concepts']
exports = {}
ownership = {}
import_edges = 0
peer_links = 0
for repo, card in cards.items():
jsonschema.validate(card, schema)
require(card['consumer'] == repo, f'{repo}: wrong consumer')
require(card['status'] == 'published', f'{repo}: unpublished')
require(card['schema_source'] == {'repository': 'info-tech-canon', 'path': schema_path}, 'Schema drift')
peers = card['peers']
require(len(peers) == 2 and {p['repository'] for p in peers} == set(cards) - {repo}, f'{repo}: peer coverage')
for peer in peers:
other = peer['repository']
require(peer['card'] == CARD_PATHS[other], f'{repo}: bad peer card path')
require(any(p['repository'] == repo and p['card'] == CARD_PATHS[repo]
for p in cards[other]['peers']), f'{repo}: nonreciprocal peer')
peer_links += 1
require(card['canon_surfaces'] == [e['artifact'] for e in card['exports']], 'Export index drift')
for entry in card['exports']:
key = (repo, entry['artifact'])
require(key not in exports, f'Duplicate export {key}')
exports[key] = entry
require((workspace / repo / entry['path']).is_file(), f'Missing export {key}')
if entry['kind'] == 'ecosystem-governance':
require(repo == 'the-custodian' and entry['concepts'] == [], 'Governance claims domain semantics')
require(set(entry['governs']) == set(cards) - {repo}, 'Governance coverage')
else:
registry = yaml.safe_load((workspace / repo / 'canon.yaml').read_text())
matches = [m for m in registry['models'] + registry.get('concept_areas', []) if m['id'] == entry['artifact']]
require(len(matches) == 1, f'Unregistered export {key}')
for field in ['status', 'path']:
require(entry[field] == matches[0][field], f'{key}: registry {field} drift')
if entry['artifact'] == 'family-area':
require(entry['kind'] == 'concept-area-seed' and entry['availability'] == 'seeded-not-authored', 'Family promoted')
for concept in entry['concepts']:
require(concept not in ownership, f'Duplicate domain owner: {concept}')
ownership[concept] = (repo, entry['ledger_model'])
authority = card['authority']
require(authority == cards['the-custodian']['authority'], 'Authority mismatch')
require(authority['repository'] == 'the-custodian' and authority['artifact'] == 'CUST-ADR-006'
and authority['revision'] == 'accepted-1', 'Unreviewed authority')
adr = git_blob(workspace / 'the-custodian', authority['source_commit'], authority['path'])
require(sha(adr) == authority['sha256'], 'Pinned ADR hash mismatch')
require(adr == (workspace / 'the-custodian' / authority['path']).read_bytes(), 'ADR changed since review')
for target in targets:
require(ownership.get(target['concept']) == (target['owner']['canon'], target['owner']['model']),
f"Ledger disagreement: {target['concept']}")
for repo, card in cards.items():
seen = set()
for entry in card['imports']:
key = (entry['repository'], entry['artifact'])
require(key not in seen, f'{repo}: duplicate import')
seen.add(key)
require(key in exports and entry['repository'] != repo, f'{repo}: missing upstream export {key}')
require(entry['kind'] == exports[key]['kind'], 'Import kind mismatch')
require(set(entry['concepts']) <= set(exports[key]['concepts']), 'Import exceeds export')
require(not any(ownership[c][0] == repo for c in entry['concepts']), 'Import redefined locally')
import_edges += 1
require(cards['the-custodian']['imports'] == [], 'Custodian domain dependency introduced')
require(len(cards['info-tech-canon']['imports']) == 1, 'Unreviewed reverse domain import')
require(len(cards['the-custodian']['exports']) == 1, 'Custodian federation scope drift')
commerce = workspace / 'commerce-canon'
model_dir = commerce / 'infospace/models/counterparty'
manifest_path = model_dir / 'imports.json'
current = json.loads(manifest_path.read_text())
review = current['review']
require((model_dir / review['record']).is_file(), 'Missing import review')
previous_bytes = (model_dir / review['previous_manifest']).read_bytes()
require(sha(previous_bytes) == review['previous_manifest_sha256'], 'Historical manifest changed')
previous = json.loads(previous_bytes)
require(previous['source_commit'] == '361c944325934ccdb190470baf6f55440b6b486e', 'Original review pin changed')
require(review['concept_changes'] == [], 'Unexpected concept adoption')
require([(r['model'], r['concepts']) for r in previous['imports']] ==
[(r['model'], r['concepts']) for r in current['imports']], 'Unreviewed import change')
checked_blobs = 0
drift = []
for manifest in [previous, current]:
require(manifest['source_repository'] == 'info-tech-canon', 'Wrong import source')
for entry in manifest['imports']:
blob = git_blob(workspace / 'info-tech-canon', manifest['source_commit'], entry['path'])
require(sha(blob) == entry['sha256'], f"Pinned import hash mismatch: {entry['model']}")
require(set(entry['concepts']) <= declared_concepts(blob.decode()), f"Import not owned: {entry['model']}")
checked_blobs += 1
if manifest is current and blob != (workspace / 'info-tech-canon' / entry['path']).read_bytes():
drift.append(entry['path'])
domain_imports = [e for e in cards['commerce-canon']['imports'] if e['kind'] == 'domain-model']
require(len(domain_imports) == len(current['imports']) == 4, 'Import model coverage')
for row in current['imports']:
exported = exports[('info-tech-canon', row['model'])]
require(exported['path'] == row['path'], 'Import/export source mismatch')
matches = [e for e in domain_imports if e['artifact'] == row['model']]
require(len(matches) == 1 and matches[0]['concepts'] == row['concepts'], 'Card/manifest mismatch')
require(commerce / matches[0]['manifest'] == manifest_path, 'Wrong manifest pointer')
links = 0
for repo, path in CARD_PATHS.items():
root = workspace / repo
for document in [root / 'README.md', root / Path(path).parent / 'README.md']:
for link in re.findall(r'\]\(([^)]+)\)', document.read_text()):
if '://' in link or link.startswith('#'):
continue
require((document.parent / link.split('#')[0]).exists(), f'Broken link: {document}: {link}')
links += 1
return {'gate': 'G7', 'result': 'pass', 'cards': len(cards), 'reciprocal_peer_links': peer_links,
'import_edges': import_edges, 'ledger_concepts_and_seed_covered': len(targets),
'imported_concepts': sum(len(e['concepts']) for e in domain_imports),
'historical_and_current_import_blobs_checked': checked_blobs,
'source_commit': current['source_commit'], 'upstream_changes_since_review': drift,
'navigation_links_checked': links, 'custodian_domain_concepts': 0,
'family': 'seeded-not-authored'}
if __name__ == '__main__':
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('--workspace', type=Path, default=Path(__file__).resolve().parents[2])
args = parser.parse_args()
print(json.dumps(validate(args.workspace.resolve()), indent=2))

View file

@ -299,7 +299,7 @@ does not promote historical assertions. G6 passes; T08 is now todo.
```task
id: CFED-WP-0001-T08
status: todo
status: done
priority: medium
state_hub_task_id: "e0558c32-415f-5563-bca2-438b35fa6b53"
```
@ -317,11 +317,22 @@ kernel references that still mark upstream extensions pending. Keep historical
import revisions verifiable; do not silently adopt new upstream definitions.
**Result (2026-09-06):** Native INFO-WP-0025, COMMERCE-WP-0004 and THE-WP-0001
publish reciprocal interface cards in all three canons. [G7 evidence](../docs/evidence/2026-09-06-interface-cards.md)
verifies three schema-valid cards, six reciprocal links, all ledger concept/seed
assignments and 25 unchanged imports. Commerce advances its reviewed upstream
pin with the previous manifest preserved; kernel references acknowledge T12/T13.
InfoTechCanon checks pass (46 tests); project rejection/ownership tests pass (13).
Custodian's historical projection failures and conflicting generated prefix
instructions have live residual [CUST-IN-0017](../../the-custodian/intakes.md).
G7 passes; T09 is now todo. Whole-fleet consistency is not claimed by this gate.
## Sweep fleet references
```task
id: CFED-WP-0001-T09
status: wait
status: todo
priority: medium
state_hub_task_id: "42ebf476-6a45-5e23-b507-eb90bc4f5c07"
```