32 KiB
ReleaseKit v0.2.0 implementation plan
Status: Agreed stages for the remaining v0.2.0 work.
This plan replaces the completed foundation sequence. It implements the target state in v0.2.0.md, using the shared design in model.md, ADR 0003, and ADR 0004. A Luna coding agent should execute one numbered stage per prompt, in order.
Current baseline and completion scope
At 3974a46, the foundation and all six remediation findings
are complete. Check and Publish share candidate-request conversion and validation.
internal/validation runs the default offline suite and owns diagnostics and
candidate-tree access. Committed-file readers are offline; destination resolution
handles symlinks, parent traversal, cancellation, and absolute in-checkout paths.
The root error types and CLI presentation preserve findings and cause context.
buildinfo retains its independent runtime dependency graph.
The shared validation specification and profile settings are implemented incrementally with each capability; remaining selections are not yet implemented. The consumer CI template still selects an independent tool version. This sequence completes every remaining release-roadmap capability and Audita's CI migration. It ends with local verification and committed changes. Architecture review, hosted deployment, release tagging, and decisions about further testing follow this implementation.
| Release-roadmap item | Implementation stages |
|---|---|
| 1. Shared validation API/profile model | 1–3, 5–11, 15 |
| 2. Module-selected CI tool and Audita migration | 12–14 |
| 3. One suite with race selection | 1 |
| 4. Separate full vet | 2 |
| 5. Package compilation | 3 |
| 6. Expected publication endpoint | 4 |
| 7. Go formatting | 5 |
| 8. Markdown links and optional boundary | 9–11 |
| 9. Independent distribution rules | 6–7 |
| 10. Individual file size | 8 |
Instructions for every stage
- Start with development.md and applicable policies. Locate current symbols with the codebase graph and inspect the worktree. The named paths below describe the current baseline.
- Introduce each public and profile setting with its working capability, as agreed. Update its GoDoc, configuration reference, consumer guidance, and relevant CLI/internal documentation in that same stage.
- Use ordinary internal structs/functions and explicit facade conversions.
Keep product assertions in
AdditionalChecksand profilechecks. - Select tests for the stage's actual risks under the testing policy. Use local Git repositories, Go packages, controlled command doubles, and HTTP fixtures. Default tests remain offline and independent of real credentials or sibling checkouts.
- Verification lists describe required evidence, including existing tests. Give each behavior a test owner: parser/checker tests cover syntax and rules; candidate-tree and Git tests cover file access and resolution; conversion tests cover each API/profile selection; shared orchestration tests cover ordering, failure stopping, cancellation, and callback execution. Use representative integration cases to verify these boundaries work together. Add coverage where the change introduces a risk or leaves an evidence gap.
- Prepare newly selected development dependencies before offline validation. Apply the OSS policy when adding dependencies or adapting third-party material, including any required attribution and license texts.
- Verify the focused outcome, stage its relevant changes, review the diff, and create a nonempty commit with a short plain English message. Preserve unrelated work, report the stage's outcome and verification, and stop until the next stage is requested. These stages require local work and automated checks; consumer changes in Stage 14 are committed in that repository.
Design carried through the stages
Public and profile declarations
The completed specification is facade-owned:
type ValidationSpec struct {
Go GoValidationSpec
GoFormat bool
Markdown *MarkdownValidationSpec
ModuleDistribution ModuleDistributionValidationSpec
FileSize *FileSizeValidationSpec
}
type GoValidationSpec struct {
Race bool
FullVet bool
CompileTargets []Target
}
type MarkdownValidationSpec struct {
EnforceCheckoutBoundary bool
}
type ModuleDistributionValidationSpec struct {
WorkspaceFiles bool
LocalReplacements bool
}
type FileSizeValidationSpec struct {
LimitBytes *int64
Exclusions []string
}
Add Validation ValidationSpec and ExpectedPushURL string to ReleaseRequest.
Target is the existing root-facade operating-system/architecture pair. Each
stage adds only the fields it makes operational. The CLI owns corresponding
JSON structs and converts them in cmd/releasekit; internal production packages
use their own contracts.
| Go selection | Profile selection | Omitted/zero behavior |
|---|---|---|
Go.Race |
validation.go.race |
Ordinary native test suite |
Go.FullVet |
validation.go.full_vet |
Existing test-time vet |
Go.CompileTargets |
validation.go.compile_targets |
No package-compilation pass |
GoFormat |
validation.go_format |
No formatting check |
Markdown |
validation.markdown |
Nil/omitted/null disables the check; {} enables it |
Markdown.EnforceCheckoutBoundary |
validation.markdown.enforce_checkout_boundary |
Outside-checkout links reported as out of scope |
ModuleDistribution.WorkspaceFiles |
validation.module_distribution.workspace_files |
Rule disabled |
ModuleDistribution.LocalReplacements |
validation.module_distribution.local_replacements |
Rule disabled |
FileSize |
validation.file_size |
Nil/omitted/null disables the check; {} enables it |
FileSize.LimitBytes |
validation.file_size.limit_bytes |
Nil/omitted/null selects 1,000,000 bytes when enabled |
FileSize.Exclusions |
validation.file_size.exclusions |
No exclusions |
ExpectedPushURL |
expected_push_url |
Empty/omitted disables the publication expectation |
Profile compilation targets use GOOS/GOARCH strings. Require a complete pair
because a partial target would otherwise silently select different compilation.
Use the existing Go target/environment mechanisms; let the selected Go toolchain
report unsupported targets. An artifact naming constraint does not determine
package-compilation compatibility.
Byte limits are integer counts; zero is an explicit zero-byte limit, and negative
counts are invalid. Exclusions are literal repository-relative file or directory
paths; directory selections include committed descendants. Match path boundaries
so excluding assets leaves assets-other selected. Ordinary relative path
normalization is sufficient. An unmatched exclusion has no effect. Metacharacters
remain literal Git path characters.
Execution and ownership
The shared procedure is one native test suite, selected full vet, selected package-compilation targets, and selected file checks, followed by product checks and existing artifact builds/rechecks. File-check ordering is an internal procedure: formatting, workspace files, local replacements, file size, then Markdown. Stop after a failed check. A checker may return multiple findings; this plan does not require collecting failures from every selected check.
Resolve the Go environment once per validation operation and reuse it. Native
race/vet work preserves the existing effective cgo/C-tool configuration. Static
package compilation uses CGO_ENABLED=0. The existing offline module/toolchain
controls remain owned by internal/gotool.
Pass settings through the root candidateRequest, internal/candidate.Request,
internal/publish.Request, and validation.Request. Both operations and their
CLI forms use the same decisions. Keep expected URL comparison in publication
preflight. Existing capture/rechecks, endpoint guards, recovery, publication
completion, and delivery outcomes retain their meaning.
Reuse the existing internal failures and facade conversion. Add stable identities
go-vet, package-compile, go-format, workspace-files, local-replacements,
file-size, and markdown-links as implemented. Supply paths, locations,
targets, directives, and measurements as applicable. Preserve causes and
cancellation through errors.Is/errors.As. CLI failures use existing exit
classifications and complete contextual presentation.
File checks share one candidate inventory per validation operation and load blobs as needed. Inventory includes tracked vendor files and nested modules. Regular source blobs feed formatting and Markdown parsing. Workspace-file detection includes named symlink blobs; module parsing follows committed symlinks to candidate-contained regular declarations. Unavailable selected input produces an inspection error. File size measures regular and symlink blobs. Gitlinks have no parent-tree blob size, and their contents remain outside the inspected tree.
Dependencies and Markdown convention
Use standard go/format for Go formatting. Its convention follows the Go
standard library used to build ReleaseKit. Use golang.org/x/mod/modfile at
golang.org/x/mod v0.40.0 for complete module-declaration parsing. Use
github.com/yuin/goldmark/v2 v2.1.6 internally for Markdown AST parsing and source
positions. Both selected module manifests support the existing Go 1.25 baseline;
implementation should record their exact source revisions and notices under the
OSS policy. References: modfile
and Goldmark.
PromptKit's current script supplies the starting heading/link examples. Preserve
its basic anchor transformation: lowercase heading text, retain Unicode letters
and numbers, underscore, hyphen, and spaces, then replace spaces with hyphens.
Use visible heading text from the Markdown AST, including inline code text and
excluding HTML tags/formatting delimiters. Support ATX and Setext headings. For
repeated headings, append increasing numeric suffixes starting at -1, selecting
an unused identifier when a generated suffix collides with another heading.
Document these refinements to the starting script's behavior.
Recognize inline links, images, and full/collapsed/shortcut reference links through the parser. Code blocks and inline code supply examples rather than link nodes. Raw HTML destinations remain outside this Markdown-link capability. Undefined references rendered as ordinary text by the parser are not a new Markdown lint rule. Decode Markdown escapes/entities through the parser and percent escapes once when resolving URI path/fragment components. Ignore URI query components for file existence. Empty paths target the source document; an empty fragment selects its top. Schemed and protocol-relative URIs receive no availability request. Fragment checking applies to regular Markdown destinations; other existing files/directories receive existence checking.
Use committed destination resolution and cached parsed documents/anchors. Missing destinations, unresolved cycles, and missing supported anchors fail the selected Markdown check. Actual outside-checkout destinations are reported as out of scope by default and fail with boundary enforcement. Submodule-content observations remain reported as out of scope under either setting: the boundary option concerns checkout escape and does not establish a submodule prohibition. Write nonfailure observations to the supplied output writer; a nil writer selects ordinary quiet library use. Diagnostics identify the source use site, location, and destination. Document source columns as one-based byte columns.
CI tool bootstrap
Build using temporary copies of the released application's go.mod and go.sum,
with Go's alternate -modfile and normal module preparation in those copies.
Confirm that ReleaseKit is already selected before building its command. This
preserves the application's version declaration and require/replace semantics
while allowing missing tool-only indirect requirements/checksums to be prepared
without dirtying immutable tagged source. It supports consumers whose application
imports only lightweight buildinfo. Stages 12–14 implement this agreed approach.
Stage 1: Introduce the specification with race selection
Completion: Complete. ReleaseRequest.Validation.Go.Race and profile
validation.go.race select -race for the single native Go suite. Both
candidate operations share the selection, and race failures retain the go-test
identity without falling back to an ordinary suite.
Outcome: The first public/profile selection changes the one existing suite.
- Add
ReleaseRequest.Validation,ValidationSpec.Go, andGoValidationSpec.Race, plus equivalent CLI-owned JSON settings. Add explicit conversions through both candidate and publication request paths. - Build the base invocation in
internal/validation: preservego test -mod=readonly -count=1 ./..., adding-racewhen selected. Reuse the native Go environment and report tool/prerequisite failures asgo-test. - Preserve additional-check and build ordering. Update exact API/profile references and add a minimal consumer example for the selection.
Verification: Default and selected invocations, exactly one suite, API/profile selection equivalence, both operations, unavailable race prerequisites with no silent fallback, preserved causes/cancellation, and failure before product checks/builds/tag creation. Use a small real race-enabled fixture on supported hosts and a controlled Go command for portable prerequisite-failure coverage.
Stage 2: Coordinate a separate full vet pass
Completion: Complete. ReleaseRequest.Validation.Go.FullVet and profile
validation.go.full_vet disable test-time vet for the one native test suite and
run native go vet -mod=readonly ./... afterward. Vet failures retain the
go-vet identity, and the selection is shared by the API and profile paths.
Outcome: Full vet replaces test-time vet overlap through one declaration.
- Add
Go.FullVetandvalidation.go.full_vetthrough the same conversion path. - When enabled, add
-vet=offto the one test invocation and run nativego vet -mod=readonly ./...afterward using the same tool/environment. - Attribute vet failures to
go-vetand update canonical usage guidance.
Verification: Ordinary, race-only, vet-only, and combined selections; one suite; vet after successful tests; suppression of test-time vet only when selected; failure/cancellation stopping; default behavior and API/profile parity. Protect the selected command relationship without freezing incidental flag order.
Stage 3: Compile packages for selected targets
Completion: Complete. Go.CompileTargets and profile
validation.go.compile_targets select static package compilation after tests
and vet. Failures use package-compile and include the selected target;
artifact building remains separate.
Outcome: Source compatibility checks work independently of artifacts.
- Add
Go.CompileTargetsand string-array profile targets. Convert to internal Go targets and validate complete pairs consistently for API and profile use. - After test/vet, run
go build -mod=readonly -o <os.DevNull> ./...in static mode for each selected target. The Go build null-output mode suppresses executable output, including a module with a single main package. - Report failures as
package-compile, including the selected target. Keep output names, linker version injection, smoke tests, receipts, and manifests in artifact building. Document compilation versus target execution.
Verification: Linux amd64/arm64, a supported additional Go pair, source-only
library, single-main and multiple-main modules (including repeated executable
basenames), target failure, unchanged candidate files, CGO_ENABLED=0, preserved
ordering, and page-only delivery with compilation selected but no build targets.
Reuse the existing Go environment tests for controls already protected there.
Stage 4: Compare the optional expected push URL
Completion: Complete. ReleaseRequest.ExpectedPushURL and profile
expected_push_url require an exact match with Git's resolved effective push
URL before validation. Mismatches return ErrUnexpectedPushURL with expected
and resolved values; Check ignores the publication-only expectation.
Outcome: Publication rejects a different effective destination before validation.
- Add
ExpectedPushURLandexpected_push_url, with an empty value selecting existing behavior. Carry it only into the publication request. - Immediately after resolving/capturing
endpoint.PushURL, compare exact strings. Report expected and resolved values through a publication preflight error. AddErrUnexpectedPushURLas a public sentinel using the existing shared-error ownership pattern so callers can useerrors.Is. - Keep later endpoint rechecks and reconciliation intact. Update GoDoc, publication guidance, and the profile reference.
Verification: Omitted/matching/mismatching values, Git insteadOf resolution,
separate fetch/push URLs, exact spelling differences, mismatch before Go/callbacks
or tag creation, and a local-only Check that ignores the publication expectation.
Existing endpoint-change and uncertain-push tests keep their ownership.
Stage 5: Check committed Go formatting
Completion: Complete. ValidationSpec.GoFormat and profile
validation.go_format run go/format on regular Go blobs from the captured
commit. Findings identify unformatted paths; parser and inspection failures
retain their causes, and the check leaves repository contents unchanged.
Outcome: A declaration replaces tracked-file formatting loops.
- Add
GoFormatandvalidation.go_formatwith working executor integration. - Load the shared captured inventory and apply
format.Sourceto regular.goblobs. Compare original and formatted bytes, preserving repository contents. - Return
go-formatfindings for affected paths and preserve parser/inspection causes. Update usage and formatting-convention documentation.
Verification: Formatted and unformatted files, parse errors, vendor/nested source, unusual filenames, committed versus worktree bytes, disabled/default behavior, API/profile parity, and failure before later product/build work.
Stage 6: Select committed workspace-file inspection
Outcome: One distribution rule works independently of the Go environment.
- Add
ModuleDistributionValidationSpec.WorkspaceFilesand the matching JSON group/field. The remaining rule is added in Stage 7. - Inspect committed blob entries named
go.workorgo.work.sum, including nested and symlink entries. Report paths usingworkspace-files. - Keep testing's existing workspace setting and consumer vendor choices in their current owners. Document the distinction between environment and distribution.
Verification: Either workspace filename, nested paths, symlink names,
committed files with GOWORK=off, uncommitted files excluded from inspection,
selection disabled, and shared API/profile execution. Use meaningful rule cases
rather than retesting Git enumeration mechanics.
Stage 7: Select filesystem replacement inspection
Outcome: The second distribution rule parses actual module declarations.
- Add
ModuleDistribution.LocalReplacementsand the equivalent profile field. Preparegolang.org/x/mod v0.40.0, module sums, and required OSS notices. - Parse committed
go.modfiles withmodfile.Parse, including nested/vendor declarations. Resolve symlink declarations within the candidate; report an inspection error when their selected contents cannot be obtained locally. - Identify filesystem replacements by the parsed replacement's absent version;
permit versioned replacements. Report path, directive/source location, and
target through
local-replacements, preserving parse/inspection causes. - Document independent distribution selections and their inspection scope.
Verification: Single and block directives, comments, quoted paths, relative and absolute filesystem targets, versioned replacements, nested declarations, valid/broken symlinks, parse failure, and all independent boolean combinations. The rule applies to candidate contents even when testing disables workspace use.
Stage 8: Inspect individual committed file sizes
Outcome: Optional limits and intentional path exceptions are operational.
- Add
FileSizeValidationSpec,ValidationSpec.FileSize, and matching JSON fields according to the declaration table. Validate nonnegative byte limits. - Use shared blob sizes for regular files and symlink link-text blobs. Apply
literal file/directory exclusions. On an oversized blob, return
file-sizewith its path and existingFileSizeMeasurementfields; reporting one offending file per failure fits the current diagnostic model. - Document decimal bytes, strict greater-than comparison, exclusions, and current-candidate scope. Preserve default disabled behavior.
Verification: Below/at/above limits, the exact 1,000,000-byte enabled default, zero/custom/negative limits, nil versus empty objects, directory/path boundaries, literal metacharacters, unmatched exclusions, small binaries, symlink sizes, and omitted submodule sizes. Historical and aggregate size do not become release gates.
Stage 9: Implement internal Markdown parsing and anchors
Outcome: A parser with source positions and documented anchor semantics is ready.
- Add
github.com/yuin/goldmark/v2 v2.1.6, prepared dependencies, and applicable OSS notices. Keep parser types inside internal implementation. - Parse links/images, reference uses, headings, and source positions into small internal records. Derive visible heading text and apply the convention above.
- Cache parsed records/anchors per candidate document. Keep this stage internal; Stage 11 adds the public selection once complete checking works.
- Compare fixtures with PromptKit's starting examples. Record intended refinements in the roadmap until the public behavior lands, avoiding a second regex parser.
Verification: Inline/reference forms and images, escaped/parenthesized and angle-bracket destinations, optional titles, code fences/inline code, Unicode/entity headings, ATX/Setext headings, repeated headings and suffix collisions, and source use-site locations including repeated reference uses. Undefined references and HTML prose remain governed by parser interpretation.
Stage 10: Implement internal destination and fragment checking
Outcome: Committed Markdown navigation is checked with boundary observations.
- Resolve parsed local URI components through
CandidateTree.ResolveDestination. Apply escaping/query/fragment rules above and use actual resolved identities for target-document anchor lookup. - Check committed existence and supported heading fragments, recording source
path/location/target. Produce
markdown-linksfailures and distinct nonfailure observations for outside-checkout and submodule contents. - Implement optional checkout-boundary enforcement internally. Preserve the distinction between external URIs, checkout escapes, and uninspected submodules.
- Reuse remediated symlink/cancellation/local-object behavior. Keep parsing, resolution, and rule evaluation in ordinary internal functions.
Verification: Valid/missing files and anchors, same-document/empty fragments, percent-escaped paths and fragments, query strings, directories and non-Markdown files, outside links with both settings, and submodule observations. Check how resolver results and inspection errors become Markdown findings, preserving causes and cancellation. Use representative committed-tree integration cases and verify unchanged candidate/worktree bytes. Existing candidate-tree and Git tests own detailed absolute-path, symlink-parent, cycle, neighboring-file, missing-object, and traversal-cancellation cases.
Stage 11: Expose Markdown selection and complete validation integration
Outcome: All agreed validation selections work through both public operations.
- Add
MarkdownValidationSpec,ValidationSpec.Markdown, and their JSON fields. Enable on a non-nil group/empty object and map the boundary boolean explicitly. - Wire the checker and nonfailure observations into the shared executor/output writer. Reuse existing facade/CLI diagnostic formatting and exit classification.
- Document the newly operational Markdown selection in its canonical owners. Review earlier stages' GoDoc, configuration, check/publish guides, CLI reference, internal inventory, and examples for consistency across combined selections.
- Use self-contained fixtures representing Audita defaults/artifacts, ConfigKit's race/vet/compilation, and PromptKit's shared settings plus example assertions. Document how consumers remove duplicate generic commands when adopting settings.
Verification: Equivalent Go/profile declarations, nil/empty/null Markdown
settings, warnings with successful results, boundary failures before product/build
work, all-zero compatibility, representative combined selections, one suite and
one additional-check callback. Run the compiled API/dependency check, including
buildinfo's standard-library/runtime-only dependency boundary.
Stage 12: Build the CI tool from verified released module configuration
Outcome: The standard template has one tool-version declaration.
- Revise
examples/woodpecker/tag-delivery.ymlinto a compact bootstrap/delivery step. Use available Git to validate/fetch the explicit event tag, compare its peeled commit to the full provider object ID using existing case-insensitive object-ID semantics, check out that commit detached, and confirm HEAD and the existing clean tagged-source requirement. This ensures module files actually belong to the verified release before selecting the tool. Do this before reading/resolving the application module or executing Go. - Apply the agreed CI tool bootstrap approach: create a disposable directory
outside the source checkout, copy its
go.modand existinggo.sum, and use an alternate-modfilefor tool resolution/build. Run from the verified source withGOWORK=offandGOTOOLCHAIN=local. - Confirm the ReleaseKit module is already selected by that module configuration
using
go list -m; then build itscmd/releasekitpackage without an@versionsuffix. Allow ordinary network-capable module preparation in the temporary metadata copies (-mod=mod). Respect selected require/replace relationships. - Invoke the resulting native executable's existing
ci-deliverwith the event repository, commit, and tag. Keep delivery credentials in the existing delivery step and use an exit cleanup trap for temporary metadata and executable files. - Remove the independent
RELEASEKIT_VERSIONworkflow setting. Preserve current Go-image customization, destination/profile ownership, and delivery outcomes. Keep the bootstrap Git block small; the built tool retains its runtime guards.
Verification: Execute maintained template commands with a local tag/module fixture and instrument Go/transport operations. Prove wrong tag/commit stops before module resolution/build, a dirty module cannot select a different tool, the verified checkout selects the tool, module metadata and source remain unchanged, and the executable/temporary files are cleaned up. Tool metadata preparation is separate from offline candidate checks. Include a representative case that verifies invocation of the selected executable with the event arguments and propagation of its exit status. Existing delivery tests own hosted behavior.
Stage 13: Verify upgrades, retries, and bootstrap variants
Outcome: Tool selection follows the triggering release across supported uses.
- Extend Stage 12's bootstrap fixtures with a local module proxy for two tool versions and tagged consumer module configurations. Execute the maintained workflow body against both. Keep live infrastructure outside the default test suite.
- Verify a retry of an older tag still selects that tag's module configuration when the default branch has upgraded. Include missing tool-only checksums and an existing versioned replacement to protect source-based resolution.
- Align
releasekit-source-delivery.ymlwith source verification before self bootstrap and temporary output. Preserve self-bootstrap from./cmd/releasekitand separately installed-tool guidance using the existing command. - Update delivery/configuration/CLI guidance and maintained templates together. Explain compatible Go environments, dependency preparation, immutable-source retries, and the distinct tool/app artifact preparation steps.
Verification: Two dependency versions, older-source retries, self bootstrap, and separately installed tool, using the shared bootstrap fixtures. Existing delivery and publication tests retain ownership of source-only pages, binary delivery, destination handling, and publication states. Add integration coverage for any new interaction introduced by bootstrap changes. An application without a declared ReleaseKit dependency uses the installed-tool integration.
Stage 14: Migrate Audita's local CI integration
Outcome: Audita's local wrapper and CI select the same module-declared tool.
- Read
../auditaorientation/policies and inspect its worktree before editing. Adapt.woodpecker/release.ymlto the maintained module-based template, preserving its Go image, Gitea secret name, and release profile. - Retain its existing released ReleaseKit module selection for this migration;
that version already supplies
ci-deliver. Make any necessary adjustments toscripts/release.shfor the selected bootstrap metadata approach, preserving arguments and native executable exit behavior. Keep generated tool output outside the candidate source where needed. - Verify the consumer's actual wrapper/workflow using local tagged fixtures and prepared module caches. Confirm matching tool selection, preserved arguments and exit status, and unchanged source files. Review the diff for preservation of the release profile and binary targets. Existing consumer and ReleaseKit tests retain ownership of source validation and hosted delivery behavior.
- Commit the focused migration in Audita with a plain English message. Record its commit and local verification in this plan's implementation status.
Verification: The actual adapted consumer declarations use one dependency version; local and CI bootstraps agree and retain existing caller arguments/status semantics. Keep integration fixtures self-contained in ReleaseKit's default suite. This migration uses an existing release and requires no intermediate publication or live Woodpecker/Gitea run to complete the stage.
Stage 15: Audit the completed v0.2.0 implementation
Outcome: The entire scoped feature set is implemented and locally verified.
- Match every row in the roadmap/stage table to implemented settings, execution, diagnostics, current documentation, and focused behavioral evidence. Verify all-zero compatibility, independent distribution choices, one coordinated Go suite, source-only compilation/delivery, and selected endpoint preflight.
- Review new code and tests for unintended defaults, restrictions, caps, or stronger guarantees. Preserve user choice and the existing facade boundaries.
- Run
go test ./...andgo run ./internal/apicheck. Add further integration coverage only for a concrete remaining risk. Check documentation links, fragments, whitespace, dependency notices, and maintained examples. - Update statuses in this plan, the release roadmap, and the model roadmap to reflect actual completion, including the Audita migration evidence. Update canonical current-behavior owners as needed and remove stale prospective text.
- Commit the completed unit, report each stage's outcome and remaining work, and finish with a clean workspace while preserving any unrelated user changes. The subsequent architecture review and release/testing decisions follow here.
Open Questions
None.