Plan the profile policy implementation

This commit is contained in:
2026-09-22 12:06:24 +00:00
parent e5870453f9
commit 3bc624ec3f

View File

@@ -1,337 +1,262 @@
# Public Facade Refactor Implementation Plan
# Profile Policy Implementation Plan
## Scope And Authority
## Scope And Starting Point
Implement the [public facade roadmap](public-facade.md) without changing the
consumer API or execution behavior. This plan owns implementation sequence;
the feature roadmap owns the target state and compatibility requirements.
The provisional [profile policy](profile-policy.md) is a separate, subsequent
scope. Do not update catalog dependencies, introduce standard profiles, change
profile stability promises, or prepare a release in these stages.
Implement the [profile-policy roadmap](profile-policy.md): volatile external
profile catalogs, dated `/v2` catalog modules, and two Promptkit-owned stable
profile names. This replaces the completed public-facade implementation plan.
The facade refactor and its review remediation are complete; composition work
belongs in `internal/engine`, not the public package.
Read `AGENTS.md`, the [development guide](../development.md), and all three
policies before starting: [architecture](../policy/architecture.md),
[documentation](../policy/documentation.md), and [testing](../policy/testing.md).
Use existing GoDoc and canonical consumer/format documentation to distinguish
intentional contracts from incidental implementation. If a relocation appears
to require a consumer-facing change, stop and report it rather than silently
changing the contract. Existing exported declarations are not removal candidates
merely because a guide does not mention them.
The feature roadmap still labels its policy provisional. Before executing
Stage 1, confirm maintainer acceptance of this plan and update that roadmap's
status to accepted for implementation, linking here for sequencing. Remove
superseded procedural language there without changing its intended end state.
Until implementation lands, existing durable contracts remain authoritative.
Each numbered stage is one implementation prompt. Complete stages in order;
keep the repository building and maintain one active production path after
each stage. Update affected durable documentation when its described ownership
changes, rather than leaving inaccurate descriptions until the final stage.
For each stage, run focused tests while developing and the complete
[maintainer validation workflow](../development.md#maintainer-validation)
before acceptance. Report changes, validation results, and any unresolved
failures. Do not use live providers, credentials, sibling repositories, module
replacements, or a Go workspace to validate the result.
Execute stages in numerical order, one coding-agent prompt per stage. Stage 2
is a release handoff requiring explicit publication authority. This plan does
not itself authorize releases or pushes. Do not carry forward completion marks
or API snapshots from the previous implementation plan.
Read `AGENTS.md`, [development](../development.md), all policies under
`docs/policy/`, [formats](../formats.md), [internal sources](../internal/sources.md),
and [release procedure](../release.md). Read each catalog repository's own
instructions and release procedure before editing it. Preserve unrelated
changes. For every implementation stage, run focused tests and the affected
repository's complete validation workflow before acceptance. Report results
and blockers; do not treat an unrun check as successful.
## Implementation Decisions
- Add `internal/engine` as the composition owner. It owns engine construction,
defaults, source assembly, catalog loading, registry and capacity construction,
and runner/repairer wiring. It delegates execution to `internal/usecase`;
it does not become a second runner.
- Keep root-defined public types, errors, options, conversions, collaborator
adapters, and formatting. Root `Engine` holds a private `*engine.Engine`.
The internal engine exposes only the domain-level operations needed for
the existing facade methods. No public bridge methods or internal aliases.
- Preserve root `Option` and its sealed `apply(*engineOptions) error` mechanism.
Ultimately, private root `engineOptions` wraps an internal `engine.Options`
value whose private state and setters own source construction and option
accumulation. Root options remain closures applying in caller order; do not
replace them with a deferred list that changes when errors or copies occur.
- Put the memory profile repository in `internal/profile`. Existing domain,
profile validation, and JSON-copy helpers remain the owners of their rules.
Do not duplicate validation in the facade and repository.
- Keep public error classification and redacted public error construction in
the root. Internal construction returns descriptive errors; `NewEngine`
translates construction failures to `ErrInvalidConfig` as it does today.
Runtime errors continue through `mapPublicError` at the public boundary.
- Keep `PreparedExecution` root-defined with its existing private use-case
handle. Pass that internal handle through engine delegation without copying
its execution state or creating another lifecycle owner. Private root
references to specialized internal packages are allowed.
- Do not impose a single internal import on the root, introduce a generic
builder framework, add caching, broaden validation, or migrate all private
helpers merely to reduce root line count. Straightforward public convenience
constructors and boundary conversions may remain where they are.
- Both catalog modules move to `/v2` paths and `v2.YYYYMMDD.N` releases. Use the
actual UTC publication date and the next unused revision starting at zero;
no placeholder tag or preliminary `v2.0.0` is needed. Modules release
independently. Preserve published tags and their historical contracts.
- Only external profile data becomes volatile. Go APIs, manifest/format
semantics, backend IDs and definitions, and Promptkit runtime behavior remain
outside the exception. Promptkit adds no live model or endpoint checks.
Catalog owners remain responsible for upstream mapping accuracy.
- The only profile-specific continuity guarantees are the literal names
`promptkit-openrouter-standard` and `promptkit-openrouter-auto`, within the
selected-and-tested dependency scope and absent consumer overrides. Models,
backends, routing, defaults, and other selection characteristics are not
permanent promises. Do not add notice or approval gates for later selections.
- Initially, standard inherits `gemini-flash-latest`; auto directly selects
backend `openrouter` and model `openrouter/auto`. Add no generation overrides,
connection metadata, implicit default selection, public API, or fallback loop.
- Construct the two raw definitions as internal Go values through
`profile.NewMemoryRepository`, owned by a focused `internal/engine` helper.
Two definitions do not justify another embedded asset tree or package.
- Compose raw sources in this order: consumer memory, ordinary consumer source,
consumer fallback source, Promptkit-owned profiles, external catalogs. Keep
one runtime resolver over the complete hierarchy. Separately validate the
maintained-only composition at construction without freezing its resolved
values into the runtime source.
- Reject the exact `promptkit-` prefix on normalized external catalog IDs in
`internal/catalog.Load`. Do not impose that reservation on consumer sources,
fold case beyond existing ID rules, or alter generic repositories.
- Replace the old external-catalog extraction snapshot with structural and
maintained-name tests. Do not create another full-profile inventory snapshot:
module versions/checksums identify selected data, while repeated snapshots
recreate catalog churn. Preserve backend-contract coverage separately.
- The transition targets a new Promptkit minor release, currently `v0.10.0`.
Later catalog-only updates and maintained-selection adjustments may ship as
patches if other contracts remain intact. Promptkit retains semantic versioning.
## Stage 1: Establish The Compatibility Baseline
## Stage 1: Prepare Both Catalog Modules For The New Contract
Purpose: make the compatibility review concrete before moving ownership.
Repositories: `../promptkit-backend-openrouter` and
`../promptkit-backend-rakestrawhome`. Their small data-only packages make this
one bounded prompt; keep changes in their respective repositories.
1. Read the root declarations and tests, the
[consumer guide](../consumers/pkg-promptkit.md),
[component overview](../internal/overview.md),
[sources document](../internal/sources.md), and
[runner document](../internal/runner.md). Identify existing contract coverage
for constructor options, profile sources, injection, errors, and prepared
execution. Read their owning internal tests before adding new coverage.
2. Record the pre-refactor commit ID in this plan and capture an exported API
inventory for the final comparison. Include exported declarations, named
types, fields and tags, interface signatures, value and pointer method sets,
constants, error variables, and serialization/formatting contracts. `go doc
-all` is a useful starting point, not a complete method-set comparison.
Temporary comparison output belongs outside tracked source; do not introduce
a permanent snapshot of private structure or freeze every future API addition.
3. Use existing tests first. Add only missing, consequential public regression
coverage for relocation risks: source replacement versus backend accumulation,
option application/capture timing, ownership of injected values and profiles,
nil/zero facade behavior, and typed error translation. Keep public behavior
tests in the external test package where practical. Do not duplicate full
source, transport, capacity, or runner matrices.
4. In particular, inspect the existing contracts around `WithProfiles` copying
during option application and `WithBackend` capturing the queue-capacity
pointer value during option creation. Preserve explicit zero versus unset.
Keep errors from an invalid earlier option observable even if a later option
would replace it. Do not add reflection-based typed-nil rejection or eagerly
read lazy consumer sources as part of the refactor.
1. Inspect both worktrees, module files, tags, assets, tests, README files, and
`docs/release.md`. Preserve maintainer changes. The current OpenRouter
checkout already contains a profile refresh; retain it rather than reverting
to Promptkit's selected v1 catalog. Additional model curation is out of scope.
2. Change each module declaration to its existing path plus `/v2`, and update
self-imports and examples. Preserve package names, `FS()`, `Root`, embedded
layout, manifest schema, and backend definitions. Do not introduce a
dependency on Promptkit or duplicate its runtime validation.
3. Revise compatibility documentation: profiles may be added, removed, renamed,
or modified without deprecation or notice; backend definitions, public Go
API, and schema compatibility do not gain that exception. Describe dated
versions and explain that dates do not certify live availability. Do not
pretend a README change retroactively changes the v1 contract.
4. Update each release procedure for `/v2`, dated tags, immutable versions,
independent release dates, and normal module-resolution checks. Retain its
existing validation and annotated source-tag publication requirements.
5. Keep proportionate data-package tests for the exported filesystem and asset
shape. No network calls, credentials, provider SDKs, runtime dependencies,
or cross-version profile-continuity assertions. Run both full workflows.
Acceptance: the pre-refactor baseline is identified, necessary regression
coverage passes, and no production ownership or behavior has changed. If the
existing tests already cover these risks, do not add tests solely to fill this
stage; record the coverage reviewed and proceed.
Acceptance: both source trees are ready for dated v2 releases; their asset APIs
and backend manifests are unchanged apart from module identity. Report the
candidate commits and validation. Do not publish without authority.
### Completion
## Stage 2: Publish And Verify The Catalog Releases
- [x] Pre-refactor baseline commit: `7a858c2365e1a3625de67a46f5c488e0fe31856b`.
- [x] Captured the exported API inventory outside the tracked repository for
the final comparison.
- [x] Reviewed existing public coverage for source replacement, backend
accumulation, option error and capture timing, injected-value and profile
ownership, nil and zero facade behavior, prepared execution, and typed error
translation. The existing tests cover these relocation risks without a
duplicate matrix.
This is a maintainer-authorized publication stage, not a coding workaround for
unavailable dependencies. If authority or remote access is missing, report the
handoff and stop before adopting unpublished dependencies.
## Stage 2: Relocate The Memory Profile Repository
1. Follow each catalog's updated release procedure. Select an unused
`v2.YYYYMMDD.N` tag using the publication date, validate the clean candidate,
publish its source commit and only the selected annotated tag, and verify
the remote tag and peeled commit. Never move a published tag.
2. From a temporary module outside these repositories, resolve each exact
`/v2@version` with `GOWORK=off`, without replacements or vendoring. Verify
module identity and version. Downloads are not inference-provider probes
and are separate from offline test execution.
3. Record the two actual module versions and source commits in execution notes
in this plan for Stage 5. They need not share dates or revision numbers.
Purpose: move a self-contained repository before changing engine assembly.
Acceptance: both published dependencies resolve normally without sibling
checkouts, workspaces, or replacements.
1. Introduce `internal/profile.NewMemoryRepository` accepting internal profile
definitions. Move the map-backed repository and lookup implementation from
root `profiles.go` to that package. Preserve normalized duplicate-ID detection,
definition validation, missing-profile classification, inheritance metadata,
and independently owned values on storage and lookup.
2. Separate public field conversion from repository normalization as necessary.
Root `WithProfiles` converts at application time and invokes the new internal
constructor. Use the existing definition-normalization and JSON-copy owners
once at the repository boundary; preserve rejection of invalid extra values
and deep-copy guarantees without an unnecessary second validation pass.
Audit other callers before changing the responsibilities of `toDomainProfile`.
3. Remove the root repository implementation. Leave public `Profile` and
`OpenAICompatibleProfile` unchanged, including the convenience constructor's
documented copy behavior; do not strengthen that contract incidentally.
4. Move private repository tests to `internal/profile`, adapting inputs to
internal values. Retain representative public `WithProfiles` integration and
conversion coverage at the root. Add only uncovered copy/validation cases.
Update the internal source document and inventory for the new owner.
## Stage 3: Enforce The External Catalog Namespace
Acceptance: `WithProfiles` uses the internal repository in the active engine;
public behavior is unchanged and no duplicate root repository remains.
Repository: Promptkit. Keep current v1 dependencies during this stage;
dependency adoption remains atomic in Stage 5.
### Completion
1. In `internal/catalog.Load`, reject normalized profile IDs starting with
`promptkit-` while inspecting eager-loaded catalog metadata. Use the existing
descriptive catalog-construction error style with source context. Public
construction continues to classify failures as `ErrInvalidConfig`.
2. Preserve catalog-local inheritance, owning-backend validation, duplicate
detection, secret/connection-field rules, strict decoding, and value checks.
Do not relax these because profiles are volatile or add upstream validation.
3. Extend synthetic catalog tests with a reserved maintained name and an
otherwise unused `promptkit-` name. Confirm ordinary IDs still load. Keep
the rule out of generic parsing so consumer definitions can use the prefix.
4. Update internal source documentation for the implemented catalog-only
reservation. Do not yet claim the maintained profiles exist.
- [x] Moved the in-memory repository, normalization, validation, and defensive
copies into `internal/profile`.
- [x] Kept public conversion and `WithProfiles` application timing at the root.
- [x] Moved focused repository coverage to `internal/profile` and retained
facade-level copy timing coverage.
- [x] Updated the implemented component and source ownership documentation.
Acceptance: catalogs cannot occupy the namespace; existing protections and
consumer source behavior are unchanged.
## Stage 3: Move Engine Assembly And Delegation Inward
## Stage 4: Add And Compose Promptkit-Owned Profiles
Purpose: establish the internal engine while leaving source-option relocation
for the next prompt.
1. Add a maintained-profile helper in `internal/engine` with the two raw
definitions specified above. Build its memory repository, overlay it above
the raw external catalog repository, and supply that raw composition to the
existing consumer-source assembly.
2. During construction, resolve each Promptkit-owned definition through a
maintained-only resolver and check that its effective backend exists in the
maintained backend set. Reuse existing resolver and backend lookup owners;
do not implement another inheritance walker or target-policy validator.
External profiles retain catalog-local validation in `catalog.Load`.
Together these checks cover the maintained set without consumer definitions
or network access.
3. If a maintained definition fails to resolve, fail construction through the
existing `ErrInvalidConfig` boundary. Consumer overrides must not mask broken
bundled definitions. Keep raw definitions for runtime resolution so consumer
overrides of a maintained profile or its base still work. No resolved-profile
cache or global mutable repository is needed.
4. Use minimal synthetic composition tests for inherited selection, direct
selection, missing-base failure, and invalid backend reference. Expected
selections should follow the supplied definitions, not become permanent
literal model promises.
5. Add representative public inspection/preparation coverage proving both
literal names resolve, consumers can replace maintained profiles or their
bases, and default-profile selection is unchanged. Reuse source-precedence
and prepared-execution coverage rather than duplicating full matrices.
6. Update formats with the two current definitions, opt-in selection, and
precedence. Update internal ownership and source-validation documentation.
Scope intermediate compatibility claims to policy actually adopted so far.
1. Add internal `Config`, `Options`, and `Engine` types. Internal `Config` carries
the existing construction settings, not a new consumer configuration API.
For this stage, `Options` may carry the already-prepared collaborators,
repositories, backend definitions, and source-presence flags from the root
option state. Do not lose distinctions between an absent source and an
explicitly supplied empty source. Stage 4 removes this transitional mapping.
2. Move the assembly portion of root `NewEngine`, after option application,
into `internal/engine.New`, including maintained module imports and
`newProfileRepository`. Preserve the existing assembly semantics:
- prompt-source requirement and configured source defaults;
- validated maintained catalogs and engine-local backend registry;
- raw profile precedence: memory, ordinary configured source, application
fallback, maintained catalog; an explicit ordinary source replaces
`Config.ProfileDir`, and one resolver wraps the complete overlay;
- schema default and supplied validator selection;
- supplied or default client and artifact reader selection; and
- one capacity manager per engine, one capacity wrapper around the selected
client, and that same wrapped client used by runner and repairer.
3. Give internal `Engine` domain-level forwarding methods for the existing
prepare, run, prepared-execution, and inspection operations. Keep runner
orchestration and prepared-handle lifecycle in `internal/usecase`. Do not
add another queue, retry loop, mutex, source cache, or execution state machine.
4. Change root `Engine` to hold the internal engine. Root `NewEngine` still
applies options and maps constructor errors. Root methods still check
nil/zero receivers, convert/validate public requests at their existing
boundary, convert results, and translate runtime errors. Do not wrap an
error twice or expose internal typed provider errors instead of public ones.
5. Adapt tests that inspect private runner fields to the new owner or, where
feasible, observable contract assertions. Reuse existing tests for prepared
handle engine binding, shared copied-handle state, consumption/discard,
cancellation, redaction, repair, and capacity. Add an assembly test only if
a consequential wiring obligation is otherwise untested.
6. Update architecture, component inventory, sources, and runner documentation
to describe the implemented split. Remove the superseded root assembly path.
Acceptance: both names work through existing APIs, consumer precedence remains
effective, and no public exports or provider routing logic have been added.
Acceptance: all public operations route through one internal engine and the
existing runner; maintained catalogs and component wiring are internally owned.
Prepared-execution behavior and public error contracts remain unchanged.
## Stage 5: Adopt Published V2 Catalogs And Replace Snapshot Tests
### Completion
1. Update catalog imports in production and tests to `/v2`. Select the exact
Stage 2 versions through normal Go tooling, tidy module metadata, and review
`go.mod`/`go.sum`. No `latest`, unpublished revisions, unrelated upgrades,
or local replacements. Remove unused v1 requirements.
2. Replace `TestLoadPublishedCatalogsMatchCompatibilityFixture` with an offline
integration test loading both selected catalogs for structural acceptance.
Remove snapshot-only helpers and `testdata/builtin-catalog-v1.json` once no
callers remain. Retain malformed-input tests and backend metadata contract
coverage; add focused backend assertions if deleting the snapshot removes
their only protection. Backend definitions are not volatile profile data.
3. Run maintained-profile tests against the new modules. Verify standard's base
exists locally; if absent, change the maintained selection in this same
dependency update and document the current definition. This is not a new
permanent selection-approval gate. The inspected catalog currently contains
`gemini-flash-latest`, so no replacement is planned.
4. Convert tests that use removed external profiles for unrelated runtime
behavior to consumer-owned fixtures. Keep small real-catalog integration
coverage without coupling every runtime test to external inventories.
5. Review the catalog diff for local compatibility consequences, not provider
health. Do not restore removed IDs or add migration aliases just to preserve
the old snapshot. Confirm backend manifests and public/runtime contracts
did not change as a side effect.
- [x] Added `internal/engine` as the owner of engine assembly and runner
delegation.
- [x] Kept the public facade's option application, conversions, nil checks,
prepared-execution wrapper, and error translation at the root.
- [x] Updated architecture, component, source, and runner documentation for
the implemented ownership split.
Acceptance: Promptkit passes its full workflow using published v2 dependencies;
tests protect structural validity and maintained names without promising an
external inventory across releases.
## Stage 4: Move Option State And Source Construction Inward
## Stage 6: Publish Durable Policy And Consumer Guidance
Purpose: finish the ownership split without changing the public option API.
1. Update `docs/release.md`, the release-policy owner: narrow external-profile
exception, two-name continuity scope, initial minor transition, and later
patch eligibility. Replace its blanket catalog-update instruction to claim
no consumer migration is needed: removals may require consumer action.
Preserve ordinary compatibility and release records; do not require model
change announcements or additional selection gates.
2. Replace the exhaustive external profile table in `docs/formats.md` with links
to inventories at the selected catalog versions. Keep the small Promptkit
inventory here, label selections current rather than permanent, and link to
release policy for cross-version guarantees.
3. Explain consumer choices in the consumer guide: use a maintained name,
accept a volatile external profile, or define a complete application-owned
profile. Inheritance still follows base changes and can fail if the base
disappears; an application alias is not a frozen copy.
4. Explain selected-and-tested dependency scope and the resolved module graph:
independently upgrading a transitive catalog can break an inherited base.
Pinned data does not preserve upstream availability; running binaries neither
download updates nor automatically replace withdrawn models.
5. Update architecture, internal source/overview, and contributor documentation
only where ownership or workflow changed. Avoid duplicate inventories and
exact contracts. No live endpoint/model-list check belongs in adoption,
tests, or release validation.
6. Prepare `docs/releases/v0.10.0.md` as supplemental transition guidance linking
canonical policy/formats and describing potential profile migration. Add a
README link labeled unreleased until publication. Do not claim release
completion or require individual model-change notices.
1. Replace the root collaborator/flag record with a private wrapper around
`engine.Options`. Move the construction state into private fields of that
internal type. Remove Stage 3's transitional root-to-internal state mapping.
Internal setters correspond to the existing source, profile, backend, client,
and artifact options; no generic option registry or callback framework.
2. Move filesystem/`fs.FS` repository and validator construction, `fileSource`,
source-presence flags, replacement rules, and backend accumulation into
internal option methods. Invoke them during each root option's `apply`, not
collectively after all options. Preserve current file checks and lazy source
loading; do not add path restrictions or normalize actual paths beyond the
existing contract. Preserve separate blank checks for whitespace-bearing
valid paths.
3. Keep public-to-internal conversion and public collaborator adapters at the
root. Preserve closure capture and validation timing from Stage 1, including
queue-capacity capture, profile copies, nil options, and ordinary interface
nil checks. Internal methods consume internal values/interfaces without
importing root types. Do not copy injected client or reader implementations.
4. Root `NewEngine` now performs only ordered option application, configuration
translation, internal construction, and public error translation. Review the
remaining root imports/helpers: retain boundary work, remove dead assembly
helpers, and do not relocate formatting or conversion for appearance alone.
5. Move implementation-only option/source setup tests with their owner, while
retaining public timing and error assertions at the facade. Update affected
documentation immediately. No exact private field layout becomes a test
requirement.
Acceptance: durable documentation distinguishes stable literal names from
volatile selections and agrees across repositories without weakening unrelated
contracts.
Acceptance: the root no longer constructs repositories, validators, registries,
capacity managers, catalogs, or runners. Public options still have their existing
names, signatures, ordering, capture, and error behavior. No transitional state
mapping or duplicate source-assembly path remains.
## Stage 7: Final Integration Review And Release Handoff
### Completion
1. Run the complete Promptkit maintainer workflow: ordinary/race tests, vet,
build, both offline examples, formatting, local links, and hygiene. Verify
normal module resolution independent of sibling checkouts.
2. Compare public declarations against the completed facade baseline: no new
API, internal type leak, default-selection change, or consumer restriction
is intended. Confirm existing error, injection, override, inheritance, repair,
prepared-execution, and capacity tests still pass.
3. Check recorded dependency versions, maintained-name resolution without
consumer help, consumer overrides, and absence of cross-version external
inventory promises in tests or documentation.
4. Review for stronger promises than authorized: permanent backend/routing
implied by a profile name, change announcements, deprecation periods, or
live-service checks. Remove accidental guarantees rather than adding gates.
5. Report completion and the minor-release candidate. Retire completed roadmaps
only when requested or approved during release preparation. Promptkit
publication follows its release procedure under separate authority; do not
tag or push it merely because this stage passes.
- [x] Wrapped the root option state around internal engine options with private
construction state.
- [x] Moved filesystem and file source setup, source replacement, profile
repository construction, validator construction, and backend accumulation
into internal option methods.
- [x] Kept ordered public option application, boundary conversion, collaborator
adaptation, and error translation in the root facade.
- [x] Updated current architecture and internal ownership documentation.
## Stage 5: Guard The Public Boundary And Dependency Direction
Purpose: protect the intended architecture without freezing private layout.
1. Add a focused root architecture test using Go type information. Load the
compiled root package with standard-library `go list` export data and
`go/importer`/`go/types`; avoid a new production dependency or parsing only
surface syntax. It must work in the ordinary offline maintainer workflow
once normal module dependencies are available.
2. Inspect exported declarations, public field types, function signatures,
interface methods, and both pointer and value method sets. Follow nested
type expressions and aliases with a visited set to avoid recursion. Reject
references to this module's internal types in accessible public surfaces,
public aliases to those types, and internal anonymous embedding that exposes
implementation methods. Account for generics if encountered rather than
silently ignoring their signatures or constraints.
3. Permit private internal fields and the sealed `Option` method. Do not follow
inaccessible fields as if they were public contracts or reject all aliases
indiscriminately. Check accessible promoted methods even if the embedded
field itself is unexported. Do not require the root to import only
`internal/engine`, or impose rules on unrelated third-party internals.
4. Check production package imports, using package metadata, for any dependency
from this module's `internal/` packages to its root. Exclude external test
packages from that restriction. Do not assert an exact internal package list.
5. Exercise the boundary checker with a small in-memory fixture set: allowed
private internal state and sealed option; forbidden direct/nested internal
signature or field; forbidden internal alias and promoted method. Keep the
test helper local and proportionate, not a reusable architecture framework.
Acceptance: the completed refactor passes the checks; representative violations
fail for the intended reason, and ordinary private implementation changes remain
possible. No ConfigKit checkout or other sibling is needed.
### Completion
- [x] Added a compiled-export-data checker for the root facade's reachable
public type surface, including aliases, promoted methods, and generic
constraints.
- [x] Added package-metadata validation that production internal packages do
not import the root facade.
- [x] Added compact in-memory fixtures for permitted private state and sealed
options, and for direct, nested, field, alias, and promoted-method leaks.
- [x] Recorded the dependency-direction rule in the architecture policy.
## Stage 6: Complete Compatibility And Documentation Review
Purpose: verify the whole refactor, not just successful compilation of each move.
1. Compare the final exported API against the Stage 1 commit, including method
sets, fields/tags, type ownership, interfaces, and public error identities.
Review any difference; no API additions/removals/redesigns are authorized.
Inspect supported serialization and formatting alongside the existing tests.
2. Review the final root package for retained business assembly or duplicated
repositories, and the internal engine for duplicated runner behavior. Review
test moves for lost assertions and duplicate matrices. Existing specialized
packages should still own their detailed behavior tests; facade tests should
prove conversion, compatibility, and representative assembled behavior.
3. Finish the durable documentation review: architecture owns dependency rules;
the internal overview inventories owners; sources and runner docs explain
their current implementation. Correct stale links and root-assembly claims.
Keep public GoDoc authoritative and avoid adding consumer migration steps,
format rules, or new guarantees for an internal relocation. No separate ADR
is needed merely to restate the existing facade policy.
4. Run the entire maintainer workflow, including race tests, vet, build, both
offline examples, formatting, local links, and repository hygiene checks.
Review the complete diff against the baseline. Report any environmental
validation blocker explicitly; do not call an unrun check successful.
5. Report completion against the feature roadmap criteria. Retain these two
temporary documents for the maintainer's completion review; their later
retirement follows documentation policy. Do not start the profile-policy
work or tag a release as part of this plan.
Acceptance: compatibility review finds no unauthorized changes, all required
validation passes, documentation matches the implemented architecture, and the
refactor is ready for independent review before subsequent feature work.
### Completion
- [x] Compared the final exported GoDoc inventory with the recorded baseline;
no exported API difference was found. Reviewed the root source diff to
confirm that fields, tags, interfaces, method sets, error identities, and
formatting contracts remain unchanged.
- [x] Confirmed that root production code retains boundary conversion and error
mapping only, while internal engine assembly delegates to the existing runner
and specialized packages retain their focused behavior coverage.
- [x] Reviewed architecture, component inventory, source, runner, and model
client documentation for current ownership and local links.
- [x] Completed the full offline maintainer validation workflow and repository
hygiene review.
Acceptance: ready for independent review and subsequent release preparation,
with validation results and any blockers reported.
## Open Questions
None requiring a product decision for this scope. The refactor preserves the
existing API and behavior; the provisional catalog policy and its release
decisions remain outside this plan.
No unresolved product or architecture decision is needed for this proposed
implementation. Maintainer acceptance of the still-provisional policy and
authority to publish catalog releases are execution prerequisites, not assumed
permissions. Exact version strings are selected at publication using the
agreed date convention and recorded before Promptkit adoption.