---
id: ATS-PFM-LLM-005
scope: CAP-PFM-LLM-005
product_area: platform
module: llm
revision: 2
status: proposed
source_sha:
  services-platform: ad3f6a6582843008ed0f5a17b131878d15829af1
  react-console: baf6dae382d6f41dce976c7f848667ccc37e076f
scenarios:
  - id: ATS-PFM-LLM-005-01
    title: Reservation obeys the declared ceiling
    level: unit
    proves:
      - BR-CAP-PFM-LLM-005-01
      - INV-DOM-PFM-LLM-002-05
    preconditions: 'A projected estimate exceeds its request ceiling, alongside an ordinary operation.'
    steps: Calculate both holds.
    expected: The large projection is capped and the ordinary estimate stays below its ceiling.
    negative: false
    data_needs: 'Fixtures representing a projected estimate exceeds its request ceiling, alongside an ordinary operation.'
    bound_to:
      - TST-PFM-LLM-058
    provenance: test
    source: >-
      services-platform:modules/llm/tests/unit/catalog/pricing.spec.ts#reserves the per-turn estimate across
      every turn the operation may take
    category: rule
    test_sources:
      - >-
        services-platform:modules/llm/tests/unit/catalog/pricing.spec.ts#reserves the per-turn estimate across
        every turn the operation may take
      - >-
        services-platform:modules/llm/tests/unit/catalog/pricing.spec.ts#never reserves more than the
        operation’s declared ceiling, which is what a tenant can lose on one call
  - id: ATS-PFM-LLM-005-02
    title: Invalid catalog publication is atomic
    level: api
    proves:
      - BR-CAP-PFM-LLM-005-02
      - INV-DOM-PFM-LLM-002-02
    preconditions: A declaration routes an operation to an unpriced model.
    steps: Publish the catalog.
    expected: The error identifies the operation and no routing or rate version is appended.
    negative: true
    data_needs: Fixtures representing a declaration routes an operation to an unpriced model.
    bound_to:
      - TST-PFM-LLM-023
      - TST-PFM-LLM-060
    provenance: test
    source: >-
      services-platform:modules/llm/tests/integration/services/catalog/materialize-catalog.integration.spec.js#refuses
      the deploy
    category: validation
    test_sources:
      - >-
        services-platform:modules/llm/tests/integration/services/catalog/materialize-catalog.integration.spec.js#refuses
        the deploy
      - >-
        services-platform:modules/llm/tests/integration/services/catalog/materialize-catalog.integration.spec.js#wrote
        no rate version either, although every rate in the publication was valid
      - >-
        services-platform:modules/llm/tests/unit/catalog/validate-catalog-declarations.spec.ts#refuses the
        whole publication rather than writing the part that was fine
  - id: ATS-PFM-LLM-005-03
    title: Unchanged publication leaves history alone
    level: api
    proves:
      - BR-CAP-PFM-LLM-005-03
      - INV-DOM-PFM-LLM-002-03
    preconditions: A catalog is already published.
    steps: 'Republish unchanged, then publish one changed operation.'
    expected: The replay appends nothing and the changed publication adds only the changed routing version.
    negative: false
    data_needs: Fixtures representing a catalog is already published.
    bound_to:
      - TST-PFM-LLM-023
    provenance: test
    source: >-
      services-platform:modules/llm/tests/integration/services/catalog/materialize-catalog.integration.spec.js#publishes
      no operation the second time, so an ordinary deploy leaves the histories alone
    category: transition
    test_sources:
      - >-
        services-platform:modules/llm/tests/integration/services/catalog/materialize-catalog.integration.spec.js#publishes
        no operation the second time, so an ordinary deploy leaves the histories alone
      - >-
        services-platform:modules/llm/tests/integration/services/catalog/materialize-catalog.integration.spec.js#publishes
        the changed operation
      - >-
        services-platform:modules/llm/tests/integration/services/catalog/materialize-catalog.integration.spec.js#publishes
        no rate, because only the operation changed
  - id: ATS-PFM-LLM-005-04
    title: Historical versions resist mutation
    level: api
    proves:
      - BR-CAP-PFM-LLM-005-04
      - INV-DOM-PFM-LLM-002-04
    preconditions: Published routing and price versions exist.
    steps: Attempt updates and deletions under application and publishing roles.
    expected: Every mutation is refused and historical contents remain intact.
    negative: true
    data_needs: Fixtures representing published routing and price versions exist.
    bound_to:
      - TST-PFM-LLM-011
    provenance: test
    source: >-
      services-platform:modules/llm/tests/integration/db/llm-catalog-tables.integration.spec.js#refuses an
      update by the owner, who publishes the versions, so no deploy can rewrite one
    category: invariant
    test_sources:
      - >-
        services-platform:modules/llm/tests/integration/db/llm-catalog-tables.integration.spec.js#refuses an
        update by the owner, who publishes the versions, so no deploy can rewrite one
      - >-
        services-platform:modules/llm/tests/integration/db/llm-catalog-tables.integration.spec.js#refuses a
        re-pricing in place by the application role, which would rewrite what every past call cost
  - id: ATS-PFM-LLM-005-05
    title: New prices preserve old request pricing
    level: api
    proves:
      - BR-CAP-PFM-LLM-005-05
    preconditions: A model has an original and a revised rate version.
    steps: Price work using each version.
    expected: New requests use revised prices while historical versions retain their original rate.
    negative: false
    data_needs: Fixtures representing a model has an original and a revised rate version.
    bound_to:
      - TST-PFM-LLM-040
    provenance: test
    source: >-
      services-platform:modules/llm/tests/integration/services/persistence/rate-versions.integration.spec.js#charges
      the new price from the new version
    category: rule
    test_sources:
      - >-
        services-platform:modules/llm/tests/integration/services/persistence/rate-versions.integration.spec.js#charges
        the new price from the new version
      - >-
        services-platform:modules/llm/tests/integration/services/persistence/rate-versions.integration.spec.js#leaves
        the old version at the old price, because an invocation settled under it still names it
  - id: ATS-PFM-LLM-005-06
    title: Credit and cent rounding serve different purposes
    level: unit
    proves:
      - BR-CAP-PFM-LLM-005-06
      - INV-DOM-PFM-LLM-002-06
    preconditions: Reported quantities produce fractional costs.
    steps: Calculate credit and cent prices over the summed dimensions.
    expected: Credits round upward and cents to nearest after a single final division.
    negative: false
    data_needs: Fixtures representing reported quantities produce fractional costs.
    bound_to:
      - TST-PFM-LLM-058
    provenance: test
    source: >-
      services-platform:modules/llm/tests/unit/catalog/pricing.spec.ts#rounds a fractional credit up, so small
      calls cannot slip past an allowance
    category: boundary
    test_sources:
      - >-
        services-platform:modules/llm/tests/unit/catalog/pricing.spec.ts#rounds a fractional credit up, so
        small calls cannot slip past an allowance
      - >-
        services-platform:modules/llm/tests/unit/catalog/pricing.spec.ts#rounds to nearest rather than up,
        because it is a report and not a gate
      - >-
        services-platform:modules/llm/tests/unit/catalog/pricing.spec.ts#divides once over the whole sum
        rather than per dimension
  - id: ATS-PFM-LLM-005-07
    title: Unknown usage stays visible without guessed charges
    level: unit
    proves:
      - BR-CAP-PFM-LLM-005-08
    preconditions: Reported usage contains an unpriced dimension.
    steps: Classify and price that usage.
    expected: The dimension retains its provider name as unpriced and contributes no cost.
    negative: false
    data_needs: Fixtures representing reported usage contains an unpriced dimension.
    bound_to:
      - TST-PFM-LLM-055
      - TST-PFM-LLM-058
    provenance: test
    source: >-
      services-platform:modules/llm/tests/unit/catalog/classify-usage-dimensions.spec.ts#reports it as
      unpriced rather than filtering it out
    category: edge
    test_sources:
      - >-
        services-platform:modules/llm/tests/unit/catalog/classify-usage-dimensions.spec.ts#reports it as
        unpriced rather than filtering it out
      - >-
        services-platform:modules/llm/tests/unit/catalog/pricing.spec.ts#charges nothing for a dimension this
        rate version does not price
  - id: ATS-PFM-LLM-005-08
    title: HQ catalog access requires the staff usage key
    category: permission
    level: api
    proves:
      - BR-CAP-PFM-LLM-005-10
    preconditions: 'A keyed staff reader, a customer administrator and an unkeyed staff caller are available.'
    steps: Read catalog and rates as each caller.
    expected: Only keyed staff receive the catalog and rates; denied callers receive no data.
    negative: true
    data_needs: Published catalog and three distinct security contexts.
    bound_to:
      - TST-PFM-LLM-009
    provenance: test
    source:
      - 'services-platform:modules/llm/tests/e2e/llm-usage.e2e.spec.js#answers the catalog and the rates'
      - >-
        services-platform:modules/llm/tests/e2e/llm-usage.e2e.spec.js#refuses a staff member who holds only
        another HQ key
      - >-
        services-platform:modules/llm/tests/e2e/llm-usage.e2e.spec.js#refuses a customer’s administrator,
        whatever they hold at their customer’s scope
    test_sources:
      - 'services-platform:modules/llm/tests/e2e/llm-usage.e2e.spec.js#answers the catalog and the rates'
      - >-
        services-platform:modules/llm/tests/e2e/llm-usage.e2e.spec.js#refuses a staff member who holds only
        another HQ key
      - >-
        services-platform:modules/llm/tests/e2e/llm-usage.e2e.spec.js#refuses a customer’s administrator,
        whatever they hold at their customer’s scope
  - id: ATS-PFM-LLM-005-09
    title: Stub guards protect catalog-priced checks
    category: interaction
    level: api
    proves:
      - BR-CAP-PFM-LLM-005-06
      - BR-CAP-PFM-LLM-006-02
    exercises:
      - CAP-PFM-LLM-005
      - CAP-PFM-LLM-006
    preconditions: A declared operation is priced and stub mode has a prepared script.
    steps: Run its scripted request and attempt to construct the live adapter in the same mode.
    expected: Scripted usage is priced normally while live-adapter construction refuses before reaching a model.
    negative: true
    data_needs: 'An isolated workspace with the records, clock instants and caller authority stated in the preconditions.'
    bound_to: []
    provenance: proposed
    source:
      - 'services-platform:modules/llm/catalog/pricing.ts'
      - >-
        services-platform:modules/llm/tests/unit/runtime/anthropic-provider.spec.ts#refuses, rather than
        reaching a provider a test never meant to call
  - id: ATS-PFM-LLM-005-10
    title: A changed estimate changes affordability
    category: interaction
    level: api
    proves:
      - BR-CAP-PFM-LLM-005-01
      - BR-CAP-PFM-LLM-007-02
    exercises:
      - CAP-PFM-LLM-005
      - CAP-PFM-LLM-007
    preconditions: >-
      Remaining capacity admits the old reservation but cannot admit the larger reservation in a new routing
      version.
    steps: 'Publish the changed estimate, resolve afresh and request admission.'
    expected: The new estimate drives refusal without repricing or changing earlier settled requests.
    negative: true
    data_needs: 'An isolated workspace with the records, clock instants and caller authority stated in the preconditions.'
    bound_to: []
    provenance: proposed
    source:
      - 'services-platform:modules/llm/catalog/pricing.ts'
      - 'services-platform:modules/llm/services/persistence/allowance-periods.ts'
  - id: ATS-PFM-LLM-005-11
    title: Reporting retains historical price identity
    category: interaction
    level: api
    proves:
      - BR-CAP-PFM-LLM-005-05
      - BR-CAP-PFM-LLM-010-08
    exercises:
      - CAP-PFM-LLM-005
      - CAP-PFM-LLM-010
    preconditions: Requests under two price versions settle on the same reporting day.
    steps: Rebuild the day and read model and operation breakdowns.
    expected: Both historical charges contribute at their recorded prices rather than the currently published rate.
    negative: false
    data_needs: 'An isolated workspace with the records, clock instants and caller authority stated in the preconditions.'
    bound_to: []
    provenance: proposed
    source:
      - >-
        services-platform:modules/llm/tests/integration/services/persistence/rate-versions.integration.spec.js#leaves
        the old version at the old price, because an invocation settled under it still names it
      - 'services-platform:modules/llm/services/reconciliation/rollup-settled-invocations.ts'
  - id: ATS-PFM-LLM-005-12
    title: Limit validation follows declared operation identity
    category: interaction
    level: api
    proves:
      - BR-CAP-PFM-LLM-005-02
      - BR-CAP-PFM-LLM-013-03
    exercises:
      - CAP-PFM-LLM-005
      - CAP-PFM-LLM-013
    preconditions: An organization has stored limits and a catalog with a known operation.
    steps: 'Preview disabling the known operation, then try a name absent from the catalog.'
    expected: >-
      The declared operation is accepted for preview without writes; the unknown name is refused without
      changing limits or audit.
    negative: true
    data_needs: 'An isolated workspace with the records, clock instants and caller authority stated in the preconditions.'
    bound_to: []
    provenance: proposed
    source:
      - 'services-platform:modules/llm/services/catalog/materialize-catalog.ts'
      - 'services-platform:modules/llm/services/limits/tenant-limits.ts'
  - id: ATS-PFM-LLM-005-13
    title: A historical price remains readable unchanged
    category: invariant
    level: api
    proves:
      - BR-CAP-PFM-LLM-005-05
    preconditions: >-
      The suite owns isolated fixtures representing the valid control and the contrasting case described by
      its steps.
    steps: Publish a newer rate and read the earlier version by its identity.
    expected: The earlier schedule remains unchanged and does not become the current price.
    negative: false
    data_needs: 'Suite-owned fixtures, with a fixed clock where dates or grant windows matter.'
    bound_to:
      - TST-PFM-LLM-041
    provenance: test
    source: >-
      services-platform:modules/llm/tests/integration/services/persistence/rate-versions.queries.integration.spec.js#answers
      the first by its id, unchanged, which is how a past settlement stays explicable
    test_sources:
      - >-
        services-platform:modules/llm/tests/integration/services/persistence/rate-versions.queries.integration.spec.js#answers
        the first by its id, unchanged, which is how a past settlement stays explicable
  - id: ATS-PFM-LLM-005-14
    title: Concurrent identical publication shares one version
    category: concurrency
    level: api
    proves:
      - BR-CAP-PFM-LLM-005-03
    preconditions: >-
      The suite owns isolated fixtures representing the valid control and the contrasting case described by
      its steps.
    steps: Race publication of the same routing declaration.
    expected: At most one append occurs and all callers receive the same version.
    negative: false
    data_needs: 'Suite-owned fixtures, with a fixed clock where dates or grant windows matter.'
    bound_to:
      - TST-PFM-LLM-042
    provenance: test
    source: >-
      services-platform:modules/llm/tests/integration/services/persistence/routing-versions.integration.spec.js#answers
      them all the same version, so a loser agrees with the winner rather than retrying
    test_sources:
      - >-
        services-platform:modules/llm/tests/integration/services/persistence/routing-versions.integration.spec.js#answers
        them all the same version, so a loser agrees with the winner rather than retrying
  - id: ATS-PFM-LLM-005-15
    title: Historical routing remains beside its successor
    category: invariant
    level: api
    proves:
      - BR-CAP-PFM-LLM-005-04
    preconditions: >-
      The suite owns isolated fixtures representing the valid control and the contrasting case described by
      its steps.
    steps: Publish a changed routing and inspect both versions by number and history.
    expected: The earlier routing is unchanged and history orders the newer version first.
    negative: false
    data_needs: 'Suite-owned fixtures, with a fixed clock where dates or grant windows matter.'
    bound_to:
      - TST-PFM-LLM-043
    provenance: test
    source: >-
      services-platform:modules/llm/tests/integration/services/persistence/routing-versions.queries.integration.spec.js#answers
      the first by its number, unchanged, which is what makes a past call attributable
    test_sources:
      - >-
        services-platform:modules/llm/tests/integration/services/persistence/routing-versions.queries.integration.spec.js#answers
        the first by its number, unchanged, which is what makes a past call attributable
  - id: ATS-PFM-LLM-005-16
    title: Routing identity ignores object property order
    category: invariant
    level: unit
    proves:
      - BR-CAP-PFM-LLM-005-03
    preconditions: >-
      The suite owns isolated fixtures representing the valid control and the contrasting case described by
      its steps.
    steps: Digest equal routing declarations whose object properties have different insertion order.
    expected: Both declarations receive the same content digest.
    negative: false
    data_needs: 'Suite-owned fixtures, with a fixed clock where dates or grant windows matter.'
    bound_to:
      - TST-PFM-LLM-056
    provenance: test
    source: >-
      services-platform:modules/llm/tests/unit/catalog/digest-declarations.spec.ts#is the same for two
      declarations differing only in property order
    test_sources:
      - >-
        services-platform:modules/llm/tests/unit/catalog/digest-declarations.spec.ts#is the same for two
        declarations differing only in property order
  - id: ATS-PFM-LLM-005-17
    title: Usage spelling preserves declared pricing
    category: edge
    level: unit
    proves:
      - BR-CAP-PFM-LLM-005-08
    preconditions: >-
      The suite owns isolated fixtures representing the valid control and the contrasting case described by
      its steps.
    steps: 'Resolve authored and stored spellings of one priced dimension, then an unknown dimension.'
    expected: Known spellings share the declared numerator while the unknown dimension resolves no price.
    negative: false
    data_needs: 'Suite-owned fixtures, with a fixed clock where dates or grant windows matter.'
    bound_to:
      - TST-PFM-LLM-059
    provenance: test
    source: >-
      services-platform:modules/llm/tests/unit/catalog/rate-conversions.spec.ts#resolves the same dimension
      reported in the stored spelling
    test_sources:
      - >-
        services-platform:modules/llm/tests/unit/catalog/rate-conversions.spec.ts#resolves the same dimension
        reported in the stored spelling
