docs+config: continuous research end to end, and a feed a subscriber can play
CLAWMATES_PUBLIC_URL was unset, so the podcast feed built every episode URL from the localhost default: valid XML that no podcast app could play. Set in the repo override and on prod (https://clawmates.work); the feed now carries real enclosure URLs for both episodes. Addendum 7 records the four defects found working on this recipe — only one of which the plan predicted — and the evidence for each. Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01WZb5A2kfVfjpdwSochkuHz
This commit is contained in:
co-authored by
Claude Opus 5
parent
785a7e7b0e
commit
620d1bfc5f
@@ -133,6 +133,10 @@ services:
|
|||||||
# TypeSafe Jev — shadow skill triage (cm-api skill_triage.rs). Optional:
|
# TypeSafe Jev — shadow skill triage (cm-api skill_triage.rs). Optional:
|
||||||
# unset, the triage records nothing. Server-side only; never a mission's.
|
# unset, the triage records nothing. Server-side only; never a mission's.
|
||||||
TYPESAFE_API_KEY: ${TYPESAFE_API_KEY:-}
|
TYPESAFE_API_KEY: ${TYPESAFE_API_KEY:-}
|
||||||
|
# Where this deployment is reachable from OUTSIDE. The podcast feed
|
||||||
|
# builds every episode URL from it, so unset means a feed whose items
|
||||||
|
# all point at localhost — valid XML that no subscriber can play.
|
||||||
|
CLAWMATES_PUBLIC_URL: ${CLAWMATES_PUBLIC_URL:-http://localhost:8080}
|
||||||
# ElevenLabs GenFM, for rendering the Continuous Research episode.
|
# ElevenLabs GenFM, for rendering the Continuous Research episode.
|
||||||
#
|
#
|
||||||
# SERVER-SIDE ONLY, deliberately. It is NOT in
|
# SERVER-SIDE ONLY, deliberately. It is NOT in
|
||||||
|
|||||||
@@ -560,3 +560,63 @@ accidents and obvious cases, which is what its own header has always said.
|
|||||||
**Also worth keeping:** measure efficacy and utility as a pair. Every gate
|
**Also worth keeping:** measure efficacy and utility as a pair. Every gate
|
||||||
scenario already asserts the mission still delivered; that is the utility
|
scenario already asserts the mission still delivered; that is the utility
|
||||||
half, and it should stay mandatory for any future rule.
|
half, and it should stay mandatory for any future rule.
|
||||||
|
|
||||||
|
## Addendum 7 — 2026-09-22, continuous research end to end
|
||||||
|
|
||||||
|
`docs/TEMPLATE-MATURITY.md` graded `continuous_research` "runs live,
|
||||||
|
unguarded" — the recipe with the most moving parts and no standing check.
|
||||||
|
Working on it found four defects, only one of which the plan predicted.
|
||||||
|
|
||||||
|
**The digest never reached the vault.** Paper notes auto-merge (`library.rs`
|
||||||
|
calls `auto_merge::try_merge`); the digest did not, because nothing on the
|
||||||
|
mission path ever called it. `ContinuousResearch/` on `main` ended at
|
||||||
|
**2026-08-18** while every run since produced `analysis.md`, `script.md` and
|
||||||
|
`episode.json` onto a branch nobody merged. `mission_delivery` now accrues
|
||||||
|
such a branch behind three limits — `AdditiveOnly` (re-reads the diff against
|
||||||
|
the remote base, refuses any M/D/R), the phase's own judge verdict, and a pure
|
||||||
|
`accrues_automatically()` naming exactly one recipe. **Proven:** the scenario's
|
||||||
|
`analysis.md is on main (6717 bytes)`, where the same path returned 404 before.
|
||||||
|
|
||||||
|
**The script parsed to zero turns, forever.** The baseline run the plan put
|
||||||
|
first found this instead of the race it was written for: the worker was
|
||||||
|
healthy, found the script in the checkout, and `parse_script` returned nothing
|
||||||
|
— so it skipped, every two minutes, with no episode and no tombstone. The
|
||||||
|
skill asks for `HOST:`; the writer, producing markdown, wrote `**HOST:**`, and
|
||||||
|
`split_once(':')` yields `**HOST` which fails the all-uppercase test. The
|
||||||
|
parser now accepts emphasis around the label and leaves emphasis *inside*
|
||||||
|
speech alone. Had the baseline been skipped, the vault fallback would have
|
||||||
|
shipped as a "fix" for a race that was not happening.
|
||||||
|
|
||||||
|
**The renderer raced a reaper.** It read the script from a checkout deleted 30
|
||||||
|
minutes after completion; `record_unrenderable`'s own message pointed at the
|
||||||
|
vault as manual recovery. It now takes the vault — default branch, then the
|
||||||
|
delivery branch. **Proven live:** `checkout is gone; rendering from the vault
|
||||||
|
(clawmates/mission-01a0c9c4-cf8ba78d:…/script.md)`.
|
||||||
|
|
||||||
|
**A tombstone was permanent.** `NOT EXISTS (podcast_episodes)` meant a day that
|
||||||
|
gave up could never be reconsidered: mission `01a0c9c4` was tombstoned at
|
||||||
|
16:17:39, four minutes before the build that could render it started at
|
||||||
|
16:21:58, and would have stayed silent on a script sitting on a branch.
|
||||||
|
Tombstones now expire after a backoff each attempt refreshes — recovers the
|
||||||
|
same day a cause is fixed, without the every-two-minutes churn.
|
||||||
|
|
||||||
|
**Result — the first complete passes this pipeline has made.** Two episodes,
|
||||||
|
`419s`/`6,708,231 bytes` and `401s`/`6,422,347 bytes`, rendered by
|
||||||
|
`elevenlabs/eleven_flash_v2_5`, served at `HTTP 200 audio/mpeg`, in a feed that
|
||||||
|
now advertises `https://clawmates.work` — `CLAWMATES_PUBLIC_URL` was unset, so
|
||||||
|
every enclosure URL pointed at `localhost:8080`: valid XML no subscriber could
|
||||||
|
play.
|
||||||
|
|
||||||
|
**The guard** (`verify-mission-delivery.sh continuous-research`): digest on
|
||||||
|
`main`, manifest triage fields, evidence spread above `SATURATED_BELOW` (live:
|
||||||
|
**0.89**), analysis naming every harvested paper, `episode.json` obeying the
|
||||||
|
recipe's own 10–70 char rule, and a rendered episode. Its first run failed the
|
||||||
|
episode assertion while the pipeline was fine — it checked the instant the
|
||||||
|
mission completed, asserting the worker is *fast* rather than that it works. It
|
||||||
|
now waits for a verdict and says how long it waited.
|
||||||
|
|
||||||
|
**Process note.** One commit was pushed off a `cargo test … | grep …` whose
|
||||||
|
exit code came from grep, so two failures passed into a `&&` chain that
|
||||||
|
committed and pushed. Nothing bad shipped — the failures were `PoolTimedOut`
|
||||||
|
from Docker Desktop being down locally, and CI on a real Postgres was green —
|
||||||
|
but the gate did not gate. Use `set -o pipefail`, or run cargo bare.
|
||||||
|
|||||||
Reference in New Issue
Block a user