Manifest Loading
███╗ ███╗ █████╗ ███╗ ██╗██╗███████╗███████╗███████╗████████╗ ████╗ ████║██╔══██╗████╗ ██║██║██╔════╝██╔════╝██╔════╝╚══██╔══╝ ██╔████╔██║███████║██╔██╗ ██║██║█████╗ █████╗ ███████╗ ██║ ██║╚██╔╝██║██╔══██║██║╚██╗██║██║██╔══╝ ██╔══╝ ╚════██║ ██║ ██║ ╚═╝ ██║██║ ██║██║ ╚████║██║██║ ███████╗███████║ ██║ ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═══╝╚═╝╚═╝ ╚══════╝╚══════╝ ╚═╝
A .dl policy file is not loaded in isolation in production. In Maelys DL, a
manifest governs how policies are loaded, identified, checked, and exposed to
callers.
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.
Manifest loading is fail-closed. If the manifest is malformed, if a policy file is missing, if a SHA-256 does not match, or if a test-only policy is loaded without explicit permission, loading fails.
A manifest does not replace the registry model. Each policy selects a registered domain, and the selected domain remains the sole authority for the predicate vocabulary. The manifest never creates predicates. See Registries for domain and predicate registry details.
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. |
In short:
Domain Registry = predicate vocabulary authority
Policy source = Datalog logic
Manifest = deployment contract and public observation gateWhere 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.
Example manifest
A typical manifest looks like this:
{
"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, MAELYS-DATALOG-TEXT-v1 for buffer-based loading. |
created_for | string | yes | Intended environment, for example production or test. |
strict_loading | boolean | yes | If true, unknown or inconsistent fields are rejected instead of ignored. |
fail_closed | boolean | yes | Documents that load or solve failures must deny by default. |
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 and receipts. |
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. |
idb_predicates | array | no | Deprecated. Accepted for compatibility but has no semantic effect. Do not use in new manifests. |
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.
manifest domain
→ registered domain lookup
→ predicate vocabulary installation
→ policy parsing and validationA manifest cannot create predicates. If a policy uses a predicate that is not declared by the selected domain, loading fails.
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.
The manifest never creates predicates. The queries field only exposes
predicates that the Domain Registry has already declared as queryable.
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.
Domain capabilities:
allow/2 IDB|QUERY
debug_trace/2 IDB|QUERY
Production manifest queries:
allow/2 ← publicly observable
Solver behavior:
debug_trace/2 is still computed internally.
It may help derive allow/2.
It is not accessible through the public query API.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:
1. The predicate exists in the Domain Registry.
2. The arity matches exactly.
3. The predicate has the QUERY capability flag.If any check fails, loading fails closed.
Fail-closed defaults
queries: [] → nothing is publicly queryable
queries field absent → nothing is publicly queryableIf a predicate is not explicitly listed, it is not publicly observable for this deployment. This is the most fail-closed behavior.
Manifest declaration
{
"name": "allow",
"arity": 2
}Publicly queryable fact
allow("alice", "roadmap.pdf").Deprecated: idb_predicates
The idb_predicates field is deprecated.
It is accepted syntactically for compatibility with older manifests but has no semantic effect. It does not create predicates, does not modify the predicate registry, and does not affect loading or evaluation.
Do not use idb_predicates in new manifests. If a policy uses a predicate,
that predicate must be declared by the selected domain. The manifest cannot
extend the domain vocabulary.
Loading architectures
Maelys DL supports two loading families — manifest and inline — across five APIs total (File manifest loading has two: a simple wrapper and an extended variant with diagnostics). Inline loading has two variants: dynamic (register the domain separately, then load) and static domain (register and load in one call, from a compile-time predicate table).
| Loading style | Metadata | Source bytes | Query whitelist | Use case |
|---|---|---|---|---|
| File manifest loading | Manifest JSON file | Policy files on disk | Manifest queries field | Production deployments. |
| Buffer manifest loading | Manifest JSON buffer | In-memory source bundle | Manifest queries field | Embedded, tests, streaming — any caller with in-memory sources. |
| Inline loading (dynamic) | Function arguments | In-memory src/src_len | None — all QUERY predicates accessible | Tests, examples, REPLs, simple embedded callers; the domain is registered separately, beforehand. |
| Inline loading (static) | Function arguments + compile-time predicate table | In-memory src/src_len | None — all QUERY predicates accessible | C static tables, WASM production builds, embedded C where the domain is compiled in — registers and loads in one call. |
Loading APIs
Maelys DL exposes five public loading APIs.
| API | Loading style | Use when |
|---|---|---|
maelys_datalog_manifest_load | File manifest | The manifest and policy files are on disk, and structured diagnostics are not needed. |
maelys_datalog_manifest_load_ex | File manifest | The manifest and policy files are on disk, and the caller wants structured diagnostics. |
maelys_datalog_manifest_load_from_text | In-memory manifest | The caller has manifest JSON and policy source bytes in memory, but still wants manifest metadata, modes, SHA verification, bundles, or multiple policies. |
maelys_datalog_load_policy_inline | In-memory inline source | The caller has one .dl policy source in memory and does not need manifest JSON, caller-provided SHA-256, bundles, modes, or multi-policy metadata. The domain is already registered. |
maelys_datalog_load_policy_inline_with_static_domain | In-memory inline source, static domain | The caller has a compile-time predicate table and wants to register the domain and load the policy in one call — no separate registration step. |
Choosing a loading path
Use file manifest loading when policies are deployed on disk.
Use buffer manifest loading when there is no filesystem, but the caller still wants the manifest model:
policy_set_id,policy_set_version- multi-policy loading
- loading modes
- caller-provided SHA-256 verification
- Public Query Whitelist
Use inline loading when the caller simply wants to load one .dl source already
in memory. Inline loading has no manifest Public Query Whitelist — all
predicates declared as QUERY by the selected domain are accessible.
Use the static domain variant specifically when the predicate table is already written as a compile-time C array and a separate registration call would just be extra ceremony — C static tables, WASM production builds, tests that want a one-call setup. Use the plain (dynamic) variant when the domain is registered separately, from JavaScript, from another module, or from a callback — anywhere the predicate table is not a literal C array sitting next to the load call.
Inline loading is not a manifest shortcut with fewer fields. It is a different loading style with different query access semantics: single-policy, no manifest JSON, no SHA, no bundle, and no Public Query Whitelist restriction.
File manifest loading
File manifest loading uses a manifest JSON file on disk. The manifest references policy source files by safe relative path, and the loader reads those files during loading.
Simple file variant
maelys_result_t
maelys_datalog_manifest_load(
const char *manifest_path,
unsigned flags,
maelys_datalog_policy_set_t *out_set);This is a convenience wrapper. It loads a manifest file without returning
structured diagnostics. Equivalent to calling the extended variant with
out_diag = NULL.
Extended file variant
maelys_result_t
maelys_datalog_manifest_load_ex(
const char *manifest_path,
unsigned flags,
maelys_datalog_policy_set_t *out_set,
maelys_datalog_diagnostic_t *out_diag);Use _ex when the caller needs to explain a loading failure precisely.
See Error codes for the full diagnostic code reference.
File loading example
#include "include/maelys_datalog.h"
maelys_result_t
load_document_access_from_files(void)
{
maelys_result_t rc;
maelys_datalog_policy_set_t policy_set;
maelys_datalog_diagnostic_t diag;
rc = document_access_domains_install();
if (rc != MAELYS_OK) return rc;
rc = maelys_datalog_manifest_load_ex(
"policies/manifest.json",
0,
&policy_set,
&diag);
if (rc != MAELYS_OK) return rc; /* fail closed */
/*
* policy_set is now ready. Pass policy_set.policies[0].symbols and
* .registry to edb_init() to initialize the runtime EDB.
* See: /docs/api/edb
*/
return MAELYS_OK;
}Buffer manifest loading
Buffer manifest loading uses the same manifest model, but avoids filesystem access. The caller provides manifest JSON bytes and source bundle entries.
maelys_result_t
maelys_datalog_manifest_load_from_text(
const char *manifest_json,
size_t manifest_json_len,
const maelys_datalog_policy_bundle_entry_t *bundle,
size_t bundle_count,
unsigned flags,
maelys_datalog_policy_set_t *out_set,
maelys_datalog_diagnostic_t *out_diag);The buffer loader:
- Parses the manifest JSON.
- For each enabled policy, finds the matching source entry by
policy_id. - Verifies the SHA-256 of the source bytes against the manifest.
- Installs the selected domain vocabulary.
- Validates and loads the policy source.
- Stores the
queriesPublic Query Whitelist in the returned policy set.
manifest_json does not need to be NUL-terminated. manifest_json_len is
authoritative.
In-memory policy sources
typedef struct {
const char *policy_id; /* matches policy_id in manifest JSON */
const char *src; /* .dl source bytes */
size_t src_len; /* byte length of src */
} maelys_datalog_policy_bundle_entry_t;Buffer loading example
#include <stdio.h>
#include "include/maelys_datalog.h"
maelys_result_t
load_document_access_from_buffers(void)
{
maelys_result_t rc;
maelys_datalog_policy_set_t policy_set;
maelys_datalog_diagnostic_t diag;
static const char policy_src[] =
"blocked(\"mallory\").\n"
"\n"
"allow(User, Document) :-\n"
" owns(User, Document),\n"
" not blocked(User),\n"
" sensitivity_level(User, Level),\n"
" Level >= 3.\n"
"\n"
"allow(User, Document) :-\n"
" shared_with(User, Document),\n"
" not blocked(User),\n"
" sensitivity_level(User, Level),\n"
" Level >= 3.\n";
rc = document_access_domains_install();
if (rc != MAELYS_OK) return rc;
/* Compute SHA-256 of the source bytes */
char sha256[65];
maelys_sha256_hex(
(const unsigned char *)policy_src,
sizeof(policy_src) - 1,
sha256);
/* Build manifest JSON — check for truncation */
char manifest[2048];
int written = snprintf(
manifest, sizeof(manifest),
"{"
"\"policy_set_id\":\"document_access.buffer\","
"\"policy_set_version\":\"1\","
"\"manifest_version\":\"1\","
"\"default_profile\":\"MAELYS-DATALOG-TEXT-v1\","
"\"created_for\":\"test\","
"\"strict_loading\":true,"
"\"fail_closed\":true,"
"\"capabilities\":[],"
"\"policies\":[{"
"\"policy_id\":\"document_access.main\","
"\"domain\":\"document_access\","
"\"file\":\"ignored-for-buffer-loading.dl\","
"\"sha256\":\"%s\","
"\"mode\":\"shadow\","
"\"enabled\":true,"
"\"description\":\"buffer loading example\","
"\"queries\":[{\"name\":\"allow\",\"arity\":2}]"
"}]"
"}",
sha256);
if (written < 0 || (size_t)written >= sizeof(manifest))
return MAELYS_ERR_PAYLOAD_TOO_LARGE;
maelys_datalog_policy_bundle_entry_t sources[] = {
{
.policy_id = "document_access.main",
.src = policy_src,
.src_len = sizeof(policy_src) - 1,
},
};
rc = maelys_datalog_manifest_load_from_text(
manifest, (size_t)written,
sources, sizeof(sources) / sizeof(sources[0]),
0, &policy_set, &diag);
if (rc != MAELYS_OK) return rc;
/*
* policy_set now has allow/2 in its Public Query Whitelist.
* Pass policy_set.policies[0].symbols and .registry to edb_init()
* to initialize the runtime EDB for evaluation.
* See: /docs/api/edb
*/
return MAELYS_OK;
}Inline loading
Inline loading is the low-ceremony path for loading one policy directly from an
in-memory .dl source. It does not use a manifest.
maelys_result_t
maelys_datalog_load_policy_inline(
const char *domain,
const char *policy_id,
const char *src,
size_t src_len,
unsigned flags,
maelys_datalog_policy_set_t *out_set,
maelys_datalog_diagnostic_t *out_diag);Inline loading has no manifest Public Query Whitelist. All predicates
declared as QUERY by the selected domain are accessible through the query API.
There is no observation gate between the solver output and the caller.
Inline domain-closed vocabulary
All predicates used by the inline source must be declared by the selected domain. Inline loading does not support manifest-level overlays or per-call vocabulary extensions.
This is valid if the selected domain declares owns/2, sensitivity_level/2,
and allow/2:
allow(User, Document) :-
owns(User, Document),
sensitivity_level(User, Level),
Level >= 3.This is invalid unless the selected domain also declares helper/2:
helper(User, Document) :- owns(User, Document).
allow(User, Document) :- helper(User, Document).Inline loading is not a way to create policy-local predicates. The selected domain must declare every predicate used by the inline source.
See Registries for the domain-closed vocabulary model.
Inline loading example
#include "include/maelys_datalog.h"
maelys_result_t
load_document_access_inline(void)
{
maelys_result_t rc;
maelys_datalog_policy_set_t policy_set;
maelys_datalog_diagnostic_t diag;
static const char policy_src[] =
"allow(User, Document) :-\n"
" owns(User, Document),\n"
" sensitivity_level(User, Level),\n"
" Level >= 3.\n";
rc = document_access_domains_install();
if (rc != MAELYS_OK) return rc;
rc = maelys_datalog_load_policy_inline(
"document_access",
"document_access.inline",
policy_src,
sizeof(policy_src) - 1,
0,
&policy_set,
&diag);
if (rc != MAELYS_OK) return rc;
/*
* All domain QUERY predicates are accessible — no whitelist.
* Pass policy_set.policies[0].symbols and .registry to edb_init()
* to initialize the runtime EDB for evaluation.
* See: /docs/api/edb
*/
return MAELYS_OK;
}Inline loading with a static domain
maelys_datalog_load_policy_inline_with_static_domain registers a domain from
a compile-time predicate table and loads a policy in one call — no separate
registration step, no separate domain_registry_register call to write.
maelys_result_t
maelys_datalog_load_policy_inline_with_static_domain(
const maelys_datalog_predicate_def_t *predicates,
size_t predicate_count,
const char *domain_name,
const char *policy_id,
const char *src,
size_t src_len,
unsigned flags,
maelys_datalog_policy_set_t *out_set,
maelys_datalog_diagnostic_t *out_diag);Verified against the implementation: this function is a thin wrapper — it
calls maelys_datalog_domain_registry_register with predicates/
predicate_count/domain_name, then calls maelys_datalog_load_policy_inline
with the remaining arguments unchanged, flags included. Every constraint of
the dynamic variant (flags must be 0, domain-closed vocabulary, no
Public Query Whitelist) applies identically here.
domain_name and predicates are stored by pointer in the global domain
registry (first-registration-wins, see
Registries — Registering a domain)
and must remain valid for as long as the registry may reference them — a
static const array and string literals satisfy this automatically, which is
why this API exists specifically for compile-time C tables rather than
heap-built or short-lived ones.
This is the API the WASM static-domain production target uses under the hood — see Registries — Production target: domain table compiled in C.
Static domain loading example
Reuses the document_access_predicates static table from
Registries — Method 1: static predicate table.
#include "include/maelys_datalog.h"
maelys_result_t
load_document_access_static(void)
{
maelys_result_t rc;
maelys_datalog_policy_set_t policy_set;
maelys_datalog_diagnostic_t diag;
static const char policy_src[] =
"allow(User, Document) :-\n"
" owns(User, Document),\n"
" sensitivity_level(User, Level),\n"
" Level >= 3.\n";
rc = maelys_datalog_load_policy_inline_with_static_domain(
document_access_predicates,
sizeof(document_access_predicates) / sizeof(document_access_predicates[0]),
"document_access",
"document_access.static",
policy_src,
sizeof(policy_src) - 1,
0,
&policy_set,
&diag);
if (rc != MAELYS_OK) return rc; /* fail closed */
/*
* No separate document_access_domains_install() call needed above —
* this one call registered the domain and loaded the policy.
* Pass policy_set.policies[0].symbols and .registry to edb_init()
* to initialize the runtime EDB.
* See: /docs/api/edb
*/
return MAELYS_OK;
}WASM loading
For WASM and embedded environments, use the in-memory loading paths. See WASM bindings for the full build and API reference.
| API | Use when |
|---|---|
maelys_datalog_manifest_load_from_text | The caller still wants manifest metadata, multiple policies, loading modes, SHA verification, or a Public Query Whitelist. |
maelys_datalog_load_policy_inline | The dynamic builder path (domainBegin/domainAddPredicate/domainCommit) registers the domain, then calls this to load the policy. No whitelist — all domain QUERY predicates accessible. |
maelys_datalog_load_policy_inline_with_static_domain | The static-domain WASM production target: the predicate table is a C array compiled into the module, and this call registers it and loads the policy in one step. See Registries — Production target. |
What loading returns
Every loading function writes its result into out_set on success. The
policy_set you receive is not just a receipt — it is the shared context
that every subsequent operation depends on.
maelys_datalog_policy_set_t policy_set; /* filled by any loader */
policy_set.policies[0] /* first loaded policy (one per manifest entry) */
.symbols /* shared string intern table: "alice" → ID 1 */
.registry /* predicate registry: which predicates exist */
/* ... parsed rules, strata, query whitelist, identity ... */These two fields are the bridge between loading and runtime evaluation. The EDB must share the same symbol table and predicate registry as the policy it will be solved against. If they used different tables, string IDs would not match between EDB facts and ruleset rules — no fact would ever match a rule.
/* After loading, initialize the EDB with the policy's shared context */
static maelys_datalog_edb_t edb;
static maelys_datalog_fact_t pool[MAELYS_DATALOG_MAX_EDB_FACTS];
maelys_datalog_edb_init(
&edb,
pool,
MAELYS_DATALOG_MAX_EDB_FACTS,
&policy_set.policies[0].symbols, /* same string table as the ruleset */
&policy_set.policies[0].registry); /* same predicate vocabulary */From this point, loading is complete. The full evaluation lifecycle is:
1. Load — manifest loading produces policy_set
2. Init — edb_init(&edb, pool, N, &policy_set.policies[0].symbols,
&policy_set.policies[0].registry)
3. Add — edb_add_fact(&edb, "owns", terms, 2) per request
4. Finalize — edb_finalize(&edb)
5. Solve — solve_once(&policy_set.policies[0], &edb, &result)
6. Query — query_solved_ground_fact(result, "allow", terms, 2, &present)
7. Free — solve_result_free(result)
8. Repeat — edb_clear(&edb), go to step 3 for the next requestThe ruleset (policy_set.policies[0]) is loaded once and reused across all
requests. Only the EDB changes per request.
See Runtime EDB — initialization for a detailed explanation of the EDB lifecycle and why the shared symbol table is required.
Parameter reference
| Function | Whitelist enforced | Diagnostics |
|---|---|---|
maelys_datalog_manifest_load | Yes — manifest queries | No |
maelys_datalog_manifest_load_ex | Yes — manifest queries | Optional out_diag |
maelys_datalog_manifest_load_from_text | Yes — manifest queries | Optional out_diag |
maelys_datalog_load_policy_inline | No — all QUERY accessible | Optional out_diag |
maelys_datalog_load_policy_inline_with_static_domain | No — all QUERY accessible | Optional out_diag |
Shared output parameters
| Name | Type | Meaning |
|---|---|---|
out_set | maelys_datalog_policy_set_t * | Receives the loaded policy set on success. Cleared on failure. Must not be NULL. |
out_diag | maelys_datalog_diagnostic_t * | Optional structured diagnostic output. May be NULL for APIs that expose it. |
File manifest parameters
| Name | Type | Meaning |
|---|---|---|
manifest_path | const char * | Filesystem path to the manifest JSON file. Must not be NULL. |
flags | unsigned | Manifest loading flags. Use 0 for strict production loading. |
out_set | maelys_datalog_policy_set_t * | Receives the loaded policy set. Cleared on failure. |
out_diag | maelys_datalog_diagnostic_t * | Optional diagnostics. Only on _ex. May be NULL. |
Buffer manifest parameters
| Name | Type | Meaning |
|---|---|---|
manifest_json | const char * | Manifest JSON bytes. Does not need to be NUL-terminated. |
manifest_json_len | size_t | Authoritative byte length of manifest_json. |
bundle | const maelys_datalog_policy_bundle_entry_t * | In-memory .dl source entries matched by policy_id. May be NULL if bundle_count is zero. |
bundle_count | size_t | Number of entries in bundle. |
flags | unsigned | Manifest loading flags. Use 0 for strict production loading. |
out_set | maelys_datalog_policy_set_t * | Receives the loaded policy set. Cleared on failure. |
out_diag | maelys_datalog_diagnostic_t * | Optional diagnostics. May be NULL. |
Inline (dynamic) parameters
| Name | Type | Meaning |
|---|---|---|
domain | const char * | Registered domain name. Non-NULL, non-empty. |
policy_id | const char * | Stable identifier for this inline policy. Non-NULL, non-empty. |
src | const char * | .dl policy source bytes. Does not need to be NUL-terminated. |
src_len | size_t | Authoritative byte length of src. Must be greater than zero. |
flags | unsigned | Reserved. Must be 0. |
out_set | maelys_datalog_policy_set_t * | Receives the loaded single-policy set. Cleared on failure. |
out_diag | maelys_datalog_diagnostic_t * | Optional diagnostics. May be NULL. |
Inline (static domain) parameters
Same as the dynamic variant, plus the predicate table registered before loading:
| Name | Type | Meaning |
|---|---|---|
predicates | const maelys_datalog_predicate_def_t * | Compile-time predicate table. Stored by pointer in the domain registry — must remain valid for the registry's lifetime. |
predicate_count | size_t | Number of entries in predicates. |
domain_name | const char * | Domain name to register. Stored by pointer — same lifetime requirement as predicates. |
policy_id | const char * | Stable identifier for this inline policy. Non-NULL, non-empty. |
src | const char * | .dl policy source bytes. Does not need to be NUL-terminated. |
src_len | size_t | Authoritative byte length of src. Must be greater than zero. |
flags | unsigned | Reserved. Must be 0 — passed through unchanged to the same check load_policy_inline performs. |
out_set | maelys_datalog_policy_set_t * | Receives the loaded single-policy set. Cleared on failure. |
out_diag | maelys_datalog_diagnostic_t * | Optional diagnostics. May be NULL. |
Flags
| Loading style | Accepted flags | Meaning |
|---|---|---|
| Manifest loading | 0 | Strict production loading. Test-only policies are rejected. |
| Manifest loading | MAELYS_DATALOG_MANIFEST_ALLOW_TEST_ONLY | Allows test_only policies. Tests and development only. |
| Inline loading (dynamic) | 0 | Required. |
| Inline loading (dynamic) | Any non-zero value | Rejected with MAELYS_ERR_INVALID_ARGUMENT. |
| Inline loading (static domain) | 0 | Required — passed through unchanged to the same check as the dynamic variant. |
| Inline loading (static domain) | Any non-zero value | Rejected with MAELYS_ERR_INVALID_ARGUMENT. |
Do not use MAELYS_DATALOG_MANIFEST_ALLOW_TEST_ONLY in production.
Diagnostics
The return code tells the caller the broad class of failure. The diagnostic object explains the precise cause.
A manifest SHA mismatch:
Return code : MAELYS_ERR_INVALID_FIELD
Diagnostic : code=MAELYS_DATALOG_DIAG_MANIFEST_SHA_MISMATCH
field=sha256 / hint=update manifest sha256 after policy editA rejected test-only policy:
Return code : MAELYS_ERR_FORBIDDEN
Diagnostic : code=MAELYS_DATALOG_DIAG_MANIFEST_TEST_ONLY_REJECTEDA Public Query Whitelist validation failure:
Return code : MAELYS_ERR_INVALID_FIELD
(unknown predicate, arity mismatch, or missing QUERY flag)A non-whitelisted query at runtime:
Return code : MAELYS_ERR_FORBIDDEN
(predicate exists but is not in the Public Query Whitelist)Diagnostics do not change loader behavior. Loading remains fail-closed.
See Error codes for the full diagnostic code reference.
Return values
| Return code | Meaning |
|---|---|
MAELYS_OK | Loading succeeded. |
MAELYS_ERR_INVALID_ARGUMENT | A required argument is invalid. For inline loading, also includes non-zero flags. |
MAELYS_ERR_NOT_FOUND | Manifest file, referenced policy file, or bundle entry not found. |
MAELYS_ERR_INVALID_FIELD | Invalid manifest JSON, policy source, or Public Query Whitelist validation failure. |
MAELYS_ERR_UNSUPPORTED | Unknown domain. |
MAELYS_ERR_FORBIDDEN | Test-only policy without flag, or non-whitelisted query at runtime. |
MAELYS_ERR_IO | File read failure. File manifest loading only. |
MAELYS_ERR_INTERNAL | Internal allocation failure. |
MAELYS_ERR_PAYLOAD_TOO_LARGE | Static capacity or bounded field size exceeded. |
Summary
Manifest loading is the production governance path: policy discovery, SHA integrity, domain binding, loading modes, and a Public Query Whitelist that controls public observation.
Buffer manifest loading keeps that model entirely in memory.
Inline loading removes the manifest for one in-memory source. It preserves
the domain-closed vocabulary model but has no Public Query Whitelist — all
domain QUERY predicates are accessible. It has two variants: dynamic
(maelys_datalog_load_policy_inline, domain registered separately) and
static domain (maelys_datalog_load_policy_inline_with_static_domain,
register-and-load in one call from a compile-time predicate table).
Domain Registry = vocabulary authority (predicates, arities, kind flags)
Policy source = Datalog logic using that vocabulary
Manifest = deployment contract: SHA, mode, metadata,
and Public Query WhitelistAuthorization decisions are produced exclusively by policy evaluation.