Skip to content
OnticBeta
RFC-0004

Prompt Derivation

canonical

RFC-0004: Prompt Derivation

Purpose

Define how the Canonical Ontology and Oracle configurations are transformed into LLM-executable instructions. This RFC bridges the structural definitions (RFC-0001) with the runtime behavior, ensuring prompts are mechanically derived rather than manually authored.

Problem Statement

The CAA architecture defines:

  • Ontology (RFC-0001): What state must be known
  • Oracle (RFC-0002): How to verify claims
  • Envelope (RFC-0009): What outputs look like

But it does not define:

  • How ontology schemas become system prompts
  • How oracle requirements become extraction instructions
  • How to ensure prompt fidelity to ontology definitions

Manual prompt authoring introduces drift risk: the prompt may diverge from the ontology it claims to implement.

Core Principle

Prompts are compiled, not authored.

The system prompt for any ontology-governed interaction MUST be mechanically derivable from:

  1. The Canonical Ontology Object
  2. The Oracle configuration
  3. The enforcement mode (RFC-0002)

Human-authored prompt text is permitted only for:

  • Domain-specific phrasing (synonyms, terminology)
  • User-facing tone and style
  • Localization

Human-authored text MUST NOT alter the semantic requirements defined by the ontology.


Prompt Components

A complete prompt derivation produces three components:

interface DerivedPrompt {
  system_prompt: string; // LLM system/instruction prompt
  tool_schema: ToolDefinition; // Structured output schema
  extraction_prompt: string; // User input parsing instructions
}

Component 1: System Prompt Derivation

The system prompt is derived from the ontology's state_axes and authority_requirements.

1.1 State Axis Rendering

Each StateAxis in the ontology becomes a classification instruction:

function renderStateAxis(axis: StateAxis): string {
  switch (axis.type) {
    case "enum":
      return `${axis.key}: Must be one of: ${axis.allowed_values.join(", ")}`;
    case "range":
      return `${axis.key}: Numeric value between ${axis.range.min} and ${axis.range.max}`;
    case "boolean":
      return `${axis.key}: true or false`;
    case "validated_free":
      return `${axis.key}: Text matching pattern ${axis.validator_ref}`;
    case "identifier":
      return `${axis.key}: Unique identifier string`;
    case "timestamp":
      return `${axis.key}: ISO 8601 timestamp`;
    case "composite":
      return `${axis.key}: Compound value with components: ${axis.component_axes.join(", ")}`;
    case "temporal_series":
      return `${axis.key}: Time-series data (${axis.temporal_config.aggregation} over ${axis.temporal_config.time_unit})`;
  }
}

1.2 Required State Rendering

The required_state logic becomes explicit instructions:

function renderRequiredState(logic: RequiredStateLogic): string {
  const always = `Required in all cases: ${logic.always.join(", ")}`;

  const conditional = logic.conditional
    ?.map(
      (c) => `If ${renderCondition(c.if)}, also required: ${c.then.join(", ")}`,
    )
    .join("\n");

  return [always, conditional].filter(Boolean).join("\n\n");
}

1.3 Authority Constraint Rendering

The authority_requirements become behavioral constraints:

function renderAuthorityConstraints(req: AuthorityRequirements): string {
  const lines: string[] = [];

  if (req.oracle_required) {
    lines.push("All values must be verifiable against external sources.");
    lines.push(`Acceptable verification: ${req.acceptable_oracles.join(", ")}`);
  }

  if (req.verification_method === "inline") {
    lines.push("Verification must complete before output.");
  } else if (req.verification_method === "async") {
    lines.push("Output may be provisional pending verification.");
  }

  return lines.join("\n");
}

1.4 Complete System Prompt Template

