When an AI for Thai specialist service returns a result, thcode seals that result into an immutableDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/Temicide/thcode/llms.txt
Use this file to discover all available pages before exploring further.
SpecialistEvidence envelope and stores it in an EvidenceRepository. The next time the same operation is requested with the same inputs, the cached evidence is returned directly — no outbound transfer occurs, no re-consent is required, and the original consent provenance is preserved intact inside the evidence record. This page explains each layer of the caching pipeline: how evidence is sealed, how cache identity is computed, how hits are resolved, and how entries are invalidated or expired.
The SpecialistEvidence Envelope
Every specialist invocation — success or failure — produces aSpecialistEvidence record. The record is the immutable, deep-frozen output of sealSpecialistEvidence.
id field is deterministic: the same sealed content always produces the same ev-<hex> identifier.
Completeness
'sanitized-with-omissions'. Failure outcomes are always sealed with completeness: 'failed' and fields: {}.
Sealing Evidence
sealSpecialistEvidence in evidence/seal.ts turns a SpecialistResult or SpecialistFailure into an immutable SpecialistEvidence. The function:
- Sanitizes all text and structured fields via the sanitizer (
'remote-payload'content class), tracking omissions. - Determines
completenessfrom the omission count. - Computes a deterministic
idfrom the SHA-256 of the canonical JSON of all sealed fields (excluding theiditself). - Deep-freezes the entire record, including all nested objects and arrays.
Sanitize fields
Each
SpecialistFieldValue of kind 'text' is passed through sanitizer.sanitize(value, 'remote-payload'). Structured fields are sanitized recursively — only string leaves are touched; numbers, booleans, and nulls pass through unchanged.Determine completeness
If any omissions were recorded,
completeness is set to 'sanitized-with-omissions'. For failures, it is always 'failed'.Compute deterministic id
canonicalJson serializes all fields in sorted-key order. The SHA-256 of the canonical JSON produces the ev-<hex> id. Identical sealed content always produces the same id.Failure evidence requires explicit
serviceIdentity and consentReference inputs — they are never synthesized from the failure outcome itself. Passing either as undefined throws immediately rather than producing an incomplete sealed record.Thai Text and UTF-8 Preservation
Text fields are passed to the sanitizer as UTF-8 strings. The sanitizer operates on the decoded string layer; it never re-encodes to ASCII or strips non-ASCII characters. Structured fields preserve their original object shape, with only string leaves sanitized. This means Thai text in'text' and 'structured' fields flows through every sealing, storage, and retrieval step without modification, provided the sanitizer does not redact it as a credential or unsafe active content.
The SpecialistAdapterResult Contract
SpecialistResult is the result that gets sealed into evidence. The adapter produces it; the sealer consumes it:
SpecialistFieldValue is a discriminated union that explicitly represents absent fields rather than omitting them:
The EvidenceRepository
EvidenceRepository is the storage port. The current implementation is InMemoryEvidenceRepository:
store is idempotent — storing the same id overwrites the record with an identical frozen copy. All accessors return the same frozen record. Durable persistence across sessions is a later epic; this port allows it to be swapped in without changing any caller.
Cache Identity: CacheManifest
Each specialist invocation is uniquely identified by aCacheManifest. The manifest binds every input field that could change the service’s response into a single SHA-256 digest:
buildCacheManifest in evidence/cacheManifest.ts computes the digest using computeCacheManifestDigest. Hashing uses a fixed field order with null-byte separators between fields, and semanticInputs entries are hashed in their declared order (order matters for multi-artifact calls). Any change to any field — a different endpoint, a rotated credential revision, a changed contract version, a different content hash — produces a completely different digest and therefore a cache miss.
cacheManifestMatches recomputes the candidate digest and compares — no partial matches, no fuzzy equality.
The CacheIndex
CacheIndex is an in-memory index mapping cacheManifestDigest → CacheIndexEntry. It is the lookup layer between the manifest digest and the stored evidence:
credentialRevision is the opaque revision string — it identifies the credential version without exposing its value.
The CacheIndex exposes six operations:
| Method | Description |
|---|---|
record(digest, evidenceId, opts) | Add or overwrite an entry. Used after a live invocation produces new evidence. |
lookup(digest) | Find a valid entry by digest. Returns typed miss/expired/invalidated causes. |
markExpired(now) | Sweep entries whose expiresAt < now, marking them 'expired'. Does not delete. |
invalidate(scope) | Mark matching entries 'invalidated' by scope. Returns affected digests. |
invalidateDigest(digest) | Mark one specific entry invalidated. Used for corrupt-evidence recovery. |
list() | Return a read-only snapshot of all entries regardless of state. |
Cache Lookup Resolution
resolveCacheHit in evidence/cacheLookup.ts encodes the full gating order for every specialist invocation:
Force-fresh bypass (if requested)
If
forceFresh: true, the cache is bypassed entirely. The prior evidence is preserved — the index entry is not deleted. An 'available' health state is required before proceeding to live dispatch; if the service is not available, the result is cause: 'unavailable'.Retention sweep
Before looking up,
index.markExpired(now) runs to transition any TTL-expired entries to 'expired'. This sweep runs regardless of what the lookup finds.Digest lookup
The cache manifest digest is looked up in the index. A
'miss' or 'invalidated' result proceeds to health gating and live adapter dispatch. An 'expired' result returns cause: 'expired' immediately.Evidence load
On a valid index hit, the evidence record is loaded from the
EvidenceRepository. A 'not-found' result (orphaned index entry) is treated as a miss. A 'corrupt' result marks the index entry invalidated via invalidateDigest and returns cause: 'corrupt'.Cache Behavior Options
force-fresh
Bypasses the cache entirely for a live service call. Prior evidence is preserved in the index. Requires
'available' health before any transfer.retain (no TTL)
A
RetentionPolicy of { kind: 'none' } means the entry never expires. It can only be removed via explicit invalidation.TTL expiry
A
RetentionPolicy of { kind: 'ttl', ttlMs: number } sets an expiresAt on the index entry. Expired entries are marked during the retention sweep, never deleted.Evidence Retention
evaluateRetention in evidence/retention.ts evaluates a single cache index entry against the current time:
applyRetention is a convenience wrapper that calls index.markExpired(now) to sweep all entries. Entries that expire are transitioned to 'expired' state — evidence records are never deleted in this implementation (deletion is a later epic). Expired entries remain in the index in 'expired' state and can be observed via index.list().
Evidence Invalidation
invalidateCache in evidence/invalidation.ts marks matching entries as 'invalidated' via a CacheInvalidationScope:
serviceId does not touch evidence for other services. Invalidating by sourceContentHash invalidates only entries whose bound source content changed — unrelated entries for the same service with different source files are untouched.
InvalidationReceipt reports the scope, the number of affected entries, and their digests:
Source artifact changed
Source artifact changed
Use
{ kind: 'sourceContentHash', hash: previousHash }. Only evidence entries bound to the old content hash are invalidated. Evidence for other files is untouched.Contract version updated
Contract version updated
Use
{ kind: 'contractVersion', version: previousVersion }. Evidence from the old adapter contract version is invalidated. Evidence from other services or versions is preserved.Credential rotated
Credential rotated
Use
{ kind: 'credentialRevision', revision: previousRevision }. Evidence bound to the old credential revision is invalidated. This aligns with isCredentialAuthorityStale in the consent pipeline, which also detects stale credentials.Effective configuration changed
Effective configuration changed
Use
{ kind: 'effectiveConfigurationId', id: previousGenerationId }. Invalidates all evidence from the previous configuration generation for all services.Corrupt evidence record
Corrupt evidence record
resolveCacheHit automatically calls index.invalidateDigest(digest) when repo.load returns cause: 'corrupt'. This per-digest invalidation follows the smallest proven scope (AD-18) — only the corrupt entry is dropped; no other entries are affected.Caching and Consent Interaction
A cache hit does not require re-consent. TheConsentReference stored inside the SpecialistEvidence record is the provenance of the original consent that authorized the live invocation. When the cached evidence is returned as reuseState: 'reused', the consent reference from that original invocation is carried forward intact:
'fresh'. The reuseState projection ('reused') is applied at the call site without modifying the stored record.