Parse an operational policy into a typed rule with a responsible actor, trigger, required action, deadline and exception scope.
Operational rules: actors, triggers, obligations and exceptions
Separate the rule components
“When gateway-west is degraded, on-call must page the owner within 47 minutes unless maintenance is approved” contains more than an action phrase. It names a trigger, actor, action, deadline and exception. Each component needs a source span and a typed meaning. A missing exception is not the same as an exception known to be false. Keep the original clause and revision beside the proposed frame. Predicate roles help identify who must do what.
Attach exceptions to the right rule
An exception may sit in a following sentence or a footnote. It may modify one deadline, one actor or an entire section. Do not apply an exception globally just because it occurs nearby. Link it to a specific rule ID and record the evidence supporting that link. If the scope is ambiguous, hold the policy decision for review. Discourse scope helps distinguish a local qualification from a broad rule.
Distinguish obligation from observation
“On-call pages the owner” describes what happened; “on-call must page the owner” prescribes an action. Negation and modal verbs change the policy state. Dates, units and role names may need normalization, but a model’s normalized values should never become authority without a governed rule review. The code below validates only the shape and source spans of an extracted rule; it does not decide whether a live alert is required.
Evaluate policy interpretation
Test trigger detection, actor binding, action binding, exception attachment and deadline normalization independently. Include negated triggers, double exceptions, outdated policies and references to another section. Score false required actions and false exemptions separately; both can cause operational harm. The precedence lesson handles multiple rule versions, and the project tests a conservative decision ledger.
Implementation
def validate_operational_rule(source, frame):
for component in ("trigger", "actor", "action", "exception"):
start, end = frame[component]["span"]
if not 0 <= start < end <= len(source):
return {"state": "review", "reason": "invalid-span"}
if source[start:end] != frame[component]["text"]:
return {"state": "review", "reason": "span-mismatch"}
if frame.get("deadline_minutes") != 47:
return {"state": "review", "reason": "deadline-policy"}
return {"state": "frame-valid"}
source = ("When gateway-west is degraded, on-call must page the owner "
"within 47 minutes unless maintenance is approved.")
def span_of(phrase):
start = source.index(phrase)
return {"text": phrase, "span": (start, start + len(phrase))}
frame = {"trigger": span_of("gateway-west is degraded"),
"actor": span_of("on-call"),
"action": span_of("page the owner"),
"exception": span_of("maintenance is approved"),
"deadline_minutes": 47}
assert validate_operational_rule(source, frame)["state"] == "frame-valid"
Performance and operating cost
Four fixed span checks take O(e) time and space for copied evidence substrings of total length e. A larger schema costs O(f+e) across f fields. Valid spans prove only provenance, not that the exception truly modifies this rule; that semantic link requires separate review.
Common Mistakes
- Dropping “unless” and applying the rule unconditionally.
- Treating a descriptive sentence as an obligation.
- Applying an exception to the wrong clause.
- Using a model-derived rule as live operational authority.
