A model endpoint can be healthy while the feature around it is broken.

A valid model response says nothing about whether the application used authorized data, checked current business facts, or completed a requested state change.

The model does not own most of the feature’s contract. Application code must enforce account scope, choose the right systems of record, validate hard constraints, and report whether state changes succeeded.

A dependency register adds behavioral contracts to the interactions shown in an architecture diagram.

Start with enforceable properties

“Recommend a suitable guitar from our current catalog” is a useful product promise, but it is not precise enough for an operational contract.

Translate it into properties the application can enforce:

  • Every recommended product ID resolves against the accepted catalog version used for the request.
  • Every displayed price comes from the designated pricing source and is no older than the allowed maximum when the response is produced.
  • The feature says “in stock” only when the inventory observation is recent enough for that claim.
  • Every customer record matches the authenticated account scope before the application uses it.
  • The response reports a successful save only after the shortlist write is confirmed.

Not every part of the product promise becomes a runtime invariant. Product existence, account scope, freshness, and save outcomes can be enforced deterministically. Whether a recommendation is genuinely useful or subjectively suitable remains an evaluation problem. It needs quality criteria, representative test cases, and feedback; the application cannot generally prove subjective suitability for each request.

Freshness limits and time budgets belong to the product and its service objectives. Name them, assign an owner, and enforce them.

For the guitar assistant, the request path might look like this:

authenticated shopper
    -> resolve account scope
    -> authorize profile access
    -> read preferences and optional purchase history when enabled
    -> resolve the accepted catalog version
    -> verify that the version is still acceptable
    -> read product records and specifications
    -> read current price observations
    -> read inventory observations when availability matters
    -> resolve prompt, schema, route, deployment, and model versions
    -> call the model
    -> validate schema and selected product references
    -> resolve authoritative prices and availability when relevant
    -> revalidate budget and applicable availability constraints
    -> compose authoritative facts into the response
    -> write a shortlist when requested
    -> return recommendation and save outcome

observability: signals across the complete path

Catalog-version selection and request-time freshness validation are separate because they fail differently.

For exact business facts, the model can rank product IDs while application code resolves price and relevant availability from their systems of record. If the final price exceeds the budget or required availability no longer satisfies the request, reject that candidate. Use another validated candidate, make one bounded regeneration when the contract allows it, or state that the product-backed request cannot be completed.

The register applies established reliability thinking to any distributed feature. AI makes it especially useful because a successful model call can still produce an invalid result. Generated references, probabilistic quality, token and quota limits, content filters, and fallback compatibility are especially easy to miss when teams rely mainly on service diagrams.

Separate three dependency roles

Not every dependency participates in the immediate response. I separate three roles before deciding how critical an interaction is.

RolePurposeGuitar assistant example
ExecutionProduces or validates the result or a requested state changeAccount authorization, price read, model request, shortlist write
PrerequisiteCreates usable state before requests can consume itCatalog ingestion and accepted-version publication
OperationalDetects, supports, audits, or recovers the featureTelemetry export, security-event delivery, recovery scheduler

An operational dependency may not affect one response, yet remain required for audit, billing, safety, or recovery. Analytics may be best effort; required security-event delivery is not.

Classify interactions, not services

A capability rarely has one relationship to the request: catalog publication happens beforehand, version validation inline, and recovery later. Give each identifiable interaction a row with its role, condition, criticality and horizon, timing, and contract reference. Split it again at another owned boundary or operating lifecycle; keep different failure classes of one call inside its failure contract.

Timing does not imply importance. Criticality has three useful values:

  • Required: The declared capability, claim, or operational obligation cannot be fulfilled without the interaction.
  • Degradable: The system may omit or reduce the affected capability or operational behavior under an explicitly defined degraded mode. Any user-visible limitation must be made clear.
  • Best effort: Failure invalidates neither the user-visible result nor any required operational obligation, although it may reduce analytical or operational value.

Criticality describes whether the affected capability or operational obligation may be omitted under the stated condition. It never relaxes security, integrity, authorization, or correctness constraints when an interaction is attempted. “Live inventory is required” is too broad. “A current inventory observation is required for this request when the response claims an item is in stock” is operationally useful.

For the guitar recommendation, an initial classification could look like this:

