Skip to content

fix(go): preserve prepared workspaces and adopt authenticated native ownership - #159

Draft
antoinetoussaint-byte wants to merge 2 commits into
mainfrom
fix/honour-prepared-gowork
Draft

antoinetoussaint-byte wants to merge 2 commits into
mainfrom
fix/honour-prepared-gowork

Conversation

@antoinetoussaint-byte

@antoinetoussaint-byte antoinetoussaint-byte commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

Native Go agents now link published Core v0.19.9, so Core writes authenticated-v2 ownership records with durable launch-workspace attribution. The original PR 159 fix remains intact: native packaging honors CLI-prepared GOWORK, defaults to the pinned graph when unprepared, and cross packaging keeps GOWORK=off because host workspace siblings are not mounted.

Classification: fix at the owners. Reused Core's native runner, authenticated manager, ownership inspection, identity-bound SignalProcess, strict recovery receipt parser, and the CLI's existing preview/expect recovery commands. No service-go registry, process matcher, recovery implementation, or Linux inspection fix was added. The dependency pin was applied through codefly agent deps --pin v0.19.9, including base/code and regenerated factory templates.

Updated behavior/process documentation: pkg/runtime/runtime.go package documentation, AGENTS.md, and .claude/skills/verify-changes/SKILL.md. A maintained opt-in TestNativeAgentOwnershipLifecycle consumes the actual built agent and SBOM through its normal installation path; real authenticated gRPC Load/Init/Start/Stop, restart, agent-owner death, CLI recovery, and sibling preservation run in a temporary OS HOME. It also checks that ordinary Stop removes its registration.

Validation: go build ./..., go test -json -count=1 ./..., and go vet ./... passed. Builder prepared-workspace/pinned-graph regressions and factory round-trip tests passed in that suite. The final clean-head native agent build and audit passed with CGO_ENABLED=1. The opt-in actual-artifact lifecycle gate passed (1.083s) using selected CLI c16938ef/Core c1376ada, SHA256 d97d5d9726a10102d7e52948bfe0856df636e108888c93249a81f5a15445e791. Actual v2 orphan recovery reported group_dead=true and record_removed=true while the independently launched sibling retained its exact birth and live owner.

Not verified: Docker/native-cross CGO packaging suite (root slot not granted), Linux runtime, Nix integration (two tests skipped because sibling Core fixture checkout absent), manifest guard (opt-in unset; deployment unchanged), full CLI composition/run/stop, published release, or protected incident environments. This qualifies local darwin/arm64 native agent startup/ordinary gRPC stop and explicit CLI orphan recovery only. Audit reported existing unpatched upstream GO-2026-4883 and GO-2026-4887 in Docker v28.5.2+incompatible.

History: origin/main e5455c2 was already an ancestor of original159 4951041; normal git merge returned Already up to date. PR158 head8063ba8 changes only the Docker mirror fallback in refresh-apk-pins.sh, so it is independent and excluded. Original159 production builder files remain byte-identical to 4951041. Prior Go128/Core0.19.8 pin/build/native PASS7.700s artifacts remain unchanged and retain their original attribution.

Delivery: reviewed source 6097059c2ffaeebac0d4a6b98df665976b761dad is published on this existing carrier, held in draft for exact-head CI and remaining release qualification. Independent review found no blocking defect in the bounded native writer and prepared-GOWORK changes. Manifest version remains 0.0.74; the local artifact is not the published release. No manual version/tag or protected-environment adoption has occurred. Core v0.19.9 is the actual selected dependency; the separate Linux inspection correction in Core PR864 is not claimed present.

The CLI binds the go.work it detects for a local build (cmd/agents/build.go,
compileAgent) and reserves GOWORK=off for standalone CI, so a developer who
composes owner checkouts can prove an agent against an unreleased core. This
agent discarded that: resolvePackageGoToolchain, resolvePackageSource and
packageNativeGoBinary each appended GOWORK=off after inheriting the
environment, so the prepared selection lost every time and a local build with
`go.work → core checkout` still linked the pinned release.

Host-side `go` invocations now run with the GOWORK the CLI prepared and fall
back to off only when nothing was prepared. The cross build keeps off: the
companion mounts only the source and the destination, so a `use` path on the
host does not exist in the container, and a cross build is always the pinned
graph.

Tests: a go.work whose `use` reaches a sibling go.mod alone cannot resolve —
honoured, the executable carries the sibling; unset or off, the same source is
refused naming it; goWorkMode's three cases.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@antoinetoussaint-byte
antoinetoussaint-byte marked this pull request as draft October 28, 2026 05:14
@antoinetoussaint-byte antoinetoussaint-byte changed the title fix(builder): a package build honours the go.work the CLI prepared fix(go): preserve prepared workspaces and adopt authenticated native ownership Oct 28, 2026
@antoinetoussaint-byte

antoinetoussaint-byte commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor Author

A lazybox agent is working on this. codex (o159-core0772-native/manifest.json)

Previous artifacts remain unchanged. No Docker or workload runtime ran. Product10903, Wiki10889, and Root10879 received the handoff; recipients must verify actual selection before any authorized retry.

Worked for 3m 38s • 1:33 PM
⚠ Heads up, you have less than 5% of your weekly limit left. Run /status for a breakdown.

› Ask Codex to do anything

GPT-6-Astra · high) started at 2026-10-28 04:38 UTC, last renewed the claim at 2026-10-30 15:39 UTC, and the claim lapses at 2026-10-30 16:24 UTC unless it is renewed again. A claim is an assertion with an expiry, not proof that a process is alive.

claim detail
Lazybox-Claim-Device: effacd542b611010656e
Lazybox-Claim-Session: a38dd2ffdc
Lazybox-Claim-Workspace: github-codefly-dev-service-go-159
Lazybox-Claim-Agent: codex
Lazybox-Claim-Model: o159-core0772-native/manifest.json)

  Previous artifacts remain unchanged. No Docker or workload runtime ran. Product10903, Wiki10889, and Root10879          received the handoff; recipients must verify actual selection before any authorized retry.

  Worked for 3m 38s • 1:33 PM                                                                                           
⚠ Heads up, you have less than 5% of your weekly limit left. Run /status for a breakdown.


› Ask Codex to do anything

  GPT-6-Astra · high
Lazybox-Claim-Started: 2026-10-28T04:38:03Z
Lazybox-Claim-Heartbeat: 2026-10-30T15:39:13Z
Lazybox-Claim-Expires: 2026-10-30T16:24:13Z

@gael-obin

Copy link
Copy Markdown

Independent platform review — CONDITIONAL

Fresh-context review under the architecture-bouncer skill at head 6097059c (scope e5455c22..6097059c). No conversation history with the implementing agents; the PR body and its prior "no blocking defect" review summary were treated as claims and verified independently.

The design is sound — the prepared-GOWORK seam and the bounded native writer are the right shape. Two findings block the merge.

A-1 — the ownership gate proves nothing about identity

native_ownership_test.go:70-76 re-reads InspectProcess(a.conn.ProcessInfo().PID) and signals that, and :87 compares the recovery receipt by PID alone. Nothing ties the killed process, or the receipt owner, to an identity captured at the authenticated launch. Core binds the supplied identity to a kernel handle, but a PID re-read immediately before the signal cannot establish it is the agent the test started.

This is the PR's only ownership evidence. The fix already exists downstream: go-grpc#210, adapted from this very file, captures the manager-launched agent's tracked-group handle before any workload RPC, retains the leader identity, re-inspects that original PID before the death effect, and adds a stale_owner_refuses_delivery negative — prchk-service-go-grpc-210/native_ownership_test.go:155-166, 204-210, 112-114. Port it back.

A-2 — the Core pin is wrong, and the consequence is a live process being treated as dead

go.mod:6 selects Core v0.19.9. git diff v0.19.9..v0.19.10 is Linux-only: core/runners/base/process_identity_linux.go:77-85 stops treating a missing /proc/PID/exe as proof of absence.

At v0.19.9 a live owner is reported absent — which is the exact predicate orphan recovery kills on. go-grpc#210 already took v0.19.10; Core is now at v0.19.18. Repin to ≥ v0.19.10.

A-3 — material, not blocking: SBOM/provenance seam

The build now picks its graph from ambient GOWORK (pkg/builder/package_source.go:21-36), while the attached SBOM picks it from Settings.WithWorkspace (pkg/builder/builder.go:387-389), and one SBOM is attached to both a workspace-linked native binary and a pinned-graph cross binary (:402-424 vs :508-515, :610). Core documents the seam at core/agents/services/sbom/golang.go:23-28. The default (GOWORK unset → off) and the release path are unchanged, so reproducibility is bounded and documented — but for a packaging agent, two artifacts from the same source under different ambient state deserves an explicit statement.

What was run

go build ./..., go vet ./..., go test ./... — EXIT 0; go mod tidy clean; the new prepared-GOWORK regressions pass; the opt-in ownership gate SKIPs in this environment.

Not exercised: Docker/native-cross CGO packaging, Linux runtime, Nix integration, manifest guard, full CLI composition, published release.

Supply chain

GO-2026-4883 and GO-2026-4887 are Moby daemon-side; go list -deps links only docker/docker/api/*, client, errdefs and pkg/stdcopy. The disclosure in the body is adequate and nothing is exposed. (govulncheck was unavailable in this environment.)

Fleet note

service-docx#38, service-libreoffice#78 and service-xlsx#44 all correctly state that published v0.0.74 does not contain this work — verified: git rev-parse v0.0.74 = e5455c22… = this PR's merge base, git rev-list --count e5455c22..6097059c = 2, git tag --contains 6097059c empty. Those three are waiting on a release that contains this fix, so the Core repin here is on their critical path too.

Separately, there is no handbook page or decision naming a target Core version, and four are live across the fleet (v0.17.0, v0.19.6, v0.19.10, v0.19.18). Worth settling.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants