Skip to content

Commit ec3399e

Browse files
committed
Prepare development package identity and defer product release
1 parent c241575 commit ec3399e

12 files changed

Lines changed: 109 additions & 15 deletions

File tree

‎.github/workflows/release.yml‎

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ jobs:
1818
timeout-minutes: 10
1919
outputs:
2020
version: ${{ steps.reserve.outputs.version }}
21+
package_version: ${{ steps.reserve.outputs.package_version }}
2122
tag: ${{ steps.reserve.outputs.tag }}
2223
assembly_version: ${{ steps.reserve.outputs.assembly_version }}
2324
file_version: ${{ steps.reserve.outputs.file_version }}
@@ -66,6 +67,7 @@ jobs:
6667
timeout-minutes: 60
6768
env:
6869
RELEASE_VERSION: ${{ needs.version.outputs.version }}
70+
RELEASE_PACKAGE_VERSION: ${{ needs.version.outputs.package_version }}
6971
RELEASE_ASSEMBLY_VERSION: ${{ needs.version.outputs.assembly_version }}
7072
RELEASE_FILE_VERSION: ${{ needs.version.outputs.file_version }}
7173
steps:
@@ -99,13 +101,13 @@ jobs:
99101
run: |
100102
node scripts/Features/RepositoryGovernance/verify.mjs
101103
dotnet restore KeyLoad.slnx
102-
dotnet build KeyLoad.slnx --no-restore --configuration Release -p:Version="$RELEASE_VERSION" -p:AssemblyVersion="$RELEASE_ASSEMBLY_VERSION" -p:FileVersion="$RELEASE_FILE_VERSION"
104+
dotnet build KeyLoad.slnx --no-restore --configuration Release -p:Version="$RELEASE_VERSION" -p:PackageVersion="$RELEASE_PACKAGE_VERSION" -p:AssemblyVersion="$RELEASE_ASSEMBLY_VERSION" -p:FileVersion="$RELEASE_FILE_VERSION"
103105
dotnet format KeyLoad.slnx --verify-no-changes --no-restore
104106
- name: Build all NuGet packages and the Linux x64 RF3 database distribution
105107
if: env.RELEASE_ASSETS_EXISTS == '0'
106108
shell: bash
107109
run: |
108-
args=(-p:Version="$RELEASE_VERSION" -p:AssemblyVersion="$RELEASE_ASSEMBLY_VERSION" -p:FileVersion="$RELEASE_FILE_VERSION")
110+
args=(-p:Version="$RELEASE_VERSION" -p:PackageVersion="$RELEASE_PACKAGE_VERSION" -p:AssemblyVersion="$RELEASE_ASSEMBLY_VERSION" -p:FileVersion="$RELEASE_FILE_VERSION")
109111
dotnet pack KeyLoad.slnx --no-build --no-restore --configuration Release "${args[@]}" --output artifacts/assets
110112
dotnet publish src/KeyLoad.Server/KeyLoad.Server.csproj --configuration Release --runtime linux-x64 --self-contained true "${args[@]}" --output artifacts/distribution/server
111113
dotnet publish src/KeyLoad.Cli/KeyLoad.Cli.csproj --configuration Release --runtime linux-x64 --self-contained true "${args[@]}" --output artifacts/distribution/cli
@@ -136,6 +138,7 @@ jobs:
136138
(cd artifacts/assets && sha256sum --check SHA256SUMS)
137139
fi
138140
python3 scripts/Features/ReleaseDelivery/release-assets.py --reservation=artifacts/reservation/release-version.json --assets=artifacts/assets --images=artifacts/images.json
141+
jq -e --arg expected "$RELEASE_PACKAGE_VERSION" '.packageVersion == $expected' artifacts/assets/release-manifest.json
139142
- name: Retain immutable release packages, distribution and image exports
140143
if: env.RELEASE_ASSETS_EXISTS == '0'
141144
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1

‎AGENTS.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,7 @@ For changes outside existing owner authorization, obtain direction before changi
414414
- Repeated permission questions for already authorized work.
415415
- GitHub Actions MUST expose exactly three plainly named workflows: CI combines build and ordinary project tests for PR/push/manual checks; Benchmarks runs all load/comparison suites, produces complete authenticated measurements and then qualifies/publishes the website; Release builds the solution, real database images/distribution and packages, then creates a GitHub Release and immutable version tag. Do not split Tests or Website into additional workflows (explicit owner correction 2026-10-03 supersedes the earlier five-workflow layout).
416416
- Release tags MUST be `v<major>.<minor>.<yyMMdd>.<daily-build>`: major/minor are configured in source, the third component is the UTC date and the fourth starts at 1 each day and increases without tag reuse or overwrite. Build/package/image/manifest identities MUST agree; reruns recover their original reservation. Release automation is authorized to create the corresponding Git tag, GitHub Release and versioned database image/package assets; preserve protections and qualification gates (owner direction 2026-10-03).
417+
- KeyLoad product release packaging and publication are deferred until the owner explicitly requests a release or confirms product readiness. Keep Release prepared and manual; do not dispatch package/image builds, create release tags or publish releases merely to prove this workflow while the product is unfinished (owner correction 2026-10-03).
417418
- Repository-rule checks MUST always run inside the standard CI pipeline, never as a separate governance workflow (owner correction 2026-10-03).
418419
- All comparative performance tests, including TimeSeries image checks, MUST run in one separate Benchmarks pipeline; do not name it Comparisons or create feature-specific comparison workflows. Preserve isolated Linux runners, real native topology, complete workloads and authenticated artifacts (owner clarification 2026-10-03).
419420
- Fake production readiness, power-loss claims from process-kill tests, or unsupported performance supremacy.

‎docs/ADR/ADR-064-three-pipeline-release-delivery.md‎

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
Status: Accepted. Date: 2026-10-03. Owner: KeyLoad lead/integrator.
44
Requirements/acceptance: REQ/AC-PIPE-001..004 and REQ/AC-REL-001..003.
55
Supersedes ADR-062's five-workflow placement under explicit owner direction.
6+
The later owner correction defers actual Release packaging/publication until product
7+
readiness or an explicit release request; retain this implementation contract for
8+
the prepared manual workflow. Provider qualification remains deferred.
69

710
## Decision and implementation contract
811

@@ -47,7 +50,10 @@ flowchart TD
4750
date/run/source/version in an immutable same-run artifact. Daily N starts at 1,
4851
is >= actual daily run ordinal and > existing dated tag counters. Reruns recover
4952
the exact reservation; malformed/foreign/colliding/exhausted identity fails.
50-
Package/informational/image/tag use M.m.yyMMdd.N; CLR versions use M.m.0.0 and
53+
Informational/image/tag use M.m.yyMMdd.N. NuGet retains the configured source
54+
development stage as M.m.yyMMdd.N-dev, because the existing third-party Cartograph
55+
dependency is alpha-only; do not suppress NU5104 or pretend it is stable. Freeze
56+
this derived package version in the reservation and inspect real nuspecs. CLR versions use M.m.0.0 and
5157
M.m.0.N so components remain <=65534. Never edit source version to count builds.
5258
6. Read-only build restores/builds/formats/governs full source, packs actual projects,
5359
publishes Linux x64 server distribution, builds/exports existing server and

‎docs/Features/ReleaseDelivery.md‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,15 @@ frozen to the authenticated release run. Example: `v0.1.261003.1` for the curren
88
have smaller bounds, so use stable `M.m.0.0` / `M.m.0.N` and full informational
99
version ([NuGet](https://learn.microsoft.com/en-us/nuget/concepts/package-versioning),
1010
[CLR metadata](https://learn.microsoft.com/en-us/dotnet/api/system.reflection.assemblyversionattribute)).
11+
NuGet packages retain the current source's development stage as `M.m.yyMMdd.N-dev`;
12+
tag, image and informational versions retain the requested four numeric components.
13+
This keeps the alpha-only Cartograph dependency visible and respects
14+
[NU5104](https://learn.microsoft.com/en-us/nuget/reference/errors-and-warnings/nu5104)
15+
without suppressing diagnostics or claiming stable packages.
16+
17+
The owner subsequently deferred packaging because the product is unfinished.
18+
Release remains manual and prepared for a later explicit release/readiness request;
19+
current workflow implementation and CI checks do not authorize dispatch or publication.
1120

1221
Requirements/acceptance are REQ/AC-PIPE-001..004 and REQ/AC-REL-001..003 in the
1322
[acceptance matrix](../implementation/pipeline-release-v2-acceptance.md).

‎docs/implementation/pipeline-release-v2-acceptance.md‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,12 @@ Benchmarks; a manual own-main Release can reserve/build, with write privileges o
1313
at publication. UTC is the daily counter boundary; configured source major/minor
1414
remain owner controlled. All qualification executes in Linux GitHub Actions.
1515

16+
Owner correction 2026-10-03: the product is not ready for packaging. Current scope
17+
is the prepared three-pipeline implementation and CI verification. Actual Release
18+
dispatch, package/image builds, tag creation and provider publication are deferred
19+
until a later explicit release/readiness instruction. Retain the future release
20+
requirements and report their provider qualification as deferred, never passing.
21+
1622
- AC-PIPE-001 / REQ-PIPE-001: exactly ci.yml, benchmarks.yml and release.yml remain;
1723
names are CI, Benchmarks and Release. CI runs push(main), pull_request and manual;
1824
preserve full build/format/rules/analyzer/unit/scalar/recovery/real SDK/MCP RF3.
@@ -42,6 +48,10 @@ remain owner controlled. All qualification executes in Linux GitHub Actions.
4248
Check nonempty files, embedded package versions, hashes, image digest/labels and
4349
source/run provenance before publication. CLR version mapping remains bounded;
4450
package/informational/image/git identities retain the complete owner version.
51+
Preserve the source's `dev` package stage: NuGet versions append `-dev` to the
52+
same four numeric components; git tags and image versions retain the exact
53+
requested numeric format. Inspect this derived package version in reservation,
54+
nuspecs and manifest. Never suppress NU5104 or hide alpha dependencies.
4555
- AC-REL-003 / REQ-REL-003: final publication authenticates successful exact-source
4656
CI and owned build artifacts, pushes immutable versioned GHCR image(s), creates
4757
source-bound annotated git tag and GitHub Release with real database/package/

‎docs/implementation/pipeline-release-v2-execution.md‎

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ three-pipeline/public-release correction; existing required gates remain mandato
1111
| TASK-REL-TOOLS | REL-001/002/003 | capable script worker | scripts/Features/ReleaseDelivery helpers only | approved feature/ADR | syntax, actual source outputs through GitHub; no local tests |
1212
| TASK-PIPE-TESTS | PIPE-001/002/004, REL-001/002 | capable C# worker | named workflow tests and new Features/ReleaseDelivery TUnit files | approved contracts | compiled unit/source/version cases in CI; no local tests |
1313
| TASK-PIPE-LEAD | all | lead | workflows, central version, policies/docs, RF3 release distribution, source closure, delivery | serialized integration | inspect all diffs, static checks, scoped commit/push, GitHub evidence |
14+
| TASK-REL-PACK-STAGE | REL-001/002 | script worker | version/CLI/context/asset helpers only | real run37116935776 NU5104; amended package-stage contract | freeze derived -dev package version; no suppression or local tests; lead owns workflow |
15+
| TASK-REL-PACK-TEST | REL-001/002 | C# worker | ReleaseDelivery TUnit and role tests only | amended package-stage contract and agreed schema | real tool positive/tamper/retry assertions; GitHub CI |
1416

1517
- [x] Read policies/architecture; record exact owner correction first.
1618
- [x] Read-only parallel provenance/release discovery and explicit safe write scopes.
@@ -28,6 +30,15 @@ three-pipeline/public-release correction; existing required gates remain mandato
2830
gated by genuine successful exact-source CI; no duplicated full qualification.
2931
- [ ] Verify actual tag/GitHub Release/GHCR only when all required gates pass; retain
3032
exact blockers otherwise and never claim packaging or configuration is release.
33+
- [ ] Repair stable-package NU5104 from alpha-only Cartograph by preserving the
34+
source's `dev` package stage with the same numeric identity; verify reservation,
35+
actual nuspecs and checksums in GitHub without altering the exact git tag format.
36+
37+
Owner correction: actual packaging/publication is now deferred because the product
38+
is unfinished. Do not dispatch another Release. Version/package-stage helpers,
39+
workflow and TUnit checks remain prepared; future package/image/provider checks
40+
above remain unchecked until a later explicit release/readiness request. All prior
41+
Release runs are already completed; no active Release needs cancellation.
3142

3243
Baseline: earlier milestone CI/release build passes, all four layout and183 recovery
3344
cases pass. Full units fail one existing SDK-status assertion; RF3 fails one SQL
@@ -40,3 +51,29 @@ Joined static review: all original eight benchmark job objects and all ordinary
4051
test job commands are preserved; exact three workflow YAMLs and composite shell
4152
syntax pass. Current shared governance validates26 projects; the scoped delivered
4253
source will be checked independently because unrelated diagnostics remain uncommitted.
54+
55+
Delivered checkpoints: e050b5e3213ccc007622092587c35fd0a0bbf378 contains the three
56+
pipelines; e089f3ccc77460c0fc6610581025b57651eac96a fixes the new test compiler
57+
errors and authenticates the latest exact-source CI. GitHub reports exactly three
58+
active workflows (CI372183043, Benchmarks373808964, Release373808965).
59+
60+
Exact e089 verification: [Release37116935776](https://github.com/managedcode/KeyLoad/actions/runs/37116935776)
61+
reserved `v0.1.261003.3` in immutable artifact11271662391
62+
(`sha256:5c1f33584b6784c4418b70e6ca5edcdac995a25f781e39d64ab503174ce376e7`).
63+
Job111185484820 passed complete solution build (zero warnings/errors), formatter
64+
and governance, then failed NU5104: third-party Cartograph/Catalog0.1.0-alpha cannot
65+
be dependencies of stable NuGet packages. Publication was skipped. No stable
66+
Cartograph version exists in its authenticated feed inventory; upstream publishing
67+
access is unavailable. The bounded repair preserves the existing source `dev` stage
68+
in NuGet only, freezes schema2/packageVersion and validates actual nuspecs/manifest;
69+
the requested numeric tag/image format is unchanged. Static syntax, all65 workflow
70+
bash blocks and26-project governance pass; real packaging remains to be rerun.
71+
72+
[Benchmarks37116893060](https://github.com/managedcode/KeyLoad/actions/runs/37116893060)
73+
passed full build/format/rules, image round-trip1/1, current-job identity1/1 and real
74+
pinned Timescale image1/1. Native model job111186389331 failed4 of98 existing cases
75+
because the image tag is represented in the pinned image string, while tests read
76+
the empty separate Tag field. All remaining cells, aggregate and site publication
77+
were correctly skipped. The separately delivered c2415755d source contains that
78+
assertion repair; it has not been called qualified here. e089 CI37116893088 is still
79+
running at this checkpoint; no full CI/release/site success is claimed.

‎scripts/Features/ReleaseDelivery/release-assets.py‎

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -72,9 +72,9 @@ def read_json(path, maximum):
7272

7373
def validate_reservation(value):
7474
keys = {"schemaVersion", "repository", "sourceRevision", "runId", "baseVersion", "major", "minor", "date",
75-
"sequence", "version", "tag", "assemblyVersion", "fileVersion"}
75+
"sequence", "version", "packageVersion", "tag", "assemblyVersion", "fileVersion"}
7676
if not is_plain_object(value) or set(value) != keys or type(value["schemaVersion"]) is not int \
77-
or value["schemaVersion"] != 1 or value["repository"] != REPOSITORY:
77+
or value["schemaVersion"] != 2 or value["repository"] != REPOSITORY:
7878
fail("Release reservation has an unsupported shape or repository.")
7979
if not isinstance(value["sourceRevision"], str) or not re.fullmatch(r"[a-f0-9]{40}", value["sourceRevision"]):
8080
fail("Release reservation source revision is invalid.")
@@ -97,7 +97,7 @@ def validate_reservation(value):
9797
if parsed.strftime("%y%m%d") != value["date"]:
9898
fail("Release reservation UTC date is not canonical.")
9999
version = f"{major}.{minor}.{value['date']}.{sequence}"
100-
expected = {"major": major, "minor": minor, "version": version, "tag": f"v{version}",
100+
expected = {"major": major, "minor": minor, "version": version, "packageVersion": f"{version}-dev", "tag": f"v{version}",
101101
"assemblyVersion": f"{major}.{minor}.0.0", "fileVersion": f"{major}.{minor}.0.{sequence}"}
102102
if any(value[key] != expectedValue for key, expectedValue in expected.items()):
103103
fail("Release reservation derived version fields do not agree.")
@@ -331,9 +331,9 @@ def write_immutable(path, content):
331331

332332

333333
def build_manifest(reservation, packages, database, images):
334-
return {"schemaVersion": 1, "repository": REPOSITORY, "sourceRevision": reservation["sourceRevision"],
334+
return {"schemaVersion": 2, "repository": REPOSITORY, "sourceRevision": reservation["sourceRevision"],
335335
"runId": reservation["runId"], "baseVersion": reservation["baseVersion"],
336-
"version": reservation["version"], "tag": reservation["tag"],
336+
"version": reservation["version"], "packageVersion": reservation["packageVersion"], "tag": reservation["tag"],
337337
"assemblyVersion": reservation["assemblyVersion"], "fileVersion": reservation["fileVersion"],
338338
"packages": packages, "database": database, "images": images}
339339

@@ -363,7 +363,7 @@ def main():
363363
f"keyload-server-{version}-linux-amd64.docker.tar.gz",
364364
f"keyload-benchmarks-{version}-linux-amd64.docker.tar.gz"}
365365
validate_asset_directory(asset_root, expected)
366-
packages = [read_package(item, version) for item in package_paths]
366+
packages = [read_package(item, reservation["packageVersion"]) for item in package_paths]
367367
if len({item["id"].casefold() for item in packages}) != len(packages):
368368
fail("NuGet package ids must be unique within the release.")
369369
database = verify_database_distribution(database_path, reservation)

‎scripts/Features/ReleaseDelivery/release-version-cli.mjs‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,11 @@ const INPUT_KEYS = Object.freeze(['baseVersion', 'sourceRevision', 'runId', 'utc
88
const ENV_VALUES = Object.freeze([
99
['RELEASE_VERSION', 'version'], ['RELEASE_TAG', 'tag'],
1010
['RELEASE_ASSEMBLY_VERSION', 'assemblyVersion'], ['RELEASE_FILE_VERSION', 'fileVersion'],
11+
['RELEASE_PACKAGE_VERSION', 'packageVersion'],
1112
]);
1213
const OUTPUT_VALUES = Object.freeze([
1314
['version', 'version'], ['tag', 'tag'], ['assembly_version', 'assemblyVersion'], ['file_version', 'fileVersion'],
15+
['package_version', 'packageVersion'],
1416
]);
1517

1618
function fail(message) { throw new Error(message); }

‎scripts/Features/ReleaseDelivery/release-version.mjs‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
const RELEASE_REPOSITORY = 'managedcode/KeyLoad';
2-
const SCHEMA_VERSION = 1;
2+
const SCHEMA_VERSION = 2;
33
const MAX_VERSION_COMPONENT = 65534;
44
const MAX_INVENTORY_ITEMS = 10000;
55
const RESERVATION_KEYS = Object.freeze(['schemaVersion', 'repository', 'sourceRevision', 'runId', 'baseVersion',
6-
'major', 'minor', 'date', 'sequence', 'version', 'tag', 'assemblyVersion', 'fileVersion']);
6+
'major', 'minor', 'date', 'sequence', 'version', 'packageVersion', 'tag', 'assemblyVersion', 'fileVersion']);
77

88
export const RELEASE_VERSION_ERRORS = Object.freeze({
99
input: 'E_RELEASE_INPUT', date: 'E_RELEASE_DATE', dailyRuns: 'E_RELEASE_DAILY_RUNS', tags: 'E_RELEASE_TAGS',
@@ -101,7 +101,7 @@ function makeReservation({ baseVersion, sourceRevision, runId, major, minor, dat
101101
const version = `${major}.${minor}.${date}.${sequence}`;
102102
return {
103103
schemaVersion: SCHEMA_VERSION, repository: RELEASE_REPOSITORY, sourceRevision, runId, baseVersion,
104-
major, minor, date, sequence, version, tag: `v${version}`,
104+
major, minor, date, sequence, version, packageVersion: `${version}-dev`, tag: `v${version}`,
105105
assemblyVersion: `${major}.${minor}.0.0`, fileVersion: `${major}.${minor}.0.${sequence}`,
106106
};
107107
}

‎tests/KeyLoad.UnitTests/Features/ReleaseDelivery/ReleaseVersionFields.cs‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ internal static class ReleaseVersionFields
1717
internal const string Repository = "repository";
1818
internal const string Date = "date";
1919
internal const string Sequence = "sequence";
20+
internal const string PackageVersion = "packageVersion";
2021
internal const string Foreign = "foreign";
2122
internal const string Id = "id";
2223
internal const string RunNumber = "run_number";

0 commit comments

Comments
 (0)