[AAASM-4856] ✨ (python-sdk): Expose public ENFORCEMENT_MODES parity surface#280
Conversation
Introduce a public, ordered canonical enforcement-mode tuple
("enforce", "observe", "disabled") as the parity surface the cross-SDK
conformance cross-check reads. Ordered + immutable, unlike the private
unordered _VALID_ENFORCEMENT_MODES frozenset.
Refs AAASM-4856
Make ENFORCEMENT_MODES the single source of truth: build the private
membership validator via frozenset(ENFORCEMENT_MODES) so the public
ordered surface and the private validator can never drift. Set membership
is unchanged — still {enforce, observe, disabled}.
Refs AAASM-4856
Wire the public constant through the lazy-export mechanism so agent_assembly.ENFORCEMENT_MODES resolves and appears in __all__, via both agent_assembly.core and the top-level package __getattr__. Import stays lazy — no eager httpx/pydantic pull-in. This is what the e2e-public cross-SDK conformance cross-check reads (getattr(agent_assembly, "ENFORCEMENT_MODES", None)); it previously returned None. Refs AAASM-4856
Pin the AAASM-4856 contract: agent_assembly.ENFORCEMENT_MODES resolves to the exact canonical order, is discoverable via __all__, resolves lazily through core.__getattr__, and stays in sync with the private _VALID_ENFORCEMENT_MODES validator it derives. Extend the core lazy-export set assertion to cover the new public export. Refs AAASM-4856
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
|
Review — Claude CodeCI: ✅ green — full test matrix + CodeQL + SonarCloud + codecov/patch all pass. The Scope vs AAASM-4856: ✅ complete.
Side-effects: none. The membership validator is byte-equivalent (frozenset of the same 3 tokens); the Front-end: none (SDK library) → no Playwright needed. Verdict: ✅ ready to approve + merge — closes the Python leg of the cross-SDK |



Description
The Python SDK did not expose a public
ENFORCEMENT_MODESparity surface. The onlyenforcement-mode collection was a private, unordered
_VALID_ENFORCEMENT_MODES: frozenset[EnforcementMode]inagent_assembly/core/assembly.py— underscore-private,a
frozenset(unordered), and absent fromagent_assembly.__all__. The cross-SDKenforcement-mode parity conformance cross-check in e2e-public reads
getattr(agent_assembly, "ENFORCEMENT_MODES", None)and gotNone, so the Python legof cross-SDK enforcement-mode parity could not run.
This PR adds the public surface, additively and behavior-preserving:
ENFORCEMENT_MODES: tuple[EnforcementMode, ...] = ("enforce", "observe", "disabled")— a public, ordered, immutable canonical tuple in
core/assembly.py, made thesingle source of truth: the private
_VALID_ENFORCEMENT_MODESis now derivedvia
frozenset(ENFORCEMENT_MODES), so the ordered public surface and the privatevalidator can never drift.
agent_assembly.ENFORCEMENT_MODESthrough the existing lazy-exportmechanism (
_LAZY_EXPORTS/_ALWAYS_EXPORTED+ module__getattr__/__dir__onthe top-level package, and the matching
__getattr__/__all__onagent_assembly.core). It now appears inagent_assembly.__all__. Import stayslazy —
import agent_assemblystill does not eagerly pull in httpx/pydantic.No validation behavior changed:
_VALID_ENFORCEMENT_MODESstill contains exactly{"enforce", "observe", "disabled"}and theinit_assemblymembership check behavesidentically.
EnforcementModetyping is intact.Type of Change
Breaking Changes
Purely additive — a new public export plus an internal single-source-of-truth
refactor. No existing behavior changes.
Related Issues
by AAASM-4853 (previously masked behind the now-Done AAASM-3158).
Closes AAASM-4856
Testing
New regression test
test/unit/test_enforcement_modes_export.pyasserts:agent_assembly.ENFORCEMENT_MODES == ("enforce", "observe", "disabled")(exact order),"ENFORCEMENT_MODES" in agent_assembly.__all__,frozenset(agent_assembly.ENFORCEMENT_MODES) == agent_assembly.core.assembly._VALID_ENFORCEMENT_MODES(public constant and private validator stay in sync).
test/unit/core/test_core_lazy_exports.pyextended to cover the new lazycore.__getattr__branch and the extended
core.__all__set.How to verify:
.venv/bin/python -m pytest test/ -q→ 1184 passed, 16 skipped..venv/bin/ruff check/ruff format --checkclean on all changed files..venv/bin/mypy agent_assemblyadds no new errors (the pre-existingagent_assembly._coreimport-not-found notes are the un-built native shim, anenvironment limitation, not from this change).
test_enforcement_mode_paritycross-check(
getattr(agent_assembly, "ENFORCEMENT_MODES", None)) now resolves to the orderedtuple instead of
None.Checklist
Cross-SDK parity (informational — no changes here)
ENFORCEMENT_MODES(
src/types/enforcement-mode.ts, re-exported fromsrc/index.ts). Parity present.EnforcementModetype + individual constants(
EnforcementModeEnforce/Observe/Disabled) + aValid()method, but no exportedordered collection equivalent to
ENFORCEMENT_MODES. Potential follow-up gap ifthe conformance harness expects an ordered public slice — to be filed separately.
🤖 Generated with Claude Code