From edc216c81f2bb2fade62380d591e048a1937073f Mon Sep 17 00:00:00 2001 From: gilesb Date: Wed, 7 Jan 2026 21:29:40 +0000 Subject: [PATCH] Store and display full provenance including effect_url MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - record-run now stores effect_url, effects_commit, infrastructure in provenance - Asset detail uses stored effect_url (with fallback for older records) - Shows effects commit hash under effect button - Shows infrastructure info (software/hardware) if available 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- .env.example | 8 +++++++- server.py | 37 ++++++++++++++++++++++++++++++++++--- 2 files changed, 41 insertions(+), 4 deletions(-) diff --git a/.env.example b/.env.example index b53dc65..4e83bd2 100644 --- a/.env.example +++ b/.env.example @@ -6,6 +6,12 @@ ARTDAG_DOMAIN=artdag.rose-ash.com # JWT secret for token signing (generate with: openssl rand -hex 32) JWT_SECRET=your-secret-here-generate-with-openssl-rand-hex-32 +# L1 server URL for fetching content (images/videos) +L1_PUBLIC_URL=https://celery-artdag.rose-ash.com + +# Effects repository URL for linking to effect source code +EFFECTS_REPO_URL=https://git.rose-ash.com/art-dag/effects + # Notes: # - ARTDAG_USER removed - now multi-actor, each registered user is their own actor -# - ARTDAG_L1 removed - L1 server URL is sent with each request +# - L1 URL can also come from provenance data per-asset diff --git a/server.py b/server.py index d00fa6e..b76a5e8 100644 --- a/server.py +++ b/server.py @@ -736,9 +736,17 @@ async def ui_asset_detail(name: str, request: Request): inputs = provenance.get("inputs", []) l1_run_id = provenance.get("l1_run_id", "") rendered_at = provenance.get("rendered_at", "")[:10] if provenance.get("rendered_at") else "" + effects_commit = provenance.get("effects_commit", "") + infrastructure = provenance.get("infrastructure", {}) - # Build effect link - effect_url = f"{EFFECTS_REPO_URL}/src/branch/main/{recipe}" + # Use stored effect_url or build fallback + effect_url = provenance.get("effect_url") + if not effect_url: + # Fallback for older records + if effects_commit and effects_commit != "unknown": + effect_url = f"{EFFECTS_REPO_URL}/src/commit/{effects_commit}/{recipe}" + else: + effect_url = f"{EFFECTS_REPO_URL}/src/branch/main/{recipe}" # Build inputs display inputs_html = "" @@ -752,6 +760,24 @@ async def ui_asset_detail(name: str, request: Request): ''' + # Infrastructure display + infra_html = "" + if infrastructure: + software = infrastructure.get("software", {}) + hardware = infrastructure.get("hardware", {}) + if software or hardware: + infra_html = f''' +
+

Infrastructure

+
+ {f"Software: {software.get('name', 'unknown')}" if software else ""} + {f" ({software.get('content_hash', '')[:16]}...)" if software.get('content_hash') else ""} + {" | " if software and hardware else ""} + {f"Hardware: {hardware.get('name', 'unknown')}" if hardware else ""} +
+
+ ''' + provenance_html = f'''

Provenance

@@ -766,6 +792,7 @@ async def ui_asset_detail(name: str, request: Request): {recipe} + {f'
Commit: {effects_commit[:12]}...
' if effects_commit else ''}

Input(s)

@@ -780,6 +807,7 @@ async def ui_asset_detail(name: str, request: Request):

Rendered

{rendered_at if rendered_at else 'Unknown'}
+ {infra_html} ''' @@ -1339,9 +1367,12 @@ async def record_run(req: RecordRunRequest, user: User = Depends(get_required_us provenance = { "inputs": [{"content_hash": h} for h in run.get("inputs", [])], "recipe": run.get("recipe"), + "effect_url": run.get("effect_url"), + "effects_commit": run.get("effects_commit"), "l1_server": l1_url, "l1_run_id": req.run_id, - "rendered_at": run.get("completed_at") + "rendered_at": run.get("completed_at"), + "infrastructure": run.get("infrastructure") } # Register the output under the authenticated user