122 Commits

Author SHA1 Message Date
Paul O'Reilly
c67d9736fd R3b [fw]: delete legacy workflow-script/v1 composite and cp-service-token/v1 context (dbc5efc6)
Control plane 0.0.5.1890 no longer falls back to either. Invariant tests now
assert both stay gone.

Claude-Session: https://claude.ai/code/session_01N218bERyNeLhbLmDRDvbWF
2026-10-19 01:41:44 +13:00
Paul O'Reilly
d0424879c2 R2: remove AU-51 bearer layer from planning/spec-writing model composites; delete retired @1 templates (dbc5efc6)
The @2 templates use CP-side verdict/WIA decompose and never read the bearer.
Triggers already pin version 2.

Claude-Session: https://claude.ai/code/session_01N218bERyNeLhbLmDRDvbWF
2026-10-19 00:24:55 +13:00
Paul O'Reilly
37a94dcd07 fw: A8 template migration (drop on_fail: continue) and cp-docs-token/v1 layer (be110e25, 1d7ef09a)
Claude-Session: https://claude.ai/code/session_01N218bERyNeLhbLmDRDvbWF
2026-10-17 20:52:35 +13:00
Paul O'Reilly
44334a2143 docs: end-session 2026-10-13 (CONTEXT.md, session log, benchmarks/ + model-slug note in CLAUDE.md) 2026-10-13 14:47:57 +13:00
Paul O'Reilly
418d634afa benchmarks: add Artificial Analysis snapshot and placeholder M3.1-Flash estimate
- artificial-analysis/2026-10-13.csv: Anthropic, Qwen, MiniMax-M3 rows with
  cost per task and derived cost per intelligence point
- minimax-m3-1-flash-unverified.md: operator-supplied KingBench figures, unverified
- estimates.csv: TODO placeholder for M3.1 Flash (0.9x M3 cost, index scaled by
  KingBench ratio) -- replace with measured/published values
2026-10-13 14:33:53 +13:00
Paul O'Reilly
d7decc1dec minimax: move to MiniMax-M3.1-Flash-Preview; drop bare minimax/minimax-m2 slugs
- new context minimax-m31-flash/v1 (model pin; no thinking-budget init, Flash
  ignores it); four composites switch from minimax-m3-max/v1 (kept for rollback)
- models + registry for minimax-m31-flash-{max,medium}; removes the dangling
  model-registry/minimax.yaml (endpoint "minimax" never existed)
- tiers, harness-roles, minimax-* task templates and the *-review-loop@1
  workflows use the Flash slugs (MiniMax silently maps unknown names to M3, so
  the provider-id translation lands in agent-runtimes)
