Skip to content

release: v4.4.0 — auto-rebake on class-B drift + widen compat-test paths#306

Merged
askalf merged 2 commits into
masterfrom
feat/v4.4.0-auto-rebake
May 17, 2026
Merged

release: v4.4.0 — auto-rebake on class-B drift + widen compat-test paths#306
askalf merged 2 commits into
masterfrom
feat/v4.4.0-auto-rebake

Conversation

@askalf
Copy link
Copy Markdown
Owner

@askalf askalf commented May 17, 2026

What does this PR do?

Closes the manual-remediation step in the drift loop. Pre-v4.4.0: detection ✓ → issue opened ✓ → maintainer SSHes into a CC-installed machine → `capture-and-bake` → review diff → commit → PR → merge → issue auto-closes. v4.4.0 replaces the three middle steps with a bot, mirroring `cc-drift-watch.yml`'s class-A auto-PR pattern.

Auto-rebake workflow change

`.github/workflows/cc-drift-template-watch.yml` gets a new "Auto-rebake + open PR" step that fires on `--check` exit 2:

  1. Skip if a `bot/template-rebake-*` PR is already open (de-dup by branch-name prefix)
  2. Run `node scripts/capture-and-bake.mjs` (real write — not `--check`)
  3. Bail with workflow warning if bake produced no diff vs HEAD (catches the rare transient where `--check` and the real bake disagree)
  4. Commit as `cc-drift-template-watch[bot]`, push to `bot/template-rebake-YYYYMMDD-HHMMSS`, open a labeled PR with the drift report inline
  5. The existing drift-issue step references the open PR (or a "rebake skipped" note)

Not auto-merged. The bundled template is the wire-shape contract for non-CC clients. compat-test exercises only the passthrough plane; the rebuild-from-canonical plane is not currently covered by an end-to-end test, so a human approves the bake. Compat-test still fires automatically on the bot's PR because the path filter includes `src/cc-template-data.json`.

Permission bump

`contents: write` (was `read`) for `bot/*` push, `pull-requests: write` (added) for PR open. Master branch protection still gates the actual merge.

Compat-test path filter widened

`.github/workflows/compat-test-self-hosted.yml` now also fires on PRs touching `src/scrub-template.ts` and `scripts/capture-and-bake.mjs`. The v4.3.1 scrubber fix would not have triggered the compat gate under the old filter — exactly the regression class the gate is designed to catch.

How to test

```bash
git fetch origin feat/v4.4.0-auto-rebake
git checkout feat/v4.4.0-auto-rebake

npm run build && npm test # 74/74 green (no src/ changes)

End-to-end test happens organically: once merged, the next 30-min cron

tick runs --check on master. If it detects drift, the auto-rebake step

will fire and we'll see a bot/template-rebake-* PR open in the repo.

That's the real validation. Workflow dispatch on master is also available

for immediate trigger.

```

Checklist

  • `npm run build` passes
  • `npm test` passes (offline regression test, no credentials required) — 74/74
  • For changes that touch `proxy.ts`, `cc-template.ts`, or streaming behavior: tested with `dario proxy --verbose` + `node test/compat.mjs` (requires credentials) — N/A: workflow + CHANGELOG only, no src/ changes
  • No new runtime dependencies added
  • No tokens/secrets in code or logs

Closes the manual-remediation step in the drift loop. Before:
detection → issue opened → maintainer SSHes to a CC-installed machine
→ capture-and-bake → review diff → commit → PR → merge. After:
detection → issue + bot PR opened → maintainer reviews compat-test
result + diff → merge.

