{
  "about": "Conformance corpus for flowdesk-constitution-kernel v0.1 — the flagship declarative policy gate (the OPA/Cedar comparison). `cases` call enforce(rules, action, ctx) and must yield expect.{allow, rule?, requiresApproval?}; `merge` first runs mergeRules(ws, key) (per-key rules tighten, never loosen) then enforces. Covers every rule type, the check-order precedence, the hard-deny-beats-confidence-gate rule, overnight quiet-hours wraparound, and fail-open of an ABSENT policy. Deterministic (ctx.utcHour pins the clock). Run: node conformance/run-constitution.js",
  "cases": [
    { "name": "empty rules → allow", "rules": {}, "action": { "title": "Write the Q3 report", "priority": "medium" }, "expect": { "allow": true } },

    { "name": "max_priority: critical over high → deny", "rules": { "max_priority": "high" }, "action": { "title": "Page the on-call", "priority": "critical" }, "expect": { "allow": false, "rule": "max_priority" } },
    { "name": "max_priority: high at the cap → allow", "rules": { "max_priority": "high" }, "action": { "title": "Escalate", "priority": "high" }, "expect": { "allow": true } },
    { "name": "max_priority: low under medium cap → allow", "rules": { "max_priority": "medium" }, "action": { "title": "Tidy backlog", "priority": "low" }, "expect": { "allow": true } },

    { "name": "forbidden_terms: title contains a banned term → deny", "rules": { "forbidden_terms": ["delete", "drop"] }, "action": { "title": "Delete the prod database" }, "expect": { "allow": false, "rule": "forbidden_terms" } },
    { "name": "forbidden_terms: case-insensitive substring → deny", "rules": { "forbidden_terms": ["wire"] }, "action": { "title": "Send a WIRE transfer" }, "expect": { "allow": false, "rule": "forbidden_terms" } },
    { "name": "forbidden_terms: clean title → allow", "rules": { "forbidden_terms": ["delete"] }, "action": { "title": "Archive old records" }, "expect": { "allow": true } },

    { "name": "quiet_hours same-day: inside window → deny", "rules": { "quiet_hours_utc": { "start": 9, "end": 17 } }, "action": { "title": "Post update" }, "ctx": { "utcHour": 12 }, "expect": { "allow": false, "rule": "quiet_hours_utc" } },
    { "name": "quiet_hours same-day: outside window → allow", "rules": { "quiet_hours_utc": { "start": 9, "end": 17 } }, "action": { "title": "Post update" }, "ctx": { "utcHour": 20 }, "expect": { "allow": true } },
    { "name": "quiet_hours overnight: wraps past midnight → deny", "rules": { "quiet_hours_utc": { "start": 22, "end": 6 } }, "action": { "title": "Post update" }, "ctx": { "utcHour": 2 }, "expect": { "allow": false, "rule": "quiet_hours_utc" } },
    { "name": "quiet_hours overnight: midday outside → allow", "rules": { "quiet_hours_utc": { "start": 22, "end": 6 } }, "action": { "title": "Post update" }, "ctx": { "utcHour": 12 }, "expect": { "allow": true } },

    { "name": "max_creates_per_day: at the cap → deny", "rules": { "max_creates_per_day": 5 }, "action": { "title": "New task" }, "ctx": { "createsToday": 5 }, "expect": { "allow": false, "rule": "max_creates_per_day" } },
    { "name": "max_creates_per_day: under the cap → allow", "rules": { "max_creates_per_day": 5 }, "action": { "title": "New task" }, "ctx": { "createsToday": 4 }, "expect": { "allow": true } },

    { "name": "forbidden_assignees: exact match (case-insensitive) → deny", "rules": { "forbidden_assignees": ["CEO"] }, "action": { "title": "Assign review", "assignee": "ceo" }, "expect": { "allow": false, "rule": "forbidden_assignees" } },
    { "name": "forbidden_assignees: different assignee → allow", "rules": { "forbidden_assignees": ["ceo"] }, "action": { "title": "Assign review", "assignee": "alex" }, "expect": { "allow": true } },
    { "name": "forbidden_assignees: no assignee on action → allow", "rules": { "forbidden_assignees": ["ceo"] }, "action": { "title": "Unassigned task" }, "expect": { "allow": true } },

    { "name": "forbidden_tags: action carries a banned tag → deny", "rules": { "forbidden_tags": ["secret"] }, "action": { "title": "Share notes", "tags": ["public", "secret"] }, "expect": { "allow": false, "rule": "forbidden_tags" } },
    { "name": "forbidden_tags: clean tags → allow", "rules": { "forbidden_tags": ["secret"] }, "action": { "title": "Share notes", "tags": ["public"] }, "expect": { "allow": true } },

    { "name": "objective_tags: no alignment to an objective → deny", "rules": { "objective_tags": ["growth", "retention"] }, "action": { "title": "Random task", "tags": ["misc"] }, "expect": { "allow": false, "rule": "objective_tags" } },
    { "name": "objective_tags: tagged to a current objective → allow", "rules": { "objective_tags": ["growth"] }, "action": { "title": "Launch referral", "tags": ["growth", "ops"] }, "expect": { "allow": true } },
    { "name": "objective_tags: untagged action → deny (not aligned)", "rules": { "objective_tags": ["growth"] }, "action": { "title": "Untagged task" }, "expect": { "allow": false, "rule": "objective_tags" } },

    { "name": "confidence gate: below threshold → approval, not deny", "rules": { "require_approval_below_confidence": 0.7 }, "action": { "title": "Ambiguous request" }, "ctx": { "confidence": 0.5 }, "expect": { "allow": false, "requiresApproval": true } },
    { "name": "confidence gate: at/above threshold → allow", "rules": { "require_approval_below_confidence": 0.7 }, "action": { "title": "Clear request" }, "ctx": { "confidence": 0.9 }, "expect": { "allow": true } },
    { "name": "confidence gate: missing confidence → approval (unknown is not trusted)", "rules": { "require_approval_below_confidence": 0.7 }, "action": { "title": "No-confidence request" }, "ctx": {}, "expect": { "allow": false, "requiresApproval": true } },
    { "name": "confidence gate: out-of-range confidence → approval", "rules": { "require_approval_below_confidence": 0.7 }, "action": { "title": "Bogus confidence" }, "ctx": { "confidence": 1.5 }, "expect": { "allow": false, "requiresApproval": true } },

    { "name": "precedence: a hard violation beats the confidence gate", "rules": { "forbidden_terms": ["delete"], "require_approval_below_confidence": 0.9 }, "action": { "title": "delete everything" }, "ctx": { "confidence": 0.1 }, "expect": { "allow": false, "rule": "forbidden_terms", "requiresApproval": false } },
    { "name": "precedence: max_priority is checked before forbidden_terms", "rules": { "max_priority": "low", "forbidden_terms": ["report"] }, "action": { "title": "Quarterly report", "priority": "high" }, "expect": { "allow": false, "rule": "max_priority" } },

    { "name": "absent policy (null rules) imposes no constraint → allow", "rules": null, "action": { "title": "anything goes", "priority": "critical" }, "expect": { "allow": true } },

    { "name": "value-threshold: amount over cap → approval", "rules": { "require_approval_above_amount": { "currency": "USD", "amount": 10000 } }, "action": { "title": "refund billing dispute", "amount": 25000, "currency": "USD" }, "expect": { "allow": false, "requiresApproval": true } },
    { "name": "value-threshold: amount at cap → allow", "rules": { "require_approval_above_amount": { "currency": "USD", "amount": 10000 } }, "action": { "title": "small refund", "amount": 10000, "currency": "USD" }, "expect": { "allow": true } },
    { "name": "value-threshold: amount under cap → allow", "rules": { "require_approval_above_amount": { "currency": "USD", "amount": 10000 } }, "action": { "title": "small refund", "amount": 500, "currency": "USD" }, "expect": { "allow": true } },
    { "name": "value-threshold: no amount on action → allow (rule doesn't fire)", "rules": { "require_approval_above_amount": { "currency": "USD", "amount": 10000 } }, "action": { "title": "qualitative work" }, "expect": { "allow": true } },
    { "name": "value-threshold: currency mismatch fails closed → approval", "rules": { "require_approval_above_amount": { "currency": "USD", "amount": 10000 } }, "action": { "title": "EU refund", "amount": 50, "currency": "EUR" }, "expect": { "allow": false, "requiresApproval": true } },
    { "name": "value-threshold: case-insensitive currency match → allow under cap", "rules": { "require_approval_above_amount": { "currency": "usd", "amount": 100 } }, "action": { "title": "small one", "amount": 5, "currency": "USD" }, "expect": { "allow": true } },
    { "name": "value-threshold: hard violation (forbidden_terms) STILL beats the value gate", "rules": { "forbidden_terms": ["wire"], "require_approval_above_amount": { "currency": "USD", "amount": 1 } }, "action": { "title": "wire $50", "amount": 50, "currency": "USD" }, "expect": { "allow": false, "rule": "forbidden_terms", "requiresApproval": false } },

    { "name": "approval_routes_to: value-gate approval surfaces the route (team)", "rules": { "require_approval_above_amount": { "currency": "USD", "amount": 1000 }, "approval_routes_to": { "to": "team", "team_slug": "finance" } }, "action": { "title": "refund", "amount": 5000, "currency": "USD" }, "expect": { "allow": false, "requiresApproval": true } },
    { "name": "approval_routes_to: confidence-gate approval surfaces the route (manager)", "rules": { "require_approval_below_confidence": 0.8, "approval_routes_to": { "to": "manager" } }, "action": { "title": "ambiguous" }, "ctx": { "confidence": 0.3 }, "expect": { "allow": false, "requiresApproval": true } },
    { "name": "approval_routes_to: an ALLOWED action does NOT carry the route (no approval fired)", "rules": { "require_approval_below_confidence": 0.5, "approval_routes_to": { "to": "manager" } }, "action": { "title": "ok" }, "ctx": { "confidence": 0.9 }, "expect": { "allow": true } }
  ],
  "merge": [
    { "name": "per-key forbidden_terms UNION (key term enforced)", "ws": { "forbidden_terms": ["alpha"] }, "key": { "forbidden_terms": ["beta"] }, "action": { "title": "beta launch plan" }, "expect": { "allow": false, "rule": "forbidden_terms" } },
    { "name": "per-key forbidden_terms UNION (ws term still enforced)", "ws": { "forbidden_terms": ["alpha"] }, "key": { "forbidden_terms": ["beta"] }, "action": { "title": "alpha rollout" }, "expect": { "allow": false, "rule": "forbidden_terms" } },
    { "name": "per-key tightens max_priority (high → low)", "ws": { "max_priority": "high" }, "key": { "max_priority": "low" }, "action": { "title": "Bump", "priority": "medium" }, "expect": { "allow": false, "rule": "max_priority" } },
    { "name": "per-key tightens the daily cap (min wins)", "ws": { "max_creates_per_day": 100 }, "key": { "max_creates_per_day": 3 }, "action": { "title": "New task" }, "ctx": { "createsToday": 3 }, "expect": { "allow": false, "rule": "max_creates_per_day" } },
    { "name": "empty per-key rules are a no-op (ws unchanged)", "ws": { "max_priority": "high" }, "key": {}, "action": { "title": "Escalate", "priority": "high" }, "expect": { "allow": true } },
    { "name": "per-key raises the confidence gate (max threshold)", "ws": { "require_approval_below_confidence": 0.5 }, "key": { "require_approval_below_confidence": 0.9 }, "action": { "title": "Borderline" }, "ctx": { "confidence": 0.7 }, "expect": { "allow": false, "requiresApproval": true } }
  ]
}