evidence:
  - >-
    services-platform at ad3f6a6582843008ed0f5a17b131878d15829af1: bound or cited
    modules/llm/tests/integration/db/llm-catalog-tables.integration.spec.js;
    modules/llm/tests/integration/services/catalog/materialize-catalog.integration.spec.js;
    modules/llm/tests/integration/services/persistence/rate-versions.integration.spec.js;
    modules/llm/tests/unit/catalog/classify-usage-dimensions.spec.ts;
    modules/llm/tests/unit/catalog/pricing.spec.ts;
    modules/llm/tests/unit/catalog/validate-catalog-declarations.spec.ts.
coverage:
  rule: 'gap: FND-PFM-LLM-064'
  transition: 'gap: FND-PFM-LLM-064'
  validation: covered
  permission: covered
  edge: covered
  failure: 'gap: FND-PFM-LLM-064'
  boundary: covered
  concurrency: covered
  invariant: 'gap: FND-PFM-LLM-064'
  interaction: covered
coverage_notes:
  transition: >-
    Existing transition scenarios are retained; the model transition register below records the remaining
    exhaustive mapping obligation.
  interaction: >-
    The related interaction register cites a concrete experiment for every dependency and related capability,
    including cross-capability workflow seams.
  invariant: >-
    The domain-invariant register maps each relevant invariant to a scenario or to the capability coverage
    finding; an example does not establish every invariant.
  rule: >-
    All must-prove rules have scenario references, but the coverage finding retains untested clauses and
    combined outcomes; scenario presence alone is not exhaustive rule proof.
