Concepts
Manifest loading
Load policy sources through an integrity-checked, fail-closed deployment manifest.A manifest is a JSON document describing a policy bundle: which sources to load, how to verify them, and what callers may inspect after solving. It is useful when deploying separately maintained policy files. Inline loading is also supported: it loads one in-memory source without a manifest.
A manifest binds policy source files to:
- stable policy identifiers
- registered domains
- SHA-256 integrity fingerprints
- loading modes
- Public Query Whitelist
- policy-set metadata
The policy source contains the logic. The manifest is the governance layer around that logic.
For programming details, see C Stable manifest loading and Advanced in-memory manifests. Python exposes file-manifest loading; the typed WASM wrapper exposes inline loading, not manifests.
Why manifests exist
A manifest gives Maelys DL a controlled loading boundary.
| Responsibility | Meaning |
|---|---|
| Policy discovery | Identify which policy sources belong to a policy set. |
| Integrity verification | Verify SHA-256 fingerprints before parsing policy source. |
| Domain binding | Select the registered predicate vocabulary used to validate each policy. |
| Loading mode | Decide whether a policy is active, shadow, test-only, or disabled. |
| Public Query Whitelist | Control which domain-declared QUERY predicates are publicly observable for this deployment. |
| Metadata | Attach stable policy-set and policy identifiers to loaded rulesets. |
These responsibilities stay separate:
| Element | Responsibility |
|---|---|
| Domain | Declares the allowed predicates, their arities and their roles. |
| Policy source | Defines the facts and rules used to reach a decision. |
| Manifest | Selects policies and domains, verifies source integrity, and limits public queries. |
Where the manifest fits
The manifest selects and constrains loading before the policy is parsed. The loaded result — the policy set — then connects to runtime evaluation.
Manifestidentity, domain, queries
Verify and loadcheck SHA + source vocabulary
Policy setvalidated policy entries
Sessionselect one policy
Request EDBcomplete runtime facts
Solveproduce a result
- Manifest → Verify and load
- Verify and load → Policy set
- Policy set → Session
- Session → Request EDB
- Request EDB → Solve
Example manifest
A typical manifest looks like this. The abbreviated SHA below is a placeholder: an actual manifest requires the exact 64-character lowercase SHA-256 of the source bytes.
{
"policy_set_id": "document_access.v1",
"policy_set_version": "1.0.0",
"manifest_version": "1",
"default_profile": "enforce",
"created_for": "production",
"strict_loading": true,
"fail_closed": true,
"capabilities": [],
"policies": [
{
"policy_id": "document_access.main",
"domain": "document_access",
"file": "policies/document_access.dl",
"sha256": "a3f7c291...",
"mode": "enforce",
"enabled": true,
"description": "Document access policy",
"queries": [
{ "name": "allow", "arity": 2 }
]
}
]
}This manifest says:
- Load the policy called
document_access.main. - Validate it with the
document_accessdomain. - Read the source from
policies/document_access.dl. - Verify the source SHA-256 before parsing.
- Load it in
enforcemode. - Expose only
allow/2as the publicly queryable surface.
The source can also use sensitivity_level/2 as an EDB guard. That predicate is
installed by the selected domain, not by the manifest.
Manifest fields
The manifest root object is strict: unknown fields are rejected, and each required field must have the expected type.
| Field | Type | Required | Meaning |
|---|---|---|---|
policy_set_id | string | yes | Stable identifier for the whole set of policies. |
policy_set_version | string | yes | Human-readable version of this policy set. |
manifest_version | string | yes | Version of the manifest schema. |
default_profile | string | yes | Default loading profile. Use enforce for file-based loading and MAELYS-DATALOG-v2 for buffer-based loading. |
created_for | string | yes | Intended environment, for example production or test. |
strict_loading | boolean | yes | Required metadata. The current loaders always reject unknown fields; setting this to false does not enable permissive parsing. |
fail_closed | boolean | yes | Required metadata expressing intent. Setting it to false does not turn an engine error into a successful result or authorize a request. |
capabilities | array | yes | Reserved manifest-level field. Must currently be an array; values are not interpreted yet. |
policies | array | yes | List of policy entries to load. |
Capabilities
The capabilities field is currently reserved for future manifest-level
feature negotiation. It is required and must be an array, but its values are
not interpreted yet and do not affect loading or evaluation.
For production manifests, use an empty array:
{
"capabilities": []
}Policy entry fields
Each item in policies describes one policy source file. Disabled policies are
accepted by the manifest but skipped by the loader.
| Field | Type | Required | Meaning |
|---|---|---|---|
policy_id | string | yes | Stable identifier for this policy. Used in diagnostics. |
domain | string | yes | Registered domain used to validate predicates and queries. |
file | string | yes | Safe relative path to the .dl policy source file. Absolute paths, .., and backslashes are rejected. Ignored for buffer-based loading. |
sha256 | string | yes | Lowercase hex SHA-256 of the .dl file bytes. Must match exactly. |
mode | string | yes | Policy loading mode: enforce, shadow, or test_only. |
enabled | boolean | yes | Disabled policies are present in the manifest but not loaded for decisions. |
description | string | yes | Human-readable description. No effect on evaluation. |
queries | array | no | Public Query Whitelist. Selects which domain-declared QUERY predicates are publicly observable. Does not create predicates. |
Domain binding
The manifest does not create a domain. It selects one.
{
"domain": "document_access"
}During loading, Maelys DL looks up the selected domain in the domain registry. The domain installs the predicate vocabulary used to validate the policy source.
Select domainmanifest names document_access
Look up domainpreviously registered declaration
Install vocabularypredicates + source atoms
Parse sourcevalidate names, arity and safety
- Select domain → Look up domain
- Look up domain → Install vocabulary
- Install vocabulary → Parse source
Public Query Whitelist
The queries field is the Public Query Whitelist. It controls which
predicates are publicly observable after solving. It does not declare predicates
— the Domain Registry is the sole vocabulary authority.
{
"queries": [
{ "name": "allow", "arity": 2 }
]
}This says: after solving, callers may inspect allow/2 results. The predicate
must already exist in the selected domain with the QUERY capability — the
manifest entry only selects it for public exposure.
Observation vs computation
The Public Query Whitelist restricts public observation, not solver
computation. Predicates absent from queries are still evaluated internally
and may contribute to deriving whitelisted predicates.
Suppose the domain declares both allow/2 and debug_trace/2 as
IDB|QUERY, but the production manifest lists only allow/2:
| Predicate | Computation | Public observation |
|---|---|---|
allow/2 | Evaluated by the solver. | May be queried. |
debug_trace/2 | Still evaluated; may help derive allow/2. | May not be queried. |
This lets a production manifest expose a minimal surface while a development manifest exposes additional predicates for inspection.
Validation
For each entry in queries, the loader verifies:
- Declared predicate: its name must exist in the selected domain.
- Matching arity: the number of arguments must match the domain declaration exactly.
- Query permission: the domain must declare that predicate with the
QUERYflag.
If any check fails, loading fails closed.
Fail-closed defaults
| Manifest entry | Public query access |
|---|---|
queries: [] | No predicate may be queried. |
No queries field | No predicate may be queried. |
Only predicates explicitly listed in queries may be inspected for this
deployment. An empty or missing list grants no public query access.
Manifest declaration
{
"name": "allow",
"arity": 2
}Publicly queryable fact
allow("alice", "roadmap.pdf").
Manifest versus in-memory sources
Choose the loading path according to where the JSON and source bytes are stored. Advanced C includes the Stable C operations, so those paths appear in both columns.
| Path | Variant | Stable C | Advanced C |
|---|---|---|---|
| Manifest | files on disk | ✓ | ✓ |
| Manifest | JSON and source in memory | ✕ | ✓ |
| Inline | source bytes; registered domain | ✓ | ✓ |
A green check means that path is available; a red cross means it is not. A static declaration table and in-memory source work by registering the domain, then loading the policy.
The manifest is the contract: it describes which policies exist, which domain they use, which predicates are queryable, and which SHA-256 each source must match.
For buffer-based loading, the .dl sources are supplied separately as
in-memory policy sources. They are matched to manifest entries by policy_id.
For example, the source for manifest entry document_access.main must carry
that same policy_id, not merely occupy the same position in an array.
This means the manifest still controls policy identity, domain binding, query
surface, and integrity checks. The source array only provides the actual .dl
bytes.
Loading permissions
The manifest loader has two independent opt-in permissions:
- Accept test-only policies. Without permission, an enabled entry marked
test_onlyrejects the load. With permission it is loaded and evaluated normally; this is not a dry run. - Accept undeclared policy-source atoms. Without permission, a quoted
string written in the source must be in the selected domain's
atoms. With permission, it can be accepted locally for that loaded policy; the registered domain is not expanded.
Neither permission bypasses source SHA verification or permits undeclared predicates. Unknown permission bits are rejected. Inline loading exposes no such override and always requires declared source strings.
A runtime EDB value such as "alice" does not need to appear in atoms
unless the policy source itself also names it.
What you have learned
KEEP THIS MODEL
Choose how to load and expose a policy- The manifest governs a deployment
Manifest loading is the production governance path: policy discovery, SHA integrity, domain binding, loading modes, and a Public Query Whitelist that controls public observation.
- The same manifest checks work in memory
Buffer manifest loading keeps that model entirely in memory.
- Inline loading has no manifest whitelist
Inline loading removes the manifest for one in-memory source. It preserves the domain predicate and source-atom checks, but all domain QUERY predicates are accessible.
- Declaration tables work with either path
A static declaration table works with inline loading too, but registration and loading remain separate public operations.
- Loading is not an authorization decision
The selected domain defines the vocabulary; the policy supplies the logic; the manifest adds source-integrity checks, deployment metadata and a public-query boundary. Authorization decisions are produced exclusively by policy evaluation.