feat(moments): rules mount on moments, through every rule door (milestone 458 step 3, #4921)
CI & Build / Python lint (push) Successful in 3s
CI & Build / Plugin hooks (push) Successful in 12s
CI & Build / TypeScript typecheck (push) Successful in 54s
CI & Build / integration (push) Successful in 1m0s
CI & Build / Python tests (push) Successful in 1m51s
CI & Build / Build & push image (push) Successful in 29s
CI & Build / Python lint (push) Successful in 3s
CI & Build / Plugin hooks (push) Successful in 12s
CI & Build / TypeScript typecheck (push) Successful in 54s
CI & Build / integration (push) Successful in 1m0s
CI & Build / Python tests (push) Successful in 1m51s
CI & Build / Build & push image (push) Successful in 29s
rule_moments (migration 0117) records which moments a rule arrives at, by catalog name, cascading with the rule. rule_detail, the one seam every rule door already returns through, gains moments beside system_ids: None leaves the mounts alone, a list replaces them. get_rule and both list_rules doors read them back, batched per page. All five MCP rule/preference writes and the three REST ones take moments and validate them before their create or update. An unknown name is refused with the catalog listed and leaves no half-made rule behind; a parity test pins that ordering on every door. Backup v22 carries the mounts as a join table remapped through the rule map; a real-Postgres round trip checks they land on the restored rule. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -142,6 +142,20 @@ def require_moment(name: str) -> str:
|
||||
)
|
||||
|
||||
|
||||
def require_moments(names: list[str] | None) -> list[str] | None:
|
||||
"""A rule's moments, normalised and de-duplicated — or the first refusal.
|
||||
|
||||
None passes through as None, which every rule door reads as "leave the
|
||||
mounts alone"; a list, [] included, is the whole set after the write.
|
||||
All are checked before any is stored, so a refusal leaves nothing
|
||||
half-mounted.
|
||||
"""
|
||||
if names is None:
|
||||
return None
|
||||
if isinstance(names, str):
|
||||
names = [names]
|
||||
return list(dict.fromkeys(require_moment(n) for n in names))
|
||||
|
||||
def catalog() -> dict:
|
||||
"""The catalog as plain data, for the MCP tool and the REST door alike."""
|
||||
return {
|
||||
|
||||
Reference in New Issue
Block a user