Prepare the v0.10.0 release
This commit is contained in:
@@ -33,7 +33,7 @@ boundary and constraints that framework work must preserve.
|
|||||||
|
|
||||||
## Release Guidance
|
## Release Guidance
|
||||||
|
|
||||||
Consumers preparing for the unreleased `v0.10.0` profile-policy transition
|
Consumers upgrading to the `v0.10.0` profile-policy transition
|
||||||
should read the [v0.10.0 transition guide](docs/releases/v0.10.0.md).
|
should read the [v0.10.0 transition guide](docs/releases/v0.10.0.md).
|
||||||
|
|
||||||
Consumers upgrading from `v0.8.0` to `v0.9.0` should read the
|
Consumers upgrading from `v0.8.0` to `v0.9.0` should read the
|
||||||
|
|||||||
@@ -264,7 +264,7 @@ only the setting it owns:
|
|||||||
```go
|
```go
|
||||||
promptkit.WithProfiles(promptkit.Profile{
|
promptkit.WithProfiles(promptkit.Profile{
|
||||||
ID: "weather-light",
|
ID: "weather-light",
|
||||||
BaseProfileID: "deepseek-4-flash",
|
BaseProfileID: "promptkit-openrouter-standard",
|
||||||
ReasoningEffort: "high",
|
ReasoningEffort: "high",
|
||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -346,7 +346,7 @@ cross-version guarantee for these names.
|
|||||||
The external profile inventory is defined by the selected catalog modules, not
|
The external profile inventory is defined by the selected catalog modules, not
|
||||||
duplicated here. Browse the exact data selected by this Promptkit version:
|
duplicated here. Browse the exact data selected by this Promptkit version:
|
||||||
|
|
||||||
- [OpenRouter catalog v2.20260922.0 profiles](https://gitea.maximumdirect.net/eric/promptkit-backend-openrouter/src/tag/v2.20260922.0/catalog/profiles)
|
- [OpenRouter catalog v2.20260922.1 profiles](https://gitea.maximumdirect.net/eric/promptkit-backend-openrouter/src/tag/v2.20260922.1/catalog/profiles)
|
||||||
- [Rakestrawhome catalog v2.20260922.0 profiles](https://gitea.maximumdirect.net/eric/promptkit-backend-rakestrawhome/src/tag/v2.20260922.0/catalog/profiles)
|
- [Rakestrawhome catalog v2.20260922.0 profiles](https://gitea.maximumdirect.net/eric/promptkit-backend-rakestrawhome/src/tag/v2.20260922.0/catalog/profiles)
|
||||||
|
|
||||||
External profile entries are volatile across catalog releases. The
|
External profile entries are volatile across catalog releases. The
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
# Promptkit v0.10.0 (Unreleased)
|
# Promptkit v0.10.0
|
||||||
|
|
||||||
This supplemental transition guide describes the planned `v0.10.0` catalog
|
This supplemental guide summarizes the `v0.10.0` changes and migration needs.
|
||||||
profile-policy change. It is not a release record and does not claim that the
|
The annotated tag remains the authoritative release record.
|
||||||
version has been published. The annotated tag, when created, remains the
|
|
||||||
authoritative release record.
|
|
||||||
|
|
||||||
## Transition Summary
|
## Transition Summary
|
||||||
|
|
||||||
@@ -12,6 +10,13 @@ modules whose external profile data can change between catalog releases. It
|
|||||||
also introduces the maintained literal names
|
also introduces the maintained literal names
|
||||||
`promptkit-openrouter-standard` and `promptkit-openrouter-auto`.
|
`promptkit-openrouter-standard` and `promptkit-openrouter-auto`.
|
||||||
|
|
||||||
|
The public package now delegates assembly to an internal engine while retaining
|
||||||
|
the existing Go API. This refactor requires no consumer code changes.
|
||||||
|
|
||||||
|
This release selects OpenRouter `v2.20260922.1` and Rakestrawhome
|
||||||
|
`v2.20260922.0`; their exact inventories are linked from the
|
||||||
|
[format reference](../formats.md#external-profile-inventories).
|
||||||
|
|
||||||
The maintained names provide continuity only within the catalog versions
|
The maintained names provide continuity only within the catalog versions
|
||||||
selected and tested by a Promptkit release and when consumers do not override
|
selected and tested by a Promptkit release and when consumers do not override
|
||||||
the name or its base. Their current selections may change. External catalog
|
the name or its base. Their current selections may change. External catalog
|
||||||
@@ -26,6 +31,12 @@ catalog profile's volatility, or define a complete application-owned profile
|
|||||||
when the application must control its target and settings. An alias that
|
when the application must control its target and settings. An alias that
|
||||||
inherits from an external base is not a frozen copy.
|
inherits from an external base is not a frozen copy.
|
||||||
|
|
||||||
|
In particular, the selected OpenRouter catalog removes `deepseek-3-2`,
|
||||||
|
`deepseek-4-flash`, and `deepseek-4-pro`. Consumers using those IDs must choose
|
||||||
|
an available profile or supply their own complete definition; the new
|
||||||
|
`deepseek-flash-latest` and `deepseek-pro-latest` profiles are not automatic
|
||||||
|
aliases and need not preserve the previous settings.
|
||||||
|
|
||||||
See the [release policy](../release.md#catalog-profile-compatibility) for the
|
See the [release policy](../release.md#catalog-profile-compatibility) for the
|
||||||
compatibility boundary, the [format reference](../formats.md#built-in-profile-catalog)
|
compatibility boundary, the [format reference](../formats.md#built-in-profile-catalog)
|
||||||
for current Promptkit-owned definitions and selected external inventories, and
|
for current Promptkit-owned definitions and selected external inventories, and
|
||||||
|
|||||||
@@ -1,284 +0,0 @@
|
|||||||
# Profile Policy Implementation Plan
|
|
||||||
|
|
||||||
## Scope And Starting Point
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
- 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: Prepare Both Catalog Modules For The New Contract
|
|
||||||
|
|
||||||
**Completed:** 2026-09-22
|
|
||||||
|
|
||||||
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. 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: 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.
|
|
||||||
|
|
||||||
## Stage 2: Publish And Verify The Catalog Releases
|
|
||||||
|
|
||||||
**Completed:** 2026-09-22
|
|
||||||
|
|
||||||
**Publication record:**
|
|
||||||
|
|
||||||
- OpenRouter: `gitea.maximumdirect.net/eric/promptkit-backend-openrouter/v2`
|
|
||||||
`v2.20260922.0` from `ad0b16f77035d8acbe38a6ae1e278eaf7eeb0dc8`.
|
|
||||||
- Rakestrawhome:
|
|
||||||
`gitea.maximumdirect.net/eric/promptkit-backend-rakestrawhome/v2`
|
|
||||||
`v2.20260922.0` from `d664696142bf7c2d93db2a6b2e07f3deb55f2226`.
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
Acceptance: both published dependencies resolve normally without sibling
|
|
||||||
checkouts, workspaces, or replacements.
|
|
||||||
|
|
||||||
## Stage 3: Enforce The External Catalog Namespace
|
|
||||||
|
|
||||||
**Completed:** 2026-09-22
|
|
||||||
|
|
||||||
Repository: Promptkit. Keep current v1 dependencies during this stage;
|
|
||||||
dependency adoption remains atomic in Stage 5.
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
Acceptance: catalogs cannot occupy the namespace; existing protections and
|
|
||||||
consumer source behavior are unchanged.
|
|
||||||
|
|
||||||
## Stage 4: Add And Compose Promptkit-Owned Profiles
|
|
||||||
|
|
||||||
**Completed:** 2026-09-22
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
Acceptance: both names work through existing APIs, consumer precedence remains
|
|
||||||
effective, and no public exports or provider routing logic have been added.
|
|
||||||
|
|
||||||
## Stage 5: Adopt Published V2 Catalogs And Replace Snapshot Tests
|
|
||||||
|
|
||||||
**Completed:** 2026-09-22
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
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 6: Publish Durable Policy And Consumer Guidance
|
|
||||||
|
|
||||||
**Completed:** 2026-09-22
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
Acceptance: durable documentation distinguishes stable literal names from
|
|
||||||
volatile selections and agrees across repositories without weakening unrelated
|
|
||||||
contracts.
|
|
||||||
|
|
||||||
## Stage 7: Final Integration Review And Release Handoff
|
|
||||||
|
|
||||||
**Completed:** 2026-09-22
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
Acceptance: ready for independent review and subsequent release preparation,
|
|
||||||
with validation results and any blockers reported.
|
|
||||||
|
|
||||||
## Open Questions
|
|
||||||
|
|
||||||
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.
|
|
||||||
@@ -1,359 +0,0 @@
|
|||||||
# Built-In Profile Compatibility Policy
|
|
||||||
|
|
||||||
## Status
|
|
||||||
|
|
||||||
Accepted for implementation on 2026-09-22. The implementation sequence and
|
|
||||||
completion status are maintained in the
|
|
||||||
[profile-policy implementation plan](implementation.md). Current code, GoDoc,
|
|
||||||
durable documentation, published module contracts, and release tags remain
|
|
||||||
authoritative until each corresponding implementation change lands.
|
|
||||||
|
|
||||||
## Prerequisite And Sequencing
|
|
||||||
|
|
||||||
Implementation of this roadmap must begin only after the
|
|
||||||
[public facade refactor](public-facade.md) is complete and its compatibility
|
|
||||||
and validation criteria have passed. The refactor preserves existing behavior;
|
|
||||||
this subsequent work introduces the deliberate profile-policy changes.
|
|
||||||
|
|
||||||
Profile-source composition, maintained-profile construction, and catalog
|
|
||||||
dependency assembly must use the internal owners established by that refactor.
|
|
||||||
Both scopes may ship in `v0.10.0`, but they remain separately reviewable changes.
|
|
||||||
This prerequisite has been satisfied. The remaining work proceeds through the
|
|
||||||
[profile-policy implementation plan](implementation.md).
|
|
||||||
|
|
||||||
## Purpose
|
|
||||||
|
|
||||||
Define a truthful compatibility and release boundary for Promptkit's
|
|
||||||
maintained built-in profiles. The intended direction is to permit exceptionally
|
|
||||||
rapid catalog updates without weakening Promptkit's stability commitments for
|
|
||||||
its engine, public Go API, configuration semantics, backend registry, or other
|
|
||||||
non-profile behavior.
|
|
||||||
|
|
||||||
Model catalogs change faster than the Promptkit runtime. Providers control
|
|
||||||
their own model catalogs and service lifecycles. Promptkit cannot
|
|
||||||
reasonably guarantee that a maintained profile's upstream model or endpoint
|
|
||||||
will remain available, and retaining obsolete profiles can be actively
|
|
||||||
misleading when their targets no longer provide the expected service.
|
|
||||||
|
|
||||||
The release model should treat external catalog profiles as volatile data,
|
|
||||||
while providing a small set of Promptkit-owned aliases with stable IDs for
|
|
||||||
applications that prefer a maintained general-purpose selection.
|
|
||||||
|
|
||||||
## Proposed Compatibility Boundary
|
|
||||||
|
|
||||||
The provisional policy would exclude external catalog profile data from
|
|
||||||
Promptkit's cross-version compatibility surface. A catalog or Promptkit
|
|
||||||
release could, without deprecation or advance notice:
|
|
||||||
|
|
||||||
- add or remove an external catalog profile;
|
|
||||||
- rename a profile, represented as removing one ID and adding another;
|
|
||||||
- change the upstream model selected by a profile;
|
|
||||||
- change profile defaults such as reasoning effort, timeout, service tier,
|
|
||||||
sampling controls, token limits, or extra parameters; and
|
|
||||||
- correct or otherwise revise profile metadata in response to upstream
|
|
||||||
behavior.
|
|
||||||
|
|
||||||
Promptkit would make no cross-version promise about the continued presence,
|
|
||||||
identity, settings, suitability, or upstream availability of an external
|
|
||||||
catalog profile. The separately defined Promptkit-owned alias IDs would have
|
|
||||||
the continuity guarantee below. Promptkit would make no claim that an upstream
|
|
||||||
provider will continue to serve a cataloged model or endpoint for the lifetime
|
|
||||||
of a Promptkit or catalog release.
|
|
||||||
|
|
||||||
This volatility exception should apply only to external catalog profile
|
|
||||||
data. It should not silently weaken the ordinary compatibility rules for:
|
|
||||||
|
|
||||||
- Promptkit's exported Go API and GoDoc contracts;
|
|
||||||
- prompt, profile, and schema format semantics;
|
|
||||||
- request preparation, execution, validation, repair, cancellation, error,
|
|
||||||
credential, ownership, and concurrency behavior;
|
|
||||||
- public built-in backend IDs and registry behavior;
|
|
||||||
- the external catalog packages' exported Go API;
|
|
||||||
- the catalog manifest and asset schema understood by Promptkit; or
|
|
||||||
- consumer-defined profiles and backends.
|
|
||||||
|
|
||||||
Backend definitions, including endpoint, credential-environment, and capacity
|
|
||||||
metadata, remain outside the profile-volatility exception and subject to the
|
|
||||||
ordinary compatibility policy.
|
|
||||||
|
|
||||||
## Proposed Stable Promptkit Profiles
|
|
||||||
|
|
||||||
Promptkit would maintain a small, explicitly documented set of built-in
|
|
||||||
profiles using existing profile definitions and inheritance:
|
|
||||||
|
|
||||||
| Stable profile ID | Initial definition | Initial purpose |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| `promptkit-openrouter-standard` | Inherits from external catalog profile `gemini-flash-latest`. | A maintained selection for general-purpose text generation. |
|
|
||||||
| `promptkit-openrouter-auto` | Selects backend `openrouter` and model `openrouter/auto`. | Delegates model selection to OpenRouter's automatic routing. |
|
|
||||||
|
|
||||||
These definitions and purposes describe the initial selections only and are
|
|
||||||
not continuing model-selection promises.
|
|
||||||
|
|
||||||
The auto profile can initially be a direct profile definition; it does not
|
|
||||||
require a second catalog alias or a new public API. It inherits connection and credential
|
|
||||||
metadata from the OpenRouter backend and need not add generation overrides.
|
|
||||||
Promptkit forwards `openrouter/auto` as the model identifier through its ordinary
|
|
||||||
client. OpenRouter owns the routing decision, eligible models, and resulting
|
|
||||||
provider behavior. Promptkit adds no model-selection algorithm or fallback
|
|
||||||
loop. Its ordinary local validation does not check the upstream availability
|
|
||||||
of `openrouter/auto`.
|
|
||||||
|
|
||||||
Both profiles receive the stable-ID guarantee below. References to aliases
|
|
||||||
describe inherited definitions where applicable; the same namespace,
|
|
||||||
precedence, and structural-validation requirements cover direct definitions.
|
|
||||||
Only these two profiles are in scope. This roadmap imposes no additional
|
|
||||||
approval process for future profiles.
|
|
||||||
|
|
||||||
The only profile-specific continuity promise is that the literal names
|
|
||||||
`promptkit-openrouter-standard` and `promptkit-openrouter-auto` remain
|
|
||||||
available, subject to the supported dependency and consumer-override scope
|
|
||||||
below. Their actual models may change at any time, for any reason, without
|
|
||||||
notice to anyone. No deprecation, approval, or change-announcement gate applies
|
|
||||||
to model selection. The names do not promise a permanent model, provider,
|
|
||||||
routing strategy, or set of defaults. Both initially use OpenRouter, but the
|
|
||||||
profile names themselves are the only continuity guarantee.
|
|
||||||
|
|
||||||
In particular, `promptkit-openrouter-auto` is not required to retain
|
|
||||||
`openrouter/auto` or automatic routing indefinitely. Neither profile guarantees
|
|
||||||
unchanged output, cost, latency, capabilities, or upstream availability. While
|
|
||||||
using upstream automatic routing, the selected model can vary between requests
|
|
||||||
even with unchanged Promptkit and catalog versions.
|
|
||||||
|
|
||||||
Catalog dependency updates must preserve local resolution of the two maintained
|
|
||||||
profile names. If a referenced catalog profile disappears or is renamed,
|
|
||||||
adjust the affected alias together with the dependency update and ship both in
|
|
||||||
the same Promptkit release. If the catalog retains the referenced ID but
|
|
||||||
changes its model, inheritance picks up the change automatically; no separate
|
|
||||||
model-selection approval is required. Ordinary code review and structural
|
|
||||||
validation apply. Upstream deprecation, retirement, and mapping accuracy remain
|
|
||||||
the catalog library's responsibility and do not create a Promptkit monitoring
|
|
||||||
or upstream-verification obligation.
|
|
||||||
|
|
||||||
Release validation must prove that every maintained alias resolves against
|
|
||||||
the selected catalog versions. This continuity guarantee applies to the
|
|
||||||
versions selected and tested by Promptkit and assumes consumers have not
|
|
||||||
overridden the alias or its base with their own definitions. Independently
|
|
||||||
upgrading a transitive catalog can remove an alias's base without updating
|
|
||||||
Promptkit; that untested combination is outside the guarantee.
|
|
||||||
|
|
||||||
Aliases would retain the ordinary profile precedence and inheritance
|
|
||||||
semantics. They would introduce no new public API or automatic model failover.
|
|
||||||
An already deployed application would retain its compiled alias and catalog
|
|
||||||
data until upgraded; an upstream withdrawal would not change its selection
|
|
||||||
automatically.
|
|
||||||
|
|
||||||
Adding these profiles does not change existing default-profile selection.
|
|
||||||
Consumers opt into them through the existing profile-selection mechanisms.
|
|
||||||
|
|
||||||
### Ownership, Precedence, And Composition
|
|
||||||
|
|
||||||
The maintained alias definitions belong to a small Promptkit-owned profile
|
|
||||||
source. Profile precedence is consumer sources in their existing order, then
|
|
||||||
Promptkit-owned aliases, then external catalog profiles. Consumers may override
|
|
||||||
an alias or its base using the ordinary profile mechanisms.
|
|
||||||
|
|
||||||
Reserve the `promptkit-` profile-ID prefix against definitions in external
|
|
||||||
catalogs. Reject such catalog definitions even if they do not yet collide with
|
|
||||||
an existing alias. This namespace rule does not prohibit consumer overrides.
|
|
||||||
|
|
||||||
Retain existing catalog-local inheritance and backend-ownership validation,
|
|
||||||
and verify that the combined maintained profiles resolve without relying on
|
|
||||||
consumer overrides. Do not assert a permanent model or routing selection based
|
|
||||||
on a profile name. Runtime inheritance must continue to observe the complete
|
|
||||||
source hierarchy, including consumer overrides of aliases and their bases.
|
|
||||||
Reuse the existing resolver; exact private assembly and validation sequencing
|
|
||||||
belongs in the implementation plan. Do not introduce a second inheritance
|
|
||||||
implementation or freeze alias values in a way that bypasses consumer overrides.
|
|
||||||
|
|
||||||
## Local Validation And Existing Safeguards
|
|
||||||
|
|
||||||
Profile volatility does not remove existing structural validation or library
|
|
||||||
safeguards. Preserve the following implemented responsibilities without making
|
|
||||||
them additional profile-availability or permanent implementation promises:
|
|
||||||
|
|
||||||
- catalog assets are immutable build inputs rather than runtime downloads;
|
|
||||||
- manifests and profiles satisfy the supported schemas;
|
|
||||||
- IDs are unique and profiles select their owning backend;
|
|
||||||
- external catalogs do not define IDs in the reserved `promptkit-` namespace;
|
|
||||||
- secret-bearing fields and prohibited connection metadata are rejected;
|
|
||||||
- profile values are normalized, copied, resolved, and overlaid through the
|
|
||||||
existing Promptkit architecture;
|
|
||||||
- the selected catalogs pass Promptkit's integration suite before a Promptkit
|
|
||||||
release adopts them; and
|
|
||||||
- the module graph and checksums provide a reproducible identity for the data
|
|
||||||
that was tested.
|
|
||||||
|
|
||||||
These checks establish local integrity for selected data, together with the
|
|
||||||
maintained-profile resolution requirement above. They do not establish external
|
|
||||||
catalog profile continuity across versions or live upstream availability.
|
|
||||||
|
|
||||||
Promptkit's checks cover local syntax and structural semantics: supported
|
|
||||||
fields, duplicate IDs, namespace conflicts, inheritance resolution, backend
|
|
||||||
references, endpoint URL format, and existing security and value constraints.
|
|
||||||
They expressly exclude attempts to verify that an endpoint exists, a model ID
|
|
||||||
is recognized upstream, or a provider serves that model. Catalog libraries own
|
|
||||||
the accuracy of upstream model and endpoint mappings. Promptkit must not add
|
|
||||||
network probes, model-list lookups, or paid inference checks to catalog adoption
|
|
||||||
or release validation. Ordinary execution continues to report upstream errors
|
|
||||||
through the existing generation-error contract.
|
|
||||||
|
|
||||||
## Provisional Release Model
|
|
||||||
|
|
||||||
The first release adopting this policy should be a new Promptkit minor release
|
|
||||||
because it changes a previously documented consumer expectation and may remove
|
|
||||||
profile IDs on which deployed configuration depends. `v0.10.0` is the current
|
|
||||||
candidate.
|
|
||||||
|
|
||||||
The OpenRouter catalog's published `v1.0.0` contract promised stable profile
|
|
||||||
IDs and advance handling before removal. A later README cannot retroactively
|
|
||||||
weaken that promise. The current recommendation is therefore to establish the
|
|
||||||
new boundary in `promptkit-backend-openrouter` major version 2, using the dated
|
|
||||||
release convention below, even if its exported Go declarations and manifest
|
|
||||||
schema do not change.
|
|
||||||
|
|
||||||
After that boundary is established, maintained catalog releases could publish
|
|
||||||
profile additions, deletions, and modifications rapidly under their documented
|
|
||||||
volatile-data policy. Promptkit could select a reviewed catalog update without
|
|
||||||
treating profile churn as a compatibility break in its otherwise stable core.
|
|
||||||
Later catalog updates and corresponding alias adjustments may ship in a
|
|
||||||
Promptkit patch release, such as `v0.10.1` after `v0.10.0`, provided unrelated
|
|
||||||
compatibility contracts remain intact. Profile churn alone does not require
|
|
||||||
`v0.11.0` or another minor release.
|
|
||||||
|
|
||||||
Promptkit's integration validation covers the catalog versions it selected
|
|
||||||
and tested. It does not guarantee upstream correctness for those versions.
|
|
||||||
Go module version selection may cause an advanced consumer's build
|
|
||||||
to select a newer compatible catalog module than Promptkit's own requirement;
|
|
||||||
the resolved module graph, rather than Promptkit's `go.mod` alone, determines
|
|
||||||
the actual embedded data.
|
|
||||||
|
|
||||||
Release notes may identify selected catalog updates and summarize changes for
|
|
||||||
convenience, but no notice of model-selection changes is required, in advance
|
|
||||||
or afterward. Ordinary release records and validation still apply; they must
|
|
||||||
not introduce a profile-change announcement gate.
|
|
||||||
|
|
||||||
### Proposed Date-Based Catalog Versions
|
|
||||||
|
|
||||||
The proposed catalog version convention is `vMAJOR.YYYYMMDD.N`. This is a
|
|
||||||
calendar-based convention encoded in Go-compatible semantic-version syntax:
|
|
||||||
|
|
||||||
- `MAJOR` identifies the compatibility generation of the exported Go package
|
|
||||||
and catalog asset format. Profile additions, deletions, renames, and setting
|
|
||||||
changes do not require a major-version increase under the proposed policy.
|
|
||||||
- `YYYYMMDD` is the release publication date in UTC. It occupies the numeric
|
|
||||||
minor-version component and communicates snapshot freshness, not the scale
|
|
||||||
or compatibility of a profile change.
|
|
||||||
- `N` starts at zero for each UTC date and increments for every additional
|
|
||||||
release that day, regardless of the kind of profile change. It occupies the
|
|
||||||
numeric patch-version component and carries no profile-continuity promise.
|
|
||||||
|
|
||||||
For example, `v2.20260922.0` and `v2.20260922.1` would be successive releases
|
|
||||||
on September 22, 2026, followed by `v2.20260923.0` on the next day. These are
|
|
||||||
illustrative dates, not scheduled releases. Use the actual publication date;
|
|
||||||
published versions remain immutable, and corrections receive new versions.
|
|
||||||
Within a major generation, these versions sort chronologically under Go's
|
|
||||||
ordinary module-version ordering.
|
|
||||||
|
|
||||||
Go requires a matching major-version suffix in module paths for version 2 and
|
|
||||||
later. The OpenRouter transition would therefore use
|
|
||||||
`gitea.maximumdirect.net/eric/promptkit-backend-openrouter/v2` in the catalog's
|
|
||||||
module declaration and Promptkit's imports and dependency requirement. A first
|
|
||||||
release on the example date would be `v2.20260922.0`; a preliminary `v2.0.0`
|
|
||||||
release is not required. Promptkit consumers would continue importing
|
|
||||||
Promptkit through its existing module path. See the
|
|
||||||
[Go module version rules](https://go.dev/ref/mod#versions) and
|
|
||||||
[major-version suffix rules](https://go.dev/ref/mod#major-version-suffixes).
|
|
||||||
|
|
||||||
Both maintained catalog libraries, OpenRouter and Rakestrawhome, would
|
|
||||||
transition to this policy and dated major-version-2 convention as part of this
|
|
||||||
work, with matching `/v2` module paths. Thereafter each would release
|
|
||||||
independently; releases need not share dates or revision numbers.
|
|
||||||
Promptkit itself would retain its existing version-number
|
|
||||||
convention and explicitly select and test individual catalog versions.
|
|
||||||
|
|
||||||
This proposal replaces the earlier idea of classifying catalog refreshes as
|
|
||||||
ordinary minor releases and metadata corrections as patches. The date records
|
|
||||||
when a snapshot was published; release notes may summarize what changed.
|
|
||||||
Neither establishes live upstream availability or cross-version profile
|
|
||||||
continuity. The convention remains provisional along with this roadmap.
|
|
||||||
|
|
||||||
## Consumer Guidance
|
|
||||||
|
|
||||||
The eventual durable documentation should make the tradeoff explicit:
|
|
||||||
|
|
||||||
- external catalog profiles optimize for convenient access to a maintained
|
|
||||||
current model catalog;
|
|
||||||
- selecting or inheriting directly from an external catalog profile accepts
|
|
||||||
its volatility;
|
|
||||||
- selecting either `promptkit-openrouter-standard` or
|
|
||||||
`promptkit-openrouter-auto` guarantees only continued availability of that
|
|
||||||
literal profile name within the supported dependency scope; models and
|
|
||||||
settings may change for any reason without notice;
|
|
||||||
- `promptkit-openrouter-auto` initially delegates model selection to OpenRouter;
|
|
||||||
its initial routing behavior is not a permanent contract, and upstream
|
|
||||||
routing can change independently of a library upgrade;
|
|
||||||
- pinning the complete resolved Go module graph preserves the exact catalog
|
|
||||||
assets used by that build, but cannot preserve live upstream availability;
|
|
||||||
- applications that require their own fixed model selection or settings should
|
|
||||||
define a complete application-owned profile with an explicit backend, model,
|
|
||||||
and defaults; and
|
|
||||||
- an application-owned alias that inherits from an external catalog profile
|
|
||||||
isolates application configuration from the catalog ID only while that base
|
|
||||||
exists; it deliberately continues to inherit changes to the base profile.
|
|
||||||
|
|
||||||
Promptkit should not promise automatic migration or replacement aliases for
|
|
||||||
every removed external catalog ID, deprecation windows for catalog profiles,
|
|
||||||
or runtime fallback from a removed or unavailable model. Its small maintained
|
|
||||||
alias set provides continuity through coordinated library releases.
|
|
||||||
|
|
||||||
## Expected Documentation And Repository Changes
|
|
||||||
|
|
||||||
If accepted, implementation would likely require coordinated changes in
|
|
||||||
Promptkit and each maintained catalog repository:
|
|
||||||
|
|
||||||
- revise catalog compatibility and release documentation to distinguish the
|
|
||||||
stable Go/schema boundary from volatile profile data and document the
|
|
||||||
`vMAJOR.YYYYMMDD.N` convention;
|
|
||||||
- update Promptkit's release policy with a narrowly scoped built-in-profile
|
|
||||||
volatility exception for external catalogs and an explicit continuity
|
|
||||||
guarantee for Promptkit-owned alias IDs, while retaining its other pre-`v1`
|
|
||||||
compatibility rules;
|
|
||||||
- add `promptkit-openrouter-standard` through existing profile inheritance and
|
|
||||||
`promptkit-openrouter-auto` as a direct `openrouter/auto` profile; document
|
|
||||||
their distinct purposes and opt-in selection;
|
|
||||||
- require coordinated catalog and alias updates, with release checks proving
|
|
||||||
every maintained alias resolves against the selected catalog versions;
|
|
||||||
- update the architecture, format, source, development, and consumer
|
|
||||||
documentation at their existing ownership boundaries;
|
|
||||||
- keep exact external profile inventories in the catalog repositories, linking
|
|
||||||
to the selected versions from Promptkit rather than duplicating their tables;
|
|
||||||
keep Promptkit's small alias inventory and runtime semantics in its own
|
|
||||||
canonical documentation;
|
|
||||||
- revise tests and compatibility-fixture terminology so they protect local
|
|
||||||
structural validity and maintained-profile resolution, without asserting
|
|
||||||
cross-version stability of external profiles; retain an exact selected-version
|
|
||||||
snapshot only where its review value justifies its maintenance cost;
|
|
||||||
- publish both revised catalog contracts as dated major-version-2 releases
|
|
||||||
with matching `/v2` module paths;
|
|
||||||
- update Promptkit's catalog imports and requirement, current selected-profile
|
|
||||||
documentation, and release guidance; and
|
|
||||||
- publish the policy transition and its consumer impact in the eventual
|
|
||||||
Promptkit minor release note and annotated tag.
|
|
||||||
|
|
||||||
Implementation is sequenced and tracked in the
|
|
||||||
[profile-policy implementation plan](implementation.md).
|
|
||||||
|
|
||||||
## Non-Goals
|
|
||||||
|
|
||||||
This proposal does not introduce:
|
|
||||||
|
|
||||||
- runtime catalog downloads, discovery, or mutable global registration;
|
|
||||||
- any upstream endpoint or model-existence verification by Promptkit, or
|
|
||||||
guarantees based on current provider health;
|
|
||||||
- automatic replacement aliases or migration tables for every removed catalog
|
|
||||||
profile, or runtime fallback models;
|
|
||||||
- weakened validation of catalog structure or content;
|
|
||||||
- weaker compatibility for Promptkit's public engine or consumer-defined
|
|
||||||
configuration; or
|
|
||||||
- a general exception allowing arbitrary dependency updates to break stable
|
|
||||||
Promptkit behavior.
|
|
||||||
@@ -1,217 +0,0 @@
|
|||||||
# 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.
|
|
||||||
@@ -1,86 +0,0 @@
|
|||||||
# Public Facade Review Remediation
|
|
||||||
|
|
||||||
## Scope
|
|
||||||
|
|
||||||
Review of implementation commits after baseline `7a858c2` through `06251e3`,
|
|
||||||
against the [feature roadmap](public-facade.md) and
|
|
||||||
[implementation plan](implementation.md).
|
|
||||||
|
|
||||||
The production ownership split is in place. No production behavior regression
|
|
||||||
or public API change was identified in the reviewed diff. One required
|
|
||||||
architecture-test gap was identified and has now been addressed; it did not
|
|
||||||
establish an existing public type leak in Promptkit.
|
|
||||||
|
|
||||||
## Finding 1: Complete Reachable Public Type Inspection (P2)
|
|
||||||
|
|
||||||
Status: addressed.
|
|
||||||
|
|
||||||
Location: [public boundary checker](../../public_boundary_test.go),
|
|
||||||
`publicSurfaceViolations`, in its named/alias and method-set traversal.
|
|
||||||
|
|
||||||
The original checker inspected method sets only for exported package-scope type
|
|
||||||
names. It did not inspect methods on an unexported root type reached through an
|
|
||||||
exported function or field. Such methods are still callable by consumers. It
|
|
||||||
also walked generic parameter constraints but not instantiated type arguments;
|
|
||||||
an internal argument can escape without appearing in the underlying fields.
|
|
||||||
|
|
||||||
Both examples below were type-checked through the existing fixture helper and
|
|
||||||
incorrectly produced zero violations:
|
|
||||||
|
|
||||||
```go
|
|
||||||
// Example 1: a caller can invoke New().Leak().
|
|
||||||
type result struct{}
|
|
||||||
func (result) Leak() hidden.Value { return hidden.Value{} }
|
|
||||||
func New() result { return result{} }
|
|
||||||
```
|
|
||||||
|
|
||||||
```go
|
|
||||||
// Example 2: an internal type appears in an exported result signature even
|
|
||||||
// though Box has no field using its type parameter.
|
|
||||||
type Box[T any] struct{}
|
|
||||||
func New() Box[hidden.Value] { return Box[hidden.Value]{} }
|
|
||||||
```
|
|
||||||
|
|
||||||
Here `hidden` is the fixture's own-module internal package. These are separate
|
|
||||||
fixture packages, not additions to Promptkit's API. Temporary diagnostic tests
|
|
||||||
confirmed both false negatives and were removed after review.
|
|
||||||
|
|
||||||
### Resolution
|
|
||||||
|
|
||||||
The recursive named-type traversal now checks reachable root types' value and
|
|
||||||
pointer method sets, using instantiated selections for their signatures. Named
|
|
||||||
types and aliases have their concrete type arguments inspected before their
|
|
||||||
underlying representation is considered. The separate package-scope method
|
|
||||||
loop was removed. Regression fixtures cover returned private types, private
|
|
||||||
field types with public pointer methods, generic arguments, aliases that erase
|
|
||||||
their arguments, and allowed public arguments with recursive method signatures.
|
|
||||||
|
|
||||||
### Acceptance Criteria
|
|
||||||
|
|
||||||
Extend the existing recursive traversal rather than adding a second checker:
|
|
||||||
|
|
||||||
- Inspect accessible methods of reachable root named types, including
|
|
||||||
unexported types, with the existing cycle protection and promoted-method
|
|
||||||
checks. Cover pointer and value method sets where applicable.
|
|
||||||
- Inspect concrete generic type arguments on named types and aliases before
|
|
||||||
losing them through unaliasing or skipping an external named type's internals.
|
|
||||||
Continue checking constraints. Do not recursively police unrelated dependency
|
|
||||||
implementation details.
|
|
||||||
- Add the two reproductions to the compact fixture table and exercise an
|
|
||||||
allowed public type argument as a control. Preserve acceptance of private
|
|
||||||
internal fields and sealed options. Avoid duplicated method traversal.
|
|
||||||
|
|
||||||
Acceptance: both examples are rejected, legitimate private state still passes,
|
|
||||||
and the full maintainer workflow succeeds. No production API changes are needed.
|
|
||||||
|
|
||||||
## Review Validation
|
|
||||||
|
|
||||||
The existing full maintainer workflow passed: ordinary and race tests, vet,
|
|
||||||
build, both offline examples, formatting, Markdown links, and repository
|
|
||||||
hygiene. The targeted diagnostic tests failed as expected, demonstrating the
|
|
||||||
checker gap rather than a runtime failure. No production or permanent test
|
|
||||||
files were changed during this review.
|
|
||||||
|
|
||||||
After remediation, the focused checker tests and full maintainer workflow also
|
|
||||||
passed. The changes are confined to the architecture test and this review log;
|
|
||||||
production code and public contracts remain unchanged.
|
|
||||||
2
go.mod
2
go.mod
@@ -3,7 +3,7 @@ module gitea.maximumdirect.net/eric/promptkit
|
|||||||
go 1.25.5
|
go 1.25.5
|
||||||
|
|
||||||
require (
|
require (
|
||||||
gitea.maximumdirect.net/eric/promptkit-backend-openrouter/v2 v2.20260922.0
|
gitea.maximumdirect.net/eric/promptkit-backend-openrouter/v2 v2.20260922.1
|
||||||
gitea.maximumdirect.net/eric/promptkit-backend-rakestrawhome/v2 v2.20260922.0
|
gitea.maximumdirect.net/eric/promptkit-backend-rakestrawhome/v2 v2.20260922.0
|
||||||
github.com/santhosh-tekuri/jsonschema/v6 v6.0.2
|
github.com/santhosh-tekuri/jsonschema/v6 v6.0.2
|
||||||
gopkg.in/yaml.v3 v3.0.1
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
|
|||||||
4
go.sum
4
go.sum
@@ -1,5 +1,5 @@
|
|||||||
gitea.maximumdirect.net/eric/promptkit-backend-openrouter/v2 v2.20260922.0 h1:uxvVFOylxXrzcg0jJLXcRBIj73BGNjvnsRuMoOeoYKw=
|
gitea.maximumdirect.net/eric/promptkit-backend-openrouter/v2 v2.20260922.1 h1:S2/Q/JDE+m8Ca3pDhAjVbfYrdlEhs9blj0STgNopHo0=
|
||||||
gitea.maximumdirect.net/eric/promptkit-backend-openrouter/v2 v2.20260922.0/go.mod h1:a3VBbh9oaGXD6ruxhtwHj+AWW6DY/SSyby1QtMmYSUo=
|
gitea.maximumdirect.net/eric/promptkit-backend-openrouter/v2 v2.20260922.1/go.mod h1:a3VBbh9oaGXD6ruxhtwHj+AWW6DY/SSyby1QtMmYSUo=
|
||||||
gitea.maximumdirect.net/eric/promptkit-backend-rakestrawhome/v2 v2.20260922.0 h1:Y0EXc3eh12eKW2NrOviVqdk3oBo6UUjopt1YAa1B3Oc=
|
gitea.maximumdirect.net/eric/promptkit-backend-rakestrawhome/v2 v2.20260922.0 h1:Y0EXc3eh12eKW2NrOviVqdk3oBo6UUjopt1YAa1B3Oc=
|
||||||
gitea.maximumdirect.net/eric/promptkit-backend-rakestrawhome/v2 v2.20260922.0/go.mod h1:mtgD1E0SGm0e/I8Ffhz+AYX7GN7RKUWJXehNFIKHs4Y=
|
gitea.maximumdirect.net/eric/promptkit-backend-rakestrawhome/v2 v2.20260922.0/go.mod h1:mtgD1E0SGm0e/I8Ffhz+AYX7GN7RKUWJXehNFIKHs4Y=
|
||||||
github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxKI=
|
github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxKI=
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ func TestProfileInheritanceBuiltInAliasWorkflow(t *testing.T) {
|
|||||||
SchemaDir: frameworkSchemaDir,
|
SchemaDir: frameworkSchemaDir,
|
||||||
}, promptkit.WithProfiles(promptkit.Profile{
|
}, promptkit.WithProfiles(promptkit.Profile{
|
||||||
ID: "weather-light",
|
ID: "weather-light",
|
||||||
BaseProfileID: "deepseek-4-flash",
|
BaseProfileID: "promptkit-openrouter-standard",
|
||||||
ReasoningEffort: "high",
|
ReasoningEffort: "high",
|
||||||
TimeoutSeconds: 120,
|
TimeoutSeconds: 120,
|
||||||
}))
|
}))
|
||||||
@@ -26,7 +26,7 @@ func TestProfileInheritanceBuiltInAliasWorkflow(t *testing.T) {
|
|||||||
t.Fatalf("construct alias engine: %v", err)
|
t.Fatalf("construct alias engine: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
base, err := engine.InspectProfile(context.Background(), "deepseek-4-flash")
|
base, err := engine.InspectProfile(context.Background(), "promptkit-openrouter-standard")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("inspect base: %v", err)
|
t.Fatalf("inspect base: %v", err)
|
||||||
}
|
}
|
||||||
@@ -84,7 +84,7 @@ func TestProfileInheritanceYAMLAliasOfBuiltIn(t *testing.T) {
|
|||||||
engine, err := promptkit.NewEngine(promptkit.Config{},
|
engine, err := promptkit.NewEngine(promptkit.Config{},
|
||||||
promptkit.WithPromptFS(fstest.MapFS{}, "."),
|
promptkit.WithPromptFS(fstest.MapFS{}, "."),
|
||||||
promptkit.WithProfileFS(fstest.MapFS{
|
promptkit.WithProfileFS(fstest.MapFS{
|
||||||
"alias.yaml": &fstest.MapFile{Data: []byte("id: yaml-alias\nbase_profile: deepseek-4-flash\n")},
|
"alias.yaml": &fstest.MapFile{Data: []byte("id: yaml-alias\nbase_profile: promptkit-openrouter-standard\n")},
|
||||||
}, "."),
|
}, "."),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
Reference in New Issue
Block a user