Own mobile relay runtime in L7

This commit is contained in:
rcourtman
2026-03-28 18:07:44 +00:00
parent 091f7a9957
commit 8020306ca8
9 changed files with 382 additions and 43 deletions
@@ -3558,7 +3558,8 @@
"lane": "L7",
"contract": "docs/release-control/v6/internal/subsystems/relay-runtime.md",
"owned_prefixes": [
"internal/relay/"
"internal/relay/",
"pulse-mobile:src/relay/"
],
"owned_files": [
"internal/config/persistence_relay.go"
@@ -3568,7 +3569,15 @@
"test_prefixes": [],
"exact_files": [
"internal/config/persistence_relay_test.go",
"internal/relay/client_test.go"
"internal/relay/client_test.go",
"pulse-mobile:src/relay/__tests__/channel.test.ts",
"pulse-mobile:src/relay/__tests__/client-hardening.test.ts",
"pulse-mobile:src/relay/__tests__/client.test.ts",
"pulse-mobile:src/relay/__tests__/encryption.test.ts",
"pulse-mobile:src/relay/__tests__/identity.test.ts",
"pulse-mobile:src/relay/__tests__/protocol-contract.test.ts",
"pulse-mobile:src/relay/__tests__/protocol.test.ts",
"pulse-mobile:src/relay/__tests__/proxy.test.ts"
],
"require_explicit_path_policy_coverage": true,
"path_policies": [
@@ -3597,6 +3606,26 @@
"exact_files": [
"internal/config/persistence_relay_test.go"
]
},
{
"id": "mobile-relay-runtime",
"label": "mobile relay runtime proof",
"match_prefixes": [
"pulse-mobile:src/relay/"
],
"match_files": [],
"allow_same_subsystem_tests": false,
"test_prefixes": [],
"exact_files": [
"pulse-mobile:src/relay/__tests__/channel.test.ts",
"pulse-mobile:src/relay/__tests__/client-hardening.test.ts",
"pulse-mobile:src/relay/__tests__/client.test.ts",
"pulse-mobile:src/relay/__tests__/encryption.test.ts",
"pulse-mobile:src/relay/__tests__/identity.test.ts",
"pulse-mobile:src/relay/__tests__/protocol-contract.test.ts",
"pulse-mobile:src/relay/__tests__/protocol.test.ts",
"pulse-mobile:src/relay/__tests__/proxy.test.ts"
]
}
]
}
@@ -15,15 +15,19 @@
## Purpose
Own the desktop relay runtime, its persisted client configuration, and the
canonical reconnect, encryption, and relay-trust behavior for Pulse instance
bridging.
Own the desktop and mobile relay runtimes, their persisted relay state
boundaries, and the canonical reconnect, encryption, protocol, proxy, and
relay-trust behavior for Pulse instance bridging.
## Canonical Files
1. `internal/relay/client.go`
2. `internal/relay/protocol.go`
3. `internal/config/persistence_relay.go`
4. `pulse-mobile:src/relay/client.ts`
5. `pulse-mobile:src/relay/protocol.ts`
6. `pulse-mobile:src/relay/proxy.ts`
7. `pulse-mobile:src/relay/encryption.ts`
## Shared Boundaries
@@ -34,7 +38,8 @@ bridging.
1. Add or change desktop relay reconnect, registration, drain, proxy-stream, or encrypted channel behavior through `internal/relay/`
2. Add or change relay control payload schemas, including mobile-visible push notification metadata, through `internal/relay/protocol.go`
3. Add or change persisted relay enablement, server URL, or reconnect-safe default loading through `internal/config/persistence_relay.go`
4. Keep desktop relay changes aligned with the governed mobile and server relay surfaces represented by the L7 lane evidence
4. Add or change mobile relay reconnect, drain, channel, encryption, proxy, or identity behavior through `pulse-mobile:src/relay/`
5. Keep desktop and mobile relay changes aligned with the governed server relay surfaces represented by the L7 lane evidence
## Forbidden Paths
@@ -47,12 +52,14 @@ bridging.
1. Update this contract when new desktop relay runtime or persistence entry points become canonical
2. Keep relay client changes tied to explicit runtime proof in `internal/relay/client_test.go`
3. Keep persisted relay config loading tied to explicit proof in `internal/config/persistence_relay_test.go`
4. Keep mobile relay runtime changes tied to explicit proof in `pulse-mobile:src/relay/__tests__/`
## Current State
The desktop relay client had been carrying real runtime behavior without any
explicit subsystem ownership even though L7 already treats relay readiness as a
governed release lane. This contract makes that desktop boundary explicit.
The relay lane had been carrying real desktop and mobile runtime behavior
without fully explicit subsystem ownership even though L7 already treats relay
readiness as a governed release lane. This contract makes both relay-runtime
boundaries explicit.
The canonical relay runtime now includes local CA-bundle trust via
`SSL_CERT_FILE`, so self-hosted relay deployments can use a private CA without
forking the dial path or disabling TLS verification globally.
@@ -86,3 +93,7 @@ the runtime can read legacy plaintext relay settings, it must rewrite
canonical encrypted storage immediately on load instead of leaving
`instance_secret` or the relay identity private key on disk as a normal
runtime path.
The mobile relay runtime is part of the same owned surface: reconnect drain
failover hints are one-shot recovery instructions, not permanent relay URL
overrides, so a successful failover reconnect must return future reconnects to
the instance's canonical relay URL unless the server sends a fresh drain hint.
@@ -18,41 +18,65 @@ from canonical_completion_guard import (
subsystem_matches_path,
)
WORKSPACE_REPOS_ROOT = REPO_ROOT.parent
def split_workspace_path(path: str) -> tuple[Path, str]:
if ":" not in path:
return REPO_ROOT, path
repo_id, rel = path.split(":", 1)
return WORKSPACE_REPOS_ROOT / repo_id, rel
def qualify_workspace_path(repo_root: Path, rel: str) -> str:
if repo_root == REPO_ROOT:
return rel
return f"{repo_root.name}:{rel}"
def owned_runtime_files(rule: dict) -> list[str]:
owned: set[str] = set()
search_roots: set[Path] = set()
for prefix in rule.get("owned_prefixes", []):
root = REPO_ROOT / prefix
repo_root, rel_prefix = split_workspace_path(prefix.rstrip("/"))
root = repo_root / rel_prefix
if root.exists():
search_roots.add(root if root.is_dir() else root.parent)
continue
parent = root.parent
while parent != REPO_ROOT and not parent.exists():
while parent != repo_root and not parent.exists():
parent = parent.parent
if parent.exists():
search_roots.add(parent)
for root in search_roots:
repo_root = root
while repo_root != WORKSPACE_REPOS_ROOT and repo_root.parent != WORKSPACE_REPOS_ROOT:
repo_root = repo_root.parent
if repo_root.parent != WORKSPACE_REPOS_ROOT:
repo_root = REPO_ROOT
for path in root.rglob("*"):
if not path.is_file():
continue
rel = path.relative_to(REPO_ROOT).as_posix()
if is_test_or_fixture(rel) or is_ignored_runtime_file(rel):
rel = path.relative_to(repo_root).as_posix()
candidate = qualify_workspace_path(repo_root, rel)
if is_test_or_fixture(candidate) or is_ignored_runtime_file(candidate):
continue
if subsystem_matches_path(rule, rel):
owned.add(rel)
if subsystem_matches_path(rule, candidate):
owned.add(candidate)
for rel in rule.get("owned_files", []):
path = REPO_ROOT / rel
repo_root, repo_rel = split_workspace_path(rel)
path = repo_root / repo_rel
if not path.exists() or not path.is_file():
continue
if is_test_or_fixture(rel) or is_ignored_runtime_file(rel):
candidate = qualify_workspace_path(repo_root, repo_rel)
if is_test_or_fixture(candidate) or is_ignored_runtime_file(candidate):
continue
if subsystem_matches_path(rule, rel):
owned.add(rel)
if subsystem_matches_path(rule, candidate):
owned.add(candidate)
return sorted(owned)
@@ -220,6 +244,42 @@ class CanonicalCompletionGuardTest(unittest.TestCase):
],
)
def test_mobile_relay_runtime_change_requires_relay_contract(self):
required = infer_impacted_subsystems(["pulse-mobile:src/relay/client.ts"])
self.assertEqual(set(required), {"relay-runtime"})
relay = required["relay-runtime"]
self.assertEqual(
relay["contract"],
"docs/release-control/v6/internal/subsystems/relay-runtime.md",
)
self.assertEqual(
relay["touched_runtime_files"],
["pulse-mobile:src/relay/client.ts"],
)
self.assertEqual(
relay["verification_requirements"],
[
{
"id": "mobile-relay-runtime",
"label": "mobile relay runtime proof",
"touched_runtime_files": ["pulse-mobile:src/relay/client.ts"],
"allow_same_subsystem_tests": False,
"test_prefixes": [],
"exact_files": [
"pulse-mobile:src/relay/__tests__/channel.test.ts",
"pulse-mobile:src/relay/__tests__/client-hardening.test.ts",
"pulse-mobile:src/relay/__tests__/client.test.ts",
"pulse-mobile:src/relay/__tests__/encryption.test.ts",
"pulse-mobile:src/relay/__tests__/identity.test.ts",
"pulse-mobile:src/relay/__tests__/protocol-contract.test.ts",
"pulse-mobile:src/relay/__tests__/protocol.test.ts",
"pulse-mobile:src/relay/__tests__/proxy.test.ts",
],
}
],
)
def test_windows_install_script_change_uses_shared_installer_policies(self):
required = infer_impacted_subsystems(["scripts/install.ps1"])
self.assertEqual(set(required), {"agent-lifecycle", "deployment-installability"})
+78 -9
View File
@@ -66,6 +66,7 @@ PATH_SUFFIXES = (
".yaml",
".yml",
)
WORKSPACE_REPOS_ROOT = REPO_ROOT.parent
def sorted_casefold(values: list[str]) -> list[str]:
@@ -107,17 +108,61 @@ def looks_like_repo_path(token: str) -> bool:
return "/" in candidate or candidate.endswith(PATH_SUFFIXES)
def validate_repo_path_token(token: str, *, rel: str, heading: str, errors: list[str]) -> None:
def repo_roots_for_status(status_payload: dict[str, Any]) -> dict[str, Path]:
active_repos = [
repo_id
for repo_id in status_payload.get("scope", {}).get("active_repos", [])
if isinstance(repo_id, str) and repo_id.strip()
]
repo_roots = {REPO_ROOT.name: REPO_ROOT}
for repo_id in active_repos:
if repo_id == REPO_ROOT.name:
continue
repo_roots[repo_id] = WORKSPACE_REPOS_ROOT / repo_id
return repo_roots
def resolve_repo_path_token(token: str, *, repo_roots: dict[str, Path]) -> Path | None:
raw = token.rstrip("/") if token.endswith("/") else token
if not raw:
errors.append(f"{rel} {heading} contains non-clean repo-relative path {token!r}")
return
return None
repo_id = REPO_ROOT.name
repo_rel = raw
if ":" in raw:
repo_id, repo_rel = raw.split(":", 1)
if not repo_id:
return None
candidate = Path(raw)
normalized = candidate.as_posix()
if candidate.is_absolute() or raw.startswith("../") or "/../" in raw or normalized != raw:
return None
repo_candidate = Path(repo_rel)
repo_normalized = repo_candidate.as_posix()
if (
repo_candidate.is_absolute()
or repo_rel.startswith("../")
or "/../" in repo_rel
or repo_normalized != repo_rel
):
return None
repo_root = repo_roots.get(repo_id)
if repo_root is None:
return None
return repo_root / repo_rel
def validate_repo_path_token(
token: str,
*,
rel: str,
heading: str,
errors: list[str],
repo_roots: dict[str, Path],
) -> None:
resolved = resolve_repo_path_token(token, repo_roots=repo_roots)
if resolved is None:
errors.append(f"{rel} {heading} contains non-clean repo-relative path {token!r}")
return
resolved = REPO_ROOT / raw
if not resolved.exists():
errors.append(f"{rel} {heading} references missing path {token!r}")
return
@@ -151,7 +196,12 @@ def parse_contract_metadata(body_lines: list[str]) -> tuple[dict[str, Any] | Non
return payload, errors
def audit_contract_text(rel: str, content: str) -> tuple[dict[str, Any], list[str]]:
def audit_contract_text(
rel: str,
content: str,
*,
repo_roots: dict[str, Path],
) -> tuple[dict[str, Any], list[str]]:
errors: list[str] = []
path_references: list[dict[str, str]] = []
section_items: dict[str, list[str]] = {}
@@ -200,13 +250,25 @@ def audit_contract_text(rel: str, content: str) -> tuple[dict[str, Any], list[st
errors.append(f"{rel} section {heading!r} entries must include at least one repo path")
continue
for token in path_tokens:
validate_repo_path_token(token, rel=rel, heading=heading, errors=errors)
validate_repo_path_token(
token,
rel=rel,
heading=heading,
errors=errors,
repo_roots=repo_roots,
)
path_references.append({"heading": heading, "path": token})
if heading == "## Extension Points":
for _, item in items:
for token in re.findall(r"`([^`]+)`", item):
if looks_like_repo_path(token):
validate_repo_path_token(token, rel=rel, heading=heading, errors=errors)
validate_repo_path_token(
token,
rel=rel,
heading=heading,
errors=errors,
repo_roots=repo_roots,
)
path_references.append({"heading": heading, "path": token})
return {
@@ -284,6 +346,7 @@ def audit_contract_payload(
for subsystem in registry_subsystems
if isinstance(subsystem, dict) and isinstance(subsystem.get("contract"), str)
}
repo_roots = repo_roots_for_status(status_payload)
expected_subsystem_ids = {
str(subsystem.get("id", "")).strip()
for subsystem in registry_subsystems
@@ -302,7 +365,7 @@ def audit_contract_payload(
seen_subsystem_ids: set[str] = set()
for rel in sorted(actual_contracts):
parsed, parse_errors = audit_contract_text(rel, contract_texts[rel])
parsed, parse_errors = audit_contract_text(rel, contract_texts[rel], repo_roots=repo_roots)
errors.extend(parse_errors)
metadata = parsed.get("metadata")
subsystem = expected_contracts.get(rel)
@@ -420,7 +483,13 @@ def audit_contract_payload(
)
continue
shared_path = path_tokens[0]
validate_repo_path_token(shared_path, rel=rel, heading="## Shared Boundaries", errors=errors)
validate_repo_path_token(
shared_path,
rel=rel,
heading="## Shared Boundaries",
errors=errors,
repo_roots=repo_roots,
)
actual_shared_paths.append(shared_path)
if shared_path in seen_shared_paths:
errors.append(
@@ -295,6 +295,76 @@ Canonical alert identity is live runtime truth.
"\n".join(report["errors"]),
)
def test_audit_contract_payload_accepts_cross_repo_contract_paths(self) -> None:
registry_payload = {
"subsystems": [
{
"id": "relay-runtime",
"lane": "L7",
"contract": "docs/release-control/v6/internal/subsystems/relay-runtime.md",
}
]
}
status_payload = {
"scope": {
"active_repos": ["pulse", "pulse-mobile"],
},
"lanes": [{"id": "L7"}],
}
contract_texts = {
"docs/release-control/v6/internal/subsystems/relay-runtime.md": """# Relay Runtime Contract
## Contract Metadata
```json
{
"subsystem_id": "relay-runtime",
"lane": "L7",
"contract_file": "docs/release-control/v6/internal/subsystems/relay-runtime.md",
"status_file": "docs/release-control/v6/internal/status.json",
"registry_file": "docs/release-control/v6/internal/subsystems/registry.json",
"dependency_subsystem_ids": []
}
```
## Purpose
Own relay runtime truth.
## Canonical Files
1. `pulse-mobile:src/relay/client.ts`
## Shared Boundaries
1. None.
## Extension Points
1. Add mobile relay reconnect behavior through `pulse-mobile:src/relay/`
## Forbidden Paths
1. Ad hoc mobile relay reconnect state.
## Completion Obligations
1. Keep mobile relay runtime changes tied to tests.
## Current State
Cross-repo relay ownership is explicit.
""",
}
report = audit_contract_payload(
registry_payload=registry_payload,
status_payload=status_payload,
contract_texts=contract_texts,
)
self.assertEqual(report["errors"], [])
def test_audit_contract_payload_rejects_missing_extension_point_reference(self) -> None:
registry_payload = {
"subsystems": [
+36 -14
View File
@@ -5,6 +5,7 @@ from __future__ import annotations
import argparse
import json
import os
from pathlib import Path
import re
import subprocess
@@ -61,20 +62,35 @@ def sorted_casefold(values: list[str]) -> list[str]:
def tracked_repo_files() -> set[str]:
result = subprocess.run(
["git", "ls-files", "-z"],
cwd=REPO_ROOT,
check=True,
capture_output=True,
text=False,
)
files = {
entry.decode("utf-8")
for entry in result.stdout.split(b"\x00")
if entry
}
return tracked_workspace_files(active_repos=[REPO_ROOT.name], local_repo=REPO_ROOT.name)
def tracked_workspace_files(*, active_repos: list[str], local_repo: str) -> set[str]:
files: set[str] = set()
repos_root = REPO_ROOT.parent
for repo_id in active_repos:
repo_root = REPO_ROOT if repo_id == local_repo else repos_root / repo_id
if not repo_root.exists():
continue
env = os.environ.copy()
if repo_root != REPO_ROOT:
env.pop("GIT_INDEX_FILE", None)
result = subprocess.run(
["git", "ls-files", "-z"],
cwd=repo_root,
check=True,
capture_output=True,
text=False,
env=env,
)
for entry in result.stdout.split(b"\x00"):
if not entry:
continue
rel = entry.decode("utf-8")
files.add(rel if repo_id == local_repo else f"{repo_id}:{rel}")
# Governance files are filesystem-only (gitignored). Supplement with any
# files that exist on disk under the subsystems/contracts directory so that
# files that exist on disk under the control-plane contracts directory so
# contract path references in the registry resolve correctly.
contracts_dir = Path(DEFAULT_CONTROL_PLANE["subsystems_dir_path"])
if contracts_dir.exists():
@@ -612,6 +628,12 @@ def render_pretty(report: dict[str, Any]) -> str:
def main(argv: list[str] | None = None) -> int:
args = parse_args(list(argv or []))
status_payload = load_status_payload(staged=args.staged)
scope = status_payload.get("scope", {})
active_repos = [
repo_id
for repo_id in scope.get("active_repos", [])
if isinstance(repo_id, str) and repo_id.strip()
] or [REPO_ROOT.name]
lane_ids = {
lane.get("id")
for lane in status_payload.get("lanes", [])
@@ -619,7 +641,7 @@ def main(argv: list[str] | None = None) -> int:
}
report = audit_registry_payload(
load_registry_payload(staged=args.staged),
tracked_files=tracked_repo_files(),
tracked_files=tracked_workspace_files(active_repos=active_repos, local_repo=REPO_ROOT.name),
status_lane_ids=lane_ids,
schema_contract=registry_schema_contract(staged=args.staged),
)
@@ -53,6 +53,52 @@ class RegistryAuditTest(unittest.TestCase):
self.assertEqual(report["summary"]["shared_ownership_count"], 0)
self.assertEqual(report["subsystems"][0]["default_fallback_count"], 0)
def test_audit_registry_payload_accepts_cross_repo_owned_prefixes(self) -> None:
payload = {
"version": 12,
"shared_ownerships": [],
"subsystems": [
{
"id": "relay-runtime",
"lane": "L7",
"contract": "docs/release-control/v6/internal/subsystems/relay-runtime.md",
"owned_prefixes": ["pulse-mobile:src/relay/"],
"owned_files": [],
"verification": {
"allow_same_subsystem_tests": True,
"test_prefixes": [],
"exact_files": [
"pulse-mobile:src/relay/__tests__/client.test.ts",
],
"require_explicit_path_policy_coverage": True,
"path_policies": [
{
"id": "mobile-relay-runtime",
"label": "mobile relay runtime proof",
"match_prefixes": ["pulse-mobile:src/relay/"],
"match_files": [],
"allow_same_subsystem_tests": False,
"test_prefixes": [],
"exact_files": [
"pulse-mobile:src/relay/__tests__/client.test.ts",
],
}
],
},
}
],
}
tracked_files = {
"docs/release-control/v6/internal/subsystems/relay-runtime.md",
"pulse-mobile:src/relay/__tests__/client.test.ts",
"pulse-mobile:src/relay/client.ts",
}
report = audit_registry_payload(payload, tracked_files=tracked_files, status_lane_ids={"L7"})
self.assertEqual(report["errors"], [])
self.assertEqual(report["subsystems"][0]["owned_runtime_file_count"], 1)
def test_audit_registry_payload_flags_unknown_lane_and_missing_contract(self) -> None:
payload = {
"version": 12,
+15 -1
View File
@@ -23,13 +23,27 @@ from canonical_completion_guard import (
from status_audit import audit_status_payload, load_status_payload
from registry_audit import load_registry_payload
WORKSPACE_REPOS_ROOT = REPO_ROOT.parent
def normalize_input_path(raw: str) -> str:
candidate = Path(raw.strip())
if candidate.is_absolute():
candidate = candidate.resolve()
try:
candidate = candidate.resolve().relative_to(REPO_ROOT)
candidate = candidate.relative_to(REPO_ROOT)
except ValueError:
try:
repo_relative = candidate.relative_to(WORKSPACE_REPOS_ROOT)
except ValueError:
return candidate.as_posix()
parts = repo_relative.parts
if len(parts) >= 2:
repo_id = parts[0]
rel = Path(*parts[1:]).as_posix()
if repo_id == REPO_ROOT.name:
return rel
return f"{repo_id}:{rel}"
return candidate.as_posix()
return candidate.as_posix()
@@ -62,6 +62,24 @@ class SubsystemLookupTest(unittest.TestCase):
result = lookup_paths(["README.md"])
self.assertEqual(result["unowned_runtime_files"], ["README.md"])
def test_lookup_paths_normalizes_cross_repo_absolute_runtime_paths(self) -> None:
result = lookup_paths([str(REPO_ROOT.parent / "pulse-mobile" / "src/relay/client.ts")])
self.assertEqual(result["unowned_runtime_files"], [])
self.assertEqual(
{item["subsystem"] for item in result["impacted_subsystems"]},
{"relay-runtime"},
)
file_entry = result["files"][0]
self.assertEqual(file_entry["path"], "pulse-mobile:src/relay/client.ts")
self.assertEqual(file_entry["classification"], "runtime")
self.assertEqual(
{match["subsystem"] for match in file_entry["matches"]},
{"relay-runtime"},
)
match = file_entry["matches"][0]
self.assertEqual(match["lane_context"]["lane_id"], "L7")
self.assertEqual(match["verification_requirement"]["id"], "mobile-relay-runtime")
def test_lookup_paths_assigns_shared_tag_badges_to_frontend_primitives(self) -> None:
result = lookup_paths(["frontend-modern/src/components/shared/TagBadges.tsx"])
self.assertEqual(result["unowned_runtime_files"], [])