-
Notifications
You must be signed in to change notification settings - Fork 9
fix(opencode): restore exact-pair release gate #757
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,120 @@ | ||
| # Test 745 — OpenCode exact-pair release gate and rename recovery | ||
|
|
||
| Date: 2026-08-13 (Asia/Shanghai) | ||
| Base commit: e0c27341ea004a46da3ff7abfaba2fd2cc165bc5 | ||
| Source commit: 03fa958a3261d2ae59a34883670a69e083af4e14 | ||
| Scope: OpenCode agent-network/agent-node exact-pair pins, release synchronization, | ||
| test384/test386 fixtures, and the private-root rename lifecycle required by test384. | ||
|
|
||
| ## Result | ||
|
|
||
| PASS. No production deployment, npm publication, registry tag mutation, database | ||
| write, or running-node change was performed. | ||
|
|
||
| The exact preview pair observed in the public registry and pinned by this source is: | ||
|
|
||
| - @sleep2agi/agent-network@2.3.0-preview.39 | ||
| - @sleep2agi/agent-node@2.5.0-preview.31 | ||
| - opencode-ai@1.18.1 (the test384 OpenCode dependency) | ||
|
|
||
| ## Why the lifecycle fix is in the same source | ||
|
|
||
| Updating only the pair constants did not make the committed release gate pass. | ||
| The diagnostic progression was: | ||
|
|
||
| 1. The base test384 Dockerfile failed before the product test because run.sh | ||
| sourced tests/lib/safe-rm.sh but the image did not contain that file. | ||
| 2. After supplying that dependency, the wizard fixture still modeled six runtime | ||
| choices and selected the wrong entry after grok-build-cli had become a seventh | ||
| production choice. | ||
| 3. With those fixture defects repaired, the real rename lifecycle reached L8 and | ||
| failed because the copied OpenCode tree contained a nested .config directory | ||
| with mode 0755. The existing rename code pre-created only the destination root | ||
| at 0700; cpSync could create nested private roots with a wider mode. | ||
| 4. The source now calls prepareOpencodeNodeForProfileWrite(newDir) before cpSync, | ||
| so .config, .local/share, and .local/state are created or validated as private | ||
| roots before any recursive copy. The normal and deliberately slowed lifecycle | ||
| both pass. | ||
|
|
||
| This is the same reproducible failure family tracked by issue #457. It is not a | ||
| post-copy chmod repair and does not create a permissions-widening interval. | ||
|
|
||
| ## Registry artifact capability smoke | ||
|
|
||
| A clean node:22-bookworm-slim environment installed the exact public-registry | ||
| versions above. The observed versions were exact, agent-node was executable, | ||
| agent-node help exposed opencode-cli, anet --version reported network preview.39 | ||
| with node preview.31, and the OpenCode ACP help path succeeded. | ||
|
|
||
| Marker: REGISTRY_PAIR_CAPABILITY_SMOKE_PASS | ||
|
|
||
| This smoke verifies installability and command/help capabilities only. It did not | ||
| run a real CommHub task through the npm registry artifacts. | ||
|
|
||
| ## Docker evidence | ||
|
|
||
| All commands were run from the clean source worktree with Docker via sg docker. | ||
|
|
||
| ### test384 — local-package OpenCode E2E | ||
|
|
||
| - Image: sha256:90b67da6f0d5cb51109db38c9194ced6e2af36d35880e452d363a317d70d20ed | ||
| - Runner log SHA256: 5b843feda25c7752dc859b9176b058449964f24a5611bedad6413acc608bb448 | ||
| - Result: OVERALL PASS | ||
| - Exact local tarballs: network preview.39 / node preview.31 | ||
| - Real picker: seven runtime choices, OpenCode selected | ||
| - Security: private roots and keys checked; hostile configurations rejected | ||
| - Runtime: real OpenCode 1.18.1 task reached replied; zero orphan task | ||
| - Lifecycle: rename preserved node_id and binding, then delete completed | ||
|
|
||
| The same image was run with bash -x to perturb timing: | ||
|
|
||
| - Slow runner log SHA256: 0423ca20c2aea5fe48447f33829778e4a1e531044bb95180d759d8a2dff9d15c | ||
| - Result: OVERALL PASS, including L8 rename/delete lifecycle | ||
|
|
||
| ### test386 — exact agent-node selection gate | ||
|
|
||
| - Image: sha256:aa446982ccd0682e879d00d1c515aa6edff5431911175949354786a405f79c18 | ||
| - Runner log SHA256: 76df79d692c173221bd5480601be71f44b21018838574271e62674872d6bf2f2 | ||
| - Result: OVERALL PASS | ||
| - Exact expectations and fixtures: network preview.39 / node preview.31 | ||
|
|
||
| ### test621 — test384 hold-open layer isolation | ||
|
|
||
| - Image: sha256:6d95199da9d04f7031a5b7bba6035781dd4d76678f99e465040f29d5a5e565a6 | ||
| - Image env TEST621_SOURCE_COMMIT: 03fa958a3261d2ae59a34883670a69e083af4e14 | ||
| - Runner log SHA256: e555485489e6306c56b7313ecc7dccba78eb4a3a6680edf39b395c21b2669979 | ||
| - Result: PASS | ||
| - Witnessed red: hold-open-layer-cancel, rc=1 | ||
|
|
||
| ## Release synchronization behavior | ||
|
|
||
| scripts/sync-pinned-versions.sh now treats the two exported OpenCode pair | ||
| constants as release pins. A diagnostic apply run first reverted both constants, | ||
| then updated each to the exact package version. It also verified that the source | ||
| file still ended in byte 0a. The implementation preserves a trailing newline | ||
| through command substitution by adding and removing an explicit sentinel. | ||
|
|
||
| docs/RELEASE-SOP.md now requires reading both OpenCode constants back from | ||
| origin/main and matching them to the preview tags before release. | ||
|
|
||
| ## Provenance boundary | ||
|
|
||
| The source commit contains two implementation commits. The report is added only | ||
| after that frozen source; no source or test file is changed by the report commit. | ||
| The local image IDs and runner digests above are execution evidence, not a claim | ||
| that logs containing generated IDs or model output are reproducible byte-for-byte. | ||
|
|
||
| ## Honest limits | ||
|
|
||
| - No Windows execution was performed. | ||
| - No npm publish, GitHub release, deployment, production DB access, or fleet | ||
| restart was performed. | ||
| - The registry smoke was non-interactive capability verification only. | ||
| - The real replied-task E2E used source-built local tarballs, not the npm registry | ||
| artifacts. | ||
| - test384 uses a live free OpenCode model; response content and generated IDs are | ||
| nondeterministic. Its runner digest is an integrity record for this run, not a | ||
| reproducible provenance anchor. | ||
| - A mandatory CI gate for the complete agent-network unit-test domain remains | ||
| NOT COVERED. That governance/CI tail remains tracked by issue #745 and is not | ||
| represented as solved by this source. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -68,6 +68,7 @@ register() { | |
| # @sleep2agi/agent-network — 用户安装入口 | ||
| register "@sleep2agi/agent-network" "docs-site/docs/guide/runtimes.md" | ||
| register "@sleep2agi/agent-network" "docs-site/docs/en/guide/runtimes.md" | ||
| register "@sleep2agi/agent-network" "agent-network/src/opencode-agent-node-pair.ts:OPENCODE_AGENT_NETWORK_VERSION" | ||
|
|
||
| # @sleep2agi/agent-node — runtime + SDK 行号锚点 | ||
| register "@sleep2agi/agent-node" "docs-site/docs/guide/runtimes.md" | ||
|
|
@@ -76,6 +77,7 @@ register "@sleep2agi/agent-node" "docs-site/docs/guide/agent-node.md" | |
| register "@sleep2agi/agent-node" "docs-site/docs/en/guide/agent-node.md" | ||
| register "@sleep2agi/agent-node" "docs-site/docs/guide/sdk-deep-dive.md" | ||
| register "@sleep2agi/agent-node" "docs-site/docs/en/guide/sdk-deep-dive.md" | ||
| register "@sleep2agi/agent-node" "agent-network/src/opencode-agent-node-pair.ts:OPENCODE_AGENT_NODE_VERSION" | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The new registration relies on AGENTS.md reference: AGENTS.md:L25-L25 Useful? React with 👍 / 👎. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Adding this target makes every real agent-node version bump reach the AGENTS.md reference: AGENTS.md:L24-L25 Useful? React with 👍 / 👎. |
||
|
|
||
| # @sleep2agi/commhub-server — agent-network CLI 内 PINNED_SERVER_VERSION 常量 | ||
| register "@sleep2agi/commhub-server" "agent-network/bin/cli.ts:PINNED_SERVER_VERSION" | ||
|
|
@@ -121,12 +123,13 @@ md_pattern() { | |
| "$pkg_no_scope" "$ESCAPED_VERSION" | ||
| } | ||
|
|
||
| # cli.ts PINNED 常量模板:仅替换 `const NAME = "..."` 字串字面值 | ||
| # PINNED 常量模板:仅替换 `const NAME = "..."` 或 | ||
| # `export const NAME = "..."` 的字串字面值。 | ||
| # 不动 declaration 周围 logic、不动 NAME 之外的同字串引用、不改类型/作用域 | ||
| ts_pinned_pattern() { | ||
| local const_name="$1" | ||
| # 严格锚定 `const <NAME> = "x.y.z..."`,保留引号 + 行内其它内容 | ||
| printf 's#\\(const %s = \\)"[^"]*"#\\1"%s"#g' \ | ||
| # 严格锚定可选 export + `const <NAME> = "x.y.z..."`,保留其它内容。 | ||
| printf 's#\\(\\(export \\)\\?const %s = \\)"[^"]*"#\\1"%s"#g' \ | ||
| "$const_name" "$ESCAPED_VERSION" | ||
| } | ||
|
|
||
|
|
@@ -139,19 +142,20 @@ apply_or_preview() { | |
| return | ||
| fi | ||
| local before | ||
| before="$(cat "$file")" | ||
| # Command substitution strips trailing newlines. Append a sentinel before | ||
| # capture, then remove only that sentinel so a release sync never changes | ||
| # the target file's EOF shape as a side effect. | ||
| before="$(cat "$file"; printf '\036')" | ||
| before="${before%$'\036'}" | ||
| local after | ||
| after="$(sed "$sed_expr" "$file")" | ||
| after="$(sed "$sed_expr" "$file"; printf '\036')" | ||
| after="${after%$'\036'}" | ||
| if [[ "$before" == "$after" ]]; then | ||
| echo " unchanged: $file" | ||
| return | ||
| fi | ||
| if [[ "$MODE" == "apply" ]]; then | ||
| printf '%s' "$after" > "$file" | ||
| # 原文件如果以换行结尾,保留 | ||
| if [[ "${before: -1}" == $'\n' && "${after: -1}" != $'\n' ]]; then | ||
| printf '\n' >> "$file" | ||
| fi | ||
| echo " WROTE: $file" | ||
| CHANGED_FILES+=("$file") | ||
| else | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Registering this preview-only constant in the generic package release synchronizer means the documented rollback command in
docs/RELEASE-SOP.md§5 (sync-pinned-versions.sh ... <old-stable> --apply) rewrites the OpenCode gate to an old stableagent-networkversion, even though Step 10 requires these constants to match the preview tags. The same applies to the agent-node registration below; rolling agent-node back to a pre-OpenCode stable such as 2.4.x can therefore make a subsequent CLI build trust that unsupported runtime instead of the vetted preview pair. Restrict these registrations to preview releases or give the exact-pair pins a separate synchronized workflow.AGENTS.md reference: AGENTS.md:L24-L25
Useful? React with 👍 / 👎.