Commit Graph

71 Commits

Author SHA1 Message Date
Paul O'Reilly
2fa4dc92c2 pipeline model routing: mechanical stages to MiniMax M3, spec stages to Fable low effort
- scaffolding-repo + test-writing-repo: anthropic-cloud-paul-oauth -> minimax + minimax-m3-max
- merge@1: new best-practices-minimax-repo composite (impl-review stays Sonnet)
- spec-draft-opus@1: Opus -> Fable 5 low effort via new fable-low-effort/v1
  env context (ANTHROPIC_MODEL=claude-fable-5, MAX_THINKING_TOKENS=1024) +
  spec-writing-fable-low-repo composite
- review-spec-arch-opus@1: Qwen3.6/airouter -> Fable 5 low effort via
  best-practices-fable-low-repo (arch review was on the cheapest model)

Template names kept (trigger rules reference them). Node model: fields
removed where env pins the model — a --model flag overrides ANTHROPIC_MODEL.

Claude-Session: https://claude.ai/code/session_019tJk7P8tZzJ24PvtgoGhLN
2026-09-02 21:43:23 +12:00
Paul O'Reilly
4201b1ac3a integration-direct: route to MiniMax M3 max-effort instead of Anthropic OAuth
Integration runs were burning the personal Anthropic 5-hour window
(429 storm + window drain, 2026-09-02). New env-only context
minimax-m3-max/v1 pins ANTHROPIC_MODEL=MiniMax-M3[1m], maxes the
thinking budget, and sets the 1M auto-compact window; layered on
minimax/v1 for base URL + apiKeyHelper auth.

Claude-Session: https://claude.ai/code/session_019tJk7P8tZzJ24PvtgoGhLN
2026-09-02 21:33:50 +12:00
Paul O'Reilly
e89208f44b fix(templates): per-item branches for concept-stage nodes (was shared spec/auto-draft)
All 6 concept/idea-stage templates hardcoded the literal shared branch
spec/auto-draft instead of a per-item branch. Concurrent concept items
(now routine via the M41 auto-advance sweep) all pushed to the same
branch — a git collision risk. Switched to spec/${item.uuid}, matching
the established task/${item.uuid} convention used by every task-stage
template (merge@1, scaffold@1, etc — see spec/typed-workflows.md WF-COMP
stable-per-item-branch rationale). spec-review-loop@1's 4 nodes keep the
literal branch shared ACROSS the node set (now per-item, not global) so
loop iterations still accumulate on one branch per item, per spec's
cross-iteration-artifact caveat.

Files: review-spec-arch-opus@1.yaml, spec-draft-opus@1.yaml,
spec-review-loop@1.yaml, review-spec-arch-airouter@1.yaml,
spec-draft-airouter@2.yaml, scope-decompose-sonnet@1.yaml
2026-09-01 02:11:20 +12:00
Paul O'Reilly
e0d3a60279 fix(templates): spec-draft-opus@1 route to Opus, not airouter/Qwen3.6
Was silently dispatching to Qwen3.6 via airouter despite the name;
live runs were timing out (exit_code=124), wedging four M41 auto-advance
concepts. Mirrors agent-runtimes commit acc5cbe5.

Claude-Session: https://claude.ai/code/session_012arAwUuBQrpnMzJ36mEVBk
2026-09-01 00:37:52 +12:00
Paul O'Reilly
fefc8846c3 templates: reference triggers.yaml with WT-ADV safe defaults (M41)
version: 2 + auto_advance default deny — imported projects are inert until
a human applies a grant tag (spec/workflow-triggers.md §3b WT-ADV-8).

Claude-Session: https://claude.ai/code/session_012arAwUuBQrpnMzJ36mEVBk
2026-08-30 02:56:03 +12:00
Paul O'Reilly
73acc6a11d feat(best-practices): pointer CLAUDE.md so agents know the library exists
The 237KB library was mounted at /workspace/best-practices/ in every
consuming ConfigMap but nothing in the prompt mentioned it (directory
targets never enter the context manifest). New ~90-word CLAUDE.md file
target enters the system prompt: points at INDEX.md, instructs reading
only task-relevant topics.

