All writing

The model should generate content, not identity

Keep names, identifiers, ownership, and authorization outside model output so generated content cannot cross entity boundaries.

A model can write a useful explanation while attaching it to the wrong name, record, or account. That failure becomes possible when the response schema asks the model to reproduce identity alongside generated content.

Identity already exists in an authoritative system. Pass it through deterministic code and ask the model only for fields that genuinely require generation. This reduces both hallucination risk and the chance that one entity’s content is assigned to another.

Remove identity from the generated schema

This section defines a model response that cannot select its owner. The caller holds the authoritative identifiers and joins them to validated content after inference.

The trust boundary becomes clear when generated and authoritative fields use different types:

export type NarrativeInput = {
  subjectId: string;
  displayName: string;
  facts: Array<{ key: string; value: string | number }>;
};

export type GeneratedNarrative = {
  headline: string;
  explanation: string;
  evidenceKeys: string[];
};

export type StoredNarrative = GeneratedNarrative & {
  subjectId: string;
  displayName: string;
  generatedAt: string;
};

GeneratedNarrative contains no identifier, display name, email, tenant, or ownership field. Even if a model mentions a name inside its prose, it cannot redirect the database write because the storage key never comes from the generated object.

The display name remains part of the input only when the wording genuinely needs it. If it is decorative, omit it from the prompt as well and add it later in the interface.

Bind content after validation

This section parses a bounded response, verifies evidence references, and injects identity from the caller. Keep that join in one reviewed boundary so the transition from probabilistic content to authoritative storage is easy to inspect.

The generated schema should be strict: bounded headline and explanation, known evidence references, and no extra fields. Strict parsing rejects an identifier the model returns despite the prompt. That turns unexpected output into a visible contract error rather than silently accepting an identity claim the application never requested.

After validation, the application adds the subject identifier, display metadata, ownership context, and generation time from trusted state. The storage operation uses that authoritative identifier regardless of anything mentioned inside the generated prose.

Keep batches as isolated jobs

This section avoids another identity hazard: asking for generated content for many entities in one response and matching results by array position. A missing or reordered item can shift every later result.

Prefer one isolated generation unit per authoritative input, even when several units run concurrently. Each result then closes over its own trusted identity and no model response has to preserve the position of a multi-entity array.

If batching is required by an inference provider, create opaque per-request correlation tokens in code and validate a one-to-one match before joining. Those tokens should be temporary and should not become authorization or storage identifiers.

Test for isolation explicitly

This section verifies that malicious or malformed output cannot replace identity. The important assertion is not whether the generated sentence sounds good; it is whether the stored record still belongs to the caller’s subject.

Return an unexpected identifier from a fake model and require strict validation to reject it. Mention a different name inside generated prose and prove that it cannot alter the storage key. Reorder and omit results in a simulated batch and verify that no content crosses entity boundaries.

Add authorization tests on both sides of inference. Access can change while a background generation job is running, so permission to read the input does not automatically grant permission to write or serve the result later.

Authorization must still be checked before loading the input and again before writing the result. Removing identity from model output does not replace access control; it prevents generative output from becoming part of that control plane.

Models should author the fields that need language or interpretation. Identity, ownership, routing, and authorization belong to trusted application state, joined only after generated content passes validation.