Commit Graph

53 Commits

Author SHA1 Message Date
giles
5bc655f8c8 Include rendering status in runs list 2026-02-03 00:44:53 +00:00
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
6c973203fc Add debug logging to recipe upload and get
To help diagnose why recipes are not found after upload.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-12 20:35:06 +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
427de25e13 Fix recipe ownership tracking via item_types table
- Upload now creates item_types entry linking user to recipe
- List queries item_types for user's recipes (not all cached)
- Delete removes item_types entry (not the file)
- File only deleted when no users own it (garbage collection)

This allows multiple users to "own" the same recipe CID.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-12 19:40:39 +00:00
gilesb
a5a718e387 Remove owner check from recipe deletion (security fix)
Same reasoning as the list fix: the owner field from recipe content
could be spoofed. For L1, any authenticated user can delete recipes.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-12 19:26:36 +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
87ff3d5d14 Remove owner filtering from recipe listing (security fix)
The owner field from recipe content could be spoofed to hide recipes
from users or make recipes appear to belong to someone else.

For L1, all recipes in cache are now visible to authenticated users.
Ownership tracking should use the naming service or cache metadata,
not untrusted data from recipe content.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-12 15:33:39 +00:00
gilesb
6adef63fad Fix get_recipe to handle both YAML and S-expression formats
The upload endpoint accepts both YAML and S-expression recipes, but
get_recipe only tried to parse S-expression. Now it detects the format
and parses accordingly.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-12 15:31:25 +00:00
gilesb
f1b90fe65d Add debug logging for recipe filtering
Shows owner and actor_id values when filtering recipes.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-12 15:30:24 +00:00
gilesb
ee8719ac0b Fix media friendly names, metadata display, output recording, and plan display
- Add friendly name display to media detail and list pages
- Unpack nested meta fields to top level for template access
- Fix output_cid mismatch: use IPFS CID consistently between cache and database
- Add dual-indexing in cache_manager to map both IPFS CID and local hash
- Fix plan display: accept IPFS CIDs (Qm..., bafy...) not just 64-char hashes
- Add friendly names to recipe listing
- Add recipe upload button and handler to recipes list
- Add debug logging to recipe listing

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-12 14:21:39 +00:00
gilesb
19634a4ac5 Add friendly names system for recipes, effects, and media
- Add friendly_names table with unique constraints per actor
- Create NamingService with HMAC-signed timestamp version IDs
- Version IDs use base32-crockford encoding, always increase alphabetically
- Name normalization: spaces/underscores to dashes, lowercase, strip special chars
- Format: "my-effect 01hw3x9k" (space separator ensures uniqueness)
- Integrate naming into recipe, effect, and media uploads
- Resolve friendly names to CIDs during DAG execution
- Update effects UI to display friendly names
- Add 30 tests covering normalization, parsing, and service structure

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-12 14:02:17 +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
60344b34f4 Fix registry lookups to use cid, remove dead legacy code
- Fix all registry lookups to use "cid" instead of "hash" key
  - app/routers/recipes.py: asset and effect resolution
  - tasks/execute_sexp.py: effect config lookups
  - server_legacy.py references (now deleted)
- Prefer IPFS CID over local hash in cache operations
  - cache_service.py: import_from_ipfs, upload_content
  - orchestrate.py: plan caching
  - legacy_tasks.py: node hash tracking

Remove ~7800 lines of dead code:
- server_legacy.py: replaced by modular app/ structure
- tasks/*_cid.py: unused refactoring only imported by server_legacy

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-12 09:09:40 +00:00
gilesb
8e7228fc38 Fix recipe_id to use IPFS CID instead of local hash
The recipe upload was returning the SHA3-256 hash from artdag's cache
instead of the IPFS CID, causing recipe lookups to fail.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-12 08:58:51 +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
494a2a8650 Add IPFS CID support for asset lookup
- Upload endpoint returns both CID and content_hash
- Cache manager handles both SHA3-256 hashes and IPFS CIDs
- get_by_cid() fetches from IPFS if not cached locally
- Execute tasks support :cid in addition to :hash

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-12 07:36:18 +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
5e6ed38ca4 Improve recipe listing - check both uploader and owner
- Add better debug logging for recipe filtering
- Check both uploader and owner fields when filtering by actor_id
- This handles S-expression recipes that use 'owner' field

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-11 23:54:56 +00:00
gilesb
fe8e65881d Map owner to uploader for S-expression recipes
S-expression recipes use 'owner' field while YAML uses 'uploader'.
Normalize to 'uploader' so recipe listing filter works for both formats.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-11 23:40:50 +00:00
gilesb
24b6b4af28 Give clear error when sexp module not available
Instead of falling through to YAML parsing (which gives confusing errors),
return a clear message that artdag.sexp is required but not installed.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-11 23:17:55 +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
e59a50c000 Add S-expression recipe support
- Add format detection that correctly handles ; comments
- Import artdag.sexp parser/compiler with YAML fallback
- Add execute_step_sexp and run_plan_sexp Celery tasks
- Update recipe upload to handle both S-expr and YAML formats

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-11 23:08:53 +00:00
gilesb
9df78f771d Fix run detail: add username, total_steps, recipe_name
- Extract username from actor_id format (@user@server)
- Set total_steps and executed from recipe nodes
- Use recipe name for display instead of hash

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-11 22:23:08 +00:00
gilesb
9a8e26e79c Compute step_count in recipe service
Check multiple locations for nodes (nodes, dag.nodes, pipeline, steps)
and compute step_count for display in recipe list.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-11 22:09:34 +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
gilesb
2e9ba46f19 Use UserContext from artdag_common, remove duplicate
- Updated requirements.txt to use art-common@11aa056 with l2_server field
- All routers now import UserContext from artdag_common
- Removed duplicate UserContext from auth_service.py
- dependencies.py sets l2_server from settings on user context

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-11 17:38:02 +00:00
gilesb
9e3c4c9d78 Add l2_server to UserContext
Fixes AttributeError when running recipes - the UserContext was
missing the l2_server field that run_service expects.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-11 17:28:40 +00:00
gilesb
921d81421a Fix cache method name: get_content_path -> get_by_content_hash
The L1CacheManager uses get_by_content_hash not get_content_path.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-11 16:36:29 +00:00
gilesb
27cbb0a85c Store MIME type in database during upload
Detect actual MIME type from file content and store it instead of
generic "media" type. This enables proper media categorization
and filtering in the UI.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-11 16:18:56 +00:00
giles
e8501de466 Fix list_media to use get_user_items instead of list_cache_items
list_cache_items doesn't accept actor_id parameter.
Use get_user_items which properly filters by actor_id and item_type.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-11 14:10:49 +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
8591faf0fc Fix CacheService list_media and recipe inputs type
- Add list_media method to CacheService
- Change recipe run inputs from List to dict

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-11 13:28:27 +00:00
giles
b372d02df2 Fix list_recipes 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:43:54 +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