Claude-Session: https://claude.ac/code/session_012arAwUuBQrpnMzJ36mEVBk
2026-08-19 09:34:31 +12:00
Paul O'Reilly
1ce42a9e59 fix(harness): resolve layer contradictions + context-budget caps for airouter TDD
- tdd-gate: pass criterion is the task's TEST_FILES scope (matches
  run-ci-tests.sh M19 P-14), not the full suite — contradicted
  qwen-code-methodology rule 5 in the same system prompt
- tdd-protect: tests/ path described relative to project working dir
  (AGENT_WORKING_DIR is /workspace/project in repo composites)
- qwen-code-methodology: task_complete tool DOES exist — rule 8 said
  the opposite; pytest examples use -q
- airouter-code-tdd template: TT-39 runtime_overrides
  (max_result_bytes 24KB, max_history_turns 16)

Claude-Session: https://claude.ai/code/session_012arAwUuBQrpnMzJ36mEVBk
2026-08-19 09:10:22 +12:00
Paul O'Reilly
76a7277961 fix(decompose-template): replace inline python3 -c paste with cp-cli decompose verb
The python3 -c block imported internal entrypoint code directly and
pasted module paths into agent prompts — a security boundary violation.
Switch to the thin-client verb (added in agent-runtimes a116aedb).

Claude-Session: https://claude.ai/code/session_0124mK2BVfCdkELLXDCr5Zzs
2026-08-17 10:11:22 +12:00
Paul O'Reilly
18a702d7a0 fix(integration-direct/v1): add missing agent-repo/v1 layer
All tasks dispatched to integration-direct/v1 were failing with
harness_missing_agent_repo_layer because dispatcher DSP-1 guard
requires agent-repo in the composite when AGENT_REPO_URL is set.

direct-push/v1 sets env vars (AGENT_SKIP_BRANCH_PUSH,
AGENT_EMPTY_DELIVERABLE_CHECK) that configure agent-repo's finalize.sh,
so agent-repo/v1 must precede it in the layer list.
2026-08-01 00:17:37 +12:00
Paul O'Reilly
b5f039f73f fix(workflows): use artifacts.item_body not metadata.task_description
metadata.task_description is not in the consumer snapshot — the trigger
consumer only populates metadata.automation from the outbox typed_payload.

artifacts.item_body IS populated via dispatch_service from
item_snapshot["body"] (set from typed_payload.body in the consumer,
which comes from item.get("body") in emit_work_item_event).

For M39 items the body contains the full task description, so
${artifacts.item_body} gives the agent complete implementation instructions.
2026-07-31 10:44:14 +12:00
Paul O'Reilly
fc27ffe170 fix(workflows): airouter-impl-ready prompt was producing empty task descriptions
${metadata.automation.test_files} and ${metadata.automation.spec_ids} are
absent from M39 work items (created from dashboard without these fields),
resulting in an empty, useless prompt:
  "Implement the failing test. Test files: . Spec IDs: ."

Switch to ${metadata.task_description} — a sibling metadata key (not under
automation, so write-protected path does not apply) — populated by patching
items with their body text. The _TriggerItemView in dispatch_service.py
correctly exposes item.metadata so this resolves at compile time.

All 16 scaffolded M39 items patched with metadata.task_description via CP API.
2026-07-31 10:40:34 +12:00
Paul O'Reilly
d06a526256 feat(templates): sync 4 workflow templates from agent-runtimes
Add direct-impl-sonnet@1, plan-review-loop@1, spec-review-loop@1,
test-write-review-loop@1 — present in agent-runtimes but missing here.
These are needed before agent-runtimes drops its baked-in copies and the
CP loads workflow templates exclusively from this CRS repo.
2026-07-29 09:09:52 +12:00
Paul O'Reilly
350c0eeed4 feat(templates): 6-tier escalation ladder — add MiniMax + Fable tiers
New tiers in the coding queue:
  airouter(0-2) → minimax(3-5) → sonnet(6-7) → opus(8-9) → fable(10) → blocked(11+)

- models/claude-fable-5.yaml: Fable 5 model definition (Anthropic cloud, claude runner)
- harnesses/composites/code-fable-tdd-repo/v1: Fable TDD composite (mirrors opus, anthropic-cloud-paul-oauth auth)
- model-registry/harness-roles.yaml: claude-fable-5 → code-fable-tdd-repo under code-tdd role
- model-registry/tiers.yaml: claude-fable-5 added to coding.qualifies_today
- task-templates/workflow/minimax-impl-ready@1.yaml: MiniMax TDD workflow (scope: 3 files / 200 lines / 30m)
- task-templates/workflow/fable-impl-ready@1.yaml: Fable TDD workflow (scope: 5 files / 400 lines / 60m)

Claude-Session: https://claude.ai/code/session_015sCpoFee3LsLKbHQ4FRRWY
2026-07-29 01:59:54 +12:00
Paul O'Reilly
a12f6ddaba feat(templates): tiered escalation ladder — remove airouter-eligible gate
Remove `tags_required: [airouter-eligible]` from airouter-impl-ready so all
non-skip tasks route through the full airouter→sonnet→opus ladder automatically.
Add `airouter-skip` to airouter's tags_forbidden so opt-out tasks go directly
to sonnet from attempt 0.

Relax sonnet-impl-ready tags_forbidden (drop multi-file + algorithmic-large)
so sonnet handles complex tasks at escalation tier without template rejection.

Add opus-impl-ready@1.yaml — last-resort escalation, code-opus-tdd-repo
composite, scope_budget 5 files / 400 lines / 3600s.
2026-07-29 01:32:24 +12:00
Paul O'Reilly
2c1ec7d52c fix: update MiniMax harness base URL to api.minimaxi.chat
MiniMax moved their Anthropic-compatible API from api.minimax.io to
api.minimaxi.chat. Update ANTHROPIC_BASE_URL in the minimax/v1 context
harness and corresponding comments in init.sh and the TODO note.

Model routing is unaffected: the API defaults unrecognised model names
(e.g. "minimax" from the registry slug) to MiniMax-M3 already.

Claude-Session: https://claude.ai/code/session_01XtWRazqRbMnMRa4iV3zbVx
2026-07-17 22:55:47 +12:00
Paul O'Reilly
1da98eb708 Add model-registry/harness-roles.yaml — W3 harness auto-selection role table 2026-07-12 23:17:07 +12:00
Paul O'Reilly
78229c5dba feat(routing): add tiers.yaml + rename spec/review-arch templates to airouter
W1 stage-routing work:
- model-registry/tiers.yaml: defines planning/spec-test/coding tier floors
  (complexity≥9/creativity≥9/context≥9 | spec_adherence≥9/test_pass_rate≥9 |
  spec_adherence≥7/test_pass_rate≥7) with qualifies_today lists
- spec-draft-airouter@2.yaml: honest name for what was spec-draft-opus@1
  (always ran Qwen3.6/airouter, not Opus)
- review-spec-arch-airouter@1.yaml: honest name for review-spec-arch-opus@1

Old @1 files kept for in-flight task backward-compatibility.

Claude-Session: https://claude.ai/code/session_01B35bPAKv5uyW1F9gzMcRN7
2026-07-12 19:03:51 +12:00
Paul O'Reilly
681f0ce4fa fix(hugo-content-workspace): never commit .agent-output/ runner scratch — was creating junk content commits + spurious CI rebuilds on every AI task 2026-07-07 16:56:24 +12:00
Paul O'Reilly
ae4c8c29f8 fix(gitea-ssh-accelerators): ESO mounts the key as private_key, not id_ed25519 — matches gitea-ssh/v1 and the acct secret's data keys 2026-07-07 11:17:52 +12:00
Paul O'Reilly
10df741c4a fix(hugo-content-workspace): requires: [] — resolver treats requires as harness refs, git-access capability name crashed composition 2026-07-07 11:10:35 +12:00
Paul O'Reilly
d1dcdf4a8c fix: per-item work branch (task/${item.uuid}) across all task-stage templates 2026-07-04 19:37:03 +12:00
Paul O'Reilly
4b39c9822f fix: impl-review + merge on Sonnet/best-practices-opus-repo (unclaimable routing + empty-delivery risk) 2026-07-04 18:50:57 +12:00
Paul O'Reilly
01fb6f3ad0 fix: scope-decompose claude cli + AR-38 audit off (API-side-effect deliverable) 2026-07-04 15:19:32 +12:00
Paul O'Reilly
b1ad85f46d fix: scope-decompose-sonnet runs model:sonnet on spec-writing-sonnet-repo (was Qwen3.6/airouter — empty-delivery in E1 E2E) 2026-07-04 14:09:24 +12:00
Paul O'Reilly
71f9cc0338 feat(airouter): DeepSeek V4 Flash TDD composite + max-effort template
New code-airouter-deepseekv4flash-tdd-repo/v1 composite (deepseek
methodology + the same tdd-protect/tdd-gate/python-dev/tdd-file-lock
layers as the Qwen TDD composite), plus a task-template that sets
reasoning_effort=max via the new extra_body passthrough (agent-runtimes
TT-38). Model/endpoint/model-registry entries already existed; only
the TDD-capable harness and the template were missing.
2026-07-03 12:36:43 +12:00
Paul O'Reilly
dab3db3727 fix(best-practices): restore canonical content, dedupe, sync script, spec exemplar
- best-practices/v1: replace 9 stale symlinks (into planning/v1) with real files
  synced byte-identical from the canonical best-practices project; add INDEX.md,
  scripting.md, mechanical-test-generation.md (canonical had drifted heavily,
  e.g. api-design.md 463->807 lines)
- planning/v1: delete duplicated best-practices/ copy (requires: inheritance
  confirmed via spec/harness.md HC-1/HC-7)
- scripts/sync-best-practices.sh: idempotent re-sync from canonical checkout
- code-methodology/v1: INDEX.md + scripting.md references now resolve; point
  test-writing tasks at mechanical-test-generation.md
- spec-writing/v1: worked spec exemplar (module layout table, Why: lines, exact
  error messages, parametrize pattern table) + CLAUDE.md pointer + mount entry
2026-07-02 21:27:43 +12:00
Paul O'Reilly
97d98689be feat(templates): add missing escalation targets + concept-intake stage
fix-test-fixture-sonnet@1, review-spec-opus@1, replan-spec-opus@1 — the
dangling escalation refs from airouter-impl-*/spec-draft/feature-delivery-loop.
Sonnet-authored, Opus-reviewed; review HIGH fixes applied (explicit model: opus
on both opus nodes — node model: sets runtime model, composite name does not).
Known gap filed in work-items epic (E1-escalation-state-gap.md): escalation
edges from non-primary states 422 state_mismatch pending escalation_input_states.
concept-intake@1: optional idea-elaboration pre-stage (output state
idea-elaborated — not yet wired into spec-draft-opus input).
All four validate against controlplane WorkflowTemplate schema.
2026-07-02 21:27:43 +12:00
Paul O'Reilly
f3d7b42db5 feat(sonnet-manager): write full manager CLAUDE.md from spec/manager-sonnet.md
Replaces the 7-line stub: hard rules (eligible-list-only dispatch, code-blind,
explicit auth, read-only policy, untrusted inbox bodies), normative outer loop
+ MS-24 idle-exit sequence, typed-message routing, MS-25 fallback format,
cp-cli exit-code reactions, decision-log etiquette.
2026-07-02 21:27:43 +12:00
Paul O'Reilly
4d7acc870c reflect-logs: distill session logs into topic memory (2026-07 sweep) 2026-07-02 16:05:43 +12:00
Paul O'Reilly
dd0d9e5c0a feat: hugo-content-workspace + hugo-content-airouter harnesses
New context: hugo-content-workspace/v1
- init.sh: clones hugo-{customer}-content at HUGO_CONTENT_BRANCH and
  hugo-{customer}-integration at main via gitea-ssh-accelerators
- finalize.sh: detects changes, commits content repo first then
  integration repo; skips silently if no changes
- CLAUDE.md: instructs the agent to work in /workspace/content/

New composite: hugo-content-airouter/v1
- Combines airouter/v1 + gitea-ssh-accelerators/v1 + hugo-content-workspace/v1
- Label-gated to airouter dispatchers (ESO secret required)

Used by cms-proxy /ai/{customer}/draft endpoint.
2026-06-24 07:10:05 +12:00
Paul O'Reilly
8167035b6b Add DeepSeek V4 Flash model and coder composite via airouter
- models/airouter-deepseekv4flash.yaml: DeepSeek-V4-Flash on airouter.ch endpoint,
  temp 1.0 / top_p 1.0 per recommended reasoning defaults, 262k context / 65k output
- model-registry/airouter-deepseekv4flash.yaml: deepseek provider, complexity 9,
  creativity 9, cost_efficiency 10 (covered by airouter sub)
- harnesses/contexts/deepseek-code-methodology/v1: DeepSeek-specific methodology
  CLAUDE.md; same rules as qwen-code-methodology but with correct model header
- harnesses/composites/code-airouter-deepseekv4flash-repo/v1: coder composite
  using airouter/v1 context (shared endpoint + secret — no new ESO resources needed)
2026-06-23 22:07:33 +12:00
Paul O'Reilly
93c4dad1a7 docs: update CLAUDE.md — CRS is now required, add workflow/ subdir to structure 2026-06-23 09:08:06 +12:00
Paul O'Reilly
f5968cfab5 feat: migrate missing harnesses, templates, and workflows from agent-runtimes
Brings the framework CRS repo up to date with all content that was
living in agent-runtimes (local-dev fallback) but hadn't been promoted.

New composites: feature-delivery-loop, integration-direct, scaffolding-repo,
sonnet-impl-narrow, sonnet-manager, test-writing-repo

New contexts: integration/v1, scaffolding/v1, sonnet-manager/v1, z-ai/v1,
airouter/v1/bin (anthropic-compat-wrapper.sh), cp-harness/v1/init.sh

New task-templates: sonnet-integrator.yaml, workflow/* (17 typed workflow
task templates for the Epic 1 pipeline)

Updated: agent-repo/v1/finalize.sh — adds AR-38/F97 empty-deliverable audit
(SKIP_BRANCH_PUSH support, boilerplate-path filtering, ci_metadata.json flag)

Also adds MEMORY.md index and memory/ topic files for the framework repo.
2026-06-23 08:59:01 +12:00
Paul O'Reilly
770ba97170 feat(epic1): add spec-writing-airouter-repo and best-practices-airouter-repo composites
Required by the Epic 1 trigger pipeline in agent-runtimes:
- spec-draft-opus@1 uses spec-writing-airouter-repo (concept→spec-draft workflow)
- review-spec-arch-opus@1 uses best-practices-airouter-repo (spec-draft→spec-reviewed-arch)
- scope-decompose-sonnet@1 uses spec-writing-airouter-repo (spec-reviewed-arch→scoped-tagged)

Both composites require the airouter label so only the airouter dispatcher claims them.
2026-06-19 17:34:58 +12:00
Paul O'Reilly
38dc28fef9 fix(harness): remove agent-repo/v1 from code-sonnet-direct composite
agent-repo/v1 init.sh creates /workspace/project/results/ and .gitignore,
making the directory non-empty before the integrator clone action runs.
git clone into a non-empty directory fails with 'already exists'.
Integrators don't need the agent-repo lifecycle — they clone origin/main
directly and push back. Remove agent-repo/v1 from the composite.
2026-06-15 01:27:55 +12:00
Paul O'Reilly
50c07b850c feat(harness): add code-sonnet-direct composite + direct-push context
Copies code-sonnet-direct/v1 (composite) and direct-push/v1 (context)
from agent-runtimes local harnesses to the CRS-served framework repo.
These are required by the sonnet-integrator task template used in the
ralph coding loop. Without them, all integrator dispatches fail with
"harness not found in any concepts repo: code-sonnet-direct/v1".
2026-06-15 00:18:43 +12:00
Paul O'Reilly
415118434c debug(agent-repo): expose reference_branches clone failure mode
Probes 7-9 (2026-05-08) all "succeeded" but with empty diffs because
AR-14a fell back to fork main: "WARNING: /workspace/reference/main/.git
not found; using fork main (may be stale)". The reference clone python
loop printed "Cloning git@..." but never "Cloned main successfully" —
no error visible either.

Most likely cause: full-history clone (post-3087ad7) is hitting some
silent failure mode (auth, fs perms, OOM, timeout). With capture_output=True
the git clone's own output was hidden.

Add explicit logging:
- python3 -u (unbuffered stdout)
- pre-loop "reference_branches loop: N entries"
- post-clone "clone returncode=N"
- always-print stdout (last 1KB) and stderr (last 1KB) from subprocess
- explicit chmod return code check
- post-clone .git existence assertion

Next probe will tell us EXACTLY what's failing.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-08 17:24:10 +12:00
Paul O'Reilly
3087ad7de1 fix(agent-repo): full-history clone for reference + upstream-ref fetch
Probe 7 (2026-05-08) finally surfaced the actual push error:

  ! [remote rejected] HEAD -> task-9dc266b5 (shallow update not allowed)

Cause: REFERENCE_BRANCHES handler clones with --depth 1, AR-14a then
fetches upstream-ref --depth 1. The agent's task branch is a single
commit on top of a single shallow commit — no ancestry visible. Gitea
rejects shallow pushes server-side.

Fix:
- Reference clone drops --depth 1 (full history)
- AR-14a fetch upstream-ref drops --depth 1 (full fetch from local-path)
- Cost: a few extra MB per task on tmpfs/PVC. Acceptable.

This unblocks AR-14a's upstream-seeding for the dogfood pipeline. The
agent's branch now has the full upstream history visible to gitea.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-08 17:09:53 +12:00
Paul O'Reilly
bf18ca3ef5 fix(agent-repo): capture git push output explicitly for diagnosis
Probe 6 (2026-05-08) showed git push failing twice with exit 1 and
zero visible output — the previous form `if cmd 2>&1; then` redirected
git's stderr to stdout where the entrypoint's stderr-only log capture
missed it. CP-side log showed only the bash `set -x` trace, not the
actual git error message (e.g., "Permission denied (publickey)" or
"remote: pre-receive hook rejected").

Refactor the push retry loop:
- Capture output to PUSH_OUT via $() with `2>&1`
- Wrap in set +e/set -e to detect non-zero without aborting
- echo PUSH_OUT to stderr (where set -x trace also goes) so the
  entrypoint's stderr capture sees it

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-08 17:03:12 +12:00
Paul O'Reilly
9cf016fa1c fix(agent-repo): harden AR-21 diff-verify against set-e/pipefail abort
The 2026-05-08 attempt-2 dogfood batch had 8/8 tasks "succeed" with
zero branches pushed. Root cause: my AR-21 diff-verification block was
running under set -euo pipefail without explicit error handling. A
single non-zero exit anywhere in the `git diff | tr | sed` pipeline
killed finalize.sh before the metadata write or push ran.

Specific risk: `git diff <REF_HEAD>..HEAD` returns non-zero when the
SHA is unreachable (e.g., shallow clone with init.sh fork-fallback
where upstream-ref wasn't fetched). pipefail then kills the pipeline,
set -e kills the script.

Fix: wrap the entire AR-21 block in `set +eo pipefail` (with explicit
`set -eo pipefail` restore at the end). Also:
- Use `${arr[@]:-}` instead of `${arr[@]}` for set -u safety on empty
  arrays
- Add `|| true` to git command substitutions (belt-and-braces)
- Use `printf` instead of `echo` for the comma-wrap (more portable)

Verified locally: when `/workspace/reference/main/.git` is absent the
block correctly skips with the existing fallback; when present and
upstream-ref is reachable, the block runs and reports DIFF_VERIFIED.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-08 16:31:33 +12:00
Paul O'Reilly
07309567d5 feat(agent-repo,airouter): seed from upstream + label-gate + diff verify
Three load-bearing fixes for the airouter dogfood pipeline, derived from
the 2026-05-08 batch-3 dogfood postmortem (gotchas-airouter.md items 27-30):

1. agent-repo/v1/init.sh — seed fresh task branches from
   /workspace/reference/main/ (the upstream clone) rather than the agent
   repo's stale main. This was THE killer for batch 3: the
   agent-runtimes-agents fork has been frozen at 2026-05-04 since the
   "Fork cleanup" PR, so every agent started from old state, missing
   recent test files and the M16/M22 scripts to delete. The fork remains
   the push remote (so finalize.sh works); only the working-tree seed
   moves to the upstream reference. Falls back to fork main when the
   reference clone isn't available (preserves legacy behavior). Tagged
   AR-14a.

2. requires_labels on contexts/composites — airouter context + both
   airouter composites declare requires_labels: [airouter] so the
   dispatcher's _collect_supported_harnesses (with the matching agent-
   runtimes change) advertises them only on dispatchers carrying the
   airouter label. Stops the main dispatcher from claiming airouter-
   labeled tasks and dying at init time. Composites that wrap label-
   restricted contexts MUST redeclare their own requires_labels — no
   auto-traversal of layers (kept simple).

3. agent-repo/v1/finalize.sh — AR-21 diff-against-upstream verification.
   New env-var protocol:
     - AGENT_EXPECTED_CHANGED_FILES (comma-separated paths that MUST
       appear in `git diff <ref/main>..HEAD`)
     - AGENT_FORBIDDEN_CHANGED_FILES (paths that MUST NOT appear)
   finalize.sh fails the task (exit 1) if either invariant is violated;
   the branch is still pushed for forensics so the operator can inspect.
   Catches BOTH the false-success mode (item 30 — agent reports succeeded
   but never changed the target file) AND the destructive-Write mode
   (item 21 — task 4a2f2988 stripped 9 unrelated functions). Also writes
   diff_verified, diff_mismatch, diff_changed_files into ci_metadata.json.

CRS pulls all three on next CP poll — no agent-runtimes image rebuild
needed for the framework parts. The matching dispatcher poller filter
ships in agent-runtimes (separate commit).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-08 15:45:41 +12:00
Paul O'Reilly
45ec4af0e9 docs(qwen-methodology): add real incident to Rule 1 (Write on existing files)
After the 2026-05-08 M16 Wave A1 dogfood task `4a2f2988` produced a
correct narrow change but accidentally deleted 9 unrelated functions in
the same file (Write rather than Edit), the existing Rule 1 in
qwen-code-methodology/v1/CLAUDE.md is clearly insufficient — the agent
saw it and overrode it anyway. Concrete real-world example added inline
so the next agent reading this CLAUDE.md sees the consequence: "the
narrow test passed but the application broke everywhere else, the
branch was rejected, the agent thought it had succeeded."

CRS picks up automatically on next CP poll.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-08 13:09:52 +12:00
Paul O'Reilly
79f00b566d feat(cp-harness): migrate from agent-runtimes/harnesses/
The agent-runtimes repo is moving to a CRS-only harness model: dispatcher
images stop baking in /app/harnesses/ and discover them via CRS at runtime.
cp-harness was the only harness that lived only in the agent-runtimes
checkout (created in M16 Phase 1 D4, commit c1df4cc) — copied here so
nothing is lost in the cutover.

cp-harness has no current consumers (no composite or template references
it); it is infrastructure for the future M16 self-orchestration api_key
submission flow.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-08 12:25:47 +12:00
Paul O'Reilly
b1e3ee7052 fix(airouter): match ESO Secret schema (api_key) + drop dead wrapper
The airouter ESO ExternalSecret materialises a single key `api_key`
(matching the provider schema in agent-runtimes M22 Phase 8e cutover,
acct-59b7fb0b). The harness init script was checking for `auth_token` +
`base_url` (an Anthropic-compat shape that never existed in real Vault
state) and failing on every dispatch:

  ERROR: /run/agent/secrets/airouter/auth_token not readable.
  Check ESO ExternalSecret for airouter.

Surfaced as the second blocker for the M16 Wave A1 dogfood (the first
was the airouter dispatcher missing CRS sync; that fix went into
agent-runtimes-deploy@0f11cd1).

Same shape of bug as the minimax + gitea-ssh init scripts that landed
during the same M22 phase — those were fixed at the time, airouter was
not.

Changes:
- init.sh: verify the single `api_key` file (root-only, 0400 ESO mount).
  Stage to /var/agent-secrets/airouter/api_key with mode 0600 agent-owned
  (mirrors minimax pattern). H-SECRET-4 compliant — no exports.
- harness.yaml: add OPENAI_API_KEY_FILE pointing at the staged path.
  Agentic runner reads the file at request time per
  entrypoint/runners/agentic.py:146 (OPENAI_API_KEY_FILE precedence).
- Delete dead bin/anthropic-compat-wrapper.sh — confirmed unused per
  agent-runtimes/memory/log/2026-05-07.214249.md (post-M22-Phase-9 cleanup
  found these per-provider wrappers were never invoked; runner only
  prepends /opt/agent/claude-wrapper.sh).

CRS picks this up automatically on next CP poll; no agent-runtimes image
rebuild needed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-08 12:24:58 +12:00
8669b3da7d Merge pull request 'chore(z-ai): retire harness — no active subscription' (#2) from retire-z-ai into main 2026-05-07 21:41:33 +00:00
Paul O'Reilly
335e6f5b34 chore(z-ai): retire harness — no active subscription
Removes harnesses/contexts/z-ai/v1/. Mirrors the agent-runtimes
companion PR — the z-ai harness was never cut over to ESO and
there's no active subscription. Revival path documented in
agent-runtimes planning/future/providers F49.

Removed:
- harnesses/contexts/z-ai/v1/{harness.yaml, init.sh}

Updated:
- CLAUDE.md — drops z-ai from the 'no secrets in this repo'
  context list. Retirement note added.
- gitea-admin/v1/init.sh — comment ref to z-ai removed.
- gitea-https/v1/init.sh — comment ref to z-ai removed.

No composites layer z-ai (verified via grep across composites/);
no model registry entries reference it.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 09:40:44 +12:00
649acc07df Merge pull request 'fix(b22): bare account_ref + retarget composites + delete stale anthropic-cloud/v1' (#1) from b22-anthropic-cleanup into main 2026-05-07 20:10:15 +00:00
Paul O'Reilly
7a75c5ec3b fix(b22b): retarget composites + delete stale anthropic-cloud/v1
Phase 8 cutover (M22) renamed the anthropic harness from anthropic-cloud
→ anthropic-cloud-paul-oauth in agent-runtimes, but the equivalent
rename in this framework's composites and the deletion of the stale
SOPS-era anthropic-cloud/v1 dir were never done. Every cloud-Anthropic
composite (haiku/sonnet/opus code, planning, security-review, spec-
writing, test-writing, best-practices) layered the dead context and
silently never resolved a credential.

- Update 14 composites to layer anthropic-cloud-paul-oauth/v1
- Delete the orphaned harnesses/contexts/anthropic-cloud/v1/ directory
  (used pre-Phase-9 SOPS file delivery; now obsolete)

Closes BUG-22b. Pairs with the live PATCH /v1/accounts/{id} rename
shipped under BUG-22a.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 07:16:09 +12:00
Paul O'Reilly
3d6a50fdd7 fix(b22a): bare account_ref for anthropic-cloud-paul-oauth harness
Same bug as upstream agent-runtimes: scoped form never matched
because the dispatcher does literal scope.id compare and
owner_principal_id stores the user UUID, not 'paul'.

Pairs with PATCH /v1/accounts/{id} renaming the live account_label
to 'anthropic-cloud-paul-oauth' so the bare ref resolves uniquely.

Closes BUG-22a.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 06:58:39 +12:00
Paul O'Reilly
f8c8805f26 fix(harnesses): stage tokens for agent UID, fix three broken auth paths
Mirrors agent-runtimes audit + fix. All three M22 Phase 9 wrapper-script
auth paths were broken since the cutover: each one ran as the agent UID
trying to `cat` a 0400 root-only ESO mount. Same root cause we hit on
minimax/z-ai earlier today.

Changes:

1. anthropic-cloud-paul-oauth/v1 (NEW in framework)
   - Mirrors agent-runtimes — was previously only present there.
   - init.sh stages oauth_token into ~/.claude/.credentials.json (Claude
     Code's native subscription-OAuth schema). No env, no apiKeyHelper,
     no wrapper. Restores the equivalent of what harness_init.py used to
     do for the legacy SOPS path.
   - The legacy `bin/anthropic-wrapper.sh` was dead code (never wired).

2. gitea-https/v1
   - init.sh stages the token to $HOME/.config/git/gitea-https-token
     (0600 agent:agent) and points the per-host git credential helper at
     the staged copy. Previously the helper `cat`d the ESO mount path
     and silently failed at every git invocation.

3. gitea-admin/v1
   - init.sh stages the token to $HOME/.config/gitea-admin/token
     (0600 agent:agent). Wrapper updated to read from the staged copy.
   - Removes stale `requires: anthropic-cloud/v1` (the only anthropic
     harness in agent-runtimes is anthropic-cloud-paul-oauth/v1).

Pattern matches gitea-ssh / minimax / z-ai: ESO mount stays root-only,
init.sh runs as root and `install -m 0600 -o agent -g agent`s a single
explicit copy. Per-secret enumeration; future ESO Secret keys remain
inaccessible by default.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-07 21:05:33 +12:00