InteractionRoleConditionCriticality and horizonTimingContracts and details
Resolve and enforce account scopeExecutionStored customer data is readRequired for that readInlineProfile access policy
Read purchase historyExecutionOptional purchase-history personalization is enabledDegradable for this recommendationInlineProfile read · feature detail
Publish an accepted catalog versionPrerequisiteProduct-backed recommendations remain availableRequired over the freshness windowPre-requestCatalog publication
Verify accepted catalog versionExecutionProduct-backed recommendationRequired for this requestInlineCatalog acceptance
Read product record and specificationsExecutionResponse recommends a catalog productRequired for this requestInlineCatalog read
Read authoritative priceExecutionResponse displays a price or enforces a budgetRequired for that claimInlinePricing read
Read inventoryExecutionResponse makes an availability claimRequired for that claimInlineInventory read
Resolve compatible prompt and output-schema versionsExecutionModel-generated recommendationRequired for this requestInlinePrompt and schema contract
Resolve model route and versionExecutionModel-generated recommendationRequired for this requestInlineModel routing
Call the model deploymentExecutionModel-generated recommendationRequired for this requestInlineModel gateway
Validate schema and product referencesExecutionModel-generated recommendationRequired for this requestInlineOutput contract
Revalidate budget and applicable availability constraintsExecutionResponse enforces a budget or makes an availability claimRequired for that constraint or claimInlineRecommendation constraints
Attempt shortlist saveExecutionShopper asks to saveRequired for the save-success claimInlineShortlist write · feature detail
Discover eligible unresolved shortlist operationsOperationalInline attempt lease expired and operation remains non-terminalRequired over the recovery objectiveDeferredRecovery discovery
Resume or reconcile non-terminal shortlist operationExecutionEligible operation remains unresolvedRequired until terminal, when promised by the persistence contractDeferredShortlist recovery · feature detail
Export recommendation analyticsOperationalProduct analytics is enabledBest effort unless another obligation requires itDeferredAnalytics export

In a working register, the last cell links the shared contract and any feature detail. An explicit promise to use stored purchase history makes that read required unless the request supplies the same information.

Do not combine catalog, pricing, and inventory reads when they are separate calls or owned contracts. Conversely, DNS failure, throttling, content filtering, and malformed output may be separate failure classes of one model call rather than four register entries.

Stop at an owned boundary

Stop at an observable boundary with a documented owner and support contract. Internals stay outside the register unless your application interacts with them separately or they have a distinct operating lifecycle.

Expand only risky interactions

The classification table is the feature register. Expand rows that handle protected data, change state, return ambiguous outcomes, permit degradation, or need a distinct operational response. Other rows can reference a shared contract.

ArtifactOwns
Feature registerInteraction-specific condition, criticality, time horizon, and degraded user behavior
Shared capability contractAPI or schema version, owner, general retry semantics, SLO, and compatibility policy
Runbook or threat modelOperational response, escalation details, and trust-boundary analysis

Store shared facts once; feature entries contain only operation-specific behavior and overrides.

Use this expanded template only where the risk warrants it:

### <Interaction name>

- Feature register row: <link>
- Capability contract: <link and version>
- Data classification: <organization's classification>
- Freshness or completion requirement: <maximum age or completion target>
- Per-attempt and total time budget: <attempt and end-to-end allocation>
- Failure behavior: <response by material failure class>
- Retry override: <feature-specific difference>
- Degraded mode: <valid reduced behavior, or none>
- Consistency and idempotency: <read or write guarantees>
- Concurrency control: <lease claims and conditional transitions>
- Diagnostic signals: <outcome, duration, attempt, controlled identifiers>
- Escalation path: <owner or runbook>

Read authorized purchase history

- Feature register row: Execution, inline, and degradable when optional purchase-history personalization is enabled; authorization remains required
- Capability contract: Versioned profile-read contract with enforced authenticated account scope
- Data classification: Organization's protected-customer-data class
- Freshness or completion requirement: No feature-specific freshness override
- Per-attempt and total time budget: All attempts fit inside the request's profile-read allocation
- Failure behavior:
  - Unavailable or timed out: continue without purchase-history personalization
  - Authorization denied: do not read; continue only if an unpersonalized result is valid
  - Scope or cache-partition mismatch: suppress the result and start the security incident path
  - Malformed response: reject the data and record a contract failure
- Retry override: Do not retry authorization denials, scope mismatches, malformed data, or after caller cancellation
- Degraded mode: Omit personalization without claiming otherwise. Suspected cross-account exposure has no degraded mode
- Consistency and idempotency: Use account-partitioned cache keys and preserve account scope through every call
- Diagnostic signals: Outcome, duration, attempt, authorization reference, and controlled scope identifier; exclude purchase-history contents
- Escalation path: Profile runbook for availability; security incident runbook for suspected cross-account access

This distinction is easy to miss: purchase-history personalization is degradable, but correct authorization is not. Missing data can produce a valid reduced result. Data from the wrong account invalidates the entire operation and may indicate that protected data was exposed.

Attempt shortlist save

- Feature register row: Execution, inline, and required for the save-success claim when the shopper asks to save
- Capability contract: Versioned idempotent write state machine with status lookup by operation ID
- Command durability: `PendingDispatch` stores the immutable save command, or a durable reference sufficient to reconstruct and verify it, plus its fingerprint, operation ID, idempotency key, attempt lease, and `nextAttemptAt`
- Command identity: Reusing the operation ID or idempotency key with a different command fingerprint is rejected
- Data classification: Organization's applicable customer-data class
- Freshness or completion requirement: Report success only after the write is confirmed
- Per-attempt and total time budget: Write and inline lookup share the request's save allocation
- Failure behavior:
  - Confirmed success: report that the shortlist was saved
  - Confirmed rejection: return the recommendation with a separate save failure
  - Timeout or lost response: mark `OutcomeUnknown` and query while inline time remains; if still unknown, return the operation ID with an unconfirmed save status
