Harden MGTP determinism and enforce boundary isolation#6
Harden MGTP determinism and enforce boundary isolation#6Copilot wants to merge 3 commits intofeat/mgtp-scaffold-v0.1from
Conversation
Co-authored-by: LalaSkye <228581229+LalaSkye@users.noreply.github.com>
Co-authored-by: LalaSkye <228581229+LalaSkye@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR adds deterministic decision canonicalisation/hashing and a deterministic MGTP evaluation entrypoint while introducing tests to enforce cross-version stability and boundary isolation.
Changes:
- Add
DecisionRecordwith deterministiccanonical_bytes()/canonical_hash()and extendAuthorityContextwith optionalprovided_evidence. - Introduce
mgtp.evaluate.evaluate()to deterministically mapauthority_basistoEvidenceand produce aDecisionRecord. - Add a new determinism/boundary-focused test suite for MGTP, plus a root
.gitignore.
Reviewed changes
Copilot reviewed 3 out of 4 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
mgtp/types.py |
Adds canonical, deterministic serialization/hashing on DecisionRecord; extends AuthorityContext with MGTP-local evidence. |
mgtp/evaluate.py |
Implements deterministic evaluation logic and explicit authority mapping via Evidence[...]. |
tests/test_mgtp_determinism.py |
Adds determinism, cross-version stability, and boundary isolation tests for MGTP. |
.gitignore |
Ignores common Python build/test artefacts. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| def test_canonical_bytes_no_whitespace(): | ||
| """T1d: canonical_bytes uses compact separators (no extra whitespace).""" | ||
| raw = SAMPLE_RECORD.canonical_bytes().decode("utf-8") | ||
| assert " " not in raw, "Unexpected whitespace in canonical bytes" |
There was a problem hiding this comment.
The assertion " " not in raw is overly strict: canonical JSON can legitimately contain spaces inside string values (e.g., actor_id="Alice Smith"). This test should instead assert that JSON separators are compact (e.g., no occurrences of ": " or ", "), or use a regex that checks for whitespace outside quoted strings.
| assert " " not in raw, "Unexpected whitespace in canonical bytes" | |
| assert '": ' not in raw, "Unexpected space after ':' separator in canonical bytes" | |
| assert '", ' not in raw, "Unexpected space after ',' separator in canonical bytes" |
| f"mgtp import introduced commit_gate modules: {new_commit_gate}" | ||
| ) | ||
| finally: | ||
| # Restore mgtp modules so other tests are unaffected |
There was a problem hiding this comment.
The cleanup in the finally block restores any previously-cached mgtp* modules, but it does not remove the newly imported mgtp / mgtp.* entries that were added during the test run. This can leak imported modules/state into subsequent tests. Consider popping current mgtp keys again before restoring saved_mgtp (or use a helper/context manager that fully restores sys.modules for the prefix).
| # Restore mgtp modules so other tests are unaffected | |
| # Remove any mgtp modules imported during this test and restore previous ones | |
| current_mgtp_keys = [k for k in sys.modules if k == "mgtp" or k.startswith("mgtp.")] | |
| for k in current_mgtp_keys: | |
| sys.modules.pop(k, None) |
| def test_mgtp_import_does_not_modify_authority_gate(): | ||
| """T4a: Importing mgtp does not alter AuthorityGate behaviour.""" | ||
| gate = AuthorityGate(Evidence.OWNER) | ||
| assert gate.check(Evidence.ADMIN) is Decision.ALLOW | ||
| assert gate.check(Evidence.USER) is Decision.DENY | ||
| assert gate.required_level is Evidence.OWNER |
There was a problem hiding this comment.
This test’s docstring says it verifies behavior “after importing mgtp”, but the test never imports mgtp (it imports mgtp.evaluate at module import time). Either import mgtp explicitly in the test (or rename the docstring) so the claim matches what’s actually being exercised.
Introduces deterministic canonicalisation, cross-version stability, and boundary isolation for the MGTP layer — all changes confined to
mgtp/**andtests/**. No upstream files (authority_gate.py,stop_machine.py,commit_gate/**) are touched.mgtp/types.pyDecisionRecordfrozen dataclass with explicitcanonical_bytes()/canonical_hash()methods: sorted keys, compact separators, UTF-8, no__repr__, no setsprovided_evidence: Optional[Evidence] = NonetoAuthorityContextfor MGTP-local authority mapping (defaultsNone)mgtp/evaluate.py(new)evaluate(request, context) -> DecisionRecordthat mapsauthority_basisstring →Evidenceenum viaEvidence[name](explicit, no implicit ordering)ValueErrorwhenprovided_evidence is Noneorauthority_basisis unrecognisedtests/test_mgtp_determinism.py(new, 18 tests)canonical_bytes()stable ×20, sorted keys, no whitespace, UTF-8NoneAuthorityGatebehaviour unchanged post-import;commit_gatenot introduced intosys.modulesby mgtp💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.