API Reference

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.

i

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.

i

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.

ResponsibilityMeaning
Policy discoveryIdentify which policy sources belong to a policy set.
Integrity verificationVerify SHA-256 fingerprints before parsing policy source.
Domain bindingSelect the registered predicate vocabulary used to validate each policy.
Loading modeDecide whether a policy is active, shadow, test-only, or disabled.
Public Query WhitelistControl which domain-declared QUERY predicates are publicly observable for this deployment.
MetadataAttach 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 gate

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.

ManifestSHA, domain, queriesDomainpredicate vocabulary.dl sourceSHA-verified bytesPolicy setsymbols + registryEDBruntime factsSolvederive decisions

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_access domain.
  • Read the source from policies/document_access.dl.
  • Verify the source SHA-256 before parsing.
  • Load it in enforce mode.
  • Expose only allow/2 as 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.

FieldTypeRequiredMeaning
policy_set_idstringyesStable identifier for the whole set of policies.
policy_set_versionstringyesHuman-readable version of this policy set.
manifest_versionstringyesVersion of the manifest schema.
default_profilestringyesDefault loading profile. Use enforce for file-based loading, MAELYS-DATALOG-TEXT-v1 for buffer-based loading.
created_forstringyesIntended environment, for example production or test.
strict_loadingbooleanyesIf true, unknown or inconsistent fields are rejected instead of ignored.
fail_closedbooleanyesDocuments that load or solve failures must deny by default.
capabilitiesarrayyesReserved manifest-level field. Must currently be an array; values are not interpreted yet.
policiesarrayyesList 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.

FieldTypeRequiredMeaning
policy_idstringyesStable identifier for this policy. Used in diagnostics and receipts.
domainstringyesRegistered domain used to validate predicates and queries.
filestringyesSafe relative path to the .dl policy source file. Absolute paths, .., and backslashes are rejected. Ignored for buffer-based loading.
sha256stringyesLowercase hex SHA-256 of the .dl file bytes. Must match exactly.
modestringyesPolicy loading mode: enforce, shadow, or test_only.
enabledbooleanyesDisabled policies are present in the manifest but not loaded for decisions.
descriptionstringyesHuman-readable description. No effect on evaluation.
queriesarraynoPublic Query Whitelist. Selects which domain-declared QUERY predicates are publicly observable. Does not create predicates.
idb_predicatesarraynoDeprecated. 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 validation
!

A 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 queryable

If 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 styleMetadataSource bytesQuery whitelistUse case
File manifest loadingManifest JSON filePolicy files on diskManifest queries fieldProduction deployments.
Buffer manifest loadingManifest JSON bufferIn-memory source bundleManifest queries fieldEmbedded, tests, streaming — any caller with in-memory sources.
Inline loading (dynamic)Function argumentsIn-memory src/src_lenNone — all QUERY predicates accessibleTests, examples, REPLs, simple embedded callers; the domain is registered separately, beforehand.
Inline loading (static)Function arguments + compile-time predicate tableIn-memory src/src_lenNone — all QUERY predicates accessibleC 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.

APILoading styleUse when
maelys_datalog_manifest_loadFile manifestThe manifest and policy files are on disk, and structured diagnostics are not needed.
maelys_datalog_manifest_load_exFile manifestThe manifest and policy files are on disk, and the caller wants structured diagnostics.
maelys_datalog_manifest_load_from_textIn-memory manifestThe 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_inlineIn-memory inline sourceThe 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_domainIn-memory inline source, static domainThe 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:

  1. Parses the manifest JSON.
  2. For each enabled policy, finds the matching source entry by policy_id.
  3. Verifies the SHA-256 of the source bytes against the manifest.
  4. Installs the selected domain vocabulary.
  5. Validates and loads the policy source.
  6. Stores the queries Public 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.

i

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.

APIUse when
maelys_datalog_manifest_load_from_textThe caller still wants manifest metadata, multiple policies, loading modes, SHA verification, or a Public Query Whitelist.
maelys_datalog_load_policy_inlineThe 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_domainThe 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 request

The 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

FunctionWhitelist enforcedDiagnostics
maelys_datalog_manifest_loadYes — manifest queriesNo
maelys_datalog_manifest_load_exYes — manifest queriesOptional out_diag
maelys_datalog_manifest_load_from_textYes — manifest queriesOptional out_diag
maelys_datalog_load_policy_inlineNo — all QUERY accessibleOptional out_diag
maelys_datalog_load_policy_inline_with_static_domainNo — all QUERY accessibleOptional out_diag

Shared output parameters

NameTypeMeaning
out_setmaelys_datalog_policy_set_t *Receives the loaded policy set on success. Cleared on failure. Must not be NULL.
out_diagmaelys_datalog_diagnostic_t *Optional structured diagnostic output. May be NULL for APIs that expose it.

File manifest parameters

NameTypeMeaning
manifest_pathconst char *Filesystem path to the manifest JSON file. Must not be NULL.
flagsunsignedManifest loading flags. Use 0 for strict production loading.
out_setmaelys_datalog_policy_set_t *Receives the loaded policy set. Cleared on failure.
out_diagmaelys_datalog_diagnostic_t *Optional diagnostics. Only on _ex. May be NULL.

Buffer manifest parameters

NameTypeMeaning
manifest_jsonconst char *Manifest JSON bytes. Does not need to be NUL-terminated.
manifest_json_lensize_tAuthoritative byte length of manifest_json.
bundleconst maelys_datalog_policy_bundle_entry_t *In-memory .dl source entries matched by policy_id. May be NULL if bundle_count is zero.
bundle_countsize_tNumber of entries in bundle.
flagsunsignedManifest loading flags. Use 0 for strict production loading.
out_setmaelys_datalog_policy_set_t *Receives the loaded policy set. Cleared on failure.
out_diagmaelys_datalog_diagnostic_t *Optional diagnostics. May be NULL.

Inline (dynamic) parameters

NameTypeMeaning
domainconst char *Registered domain name. Non-NULL, non-empty.
policy_idconst char *Stable identifier for this inline policy. Non-NULL, non-empty.
srcconst char *.dl policy source bytes. Does not need to be NUL-terminated.
src_lensize_tAuthoritative byte length of src. Must be greater than zero.
flagsunsignedReserved. Must be 0.
out_setmaelys_datalog_policy_set_t *Receives the loaded single-policy set. Cleared on failure.
out_diagmaelys_datalog_diagnostic_t *Optional diagnostics. May be NULL.

Inline (static domain) parameters

Same as the dynamic variant, plus the predicate table registered before loading:

NameTypeMeaning
predicatesconst 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_countsize_tNumber of entries in predicates.
domain_nameconst char *Domain name to register. Stored by pointer — same lifetime requirement as predicates.
policy_idconst char *Stable identifier for this inline policy. Non-NULL, non-empty.
srcconst char *.dl policy source bytes. Does not need to be NUL-terminated.
src_lensize_tAuthoritative byte length of src. Must be greater than zero.
flagsunsignedReserved. Must be 0 — passed through unchanged to the same check load_policy_inline performs.
out_setmaelys_datalog_policy_set_t *Receives the loaded single-policy set. Cleared on failure.
out_diagmaelys_datalog_diagnostic_t *Optional diagnostics. May be NULL.

Flags

Loading styleAccepted flagsMeaning
Manifest loading0Strict production loading. Test-only policies are rejected.
Manifest loadingMAELYS_DATALOG_MANIFEST_ALLOW_TEST_ONLYAllows test_only policies. Tests and development only.
Inline loading (dynamic)0Required.
Inline loading (dynamic)Any non-zero valueRejected with MAELYS_ERR_INVALID_ARGUMENT.
Inline loading (static domain)0Required — passed through unchanged to the same check as the dynamic variant.
Inline loading (static domain)Any non-zero valueRejected 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 edit

A rejected test-only policy:

Return code : MAELYS_ERR_FORBIDDEN
Diagnostic  : code=MAELYS_DATALOG_DIAG_MANIFEST_TEST_ONLY_REJECTED

A 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)
i

Diagnostics do not change loader behavior. Loading remains fail-closed.

See Error codes for the full diagnostic code reference.

Return values

Return codeMeaning
MAELYS_OKLoading succeeded.
MAELYS_ERR_INVALID_ARGUMENTA required argument is invalid. For inline loading, also includes non-zero flags.
MAELYS_ERR_NOT_FOUNDManifest file, referenced policy file, or bundle entry not found.
MAELYS_ERR_INVALID_FIELDInvalid manifest JSON, policy source, or Public Query Whitelist validation failure.
MAELYS_ERR_UNSUPPORTEDUnknown domain.
MAELYS_ERR_FORBIDDENTest-only policy without flag, or non-whitelisted query at runtime.
MAELYS_ERR_IOFile read failure. File manifest loading only.
MAELYS_ERR_INTERNALInternal allocation failure.
MAELYS_ERR_PAYLOAD_TOO_LARGEStatic 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 Whitelist

Authorization decisions are produced exclusively by policy evaluation.