---
id: CAP-PFM-INT-017
title: Apply tested customizations where an application allows them
feature: FEAT-PFM-INT-05
product_area: platform
module: integrations
revision: 1
status: draft
product_intent: proposed
implementation_evidence: observed
supersedes: []
source_sha:
  services-platform: ad3f6a6582843008ed0f5a17b131878d15829af1
  react-console: baf6dae382d6f41dce976c7f848667ccc37e076f
intent_sources:
  - 'services-platform:docs/proposals/extensibility/decision-log.md#A2'
  - 'services-platform:docs/proposals/extensibility/decision-log.md#A3'
  - 'services-platform:docs/proposals/extensibility/decision-log.md#A5'
purpose: >-
  Administrators configure and test rules, while authorized code authors supply handlers for application
  extension points.
outcomes:
  - Contract validation checks a customization before execution.
  - A single-answer point has one authoritative configured answer at each scope.
  - Invocation history supports review of tests and recorded runs.
concepts:
  - CON-PFM-INT-005
actors:
  - ACT-PFM-022
  - ACT-PFM-019
  - ACT-PFM-020
surfaces:
  - console
  - api
preconditions: []
postconditions: []
permissions:
  - key: platform.extension-points.read
    where_checked: api
    scope: tenant
  - key: platform.extension-handlers.manage
    where_checked: api
    scope: tenant
  - key: platform.extension-rules.manage
    where_checked: api
    scope: tenant
  - key: platform.extension-bindings.manage
    where_checked: api
    scope: tenant
  - key: platform.extension-handlers.test
    where_checked: api
    scope: tenant
  - key: platform.extension-invocations.read
    where_checked: api
    scope: tenant
rules:
  - id: BR-CAP-PFM-INT-017-01
    proved_by: [ATS-PFM-INT-017-01, TST-PFM-INT-459, TST-PFM-INT-468]
    statement: >-
      Handlers may be Lambda functions, declarative rules or built-ins; HTTPS targets are unavailable, target
      properties are kind-specific and secret-free, and Lambda defaults its qualifier to live.
    kind: validation
    enforced_at:
      - api
      - service
    must_prove: true
    provenance: test
    source: >-
      services-platform:modules/extensions/tests/integration/services/persistence/extension-handlers.integration.spec.js#refuses
      an HTTPS handler as not available, naming decision D-02, and writes nothing
    origin: none
  - id: BR-CAP-PFM-INT-017-02
    proved_by: [ATS-PFM-INT-017-02, TST-PFM-INT-459]
    statement: >-
      Code-handler management requires extension-handlers manage, while rule authors may use extension-rules
      manage alone.
    kind: permission
    enforced_at:
      - api
    must_prove: true
    provenance: test
    source: >-
      services-platform:modules/extensions/tests/e2e/extensions.e2e.spec.js#refuses a Lambda handler to a
      caller who may manage only rules
    origin: none
  - id: BR-CAP-PFM-INT-017-03
    proved_by: [ATS-PFM-INT-017-03, TST-PFM-INT-468]
    statement: >-
      Handler secrets remain write-only in secret storage, handler deletion schedules their removal and a
      bound handler cannot be deleted.
    kind: invariant
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-platform:modules/extensions/tests/integration/services/persistence/extension-handlers.integration.spec.js#never
      stores the secret value anywhere in the row
    origin: none
  - id: BR-CAP-PFM-INT-017-04
    proved_by: [ATS-PFM-INT-017-04, TST-PFM-INT-468]
    statement: >-
      Handlers use registered points, unique workspace names and timeouts within every implemented point’s
      ceiling, with a rule supplied only for rule handlers.
    kind: validation
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-platform:modules/extensions/tests/integration/services/persistence/extension-handlers.integration.spec.js#refuses
      a timeout above the shortest ceiling of the points it implements
    origin: none
  - id: BR-CAP-PFM-INT-017-05
    proved_by: [ATS-PFM-INT-017-05, TST-PFM-INT-460, TST-PFM-INT-466, TST-PFM-INT-468]
    statement: >-
      Saving a rule checks every implemented point’s current contract, binding checks the selected version and
      invalid rules identify each problem without writes.
    kind: validation
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-platform:modules/extensions/tests/integration/services/persistence/extension-handlers.integration.spec.js#refuses
      a rule that does not fit, naming each problem by its path and code, and writes nothing
    origin: none
  - id: BR-CAP-PFM-INT-017-06
    proved_by: [ATS-PFM-INT-017-06, TST-PFM-INT-459, TST-PFM-INT-466, TST-PFM-INT-475]
    statement: >-
      Bindings require a live registered point, a permitted and correctly identified scope, an implementing
      handler, an allowed failure policy with a note for overrides, a usable newly selected contract version
      and a forward effective window.
    kind: validation
    enforced_at:
      - api
      - service
    must_prove: true
    provenance: test
    source: >-
      services-platform:modules/extensions/tests/integration/services/persistence/extension-bindings.integration.spec.js#refuses
      an overriding failure policy without a note, and accepts it with one
    origin: none
  - id: BR-CAP-PFM-INT-017-07
    proved_by: [ATS-PFM-INT-016-09, ATS-PFM-INT-017-07, ATS-PFM-INT-017-13, ATS-PFM-INT-017-15, TST-PFM-INT-466, TST-PFM-INT-475]
    statement: >-
      Binding lifecycle permits draft activation, shadow or disable, enabled-shadow interchange, disabled
      return to draft or use and disable from any state; registration alone orphans bindings, which can only
      be disabled, and edits require the version read.
    kind: lifecycle
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-platform:modules/extensions/tests/unit/lifecycle.spec.js#allows draft to become enabled, shadow
      or disabled, enabled and shadow to trade places, disabled to return, and orphaned only to be disabled
    origin: none
  - id: BR-CAP-PFM-INT-017-08
    proved_by: [ATS-PFM-INT-017-08, TST-PFM-INT-459, TST-PFM-INT-466]
    statement: A single-answer point permits at most one enabled or shadow binding at a given scope.
    kind: invariant
    enforced_at:
      - service
      - database
    must_prove: true
    provenance: test
    source: >-
      services-platform:modules/extensions/tests/e2e/extensions.e2e.spec.js#refuses a second enabled binding
      at one scope of a single point as 409
    origin: none
  - id: BR-CAP-PFM-INT-017-09
    proved_by: [ATS-PFM-INT-017-09, TST-PFM-INT-459, TST-PFM-INT-478]
    statement: >-
      Resolution chooses the enabled binding at the most specific applicable scope then lowest priority,
      reports ties as configuration errors, ignores expired windows and reports shadow separately; no winner
      uses the point default.
    kind: calculation
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-platform:modules/extensions/tests/unit/resolution.spec.js#lets a product binding beat a tenant
      binding
    origin: none
  - id: BR-CAP-PFM-INT-017-10
    proved_by: [ATS-PFM-INT-017-10, TST-PFM-INT-459, TST-PFM-INT-460]
    statement: >-
      Handler testing validates input against its contract and executes rule handlers with test invocation
      history, while code-handler tests report unavailable transport and record no execution.
    kind: policy
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-platform:modules/extensions/tests/e2e/rule-handlers.e2e.spec.js#records each run as a test
      invocation of the handler
    origin: none
  - id: BR-CAP-PFM-INT-017-11
    proved_by: [ATS-PFM-INT-017-11, TST-PFM-INT-479]
    statement: >-
      Record facts are true or false when available, unknown for missing values or refused queries and false
      for absent records, evaluated as system for the same person within the workspace with request-local
      caching.
    kind: calculation
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-platform:modules/extensions/tests/unit/rule-handlers.spec.js#answers FALSE for a subject no row
      answered, known absent
    origin: none
  - id: BR-CAP-PFM-INT-017-12
    proved_by: [ATS-PFM-INT-017-12, TST-PFM-INT-459]
    statement: >-
      Invocation readers see newest-first workspace runs filtered by point, handler, outcome, purpose and
      time, with captured references exposed only while capture is enabled.
    kind: permission
    enforced_at:
      - api
      - service
    must_prove: true
    provenance: test
    source: >-
      services-platform:modules/extensions/tests/e2e/extensions.e2e.spec.js#refuses the invocation history
      without platform.extension-invocations.read
    origin: none
  - id: BR-CAP-PFM-INT-017-13
    proved_by: [ATS-PFM-INT-017-14]
    statement: >-
      Handler and binding changes enter security history by changed field name without target or secret
      values.
    kind: invariant
    enforced_at:
      - service
    must_prove: false
    provenance: test
    source: >-
      services-platform:modules/extensions/tests/integration/services/persistence/extension-handlers.integration.spec.js#records
      the creation in the security trail, naming the secret by field and never by value
    origin: none
scenarios:
  - id: SC-CAP-PFM-INT-017-01
    given: A rule provides a discount for Northeast chapter members.
    when: The rule test evaluates a Northeast member and a member elsewhere.
    then: The first receives a fifteen-percent discount and the other receives the neutral result.
    provenance: test
    source: >-
      services-platform:modules/extensions/tests/e2e/rule-handlers.e2e.spec.js#answers the member elsewhere
      with the neutral output instead of rule_not_applicable
edge_cases: []
constraints: []
depends_on:
  - CAP-PFM-INT-016
related: []
journeys:
  - JNY-PFM-INT-005
open_questions:
  - OQ-PFM-INT-001
evidence:
  - >-
    services-platform source inventory: modules/extensions/lifecycle.ts, resolution.ts, handler-secrets.ts,
    rule-contracts.ts, services/persistence/extension-handlers.ts, extension-bindings.ts,
    services/rules/record-facts.ts, services/test-invocation/test-handler.ts, aws/api/extensions.routes.ts;
    aws/platform.service.ts (EXTENSION_KEYS); rule-level automated test references; docs/extensions.md.
  - >-
    react-console source inventory: app/(console)/console/[tenantId]/configuration/platform/extensions/**,
    components/extensions/*, lib/extensions/adapters.ts (mock adapter).
  - >-
    Operation coverage: listExtensionHandlers, createExtensionHandler, getExtensionHandler,
    updateExtensionHandler, deleteExtensionHandler, testExtensionHandler, listExtensionBindings,
    createExtensionBinding, previewExtensionResolution, updateExtensionBinding, deleteExtensionBinding,
    listExtensionInvocations, getExtensionInvocation.
  - 'Persistent record coverage: extension_handlers, extension_bindings, extension_invocations.'
  - 'End-to-end definition inventory: extensions.e2e.spec.js, rule-handlers.e2e.spec.js.'
controls: [TC-AZ-001, TC-AZ-002, TC-AZ-003, TC-AZ-004, TC-CRY-001, TC-CRY-002, TC-CRY-003, TC-CRY-004, TC-DAT-001, TC-DAT-003, TC-DAT-004, TC-DAT-006, TC-IAM-001, TC-IAM-006, TC-LOG-002, TC-LOG-003, TC-LOG-004, TC-LOG-005, TC-PI-001, TC-PI-003, TC-PI-005, TC-SEC-001, TC-SEC-002, TC-SEC-003, TC-SEC-004, TC-TEN-001, TC-TEN-002, TC-TEN-003, TC-VEN-001, TC-VEN-002, TC-VEN-003]
exercised_by: [FAS-PFM-INT-05-01, FAS-PFM-INT-05-02, FAS-PFM-INT-05-03, FAS-PFM-INT-05-04, FAS-PFM-INT-05-05]
suites: [TST-PFM-INT-459, TST-PFM-INT-460, TST-PFM-INT-466, TST-PFM-INT-468, TST-PFM-INT-475, TST-PFM-INT-478, TST-PFM-INT-479]
---
# Apply tested customizations where an application allows them

## Purpose

Administrators configure and test rules, while authorized code authors supply handlers for application extension points.

## How It Works

A configuration administrator defines a rule for an application’s customization point. Code authors with stronger permission can supply a function handler. Saving and binding check whether the customization fits the point’s contract. A binding gives the customization a business scope and an effective period. Preview helps staff understand which configured answer would apply. Rule tests execute against supplied examples and retain invocation history. Code-handler testing has no active transport in Platform. The console currently demonstrates these interactions using sample data. The product should verify a connected configuration-to-application journey before treating that demonstration as operational customization.

## Relationships

- Requires keep a shared catalogue of customization points and events to supply the prerequisite configuration or operation.