2026-10-13 10:55:03 +13:00
c8c9e7f7d0 Merge pull request 'workflow-script-nocp-norepo/v1: secret-free script composite' (#5) from feat/script-composite-norepo into main 2026-10-12 03:21:37 +00:00
Paul O'Reilly
57374c8bfb feat(harness): workflow-script-nocp-norepo/v1 secret-free script composite (e993c9fa)
Claude-Session: https://claude.ai/code/session_01N218bERyNeLhbLmDRDvbWF
2026-10-11 22:49:52 +13:00
Paul O'Reilly
e11b448f00 feat(agent-repo): opt-in AR-42 archive-and-reset of a stale task branch (f910e2ba)
init.sh now archives and resets an existing task/<uuid> branch to the current
base when AGENT_BRANCH_RESET_ON_START=true. Default off: all nodes of a
workflow share the branch, so only the workflow's first node may set it.

Claude-Session: https://claude.ai/code/session_01N218bERyNeLhbLmDRDvbWF
2026-10-09 14:13:46 +13:00
Paul O'Reilly
e64d0a1822 feat(workflow): cpw-smoke@1 one-node cp_write template for Option C smoke run (690b330f)
Claude-Session: https://claude.ai/code/session_01N218bERyNeLhbLmDRDvbWF
2026-10-05 16:18:18 +13:00
Paul O'Reilly
a1c708ac96 fix(harness): add -hatchmate composites for sonnet, haiku, deepseekv4flash (bug 678d4e8e)
Hatchmate templates resolving to claude-sonnet-5, claude-haiku-4-5 or
airouter-deepseekv4flash mounted only gitea-ssh/v1 and could not clone
hatchmate/hatchmate-agents. Mirror the existing -hatchmate composites:
non-hatchmate base layers plus gitea-ssh-hatchmate/v1 after gitea-ssh/v1 (HC-26).

Claude-Session: https://claude.ai/code/session_01N218bERyNeLhbLmDRDvbWF
2026-10-04 21:13:32 +13:00
Paul O'Reilly
887578f0eb feat(templates): explicit cp_write on every kind: script node + audit test (WF-COMP-31d, item 26754227)
cp_write: true  -> state-tx (test-validate@1, frozen-fixture-emit@1) and, in
                   the archived bug-ancestor-auto-advance@1, tag-set + state-tx.
cp_write: false -> every other script node (verdict-gate, policy-pick,
                   preflight-*, frozen-fixture-emit, parent-link-check).
tests/invariants/test_cp_write_field_set_correctly.py pins the set.

HOLD: do not merge until the CP release that adds WorkflowNode.cp_write.
The current CP schema is extra="forbid" and rejects the new key
(verified: nodes.0.cp_write extra_forbidden), so on the old CP these
template edits are NOT inert.

Claude-Session: https://claude.ai/code/session_01N218bERyNeLhbLmDRDvbWF
2026-10-04 09:36:04 +13:00
Paul O'Reilly
08ca057687 feat(harness): workflow-script-nocp/v1 + workflow-script-write/v1 composites (Option C, WF-COMP-31b/31c, item 26754227)
nocp: shared-variables/v1 + repo-readonly/v1 (no CP credential).
write: shared-variables/v1 + cp-write-token/v1 + repo-readonly/v1.
repo-readonly/v1 is last in both (WF-COMP-34); neither layers
cp-service-token/v1 or gitea-ssh/v1.

HOLD: do not merge until the CP release (AU-55/55a/56/57, WF-COMP-31b engine/
dispatch/compiler composite-set changes) and the dispatcher image
(cp-write-token delivery, AU-55b) are deployed. The dispatcher advertises every
composite found in the CRS-synced harnesses/ tree (dispatcher/poller.py
_collect_supported_harnesses), so merging this to origin/main IS the
advertisement event.

Claude-Session: https://claude.ai/code/session_01N218bERyNeLhbLmDRDvbWF
2026-10-04 09:35:34 +13:00
Paul O'Reilly
3717fc8167 feat(harness): cp-write-token/v1 context layer (Option C, WF-COMP-31c, item 26754227)
Env-only layer exporting CP_WRITE_TOKEN_FILE=/run/agent/cp-write-token/token.
The per-step wfcw_ token is delivered by the dispatcher into the script
container only (AU-55b), so the layer has no secrets_required, init script or
files. Not referenced by any composite yet; safe to merge at any time.

Claude-Session: https://claude.ai/code/session_01N218bERyNeLhbLmDRDvbWF
2026-10-04 09:35:07 +13:00
Paul O'Reilly
ea7c11265b fix(repo-readonly): own read-only deploy key; workflow-script drops write-capable gitea-ssh/v1
repo-readonly/v1 now declares write_targets: [], an ssh_hosts alias and its
own secrets_required (account platform-readonly.space:platform, a read-only
Gitea deploy key), and stages the key before cloning. workflow-script/v1 no
longer layers gitea-ssh/v1, so script nodes cannot push. Invariants updated:
credential layers in the composite must declare write_targets: [].

Bug 45a48685-23e9-4605-af1f-d93306108cef

Claude-Session: https://claude.ai/code/session_01N218bERyNeLhbLmDRDvbWF
2026-10-02 20:09:30 +13:00
Paul O'Reilly
d850a4da68 fix(repo-readonly): clone when /workspace/project is empty, not only when absent (bug eede60c3)
harness_init pre-creates an empty /workspace/project, so the -d guard always skipped the clone.

Claude-Session: https://claude.ai/code/session_01N218bERyNeLhbLmDRDvbWF
2026-10-02 17:21:35 +13:00
Paul O'Reilly
4b41236e26 feat(harness): repo-readonly/v1 + gitea-ssh layer in workflow-script/v1; agent_repo on test-validate/frozen-fixture-emit (WF-COMP-34, bug 3bee78fa/a3ba44bc) 2026-10-02 16:18:21 +13:00
Paul O'Reilly
8d7b3af77d fix(templates): add AGENT_UPSTREAM_REPO_URL/BRANCH to all workflow templates using the agent fork
Fresh agent branches were seeded from the stale fork main (AR-39 fell through to fork).
Work item 18efa01f-f941-4f16-bb67-9cafbb6d668a.

Claude-Session: https://claude.ai/code/session_01N218bERyNeLhbLmDRDvbWF
2026-10-02 15:03:34 +13:00
Paul O'Reilly
c91813de96 fix(agent-repo): AR-39b run base selector by absolute path; seed scope-decompose@2 from upstream
init.sh invoked 'python3 -m entrypoint.agent_repo_base' from /workspace/project, so a project
repo's own entrypoint/ shadowed the image's and the selector crashed. Invoke the image copy by
path. scope-decompose-sonnet@2 gains AGENT_UPSTREAM_REPO_URL/BRANCH so fresh spec branches seed
from upstream main instead of the stale fork main.

Claude-Session: https://claude.ai/code/session_01N218bERyNeLhbLmDRDvbWF
2026-10-02 14:54:37 +13:00
Paul O'Reilly
fce343cea1 test: drop archived bug-ancestor-auto-advance@1 from state-tx/CP_URL discovery sets
Template moved to _archived/ (c7da48d7); glob discovery no longer sees it.

Claude-Session: https://claude.ai/code/session_01N218bERyNeLhbLmDRDvbWF
2026-10-01 19:37:36 +13:00
Paul O'Reilly
71363a77bb merge: archive bug-ancestor-auto-advance@1 (replaced by CRS patch_item rule bug-milestone-auto-resolve)
Claude-Session: https://claude.ai/code/session_01N218bERyNeLhbLmDRDvbWF
2026-10-01 18:19:23 +13:00
Paul O'Reilly
1e236b07d0 merge: workflow-script/v1, state-tx runtime_env + FROM_STATES, ingress CP_URL
Claude-Session: https://claude.ai/code/session_01N218bERyNeLhbLmDRDvbWF
2026-10-01 18:19:22 +13:00
Paul O'Reilly
e51146fc30 fix: task templates use ingress CP_URL (https://agents.oreillyit.nz/api), not svc.cluster.local:8100
The deploy repo NetworkPolicy admits :8100 only from named apps and the traefik/cms-proxy
namespaces; agent/script pods time out, so state-tx / cp-cli calls silently lost transitions.
Invariant now rejects the in-cluster form and pins the ingress URL.

Claude-Session: https://claude.ai/code/session_01N218bERyNeLhbLmDRDvbWF
2026-10-01 18:14:30 +13:00
Paul O'Reilly
782eadb615 feat: STATE_TX_FROM_STATES on state-tx nodes; workflow-script composite invariant; refresh legacy-mount NOTE
Claude-Session: https://claude.ai/code/session_01N218bERyNeLhbLmDRDvbWF
2026-10-01 17:02:29 +13:00
Paul O'Reilly
9e2dd681a7 merge: mm/fw-script (workflow-script/v1 composite) 2026-10-01 17:02:01 +13:00
Paul O'Reilly
c5a5293edc fix: declare runtime_env on state-tx nodes in test-validate@1 and frozen-fixture-emit@1
state-tx exits 2 without CP_URL and STATE_TX_NEW_STATE. Each template's
target state is its own output.state (test-validated / test-skeleton-ready).
Adds an invariant test.

Claude-Session: https://claude.ai/code/session_01N218bERyNeLhbLmDRDvbWF
2026-10-01 16:08:39 +13:00
Paul O'Reilly
b549a28187 feat(harnesses): shared-variables/v1 context + workflow-script/v1 composite (WF-COMP-31, WV-19) (03878b12-86b5-4b88-86d5-7182ae1c471f) 2026-10-01 15:31:48 +13:00
Paul O'Reilly
d727e17825 chore(workflow-templates): archive bug-ancestor-auto-advance@1.yaml per WT-ANC-15 step 2 (c7da48d7-1688-422b-8108-1119e819f9ea) 2026-10-01 15:25:27 +13:00
Paul O'Reilly
58612d9734 feat: AR-39b — scope-decompose-sonnet@2 + bug-verify-sonnet@2 (WV-36 file-write plan, WF-COMP-25a self-transition) (31553852-e6c7-40e3-8020-b3b65094c1cc) 2026-10-01 14:24:26 +13:00
Paul O'Reilly
da23760e93 fix(models): airouter-qwen3 default_flags.model Qwen3.6 -> Qwen3.8 (live id; agent-runtimes c3551e3a)
Claude-Session: https://claude.ai/code/session_01N218bERyNeLhbLmDRDvbWF
2026-09-30 11:46:24 +13:00
f64be1d467 fix(gitea-ssh-hatchmate): correct account_ref space id (hatchmate, not platform) (#4)
Merge PR #4
2026-09-18 02:18:46 +00:00
c89cb5beab Merge pull request 'feat(forge-credential): hatchmate working-repo key layer + 4 composite forks' (#3) from feat/hatchmate-per-project-fork-key into main
Merge PR #3
2026-09-18 02:05:48 +00:00
Paul O'Reilly
59f7b9e5f8 feat(forge-credential): add gitea-ssh-hatchmate/v1 layer + 4 hatchmate composite forks
M2-CRS W4 unblock: dispatched agents could not clone hatchmate/hatchmate-agents
because the shared gitea-ssh/v1 context mounts the ai_enablement deploy key,
which is scoped to skynet/* only. Same bug would hit every project whose
working repo lives outside the skynet org.

This implements the per-org pattern the framework already uses for accelerators
(gitea-ssh-accelerators/v1) and homelab (gitea-ssh-homelab/v1):

- harnesses/contexts/gitea-ssh-hatchmate/v1/{init.sh,harness.yaml} — NEW
  forge-credential context mirroring accelerators, with account_ref
  'hatchmate.space:platform' and write_targets covering hatchmate/*. The
  init.sh stages the ESO-mounted private key to ~/.ssh/gitea-oreillyit-nz-hatchmate
  (matching the ssh alias declared in harness.yaml). URL host pattern
  'gitea.oreillyit.nz-hatchmate' (per-org alias) drives SSH config block
  selection — already auto-written by harness_init.py from each layer's
  ssh_hosts: declarations.

- harnesses/composites/code-*-tdd-repo-hatchmate/v1/ — NEW composites for
  fable/minimax/airouter/opus that compose BOTH gitea-ssh/v1 (for reference
  clones, skynet org) AND gitea-ssh-hatchmate/v1 (for working-repo clone +
  push, hatchmate org). Composites are unchanged for non-hatchmate projects.

- tests/invariants/test_forge_credentials_declare_write_targets.py — the
  existing xfail(strict=True) marker was wrong: the 4 existing layers all
  declare write_targets today, so the test was XPASSing. Removed the
  xfail marker so HC-11 is now a real positive gate (5 layers instead
  of 4). This was a pre-existing test bug surfaced by the 5th layer.

W4 next step: dispatcher's account_ref resolution needs the hatchmate CP
account + grant to be created (via the new scripts/provision-hatchmate-fork-key.sh
in the hatchmate app repo).
2026-09-18 12:28:06 +12:00
Paul O'Reilly
d19da44f7a feat: AR-39a — templates pass AGENT_UPSTREAM_REPO_URL/BRANCH; agent-repo/v1 init.sh invokes select-base (upstream > reference > fork) (bug 0772408e)
Claude-Session: https://claude.ai/code/session_01G3SkMRBRWXyiGuMGs8WVas
2026-09-16 19:34:47 +12:00
Paul O'Reilly
7e757b0fd9 harness(HC-11): declare write_targets on the four forge-credential layers (gitea-admin, gitea-ssh, gitea-ssh-accelerators, gitea-ssh-homelab) (b1de17b4)
Held locally until the agent-runtimes HC-11 composer change is deployed: the live composer is extra=forbid and would reject the new key.

Claude-Session: https://claude.ai/code/session_018LRh1S2bHJYhEgrMu3UJx8
2026-09-13 20:09:50 +12:00
Paul O'Reilly
b7cf256c44 test(invariants): HC-11 forge-credential layers must declare write_targets (xfail until layers are stamped)
Helper tests/invariants/forge_credentials.py detects credential carriers via
mounts[]/env/secrets_required[]/ssh_hosts[]; today gitea-admin, gitea-ssh,
gitea-ssh-accelerators, gitea-ssh-homelab are found and none declare
write_targets — the invariant xfails(strict) until the CRS-103 rollout stamps them.

Claude-Session: https://claude.ai/code/session_018LRh1S2bHJYhEgrMu3UJx8
2026-09-13 13:09:24 +12:00
Paul O'Reilly
e31d472ff9 fix: migrate Claude model files to current API IDs (opus-5, sonnet-5, haiku-4.5)
Bug 57d8a047-d26d-47ce-ae6f-bc5cb98fef0e: Opus-tier tasks 404'd because
models/claude-opus-4.yaml pinned default_flags.model to "claude-opus-4-5",
a retired ID. models/claude-sonnet-4.yaml was pinned to a dated snapshot
("claude-sonnet-4-20250514") with the same problem.

Slug strategy: the registry slug (filename / RegistryEntry.name) doubles
as the literal --model argument on the workflow-template pass-through path
(task-templates/workflow/*.yaml `model:` field -> compiler WF-COMP-18 ->
payload.runtime.model -> entrypoint/runners/claude.py `--model`), which has
no translation step through this file's default_flags. So rather than
patch default_flags.model in place (leaving the slug stale and the
pass-through bug latent), rename the slug to match the current API ID:

- models/claude-opus-4.yaml, model-registry/claude-opus-4.yaml
  -> claude-opus-5.yaml (name/endpoint/default_flags.model: claude-opus-5)
- models/claude-sonnet-4.yaml, model-registry/claude-sonnet-4.yaml
  -> claude-sonnet-5.yaml (claude-sonnet-5)
- model-registry/claude-haiku-4.yaml -> claude-haiku-4-5.yaml
  (claude-haiku-4-5); added the previously-missing models/claude-haiku-4-5.yaml
  so the claude runner can actually resolve this endpoint
- model-registry/harness-roles.yaml, model-registry/tiers.yaml,
  workflows/smart-agent.yaml, task-templates/workflow/{spec,plan}-review-loop@1.yaml:
  updated every claude-opus-4 / claude-sonnet-4 / claude-haiku-4 reference
  to the new slugs
- models/openrouter-sonnet.yaml: dated snapshot "claude-sonnet-4-20250514"
  -> "claude-sonnet-5" (third-party router proxying the same retired ID)
- refreshed cost_per_1k_tokens on the three renamed registry entries to
  current published pricing

Claude-Session: https://claude.ai/code/session_015nXvGNNNixJPFwZKZHNyha
2026-09-10 12:05:14 +12:00
Paul O'Reilly
30c3a75c20 feat(workflow): bug-ancestor-auto-advance@1 demo template (M43 Task 2) 2026-09-10 09:35:29 +12:00
Paul O'Reilly
3eabc924a2 refactor(python-dev): swap pip -> uv pip for project install
uv is now pre-baked into the base image
(agent-runtimes/images/base/Dockerfile) and is faster than pip with
better retry on transient network failures. Closes the last runtime
hang vector for project-deps install — apt install was removed 2026-09-06
in 0c57972f-pre-bake work but the pip install -e line in init.sh
remained. uv pip install is the equivalent operation with the new
pre-baked tooling.

Refs F-WE-PDIV/RCA-2026-09-04-zombies.
2026-09-09 21:56:48 +12:00
Paul O'Reilly
be57e1e246 fix(bug-verify): fresh UUID Idempotency-Key so re-verification with a different verdict does not 409
Claude-Session: https://claude.ai/code/session_01U3biMxRhFGkwtf4jVTNjcj
2026-09-09 13:57:40 +12:00
Paul O'Reilly
33501ca54e fix(bug-verify-sonnet@1): agent self-transitions flow_state, remove dead verdict-tx node
verdict-tx (kind: script) never worked: script nodes are harness-exempt
(WF-COMP-6/MN-38) and run in their own empty container, so it could
never credentially read /workspace/verdict from the agent's node.

Option 3: give the agent node's own composite (planning-sonnet-repo) a
cp-service-token/v1 layer, and have the agent PATCH its own item's
flow_state (verified|rejected) to the CP directly as its last step,
before task_complete. Removes verdict-tx entirely.

See agent-runtimes work item 88ecd23e and spec/typed-workflows.md
WF-COMP-25 (agent-runtimes commit 8972d266) for the finalize.py
precedence fix this depends on (ambiguous pipe-separated output.state
must never be auto-PATCHed over the agent's own value).

Claude-Session: https://claude.ai/code/session_01U3biMxRhFGkwtf4jVTNjcj
2026-09-09 13:56:34 +12:00
Paul O'Reilly
5a8cd32aec feat(harnesses): add customer-script/v1 composite
Minimal harness for kind: customer_script nodes (agent-runtimes
spec/tenant-namespaces.md SCR-1..SCR-6). No LLM turn - runs via the
"shell" runner, agent-repo/v1 clone access only. Per-script credential
needs are deliberately not baked into this base (SCR-6: narrow,
per-script review) - compose a customer-script-<need>/v1 variant
layering whichever specific credential context a given script actually
needs, rather than widening this shared base.

Without this commit, kind: customer_script was not dispatchable from
any machine other than the one it was authored on - the harness lookup
against a fresh CRS sync would fail.

Claude-Session: https://claude.ai/code/session_012arAwUuBQrpnMzJ36mEVBk
2026-09-08 07:42:48 +12:00
Paul O'Reilly
3a550837aa docs(bug-verify-sonnet): note the scratchpad/verdict follow-up, not yet wired
Attempted to wire verdict-tx to clone the agent's branch and read
scratchpad/verdict (the new cross-node artifact convention,
agent-repo/v1 init.sh) instead of the ephemeral /workspace/verdict.
Reverted: script tasks (dispatcher/task_manager.py::_run_script_task)
have no credentialed way to clone a private repo — the per-task SSH key
is provisioned through the full ESO/account harness resolution
pipeline, which script tasks deliberately bypass entirely. Left the
template on its current (still-broken-for-cross-container-reasons)
/workspace/verdict contract with a note, pending a scoped follow-up on
how script nodes get read access to the branch (new secrets plumbing,
vs. folding the state transition into the agent node's own already-
credentialed CP access).
2026-09-06 23:59:52 +12:00
Paul O'Reilly
4b4d02926d feat(agent-repo): create scratchpad/ at task branch top level
Cross-node artifact passing within a workflow manifest — nodes each run
in their own ephemeral container/pod with no shared filesystem, so an
agent node writing e.g. a verdict to /workspace/verdict is invisible to
a downstream kind: script node in the same manifest (found live
2026-09-06, bug-verify-sonnet's verdict-tx). The git task branch is the
only channel every node in a manifest actually shares: write to
scratchpad/, commit (picked up by finalize.sh's existing git add -A),
next node clones the same branch and reads it back.

scratchpad/ is scratch, never deliverable content, and must never
survive a merge into main — a CI gate in the target repo
(agent-runtimes .gitea/workflows/build-images.yaml,
no-scratchpad-in-main) is the hard backstop.
2026-09-06 23:44:51 +12:00
Paul O'Reilly
a685bf16a6 feat: bug-verify-sonnet@1 template + planning-sonnet-repo runtime
Adds the CRS-side deliverables for agent-runtimes work item f59f0132
(ai-resolve bug-verification stage, M42 concept 7666d278). Mirrors
planning-opus-repo's layer stack with the sonnet model applied at the
node level (model: sonnet), per the established convention that the
composite name is descriptive only — the workflow node's own model:/
tier: field is what actually selects the model.

The template's terminal node runs the (separately-tracked, sibling
task ad975ac6) state-tx-verdict script — this template will not be
runnable end-to-end until that script lands, but the declarative
config itself is independently valid: schema-validates cleanly and
both eligibility scenarios from the task spec pass (verify-pending +
ai-resolve -> ok=True; missing flow_state -> state_mismatch).
2026-09-05 11:34:37 +12:00
Paul O'Reilly
0384e5d453 fix: remove misplaced hatchmate-plan-review-loop@1 (project template referencing hatchmate-crs model slugs; broke CP WorkflowRegistry reload 2026-09-05)
Belongs in hatchmate-crs/task-templates/workflow/plan-review-loop@1.yaml, which already exists.

Claude-Session: https://claude.ai/code/session_01FNHuaZyTjdknKYcQdbRTcp
2026-09-05 10:24:36 +12:00
Paul O'Reilly
b4bac0d2e8 feat: hatchmate-plan-review-loop@1 — project-specific plan review template
Hand-sync of hatchmate-crs's plan-review-loop@1 under a project-prefixed name
so hatchmate's triggers can reference it via the global WorkflowRegistry.

Interim pattern until agent-runtimes ships project-scope template serving
via crs_manager (M42 gap: DispatchService only consults the concepts_syncer
WorkflowRegistry, not crs_manager's repo store). Template is hatchmate-specific
throughout: Fable-low + MiniMax-M3-max + Airouter-Qwen3.8-max reviewers,
hatchmate/hatchmate-agents clone URL, hatchmate-aware prompts and conventions.

Claude-Session: https://claude.ai/code/session_01PdFrhZypEDBTsbAeTJqHq1
2026-09-04 20:49:13 +12:00
Paul O'Reilly
253b147a39 fix(harness): cp-service-token/v1 — restage ESO secret, fix unreadable-by-agent bug
The ESO-mounted secret is root-owned mode 0400 (correct — init.sh runs as
root before the gosu drop to the agent user). The original version of
this context pointed CP_SERVICE_TOKEN_FILE directly at that raw mount,
which the agent process (uid 1000) can never read.

Confirmed live 2026-09-03: a real scope-decompose-sonnet@1 dispatch
against concept 7666d278-ae58-4f12-990d-c4959a3e19a9 hit exactly this —
the agent correctly diagnosed 'cp_cli invocation can't proceed... token
is root-owned mode 0400 so it's not readable by the agent user', wrote
its decompose plan, but could never actually call cp-cli to create the
child tasks. The trigger engine's new side-effect verification (finalize.py,
bug 9dffc5b8) correctly caught this and refused to advance flow_state —
so this was a visible, retriable failure rather than another silent
false-positive.

Fix: init.sh restages the secret to /run/agent/cp-service-token/token,
mode 0600, owned by the agent user — mirrors
anthropic-cloud-paul-oauth/v1/init.sh's existing pattern.
CP_SERVICE_TOKEN_FILE now points at the restaged copy.
2026-09-04 13:03:07 +12:00
Paul O'Reilly
38cd0b040b feat(harness): cp-service-token/v1 context — AU-51/AU-51b credential for decompose
New context mounts the cp-decompose-service-token account (system
provider type, account_id 1d963673-6ac9-4f85-875a-2ce5323e76ad, owner
(cp, cp)) via ESO and exports CP_SERVICE_TOKEN_FILE pointing at the
mounted secret file. Wired into spec-writing-sonnet-repo (backs
scope-decompose-sonnet@1, which calls back POST
/v1/work-items/{id}/decompose — bug b3a96acc / fa41caac / M42 stall).

The mounted value must match the CP's CP_INTERNAL_BEARER_TOKEN
(agent-runtimes deploy repo, overlays/{production,staging}/app-secret.sops.yaml).

No init.sh needed — the mount path is static at harness-authoring time
and entrypoint/actions/decompose_work_items.py (AU-51b, agent-runtimes
commit 0fa8b760) reads CP_SERVICE_TOKEN_FILE directly, so no
transformation/staging step is required.
2026-09-04 05:31:34 +12:00
Paul O'Reilly
2dcb9c7605 fix(minimax-m3-max, fable-low-effort): requires takes harness refs, not capability tags
'requires: [claude-code]' failed composition ('Invalid harness reference
format'). Both contexts need no hard dependency — layer ordering in the
composites already guarantees the auth layer precedes them. Validated
locally with entrypoint.harness compose_harness for all 6 affected
composites this time.

Claude-Session: https://claude.ai/code/session_019tJk7P8tZzJ24PvtgoGhLN
2026-09-03 01:13:34 +12:00