# FlowDrop Backward Compatibility Policy

This document defines the backward compatibility (BC) policy for FlowDrop starting with version 1.0.0. FlowDrop follows **pragmatic semantic versioning** (semver), meaning:

- **Patch releases** (1.0.x): Bug fixes only. No BC breaks.
- **Minor releases** (1.x.0): New features, deprecations. No BC breaks to stable API.
- **Major releases** (x.0.0): May contain BC breaks with migration path documented.

## API Classification

Every PHP class and interface in FlowDrop falls into one of two categories, indicated by PHPDoc annotations. Every class **must** carry exactly one of `@api` or `@internal`.

### `@api`

Classes and interfaces marked `@api` are the **stable public API**. They follow strict semver:

- Method signatures will not change in the 1.x release line.
- New optional parameters may be added.
- New methods may be added to classes (but not to interfaces without a deprecation cycle).
- Removal or renaming requires a major version bump with deprecation in the prior minor.

The stable API includes the **FlowDropNodeProcessor plugin system** — the classes that external modules use to create custom node types:

- **Plugin discovery**: `FlowDropNodeProcessor` attribute, `FlowDropNodeProcessorPluginManager`
- **Plugin contracts**: `FlowDropNodeProcessorInterface`, `AbstractFlowDropNodeProcessor`, `NodeExecutorInterface`, `ConfigEditProviderInterface`, `ExecutionContextAwareInterface`, `TriggerNodeProcessorInterface`
- **Lifecycle opt-ins** (1.4.0+): `CancellableNodeProcessorInterface`, `ResumableNodeProcessorInterface`
- **Parameter system**: `ParameterBag`, `ParameterBagInterface`
- **Data/Output**: `Data`, `DataInterface`, `Output`, `OutputInterface`
- **Validation**: `ValidationResult`, `ValidationError`, `ValidationWarning`
- **Execution context**: `ExecutionContextDTO`
- **Node metadata**: `NodeMetadata`, `NodeMetadataBuilder`, `NodePort`
- **Config editing**: `ConfigEdit`, `DynamicSchemaEndpoint`, `ExternalEditLink`, `ConfigEditApiEndpoints`

The **Orchestrator plugin system** is part of the stable API — the classes that external modules use to create custom workflow execution strategies:

- **Plugin discovery**: `Orchestrator` attribute
- **Plugin contracts**: `OrchestratorPluginInterface`, `OrchestratorPluginBase`, `OrchestratorInterface`
- **Interrupt contracts**: `InterruptExceptionInterface`, `FlowDropInterruptException`

The **Trigger system** and **Workflow Executor** APIs are stable:

- **Trigger contracts**: `TriggerManagerInterface`, `FlowDropTriggerConfigInterface`, `FlowDropEventTypeInterface`
- **Workflow executor contracts**: `WorkflowExecutionServiceInterface`, `WorkflowExecutionMode`, `WorkflowExecutionStatus`

The **StateGraph**, **Interrupt**, and supporting APIs are also stable:

- **StateGraph contracts**: `StateManagerInterface`, `CheckpointerInterface`, `StateAwareProcessorInterface`, `ReducerInterface`, `IteratorHelperInterface`
- **StateGraph data**: `GraphState`, `StateUpdate`, `Checkpoint`
- **StateGraph exceptions**: `MaxIterationsException`, `StateValidationException`, `CheckpointException`, `IteratorExhaustedException`
- **Interrupt contracts**: `InterruptManagerInterface`, `InterruptPersistenceInterface`
- **Interrupt data**: `InterruptState`, `InterruptType`
- **Interrupt message bus** (1.4.0+): `InterruptMessageInterface`, `AbstractInterruptMessage`, `HitlInterruptMessage`, `LinkedInterruptMessage`, `InwardSignalMessage`. The concrete shapes are the DTOs a node processor throws via `InterruptRequiredException`; the bus and handler registry (`InterruptMessageBusInterface`, `InterruptFactoryInterface`, `InterruptCreationData`) are part of the stable surface too.

The **Pipeline runtime contract** is stable (1.4.0+):

- **Runtime contract**: `FlowDropPipelineRuntimeInterface` — the narrow runtime view of a pipeline used by the storage layer, orchestrators, events, and queue workers. The full `FlowDropPipelineInterface` (entity-shaped) is `@internal`; type-hint the runtime interface in code that does not need entity-level access.

The **FlowDropSchema form builder** is stable (1.4.0+):

- **Form builder contract**: `FlowDropSchemaFormBuilderInterface` — renders Drupal form arrays from FlowDropSchema fragments. FlowDropSchema is a documented subset of JSON Schema; see [FlowDropSchema](flowdrop-schema.md) for the supported keyword set. The concrete `FlowDropSchemaFormBuilder` implementation is `@internal`.

The following surface was **stabilized in 2.0.0**:

- **Workflow launch**: `WorkflowLauncherInterface` — the supported way to start a workflow run from any context (HTTP, drush, triggers, other modules); replaces starting a run by POSTing a chat message.
- **Session turns**: `SessionTurnServiceInterface` — the single "chat turn" verb (post a message and execute the session's workflow). Access is enforced by the calling route layer, not the service.
- **Workflow definition**: `WorkflowDefinitionInterface` — the read contract for a saved workflow (nodes, edges, ports, metadata) shared by the form, API, and bundle import.
- **Workflow validation**: `WorkflowValidatorInterface` — the shared structural-validation choke point used by the entity form, the REST API, and bundle import.
- **Node-processor capability markers**: `ToolPassthroughInterface`, `BranchingNodeProcessorInterface`, `HasSideEffectsInterface` — opt-in interfaces a custom processor implements to declare tool-passthrough, branch-gating, and side-effect semantics.
- **Edge classification**: `EdgePortClassifier` — the utility orchestrators and the compiler share to classify edges (data / tool-availability / branch) consistently.
- **Resolved interrupt**: `ResolvedInterruptInterface` — the DTO contract for a resolved interrupt handed back to the orchestrator.

The bundle/marketplace transport subsystem (signing, verification, trusted publishers, capability manifest, node-type generation, bundle import/export) is **`@internal`** in 2.0.0: the PHP classes may change without notice. Its persisted surface — the `flowdrop_trusted_publisher` config entity type and its config schema — is, like all config/entity surface, covered by the Configuration Schema and Entity Type rules below.

### `@internal`

Classes marked `@internal` are implementation details with **no BC promise**:

- May change, move, or be removed in any release (including patches) without notice.
- Should not be extended, instantiated, or type-hinted against by external code.
- Typically also marked `final` to prevent extension.

This includes all classes outside the `@api` surface: entity classes and interfaces, controllers, forms, list builders, hook implementations, concrete service implementations, storage classes, DTOs, exception classes, orchestrator plugins, and queue workers.

## HTTP API Stability

FlowDrop's HTTP endpoints under `/api/*` (defined by `*ApiController` classes — pipeline, playground, interrupt, job, trigger, snapshot, chat) are **`@internal`**. They exist to serve the bundled `@flowdrop/flowdrop` JavaScript library (the **FlowDrop Editor** and **Playground** components) and are **not a public REST contract**.

- Endpoint paths, query parameters, request bodies, and response shapes may change between any two FlowDrop releases — including minor releases — without a deprecation cycle.
- The HTTP layer ships in lock-step with the bundled JS library; consumers should use the matching JS library version rather than calling endpoints directly.
- The OpenAPI document at `docs/development/api/openapi.yaml` describes the current shape for reference only and is not a stability promise.

### Why these endpoints can't be a stable contract

The HTTP layer is the interop boundary between the Drupal backend and the FlowDrop Editor / Playground JS components. Both halves are versioned together and ship from this repository as a single unit, and the wire format is dictated by what the editor of a given version needs to render and operate on. That coupling is structural, not a temporary state we plan to grow out of:

1. **Editor features extend the wire shape.** Every editor capability that surfaces backend state — new node-type metadata, port typing, visual hints, execution telemetry, interrupt shapes — adds or restructures fields on the response. The 1.4 series added typed I/O ports, schema snapshots, lifecycle events, pipeline bundles, linked interrupts, and a HITL inbox; each of those reshaped at least one endpoint to carry the new state. Holding the wire format frozen would either freeze editor evolution or force every new field through a parallel side-channel, both of which we'd reject in review.
2. **The Drupal module and the editor are released together.** A given Drupal site runs the JS library bundled in the matching FlowDrop module version. Within a single deployment there is exactly one client and exactly one server, and they're version-matched by construction. The classic motivation for a stable REST contract — independently deployed clients you cannot coordinate with — does not apply.
3. **Versioning the URL would not buy stability, only duplication.** A `/api/v1` / `/api/v2` scheme would require us to maintain both shapes in the same Drupal release, which means twice the controller code, twice the surface area for security review, and a forced freeze on whichever version is declared "stable." Given (2), the result is cost without a corresponding consumer.
4. **This matches Drupal core's posture.** The internal AJAX, layout-builder, big-pipe, and CKEditor endpoints that core uses to power its admin UI are not part of core's BC promise either, for the same structural reason: they're a private interop layer between core PHP and core JS, not a public REST API.

If you need a stable programmatic interface, type-hint against the `@api` PHP classes listed above (the FlowDropNodeProcessor, Orchestrator, Trigger, Workflow Executor, and StateGraph contracts) rather than the HTTP endpoints. For an integration that genuinely needs to be an HTTP client of FlowDrop independent of the bundled editor, open an issue describing the use case so we can decide whether to expose a separate, deliberately-stable surface for it.

## Configuration Schema

Configuration schemas (`.schema.yml`) follow these rules in 1.x:

- Existing config keys will not be removed or renamed.
- New keys may be added with sensible defaults.
- Schema changes are additive-only.
- Config export/import compatibility is maintained within the 1.x line.

### Node-type and workflow config dependencies (for module authors)

A `flowdrop_node_type` or `flowdrop_workflow` config entity's `dependencies` block is a **derived snapshot** — recomputed by `calculateDependencies()` only on a non-sync save, and imported verbatim by config sync. Modules that ship these entities in `config/install` own keeping that snapshot correct:

- A node type must declare the `module` dependency on its executor plugin's provider, and must ship in a module whose dependency closure includes that provider. (FlowDrop derives this automatically on save; an empty `dependencies: {  }` block shipped in `config/install` is a bug.)
- A workflow declares a `config` dependency on each node type it references (2.0.0+); the shipping module must depend on every module providing a referenced node type.
- Regenerate dependency blocks from a fresh save/recalculation — never hand-edit them. See the [Upgrade Guide](../../../UPGRADE.md#for-module-authors-regenerate-shipped-node-type-and-workflow-config-dependencies) for the procedure and rationale.

FlowDrop regenerates only its own shipped config; contrib and custom modules must regenerate theirs.

## Entity Type Stability

Entity type IDs and their base field definitions are stable in 1.x:

- Entity type machine names will not change.
- Base fields will not be removed (new fields may be added via update hooks).
- Storage schema changes will always include update hooks.

## Plugin System Stability

Two plugin types are stable in 1.x:

**FlowDropNodeProcessor** — for creating custom node types:

- The `FlowDropNodeProcessor` attribute and `FlowDropNodeProcessorInterface` will remain backward compatible.
- Plugin discovery mechanisms will not change.

**Orchestrator** — for creating custom workflow execution strategies:

- The `Orchestrator` attribute, `OrchestratorPluginInterface`, and `OrchestratorPluginBase` will remain backward compatible.
- The interrupt contracts (`InterruptExceptionInterface`, `FlowDropInterruptException`) will remain backward compatible.
- Concrete orchestrator implementations (e.g., `SynchronousOrchestratorPlugin`) are `@internal` and not covered by BC guarantees.

New plugin types may be added in minor releases but are not covered by BC guarantees until marked `@api`.

## Drupal Version Support

FlowDrop 2.x requires Drupal `^11.3`. Drupal 10 is not supported. (FlowDrop 1.x required `^11.2`; the 2.0.0 release raises the floor to 11.3.)

## Reporting BC Breaks

If you believe a release introduced an unintended BC break to stable API, please report it in the [FlowDrop issue queue on Drupal.org](https://www.drupal.org/project/issues/flowdrop). Unintended BC breaks to stable API will be treated as bugs and fixed in a patch release.
