Predicate Artifact Specification

Definition

A Predicate is an atomic boolean condition that forms the smallest building block of CFSE security logic. Predicates answer simple yes/no questions about system state: "Is this user the owner?" "Is MFA enabled?" "Is the token expired?"

Predicates are composed into invariants. While invariants express complete security rules, predicates express the individual conditions that those rules depend on. This separation enables reuse, testing, and clear reasoning about security logic.

Schema: predicate.schema.yaml


Required Fields

FieldTypeDescription
idPredicateIDUnique identifier following pattern P-<SYSTEM>-<NAME>
namestringHuman-readable name for the predicate
parametersPredicateParameter[]Typed input parameters for evaluation
returns"boolean"Always boolean - predicates evaluate to true or false
definitionstringPlain English description of when predicate is true

Optional Fields

FieldTypeDefaultDescription
implementationImplementation-Code hints showing how predicate maps to implementation
domainstring-Security domain (authentication, authorization, etc.)
used_inInvariantID[]-Invariants that use this predicate
negationPredicateID-ID of the logical negation predicate
relatedPredicateID[]-Related predicates often used together
statusArtifactStatusDRAFTLifecycle status: DRAFT, REVIEW, PLANNED, ACTIVE, DEPRECATED, ARCHIVED

Field Details

parameters

Parameters define what inputs the predicate requires for evaluation. Each parameter has:

  • name: snake_case identifier used in the definition
  • type: Either a Concept ID (C-*) or primitive type (string, integer, boolean, uuid, timestamp, any)
  • description: What the parameter represents

Using Concept IDs as types provides strong typing:

yaml
parameters:
  - name: user
    type: C-SHOP-USER
    description: "The user attempting the action"
  - name: item
    type: C-SHOP-ITEM
    description: "The item being accessed"

definition

The definition explains when the predicate evaluates to true. It should be:

  • Precise: No ambiguity about conditions
  • Implementable: Developers know exactly what to check
  • Testable: QA can verify the behavior

Good definitions reference parameter names and describe the exact comparison:

QualityExample
Good"True if user.id equals item.owner_id"
Good"True if current_time is less than token.expiry"
Bad"Checks if the user owns the item" (What does "own" mean?)
Bad"Returns true for valid users" (What makes a user valid?)

returns

Always "boolean". This field exists for:

  • Documentation clarity
  • Tooling support
  • Type system integration

Predicates must evaluate to exactly true or false. If you need a predicate that could be "unknown," model it as P-X-KNOWN AND P-X-VALUE where the first predicate checks knowability.


Key Patterns

  • Atomic conditions only. A predicate tests one thing. If you find yourself writing "AND" or "OR" in the definition, split into multiple predicates.

  • Parameters are positional. When predicates are used in invariant logic, parameters are matched by position: P-SHOP-IS-OWNER(user, item) maps first argument to first parameter.

  • Concept types over primitives. Use C-SHOP-USER instead of uuid when the parameter represents a concept. This enables validation and tooling.

  • Implementation hints are optional. Include them when the mapping to code is non-obvious. They help developers find and verify the implementation.


Common Mistakes

MistakeProblemFix
[ ] Complex conditionsPredicate does too much, hard to reuseSplit into atomic predicates, combine in invariants
[ ] Vague definitions"Checks if valid" - what does valid mean?Be specific: "True if X equals Y"
[ ] Missing parametersPredicate references concepts not in parametersAdd all required inputs as parameters
[ ] Primitive types everywhereLoses semantic meaning and validationUse Concept IDs when parameter represents a concept
[ ] No parameter descriptionsOthers cannot understand parameter purposeAlways describe what each parameter represents
[ ] Embedded logic"True if user.role == 'admin' OR user.role == 'superadmin'"Split: P-IS-ADMIN, P-IS-SUPERADMIN

Example: P-SHOP-IS-OWNER

yaml
id: P-SHOP-IS-OWNER
name: "Is Resource Owner"
 
parameters:
  - name: user
    type: C-SHOP-USER
    description: "The user to check ownership for"
  - name: item
    type: C-SHOP-ITEM
    description: "The item to check ownership of"
 
returns: boolean
 
definition: |
  True if user.id equals item.owner_id. The ownership check
  compares the authenticated user's identifier against the
  owner_id field stored on the item record.
 
domain: ownership
 
implementation:
  language: python
  code: |
    def is_owner(user: User, item: Item) -> bool:
        return user.id == item.owner_id
  file: "src/auth/ownership.py"
 
used_in:
  - INV-SHOP-OWNER-DELETE
  - INV-SHOP-OWNER-UPDATE
 
related:
  - P-SHOP-IS-ADMIN
  - P-SHOP-HAS-PERMISSION
 
status: ACTIVE

Example: P-AWS-HAS-MFA

yaml
id: P-AWS-HAS-MFA
name: "Has MFA Enabled"
 
parameters:
  - name: user
    type: C-AWS-IAM-USER
    description: "The IAM user to check"
 
returns: boolean
 
definition: |
  True if the IAM user has at least one MFA device configured
  and that device is in an active state. Checks the MFADevices
  list returned by iam:ListMFADevices.
 
domain: authentication
 
implementation:
  language: python
  code: |
    def has_mfa(user_arn: str) -> bool:
        devices = iam.list_mfa_devices(UserName=user_arn)
        return len(devices['MFADevices']) > 0
 
used_in:
  - INV-AWS-MFA-REQUIRED
  - INV-AWS-CONSOLE-MFA
 
status: ACTIVE

Validation Criteria

A valid predicate artifact MUST:

  1. Have a unique ID matching pattern P-<SYSTEM>-<NAME>
  2. Have a non-empty name that describes the condition
  3. Have at least one parameter with name and type
  4. Have returns set to "boolean"
  5. Have a clear definition that explains when predicate is true
  6. Use valid Concept IDs for typed parameters (if using concept types)
  7. Reference only existing invariants in used_in (if populated)

Parameter Validation

RequirementValidInvalid
Name formatuser, item_idUser, item-id
Concept typeC-SHOP-USERUser, shop-user
Primitive typestring, uuidstr, number

Predicate vs Invariant

AspectPredicateInvariant
ScopeSingle atomic checkComplete security rule
LogicNo operatorsUses FORALL, IMPLIES, AND, etc.
ReturnsAlways booleanN/A (rules, not functions)
ReusabilityHigh - used in many invariantsMedium - often unique rules
Example"Is user the owner?""Only owners can delete their items"

Predicates are the atoms; invariants are the molecules.



Common Pitfalls

  • Writing predicates that are too high-level (“is authorized”) instead of testable atomic facts.
  • Using ambiguous parameter names/types that can’t be grounded in the world model.
  • Treating predicates as implementation code; they are logical conditions that map to evidence.