Pulse/scripts/release_control/contract_audit_test.py
2026-04-09 09:35:28 +01:00

1064 lines
27 KiB
Python

import unittest
from contract_audit import audit_contract_payload, parse_args
class ContractAuditTest(unittest.TestCase):
def test_parse_args_accepts_staged_flag(self) -> None:
args = parse_args(["--check", "--staged"])
self.assertTrue(args.check)
self.assertTrue(args.staged)
def test_audit_contract_payload_accepts_valid_contracts(self) -> None:
registry_payload = {
"subsystems": [
{
"id": "alerts",
"lane": "L6",
"contract": "docs/release-control/v6/internal/subsystems/alerts.md",
}
]
}
status_payload = {
"lanes": [
{"id": "L6"},
]
}
contract_texts = {
"docs/release-control/v6/internal/subsystems/alerts.md": """# Alerts Contract
## Contract Metadata
```json
{
"subsystem_id": "alerts",
"lane": "L6",
"contract_file": "docs/release-control/v6/internal/subsystems/alerts.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 alert truth.
## Canonical Files
1. `internal/alerts/specs/types.go`
2. `go.mod`
3. `go.sum`
## Shared Boundaries
1. None.
## Extension Points
1. Add new alert rule kinds in `internal/alerts/specs/`
## Forbidden Paths
1. New ad hoc evaluator logic
## Completion Obligations
1. Update contract and tests together
## Current State
Canonical alert identity is live runtime truth.
""",
}
report = audit_contract_payload(
registry_payload=registry_payload,
status_payload=status_payload,
contract_texts=contract_texts,
)
self.assertEqual(report["errors"], [])
self.assertEqual(report["summary"]["contract_count"], 1)
self.assertEqual(report["contracts"][0]["subsystem_id"], "alerts")
def test_audit_contract_payload_rejects_metadata_mismatch(self) -> None:
registry_payload = {
"subsystems": [
{
"id": "alerts",
"lane": "L6",
"contract": "docs/release-control/v6/internal/subsystems/alerts.md",
}
]
}
status_payload = {
"lanes": [
{"id": "L6"},
]
}
contract_texts = {
"docs/release-control/v6/internal/subsystems/alerts.md": """# Alerts Contract
## Contract Metadata
```json
{
"subsystem_id": "monitoring",
"lane": "L3",
"contract_file": "docs/release-control/v6/internal/subsystems/monitoring.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 alert truth.
## Canonical Files
1. `internal/alerts/specs/types.go`
## Shared Boundaries
1. None.
## Extension Points
1. Add new alert rule kinds in `internal/alerts/specs/`
## Forbidden Paths
1. New ad hoc evaluator logic
## Completion Obligations
1. Update contract and tests together
## Current State
Canonical alert identity is live runtime truth.
""",
}
report = audit_contract_payload(
registry_payload=registry_payload,
status_payload=status_payload,
contract_texts=contract_texts,
)
joined = "\n".join(report["errors"])
self.assertIn("contract metadata subsystem_id = 'monitoring', want 'alerts'", joined)
self.assertIn("contract metadata lane = 'L3', want 'L6'", joined)
self.assertIn(
"contract metadata contract_file = 'docs/release-control/v6/internal/subsystems/monitoring.md', want 'docs/release-control/v6/internal/subsystems/alerts.md'",
joined,
)
def test_audit_contract_payload_rejects_empty_required_list_section(self) -> None:
registry_payload = {
"subsystems": [
{
"id": "alerts",
"lane": "L6",
"contract": "docs/release-control/v6/internal/subsystems/alerts.md",
}
]
}
status_payload = {
"lanes": [
{"id": "L6"},
]
}
contract_texts = {
"docs/release-control/v6/internal/subsystems/alerts.md": """# Alerts Contract
## Contract Metadata
```json
{
"subsystem_id": "alerts",
"lane": "L6",
"contract_file": "docs/release-control/v6/internal/subsystems/alerts.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 alert truth.
## Canonical Files
No list here.
## Shared Boundaries
1. None.
## Extension Points
1. Add new alert rule kinds in `internal/alerts/specs/`
## Forbidden Paths
1. New ad hoc evaluator logic
## Completion Obligations
1. Update contract and tests together
## Current State
Canonical alert identity is live runtime truth.
""",
}
report = audit_contract_payload(
registry_payload=registry_payload,
status_payload=status_payload,
contract_texts=contract_texts,
)
self.assertIn(
"docs/release-control/v6/internal/subsystems/alerts.md section '## Canonical Files' must contain a numbered list",
"\n".join(report["errors"]),
)
def test_audit_contract_payload_rejects_missing_canonical_file_reference(self) -> None:
registry_payload = {
"subsystems": [
{
"id": "alerts",
"lane": "L6",
"contract": "docs/release-control/v6/internal/subsystems/alerts.md",
}
]
}
status_payload = {"lanes": [{"id": "L6"}]}
contract_texts = {
"docs/release-control/v6/internal/subsystems/alerts.md": """# Alerts Contract
## Contract Metadata
```json
{
"subsystem_id": "alerts",
"lane": "L6",
"contract_file": "docs/release-control/v6/internal/subsystems/alerts.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 alert truth.
## Canonical Files
1. `internal/alerts/specs/missing.go`
## Shared Boundaries
1. None.
## Extension Points
1. Add new alert rule kinds in `internal/alerts/specs/`
## Forbidden Paths
1. New ad hoc evaluator logic
## Completion Obligations
1. Update contract and tests together
## Current State
Canonical alert identity is live runtime truth.
""",
}
report = audit_contract_payload(
registry_payload=registry_payload,
status_payload=status_payload,
contract_texts=contract_texts,
)
self.assertIn(
"docs/release-control/v6/internal/subsystems/alerts.md ## Canonical Files references missing path 'internal/alerts/specs/missing.go'",
"\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": [
{
"id": "alerts",
"lane": "L6",
"contract": "docs/release-control/v6/internal/subsystems/alerts.md",
}
]
}
status_payload = {"lanes": [{"id": "L6"}]}
contract_texts = {
"docs/release-control/v6/internal/subsystems/alerts.md": """# Alerts Contract
## Contract Metadata
```json
{
"subsystem_id": "alerts",
"lane": "L6",
"contract_file": "docs/release-control/v6/internal/subsystems/alerts.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 alert truth.
## Canonical Files
1. `internal/alerts/specs/types.go`
## Shared Boundaries
1. None.
## Extension Points
1. Add new alert rule kinds in `internal/alerts/specs/missing/`
## Forbidden Paths
1. New ad hoc evaluator logic
## Completion Obligations
1. Update contract and tests together
## Current State
Canonical alert identity is live runtime truth.
""",
}
report = audit_contract_payload(
registry_payload=registry_payload,
status_payload=status_payload,
contract_texts=contract_texts,
)
self.assertIn(
"docs/release-control/v6/internal/subsystems/alerts.md ## Extension Points references missing path 'internal/alerts/specs/missing/'",
"\n".join(report["errors"]),
)
def test_audit_contract_payload_requires_declared_cross_subsystem_dependencies(self) -> None:
registry_payload = {
"shared_ownerships": [],
"subsystems": [
{
"id": "monitoring",
"lane": "L6",
"contract": "docs/release-control/v6/internal/subsystems/monitoring.md",
"owned_prefixes": ["internal/monitoring/"],
"owned_files": [],
},
{
"id": "unified-resources",
"lane": "L6",
"contract": "docs/release-control/v6/internal/subsystems/unified-resources.md",
"owned_prefixes": ["internal/unifiedresources/"],
"owned_files": [],
},
]
}
status_payload = {"lanes": [{"id": "L6"}]}
contract_texts = {
"docs/release-control/v6/internal/subsystems/monitoring.md": """# Monitoring Contract
## Contract Metadata
```json
{
"subsystem_id": "monitoring",
"lane": "L6",
"contract_file": "docs/release-control/v6/internal/subsystems/monitoring.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 monitoring truth.
## Canonical Files
1. `internal/monitoring/monitor.go`
2. `internal/unifiedresources/views.go`
## Shared Boundaries
1. None.
## Extension Points
1. Add typed read access through `internal/unifiedresources/views.go`
## Forbidden Paths
1. New ad hoc snapshot truth
## Completion Obligations
1. Update contract and tests together
## Current State
Canonical monitoring still depends on unified read-state truth.
""",
"docs/release-control/v6/internal/subsystems/unified-resources.md": """# Unified Resources Contract
## Contract Metadata
```json
{
"subsystem_id": "unified-resources",
"lane": "L6",
"contract_file": "docs/release-control/v6/internal/subsystems/unified-resources.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 unified resource truth.
## Canonical Files
1. `internal/unifiedresources/views.go`
## Shared Boundaries
1. None.
## Extension Points
1. Add view adapters through `internal/unifiedresources/`
## Forbidden Paths
1. New parallel runtime registries
## Completion Obligations
1. Update contract and tests together
## Current State
Canonical read state owns the live view layer.
""",
}
report = audit_contract_payload(
registry_payload=registry_payload,
status_payload=status_payload,
contract_texts=contract_texts,
)
self.assertIn(
"docs/release-control/v6/internal/subsystems/monitoring.md contract metadata dependency_subsystem_ids = [], want ['unified-resources']",
"\n".join(report["errors"]),
)
def test_audit_contract_payload_rejects_stale_declared_dependencies(self) -> None:
registry_payload = {
"shared_ownerships": [],
"subsystems": [
{
"id": "alerts",
"lane": "L6",
"contract": "docs/release-control/v6/internal/subsystems/alerts.md",
"owned_prefixes": ["internal/alerts/"],
"owned_files": [],
},
{
"id": "monitoring",
"lane": "L6",
"contract": "docs/release-control/v6/internal/subsystems/monitoring.md",
"owned_prefixes": ["internal/monitoring/"],
"owned_files": [],
},
]
}
status_payload = {"lanes": [{"id": "L6"}]}
contract_texts = {
"docs/release-control/v6/internal/subsystems/alerts.md": """# Alerts Contract
## Contract Metadata
```json
{
"subsystem_id": "alerts",
"lane": "L6",
"contract_file": "docs/release-control/v6/internal/subsystems/alerts.md",
"status_file": "docs/release-control/v6/internal/status.json",
"registry_file": "docs/release-control/v6/internal/subsystems/registry.json",
"dependency_subsystem_ids": ["monitoring"]
}
```
## Purpose
Own alert truth.
## Canonical Files
1. `internal/alerts/specs/types.go`
## Shared Boundaries
1. None.
## Extension Points
1. Add new alert rule kinds in `internal/alerts/specs/`
## Forbidden Paths
1. New ad hoc evaluator logic
## Completion Obligations
1. Update contract and tests together
## Current State
Canonical alert identity is live runtime truth.
""",
"docs/release-control/v6/internal/subsystems/monitoring.md": """# Monitoring Contract
## Contract Metadata
```json
{
"subsystem_id": "monitoring",
"lane": "L6",
"contract_file": "docs/release-control/v6/internal/subsystems/monitoring.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 monitoring truth.
## Canonical Files
1. `internal/monitoring/monitor.go`
## Shared Boundaries
1. None.
## Extension Points
1. Add pollers in `internal/monitoring/`
## Forbidden Paths
1. New snapshot-only paths
## Completion Obligations
1. Update contract and tests together
## Current State
Canonical monitoring truth is still being consolidated.
""",
}
report = audit_contract_payload(
registry_payload=registry_payload,
status_payload=status_payload,
contract_texts=contract_texts,
)
self.assertIn(
"docs/release-control/v6/internal/subsystems/alerts.md contract metadata dependency_subsystem_ids = ['monitoring'], want []",
"\n".join(report["errors"]),
)
def test_audit_contract_payload_requires_shared_boundary_entries_from_registry(self) -> None:
registry_payload = {
"shared_ownerships": [
{
"path": "internal/api/resources.go",
"rationale": "shared api resource boundary",
"subsystems": ["api-contracts", "unified-resources"],
}
],
"subsystems": [
{
"id": "api-contracts",
"lane": "L6",
"contract": "docs/release-control/v6/internal/subsystems/api-contracts.md",
"owned_prefixes": ["internal/api/"],
"owned_files": [],
},
{
"id": "unified-resources",
"lane": "L6",
"contract": "docs/release-control/v6/internal/subsystems/unified-resources.md",
"owned_prefixes": ["internal/unifiedresources/"],
"owned_files": ["internal/api/resources.go"],
},
],
}
status_payload = {"lanes": [{"id": "L6"}]}
contract_texts = {
"docs/release-control/v6/internal/subsystems/api-contracts.md": """# API Contracts
## Contract Metadata
```json
{
"subsystem_id": "api-contracts",
"lane": "L6",
"contract_file": "docs/release-control/v6/internal/subsystems/api-contracts.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 API truth.
## Canonical Files
1. `internal/api/resources.go`
## Shared Boundaries
1. None.
## Extension Points
1. Add resource payload fields in `internal/api/resources.go`
## Forbidden Paths
1. New handler-local payload drift
## Completion Obligations
1. Update contract and tests together
## Current State
Canonical API resource payloads are live.
""",
"docs/release-control/v6/internal/subsystems/unified-resources.md": """# Unified Resources Contract
## Contract Metadata
```json
{
"subsystem_id": "unified-resources",
"lane": "L6",
"contract_file": "docs/release-control/v6/internal/subsystems/unified-resources.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 unified resource truth.
## Canonical Files
1. `internal/unifiedresources/views.go`
## Shared Boundaries
1. `internal/api/resources.go` shared with `api-contracts`: shared api resource boundary.
## Extension Points
1. Add resource adapters in `internal/unifiedresources/`
## Forbidden Paths
1. New parallel runtime registries
## Completion Obligations
1. Update contract and tests together
## Current State
Canonical read state owns the live view layer.
""",
}
report = audit_contract_payload(
registry_payload=registry_payload,
status_payload=status_payload,
contract_texts=contract_texts,
)
self.assertIn(
"docs/release-control/v6/internal/subsystems/api-contracts.md section '## Shared Boundaries' paths = [], want ['internal/api/resources.go']",
"\n".join(report["errors"]),
)
def test_audit_contract_payload_rejects_shared_boundary_without_partner_marker(self) -> None:
registry_payload = {
"shared_ownerships": [
{
"path": "internal/api/resources.go",
"rationale": "shared api resource boundary",
"subsystems": ["api-contracts", "unified-resources"],
}
],
"subsystems": [
{
"id": "api-contracts",
"lane": "L6",
"contract": "docs/release-control/v6/internal/subsystems/api-contracts.md",
"owned_prefixes": ["internal/api/"],
"owned_files": [],
},
{
"id": "unified-resources",
"lane": "L6",
"contract": "docs/release-control/v6/internal/subsystems/unified-resources.md",
"owned_prefixes": ["internal/unifiedresources/"],
"owned_files": ["internal/api/resources.go"],
},
],
}
status_payload = {"lanes": [{"id": "L6"}]}
contract_texts = {
"docs/release-control/v6/internal/subsystems/api-contracts.md": """# API Contracts
## Contract Metadata
```json
{
"subsystem_id": "api-contracts",
"lane": "L6",
"contract_file": "docs/release-control/v6/internal/subsystems/api-contracts.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 API truth.
## Canonical Files
1. `internal/api/resources.go`
## Shared Boundaries
1. `internal/api/resources.go` shared with unified-resources: shared api resource boundary.
## Extension Points
1. Add resource payload fields in `internal/api/resources.go`
## Forbidden Paths
1. New handler-local payload drift
## Completion Obligations
1. Update contract and tests together
## Current State
Canonical API resource payloads are live.
""",
"docs/release-control/v6/internal/subsystems/unified-resources.md": """# Unified Resources Contract
## Contract Metadata
```json
{
"subsystem_id": "unified-resources",
"lane": "L6",
"contract_file": "docs/release-control/v6/internal/subsystems/unified-resources.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 unified resource truth.
## Canonical Files
1. `internal/unifiedresources/views.go`
## Shared Boundaries
1. `internal/api/resources.go` shared with `api-contracts`: shared api resource boundary.
## Extension Points
1. Add resource adapters in `internal/unifiedresources/`
## Forbidden Paths
1. New parallel runtime registries
## Completion Obligations
1. Update contract and tests together
## Current State
Canonical read state owns the live view layer.
""",
}
report = audit_contract_payload(
registry_payload=registry_payload,
status_payload=status_payload,
contract_texts=contract_texts,
)
self.assertIn(
"docs/release-control/v6/internal/subsystems/api-contracts.md shared boundary 'internal/api/resources.go' must mention partner subsystem 'unified-resources' in backticks",
"\n".join(report["errors"]),
)
def test_audit_contract_payload_rejects_noncanonical_shared_boundary_text(self) -> None:
registry_payload = {
"shared_ownerships": [
{
"path": "internal/api/resources.go",
"rationale": "shared api resource boundary",
"subsystems": ["api-contracts", "unified-resources"],
}
],
"subsystems": [
{
"id": "api-contracts",
"lane": "L6",
"contract": "docs/release-control/v6/internal/subsystems/api-contracts.md",
"owned_prefixes": ["internal/api/"],
"owned_files": [],
},
{
"id": "unified-resources",
"lane": "L6",
"contract": "docs/release-control/v6/internal/subsystems/unified-resources.md",
"owned_prefixes": ["internal/unifiedresources/"],
"owned_files": ["internal/api/resources.go"],
},
],
}
status_payload = {"lanes": [{"id": "L6"}]}
contract_texts = {
"docs/release-control/v6/internal/subsystems/api-contracts.md": """# API Contracts
## Contract Metadata
```json
{
"subsystem_id": "api-contracts",
"lane": "L6",
"contract_file": "docs/release-control/v6/internal/subsystems/api-contracts.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 API truth.
## Canonical Files
1. `internal/api/resources.go`
## Shared Boundaries
1. `internal/api/resources.go` shared with `unified-resources`: shared API resource boundary.
## Extension Points
1. Add resource payload fields in `internal/api/resources.go`
## Forbidden Paths
1. New handler-local payload drift
## Completion Obligations
1. Update contract and tests together
## Current State
Canonical API resource payloads are live.
""",
"docs/release-control/v6/internal/subsystems/unified-resources.md": """# Unified Resources Contract
## Contract Metadata
```json
{
"subsystem_id": "unified-resources",
"lane": "L6",
"contract_file": "docs/release-control/v6/internal/subsystems/unified-resources.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 unified resource truth.
## Canonical Files
1. `internal/unifiedresources/views.go`
## Shared Boundaries
1. `internal/api/resources.go` shared with `api-contracts`: shared api resource boundary.
## Extension Points
1. Add resource adapters in `internal/unifiedresources/`
## Forbidden Paths
1. New parallel runtime registries
## Completion Obligations
1. Update contract and tests together
## Current State
Canonical read state owns the live view layer.
""",
}
report = audit_contract_payload(
registry_payload=registry_payload,
status_payload=status_payload,
contract_texts=contract_texts,
)
self.assertIn(
"docs/release-control/v6/internal/subsystems/api-contracts.md section '## Shared Boundaries' items = ['`internal/api/resources.go` shared with `unified-resources`: shared API resource boundary.'], want ['`internal/api/resources.go` shared with `unified-resources`: shared api resource boundary.']",
"\n".join(report["errors"]),
)
if __name__ == "__main__":
unittest.main()