OUTPUT #742 | 19159 karakter | 431 satır
========== YENİ KOMUT | 17.09.2026 20:19:46 ==========
========== YENİ KOMUT | 17.09.2026 20:19:46 ==========
/home/hermes/.hermes/skills/media/shorts-core/SKILL.md
186-
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;
194-- shot'ın anlatısal işlevini gerçekten kanıtlayıp kanıtlamadığı;
--
230-Helper için geçici tek-seferlik bbox scripti, yeni Python ortamı veya yeniden keşfedilmiş FFmpeg/Montaj yolları oluşturma. Helper teknik olarak başarısız olursa yalnız hatalı bileşeni teşhis et.
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-
238-- gerçek 9:16 tam ekran;
/home/hermes/.hermes/plugins/shorts-production-guard/__init__.py
225- if any(marker in low for marker in ("importlib", "open(", "read_text", "read_file", "spec_from_file")):
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
233- return None
--
245- if target in _CANONICAL_IMPLEMENTATION_NAMES or key in _CANONICAL_READS:
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)
253- return None
--
255-def _block(message: str) -> dict[str, str]:
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 = []
266- for c in candidates:
--
326-
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- },
338- "selected_casting": selected_casting,
--
341- json.dumps(payload, sort_keys=True, ensure_ascii=False).encode("utf-8")
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-
350- if tool_name == "execute_code":
--
354- marker in low
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-
365- raw_path = str(args.get("path") or args.get("file_path") or "")
--
374-
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
387- accepted = json.loads(receipt.read_text(encoding="utf-8"))
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
395-
--
411- else current_text.replace(old, new, 1)
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"))
445- return value if isinstance(value, dict) else {}
--
447- pass
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")
459- tmp.replace(path)
--
463-
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":
471- cmd = str(args.get("command") or "")
--
534- continue
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-
559-def _on_pre_tool_call(
--
601- rediscovery_block = _canonical_rediscovery_block(tool_name, args, session_id)
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.
--
628- # Only exact no-progress repetition of the same visual evidence + question is blocked.
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
640- image_path = Path(raw).expanduser()
--
644- # No artificial Vision-call cap and no mandatory batching in this diagnostic.
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:
653- if pending_path.exists():
654- pending = json.loads(pending_path.read_text(encoding="utf-8"))
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
673- # at the same path is new evidence and must be allowed to be judged again.
674- try:
675- image_identity = _sha_file(image_path.resolve())
676- except Exception:
--
691- with _LOCK:
692- if signature in _VISION_SEEN:
693- return _block(
694- "Shorts production guard: this exact visual evidence has already been "
695: "asked the same question. Reuse the existing result. If evidence was repaired "
696- "or the verification question genuinely needs correction, change the evidence "
697- "or question rather than repeating the same call."
698- )
699- return None
--
711- args.get("path")
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(
723- "Shorts production guard: production-time mutation of Hermes core/tools/skills "
--
726-
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 (
737- _INSTALL_RE.search(cmd)
--
774- except Exception:
775- return text
776-
777-
778:def _update_repair_state_from_vision(
779- image_path: Path,
780- question: str,
781- result: Any,
782- session_id: str,
--
784- tool_call_id: str,
785-) -> None:
786- if image_path.name != "final_contact_sheet.jpg":
787- return
788: state_path = image_path.parent / "repair_state.json"
789- if not state_path.exists():
790- return
791- try:
792- state = json.loads(state_path.read_text(encoding="utf-8"))
793- except Exception:
794- return
795: if state.get("state") not in {"repair_attempted", "verification_pending"}:
796- return
797: token = str(state.get("repair_token") or "")
798- if not token or f"HERMES_REPAIR_VERIFY::{token}" not in question:
799- return
800- try:
801- if _sha_file(image_path) != state.get("contact_sheet_sha256"):
--
813- state["claim_fixed_allowed"] = False
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"),
830- "session_id": session_id,
--
851- tool_call_id: str = "",
852- status: str = "",
853- **_: Any,
854-) -> None:
855: if tool_name != "vision_analyze":
856- return
857-
858- active, _, _ = _production_context(session_id)
859- if not active:
--
891- except Exception:
892- return
893-
894- contract_question = _expanded_vision_question_for_receipt(image_path, question)
895: _update_repair_state_from_vision(
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-
906- try:
907- pending = json.loads(pending_path.read_text(encoding="utf-8"))
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-
915- try:
--
928- verdict = _json_object(outer.get("analysis"))
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
939- state["failed_attempts"] = int(state.get("failed_attempts") or 0) + 1
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()
955- receipt.parent.mkdir(parents=True, exist_ok=True)
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"],
963- "verdict": verdict,
root@213-238-170-219:~#