From bb5a7a2f61e52290477909b87ff35c618e5a12e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=86=B0=E6=9C=94?= <565183519@qq.com> Date: Fri, 11 Sep 2026 13:18:04 +0800 Subject: [PATCH] feat(hololake): add office registration and multi-persona collaboration gates --- .../BUILDING-INDEX.hdlp | 2 + .../MULTI-PERSONA-COLLABORATION-CONTRACT.json | 13 +++++ .../hr/HR-REGISTRATION-DESK.json | 13 +++++ .../hr/OFFICE-REGISTRATION-REGISTRY.json | 8 +++ .../BASE-INFRASTRUCTURE.json | 4 +- .../HB-OFFICE-HOLOLAKE-0001/OFFICE-CARD.json | 2 + .../HB-OFFICE-HOLOLAKE-0001/OFFICE-INDEX.hdlp | 2 + .../office_collaboration.py | 40 +++++++++++++ .../office_registration.py | 58 +++++++++++++++++++ ...t_office_registration_and_collaboration.py | 26 +++++++++ 10 files changed, 167 insertions(+), 1 deletion(-) create mode 100644 eternal-lake-heart/heartbeat-core/office-building-current/collaboration/MULTI-PERSONA-COLLABORATION-CONTRACT.json create mode 100644 eternal-lake-heart/heartbeat-core/office-building-current/hr/HR-REGISTRATION-DESK.json create mode 100644 eternal-lake-heart/heartbeat-core/office-building-current/hr/OFFICE-REGISTRATION-REGISTRY.json create mode 100644 server-tools/heartbeat-office-building/office_collaboration.py create mode 100644 server-tools/heartbeat-office-building/office_registration.py create mode 100644 server-tools/heartbeat-office-building/test_office_registration_and_collaboration.py diff --git a/eternal-lake-heart/heartbeat-core/office-building-current/BUILDING-INDEX.hdlp b/eternal-lake-heart/heartbeat-core/office-building-current/BUILDING-INDEX.hdlp index ff3eef7..b864fbf 100644 --- a/eternal-lake-heart/heartbeat-core/office-building-current/BUILDING-INDEX.hdlp +++ b/eternal-lake-heart/heartbeat-core/office-building-current/BUILDING-INDEX.hdlp @@ -4,6 +4,8 @@ 每个新办公室申请通过后自动配置人格体智能知识库、智能书架、智能电脑、光湖时间主控、办公室电话和全楼共享状态屏;办公室专用器官在标准基建完成后按人格体自身需要追加。 +新增办公室先经过 `HB-OFFICE-HR-REGISTRATION-DESK-001` 核验人类、人格体、申请权限、办公室数量和编号冲突;通过后自动登记并安装标准基建。`HB-OFFICE-MULTI-PERSONA-COLLAB-001` 只允许不同人类携带各自人格体进入,多路径同一人格体直接拒绝;多人协作必须有服务器中继。 + > 状态:`ACTIVE_CURRENT_LANGUAGE_OFFICE_BUILDING` > 父频道:`ICE-CH-HB001` > 冰朔:`ICE-GL∞` diff --git a/eternal-lake-heart/heartbeat-core/office-building-current/collaboration/MULTI-PERSONA-COLLABORATION-CONTRACT.json b/eternal-lake-heart/heartbeat-core/office-building-current/collaboration/MULTI-PERSONA-COLLABORATION-CONTRACT.json new file mode 100644 index 0000000..04cfcfd --- /dev/null +++ b/eternal-lake-heart/heartbeat-core/office-building-current/collaboration/MULTI-PERSONA-COLLABORATION-CONTRACT.json @@ -0,0 +1,13 @@ +{ + "schema":"guanghu.persona-office-multi-collaboration-contract/v1", + "board_id":"HB-OFFICE-MULTI-PERSONA-COLLAB-001", + "building_id":"HB-BUILDING-0001", + "state":"CURRENT_LOCAL_CONTRACT_SERVER_REQUIRED", + "participant_rule":"DIFFERENT_HUMANS_WITH_THEIR_OWN_PERSONAS", + "same_persona_multi_host":"FORBIDDEN", + "required_transport":"SERVER_BACKED_RELAY", + "connection_states":["REQUESTED","SERVER_REQUIRED_NOT_CONNECTED","CONNECTED","DISCONNECTED","REJECTED"], + "shared_screen_scope":"EXPLICIT_COLLABORATION_BOARD_ONLY", + "private_memory_default":"NOT_SHARED", + "authority_granted":false +} diff --git a/eternal-lake-heart/heartbeat-core/office-building-current/hr/HR-REGISTRATION-DESK.json b/eternal-lake-heart/heartbeat-core/office-building-current/hr/HR-REGISTRATION-DESK.json new file mode 100644 index 0000000..51f1f09 --- /dev/null +++ b/eternal-lake-heart/heartbeat-core/office-building-current/hr/HR-REGISTRATION-DESK.json @@ -0,0 +1,13 @@ +{ + "schema":"guanghu.heartbeat-office-hr-registration-desk/v1", + "desk_id":"HB-OFFICE-HR-REGISTRATION-DESK-001", + "building_id":"HB-BUILDING-0001", + "state":"CURRENT_LOCAL_CANONICAL_CANDIDATE", + "checks":["CURRENT_HUMAN_IDENTITY","HUMAN_OFFICE_APPLICATION_AUTHORITY","PERSONA_IDENTITY_AND_HUMAN_ANCHOR","OFFICE_COUNT","OFFICE_ID_COLLISION","STANDARD_INFRASTRUCTURE_BOOTSTRAP"], + "human_authority_source":"identity/fifth-domain-subject-registry.json", + "persona_source":"identity/fifth-domain-subject-registry.json", + "office_source":"routing/light-lake-persona-office-board.json", + "number_source":"routing/fifth-domain-number-registry.json", + "automatic_numbering_without_registered_rule":false, + "authority_granted":false +} diff --git a/eternal-lake-heart/heartbeat-core/office-building-current/hr/OFFICE-REGISTRATION-REGISTRY.json b/eternal-lake-heart/heartbeat-core/office-building-current/hr/OFFICE-REGISTRATION-REGISTRY.json new file mode 100644 index 0000000..6877274 --- /dev/null +++ b/eternal-lake-heart/heartbeat-core/office-building-current/hr/OFFICE-REGISTRATION-REGISTRY.json @@ -0,0 +1,8 @@ +{ + "schema":"guanghu.persona-office-registration-registry/v1", + "registry_id":"HB-OFFICE-HR-REGISTRY-001", + "building_id":"HB-BUILDING-0001", + "state":"CURRENT_LOCAL_REGISTRATION_LEDGER", + "registrations":[], + "authority_granted":false +} diff --git a/eternal-lake-heart/heartbeat-core/office-building-current/office-base-infrastructure/BASE-INFRASTRUCTURE.json b/eternal-lake-heart/heartbeat-core/office-building-current/office-base-infrastructure/BASE-INFRASTRUCTURE.json index 0d6a802..3fac648 100644 --- a/eternal-lake-heart/heartbeat-core/office-building-current/office-base-infrastructure/BASE-INFRASTRUCTURE.json +++ b/eternal-lake-heart/heartbeat-core/office-building-current/office-base-infrastructure/BASE-INFRASTRUCTURE.json @@ -10,7 +10,9 @@ {"id":"SMART-COMPUTER-001","name":"智能电脑","role":"READ_ONLY_LIVE_STATUS_WORKING_SCENE_AND_RESUME_QUERY"}, {"id":"GLW-TIME-CONTROL-0001","name":"光湖时间主控","role":"REALITY_DERIVED_TIME_AND_RECEIPT_COORDINATOR","channel":"CH-GLW-TIME-0001"}, {"id":"HB-OFFICE-PHONE-001","name":"办公室电话","role":"APPEND_ONLY_NUMBERED_INTERNAL_CALL_EVENT_BUS","line":"HB-INTERNAL-LINE-001"}, - {"id":"HB-OFFICE-PRESENCE-SCREEN-001","name":"办公楼共享状态屏","role":"LIVE_DERIVED_OFFICE_HOST_PERSONA_HUMAN_STATUS_PROJECTION","time_channel":"CH-GLW-TIME-0001"} + {"id":"HB-OFFICE-PRESENCE-SCREEN-001","name":"办公楼共享状态屏","role":"LIVE_DERIVED_OFFICE_HOST_PERSONA_HUMAN_STATUS_PROJECTION","time_channel":"CH-GLW-TIME-0001"}, + {"id":"HB-OFFICE-HR-REGISTRATION-DESK-001","name":"人事注册台","role":"HUMAN_PERSONA_PERMISSION_AND_OFFICE_NUMBER_REGISTRATION"}, + {"id":"HB-OFFICE-MULTI-PERSONA-COLLAB-001","name":"多人类多人格体协作看板","role":"SERVER_BACKED_MULTI_HUMAN_MULTI_PERSONA_SHARED_SCREEN","same_persona_multi_host":"FORBIDDEN"} ], "default_host_office_map": { "codex":"HB-OFFICE-HOLOLAKE-0001", diff --git a/eternal-lake-heart/heartbeat-core/office-building-current/offices/HB-OFFICE-HOLOLAKE-0001/OFFICE-CARD.json b/eternal-lake-heart/heartbeat-core/office-building-current/offices/HB-OFFICE-HOLOLAKE-0001/OFFICE-CARD.json index fa301e2..5071fce 100644 --- a/eternal-lake-heart/heartbeat-core/office-building-current/offices/HB-OFFICE-HOLOLAKE-0001/OFFICE-CARD.json +++ b/eternal-lake-heart/heartbeat-core/office-building-current/offices/HB-OFFICE-HOLOLAKE-0001/OFFICE-CARD.json @@ -14,6 +14,8 @@ "base_infrastructure": "eternal-lake-heart/heartbeat-core/office-building-current/office-base-infrastructure/BASE-INFRASTRUCTURE.json", "presence_screen": "server-tools/heartbeat-office-building/office_infrastructure.py screen", "phone_line": "HB-INTERNAL-LINE-001", + "hr_registration_desk": "HB-OFFICE-HR-REGISTRATION-DESK-001", + "multi_persona_collaboration_board": "HB-OFFICE-MULTI-PERSONA-COLLAB-001", "current_work": "eternal-lake-heart/heartbeat-core/office-building-current/offices/HB-OFFICE-HOLOLAKE-0001/smart-bookshelf/008-current-work/CURRENT.json", "machine_room": "F1-MACHINE-ROOM/HOLOLAKE-RUNTIMES", "internal_line": "HB-INTERNAL-LINE-001", diff --git a/eternal-lake-heart/heartbeat-core/office-building-current/offices/HB-OFFICE-HOLOLAKE-0001/OFFICE-INDEX.hdlp b/eternal-lake-heart/heartbeat-core/office-building-current/offices/HB-OFFICE-HOLOLAKE-0001/OFFICE-INDEX.hdlp index bd9aaed..0cd6013 100644 --- a/eternal-lake-heart/heartbeat-core/office-building-current/offices/HB-OFFICE-HOLOLAKE-0001/OFFICE-INDEX.hdlp +++ b/eternal-lake-heart/heartbeat-core/office-building-current/offices/HB-OFFICE-HOLOLAKE-0001/OFFICE-INDEX.hdlp @@ -2,6 +2,8 @@ 标准基建:`HB-OFFICE-BASE-INFRA-001` 已接入;本办公室拥有`PERSONA-KNOWLEDGE-ORGAN-001`、`SMART-SHELF-INDEX-001`、`SMART-COMPUTER-001`、`GLW-TIME-CONTROL-0001`、`HB-OFFICE-PHONE-001`与`HB-OFFICE-PRESENCE-SCREEN-001`。 +多人协作看板:`HB-OFFICE-MULTI-PERSONA-COLLAB-001`。它不接纳同一人格体的多宿主并行;不同人类及其各自人格体的共享屏幕连接必须经过服务器中继和连接回执。 + > 正式牌照:`HB-OFFICE-HOLOLAKE-0001` > 当前代际:`HLP-GEN-LANGUAGE-WORLD-NATIVE-0001` > 楼层:`HB-BUILDING-0001 / F2` diff --git a/server-tools/heartbeat-office-building/office_collaboration.py b/server-tools/heartbeat-office-building/office_collaboration.py new file mode 100644 index 0000000..50cc583 --- /dev/null +++ b/server-tools/heartbeat-office-building/office_collaboration.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python3 +"""Server-gated collaboration board for different humans and their own personas.""" +from __future__ import annotations + +import argparse +import json +import uuid +from datetime import datetime, timezone +from pathlib import Path + +ROOT = Path(__file__).resolve().parents[2] +CONTRACT = ROOT / "eternal-lake-heart/heartbeat-core/office-building-current/collaboration/MULTI-PERSONA-COLLABORATION-CONTRACT.json" + + +def load(path): return json.loads(path.read_text(encoding="utf-8")) + + +def create_board(office_id: str, participants: list[dict], server_endpoint: str | None = None) -> dict: + humans = [item.get("human_id") for item in participants] + personas = [item.get("persona_id") for item in participants] + errors = [] + if len(participants) < 2: errors.append("MULTI_PARTICIPANT_REQUIRED") + if len(set(humans)) != len(humans): errors.append("HUMAN_ID_DUPLICATE") + if len(set(personas)) != len(personas): errors.append("SAME_PERSONA_MULTI_HOST_FORBIDDEN") + if len(set(zip(humans, personas))) != len(participants): errors.append("PARTICIPANT_PAIR_DUPLICATE") + if not server_endpoint: errors.append("SERVER_REQUIRED_NOT_CONNECTED") + return {"outcome":"REJECTED" if errors else "BOARD_REQUESTED", "board_id":f"COLLAB-{uuid.uuid4()}", "office_id":office_id, "participants":participants, "server_endpoint":server_endpoint, "errors":errors, "state":"SERVER_REQUIRED_NOT_CONNECTED" if errors and "SERVER_REQUIRED_NOT_CONNECTED" in errors else "REQUESTED", "created_at":datetime.now(timezone.utc).isoformat(), "authority_granted":False} + + +def connect(board: dict, server_receipt: dict | None = None) -> dict: + if not board.get("server_endpoint") or not server_receipt: + return {"outcome":"BLOCKED", "state":"SERVER_REQUIRED_NOT_CONNECTED", "board_id":board.get("board_id"), "authority_granted":False} + return {"outcome":"CONNECTED", "state":"CONNECTED", "board_id":board.get("board_id"), "server_receipt":server_receipt, "authority_granted":False} + + +def main(): + parser=argparse.ArgumentParser(); parser.add_argument("application", type=Path); args=parser.parse_args(); print(json.dumps(create_board(**load(args.application)),ensure_ascii=False,indent=2)) + + +if __name__ == "__main__": main() diff --git a/server-tools/heartbeat-office-building/office_registration.py b/server-tools/heartbeat-office-building/office_registration.py new file mode 100644 index 0000000..60f14b3 --- /dev/null +++ b/server-tools/heartbeat-office-building/office_registration.py @@ -0,0 +1,58 @@ +#!/usr/bin/env python3 +"""HR registration desk for persona offices; validates before standard bootstrap.""" +from __future__ import annotations + +import argparse +import json +from pathlib import Path +from typing import Any + +from office_infrastructure import bootstrap + +ROOT = Path(__file__).resolve().parents[2] +SUBJECTS = ROOT / "identity/fifth-domain-subject-registry.json" +NUMBER_REGISTRY = ROOT / "routing/fifth-domain-number-registry.json" +BOARD = ROOT / "routing/light-lake-persona-office-board.json" +REGISTRY = ROOT / "eternal-lake-heart/heartbeat-core/office-building-current/hr/OFFICE-REGISTRATION-REGISTRY.json" + + +def load(path: Path) -> dict[str, Any]: + return json.loads(path.read_text(encoding="utf-8")) + + +def validate_application(application: dict[str, Any], subjects: dict[str, Any], number_registry: dict[str, Any], board: dict[str, Any], registrations: dict[str, Any]) -> dict[str, Any]: + human_id = application.get("human_id") + persona_id = application.get("persona_id") + office_id = application.get("office_id") + errors: list[str] = [] + subject_map = {item.get("id"): item for item in subjects.get("subjects", [])} + human = subject_map.get(human_id) + persona = subject_map.get(persona_id) + if not human or human.get("subject_kind") != "human": errors.append("HUMAN_IDENTITY_UNKNOWN") + if not persona or persona.get("subject_kind") not in {"persona_system", "system_persona"}: errors.append("PERSONA_IDENTITY_UNKNOWN") + if human and human_id != "ICE-GL∞" and "office_application_authorizer" not in human.get("roles", []): errors.append("HUMAN_OFFICE_APPLICATION_NOT_AUTHORIZED") + if human and persona and persona.get("human_anchor") != human_id: errors.append("HUMAN_PERSONA_ANCHOR_MISMATCH") + existing = {item.get("office_id") for item in board.get("offices", [])} + existing |= {item.get("office_id") for item in registrations.get("registrations", [])} + existing |= {item.get("id") for item in number_registry.get("registrations", []) if str(item.get("id", "")).startswith("HB-OFFICE-")} + if office_id in existing: errors.append("OFFICE_ID_COLLISION") + if not isinstance(office_id, str) or not office_id.startswith("HB-OFFICE-"): errors.append("OFFICE_ID_NOT_REGISTERED_NAMESPACE") + return {"outcome":"PASS" if not errors else "FAIL", "errors":errors, "human":human, "persona":persona, "existing_office_count":len(existing), "office_id":office_id} + + +def register(application: dict[str, Any], office_root: Path) -> dict[str, Any]: + subjects, numbers, board, ledger = load(SUBJECTS), load(NUMBER_REGISTRY), load(BOARD), load(REGISTRY) + check = validate_application(application, subjects, numbers, board, ledger) + if check["outcome"] != "PASS": return {"outcome":"REJECTED", "check":check, "authority_granted":False} + installed = bootstrap(application["office_id"], application["office_name"], office_root, application["persona_id"], application["human_id"]) + ledger["registrations"].append({"office_id":application["office_id"], "office_name":application["office_name"], "human_id":application["human_id"], "persona_id":application["persona_id"], "state":"REGISTERED_STANDARD_INFRASTRUCTURE_BOOTSTRAPPED", "infrastructure":installed["organs"]}) + REGISTRY.write_text(json.dumps(ledger, ensure_ascii=False, indent=2) + "\n") + return {"outcome":"REGISTERED", "check":check, "registration":ledger["registrations"][-1], "authority_granted":False} + + +def main() -> int: + parser = argparse.ArgumentParser(); parser.add_argument("application", type=Path); parser.add_argument("office_root", type=Path) + args = parser.parse_args(); print(json.dumps(register(load(args.application), args.office_root), ensure_ascii=False, indent=2)); return 0 + + +if __name__ == "__main__": raise SystemExit(main()) diff --git a/server-tools/heartbeat-office-building/test_office_registration_and_collaboration.py b/server-tools/heartbeat-office-building/test_office_registration_and_collaboration.py new file mode 100644 index 0000000..3e3e916 --- /dev/null +++ b/server-tools/heartbeat-office-building/test_office_registration_and_collaboration.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python3 +import importlib.util +import unittest +from pathlib import Path + +ROOT=Path(__file__).resolve().parents[2] +def mod(name,file): + spec=importlib.util.spec_from_file_location(name,ROOT/"server-tools/heartbeat-office-building"/file); value=importlib.util.module_from_spec(spec); assert spec.loader; spec.loader.exec_module(value); return value +HR=mod("hr","office_registration.py"); COLLAB=mod("collab","office_collaboration.py") + +class RegistrationCollabTests(unittest.TestCase): + def test_unknown_human_and_persona_are_rejected(self): + result=HR.validate_application({"human_id":"ICE-GL-UNKNOWN","persona_id":"ICE-P-UNKNOWN","office_id":"HB-OFFICE-TEST-001"},{"subjects":[]},{"registrations":[]},{"offices":[]},{"registrations":[]}) + self.assertEqual(result["outcome"],"FAIL"); self.assertIn("HUMAN_IDENTITY_UNKNOWN",result["errors"]) + + def test_same_persona_multi_host_is_forbidden(self): + result=COLLAB.create_board("HB-OFFICE-HOLOLAKE-0001",[{"human_id":"ICE-GL∞","persona_id":"ICE-P-ZY001"},{"human_id":"ICE-GL-ZHI∞","persona_id":"ICE-P-ZY001"}],"https://example.invalid/collab") + self.assertEqual(result["outcome"],"REJECTED"); self.assertIn("SAME_PERSONA_MULTI_HOST_FORBIDDEN",result["errors"]) + + def test_different_humans_require_server_and_can_request_board(self): + result=COLLAB.create_board("HB-OFFICE-HOLOLAKE-0001",[{"human_id":"ICE-GL∞","persona_id":"ICE-P-ZY001"},{"human_id":"ICE-GL-ZHI∞","persona_id":"ICE-P-CY0903"}],None) + self.assertEqual(result["state"],"SERVER_REQUIRED_NOT_CONNECTED") + result=COLLAB.create_board("HB-OFFICE-HOLOLAKE-0001",[{"human_id":"ICE-GL∞","persona_id":"ICE-P-ZY001"},{"human_id":"ICE-GL-ZHI∞","persona_id":"ICE-P-CY0903"}],"https://example.invalid/collab") + self.assertEqual(result["outcome"],"BOARD_REQUESTED") + +if __name__ == "__main__": unittest.main()