related_interactions:
  - with: CAP-PFM-LLM-001
    scenarios:
      - ATS-PFM-LLM-001-14
    source: 'services-platform:modules/llm/services/catalog/catalog-authority.ts:resolveLlmOperation'
  - with: CAP-PFM-LLM-002
    scenarios:
      - ATS-PFM-LLM-002-12
    source: >-
      services-platform:modules/llm/tests/unit/runtime/run-tool-loop.spec.ts#stops a conversation that will
      not converge
  - with: CAP-PFM-LLM-006
    scenarios:
      - ATS-PFM-LLM-005-09
    source: 'services-platform:tests/unit/llm-stub-mode-config.spec.ts#forces stub mode in the integration tier'
  - with: CAP-PFM-LLM-007
    scenarios:
      - ATS-PFM-LLM-005-10
    source: 'services-platform:modules/llm/services/persistence/allowance-periods.ts'
  - with: CAP-PFM-LLM-010
    scenarios:
      - ATS-PFM-LLM-005-11
    source: >-
      services-platform:modules/llm/tests/e2e/llm-usage.e2e.spec.js#refuses a customer’s administrator,
      whatever they hold at their customer’s scope
  - with: CAP-PFM-LLM-013
    scenarios:
      - ATS-PFM-LLM-005-12
    source: >-
      services-platform:modules/llm/tests/e2e/llm-limits.e2e.spec.js#is refused the write before a handler
      runs, whatever the customer’s scope grants
state_models:
  - STATE-PFM-LLM-004
coverage_obligations:
  must_prove:
    - rule: BR-CAP-PFM-LLM-005-01
      scenarios:
        - ATS-PFM-LLM-005-01
        - ATS-PFM-LLM-005-10
      source: 'services-platform:modules/llm/catalog/pricing.ts'
      coverage: specified
    - rule: BR-CAP-PFM-LLM-005-02
      scenarios:
        - ATS-PFM-LLM-005-02
        - ATS-PFM-LLM-005-12
      source: 'services-platform:modules/llm/services/catalog/materialize-catalog.ts'
      coverage: partial
      gap: FND-PFM-LLM-064
    - rule: BR-CAP-PFM-LLM-005-03
      scenarios:
        - ATS-PFM-LLM-005-03
        - ATS-PFM-LLM-005-14
        - ATS-PFM-LLM-005-16
      source: 'services-platform:modules/llm/services/catalog/materialize-catalog.ts'
      coverage: partial
      gap: FND-PFM-LLM-064
    - rule: BR-CAP-PFM-LLM-005-04
      scenarios:
        - ATS-PFM-LLM-005-04
        - ATS-PFM-LLM-005-15
      source: >-
        services-platform:modules/llm/tests/integration/db/llm-catalog-tables.integration.spec.js#refuses an
        update by the owner, who publishes the versions, so no deploy can rewrite one
      coverage: specified
    - rule: BR-CAP-PFM-LLM-005-05
      scenarios:
        - ATS-PFM-LLM-005-05
        - ATS-PFM-LLM-005-11
        - ATS-PFM-LLM-005-13
      source: >-
        services-platform:modules/llm/tests/integration/services/persistence/rate-versions.integration.spec.js#leaves
        the old version at the old price, because an invocation settled under it still names it
      coverage: partial
      gap: FND-PFM-LLM-064
    - rule: BR-CAP-PFM-LLM-005-06
      scenarios:
        - ATS-PFM-LLM-005-06
        - ATS-PFM-LLM-005-09
      source: 'services-platform:modules/llm/catalog/pricing.ts'
      coverage: specified
    - rule: BR-CAP-PFM-LLM-005-08
      scenarios:
        - ATS-PFM-LLM-005-07
        - ATS-PFM-LLM-005-17
      source: >-
        services-platform:modules/llm/tests/unit/catalog/classify-usage-dimensions.spec.ts#reports it as
        unpriced rather than filtering it out
      coverage: specified
  state_transitions:
    - model: STATE-PFM-LLM-004
      transition: 1
      from: declared
      to: current
      trigger: Deployment publishes a changed or first declaration.
      gap: FND-PFM-LLM-064
      provenance: proposed
      source: 'services-platform:modules/llm/services/catalog/materialize-catalog.ts:materializeLlmCatalog'
    - model: STATE-PFM-LLM-004
      transition: 2
      from: current
      to: superseded
      trigger: A later deployment appends changed or reverted content.
      gap: FND-PFM-LLM-064
      provenance: proposed
      source: 'services-platform:modules/llm/services/persistence/routing-versions.ts:appendRoutingVersion'
    - model: STATE-PFM-LLM-004
      transition: 3
      from: current
      to: current
      trigger: Deployment presents the existing current digest.
      gap: FND-PFM-LLM-064
      provenance: proposed
      source: 'services-platform:modules/llm/services/persistence/rate-versions.ts:appendRateVersion'
  domain_invariants:
    - invariant: INV-DOM-PFM-LLM-002-01
      scenarios: []
      gap: FND-PFM-LLM-064
      provenance: proposed
      source: 'services-platform:modules/llm/services/catalog/catalog-authority.ts:resolveLlmOperation'
    - invariant: INV-DOM-PFM-LLM-002-02
      scenarios:
        - ATS-PFM-LLM-005-02
      provenance: documented
      source: 'services-platform:modules/llm/catalog/validate-catalog-declarations.ts:assertCatalogDeclarationsValid'
    - invariant: INV-DOM-PFM-LLM-002-03
      scenarios:
        - ATS-PFM-LLM-005-03
      provenance: documented
      source: 'services-platform:modules/llm/services/persistence/routing-versions.ts:appendRoutingVersion'
    - invariant: INV-DOM-PFM-LLM-002-04
      scenarios:
        - ATS-PFM-LLM-005-04
      provenance: documented
      source: 'services-platform:db/migrations/0048_llm.sql:llm_refuse_version_change'
    - invariant: INV-DOM-PFM-LLM-002-05
      scenarios:
        - ATS-PFM-LLM-005-01
      provenance: documented
      source: 'services-platform:modules/llm/catalog/pricing.ts:reservationCredits'
    - invariant: INV-DOM-PFM-LLM-002-06
      scenarios:
        - ATS-PFM-LLM-005-06
      provenance: documented
      source: 'services-platform:modules/llm/catalog/pricing.ts:convertUsageToCredits'
    - invariant: INV-DOM-PFM-LLM-002-08
      scenarios: []
      gap: FND-PFM-LLM-064
      provenance: proposed
      source: 'services-platform:modules/llm/services/persistence/routing-versions.ts:appendRoutingVersion'