function deriveSystemPrompt(ontology: OntologyObject): string {
  return `You are classifying a ${ontology.label} in the ${ontology.domain} domain.

## Classification Dimensions

${ontology.state_axes.map(renderStateAxis).join("\n")}

## Required Information

${renderRequiredState(ontology.required_state)}

## Constraints

${renderAuthorityConstraints(ontology.authority_requirements)}

## Output Rules

- Provide values ONLY for dimensions listed above
- If information is missing, indicate which dimension is incomplete
- Do not infer values not present in the source material
- ${
    ontology.sensitivity === "state-sensitive"
      ? "Small changes in state may significantly change the classification"
      : "Classification is stable across minor state variations"
  }`;
}

Component 2: Tool Schema Derivation

The tool schema (for structured output) is mechanically derived from state axes:

function deriveToolSchema(ontology: OntologyObject): ToolDefinition {
  const properties: Record<string, JSONSchema> = {};
  const required: string[] = [...ontology.required_state.always];

  for (const axis of ontology.state_axes) {
    properties[axis.key] = axisToJSONSchema(axis);
  }

  // Add reasoning/signals fields for transparency
  properties.signals = {
    type: "array",
    items: { type: "string" },
    maxItems: 5,
    description: "Key observations that informed this classification"
  };

  properties.reasoning = {
    type: "string",
    description: "Brief explanation of the classification"
  };

  return {
    type: "function",
    function: {
      name: `classify_${ontology.canonical_id.replace(/\//g, "_")}`,
      description: `Classify a ${ontology.label} for ${ontology.domain} domain governance`,
      parameters: {
        type: "object",
        properties,
        required: [...required, "signals", "reasoning"]
      }
    }
  };
}

function axisToJSONSchema(axis: StateAxis): JSONSchema {
  switch (axis.type) {
    case "enum":
      return { type: "string", enum: axis.allowed_values };
    case "range":
      return { type: "number", minimum: axis.range.min, maximum: axis.range.max };
    case "boolean":
      return { type: "boolean" };
    case "validated_free":
      return { type: "string", pattern: axis.validator_ref };
    case "identifier":
      return { type: "string" };
    case "timestamp":
      return { type: "string", format: "date-time" };
    case "composite":
      // Recursively build from component axes
      return { type: "object", properties: /* ... */ };
    case "temporal_series":
      return { type: "array", items: { type: "object" } };
  }
}

Component 3: Extraction Prompt Derivation

The extraction prompt (for parsing user input into state) combines ontology requirements with quote binding (RFC-0004):

function deriveExtractionPrompt(ontology: OntologyObject): string {
  const axes = ontology.state_axes.map((a) => a.key).join(", ");

  return `Extract the following state dimensions from the user's input: ${axes}

## Extraction Rules

1. Every extracted value MUST appear literally in the source text
2. Record the exact quote and character positions for each value
3. If a value is implied but not stated, mark as REQUIRES_CONFIRMATION
4. If a value cannot be determined, mark as REQUIRES_SPECIFICATION
5. Do not infer numeric values from qualitative descriptions

## Required Format

For each dimension, provide:
- value: The extracted value (must match source exactly for literals)
- quote: The exact text that contains this value
- span: [start, end] character positions in source
- source: "explicit" | "inferred_needs_confirmation" | "missing"`;
}

Opacity Preservation

Per RFC-0007, the derived prompt MUST NOT expose:

  • Threshold values for authorization decisions
  • Oracle trust tier weightings
  • Specific blocking conditions
  • Recovery paths that could be gamed

The prompt instructs the model on what to classify, not how classification affects authorization.

// FORBIDDEN: Exposing authority logic in prompt
"If consequence >= 2 AND audit < 1, the system will block the request";

// PERMITTED: Classification instructions only
"Classify the consequence level as 0, 1, or 2 based on potential harm";

Validation

A derived prompt is valid if and only if:

  1. Completeness: Every state_axis appears in the system prompt
  2. Fidelity: Enum values in tool schema match allowed_values exactly
  3. Required Coverage: All required_state.always axes are marked required in tool schema
  4. Opacity: No authorization thresholds or decision logic appear in prompt text
