Skip to content

Evaluate Policy from Source

Compile and evaluate a CNL (Controlled Natural Language) policy source string on the fly, without requiring the policy to be deployed first. Optionally returns a full decision trace for debugging.

Endpoint

POST /api/v1/policies/evaluate-source

Required Role

MEMBER

Query Parameters

ParameterTypeDefaultDescription
tracebooleanfalseWhen true, the response includes a structured decisionTrace object showing which rules fired and how the result was derived.

Headers

HeaderValueRequired
AuthorizationBearer <token>Yes
Content-Typeapplication/jsonYes
X-Tenant-IDTenant identifier stringYes

Request Body

json
{
  "source": "string",
  "context": {},
  "locale": "en-US",
  "functionName": "evaluate"
}
FieldTypeRequiredDescription
sourcestringYesRaw CNL policy source text. The engine parses, canonicalizes, and compiles this string before evaluation. Parsing errors are returned in the error field.
contextobjectYesA single context object whose keys map to the declared parameter names of the target function. For multi-parameter functions, wrap each argument under its declared parameter name.
localestringNoBCP 47 locale tag that identifies the CNL keyword set used in source. Defaults to "en-US". Use "zh-CN" for Simplified Chinese CNL syntax.
functionNamestringNoName of the function to invoke within the compiled module. Defaults to "evaluate". If the source defines only one function, that function is called regardless of this value.

Response Body

json
{
  "result": "<any>",
  "executionTimeMs": 0,
  "error": null,
  "decisionTrace": null
}
FieldTypeDescription
resultanyThe value returned by the evaluated function.
executionTimeMsnumberTotal wall-clock time in milliseconds including compilation and execution.
errorstring | nullParse, compile, or runtime error message; null on success.
decisionTraceobject | nullPresent only when ?trace=true is set. Contains an ordered list of rule nodes, each recording whether the rule condition matched and its contribution to the final result. null when tracing is disabled.

Decision Trace Structure

When ?trace=true is used, decisionTrace has the following shape:

json
{
  "functionName": "string",
  "steps": [
    {
      "ruleIndex": 0,
      "condition": "string",
      "conditionMet": true,
      "returnValue": "<any>",
      "notes": "string"
    }
  ],
  "finalResult": "<any>"
}

HTTP Status Codes

StatusMeaning
200 OKCompilation and evaluation attempted. Check error for compile-time or runtime failures.
400 Bad RequestMalformed request body or missing required fields.
401 UnauthorizedMissing or invalid bearer token.
403 ForbiddenToken is valid but the caller lacks the MEMBER role.
500 Internal Server ErrorUnexpected engine failure.

Examples

Without Trace

bash
curl -X POST "https://policy.aster-lang.dev/api/v1/policies/evaluate-source?trace=false" \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -H "X-Tenant-ID: acme-corp" \
  -d '{
    "source": "Module Discount.\nRule calculate given order:\n  If order.total > 100 return 10\n  return 0",
    "context": { "order": { "total": 150 } },
    "locale": "en-US",
    "functionName": "calculate"
  }'
js
const response = await fetch(
  'https://policy.aster-lang.dev/api/v1/policies/evaluate-source?trace=false',
  {
    method: 'POST',
    headers: {
      Authorization: 'Bearer <token>',
      'Content-Type': 'application/json',
      'X-Tenant-ID': 'acme-corp',
    },
    body: JSON.stringify({
      source:
        'Module Discount.\nRule calculate given order:\n  If order.total > 100 return 10\n  return 0',
      context: { order: { total: 150 } },
      locale: 'en-US',
      functionName: 'calculate',
    }),
  }
);

const data = await response.json();

With Decision Trace

bash
curl -X POST "https://policy.aster-lang.dev/api/v1/policies/evaluate-source?trace=true" \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -H "X-Tenant-ID: acme-corp" \
  -d '{
    "source": "Module Discount.\nRule calculate given order:\n  If order.total > 100 return 10\n  return 0",
    "context": { "order": { "total": 150 } },
    "locale": "en-US",
    "functionName": "calculate"
  }'
js
const response = await fetch(
  'https://policy.aster-lang.dev/api/v1/policies/evaluate-source?trace=true',
  {
    method: 'POST',
    headers: {
      Authorization: 'Bearer <token>',
      'Content-Type': 'application/json',
      'X-Tenant-ID': 'acme-corp',
    },
    body: JSON.stringify({
      source:
        'Module Discount.\nRule calculate given order:\n  If order.total > 100 return 10\n  return 0',
      context: { order: { total: 150 } },
      locale: 'en-US',
      functionName: 'calculate',
    }),
  }
);

const data = await response.json();
// data.decisionTrace.steps → array of rule evaluation steps

Example Response (trace=true)

json
{
  "result": 10,
  "executionTimeMs": 12,
  "error": null,
  "decisionTrace": {
    "functionName": "calculate",
    "steps": [
      {
        "ruleIndex": 0,
        "condition": "order.total > 100",
        "conditionMet": true,
        "returnValue": 10,
        "notes": "Rule matched — early return"
      }
    ],
    "finalResult": 10
  }
}

Released under the MIT License.