---
id: DOM-PFM-INT-005
title: Extension
realises: CON-PFM-INT-005
product_area: platform
module: integrations
revision: 1
status: draft
design_intent: proposed
implementation_evidence: partially-observed
source_sha:
  services-platform: ad3f6a6582843008ed0f5a17b131878d15829af1
  react-console: baf6dae382d6f41dce976c7f848667ccc37e076f
owned_by: SVC-PFM-INT-extensions
lifecycle:
  - STATE-PFM-INT-013
  - STATE-PFM-INT-014
  - STATE-PFM-INT-017
custom_fields: none
identity: >-
  Applications declare dotted keys for points and business event types, with numbered contract versions.
  Handlers, bindings and invocations use generated identifiers; an invocation takes its execution identity
  from the host envelope.
attributes:
  - name: extension point
    kind: document
    required: true
    computed: false
    notes: >-
      A point states its application, kind, cardinality, scope order, modes, timeout ceiling, failure policies
      and registry status.
  - name: contract version
    kind: collection
    required: true
    computed: false
    notes: >-
      Numbered contracts retain input and output schemas, condition facts, examples, optional neutral output
      and version status.
  - name: business event type
    kind: document
    required: false
    computed: false
    notes: >-
      Event declarations supply their application, subject kind, permitted scopes, payload versions and native
      subscribers.
  - name: handler
    kind: document
    required: false
    computed: false
    notes: >-
      Handlers retain kind, safe target, secret reference, implemented contracts, rule settings, timeout and
      capture flag; HTTPS configuration is refused.
  - name: binding
    kind: document
    required: false
    computed: false
    notes: >-
      Bindings attach a handler at a point and scope with a contract version, priority, failure policy,
      effective interval and lifecycle status.
  - name: invocation
    kind: document
    required: false
    computed: false
    notes: >-
      Invocation records explain the point, handler, binding, mode, purpose, result, timing, errors and
      optional diagnostic references.
  - name: workspace binding counts
    kind: computed
    required: false
    computed: true
    notes: Catalogue reads aggregate the current workspace’s binding counts for each point.
  - name: version
    kind: computed
    required: true
    computed: true
    notes: Handler and binding edits require the version previously read.
relationships:
  - to: DOM-PFM-INT-006
    cardinality: A declared business event can correspond to a trigger registered for automation by its application.
    ownership: The services keep separate registries and do not enforce that correspondence.
    cross_service: true
  - to: DOM-PFM-INT-004
    cardinality: External business-event delivery uses the integration event service.
    ownership: The extension registry contains no customer event-subscription facility.
    cross_service: true
invariants:
  - id: INV-DOM-PFM-INT-005-01
    statement: Registration validates the entire declaration and commits no registry changes when validation fails.
    enforced_at:
      - service
    provenance: test
    source: >-
      services-platform:modules/extensions/tests/integration/services/registration/register-service-extensions.integration.spec.js#refuses
      a malformed fragment as ObjectInvalid, naming the path
  - id: INV-DOM-PFM-INT-005-02
    statement: A key already attributed to another declared service cannot be adopted by a new declaration.
    enforced_at:
      - service
    provenance: test
    source: >-
      services-platform:modules/extensions/tests/integration/services/registration/register-service-extensions.integration.spec.js#refuses
      a key another service declares, naming that service
  - id: INV-DOM-PFM-INT-005-03
    statement: >-
      Omitting a customization point retires it and its versions and orphans its bindings across all
      workspaces.
    enforced_at:
      - service
    provenance: test
    source: >-
      services-platform:modules/extensions/tests/integration/services/registration/register-service-extensions.integration.spec.js#orphans
      every binding of a retired point, in every tenant, whatever its status
  - id: INV-DOM-PFM-INT-005-04
    statement: A scope on a single-answer point can contain only one binding whose status is enabled or shadow.
    enforced_at:
      - service
      - database
    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
  - id: INV-DOM-PFM-INT-005-05
    statement: >-
      Only registration can mark a binding orphaned; the administrative lifecycle permits an orphaned binding
      to move only to disabled.
    enforced_at:
      - service
    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
  - id: INV-DOM-PFM-INT-005-06
    statement: >-
      Rule saves check every implemented point’s current contract; binding validation checks the explicitly
      selected version.
    enforced_at:
      - service
    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
  - id: INV-DOM-PFM-INT-005-07
    statement: >-
      Handler secret storage supports writing, replacing and scheduling deletion, while the Platform handler
      API does not read values back.
    enforced_at:
      - service
    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
  - id: INV-DOM-PFM-INT-005-08
    statement: Deleting a handler fails while a binding still references it.
    enforced_at:
      - service
      - database
    provenance: test
    source: >-
      services-platform:modules/extensions/tests/integration/services/persistence/extension-handlers.integration.spec.js#refuses
      to delete a handler a binding uses, naming why, and keeps it
  - id: INV-DOM-PFM-INT-005-09
    statement: >-
      Handler and binding mutations commit security history that names changed fields while omitting target
      and secret contents.
    enforced_at:
      - service
    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
