Align project policies and simplify the release workflow
This commit is contained in:
34
AGENTS.md
34
AGENTS.md
@@ -1,35 +1,5 @@
|
|||||||
Please review `docs/development.md` for initial orientation in this repository
|
Please review `docs/development.md` for initial orientation in this repository
|
||||||
and follow its task-specific reading guide.
|
and follow its task-specific reading guide.
|
||||||
|
|
||||||
## Implementation Discipline
|
Review and follow `docs/policy/agents.md` before recommending, planning, or
|
||||||
|
implementing any changes to this repository.
|
||||||
Simplify the mechanism, not the user's choices.
|
|
||||||
|
|
||||||
**Keep implementation machinery proportionate.** Use straightforward,
|
|
||||||
idiomatic code and introduce only the machinery needed to support the requested
|
|
||||||
behavior and flexibility. Optimize for conceptual simplicity and
|
|
||||||
maintainability, not for the fewest lines, fewest options, or narrowest product
|
|
||||||
surface.
|
|
||||||
|
|
||||||
**Do not invent restrictions.** Do not reject, prohibit, constrain, cap,
|
|
||||||
harden, or otherwise narrow behavior unless required by the user, an explicit
|
|
||||||
repository contract, or an unavoidable correctness constraint. Preserve
|
|
||||||
operator and caller choice where policy has not been established. If an
|
|
||||||
additional restriction appears advisable, present it as a decision rather than
|
|
||||||
silently implementing it.
|
|
||||||
|
|
||||||
A correctness constraint must follow from the requested behavior or an
|
|
||||||
established invariant, not from the convenience of the chosen implementation.
|
|
||||||
Explain the specific failure it prevents and why a less restrictive
|
|
||||||
implementation cannot satisfy the contract.
|
|
||||||
|
|
||||||
**An implementation detail is not repository policy.** Tests and documentation
|
|
||||||
must not elevate incidental behavior into a durable guarantee or restriction
|
|
||||||
unless that behavior was expressly selected as part of the contract. Existing
|
|
||||||
explicit contracts remain authoritative; changing or weakening one requires a
|
|
||||||
deliberate decision rather than being inferred from this principle.
|
|
||||||
|
|
||||||
Agent-authored plans, tests, documentation, and prior implementations are not
|
|
||||||
evidence that an additional restriction was deliberately approved. Identify the
|
|
||||||
authorizing requirement or decision; when that authority is unclear, surface
|
|
||||||
the ambiguity rather than treating repetition as approval.
|
|
||||||
|
|||||||
@@ -252,7 +252,7 @@ a catalog dependency can remove an inherited base and produce an untested
|
|||||||
combination. Pinning the resolved module graph preserves the embedded data for
|
combination. Pinning the resolved module graph preserves the embedded data for
|
||||||
a build, but cannot preserve provider availability. Running binaries neither
|
a build, but cannot preserve provider availability. Running binaries neither
|
||||||
download catalog updates nor automatically replace withdrawn models. See the
|
download catalog updates nor automatically replace withdrawn models. See the
|
||||||
[release policy](../release.md#catalog-profile-compatibility) for the exact
|
[release policy](../policy/release.md#catalog-profile-compatibility) for the exact
|
||||||
cross-version guarantees.
|
cross-version guarantees.
|
||||||
|
|
||||||
### Alias A Built-In Profile
|
### Alias A Built-In Profile
|
||||||
|
|||||||
@@ -2,7 +2,8 @@
|
|||||||
|
|
||||||
This is the contributor entry point for Promptkit, a reusable Go library. All
|
This is the contributor entry point for Promptkit, a reusable Go library. All
|
||||||
contributors must read the
|
contributors must read the
|
||||||
[architecture policy](policy/architecture.md) before making changes.
|
[architecture policy](policy/architecture.md) before making changes. Agents must
|
||||||
|
also follow the [agent policy](policy/agents.md) before recommendations or work.
|
||||||
|
|
||||||
## Initial Orientation
|
## Initial Orientation
|
||||||
|
|
||||||
@@ -25,7 +26,8 @@ Start with:
|
|||||||
documentation;
|
documentation;
|
||||||
- the [testing policy](policy/testing.md) before adding, rewriting, or deleting
|
- the [testing policy](policy/testing.md) before adding, rewriting, or deleting
|
||||||
tests; and
|
tests; and
|
||||||
- the [release procedure](release.md) for version and publication work.
|
- the [release policy](policy/release.md) and [release procedure](release.md)
|
||||||
|
for version and publication work.
|
||||||
|
|
||||||
## Task-Specific Reading Guide
|
## Task-Specific Reading Guide
|
||||||
|
|
||||||
@@ -40,7 +42,7 @@ Start with:
|
|||||||
| Tests or test fixtures | The [testing policy](policy/testing.md), owning package, and focused internal document listed by the component overview. |
|
| Tests or test fixtures | The [testing policy](policy/testing.md), owning package, and focused internal document listed by the component overview. |
|
||||||
| Maintained example | The [example](../examples/go-library/prepare/main.go), [consumer guide](consumers/pkg-promptkit.md), [framework format reference](formats.md), and [documentation policy](policy/documentation.md). |
|
| Maintained example | The [example](../examples/go-library/prepare/main.go), [consumer guide](consumers/pkg-promptkit.md), [framework format reference](formats.md), and [documentation policy](policy/documentation.md). |
|
||||||
| Documentation | The [documentation policy](policy/documentation.md) and canonical owner of every affected contract. |
|
| Documentation | The [documentation policy](policy/documentation.md) and canonical owner of every affected contract. |
|
||||||
| Release preparation or publication | The [release procedure](release.md). |
|
| Release preparation or publication | The [release policy](policy/release.md) and [release procedure](release.md). |
|
||||||
|
|
||||||
For cross-cutting changes, follow every applicable row. Do not create
|
For cross-cutting changes, follow every applicable row. Do not create
|
||||||
placeholder documents for packages, APIs, or integrations that do not yet
|
placeholder documents for packages, APIs, or integrations that do not yet
|
||||||
@@ -48,187 +50,40 @@ exist.
|
|||||||
|
|
||||||
## Maintainer Validation
|
## Maintainer Validation
|
||||||
|
|
||||||
This section is the canonical local validation workflow for Promptkit. Run
|
For ordinary work, select validation proportionate to the change. Do not repeat
|
||||||
every command from the repository root before accepting a change. The test
|
successful checks for unchanged content merely to create a commit. The full
|
||||||
suite and maintained examples are deterministic, offline, and require no real
|
release-candidate checks have one executable entry point from the repository root:
|
||||||
provider credentials.
|
|
||||||
|
|
||||||
### Tests, Analysis, Build, And Examples
|
|
||||||
|
|
||||||
Run the ordinary and race-enabled suites, static analysis, the build, and both
|
|
||||||
maintained consumer examples:
|
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
go test ./...
|
./scripts/release-check.sh
|
||||||
go test -race ./...
|
|
||||||
go vet ./...
|
|
||||||
go build ./...
|
|
||||||
go run ./examples/go-library/prepare
|
|
||||||
go run ./examples/go-library/run
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Both examples must exit successfully. Review their JSON output: preparation
|
The [script](../scripts/release-check.sh) owns the executable checks:
|
||||||
must report the selected offline prompt, profile, model, and message count;
|
race-enabled tests, vet, both offline consumer examples with semantic output
|
||||||
execution must report the deterministic generated output, successful
|
assertions, tracked Go formatting, local Markdown links, module/workspace
|
||||||
validation, selected offline model, and usage. Neither command may contact a
|
hygiene, whitespace, and the credential-pattern scan. It does not publish,
|
||||||
provider or require credentials.
|
change files, validate release-note structure, or retire roadmaps. It requires Go,
|
||||||
|
Git, a POSIX shell, and Python 3. Tests and examples require no provider
|
||||||
|
credentials or live inference calls.
|
||||||
|
|
||||||
### Go Formatting
|
The script can run on intended uncommitted changes during development.
|
||||||
|
Formatting and documentation checks use tracked files; stage intended new
|
||||||
|
files before final validation so those checks include them. The release
|
||||||
|
procedure separately enforces a clean, committed candidate.
|
||||||
|
|
||||||
Check every tracked Go file. The final command must succeed and the captured
|
### Change Review
|
||||||
list must be empty:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
unformatted=$(
|
|
||||||
git ls-files '*.go' |
|
|
||||||
while IFS= read -r go_file
|
|
||||||
do
|
|
||||||
gofmt -l "$go_file"
|
|
||||||
done
|
|
||||||
)
|
|
||||||
test -z "$unformatted"
|
|
||||||
```
|
|
||||||
|
|
||||||
### Local Markdown Links
|
|
||||||
|
|
||||||
Use the Python standard library to verify every repository-relative Markdown
|
|
||||||
target and local heading fragment. The check is offline and prints nothing on
|
|
||||||
success:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
python3 - <<'PY'
|
|
||||||
from pathlib import Path
|
|
||||||
import re
|
|
||||||
import subprocess
|
|
||||||
import sys
|
|
||||||
from urllib.parse import unquote
|
|
||||||
|
|
||||||
root = Path.cwd().resolve()
|
|
||||||
markdown_files = [
|
|
||||||
root / name
|
|
||||||
for name in subprocess.check_output(
|
|
||||||
["git", "ls-files", "*.md"], text=True
|
|
||||||
).splitlines()
|
|
||||||
]
|
|
||||||
link_pattern = re.compile(r"!?\[[^]]*\]\(([^)]+)\)")
|
|
||||||
heading_pattern = re.compile(r"^#{1,6}\s+(.+?)\s*#*\s*$")
|
|
||||||
scheme_pattern = re.compile(r"^[a-z][a-z0-9+.-]*:", re.IGNORECASE)
|
|
||||||
|
|
||||||
|
|
||||||
def markdown_lines(path):
|
|
||||||
in_fence = False
|
|
||||||
fence = ""
|
|
||||||
for line in path.read_text(encoding="utf-8").splitlines():
|
|
||||||
stripped = line.lstrip()
|
|
||||||
marker = stripped[:3]
|
|
||||||
if marker in {"```", "~~~"}:
|
|
||||||
if not in_fence:
|
|
||||||
in_fence = True
|
|
||||||
fence = marker
|
|
||||||
elif marker == fence:
|
|
||||||
in_fence = False
|
|
||||||
fence = ""
|
|
||||||
continue
|
|
||||||
if not in_fence:
|
|
||||||
yield line
|
|
||||||
|
|
||||||
|
|
||||||
anchor_cache = {}
|
|
||||||
|
|
||||||
|
|
||||||
def anchors(path):
|
|
||||||
if path in anchor_cache:
|
|
||||||
return anchor_cache[path]
|
|
||||||
found = set()
|
|
||||||
counts = {}
|
|
||||||
for line in markdown_lines(path):
|
|
||||||
match = heading_pattern.match(line)
|
|
||||||
if not match:
|
|
||||||
continue
|
|
||||||
heading = re.sub(r"<[^>]+>", "", match.group(1)).replace("`", "")
|
|
||||||
base = re.sub(r"[^\w\- ]", "", heading.lower()).replace(" ", "-")
|
|
||||||
count = counts.get(base, 0)
|
|
||||||
counts[base] = count + 1
|
|
||||||
found.add(base if count == 0 else f"{base}-{count}")
|
|
||||||
anchor_cache[path] = found
|
|
||||||
return found
|
|
||||||
|
|
||||||
|
|
||||||
failures = []
|
|
||||||
for source in markdown_files:
|
|
||||||
text = "\n".join(markdown_lines(source))
|
|
||||||
for match in link_pattern.finditer(text):
|
|
||||||
target = match.group(1).strip()
|
|
||||||
if target.startswith("<") and target.endswith(">"):
|
|
||||||
target = target[1:-1]
|
|
||||||
if scheme_pattern.match(target) or target.startswith("//"):
|
|
||||||
continue
|
|
||||||
path_text, separator, fragment = target.partition("#")
|
|
||||||
destination = source if not path_text else source.parent / unquote(path_text)
|
|
||||||
try:
|
|
||||||
destination = destination.resolve()
|
|
||||||
destination.relative_to(root)
|
|
||||||
except ValueError:
|
|
||||||
failures.append(f"{source.relative_to(root)}: escapes repository: {target}")
|
|
||||||
continue
|
|
||||||
if not destination.exists():
|
|
||||||
failures.append(f"{source.relative_to(root)}: missing target: {target}")
|
|
||||||
continue
|
|
||||||
if separator and destination.suffix.lower() == ".md":
|
|
||||||
fragment = unquote(fragment).lower()
|
|
||||||
if fragment not in anchors(destination):
|
|
||||||
failures.append(f"{source.relative_to(root)}: missing anchor: {target}")
|
|
||||||
|
|
||||||
if failures:
|
|
||||||
print("\n".join(failures), file=sys.stderr)
|
|
||||||
raise SystemExit(1)
|
|
||||||
PY
|
|
||||||
```
|
|
||||||
|
|
||||||
### Repository Hygiene And Review
|
|
||||||
|
|
||||||
Reject an active Go workspace, tracked workspace files, a vendor tree, or a
|
|
||||||
module replacement:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
case "$(go env GOWORK)" in
|
|
||||||
''|off) ;;
|
|
||||||
*) printf '%s\n' 'an active Go workspace is not allowed' >&2; exit 1 ;;
|
|
||||||
esac
|
|
||||||
test -z "$(git ls-files go.work go.work.sum)"
|
|
||||||
test ! -e vendor
|
|
||||||
if grep -Eq '^[[:space:]]*replace([[:space:]]|\()' go.mod
|
|
||||||
then
|
|
||||||
printf '%s\n' 'go.mod contains a replacement' >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
```
|
|
||||||
|
|
||||||
Check whitespace in both unstaged and staged changes. List ignored files and
|
|
||||||
scan tracked content for common credential forms:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
git diff --check
|
|
||||||
git diff --cached --check
|
|
||||||
test -z "$(git ls-files --others --ignored --exclude-standard)"
|
|
||||||
credential_pattern='-----BEGIN ([A-Z0-9]+ )?PRIV''ATE KEY-----|AKI''A[0-9A-Z]{16}|gh[pousr]_[A-Za-z0-9]{36,}|sk-[A-Za-z0-9]{32,}'
|
|
||||||
if git grep -nEI -e "$credential_pattern" -- .
|
|
||||||
then
|
|
||||||
printf '%s\n' 'possible credential found' >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
```
|
|
||||||
|
|
||||||
Inspect `git status --short --untracked-files=all` and the complete diff before
|
Inspect `git status --short --untracked-files=all` and the complete diff before
|
||||||
accepting a change. The status may contain only the intended source changes
|
accepting a change. Reject unintended files, credentials, private data,
|
||||||
during development. Reject credentials, private keys, environment files,
|
generated binaries, test output, downloaded assets, and template residue.
|
||||||
generated binaries, test or coverage output, downloaded assets, template
|
The automated credential scan does not replace review of the actual change.
|
||||||
residue, and any other artifact that does not belong in source control. The
|
|
||||||
credential scan catches common forms but does not replace inspection of the
|
|
||||||
actual change.
|
|
||||||
|
|
||||||
After committing the accepted change, require a clean candidate:
|
For releases, follow the [release procedure](release.md). Its publication
|
||||||
|
command runs the full local checks once on the final committed candidate and
|
||||||
|
automates release-note structure and Git checks. Do not repeat ordinary change
|
||||||
|
review as a release sign-off. Roadmap retirement remains preparation housekeeping.
|
||||||
|
|
||||||
```sh
|
Follow the [agent commit policy](policy/agents.md#git-commit-policy) for local
|
||||||
test -z "$(git status --porcelain)"
|
commits. Ordinary commits may leave unrelated work in the workspace; preserve
|
||||||
```
|
and report it. A clean worktree and index are required for release candidates,
|
||||||
|
as enforced by the publication command, not for every ordinary commit.
|
||||||
|
|||||||
@@ -338,7 +338,7 @@ selections, not automatic defaults:
|
|||||||
Select either name through an existing request `profile_id` or prompt
|
Select either name through an existing request `profile_id` or prompt
|
||||||
`default_profile`. Consumers can replace either definition or its inherited
|
`default_profile`. Consumers can replace either definition or its inherited
|
||||||
base through the ordinary profile-source precedence above. The
|
base through the ordinary profile-source precedence above. The
|
||||||
[release policy](release.md#catalog-profile-compatibility) defines the
|
[release policy](policy/release.md#catalog-profile-compatibility) defines the
|
||||||
cross-version guarantee for these names.
|
cross-version guarantee for these names.
|
||||||
|
|
||||||
## External Profile Inventories
|
## External Profile Inventories
|
||||||
@@ -350,7 +350,7 @@ duplicated here. Browse the exact data selected by this Promptkit version:
|
|||||||
- [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
|
||||||
[release policy](release.md#catalog-profile-compatibility) owns the precise
|
[release policy](policy/release.md#catalog-profile-compatibility) owns the precise
|
||||||
compatibility boundary; a selected module version identifies tested local data,
|
compatibility boundary; a selected module version identifies tested local data,
|
||||||
not live provider availability.
|
not live provider availability.
|
||||||
|
|
||||||
|
|||||||
88
docs/policy/agents.md
Normal file
88
docs/policy/agents.md
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
# Agent Policy
|
||||||
|
|
||||||
|
**Base Policy Version:** 1.1
|
||||||
|
|
||||||
|
**Last Updated:** 2026-09-23
|
||||||
|
|
||||||
|
## Purpose
|
||||||
|
|
||||||
|
Agents must follow these house rules before recommending, planning, or
|
||||||
|
implementing repository changes.
|
||||||
|
|
||||||
|
## Implementation Discipline
|
||||||
|
|
||||||
|
Write the simplest idiomatic code that satisfies the user's request.
|
||||||
|
Simplify the mechanism, not the user's choices. Do not implicitly strengthen
|
||||||
|
requirements, restrictions, or guarantees.
|
||||||
|
|
||||||
|
**Keep implementation machinery proportionate.** Use straightforward,
|
||||||
|
idiomatic code and introduce only the machinery needed to support the requested
|
||||||
|
behavior and flexibility. Optimize for conceptual simplicity and
|
||||||
|
maintainability, not for the fewest lines, fewest options, or narrowest product
|
||||||
|
surface.
|
||||||
|
|
||||||
|
**Do not invent restrictions.** Do not reject, prohibit, constrain, cap,
|
||||||
|
harden, or otherwise narrow behavior unless required by the user, an explicit
|
||||||
|
repository contract, or an unavoidable correctness constraint. Preserve
|
||||||
|
operator and caller choice where policy has not been established. If an
|
||||||
|
additional restriction appears advisable, present it as a decision rather than
|
||||||
|
silently implementing it.
|
||||||
|
|
||||||
|
A correctness constraint must follow from the requested behavior or an
|
||||||
|
established invariant, not from the convenience of the chosen implementation.
|
||||||
|
Explain the specific failure it prevents and why a less restrictive
|
||||||
|
implementation cannot satisfy the contract.
|
||||||
|
|
||||||
|
**An implementation detail is not repository policy.** Tests and documentation
|
||||||
|
must not elevate incidental behavior into a durable guarantee or restriction
|
||||||
|
unless that behavior was expressly selected as part of the contract. Existing
|
||||||
|
explicit contracts remain authoritative; changing or weakening one requires a
|
||||||
|
deliberate decision rather than being inferred from this principle.
|
||||||
|
|
||||||
|
Agent-authored plans, tests, documentation, and prior implementations are not
|
||||||
|
evidence that an additional restriction was deliberately approved. Identify the
|
||||||
|
authorizing requirement or decision; when that authority is unclear, surface
|
||||||
|
the ambiguity rather than treating repetition as approval.
|
||||||
|
|
||||||
|
**Do not invent guarantees.** Do not strengthen public contracts, guarantees,
|
||||||
|
or invariants beyond those expressly requested by the user.
|
||||||
|
|
||||||
|
**Use the standard library.** Prefer simple, idiomatic standard-library
|
||||||
|
implementations when they satisfy the requested behavior. Do not add custom
|
||||||
|
power-loss protection or defenses against privileged concurrent filesystem
|
||||||
|
actors unless expressly required. Preserve existing repository contracts.
|
||||||
|
|
||||||
|
## Git Commit Policy
|
||||||
|
|
||||||
|
By default, create a commit after completing each coherent unit of work, using a
|
||||||
|
concise, plain-English message describing what changed. This policy is standing
|
||||||
|
authorization to create those local commits; a separate user request is not
|
||||||
|
required. An explicit user instruction to leave work uncommitted takes precedence.
|
||||||
|
|
||||||
|
A unit of work is a focused, reviewable outcome, including its relevant tests and
|
||||||
|
documentation. Do not commit after every intermediate edit or create empty commits.
|
||||||
|
Complete the appropriate validation before committing. If work is incomplete or
|
||||||
|
validation is blocked, report that state rather than presenting it as completed.
|
||||||
|
|
||||||
|
Before committing:
|
||||||
|
|
||||||
|
1. Run `git status --short` and review the relevant diff, including any staged
|
||||||
|
changes. Identify changes that predate the current unit of work.
|
||||||
|
2. Exclude secrets, local environment files, generated junk, and unrelated changes.
|
||||||
|
3. Stage only the files or hunks belonging to the completed unit. Use `git add .`
|
||||||
|
only when every included change belongs to that unit. Do not disturb unrelated
|
||||||
|
staged or unstaged work.
|
||||||
|
4. Review `git diff --staged` and run appropriate checks for the change. Do not
|
||||||
|
repeat checks already passed for unchanged content merely to create a commit.
|
||||||
|
5. Review `git log --oneline -n 10` and use
|
||||||
|
`git commit -m "<concise plain-English commit message>"`.
|
||||||
|
6. Report the commit identifier and any remaining uncommitted work.
|
||||||
|
|
||||||
|
If the unit cannot be safely separated from pre-existing work, leave it uncommitted
|
||||||
|
and explain the overlap rather than silently including that work. If a commit
|
||||||
|
fails, preserve the changes and report the failure; do not bypass hooks.
|
||||||
|
|
||||||
|
Default commit authorization does not authorize pushing, publishing, amending,
|
||||||
|
resetting, reverting, or rewriting history. Those actions require a separate user
|
||||||
|
instruction. Do not use `git commit -a` or `git commit --no-verify` to bypass the
|
||||||
|
staging and validation discipline above.
|
||||||
@@ -1,5 +1,9 @@
|
|||||||
# Architecture Policy
|
# Architecture Policy
|
||||||
|
|
||||||
|
**Base Policy Version:** 1.0
|
||||||
|
|
||||||
|
**Last Updated:** 2026-09-23
|
||||||
|
|
||||||
## Purpose
|
## Purpose
|
||||||
|
|
||||||
This document defines Promptkit's current high-level architecture and the
|
This document defines Promptkit's current high-level architecture and the
|
||||||
@@ -17,42 +21,9 @@ The module root contains package `promptkit`, which is the public facade. It
|
|||||||
provides the supported engine, configuration and source options, requests,
|
provides the supported engine, configuration and source options, requests,
|
||||||
results, public values, extension interfaces, profiles, and error sentinels.
|
results, public values, extension interfaces, profiles, and error sentinels.
|
||||||
|
|
||||||
The implemented internal components consist of:
|
The [internal component overview](../internal/overview.md) owns the inventory
|
||||||
|
of implemented packages and their concrete responsibilities. This policy owns
|
||||||
- `internal/domain`, which owns framework data values and source-neutral
|
the boundaries and dependency rules those components must preserve.
|
||||||
invariants shared by later internal components;
|
|
||||||
- `internal/backend`, which owns validated immutable OpenAI-compatible backend
|
|
||||||
definitions;
|
|
||||||
- `internal/capacity`, which owns engine-local bounded run admission and
|
|
||||||
model-generation scheduling for limited backends;
|
|
||||||
- `internal/defaults`, which owns application-neutral framework defaults and
|
|
||||||
constructs the default execution target;
|
|
||||||
- `internal/filecatalog`, which discovers YAML files and provides source-path
|
|
||||||
helpers for filesystem and `fs.FS` consumers;
|
|
||||||
- `internal/catalog`, which validates immutable external maintained-catalog
|
|
||||||
assets and their reserved profile namespace before they are eligible for
|
|
||||||
engine assembly;
|
|
||||||
- `internal/jsonvalue`, which validates and defensively copies JSON-compatible
|
|
||||||
extra-parameter trees;
|
|
||||||
- `internal/promptdef`, which loads and validates prompt definitions from
|
|
||||||
filesystem and `fs.FS` sources;
|
|
||||||
- `internal/profile`, which loads, validates, and overlays execution profiles
|
|
||||||
from filesystem and `fs.FS` sources;
|
|
||||||
- `internal/prompt`, which renders prompt messages from Go templates;
|
|
||||||
- `internal/artifact`, which resolves ordinary inline and unrestricted
|
|
||||||
caller-selected file references;
|
|
||||||
- `internal/validate`, which validates basic, JSON, and JSON Schema output
|
|
||||||
using filesystem and `fs.FS` schema sources;
|
|
||||||
- `internal/llm`, which defines the provider-neutral generation boundary and
|
|
||||||
implements outbound OpenAI-compatible chat requests; and
|
|
||||||
- `internal/usecase`, which coordinates preparation and execution across the
|
|
||||||
internal framework components.
|
|
||||||
- `internal/engine`, which assembles those components into one engine and
|
|
||||||
delegates execution to the use-case runner.
|
|
||||||
|
|
||||||
The `examples/go-library/prepare` and `examples/go-library/run` packages are
|
|
||||||
maintained downstream consumers of the root facade. They do not expose library
|
|
||||||
packages or participate in internal assembly.
|
|
||||||
|
|
||||||
The internal engine assembles one immutable backend registry, one capacity manager,
|
The internal engine assembles one immutable backend registry, one capacity manager,
|
||||||
the internal repositories, renderer, validator, outbound client, and use-case
|
the internal repositories, renderer, validator, outbound client, and use-case
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
# Documentation Policy
|
# Documentation Policy
|
||||||
|
|
||||||
|
**Base Policy Version:** 1.1
|
||||||
|
|
||||||
|
**Last Updated:** 2026-09-23
|
||||||
|
|
||||||
## Purpose
|
## Purpose
|
||||||
|
|
||||||
This policy assigns each Promptkit documentation topic to one canonical owner.
|
This policy assigns each Promptkit documentation topic to one canonical owner.
|
||||||
@@ -68,17 +72,19 @@ mechanisms, not secret values.
|
|||||||
|
|
||||||
| Topic | Canonical owner | Owned content | Content owned elsewhere |
|
| Topic | Canonical owner | Owned content | Content owned elsewhere |
|
||||||
| --- | --- | --- | --- |
|
| --- | --- | --- | --- |
|
||||||
| Project orientation | `README.md` | What Promptkit is, its current usability, module identity, license summary, and links onward. | Exact API contracts, contributor procedures, architecture detail, and release steps. |
|
| Project orientation | `README.md` | What Promptkit is, its current usability, module identity, license summary, a minimal successful quickstart, and links onward. | Exact API contracts, contributor procedures, architecture detail, and release steps. |
|
||||||
| Contributor workflow | `docs/development.md` | Task-oriented reading guide, local workflow, validation commands, and repository hygiene. | Architecture rules, API semantics, subsystem behavior, and release procedure. |
|
| Contributor workflow | `docs/development.md` | Task-oriented reading guide, local workflow, validation commands, and repository hygiene. | Architecture rules, API semantics, subsystem behavior, and release procedure. |
|
||||||
| Current architecture | `docs/policy/architecture.md` | System shape, normative ownership, dependency direction, package boundaries, invariants, and non-goals. | Concrete component inventory, implementation mechanics, contributor procedures, decision history, and future work. |
|
| Current architecture | `docs/policy/architecture.md` | System shape, normative ownership, dependency direction, package boundaries, invariants, and non-goals. | Concrete component inventory, implementation mechanics, contributor procedures, decision history, and future work. |
|
||||||
|
| Agent policy | `docs/policy/agents.md` | Agent implementation discipline, proportionality, idiomatic simplicity, local commit authorization and discipline, and rules against inventing restrictions, guarantees, or repository policy. | Public contracts, architecture, testing, and contributor procedures. |
|
||||||
| Documentation organization | `docs/policy/documentation.md` | Documentation ownership, audience boundaries, maintenance rules, and document lifecycle. | Library architecture or runtime behavior. |
|
| Documentation organization | `docs/policy/documentation.md` | Documentation ownership, audience boundaries, maintenance rules, and document lifecycle. | Library architecture or runtime behavior. |
|
||||||
| Testing policy | `docs/policy/testing.md` | Test philosophy, risk-based sufficiency, test boundaries, doubles, coverage guidance, regression policy, and test maintenance. | Subsystem behavior, exact public contracts, subsystem-specific test inventories, and implementation plans. |
|
| Testing policy | `docs/policy/testing.md` | Test philosophy, risk-based sufficiency, test boundaries, doubles, coverage guidance, regression policy, and test maintenance. | Subsystem behavior, exact public contracts, subsystem-specific test inventories, and implementation plans. |
|
||||||
| Release procedure | `docs/release.md`, when present | Required release validation, version and tag procedure, release ordering, and post-publication checks. | General contributor workflow, public API semantics, and decision history. |
|
| Release policy | `docs/policy/release.md` | Versioning, compatibility, release-note requirements, validation obligations, immutability, recovery, and adoption scope. | Executable commands, publication mechanics, and historical release summaries. |
|
||||||
|
| Release procedure | `docs/release.md` | Maintainer prerequisites, candidate preparation, concrete publication guards and commands, verification, and recovery steps. | Release-policy requirements, public API semantics, and historical summaries. |
|
||||||
| Exact exported Go API | Go declarations and GoDoc, as APIs are implemented | Exported names, signatures, types, values, errors, and exact behavioral contracts. | Task-oriented consumer walkthroughs, implementation details, and future API proposals. |
|
| Exact exported Go API | Go declarations and GoDoc, as APIs are implemented | Exported names, signatures, types, values, errors, and exact behavioral contracts. | Task-oriented consumer walkthroughs, implementation details, and future API proposals. |
|
||||||
| Framework file formats | `docs/formats.md` | Prompt-definition and profile YAML fields, schema references, defaults, validation modes, built-in profiles, credentials, and file-to-request precedence. | Exported Go declarations, outbound wire behavior, internal parsing mechanics, and application configuration. |
|
| Framework file formats | `docs/formats.md` | Prompt-definition and profile YAML fields, schema references, defaults, validation modes, built-in profiles, credentials, and file-to-request precedence. | Exported Go declarations, outbound wire behavior, internal parsing mechanics, and application configuration. |
|
||||||
| Consumer guidance | `docs/consumers/`, when consumer workflows require dedicated guidance | Task-oriented use of implemented public APIs, minimal examples, and consumer responsibilities. | Exact exported declarations and internal mechanics. |
|
| Consumer guidance | `docs/consumers/`, when consumer workflows require dedicated guidance | Task-oriented use of implemented public APIs, minimal examples, and consumer responsibilities. | Exact exported declarations and internal mechanics. |
|
||||||
| Durable integration contracts | `docs/integrations/`, when integrations exist | External formats and protocols, compatibility behavior, and upstream or downstream responsibilities. | Internal transformations and public Go declarations. |
|
| Durable integration contracts | `docs/integrations/`, when integrations exist | External formats and protocols, compatibility behavior, and upstream or downstream responsibilities. | Internal transformations and public Go declarations. |
|
||||||
| Supplemental release guidance | None. `docs/releases/` may be used when a release benefits from a changelog or migration guide. | No canonical content. These files may briefly summarize release-specific changes, compatibility, and consumer migration paths, and may be corrected, consolidated, archived, or removed when no longer useful. | Public API and behavior contracts, formats, integrations, architecture, release procedure, and the authoritative annotated-tag release record. |
|
| Release-note history | `docs/releases/` | Mandatory version-matched historical summaries for releases made under the adopted release policy; the note at the immutable tag records that release. | Current APIs, behavior, formats, compatibility contracts, and release procedures. |
|
||||||
| Implemented component inventory | `docs/internal/overview.md` | Current packages and components, their implemented responsibilities, and links to focused internal documents. | Normative architecture, contributor workflow, external contracts, and proposed components. |
|
| Implemented component inventory | `docs/internal/overview.md` | Current packages and components, their implemented responsibilities, and links to focused internal documents. | Normative architecture, contributor workflow, external contracts, and proposed components. |
|
||||||
| Internal subsystem behavior | Other files under `docs/internal/`, when a subsystem needs durable detail | Implementation flow, internal collaborators and state transitions, package-local guarantees and failures, and relevant tests. | Global architecture invariants, public API definitions, and future package plans. |
|
| Internal subsystem behavior | Other files under `docs/internal/`, when a subsystem needs durable detail | Implementation flow, internal collaborators and state transitions, package-local guarantees and failures, and relevant tests. | Global architecture invariants, public API definitions, and future package plans. |
|
||||||
| Architectural decision history | `docs/adr/`, when repository-local decisions require records | Significant decisions, context, alternatives, rationale, consequences, and supersession history. | Current behavior reference, implementation status, and task sequencing. |
|
| Architectural decision history | `docs/adr/`, when repository-local decisions require records | Significant decisions, context, alternatives, rationale, consequences, and supersession history. | Current behavior reference, implementation status, and task sequencing. |
|
||||||
@@ -110,22 +116,22 @@ but must link to its canonical definition rather than restate it.
|
|||||||
The [framework format reference](../formats.md) owns exact prompt, profile, and
|
The [framework format reference](../formats.md) owns exact prompt, profile, and
|
||||||
schema-file contracts. Integration documents own external wire formats.
|
schema-file contracts. Integration documents own external wire formats.
|
||||||
|
|
||||||
### Supplemental Release Guidance
|
### Release Documentation
|
||||||
|
|
||||||
Files under `docs/releases/` may provide changelog-style summaries and
|
The [release policy](release.md) owns release requirements; the
|
||||||
migration guidance for a particular release. They are navigation and
|
[repository release procedure](../release.md) owns their concrete execution.
|
||||||
orientation aids, not canonical owners of public APIs, behavior, formats,
|
Version-matched checked-in notes are required for future releases under that
|
||||||
integrations, architecture, release procedure, or other durable facts. When a
|
policy. The source tag is the release identity, and the note in its immutable
|
||||||
reader needs detail beyond a short release-specific note, the release document
|
tree is the historical summary; annotated tag messages complement that record.
|
||||||
must link to the applicable canonical documentation rather than reproduce its
|
|
||||||
contract.
|
|
||||||
|
|
||||||
The annotated tag message required by the
|
Release notes do not own current API or behavior contracts. Link to the
|
||||||
[release procedure](../release.md#write-the-release-note) remains the
|
canonical owners for details instead of reproducing those contracts. Published
|
||||||
authoritative release record. Supplemental release documents may be corrected,
|
notes are not disposable guidance and must not be replaced under the same
|
||||||
consolidated, archived, or removed at any time when they are no longer useful,
|
version. Corrections belong in a subsequent release.
|
||||||
provided maintained documentation does not depend on them and the annotated
|
|
||||||
tag record remains intact.
|
Adoption is prospective. Previously published tags and historical notes retain
|
||||||
|
their original records and are not reformatted or rewritten to satisfy the new
|
||||||
|
requirements.
|
||||||
|
|
||||||
### Security Topics
|
### Security Topics
|
||||||
|
|
||||||
@@ -178,9 +184,8 @@ durable owners, update incoming links, and archive or remove the roadmap
|
|||||||
according to repository practice. Do not preserve completed roadmaps as a
|
according to repository practice. Do not preserve completed roadmaps as a
|
||||||
second current-state reference.
|
second current-state reference.
|
||||||
|
|
||||||
Supplemental release documents may likewise be removed without preserving a
|
Retain release notes as historical records under the release policy. Do not
|
||||||
replacement. Before removal, update maintained incoming links so current
|
apply temporary-roadmap retirement rules to published release notes.
|
||||||
documentation does not depend on an optional historical guide.
|
|
||||||
|
|
||||||
Before completing documentation work:
|
Before completing documentation work:
|
||||||
|
|
||||||
|
|||||||
146
docs/policy/release.md
Normal file
146
docs/policy/release.md
Normal file
@@ -0,0 +1,146 @@
|
|||||||
|
# Release Policy
|
||||||
|
|
||||||
|
**Base Policy Version:** 1.0
|
||||||
|
|
||||||
|
**Last Updated:** 2026-09-23
|
||||||
|
|
||||||
|
## Purpose And Adoption Scope
|
||||||
|
|
||||||
|
This policy owns Promptkit's release requirements and compatibility rules.
|
||||||
|
The [release procedure](../release.md) owns the commands used to satisfy them.
|
||||||
|
This scoped adoption applies to releases prepared after its adoption on
|
||||||
|
2026-09-23. Published tags and historical notes are not rewritten to retrofit
|
||||||
|
the new note format.
|
||||||
|
|
||||||
|
## Release Model And Compatibility
|
||||||
|
|
||||||
|
Promptkit publishes source-only Go module releases from committed, pushed
|
||||||
|
`main` candidates through annotated `vMAJOR.MINOR.PATCH` tags. It publishes
|
||||||
|
no binaries, hosted releases, or other artifacts and uses maintainer-run
|
||||||
|
validation rather than hosted CI. Versions must be unused locally and on
|
||||||
|
`origin`; the existing procedure accepts stable version tags only.
|
||||||
|
|
||||||
|
Before v1, minor releases may change the public API and patches preserve
|
||||||
|
compatibility within their minor line, subject to the catalog-data provision
|
||||||
|
below. Release notes must identify compatibility impact, public API changes,
|
||||||
|
and required consumer action. The source tag identifies the exact release;
|
||||||
|
the checked-in note at that tag records its historical summary.
|
||||||
|
|
||||||
|
## Catalog Profile Compatibility
|
||||||
|
|
||||||
|
External catalog profile data may be added, removed, renamed, or modified
|
||||||
|
without deprecation or advance notice. This exception is limited to profile
|
||||||
|
data imported from the maintained catalog modules. It does not weaken ordinary
|
||||||
|
compatibility for Promptkit's public Go API, configuration and format semantics,
|
||||||
|
runtime behavior, catalog-module APIs, manifest schema, backend definitions, or
|
||||||
|
consumer-owned definitions.
|
||||||
|
|
||||||
|
Within the catalog versions selected and tested by a Promptkit release, and
|
||||||
|
unless a consumer overrides the name or its base, Promptkit keeps the literal
|
||||||
|
profile IDs `promptkit-openrouter-standard` and
|
||||||
|
`promptkit-openrouter-auto` available. The names do not promise a permanent
|
||||||
|
model, backend, routing behavior, settings, cost, output, or upstream
|
||||||
|
availability. The [framework format reference](../formats.md#built-in-profile-catalog)
|
||||||
|
owns their current definitions.
|
||||||
|
|
||||||
|
`v0.10.0` is the initial minor release for this compatibility transition.
|
||||||
|
Afterward, catalog-only updates and adjustments to the current selections may
|
||||||
|
ship in a patch release when all other compatibility obligations remain intact.
|
||||||
|
External profile removals can require consumer action; they are not automatic
|
||||||
|
migrations.
|
||||||
|
|
||||||
|
Catalog adoption and release validation remain local and offline. They do not
|
||||||
|
probe provider endpoints, request model lists, or make inference calls.
|
||||||
|
|
||||||
|
## Release Documentation
|
||||||
|
|
||||||
|
Every new release must include `docs/releases/<version>.md` in the tagged
|
||||||
|
source, using the complete tag as the filename. Its title contains Promptkit
|
||||||
|
and that exact version. Use this structure:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
# Promptkit vMAJOR.MINOR.PATCH
|
||||||
|
|
||||||
|
This release ...
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
|
||||||
|
## Compatibility
|
||||||
|
|
||||||
|
## Upgrade
|
||||||
|
|
||||||
|
## Changes
|
||||||
|
```
|
||||||
|
|
||||||
|
State “No action required” or “None” where appropriate rather than omitting a
|
||||||
|
section. Keep exact current contracts in their canonical documents and link
|
||||||
|
to them. Update affected canonical documentation in the same candidate.
|
||||||
|
|
||||||
|
These notes are historical records, not optional disposable guidance. Published
|
||||||
|
release-note contents must not be replaced under the same version. Corrections
|
||||||
|
belong in a subsequent release. Annotated-tag messages complement the checked-in
|
||||||
|
note: generate the annotation from that note and the validated commit rather
|
||||||
|
than maintaining a second summary.
|
||||||
|
|
||||||
|
## Validation And Publication
|
||||||
|
|
||||||
|
The [publication script](../../scripts/release.sh) runs the
|
||||||
|
[local checks](../../scripts/release-check.sh) once for the final candidate.
|
||||||
|
Retain clean-candidate, synchronized-main, unused-version, module-hygiene,
|
||||||
|
release-note structure, and tag-target checks. Publish only the selected tag
|
||||||
|
ref. Changing the candidate requires fresh validation. No provider endpoint
|
||||||
|
probes or inference calls are release checks.
|
||||||
|
|
||||||
|
Release-note content and retirement of completed roadmaps are preparation
|
||||||
|
responsibilities, not separate human sign-off gates. Preserve planned and
|
||||||
|
deferred work and repair links. Ordinary change review covers unintended files,
|
||||||
|
secrets, and private data; do not repeat it as a release-specific approval.
|
||||||
|
|
||||||
|
A successful tag push to origin completes the release. Never wait for CI to
|
||||||
|
finish or succeed. CI results, remote read-back, and Go module availability
|
||||||
|
are informational follow-ups, not completion gates. An ambiguous push result
|
||||||
|
requires confirming publication on origin, not waiting for CI.
|
||||||
|
|
||||||
|
## Immutability And Failure Recovery
|
||||||
|
|
||||||
|
Never move, replace, recreate, or delete a published tag or replace published
|
||||||
|
release contents. If validation fails before publication, correct the candidate,
|
||||||
|
rerun the complete checks, and repeat the publication guards. Remove an
|
||||||
|
unpublished local tag only after confirming it was not published.
|
||||||
|
|
||||||
|
If publication or subsequent investigation reveals a defect, leave the
|
||||||
|
published release intact. Correct the defect on main, select a new patch or
|
||||||
|
other semantically appropriate version, write its matching release note, and
|
||||||
|
repeat the complete procedure. If publication status is uncertain, inspect
|
||||||
|
the authoritative remote before deciding whether a tag is unpublished; do not
|
||||||
|
overwrite it to retry.
|
||||||
|
|
||||||
|
Transient network, authentication, CI, or module-availability failures do not
|
||||||
|
by themselves warrant a new version. Investigate separately and publish a
|
||||||
|
corrective release only when published contents actually need changing.
|
||||||
|
|
||||||
|
## Policy Exceptions And Deliberate Scope
|
||||||
|
|
||||||
|
This adoption follows the maintainer-approved lean workflow rather than every
|
||||||
|
base-policy guard:
|
||||||
|
|
||||||
|
- Collision checks concern origin, the authoritative publication destination,
|
||||||
|
rather than every configured remote. Local and origin tag checks, synchronized
|
||||||
|
main, and an explicit selected-ref push protect the actual release channel.
|
||||||
|
- Automated local validation and publication-state checks replace manual
|
||||||
|
mechanical inspections and separate human sign-offs. Ordinary change review,
|
||||||
|
editorial responsibility for release notes, and roadmap housekeeping remain;
|
||||||
|
repeating them as approvals would add friction without distinct protection.
|
||||||
|
- Successful tag publication completes this source-only release. CI can be slow
|
||||||
|
or unreliable, and module availability depends on external services. Neither
|
||||||
|
is a completion gate. Local candidate validation and explicit tag-target
|
||||||
|
checks protect publication; ambiguous push results are resolved against origin.
|
||||||
|
Actual defects are corrected in a new release, never by replacing a tag.
|
||||||
|
|
||||||
|
Ignored local files are not prohibited merely because they exist: they are not
|
||||||
|
included in the tagged commit. The clean-candidate guard and ordinary review of
|
||||||
|
tracked changes protect the published contents.
|
||||||
|
|
||||||
|
The catalog profile provision preserves an already approved compatibility
|
||||||
|
boundary; it does not extend volatility to backend definitions or runtime
|
||||||
|
contracts. Further release-governance changes require deliberate approval.
|
||||||
@@ -1,5 +1,9 @@
|
|||||||
# Testing Policy
|
# Testing Policy
|
||||||
|
|
||||||
|
**Base Policy Version:** 1.0
|
||||||
|
|
||||||
|
**Last Updated:** 2026-09-23
|
||||||
|
|
||||||
## Purpose
|
## Purpose
|
||||||
|
|
||||||
Our tests exist to make **incorrect changes expensive and correct changes cheap**.
|
Our tests exist to make **incorrect changes expensive and correct changes cheap**.
|
||||||
@@ -50,16 +54,21 @@ Examples of appropriate seams include clocks, randomness, subprocesses, remote A
|
|||||||
## Test execution requirements
|
## Test execution requirements
|
||||||
|
|
||||||
Promptkit currently uses maintainer-run validation rather than hosted CI.
|
Promptkit currently uses maintainer-run validation rather than hosted CI.
|
||||||
Maintainers run the complete local workflow in the
|
Ordinary work requires validation proportionate to its scope and risk. Do not
|
||||||
[development guide](../development.md#maintainer-validation) before accepting
|
repeat successful checks for unchanged content merely to create a commit.
|
||||||
changes. That guide is the canonical owner of exact commands, formatting,
|
Release candidates require the complete local workflow in the
|
||||||
documentation-link validation, and repository-hygiene checks.
|
[development guide](../development.md#maintainer-validation). That guide routes
|
||||||
|
contributors to the executable checks for formatting, documentation links,
|
||||||
|
and repository hygiene.
|
||||||
Introducing hosted CI later would supplement, not silently redefine, this
|
Introducing hosted CI later would supplement, not silently redefine, this
|
||||||
documented validation model.
|
documented validation model.
|
||||||
|
|
||||||
Maintainer validation must include ordinary and race-enabled package tests,
|
Full release-candidate validation includes race-enabled package tests, explicit
|
||||||
static analysis, a complete build, and execution of both maintained offline
|
static analysis, and execution with automated semantic checks of both maintained
|
||||||
consumer examples. The preparation example protects assembled preparation and
|
offline consumer examples. The test run builds the packages; the examples
|
||||||
|
also exercise ordinary compilation. Separate ordinary tests and a standalone
|
||||||
|
build are not additional release gates. Ordinary tests remain useful during
|
||||||
|
development. The preparation example protects assembled preparation and
|
||||||
inspection behavior. The execution example separately protects assembled
|
inspection behavior. The execution example separately protects assembled
|
||||||
`Run`, injected-client, validation, usage, and result behavior.
|
`Run`, injected-client, validation, usage, and result behavior.
|
||||||
|
|
||||||
|
|||||||
320
docs/release.md
320
docs/release.md
@@ -1,276 +1,82 @@
|
|||||||
# Release Procedure
|
# Release Procedure
|
||||||
|
|
||||||
## Release Model
|
This runbook implements the [release policy](policy/release.md). A successful
|
||||||
|
push of the selected annotated tag to origin completes the release. Never wait
|
||||||
|
for CI to finish or succeed.
|
||||||
|
|
||||||
Promptkit publishes a Go library through source commits and semantic Go module
|
## Prepare The Candidate
|
||||||
tags. It does not publish runnable binaries or binary packages and does not
|
|
||||||
currently use hosted CI. The release maintainer performs and records the
|
|
||||||
required validation.
|
|
||||||
|
|
||||||
`v0.1.0` is the initial published release. Later releases use semantic
|
Required tools are Git, Go with race-detector support, POSIX shell, and Python
|
||||||
`vMAJOR.MINOR.PATCH` tags. Before `v1`, minor releases may change the public
|
3. Publication requires push access to origin. Work from the repository root.
|
||||||
API and patch releases preserve compatibility within their minor line. Every
|
|
||||||
pre-`v1` release note must summarize compatibility, identify public API
|
|
||||||
changes, and state any action required of consumers.
|
|
||||||
|
|
||||||
Promptkit releases are source-only. The annotated tag message is the release
|
Select an unused version and create `docs/releases/<version>.md` using the
|
||||||
note; there is no separate hosted release or binary packaging step.
|
[required structure](policy/release.md#release-documentation). Describe
|
||||||
|
compatibility impact and consumer actions and update affected canonical docs.
|
||||||
|
For catalog updates, record selected catalog versions and any consumer action,
|
||||||
|
linking to the catalog policy rather than repeating its contracts.
|
||||||
|
|
||||||
|
Retire completed roadmaps, preserving planned or deferred work and repairing
|
||||||
|
links. This is housekeeping, not a separate approval gate. Review changes
|
||||||
|
through the ordinary development workflow, commit them, and push main to
|
||||||
|
origin. No repeated release-specific diff review is required.
|
||||||
|
|
||||||
|
## Validate And Publish
|
||||||
|
|
||||||
|
Run the following with the chosen unused version (replace the placeholder):
|
||||||
|
|
||||||
|
```sh
|
||||||
|
./scripts/release.sh vMAJOR.MINOR.PATCH
|
||||||
|
```
|
||||||
|
|
||||||
|
The [publication script](../scripts/release.sh) checks a clean, synchronized
|
||||||
|
main candidate, the version and unused tag, and the release note's title and
|
||||||
|
required headings. It runs the [local checks](../scripts/release-check.sh)
|
||||||
|
once, rechecks candidate identity and publication state, generates the
|
||||||
|
annotation from the committed note plus the validated commit, and pushes only
|
||||||
|
the selected annotated tag.
|
||||||
|
|
||||||
|
There is no separate tag-message authoring, example-output inspection,
|
||||||
|
metadata inspection, or human sign-off. Compatibility and release-note content
|
||||||
|
remain ordinary editorial responsibilities. Development validation is useful
|
||||||
|
but does not require a second full run before invoking the publication script.
|
||||||
|
|
||||||
|
The script stops successfully after the tag push. CI completion, CI success,
|
||||||
|
remote read-back, and Go module availability are not release completion gates.
|
||||||
|
Do not wait or poll for them. Provider probes and inference calls are never
|
||||||
|
part of release validation.
|
||||||
|
|
||||||
## Catalog Profile Compatibility
|
## Catalog Profile Compatibility
|
||||||
|
|
||||||
External catalog profile data may be added, removed, renamed, or modified
|
The [release policy](policy/release.md#catalog-profile-compatibility) owns the
|
||||||
without deprecation or advance notice. This exception is limited to profile
|
catalog compatibility boundary. This heading preserves older incoming links.
|
||||||
data imported from the maintained catalog modules. It does not weaken ordinary
|
|
||||||
compatibility for Promptkit's public Go API, configuration and format semantics,
|
|
||||||
runtime behavior, catalog-module APIs, manifest schema, backend definitions, or
|
|
||||||
consumer-owned definitions.
|
|
||||||
|
|
||||||
Within the catalog versions selected and tested by a Promptkit release, and
|
## Failure Recovery
|
||||||
unless a consumer overrides the name or its base, Promptkit keeps the literal
|
|
||||||
profile IDs `promptkit-openrouter-standard` and
|
|
||||||
`promptkit-openrouter-auto` available. The names do not promise a permanent
|
|
||||||
model, backend, routing behavior, settings, cost, output, or upstream
|
|
||||||
availability. The [framework format reference](formats.md#built-in-profile-catalog)
|
|
||||||
owns their current definitions.
|
|
||||||
|
|
||||||
`v0.10.0` is the initial minor release for this compatibility transition.
|
If local checks fail, fix the candidate, commit and push changes, then rerun
|
||||||
Afterward, catalog-only updates and adjustments to the current selections may
|
the publication command. It never automatically removes a tag.
|
||||||
ship in a patch release when all other compatibility obligations remain intact.
|
|
||||||
External profile removals can require consumer action; they are not automatic
|
|
||||||
migrations.
|
|
||||||
|
|
||||||
Catalog adoption and release validation remain local and offline. They do not
|
If a push fails or its result is ambiguous, set `RELEASE_VERSION` to the
|
||||||
probe provider endpoints, request model lists, or make inference calls.
|
attempted version and inspect origin before retrying:
|
||||||
|
|
||||||
## Establish The Candidate
|
|
||||||
|
|
||||||
Choose a version that has not been published and export it as
|
|
||||||
`RELEASE_VERSION`. Run every command in this procedure from the Promptkit
|
|
||||||
repository root in the same POSIX shell. Do not reuse `v0.1.0` or another
|
|
||||||
existing version.
|
|
||||||
|
|
||||||
The following guard derives the release commit from `HEAD` and stops on a
|
|
||||||
missing or malformed version, a checkout other than synchronized `main`,
|
|
||||||
uncommitted changes, an active Go workspace, a module replacement, a vendor
|
|
||||||
tree, or an existing local or remote tag:
|
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
set -eu
|
git ls-remote --tags origin "refs/tags/$RELEASE_VERSION" "refs/tags/$RELEASE_VERSION^{}"
|
||||||
|
git rev-parse "refs/tags/$RELEASE_VERSION" "refs/tags/$RELEASE_VERSION^{}"
|
||||||
: "${RELEASE_VERSION:?export an unpublished vMAJOR.MINOR.PATCH version}"
|
|
||||||
if ! printf '%s\n' "$RELEASE_VERSION" |
|
|
||||||
grep -Eq '^v(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$'
|
|
||||||
then
|
|
||||||
printf '%s\n' "invalid release version: $RELEASE_VERSION" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
RELEASE_COMMIT=$(git rev-parse --verify 'HEAD^{commit}')
|
|
||||||
export RELEASE_COMMIT
|
|
||||||
|
|
||||||
check_release_candidate() {
|
|
||||||
test "$(git branch --show-current)" = main
|
|
||||||
test -z "$(git status --porcelain)"
|
|
||||||
|
|
||||||
gowork_value=$(go env GOWORK)
|
|
||||||
case "$gowork_value" in
|
|
||||||
''|off) ;;
|
|
||||||
*)
|
|
||||||
printf '%s\n' "active Go workspace: $gowork_value" >&2
|
|
||||||
return 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
test -z "$(git ls-files go.work go.work.sum)"
|
|
||||||
test ! -e vendor
|
|
||||||
if grep -Eq '^[[:space:]]*replace([[:space:]]|\()' go.mod
|
|
||||||
then
|
|
||||||
printf '%s\n' 'go.mod contains a replacement' >&2
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
git fetch origin main --tags
|
|
||||||
test "$RELEASE_COMMIT" = \
|
|
||||||
"$(git rev-parse --verify 'refs/remotes/origin/main^{commit}')"
|
|
||||||
|
|
||||||
if git show-ref --verify --quiet "refs/tags/$RELEASE_VERSION"
|
|
||||||
then
|
|
||||||
printf '%s\n' "local tag already exists: $RELEASE_VERSION" >&2
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
if test -n "$(
|
|
||||||
git ls-remote --tags origin \
|
|
||||||
"refs/tags/$RELEASE_VERSION" \
|
|
||||||
"refs/tags/$RELEASE_VERSION^{}"
|
|
||||||
)"
|
|
||||||
then
|
|
||||||
printf '%s\n' "remote tag already exists: $RELEASE_VERSION" >&2
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
check_release_candidate
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Do not continue unless the guard completes successfully. In particular, push
|
Matching remote tag and peeled commit values confirm publication, even if the
|
||||||
the intended commit through the normal `main` branch workflow before release;
|
push command reported an error. If the remote query fails, publication status
|
||||||
the tag procedure is not a substitute for publishing the source commit.
|
is still unknown. Do not delete or recreate the local tag until absence on
|
||||||
|
origin is confirmed. Once confirmed unpublished, an unsuccessful attempt's
|
||||||
|
local tag can be removed and the publication command rerun. Never overwrite
|
||||||
|
a published tag.
|
||||||
|
|
||||||
## Validate The Candidate
|
CI or module-resolution problems may be investigated separately; temporary
|
||||||
|
service, network, or authentication failures do not require another release.
|
||||||
Confirm the module and root package metadata:
|
Only an actual defect requiring changes to published contents warrants a new
|
||||||
|
appropriate version. See the [recovery policy](policy/release.md#immutability-and-failure-recovery).
|
||||||
```sh
|
|
||||||
go list -m -f '{{.Path}} {{.GoVersion}}'
|
|
||||||
go list -f '{{.Name}} {{.ImportPath}}' .
|
|
||||||
```
|
|
||||||
|
|
||||||
The output must be:
|
|
||||||
|
|
||||||
```text
|
|
||||||
gitea.maximumdirect.net/eric/promptkit 1.25.5
|
|
||||||
promptkit gitea.maximumdirect.net/eric/promptkit
|
|
||||||
```
|
|
||||||
|
|
||||||
As a release prerequisite, run the complete
|
|
||||||
[maintainer validation workflow](development.md#maintainer-validation) against
|
|
||||||
the clean candidate. Do not substitute a partial command list: the development
|
|
||||||
guide owns the tests, race checks, analysis, build, both offline examples,
|
|
||||||
formatting, Markdown links, generated-output and credential review, and
|
|
||||||
repository hygiene. Record the successful workflow result with the candidate.
|
|
||||||
|
|
||||||
## Write The Release Note
|
|
||||||
|
|
||||||
Prepare a plain-text annotated-tag message outside the repository and export
|
|
||||||
its path as `RELEASE_NOTES_FILE`. Use this form, replacing each summary with
|
|
||||||
release-specific text; write `None.` when there are no public API changes or
|
|
||||||
consumer actions:
|
|
||||||
|
|
||||||
```text
|
|
||||||
Promptkit vMAJOR.MINOR.PATCH
|
|
||||||
|
|
||||||
Validated commit: full commit ID
|
|
||||||
Compatibility: compatibility summary
|
|
||||||
Public API changes: changes or None.
|
|
||||||
Consumer action: required action or None.
|
|
||||||
```
|
|
||||||
|
|
||||||
After writing it, require all release-note fields, the selected version, and
|
|
||||||
the validated commit to be present:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
: "${RELEASE_NOTES_FILE:?export the path to the release-note file}"
|
|
||||||
test -f "$RELEASE_NOTES_FILE"
|
|
||||||
test -s "$RELEASE_NOTES_FILE"
|
|
||||||
grep -F "Promptkit $RELEASE_VERSION" "$RELEASE_NOTES_FILE"
|
|
||||||
grep -F "Validated commit: $RELEASE_COMMIT" "$RELEASE_NOTES_FILE"
|
|
||||||
grep -F 'Compatibility:' "$RELEASE_NOTES_FILE"
|
|
||||||
grep -F 'Public API changes:' "$RELEASE_NOTES_FILE"
|
|
||||||
grep -F 'Consumer action:' "$RELEASE_NOTES_FILE"
|
|
||||||
```
|
|
||||||
|
|
||||||
Inspect the complete message and confirm that it accurately records the
|
|
||||||
compatibility impact, public API changes, and required consumer action.
|
|
||||||
|
|
||||||
When a release introduces or updates the maintained external catalogs, state
|
|
||||||
the two independently versioned selected data dependencies and any resulting
|
|
||||||
consumer action. State that external profile additions, removals, renames, and
|
|
||||||
selection changes are covered by the catalog-profile policy, while the ordinary
|
|
||||||
public API and configuration contracts remain in force. Link to the current
|
|
||||||
format and consumer documentation rather than duplicating catalog inventories
|
|
||||||
or contracts in the release note.
|
|
||||||
|
|
||||||
## Create And Inspect The Tag
|
|
||||||
|
|
||||||
Run the candidate guard again immediately before tag creation. This ensures
|
|
||||||
that validation or release-note preparation did not change the checkout and
|
|
||||||
that the commit is still published and untagged:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
check_release_candidate
|
|
||||||
```
|
|
||||||
|
|
||||||
Create the annotated tag from the prepared release note and bind it explicitly
|
|
||||||
to the validated commit:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
git tag --annotate "$RELEASE_VERSION" \
|
|
||||||
--file "$RELEASE_NOTES_FILE" \
|
|
||||||
"$RELEASE_COMMIT"
|
|
||||||
```
|
|
||||||
|
|
||||||
Inspect both the tag message and its source commit before publication:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
test "$(git cat-file -t "refs/tags/$RELEASE_VERSION")" = tag
|
|
||||||
git show --no-patch --decorate "refs/tags/$RELEASE_VERSION"
|
|
||||||
test "$(
|
|
||||||
git rev-parse --verify "refs/tags/$RELEASE_VERSION^{commit}"
|
|
||||||
)" = "$RELEASE_COMMIT"
|
|
||||||
```
|
|
||||||
|
|
||||||
If inspection finds an error, delete the unpublished local tag, correct the
|
|
||||||
release note or candidate, and repeat the guards. Never move or recreate a tag
|
|
||||||
that has been published.
|
|
||||||
|
|
||||||
## Publish The Selected Tag
|
|
||||||
|
|
||||||
Push only the selected tag ref. Do not use `git push --tags`:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
git push origin \
|
|
||||||
"refs/tags/$RELEASE_VERSION:refs/tags/$RELEASE_VERSION"
|
|
||||||
```
|
|
||||||
|
|
||||||
## Verify Publication
|
|
||||||
|
|
||||||
Compare the remote annotated-tag object with the local object, then compare the
|
|
||||||
remote peeled source commit with the validated commit:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
remote_tag=$(
|
|
||||||
git ls-remote --tags origin "refs/tags/$RELEASE_VERSION" |
|
|
||||||
awk 'NR == 1 { print $1 }'
|
|
||||||
)
|
|
||||||
remote_commit=$(
|
|
||||||
git ls-remote --tags origin "refs/tags/$RELEASE_VERSION^{}" |
|
|
||||||
awk 'NR == 1 { print $1 }'
|
|
||||||
)
|
|
||||||
test -n "$remote_tag"
|
|
||||||
test "$remote_tag" = \
|
|
||||||
"$(git rev-parse --verify "refs/tags/$RELEASE_VERSION")"
|
|
||||||
test "$remote_commit" = "$RELEASE_COMMIT"
|
|
||||||
```
|
|
||||||
|
|
||||||
Finally, resolve the version as an ordinary Go module in a temporary module
|
|
||||||
outside this repository and without a workspace or replacement:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
resolution_dir=$(mktemp -d)
|
|
||||||
(
|
|
||||||
trap 'rm -rf "$resolution_dir"' 0 1 2 15
|
|
||||||
cd "$resolution_dir"
|
|
||||||
GOWORK=off go mod init example.com/promptkit-release-check
|
|
||||||
GOWORK=off go mod download \
|
|
||||||
"gitea.maximumdirect.net/eric/promptkit@$RELEASE_VERSION"
|
|
||||||
resolved_version=$(
|
|
||||||
GOWORK=off go list -m -f '{{.Version}}' \
|
|
||||||
"gitea.maximumdirect.net/eric/promptkit@$RELEASE_VERSION"
|
|
||||||
)
|
|
||||||
test "$resolved_version" = "$RELEASE_VERSION"
|
|
||||||
)
|
|
||||||
```
|
|
||||||
|
|
||||||
Promptkit must publish and verify the required version before Scriptorium or
|
|
||||||
another consumer publishes a release that depends on it. This ordering does
|
|
||||||
not replace the consumer project's own release procedure. Released consumers
|
|
||||||
must select the published Promptkit tag through ordinary module resolution,
|
|
||||||
without a workspace, replacement, vendored Promptkit source, or unpublished
|
|
||||||
revision.
|
|
||||||
|
|
||||||
## Policy Changes
|
## Policy Changes
|
||||||
|
|
||||||
Document and approve a durable policy change before introducing hosted
|
Update the policy and this procedure together when changing release governance.
|
||||||
automation, binary artifacts, or different release governance. Update this
|
Consumers own their dependency-availability and release checks; their readiness
|
||||||
procedure in the same change so maintainers do not rely on hidden release
|
does not delay completion of a Promptkit release.
|
||||||
requirements.
|
|
||||||
|
|||||||
145
scripts/release-check.sh
Executable file
145
scripts/release-check.sh
Executable file
@@ -0,0 +1,145 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Run local checks without publishing or changing files.
|
||||||
|
set -eu
|
||||||
|
cd "$(dirname "$0")/.."
|
||||||
|
|
||||||
|
go test -race -vet=off ./...
|
||||||
|
go vet ./...
|
||||||
|
python3 - <<'PY'
|
||||||
|
import json
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
def example(name):
|
||||||
|
return json.loads(subprocess.check_output(
|
||||||
|
["go", "run", "./examples/go-library/" + name], text=True))
|
||||||
|
|
||||||
|
prepared = example("prepare")
|
||||||
|
assert prepared["prompt_id"] == "example.prepare", prepared
|
||||||
|
assert prepared["selected_profile"] == "offline-example", prepared
|
||||||
|
assert prepared["model"] == "offline-model", prepared
|
||||||
|
assert prepared["message_count"] > 0, prepared
|
||||||
|
result = example("run")
|
||||||
|
assert result["output"] == "Ada finished the migration review.", result
|
||||||
|
assert result["is_valid"] is True, result
|
||||||
|
assert result["validation_status"] == "passed", result
|
||||||
|
assert result["model"] == "offline-model", result
|
||||||
|
assert result["total_tokens"] == 18, result
|
||||||
|
PY
|
||||||
|
|
||||||
|
unformatted=$(
|
||||||
|
git ls-files '*.go' |
|
||||||
|
while IFS= read -r go_file
|
||||||
|
do
|
||||||
|
gofmt -l "$go_file"
|
||||||
|
done
|
||||||
|
)
|
||||||
|
test -z "$unformatted"
|
||||||
|
|
||||||
|
python3 - <<'PY'
|
||||||
|
from pathlib import Path
|
||||||
|
import re
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
from urllib.parse import unquote
|
||||||
|
|
||||||
|
root = Path.cwd().resolve()
|
||||||
|
markdown_files = [
|
||||||
|
root / name
|
||||||
|
for name in subprocess.check_output(
|
||||||
|
["git", "ls-files", "*.md"], text=True
|
||||||
|
).splitlines()
|
||||||
|
]
|
||||||
|
link_pattern = re.compile(r"!?\[[^]]*\]\(([^)]+)\)")
|
||||||
|
heading_pattern = re.compile(r"^#{1,6}\s+(.+?)\s*#*\s*$")
|
||||||
|
scheme_pattern = re.compile(r"^[a-z][a-z0-9+.-]*:", re.IGNORECASE)
|
||||||
|
|
||||||
|
|
||||||
|
def markdown_lines(path):
|
||||||
|
in_fence = False
|
||||||
|
fence = ""
|
||||||
|
for line in path.read_text(encoding="utf-8").splitlines():
|
||||||
|
stripped = line.lstrip()
|
||||||
|
marker = stripped[:3]
|
||||||
|
if marker in {"```", "~~~"}:
|
||||||
|
if not in_fence:
|
||||||
|
in_fence = True
|
||||||
|
fence = marker
|
||||||
|
elif marker == fence:
|
||||||
|
in_fence = False
|
||||||
|
fence = ""
|
||||||
|
continue
|
||||||
|
if not in_fence:
|
||||||
|
yield line
|
||||||
|
|
||||||
|
|
||||||
|
anchor_cache = {}
|
||||||
|
|
||||||
|
|
||||||
|
def anchors(path):
|
||||||
|
if path in anchor_cache:
|
||||||
|
return anchor_cache[path]
|
||||||
|
found = set()
|
||||||
|
counts = {}
|
||||||
|
for line in markdown_lines(path):
|
||||||
|
match = heading_pattern.match(line)
|
||||||
|
if not match:
|
||||||
|
continue
|
||||||
|
heading = re.sub(r"<[^>]+>", "", match.group(1)).replace("`", "")
|
||||||
|
base = re.sub(r"[^\w\- ]", "", heading.lower()).replace(" ", "-")
|
||||||
|
count = counts.get(base, 0)
|
||||||
|
counts[base] = count + 1
|
||||||
|
found.add(base if count == 0 else f"{base}-{count}")
|
||||||
|
anchor_cache[path] = found
|
||||||
|
return found
|
||||||
|
|
||||||
|
|
||||||
|
failures = []
|
||||||
|
for source in markdown_files:
|
||||||
|
text = "\n".join(markdown_lines(source))
|
||||||
|
for match in link_pattern.finditer(text):
|
||||||
|
target = match.group(1).strip()
|
||||||
|
if target.startswith("<") and target.endswith(">"):
|
||||||
|
target = target[1:-1]
|
||||||
|
if scheme_pattern.match(target) or target.startswith("//"):
|
||||||
|
continue
|
||||||
|
path_text, separator, fragment = target.partition("#")
|
||||||
|
destination = source if not path_text else source.parent / unquote(path_text)
|
||||||
|
try:
|
||||||
|
destination = destination.resolve()
|
||||||
|
destination.relative_to(root)
|
||||||
|
except ValueError:
|
||||||
|
failures.append(f"{source.relative_to(root)}: escapes repository: {target}")
|
||||||
|
continue
|
||||||
|
if not destination.exists():
|
||||||
|
failures.append(f"{source.relative_to(root)}: missing target: {target}")
|
||||||
|
continue
|
||||||
|
if separator and destination.suffix.lower() == ".md":
|
||||||
|
fragment = unquote(fragment).lower()
|
||||||
|
if fragment not in anchors(destination):
|
||||||
|
failures.append(f"{source.relative_to(root)}: missing anchor: {target}")
|
||||||
|
|
||||||
|
if failures:
|
||||||
|
print("\n".join(failures), file=sys.stderr)
|
||||||
|
raise SystemExit(1)
|
||||||
|
PY
|
||||||
|
|
||||||
|
case "$(go env GOWORK)" in
|
||||||
|
''|off) ;;
|
||||||
|
*) printf '%s\n' 'an active Go workspace is not allowed' >&2; exit 1 ;;
|
||||||
|
esac
|
||||||
|
test -z "$(git ls-files go.work go.work.sum)"
|
||||||
|
test ! -e vendor
|
||||||
|
if grep -Eq '^[[:space:]]*replace([[:space:]]|\()' go.mod
|
||||||
|
then
|
||||||
|
printf '%s\n' 'go.mod contains a replacement' >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
git diff --check
|
||||||
|
git diff --cached --check
|
||||||
|
credential_pattern='-----BEGIN ([A-Z0-9]+ )?PRIV''ATE KEY-----|AKI''A[0-9A-Z]{16}|gh[pousr]_[A-Za-z0-9]{36,}|sk-[A-Za-z0-9]{32,}'
|
||||||
|
if git grep -nEI -e "$credential_pattern" -- .
|
||||||
|
then
|
||||||
|
printf '%s\n' 'possible credential found' >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
57
scripts/release.sh
Executable file
57
scripts/release.sh
Executable file
@@ -0,0 +1,57 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Validate one committed candidate and publish only its selected annotated tag.
|
||||||
|
set -eu
|
||||||
|
cd "$(dirname "$0")/.."
|
||||||
|
|
||||||
|
release_version=${1:?usage: scripts/release.sh vMAJOR.MINOR.PATCH}
|
||||||
|
printf '%s\n' "$release_version" |
|
||||||
|
grep -Eq '^v(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$'
|
||||||
|
release_commit=$(git rev-parse --verify 'HEAD^{commit}')
|
||||||
|
|
||||||
|
check_candidate() {
|
||||||
|
test "$(git branch --show-current)" = main
|
||||||
|
test -z "$(git status --porcelain)"
|
||||||
|
test "$(git rev-parse HEAD)" = "$release_commit"
|
||||||
|
git fetch origin main
|
||||||
|
test "$(git rev-parse refs/remotes/origin/main)" = "$release_commit"
|
||||||
|
if git show-ref --verify --quiet "refs/tags/$release_version"; then
|
||||||
|
printf '%s\n' "local tag already exists: $release_version" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
remote_refs=$(git ls-remote --tags origin "refs/tags/$release_version" "refs/tags/$release_version^{}")
|
||||||
|
test -z "$remote_refs"
|
||||||
|
}
|
||||||
|
|
||||||
|
check_candidate
|
||||||
|
python3 - "$release_version" <<'PY'
|
||||||
|
from pathlib import Path
|
||||||
|
import sys
|
||||||
|
|
||||||
|
version = sys.argv[1]
|
||||||
|
note = Path("docs/releases") / (version + ".md")
|
||||||
|
lines = note.read_text(encoding="utf-8").splitlines()
|
||||||
|
assert lines and lines[0] == "# Promptkit " + version, f"wrong release title: {note}"
|
||||||
|
headings = set()
|
||||||
|
fence = None
|
||||||
|
for line in lines:
|
||||||
|
marker = line.lstrip()[:3]
|
||||||
|
if marker in {"```", "~~~"}:
|
||||||
|
if fence is None:
|
||||||
|
fence = marker
|
||||||
|
elif fence == marker:
|
||||||
|
fence = None
|
||||||
|
elif fence is None:
|
||||||
|
headings.add(line)
|
||||||
|
for section in ("Summary", "Compatibility", "Upgrade", "Changes"):
|
||||||
|
assert "## " + section in headings, f"missing {section}: {note}"
|
||||||
|
PY
|
||||||
|
|
||||||
|
./scripts/release-check.sh
|
||||||
|
check_candidate
|
||||||
|
release_note=$(git show "$release_commit:docs/releases/$release_version.md")
|
||||||
|
printf '%s\n\nValidated commit: %s\n' "$release_note" "$release_commit" |
|
||||||
|
git tag --annotate --cleanup=verbatim "$release_version" --file - "$release_commit"
|
||||||
|
test "$(git cat-file -t "refs/tags/$release_version")" = tag
|
||||||
|
test "$(git rev-parse "refs/tags/$release_version^{commit}")" = "$release_commit"
|
||||||
|
git push origin "refs/tags/$release_version:refs/tags/$release_version"
|
||||||
|
printf '%s\n' "Released $release_version. No CI or module-availability wait is required."
|
||||||
Reference in New Issue
Block a user