Adopt updated policies and simplify release publication
This commit is contained in:
@@ -7,12 +7,13 @@ framework implementation work belongs in Promptkit.
|
||||
|
||||
## Initial Orientation
|
||||
|
||||
Before starting work:
|
||||
Before recommending, planning, or implementing work:
|
||||
|
||||
1. inspect the working tree and preserve unrelated changes;
|
||||
2. read the [architecture policy](policy/architecture.md);
|
||||
3. follow the task-specific contracts and internal documents below; and
|
||||
4. inspect the relevant implementation and tests before changing them.
|
||||
1. read the [agent policy](policy/agents.md);
|
||||
2. inspect the working tree and preserve unrelated changes;
|
||||
3. read the [architecture policy](policy/architecture.md);
|
||||
4. follow the task-specific contracts and internal documents below; and
|
||||
5. inspect the relevant implementation and tests before changing them.
|
||||
|
||||
Also read the [documentation policy](policy/documentation.md) before changing
|
||||
documentation and the [testing policy](policy/testing.md) before changing
|
||||
@@ -31,7 +32,7 @@ tests.
|
||||
| OpenAI-compatible outbound behavior or timeout layering | [Promptkit integration contract](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.9.0/docs/integrations/openai-compatible-chat.md) |
|
||||
| Subprocess behavior | [Subprocess integration](integrations/subprocess.md) and [CLI contract](cli.md) |
|
||||
| Runtime operation or recovery | [Operations](operations.md) |
|
||||
| Release packaging or publication | The [release procedure](release.md), [hosted release workflow](../.woodpecker/release.yml), and [architecture policy](policy/architecture.md) |
|
||||
| Release packaging or publication | The [release policy](policy/release.md), [release procedure](release.md), [hosted release workflow](../.woodpecker/release.yml), and [architecture policy](policy/architecture.md) |
|
||||
| Examples or copyable assets | The owning Scriptorium contract, the relevant [Promptkit format contract](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.9.0/docs/formats.md), and the related files under `examples/` |
|
||||
| Architecture decisions or future work | The [documentation policy](policy/documentation.md), relevant accepted ADRs, and relevant roadmap documents |
|
||||
|
||||
|
||||
77
docs/policy/agents.md
Normal file
77
docs/policy/agents.md
Normal file
@@ -0,0 +1,77 @@
|
||||
# Agent Policy
|
||||
|
||||
**Base Policy Version:** 1.1
|
||||
|
||||
**Last Updated:** 2026-09-26
|
||||
|
||||
## Purpose
|
||||
|
||||
Agents working in this repository must read and adhere to the following house rules.
|
||||
|
||||
## Implementation Discipline
|
||||
|
||||
**KEY PRINCIPLES:** Write the simplest idiomatic code that satisfies the user's
|
||||
request. Do not implicitly strengthen requirements, restrictions, or guarantees
|
||||
beyond what the user actually requested.
|
||||
|
||||
**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.
|
||||
|
||||
**Do not invent guarantees.** Do not strengthen public contracts, guarantees,
|
||||
or invariants beyond those expressly requested by the user.
|
||||
|
||||
**Use the standard library.** For example: in almost every case, the best
|
||||
approach to copying files is to use the standard library. Writing custom code to
|
||||
implement power-loss protection at the application level, or to guard against
|
||||
bad actors with privileged and concurrent access to the host's filesystem,
|
||||
is wasteful, unnecessary, and not idiomatic. Stick to the simple, standard, and
|
||||
idiomatic approach unless another path is expressly requested by the user.
|
||||
|
||||
**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.
|
||||
|
||||
## 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,7 +1,21 @@
|
||||
# Architecture
|
||||
# Architecture Policy
|
||||
|
||||
This document defines Scriptorium's current application architecture and
|
||||
durable development boundaries.
|
||||
**Base Policy Version:** 1.1
|
||||
|
||||
**Last Updated:** 2026-09-26
|
||||
|
||||
## Purpose And Ownership
|
||||
|
||||
This policy defines Scriptorium's purpose, responsibility and dependency
|
||||
boundaries, established invariants, and non-goals. Concrete component inventory
|
||||
and implementation mechanics belong in [internal documentation](../internal/overview.md);
|
||||
public behavior belongs in its canonical contracts.
|
||||
|
||||
Adopted constraints govern future development without implying that every
|
||||
capability they could govern exists or is planned. Keep proposed structure and
|
||||
implementation status in roadmaps, and decision rationale in ADRs. Acceptance
|
||||
of a decision is not proof of implementation. Do not turn incidental choices
|
||||
into architectural invariants.
|
||||
|
||||
## System Shape
|
||||
|
||||
@@ -21,6 +35,16 @@ deployment policy.
|
||||
The concrete package inventory is maintained in the
|
||||
[internal overview](../internal/overview.md).
|
||||
|
||||
As established by [ADR 0004](../adr/0004-definition-boundary.md), Scriptorium
|
||||
aims to support the complete set of features in valid Promptkit prompt and
|
||||
profile definitions for its selected upstream version. Promptkit remains the
|
||||
canonical parser and validator. Library-only features are considered
|
||||
individually against the simple predefined-prompt execution model.
|
||||
|
||||
Maintain adapter boundaries with proportionate, idiomatic code. This approach
|
||||
does not require an interface for every type, additional wrappers, or a fixed
|
||||
directory tree for integrations that do not exist.
|
||||
|
||||
## Dependency Direction
|
||||
|
||||
```text
|
||||
@@ -46,6 +70,10 @@ gitea.maximumdirect.net/eric/promptkit
|
||||
The repository architecture guard enforces these import and removal
|
||||
invariants.
|
||||
|
||||
Cross-project changes land and release in Promptkit before Scriptorium adopts
|
||||
the tagged dependency. Do not commit Go workspaces, local replacements,
|
||||
vendored Promptkit implementation, or unpublished dependency assumptions.
|
||||
|
||||
## Retained Boundaries
|
||||
|
||||
- `internal/adapter/cli` owns commands, flags, configuration precedence,
|
||||
@@ -71,6 +99,13 @@ That reader denies file references without an artifact root, enforces the
|
||||
configured byte limit, and applies Scriptorium's lexical root-containment rule.
|
||||
The operating system still follows symlinks after the lexical check.
|
||||
|
||||
This boundary handles untrusted request references under the documented
|
||||
deployment model; it is not a filesystem sandbox. Defending against a
|
||||
privileged actor concurrently modifying the host filesystem is outside the
|
||||
adopted scope, not a claim that such activity cannot occur. Do not infer
|
||||
additional defenses or guarantees from hypothetical threats; raise unsettled
|
||||
scope decisions under the [agent policy](agents.md).
|
||||
|
||||
The [HTTP API](../api.md) owns observable request outcomes, and
|
||||
[operations](../operations.md) owns deployment permissions and root selection.
|
||||
|
||||
@@ -80,6 +115,14 @@ Scriptorium has no durable run-state store, checkpoint, cache, or resume
|
||||
mechanism. Recovery is a new request after correcting inputs, configuration, or
|
||||
environment.
|
||||
|
||||
Each request is self-contained from the caller's perspective, without
|
||||
conversation or workflow state retained from completed requests. This does
|
||||
not mean the process is internally stateless. Shared engines, backend capacity
|
||||
and queue accounting, in-flight coordination, cancellation, and server
|
||||
lifecycle resources are permitted and must be shared where necessary to
|
||||
enforce configured backend limits across concurrent requests. Such state must
|
||||
be concurrency-safe and does not create a durable user-workflow contract.
|
||||
|
||||
Adapters map Promptkit public error identities into CLI exits or HTTP statuses
|
||||
without classifying by message text. Raw API keys are not accepted in
|
||||
Scriptorium configuration, CLI arguments, or HTTP payloads, and resolved
|
||||
@@ -102,5 +145,7 @@ secrets must not be emitted.
|
||||
into Scriptorium.
|
||||
- Do not move CLI, inbound HTTP, process, or deployment policy into Promptkit.
|
||||
- Do not add durable workflow, archive, or resume behavior.
|
||||
- Do not add application-managed prompt modification, follow-up message flows,
|
||||
conversation management, or multi-step workflow orchestration.
|
||||
|
||||
Work that is not implemented belongs in `docs/roadmap/`.
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
# Documentation Policy
|
||||
|
||||
**Base Policy Version:** 1.3
|
||||
|
||||
**Last Updated:** 2026-09-26
|
||||
|
||||
## Purpose
|
||||
|
||||
This policy assigns each documentation topic to one canonical owner. Its goal is
|
||||
@@ -30,10 +34,14 @@ semantics.
|
||||
Outside `docs/roadmap/`, documentation describes implemented behavior only.
|
||||
Partial features may be described only to their implemented boundary.
|
||||
|
||||
ADRs are the narrow exception: an ADR may record an accepted architectural
|
||||
decision before implementation, but acceptance must not be presented as proof
|
||||
that the behavior exists. The roadmap owns implementation status and sequencing
|
||||
until the decision is implemented. Current architecture, user, operator,
|
||||
Architectural constraints may govern future changes without implying that the
|
||||
components or capabilities they would govern already exist. This does not
|
||||
permit describing a proposed system structure as implemented.
|
||||
|
||||
ADRs may record an accepted architectural decision before implementation, but
|
||||
acceptance must not be presented as proof that the behavior exists. The roadmap
|
||||
owns implementation status and sequencing until the decision is implemented.
|
||||
Current architecture, user, operator,
|
||||
integration, and internal documentation are updated when the behavior lands.
|
||||
|
||||
### Audience And Detail
|
||||
@@ -65,13 +73,15 @@ secret values.
|
||||
| --- | --- | --- | --- |
|
||||
| Product orientation and minimal end-to-end quickstart | `README.md` | What this project is, why it is useful, one shortest successful invocation, and links onward. | Complete command reference, configuration reference, operational procedures, implementation detail. |
|
||||
| Contributor entry point | `docs/development.md` | Task-oriented reading guide, minimal contributor orientation, baseline validation commands, and links to canonical docs. | Package inventory, architecture rules, subsystem behavior, and detailed change recipes, which belong in the relevant internal component document. |
|
||||
| Current application architecture | `docs/policy/architecture.md` | System shape, normative ownership, dependency direction, architectural boundaries, invariants, safety properties, and non-goals. | Concrete package inventory, implementation mechanics, contributor procedures, decision history, future work. |
|
||||
| Application architecture policy | `docs/policy/architecture.md` | System shape, normative ownership, dependency direction, architectural boundaries, invariants, safety properties, and non-goals. | Concrete package inventory, implementation mechanics, contributor procedures, decision history, future work. |
|
||||
| Agent policy | `docs/policy/agents.md` | Agent implementation discipline, proportionality, idiomatic simplicity, local commit rules, and rules against inventing requirements, restrictions, guarantees, or repository policy. | Application contracts, architecture, testing policy, and contributor procedures. |
|
||||
| Documentation organization | `docs/policy/documentation.md` | Documentation ownership, audience boundaries, maintenance rules, and ADR/document lifecycle. | Application architecture or product behavior. |
|
||||
| Testing policy | `docs/policy/testing.md` | Test philosophy, risk-based sufficiency, test boundaries, doubles, coverage guidance, regression-test policy, and criteria for adding, rewriting, or deleting tests. | Subsystem behavior, application contracts, subsystem-specific test inventories, and implementation plans. |
|
||||
| CLI contract | `docs/cli.md` | Commands, arguments, flags, invocation semantics, and exit codes. | End-to-end operating procedures, configuration field definitions, runtime filesystem layout, module implementation details. |
|
||||
| Configuration contract | `docs/config.md` | Application discovery and precedence, source locations, server fields, render default, HTTP limits, and credential mapping. | Promptkit framework formats and defaults, complete example files, CLI syntax, runtime lifecycle, and implementation detail. |
|
||||
| Operations | `docs/operations.md` | Runtime workflows, physical filesystem and state layout, output, cache, and debug handling, resume, cleanup, permissions, recovery, and operational limits. | CLI flag syntax, configuration field definitions, logical output schemas, implementation mechanics. |
|
||||
| Release procedure | `docs/release.md` | Candidate validation, version and tag operations, hosted-workflow observation, and published-artifact verification. | Runtime operations, version-specific announcements, and complete application-interface contracts. |
|
||||
| Release policy | `docs/policy/release.md` | Versioning and compatibility, release integrity and immutability, documentation requirements, proportionate gates, publication controls, source completion, and optional verification boundaries. | Repository-specific commands, installation guidance, historical summaries, and CI implementation details. |
|
||||
| Release procedure | `docs/release.md` | Maintainer prerequisites, candidate preparation, publication command and guards, asynchronous delivery, optional diagnostics, and failure recovery. | General release requirements, runtime operations, historical announcements, and current application contracts. |
|
||||
| Version-specific release notes | `docs/releases/` | Immutable release summaries, compatibility notices, and migration announcements for one published version. | Complete CLI, HTTP, configuration, operations, or dependency contracts. |
|
||||
| Public HTTP contract | `docs/api.md` | Routes, authentication, media types, request and response schemas, status codes, pagination, caching, idempotency, rate limits, and HTTP retry semantics. | Client walkthroughs, upstream or downstream integration internals, implementation detail. |
|
||||
| Consumer guidance | `docs/consumers/` | Choosing between Scriptorium's executable interfaces and understanding consumer responsibilities. | HTTP wire semantics, CLI syntax, Promptkit's Go package, and internal implementation detail. |
|
||||
@@ -103,6 +113,15 @@ runtime state and how to operate or recover the application. When a workflow
|
||||
crosses these topics, choose the document that owns the task and link to the
|
||||
other contracts.
|
||||
|
||||
### Releases
|
||||
|
||||
The release policy owns release requirements; the release procedure supplies
|
||||
the commands that satisfy them. Release notes are historical summaries, not
|
||||
current-state contract owners. The checked-in note at an immutable tag records
|
||||
that release; current documentation changes with the behavior it describes.
|
||||
Neither a procedure nor a note may weaken policy or defer required updates to
|
||||
canonical contracts.
|
||||
|
||||
### Contracts And Implementation
|
||||
|
||||
Integration and API documents define externally observable shapes and
|
||||
@@ -150,6 +169,11 @@ ADR; rejected product ideas belong in the roadmap.
|
||||
|
||||
## Maintenance
|
||||
|
||||
Every policy document records its underlying template version and local
|
||||
last-updated date immediately below the title. Update the date when revising
|
||||
local policy; change the base version only when adopting a newer template.
|
||||
Do not retain template adoption instructions in the local policy.
|
||||
|
||||
When behavior changes, update its canonical owner in the same change. If
|
||||
ownership moves, remove the old definition and replace it with a link where
|
||||
navigation remains useful.
|
||||
|
||||
207
docs/policy/release.md
Normal file
207
docs/policy/release.md
Normal file
@@ -0,0 +1,207 @@
|
||||
# Release Policy
|
||||
|
||||
**Base Policy Version:** 1.1
|
||||
|
||||
**Last Updated:** 2026-09-26
|
||||
|
||||
## Purpose
|
||||
|
||||
This policy defines a proportionate workflow for validating and publishing an
|
||||
intended source revision under a fresh version. Releases should require little
|
||||
routine intervention, avoid repeated work, and preserve published contents.
|
||||
|
||||
The repository-specific commands belong in `docs/release.md`. Historical release
|
||||
summaries belong in `docs/releases/`. The procedure must agree with the adopted
|
||||
policy and link to it rather than introduce additional release requirements.
|
||||
|
||||
## Release Model And Completion
|
||||
|
||||
A source release identifies one exact committed source revision through an
|
||||
immutable version tag and a version-matched, checked-in release note. The
|
||||
primary release branch is `main`; the authoritative publication remote is
|
||||
`origin`.
|
||||
|
||||
A successful push of the intended tag, with its source commit available on the
|
||||
authoritative primary branch, completes the release. Publish `main` before
|
||||
invoking the publication command; the command requires
|
||||
that the remote branch exactly identifies the validated candidate and pushes
|
||||
only the selected annotated tag.
|
||||
|
||||
Release commands must finish at successful publication. They must not wait for
|
||||
or poll CI, require successful CI status, inspect downloadable artifacts, or
|
||||
check consumer installation or Go module availability as completion gates.
|
||||
A failed or ambiguous push requires resolving the authoritative remote state
|
||||
before declaring success or retrying; successful pushes do not require a
|
||||
separate remote read-back gate.
|
||||
|
||||
Scriptorium publishes Linux binaries and checksums asynchronously from the
|
||||
tagged source. The procedure must identify those deliverables and the
|
||||
responsibility of their automation. Published deliverables must be traceable
|
||||
to that source and identify the same version.
|
||||
|
||||
Artifact delivery is a separate status. A successful tag push is not evidence
|
||||
that artifacts are available. Delivery failures do not reverse source-release
|
||||
success, and optional investigation must not delay release completion.
|
||||
|
||||
## Versioning And Compatibility
|
||||
|
||||
Stable releases use Semantic Versioning in the form `vMAJOR.MINOR.PATCH`, with
|
||||
no leading zeroes. Prereleases are not part of the adopted release channel.
|
||||
|
||||
The selected version must be unused locally and on the authoritative remote.
|
||||
Do not require queries to every configured remote or publication service.
|
||||
A version known to have already been published must not be reused, even if the
|
||||
normal guards do not inspect that channel. Adding a distribution channel
|
||||
requires a deliberate update to the policy and procedure where needed.
|
||||
|
||||
For releases at or after `v1.0.0`:
|
||||
|
||||
- a major release may make intentional incompatible changes;
|
||||
- a minor release may add backward-compatible behavior; and
|
||||
- a patch release may make backward-compatible fixes.
|
||||
|
||||
Before `v1.0.0`, a minor release may change a documented public, operational,
|
||||
configuration, data, integration, or compatibility contract when the release
|
||||
note explains the impact and required consumer action. A patch release must
|
||||
not intentionally break those contracts within its minor line.
|
||||
|
||||
Additional compatibility promises and deliberate exceptions belong in the
|
||||
adopted policy or canonical contract documentation. Release notes explain
|
||||
changes; they do not redefine current compatibility contracts.
|
||||
|
||||
## Release Documentation And Preparation
|
||||
|
||||
Every new release must include `docs/releases/<version>.md` in the tagged
|
||||
source tree. Use the complete version tag as the filename and begin with a
|
||||
title containing the product name and that exact version.
|
||||
|
||||
Include a short summary and any relevant compatibility impact or upgrade
|
||||
instructions. Keep the note proportionate to the change. Fixed sections and
|
||||
explicit no-action boilerplate are not required. Existing historical notes
|
||||
need not be rewritten to adopt this format.
|
||||
|
||||
Keep exact current contracts in their canonical documents and update affected
|
||||
documentation with the behavior change. Link to those documents from the note
|
||||
where useful. A release note must not substitute for current documentation.
|
||||
Use annotated tags with their message derived from the checked-in note rather
|
||||
than requiring a separately authored account of the same release.
|
||||
|
||||
Version selection, release-note content, and retirement of completed roadmaps
|
||||
are preparation responsibilities, not separate human approval gates. Preserve
|
||||
planned and deferred work and repair affected links when retiring roadmaps.
|
||||
Ordinary change review covers unintended files, credentials, and private data;
|
||||
do not repeat it as a release-specific sign-off. Ignored local files are not
|
||||
prohibited merely because they exist: they are not included in the tagged source.
|
||||
|
||||
## Candidate Validation
|
||||
|
||||
Provide one publication command that validates the final committed candidate,
|
||||
checks publication state, and publishes the intended refs. A validation-only
|
||||
mode or command may be provided for diagnosis, but must not be a required step
|
||||
before publication repeats the same checks.
|
||||
|
||||
Run the complete deterministic, offline default test suite once for the final
|
||||
candidate, following the [testing policy](testing.md), and verify the required
|
||||
build targets. Select those targets for the application's actual support
|
||||
commitments; native testing on each platform and access to particular hardware
|
||||
are not default release prerequisites.
|
||||
|
||||
The selected test invocation includes the race detector because the HTTP
|
||||
service shares engines and backend capacity state across concurrent requests.
|
||||
This single invocation covers both ordinary assertions and race detection.
|
||||
Build both declared Linux architectures with the hosted release flags to catch
|
||||
cross-compilation and packaging failures; native test hardware for each target
|
||||
is not required. Existing architecture tests enforce dependency boundaries.
|
||||
|
||||
Retain narrow source guards against committed workspaces, vendor trees, and
|
||||
module replacements: these can otherwise make a passing local build depend on
|
||||
unpublished or substituted framework code. Disable workspace discovery and
|
||||
vendor mode during validation. These guards preserve the established
|
||||
cross-project boundary; they do not require exact dependency-version audits or
|
||||
module-metadata rewrites at release time.
|
||||
|
||||
Additional gates must address a concrete risk that the existing checks do not
|
||||
adequately cover. Do not automatically require linting, race testing, module
|
||||
hygiene audits, documentation audits, credential scans, example validation, or
|
||||
expanded platform matrices solely because they are possible. Retain such
|
||||
checks when their distinct protection justifies their cost. A one-time migration
|
||||
check must not silently become a permanent release requirement.
|
||||
|
||||
Release tests must not require real credentials, mutable application services,
|
||||
paid APIs, provider probes, or inference calls. The procedure describes
|
||||
dependency preparation separately from offline validation.
|
||||
|
||||
Avoid duplicate validation across release phases. Successful checks for the
|
||||
same final candidate need not be repeated solely to satisfy another phase;
|
||||
any reuse must clearly apply to that exact candidate. Persistent validation
|
||||
caches are not required. If the candidate changes, validate the new candidate.
|
||||
Cheap publication-state checks may be repeated immediately before pushing
|
||||
because local or remote state may have changed during validation.
|
||||
|
||||
Automate mechanical guards. Human review gates are strongly disfavored: add one
|
||||
only through an explicit project-specific policy decision explaining the
|
||||
concrete risk and why ordinary change review or automation is insufficient.
|
||||
Do not add routine confirmations for checks the command can perform itself.
|
||||
|
||||
## Publication Guards
|
||||
|
||||
Automate the checks needed to publish the intended source under a fresh version:
|
||||
|
||||
- the version has the adopted format and is unused locally and on the
|
||||
authoritative remote;
|
||||
- the worktree and index are clean on the primary release branch;
|
||||
- the source being published is the exact candidate that passed validation,
|
||||
including its matching release note;
|
||||
- the remote primary branch already identifies that exact candidate; and
|
||||
- the tag identifies the validated candidate and only the intended refs are
|
||||
published.
|
||||
|
||||
Fetch the authoritative branch and tag state as needed for these checks.
|
||||
Do not force branch or tag updates to bypass a failed guard. Publish explicit
|
||||
refs rather than all local tags. Do not require CI success, publication-service
|
||||
availability checks, or a separate manual confirmation for each guard.
|
||||
|
||||
## Immutability And Failure Recovery
|
||||
|
||||
Published version tags and published contents are immutable. Do not move,
|
||||
overwrite, recreate, or delete a published tag, or replace a published artifact,
|
||||
checksum, signature, provenance statement, or release note under that version.
|
||||
The checked-in note at the immutable tag is that release's historical record.
|
||||
|
||||
If validation fails before publication, correct and commit the candidate and
|
||||
rerun the publication command. If a push fails or its outcome is ambiguous,
|
||||
inspect the authoritative remote before retrying. Remove an unpublished local
|
||||
tag only after confirming it was never published or used by a release channel.
|
||||
An unavailable remote leaves publication status unknown; do not overwrite a tag
|
||||
to resolve uncertainty.
|
||||
|
||||
Transient network, authentication, CI, or consumer-availability failures do not
|
||||
by themselves require a new version. Asynchronous delivery may be retried from
|
||||
the same immutable tag. Missing artifacts may be published later, provided
|
||||
existing published contents are not replaced and the additions remain consistent
|
||||
with the tagged source and any already-published checksum manifest. If that
|
||||
cannot be achieved, publish a new version.
|
||||
|
||||
A defect requiring changes to published source or contents requires a corrected
|
||||
commit, a new semantically appropriate version, a matching release note, and
|
||||
the release procedure again. Leave the original release intact. A channel's
|
||||
yank, deprecation, or advisory mechanism may warn consumers away from a defective
|
||||
release without replacing its contents or reusing its version.
|
||||
|
||||
## Repository Release Procedure
|
||||
|
||||
Maintain `docs/release.md` as a short, executable maintainer runbook. It must
|
||||
identify:
|
||||
|
||||
1. prerequisites, primary branch, and authoritative remote;
|
||||
2. version and release-note preparation;
|
||||
3. one publication command with its selected local checks and automated guards;
|
||||
4. declared deliverables, required build targets, and automation responsibilities;
|
||||
5. the successful-push completion point and separately reported delivery status;
|
||||
and
|
||||
6. failure handling, ambiguous-push recovery, and asynchronous delivery retries.
|
||||
|
||||
Use copyable commands where practical. Keep optional diagnostics and consumer
|
||||
verification clearly optional. The procedure must not turn preparation work,
|
||||
ordinary change review, or post-publication investigation into additional
|
||||
release gates.
|
||||
@@ -1,5 +1,9 @@
|
||||
# Testing Policy
|
||||
|
||||
**Base Policy Version:** 1.1
|
||||
|
||||
**Last Updated:** 2026-09-26
|
||||
|
||||
## Purpose
|
||||
|
||||
Our tests exist to make **incorrect changes expensive and correct changes cheap**.
|
||||
@@ -8,29 +12,16 @@ We do not optimize for test count, line coverage, exhaustive isolation, or the f
|
||||
|
||||
## Every test has a cost
|
||||
|
||||
Testing is not an unqualified good. Every test imposes both an immediate cost and a continuing lifetime cost.
|
||||
|
||||
A test must be:
|
||||
|
||||
- written and reviewed;
|
||||
- understood by future maintainers and coding agents;
|
||||
- executed in local and CI workflows;
|
||||
- diagnosed when it fails;
|
||||
- updated when legitimate behavior changes;
|
||||
- maintained as fixtures, APIs, and dependencies evolve; and
|
||||
- removed or rewritten when it becomes redundant, brittle, misleading, or obsolete.
|
||||
|
||||
Tests also create cognitive and architectural friction. They can constrain refactoring, duplicate policy, slow feedback loops, add noise to failures, and cause harmless implementation changes to require unrelated edits across the suite.
|
||||
Every test has an immediate and continuing cost: writing, review, execution,
|
||||
diagnosis, fixture maintenance, and updates when legitimate behavior changes.
|
||||
Tests can also constrain refactoring, duplicate policy, and add failure noise.
|
||||
|
||||
A test is warranted only when the confidence it provides justifies these costs.
|
||||
|
||||
Apply this cost-benefit analysis at two levels:
|
||||
Evaluate that tradeoff at two levels:
|
||||
|
||||
1. **Per test:** What realistic defect does this test detect, how consequential would that defect be, and is that protection worth the test's lifetime cost?
|
||||
2. **Across the suite:** Does this collection provide materially more confidence than a smaller, simpler suite would?
|
||||
|
||||
The preferred test suite is a **lean suite that provides sufficient confidence in the risks that matter, without redundant or low-value tests**. We seek sufficient confidence with the least unnecessary testing friction, not the fewest possible tests.
|
||||
|
||||
Some friction is intentional. Tests should make dangerous changes—such as breaking compatibility, corrupting data, violating security boundaries, or reintroducing subtle bugs—require deliberate review. They should not make ordinary internal changes needlessly expensive.
|
||||
|
||||
The cost of a test is not a reason to omit testing by default. Do not cite maintenance cost abstractly. When omitting a plausible test, be able to state why the protected failure is low-risk, already covered, obvious, reversible, or cheaper to detect elsewhere. For consequential, subtle, or difficult-to-observe behavior, the presumption should favor testing.
|
||||
@@ -55,7 +46,7 @@ Control clocks, randomness, environment variables, and other process-global or m
|
||||
|
||||
## What deserves tests
|
||||
|
||||
Prioritize tests for:
|
||||
To the extent the following features are present in the application, prioritize tests for:
|
||||
|
||||
1. Public and package-level contracts.
|
||||
2. Domain rules and important invariants.
|
||||
@@ -67,7 +58,18 @@ Prioritize tests for:
|
||||
|
||||
A package-level contract is behavior relied upon by another package or major collaborator, not every observable detail of a package implementation.
|
||||
|
||||
For behavior involving **data integrity, destructive operations, compatibility, security, concurrency, idempotency, or recovery**, presume that durable tests are required unless the behavior is already credibly protected at another layer.
|
||||
Choose tests for requested behavior and established contracts. Tests must not
|
||||
introduce new restrictions, guarantees, or threat scenarios merely because they
|
||||
could be asserted. Follow the [agent policy](agents.md) when deciding whether a
|
||||
behavior belongs to the contract; current implementation behavior alone is not
|
||||
sufficient authority.
|
||||
|
||||
For established behavior involving **data integrity, destructive operations,
|
||||
compatibility, security, concurrency, idempotency, or recovery**, favor durable
|
||||
tests for realistic failures whose consequences warrant protection. Identify
|
||||
the failure and the existing contract it would violate. These categories call
|
||||
for attention, not an automatic test inventory or permission to strengthen the
|
||||
application's guarantees. Account for protection already provided at other layers.
|
||||
|
||||
Do not add tests merely because a function, branch, or line exists. Do not add a test when the same meaningful risk is already adequately protected elsewhere.
|
||||
|
||||
@@ -77,7 +79,7 @@ Test through the narrowest stable boundary that expresses the behavior clearly.
|
||||
|
||||
This is often the package API, but it may instead be:
|
||||
|
||||
- a smaller pure function when dense application logic is most clearly isolated there;
|
||||
- a smaller pure function when dense domain logic is most clearly isolated there;
|
||||
- a package-level operation when several internal collaborators jointly produce the behavior; or
|
||||
- a larger integration boundary when correctness emerges from interaction with a real dependency.
|
||||
|
||||
@@ -85,11 +87,7 @@ Do not force all behavior through oversized end-to-end tests. Do not test every
|
||||
|
||||
## Test behavior, not implementation
|
||||
|
||||
A test should protect a decision, contract, or invariant—not memorialize the current implementation.
|
||||
|
||||
Before adding or retaining a test, ask:
|
||||
|
||||
> What realistic defect would this test catch?
|
||||
A test should protect a decision, contract, or invariant. A test must not memorialize the current implementation.
|
||||
|
||||
A test is suspect when its main purpose is to detect that someone:
|
||||
|
||||
@@ -102,8 +100,6 @@ A test is suspect when its main purpose is to detect that someone:
|
||||
|
||||
Refactoring should normally require no test edits unless the refactored structure is itself part of the contract.
|
||||
|
||||
A test can be factually correct and still have negative value. Accurately describing current behavior is not enough; the protected behavior must be important enough to justify the future friction.
|
||||
|
||||
## Expected effects of different changes
|
||||
|
||||
Use the following expectations when evaluating test failures and test maintenance:
|
||||
@@ -121,10 +117,11 @@ A test failing is not the same as a test needing to be edited. Many tests may co
|
||||
|
||||
Configurable thresholds and defaults must not be duplicated throughout the test suite.
|
||||
|
||||
For example, do not encode an internal concurrency limit indirectly:
|
||||
For this example, assume the selected contract rejects a request to start more
|
||||
processes than a configured limit. Do not encode its production default indirectly:
|
||||
|
||||
```go
|
||||
// Production policy:
|
||||
// Production default:
|
||||
const maxConcurrency = 4
|
||||
|
||||
// Brittle test:
|
||||
@@ -142,18 +139,23 @@ require.NoError(t, runner.Start(limit))
|
||||
require.ErrorIs(t, runner.Start(limit+1), ErrTooMuchConcurrency)
|
||||
```
|
||||
|
||||
The test should prove:
|
||||
For this selected contract, the test should prove:
|
||||
|
||||
- the configured limit is accepted; and
|
||||
- one beyond the configured limit is rejected.
|
||||
|
||||
Rejection is not a general requirement for concurrency control. If the selected
|
||||
contract queues excess work or limits active workers while accepting larger
|
||||
batches, test that behavior instead. Do not add rejection or a configurable
|
||||
limit solely to reproduce this example.
|
||||
|
||||
The production default should be tested exactly only when its literal value is itself a public, operational, safety, protocol, or compatibility requirement.
|
||||
|
||||
Apply the same rule to limits, timeouts, capacities, retry counts, and ranges: test relationships and behavior, not duplicated literals.
|
||||
|
||||
For concurrency limits, test both kinds of behavior when relevant:
|
||||
For established concurrency limits, distinguish these behaviors where the contract requires them:
|
||||
|
||||
1. **Configuration enforcement:** invalid or excessive requested values are handled correctly.
|
||||
1. **Configuration handling:** values are accepted or rejected according to the selected contract.
|
||||
2. **Runtime enforcement:** observed peak concurrency never exceeds the configured limit.
|
||||
|
||||
Use a test-controlled limit and measure the behavior relative to that limit. Do not merely assert today's default value.
|
||||
@@ -162,21 +164,21 @@ Use a test-controlled limit and measure the behavior relative to that limit. Do
|
||||
|
||||
Each behavior should have a clear test owner.
|
||||
|
||||
- Configuration tests own application YAML, discovery, precedence, and
|
||||
application defaults.
|
||||
- Configuration tests own application YAML, strict decoding, discovery,
|
||||
precedence, and application defaults.
|
||||
- CLI tests own argument mapping, streams, summaries, exit behavior, and
|
||||
representative command workflows.
|
||||
- HTTP tests own DTOs, strict decoding, limits, status mapping, and restricted
|
||||
artifact policy.
|
||||
- Formatter tests own prepared-run text and JSON presentation.
|
||||
- Formatter tests own prepared-run and definition-inspection text and JSON
|
||||
presentation.
|
||||
- Architecture tests own dependency direction and removal invariants.
|
||||
- Promptkit owns framework parsing, orchestration, validation, profiles, and
|
||||
model-client behavior.
|
||||
model-client behavior. Scriptorium's definition compatibility fixtures protect
|
||||
its adapter plumbing without duplicating the upstream format contract.
|
||||
|
||||
Higher-level tests should not repeat every lower-level case. A single intentional policy change should not require unrelated edits across many test files.
|
||||
|
||||
Tests that are individually reasonable may still be collectively redundant. Evaluate the marginal value of each additional test in light of the protection already provided by the rest of the suite.
|
||||
|
||||
## Use test doubles deliberately
|
||||
|
||||
Choose the least elaborate test double that provides the required control or observation.
|
||||
@@ -200,15 +202,16 @@ Do not use mocks merely to isolate every object or reproduce the implementation'
|
||||
|
||||
## Go-specific guidance
|
||||
|
||||
Use:
|
||||
Select techniques according to the behavior and risk being tested. The following
|
||||
are options, not a checklist that every package or application must satisfy:
|
||||
|
||||
- table-driven tests for meaningful behavioral categories and boundaries;
|
||||
- `t.TempDir()` for real filesystem behavior;
|
||||
- `httptest.Server` for realistic HTTP interactions;
|
||||
- fuzz tests for parsers, normalization, path handling, and broad input spaces;
|
||||
- fuzz tests when exploring broad input spaces, such as parsers or path handling, adds useful protection beyond representative cases;
|
||||
- golden files only when the complete output is intentionally stable;
|
||||
- integration tests where correctness depends on component interaction; and
|
||||
- a small number of representative end-to-end tests.
|
||||
- a small number of representative end-to-end tests when assembled workflows expose meaningful risks not adequately covered at narrower boundaries.
|
||||
|
||||
Avoid exact error-string assertions unless the wording is itself contractual. Prefer `errors.Is`, `errors.As`, typed errors, or structured error fields.
|
||||
|
||||
@@ -228,8 +231,6 @@ Security-sensitive HTTP containment and external mappings may warrant denser
|
||||
coverage than straightforward process wiring. Uneven coverage is acceptable
|
||||
when it reflects risk.
|
||||
|
||||
Increasing coverage is valuable only when the newly covered behavior protects a meaningful risk at an acceptable cost.
|
||||
|
||||
## Regression tests
|
||||
|
||||
A bug fix should normally include a regression test that fails before the fix and passes afterward.
|
||||
@@ -258,44 +259,26 @@ Strong candidates include tests that:
|
||||
|
||||
Several brittle tests may encode one genuine requirement. Replace them with one durable behavior-level or invariant test rather than preserving all of them.
|
||||
|
||||
Deleting a low-value test can improve the quality of the suite by reducing noise, maintenance burden, and friction around legitimate change.
|
||||
|
||||
## Reviewing a proposed test
|
||||
|
||||
Use the following questions when the value, boundary, or durability of a proposed test is not self-evident. Significant test additions should be reviewable against them, but written answers are not required for every routine test.
|
||||
|
||||
1. What realistic defect would it catch?
|
||||
2. How likely is that defect?
|
||||
3. How consequential would it be?
|
||||
4. Is the behavior already protected elsewhere?
|
||||
5. At which layer should this behavior be owned?
|
||||
6. Does the test assert a durable contract or an incidental implementation detail?
|
||||
7. Could the implementation be refactored without changing the behavior and without editing this test?
|
||||
8. What should cause this test to fail?
|
||||
9. What legitimate changes should not cause this test to fail?
|
||||
10. What ongoing maintenance, execution, and diagnostic cost will the test impose?
|
||||
11. Is there a smaller or more direct test that protects the same risk?
|
||||
|
||||
Do not add the test when its expected lifetime cost exceeds its expected protective value.
|
||||
|
||||
When deciding not to test plausible behavior, record or be able to explain why the risk is low, already protected, obvious, reversible, or cheaper to detect elsewhere.
|
||||
1. Which requested behavior or established contract does it protect, and what realistic defect would violate it?
|
||||
2. How likely and consequential is that defect, and is it already protected elsewhere?
|
||||
3. What is the narrowest stable boundary that can test it clearly?
|
||||
4. Would a correct internal refactor or a change to an incidental default require test edits?
|
||||
5. Does its confidence justify its maintenance, execution, and diagnostic cost, or would a smaller test suffice?
|
||||
|
||||
## Definition of sufficient
|
||||
|
||||
A test suite is sufficient when:
|
||||
|
||||
- important contracts and invariants are protected;
|
||||
- meaningful boundaries and failure modes are exercised;
|
||||
- realistic and consequential regressions are credibly protected against silent recurrence;
|
||||
- behavior involving data integrity, destructive operations, compatibility, security, concurrency, idempotency, and recovery is credibly protected;
|
||||
- important external boundaries have realistic integration coverage;
|
||||
- representative complete workflows are tested;
|
||||
- important requested behavior and established contracts are protected against realistic, consequential failures;
|
||||
- boundaries and component interactions have coverage where they introduce meaningful risks not protected elsewhere;
|
||||
- failures provide useful signal rather than redundant noise;
|
||||
- legitimate internal changes usually do not require test edits; and
|
||||
- additional tests would mostly repeat existing protection or preserve inconsequential implementation details.
|
||||
|
||||
Sufficiency is a risk judgment, not a coverage percentage or test count. Reassess it as the application, its users, and the consequences of failure evolve.
|
||||
|
||||
The governing rule is:
|
||||
|
||||
> Test heavily where failure is consequential, subtle, or difficult to detect after the fact. Test lightly where failure is obvious, reversible, and inexpensive—and retain no test whose lifetime cost exceeds the confidence it provides.
|
||||
Sufficiency is a risk judgment, not a coverage percentage, test count, or required
|
||||
mix of testing techniques. Reassess it as the application, its users, and the
|
||||
consequences of failure evolve.
|
||||
|
||||
461
docs/release.md
461
docs/release.md
@@ -1,377 +1,130 @@
|
||||
# Release Procedure
|
||||
|
||||
## Release Model And Status
|
||||
The [release policy](policy/release.md) owns versioning, compatibility,
|
||||
publication completion, and immutability. This runbook supplies Scriptorium's
|
||||
commands; release notes under `docs/releases/` are historical summaries.
|
||||
|
||||
Scriptorium publishes annotated semantic tags and tag-triggered Linux binary
|
||||
releases. The hosted
|
||||
[release workflow](../.woodpecker/release.yml) builds `amd64` and `arm64`
|
||||
executables, publishes their SHA-256 checksums, and uses the matching file
|
||||
under `docs/releases/` as the hosted release body.
|
||||
## Prepare The Candidate
|
||||
|
||||
`v0.12.0` is the first published application-only release. For each later
|
||||
release, select a new `vMAJOR.MINOR.PATCH` version according to the intended
|
||||
compatibility change. A selected version remains an unreleased candidate until
|
||||
its annotated tag is published, the hosted workflow succeeds, and every
|
||||
published artifact is verified.
|
||||
|
||||
Run this procedure from the Scriptorium repository root. A release must not
|
||||
depend on a Go workspace, module replacement, vendor tree, sibling checkout,
|
||||
unpublished dependency, or unpushed source commit.
|
||||
|
||||
## Establish The Candidate
|
||||
|
||||
Start a POSIX shell, choose a semantic version that has not been published, and
|
||||
export it as `RELEASE_VERSION`. For example, if `v0.12.1` is the intended next
|
||||
version and remains unpublished, select:
|
||||
Use a POSIX shell, Git with a configured tagger identity and access to
|
||||
`origin`, and a Go toolchain compatible with `go.mod`. The native host must
|
||||
support Go's race detector and have its required C compiler. If Git is
|
||||
configured to sign tags, its signing tool and key must be available. Run from the
|
||||
repository root. Provision the toolchain and module cache before offline
|
||||
validation; when dependencies are not cached:
|
||||
|
||||
```sh
|
||||
export RELEASE_VERSION=v0.12.1
|
||||
GOWORK=off go mod download
|
||||
```
|
||||
|
||||
Use the version appropriate to the actual compatibility change rather than
|
||||
assuming that the example is the next release. Then run the following guard in
|
||||
that same shell:
|
||||
Choose an unused stable version under the release policy. Commit its note as
|
||||
`docs/releases/<version>.md`, beginning with a title such as
|
||||
`# Scriptorium v0.14.0` (an example, not an instruction to select that version).
|
||||
Include a concise summary and relevant compatibility impact or upgrade action.
|
||||
Update affected canonical documentation with the change, and retire completed
|
||||
roadmap material when appropriate while preserving deferred work and links.
|
||||
No extra release-specific review signoff is required.
|
||||
|
||||
Finish and commit the intended candidate on `main`, then publish that branch:
|
||||
|
||||
```sh
|
||||
set -eu
|
||||
|
||||
: "${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
|
||||
git -c push.followTags=false push origin refs/heads/main:refs/heads/main
|
||||
```
|
||||
|
||||
Do not continue unless this guard succeeds. It deliberately requires the
|
||||
candidate to be the exact clean commit already published at `origin/main`.
|
||||
The publication command inspects the configured push endpoint of `origin`,
|
||||
not a potentially stale remote-tracking ref. If a separate push URL is
|
||||
configured, it is authoritative for both checks and publication. Configure one
|
||||
publication URL; multiple push endpoints cannot be validated as one remote.
|
||||
|
||||
## Verify Modules And Repository Boundaries
|
||||
## Publish
|
||||
|
||||
Confirm the module path and declared Go version:
|
||||
Invoke the single [publication command](../scripts/release.sh), substituting
|
||||
the selected version:
|
||||
|
||||
```sh
|
||||
test "$(
|
||||
GOWORK=off go list -m -f '{{.Path}} {{.GoVersion}}'
|
||||
)" = 'gitea.maximumdirect.net/eric/scriptorium 1.25.5'
|
||||
sh scripts/release.sh v0.14.0
|
||||
```
|
||||
|
||||
Require Promptkit `v0.9.0` as both the direct module-graph edge and the selected
|
||||
module version:
|
||||
The command validates a clean worktree and index on `main`, an unused local and
|
||||
remote version, exact agreement with authoritative remote `main`, and a
|
||||
checked-in note whose first-level title contains Scriptorium and the exact
|
||||
version. Ignored local files do not make the candidate dirty.
|
||||
|
||||
The existing source-boundary guards reject committed workspaces, vendor trees,
|
||||
and module replacements. No migration-specific exact Promptkit version audit
|
||||
is required.
|
||||
|
||||
It then runs the complete suite once with the race detector and builds Linux
|
||||
amd64 and arm64 binaries using `CGO_ENABLED=0`, `-trimpath`, and
|
||||
`-ldflags '-s -w'`. The native test run uses the host platform and enables cgo.
|
||||
Validation disables workspaces, uses read-only module mode, and disables module
|
||||
and toolchain downloads. Missing dependencies must be provisioned separately;
|
||||
fix the environment and rerun the command. No persistent validation cache is
|
||||
maintained by the release tool.
|
||||
|
||||
The command rechecks candidate and publication state, creates an annotated tag
|
||||
from the committed note, and pushes only that tag's exact object to its explicit
|
||||
ref. It does not push branches, follow other tags, force updates, or wait for
|
||||
CI. Temporary notes and validation builds are removed on exit. The successful
|
||||
summary identifies the source commit and tag object and reports binary
|
||||
delivery separately as asynchronous and unverified.
|
||||
|
||||
## Asynchronous Binary Delivery
|
||||
|
||||
The tag-triggered [hosted workflow](../.woodpecker/release.yml) builds and
|
||||
publishes:
|
||||
|
||||
- `scriptorium-<version>-linux-amd64`;
|
||||
- `scriptorium-<version>-linux-arm64`; and
|
||||
- `SHA256SUMS`.
|
||||
|
||||
The matching checked-in note supplies the hosted release body. The workflow
|
||||
owns image selection, packaging, checksum generation, and upload configuration.
|
||||
Its upload step skips existing files and does not overwrite the release.
|
||||
Source-publication success does not attest to workflow success or asset
|
||||
availability.
|
||||
|
||||
Workflow inspection, downloads, checksum verification, and a compatible-host
|
||||
smoke test are optional delivery diagnostics. They must not delay or redefine
|
||||
source-release completion. No polling or consumer-installation check is part
|
||||
of the publication command.
|
||||
|
||||
## Failure Recovery
|
||||
|
||||
Before tag creation, correct and commit a failed candidate, publish `main`,
|
||||
and invoke the publication command again. A changed candidate must pass its
|
||||
own validation.
|
||||
|
||||
After an unsuccessful push, the command queries the authoritative endpoint.
|
||||
If it confirms the exact tag object and candidate, it reports source success.
|
||||
Otherwise it exits unsuccessfully and preserves the local tag. It never retries
|
||||
a push or deletes a tag automatically. If the endpoint is unavailable, the
|
||||
publication status is unknown, not evidence that nothing was published.
|
||||
|
||||
For manual diagnosis, select the affected version and compare the local tag
|
||||
object and peeled commit with the authoritative remote:
|
||||
|
||||
```sh
|
||||
direct_promptkit=$(
|
||||
GOWORK=off go mod graph |
|
||||
awk '
|
||||
$1 == "gitea.maximumdirect.net/eric/scriptorium" &&
|
||||
$2 ~ /^gitea\.maximumdirect\.net\/eric\/promptkit@/ {
|
||||
print $2
|
||||
}
|
||||
'
|
||||
)
|
||||
test "$direct_promptkit" = \
|
||||
'gitea.maximumdirect.net/eric/promptkit@v0.9.0'
|
||||
test "$(
|
||||
GOWORK=off go list -m -f '{{.Path}}@{{.Version}}' \
|
||||
gitea.maximumdirect.net/eric/promptkit
|
||||
)" = 'gitea.maximumdirect.net/eric/promptkit@v0.9.0'
|
||||
GOWORK=off go list -m all
|
||||
release_version=v0.14.0
|
||||
release_remote=$(git remote get-url --push origin)
|
||||
git rev-parse "refs/tags/$release_version" "refs/tags/$release_version^{commit}"
|
||||
git ls-remote "$release_remote" refs/heads/main \
|
||||
"refs/tags/$release_version" "refs/tags/$release_version^{}"
|
||||
```
|
||||
|
||||
Require tidy module metadata and recheck the repository exclusions:
|
||||
Do not retry while the outcome remains unknown. If the tag exists remotely,
|
||||
do not move, recreate, or delete it. If the tag was never published or used by
|
||||
any release channel, an explicitly authorized local cleanup may delete only
|
||||
that unpublished tag; then rerun the command to validate and publish the
|
||||
candidate. The command intentionally rejects an existing local tag rather than
|
||||
assuming that a previous process validated it.
|
||||
|
||||
```sh
|
||||
GOWORK=off go mod tidy -diff
|
||||
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
|
||||
test -z "$(git status --porcelain)"
|
||||
```
|
||||
|
||||
## Validate The Application
|
||||
|
||||
Run the complete application validation:
|
||||
|
||||
```sh
|
||||
GOWORK=off go test ./...
|
||||
GOWORK=off go test -race ./...
|
||||
GOWORK=off go vet ./...
|
||||
validation_build_dir=$(mktemp -d)
|
||||
GOWORK=off go build \
|
||||
-o "$validation_build_dir/scriptorium" \
|
||||
./cmd/scriptorium
|
||||
```
|
||||
|
||||
The ordinary test run includes the architecture guard that rejects a root Go
|
||||
package, former framework package families, and imports of Promptkit internal
|
||||
packages. Inspect the repository for generated binaries, credentials,
|
||||
temporary output, sibling paths, and other files that do not belong in the
|
||||
tracked release source.
|
||||
|
||||
Check every tracked Go file. This command must produce no output:
|
||||
|
||||
```sh
|
||||
unformatted=$(
|
||||
git ls-files '*.go' |
|
||||
while IFS= read -r go_file
|
||||
do
|
||||
gofmt -l "$go_file"
|
||||
done
|
||||
)
|
||||
test -z "$unformatted"
|
||||
```
|
||||
|
||||
Run the maintained render and Promptkit v0.9 feature scripts, then smoke-test
|
||||
both maintained configuration examples without a model call:
|
||||
|
||||
```sh
|
||||
GOWORK=off ./examples/render-markdown-summary.sh
|
||||
GOWORK=off ./examples/render-v0.9-features.sh
|
||||
for config_file in examples/config.yml examples/config.full.yml
|
||||
do
|
||||
GOWORK=off go run ./cmd/scriptorium render \
|
||||
--config "$config_file" \
|
||||
--prompt generic.markdown_summary \
|
||||
--input transcript=./examples/fixtures/transcript.md \
|
||||
--input glossary=./examples/fixtures/glossary.yml \
|
||||
--format json >/dev/null
|
||||
done
|
||||
```
|
||||
|
||||
Exercise usage output and offline rendering with the temporary native
|
||||
executable:
|
||||
|
||||
```sh
|
||||
usage_output="$validation_build_dir/usage.txt"
|
||||
if "$validation_build_dir/scriptorium" >"$usage_output" 2>&1
|
||||
then
|
||||
printf '%s\n' 'expected an invocation without a command to fail' >&2
|
||||
exit 1
|
||||
fi
|
||||
grep -F 'usage: scriptorium' "$usage_output"
|
||||
"$validation_build_dir/scriptorium" render \
|
||||
--config ./examples/config.yml \
|
||||
--prompt generic.markdown_summary \
|
||||
--input transcript=./examples/fixtures/transcript.md \
|
||||
--input glossary=./examples/fixtures/glossary.yml \
|
||||
--format text >/dev/null
|
||||
```
|
||||
|
||||
Follow every maintained local, Promptkit-tagged, and other external Markdown
|
||||
link. Confirm that all repository-relative link targets exist. Finish the
|
||||
application checks with:
|
||||
|
||||
```sh
|
||||
git diff --check
|
||||
test -z "$(git status --porcelain)"
|
||||
```
|
||||
|
||||
## Require Release Notes And Reproduce Packaging
|
||||
|
||||
The immutable release note must exist before tagging:
|
||||
|
||||
```sh
|
||||
release_notes="docs/releases/$RELEASE_VERSION.md"
|
||||
test -f "$release_notes"
|
||||
test -s "$release_notes"
|
||||
```
|
||||
|
||||
Validate every local and currently published link in the note. For links
|
||||
pinned to the candidate Scriptorium tag, confirm that the corresponding
|
||||
repository-relative path exists even though its tag URL is not live yet.
|
||||
|
||||
Reproduce the hosted build flags, targets, and filenames in a temporary
|
||||
directory:
|
||||
|
||||
```sh
|
||||
release_dist=$(mktemp -d)
|
||||
release_package='gitea.maximumdirect.net/eric/scriptorium/cmd/scriptorium'
|
||||
|
||||
build_release_binary() {
|
||||
target_os="$1"
|
||||
target_arch="$2"
|
||||
output="$release_dist/scriptorium-$RELEASE_VERSION-$target_os-$target_arch"
|
||||
|
||||
CGO_ENABLED=0 GOOS="$target_os" GOARCH="$target_arch" GOWORK=off \
|
||||
go build -trimpath -ldflags '-s -w' \
|
||||
-o "$output" "$release_package"
|
||||
}
|
||||
|
||||
build_release_binary linux amd64
|
||||
build_release_binary linux arm64
|
||||
|
||||
test -s "$release_dist/scriptorium-$RELEASE_VERSION-linux-amd64"
|
||||
test -s "$release_dist/scriptorium-$RELEASE_VERSION-linux-arm64"
|
||||
file "$release_dist/scriptorium-$RELEASE_VERSION-linux-amd64"
|
||||
file "$release_dist/scriptorium-$RELEASE_VERSION-linux-arm64"
|
||||
```
|
||||
|
||||
Require `file` to identify Linux executables for `x86-64` and `ARM aarch64`,
|
||||
respectively. Inspect the
|
||||
[hosted workflow](../.woodpecker/release.yml) and confirm that it uses the
|
||||
same build flags and names, copies the selected release note to
|
||||
`dist/RELEASE_NOTES.md`, publishes only `dist/scriptorium-*`, and keeps
|
||||
checksum generation enabled.
|
||||
|
||||
## Create And Publish The Tag
|
||||
|
||||
Run the candidate guard again immediately before creating the tag:
|
||||
|
||||
```sh
|
||||
check_release_candidate
|
||||
test -f "$release_notes"
|
||||
test -s "$release_notes"
|
||||
```
|
||||
|
||||
Create an annotated tag explicitly bound to the validated commit, using the
|
||||
version-specific release note as its message:
|
||||
|
||||
```sh
|
||||
git tag --annotate "$RELEASE_VERSION" \
|
||||
--file "$release_notes" \
|
||||
"$RELEASE_COMMIT"
|
||||
```
|
||||
|
||||
Inspect the tag and require it to resolve to the validated source:
|
||||
|
||||
```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 only the unpublished local tag, correct
|
||||
the candidate, and repeat the complete validation. Never move or recreate a
|
||||
published tag.
|
||||
|
||||
Push only the selected tag ref:
|
||||
|
||||
```sh
|
||||
git push origin \
|
||||
"refs/tags/$RELEASE_VERSION:refs/tags/$RELEASE_VERSION"
|
||||
```
|
||||
|
||||
## Observe And Verify Publication
|
||||
|
||||
Open the hosted workflow run for the selected tag. Require
|
||||
`build-release-assets` to succeed before `publish-release`, then require the
|
||||
publication step and hosted release to succeed. A queued, running, failed, or
|
||||
partially published workflow is not a verified release.
|
||||
|
||||
Compare the local and remote annotated-tag objects and their source commits:
|
||||
|
||||
```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"
|
||||
```
|
||||
|
||||
Download the hosted binaries and checksum file into a temporary directory:
|
||||
|
||||
```sh
|
||||
release_base="https://gitea.maximumdirect.net/eric/scriptorium/releases/download/$RELEASE_VERSION"
|
||||
download_dir=$(mktemp -d)
|
||||
(
|
||||
cd "$download_dir"
|
||||
for asset in \
|
||||
"scriptorium-$RELEASE_VERSION-linux-amd64" \
|
||||
"scriptorium-$RELEASE_VERSION-linux-arm64" \
|
||||
SHA256SUMS
|
||||
do
|
||||
curl --fail --location --remote-name "$release_base/$asset"
|
||||
done
|
||||
|
||||
test -s "scriptorium-$RELEASE_VERSION-linux-amd64"
|
||||
test -s "scriptorium-$RELEASE_VERSION-linux-arm64"
|
||||
test -s SHA256SUMS
|
||||
sha256sum --check SHA256SUMS
|
||||
test "$(wc -l < SHA256SUMS | tr -d ' ')" = 2
|
||||
file "scriptorium-$RELEASE_VERSION-linux-amd64"
|
||||
file "scriptorium-$RELEASE_VERSION-linux-arm64"
|
||||
)
|
||||
```
|
||||
|
||||
Require the same Linux architectures observed in the local packaging check and
|
||||
confirm that the hosted release contains no unexpected asset. On a compatible
|
||||
Linux host, make the matching downloaded binary executable and repeat the
|
||||
usage-output and offline-render smoke checks against it.
|
||||
|
||||
Only after the tag, workflow, release body, binaries, architectures, and
|
||||
checksums all pass verification is the candidate a verified published release.
|
||||
|
||||
## Handle Failures
|
||||
|
||||
Before tag publication, correct the release commit or note and restart the
|
||||
complete procedure. After tag publication, never delete, move, overwrite, or
|
||||
recreate the tag. A transient hosted failure may be retried only against the
|
||||
same immutable tag and commit and only when doing so cannot overwrite or
|
||||
silently retain partial assets. A source, packaging, note, or artifact defect
|
||||
requires a new corrective semantic version from a new validated commit.
|
||||
|
||||
Record the selected version, validated commit, tag object, workflow result,
|
||||
artifact names, checksum result, and smoke-check outcome in the release
|
||||
checkpoint. Keep temporary builds and downloaded assets outside the repository,
|
||||
and require a clean `main` synchronized with `origin/main` when verification
|
||||
is complete.
|
||||
For transient delivery failures, inspect what has already been uploaded before
|
||||
retrying the same immutable tag. The upload step's skip behavior alone does not
|
||||
prove checksum consistency. Add missing assets only if they match the tagged
|
||||
source and any already-published manifest, without replacing existing contents.
|
||||
Compare rebuilt bytes with published checksums when recovering a partial
|
||||
upload; do not assume toolchain changes reproduce identical binaries. If safe
|
||||
completion is impossible, or published source, notes, packaging, or artifact
|
||||
contents need correction, leave the original release intact and publish a new
|
||||
version from a corrected commit.
|
||||
|
||||
289
docs/roadmap/policy.md
Normal file
289
docs/roadmap/policy.md
Normal file
@@ -0,0 +1,289 @@
|
||||
# Policy Template Adoption
|
||||
|
||||
## Status And Intent
|
||||
|
||||
Completed and validated on 2026-09-26. This roadmap retains the accepted
|
||||
adoption requirements and implementation record. The implemented documents
|
||||
under `docs/policy/` own current policy; this roadmap does not authorize release
|
||||
publication.
|
||||
|
||||
### Implementation Record
|
||||
|
||||
- Added agent and release policies and merged the architecture, documentation,
|
||||
and testing updates. All five policies have the specified provenance headers.
|
||||
- Updated repository entry points and the contributor reading guide, preserving
|
||||
the local ADR lifecycle and executable-interface documentation ownership.
|
||||
- Added [the publication command](../../scripts/release.sh) and
|
||||
[local-repository regression tests](../../scripts/release_test.go), and
|
||||
replaced the old release procedure with the [short runbook](../release.md).
|
||||
- Retained the hosted workflow after checking its targets, flags, release-note
|
||||
source, checksums, and non-overwrite settings. Recovery guidance explicitly
|
||||
requires consistency with already-published manifests before adding assets.
|
||||
- The complete `go test ./...` and `go test -race ./...` suites pass, including
|
||||
the release-tool tests and existing CLI tests. Both declared Linux builds,
|
||||
the native build, `go vet ./...`, shell syntax, changed-document links, and
|
||||
whitespace checks pass. Validation used the installed Go 1.25.5 toolchain
|
||||
and a temporary build cache, without provider credentials or inference calls.
|
||||
- Initial sandbox restrictions on local listeners and Git metadata were
|
||||
lifted before final verification. No tests were weakened or skipped to work
|
||||
around them. No real tag or release was published during implementation.
|
||||
|
||||
Use the templates in the sibling `../policy` repository at commit `45591a7` as
|
||||
the adoption baseline. Customize them for Scriptorium rather than replacing
|
||||
the existing policies verbatim. The sibling checkout is a review source, not a
|
||||
new build, runtime, or contributor dependency.
|
||||
|
||||
The desired outcome is a complete, consistent policy set that preserves
|
||||
Scriptorium's application boundaries, gives agents clear working rules, and
|
||||
makes release preparation proportionate and repeatable.
|
||||
|
||||
## Policy Set And Provenance Headers
|
||||
|
||||
Every adopted policy document must place its base template version and local
|
||||
last-updated date immediately below its title. For this adoption, use today's
|
||||
date, **2026-09-26**, rather than the upstream template's last-updated date.
|
||||
|
||||
| Policy document | Adoption | Base Policy Version | Last Updated |
|
||||
| --- | --- | --- | --- |
|
||||
| `docs/policy/agents.md` | Add | 1.1 | 2026-09-26 |
|
||||
| `docs/policy/architecture.md` | Merge with existing policy | 1.1 | 2026-09-26 |
|
||||
| `docs/policy/documentation.md` | Merge with existing policy | 1.3 | 2026-09-26 |
|
||||
| `docs/policy/release.md` | Add | 1.1 | 2026-09-26 |
|
||||
| `docs/policy/testing.md` | Merge with existing policy | 1.1 | 2026-09-26 |
|
||||
|
||||
Use this header shape, substituting the applicable title and base version:
|
||||
|
||||
```markdown
|
||||
# Architecture Policy
|
||||
|
||||
**Base Policy Version:** 1.1
|
||||
|
||||
**Last Updated:** 2026-09-26
|
||||
```
|
||||
|
||||
The base version identifies the underlying upstream template, not a local
|
||||
policy revision or Scriptorium release. Subsequent local revisions update the
|
||||
date; the base version changes only when a newer template is adopted. Remove
|
||||
upstream adoption instructions and template scaffolding from the finished
|
||||
policies. All five documents must be substantive, repository-specific policy.
|
||||
|
||||
## Agent Guidance And Discoverability
|
||||
|
||||
Add `docs/policy/agents.md` as the canonical owner of coding-agent behavior.
|
||||
Update `AGENTS.md` and the [development guide](../development.md) so agents read
|
||||
it before recommending, planning, or implementing work, then follow the
|
||||
task-specific reading guide. Preserve other applicable repository instructions.
|
||||
|
||||
The policy should favor idiomatic Go, standard-library facilities where
|
||||
appropriate, simple ownership, and machinery proportionate to the actual
|
||||
problem. It must discourage speculative abstractions, invented requirements,
|
||||
unsupported guarantees, and treating incidental implementation details as
|
||||
permanent policy.
|
||||
|
||||
Adopt the upstream local-commit default: complete and validate coherent units
|
||||
of authorized work, review status and staged diffs, and commit those units with
|
||||
plain English messages. Protect unrelated user changes and secrets, and do not
|
||||
bypass hooks. An explicit request to leave work uncommitted overrides the
|
||||
default. This rule does not authorize pushing, publishing releases, rewriting
|
||||
history, or committing unrelated changes.
|
||||
|
||||
## Documentation Ownership
|
||||
|
||||
Merge the updated documentation template into the existing
|
||||
[documentation policy](../policy/documentation.md), preserving its useful
|
||||
Scriptorium-specific decisions:
|
||||
|
||||
- One canonical owner per contract, with short summaries and links elsewhere.
|
||||
- Executable-interface consumer guidance, not a fictitious public Go API.
|
||||
- Tested minimal orientation examples and complete copyable assets in
|
||||
`examples/`.
|
||||
- No irrelevant placeholder documents or template-only TODO sections.
|
||||
- The existing ADR lifecycle, including proposed, accepted, rejected, and
|
||||
superseded decisions; immutable accepted decision content; and reciprocal
|
||||
supersession links.
|
||||
|
||||
Add ownership for agent policy and release policy. The release policy owns
|
||||
versioning, compatibility, integrity, gate selection, publication controls,
|
||||
immutability, and the definition of release completion. The
|
||||
[release runbook](../release.md) owns concrete repository commands and recovery
|
||||
procedures. Version-specific notes remain immutable release history.
|
||||
|
||||
Architecture policy owns deliberate constraints and normative boundaries;
|
||||
the [internal overview](../internal/overview.md) owns implemented component
|
||||
structure. Roadmaps own planned work and implementation status. Accepted ADRs
|
||||
may precede implementation but must not imply that planned behavior exists.
|
||||
Update reading-guide links and ownership descriptions together so old and new
|
||||
documents do not prescribe competing workflows.
|
||||
|
||||
## Architecture Refinements
|
||||
|
||||
Retain the existing adapter-oriented architecture and supported Promptkit root
|
||||
package dependency. This policy refresh does not require new wrappers,
|
||||
interfaces, packages, or another architecture migration.
|
||||
|
||||
Explicitly connect the policy to
|
||||
[ADR 0004](../adr/0004-definition-boundary.md): support valid prompt and profile
|
||||
definitions for the selected Promptkit version, while considering library-only
|
||||
features individually. Requests remain independent from the caller's
|
||||
perspective; shared process-scoped engines, backend capacity accounting,
|
||||
in-flight coordination, and lifecycle state remain permitted and, when needed
|
||||
to enforce limits, required. Do not describe the application as internally
|
||||
stateless or introduce conversation and durable workflow responsibilities.
|
||||
|
||||
Preserve strict application decoding, application-owned HTTP artifact limits,
|
||||
and the separation between tagged upstream dependencies and Scriptorium's
|
||||
executable adapters. Retain the existing guards against local replacements,
|
||||
committed workspaces, vendored Promptkit implementation, and unsupported
|
||||
imports.
|
||||
|
||||
State architectural constraints deliberately rather than freezing every
|
||||
current implementation choice. Explain the actual artifact threat boundary:
|
||||
lexical containment does not prevent operating-system symlink following. Do
|
||||
not invent a stronger filesystem-security guarantee or require defenses
|
||||
against concurrent privileged filesystem modification as part of this update.
|
||||
Keep operational mitigations and interface outcomes in their canonical owners.
|
||||
|
||||
## Risk-Based Testing
|
||||
|
||||
Merge the updated testing template into the
|
||||
[testing policy](../policy/testing.md). Test sufficiency should follow the
|
||||
established contract, realistic failure risk, and protections already supplied
|
||||
by other layers, rather than a mandatory matrix of possible cases.
|
||||
|
||||
Preserve existing coverage responsibilities for configuration precedence and
|
||||
strict decoding; CLI streams, summaries, exits, and representative workflows;
|
||||
HTTP DTOs, limits, statuses, and artifact restrictions; deterministic prepared
|
||||
run and definition-inspection presentation; and architecture boundaries.
|
||||
Promptkit remains responsible for framework semantics, while Scriptorium's
|
||||
compatibility fixtures protect its adapter plumbing.
|
||||
|
||||
Use real collaborators where practical, deterministic offline tests, and no
|
||||
required provider credentials or paid API calls. Assert meaningful behavior
|
||||
rather than helper structure or incidental wording. Concurrency tests must
|
||||
follow the selected admission and queueing contract; an upstream example of
|
||||
rejection is not a mandate to reject requests that should queue. Fuzzing,
|
||||
matrices, and other techniques are options justified by risk, not universal
|
||||
requirements. This adoption is not a blanket test rewrite or an excuse to
|
||||
remove valuable compatibility coverage.
|
||||
|
||||
## Release Policy And Publication Workflow
|
||||
|
||||
The largest functional change in this adoption is release tooling and guidance,
|
||||
not application behavior. Add `docs/policy/release.md` and shorten the existing
|
||||
runbook around one repository-owned publication command, with its concrete
|
||||
invocation documented there. Keep CI implementation details in the workflow.
|
||||
|
||||
### Versioning And Release Identity
|
||||
|
||||
Retain `origin` as the authoritative remote, `main` as the release branch,
|
||||
annotated stable tags in `vMAJOR.MINOR.PATCH` form, and matching
|
||||
`docs/releases/<version>.md` notes and titles. Reject invalid versions,
|
||||
including leading-zero components, and tags already present locally or on the
|
||||
authoritative remote. Do not add a prerelease channel in this adoption.
|
||||
|
||||
Before 1.0, minor releases may change documented contracts when release notes
|
||||
explain the impact and required action; patch releases preserve the minor
|
||||
line's compatibility. From 1.0 onward, use normal semantic-versioning
|
||||
compatibility rules. Preserve cross-project tagged-release boundaries rather
|
||||
than reviving migration-specific dependency audits.
|
||||
|
||||
### A Single Validated Candidate
|
||||
|
||||
Publish the intended `main` commit before invoking the release command. The
|
||||
command must establish a clean candidate on `main` that exactly matches
|
||||
authoritative `origin/main`, validate its version and notes, run the required
|
||||
checks, and bind publication to that exact commit. A changed candidate
|
||||
invalidates validation. Check publication-sensitive state again where needed
|
||||
without rerunning expensive tests on an unchanged candidate.
|
||||
|
||||
Use one complete deterministic offline test-suite invocation for the final
|
||||
candidate. The recommended invocation is `GOWORK=off go test -race ./...`:
|
||||
it checks ordinary assertions and race behavior together, with race coverage
|
||||
justified by the application's shared HTTP and backend operational state.
|
||||
Keep dependency provisioning separate from offline test execution.
|
||||
|
||||
Build both existing Linux targets, amd64 and arm64, using the release settings
|
||||
(`CGO_ENABLED=0`, `-trimpath`, and `-ldflags "-s -w"`). Cross-building does not
|
||||
imply requiring native test hardware for both architectures. Existing
|
||||
architecture tests continue to enforce dependency boundaries.
|
||||
|
||||
Remove unconditional duplicate test runs, migration-era exact Promptkit
|
||||
version audits, repeated example checks, broad documentation-link scans, and
|
||||
other release gates without a distinct release-risk justification. Formatting,
|
||||
vetting, affected examples, and documentation validation remain appropriate
|
||||
change-development checks; they need not all be repeated as publication gates.
|
||||
Do not introduce a persistent validation cache or a new platform matrix.
|
||||
Ignored local build products are not inherently release blockers and do not
|
||||
justify broad cleanup. Normal change review still protects against tracked
|
||||
junk and secrets.
|
||||
|
||||
### Source Publication And Asynchronous Delivery
|
||||
|
||||
Create the annotated tag for the validated commit using its release notes and
|
||||
push only that explicit tag ref. Do not force-push or publish all local tags.
|
||||
A successful tag push completes source publication. Report binary delivery
|
||||
separately as asynchronous and unverified unless actually checked.
|
||||
|
||||
Preserve the hosted workflow's Linux amd64/arm64 binaries, release-note body,
|
||||
and `SHA256SUMS` delivery. Align the workflow only where needed to support the
|
||||
policy. CI polling, artifact downloads, consumer installation checks, module
|
||||
availability checks, and remote readback after an unequivocally successful
|
||||
push are optional diagnostics, not completion gates. Failed or ambiguous
|
||||
pushes require authoritative remote-state resolution before reporting success
|
||||
or deciding whether to retry.
|
||||
|
||||
Published tags, source release notes, binaries, and checksums remain immutable.
|
||||
Transient CI, authentication, or network failures do not automatically require
|
||||
a new version: missing assets may be delivered later for the same tag without
|
||||
overwriting existing assets or creating inconsistent checksum manifests.
|
||||
Corrections that change published contents require a corrective commit and a
|
||||
new version. Recovery guidance must distinguish these situations.
|
||||
|
||||
Version selection, release-note preparation, and retirement of completed
|
||||
roadmaps are normal preparation work, not additional approval or signoff gates.
|
||||
Preserve deferred work and useful references when retiring roadmap material.
|
||||
|
||||
## Adoption Sequence
|
||||
|
||||
The completed implementation covers these three adoption units:
|
||||
|
||||
1. **Working guidance:** add agent policy; merge documentation and testing
|
||||
policies; add their provenance headers; update `AGENTS.md` and contributor
|
||||
navigation. Preserve local ADR and application-consumer conventions.
|
||||
2. **Architectural clarity:** merge architecture-template refinements, add its
|
||||
header, and connect the policy to ADR 0004 and the actual threat scope
|
||||
without changing runtime behavior or historical decisions.
|
||||
3. **Release simplification:** add release policy and its header, implement and
|
||||
validate the publication command, simplify the runbook, and align workflow
|
||||
and documentation ownership references as necessary. Land the new release
|
||||
procedure with its working tooling rather than documenting a command that
|
||||
does not yet exist.
|
||||
|
||||
This sequence is an adoption outline, not an application-feature implementation
|
||||
plan. Current policy is maintained in the adopted policy documents.
|
||||
|
||||
## Validation And Completion
|
||||
|
||||
The adoption is complete when:
|
||||
|
||||
- All five policies have the specified base-version and last-updated headers,
|
||||
substantive local content, and no upstream adoption scaffolding.
|
||||
- Repository entry points lead to the appropriate policy, links resolve, and
|
||||
ownership is consistent across policy, runbook, ADRs, and internal docs.
|
||||
- Existing product boundaries, compatibility protections, and security claims
|
||||
are preserved without speculative guarantees or unrelated refactoring.
|
||||
- The release command enforces the exact validated candidate and explicit tag
|
||||
publication, and the runbook clearly distinguishes source completion from
|
||||
optional delivery verification and recovery.
|
||||
- Release-tool tests use temporary local Git repositories rather than real
|
||||
publication. Cover meaningful failures such as invalid or reused versions,
|
||||
dirty or staged changes, wrong branch or remote mismatch, missing or
|
||||
mismatched notes, failed validation, a changed candidate, and ambiguous push
|
||||
outcomes, as well as successful publication of a clean published candidate.
|
||||
Keep this coverage proportionate; do not require external CI or providers.
|
||||
- Published-content immutability and safe missing-artifact recovery remain
|
||||
intact. No actual release is created merely to validate this adoption.
|
||||
|
||||
Application features, Promptkit upgrades, rewriting accepted ADR decisions,
|
||||
editing historical published release notes, and release publication are outside
|
||||
this roadmap's implementation scope.
|
||||
Reference in New Issue
Block a user