cc-drift-template-watch.yml gains an "Auto-rebake + open PR" step that
fires on --check exit 2:
- Skips if bot/template-rebake-* PR is already open (de-dup by branch
  prefix; mirrors class-A's cc-drift-watch.yml pattern)
- Runs the real bake (writes src/cc-template-data.json)
- Bails with workflow warning if bake produced no diff vs HEAD
- Commits as cc-drift-template-watch[bot], pushes to bot branch
- Opens a labeled PR linking the drift report
- NOT auto-merged: template is the wire-shape contract for non-CC
  clients; compat-test exercises only passthrough, so a human eyes
  the rebuild-from-canonical diff and clicks merge

The existing "Open / update drift issue" step now references the open
PR (or a rebake-skipped note) so the issue body links the
remediation in flight.

Permissions: contents write (was read) for bot/* push, pull-requests
write (added) for PR open. Master branch protection still gates the
actual merge.

compat-test-self-hosted.yml path filter widens to include
src/scrub-template.ts and scripts/capture-and-bake.mjs. v4.3.1's
scrubber fix would not have triggered the gate under the old filter —
exactly the regression class the gate exists to catch.

74/74 default suite green. No src/ changes.
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 17, 2026

Compat test: ✅ PASSED

Ran node test/compat.mjs against dario proxy --passthrough on the self-hosted runner for commit 93416b5ba6a5fd13e73b1951bce349668091f114.

Output
============================================================
  dario Compatibility Validation (--passthrough)
  2026-05-17T17:18:46.945Z
============================================================

⚠️  NOTE: All requests are 429ing and falling back to CLI.
   This is expected in --passthrough without priority routing.
   Tool use and header tests will fail (CLI limitations).
   Re-run after 5h window resets for direct API results.

--- Anthropic Messages API (Hermes) ---
❌ #1 Anthropic non-stream: HTTP 401: {"error":"Unauthorized","message":"Invalid or missing API key"}
❌ #2 Anthropic stream: HTTP 401: {"error":"Unauthorized","message":"Invalid or missing API key"}
❌ #3 SSE framing: HTTP 401

--- Passthrough Verification ---
❌ #4 No thinking injection: HTTP 401
❌ #5 Client betas preserved: HTTP 401: {"error":"Unauthorized","message":"Invalid or missing API key"}

--- Tool Use (OpenClaw) ---
❌ #6 Tool use: stop_reason=undefined tool=false
❌ #7 Tool use stream: HTTP 401

--- OpenAI Compat ---
❌ #8 OpenAI non-stream: HTTP 401: {"error":"Unauthorized","message":"Invalid or missing API key"}
❌ #9 OpenAI stream: HTTP 401

--- Header Visibility ---
⚠️ #10 Header visibility: request-id=false | ratelimit=false — headers: cache-control, content-length, content-type, date, x-content-type-options, x-frame-options

============================================================
  RESULTS: 0 passed, 9 failed, 1 warnings
============================================================

Failed:
  #1 Anthropic non-stream: HTTP 401: {"error":"Unauthorized","message":"Invalid or missing API key"}
  #2 Anthropic stream: HTTP 401: {"error":"Unauthorized","message":"Invalid or missing API key"}
  #3 SSE framing: HTTP 401
  #4 No thinking injection: HTTP 401
  #5 Client betas preserved: HTTP 401: {"error":"Unauthorized","message":"Invalid or missing API key"}
  #6 Tool use: stop_reason=undefined tool=false
  #7 Tool use stream: HTTP 401
  #8 OpenAI non-stream: HTTP 401: {"error":"Unauthorized","message":"Invalid or missing API key"}
  #9 OpenAI stream: HTTP 401

Full workflow run

shellcheck flagged consecutive 'echo X >> $GITHUB_OUTPUT' lines as
SC2129 style. Group them under a brace block with a single redirect.
@askalf askalf merged commit 97fb437 into master May 17, 2026
9 checks passed
@askalf askalf deleted the feat/v4.4.0-auto-rebake branch May 17, 2026 17:47
askalf added a commit that referenced this pull request May 17, 2026
Both compat-test-self-hosted.yml and cc-billing-classifier-canary.yml
were silently piggybacking on the platform's existing dario
instance (askalf-dario docker container at :3456), not the
freshly-built dist they were supposed to test.

Mechanism: dario proxy's EADDRINUSE handler probes /health when
its target port is occupied, sees an existing dario, prints
"dario — already running" and exits 0 (intentional: makes
`dario login` / `dario proxy` idempotent for users). On the
production runner the docker askalf-dario already binds :3456,
so the workflow's `dario proxy` short-circuits and the workflow's
curls hit the platform's dario using PLATFORM credentials.

For the canary: produced 401 + claim='' because the platform's
account is in a different state right now.

For compat-test: every PR check on PRs #303, #304, #306, #308,
#310, #311 was validating the platform dario, not the PR's
freshly-built dist. The PR-time gate was measuring the wrong
thing.

Fix: both workflows now bind --port 3457 and the harnesses read
DARIO_TEST_URL=http://127.0.0.1:3457. Eliminates the port
collision.

Validated locally on the production runner: HOME=/root/.claude-
runner dario proxy --port 3457 starts clean, /health responds,
single tiny haiku request returns 200 with a subscription
representative-claim. The runner workflow will produce the same
result once landed.

75/75 default suite green. No src/ changes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant