Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .github/workflows/build-binaries.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ name: Build and release Linux CLI

on:
workflow_dispatch:
pull_request:
branches:
- main
push:
tags:
- "v*"
Expand All @@ -22,6 +25,8 @@ jobs:
bun-version: "1.4.2"
- run: npm ci
- run: npm run check
- name: Prepare private test workspace
run: mkdir -p -m 700 /tmp/opencode
- run: bun test
- name: Verify tag version
if: github.ref_type == 'tag'
Expand Down
9 changes: 5 additions & 4 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ Follow the commands and conventions below.
- Store non-secret service settings in `castloop.toml` at the working-directory root. Keep unpublished job IDs in a git-ignored local state file, not in service TOML.
- The public URL is a Worker URL; a custom domain is optional. Store `public_base_url` in the service config, never an R2 public URL in show metadata.
- Local TOML files are the editable source; R2 stores published snapshots and job status.
- M6 new Show registration claims a permanent `reservation_id` in the Show control record before completing its matching reservation record; block mutations while registration is incomplete, never recreate an advanced or deleted Show, and retain the identity after deletion. New Episode controls are initialized only under the exact Show staging owner after checking for orphan data. These internal paths do not authorize exposing M6 write commands before the release gates pass.
- M6 new Show registration claims a permanent `reservation_id` in the Show control record before completing its matching reservation record; block mutations while registration is incomplete, never recreate an advanced or deleted Show, and retain the identity after deletion. New Episode controls are initialized only under the exact Show staging owner after checking for orphan data. Formal M6 development commands reuse these runners and must preserve runtime readiness and admission checks.
- `create-show` requires a real site URL supplied by the administrator and writes it into the local `show.toml`; publication requires `site_url`. `update-show` stages Show TOML and cover art in R2 without publishing; only `publish-show` creates its commit marker and starts publication.
- `create-episode` fills `published_at` with the current timestamp as a quoted RFC 3339 string including seconds and an offset. Render RSS pubDate as RFC 2822.
- Service and show metadata: `system/service.toml` and `system/shows/<showId>/show.toml`.
Expand All @@ -34,7 +34,7 @@ Follow the commands and conventions below.
- `create-episode` creates a local TOML draft. `update-episode` stages only metadata, and `update-episode-audio` stages only MP3 audio in R2. Neither update command publishes. Only `publish-episode` validates the staged inputs and writes `commit.json` last; initial and subsequent publications both require an explicit publish command.
- Keep one job ID for an unpublished draft. After writing `commit.json`, freeze that draft; use a new job ID for later edits. Reject stale local metadata rather than silently publishing an older staged copy.
- Do not assume R2 binding CAS applies to the Cloudflare R2 REST object PUT endpoint. Dedicated M6 tests observed overwrites despite a mismatched If-Match header; this does not prove that aborted PUTs continue writing. The administrator decided on 2026-10-01 to retain simple REST single-object PUTs for M6 and assume that a PUT does not create or update an object later after client disconnection. Record this as an unverified assumption and unresolved concern U1 in design/m6_upload_recovery_options.md, not a Cloudflare guarantee. Do not require multipart uploads or resolution of U1 as an M6 release gate. Preserve upload admission, size/content verification and owner/generation-checked recovery; never release a still-running PUT or publication consumer merely because time elapsed or HEAD found no object. Do not contact Cloudflare support about U1.
- Keep the immutable published audio and revision history during normal publication. M6 explicit deletion is the approved exception, but do not expose it before admission, delivery, recovery and deletion gates pass. Decide staging audio retention separately from published media; do not apply a blanket expiration rule to active or recoverable drafts.
- Keep the immutable published audio and revision history during normal publication. M6 explicit deletion is the approved exception and uses confirmed, admission-checked lifecycle runners. Decide staging audio retention separately from published media; do not apply a blanket expiration rule to active or recoverable drafts.
- The administrator approved M6 retention on 2026-10-01: explicitly delete payloads, but retain necessary small reservations, lifecycle/tombstone records, frozen requests, commit markers and job status/progress without automatic expiration. Do not copy titles, descriptions, email addresses or secrets into retained operational records. Persist only allowlisted diagnostic codes/messages, not arbitrary exception messages. Keep unfinished/recoverable job records; time-based audit cleanup is deferred. See design/m6_review_queue.md.
- Published feeds and media: `public/podcasts/<showId>/feed.xml`, `cover.<ext>`, and `episodes/<episodeId>/<revisionId>.mp3`.
- Current episode metadata: `public/episodes/<showId>/<episodeId>/metadata.toml`.
Expand All @@ -50,14 +50,15 @@ Follow the commands and conventions below.
- Overwrite the Show cover art at the approved `public/podcasts/<showId>/cover.<ext>` key on image updates and purge its cache tag. Do not mark a publication job as complete until feed and applicable cover-art Workers Cache purges succeed. Retry purge failures without duplicating published media.

