fffiloni commited on
Commit
1b122ec
·
verified ·
1 Parent(s): bf0b3e5

Upload 15 files

Browse files
Files changed (3) hide show
  1. src/version.py +2 -2
  2. src/view_models.py +68 -11
  3. src/worker_payload.py +43 -3
src/version.py CHANGED
@@ -1,7 +1,7 @@
1
  from __future__ import annotations
2
 
3
- ASF_APP_VERSION = "v198.26.7"
4
- ASF_RELEASE_NAME = "Agentic Space Factory v198.26.7"
5
 
6
 
7
  def resolve_app_version(value: str | None = None) -> str:
 
1
  from __future__ import annotations
2
 
3
+ ASF_APP_VERSION = "v198.26.8"
4
+ ASF_RELEASE_NAME = "Agentic Space Factory v198.26.8"
5
 
6
 
7
  def resolve_app_version(value: str | None = None) -> str:
src/view_models.py CHANGED
@@ -454,8 +454,13 @@ def build_diagnostics(bundle: dict[str, Any], status_model: dict[str, Any], phas
454
  issue_detail = "Automatic hardware selection was not available. Choose hardware in Space settings, then run Space Test."
455
  issue_status = "action_required"
456
  elif status_model["global_status"] == "failed":
457
- issue_title = "Run failed"
458
- issue_detail = "Inspect logs and run artifacts for the failing step."
 
 
 
 
 
459
  issue_status = "open"
460
 
461
  health_passed = bool((gate.get("implementation_signals") or {}).get("health_passed") or smoke.get("health_passed"))
@@ -536,21 +541,65 @@ def _space_target_url_from_bundle(bundle: dict[str, Any], target: str = "") -> s
536
  return f"https://huggingface.co/spaces/{target}" if target else ""
537
 
538
 
539
- def _space_links_ready_from_bundle(bundle: dict[str, Any]) -> bool:
 
 
 
 
 
 
 
540
  identity = bundle.get("space_identity") or {}
541
- if identity.get("links_ready") or identity.get("space_created") or identity.get("space_uploaded"):
542
- return True
543
  runtime_upload_epoch = bundle.get("runtime_upload_epoch") or {}
544
- if runtime_upload_epoch.get("last_upload_completed_at"):
545
- return True
 
 
 
 
546
  for event in bundle.get("events") or []:
547
  if not isinstance(event, dict):
548
  continue
549
  step = str(event.get("step") or "")
550
  status = str(event.get("status") or "").lower()
551
- if status == "success" and step in {"create_space", "create_space_hardware", "upload_files", "runtime_upload_epoch"}:
552
- return True
553
- return False
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
554
 
555
 
556
  def _known_gradio_endpoint_info(bundle: dict[str, Any]) -> dict[str, Any]:
@@ -744,11 +793,18 @@ def build_run_view_model(
744
  elapsed_seconds = int((end - created).total_seconds())
745
  target = _space_target_from_bundle(bundle)
746
  target_url = _space_target_url_from_bundle(bundle, target)
 
747
  links = {
748
  "job_url": _job_url_from_view_sources(bucket_source=bucket_source, summary=summary, state=state, launch=bundle.get("launch") or {}),
749
  "target_space_url": target_url,
750
  "target_space_settings_url": f"{target_url}/settings" if target_url else "",
751
  "artifacts_url": summary.get("artifacts_url") or f"https://huggingface.co/buckets/{bucket_source}/tree/{_runs_prefix()}/{run_id}",
 
 
 
 
 
 
752
  }
753
  return {
754
  "schema_version": "run_view_model.v1",
@@ -777,6 +833,7 @@ def build_run_view_model(
777
  "diagnostics": build_diagnostics(bundle, status_model, phase),
778
  "space_test": {**build_space_test_model(bundle, status_model), "linked_validation": manual_validation, "mode": "linked_build_run"},
779
  "space_test_policy": space_test_policy,
 
780
  "manual_validation": manual_validation,
781
  "post_build_validation": effective_run_status.get("post_build_validation") or {},
782
  "display_status": effective_run_status.get("display_status") or status_model.get("global_status"),
@@ -785,7 +842,7 @@ def build_run_view_model(
785
  "actions": {
786
  "can_resume": status_model["global_status"] in {"running", "stale", "unknown"},
787
  "can_stop": status_model["global_status"] in {"running", "queued", "unknown"},
788
- "can_open_space": bool(target_url and _space_links_ready_from_bundle(bundle)),
789
  "can_validate": bool(space_test_policy.get("enabled")),
790
  "requires_manual_action": status_model["requires_manual_action"],
791
  },
 
454
  issue_detail = "Automatic hardware selection was not available. Choose hardware in Space settings, then run Space Test."
455
  issue_status = "action_required"
456
  elif status_model["global_status"] == "failed":
457
+ link_state = build_space_link_state(bundle)
458
+ if link_state.get("links_ready"):
459
+ issue_title = "Validation failed after Space upload"
460
+ issue_detail = "The generated Space exists and remains available, but automatic validation or recovery ended in failure."
461
+ else:
462
+ issue_title = "Run failed"
463
+ issue_detail = "Inspect logs and run artifacts for the failing step."
464
  issue_status = "open"
465
 
466
  health_passed = bool((gate.get("implementation_signals") or {}).get("health_passed") or smoke.get("health_passed"))
 
541
  return f"https://huggingface.co/spaces/{target}" if target else ""
542
 
543
 
544
+ def build_space_link_state(bundle: dict[str, Any], *, target: str = "", target_url: str = "") -> dict[str, Any]:
545
+ """Return durable Space link readiness for Active Run.
546
+
547
+ v198.26.8 invariant: Space links are a persisted run fact. They must not
548
+ depend on the frontend receiving the create/upload event inside a truncated
549
+ recent-events window. If a runtime upload epoch or Space runtime probe is
550
+ present, a terminal failed run still gets Open Space / Settings links.
551
+ """
552
  identity = bundle.get("space_identity") or {}
 
 
553
  runtime_upload_epoch = bundle.get("runtime_upload_epoch") or {}
554
+ runtime_history = runtime_upload_epoch.get("history") if isinstance(runtime_upload_epoch.get("history"), list) else []
555
+ space_runtime = bundle.get("space_runtime") or {}
556
+ target = _space_target_from_bundle(bundle) if not target else _normalize_target_space_id(target)
557
+ target_url = target_url or _space_target_url_from_bundle(bundle, target)
558
+ create_event_ok = False
559
+ upload_event_ok = False
560
  for event in bundle.get("events") or []:
561
  if not isinstance(event, dict):
562
  continue
563
  step = str(event.get("step") or "")
564
  status = str(event.get("status") or "").lower()
565
+ if status == "success" and step in {"create_space", "create_space_hardware"}:
566
+ create_event_ok = True
567
+ if status == "success" and step in {"upload_files", "runtime_upload_epoch"}:
568
+ upload_event_ok = True
569
+ runtime_uploaded = bool(identity.get("runtime_uploaded") or identity.get("space_uploaded") or runtime_upload_epoch.get("last_upload_completed_at") or runtime_upload_epoch.get("upload_sequence") or runtime_history or upload_event_ok)
570
+ space_runtime_known = bool(identity.get("space_runtime_known") or (isinstance(space_runtime, dict) and (space_runtime.get("stage") or space_runtime.get("status") or space_runtime.get("runtime_status") or space_runtime.get("updated_at") or space_runtime.get("url"))))
571
+ space_created = bool(identity.get("space_created") or (target and (create_event_ok or runtime_uploaded or space_runtime_known)))
572
+ links_ready = bool(target_url and (identity.get("links_ready") or space_created or runtime_uploaded or space_runtime_known))
573
+ sources: list[str] = []
574
+ if identity.get("source"):
575
+ sources.append(str(identity.get("source")))
576
+ if create_event_ok:
577
+ sources.append("create_space_event")
578
+ if upload_event_ok:
579
+ sources.append("upload_event")
580
+ if runtime_uploaded:
581
+ sources.append("runtime_upload_epoch")
582
+ if space_runtime_known:
583
+ sources.append("space_runtime")
584
+ return {
585
+ "schema_version": "space_link_state.v198_26_8",
586
+ "target_space": target,
587
+ "target_space_id": target,
588
+ "target_space_known": bool(target),
589
+ "target_space_url": target_url,
590
+ "target_space_settings_url": f"{target_url}/settings" if target_url else "",
591
+ "space_created": bool(space_created),
592
+ "runtime_uploaded": bool(runtime_uploaded),
593
+ "space_uploaded": bool(runtime_uploaded),
594
+ "space_runtime_known": bool(space_runtime_known),
595
+ "links_ready": bool(links_ready),
596
+ "can_open_space": bool(links_ready),
597
+ "source": "+".join(dict.fromkeys([s for s in sources if s])) or "resolved_from_persisted_artifacts",
598
+ }
599
+
600
+
601
+ def _space_links_ready_from_bundle(bundle: dict[str, Any]) -> bool:
602
+ return bool(build_space_link_state(bundle).get("links_ready"))
603
 
604
 
605
  def _known_gradio_endpoint_info(bundle: dict[str, Any]) -> dict[str, Any]:
 
793
  elapsed_seconds = int((end - created).total_seconds())
794
  target = _space_target_from_bundle(bundle)
795
  target_url = _space_target_url_from_bundle(bundle, target)
796
+ space_link_state = build_space_link_state(bundle, target=target, target_url=target_url)
797
  links = {
798
  "job_url": _job_url_from_view_sources(bucket_source=bucket_source, summary=summary, state=state, launch=bundle.get("launch") or {}),
799
  "target_space_url": target_url,
800
  "target_space_settings_url": f"{target_url}/settings" if target_url else "",
801
  "artifacts_url": summary.get("artifacts_url") or f"https://huggingface.co/buckets/{bucket_source}/tree/{_runs_prefix()}/{run_id}",
802
+ "links_ready": bool(space_link_state.get("links_ready")),
803
+ "space_created": bool(space_link_state.get("space_created")),
804
+ "space_uploaded": bool(space_link_state.get("runtime_uploaded")),
805
+ "runtime_uploaded": bool(space_link_state.get("runtime_uploaded")),
806
+ "space_runtime_known": bool(space_link_state.get("space_runtime_known")),
807
+ "source": space_link_state.get("source") or "",
808
  }
809
  return {
810
  "schema_version": "run_view_model.v1",
 
833
  "diagnostics": build_diagnostics(bundle, status_model, phase),
834
  "space_test": {**build_space_test_model(bundle, status_model), "linked_validation": manual_validation, "mode": "linked_build_run"},
835
  "space_test_policy": space_test_policy,
836
+ "space_link_state": space_link_state,
837
  "manual_validation": manual_validation,
838
  "post_build_validation": effective_run_status.get("post_build_validation") or {},
839
  "display_status": effective_run_status.get("display_status") or status_model.get("global_status"),
 
842
  "actions": {
843
  "can_resume": status_model["global_status"] in {"running", "stale", "unknown"},
844
  "can_stop": status_model["global_status"] in {"running", "queued", "unknown"},
845
+ "can_open_space": bool(space_link_state.get("can_open_space")),
846
  "can_validate": bool(space_test_policy.get("enabled")),
847
  "requires_manual_action": status_model["requires_manual_action"],
848
  },
src/worker_payload.py CHANGED
@@ -35,8 +35,8 @@ DEFAULT_PREFERRED_SPACE_HARDWARE = "zero-a10g"
35
  DEFAULT_FALLBACK_SPACE_HARDWARE = "a10g-large"
36
  DEFAULT_MODEL_ID = "sshleifer/tiny-gpt2"
37
  MAX_PI_REPAIR_ATTEMPTS = 3
38
- APP_VERSION = "v198.26.7"
39
- app_version = "v198.26.7"
40
 
41
  # Internal agent/recovery files may be needed inside the transient Pi
42
  # workspace, but they should not be published to the generated Space or shown
@@ -2056,6 +2056,7 @@ def fail(run_dir: Path, events_path: Path, message: str, details: dict | None =
2056
  write_json(run_dir / "state.json", failure_state)
2057
  cleanup_status = run_final_cleanup_if_needed(run_dir, events_path, failure_state)
2058
  failure_state["cleanup"] = cleanup_status
 
2059
  write_final_summary(run_dir, failure_state, {}, {}, status=status, message=message)
2060
  live_failure_data = dict(safe)
2061
  live_failure_data["cleanup"] = cleanup_status
@@ -5250,6 +5251,45 @@ def reconcile_final_success_state(run_dir: Path, events_path: Path | None, final
5250
  return clean
5251
 
5252
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5253
 
5254
  def _normalize_dependency_package_name(value: str = "") -> str:
5255
  name = re.split(r"[<>=!~;\[,\s]", str(value or "").strip(), 1)[0].strip().lower().replace("_", "-")
@@ -12463,7 +12503,7 @@ def smoke_generate(target_space_id: str, token: str, run_dir: Path, events_path:
12463
  # write_json(run_dir / "tests" / "payload_source.json", payload_source_record)
12464
  # write_json(run_dir / "tests" / "replay_source.json", replay_source)
12465
  # write_json(run_dir / "tests" / "validation_preflight.json", validation_preflight)
12466
- app_version = "v198.26.7"
12467
  engine_version = "unified_gradio_validation_harness_v198_25_3"
12468
  parent_build_run_id = os.environ.get("PARENT_BUILD_RUN_ID", "").strip()
12469
  validation_mode = os.environ.get("VALIDATION_MODE") or os.environ.get("SPACE_TEST_POLICY_MODE") or "linked"
 
35
  DEFAULT_FALLBACK_SPACE_HARDWARE = "a10g-large"
36
  DEFAULT_MODEL_ID = "sshleifer/tiny-gpt2"
37
  MAX_PI_REPAIR_ATTEMPTS = 3
38
+ APP_VERSION = "v198.26.8"
39
+ app_version = "v198.26.8"
40
 
41
  # Internal agent/recovery files may be needed inside the transient Pi
42
  # workspace, but they should not be published to the generated Space or shown
 
2056
  write_json(run_dir / "state.json", failure_state)
2057
  cleanup_status = run_final_cleanup_if_needed(run_dir, events_path, failure_state)
2058
  failure_state["cleanup"] = cleanup_status
2059
+ write_terminal_status_reconciliation(run_dir, events_path, failure_state, status=status, message=message, details=safe, job_exit_code=1)
2060
  write_final_summary(run_dir, failure_state, {}, {}, status=status, message=message)
2061
  live_failure_data = dict(safe)
2062
  live_failure_data["cleanup"] = cleanup_status
 
5251
  return clean
5252
 
5253
 
5254
+ def write_terminal_status_reconciliation(run_dir: Path, events_path: Path | None, final_state: dict, *, status: str, message: str = "", details: dict | None = None, job_exit_code: int | None = None) -> dict:
5255
+ """Persist a terminal truth artifact for every final outcome.
5256
+
5257
+ v198.26.8: the UI must not have to infer failed/stopped states from a mix
5258
+ of state, repair_outcome and recent events. Success already writes
5259
+ final_status_reconciliation.json; failed/auth/cancelled terminal paths now
5260
+ write the same artifact so Active Run can converge deterministically.
5261
+ """
5262
+ state = final_state or {}
5263
+ safe = safe_details(details or {})
5264
+ runtime_upload_epoch = load_json_if_exists(run_dir / "runtime_upload_epoch.json") if (run_dir / "runtime_upload_epoch.json").exists() else {}
5265
+ space_runtime = load_json_if_exists(run_dir / "space_runtime.json") if (run_dir / "space_runtime.json").exists() else {}
5266
+ runtime_history = runtime_upload_epoch.get("history") if isinstance(runtime_upload_epoch.get("history"), list) else []
5267
+ target_space = state.get("target_space") or state.get("target_space_id") or runtime_upload_epoch.get("target_space_id") or os.environ.get("TARGET_SPACE_ID", "")
5268
+ runtime_uploaded = bool(runtime_upload_epoch.get("last_upload_completed_at") or runtime_upload_epoch.get("upload_sequence") or runtime_history)
5269
+ space_runtime_known = bool(isinstance(space_runtime, dict) and (space_runtime.get("stage") or space_runtime.get("status") or space_runtime.get("runtime_status") or space_runtime.get("updated_at") or space_runtime.get("url")))
5270
+ payload = {
5271
+ "schema_version": "final_status_reconciliation.v198_26_8",
5272
+ "status": status,
5273
+ "terminal": True,
5274
+ "message": message or state.get("message") or "",
5275
+ "job_exit_code": int(job_exit_code if job_exit_code is not None else (0 if status == "full_inference_success" else 1)),
5276
+ "target_space": target_space,
5277
+ "target_space_url": f"https://huggingface.co/spaces/{target_space}" if target_space else "",
5278
+ "space_created": bool(target_space and (runtime_uploaded or space_runtime_known)),
5279
+ "runtime_uploaded": bool(runtime_uploaded),
5280
+ "space_uploaded": bool(runtime_uploaded),
5281
+ "space_runtime_known": bool(space_runtime_known),
5282
+ "failure_type": safe.get("failure_type") or safe.get("repair_failure_type") or state.get("failure_type") or "",
5283
+ "failure_phase": safe.get("phase") or safe.get("failure_phase") or safe.get("step") or "",
5284
+ "details": safe,
5285
+ "updated_at": now(),
5286
+ }
5287
+ write_json(run_dir / "final_status_reconciliation.json", payload)
5288
+ if events_path is not None:
5289
+ append_event(events_path, "final_status_reconciliation", "success" if status == "full_inference_success" else "failed", "Wrote terminal final status reconciliation", {k: payload.get(k) for k in ("status", "job_exit_code", "target_space", "runtime_uploaded", "space_runtime_known", "failure_type")})
5290
+ return payload
5291
+
5292
+
5293
 
5294
  def _normalize_dependency_package_name(value: str = "") -> str:
5295
  name = re.split(r"[<>=!~;\[,\s]", str(value or "").strip(), 1)[0].strip().lower().replace("_", "-")
 
12503
  # write_json(run_dir / "tests" / "payload_source.json", payload_source_record)
12504
  # write_json(run_dir / "tests" / "replay_source.json", replay_source)
12505
  # write_json(run_dir / "tests" / "validation_preflight.json", validation_preflight)
12506
+ app_version = "v198.26.8"
12507
  engine_version = "unified_gradio_validation_harness_v198_25_3"
12508
  parent_build_run_id = os.environ.get("PARENT_BUILD_RUN_ID", "").strip()
12509
  validation_mode = os.environ.get("VALIDATION_MODE") or os.environ.get("SPACE_TEST_POLICY_MODE") or "linked"