OUTPUT #739 | 14885 karakter | 341 satır
========== YENİ KOMUT | 17.09.2026 20:06:12 ==========


========== YENİ KOMUT | 17.09.2026 20:06:12 ==========

/home/hermes/.hermes/skills/media/shorts-core/SKILL.md
187-### ASSET-001 — Pre-casting visual inspection diagnostic
188-
189-Bu tanı koşusunda asset/casting kararını yalnız metadata, dosya adı veya arama açıklamasından verme.
190:Gerekli olduğunda aday gerçek footage/source/range/assetleri `vision_analyze` ile gerçekten gör.
191-
192-Değerlendir:
193-- gerçek hareket ve görüntü kalitesi;
--
231-
232-### Faz 3 — Tek görsel QA geçidi
233-
234:Deterministic pipeline PASS verdikten sonra yalnız final contact sheet'i `vision_analyze` ile değerlendir.
235-
236-Kontrol et:
237-

/home/hermes/.hermes/plugins/shorts-production-guard/__init__.py
226-            return target
227-    if tool_name == "terminal":
228-        low = str(args.get("command") or "").lower()
229:        # Normal preflight/proof-check/segment-build/pipeline runs are the public
230-        # interface and remain available. Introspection is rediscovery.
231-        if any(marker in low for marker in ("--help", "grep ", "rg ", "cat ", "sed ", "python -c")):
232-            return target
--
246-        return _block(
247-            "Shorts production guard: normal production must use the documented interface "
248-            f"instead of re-reading {target} to rediscover schema. Run the canonical "
249:            "preflight/proof-check/pipeline command. Source and tests remain readable in an "
250-            "explicit engineering/system-change task."
251-        )
252-    _CANONICAL_READS.add(key)
--
256-    return {"action": "block", "message": message}
257-
258-
259:def _runtime_proof_fingerprint(data: dict) -> str:
260:    """Mirror the canonical proof fingerprint so accepted proof can be frozen at runtime."""
261-    creative = data.get("creative_intent") or {}
262:    gate = data.get("proof_gate") or {}
263-    candidates = gate.get("candidates") or []
264-
265-    normalized = []
--
327-    payload = {
328-        "creative_intent": {
329-            "promise": creative.get("promise"),
330:            "primary_visual_proof": creative.get("primary_visual_proof"),
331-            "hook_visual_goal": creative.get("hook_visual_goal"),
332-            "payoff": creative.get("payoff"),
333-        },
334:        "proof_gate": {
335-            "mode": gate.get("mode"),
336-            "candidates": normalized,
337-        },
--
342-    ).hexdigest()
343-
344-
345:def _proof_freeze_block(tool_name: str, args: dict) -> Optional[dict]:
346:    """After a valid proof PASS, prevent edits that invalidate the accepted proof."""
347-    if tool_name not in {"patch", "write_file", "execute_code"}:
348-        return None
349-
--
355-            for marker in ("write_file(", "write_text(", ".write(", "json.dump(", "open(")
356-        ):
357-            return _block(
358:                "Shorts production guard: PROOF_FREEZE — do not mutate manifest.json through "
359:                "execute_code after an accepted proof. Use patch/write_file instead so the runtime "
360:                "can compare the prospective proof fingerprint and allow proof-irrelevant edits "
361:                "while blocking changes to accepted creative proof/casting."
362-            )
363-        return None
364-
--
375-    try:
376-        current_text = path.read_text(encoding="utf-8")
377-        current = json.loads(current_text)
378:        gate = current.get("proof_gate") or {}
379-        receipt_value = gate.get("receipt")
380-        receipt = (
381-            Path(str(receipt_value)).expanduser().resolve()
382-            if receipt_value
383:            else (path.parent / "proof_gate" / "proof_receipt.json").resolve()
384-        )
385-        if not receipt.exists():
386-            return None
--
388-        if accepted.get("pass") is not True:
389-            return None
390-
391:        current_fp = _runtime_proof_fingerprint(current)
392-        if accepted.get("fingerprint") != current_fp:
393-            # Already stale: do not create a new policy trap here.
394-            return None
--
412-            )
413-
414-        prospective = json.loads(prospective_text)
415:        if _runtime_proof_fingerprint(prospective) != current_fp:
416-            return _block(
417:                "Shorts production guard: PROOF_FREEZE — accepted proof is locked. "
418:                "Do not change creative_intent, proof candidates, or selected footage/casting "
419-                "after Vision PASS. Continue with TTS/render/final QA using the accepted plan. "
420:                "A genuine proof failure must be handled before acceptance, not by reopening "
421:                "the proof loop after PASS."
422-            )
423-    except Exception:
424-        return None
425-    return None
426-
427-
428:def _proof_attempt_state_path(image_path: Path, pending: Optional[dict] = None) -> Path:
429:    """Use one attempt ledger per canonical proof receipt, not per proofN workdir."""
430-    if isinstance(pending, dict):
431-        receipt = pending.get("receipt")
432-        if isinstance(receipt, str) and receipt.strip():
433-            try:
434:                return Path(receipt).expanduser().resolve().parent / "proof_attempt_state.json"
435-            except Exception:
436-                pass
437:    return image_path.parent / "proof_attempt_state.json"
438-
439-
440:def _read_proof_attempt_state(image_path: Path, pending: Optional[dict] = None) -> dict:
441:    path = _proof_attempt_state_path(image_path, pending)
442-    try:
443-        if path.exists():
444-            value = json.loads(path.read_text(encoding="utf-8"))
--
448-    return {}
449-
450-
451:def _write_proof_attempt_state(
452-    image_path: Path, state: dict, pending: Optional[dict] = None
453-) -> None:
454-    try:
455:        path = _proof_attempt_state_path(image_path, pending)
456-        path.parent.mkdir(parents=True, exist_ok=True)
457-        tmp = path.with_suffix(path.suffix + ".tmp")
458-        tmp.write_text(json.dumps(state, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
--
464-def _direct_render_bypass(tool_name: str, args: dict) -> bool:
465-    """Block manual TTS/final assembly during normal Shorts production.
466-
467:    Asset inspection, proof generation and deterministic QA remain available.
468-    Final production must go through the canonical shorts_fast_pipeline.
469-    """
470-    if tool_name == "terminal":
--
535-    return None
536-
537-
538:def _normalized_proof_token(value: Any) -> str:
539-    """Accept the harmless exact-prefix variation repeatedly emitted by Vision."""
540-    token = str(value or "").strip()
541-    prefix = "HERMES_PROOF_GATE::"
542-    return token[len(prefix):] if token.startswith(prefix) else token
543-
544-
545:def _proof_verdict_accepted(verdict: Any, token: str) -> bool:
546:    """Accept proof only when every selected footage role is unambiguous."""
547-    return bool(
548-        isinstance(verdict, dict)
549-        and verdict.get("verdict") == "PASS"
550:        and verdict.get("verifier") == "vision_analyze"
551:        and verdict.get("primary_visual_proof") is True
552-        and verdict.get("hook_visual_goal") is True
553:        and verdict.get("proof_visible_and_unmistakable") is True
554-        and verdict.get("casting_subjects_clear") is True
555:        and _normalized_proof_token(verdict.get("proof_token")) == token
556-    )
557-
558-
--
602-        if rediscovery_block:
603-            return rediscovery_block
604-
605:        freeze_block = _proof_freeze_block(tool_name, args)
606-        if freeze_block:
607-            return freeze_block
608-
609-    if not alternate_method and not explicit_system_change and _direct_render_bypass(tool_name, args):
610-        return _block(
611-            "Shorts production guard: direct TTS/final assembly outside the canonical pipeline "
612:            "is blocked during normal production. Use shorts_fast_pipeline.py. If proof Vision "
613:            "cannot issue a valid receipt, stop with QA_UNAVAILABLE; do not build a fallback final."
614-        )
615-
616-    # Explicitly requested alternate/code-driven workflows remain available.
--
629-    if tool_name in {"browser_vision", "computer_use"} and not alternate_method:
630-        return _block(
631-            "Shorts production guard: this QA fallback is disabled during normal production. "
632:            "Use vision_analyze as the primary visual QA path; if Vision is unavailable after "
633:            "the permitted retry, continue with controlled QA_UNAVAILABLE rather than inventing a fallback."
634-        )
635-
636:    if tool_name == "vision_analyze":
637-        image_url = str(args.get("image_url") or "")
638-        question = str(args.get("question") or "").strip()
639-        raw = image_url[7:] if image_url.startswith("file://") else image_url
--
645-        # Use visual inspection only when it helps choose footage that actually fulfills
646-        # the creative contract. Existing duplicate/no-progress and other guards remain active.
647-
648:        if image_path.name == "proof_contact_sheet.jpg":
649:            pending_path = image_path.parent / "proof_pending.json"
650-            current_fingerprint = None
651-            pending = {}
652-            try:
--
655-                    current_fingerprint = pending.get("fingerprint")
656-            except Exception:
657-                pending = {}
658:            proof_state = _read_proof_attempt_state(image_path, pending)
659-
660-            if (
661:                int(proof_state.get("failed_attempts") or 0) >= 2
662-                and current_fingerprint
663:                and proof_state.get("last_fingerprint") == current_fingerprint
664-            ):
665-                return _block(
666:                    "Shorts production guard: PROOF_STRATEGY_EXHAUSTED — this proof strategy "
667-                    "already failed initial review plus one repair. Do not retry Vision on the "
668:                    "same accepted candidates/casting. Materially change the proof footage or "
669:                    "casting, rerun proof-check, and continue the production autonomously."
670-                )
671-
672-        # Content identity matters more than filename: a repaired final_contact_sheet
--
712-                or args.get("file_path")
713-                or ""
714-            )
715:            if path.endswith("proof_receipt.json") or path.endswith("proof_pending.json"):
716-                return _block(
717:                    "Shorts production guard: proof state is runtime-owned. "
718:                    "Do not write or patch proof receipts/pending attestations manually; "
719:                    "only a real vision_analyze PASS may issue the receipt."
720-                )
721-            if any(path.startswith(prefix) for prefix in _PROTECTED_PREFIXES):
722-                return _block(
--
727-        if tool_name == "terminal":
728-            cmd = str(args.get("command") or "")
729-            low = cmd.lower()
730:            if "proof_receipt.json" in low or "proof_pending.json" in low:
731-                return _block(
732:                    "Shorts production guard: proof state is runtime-owned. "
733:                    "Do not create, edit, copy, delete, or inspect proof receipt/pending files "
734-                    "through terminal commands during production."
735-                )
736-            if (
--
814-    else:
815-        accepted = (
816-            verdict.get("verdict") == "PASS"
817:            and verdict.get("verifier") == "vision_analyze"
818:            and verdict.get("post_repair_semantic_verified") is True
819:            and _normalized_proof_token(verdict.get("repair_token")) == token
820-        )
821-        failed = verdict.get("verdict") == "FAIL"
822-        state["state"] = "verified" if accepted else ("failed" if failed else "unverified")
823-        state["verification_pending"] = False
824-        state["claim_fixed_allowed"] = accepted
825-        state["verification"] = {
826:            "verifier": "vision_analyze",
827-            "verdict": verdict.get("verdict"),
828-            "artifact_sha256": state.get("artifact_sha256"),
829-            "contact_sheet_sha256": state.get("contact_sheet_sha256"),
--
852-    status: str = "",
853-    **_: Any,
854-) -> None:
855:    if tool_name != "vision_analyze":
856-        return
857-
858-    active, _, _ = _production_context(session_id)
--
896-        image_path, contract_question, result, session_id, turn_id, tool_call_id
897-    )
898-
899:    if image_path.name != "proof_contact_sheet.jpg":
900-        return
901-
902:    pending_path = image_path.parent / "proof_pending.json"
903-    if not pending_path.exists():
904-        return
905-
--
908-    except Exception:
909-        return
910-
911:    token = str(pending.get("proof_token") or "")
912-    if not token or f"HERMES_PROOF_GATE::{token}" not in contract_question:
913-        return
914-
--
929-    if not verdict:
930-        return
931-
932:    accepted = _proof_verdict_accepted(verdict, token)
933-    if not accepted:
934-        if verdict.get("verdict") == "FAIL":
935:            state = _read_proof_attempt_state(image_path, pending)
936-            fingerprint = pending.get("fingerprint")
937-            if state.get("last_fingerprint") != fingerprint:
938-                state["failed_attempts"] = 0
--
940-            state["last_verdict"] = "FAIL"
941-            state["last_fingerprint"] = fingerprint
942-            state["updated_at"] = time.time()
943:            _write_proof_attempt_state(image_path, state, pending)
944-        return
945-
946:    state = _read_proof_attempt_state(image_path, pending)
947-    state["accepted"] = True
948-    state["last_verdict"] = "PASS"
949-    state["last_fingerprint"] = pending.get("fingerprint")
950-    state["updated_at"] = time.time()
951:    _write_proof_attempt_state(image_path, state, pending)
952-
953-    try:
954-        receipt = Path(str(pending["receipt"])).expanduser().resolve()
--
956-        obj = {
957-            "pass": True,
958-            "receipt_source": "shorts-production-guard/post_tool_call",
959:            "verifier": "vision_analyze",
960-            "fingerprint": pending["fingerprint"],
961-            "contact_sheet": str(image_path),
962-            "contact_sheet_sha256": pending["contact_sheet_sha256"],
root@213-238-170-219:~#