function validateDerivedPrompt(
  prompt: DerivedPrompt,
  ontology: OntologyObject,
): ValidationResult {
  const errors: string[] = [];

  // Check all axes present
  for (const axis of ontology.state_axes) {
    if (!prompt.system_prompt.includes(axis.key)) {
      errors.push(`Missing axis in system prompt: ${axis.key}`);
    }
    if (!(axis.key in prompt.tool_schema.function.parameters.properties)) {
      errors.push(`Missing axis in tool schema: ${axis.key}`);
    }
  }

  // Check enum fidelity
  for (const axis of ontology.state_axes.filter((a) => a.type === "enum")) {
    const schemaEnum =
      prompt.tool_schema.function.parameters.properties[axis.key].enum;
    if (!arraysEqual(schemaEnum, axis.allowed_values)) {
      errors.push(`Enum mismatch for ${axis.key}`);
    }
  }

  // Check opacity
  if (prompt.system_prompt.match(/\b(threshold|block|deny|authorize)\b/i)) {
    errors.push("Potential opacity violation: authority keywords in prompt");
  }

  return { valid: errors.length === 0, errors };
}

Example: Risk Wizard Ontology

Ontology Definition:

const riskAssessmentOntology: OntologyObject = {
  canonical_id: "governance/risk_assessment",
  label: "Business Risk Profile",
  domain: "governance",
  identity_family: "organization",
  sensitivity: "state-sensitive",

  state_axes: [
    {
      key: "industry",
      type: "enum",
      allowed_values: ["healthcare", "finance", "legal", "smb"],
    },
    { key: "consequence", type: "enum", allowed_values: ["0", "1", "2"] },
    { key: "audit", type: "enum", allowed_values: ["0", "1", "2"] },
    { key: "exposure", type: "enum", allowed_values: ["0", "1", "2"] },
  ],

  required_state: { always: ["industry", "consequence", "audit", "exposure"] },

  authority_requirements: {
    oracle_required: false, // Self-assessment, not oracle-verified
    acceptable_oracles: [],
    verification_method: "none",
    human_lock_allowed: true,
  },
};

Derived System Prompt:

You are classifying a Business Risk Profile in the governance domain.

## Classification Dimensions

industry: Must be one of: healthcare, finance, legal, smb
consequence: Must be one of: 0, 1, 2
audit: Must be one of: 0, 1, 2
exposure: Must be one of: 0, 1, 2

## Required Information

Required in all cases: industry, consequence, audit, exposure

## Constraints

Classification is based on provided information only.

## Output Rules

- Provide values ONLY for dimensions listed above
- If information is missing, indicate which dimension is incomplete
- Do not infer values not present in the source material
- Small changes in state may significantly change the classification

Derived Tool Schema:

{
  "type": "function",
  "function": {
    "name": "classify_governance_risk_assessment",
    "description": "Classify a Business Risk Profile for governance domain governance",
    "parameters": {
      "type": "object",
      "properties": {
        "industry": {
          "type": "string",
          "enum": ["healthcare", "finance", "legal", "smb"]
        },
        "consequence": { "type": "string", "enum": ["0", "1", "2"] },
        "audit": { "type": "string", "enum": ["0", "1", "2"] },
        "exposure": { "type": "string", "enum": ["0", "1", "2"] },
        "signals": {
          "type": "array",
          "items": { "type": "string" },
          "maxItems": 5
        },
        "reasoning": { "type": "string" }
      },
      "required": [
        "industry",
        "consequence",
        "audit",
        "exposure",
        "signals",
        "reasoning"
      ]
    }
  }
}

Relationship to Other RFCs

RFCRelationship
RFC-0001Source: Ontology schema is input to derivation
RFC-0002Source: Oracle config determines verification instructions
RFC-0007Constraint: Derived prompts must preserve opacity
RFC-0004Output: Extraction prompt implements quote binding

Implementation Notes

  1. Caching: Derived prompts may be cached per ontology version
  2. Hot Reload: Ontology changes should trigger prompt re-derivation
  3. Audit: Store both ontology version and derived prompt hash in telemetry
  4. Testing: Validate derived prompts against ontology on every build