C Stable API
Errors
Interpret stable C status values and public diagnostics fail-closed.The C facade returns maelys_datalog_status_t from its public calls. Use
these status names from <maelys/datalog.h> when handling a failure. A diagnostic can add
source context; it does not turn a failed operation into a result.
Types
Defined on this page
| Type | Purpose |
|---|---|
maelys_datalog_status_t | Machine-readable outcome of a public call. |
maelys_datalog_diagnostic_t | Optional source location, reason and typed details for a failed call. |
Functions
| Function | Purpose |
|---|---|
maelys_datalog_status_name() | Print a public status for diagnostics. |
maelys_datalog_diagnostic_initializer() | Make a correctly initialized diagnostic value. |
maelys_datalog_diagnostic_init() | Initialize caller-owned diagnostic storage. |
maelys_datalog_diagnostic_clear() | Reuse a diagnostic after a call. |
maelys_datalog_diag_code_name() | Print a typed diagnostic reason. |
Status type
typedef enum {
MAELYS_DATALOG_STATUS_OK = 0,
MAELYS_DATALOG_STATUS_INVALID_ARGUMENT = -1,
MAELYS_DATALOG_STATUS_INVALID_FIELD = -2,
MAELYS_DATALOG_STATUS_NOT_FOUND = -3,
MAELYS_DATALOG_STATUS_NOT_IMPLEMENTED = -4,
MAELYS_DATALOG_STATUS_UNSUPPORTED = -5,
MAELYS_DATALOG_STATUS_TIMEOUT = -6,
MAELYS_DATALOG_STATUS_IO = -7,
MAELYS_DATALOG_STATUS_INTERNAL = -8,
MAELYS_DATALOG_STATUS_UNAUTHORIZED = -9,
MAELYS_DATALOG_STATUS_FORBIDDEN = -10,
MAELYS_DATALOG_STATUS_RATE_LIMITED = -11,
MAELYS_DATALOG_STATUS_PAYLOAD_TOO_LARGE = -12,
MAELYS_DATALOG_STATUS_INVALID_STATE = -13,
MAELYS_DATALOG_STATUS_STORAGE_TOO_SMALL = -14
} maelys_datalog_status_t;Public diagnostics
Ask for a diagnostic when a loading, input or solve failure needs more detail than its status. Check the present mask before reading an optional section.
typedef struct {
size_t struct_size;
uint32_t abi_version;
maelys_datalog_diagnostic_source_t source;
maelys_datalog_status_t status;
maelys_datalog_diag_code_t code;
uint64_t present;
size_t line, column;
char phase[32], message[256], hint[256];
char file[256], predicate[96];
size_t arity, observed_count, limit, depth, depth_limit, rule_id;
unsigned comparison_result, expected_kind, lhs_kind, rhs_kind, comparison_op;
maelys_datalog_limit_t limit_kind; /* 0 when the producer cannot identify the budget. */
size_t term_index, expected_arity, observed_arity;
char token[96], field[96], domain[96];
} maelys_datalog_diagnostic_t;The caller owns this record. Initialize it before passing it to a loader, an
input insertion or a solve. Diagnostic ABI 1 requires the complete, naturally
aligned object: use sizeof(maelys_datalog_diagnostic_t), not a hard-coded byte
count. It measures 1328 bytes on the verified macOS arm64 build, but its size
is a property of the installed header and target ABI.
Public status values
const char *
maelys_datalog_status_name(
maelys_datalog_status_t status
);const char *Returns a readable status name for diagnostics; do not infer success from the text alone.
const char *name = maelys_datalog_status_name(status);All values below belong to maelys_datalog_status_t in the installed
<maelys/datalog.h> header. The table abbreviates the common
MAELYS_DATALOG_STATUS_ prefix. A particular operation may return only a
subset; its own contract remains the authority for that call.
| Suffix | Value | Meaning |
|---|---|---|
OK | 0 | Operation succeeded; for a query, inspect out_present separately. |
INVALID_ARGUMENT | -1 | Required argument or call shape is invalid. |
INVALID_FIELD | -2 | Input content violates a field or policy constraint. |
NOT_FOUND | -3 | A required item, policy, or query symbol is absent. |
NOT_IMPLEMENTED | -4 | The requested operation is recognized but not implemented. |
UNSUPPORTED | -5 | A capability, backend feature, or limit key is unavailable. |
TIMEOUT | -6 | A bounded operation exceeded its allowance. |
IO | -7 | File or other I/O failed. |
INTERNAL | -8 | The engine encountered an internal failure. |
UNAUTHORIZED | -9 | The caller is not authorized for an operation that requires it. |
FORBIDDEN | -10 | A guarded action was refused, for example loading an enabled test-only policy without permission. |
RATE_LIMITED | -11 | A provider or bounded service rejected an operation due to rate limiting. |
PAYLOAD_TOO_LARGE | -12 | A bound was exceeded or an explanation output-text buffer is too short; inspect the specific call's contract and required-length output. |
INVALID_STATE | -13 | The object's current lifetime or lease does not permit the operation. |
STORAGE_TOO_SMALL | -14 | Caller-supplied explanation workspace cannot hold the preparation. |
maelys_datalog_status_name() returns the name for a status. Do not parse a
human diagnostic message to determine the status, and do not treat any
non-OK value as a negative membership result.
Example — document access
The example returns two different kinds of “no”: a failed API call and a
successful query in which allow("mallory","roadmap.pdf") is absent.
Neither authorizes access.
int present = 0;
maelys_datalog_status_t status = maelys_datalog_result_query(
result, "allow", mallory_query, 2u, &present);
if (status != MAELYS_DATALOG_STATUS_OK) {
fprintf(stderr, "query failed: %s\n", maelys_datalog_status_name(status));
return DENY;
}
return present ? ALLOW : DENY;Here mallory_query is the two-symbol array on
Querying; ALLOW
and DENY are application decisions, not engine status values. A
load or solve failure is handled before this code can run.
Diagnostic functions
maelys_datalog_diagnostic_t
maelys_datalog_diagnostic_initializer(
void
);maelys_datalog_diagnostic_tReturns a zeroed diagnostic with struct_size and abi_version set for diagnostic ABI 1. MAELYS_DATALOG_DIAGNOSTIC_INIT is the equivalent initializer macro.
maelys_datalog_status_t
maelys_datalog_diagnostic_init(
void * storage,
size_t storage_bytes
);maelys_datalog_status_tInitializes the known ABI 1 object. Rejects storage that is too small before writing a diagnostic payload.
maelys_datalog_status_t
maelys_datalog_diagnostic_clear(
maelys_datalog_diagnostic_t * diagnostic
);maelys_datalog_status_tResets the known fields while preserving struct_size and abi_version. This is not secure erasure.
When a diagnostic contains a typed reason code, turn it into a stable textual name for logs. Do not parse the human message to decide control flow.
const char *
maelys_datalog_diag_code_name(
maelys_datalog_diag_code_t
);const char *Returns a stable reason name suitable for diagnostics; the status remains the call outcome.
For example:
maelys_datalog_diagnostic_t diagnostic =
maelys_datalog_diagnostic_initializer();
maelys_datalog_status_t rc =
maelys_datalog_session_solve_edb(session, edb, &result, &diagnostic);
if (rc != MAELYS_DATALOG_STATUS_OK) {
fprintf(stderr, "%s: %s\n",
maelys_datalog_status_name(rc),
maelys_datalog_diag_code_name(diagnostic.code));
}{0} alone is not a valid diagnostic initializer in 0.10.0: it leaves
struct_size and abi_version unset. Alternatively, call
maelys_datalog_diagnostic_init(&diagnostic, sizeof diagnostic) on aligned
storage and check its return status. Use diagnostic_clear(&diagnostic) only
after initialization when reusing the same object.
The function return value remains the authority. source == NONE means no
detail was supplied, even if a diagnostic object was passed. Otherwise
status records the associated failure and code names the precise cause.
message and hint are bounded human text; do not parse them as an error
protocol or serialize the entire struct. Clearing leaves text bytes after the
first NUL unspecified.
Read only the sections present
present is a bitmask, not a single choice. For example, a capacity
diagnostic may also identify a predicate. Test each bit before reading its
fields:
| Presence bit | Relevant fields |
|---|---|
LOCATION | file, line, column |
PREDICATE | predicate, arity |
CAPACITY | observed_count, limit, limit_kind |
DEPTH | depth, depth_limit |
COMPARISON | comparison_result, kind fields, comparison_op |
ARITY | expected_arity, observed_arity, term_index |
RULE | rule_id |
CONTEXT | token, field, domain |
AGGREGATE | field, token, lhs_kind, term_index, limit |
These bit names carry the MAELYS_DATALOG_DIAGNOSTIC_ prefix. Unknown future
bits must be ignored; fields from absent sections must not be interpreted.
term_index is a zero-based source position when its section supplies one,
not a value to recover from the message.
Aggregate rejection in 0.10.0
The two new maelys_datalog_diag_code_t values have stable names:
| Code | maelys_datalog_diag_code_name() | Meaning |
|---|---|---|
MAELYS_DATALOG_DIAG_SOLVE_AGGREGATE_DOMAIN_ERROR | solve_aggregate_domain_error | A projected value for min, max or sum is not an integer in the accepted range 0–2147483647. |
MAELYS_DATALOG_DIAG_SOLVE_SUM_OVERFLOW | solve_sum_overflow | The first partial sum exceeds 2147483647. |
Both return INVALID_FIELD and publish no partial result. The
AGGREGATE, PREDICATE and CONTEXT sections identify the source relation
and value. In AGGREGATE, field names min, max or sum; token
contains the offending value (or the first overflowing partial sum);
term_index is the zero-based projection argument; and limit is the
inclusive numeric bound 2147483647. This is not a storage-capacity error:
the CAPACITY bit and limit_get selectors describe a different kind of
limit.
The 0.9.1 low-level diagnostic catalog is retained for historical integrations. New code uses this versioned public diagnostic protocol, not the 0.9.1 layout.
Errors and fail-closed behavior
Most operations return maelys_datalog_status_t; name and initializer helpers return their documented values. Convert a returned status to a stable name
with maelys_datalog_status_name(). Loading and solving can additionally fill
maelys_datalog_diagnostic_t with a source, code, location, phase,
message, and hint.