Repository navigation
Prepare cross-registry CLI/LSP packages, PGO artifacts, and gated publication workflows #471
Description
Activity
- addedenhancementNew feature or requestNew feature or requesthuman-discussionPeople are still discussing this; no machine lays work on it until the label comes offPeople are still discussing this; no machine lays work on it until the label comes offand removedhuman-discussionPeople are still discussing this; no machine lays work on it until the label comes offPeople are still discussing this; no machine lays work on it until the label comes off
on Oct 5, 2026 Claimed by
vjovanov@kung-fu-workstationon 2026-10-05 23:54Z · released on 2026-10-09 10:39Z (completed).Record · 52 transitions · now
completed· last 2026-10-09 09:49Z
Holdervjovanov@kung-fu-workstation· since 2026-10-05 23:54Z1 · supervising → supervising 2026-10-05 23:56Z · `PATH: planned`
plan
runtime/supervision/plan.md(not shown; this comment is at its size limit)decision
runtime/supervision/decision.md(not shown; this comment is at its size limit)2 · ticket.triage · intake → triage 2026-10-05 23:56Z
ticket
runtime/ticket/github-issues-agent-grounds-grund-471-implement-454b7621.ticket.triage.json(not shown; this comment is at its size limit)3 · ticket.triage · triage → assessing 2026-10-05 23:56Z
candidates
runtime/triage/github-issues-agent-grounds-grund-471-implement-454b7621.ticket.triage.candidates.md(not shown; this comment is at its size limit)4 · ticket.triage · assessing → route-assessment 2026-10-06 00:00Z · `VERDICT: none`
verdict
runtime/triage/github-issues-agent-grounds-grund-471-implement-454b7621.ticket.triage.verdict.md(not shown; this comment is at its size limit)5 · ticket.triage · route-assessment → validating 2026-10-06 00:00Z
6 · ticket.triage · validating → fitting 2026-10-06 00:00Z
7 · ticket.triage · fitting → route-fit 2026-10-06 00:05Z · `FIT: fits` · `SIZE: complex`
fit
runtime/triage/github-issues-agent-grounds-grund-471-implement-454b7621.ticket.triage.fit.md(not shown; this comment is at its size limit)8 · ticket.triage · route-fit → validated 2026-10-06 00:05Z
9 · ticket.triage · validated → completed 2026-10-06 00:06Z
validation
runtime/exports/github-issues-agent-grounds-grund-471-implement-454b7621.ticket.triage/validation.md(not shown; this comment is at its size limit)10 · ticket.agora · agora → cancelled
11 · supervising → supervising 2026-10-05 23:56Z
12 · ticket.clarify · clarifying → asking 2026-10-06 00:10Z · `QUESTIONS: ready`
questions
runtime/clarify/questions-1.mdAfter this work, a rehearsal could produce a local tarball for
npm install --global ./candidate/grund-cli-X.Y.Z.tgz, then exercise the installedgrundcommand without publishing anything (filename illustrative). Today there is no such npm package assembly here. Two facts remain open before proposing that packaging and its future publication workflows; neither question requests permission to release.-
Does the no-publication-on-merge boundary include the existing scheduled Cargo publisher? For example, after this PR changes
scripts/, Monday'sauto-bump.ymlcan count those paths as substantive, validate a patch candidate, and dispatchrelease.ymlwith Cargo publication and GitHub release creation enabled. Answer “include scheduled Cargo” and the proposal must hold automatic publication of a candidate containing this work until a separate operator decision; answer “new publication lane only” and existing scheduled Cargo policy continues, while the new cross-registry publisher remains disabled. The current helper contract explicitly includes live dispatch (§FS-distribution.4.4).Why needed: These readings require different workflow scope, and neither permission to release nor a change to existing Cargo policy can be inferred from the ticket.
Assumption without an answer: Rehearsal stays separate and the new publisher stays disabled; the existing scheduled-Cargo interaction remains unresolved, with implementation and merge held pending your answer. No release or permanent disabling of Cargo automation is authorized.
… cut at 3000 characters; the whole file is runtime/clarify/questions-1.md
questions
runtime/clarify/questions-2.mdnpm install --global ./candidate/grund-cli-X.Y.Z.tgz(illustrative filename) is the local-install rehearsal this ticket will prepare; today this checkout has no such npm package assembly. The author's answer settles both open matters, so no further clarification is needed before proposing the change. The proposal will preserve the weekly Cargo patch path, which may ship this change through Cargo and a GitHub release, while keeping new npm/PyPI publication unreachable from that path and disabled pending separate operator authorization. Names for both npm platform families remain provisional; npm/PyPI authority and account setup remain unmet prerequisites, with no established signing/notarization identities or existing publication obligations. The assumptions carried into planning are that rehearsal is credential-free and publishes nothing; the current crates.io identity guard remains intact; account, secret and protection changes stay outside this ticket; and technical choices about support, ABI, PGO, provenance and gates are recommendations for proposal review. Full native parity still depends on #469/#470, and this ticket stays outside #347's 1.0 gate. These answers settle scope and owner facts; implementation still requires an approved proposal, and completing this ticket authorizes no release action.QUESTIONS: none
questions
runtime/clarify/questions.mdnpm install --global ./candidate/grund-cli-X.Y.Z.tgz(illustrative filename) is the local-install rehearsal this ticket will prepare; today this checkout has no such npm package assembly. The author's answer settles both open matters, so no further clarification is needed before proposing the change. The proposal will preserve the weekly Cargo patch path, which may ship this change through Cargo and a GitHub release, while keeping new npm/PyPI publication unreachable from that path and disabled pending separate operator authorization. Names for both npm platform families remain provisional; npm/PyPI authority and account setup remain unmet prerequisites, with no established signing/notarization identities or existing publication obligations. The assumptions carried into planning are that rehearsal is credential-free and publishes nothing; the current crates.io identity guard remains intact; account, secret and protection changes stay outside this ticket; and technical choices about support, ABI, PGO, provenance and gates are recommendations for proposal review. Full native parity still depends on #469/#470, and this ticket stays outside #347's 1.0 gate. These answers settle scope and owner facts; implementation still requires an approved proposal, and completing this ticket authorizes no release action.QUESTIONS: none
13 · ticket.clarify · asking → clarifying 2026-10-06 00:10Z · `CLARIFICATION: answered`
answers
runtime/clarify/answers.mdQuestions and answers on #471
Round 1 of 2
Asked at: #471 (comment)
After this work, a rehearsal could produce a local tarball for
npm install --global ./candidate/grund-cli-X.Y.Z.tgz, then exercise the installedgrundcommand without publishing anything (filename illustrative). Today there is no such npm package assembly here. Two facts remain open before proposing that packaging and its future publication workflows; neither question requests permission to release.-
Does the no-publication-on-merge boundary include the existing scheduled Cargo publisher? For example, after this PR changes
scripts/, Monday'sauto-bump.ymlcan count those paths as substantive, validate a patch candidate, and dispatchrelease.ymlwith Cargo publication and GitHub release creation enabled. Answer “include scheduled Cargo” and the proposal must hold automatic publication of a candidate containing this work until a separate operator decision; answer “new publication lane only” and existing scheduled Cargo policy continues, while the new cross-registry publisher remains disabled. The current helper contract explicitly includes live dispatch (§FS-distribution.4.4).Why needed: These readings require different workflow scope, and neither permission to release nor a change to existing Cargo policy can be inferred from the ticket.
Assumption without an answer: Rehearsal stays separate and the new publisher stays disabled; the existing scheduled-Cargo interaction remains unresolved, with implementation and merge held pending your answer. No release or permanent disabling of Cargo automation is authorized.
… cut at 3000 characters; the whole file is runtime/clarify/answers.md
clarification
runtime/exports/github-issues-agent-grounds-grund-471-implement-454b7621.ticket.clarify/clarification.mdClarification of #471
CLARIFICATION: answered
Questions and answers on #471
Round 1 of 2
Asked at: #471 (comment)
After this work, a rehearsal could produce a local tarball for
npm install --global ./candidate/grund-cli-X.Y.Z.tgz, then exercise the installedgrundcommand without publishing anything (filename illustrative). Today there is no such npm package assembly here. Two facts remain open before proposing that packaging and its future publication workflows; neither question requests permission to release.-
Does the no-publication-on-merge boundary include the existing scheduled Cargo publisher? For example, after this PR changes
scripts/, Monday'sauto-bump.ymlcan count those paths as substantive, validate a patch candidate, and dispatchrelease.ymlwith Cargo publication and GitHub release creation enabled. Answer “include scheduled Cargo” and the proposal must hold automatic publication of a candidate containing this work until a separate operator decision; answer “new publication lane only” and existing scheduled Cargo policy continues, while the new cross-registry publisher remains disabled. The current helper contract explicitly includes live dispatch (§FS-distribution.4.4).Why needed: These readings require different workflow scope, and neither permission to release nor a change to existing Cargo policy can be inferred from the ticket.
Assumption without an answer: Rehearsal stays separate and the new publisher stays disabled; the existing scheduled-Cargo interaction remains unresolved, with implementation and merge held pending your answer. No release or permanent disabling of Cargo automation is authorized.
… cut at 3000 characters; the whole file is runtime/exports/github-issues-agent-grounds-grund-471-implement-454b7621.ticket.clarify/clarification.md
14 · ticket.clarify · clarifying → asking 2026-10-06 00:10Z
15 · ticket.clarify · asking → completed 2026-10-06 00:10Z
16 · supervising → supervising 2026-10-05 23:56Z
17 · ticket.plan · planning → discussing 2026-10-06 00:33Z
proposal
runtime/plan/proposal-1.md1. What changes
After the rehearsal starts its local, read-only npm registry:
# X.Y.Z is the candidate version; the filename is illustrative. npm install -g --registry=http://127.0.0.1:4873 ./candidate/grund-cli-X.Y.Z.tgz grund check --format=json tests/e2e/cases/json-report/repoToday this checkout cannot produce that tarball. Afterwards it installs without Rust and emits the existing
danglingJSON finding, empty stderr and exit1. Python gets the same command plusimport grund; editors get independently installedgrund-lsp. This delivers local candidates and a disabled publisher; registry versions remain unpublished.2. Design and choices
A shared artifact builder extends
scripts/pgo-build.sh, registry guards and version tooling, reusing real CLI/server binaries and #469/#470's modules, loaders and fixtures. Assembly realizes §AR-bindings.5 and §AR-bindings.6, preserving engine logic and frontend isolation (§AR-bindings.1).Recommend Node 22.x/24.x, N-API 8 (ABI contract) and ordinary CPython 3.10–3.14, per-interpreter wheels (cibuildwheel support). Coordinate these proposals with #469/#470; neither has approved them. Defer
abi3, free-threaded Python, PyPy, musl and other architectures.OS / payload floor Rust target npm suffix, both families Wheel platform Installed-artifact runner Linux x64 / glibc 2.17 x86_64-unknown-linux-gnulinux-x64-gnumanylinux2014_x86_64ubuntu-latest, pinned manylinux containerLinux arm64 / glibc 2.17 aarch64-unknown-linux-gnulinux-arm64-gnumanylinux2014_aarch64ubuntu-24.04-arm, pinned manylinux containermacOS x64 / 11.0 x86_64-apple-darwindarwin-x64macosx_11_0_x86_64macos-15-intelmacOS arm64 / 11.0 aarch64-apple-darwindarwin-arm64macosx_11_0_arm64macos-15Windows x64 / Windows 10, MSVC 14 runtime x86_64-pc-windows-msvcwin32-x64-msvcwin_amd64windows-latestWindows arm64 / Windows 11, MSVC 14 runtime aarch64-pc-windows-msvcdeferred deferred windows-11-arm: downloadable binaries only… cut at 3000 characters; the whole file is runtime/plan/proposal-1.md
proposal
runtime/plan/proposal.md1. What changes
After the rehearsal starts its local, read-only npm registry:
# X.Y.Z is the candidate version; the filename is illustrative. npm install -g --registry=http://127.0.0.1:4873 ./candidate/grund-cli-X.Y.Z.tgz grund check --format=json tests/e2e/cases/json-report/repoToday this checkout cannot produce that tarball. Afterwards it installs without Rust and emits the existing
danglingJSON finding, empty stderr and exit1. Python gets the same command plusimport grund; editors get independently installedgrund-lsp. This delivers local candidates and a disabled publisher; registry versions remain unpublished.2. Design and choices
A shared artifact builder extends
scripts/pgo-build.sh, registry guards and version tooling, reusing real CLI/server binaries and #469/#470's modules, loaders and fixtures. Assembly realizes §AR-bindings.5 and §AR-bindings.6, preserving engine logic and frontend isolation (§AR-bindings.1).Recommend Node 22.x/24.x, N-API 8 (ABI contract) and ordinary CPython 3.10–3.14, per-interpreter wheels (cibuildwheel support). Coordinate these proposals with #469/#470; neither has approved them. Defer
abi3, free-threaded Python, PyPy, musl and other architectures.OS / payload floor Rust target npm suffix, both families Wheel platform Installed-artifact runner Linux x64 / glibc 2.17 x86_64-unknown-linux-gnulinux-x64-gnumanylinux2014_x86_64ubuntu-latest, pinned manylinux containerLinux arm64 / glibc 2.17 aarch64-unknown-linux-gnulinux-arm64-gnumanylinux2014_aarch64ubuntu-24.04-arm, pinned manylinux containermacOS x64 / 11.0 x86_64-apple-darwindarwin-x64macosx_11_0_x86_64macos-15-intelmacOS arm64 / 11.0 aarch64-apple-darwindarwin-arm64macosx_11_0_arm64macos-15Windows x64 / Windows 10, MSVC 14 runtime x86_64-pc-windows-msvcwin32-x64-msvcwin_amd64windows-latestWindows arm64 / Windows 11, MSVC 14 runtime aarch64-pc-windows-msvcdeferred deferred windows-11-arm: downloadable binaries only… cut at 3000 characters; the whole file is runtime/plan/proposal.md
18 · ticket.plan · discussing → completed 2026-10-06 00:33Z
response
runtime/plan/response.mdThe author approved the plan by reaction
Round 1 of 3, posted at: #471 (comment)
vjovanov reacted 👍 to round 1 and wrote nothing further.
That is approval of the plan as proposed: implement it as written.
No part of it was amended, and nothing was added - where the plan left
something to your judgement, it is still yours.19 · supervising → supervising 2026-10-05 23:56Z
20 · ticket.dependencies · dependencies → completed 2026-10-06 00:54Z · `DEPENDENCIES: clear`
dependencies
runtime/exports/github-issues-agent-grounds-grund-471-implement-454b7621.ticket.dependencies/dependencies.mdDependencies for #471
- agent-grounds/grund#469 —
closed - agent-grounds/grund#470 —
closed
DEPENDENCIES: clear
21 · supervising → supervising 2026-10-05 23:56Z
22 · ticket.specify · specify → opening 2026-10-07 18:11Z · `PR: https://github.com//pull/516`
contract
runtime/exports/github-issues-agent-grounds-grund-471-implement-454b7621.ticket.specify/contract.mdThe contract for #471: specification and failing tests
Commit
09247c9199dff1bd007fe13be7fdfb83aaeba657onfix/issue-471(one
standalone commit on18f1a5a695, with no attribution trailer; not pushed). The pull request will come from
vjovanov:fix/issue-471, opened byopening.Spec IDs written or changed
New:
FS-distribution-candidate(docs/functional-spec/FS-distribution-candidate.md):
the lead,terms, and every leaf below.- 1.1 the six-row matrix table, 1.2 every registry row proves every runtime,
1.3 runtime floors are inspected, 1.4 deferred targets gain no support. - 2.1 thirty-nine artifacts, 2.2 npm selection, 2.3 one assembly recipe,
2.4 READMEs and licence. - 3.1 placements, 3.2 the invisible launcher, 3.3 a missing payload is an error,
3.4 the LSP's stdout. - 4.1 npm
build:source, 4.2 sdists, 4.3 prerequisites named. - 5.1 no credential, 5.2 fresh installs without Rust, 5.3 CLI parity,
5.4 API parity, 5.5 LSP lifecycle, 5.6 own runner, skipped row named. - 6.1 manifest, 6.2 one version, 6.3 binding-only, 6.4 verify, 6.5 receipts.
- 7.1 per-product training, 7.2 profile keys, 7.3 profile-use build,
7.4 the Windows arm64 exception. - 8.1 disabled publisher, 8.2 identity is not authority, 8.3 verified only,
8.4 order and readiness, 8.5 reruns and status, 8.6 attestations,
8.7 the Cargo release cannot reach it.
- 1.1 the six-row matrix table, 1.2 every registry row proves every runtime,
FS-distribution.4.13— a candidate is rehearsed before anything is published.
Changed:
FS-distribution: the lead, the §1 lead, the npm/PyPI rows of the table (status
candidate), 1.1, 1.2, 1.3, 2, 3.2, 3.3, the §4 lead, 4.2.6, 4.3, 4.4, 4.5,
4.8, 4.9, 4.10, 4.11.FS-lsp.2.1— local candidate install of npm/PyPIgrund-lsp, each family
installed alone.AR-bindings.5,AR-bindings.6,AR-bindings.7.DA-pgo-release.2,AR-benchmarks.1.5,AR-ci.6.docs/functional-spec/README.mdlists the new spec under Packaging.tests/integration/functional_spec_coverage_policy.rsdrops the
FS-distribution.2andFS-distribution.4.11exceptions (tests now cite both)
and addsFS-distribution-candidate.terms.
Tests, by file, name and lane
Lane ordinary:
python -m unittest discover -s tests/integration -p 'test_*.py',
the gate that pre-commit and push/PR CI run. It is offline, needs no registry and no credential,
and all of it ran here. Lane rehearsal:tests/integration/rehearsal/run.py, which
the manualcandidate-rehearsal.ymlruns on each row's own runner. It is not
collected by discover: the directory has no__init__.pyand notest_*module.Ordinary lane
tests/integration/test_distribution_candidate.py(27 failing results today):MatrixTests:test_the_tool_matrix_is_the_spec_table,
test_linux_rows_build_in_the_release_images,test_windows_arm64_is_downloads_only.PlanTests:test_the_plan_names_exactly_the_inventory,
… cut at 3000 characters; the whole file is runtime/exports/github-issues-agent-grounds-grund-471-implement-454b7621.ticket.specify/contract.md
pr
runtime/spec/pr.mdPR: #516
23 · ticket.specify · opening → completed 2026-10-07 18:11Z
24 · supervising → supervising 2026-10-05 23:56Z
25 · ticket.implement · implement → completed 2026-10-07 20:14Z
report
runtime/exports/github-issues-agent-grounds-grund-471-implement-454b7621.ticket.implement/report.md{ … cut at 3000 characters; the whole file is runtime/exports/github-issues-agent-grounds-grund-471-implement-454b7621.ticket.implement/report.md </details> <details><summary><b>26 · supervising → supervising</b> 2026-10-05 23:56Z</summary> </details> <details><summary><b>27 · ticket.review-1 · review → completed</b> 2026-10-07 21:09Z</summary> _findings_ `runtime/exports/github-issues-agent-grounds-grund-471-implement-454b7621.ticket.review-1/findings.md` ```json { "round": 1, "verdict": "changes-requested", "findings": [ { "id": "R1-01", "severity": "major", "category": "release-safety", "file": ".github/workflows/release.yml", "line": 448, "summary": "The weekly Cargo release now requires `pgo-build.sh --product grund-lsp`, and the new train.py LSP harness inside it, on four rows (macOS x64, macOS arm64, Windows x64, Linux arm64) where it has never run once; if it fails there, nothing is published and the tag is already pushed.", "repro": "Code path. release.yml:448 (build-native-pgo, `continue-on-error: ${{ ! matrix.pgo_required }}`, pgo_required true for macos-15-intel, macos-15 and windows-latest) and release.yml:349 (build-linux-gnu-pgo, also the aarch64 row) both run `bash scripts/pgo-build.sh --product grund-lsp`. Before the build matrix runs, prepare-release-ref pushes the tag (release.yml:306). publish-crates `needs` both build jobs, and github-release requires `needs.build-native-pgo.result == 'success'` (release.yml:650). A rerun for the same version re-checks-out the tagged commit, which still holds the failing script. Evidence: runtime/implement-evidence/ holds one replay of this step, release-yml-linux-pgo-step-replay.log (x86_64 container only). Nothing ever ran the LSP step on the other four. Reading the step for those runners, I found no failing line. Git Bash converts the instrumented payload's POSIX path for native Python; find_python takes `python` on Windows and /opt/python/cp312-cp312 in the aarch64 image; train.py sends file:///D:/… URIs, which grund-lsp's `uri.to_file_path()` accepts; the profile is written at a normal exit after `exit`. So this is an unexercised step on the live path, not a reproduced crash. No existing runner covers it either: pre-release-checks.yml runs pgo-build.sh on ubuntu-latest only. A release.yml dry run from this branch also cannot cover it as-is: `python3 scripts/check_release_ramps.py 0.16.2-dev` prints `error: release must look like 0.13.0, got '0.16.2-dev'` (rc 2), and the verify job requires the input version to equal the tree's.", "fix": "Before merge, a person authorizes one run that executes `pgo-build.sh --product grund-lsp` on macos-15-intel, macos-15, windows-latest and ubuntu-24.04-arm. The smallest is a fork dispatch of candidate-rehearsal.yml at this head: its build job runs the same script and train.py on every row's runner, and it also settles R1-02. No code change is needed, and the fix round cannot substitute for the run.", "criterion": "Author's answer 1 (\"The weekly Cargo patch keeps running as it does today\"); ticket criterion 9 (\"Existing release behavior is reconciled deliberately rather than weakened\")" }, { "id": "R1-02", "severity": "minor", "category": "evidence", "file": "tests/integration/rehearsal/run.py", "line": 0, … cut at 3000 characters; the whole file is runtime/exports/github-issues-agent-grounds-grund-471-implement-454b7621.ticket.review-1/findings.md </details> <details><summary><b>28 · supervising → supervising</b> 2026-10-05 23:56Z</summary> </details> <details><summary><b>29 · ticket.fix-1 · fix → completed</b> 2026-10-07 21:43Z</summary> _resolutions_ `runtime/exports/github-issues-agent-grounds-grund-471-implement-454b7621.ticket.fix-1/resolutions.md` ```json { "round": 1, "resolutions": [ { "id": "R1-01", "status": "needs-person", "commit": null, … cut at 3000 characters; the whole file is runtime/exports/github-issues-agent-grounds-grund-471-implement-454b7621.ticket.fix-1/resolutions.md </details> <details><summary><b>30 · supervising → supervising</b> 2026-10-05 23:56Z</summary> </details> <details><summary><b>31 · ticket.review-2 · review → completed</b> 2026-10-07 22:33Z</summary> _findings_ `runtime/exports/github-issues-agent-grounds-grund-471-implement-454b7621.ticket.review-2/findings.md` ```json { "round": 2, "verdict": "changes-requested", "findings": [ { "id": "R2-01", "severity": "major", "category": "ci", "file": "tests/integration/distribution_support.py", "line": 366, "summary": "`synthetic_candidate` writes manifest.json in text mode but returns the sha256 of the LF text. On Windows the file on disk is CRLF, so the publisher's gate refuses every publishing test at the manifest-digest check, and the required check `cargo test (windows-latest)` is red at both ead9550e5d and b332c7af0a.", "repro": "CI at ead9550e5d (run 37685711365, job 113012857654, step 'python tests'): 'Ran 468 tests in 1044.958s / FAILED (failures=12, skipped=23)'. All 12 failures are in test_cross_registry_publisher, each with 'error: --manifest-sha256 de81538c... is not the candidate's manifest (5d13ebae...)', and every receipt 'names manifest de81538c..., not this candidate's 5d13ebae...'. CI at b332c7af0a (run 37691406563, job 113032218350): 'Ran 472 tests in 1424.994s / FAILED (failures=16, skipped=23)', the same 12 plus all 4 new FreshTokenTests. Code path: distribution_support.py:366 `(root / \"manifest.json\").write_text(text, encoding=\"utf-8\")` turns \\n into \\r\\n on Windows, and :367 returns `sha256(text.encode())`, the LF digest. publish.gate -> verify.read_manifest (verify.py:216-218) hashes the bytes on disk, so `actual != digest` (publish.py:40-41), and the receipts, which write_receipts wrote with the LF digest, are refused too. Reproduced locally with Windows text mode simulated: ~/ag/tmp/review471-2/winsim/sitecustomize.py makes every text-mode write with newline=None use '\\r\\n', as Windows does. In a git-archive copy of b332c7af0a, `cd tests/integration && PYTHONPATH=~/ag/tmp/review471-2/winsim python3 -m unittest test_cross_registry_publisher` prints exactly CI's 16 FAIL lines and 'Ran 21 tests / FAILED (failures=16)'. Without the simulation it prints 'Ran 21 tests / OK'. With line 366 changed to `(root / \"manifest.json\").write_bytes(text.encode())`, the simulated run prints 'Ran 21 tests / OK'. rewrite_manifest (:387-388) has the same mismatch, latent because its three callers in test_distribution_candidate ignore the digest. `gh api repos/agent-grounds/grund/rules/branches/main` lists cargo test (windows-latest) as a required status check. The helper came in with this change in 09247c9199.", "fix": "Write the manifest as bytes in synthetic_candidate, `(root / \"manifest.json\").write_bytes(text.encode())`, and do the same in rewrite_manifest. Leave verify.read_manifest hashing the bytes on disk (§FS-distribution-candidate.6.1).", "criterion": "Ticket acceptance: the change is merged with CI green (required check cargo test (windows-latest) is red at b332c7af0a)" }, { "id": "R2-02", "severity": "major", "category": "correctness", "file": "scripts/distribution/assemble.py", "line": 97, … cut at 3000 characters; the whole file is runtime/exports/github-issues-agent-grounds-grund-471-implement-454b7621.ticket.review-2/findings.md </details> <details><summary><b>32 · supervising → supervising</b> 2026-10-05 23:56Z</summary> </details> <details><summary><b>33 · ticket.fix-2 · fix → completed</b> 2026-10-07 23:13Z</summary> _resolutions_ `runtime/exports/github-issues-agent-grounds-grund-471-implement-454b7621.ticket.fix-2/resolutions.md` ```json { "round": 2, "resolutions": [ { "id": "R2-01", "status": "fixed", "commit": "c3db923909", "note": "tests/integration/distribution_support.py: synthetic_candidate and rewrite_manifest now encode the manifest once, write those bytes with write_bytes and return sha256 of the same bytes. write_receipts is unchanged: its JSON is only parsed. verify.read_manifest still hashes the bytes on disk (§FS-distribution-candidate.6.1). Under review-2's Windows text-mode simulation (PYTHONPATH=~/ag/tmp/review471-2/winsim), test_cross_registry_publisher fails before and passes after. Fail-before, in a git-archive of b332c7af0a: 'Ran 22 tests / FAILED (failures=16, errors=1)'. The 16 FAIL lines are CI's 16, each '--manifest-sha256 f01dcdc4... is not the candidate's manifest (a9c9f021...)'; the 1 error is the ShareTests name this old tree lacks. Pass-after, in a git-archive of HEAD with test_distribution_candidate.ShareTests run alongside: 'Ran 24 tests / OK'. Without the simulation both trees pass the publisher tests." }, { "id": "R2-02", "status": "fixed", "commit": "750a280dd2", … cut at 3000 characters; the whole file is runtime/exports/github-issues-agent-grounds-grund-471-implement-454b7621.ticket.fix-2/resolutions.md </details> <details><summary><b>34 · supervising → supervising</b> 2026-10-05 23:56Z</summary> </details> <details><summary><b>35 · ticket.green · green → green-fix</b> 2026-10-08 00:13Z · `READY: yes`</summary> _green_ `runtime/exports/github-issues-agent-grounds-grund-471-implement-454b7621.ticket.green/green.md` # The gate, run 2 Checkout `/home/vjovanov/ag/grund/fix/issue-471` on `fix/issue-471` at `7f5615eb27`; 1 command(s), 12m05s in all. grund: the installed grund 0.15.1-dev, since the checkout pins none. | check | command | exit | time | |---|---|---|---| | 1 | `pre-commit run --all-files` | 0 | 12m05s | ## 1. `pre-commit run --all-files` - passed Verdict lines:grund fmt................................................................Passed
grund init --check (managed block is current)............................Passed
lychee...................................................................Passed
fissile (file size budgets)..............................................Passed
no Claude attribution boilerplate (staged files).........................Passed## What green-fix changed between runs ### fix-1 - `pre-commit run --all-files`, hook `python-test` (`python scripts/run_python_gate.py`): `test_parity.NodeParityTests.test_complete_data_matches_same_source_rust_oracle` and its `test_node_binding_acceptance.NodeAcceptanceWorkflowTests.test_node_acceptance_is_in_the_complete_local_gate` wrapper failed with `AssertionError: None is not true : shared corpus prerequisite absent: GRUND_BINDINGS_ORACLE` (R1-07, outside this ticket's scope, fixed as the brief authorized). Fixed in 7f5615eb27, "Build the binding oracle for the local Python gate as CI does". When `GRUND_BINDINGS_ORACLE` is unset, `scripts/run_python_gate.py`'s `inputs()` now builds `cargo build --locked -p grund-core --example grund-binding-oracle` with `GRUND_BINDINGS_SOURCE_SHA=$(git rev-parse HEAD)` into `~/ag/tmp/grund-bindings-oracle`, as ci.yml does, citing §FS-distribution.3.0.3. It raises if the build fails or the executable is missing, and leaves a set variable alone, so CI is unchanged. No test, `tests/bindings/`, `.pre-commit-config.yaml`, ci.yml or file the brief froze was touched. `env -u GRUND_BINDINGS_ORACLE TMPDIR=/dev/shm pre-commit run python-test --all-files` now ends `python tests.............................................................Passed` (exit 0). READY: yes </details> <details><summary><b>36 · ticket.green · green-fix → green</b> 2026-10-08 00:23Z</summary> _fix_ `runtime/green/github-issues-agent-grounds-grund-471-implement-454b7621.ticket.green/fix-1.md` - `pre-commit run --all-files`, hook `python-test` (`python scripts/run_python_gate.py`): `test_parity.NodeParityTests.test_complete_data_matches_same_source_rust_oracle` and its `test_node_binding_acceptance.NodeAcceptanceWorkflowTests.test_node_acceptance_is_in_the_complete_local_gate` wrapper failed with `AssertionError: None is not true : shared corpus prerequisite absent: GRUND_BINDINGS_ORACLE` (R1-07, outside this ticket's scope, fixed as the brief authorized). Fixed in 7f5615eb27, "Build the binding oracle for the local Python gate as CI does". When `GRUND_BINDINGS_ORACLE` is unset, `scripts/run_python_gate.py`'s `inputs()` now builds `cargo build --locked -p grund-core --example grund-binding-oracle` with `GRUND_BINDINGS_SOURCE_SHA=$(git rev-parse HEAD)` into `~/ag/tmp/grund-bindings-oracle`, as ci.yml does, citing §FS-distribution.3.0.3. It raises if the build fails or the executable is missing, and leaves a set variable alone, so CI is unchanged. No test, `tests/bindings/`, `.pre-commit-config.yaml`, ci.yml or file the brief froze was touched. `env -u GRUND_BINDINGS_ORACLE TMPDIR=/dev/shm pre-commit run python-test --all-files` now ends `python tests.............................................................Passed` (exit 0). </details> <details><summary><b>37 · ticket.green · green → completed</b> 2026-10-08 00:13Z</summary> </details> <details><summary><b>38 · supervising → supervising</b> 2026-10-05 23:56Z</summary> </details> <details><summary><b>39 · ticket.describe · describe → completed</b> 2026-10-08 00:46Z</summary> _description_ `runtime/exports/github-issues-agent-grounds-grund-471-implement-454b7621.ticket.describe/description.md` ```json { "title": "Build and rehearse npm and PyPI packages locally without publishing them, and attach grund-lsp archives to releases", "body_path": "runtime/supervision/pr-description.md", "ticket": "#471", "steps_summarized": 25, "accounting": "measured", "notes": "Title and body are already on PR #516, set through `gh api -X PATCH repos/agent-grounds/grund/pulls/516`, because `gh pr edit` fails on this gh client with the deprecated projectCards GraphQL field. The PR is still a draft. Supervisor, please check one correction: the brief said the live Cargo release changes in exactly three ways, but two scripts the live workflows run also changed, and the body lists them as items 4 and 5. First, scripts/pgo-build.sh was rewritten, so the `grund` PGO build itself, not only the new grund-lsp step, runs rewritten code on linux-arm64, macOS x64, macOS arm64 and Windows x64, where it has never run. That makes R1-01 wider than the grund-lsp step. Second, scripts/check-registry-names.sh, which release.yml's verify job runs, now makes ten more live npm queries. Each fails the release closed if it cannot be read or if another project holds the name. Pre-ship gate: R1-01/R1-02 still need an operator.md answer before ship. If a cross-row candidate-rehearsal.yml run happens, update the row table under 'What is proved, and on which rows' and the 'Open before merge' section. If merging without that run is accepted, the body already claims criteria 3-6 for linux-x64-gnu only. CI run 37708585118 at 7f5615eb27 was still pending when the body was written, and the body says so; do not merge before it is green." }pr-description
runtime/supervision/pr-description.mdCloses #471
This adds a manual lane that builds every npm and PyPI package of
grundandgrund-lspfrom one commit, installs each one fresh, and checks it against the Rust engine. It also adds a publisher for those packages, and the publisher is disabled. Nothing is published to npm or PyPI, and nothing in this change can publish there. The only workflow that could upload has its publishing job set to a literalif: ${{ false }}. The weekly Cargo release still publishes only the crates and the GitHub release. Everything this change does to it is listed under What reaches the live Cargo release. The part users will see is agrund-lsparchive beside eachgrundarchive.Before (on
mainat18f1a5a695), nothing in the repository builds an npm or PyPI package:$ python3 scripts/distribution/candidate.py matrix python3: can't open file '…/scripts/distribution/candidate.py': [Errno 2] No such file or directory
The weekly release attached
grund-<version>-<triple>archives only, and the Install section ofdocs/user-facing/lsp.mdbegan with "Install the CLI first".After (this branch). The listing below is a local
linux-x64-gnurow candidate, built withcandidate.py build --row linux-x64-gnubefore the rehearsal. All four of its payloads are PGO builds:$ ls candidate/*/ candidate/archives/: grund-0.16.2-dev-x86_64-unknown-linux-gnu.tar.gz grund-0.16.2-dev-x86_64-unknown-linux-gnu.tar.gz.sha256 grund-lsp-0.16.2-dev-x86_64-unknown-linux-gnu.tar.gz grund-lsp-0.16.2-dev-x86_64-unknown-linux-gnu.tar.gz.sha256 candidate/cargo/: grund-0.16.2-dev.crate grund-core-0.16.2-dev.crate grund-lsp-0.16.2-dev.crate candidate/npm/: grund-cli-0.16.2-dev.tgz grund-cli-linux-x64-gnu-0.16.2-dev.tgz grund-lsp-0.16.2-dev.tgz grund-lsp-linux-x64-gnu-0.16.2-dev.tgz candidate/pypi/: grund-0.16.2.dev0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl grund-0.16.2.dev0.tar.gz grund_lsp-0.16.2.dev0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl grund_lsp-0.16.2.dev0.tar.gz candidate/receipts/: linux-x64-gnu.json $ python3 -m venv .venv && .venv/bin/pip install -q --no-index candidate/pypi/grund_lsp-*.whl $ ls .venv/bin | grep grund grund-lsp $ .venv/bin/grund-lsp --version grund-lsp 0.16.2-dev
The language server installs alone, with no
grundcommand beside it; the rehearsal installs it the same way with Rust masked. That one-row candidate verifies, andverify --releaserefuses it with three named errors: one row rather than the full matrix, scoperehearsalrather thanfull-release, and a development version.… cut at 3000 characters; the whole file is runtime/supervision/pr-description.md
40 · supervising → supervising 2026-10-05 23:56Z
41 · ticket.fix-3 · fix → completed 2026-10-09 03:58Z
resolutions
runtime/exports/github-issues-agent-grounds-grund-471-implement-454b7621.ticket.fix-3/resolutions.md{ "round": 3, "resolutions": [ { "id": "R3-01", "status": "fixed", "commit": "c0137805e4", "note": "win32-x64-msvc failed at payloads.py:90 (job 113093622446 of run 37710056388) because pgo-build.sh resolves --target-dir with `cd && pwd`, so under Git Bash its paths are MSYS paths (/d/a/_temp/target/...). The evidence JSON carried them as text: Git Bash converts an MSYS path when it is an argument to a native program, which is why the builds, the merge and train.py's arguments worked, but never the contents of a file. Where the conversion lives: in pgo-build.sh, where the evidence is written. The script already held the one helper that turns its paths into what native programs read (`cygpath -m` on a Windows host, for rustc's flags). It is renamed native_path, and the evidence's `profile` and `payload` now go through it. The evidence is the script's interface to native readers: candidate.py keeps the payload it names (§FS-distribution-candidate.7.3), and the rehearsal hands its profile back. Python has no cygpath, and converting in each reader would teach every reader about MSYS. Audit of other Git-Bash paths reaching a native reader: the build job's only bash-produced paths are the script's own. candidate.py build passes native $RUNNER_TEMP paths in, and the merge, train.py and rustc get theirs as converted arguments. The .key file carries no path. assemble and share run on ubuntu-latest. The rehearsal harness's paths come from native Python: setup-python outputs, the oracle step's GITHUB_ENV write, and pathlib. So the evidence's two fields were the only path a file carried. Pinned by EvidenceTests.test_the_evidence_names_files_this_host_opens in tests/integration/test_pgo_build.py (new), which ci.yml runs on every leg through scripts/run_python_gate.py. It runs the real pgo-build.sh with --evidence under stand-in rustc and cargo, and requires the `payload` and `profile` the evidence names to be files this host's Python opens. On windows-latest, --target-dir is a native path that the script turns into /c/...; before this commit the evidence carried that, and Path.is_file() is false for it there. On Linux the test passes either way, so the fail-before holds on windows-latest only, by construction, not by a run of the old code there. Real-runner proof: both the win32-x64-msvc build of run 37873822459 (job 113637669650) and that of the final run built and verified all four payloads past payloads.py:90 (`ok: D:\\a\\_temp/candidate verifies`). Cites §FS-distribution-candidate.5.6 and §FS-distribution-candidate.7.3." }, { "id": "R3-02", "status": "fixed", "commit": "bb3c17adea", … cut at 3000 characters; the whole file is runtime/exports/github-issues-agent-grounds-grund-471-implement-454b7621.ticket.fix-3/resolutions.md </details> <details><summary><b>42 · supervising → supervising</b> 2026-10-05 23:56Z</summary> </details> <details><summary><b>43 · ticket.review-3 · review → completed</b> 2026-10-09 06:16Z</summary> _findings_ `runtime/exports/github-issues-agent-grounds-grund-471-implement-454b7621.ticket.review-3/findings.md` ```json { "round": 3, "verdict": "changes-requested", "findings": [ { "id": "R3-20", "severity": "major", "category": "ci", "file": "scripts/pgo-build.sh", "line": 134, "summary": "The required check `cargo test (windows-latest)` is red at 6ace36a404, on the test this round added. `sha256()` passes `sha256sum` a path, and GNU sha256sum escapes a filename that contains a backslash by putting `\\` at the start of its output line. So the evidence's `profile_sha256` begins `\\2b2c…`, and the evidence file pgo-build.sh writes is not valid JSON.", "repro": "PR #516 CI run 37889260246 at 6ace36a404, job 113686222234, step 'python tests': 'ERROR: test_the_evidence_names_files_this_host_opens (test_pgo_build.EvidenceTests.test_the_evidence_names_files_this_host_opens)', 'json.decoder.JSONDecodeError: Invalid \\escape: line 8 column 22 (char 418)', 'Ran 490 tests in 1560.577s', 'FAILED (errors=1, skipped=23)'. Line 8 of the evidence is `\"profile_sha256\"`, written at pgo-build.sh:313 as `$(sha256 \"$profdata\")`, and column 22 is the first character of its value. The test passes `--profile` as `str(profile)` (test_pgo_build.py:113), which on Windows is a backslash path. pgo-build.sh:226 keeps it verbatim as `$profdata`; only `--target-dir` is normalised (:72, `cd … && pwd`). Local reproduction on Linux: ~/ag/tmp/review3/mut/repro/r.py runs the test's own stand-ins with a stand-in `cygpath` and a profile under a directory named `native\\dir`. It prints rc 0, then evidence line 8 `\"profile_sha256\": \"\\2b2c81bb82ef3e905b9fec32d7a6d42c9c5437916f2d51db2076281929d36ddf\"`, then 'json.decoder.JSONDecodeError: Invalid \\escape: line 8 column 22 (char 385)'. `sha256sum` given that path prints a line beginning `\\2b2c…`; given the same file on stdin it prints `2b2c… -`. Ubuntu and macOS pass the test because their temp paths contain no backslash. No production caller passes a backslash `--profile` with `--evidence`: release.yml passes no `--profile` at all, and the rehearsal's two `--profile` calls (profile_payload_provenance.py:153 and :158) pass either the evidence's own `cygpath -m` path or no `--evidence`. So the live release and run 37879010550's candidate are unaffected; what is red is the merge gate. As a consequence, R3-01's own pin errors on Windows before it reaches its assertions, although run 37879010550 proved R3-01 on the real Windows runners.", … cut at 3000 characters; the whole file is runtime/exports/github-issues-agent-grounds-grund-471-implement-454b7621.ticket.review-3/findings.md </details> <details><summary><b>44 · supervising → supervising</b> 2026-10-05 23:56Z</summary> </details> <details><summary><b>45 · ticket.ship · ship → ship-fix</b> 2026-10-09 06:25Z</summary> _shipped_ `runtime/exports/github-issues-agent-grounds-grund-471-implement-454b7621.ticket.ship/shipped.md` ```json { "pr": 516, "url": "https://github.com/agent-grounds/grund/pull/516", "branch": "fix/issue-471", "merged": true, "merge_commit": "2919bbed3b3beb07b914c83eeef72f424b4728c7", "ci": { "cargo test (ubuntu-latest)": "pass", "cargo test (macos-latest)": "pass", "cargo test (windows-latest)": "pass", "commit message attribution gate": "pass", "cargo bench (instruction counts)": "pass" }, "fixups": [ "e8de52d57c \"Hash the PGO evidence's files from stdin so a backslash path stays valid JSON\". sha256() in scripts/pgo-build.sh hashes from stdin in both branches (R3-20), and the digest is unchanged for every backslash-free path.", "PR #516 body corrected per R3-11 to R3-19, with the AI-workflow block regenerated, and put on the pull request through gh api. It still opens with `Closes #471`, and the title is unchanged." ], "main": { "commit": "2919bbed3b3beb07b914c83eeef72f424b4728c7", "runs": { "CI": "success" }, "status": "green" }, "notes": "Merged as 2919bbed3b3beb07b914c83eeef72f424b4728c7; main is green on it (1 run(s))." }46 · ticket.ship · ship-fix → ship 2026-10-09 06:47Z
fix
runtime/ship/github-issues-agent-grounds-grund-471-implement-454b7621.ticket.ship/fix-1.mdCalled by the supervisor's brief (
SHIP: agent, visit 15 attempt 3), which carries the operator's SHIP WITH R3-20 ruling. I did the two things it names: the R3-20 code change as its own commit, then review-3's body corrections R3-11 to R3-19.The R3-20 commit, "Hash the PGO evidence's files from stdin so a backslash path stays valid JSON", is e8de52d57c on 6ace36a before the program's rebase. It changes
sha256()in scripts/pgo-build.sh and nothing else:sha256sum < "$1"andshasum -a 256 < "$1", with a one-line comment on why. No test, workflow, scripts/distribution/ or tests/integration/rehearsal/ file changed.git diff --stat 6ace36a404 HEADshows one file, scripts/pgo-build.sh, with 3 insertions and 2 deletions.What I checked before handing back:
- Review-3's reproduction,
python3 -I ~/ag/tmp/review3/mut/repro/r.py "$PWD/tests/integration", run from the checkout.- At 6ace36a it printed
"profile_sha256": "\2b2c81bb…"and thenjson.decoder.JSONDecodeError: Invalid \escape: line 8 column 22 (char 385). - With the change it prints
"profile_sha256": "2b2c81bb82ef3e905b9fec32d7a6d42c9c5437916f2d51db2076281929d36ddf", and the evidence parses with no error.
- At 6ace36a it printed
- The digest for a path with no backslash is unchanged. This is the operator's ground for not rehearsing again. I ran the old and new
sha256()functions, taken fromgit show HEAD~1:scripts/pgo-build.shand from the working file, on a 1 MiB file~/ag/tmp/ship471/sample.profdata:- old
sha256(): b04b3be5752067c7039ccbf1dfe148c54484a6d69e20d588d292298b20270923 - new
sha256(): b04b3be5752067c7039ccbf1dfe148c54484a6d69e20d588d292298b20270923 - The bare commands give the same digest:
sha256sumold and new, andshasum -a 256old and new.Cargo.lockgives 3c22e61c… in both forms. - The same file under
native\dir/gives\b04b3be5…from the old function andb04b3be5…from the new one.
- old
sha256()is also called on release.yml's path, at pgo-build.sh:240 and :295, but only on$payloadand$pgo_dir/training. Both are built from the normalised target dir (cd … && pwd) and hold no backslash, so their digests are unchanged.(cd tests/integration && TMPDIR=/dev/shm python3 -m unittest test_pgo_build): Ran 8 tests, OK.- The distribution slice (test_pgo_build test_distribution_candidate test_distribution_launchers test_cross_registry_publisher test_cross_registry_workflows test_release_workflow test_distribution_packages test_architecture_page_paths): Ran 151 tests, OK.
TMPDIR=/dev/shm pre-commit run --all-filesexited 1 with two red hooks, neither caused by this change. Log: ~/ag/tmp/ship471/precommit.log.
… cut at 3000 characters; the whole file is runtime/ship/github-issues-agent-grounds-grund-471-implement-454b7621.ticket.ship/fix-1.md
47 · ticket.ship · ship → awaiting-checks 2026-10-09 06:25Z
48 · ticket.ship · awaiting-checks → merging 2026-10-09 06:48Z
49 · ticket.ship · merging → awaiting-checks 2026-10-09 08:16Z
50 · ticket.ship · awaiting-checks → merging 2026-10-09 06:48Z
51 · ticket.ship · merging → watching-main 2026-10-09 08:16Z
52 · ticket.ship · watching-main → completed 2026-10-09 09:49Z
Also on disk:
runtime/exports/github-issues-agent-grounds-grund-471-implement-454b7621.ticket.plan/proposal.md,runtime/triage/github-issues-agent-grounds-grund-471-implement-454b7621.ticket.triage.evidence.mdOutcome
completed· Verdict: shipped - PR #516 (#516) rebase-merged onto main, tip 2919bbe; #471 closed as completed, and main's CI run 37913725176 on that commit is green.Outcome
github-issues-agent-grounds-grund-471-implement-454b7621.ticket.triage· Validated: kind feature, verdict none, fit fits, size complex. The export is runtime/exports/github-issues-agent-grounds-grund-471-implement-454b7621.ticket.triage/validation.md.Outcome
github-issues-agent-grounds-grund-471-implement-454b7621.ticket.agora· Planned path: triage found FIT fits and SIZE complex; no opposing ground or goal/requirement change requires an agora.Outcome
github-issues-agent-grounds-grund-471-implement-454b7621.ticket.clarify· The author's answers on #471 settled it and nothing further was open. The record is in runtime/clarify/answers.md.Outcome
github-issues-agent-grounds-grund-471-implement-454b7621.ticket.plan· The author approved the plan on #471 by reaction. Their answer is in runtime/plan/response.md.Outcome
github-issues-agent-grounds-grund-471-implement-454b7621.ticket.dependencies· Every prerequisite declared for #471 is closed.Outcome
github-issues-agent-grounds-grund-471-implement-454b7621.ticket.specify· Draft pull request #516 opened from fix/issue-471 with the specification change and the failing test.Outcome
github-issues-agent-grounds-grund-471-implement-454b7621.ticket.implement· Implemented the cross-registry candidate lane in six commits (fe036e8..ead9550). The ordinary lane is green, and a real PGO linux-x64-gnu candidate passed all seven rehearsal checks on Node 22 and Node 24 and wrote its receipt.Outcome
github-issues-agent-grounds-grund-471-implement-454b7621.ticket.review-1· Changes requested: 1 major, 3 minor, 2 nit and 1 adjacent. The major (R1-01) holds the verdict: the weekly Cargo release now requires a grund-lsp PGO step that has never run on four of its required rows. The code itself reads correct, and the contract's tests pass for the reasons the spec gives.Outcome
github-issues-agent-grounds-grund-471-implement-454b7621.ticket.fix-1· Fixed R1-03 (fresh registry token before each upload, spec-first, 4 new tests), R1-04 (attestation wording, and the registry attestations listed as unmet) and R1-06 (train.py docstring) in three commits. R1-01 and R1-02 need a person: one fork run of candidate-rehearsal.yml at the final head, whose steps are written inresolutions. R1-05 is deferred and R1-07 adjacent, both as briefed.Outcome
github-issues-agent-grounds-grund-471-implement-454b7621.ticket.review-2· Changes requested: 3 major (new: R2-01 and R2-02; carried as needs-person: R1-01) and 2 minor (new: R2-03; carried as needs-person: R1-02). Fix-1's R1-03, R1-04 and R1-06 are verified fixed, but PR #516 is red at b332c7a on two required checks, and the real rehearsal cannot bind the win32-x64-msvc receipt.Outcome
github-issues-agent-grounds-grund-471-implement-454b7621.ticket.fix-2· Fixed R2-01 (the Windows test helper's manifest digest), R2-02 (every candidate manifest is now LF bytes, receipts hash them, with a 6.1 sentence first and new ShareTests) and R2-03 (git background writers kept out of the macOS version test); R1-01 and R1-02 still need a person, and R1-05 and R1-07 stay deferred and adjacent.Outcome
github-issues-agent-grounds-grund-471-implement-454b7621.ticket.green· The gate is green: 1 command(s) passed on 7f5615e in 12m05s.Outcome
github-issues-agent-grounds-grund-471-implement-454b7621.ticket.describe· Set PR #516's title to "Build and rehearse npm and PyPI packages locally without publishing them, and attach grund-lsp archives to releases" and replaced its body with what landed at 7f5615e; the PR is still a draft.Outcome
github-issues-agent-grounds-grund-471-implement-454b7621.ticket.fix-3· Fixed both Windows rows (R3-01 MSYS evidence paths, R3-02 the §FS-distribution-candidate.7.4 correction to the real rustc crash) and the five first-run rehearsal defects behind them (R3-03..R3-07); fork rehearsal run 37879010550 at the exit HEAD 6ace36a is green on every job of every row, nothing was deferred or rejected, and release.yml is untouched.Outcome
github-issues-agent-grounds-grund-471-implement-454b7621.ticket.review-3· Changes requested, with 1 major (new: R3-20), 11 minor (new: R3-08; carried and narrowed: R1-01; PR-body corrections: R3-11 to R3-19) and 2 nit (R3-09, R3-10) findings: run 37879010550 proves the candidate on every row and R3-01 to R3-07 are fixed, but this round's own test is red on the required checkcargo test (windows-latest)at 6ace36a.Outcome
github-issues-agent-grounds-grund-471-implement-454b7621.ticket.ship· Pull request #516 merged as 2919bbe.Rendered from
github-issues-agent-grounds-grund-471-implement-454b7621/tasks/01-ticket.mdbyscripts/lifecycle-sync.sh.-
- addedstate:triageFiled; being checked against what is already knownFiled; being checked against what is already knownstate:validatingReproducer being built, or fit against the ground being establishedReproducer being built, or fit against the ground being establishedstate:decidingThe supervisor is choosing the pathThe supervisor is choosing the pathpath:plannedA written plan, discussed on the ticket, before the fixA written plan, discussed on the ticket, before the fixstate:clarifyingQuestions posted on this ticket wait for its author: words answer them, +1 accepts the assumptionsQuestions posted on this ticket wait for its author: words answer them, +1 accepts the assumptionsand removedstate:triageFiled; being checked against what is already knownFiled; being checked against what is already knownstate:validatingReproducer being built, or fit against the ground being establishedReproducer being built, or fit against the ground being establishedstate:decidingThe supervisor is choosing the pathThe supervisor is choosing the path
on Oct 5, 2026 Questions before the plan, round 1 of 2 - please answer on this issue
This ticket is about to be planned, or argued out in an agora. Before
either, the few things it leaves open are put to you here. Reply on
this issue with an answer to each, in any form; the work is on hold
until then.Each question states the assumption it would otherwise proceed under,
so a 👍 on this comment is a complete answer: it accepts every
assumption as written. A 👎 stops the work and hands the ticket to a
person. Words beat a reaction where both are present.After this work, a rehearsal could produce a local tarball for
npm install --global ./candidate/grund-cli-X.Y.Z.tgz, then exercise the installedgrundcommand without publishing anything (filename illustrative). Today there is no such npm package assembly here. Two facts remain open before proposing that packaging and its future publication workflows; neither question requests permission to release.-
Does the no-publication-on-merge boundary include the existing scheduled Cargo publisher? For example, after this PR changes
scripts/, Monday'sauto-bump.ymlcan count those paths as substantive, validate a patch candidate, and dispatchrelease.ymlwith Cargo publication and GitHub release creation enabled. Answer “include scheduled Cargo” and the proposal must hold automatic publication of a candidate containing this work until a separate operator decision; answer “new publication lane only” and existing scheduled Cargo policy continues, while the new cross-registry publisher remains disabled. The current helper contract explicitly includes live dispatch (§FS-distribution.4.4).Why needed: These readings require different workflow scope, and neither permission to release nor a change to existing Cargo policy can be inferred from the ticket.
Assumption without an answer: Rehearsal stays separate and the new publisher stays disabled; the existing scheduled-Cargo interaction remains unresolved, with implementation and merge held pending your answer. No release or permanent disabling of Cargo automation is authorized.
-
Which registry identities and existing publication obligations can the proposal rely on? The architecture illustrates a CLI/native platform package named
@grund-cli/linux-x64, but does not establish control of that scope or name an independent LSP platform scope (§AR-bindings.5). Please identify the controlled npm scope(s) for both families, their publishing account/team, the npm umbrella and PyPIgrund/grund-lsppublishing identities, and any already-required signing/notarization identities or publishing environments. For example, “we control these scopes under this team, these PyPI accounts have authority, and this environment/signing identity is required” lets the proposal use those facts; “none established; no existing obligations” makes names provisional and account setup an unmet prerequisite. A registry's available name is not publishing authority; the existing crates.iovjovanovowner guard remains unchanged (§FS-distribution.1.1.1). Please provide identities or requirements only, not credentials.Why needed: The proposal cannot name actual package families and publication prerequisites accurately without owner-held facts; new technical choices about credentials, attestations and gates belong in the proposal for review.
Assumption without an answer: No npm scope control, npm/PyPI publishing authority, or existing signing/environment obligation is established by the available evidence. Intended names and authority/setup requirements remain explicitly unverified prerequisites; no account, secret or protection changes will be made. Silence does not approve implementation or publication.
Posted by an agent working this ticket. Round 1 of 2; after the last round the answers stand as given.
-
13 remaining items
- addedstate:shippingPR ready; CI watched; mergingPR ready; CI watched; mergingand removedstate:implementingPR open; implement, review, fix, greenPR open; implement, review, fix, green
on Oct 9, 2026 - added 10 commits that reference this issue
on Oct 9, 2026 - removedstate:shippingPR ready; CI watched; mergingPR ready; CI watched; merging
on Oct 9, 2026
Outcome and discussion status
Prepare installable npm and PyPI distributions of the existing
grundCLI and optionalgrund-lsp, with one audited artifact pipeline that also preserves the Cargo release path. A non-publishing rehearsal must prove that the exact candidate artifacts can be installed and behave like the Rust engine before an operator considers publishing them.This is the shared packaging/build portion of §RM-distribution. Keep
human-discussionuntil the owner settles the choices below and authorizes implementation. This ticket authorizes no release: do not publish to crates.io, npm, PyPI, or TestPyPI; create or push release tags; run a live release workflow; or create a GitHub release as part of completing it. Preparing and reviewing the workflows is the outcome. A later, explicit operator decision must authorize any publication; merging or closing this ticket must not trigger it.Placement relative to 1.0 remains undecided. This is not a child of #347 and does not add itself to the 1.0 gate.
Why this remains a separate deliverable
The Node and Python binding tickets own their language APIs, conversion/error contracts, and local build metadata. This ticket consumes those outputs and owns target matrices, executable bundling, package selection, release artifacts, cross-install parity and workflow orchestration. The standalone LSP packages have no need to depend on either embedding API. Combining all of this with either binding would make its completion depend on the other language and on unrelated release infrastructure.
#467 owns the adopted 1.0 contract freeze and release evidence. It does not build missing registry distributions. This ticket supplies packaging evidence when appropriate; it neither duplicates that audit nor performs a release. #466 owns the Rust API transition; changes to that API are handled there and in the bindings rather than being introduced by packaging.
Current starting point
Reviewed main at
df506acfae6d39169e7e2cdabd2327f669a21c3d:grund-cliandgrund-lsp, and PyPIgrundandgrund-lsp. The CLI and LSP installs are independent.release.ymlpublishes Cargo crates in dependency order and builds downloadable CLI artifacts for Linux x64/arm64, macOS x64/arm64 and Windows x64/arm64. It does not contain npm/PyPI packaging jobs. Its artifact packaging copiesgrund; do not assume equivalent prebuilt LSP packaging already exists.scripts/pgo-build.shprofiles the CLI hot-command workload. Extending it to LSP and native binding products requires explicit training/build design rather than merely labelling an ordinary build PGO.Scope and package contract
grund-core,grund,grund-lspgrund-cligrundexecutable,npx grund-cli, and the sibling ticket's JS/native APIgrund-lspgrund-lspexecutable over stdiogrundgrundexecutable and importablegrundAPIgrund-lspgrund-lspexecutable; usable withpipx install grund-lspReuse the existing CLI and server binaries. Launchers must preserve arguments, exit codes, signals, stdin/stdout/stderr, paths containing spaces and Unicode, and executable permissions. LSP stdout remains protocol-only. Packaging must not implement scanning, checking or rendering logic, or introduce frontend-to-frontend Cargo dependencies merely to put binaries in the same distribution.
Platform and compatibility decisions
Before implementation, record one matrix connecting OS/architecture/libc, Rust target, npm platform package, wheel tag, supported runtime range and the runner that actually executes the artifact.
@grund-cli/linux-x64does not prove the scope is controlled.Build graph and PGO
Build all registry artifacts from one immutable candidate commit with an explicit manifest of product, version, source SHA, target, runtime/ABI, build toolchain and checksum. CLI/LSP packages within a full release carry the matching engine version per §FS-distribution.4.11. Document how any independently versioned binding-only maintenance permitted by AR-bindings remains compatible with that rule.
Extend the existing PGO path for the prebuilt CLI/LSP/native products, reconcile the current CLI-focused wording in §FS-distribution.4.9 and §DA-pgo-release.2, and specify how the benchmark's shared engine workload trains each product. Profiles must match the compiler/target and relevant code build; do not reuse stale or incompatible profiles. Demonstrate that the packaged payload is the profile-use result. Add any necessary LSP protocol or binding entry-point training deliberately, without inventing a second divergent engine workload.
Keep PGO in manual packaging/pre-release or benchmark paths, outside the regular push/PR feedback loop. Preserve the documented, explicitly identified platform-broken PGO exception with self-checked LTO artifacts; a general build failure must not silently become a successful fallback. Source installs remain ordinary LTO builds.
Publication workflow preparation and ownership
Prepare an auditable separation between build/validate and publish. The build/rehearsal path must need no registry-write credentials and create no tag or release. The future publication path consumes the already verified artifact set rather than rebuilding it differently, remains disabled pending explicit operator authorization, and cannot be reached accidentally through the rehearsal or a normal merge.
grund-corefirst; wait for dependency resolvability before dependent crates). For npm, platform dependencies must be available before the umbrella package; PyPI needs the complete intended wheel/sdist set. Define bounded readiness checks, partial-publication recovery, version immutability and rerun behavior. Registry writes cannot be atomic across ecosystems: report a partial release honestly and do not mark it complete while an artifact is missing.Acceptance criteria for implementation
npx/npm executable selection and pip/pipx entry points locate the bundled binary on supported systems.Dependencies and exclusions
Depends on #469 (Node napi-rs) and #470 (Python PyO3) binding deliverables for their native modules, API loaders and agreed ABI/runtime metadata. Packaging planning and independent LSP assembly can proceed before both APIs are complete; full installed-package parity cannot. Coordinate changes in #466 so the packages embed the intended supported engine API.
No new CLI command, LSP capability, engine rule or user-facing finding policy is part of this ticket. The 1.0 freeze in #467, actual release/changelog preparation for a selected version, package publication, tag creation, release dispatch and organization-account changes require their own authorization. Full distribution readiness is evidence available to that decision, not permission to take it.