coverage_limits:
  finding: FND-PFM-LLM-064
  statement: >-
    Changed and reverted publication needs complete lifecycle coverage; different-content racing publication,
    partial persistence failure and warm-cache convergence remain unproved.
  provenance: proposed
  source:
    - 'services-platform:modules/llm/catalog/pricing.ts'
    - 'services-platform:modules/llm/services/catalog/materialize-catalog.ts'
    - 'services-platform:modules/llm/services/catalog/materialize-catalog.ts'
    - >-
      services-platform:modules/llm/tests/integration/db/llm-catalog-tables.integration.spec.js#refuses an
      update by the owner, who publishes the versions, so no deploy can rewrite one
    - >-
      services-platform:modules/llm/tests/integration/services/persistence/rate-versions.integration.spec.js#leaves
      the old version at the old price, because an invocation settled under it still names it
    - 'services-platform:modules/llm/catalog/pricing.ts'
    - >-
      services-platform:modules/llm/tests/unit/catalog/classify-usage-dimensions.spec.ts#reports it as
      unpriced rather than filtering it out
    - 'services-platform:modules/llm/services/catalog/catalog-authority.ts:resolveLlmOperation'
    - 'services-platform:modules/llm/services/persistence/routing-versions.ts:appendRoutingVersion'
  invariants_without_scenarios:
    - INV-DOM-PFM-LLM-002-01
    - INV-DOM-PFM-LLM-002-08
---

# Publish AI operation definitions and historical prices: Capability Test Specification

## Coverage

| Rule | Scenario |
|---|---|
| `BR-CAP-PFM-LLM-005-01` | `ATS-PFM-LLM-005-01` |
| `BR-CAP-PFM-LLM-005-02` | `ATS-PFM-LLM-005-02` |
| `BR-CAP-PFM-LLM-005-03` | `ATS-PFM-LLM-005-03` |
| `BR-CAP-PFM-LLM-005-04` | `ATS-PFM-LLM-005-04` |
| `BR-CAP-PFM-LLM-005-05` | `ATS-PFM-LLM-005-05` |
| `BR-CAP-PFM-LLM-005-06` | `ATS-PFM-LLM-005-06` |
| `BR-CAP-PFM-LLM-005-08` | `ATS-PFM-LLM-005-07` |

## Interactions With Related Capabilities

The interaction register links concrete experiments with run ai requests with consistent attribution and accounting; bound ai conversations and handle recoverable failures; check ai behavior with scripted models and deliberate live runs; admit ai work against the organization’s monthly allowance; monitor ai usage across organizations; set an organization’s ai access and recurring limits. Each experiment checks the outcome at the shared boundary; an unbound experiment remains proposed.

Changed and reverted publication needs complete lifecycle coverage; different-content racing publication, partial persistence failure and warm-cache convergence remain unproved.
