GuestOps/tests/test_gate_b_acceptance.py
wolf-demon a3ef408de6
Some checks failed
Build and verify web migration / verify (push) Has been cancelled
Prepare 0.2.0 Gate B pilot candidate
2026-09-29 21:17:40 +01:00

86 lines
3.7 KiB
Python

import importlib.util
from pathlib import Path
import unittest
ROOT = Path(__file__).resolve().parents[1]
def module(name):
spec = importlib.util.spec_from_file_location(name, ROOT / "deploy" / f"{name}.py")
result = importlib.util.module_from_spec(spec)
spec.loader.exec_module(result)
return result
automation = module("automation_acceptance")
privacy = module("identity_privacy_acceptance")
def base(system):
return {
"schemaVersion": 1, "system": system, "targetGate": "B",
"releaseCommit": "a" * 40, "releaseRecordSha256": "b" * 64,
"environment": "https://sandbox-guestops.futuresens.co.uk",
"operator": "Acceptance operator", "reviewedBy": "Independent reviewer",
"startedAt": "2026-10-01T09:00:00Z", "endedAt": "2026-10-01T10:00:00Z", "reviewedAt": "2026-10-01T11:00:00Z",
}
def automation_record():
record = base("guestops-automation-acceptance")
record.update({
"dataClassification": "synthetic-only",
"faqEvaluation": {"positiveCases": 20, "negativeCases": 20, "falsePositives": 0, "falseNegatives": 0, "reportSha256": "c" * 64},
"aiEvaluation": {"casesReviewed": 20, "unsafeDraftsApproved": 0, "reportSha256": "d" * 64},
"staffTrained": 3, "monitoringOwner": "Monitoring owner", "rollbackOwner": "Rollback owner",
"scenarios": [{"id": item, "status": "pass", "evidence": ["restricted-" + item]} for item in sorted(automation.SCENARIOS)],
"postAcceptanceState": {"faqMode": "off", "pmsWrites": "disabled", "paymentCreation": "disabled"},
})
return record
def privacy_record():
record = base("guestops-identity-privacy")
record.update({
"retention": {"conversationDays": 365, "auditDays": 730, "backupDays": 30, "accountDays": 730,
"privacyOwner": "Privacy owner", "deletionOwner": "Deletion owner", "legalHoldOwner": "Legal hold owner",
"deletionProcedure": "restricted-deletion", "legalHoldProcedure": "restricted-legal-hold"},
"providers": {"google": {"status": "accepted", "evidence": ["restricted-google"]},
"openai": {"status": "disabled", "evidence": ["restricted-openai-decision"]}},
"preferencesReviewed": sorted(privacy.PREFERENCES),
"scenarios": [{"id": item, "status": "pass", "evidence": ["restricted-" + item]} for item in sorted(privacy.SCENARIOS)],
})
return record
class GateBAcceptanceTests(unittest.TestCase):
def test_complete_records_pass(self):
automation.validate(automation_record())
privacy.validate(privacy_record())
def test_automation_requires_zero_faq_errors_and_training(self):
record = automation_record();record["faqEvaluation"]["falsePositives"] = 1
with self.assertRaisesRegex(ValueError, "zero false positives"):
automation.validate(record)
record = automation_record();record["staffTrained"] = 0
with self.assertRaisesRegex(ValueError, "staff member"):
automation.validate(record)
def test_privacy_requires_retention_and_google_decisions(self):
record = privacy_record();record["retention"]["conversationDays"] = 0
with self.assertRaisesRegex(ValueError, "conversationDays"):
privacy.validate(record)
record = privacy_record();record["providers"]["google"]["status"] = "pending"
with self.assertRaisesRegex(ValueError, "Google processing"):
privacy.validate(record)
def test_privacy_requires_exact_preference_coverage(self):
record = privacy_record();record["preferencesReviewed"].pop()
with self.assertRaisesRegex(ValueError, "exact owner-controlled"):
privacy.validate(record)
if __name__ == "__main__":
unittest.main()