Commit Graph

27 Commits

Author SHA1 Message Date
giles
d20eef76ad Fix completed runs not appearing in list + add purge-failed endpoint
- Update save_run_cache to also update actor_id, recipe, inputs on conflict
- Add logging for actor_id when saving runs to run_cache
- Add admin endpoint DELETE /runs/admin/purge-failed to delete all failed runs

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-02 23:24:39 +00:00
gilesb
59c72500ac Fix status: check task result success flag, not just Celery success
Celery task "succeeds" (no exception) but may return {"success": False}.
Now we check the task result's success field AND output_cid before
marking run as completed.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-13 02:13:03 +00:00
gilesb
84d465b264 Include failed runs in list_runs output
Failed runs were not showing in UI/CLI because list_runs only
included runs with status "pending" or "running", excluding "failed".

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-13 02:10:58 +00:00
gilesb
d08fbfc0bd Fix SOURCE node resolution for user inputs in execute_recipe
- SOURCE nodes with :input true now resolve CID from input_hashes
- Tries multiple name formats: exact, lowercase-dashes, lowercase-underscores
- Only return "completed" status for runs with actual output
- Add integration tests for SOURCE CID resolution

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-13 01:36:48 +00:00
gilesb
d603485d40 Refactor to S-expression based execution with code-addressed cache IDs
Major changes:
- Add execute_recipe task that uses S-expression planner
- Recipe S-expression unfolds into plan S-expression with code-addressed cache IDs
- Cache IDs computed from Merkle tree of plan structure (before execution)
- Add ipfs_client.add_string() for storing S-expression plans
- Update run_service.create_run() to use execute_recipe when recipe_sexp available
- Add _sexp_to_steps() to parse S-expression plans for UI visualization
- Plan endpoint now returns both sexp content and parsed steps

The code-addressed hashing means each plan step's cache_id is:
  sha3_256({node_type, config, sorted(input_cache_ids)})

This creates deterministic "buckets" for computation results computed
entirely from the plan structure, enabling automatic cache reuse.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-13 00:27:24 +00:00
gilesb
2c27eacb12 Convert DAG nodes dict to steps list in get_run_plan()
The CLI expects {"steps": [...]} but DAG format stores {"nodes": {...}}.
Added _dag_to_steps() to convert between formats, including topological
sorting so sources appear first.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-13 00:00:00 +00:00
gilesb
3e3df6ff2a Code-addressed node IDs and remove JSON index files
- Compiler now generates SHA3-256 hashes for node IDs
- Each hash includes type, config, and input hashes (Merkle tree)
- Same plan = same hashes = automatic cache reuse

Cache changes:
- Remove index.json - filesystem IS the index
- Files at {cache_dir}/{hash}/output.* are source of truth
- Per-node metadata.json for optional stats (not an index)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-12 22:38:50 +00:00
gilesb
8bf6f87c2a Implement ownership model for all cached content deletion
- cache_service.delete_content: Remove user's ownership link first,
  only delete actual file if no other owners remain

- cache_manager.discard_activity_outputs_only: Check if outputs and
  intermediates are used by other activities before deleting

- run_service.discard_run: Now cleans up run outputs/intermediates
  (only if not shared by other runs)

- home.py clear_user_data: Use ownership model for effects and media
  deletion instead of directly deleting files

The ownership model ensures:
1. Multiple users can "own" the same cached content
2. Deleting removes the user's ownership link (item_types entry)
3. Actual files only deleted when no owners remain (garbage collection)
4. Shared intermediates between runs are preserved

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-12 20:02:27 +00:00
gilesb
2e3d3a5c6d Store DAG plan to IPFS and track plan_cid in run_cache
- Add plan_cid column to run_cache schema
- Store DAG JSON to IPFS during execute_dag task
- Return plan_cid in run status and list APIs

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-12 18:43:48 +00:00
gilesb
5b05dbd31e Fix clear-data to actually delete run_cache entries
- discard_run now deletes from run_cache and pending_runs tables
- Add delete_run_cache() and delete_pending_run() database functions
- Previously clear-data only cleared Redis, leaving DB cache intact

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-12 17:42:12 +00:00
gilesb
977d9a9258 Fix artifact dict key mismatch (hash -> cid)
Template runs/detail.html expects artifact.cid but code provided
artifact.hash, causing UndefinedError when viewing run details.

- Change run_service.get_run_artifacts to return 'cid' key
- Change runs.py router inline artifact creation to use 'cid' key
- Add regression tests for artifact data structure

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-12 12:05:13 +00:00
gilesb
585c75e846 Fix item visibility bugs and add effects web UI
- Fix recipe filter to allow owner=None (S-expression compiled recipes)
- Fix media uploads to use category (video/image/audio) not MIME type
- Fix IPFS imports to detect and store correct media type
- Add Effects navigation link between Recipes and Media
- Create effects list and detail templates with upload functionality
- Add cache/not_found.html template (was missing)
- Add type annotations to service classes
- Add tests for item visibility and effects web UI (30 tests)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-12 12:01:54 +00:00
gilesb
92d26b2b72 Rename content_hash/output_hash to cid throughout
Refactor to use IPFS CID as the primary content identifier:
- Update database schema: content_hash -> cid, output_hash -> output_cid
- Update all services, routers, and tasks to use cid terminology
- Update HTML templates to display CID instead of hash
- Update cache_manager parameter names
- Update README documentation

This completes the transition to CID-only content addressing.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-12 08:02:44 +00:00
gilesb
b686ce75f8 Remove YAML support - S-expressions only
- Recipe service now only handles S-expressions
- Removed yaml import and all YAML parsing code
- Plans are just node outputs - cached by content hash
- Run service looks up plans from cache, falls back to legacy dir

Code is data. Everything is S-expressions.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-12 00:33:54 +00:00
gilesb
65a8170192 Use native S-expression for recipe/plan display
- Display recipe's original S-expression when available (code is data)
- Fall back to generating S-expression from plan for legacy JSON
- Run service now prefers .sexp plan files over .json
- Add get_run_plan_sexp() for direct S-expression access

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-12 00:26:05 +00:00
gilesb
82d94f6e0e Add inline media previews for runs list and detail page
- Run card shows thumbnail previews for inputs and output
- Run detail shows output media inline (image/video/audio)
- Add audio detection (MP3, FLAC, OGG, WAV) to detect_media_type
- Add debug logging for recipe count on home page
- Add console.log debugging for DAG elements

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-12 00:20:26 +00:00
gilesb
f7dbb952ab Preserve recipe name in run service and templates
- Pass recipe_name through create_run to display friendly names
- Update templates to show name instead of hash
- Fall back to truncated hash if no name available

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-11 23:09:33 +00:00
gilesb
aacf1ceb77 Add error logging for pending run creation 2026-01-11 21:45:29 +00:00
gilesb
59de1cf6b5 Add _ensure_inputs_list to handle legacy Redis data format
Inputs stored in old Redis format are JSON strings - this helper
ensures they're always returned as lists regardless of source.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-11 21:27:49 +00:00
gilesb
8ab0f05a7d Add durable pending runs and recipe list debugging
- Store pending runs in PostgreSQL for durability across restarts
- Add recovery method for orphaned runs
- Increase Celery result_expires to 7 days
- Add task_reject_on_worker_lost for automatic re-queuing
- Add logging to recipe list to debug filter issues

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-11 20:35:00 +00:00
gilesb
a6dd470623 Fix recipe steps display and DAG visualization
- Check multiple locations for nodes: dag.nodes, recipe.nodes, pipeline, steps
- Add dagre layout libraries for cytoscape DAG visualization
- Fix inputs parsing when stored as JSON string in Redis

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-11 20:21:24 +00:00
gilesb
209d416442 Fix running runs not appearing in UI list
- Normalize Celery status names (started -> running)
- Store full run metadata in Redis for pending runs (recipe, inputs, actor_id)
- Filter pending runs by actor_id so users only see their own
- Parse both old and new Redis task data formats for compatibility

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-11 20:15:41 +00:00
giles
854396680f Refactor storage: remove Redis duplication, use proper data tiers
- Recipes: Now content-addressed only (cache + IPFS), removed Redis storage
- Runs: Completed runs stored in PostgreSQL, Redis only for task_id mapping
- Add list_runs_by_actor() to database.py for paginated run queries
- Add list_by_type() to cache_manager for filtering by node_type
- Fix upload endpoint to return size and filename fields
- Fix recipe run endpoint with proper DAG input binding
- Fix get_run_service() dependency to pass database module

Storage architecture:
- Redis: Ephemeral only (sessions, task mappings with TTL)
- PostgreSQL: Permanent records (completed runs, metadata)
- Cache: Content-addressed files (recipes, media, outputs)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-11 14:05:31 +00:00
giles
83cce09b1a Fix list_runs to use offset parameter
Match the router's expected signature and return type.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-11 12:22:59 +00:00
giles
945fb3b413 Fix analysis display for recipe-based runs
Add get_run_analysis() to RunService to load per-input analysis from
CACHE_DIR/analysis/{hash}.json files. Update runs router and template
to display tempo, beats, energy, and beat timeline visualization.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-11 08:05:40 +00:00
giles
29d8d06d76 Fix plan artifacts display for completed runs
- Add get_run_plan() and get_run_artifacts() methods to RunService
- Merge step_results into plan steps to show cache_id per step
- Display output hash links under each completed step
- Use cache manager for artifact path lookups
- Fix RunService constructor to accept database param

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-11 08:01:12 +00:00
giles
adc876dbd6 Add modular app structure for L1 server refactoring
Phase 2 of the full modernization:
- App factory pattern with create_app()
- Settings via dataclass with env vars
- Dependency injection container
- Router stubs for auth, storage, api, recipes, cache, runs
- Service layer stubs for run, recipe, cache
- Repository layer placeholder

Routes are stubs that import from legacy server.py during migration.
Next: Migrate each router fully with templates.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-11 07:08:08 +00:00