- Retry override: After an unknown outcome, retry only with the same idempotency key when safe deduplication is guaranteed
- Degraded mode: The recommendation may still succeed, but the save result remains separate
- Consistency and idempotency: One operation ID, idempotency key, and command fingerprint identify the logical save
- Concurrency control: Dispatch requires an atomic conditional update that acquires the lease and transitions the eligible state to `Submitting` using the expected version. Terminal updates require the expected version and attempt identity so an older attempt cannot overwrite a newer result
- Diagnostic signals: Operation ID, outcome, duration, and attempt; exclude shortlist contents
- Escalation path: Persistence errors use the write runbook; the recovery scheduler discovers eligible unresolved operations

A confirmed rejection and a timeout with an unknown outcome are different states. The inline interaction ends with the response; unresolved recovery does not.

Resume or reconcile non-terminal shortlist operations

- Feature register row: Execution, deferred, and required until the operation reaches a terminal state when the persistence contract promises recovery
- Capability contract: State machine, authoritative status lookup, and idempotent retry contract for the original operation ID
- Data classification: Same class as the original save
- Freshness or completion requirement: Reach a terminal outcome within the recovery objective
- Per-attempt and total time budget: Scheduled attempts use the recovery budget, not the request budget
- Recovery eligibility: The inline attempt lease has expired and `nextAttemptAt` is due
- Concurrency control: The worker atomically acquires the lease and transitions the expected state and version before acting. Terminal updates require the active attempt identity and expected version
- Recovery behavior:
  - `PendingDispatch`: dispatch the stored command with its existing operation ID and idempotency key
  - `Submitting` or `OutcomeUnknown`: perform authoritative lookup or a safe idempotent retry of the stored command when permitted by the shared contract
  - Confirmed saved: record the terminal success
  - Confirmed rejected, or authoritatively absent after the contract's visibility window: record the terminal failure
  - Non-authoritative absence, unknown, or unavailable: reschedule within the recovery policy; escalate when its deadline is exhausted
- Retry override: Reuse the original operation ID, idempotency key, and command fingerprint; never create a new logical save
- Degraded mode: None for saving; the returned recommendation remains valid
- Consistency and idempotency: Lookup, retry, and recovery refer to one logical operation
- Result publication: Persist the terminal status so the shopper and support tooling can resolve the original operation ID
- Diagnostic signals: Operation ID, outcome class, attempt, age, and terminal result; exclude shortlist contents
- Escalation path: Exhausted recovery uses the persistence-reconciliation runbook

Recovery resolves the requested operation to a terminal outcome; it does not always complete the state change. It is deferred execution work. The discovery scheduler is operational: it scans eligible unresolved operations and exposes recovery lag. The feature’s operating or admission policy decides whether a breached recovery objective stops new saves, changes save behavior, restricts traffic, or triggers operator intervention.

Fallback routes and cross-region or cross-provider attempts also consume the same remaining budget unless the feature contract explicitly defines another execution model.

Preserve the contract when degrading

Another model is not automatically a safe fallback. It may behave differently with structured output, context limits, tools, latency, or safety controls. An older catalog version may restore access while violating the freshness limit. Skipping a failed validation step is not graceful degradation.

For a general comparison, valid degradation may omit optional purchase-history personalization or unverified availability claims. When the request explicitly requires products that are available now, return a clearly identified partial result or state that the availability-backed request cannot be completed. A recommendation may still return with a separate save failure.

The feature may return less, but it must not silently change what success means.

Use existing artifacts as inputs

The register synthesizes existing decisions. Diagrams identify interactions and trust boundaries; failure analysis supplies failure classes; SLOs supply budgets; threat models and runbooks supply controls and escalation paths.

Register entries can also inform trace design. Use stable interaction names and record duration, outcome, retry count, and controlled correlation identifiers. Do not log prompts, retrieved documents, purchase history, or tool arguments indiscriminately. Observability has its own access and retention boundaries.

Apply it one operation at a time

Start with one user-visible operation:

  1. Separate enforceable properties from quality criteria.
  2. Map and classify the interactions; split distinct boundaries and lifecycles.
  3. Link shared contracts and expand only risky rows.
  4. Test slow, stale, malformed, unauthorized, duplicated, unavailable, and unknown-outcome paths.

Use it for protected data, retrieval, tools, state changes, authoritative claims, or operational obligations. A disposable local spike may need only basic error handling.

A useful dependency register determines runtime behavior before an incident rather than merely explaining the incident afterward. A successful model response does not override a violated account boundary, stale price, unverified availability claim, or unconfirmed write.

Further reading

The dependency-register structure in this article is a synthesis. These references provide the broader failure-analysis, AI application-design, testing, retry, asynchronous-processing, and telemetry guidance behind it: