Skip to content

Story: Review and stabilize public contracts for spatial-types 1.0.0 #27

Open

Description

@Alexandre-T

Review and stabilize public contracts for spatial-types 1.0.0

As a maintainer of spatial-types,
I want to review, classify and stabilize the contracts exposed by the library before 1.0.0,
so that consumers can clearly distinguish the supported public API from internal implementation details and rely on the public contracts throughout the 1.x lifecycle.

Context

spatial-types 1.0.0 establishes the first stable public API of the library.

After 1.0.0, changes to supported public contracts must follow the project's backward-compatibility and semantic-versioning policy.

Before that boundary is established, every symbol currently accessible to consumers must therefore be intentionally reviewed.

PHP visibility alone does not determine whether a symbol belongs to the supported public API.

A class, interface, enum or other symbol may need public PHP visibility for implementation reasons while still being an internal implementation detail that consumers must not rely on.

The review must distinguish these cases explicitly before the 1.0.0 release.

Prerequisite

The normative conformance review for the 1.0.0 scope must be completed before the public contracts are stabilized.

All blocking normative findings must be resolved.

This ensures that spatial-types does not deliberately stabilize a public contract whose spatial semantics are already known to require a backward-incompatible correction.

Contract Classification

Every accessible symbol within the library must be reviewed and classified.

The supported classifications are:

Public API

A Public API symbol is an intentionally supported contract of spatial-types.

Consumers may rely on it.

Its backward compatibility is protected throughout the 1.x lifecycle according to the project's semantic-versioning policy.

Internal API

An Internal API symbol remains accessible because its visibility is required by the implementation or architecture, but it is not part of the supported public contract.

Internal symbols must be explicitly marked with:

/**
 * @internal
 */

Internal symbols may change without the backward-compatibility guarantees applied to the supported public API.

Private implementation

A symbol that does not need to be accessible outside its implementation context should not remain publicly exposed solely for convenience.

Where appropriate, its visibility must be reduced or the symbol removed from the externally accessible architecture before 1.0.0.

Internal Namespace Policy

The @internal marker is the authoritative declaration that an accessible symbol is not part of the supported public API.

When structurally appropriate, internal implementation symbols should additionally be placed under an Internal namespace.

For example:

LongitudeOne\SpatialTypes\Internal\...

Moving a symbol into an Internal namespace is encouraged when it improves the architectural boundary without unnecessarily damaging the logical organization of the package.

The namespace move is not mandatory when it would produce an artificial or less coherent structure.

The following rules apply:

  • every symbol under an Internal namespace must be marked @internal;
  • an @internal symbol is not required to belong to an Internal namespace;
  • @internal remains authoritative regardless of namespace;
  • moving an existing symbol into an Internal namespace before 1.0.0 is permitted when it improves the architecture.

Public Contract Review

Every symbol classified as Public API must be deliberately reviewed as a contract intended to remain compatible throughout the 1.x lifecycle.

The review must consider, where applicable:

  • namespace and symbol name;
  • interfaces and inheritance;
  • implemented interfaces;
  • constructor signatures;
  • public method signatures;
  • parameter types;
  • return types;
  • nullable contracts;
  • public constants;
  • enum cases;
  • documented exceptions;
  • mutability and immutability expectations;
  • value semantics;
  • spatial type semantics;
  • extension points;
  • use of final;
  • public and protected members relevant to inheritance;
  • types exposed through parameters or return values.

The review must identify contracts that would unnecessarily restrict future backward-compatible evolution.

Known design problems that would reasonably require a future backward-incompatible change must be corrected before the contract is considered stable.

Extensibility Review

Public extensibility must be intentional.

For each public class that can be extended, the review must determine whether inheritance is an intended part of the supported API.

When inheritance is not intended, the class should be made final when doing so is compatible with the architecture.

When inheritance is intentionally supported, the inherited contract must be considered part of the compatibility review, including relevant protected members and overridable methods.

Public interfaces require particular attention because adding a required method to an interface after 1.0.0 may break consumer implementations.

Interfaces must therefore expose only contracts that are intended to remain stable or evolve compatibly throughout the 1.x lifecycle.

Internal API Leakage

Internal implementation details must not leak through supported public contracts.

A Public API symbol must not require consumers to manipulate an @internal symbol in order to use the supported API.

In particular, internal symbols must not appear in public contracts where doing so effectively makes the internal type part of the consumer-facing API.

This includes, where applicable:

  • constructor parameters;
  • public method parameters;
  • public return types;
  • implemented public interfaces;
  • inherited public contracts;
  • public properties;
  • other consumer-visible type declarations.

Any such leakage must be corrected before 1.0.0.

Cross-Package Usage

Other LongitudeOne libraries should consume the supported Public API of spatial-types.

They must not rely on @internal symbols as an implicit cross-package contract.

Known usages of spatial-types internal symbols by dependent LongitudeOne libraries must be identified.

When such usage exists, either:

  • the required capability must be exposed through an intentional Public API contract; or
  • the dependent library must be changed to avoid the internal dependency.

An internal API must not become a hidden compatibility contract merely because another LongitudeOne package currently uses it.

Pre-1.0 Stabilization

This Story may modify existing contracts when necessary to establish a coherent 1.0.0 API.

Because the library has not yet established its stable 1.0.0 contract, the review may result in changes such as:

  • renaming symbols;
  • changing namespaces;
  • changing signatures;
  • reducing visibility;
  • marking symbols @internal;
  • moving symbols into an Internal namespace;
  • making classes final;
  • removing unintended extension points;
  • changing inheritance relationships;
  • removing accidentally exposed implementation details;
  • correcting other public API design issues.

Such changes must be completed before the affected contracts are declared stable.

Public API Inventory

The review must produce or maintain an identifiable inventory of the supported Public API.

The inventory must make it possible to determine which accessible symbols are protected by the 1.x backward-compatibility commitment.

The classification must be derivable from the codebase and must not rely solely on undocumented maintainer knowledge.

Internal symbols must be machine-identifiable through the @internal marker.

Acceptance Criteria

Inventory and classification

  • All externally accessible symbols are included in the review.
  • Every reviewed symbol is intentionally classified as Public API, Internal API or private implementation.
  • The supported Public API for 1.0.0 is identifiable.
  • Every accessible symbol classified as Internal API is marked @internal.
  • Every symbol located under an Internal namespace is marked @internal.
  • Internal symbols are moved under an Internal namespace when doing so improves the architecture without unnecessarily damaging its structure.
  • Symbols that do not need external visibility have their exposure reduced where appropriate.

Public contract stability

  • Namespaces and symbol names intended for the Public API have been reviewed.
  • Public constructors and method signatures have been reviewed.
  • Parameter and return types have been reviewed for long-term compatibility.
  • Public exception contracts have been reviewed.
  • Public enums and their cases have been reviewed.
  • Mutability and value semantics relevant to consumers have been reviewed.
  • Known public API design issues likely to require a future backward-incompatible correction are resolved before 1.0.0.

Extensibility

  • Every extensible public class has been reviewed to determine whether inheritance is intentionally supported.
  • Classes not intended as extension points are made final where appropriate.
  • Supported inheritance contracts have been reviewed for backward-compatibility implications.
  • Public interfaces have been reviewed with the assumption that consumer implementations may exist after 1.0.0.
  • Unintended extension points are removed before the public API is stabilized.

Internal boundaries

  • No @internal symbol leaks through a supported Public API contract in a way that requires consumers to depend on it.
  • Public constructors do not require internal types.
  • Public methods do not require internal parameter types.
  • Public methods do not expose internal return types.
  • Known cross-package usages of spatial-types internal APIs are identified.
  • Other LongitudeOne libraries required for the 1.0.0 ecosystem do not depend on spatial-types internal symbols as hidden compatibility contracts.

Stabilization

  • All changes required to establish the intended Public API boundary are completed.
  • All symbols remaining in the Public API are intentionally accepted as supported 1.x contracts.
  • All symbols intentionally excluded from the supported API are explicitly internal or no longer externally exposed.
  • The complete test suite passes after stabilization.
  • All project quality checks pass.
  • The resulting Public API is ready to serve as the compatibility baseline for spatial-types 1.0.0.

Out of Scope

This Story does not:

  • perform the normative conformance review;
  • change normative spatial behavior already approved by that review;
  • implement additional geometry types;
  • validate every supported dependency combination;
  • perform the final 1.0.0 release validation;
  • publish the 1.0.0 release;
  • define new functionality solely to anticipate hypothetical future requirements.

Those concerns belong to their respective Stories.

Completion Principle

Completion of this Story establishes the intended compatibility boundary of spatial-types 1.0.0.

After this Story is complete, a symbol remaining in the supported Public API is considered an intentional contract that must be treated according to the backward-compatibility guarantees of the 1.x lifecycle.

Symbols marked @internal remain outside that compatibility commitment even when PHP visibility requires them to remain publicly accessible.

Activity

  1. added this to the Version 1.0.0 milestone on Oct 4, 2026
  2. added theissue type on Oct 4, 2026
  3. changed the title [-]Review and stabilize public contracts for `spatial-types` 1.0.0[/-] [+]Story: Review and stabilize public contracts for `spatial-types` 1.0.0[/+] on Oct 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    impact:apiAffects the public APIimpact:architectureRequires or affects an architecture decisionspatial:geometryRelated to geometry models or types

    Type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions