218 lines
11 KiB
Markdown
218 lines
11 KiB
Markdown
# Public Facade Refactor
|
|
|
|
## Status
|
|
|
|
Accepted direction; implementation has not begun. This feature roadmap defines
|
|
the intended end state and compatibility requirements. The companion
|
|
[implementation plan](implementation.md) defines the work sequence. Current
|
|
GoDoc and durable documentation remain authoritative until implementation lands.
|
|
|
|
## Purpose
|
|
|
|
Make Promptkit's root package a deliberately maintained consumer facade while
|
|
placing engine implementation and assembly behind Go's `internal/` boundary.
|
|
Consumers should depend only on intentional public contracts, and maintainers
|
|
should be able to refactor internal behavior without changing those contracts.
|
|
|
|
The aim is a clearer ownership boundary, not the smallest possible root package
|
|
or a reduction in consumer capabilities. Private root functions are already
|
|
inaccessible to consumers; relocating them improves separation but does not by
|
|
itself control the exported API. The refactor must also protect public type
|
|
ownership, signatures, fields, and method sets against accidental exposure of
|
|
implementation details.
|
|
|
|
## Current Position
|
|
|
|
Promptkit already places execution, repair, capacity management, rendering,
|
|
source loading, transport, and validation in specialized internal packages.
|
|
Its [architecture policy](../policy/architecture.md) already identifies the
|
|
root package as the supported public facade.
|
|
|
|
The remaining root implementation includes engine construction and collaborator
|
|
assembly, source selection, profile overlay construction, filesystem source
|
|
setup, and an in-memory profile repository. These responsibilities can move
|
|
inward while the root retains public declarations and explicit adapters.
|
|
|
|
ConfigKit's completed facade refactor is a design reference: root-owned public
|
|
types wrap private engine state and expose explicitly selected methods. Its
|
|
implementation should inform this work without introducing a dependency on
|
|
ConfigKit or copying mechanisms that Promptkit does not need.
|
|
|
|
## Target End State
|
|
|
|
### Root-Owned Public Contract
|
|
|
|
The root `promptkit` package remains the consumer import path and owns:
|
|
|
|
- public named types, interfaces, constants, and error identities;
|
|
- public configuration, request, result, inspection, and profile values;
|
|
- constructors, options, and deliberate forwarding methods;
|
|
- opaque public handles backed by private internal state;
|
|
- public GoDoc and supported serialization and formatting behavior; and
|
|
- explicit value conversion, injected-collaborator adaptation, and public
|
|
error translation where they cross the facade boundary.
|
|
|
|
Public types must remain root-defined. Do not alias them to internal types,
|
|
anonymously embed internal implementations to promote methods, expose internal
|
|
types in public fields or signatures, or add public bridge methods for wiring.
|
|
Private fields may refer to internal implementations.
|
|
|
|
Straightforward convenience constructors and boundary code may remain in the
|
|
root. A forwarding layer or additional record type should have a concrete
|
|
ownership or compatibility purpose; moving every helper is not an objective.
|
|
|
|
### Internal Engine Assembly
|
|
|
|
A cohesive internal assembly owner constructs an operational engine from
|
|
internal configuration and supplied collaborators. `internal/engine` is the
|
|
proposed home; exact private package and helper layout belongs in the
|
|
implementation plan. Its responsibilities
|
|
include source selection and defaults, maintained catalog loading, profile
|
|
overlay assembly, backend registration assembly, capacity-manager construction,
|
|
default client and validator selection, and runner/repairer wiring.
|
|
|
|
The public `Engine` delegates through private state to internal implementation.
|
|
Root options express consumer choices and translate public values; internal
|
|
construction owns how those choices assemble components. Preserve established
|
|
contracts for option capture, application, validation, and source access.
|
|
Incidental private ordering is not a new compatibility requirement.
|
|
|
|
Build on the existing specialized internal responsibilities. Internal assembly
|
|
is the composition owner, not a replacement for the runner,
|
|
catalog adapter, profile repositories, transport, or domain packages. It should
|
|
not duplicate execution orchestration already owned by `internal/usecase`.
|
|
|
|
Move the in-memory profile repository behind the internal boundary;
|
|
`internal/profile` is its natural home. Reuse existing definition validation and
|
|
copying owners. Other root implementation
|
|
helpers should move to their cohesive existing owner or to internal assembly
|
|
as appropriate. Avoid generic registries, service locators, or a new extension
|
|
framework for this relocation.
|
|
|
|
Dependency direction remains root facade to internal components. Internal
|
|
production packages must not import the root package. The root can use internal
|
|
domain values and narrow collaborator interfaces for explicit conversions;
|
|
this proposal does not require all root imports to pass through a single
|
|
internal package or require duplicate forwarding APIs to achieve that shape.
|
|
|
|
## Compatibility Requirements
|
|
|
|
This is a behavior-preserving refactor covering the actual exported surface,
|
|
including methods and fields. An exported declaration is
|
|
accessible even when it is absent from the consumer guide. Do not infer that
|
|
an apparently low-level declaration is safe to remove: injected model clients
|
|
and other intentional extension contracts may rely on it.
|
|
|
|
Preserve existing public names, signatures, named-type identity, method sets,
|
|
interface satisfaction, exported struct fields, and supported value behavior.
|
|
Any discovered API removal or redesign requires a separate explicit decision
|
|
and consumer migration rationale; the minor release is not blanket permission
|
|
to remove accessible declarations.
|
|
|
|
The refactor must preserve, in particular:
|
|
|
|
- established option order, replacement and accumulation rules, nil behavior,
|
|
validation timing, and capture/copy contracts;
|
|
- profile-source precedence, lazy consumer source reads, inheritance, and
|
|
maintained-catalog validation;
|
|
- public error identities and typed errors through `errors.Is` and `errors.As`,
|
|
including cancellation propagation and sensitive-detail redaction;
|
|
- public JSON representations, formatting, and defensive-copy guarantees;
|
|
- injected client and artifact-reader contracts, including caller ownership
|
|
of collaborator values;
|
|
- preparation and inspection semantics, hash relationships, request overrides,
|
|
appended messages, output validation, and bounded repair;
|
|
- prepared-execution engine binding, shared lifecycle when handles are copied,
|
|
single-use execution, discard behavior, and credential retention; and
|
|
- engine-local concurrency, admission, cancellation, usage accounting, and
|
|
transport behavior.
|
|
|
|
Preserve intentional contracts without elevating incidental private layout,
|
|
helper names, operation ordering, diagnostic wording, or opaque hash encodings
|
|
into new promises. The baseline inventory identifies accessible API; it is
|
|
not authority to turn every observed implementation behavior into a contract.
|
|
|
|
## Verification And Test Ownership
|
|
|
|
Follow the [testing policy](../policy/testing.md). Existing external-package
|
|
contract tests and maintained offline examples should continue to exercise the
|
|
same consumer API. Tests coupled to private layout may be adapted or
|
|
consolidated under the testing policy without changing their contract-level
|
|
expectations.
|
|
|
|
Move implementation tests with their owning behavior when package relocation
|
|
requires it. Keep focused source, profile, runner, capacity, and transport
|
|
coverage at the existing internal owners. Root tests should focus on public
|
|
compatibility, boundary conversion, error adaptation, and representative
|
|
assembled workflows. Do not duplicate internal test matrices at the facade or
|
|
add one test per trivial forwarding method.
|
|
|
|
Add a focused public-boundary check that detects internal types escaping
|
|
through exported types, signatures, fields, or promoted methods, and rejects
|
|
public aliases to internal implementations. Use Go's type information where
|
|
needed to inspect the actual exported method sets. The check must permit
|
|
private internal state and the established sealed option mechanism. Protect
|
|
the no-internal-production-imports-of-root dependency rule without freezing an
|
|
incidental file layout or exact internal package inventory.
|
|
|
|
Compatibility evidence includes an unchanged exported surface and behavioral
|
|
coverage of consequential boundary risks: option timing, conversion ownership,
|
|
typed errors, and prepared-execution lifecycle. Acceptance requires the complete
|
|
[maintainer validation workflow](../development.md#maintainer-validation),
|
|
including race checks and both offline examples. No live provider calls or
|
|
sibling repository are required for validation.
|
|
|
|
## Relationship To The Profile Policy Work
|
|
|
|
This refactor and the [profile-policy proposal](profile-policy.md) are separate
|
|
scopes that may ship together in the planned `v0.10.0` release. Establish the
|
|
facade boundary with current behavior preserved before implementing the
|
|
catalog-policy and standard-profile changes. Their assembly logic can then
|
|
land in its intended internal owner.
|
|
|
|
This roadmap does not itself change catalog versions, introduce standard
|
|
profiles, or adopt the provisional profile compatibility policy. Release
|
|
guidance should distinguish the internal refactor from the deliberate consumer
|
|
policy changes accompanying it. A completed facade refactor should require no
|
|
consumer migration on its own.
|
|
|
|
## Documentation End State
|
|
|
|
Update the [architecture policy](../policy/architecture.md) to describe the
|
|
implemented facade and assembly boundary, and the
|
|
[component overview](../internal/overview.md) to identify the new owner and
|
|
relocated responsibilities. Update affected internal source and runner
|
|
documentation and links when implementation moves.
|
|
|
|
Go declarations and GoDoc remain the canonical public contract. Consumer and
|
|
format documentation should not acquire new requirements from a private
|
|
relocation. Record the durable facade decision in an ADR if needed to preserve
|
|
its rationale; ConfigKit is a reference, not an ongoing normative dependency.
|
|
Remove this temporary roadmap after completion and durable documentation
|
|
updates according to the [documentation policy](../policy/documentation.md).
|
|
|
|
## Completion Criteria
|
|
|
|
- The root exposes deliberate, root-owned consumer contracts and explicit
|
|
adapters without leaking internal types or promoted implementation methods.
|
|
- Internal assembly and repositories own the relocated implementation, with
|
|
one production path and no parallel legacy engine.
|
|
- Specialized internal components retain clear ownership and do not import
|
|
the public facade.
|
|
- Public API comparison and behavioral tests establish compatibility,
|
|
including ownership, errors, option timing, and prepared execution.
|
|
- Boundary checks protect accidental API exposure without preventing ordinary
|
|
internal refactoring or consumer extension.
|
|
- Required validation passes, documentation matches the implemented state,
|
|
and consumers require no migration for this refactor.
|
|
|
|
## Non-Goals
|
|
|
|
- Public API expansion, removal, or redesign.
|
|
- Changes to provider behavior, formats, defaults, or execution semantics.
|
|
- Replacing the existing specialized packages with one large engine package.
|
|
- A dependency on ConfigKit or a reusable facade-generation framework.
|
|
- A minimum root-package line count, exhaustive wrapper tests, or a blanket
|
|
prohibition on private boundary logic in the root.
|
|
- Implementing the separate profile-policy roadmap during this refactor.
|