fix: advance TCS root only for numbered-source changes
This commit is contained in:
parent
72fa92962f
commit
4a030c15ab
5 changed files with 21 additions and 6 deletions
|
|
@ -2,7 +2,7 @@ schema: tcs.module-lock/v1
|
||||||
module_id: MOD-TCS-MOTHER-ROOT-NAVIGATOR-001
|
module_id: MOD-TCS-MOTHER-ROOT-NAVIGATOR-001
|
||||||
module_source_sha256: eb299410bacd0247bc43732154fac0f74f181bab6a5e4e5714937d1b90b24688
|
module_source_sha256: eb299410bacd0247bc43732154fac0f74f181bab6a5e4e5714937d1b90b24688
|
||||||
module_gir_sha256: bb3246fbfc69a39b3e5412e41271aeb7c66e37a2539902b5dab2291e38a04800
|
module_gir_sha256: bb3246fbfc69a39b3e5412e41271aeb7c66e37a2539902b5dab2291e38a04800
|
||||||
runtime_sha256: 09cc06a63cbd320634e0231d3dc7887cc3f24276504527ec9154ecba344674a6
|
runtime_sha256: d1cb121af345e8e860d001133e9aac07383f2a3776d61cf42a1cce381ea3b8be
|
||||||
root_map_sha256: 2f5c4b7a4dc49edb4d83787ea68a0a8d88dff79ef78215550cd2f209e7732e88
|
root_map_sha256: 77e61b5812e0618aa5318e5090ccba09ef4feadd664b06f0ec89bdbf64fd8d3c
|
||||||
compiler_sha256: 5ad6f0c43d8db80677cad7091e6a3b706e701307b2537446dc13635e89499942
|
compiler_sha256: 5ad6f0c43d8db80677cad7091e6a3b706e701307b2537446dc13635e89499942
|
||||||
update_rule: CURRENT_DIRECT_LANGUAGE_TCS_PLUS_NUMBER_IMPACT_PLUS_COMMITTED_READBACK
|
update_rule: CURRENT_DIRECT_LANGUAGE_TCS_PLUS_NUMBER_IMPACT_PLUS_COMMITTED_READBACK
|
||||||
|
|
|
||||||
|
|
@ -115,7 +115,7 @@
|
||||||
"tcs_mother_root_navigation": {
|
"tcs_mother_root_navigation": {
|
||||||
"path": "routing/tcs-mother-root-dynamic-navigation-map.json",
|
"path": "routing/tcs-mother-root-dynamic-navigation-map.json",
|
||||||
"id": "TCS-MOTHER-ROOT-DYNAMIC-NAVIGATION-MAP-001",
|
"id": "TCS-MOTHER-ROOT-DYNAMIC-NAVIGATION-MAP-001",
|
||||||
"version": "2026-09-08.1",
|
"version": "2026-09-08.2",
|
||||||
"load_policy": "FIRST_BEFORE_WORLD_DOMAIN_HUMAN_PERSONA_CHANNEL_OR_HOST_ROUTE_RESOLUTION"
|
"load_policy": "FIRST_BEFORE_WORLD_DOMAIN_HUMAN_PERSONA_CHANNEL_OR_HOST_ROUTE_RESOLUTION"
|
||||||
},
|
},
|
||||||
"hololake_stage_relay": {
|
"hololake_stage_relay": {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"schema": "guanghu.tcs-mother-root-dynamic-navigation/v1",
|
"schema": "guanghu.tcs-mother-root-dynamic-navigation/v1",
|
||||||
"map_id": "TCS-MOTHER-ROOT-DYNAMIC-NAVIGATION-MAP-001",
|
"map_id": "TCS-MOTHER-ROOT-DYNAMIC-NAVIGATION-MAP-001",
|
||||||
"version": "2026-09-08.1",
|
"version": "2026-09-08.2",
|
||||||
"state": "CURRENT_LOCAL_CANONICAL_NOT_PUBLISHED",
|
"state": "CURRENT_LOCAL_CANONICAL_NOT_PUBLISHED",
|
||||||
"source_tcs": "runtime/fifth-domain-language-system/language/protocols/TCS-TCS-MOTHER-ROOT-DYNAMIC-NUMBER-NAVIGATION-20260908.tcs",
|
"source_tcs": "runtime/fifth-domain-language-system/language/protocols/TCS-TCS-MOTHER-ROOT-DYNAMIC-NUMBER-NAVIGATION-20260908.tcs",
|
||||||
"impact_manifest": "tcs-root/numbering/NUMBER-IMPACT-20260908.json",
|
"impact_manifest": "tcs-root/numbering/NUMBER-IMPACT-20260908.json",
|
||||||
|
|
@ -69,6 +69,7 @@
|
||||||
],
|
],
|
||||||
"automatic_update_contract": {
|
"automatic_update_contract": {
|
||||||
"ordinary_language_or_file_change_updates_current": false,
|
"ordinary_language_or_file_change_updates_current": false,
|
||||||
|
"ordinary_commit_without_numbered_source_hash_change_updates_current": false,
|
||||||
"required": ["CURRENT_DIRECT_LANGUAGE_TCS_SOURCE", "NUMBER_IMPACT_MANIFEST", "COMMITTED_TARGET_READBACK", "SOURCE_HASH_MATCH", "REFERENTIAL_INTEGRITY_PASS"],
|
"required": ["CURRENT_DIRECT_LANGUAGE_TCS_SOURCE", "NUMBER_IMPACT_MANIFEST", "COMMITTED_TARGET_READBACK", "SOURCE_HASH_MATCH", "REFERENTIAL_INTEGRITY_PASS"],
|
||||||
"trigger": "CANONICAL_CODEX_COMMIT_POST_COMMIT_HOOK_AND_SHARED_ENTRY_STATUS_CHECK",
|
"trigger": "CANONICAL_CODEX_COMMIT_POST_COMMIT_HOOK_AND_SHARED_ENTRY_STATUS_CHECK",
|
||||||
"failure": "KEEP_LAST_KNOWN_GOOD_AND_WRITE_REJECT_RECEIPT",
|
"failure": "KEEP_LAST_KNOWN_GOOD_AND_WRITE_REJECT_RECEIPT",
|
||||||
|
|
|
||||||
|
|
@ -174,6 +174,8 @@ def refresh(repo: Path, output: Path, pointer: Path, trigger: str) -> dict[str,
|
||||||
return {"outcome": "PASS", "state": "CURRENT_IDEMPOTENT", "source_commit": snapshot["source_commit"], "current_sha256": digest(current_path.read_bytes())}
|
return {"outcome": "PASS", "state": "CURRENT_IDEMPOTENT", "source_commit": snapshot["source_commit"], "current_sha256": digest(current_path.read_bytes())}
|
||||||
if previous:
|
if previous:
|
||||||
changed = {key for key, value in snapshot["registered_source_hashes"].items() if previous.get("registered_source_hashes", {}).get(key) != value}
|
changed = {key for key, value in snapshot["registered_source_hashes"].items() if previous.get("registered_source_hashes", {}).get(key) != value}
|
||||||
|
if not changed:
|
||||||
|
return {"outcome":"PASS","state":"CURRENT_NUMBER_NAV_UNCHANGED","source_commit":previous["source_commit"],"observed_repo_head":snapshot["source_commit"],"current_sha256":digest(current_path.read_bytes()),"freshness_token":previous["freshness_token"]}
|
||||||
affected = set(commit_json(repo, snapshot["source_commit"], snapshot["impact"]["path"]).get("affected_paths", []))
|
affected = set(commit_json(repo, snapshot["source_commit"], snapshot["impact"]["path"]).get("affected_paths", []))
|
||||||
if changed and not changed.issubset(affected):
|
if changed and not changed.issubset(affected):
|
||||||
raise RootError("UNADMITTED_NUMBERED_SOURCE_DRIFT:" + ",".join(sorted(changed - affected)))
|
raise RootError("UNADMITTED_NUMBERED_SOURCE_DRIFT:" + ",".join(sorted(changed - affected)))
|
||||||
|
|
@ -203,8 +205,10 @@ def status(repo: Path, output: Path, pointer: Path) -> dict[str, Any]:
|
||||||
body = (output / "CURRENT.json").read_bytes()
|
body = (output / "CURRENT.json").read_bytes()
|
||||||
current = json.loads(body)
|
current = json.loads(body)
|
||||||
head = run(repo, "rev-parse", "HEAD")
|
head = run(repo, "rev-parse", "HEAD")
|
||||||
valid = digest(body) == p.get("current_sha256") and current.get("freshness_token") == p.get("freshness_token") and current.get("source_commit") == head
|
observed = build(repo, head)
|
||||||
return {"outcome":"PASS" if valid else "FAIL","state":"TCS_ROOT_CURRENT_VERIFIED" if valid else "TCS_ROOT_CURRENT_STALE_OR_TAMPERED","source_commit":current.get("source_commit"),"repo_head":head,"current_sha256":digest(body),"freshness_token":current.get("freshness_token"),"current":str(output / "CURRENT.json")}
|
source_equivalent = current.get("registered_source_hashes") == observed.get("registered_source_hashes")
|
||||||
|
valid = digest(body) == p.get("current_sha256") and current.get("freshness_token") == p.get("freshness_token") and source_equivalent
|
||||||
|
return {"outcome":"PASS" if valid else "FAIL","state":"TCS_ROOT_CURRENT_VERIFIED" if valid else "TCS_ROOT_CURRENT_STALE_OR_TAMPERED","source_commit":current.get("source_commit"),"repo_head":head,"numbered_sources_equal_head":source_equivalent,"current_sha256":digest(body),"freshness_token":current.get("freshness_token"),"current":str(output / "CURRENT.json")}
|
||||||
|
|
||||||
|
|
||||||
def resolve(output: Path, requested: str, kind: str | None) -> dict[str, Any]:
|
def resolve(output: Path, requested: str, kind: str | None) -> dict[str, Any]:
|
||||||
|
|
|
||||||
|
|
@ -53,6 +53,16 @@ class RootAgentTest(unittest.TestCase):
|
||||||
MODULE.refresh(ROOT, output, pointer, 'negative-test')
|
MODULE.refresh(ROOT, output, pointer, 'negative-test')
|
||||||
self.assertEqual(current.read_bytes(), before)
|
self.assertEqual(current.read_bytes(), before)
|
||||||
|
|
||||||
|
def test_ordinary_commit_equivalent_sources_do_not_advance_current(self):
|
||||||
|
with tempfile.TemporaryDirectory() as temp:
|
||||||
|
base = Path(temp)
|
||||||
|
output, pointer = base / 'state', base / 'TCS-ROOT.json'
|
||||||
|
first = MODULE.refresh(ROOT, output, pointer, 'test')
|
||||||
|
current = json.loads((output / 'CURRENT.json').read_text())
|
||||||
|
same = MODULE.refresh(ROOT, output, pointer, 'ordinary-commit-test')
|
||||||
|
self.assertIn(same['state'], ['CURRENT_IDEMPOTENT', 'CURRENT_NUMBER_NAV_UNCHANGED'])
|
||||||
|
self.assertEqual(json.loads((output / 'CURRENT.json').read_text())['freshness_token'], current['freshness_token'])
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue