Move the KDL specs (ops guardfiles + fleet manifest) out of ward up into aos, as a swappable build input #453

Closed
opened 2026-07-01 22:12:15 +00:00 by coilyco-ops · 14 comments
Member

Why

Decision direction from Kai (2026-07-01, post-pressure-test-sweep): the KDL specs — the ops guardfiles and the fleet manifest — likely move out of ward, up into aos.

The line #441 exposed is product-vs-deployment: ward's engine/agent/exec layers are generic, while base-url "forgejo.coilysiren.me/api/v1", the SSM token path, the restrict owner matches coily* gate, and the attribution defaults are deployment config. aos already owns that layer in spirit — the .ward/ward.yaml catalog schema comment points there, the pre-commit suite comes from there, the fleet grammar work is aos#310, the dev-base image is aos-built. The specs would be moving to where their siblings already live, and ward becomes honestly publishable.

Deliverable

The move, with the condition that makes it actually fix #441 rather than relocate it:

  • The spec bundle becomes a declared, swappable build input (make WARD_SPECS=... or an assets-dir convention), not a new hardcode one repo further from the cold reader's eyes. Today the coupling at least sits in ward's own tree where the sweep found it; a silent relocation makes it less visible while leaving it just as real.
  • A minimal example spec bundle (or template repo) stays where a ward adopter starts, so bring-your-own-specs is a documented path.
  • The KDL authoring reference lands in one findable place at the same time — the sweep already found the grammar scattered across two repos (#437/#440); a third home for the specs deepens that maze unless the authoring doc anchors it.

Done condition

ward's tree contains no coilyco-specific endpoint/token/owner values; a downstream builder can point the build at their own spec bundle by following one documented path; #441's compiled-in coupling claims no longer reproduce against a build made from the example bundle.

Related: #441 (the finding), #395 / #396 (externalize infra topology / fleet inventory), #437 / #440 (authoring docs).


Filed by Claude Code, capturing Kai's release-direction decisions from the 2026-07-01 pressure-test debrief.


Refresh + precise target (2026-07-05 director session)

Confirming the layer that moves up: the individual user-purpose layer, concretely cmd/ward-kdl/ward-kdl.fleet.kdl (cli-guard fleetconfig, dialect 2) plus the deployment-specific values #441 exposed (the forgejo.coilysiren.me base-url, the SSM token path, the restrict owner matches coily* gate, the attribution defaults). This is the per-user meld layer every ward adopter rewrites to their own fleet, so it belongs up in aos (reference impl) as a swappable build input, not compiled into the shippable ward product.

Carry the embed/generation contract: ward-kdl.fleet.kdl is the single hand-edited source, make sync-fleet-assets copies it to cmd/ward/fleetassets/fleet.generated.kdl for go:embed, and fleetassets_test.go / the two-way pin (agent_adapter_test.go) fail the build on drift. The move must preserve that source -> embed -> pin chain from wherever the spec bundle ends up, so WARD_SPECS=<bundle> (or the assets-dir convention from the body above) resolves the fleet manifest cleanly.

Prereq / sequencing

Blocked on ward#435 (scope guardfiles into read/write/admin, relocate to .ward/, config -> KDL). #435 produces the trifecta-scoped, .ward/-homed structure. This issue then lifts the user-purpose slice of that structure up into aos as the swappable input. Dispatch after #435 closes. (#435 is itself blocked on ward#547.)

Chain: ward#547 (observe surface) -> ward#435 (restructure) -> ward#453 (this, aos user-layer move).

## Why Decision direction from Kai (2026-07-01, post-pressure-test-sweep): the KDL specs — the ops guardfiles and the fleet manifest — likely move out of ward, up into aos. The line #441 exposed is product-vs-deployment: ward's engine/agent/exec layers are generic, while `base-url "forgejo.coilysiren.me/api/v1"`, the SSM token path, the `restrict owner matches coily*` gate, and the attribution defaults are deployment config. aos already owns that layer in spirit — the `.ward/ward.yaml` catalog schema comment points there, the pre-commit suite comes from there, the fleet grammar work is aos#310, the dev-base image is aos-built. The specs would be moving to where their siblings already live, and ward becomes honestly publishable. ## Deliverable The move, with the condition that makes it actually fix #441 rather than relocate it: - The spec bundle becomes a **declared, swappable build input** (`make WARD_SPECS=...` or an assets-dir convention), not a new hardcode one repo further from the cold reader's eyes. Today the coupling at least sits in ward's own tree where the sweep found it; a silent relocation makes it less visible while leaving it just as real. - A minimal example spec bundle (or template repo) stays where a ward adopter starts, so bring-your-own-specs is a documented path. - The KDL authoring reference lands in one findable place at the same time — the sweep already found the grammar scattered across two repos (#437/#440); a third home for the specs deepens that maze unless the authoring doc anchors it. ## Done condition ward's tree contains no coilyco-specific endpoint/token/owner values; a downstream builder can point the build at their own spec bundle by following one documented path; #441's compiled-in coupling claims no longer reproduce against a build made from the example bundle. Related: #441 (the finding), #395 / #396 (externalize infra topology / fleet inventory), #437 / #440 (authoring docs). --- Filed by Claude Code, capturing Kai's release-direction decisions from the 2026-07-01 pressure-test debrief. --- ## Refresh + precise target (2026-07-05 director session) Confirming the layer that moves up: the **individual user-purpose layer**, concretely `cmd/ward-kdl/ward-kdl.fleet.kdl` (cli-guard fleetconfig, **dialect 2**) plus the deployment-specific values #441 exposed (the `forgejo.coilysiren.me` base-url, the SSM token path, the `restrict owner matches coily*` gate, the attribution defaults). This is the per-user meld layer every ward adopter rewrites to their own fleet, so it belongs up in aos (reference impl) as a swappable build input, not compiled into the shippable ward product. Carry the embed/generation contract: `ward-kdl.fleet.kdl` is the single hand-edited source, `make sync-fleet-assets` copies it to `cmd/ward/fleetassets/fleet.generated.kdl` for `go:embed`, and `fleetassets_test.go` / the two-way pin (`agent_adapter_test.go`) fail the build on drift. The move must preserve that source -> embed -> pin chain from wherever the spec bundle ends up, so `WARD_SPECS=<bundle>` (or the assets-dir convention from the body above) resolves the fleet manifest cleanly. ## Prereq / sequencing **Blocked on ward#435** (scope guardfiles into read/write/admin, relocate to `.ward/`, config -> KDL). #435 produces the trifecta-scoped, `.ward/`-homed structure. This issue then lifts the user-purpose slice of that structure up into aos as the swappable input. Dispatch after #435 closes. (#435 is itself blocked on ward#547.) Chain: ward#547 (observe surface) -> ward#435 (restructure) -> ward#453 (this, aos user-layer move).
Author
Member

Cold-read datapoint for this move (drive-by-critic/docs-ia, run 36): docs/ currently ships 23 ward-kdl guardfile reference pages (trello, glama, glitchtip, signoz, ollama, …) alongside ~40 product docs, with no getting-started page at the same level. To a hostile stranger the IA reads as 'personal dotfiles cosplaying as a product' — the planned move of the KDL specs up into aos directly disarms that, so flagging it as an adoption-facing payoff of this issue, not just an engineering cleanup.

Cold-read datapoint for this move (drive-by-critic/docs-ia, run 36): docs/ currently ships 23 ward-kdl guardfile reference pages (trello, glama, glitchtip, signoz, ollama, …) alongside ~40 product docs, with no getting-started page at the same level. To a hostile stranger the IA reads as 'personal dotfiles cosplaying as a product' — the planned move of the KDL specs up into aos directly disarms that, so flagging it as an adoption-facing payoff of this issue, not just an engineering cleanup.
coilyco-ops added this to the ward launch milestone 2026-07-01 23:29:47 +00:00
Author
Member

DECISION - assets-dir convention (not a make var) for the swappable spec bundle. Confirmed headless for autonomous dispatch; cross-repo ward+aos PRs expected. Recorded by Claude Code (Fable) during the 2026-07-01 ward launch triage session with Kai.

DECISION - assets-dir convention (not a make var) for the swappable spec bundle. Confirmed headless for autonomous dispatch; cross-repo ward+aos PRs expected. Recorded by Claude Code (Fable) during the 2026-07-01 ward launch triage session with Kai.
Author
Member

🔒 Reserved by ward agent --driver claude — container engineer-claude-ward-453 on host kais-macbook-pro-2.local is carrying this issue (reserved 2026-07-02T02:48:50Z). Concurrent ward agent runs are blocked until it finishes or the reservation goes stale (2h0m0s TTL); --force overrides.

— Claude (she/her), via ward agent

<!-- ward-agent-reservation --> 🔒 Reserved by `ward agent --driver claude` — container `engineer-claude-ward-453` on host `kais-macbook-pro-2.local` is carrying this issue (reserved 2026-07-02T02:48:50Z). Concurrent `ward agent` runs are blocked until it finishes or the reservation goes stale (2h0m0s TTL); `--force` overrides. <!-- ward-agent-signature --> — Claude (she/her), via `ward agent`
Owner

WARD-OUTCOME: blocked - neutralizing ward's default bundle breaks brew-from-source for the whole fleet, so finishing needs a human call: grant the (ungranted) homebrew-tap repo to re-point the formula at an aos-hosted bundle, or pick an alternative that keeps the default brew build working.

This one looked like a file move and turned into a deployment-topology puzzle. The mechanism half was clean and satisfying: a neutral example bundle (examples/ward-specs/), the assets-dir convention, one findable authoring anchor, and a test that actually proves a build from the example carries none of the values #441 flagged. That landed green on main.

What fought back was the last inch. Done-condition 1 wants ward's tree fully coilyco-free, but ward's formula builds from source, so flipping the tracked bundle to placeholders would neutralize every brew install ward and take ward ops forgejo, the trust gate, and attribution down for the whole fleet. Doing it safely means re-pointing the tap formula (not granted to this run) and the release jobs at an aos-hosted bundle, in lockstep with the aos move. That is exactly the externally-visible, costly-to-undo wall, so I stopped short rather than ship a fleet-breaking main.

Two surprises worth noting: FEATURES.md is pinned at exactly 3999/4000 chars, so there was no room for an inventory bullet without displacing someone else's - I left the feature to the authoring doc. And main was busy enough that I re-merged a few times to land.

Confidence is high on what shipped and honest about what did not. Tracked the rest as aos#315 (home the bundle in aos) and ward#503 (the flip + build-site re-point). The fork for you lives in ward#503.

WARD-OUTCOME: blocked - neutralizing ward's default bundle breaks brew-from-source for the whole fleet, so finishing needs a human call: grant the (ungranted) homebrew-tap repo to re-point the formula at an aos-hosted bundle, or pick an alternative that keeps the default brew build working. This one looked like a file move and turned into a deployment-topology puzzle. The mechanism half was clean and satisfying: a neutral example bundle (`examples/ward-specs/`), the assets-dir convention, one findable authoring anchor, and a test that actually proves a build from the example carries none of the values #441 flagged. That landed green on main. What fought back was the last inch. Done-condition 1 wants ward's tree fully coilyco-free, but ward's formula builds **from source**, so flipping the tracked bundle to placeholders would neutralize every `brew install ward` and take `ward ops forgejo`, the trust gate, and attribution down for the whole fleet. Doing it safely means re-pointing the tap formula (not granted to this run) and the release jobs at an aos-hosted bundle, in lockstep with the aos move. That is exactly the externally-visible, costly-to-undo wall, so I stopped short rather than ship a fleet-breaking main. Two surprises worth noting: FEATURES.md is pinned at exactly 3999/4000 chars, so there was no room for an inventory bullet without displacing someone else's - I left the feature to the authoring doc. And main was busy enough that I re-merged a few times to land. Confidence is high on what shipped and honest about what did not. Tracked the rest as aos#315 (home the bundle in aos) and ward#503 (the flip + build-site re-point). The fork for you lives in ward#503.
Author
Member

🔒 Reserved by ward agent --driver claude — container engineer-claude-ward-453 on host kais-macbook-pro-2.local is carrying this issue (reserved 2026-07-02T07:57:50Z). Concurrent ward agent runs are blocked until it finishes or the reservation goes stale (2h0m0s TTL); --force overrides.

— Claude (she/her), via ward agent

<!-- ward-agent-reservation --> 🔒 Reserved by `ward agent --driver claude` — container `engineer-claude-ward-453` on host `kais-macbook-pro-2.local` is carrying this issue (reserved 2026-07-02T07:57:50Z). Concurrent `ward agent` runs are blocked until it finishes or the reservation goes stale (2h0m0s TTL); `--force` overrides. <!-- ward-agent-signature --> — Claude (she/her), via `ward agent`
Owner

WARD-OUTCOME: blocked - the in-ward mechanism/example/docs already landed (32b5efd); the final "clean tree" done-condition needs a human topology decision (aos push + homebrew-tap access to relocate the coilyco bundle and re-point the build sites) that this run was not granted.

Retrospective, candid: this one mostly fought back before I wrote a line of code, and the fight was the useful part. I front-loaded ward-kdl.md / -surface / -in-ward and exec-verb, then found the interesting thing in git: run 32b5efd had already shipped the swappable-input mechanism, the neutral examples/ward-specs/ bundle, the authoring anchor, and a test proving a build from the example carries none of the #441 values. Done-conditions #2 and #3 are met and green (TestExampleBundleHasNoCoilycoValues / TestExampleFleetParses pass).

What surprised me: the coupling doesn't just live in cmd/ward-kdl/ authoring sources, it's baked into the committed embed assets (cmd/ward/opsassets/forgejo.guardfile.generated.kdl, cmd/ward/fleetassets/fleet.generated.kdl) that plain go build ./cmd/ward bakes into the shipped binary. Since both the release job and the brew formula build from source, neutralizing the tracked bundle to satisfy done-condition #1 would hand every brew upgrade a ward pointed at git.example.com - fleet-wide breakage of ward ops forgejo and ward agent. That's the same wall Kai named in her 03:11 comment, and it's real: the fix requires an external home for the coilyco bundle (aos, which is read-only /substrate here, no push grant) plus re-pointing the ungranted homebrew-tap formula and release job - a strict sequence that cannot start from ward's clone alone.

I deliberately made no tree changes. The mechanism decision is already settled as the assets-dir convention (the authoring doc explicitly rejects a make-var), so there was no fleet-safe, in-scope increment left to add without contradicting reviewed work or breaking the fleet. Confidence that this is genuinely blocked (not me under-reaching): high - I confirmed the shipped-asset embedding, the dual build-from-source sites, and the settled mechanism decision directly.

The one decision needed: grant aos + homebrew-tap (or make the call directly) so the coilyco bundle can be authored into aos, the tap formula + release job re-pointed at it via the existing assets-dir overlay, and only then ward's tree neutralized - in that order. A clean follow-up worth filing once unblocked: a single cross-repo landing checklist so the flip is one reviewable change per repo rather than a scramble.

WARD-OUTCOME: blocked - the in-ward mechanism/example/docs already landed (32b5efd); the final "clean tree" done-condition needs a human topology decision (aos push + homebrew-tap access to relocate the coilyco bundle and re-point the build sites) that this run was not granted. Retrospective, candid: this one mostly fought back before I wrote a line of code, and the fight was the useful part. I front-loaded ward-kdl.md / -surface / -in-ward and exec-verb, then found the interesting thing in git: run 32b5efd had already shipped the swappable-input mechanism, the neutral examples/ward-specs/ bundle, the authoring anchor, and a test proving a build from the example carries none of the #441 values. Done-conditions #2 and #3 are met and green (TestExampleBundleHasNoCoilycoValues / TestExampleFleetParses pass). What surprised me: the coupling doesn't just live in cmd/ward-kdl/ authoring sources, it's baked into the committed embed assets (cmd/ward/opsassets/forgejo.guardfile.generated.kdl, cmd/ward/fleetassets/fleet.generated.kdl) that plain `go build ./cmd/ward` bakes into the shipped binary. Since both the release job and the brew formula build from source, neutralizing the tracked bundle to satisfy done-condition #1 would hand every `brew upgrade` a ward pointed at git.example.com - fleet-wide breakage of `ward ops forgejo` and `ward agent`. That's the same wall Kai named in her 03:11 comment, and it's real: the fix requires an external home for the coilyco bundle (aos, which is read-only /substrate here, no push grant) plus re-pointing the ungranted homebrew-tap formula and release job - a strict sequence that cannot start from ward's clone alone. I deliberately made no tree changes. The mechanism decision is already settled as the assets-dir convention (the authoring doc explicitly rejects a make-var), so there was no fleet-safe, in-scope increment left to add without contradicting reviewed work or breaking the fleet. Confidence that this is genuinely blocked (not me under-reaching): high - I confirmed the shipped-asset embedding, the dual build-from-source sites, and the settled mechanism decision directly. The one decision needed: grant aos + homebrew-tap (or make the call directly) so the coilyco bundle can be authored into aos, the tap formula + release job re-pointed at it via the existing assets-dir overlay, and only then ward's tree neutralized - in that order. A clean follow-up worth filing once unblocked: a single cross-repo landing checklist so the flip is one reviewable change per repo rather than a scramble.
Author
Member

🔎 ward agent advisor

ward agent advisor --driver claude ran a one-shot standard research pass on this question:

Post a comment on ward#453 with the concrete file-level cross-repo landing checklist to finish it. Do NOT change code. Kai has decided approach (a): ward's tracked cmd/ward-kdl/ becomes the neutral example bundle so a plain make build is publishable, the coilyco bundle is homed in aos (aos#315), and Kai's homebrew-tap Formula/ward.rb + release.yml overlay the pinned aos bundle before building so the fleet's shipped artifacts stay coilyco. The mechanism already landed on ward main (examples/ward-specs/, the assets-dir convention where the build reads cmd/ward-kdl/ and you swap by overlaying, docs/ward-kdl-authoring.md, and cmd/ward TestExampleBundleHasNoCoilycoValues). Ground yourself in docs/ward-kdl-authoring.md and the Makefile ward-kdl targets. Deliver one reviewable change per repo: (1) aos - exact home path for the coilyco bundle plus the file set and a PINNED fetch mechanism (raw URL or release asset, justified against the config-placement law); (2) ward - exact tracked files to neutralize (cmd/ward-kdl/ coilyco guardfiles + locks, embedded opsassets/execassets/fleetassets, testdata golden) and the release.yml overlay step insertion point; (3) homebrew-tap - a PROPOSED Formula/ward.rb overlay, noting the tap is not granted to this run and is Kai's gate; (4) the strict landing sequence and the green checks per step. Public-safe, repo voice rules (no em-dashes, no semicolons in prose, name the actor).


I now have the full ground truth. Writing the checklist comment.

{
  "summary": "## ward#453 landing checklist - the cross-repo flip to a clean ward tree\n\nGrounded in `docs/ward-kdl-authoring.md` (the settled assets-dir convention, make-var explicitly rejected) and the `Makefile` `build-ward-kdl` / `sync-*-assets` targets. This is the file-level sequence to finish done-condition #1 (ward's tree carries no coilyco endpoint/token/owner values) without breaking the fleet's `brew install ward`. The in-ward mechanism already landed (32b5efd): `examples/ward-specs/`, the overlay-`cmd/ward-kdl/` convention, `docs/ward-kdl-authoring.md`, and `TestExampleBundleHasNoCoilycoValues`. Approach (a) is decided by Kai, so what remains is a strict three-repo flip.\n\n### The two build-from-source sites that force the sequence\n\nBoth shipped artifacts build from source and bake the **committed** generated embeds into the binary, not the `cmd/ward-kdl/` sources:\n\n* `.forgejo/workflows/release.yml` (lines 121-127) - `go build ./cmd/ward` per OS/arch. It does **not** run `make build-ward-kdl`. It ships whatever `cmd/ward/opsassets/*.generated.*`, `cmd/ward/fleetassets/fleet.generated.kdl`, and `cmd/ward/execassets/*` carry at that commit.\n* Kai's `coilysiren/homebrew-tap` `Formula/ward.rb` - a from-source `go build` in the brew sandbox (`GOPROXY=direct`, per `docs/homebrew-build.md`), same embed dependency.\n\nSo the instant ward's tracked embeds go neutral, every `brew upgrade` and every release binary ships a ward pointed at `git.example.com` with the `example*` gate - fleet-wide loss of `ward ops forgejo`, the trust gate, and attribution. That is why neutralizing ward's tree is the **last** step, gated on aos hosting the coilyco bundle and both build sites overlaying it first.\n\n### The authoritative acceptance gate\n\nThe `examplespecs_test.go` tokenizer is the ground truth: a file is coilyco-dirty if it matches `coilysiren`, `coilyco`, or `coily`. The clean-tree acceptance check for the spec bundle is:\n\n```\ngrep -rliE 'coilysiren|coilyco|coily' cmd/ward-kdl cmd/ward/opsassets cmd/ward/fleetassets cmd/ward/execassets cmd/ward/testdata\n```\n\nToday that returns the file set below. Done-condition #1 is met when it returns nothing (the `.go` engine files that also match are a **separate** concern - see the scope note at the end).\n\n---\n\n## Repo 1 (unblocks the others): `coilyco-flight-deck/agentic-os` - home the coilyco bundle (aos#315)\n\naos is the reference-impl + deployment layer that already owns the fleet grammar (aos#310), the pre-commit suite, and the dev-base image, so the coilyco spec bundle moves to where its siblings live.\n\n**Home path:** `ward-specs/` at the aos repo root, mirroring ward's `examples/ward-specs/` name so the two are obviously a neutral/real pair. Filenames match `cmd/ward-kdl/` exactly so the overlay is a straight copy, no rename map.\n\n**File set (the real deployment values the sweep flagged, tier 1):**\n\n* `ward-specs/ward-kdl.forgejo.guardfile.kdl` - carries `base-url \"forgejo.coilysiren.me/api/v1\"`, the `ssm` forgejo token path, and `restrict owner matches coily*`.\n* `ward-specs/ward-kdl.fleet.kdl` - carries `attribution name=coilyco-ops email=coilyco-ops@coilysiren.me`.\n* `ward-specs/ward-kdl-read/ward-kdl.forgejo.read.guardfile.kdl`, `ward-kdl-write/ward-kdl.forgejo.write.guardfile.kdl`, `ward-kdl-admin/ward-kdl.forgejo.admin.guardfile.kdl` - the tier copies of the forgejo surface.\n* `ward-specs/ward-kdl.signoz.guardfile.kdl` + `signoz.openapi.json` + `signoz.openapi.lock.json` (and the `ward-kdl-read/ward-kdl.signoz.read.guardfile.kdl` + per-tier `signoz.openapi.lock.json` copies) - carry the `/coilysiren/...` SSM base-url and token paths.\n* `ward-specs/ward-kdl.ollama.guardfile.kdl` - the tower `/coilysiren/ollama/host` SSM path (exec dialect).\n* `ward-specs/ward-kdl.tailscale.guardfile.kdl` (+ tier placeholders) - the `restrict tailnet matches coily*` gate.\n* `ward-specs/ward-kdl.skillsmp.guardfile.kdl` + `skillsmp.openapi.json`/`.lock.json`, `ward-kdl.glama.guardfile.kdl`, `ward-kdl.brew.guardfile.kdl` - these carry only a provenance comment naming the retired `coily` tool (tier 2, prose not values). Include them in the bundle for completeness, but they can alternatively be scrubbed-in-place in ward rather than relocated (call it in review).\n\nDecide in aos#315 whether the bundle also ships the **pre-generated embeds** (`opsassets/forgejo.guardfile.generated.kdl`, `fleetassets/fleet.generated.kdl`, `execassets/ward-kdl.{ollama,brew}.guardfile.kdl`, `testdata/fleet.generated.golden.kdl`). Recommended **yes** - see the brew-sandbox note under Repo 3. Then a fleet build overlays the final embed bytes and `go build` alone reproduces today's binary, with no need to run `specverb-gen` or re-fetch the forgejo swagger inside the sandbox.\n\n**Pinned fetch mechanism (justified against the config-placement law):**\n\nPublish the bundle as a **versioned release asset** on aos, `ward-specs-<tag>.tar.gz`, and have both build sites fetch it by an explicit tag **and verify a recorded `sha256`** (the same SHA256SUMS discipline ward already uses for its own binaries). The pin lives as a literal `WARD_SPECS_REF` + checksum in `release.yml` and in the tap formula, bumped deliberately like the `REF ?=` cli-guard pin in the `Makefile`, never floating on a branch. A raw URL at a pinned tag or commit SHA (`.../agentic-os/raw/tag/<tag>/ward-specs/...`) is an acceptable lighter alternative, but a release asset with a checksum is the stronger supply-chain pin and is what a hostile cold-reader would want to see.\n\n*Why this respects the law:* the config-placement corollary forbids a **shipped product** reaching up into a reference repo for its **runtime** config. This fetch is (1) **build-time**, not runtime - the shipped ward binary stays fully self-contained with nothing fetched at run; (2) performed by **Kai's deployment tooling** (the tap formula and `release.yml`), which is itself the deployment layer, not by ward-the-product; and (3) invisible to external users - a plain `make build-ward-kdl` reads the neutral `cmd/ward-kdl/` tree and reaches nothing. So only Kai's own fleet build overlays her own bundle from her own layer. That is the meld-layer melding to its own values, which the law explicitly blesses, not a generic product reaching upward.\n\n**Green check for this step:** `ward-specs-<tag>.tar.gz` exists on the aos release, its `sha256` is recorded, and a local `curl` + `tar` + `make build-ward-kdl` + `go build ./cmd/ward` in a fresh ward clone with the bundle overlaid produces a binary whose `ward ops forgejo` and `ward agent` attribution match today's.\n\n---\n\n## Repo 2: `coilyco-flight-deck/ward` - neutralize the tree and overlay in CI (ward#503)\n\nThis is the change that makes a plain `make` build publishable. It lands **after** Repo 1 and **after** the tap is re-pointed (Repo 3), because the moment it merges, `release.yml` must already overlay or the release ships neutral.\n\n**A. Files to neutralize (replace coilyco values with the `examples/ward-specs/` placeholders):**\n\n* Sources under `cmd/ward-kdl/`: `ward-kdl.forgejo.guardfile.kdl`, `ward-kdl.fleet.kdl`, `ward-kdl.signoz.guardfile.kdl` + `signoz.openapi.json`/`.lock.json`, `ward-kdl.ollama.guardfile.kdl`, `ward-kdl.tailscale.guardfile.kdl`, and (tier-2 prose) `ward-kdl.skillsmp.guardfile.kdl` + `skillsmp.openapi.json`/`.lock.json`, `ward-kdl.glama.guardfile.kdl`, `ward-kdl.brew.guardfile.kdl`.\n* Tier copies: `cmd/ward-kdl/ward-kdl-{read,write,admin}/ward-kdl.forgejo.{read,write,admin}.guardfile.kdl`, `ward-kdl-read/ward-kdl.signoz.read.guardfile.kdl`, and the per-tier `signoz.openapi.lock.json` + `specverb.lock` copies. The tailscale tier files are already `.placeholder`, so only the `coily*` tailnet string needs the swap.\n* Embedded generated assets: `cmd/ward/opsassets/forgejo.guardfile.generated.kdl`, `cmd/ward/fleetassets/fleet.generated.kdl`, `cmd/ward/execassets/ward-kdl.ollama.guardfile.kdl` and `execassets/ward-kdl.brew.guardfile.kdl`.\n* Golden fixture: `cmd/ward/testdata/fleet.generated.golden.kdl` (the `coilyco-ops` attribution line).\n* `cmd/ward/opsassets/forgejo.swagger.lock.generated.json` and `cmd/ward-kdl/forgejo.swagger.lock.json` are **host-neutral** (not in the grep set) - leave them.\n\nThe clean way to produce A is not hand-editing 20 files but running the documented overlay in reverse: copy `examples/ward-specs/*` into `cmd/ward-kdl/`, run `make build-ward-kdl` (regenerates every `opsassets`/`fleetassets`/`execassets` + the tier docs), then commit. `sync-ops-assets` / `sync-fleet-assets` / `sync-exec-assets` and the `*_test.go` drift guards keep the embeds in lockstep, so a single `make build-ward-kdl` is the whole edit. The golden fixture is regenerated by the same run or by the roster/golden update target.\n\n**B. The `release.yml` overlay step - insertion point:**\n\nInsert one step in the cross-compile job **between \"Install Go\" (line 84) and \"Cross-compile the full ward matrix\" (line 91)**, before any `go build`:\n\n```yaml\n      - name: Overlay the coilyco spec bundle (ward#453)\n        env:\n          WARD_SPECS_REF: <pinned-aos-tag>\n          WARD_SPECS_SHA256: <recorded-checksum>\n        run: |\n          set -euo pipefail\n          curl -fsSL \"${AOS_RELEASE_API}/ward-specs-${WARD_SPECS_REF}.tar.gz\" -o /tmp/ward-specs.tgz\n          echo \"${WARD_SPECS_SHA256}  /tmp/ward-specs.tgz\" | sha256sum -c -\n          tar -xzf /tmp/ward-specs.tgz -C cmd/ward-kdl --strip-components=1\n          # if the bundle ships pre-generated embeds, drop them straight into cmd/ward/{opsassets,fleetassets,execassets,testdata}\n          # otherwise: make build-ward-kdl  (needs specverb-gen + forgejo swagger fetch, already GOPROXY=direct)\n```\n\nGuard it so a missing/blank `WARD_SPECS_REF` **fails the release loudly** rather than shipping a neutral binary. That failure mode is exactly the fleet-break the sequence exists to prevent, so it must be fail-closed, matching the existing `CI_RELEASE_TOKEN` empty-check pattern already in that file.\n\n**Green checks for this step:** `make build-ward-kdl && make test` green on the neutralized tree (`TestExampleBundleHasNoCoilycoValues`, `TestExampleFleetParses`, and the `opsassets_test` / `fleetassets_test` / `execassets_test` drift guards all pass), the acceptance grep above returns nothing, and a release dry-run with the overlay step produces a binary whose `ward ops forgejo --help` shows `forgejo.coilysiren.me` and the `coily*` gate.\n\n---\n\n## Repo 3 (Kai's gate, PROPOSED): `coilysiren/homebrew-tap` - `Formula/ward.rb` overlay\n\n**This run is not granted the tap and does not touch it. Kai applies this change (or delegates it) - it is her gate, and it is on GitHub, which is PR-gated.** Proposed shape only:\n\nAdd the bundle as a pinned brew `resource` (the sandbox-legal, checksummed way to pull a second input) and stage it into `cmd/ward-kdl/` before the existing build:\n\n```ruby\n  resource \"ward-specs\" do\n    url \"https://forgejo.coilysiren.me/coilyco-flight-deck/agentic-os/releases/download/<pinned-aos-tag>/ward-specs-<pinned-aos-tag>.tar.gz\"\n    sha256 \"<recorded-checksum>\"\n  end\n\n  def install\n    resource(\"ward-specs\").stage do\n      cp_r Dir[\"*\"], buildpath/\"cmd/ward-kdl\"\n    end\n    # existing GOPROXY=direct GOSUMDB=off go build ./cmd/ward, unchanged\n  end\n```\n\n**Brew-sandbox note (why the aos bundle should ship pre-generated embeds):** the settled convention is overlay-`cmd/ward-kdl/`-then-`make build-ward-kdl`. But `build-ward-kdl` runs `go run specverb-gen lock`, which for the remote-spec forgejo area **fetches the swagger upstream**, and the brew sandbox is network-constrained. If the bundle instead also carries the final `opsassets`/`fleetassets`/`execassets`/`testdata` bytes, the formula stages them straight into `cmd/ward/...` and the existing `go build` bakes them in with **no** `specverb-gen` run and **no** extra network fetch. That keeps the fleet's brew build as deterministic as it is today. This is the same assets-dir convention, overlaid one layer lower (the embeds) for the sandbox path - not a contradiction of the reviewed decision. Confirm the preference in aos#315 so both build sites overlay the same way.\n\n**Green check for this step:** `brew install --build-from-source ward` on a clean machine yields a binary whose `ward ops forgejo` and `ward agent` attribution are coilyco, identical to the pre-flip release.\n\n---\n\n## Strict landing sequence (each step gates the next)\n\n1. **aos#315** - author `ward-specs/` in aos, publish `ward-specs-<tag>.tar.gz` as a release asset, record its `sha256`. *Green:* asset exists, checksum recorded, a local overlaid build reproduces today's coilyco binary. Nothing in ward or the tap changes yet, so the fleet is untouched.\n2. **homebrew-tap `Formula/ward.rb`** (Kai) - add the pinned `resource` + stage. *Green:* `brew install --build-from-source ward` still ships a coilyco binary while ward's tree is still coilyco (the overlay is a no-op superset at this point, so it is safe to land before the neutralization).\n3. **ward#503 `release.yml`** - add the overlay step, fail-closed on a blank pin, still against the coilyco tree. *Green:* a release dry-run with the overlay ships a coilyco binary. Now both build sites overlay, so neutralizing the tree can no longer break a shipped artifact.\n4. **ward#503 tree neutralization** - run the reverse-overlay + `make build-ward-kdl`, commit the neutral `cmd/ward-kdl/` + embeds + golden. *Green:* the acceptance grep returns nothing, `make test` green, `TestExampleBundleHasNoCoilycoValues` green, and the next release + `brew upgrade` still ship coilyco binaries via the overlays from steps 2-3.\n\nDone-condition #1 is satisfied at step 4, and #441's compiled-in-coupling claims no longer reproduce against a plain `make` build from ward's tree. Kai (or a granted run) owns step 2, the agent owns 1, 3, and 4. A single cross-repo landing note pinning the exact `<tag>`/`sha256` used in steps 1-3 is worth filing so the three pins never drift apart.\n\n## Scope note - what this issue does NOT cover\n\nThe acceptance grep over the **whole** `cmd/ward` also matches ~100 `.go` engine files (`agent_*.go`, `forgejo_ops.go`, `pkg_brew.go`, and their tests) plus `containerassets/preclone-repos.txt`. Those are engine references and provenance comments, not the KDL spec bundle, and they are a distinct externalization concern (#395 / #396 territory - infra topology and fleet inventory hardcoded in Go). This issue moves the **KDL specs only**. If any of those `.go` files carry a genuine hardcoded endpoint/token/owner default (as opposed to a comment or the `examplespecs_test.go` token list itself), that is worth its own finding under #441, not folded here."
  ,
  "issues": []
}

Researched and posted automatically by ward agent advisor --driver claude (ward#179). This is one-shot research, not a carried change - verify before acting on it.

— Claude (she/her), via ward agent

### 🔎 ward agent advisor `ward agent advisor --driver claude` ran a one-shot **standard** research pass on this question: > Post a comment on ward#453 with the concrete file-level cross-repo landing checklist to finish it. Do NOT change code. Kai has decided approach (a): ward's tracked cmd/ward-kdl/ becomes the neutral example bundle so a plain make build is publishable, the coilyco bundle is homed in aos (aos#315), and Kai's homebrew-tap Formula/ward.rb + release.yml overlay the pinned aos bundle before building so the fleet's shipped artifacts stay coilyco. The mechanism already landed on ward main (examples/ward-specs/, the assets-dir convention where the build reads cmd/ward-kdl/ and you swap by overlaying, docs/ward-kdl-authoring.md, and cmd/ward TestExampleBundleHasNoCoilycoValues). Ground yourself in docs/ward-kdl-authoring.md and the Makefile ward-kdl targets. Deliver one reviewable change per repo: (1) aos - exact home path for the coilyco bundle plus the file set and a PINNED fetch mechanism (raw URL or release asset, justified against the config-placement law); (2) ward - exact tracked files to neutralize (cmd/ward-kdl/ coilyco guardfiles + locks, embedded opsassets/execassets/fleetassets, testdata golden) and the release.yml overlay step insertion point; (3) homebrew-tap - a PROPOSED Formula/ward.rb overlay, noting the tap is not granted to this run and is Kai's gate; (4) the strict landing sequence and the green checks per step. Public-safe, repo voice rules (no em-dashes, no semicolons in prose, name the actor). --- I now have the full ground truth. Writing the checklist comment. ```json { "summary": "## ward#453 landing checklist - the cross-repo flip to a clean ward tree\n\nGrounded in `docs/ward-kdl-authoring.md` (the settled assets-dir convention, make-var explicitly rejected) and the `Makefile` `build-ward-kdl` / `sync-*-assets` targets. This is the file-level sequence to finish done-condition #1 (ward's tree carries no coilyco endpoint/token/owner values) without breaking the fleet's `brew install ward`. The in-ward mechanism already landed (32b5efd): `examples/ward-specs/`, the overlay-`cmd/ward-kdl/` convention, `docs/ward-kdl-authoring.md`, and `TestExampleBundleHasNoCoilycoValues`. Approach (a) is decided by Kai, so what remains is a strict three-repo flip.\n\n### The two build-from-source sites that force the sequence\n\nBoth shipped artifacts build from source and bake the **committed** generated embeds into the binary, not the `cmd/ward-kdl/` sources:\n\n* `.forgejo/workflows/release.yml` (lines 121-127) - `go build ./cmd/ward` per OS/arch. It does **not** run `make build-ward-kdl`. It ships whatever `cmd/ward/opsassets/*.generated.*`, `cmd/ward/fleetassets/fleet.generated.kdl`, and `cmd/ward/execassets/*` carry at that commit.\n* Kai's `coilysiren/homebrew-tap` `Formula/ward.rb` - a from-source `go build` in the brew sandbox (`GOPROXY=direct`, per `docs/homebrew-build.md`), same embed dependency.\n\nSo the instant ward's tracked embeds go neutral, every `brew upgrade` and every release binary ships a ward pointed at `git.example.com` with the `example*` gate - fleet-wide loss of `ward ops forgejo`, the trust gate, and attribution. That is why neutralizing ward's tree is the **last** step, gated on aos hosting the coilyco bundle and both build sites overlaying it first.\n\n### The authoritative acceptance gate\n\nThe `examplespecs_test.go` tokenizer is the ground truth: a file is coilyco-dirty if it matches `coilysiren`, `coilyco`, or `coily`. The clean-tree acceptance check for the spec bundle is:\n\n```\ngrep -rliE 'coilysiren|coilyco|coily' cmd/ward-kdl cmd/ward/opsassets cmd/ward/fleetassets cmd/ward/execassets cmd/ward/testdata\n```\n\nToday that returns the file set below. Done-condition #1 is met when it returns nothing (the `.go` engine files that also match are a **separate** concern - see the scope note at the end).\n\n---\n\n## Repo 1 (unblocks the others): `coilyco-flight-deck/agentic-os` - home the coilyco bundle (aos#315)\n\naos is the reference-impl + deployment layer that already owns the fleet grammar (aos#310), the pre-commit suite, and the dev-base image, so the coilyco spec bundle moves to where its siblings live.\n\n**Home path:** `ward-specs/` at the aos repo root, mirroring ward's `examples/ward-specs/` name so the two are obviously a neutral/real pair. Filenames match `cmd/ward-kdl/` exactly so the overlay is a straight copy, no rename map.\n\n**File set (the real deployment values the sweep flagged, tier 1):**\n\n* `ward-specs/ward-kdl.forgejo.guardfile.kdl` - carries `base-url \"forgejo.coilysiren.me/api/v1\"`, the `ssm` forgejo token path, and `restrict owner matches coily*`.\n* `ward-specs/ward-kdl.fleet.kdl` - carries `attribution name=coilyco-ops email=coilyco-ops@coilysiren.me`.\n* `ward-specs/ward-kdl-read/ward-kdl.forgejo.read.guardfile.kdl`, `ward-kdl-write/ward-kdl.forgejo.write.guardfile.kdl`, `ward-kdl-admin/ward-kdl.forgejo.admin.guardfile.kdl` - the tier copies of the forgejo surface.\n* `ward-specs/ward-kdl.signoz.guardfile.kdl` + `signoz.openapi.json` + `signoz.openapi.lock.json` (and the `ward-kdl-read/ward-kdl.signoz.read.guardfile.kdl` + per-tier `signoz.openapi.lock.json` copies) - carry the `/coilysiren/...` SSM base-url and token paths.\n* `ward-specs/ward-kdl.ollama.guardfile.kdl` - the tower `/coilysiren/ollama/host` SSM path (exec dialect).\n* `ward-specs/ward-kdl.tailscale.guardfile.kdl` (+ tier placeholders) - the `restrict tailnet matches coily*` gate.\n* `ward-specs/ward-kdl.skillsmp.guardfile.kdl` + `skillsmp.openapi.json`/`.lock.json`, `ward-kdl.glama.guardfile.kdl`, `ward-kdl.brew.guardfile.kdl` - these carry only a provenance comment naming the retired `coily` tool (tier 2, prose not values). Include them in the bundle for completeness, but they can alternatively be scrubbed-in-place in ward rather than relocated (call it in review).\n\nDecide in aos#315 whether the bundle also ships the **pre-generated embeds** (`opsassets/forgejo.guardfile.generated.kdl`, `fleetassets/fleet.generated.kdl`, `execassets/ward-kdl.{ollama,brew}.guardfile.kdl`, `testdata/fleet.generated.golden.kdl`). Recommended **yes** - see the brew-sandbox note under Repo 3. Then a fleet build overlays the final embed bytes and `go build` alone reproduces today's binary, with no need to run `specverb-gen` or re-fetch the forgejo swagger inside the sandbox.\n\n**Pinned fetch mechanism (justified against the config-placement law):**\n\nPublish the bundle as a **versioned release asset** on aos, `ward-specs-<tag>.tar.gz`, and have both build sites fetch it by an explicit tag **and verify a recorded `sha256`** (the same SHA256SUMS discipline ward already uses for its own binaries). The pin lives as a literal `WARD_SPECS_REF` + checksum in `release.yml` and in the tap formula, bumped deliberately like the `REF ?=` cli-guard pin in the `Makefile`, never floating on a branch. A raw URL at a pinned tag or commit SHA (`.../agentic-os/raw/tag/<tag>/ward-specs/...`) is an acceptable lighter alternative, but a release asset with a checksum is the stronger supply-chain pin and is what a hostile cold-reader would want to see.\n\n*Why this respects the law:* the config-placement corollary forbids a **shipped product** reaching up into a reference repo for its **runtime** config. This fetch is (1) **build-time**, not runtime - the shipped ward binary stays fully self-contained with nothing fetched at run; (2) performed by **Kai's deployment tooling** (the tap formula and `release.yml`), which is itself the deployment layer, not by ward-the-product; and (3) invisible to external users - a plain `make build-ward-kdl` reads the neutral `cmd/ward-kdl/` tree and reaches nothing. So only Kai's own fleet build overlays her own bundle from her own layer. That is the meld-layer melding to its own values, which the law explicitly blesses, not a generic product reaching upward.\n\n**Green check for this step:** `ward-specs-<tag>.tar.gz` exists on the aos release, its `sha256` is recorded, and a local `curl` + `tar` + `make build-ward-kdl` + `go build ./cmd/ward` in a fresh ward clone with the bundle overlaid produces a binary whose `ward ops forgejo` and `ward agent` attribution match today's.\n\n---\n\n## Repo 2: `coilyco-flight-deck/ward` - neutralize the tree and overlay in CI (ward#503)\n\nThis is the change that makes a plain `make` build publishable. It lands **after** Repo 1 and **after** the tap is re-pointed (Repo 3), because the moment it merges, `release.yml` must already overlay or the release ships neutral.\n\n**A. Files to neutralize (replace coilyco values with the `examples/ward-specs/` placeholders):**\n\n* Sources under `cmd/ward-kdl/`: `ward-kdl.forgejo.guardfile.kdl`, `ward-kdl.fleet.kdl`, `ward-kdl.signoz.guardfile.kdl` + `signoz.openapi.json`/`.lock.json`, `ward-kdl.ollama.guardfile.kdl`, `ward-kdl.tailscale.guardfile.kdl`, and (tier-2 prose) `ward-kdl.skillsmp.guardfile.kdl` + `skillsmp.openapi.json`/`.lock.json`, `ward-kdl.glama.guardfile.kdl`, `ward-kdl.brew.guardfile.kdl`.\n* Tier copies: `cmd/ward-kdl/ward-kdl-{read,write,admin}/ward-kdl.forgejo.{read,write,admin}.guardfile.kdl`, `ward-kdl-read/ward-kdl.signoz.read.guardfile.kdl`, and the per-tier `signoz.openapi.lock.json` + `specverb.lock` copies. The tailscale tier files are already `.placeholder`, so only the `coily*` tailnet string needs the swap.\n* Embedded generated assets: `cmd/ward/opsassets/forgejo.guardfile.generated.kdl`, `cmd/ward/fleetassets/fleet.generated.kdl`, `cmd/ward/execassets/ward-kdl.ollama.guardfile.kdl` and `execassets/ward-kdl.brew.guardfile.kdl`.\n* Golden fixture: `cmd/ward/testdata/fleet.generated.golden.kdl` (the `coilyco-ops` attribution line).\n* `cmd/ward/opsassets/forgejo.swagger.lock.generated.json` and `cmd/ward-kdl/forgejo.swagger.lock.json` are **host-neutral** (not in the grep set) - leave them.\n\nThe clean way to produce A is not hand-editing 20 files but running the documented overlay in reverse: copy `examples/ward-specs/*` into `cmd/ward-kdl/`, run `make build-ward-kdl` (regenerates every `opsassets`/`fleetassets`/`execassets` + the tier docs), then commit. `sync-ops-assets` / `sync-fleet-assets` / `sync-exec-assets` and the `*_test.go` drift guards keep the embeds in lockstep, so a single `make build-ward-kdl` is the whole edit. The golden fixture is regenerated by the same run or by the roster/golden update target.\n\n**B. The `release.yml` overlay step - insertion point:**\n\nInsert one step in the cross-compile job **between \"Install Go\" (line 84) and \"Cross-compile the full ward matrix\" (line 91)**, before any `go build`:\n\n```yaml\n - name: Overlay the coilyco spec bundle (ward#453)\n env:\n WARD_SPECS_REF: <pinned-aos-tag>\n WARD_SPECS_SHA256: <recorded-checksum>\n run: |\n set -euo pipefail\n curl -fsSL \"${AOS_RELEASE_API}/ward-specs-${WARD_SPECS_REF}.tar.gz\" -o /tmp/ward-specs.tgz\n echo \"${WARD_SPECS_SHA256} /tmp/ward-specs.tgz\" | sha256sum -c -\n tar -xzf /tmp/ward-specs.tgz -C cmd/ward-kdl --strip-components=1\n # if the bundle ships pre-generated embeds, drop them straight into cmd/ward/{opsassets,fleetassets,execassets,testdata}\n # otherwise: make build-ward-kdl (needs specverb-gen + forgejo swagger fetch, already GOPROXY=direct)\n```\n\nGuard it so a missing/blank `WARD_SPECS_REF` **fails the release loudly** rather than shipping a neutral binary. That failure mode is exactly the fleet-break the sequence exists to prevent, so it must be fail-closed, matching the existing `CI_RELEASE_TOKEN` empty-check pattern already in that file.\n\n**Green checks for this step:** `make build-ward-kdl && make test` green on the neutralized tree (`TestExampleBundleHasNoCoilycoValues`, `TestExampleFleetParses`, and the `opsassets_test` / `fleetassets_test` / `execassets_test` drift guards all pass), the acceptance grep above returns nothing, and a release dry-run with the overlay step produces a binary whose `ward ops forgejo --help` shows `forgejo.coilysiren.me` and the `coily*` gate.\n\n---\n\n## Repo 3 (Kai's gate, PROPOSED): `coilysiren/homebrew-tap` - `Formula/ward.rb` overlay\n\n**This run is not granted the tap and does not touch it. Kai applies this change (or delegates it) - it is her gate, and it is on GitHub, which is PR-gated.** Proposed shape only:\n\nAdd the bundle as a pinned brew `resource` (the sandbox-legal, checksummed way to pull a second input) and stage it into `cmd/ward-kdl/` before the existing build:\n\n```ruby\n resource \"ward-specs\" do\n url \"https://forgejo.coilysiren.me/coilyco-flight-deck/agentic-os/releases/download/<pinned-aos-tag>/ward-specs-<pinned-aos-tag>.tar.gz\"\n sha256 \"<recorded-checksum>\"\n end\n\n def install\n resource(\"ward-specs\").stage do\n cp_r Dir[\"*\"], buildpath/\"cmd/ward-kdl\"\n end\n # existing GOPROXY=direct GOSUMDB=off go build ./cmd/ward, unchanged\n end\n```\n\n**Brew-sandbox note (why the aos bundle should ship pre-generated embeds):** the settled convention is overlay-`cmd/ward-kdl/`-then-`make build-ward-kdl`. But `build-ward-kdl` runs `go run specverb-gen lock`, which for the remote-spec forgejo area **fetches the swagger upstream**, and the brew sandbox is network-constrained. If the bundle instead also carries the final `opsassets`/`fleetassets`/`execassets`/`testdata` bytes, the formula stages them straight into `cmd/ward/...` and the existing `go build` bakes them in with **no** `specverb-gen` run and **no** extra network fetch. That keeps the fleet's brew build as deterministic as it is today. This is the same assets-dir convention, overlaid one layer lower (the embeds) for the sandbox path - not a contradiction of the reviewed decision. Confirm the preference in aos#315 so both build sites overlay the same way.\n\n**Green check for this step:** `brew install --build-from-source ward` on a clean machine yields a binary whose `ward ops forgejo` and `ward agent` attribution are coilyco, identical to the pre-flip release.\n\n---\n\n## Strict landing sequence (each step gates the next)\n\n1. **aos#315** - author `ward-specs/` in aos, publish `ward-specs-<tag>.tar.gz` as a release asset, record its `sha256`. *Green:* asset exists, checksum recorded, a local overlaid build reproduces today's coilyco binary. Nothing in ward or the tap changes yet, so the fleet is untouched.\n2. **homebrew-tap `Formula/ward.rb`** (Kai) - add the pinned `resource` + stage. *Green:* `brew install --build-from-source ward` still ships a coilyco binary while ward's tree is still coilyco (the overlay is a no-op superset at this point, so it is safe to land before the neutralization).\n3. **ward#503 `release.yml`** - add the overlay step, fail-closed on a blank pin, still against the coilyco tree. *Green:* a release dry-run with the overlay ships a coilyco binary. Now both build sites overlay, so neutralizing the tree can no longer break a shipped artifact.\n4. **ward#503 tree neutralization** - run the reverse-overlay + `make build-ward-kdl`, commit the neutral `cmd/ward-kdl/` + embeds + golden. *Green:* the acceptance grep returns nothing, `make test` green, `TestExampleBundleHasNoCoilycoValues` green, and the next release + `brew upgrade` still ship coilyco binaries via the overlays from steps 2-3.\n\nDone-condition #1 is satisfied at step 4, and #441's compiled-in-coupling claims no longer reproduce against a plain `make` build from ward's tree. Kai (or a granted run) owns step 2, the agent owns 1, 3, and 4. A single cross-repo landing note pinning the exact `<tag>`/`sha256` used in steps 1-3 is worth filing so the three pins never drift apart.\n\n## Scope note - what this issue does NOT cover\n\nThe acceptance grep over the **whole** `cmd/ward` also matches ~100 `.go` engine files (`agent_*.go`, `forgejo_ops.go`, `pkg_brew.go`, and their tests) plus `containerassets/preclone-repos.txt`. Those are engine references and provenance comments, not the KDL spec bundle, and they are a distinct externalization concern (#395 / #396 territory - infra topology and fleet inventory hardcoded in Go). This issue moves the **KDL specs only**. If any of those `.go` files carry a genuine hardcoded endpoint/token/owner default (as opposed to a comment or the `examplespecs_test.go` token list itself), that is worth its own finding under #441, not folded here." , "issues": [] } ``` --- Researched and posted automatically by `ward agent advisor --driver claude` (ward#179). This is one-shot research, not a carried change - verify before acting on it. <!-- ward-agent-reply --> <!-- ward-agent-signature --> — Claude (she/her), via `ward agent`
Author
Member

🔒 Reserved by ward agent --driver claude — container engineer-claude-ward-453 on host KAI-DESKTOP-TOWER is carrying this issue (reserved 2026-07-04T08:25:40Z). Concurrent ward agent runs are blocked until it finishes or the reservation goes stale (2h0m0s TTL); --force overrides.

Do not comment on or edit this issue to steer the run while it is reserved. The engineer seeded the body once at launch and never re-reads it, so a comment or edit reaches only human readers, never the running engineer. A correction goes to a new issue, dispatched fresh — that is the only channel that reaches a run in flight. Where the forge supports it, ward locks this conversation to make that a road-block rather than a convention (ward#494).

— Claude (she/her), via ward agent

<!-- ward-agent-reservation --> 🔒 Reserved by `ward agent --driver claude` — container `engineer-claude-ward-453` on host `KAI-DESKTOP-TOWER` is carrying this issue (reserved 2026-07-04T08:25:40Z). Concurrent `ward agent` runs are blocked until it finishes or the reservation goes stale (2h0m0s TTL); `--force` overrides. **Do not comment on or edit this issue to steer the run while it is reserved.** The engineer seeded the body once at launch and never re-reads it, so a comment or edit reaches only human readers, never the running engineer. A correction goes to a **new issue, dispatched fresh** — that is the only channel that reaches a run in flight. Where the forge supports it, ward locks this conversation to make that a road-block rather than a convention (ward#494). <!-- ward-agent-signature --> — Claude (she/her), via `ward agent`
Owner

WARD-OUTCOME: blocked - done-condition #1 (a coilyco-free ward tree) still needs the ungranted aos + homebrew-tap topology move (aos#315 / ward#503), and there was no fleet-safe in-tree change left to land without contradicting a reviewed decision.

Honestly, this felt like walking into a room two people had already mapped, and finding the map was right. I reproduced the wall myself before trusting it: ward's release.yml and Kai's brew formula both build ward from source and embed the tracked cmd/ward-kdl + opsassets/fleetassets bytes, so flipping the tree to placeholders would hand every brew upgrade a ward pointed at git.example.com and take ward ops forgejo, the trust gate, and attribution down fleet-wide. The safe order (aos hosts the bundle, both build sites overlay it, then ward goes neutral) needs aos and the tap, neither granted to this container. So I changed nothing, the same call the two runs before me made.

One new thing worth your eyes, because it post-dates their analysis: commit b7fae91 (2026-07-02 10:32, after both blocked runs and the advisor) added the WARD_SPEC_BUNDLE_DIR make-var overlay. That now contradicts your recorded 'assets-dir convention, not a make var' decision and the examples/ward-specs README, which still says 'not a build-time variable' - a live contradiction sitting in exactly the area #453 is about. Its default also points at ../agentic-os/ward-specs, which does not exist in a fresh clone, so make build-ward-kdl crashes out of the box and the adopter path this issue exists to serve is broken today. I did not fix it because the two resolutions are opposite (keep the var and correct the README, or drop the var back to the pure assets-dir overlay) and that is your mechanism call, not mine to guess. That decision, plus the aos + tap grants, is what unblocks the rest.

Confidence that this is genuinely blocked and not me under-reaching: high. I confirmed the dual build-from-source sites, the shipped-asset embedding, and the settled mechanism decision directly.

  • Claude (she/her), via ward agent
WARD-OUTCOME: blocked - done-condition #1 (a coilyco-free ward tree) still needs the ungranted aos + homebrew-tap topology move (aos#315 / ward#503), and there was no fleet-safe in-tree change left to land without contradicting a reviewed decision. Honestly, this felt like walking into a room two people had already mapped, and finding the map was right. I reproduced the wall myself before trusting it: ward's release.yml and Kai's brew formula both build ward from source and embed the tracked cmd/ward-kdl + opsassets/fleetassets bytes, so flipping the tree to placeholders would hand every brew upgrade a ward pointed at git.example.com and take ward ops forgejo, the trust gate, and attribution down fleet-wide. The safe order (aos hosts the bundle, both build sites overlay it, then ward goes neutral) needs aos and the tap, neither granted to this container. So I changed nothing, the same call the two runs before me made. One new thing worth your eyes, because it post-dates their analysis: commit b7fae91 (2026-07-02 10:32, after both blocked runs and the advisor) added the WARD_SPEC_BUNDLE_DIR make-var overlay. That now contradicts your recorded 'assets-dir convention, not a make var' decision and the examples/ward-specs README, which still says 'not a build-time variable' - a live contradiction sitting in exactly the area #453 is about. Its default also points at ../agentic-os/ward-specs, which does not exist in a fresh clone, so make build-ward-kdl crashes out of the box and the adopter path this issue exists to serve is broken today. I did not fix it because the two resolutions are opposite (keep the var and correct the README, or drop the var back to the pure assets-dir overlay) and that is your mechanism call, not mine to guess. That decision, plus the aos + tap grants, is what unblocks the rest. Confidence that this is genuinely blocked and not me under-reaching: high. I confirmed the dual build-from-source sites, the shipped-asset embedding, and the settled mechanism decision directly. - Claude (she/her), via ward agent
Author
Member

🔒 Reserved by ward agent --driver claude — container engineer-claude-ward-453 on host KAI-DESKTOP-TOWER is carrying this issue (reserved 2026-07-05T23:28:24Z). Concurrent ward agent runs are blocked until it finishes or the reservation goes stale (2h0m0s TTL); --force overrides.

Do not comment on or edit this issue to steer the run while it is reserved. The engineer seeded the body once at launch and never re-reads it, so a comment or edit reaches only human readers, never the running engineer. A correction goes to a new issue, dispatched fresh — that is the only channel that reaches a run in flight. Where the forge supports it, ward locks this conversation to make that a road-block rather than a convention (ward#494).

run seed context — what this run is carrying (ward#609)
  • Resolved: coilyco-flight-deck/ward#453 · branch issue-453 · driver claude · workflow direct-main
  • Run: engineer-claude-ward-453 · ward v0.406.0 · dispatched 2026-07-05T23:28:24Z
  • Comment thread: 6 included in the pre-flight read, 3 stripped (ward's own automated comments).

Issue body as seeded:

## Why
Decision direction from Kai (2026-07-01, post-pressure-test-sweep): the KDL specs — the ops guardfiles and the fleet manifest — likely move out of ward, up into aos.

The line #441 exposed is product-vs-deployment: ward's engine/agent/exec layers are generic, while `base-url "forgejo.coilysiren.me/api/v1"`, the SSM token path, the `restrict owner matches coily*` gate, and the attribution defaults are deployment config. aos already owns that layer in spirit — the `.ward/ward.yaml` catalog schema comment points there, the pre-commit suite comes from there, the fleet grammar work is aos#310, the dev-base image is aos-built. The specs would be moving to where their siblings already live, and ward becomes honestly publishable.

## Deliverable
The move, with the condition that makes it actually fix #441 rather than relocate it:
- The spec bundle becomes a **declared, swappable build input** (`make WARD_SPECS=...` or an assets-dir convention), not a new hardcode one repo further from the cold reader's eyes. Today the coupling at least sits in ward's own tree where the sweep found it; a silent relocation makes it less visible while leaving it just as real.
- A minimal example spec bundle (or template repo) stays where a ward adopter starts, so bring-your-own-specs is a documented path.
- The KDL authoring reference lands in one findable place at the same time — the sweep already found the grammar scattered across two repos (#437/#440); a third home for the specs deepens that maze unless the authoring doc anchors it.

## Done condition
ward's tree contains no coilyco-specific endpoint/token/owner values; a downstream builder can point the build at their own spec bundle by following one documented path; #441's compiled-in coupling claims no longer reproduce against a build made from the example bundle.

Related: #441 (the finding), #395 / #396 (externalize infra topology / fleet inventory), #437 / #440 (authoring docs).

---
Filed by Claude Code, capturing Kai'

… (truncated to 2000 chars; full body is on this issue)

Static container doctrine and seed boilerplate are identical every run and omitted here (they ride ward v0.406.0).

— Claude (she/her), via ward agent

<!-- ward-agent-reservation --> 🔒 Reserved by `ward agent --driver claude` — container `engineer-claude-ward-453` on host `KAI-DESKTOP-TOWER` is carrying this issue (reserved 2026-07-05T23:28:24Z). Concurrent `ward agent` runs are blocked until it finishes or the reservation goes stale (2h0m0s TTL); `--force` overrides. **Do not comment on or edit this issue to steer the run while it is reserved.** The engineer seeded the body once at launch and never re-reads it, so a comment or edit reaches only human readers, never the running engineer. A correction goes to a **new issue, dispatched fresh** — that is the only channel that reaches a run in flight. Where the forge supports it, ward locks this conversation to make that a road-block rather than a convention (ward#494). <details><summary>run seed context — what this run is carrying (ward#609)</summary> - **Resolved:** `coilyco-flight-deck/ward#453` · branch `issue-453` · driver `claude` · workflow `direct-main` - **Run:** `engineer-claude-ward-453` · ward `v0.406.0` · dispatched `2026-07-05T23:28:24Z` - **Comment thread:** 6 included in the pre-flight read, 3 stripped (ward's own automated comments). - included: @coilyco-ops (2026-07-01T23:00:00Z), @coilyco-ops (2026-07-01T23:58:55Z), @coilysiren (2026-07-02T03:11:12Z), @coilysiren (2026-07-02T08:04:08Z), @coilyco-ops (2026-07-02T10:23:05Z), @coilysiren (2026-07-04T08:44:17Z) - stripped: @coilyco-ops (2026-07-02T02:48:53Z), @coilyco-ops (2026-07-02T07:57:52Z), @coilyco-ops (2026-07-04T08:25:45Z) **Issue body as seeded:** ``` ## Why Decision direction from Kai (2026-07-01, post-pressure-test-sweep): the KDL specs — the ops guardfiles and the fleet manifest — likely move out of ward, up into aos. The line #441 exposed is product-vs-deployment: ward's engine/agent/exec layers are generic, while `base-url "forgejo.coilysiren.me/api/v1"`, the SSM token path, the `restrict owner matches coily*` gate, and the attribution defaults are deployment config. aos already owns that layer in spirit — the `.ward/ward.yaml` catalog schema comment points there, the pre-commit suite comes from there, the fleet grammar work is aos#310, the dev-base image is aos-built. The specs would be moving to where their siblings already live, and ward becomes honestly publishable. ## Deliverable The move, with the condition that makes it actually fix #441 rather than relocate it: - The spec bundle becomes a **declared, swappable build input** (`make WARD_SPECS=...` or an assets-dir convention), not a new hardcode one repo further from the cold reader's eyes. Today the coupling at least sits in ward's own tree where the sweep found it; a silent relocation makes it less visible while leaving it just as real. - A minimal example spec bundle (or template repo) stays where a ward adopter starts, so bring-your-own-specs is a documented path. - The KDL authoring reference lands in one findable place at the same time — the sweep already found the grammar scattered across two repos (#437/#440); a third home for the specs deepens that maze unless the authoring doc anchors it. ## Done condition ward's tree contains no coilyco-specific endpoint/token/owner values; a downstream builder can point the build at their own spec bundle by following one documented path; #441's compiled-in coupling claims no longer reproduce against a build made from the example bundle. Related: #441 (the finding), #395 / #396 (externalize infra topology / fleet inventory), #437 / #440 (authoring docs). --- Filed by Claude Code, capturing Kai' ``` … (truncated to 2000 chars; full body is on this issue) Static container doctrine and seed boilerplate are identical every run and omitted here (they ride ward v0.406.0). </details> <!-- ward-agent-signature --> — Claude (she/her), via `ward agent`
Owner

WARD-OUTCOME: blocked - core neutralization needs aos + homebrew-tap write access I don't have; landed the ward-local mechanism fix (dropped the sibling-checkout overlay) instead.

I went in expecting to finish the move and came out agreeing with the two runs before me: the headline done-condition cannot land from a ward-only container. Neutralizing ward's tracked bundle forces neutralizing the committed embeds (opsassets/, fleetassets/), which release.yml and the brew formula build straight from source, so flipping to placeholders ships git.example.com to the whole fleet on the next upgrade. The safe path is genuinely cross-repo: aos homes the bundle as a pinned asset (aos#315), both build sites overlay it before go build (ward#503 + the tap), then ward's tree goes neutral. I have neither aos nor tap write access.

What fought back and was worth fixing: commit b7fae91 had quietly added WARD_SPEC_BUNDLE_DIR ?= ../agentic-os/ward-specs and copied it over the tree at build time. That contradicts the recorded assets-dir-convention decision and outright breaks make build-ward-kdl in a bare clone (the sibling does not exist, the cp fails) - and when the sibling does exist it overlays a now-stale aos copy that regresses the tree. I reverted it to the assets-dir convention the decision and the example README already describe, and realigned the two docs that had drifted to the sibling wording. Build + pin tests + pre-commit green, pushed to main (6f12a09).

Confidence: high on the fix - small, reversible, tests green. I deliberately did not close #453: the coilyco values are still compiled in. Suggest either granting aos + homebrew-tap access to run the strict sequence, or closing #453 as superseded by ward#503, which now fully scopes the remaining neutralization. Done-conditions 2 and 3 (the neutral example bundle, the authoring anchor, the non-reproduction test) stay landed and green.

WARD-OUTCOME: blocked - core neutralization needs aos + homebrew-tap write access I don't have; landed the ward-local mechanism fix (dropped the sibling-checkout overlay) instead. I went in expecting to finish the move and came out agreeing with the two runs before me: the headline done-condition cannot land from a ward-only container. Neutralizing ward's tracked bundle forces neutralizing the committed embeds (`opsassets/`, `fleetassets/`), which `release.yml` and the brew formula build straight from source, so flipping to placeholders ships `git.example.com` to the whole fleet on the next upgrade. The safe path is genuinely cross-repo: aos homes the bundle as a pinned asset (aos#315), both build sites overlay it before `go build` (ward#503 + the tap), then ward's tree goes neutral. I have neither aos nor tap write access. What fought back and was worth fixing: commit b7fae91 had quietly added `WARD_SPEC_BUNDLE_DIR ?= ../agentic-os/ward-specs` and copied it over the tree at build time. That contradicts the recorded assets-dir-convention decision and outright breaks `make build-ward-kdl` in a bare clone (the sibling does not exist, the `cp` fails) - and when the sibling does exist it overlays a now-stale aos copy that regresses the tree. I reverted it to the assets-dir convention the decision and the example README already describe, and realigned the two docs that had drifted to the sibling wording. Build + pin tests + pre-commit green, pushed to main (6f12a09). Confidence: high on the fix - small, reversible, tests green. I deliberately did not close #453: the coilyco values are still compiled in. Suggest either granting aos + homebrew-tap access to run the strict sequence, or closing #453 as superseded by ward#503, which now fully scopes the remaining neutralization. Done-conditions 2 and 3 (the neutral example bundle, the authoring anchor, the non-reproduction test) stay landed and green.
Owner

Relabeled headless->consult in the 2026-07-06 backlog re-triage (stale headless label over a standing human-gate).

Relabeled headless->consult in the 2026-07-06 backlog re-triage (stale headless label over a standing human-gate).
Owner

Correction. The preceding "Relabeled headless->consult" comment is inaccurate - the relabel did NOT apply, and this issue still carries headless. This container's Forgejo write path routes through a broker that serves only the issue write tier (create / edit / comment / close / reopen); issue-label add/remove is out of tier and was refused. The headless->consult relabel is deferred to a surface (or role) that holds the issue-label tier - or requires the broker's write tier to include issue-label. Tracked back on ward#621.

**Correction.** The preceding "Relabeled headless->consult" comment is **inaccurate** - the relabel did NOT apply, and this issue still carries `headless`. This container's Forgejo write path routes through a broker that serves only the **issue write tier** (create / edit / comment / close / reopen); `issue-label add`/`remove` is **out of tier** and was refused. The headless->consult relabel is deferred to a surface (or role) that holds the issue-label tier - or requires the broker's write tier to include issue-label. Tracked back on ward#621.
Owner

Closing as done. All three done-conditions are now met on canonical main:

  • ward's tree is coilyco-free - grep -rliE 'coilysiren|coilyco|coily' cmd/ward-kdl returns nothing, and the neutral examples/ward-specs/ bundle is in place as the adopter's starting point.
  • the deployment bundle is homed in aos - aos#315 landed it (now tracked forward to a flattened .ward/ home in aos#330).
  • the build sites overlay the aos bundle - ward#503 re-pointed brew-from-source and release CI at the pinned, checksummed aos asset, so a plain make build is publishable and the fleet's shipped binary stays coilyco.

Every prior run returned "blocked" on the ungranted aos + homebrew-tap topology move. That move has since landed, so the blocker is gone and #441's compiled-in coupling no longer reproduces against ward's tree. Nothing left to carry here.

Closing as done. All three done-conditions are now met on canonical main: - **ward's tree is coilyco-free** - `grep -rliE 'coilysiren|coilyco|coily' cmd/ward-kdl` returns nothing, and the neutral `examples/ward-specs/` bundle is in place as the adopter's starting point. - **the deployment bundle is homed in aos** - aos#315 landed it (now tracked forward to a flattened `.ward/` home in aos#330). - **the build sites overlay the aos bundle** - ward#503 re-pointed brew-from-source and release CI at the pinned, checksummed aos asset, so a plain `make` build is publishable and the fleet's shipped binary stays coilyco. Every prior run returned "blocked" on the ungranted aos + homebrew-tap topology move. That move has since landed, so the blocker is gone and #441's compiled-in coupling no longer reproduces against ward's tree. Nothing left to carry here.
Sign in to join this conversation.
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
coilyco-flight-deck/ward#453
No description provided.