specimba commited on
Commit
621cf5d
·
verified ·
1 Parent(s): f76b6e4

Deploy v4 review hardening

Browse files
app.py CHANGED
@@ -629,7 +629,11 @@ def approve_checkpoint(
629
  "checkpoint": "approved",
630
  "generated_scan": scan,
631
  "export": export_state,
632
- "message": "Checkpoint approved. Export is ready after clear ST3GG scan." if export_state == "clear" else "Checkpoint approved, but export still waits on ST3GG review.",
 
 
 
 
633
  }
634
  return _render_stateful(run, adult_mode, scan, active_section, next_state)
635
 
@@ -675,9 +679,10 @@ def export_packet(
675
  next_state = {**state, "provider_state": "blocked", "export": scan.get("export_gate", "blocked"), "message": "Export blocked: ST3GG gate is not clear. Add an explicit override reason to write an audit packet."}
676
  else:
677
  export_state = "clear" if scan.get("export_gate") == "clear" else "override"
 
678
  export_operator_state = {
679
  **state,
680
- **({"st3gg_override_reason": override_reason} if override_reason else {}),
681
  "export": export_state,
682
  }
683
  export = write_export_packet(run=run, scan=scan, operator_state=export_operator_state, adult_mode=adult_mode)
@@ -839,7 +844,7 @@ with gr.Blocks(title="NEXUS Visual Weaver") as demo:
839
  reset_btn = gr.Button("Reset Demo State", scale=1)
840
  override_reason = gr.Textbox(
841
  label="ST3GG Override Reason",
842
- placeholder="Required only when exporting an audit packet for a reviewed/blocked artifact.",
843
  lines=2,
844
  max_lines=3,
845
  )
 
629
  "checkpoint": "approved",
630
  "generated_scan": scan,
631
  "export": export_state,
632
+ "message": (
633
+ "Checkpoint approved. Export is ready after clear ST3GG scan."
634
+ if export_state == "clear"
635
+ else "Checkpoint approved. ST3GG is not clear; add an override reason and click Prepare Export Packet to write an audit packet."
636
+ ),
637
  }
638
  return _render_stateful(run, adult_mode, scan, active_section, next_state)
639
 
 
679
  next_state = {**state, "provider_state": "blocked", "export": scan.get("export_gate", "blocked"), "message": "Export blocked: ST3GG gate is not clear. Add an explicit override reason to write an audit packet."}
680
  else:
681
  export_state = "clear" if scan.get("export_gate") == "clear" else "override"
682
+ override_applies = scan.get("export_gate") != "clear" and bool(override_reason)
683
  export_operator_state = {
684
  **state,
685
+ **({"st3gg_override_reason": override_reason} if override_applies else {}),
686
  "export": export_state,
687
  }
688
  export = write_export_packet(run=run, scan=scan, operator_state=export_operator_state, adult_mode=adult_mode)
 
844
  reset_btn = gr.Button("Reset Demo State", scale=1)
845
  override_reason = gr.Textbox(
846
  label="ST3GG Override Reason",
847
+ placeholder="Required when ST3GG is review/blocked; explain why this audit packet may be written.",
848
  lines=2,
849
  max_lines=3,
850
  )
docs/HACKATHON_EVALUATION.md CHANGED
@@ -13,8 +13,8 @@ NEXUS Visual Weaver should open as a working command center, not a landing page.
13
  ## Current Strengths
14
 
15
  - Gradio-compatible app shape with `mcp_server=True`.
16
- - Pinned model governance is visible: FLUX.2 Klein 4B, LocateAnything-3B, and ST3GG.
17
- - Real FLUX.2 Klein 4B generation is wired for HF Space and falls back to an honest dry-run state outside Space.
18
  - Generated artifacts are scanned by ST3GG before checkpoint/export.
19
  - Above-fold trust strip makes ST3GG verdict, export gate, fixture evidence, and adult-mode safety boundaries visible immediately.
20
  - OpenBMB MiniCPM-V 4.6 and NVIDIA Nemotron evidence lanes are represented as real optional provider adapters with missing-secret/failed/success states.
@@ -48,5 +48,5 @@ NEXUS Visual Weaver should open as a working command center, not a landing page.
48
  | OpenBMB | Claim only after MiniCPM-V returns `success` in export evidence. |
49
  | NVIDIA | Claim only after Nemotron returns `success` in export evidence. |
50
  | OpenAI Codex | GitHub branch/PR provides Codex development trail. |
51
- | Tiny Titan | Public demo stack is eligible: active public models are each <=4B. |
52
  | Modal | Not claimed unless a real Modal job runs. |
 
13
  ## Current Strengths
14
 
15
  - Gradio-compatible app shape with `mcp_server=True`.
16
+ - Pinned model governance is visible: FLUX.2 Klein 9B, LocateAnything-3B, and ST3GG, with FLUX.2 Klein 4B kept as a sidecar fallback.
17
+ - Real FLUX.2 Klein 9B generation is wired for HF Space, falls back to the 4B sidecar when needed, and reports an honest dry-run state outside Space.
18
  - Generated artifacts are scanned by ST3GG before checkpoint/export.
19
  - Above-fold trust strip makes ST3GG verdict, export gate, fixture evidence, and adult-mode safety boundaries visible immediately.
20
  - OpenBMB MiniCPM-V 4.6 and NVIDIA Nemotron evidence lanes are represented as real optional provider adapters with missing-secret/failed/success states.
 
48
  | OpenBMB | Claim only after MiniCPM-V returns `success` in export evidence. |
49
  | NVIDIA | Claim only after Nemotron returns `success` in export evidence. |
50
  | OpenAI Codex | GitHub branch/PR provides Codex development trail. |
51
+ | Tiny Titan | Sidecar-only: claim only from an explicit 4B export packet where every active model is <=4B. |
52
  | Modal | Not claimed unless a real Modal job runs. |
docs/HANDOFF_FINAL_HACKATHON.md CHANGED
@@ -8,13 +8,13 @@
8
  - Public Space URL: `https://build-small-hackathon-nexus-visual-weaver-a107340.hf.space/`
9
  - HF rollback SHA: `410a467c55d11e7308249198bd5fe0b2c190aec6`.
10
  - Branch discipline: use only `main` and `codex/specimba/ui-polish-command-center`; no extra recovery branches.
11
- - Primary goal: finish a countable Build Small submission with real FLUX.2 4B generation, ST3GG scan, optional OpenBMB MiniCPM-V judge evidence, optional NVIDIA Nemotron evidence, checkpointed export packet, README prize mapping, demo video, and social post.
12
 
13
  ## Secrets Needed
14
 
15
  Do not paste these into chat, commits, logs, or export packets.
16
 
17
- - `HF_TOKEN`: optional for public FLUX.2 Klein 4B access and required only if private/gated research lanes are enabled.
18
  - `MINICPM_BASE_URL`: OpenBMB OpenAI-compatible endpoint base URL.
19
  - `MINICPM_API_KEY`: OpenBMB bearer token.
20
  - `MINICPM_MODEL`: default `MiniCPM-V-4.6`.
@@ -39,7 +39,7 @@ Avoid pytest `--basetemp=C:\tmp` in this Windows sandbox if `tmp_path` fixtures
39
  ## Runtime Flow
40
 
41
  1. `run_active_weave` builds the Raven Chronicle run packet.
42
- 2. FLUX.2 Klein 4B generates the image on Space when HF runtime is enabled.
43
  3. Generated artifact is scanned by ST3GG.
44
  4. MiniCPM-V judge runs when OpenBMB secrets are present.
45
  5. Nemotron evidence runs when Nemotron/NVIDIA endpoint secrets are present.
@@ -51,14 +51,14 @@ Avoid pytest `--basetemp=C:\tmp` in this Windows sandbox if `tmp_path` fixtures
51
  - OpenBMB prize claim requires `minicpm_judge.status == "success"` in an export packet.
52
  - NVIDIA prize claim requires `nemotron_evidence.status == "success"` in an export packet.
53
  - LocateAnything supports the grounding story but does not replace Nemotron for the NVIDIA prize.
54
- - Tiny Titan can be claimed only from a successful public-demo export packet because each active public model is <=4B.
55
- - FLUX.2 Klein 9B and OFFELLIA/Gemma remain private research options only.
56
  - Modal is not claimed unless a real Modal job runs and is documented.
57
 
58
  ## Known Risks
59
 
60
  - GitHub CLI may fail behind proxy `127.0.0.1:9`; use local git status and HF verification when blocked.
61
- - Real FLUX generation depends on Space GPU availability and the public 4B runtime loading successfully.
62
  - OpenBMB and Nemotron endpoints are optional and must show `missing secret` rather than fake success when not configured.
63
  - Demo video and social post links must be added before final submission.
64
 
 
8
  - Public Space URL: `https://build-small-hackathon-nexus-visual-weaver-a107340.hf.space/`
9
  - HF rollback SHA: `410a467c55d11e7308249198bd5fe0b2c190aec6`.
10
  - Branch discipline: use only `main` and `codex/specimba/ui-polish-command-center`; no extra recovery branches.
11
+ - Primary goal: finish a countable Build Small submission with real FLUX.2 Klein 9B generation, 4B sidecar fallback, ST3GG scan, optional OpenBMB MiniCPM-V judge evidence, optional NVIDIA Nemotron evidence, checkpointed export packet, README prize mapping, demo video, and social post.
12
 
13
  ## Secrets Needed
14
 
15
  Do not paste these into chat, commits, logs, or export packets.
16
 
17
+ - `HF_TOKEN`: required when the FLUX.2 Klein 9B Space runtime needs authenticated access; the 4B sidecar remains the public-safe fallback/Tiny Titan lane.
18
  - `MINICPM_BASE_URL`: OpenBMB OpenAI-compatible endpoint base URL.
19
  - `MINICPM_API_KEY`: OpenBMB bearer token.
20
  - `MINICPM_MODEL`: default `MiniCPM-V-4.6`.
 
39
  ## Runtime Flow
40
 
41
  1. `run_active_weave` builds the Raven Chronicle run packet.
42
+ 2. FLUX.2 Klein 9B generates the image on Space when HF runtime is enabled, with FLUX.2 Klein 4B as the fallback/sidecar lane.
43
  3. Generated artifact is scanned by ST3GG.
44
  4. MiniCPM-V judge runs when OpenBMB secrets are present.
45
  5. Nemotron evidence runs when Nemotron/NVIDIA endpoint secrets are present.
 
51
  - OpenBMB prize claim requires `minicpm_judge.status == "success"` in an export packet.
52
  - NVIDIA prize claim requires `nemotron_evidence.status == "success"` in an export packet.
53
  - LocateAnything supports the grounding story but does not replace Nemotron for the NVIDIA prize.
54
+ - Tiny Titan can be claimed only from an explicit 4B sidecar export packet where every active model is <=4B.
55
+ - Raven Quality Stack uses FLUX.2 Klein 9B by default; OFFELLIA/Gemma remain private research options behind Adult Mode/catalog partitioning.
56
  - Modal is not claimed unless a real Modal job runs and is documented.
57
 
58
  ## Known Risks
59
 
60
  - GitHub CLI may fail behind proxy `127.0.0.1:9`; use local git status and HF verification when blocked.
61
+ - Real FLUX generation depends on Space GPU availability and the 9B runtime loading successfully, with a 4B sidecar fallback when configured.
62
  - OpenBMB and Nemotron endpoints are optional and must show `missing secret` rather than fake success when not configured.
63
  - Demo video and social post links must be added before final submission.
64
 
src/nexus_visual_weaver/exporter.py CHANGED
@@ -64,7 +64,18 @@ def _artifact_name(output_path: Any) -> str | None:
64
  """
65
  if not output_path:
66
  return None
67
- return Path(str(output_path)).name
 
 
 
 
 
 
 
 
 
 
 
68
 
69
 
70
  SENSITIVE_KEY_RE = re.compile(r"(token|secret|api[_-]?key|authorization|payload_excerpt|raw|base64|bytes)", re.IGNORECASE)
@@ -245,7 +256,8 @@ def write_export_packet(
245
  Dictionary with "path" (str) pointing to the written JSON file and "packet" (dict)
246
  containing the constructed export packet.
247
  """
248
- run_id = getattr(getattr(run, "checkpoint", None), "checkpoint_id", f"nw-{int(time.time())}")
 
249
  run_adult_mode = bool(getattr(getattr(run, "request", None), "adult_mode", adult_mode))
250
  stack = list(getattr(run, "model_stack", None) or active_stack(run_adult_mode))
251
  budget = parameter_budget(stack)
@@ -260,11 +272,12 @@ def write_export_packet(
260
  st3gg_scan = _safe_scan(scan)
261
  minicpm_judge = _safe_provider(operator_state.get("minicpm_judge") or {})
262
  nemotron_evidence = _safe_provider(operator_state.get("nemotron_evidence") or {})
 
263
  provider_states = {
264
  "generation": generation.get("provider_state"),
265
  "minicpm": minicpm_judge.get("status"),
266
  "nemotron": nemotron_evidence.get("status"),
267
- "operator": operator_state.get("provider_state"),
268
  }
269
  override_reason = _safe_dict(operator_state.get("st3gg_override_reason", ""))
270
  packet = {
@@ -272,8 +285,8 @@ def write_export_packet(
272
  "run_id": run_id,
273
  "created_at_epoch": int(time.time()),
274
  "adult_mode": run_adult_mode,
275
- "prompt": getattr(getattr(run, "request", None), "prompt", ""),
276
- "refined_prompt": getattr(getattr(run, "refined_prompt", None), "refined", ""),
277
  "artifact": artifact,
278
  "image_basename": artifact,
279
  "creator_controls": creator_controls,
@@ -296,13 +309,13 @@ def write_export_packet(
296
  "minicpm_judge": minicpm_judge,
297
  "nemotron_evidence": nemotron_evidence,
298
  "checkpoint": {
299
- "status": operator_state.get("checkpoint"),
300
- "message": operator_state.get("message"),
301
- "recommendation": getattr(getattr(run, "checkpoint", None), "recommendation", None),
302
  "trust_score": getattr(getattr(run, "checkpoint", None), "trust_score", None),
303
- "required_actions": getattr(getattr(run, "checkpoint", None), "required_actions", []),
304
  },
305
- "provider_state": operator_state.get("provider_state"),
306
  "provider_states": provider_states,
307
  "model_stack": [
308
  {
@@ -324,6 +337,9 @@ def write_export_packet(
324
  "st3gg_export_gate": st3gg_scan.get("export_gate"),
325
  },
326
  }
327
- target = export_root() / f"{run_id}.json"
 
 
 
328
  target.write_text(json.dumps(packet, indent=2, ensure_ascii=True), encoding="utf-8")
329
  return {"path": str(target), "packet": packet}
 
64
  """
65
  if not output_path:
66
  return None
67
+ text = str(output_path)
68
+ if "\\" in text or re.match(r"^[A-Za-z]:[\\/]", text):
69
+ return PureWindowsPath(text).name
70
+ return Path(text).name
71
+
72
+
73
+ def _safe_run_id(value: Any) -> str:
74
+ text = str(value or f"nw-{int(time.time())}")
75
+ safe = re.sub(r"[^A-Za-z0-9_.-]+", "-", text).strip(".-")
76
+ while ".." in safe:
77
+ safe = safe.replace("..", ".")
78
+ return safe or f"nw-{int(time.time())}"
79
 
80
 
81
  SENSITIVE_KEY_RE = re.compile(r"(token|secret|api[_-]?key|authorization|payload_excerpt|raw|base64|bytes)", re.IGNORECASE)
 
256
  Dictionary with "path" (str) pointing to the written JSON file and "packet" (dict)
257
  containing the constructed export packet.
258
  """
259
+ raw_run_id = getattr(getattr(run, "checkpoint", None), "checkpoint_id", f"nw-{int(time.time())}")
260
+ run_id = _safe_run_id(raw_run_id)
261
  run_adult_mode = bool(getattr(getattr(run, "request", None), "adult_mode", adult_mode))
262
  stack = list(getattr(run, "model_stack", None) or active_stack(run_adult_mode))
263
  budget = parameter_budget(stack)
 
272
  st3gg_scan = _safe_scan(scan)
273
  minicpm_judge = _safe_provider(operator_state.get("minicpm_judge") or {})
274
  nemotron_evidence = _safe_provider(operator_state.get("nemotron_evidence") or {})
275
+ operator_provider_state = _safe_dict(operator_state.get("provider_state"))
276
  provider_states = {
277
  "generation": generation.get("provider_state"),
278
  "minicpm": minicpm_judge.get("status"),
279
  "nemotron": nemotron_evidence.get("status"),
280
+ "operator": operator_provider_state,
281
  }
282
  override_reason = _safe_dict(operator_state.get("st3gg_override_reason", ""))
283
  packet = {
 
285
  "run_id": run_id,
286
  "created_at_epoch": int(time.time()),
287
  "adult_mode": run_adult_mode,
288
+ "prompt": _safe_dict(getattr(getattr(run, "request", None), "prompt", "")),
289
+ "refined_prompt": _safe_dict(getattr(getattr(run, "refined_prompt", None), "refined", "")),
290
  "artifact": artifact,
291
  "image_basename": artifact,
292
  "creator_controls": creator_controls,
 
309
  "minicpm_judge": minicpm_judge,
310
  "nemotron_evidence": nemotron_evidence,
311
  "checkpoint": {
312
+ "status": _safe_dict(operator_state.get("checkpoint")),
313
+ "message": _safe_dict(operator_state.get("message")),
314
+ "recommendation": _safe_dict(getattr(getattr(run, "checkpoint", None), "recommendation", None)),
315
  "trust_score": getattr(getattr(run, "checkpoint", None), "trust_score", None),
316
+ "required_actions": _safe_dict(getattr(getattr(run, "checkpoint", None), "required_actions", [])),
317
  },
318
+ "provider_state": operator_provider_state,
319
  "provider_states": provider_states,
320
  "model_stack": [
321
  {
 
337
  "st3gg_export_gate": st3gg_scan.get("export_gate"),
338
  },
339
  }
340
+ root = export_root()
341
+ target = (root / f"{run_id}.json").resolve(strict=False)
342
+ if not (target == root or _is_within(target, root)):
343
+ raise ValueError("Unsafe export target path.")
344
  target.write_text(json.dumps(packet, indent=2, ensure_ascii=True), encoding="utf-8")
345
  return {"path": str(target), "packet": packet}
src/nexus_visual_weaver/hf_runtime.py CHANGED
@@ -8,6 +8,7 @@ import time
8
  from dataclasses import dataclass, asdict
9
  from pathlib import Path
10
  from typing import Any
 
11
 
12
  from .catalog import ADAPTER_CATALOG
13
  from .lora_adapter import load_and_apply, unload_all
@@ -274,7 +275,7 @@ def generate_flux_image(
274
  ).images[0]
275
  finally:
276
  unload_all(pipe)
277
- output_path = _output_dir() / f"nexus_flux_{int(time.time())}_{seed}.png"
278
  image.save(output_path)
279
  return HFGenerationResult(
280
  status="success",
 
8
  from dataclasses import dataclass, asdict
9
  from pathlib import Path
10
  from typing import Any
11
+ from uuid import uuid4
12
 
13
  from .catalog import ADAPTER_CATALOG
14
  from .lora_adapter import load_and_apply, unload_all
 
275
  ).images[0]
276
  finally:
277
  unload_all(pipe)
278
+ output_path = _output_dir() / f"nexus_flux_{time.time_ns()}_{seed}_{uuid4().hex[:8]}.png"
279
  image.save(output_path)
280
  return HFGenerationResult(
281
  status="success",
src/nexus_visual_weaver/lora_adapter.py CHANGED
@@ -116,6 +116,7 @@ def load_and_apply(
116
  pipe.set_adapters([adapter_name], adapter_weights=[recipe.weight])
117
  return _status("loaded", recipe, message="Adapter loaded and applied for this generation.", adapter_name=adapter_name)
118
  except Exception as exc:
 
119
  return _status("failed", recipe, message=_short_error(exc), adapter_name=adapter_name)
120
 
121
 
 
116
  pipe.set_adapters([adapter_name], adapter_weights=[recipe.weight])
117
  return _status("loaded", recipe, message="Adapter loaded and applied for this generation.", adapter_name=adapter_name)
118
  except Exception as exc:
119
+ unload_all(pipe)
120
  return _status("failed", recipe, message=_short_error(exc), adapter_name=adapter_name)
121
 
122
 
src/nexus_visual_weaver/model_relay.py CHANGED
@@ -196,7 +196,8 @@ class WeaverModelRelay:
196
  lane_records = [record for record in self.records.values() if record.lane == lane]
197
  if lane in PINNED_LANES:
198
  primary = next((record for record in lane_records if record.pinned), None)
199
- fallbacks = [self.records[model_id] for model_id in (primary.fallback_chain if primary else ()) if model_id in self.records]
 
200
  return LaneDecision(
201
  lane=lane,
202
  strategy="pinned",
@@ -206,7 +207,7 @@ class WeaverModelRelay:
206
  expected_cost_hint=primary.cost_hint if primary else "unavailable",
207
  quota_impact=self._quota_impact(primary, now) if primary else {},
208
  context_packet=context,
209
- skipped=[] if primary else [f"{lane}: no pinned model registered"],
210
  )
211
 
212
  candidates, skipped = self._eligible_records(lane_records, budget_b, public_demo, strategy, now)
 
196
  lane_records = [record for record in self.records.values() if record.lane == lane]
197
  if lane in PINNED_LANES:
198
  primary = next((record for record in lane_records if record.pinned), None)
199
+ fallback_records = [self.records[model_id] for model_id in (primary.fallback_chain if primary else ()) if model_id in self.records]
200
+ fallbacks, skipped = self._eligible_records(fallback_records, budget_b, public_demo, strategy, now)
201
  return LaneDecision(
202
  lane=lane,
203
  strategy="pinned",
 
207
  expected_cost_hint=primary.cost_hint if primary else "unavailable",
208
  quota_impact=self._quota_impact(primary, now) if primary else {},
209
  context_packet=context,
210
+ skipped=skipped if primary else [f"{lane}: no pinned model registered"],
211
  )
212
 
213
  candidates, skipped = self._eligible_records(lane_records, budget_b, public_demo, strategy, now)
src/nexus_visual_weaver/planner.py CHANGED
@@ -2,6 +2,7 @@
2
 
3
  from __future__ import annotations
4
 
 
5
  from uuid import uuid4
6
 
7
  from .catalog import ADAPTER_CATALOG, active_stack
@@ -34,12 +35,19 @@ def build_command_center_run(
34
  Returns:
35
  A GenerationRun containing the refined prompt, generated outfit, inspection results, model stack, adapters, video plan, lore components, and a human checkpoint with approval recommendation based on a computed trust score.
36
  """
37
- controls = creator_controls or {}
38
- references = reference_metadata or []
 
 
 
 
 
 
 
39
  request = CreativeRequest(
40
  prompt=prompt,
41
  adult_mode=adult_mode,
42
- references=[str(item.get("id") or item.get("basename") or item.get("url_hash")) for item in references],
43
  creator_controls=controls,
44
  reference_metadata=references,
45
  )
 
2
 
3
  from __future__ import annotations
4
 
5
+ from copy import deepcopy
6
  from uuid import uuid4
7
 
8
  from .catalog import ADAPTER_CATALOG, active_stack
 
35
  Returns:
36
  A GenerationRun containing the refined prompt, generated outfit, inspection results, model stack, adapters, video plan, lore components, and a human checkpoint with approval recommendation based on a computed trust score.
37
  """
38
+ controls = deepcopy(creator_controls or {})
39
+ references = deepcopy(reference_metadata or [])
40
+ reference_ids: list[str] = []
41
+ for item in references:
42
+ if not isinstance(item, dict):
43
+ continue
44
+ value = item.get("id") or item.get("basename") or item.get("url_hash")
45
+ if value is not None and str(value):
46
+ reference_ids.append(str(value))
47
  request = CreativeRequest(
48
  prompt=prompt,
49
  adult_mode=adult_mode,
50
+ references=reference_ids,
51
  creator_controls=controls,
52
  reference_metadata=references,
53
  )
src/nexus_visual_weaver/provider_runtime.py CHANGED
@@ -17,6 +17,14 @@ from typing import Any
17
  OPENBMB_REPO_ID = "openbmb/MiniCPM-V-4.6"
18
  NEMOTRON_PARSE_REPO_ID = "nvidia/NVIDIA-Nemotron-Parse-v1.2"
19
  NEMOTRON_NANO_REPO_ID = "nvidia/NVIDIA-Nemotron-3-Nano-4B-GGUF"
 
 
 
 
 
 
 
 
20
 
21
 
22
  @dataclass(frozen=True)
@@ -67,13 +75,36 @@ def _image_data_url(path: str | None) -> str | None:
67
  if not target.exists() or not target.is_file():
68
  return None
69
  suffix = target.suffix.lower()
70
- mime = "image/png" if suffix == ".png" else "image/jpeg" if suffix in {".jpg", ".jpeg"} else "image/webp"
 
 
71
  data = base64.b64encode(target.read_bytes()).decode("ascii")
72
  return f"data:{mime};base64,{data}"
73
  except OSError:
74
  return None
75
 
76
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
77
  def _post_json(url: str, token: str, payload: dict[str, Any], timeout: float) -> dict[str, Any]:
78
  """
79
  Send an authenticated JSON POST request and return the parsed response.
@@ -91,6 +122,8 @@ def _post_json(url: str, token: str, payload: dict[str, Any], timeout: float) ->
91
  parsed = urllib.parse.urlparse(url)
92
  if parsed.scheme not in {"http", "https"} or not parsed.netloc:
93
  raise ValueError(f"Invalid URL: expected http(s) URL with host, got {url!r}.")
 
 
94
  body = json.dumps(payload).encode("utf-8")
95
  request = urllib.request.Request(
96
  url,
@@ -287,12 +320,14 @@ def judge_with_nemotron(
287
  "Return strict JSON only with keys: sponsor_model_used, structured_parse, "
288
  "risk_notes, parameter_budget_notes, final_claim_status. Parse this visual creation run."
289
  )
 
 
290
  payload = {
291
  "model": model,
292
  "messages": [
293
  {
294
  "role": "user",
295
- "content": f"{instruction}\nPrompt: {prompt}\nRun: {json.dumps(run_packet, ensure_ascii=True)[:6000]}\nMiniCPM: {json.dumps(minicpm_result or {}, ensure_ascii=True)[:2500]}",
296
  }
297
  ],
298
  "temperature": 0.1,
 
17
  OPENBMB_REPO_ID = "openbmb/MiniCPM-V-4.6"
18
  NEMOTRON_PARSE_REPO_ID = "nvidia/NVIDIA-Nemotron-Parse-v1.2"
19
  NEMOTRON_NANO_REPO_ID = "nvidia/NVIDIA-Nemotron-3-Nano-4B-GGUF"
20
+ MAX_PROVIDER_IMAGE_BYTES = 10 * 1024 * 1024
21
+ IMAGE_MIME_BY_SUFFIX = {
22
+ ".png": "image/png",
23
+ ".jpg": "image/jpeg",
24
+ ".jpeg": "image/jpeg",
25
+ ".webp": "image/webp",
26
+ }
27
+ SENSITIVE_PROVIDER_KEYS = ("token", "secret", "api_key", "authorization", "payload", "raw", "base64", "bytes")
28
 
29
 
30
  @dataclass(frozen=True)
 
75
  if not target.exists() or not target.is_file():
76
  return None
77
  suffix = target.suffix.lower()
78
+ mime = IMAGE_MIME_BY_SUFFIX.get(suffix)
79
+ if mime is None or target.stat().st_size > MAX_PROVIDER_IMAGE_BYTES:
80
+ return None
81
  data = base64.b64encode(target.read_bytes()).decode("ascii")
82
  return f"data:{mime};base64,{data}"
83
  except OSError:
84
  return None
85
 
86
 
87
+ def _is_loopback_host(hostname: str | None) -> bool:
88
+ return hostname in {"localhost", "127.0.0.1", "::1"}
89
+
90
+
91
+ def _safe_provider_payload(value: Any) -> Any:
92
+ if isinstance(value, dict):
93
+ redacted: dict[str, Any] = {}
94
+ for key, item in value.items():
95
+ normalized = str(key).lower()
96
+ if any(marker in normalized for marker in SENSITIVE_PROVIDER_KEYS):
97
+ redacted[str(key)] = "[redacted]"
98
+ else:
99
+ redacted[str(key)] = _safe_provider_payload(item)
100
+ return redacted
101
+ if isinstance(value, list):
102
+ return [_safe_provider_payload(item) for item in value]
103
+ if isinstance(value, tuple):
104
+ return [_safe_provider_payload(item) for item in value]
105
+ return value
106
+
107
+
108
  def _post_json(url: str, token: str, payload: dict[str, Any], timeout: float) -> dict[str, Any]:
109
  """
110
  Send an authenticated JSON POST request and return the parsed response.
 
122
  parsed = urllib.parse.urlparse(url)
123
  if parsed.scheme not in {"http", "https"} or not parsed.netloc:
124
  raise ValueError(f"Invalid URL: expected http(s) URL with host, got {url!r}.")
125
+ if parsed.scheme == "http" and not _is_loopback_host(parsed.hostname):
126
+ raise ValueError("Provider URLs must use HTTPS unless targeting loopback development hosts.")
127
  body = json.dumps(payload).encode("utf-8")
128
  request = urllib.request.Request(
129
  url,
 
320
  "Return strict JSON only with keys: sponsor_model_used, structured_parse, "
321
  "risk_notes, parameter_budget_notes, final_claim_status. Parse this visual creation run."
322
  )
323
+ safe_run_packet = _safe_provider_payload(run_packet)
324
+ safe_minicpm_result = _safe_provider_payload(minicpm_result or {})
325
  payload = {
326
  "model": model,
327
  "messages": [
328
  {
329
  "role": "user",
330
+ "content": f"{instruction}\nPrompt: {prompt}\nRun: {json.dumps(safe_run_packet, ensure_ascii=True)[:6000]}\nMiniCPM: {json.dumps(safe_minicpm_result, ensure_ascii=True)[:2500]}",
331
  }
332
  ],
333
  "temperature": 0.1,
src/nexus_visual_weaver/wardrobe.py CHANGED
@@ -17,6 +17,10 @@ SLOT_BLUEPRINTS: list[tuple[str, str, str, str, str]] = [
17
  ]
18
 
19
 
 
 
 
 
20
  def build_outfit_graph(prompt: str, adult_mode: bool = False, controls: dict | None = None) -> OutfitGraph:
21
  """
22
  Constructs an outfit graph with wardrobe slots configured by prompt analysis and optional controls.
@@ -42,7 +46,7 @@ def build_outfit_graph(prompt: str, adult_mode: bool = False, controls: dict | N
42
  if name == "footwear" and controls.get("footwear"):
43
  description = str(controls["footwear"])
44
  if name == "jewelry" and controls.get("hardware"):
45
- material = str(controls["hardware"])
46
  if controls.get("palette"):
47
  palette = str(controls["palette"])
48
  locked = any(token in lowered for token in name.split("_")) or material.replace("_", " ") in lowered
 
17
  ]
18
 
19
 
20
+ def _material_token(value: object) -> str:
21
+ return str(value).strip().lower().replace("-", "_").replace(" ", "_")
22
+
23
+
24
  def build_outfit_graph(prompt: str, adult_mode: bool = False, controls: dict | None = None) -> OutfitGraph:
25
  """
26
  Constructs an outfit graph with wardrobe slots configured by prompt analysis and optional controls.
 
46
  if name == "footwear" and controls.get("footwear"):
47
  description = str(controls["footwear"])
48
  if name == "jewelry" and controls.get("hardware"):
49
+ material = _material_token(controls["hardware"])
50
  if controls.get("palette"):
51
  palette = str(controls["palette"])
52
  locked = any(token in lowered for token in name.split("_")) or material.replace("_", " ") in lowered
tests/test_app_callbacks.py CHANGED
@@ -159,6 +159,34 @@ def test_operator_actions_transition_checkpoint_export_and_stop() -> None:
159
  assert stopped[13]["provider_state"] == "stopped"
160
 
161
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
162
  def test_export_blocks_without_checkpoint() -> None:
163
  result = app.run_weave(
164
  "gothic patent leather platform boots, crimson hardware",
 
159
  assert stopped[13]["provider_state"] == "stopped"
160
 
161
 
162
+ def test_clear_export_ignores_stale_override_reason(monkeypatch) -> None:
163
+ monkeypatch.setenv("NEXUS_EXPORT_DIR", "outputs/test-exports")
164
+ result = app.run_weave(
165
+ "gothic patent leather platform boots, crimson hardware",
166
+ "Strict",
167
+ "Wan2.2 I2V",
168
+ False,
169
+ None,
170
+ "Forge",
171
+ )
172
+ run = result[13]
173
+ artifact_path = app.ROOT / "outputs" / "test-clear-override-artifact.png"
174
+ artifact_path.parent.mkdir(parents=True, exist_ok=True)
175
+ artifact_path.write_bytes(b"\x89PNG\r\n\x1a\n\x00\x00\x00\rIEND\xaeB`\x82")
176
+ operator_state = {
177
+ **result[15],
178
+ "generation": {**result[15]["generation"], "output_path": str(artifact_path)},
179
+ }
180
+ clean_scan = {"status": "pass", "export_gate": "clear", "findings": [], "purification_actions": []}
181
+
182
+ approved = app.approve_checkpoint(run, False, clean_scan, "Forge", operator_state)
183
+ exported = app.export_packet(run, False, clean_scan, "Forge", approved[13], "stale text from prior blocked run")
184
+
185
+ assert exported[13]["provider_state"] == "exported"
186
+ assert exported[13]["export"] == "clear"
187
+ assert "st3gg_override_reason" not in exported[13]
188
+
189
+
190
  def test_export_blocks_without_checkpoint() -> None:
191
  result = app.run_weave(
192
  "gothic patent leather platform boots, crimson hardware",
tests/test_command_center.py CHANGED
@@ -94,6 +94,23 @@ def test_command_center_run_is_checkpointed() -> None:
94
  assert any(model.repo_id == "nvidia/LocateAnything-3B" for model in run.model_stack)
95
 
96
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
97
  def test_security_scan_does_not_return_payload_excerpt() -> None:
98
  sample = Path(__file__).parent / "fixtures" / "sample.png"
99
  scan = scan_file(str(sample))
@@ -746,7 +763,7 @@ def test_build_outfit_graph_controls_override_hardware() -> None:
746
  jewelry_slot = next((s for s in outfit.slots if s.name == "jewelry"), None)
747
 
748
  assert jewelry_slot is not None
749
- assert jewelry_slot.material == "silver occult buckles"
750
 
751
 
752
  def test_build_outfit_graph_locked_slots_control_locks_named_slots() -> None:
 
94
  assert any(model.repo_id == "nvidia/LocateAnything-3B" for model in run.model_stack)
95
 
96
 
97
+ def test_command_center_run_snapshots_controls_and_skips_empty_reference_ids() -> None:
98
+ controls = {"wardrobe": {"footwear": "platform boots"}}
99
+ references = [{"source": "upload"}, {"basename": "reference.png"}]
100
+
101
+ run = build_command_center_run(
102
+ "gothic couture archivist",
103
+ creator_controls=controls,
104
+ reference_metadata=references,
105
+ )
106
+ controls["wardrobe"]["footwear"] = "mutated"
107
+ references[1]["basename"] = "mutated.png"
108
+
109
+ assert run.request.references == ["reference.png"]
110
+ assert run.request.creator_controls["wardrobe"]["footwear"] == "platform boots"
111
+ assert run.request.reference_metadata[1]["basename"] == "reference.png"
112
+
113
+
114
  def test_security_scan_does_not_return_payload_excerpt() -> None:
115
  sample = Path(__file__).parent / "fixtures" / "sample.png"
116
  scan = scan_file(str(sample))
 
763
  jewelry_slot = next((s for s in outfit.slots if s.name == "jewelry"), None)
764
 
765
  assert jewelry_slot is not None
766
+ assert jewelry_slot.material == "silver_occult_buckles"
767
 
768
 
769
  def test_build_outfit_graph_locked_slots_control_locks_named_slots() -> None:
tests/test_exporter.py CHANGED
@@ -1,4 +1,5 @@
1
  import json
 
2
  from pathlib import Path
3
 
4
  from nexus_visual_weaver.exporter import export_root, write_export_packet
@@ -73,6 +74,52 @@ def test_write_export_packet_records_evidence_without_secrets(monkeypatch) -> No
73
  assert "/data/" not in json.dumps(payload)
74
 
75
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
76
  def test_export_packet_has_correct_schema_version(monkeypatch) -> None:
77
  monkeypatch.setenv("NEXUS_EXPORT_DIR", "outputs/test-exports")
78
  run = build_command_center_run("dark couture brief")
 
1
  import json
2
+ from dataclasses import replace
3
  from pathlib import Path
4
 
5
  from nexus_visual_weaver.exporter import export_root, write_export_packet
 
74
  assert "/data/" not in json.dumps(payload)
75
 
76
 
77
+ def test_export_packet_sanitizes_run_id_before_writing(monkeypatch) -> None:
78
+ monkeypatch.setenv("NEXUS_EXPORT_DIR", "outputs/test-exports")
79
+ run = build_command_center_run("path traversal export brief")
80
+ run = replace(run, checkpoint=replace(run.checkpoint, checkpoint_id="../unsafe/path\\with:chars"))
81
+ scan = {"status": "pass", "export_gate": "clear"}
82
+
83
+ result = write_export_packet(run=run, scan=scan, operator_state=_make_base_state(), adult_mode=False)
84
+ path = Path(result["path"])
85
+ payload = json.loads(path.read_text(encoding="utf-8"))
86
+
87
+ assert path.parent == export_root()
88
+ assert ".." not in path.name
89
+ assert "\\" not in path.name
90
+ assert "/" not in path.name
91
+ assert payload["run_id"] == "unsafe-path-with-chars"
92
+
93
+
94
+ def test_export_packet_sanitizes_prompt_checkpoint_and_provider_state(monkeypatch) -> None:
95
+ monkeypatch.setenv("NEXUS_EXPORT_DIR", "outputs/test-exports")
96
+ run = build_command_center_run("prompt contains MINICPM_API_KEY and C:/Users/speci.000/secret.png")
97
+ run = replace(
98
+ run,
99
+ refined_prompt=replace(run.refined_prompt, refined="refined path /data/nexus_visual_weaver/secret.png"),
100
+ checkpoint=replace(
101
+ run.checkpoint,
102
+ recommendation="set NEMOTRON_API_KEY",
103
+ required_actions=["review C:/Users/speci.000/Downloads/raw.png"],
104
+ ),
105
+ )
106
+ scan = {"status": "pass", "export_gate": "clear"}
107
+ state = _make_base_state(
108
+ provider_state="Bearer " + "hidden-provider-token",
109
+ message="operator message with HF_TOKEN",
110
+ )
111
+
112
+ result = write_export_packet(run=run, scan=scan, operator_state=state, adult_mode=False)
113
+ serialized = json.dumps(json.loads(Path(result["path"]).read_text(encoding="utf-8")))
114
+
115
+ assert "MINICPM_API_KEY" not in serialized
116
+ assert "NEMOTRON_API_KEY" not in serialized
117
+ assert "HF_TOKEN" not in serialized
118
+ assert "C:/Users/speci.000" not in serialized
119
+ assert "/data/" not in serialized
120
+ assert "Bearer " + "hidden-provider-token" not in serialized
121
+
122
+
123
  def test_export_packet_has_correct_schema_version(monkeypatch) -> None:
124
  monkeypatch.setenv("NEXUS_EXPORT_DIR", "outputs/test-exports")
125
  run = build_command_center_run("dark couture brief")
tests/test_hf_runtime.py CHANGED
@@ -1,9 +1,13 @@
1
  from PIL import Image
 
 
2
 
 
3
  from nexus_visual_weaver.hf_runtime import (
4
  FLUX_REPO_ID,
5
  PRIVATE_RESEARCH_FLUX_REPO_ID,
6
  TINY_TITAN_FLUX_REPO_ID,
 
7
  _adapter_recipe,
8
  _repo_candidates,
9
  active_flux_repo_id,
@@ -14,6 +18,9 @@ from nexus_visual_weaver.hf_runtime import (
14
  from nexus_visual_weaver.render import render_artifact_lane
15
 
16
 
 
 
 
17
  def test_hf_runtime_is_disabled_locally_by_default(monkeypatch) -> None:
18
  monkeypatch.delenv("SPACE_ID", raising=False)
19
  monkeypatch.delenv("HF_SPACE_ID", raising=False)
@@ -209,3 +216,67 @@ def test_default_lora_repo_id_excludes_requires_image_adapters() -> None:
209
  recipe_result = _adapter_recipe(result)
210
  assert recipe_result is not None
211
  assert recipe_result.requires_image is False
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  from PIL import Image
2
+ from pathlib import Path
3
+ import types
4
 
5
+ import nexus_visual_weaver.hf_runtime as hf_runtime
6
  from nexus_visual_weaver.hf_runtime import (
7
  FLUX_REPO_ID,
8
  PRIVATE_RESEARCH_FLUX_REPO_ID,
9
  TINY_TITAN_FLUX_REPO_ID,
10
+ _PIPELINE_CACHE,
11
  _adapter_recipe,
12
  _repo_candidates,
13
  active_flux_repo_id,
 
18
  from nexus_visual_weaver.render import render_artifact_lane
19
 
20
 
21
+ RUNTIME_FIXTURE_DIR = Path("tests/fixtures/runtime")
22
+
23
+
24
  def test_hf_runtime_is_disabled_locally_by_default(monkeypatch) -> None:
25
  monkeypatch.delenv("SPACE_ID", raising=False)
26
  monkeypatch.delenv("HF_SPACE_ID", raising=False)
 
216
  recipe_result = _adapter_recipe(result)
217
  assert recipe_result is not None
218
  assert recipe_result.requires_image is False
219
+
220
+
221
+ def test_generate_flux_image_reports_sidecar_fallback(monkeypatch) -> None:
222
+ class FakeCuda:
223
+ @staticmethod
224
+ def is_available() -> bool:
225
+ return True
226
+
227
+ class FakeGenerator:
228
+ def __init__(self, device):
229
+ self.device = device
230
+
231
+ def manual_seed(self, seed):
232
+ self.seed = seed
233
+ return self
234
+
235
+ fake_torch = types.SimpleNamespace(cuda=FakeCuda(), bfloat16="bfloat16", Generator=FakeGenerator)
236
+
237
+ class FakePipeline:
238
+ @classmethod
239
+ def from_pretrained(cls, repo_id, torch_dtype=None, token=None):
240
+ if repo_id == FLUX_REPO_ID:
241
+ raise RuntimeError("primary denied")
242
+ return cls(repo_id)
243
+
244
+ def __init__(self, repo_id):
245
+ self.repo_id = repo_id
246
+
247
+ def enable_model_cpu_offload(self):
248
+ return None
249
+
250
+ def set_progress_bar_config(self, disable):
251
+ self.progress_disabled = disable
252
+
253
+ def __call__(self, **kwargs):
254
+ return types.SimpleNamespace(images=[Image.new("RGB", (8, 8), color=(2, 4, 6))])
255
+
256
+ fake_diffusers = types.SimpleNamespace(Flux2KleinPipeline=FakePipeline)
257
+ monkeypatch.setitem(__import__("sys").modules, "torch", fake_torch)
258
+ monkeypatch.setitem(__import__("sys").modules, "diffusers", fake_diffusers)
259
+ monkeypatch.setenv("NEXUS_ENABLE_REAL_HF", "1")
260
+ monkeypatch.delenv("NEXUS_DISABLE_REAL_HF", raising=False)
261
+ monkeypatch.delenv("NEXUS_DISABLE_TINY_TITAN_FALLBACK", raising=False)
262
+ output_dir = RUNTIME_FIXTURE_DIR / "hf-output"
263
+ output_dir.mkdir(parents=True, exist_ok=True)
264
+ monkeypatch.setenv("NEXUS_OUTPUT_DIR", str(output_dir))
265
+ monkeypatch.setattr(hf_runtime, "load_and_apply", lambda pipe, recipe, repo_id, adult_mode=False: {"status": "disabled", "repo_id": None, "message": "fake"})
266
+ monkeypatch.setattr(hf_runtime, "unload_all", lambda pipe: None)
267
+ _PIPELINE_CACHE.clear()
268
+
269
+ try:
270
+ result = generate_flux_image("prompt", seed=7)
271
+ finally:
272
+ for artifact in output_dir.glob("nexus_flux_*_7_*.png"):
273
+ artifact.unlink(missing_ok=True)
274
+
275
+ assert result.status == "success"
276
+ assert result.repo_id == TINY_TITAN_FLUX_REPO_ID
277
+ assert result.fallback_used is True
278
+ assert result.primary_error is not None
279
+ assert "primary denied" in result.primary_error
280
+ assert result.output_path is not None
281
+ assert Path(result.output_path).name.startswith("nexus_flux_")
282
+ assert "_7_" in Path(result.output_path).name
tests/test_lora_adapter.py CHANGED
@@ -36,6 +36,11 @@ class FailingLoraPipe(FakeLoraPipe):
36
  raise RuntimeError("adapter load failed")
37
 
38
 
 
 
 
 
 
39
  class UnsupportedPipe:
40
  pass
41
 
@@ -95,6 +100,21 @@ def test_load_and_apply_reports_failed_without_raising() -> None:
95
  assert "RuntimeError" in result["message"]
96
 
97
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
98
  def test_unload_all_uses_pipeline_unload_hook() -> None:
99
  pipe = FakeLoraPipe()
100
 
 
36
  raise RuntimeError("adapter load failed")
37
 
38
 
39
+ class FailingSetAdapterPipe(FakeLoraPipe):
40
+ def set_adapters(self, adapter_names: list[str], adapter_weights: list[float]) -> None:
41
+ raise RuntimeError("adapter apply failed")
42
+
43
+
44
  class UnsupportedPipe:
45
  pass
46
 
 
100
  assert "RuntimeError" in result["message"]
101
 
102
 
103
+ def test_load_and_apply_unloads_when_apply_fails() -> None:
104
+ recipe = AdapterRecipe(
105
+ repo_id="example/style-lora",
106
+ adapter_for="black-forest-labs/FLUX.2-klein-9B",
107
+ task="style",
108
+ )
109
+ pipe = FailingSetAdapterPipe()
110
+
111
+ result = load_and_apply(pipe, recipe, "black-forest-labs/FLUX.2-klein-9B")
112
+
113
+ assert result["status"] == "failed"
114
+ assert pipe.loaded == [("example/style-lora", {"adapter_name": "nexus_style"})]
115
+ assert pipe.unloaded is True
116
+
117
+
118
  def test_unload_all_uses_pipeline_unload_hook() -> None:
119
  pipe = FakeLoraPipe()
120
 
tests/test_model_relay.py CHANGED
@@ -201,6 +201,19 @@ def test_flux2_klein_9b_is_pinned_with_4b_sidecar_fallback() -> None:
201
  assert fallback.pinned is False
202
 
203
 
 
 
 
 
 
 
 
 
 
 
 
 
 
204
  def test_flux2_klein_9b_is_not_pinned_and_in_private_research() -> None:
205
  relay = WeaverModelRelay()
206
 
 
201
  assert fallback.pinned is False
202
 
203
 
204
+ def test_pinned_lane_fallbacks_respect_governance_filters() -> None:
205
+ relay = WeaverModelRelay()
206
+ fallback = relay.records["flux2-klein-4b-sidecar"]
207
+ fallback.health = "unhealthy"
208
+
209
+ decision = relay.select_lane("image_generation")
210
+
211
+ assert decision.primary is not None
212
+ assert decision.primary.model_id == "flux2-klein-9b-quality"
213
+ assert decision.fallbacks == []
214
+ assert any("flux2-klein-4b-sidecar: health=unhealthy" in reason for reason in decision.skipped)
215
+
216
+
217
  def test_flux2_klein_9b_is_not_pinned_and_in_private_research() -> None:
218
  relay = WeaverModelRelay()
219
 
tests/test_provider_runtime.py CHANGED
@@ -1,4 +1,5 @@
1
  from PIL import Image
 
2
 
3
  from nexus_visual_weaver.provider_runtime import (
4
  NEMOTRON_NANO_REPO_ID,
@@ -9,12 +10,21 @@ from nexus_visual_weaver.provider_runtime import (
9
  _image_data_url,
10
  _post_json,
11
  _safe_json_from_text,
 
12
  _short_error,
13
  judge_with_minicpm,
14
  judge_with_nemotron,
15
  )
16
 
17
 
 
 
 
 
 
 
 
 
18
  def test_minicpm_reports_missing_secret(monkeypatch) -> None:
19
  monkeypatch.delenv("MINICPM_BASE_URL", raising=False)
20
  monkeypatch.delenv("MINICPM_API_KEY", raising=False)
@@ -48,7 +58,7 @@ def test_minicpm_blocks_when_artifact_missing(monkeypatch) -> None:
48
 
49
 
50
  def test_minicpm_success_with_mocked_post(monkeypatch) -> None:
51
- image = "outputs/test-provider-artifact.png"
52
  Image.new("RGB", (8, 8), color=(12, 16, 20)).save(image)
53
  monkeypatch.setenv("MINICPM_BASE_URL", "http://example.test")
54
  monkeypatch.setenv("MINICPM_API_KEY", "test-token")
@@ -61,12 +71,15 @@ def test_minicpm_success_with_mocked_post(monkeypatch) -> None:
61
 
62
  monkeypatch.setattr("nexus_visual_weaver.provider_runtime._post_json", fake_post)
63
 
64
- result = judge_with_minicpm(
65
- prompt="gothic couture",
66
- image_path=image,
67
- scan={"export_gate": "clear"},
68
- wardrobe_summary="boots and lace",
69
- )
 
 
 
70
 
71
  assert result.status == "success"
72
  assert result.evidence["overall_status"] == "pass"
@@ -119,25 +132,52 @@ def test_image_data_url_returns_none_for_missing_file() -> None:
119
 
120
 
121
  def test_image_data_url_encodes_png_as_base64() -> None:
122
- image_path = "outputs/test-img-data-url.png"
123
  Image.new("RGB", (4, 4), color=(0, 0, 0)).save(image_path)
124
 
125
- result = _image_data_url(image_path)
 
 
 
126
 
127
  assert result is not None
128
  assert result.startswith("data:image/png;base64,")
129
 
130
 
131
  def test_image_data_url_uses_jpeg_mime_for_jpg() -> None:
132
- image_path = "outputs/test-img-data-url.jpg"
133
  Image.new("RGB", (4, 4), color=(0, 0, 0)).save(image_path)
134
 
135
- result = _image_data_url(image_path)
 
 
 
136
 
137
  assert result is not None
138
  assert result.startswith("data:image/jpeg;base64,")
139
 
140
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
141
  # --- _extract_content tests ---
142
 
143
  def test_extract_content_returns_string_from_choices() -> None:
@@ -263,7 +303,7 @@ def test_nemotron_failed_api_call_returns_failed_status(monkeypatch) -> None:
263
  def test_minicpm_failed_api_call_returns_failed_status(monkeypatch) -> None:
264
  import urllib.error
265
 
266
- image_path = "outputs/test-minicpm-fail.png"
267
  Image.new("RGB", (4, 4), color=(0, 0, 0)).save(image_path)
268
  monkeypatch.setenv("MINICPM_BASE_URL", "http://minicpm.test")
269
  monkeypatch.setenv("MINICPM_API_KEY", "test-token")
@@ -273,12 +313,15 @@ def test_minicpm_failed_api_call_returns_failed_status(monkeypatch) -> None:
273
 
274
  monkeypatch.setattr("nexus_visual_weaver.provider_runtime._post_json", fake_post)
275
 
276
- result = judge_with_minicpm(
277
- prompt="gothic couture",
278
- image_path=image_path,
279
- scan={"export_gate": "clear"},
280
- wardrobe_summary="platform boots",
281
- )
 
 
 
282
 
283
  assert result.status == "failed"
284
  assert result.provider_state == "failed"
@@ -321,7 +364,7 @@ def test_minicpm_uses_openbmb_api_key_as_fallback(monkeypatch) -> None:
321
  monkeypatch.delenv("MINICPM_API_KEY", raising=False)
322
  monkeypatch.setenv("OPENBMB_API_KEY", "openbmb-fallback-token")
323
 
324
- image_path = "outputs/test-openbmb-key.png"
325
  Image.new("RGB", (4, 4), color=(0, 0, 0)).save(image_path)
326
 
327
  captured = {}
@@ -332,12 +375,15 @@ def test_minicpm_uses_openbmb_api_key_as_fallback(monkeypatch) -> None:
332
 
333
  monkeypatch.setattr("nexus_visual_weaver.provider_runtime._post_json", fake_post)
334
 
335
- result = judge_with_minicpm(
336
- prompt="test",
337
- image_path=image_path,
338
- scan={},
339
- wardrobe_summary="",
340
- )
 
 
 
341
 
342
  assert result.status == "success"
343
  assert captured["token"] == "openbmb-fallback-token"
@@ -362,6 +408,47 @@ def test_nemotron_uses_nvidia_api_key_as_fallback(monkeypatch) -> None:
362
  assert captured["token"] == "nvidia-fallback-token"
363
 
364
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
365
  def test_post_json_rejects_unsupported_url_schemes_before_urlopen(monkeypatch) -> None:
366
  called = False
367
 
@@ -381,3 +468,44 @@ def test_post_json_rejects_unsupported_url_schemes_before_urlopen(monkeypatch) -
381
  raise AssertionError(f"{url} should have been rejected")
382
 
383
  assert called is False
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  from PIL import Image
2
+ from pathlib import Path
3
 
4
  from nexus_visual_weaver.provider_runtime import (
5
  NEMOTRON_NANO_REPO_ID,
 
10
  _image_data_url,
11
  _post_json,
12
  _safe_json_from_text,
13
+ _safe_provider_payload,
14
  _short_error,
15
  judge_with_minicpm,
16
  judge_with_nemotron,
17
  )
18
 
19
 
20
+ RUNTIME_FIXTURE_DIR = Path("tests/fixtures/runtime")
21
+
22
+
23
+ def _runtime_fixture_path(name: str) -> Path:
24
+ RUNTIME_FIXTURE_DIR.mkdir(parents=True, exist_ok=True)
25
+ return RUNTIME_FIXTURE_DIR / name
26
+
27
+
28
  def test_minicpm_reports_missing_secret(monkeypatch) -> None:
29
  monkeypatch.delenv("MINICPM_BASE_URL", raising=False)
30
  monkeypatch.delenv("MINICPM_API_KEY", raising=False)
 
58
 
59
 
60
  def test_minicpm_success_with_mocked_post(monkeypatch) -> None:
61
+ image = _runtime_fixture_path("test-provider-artifact.png")
62
  Image.new("RGB", (8, 8), color=(12, 16, 20)).save(image)
63
  monkeypatch.setenv("MINICPM_BASE_URL", "http://example.test")
64
  monkeypatch.setenv("MINICPM_API_KEY", "test-token")
 
71
 
72
  monkeypatch.setattr("nexus_visual_weaver.provider_runtime._post_json", fake_post)
73
 
74
+ try:
75
+ result = judge_with_minicpm(
76
+ prompt="gothic couture",
77
+ image_path=str(image),
78
+ scan={"export_gate": "clear"},
79
+ wardrobe_summary="boots and lace",
80
+ )
81
+ finally:
82
+ image.unlink(missing_ok=True)
83
 
84
  assert result.status == "success"
85
  assert result.evidence["overall_status"] == "pass"
 
132
 
133
 
134
  def test_image_data_url_encodes_png_as_base64() -> None:
135
+ image_path = _runtime_fixture_path("test-img-data-url.png")
136
  Image.new("RGB", (4, 4), color=(0, 0, 0)).save(image_path)
137
 
138
+ try:
139
+ result = _image_data_url(str(image_path))
140
+ finally:
141
+ image_path.unlink(missing_ok=True)
142
 
143
  assert result is not None
144
  assert result.startswith("data:image/png;base64,")
145
 
146
 
147
  def test_image_data_url_uses_jpeg_mime_for_jpg() -> None:
148
+ image_path = _runtime_fixture_path("test-img-data-url.jpg")
149
  Image.new("RGB", (4, 4), color=(0, 0, 0)).save(image_path)
150
 
151
+ try:
152
+ result = _image_data_url(str(image_path))
153
+ finally:
154
+ image_path.unlink(missing_ok=True)
155
 
156
  assert result is not None
157
  assert result.startswith("data:image/jpeg;base64,")
158
 
159
 
160
+ def test_image_data_url_rejects_unknown_suffix() -> None:
161
+ image_path = _runtime_fixture_path("not-an-image.txt")
162
+ image_path.write_text("not an image", encoding="utf-8")
163
+
164
+ try:
165
+ assert _image_data_url(str(image_path)) is None
166
+ finally:
167
+ image_path.unlink(missing_ok=True)
168
+
169
+
170
+ def test_image_data_url_rejects_oversized_file(monkeypatch) -> None:
171
+ image_path = _runtime_fixture_path("large.png")
172
+ image_path.write_bytes(b"not actually decoded because size fails")
173
+ monkeypatch.setattr("nexus_visual_weaver.provider_runtime.MAX_PROVIDER_IMAGE_BYTES", 4)
174
+
175
+ try:
176
+ assert _image_data_url(str(image_path)) is None
177
+ finally:
178
+ image_path.unlink(missing_ok=True)
179
+
180
+
181
  # --- _extract_content tests ---
182
 
183
  def test_extract_content_returns_string_from_choices() -> None:
 
303
  def test_minicpm_failed_api_call_returns_failed_status(monkeypatch) -> None:
304
  import urllib.error
305
 
306
+ image_path = _runtime_fixture_path("test-minicpm-fail.png")
307
  Image.new("RGB", (4, 4), color=(0, 0, 0)).save(image_path)
308
  monkeypatch.setenv("MINICPM_BASE_URL", "http://minicpm.test")
309
  monkeypatch.setenv("MINICPM_API_KEY", "test-token")
 
313
 
314
  monkeypatch.setattr("nexus_visual_weaver.provider_runtime._post_json", fake_post)
315
 
316
+ try:
317
+ result = judge_with_minicpm(
318
+ prompt="gothic couture",
319
+ image_path=str(image_path),
320
+ scan={"export_gate": "clear"},
321
+ wardrobe_summary="platform boots",
322
+ )
323
+ finally:
324
+ image_path.unlink(missing_ok=True)
325
 
326
  assert result.status == "failed"
327
  assert result.provider_state == "failed"
 
364
  monkeypatch.delenv("MINICPM_API_KEY", raising=False)
365
  monkeypatch.setenv("OPENBMB_API_KEY", "openbmb-fallback-token")
366
 
367
+ image_path = _runtime_fixture_path("test-openbmb-key.png")
368
  Image.new("RGB", (4, 4), color=(0, 0, 0)).save(image_path)
369
 
370
  captured = {}
 
375
 
376
  monkeypatch.setattr("nexus_visual_weaver.provider_runtime._post_json", fake_post)
377
 
378
+ try:
379
+ result = judge_with_minicpm(
380
+ prompt="test",
381
+ image_path=str(image_path),
382
+ scan={},
383
+ wardrobe_summary="",
384
+ )
385
+ finally:
386
+ image_path.unlink(missing_ok=True)
387
 
388
  assert result.status == "success"
389
  assert captured["token"] == "openbmb-fallback-token"
 
408
  assert captured["token"] == "nvidia-fallback-token"
409
 
410
 
411
+ def test_safe_provider_payload_redacts_sensitive_nested_keys() -> None:
412
+ result = _safe_provider_payload(
413
+ {
414
+ "checkpoint": "ok",
415
+ "HF_TOKEN": "should-not-leak",
416
+ "nested": {"raw_payload": "hidden", "items": [{"base64_image": "hidden"}, {"safe": "visible"}]},
417
+ }
418
+ )
419
+
420
+ assert result["checkpoint"] == "ok"
421
+ assert result["HF_TOKEN"] == "[redacted]"
422
+ assert result["nested"]["raw_payload"] == "[redacted]"
423
+ assert result["nested"]["items"][0]["base64_image"] == "[redacted]"
424
+ assert result["nested"]["items"][1]["safe"] == "visible"
425
+
426
+
427
+ def test_nemotron_redacts_run_packet_before_provider_call(monkeypatch) -> None:
428
+ monkeypatch.setenv("NEMOTRON_BASE_URL", "http://localhost:8001")
429
+ monkeypatch.setenv("NEMOTRON_API_KEY", "nvidia-token")
430
+ captured = {}
431
+
432
+ def fake_post(url, token, payload, timeout):
433
+ captured["content"] = payload["messages"][0]["content"]
434
+ return {"choices": [{"message": {"content": '{"final_claim_status":"pass"}'}}]}
435
+
436
+ monkeypatch.setattr("nexus_visual_weaver.provider_runtime._post_json", fake_post)
437
+
438
+ result = judge_with_nemotron(
439
+ prompt="brief",
440
+ run_packet={"safe": "visible", "api_key": "hidden-key", "nested": {"payload_bytes": "hidden-bytes"}},
441
+ minicpm_result={"status": "success", "authorization": "hidden-auth"},
442
+ )
443
+
444
+ assert result.status == "success"
445
+ assert "visible" in captured["content"]
446
+ assert "hidden-key" not in captured["content"]
447
+ assert "hidden-bytes" not in captured["content"]
448
+ assert "hidden-auth" not in captured["content"]
449
+ assert "[redacted]" in captured["content"]
450
+
451
+
452
  def test_post_json_rejects_unsupported_url_schemes_before_urlopen(monkeypatch) -> None:
453
  called = False
454
 
 
468
  raise AssertionError(f"{url} should have been rejected")
469
 
470
  assert called is False
471
+
472
+
473
+ def test_post_json_rejects_plain_http_non_loopback_before_urlopen(monkeypatch) -> None:
474
+ called = False
475
+
476
+ def fake_urlopen(*args, **kwargs):
477
+ nonlocal called
478
+ called = True
479
+ raise AssertionError("urlopen should not be called for plaintext remote provider URLs")
480
+
481
+ monkeypatch.setattr("urllib.request.urlopen", fake_urlopen)
482
+
483
+ try:
484
+ _post_json("http://example.test/v1/chat/completions", "token", {"ok": True}, 1.0)
485
+ except ValueError as exc:
486
+ assert "HTTPS" in str(exc)
487
+ assert "loopback" in str(exc)
488
+ else:
489
+ raise AssertionError("remote http provider URL should have been rejected")
490
+
491
+ assert called is False
492
+
493
+
494
+ def test_post_json_allows_loopback_http_for_local_tests(monkeypatch) -> None:
495
+ class FakeResponse:
496
+ def __enter__(self):
497
+ return self
498
+
499
+ def __exit__(self, exc_type, exc, tb):
500
+ return False
501
+
502
+ def read(self):
503
+ return b'{"ok": true}'
504
+
505
+ def fake_urlopen(request, timeout):
506
+ assert request.full_url == "http://127.0.0.1:8000/v1/chat/completions"
507
+ return FakeResponse()
508
+
509
+ monkeypatch.setattr("urllib.request.urlopen", fake_urlopen)
510
+
511
+ assert _post_json("http://127.0.0.1:8000/v1/chat/completions", "token", {"ok": True}, 1.0) == {"ok": True}