physical:
  - platform.extension_points
  - platform.extension_contract_versions
  - platform.event_types
  - platform.event_type_versions
  - platform.event_subscribers
  - platform.extension_handlers
  - platform.extension_bindings
  - platform.extension_invocations
evidence:
  - >-
    services-platform at ad3f6a65: modules/extensions/db/*.table.ts; lifecycle.ts; resolution.ts;
    services/registration/register-service-extensions.ts; services/persistence/*; services/rules/*;
    services/test-invocation/test-handler.ts
  - >-
    services-platform at ad3f6a65: docs/extensions.md; docs/proposals/extensibility/decision-log.md (A2, A4,
    A7)
  - 'react-console at baf6dae3: lib/extensions/adapters.ts (sample-backed adapter)'
---

# Extension

## What It Models

An extension lets customer configuration participate at a point an application deliberately offers. Platform stores the declaration, handler and binding; a host resolves the binding and invokes it through the shared library. Platform can evaluate rule handlers for tests and retain invocation records that hosts write.

## Identity and Attributes

Applications declare dotted keys for points and business event types, with numbered contract versions. Handlers, bindings and invocations use generated identifiers; an invocation takes its execution identity from the host envelope.

A point states its application, kind, cardinality, scope order, modes, timeout ceiling, failure policies and registry status. Numbered contracts retain input and output schemas, condition facts, examples, optional neutral output and version status. Event declarations supply their application, subject kind, permitted scopes, payload versions and native subscribers. Handlers retain kind, safe target, secret reference, implemented contracts, rule settings, timeout and capture flag; HTTPS configuration is refused. Bindings attach a handler at a point and scope with a contract version, priority, failure policy, effective interval and lifecycle status. Invocation records explain the point, handler, binding, mode, purpose, result, timing, errors and optional diagnostic references. Catalogue reads aggregate the current workspace’s binding counts for each point. Handler and binding edits require the version previously read.

## Relationships

A declared business event can correspond to a trigger registered for automation by its application.. The services keep separate registries and do not enforce that correspondence.. External business-event delivery uses the integration event service.. The extension registry contains no customer event-subscription facility..

## Invariants

Registration validates the entire declaration and commits no registry changes when validation fails. A key already attributed to another declared service cannot be adopted by a new declaration. Omitting a customization point retires it and its versions and orphans its bindings across all workspaces. A scope on a single-answer point can contain only one binding whose status is enabled or shadow. Only registration can mark a binding orphaned; the administrative lifecycle permits an orphaned binding to move only to disabled. Rule saves check every implemented point’s current contract; binding validation checks the explicitly selected version. Handler secret storage supports writing, replacing and scheduling deletion, while the Platform handler API does not read values back. Deleting a handler fails while a binding still references it. Handler and binding mutations commit security history that names changed fields while omitting target and secret contents.

## How It Is Stored and Shared

The extensions service owns global point and event declarations and workspace handler, binding and invocation records. Hosts have a restricted capability to create and finish invocation records, so ownership does not imply that Platform is the only writer. Handler secrets use write-only storage calls that do not share database rollback. No object declares custom fields.

## Open Design Questions

Registration does not bind the declaration’s application name to the authenticated caller. Screens are available as mock previews only. Platform code-handler test transport, payload storage and invocation retention are incomplete, and broader extension intent remains proposed.