## Milestones
- On 2026-10-04, the administrator approved completing the MVP by connecting existing runners to the formal CLI/Worker, testing changed entry points and one formal-binary walkthrough, and writing concise usage/recovery guidance. Reuse completed 300 MB, six lifecycle operation and compatible-update acceptance. Do not add a dedicated fresh-init fault harness, exhaustive failure matrix, legacy conversion, zero-downtime migration or generic future-version framework. Unknown IO and residual locks remain blocked; universal external recovery is not an MVP release gate. Preserve owner/token checks and never release on elapsed time or absent HEAD alone. This scope supersedes older broader gate descriptions; see design/m6_review_queue.md.
- M0 validates Cloudflare authentication, resource creation, R2 media delivery, Workers Caching, MP3 upload/analysis, and the R2 event-to-Queue path.
- M1 delivers service initialization, local metadata models, ID validation, and show reservation.
- M2 publishes a show through `update-show`/`publish-show` and one episode end-to-end using separate metadata/audio staging, explicit publish, job status, feed generation, and media delivery.
- M3 supports multiple episodes, metadata-only and audio-only revisions, concurrency/retry handling, and cleanup.
- M4 delivers the Bun executable and usage documentation.
- M5 removes Wrangler from the build and administrator workflows and verifies binary-only publication and recovery. See design/initial_design.md and design/m5_implementation_log.md.
- M6 is the next milestone after v0.1.2: Episode and Show unpublishing/deletion, with explicit restoration proposed as the reversible counterpart. See design/m6_content_lifecycle_plan.md and design/m6_implementation_log.md. The R2 control-record approach is decided; strict schemas and atomic-admission/public-visibility primitives are implemented but not connected to live routes. Complete the cache/REST/upload/migration gates before exposing lifecycle commands.
- On 2026-10-03, the administrator approved separating fresh M6 initialization, compatible M6 Worker updates, and legacy data conversion needed only on demand. Fresh initialization and compatible updates have internal CAS/journal/REST implementations, not released CLI or HTTP routes. Share runtime verification without a generic operation state machine; keep legacy migration audit evidence separate from current-version runtime readiness. Finish paused and require explicit resume. Never infer runtime readiness from REST settings alone, adopt unknown resources, replay unknown deploys, or bypass unfinished upload/publication owners. See design/m6_fresh_initialization.md and design/m6_compatible_updates.md. Existing Cloudflare resources are not authorized for immediate deletion.
- M6 is the next milestone after v0.1.2: Episode and Show unpublishing/deletion with explicit restoration. See design/m6_content_lifecycle_plan.md and design/m6_implementation_log.md. Formal development CLI/Worker entry points connect the existing R2 control-record, atomic-admission and lifecycle-aware delivery runners. Respect the approved MVP scope below; do not infer legacy migration permission or release readiness from source availability alone.
- On 2026-10-03, the administrator approved separating fresh M6 initialization, compatible M6 Worker updates, and legacy data conversion needed only on demand. Fresh initialization and compatible updates use CAS/journal/REST implementations connected to the formal development CLI/Worker; a packaged release remains separate. Share runtime verification without a generic operation state machine; keep legacy migration audit evidence separate from current-version runtime readiness. Finish paused and require explicit resume. Never infer runtime readiness from REST settings alone, adopt unknown resources, replay unknown deploys, or bypass unfinished upload/publication owners. See design/m6_fresh_initialization.md and design/m6_compatible_updates.md. Existing Cloudflare resources are not authorized for immediate deletion.
- The administrator decided on 2026-10-02 to use an isolated M6 test environment in the same Cloudflare account as existing services and to build migration around a planned maintenance window with temporary public-delivery and mutation downtime. Complete the full M6 feature set and release it as the next version; a limited pilot release and zero-downtime migration are not prerequisites. Defer cost and downtime measurement planning, and consideration of zero-downtime migration, until after MVP construction. Do not block ordinary implementation or feature completion on measurement approval. Preserve functional and safety acceptance, including correct 300 MB handling within runtime limits, old-IO quiescence, cache-safe delivery and owner/token-checked recovery. This does not authorize an immediate production migration, unverified destructive commands, unlimited spending or paid-plan changes. See design/m6_review_queue.md.
- Custom-domain work retains its approved plan and existing groundwork but follows M6. Do not expose domain add/remove before their existing migration and recovery gates pass. Lifecycle state must also be respected by future domain migration.

Expand Down
Loading
Loading