# 28 — Conditions and policy DSL ## Goal Conditional inputs, guardrails, workflow steps, checks and incompatibilities use a declarative data structure. Implementations must never execute condition text through JavaScript, a shell, template helpers or another general-purpose expression evaluator. ## Condition forms A condition is exactly one of: ```yaml fact: path: inputs.migrationRequired operator: eq value: true ``` ```yaml all: - fact: { path: repository.stack.languages, operator: contains, value: TypeScript } - fact: { path: repository.capabilities, operator: contains, value: build-command } ``` ```yaml any: - fact: { path: composition.workMode, operator: eq, value: execute } - fact: { path: composition.workMode, operator: eq, value: recovery } ``` ```yaml not: fact: { path: inputs.preserveCompatibility, operator: truthy } ``` ## Allowed roots - `inputs` — normalized declared playbook inputs; - `repository` — allowlisted normalized Repository Profile facts; - `composition` — work mode, autonomy, output format and resolved scope facts; - `platform` — safe platform capabilities and non-secret policy facts. No path may reference environment variables, integration secrets, raw repository files, database queries or arbitrary object prototypes. ## Operators - `exists` - `truthy` - `falsy` - `eq` - `neq` - `in` - `not-in` - `contains` - `gt` - `gte` - `lt` - `lte` Operator compatibility is type-checked. Numeric comparison does not coerce strings. `contains` supports arrays and strings. `in` tests whether the fact value is present in the supplied array. ## Three-valued evaluation Evaluation returns `true`, `false` or `unknown`. Unknown occurs when: - a path does not exist; - the value has the wrong type; - a required repository profile is absent; - an adapter cannot provide a declared capability. Handling: | Context | Unknown behavior | |---|---| | Blocking guardrail | Include the guardrail and add a warning; fail closed | | Incompatible condition | Treat as not proven incompatible and show compatibility unknown | | Required workflow/check | Include and warn | | Optional workflow/check | Exclude and warn | | Input visibility | Show the field so required context is not hidden | | Export readiness | Block only when the unresolved condition affects a required input or safety decision | ## Policy precedence Conditions decide whether a rule applies; they do not change precedence. Final policy order remains: 1. platform non-overridable policy; 2. workspace policy; 3. repository policy; 4. playbook guardrail; 5. user-selectable option. A false lower-priority condition cannot disable a higher-priority rule. ## Capability vocabulary Playbooks may require only the governed capabilities in `schemas/playbook.schema.json`. `test-command` is satisfied by at least one confirmed unit, integration or end-to-end test command. More specific capabilities require the corresponding command role. A command marked `safeForAgentSuggestion: false` may satisfy compatibility but must not be rendered as an instruction to execute without explicit user confirmation. ## Determinism - Object key order does not affect the result. - Array order for `all` and `any` does not affect the boolean result, but stored source order is preserved for provenance. - No current time, network call or mutable external state is available to the evaluator. - Every fact access is recorded in the provenance result. ## Validation failures The package importer rejects: - unknown roots or operators; - paths to undeclared inputs; - `eq` or comparison conditions with an incompatible literal type when the input type is known; - empty `all` or `any` groups; - nesting deeper than 12 levels; - more than 100 total condition nodes per package; - conditions that would require secret values.