Skip to content

Skill optimization pass: routing, fail-closed gates, colour pipeline, memory integrity and canonical backport - #26

Draft
Hao0321 wants to merge 26 commits into
mainfrom
feat/skill-optimization-audit
Draft

Hao0321 wants to merge 26 commits into
mainfrom
feat/skill-optimization-audit

Conversation

@Hao0321

@Hao0321 Hao0321 commented Oct 6, 2026

Copy link
Copy Markdown
Owner

目標與任務

相關 Issue:無(維護者直接要求的全面檢查與優化)

這個 PR 要解決什麼問題?
全面檢查 Video Autopilot Kit 的架構、視覺、美感、品質、規則與記憶。稽核找到多個「看起來綠、其實沒擋」的閘門、色彩矩陣錯誤、記憶可被重複計分或寫壞,以及文件與程式互相矛盾的規則。這個 PR 修正它們,並新增 scripts/canonical_backport.py,讓這些公開修改能先回寫到私有 canonical,再由 sync_canonical.py 正常同步。

變更範圍

  • Skill 路由:公開 SKILL.md 依任務路由全部 56 份 references(大檔只讀指定章節),每次任務先讀 creator 記憶與 context packet,並定義完成標準。觸發描述加入中文需求詞。agent card 不再預設提供遠端審片連結。

  • 回寫工具:canonical_backport.py 逐個 first-parent commit 重播並做三方合併,保留 BOM 與換行。公開版專用的改寫不寫回;--apply 失敗會整批還原;重跑結果是 ALREADY_APPLIED。另新增指令入口 scripts/hao_autopilot.py。

  • 審片完整性:審片以 HMAC 綁定成片 sha256,拒絕自我認證。缺證據是明確的 REVIEW 缺口;NaN、布林與文字評分不計分。只有 CERTIFIED_95 算已認證或可發布。

  • 閘門 fail-closed

    • 訪談來源必須標類型;共用佔位字偵測。
    • 合規章要有日期與複核人。
    • 片長必須是有限正數。
    • proof 圖以實際路徑或 hash 比對。
    • 對標合約凍結 hash。
    • gate_core 缺 fails 或零條檢查一律紅。
  • 媒體 QA:WCAG 閃光、長黑段、全片 letterbox、Shorts true peak ≤ -1 dBTP、缺音軌或影軌、-inf 響度與特殊字元檔名,都會判為失敗或 UNVERIFIED。三態結果中,任何非 PASS 都擋交付。

  • Workflow controller:resume --reaudit 處理過期或已用過的 audit receipt。state lock 改用 owner token,且只回收已死的持有者。plan 在 audit、apply 與 verify 時重新驗證。

  • 記憶與學習

    • 成效 baseline 依平台、片型與窗口分開計算,排除早、晚與重複的擷取。
    • taste 至少要 5 次不同比較,再加 95% Wilson 信賴區間判斷偏好。
    • channel state 鎖定並原子寫入。
    • 學到的規則存在 data/knowledge_state.json,更新不會覆蓋。
  • 色彩與特效:RGB 濾鏡以明確的 BT.709 轉換包住。identity LUT 的 PSNR 從 29.5 dB 提升到約 70 dB。HDR normaliser 統一為 npl=100。bloom、掃描線、halftone、whip 與 Ken Burns 的數學錯誤已修正。

  • 更新器:中斷的更新會自動回滾(INTERRUPTED_TRANSACTION_RECOVERED/INTERRUPTED_TRANSACTION),並加上安裝鎖(LOCKED)。Windows 更新後改用子行程重啟;壓縮檔順序在各 OS 一致。

  • 文件與規則:對齊程式的項目:

    • 調色順序與 LUT 強度
    • 本機審片 serve
    • 教學片節奏(以 pace_gate 為界)
    • 母帶響度 -14 LUFS/-1 dBTP
    • Signal Grid 改列為 legacy
    • voice 規則
    • 縮圖測試
    • 公開 DNA 數量

    另外,script_gate.load_vocab() 恢復可用。公開文件的審片人改用角色稱呼「創作者」(同步規則,canonical 保留原文)。

  • 健康檢查:system_health --quick 新增各閘門、記憶、回寫工具、媒體 QA 與範例 02/04/05/06 的 self-test,並偵測 Python 3.9 import 時會崩潰的 X | Y 型別註記。

相容性影響(呼叫端要注意):

  • gate_core.make_assert 遇到沒有 fails 的 report 會 raise。
  • 訪談 plan 要先填真的 CLUSTER。
  • examples/PLAN_TEMPLATE.md 原樣會被擋,這是刻意的。
  • Shorts 交付必須 30/1 fps;loop 為 required 時,首末幀相關係數要 ≥ 0.6。
  • due_report 改回傳 actions_by_owner;outcome playbook 升到 schema 2。
  • LUT 相關函式回傳完整的 BT.709 chain。
  • 舊 pipeline.py 的 HDR 輸出會變亮(npl 250→100)。

AI 協助範圍:全部由 Claude Code 產生。七個修補包在隔離 worktree 由子代理完成;主代理逐一審 diff、cherry-pick,並重跑回歸測試。

驗證證據

環境:Linux、Python 3.12.3 與 3.9.25、ffmpeg 6.1.1。在乾淨匯出的樹上執行 CI 的全部步驟。為了模擬維護者同步後的狀態,匯出樹內的 receipt 只在暫存區刷新,沒有提交。

檢查 3.12 3.9
py_compile、public_skill_skeleton.py、sanitizer self-test(68 managed outputs) ✅ ✅
public_privacy_gate.py --self-test ✅ GREEN ✅ GREEN
sync_canonical.py --self-test(含 reviewer role transform) ✅ ✅
check_links / check_drift ✅ PASS ✅ PASS
architecture_gate.py audit ✅ GREEN(fail 0;review 55→51) ✅
system_health.py --quick ✅ HEALTH GREEN ✅ HEALTH GREEN
來源樹不被改動 ✅ ✅
release_manager.py selftest ✅(94 s) ✅(94 s)
  • canonical 模擬:用 b449e7a 公開樹建立的擬 canonical 執行回寫。dry run 沒有 CONFLICT/ERROR;--apply 寫入 48 檔,重跑全部 ALREADY_APPLIED。只做改寫的檔案全部 ALREADY_APPLIED,canonical 保留原文。
  • 私有樣式模擬:visual_director.py 與 channel_tracker.py 的私有樣式模擬,合併乾淨,重新同步後與公開檔逐 byte 相同。
  • 各修補包:都在 3.12 與 3.9 跑過自己的 self-test 與 probe(修前重現、修後通過)。色彩 PSNR 與 WCAG 閃光等前後數據已記錄在各 commit 訊息與工作紀錄。

預期中的紅燈:這個 PR 改了 derived 檔,sync-receipt.json 的 output hash 會不一致。依 CONTRIBUTING,receipt 不手動修改,要等維護者回寫 canonical 並同步後重新產生。在那之前,CI 的 Quick health 與 reproducible-release 的 --verify-receipt 會紅。

未驗證:

  • Windows/macOS 實機(交給 CI matrix)。
  • 真實素材的成片視覺。
  • 私有 canonical 的實際合併結果(需要維護者本機)。
  • 範例 01/03(需要渲染)在本 PR 最終版尚未重跑。

安全、隱私與依賴

  • 我已閱讀 diff,沒有私人資料、媒體、憑證或可存取的審片連結。
  • 我有權以本專案 MIT 授權提供這些變更;第三方內容保留來源與授權。
  • 本次涉及安裝/更新、外部指令、網路、依賴、workflow、發布、隱私或授權。

若勾選最後一項,說明目的、輸入來源、權限、風險與對應驗證:

  • 更新器(release_manager.py、startup_update.py、install_or_upgrade.py)
    • 中斷回滾與安裝鎖只在安裝根目錄的 .video-autopilot/ 內寫檔。
    • 只有在恰好一筆 PENDING、而且受管檔符合新舊其中一版時,才會自動回滾;其他情況回報 INTERRUPTED_TRANSACTION,交由人工處理。
    • 錯誤訊息若含絕對路徑,只回報錯誤型別。
    • 驗證:release self-test 新增 8 個階段,包含實際 kill 子行程。
  • 外部指令:新增的 ffmpeg 呼叫都是本機分析或轉檔,沒有網路。canonical_backport.py 只呼叫本機 git,寫入前會備份。
  • 隱私:新的公開同步規則只改寫公開版文字。沒有新依賴,也沒有改 workflow 檔。

驗收與回復方式

驗收(維護者本機):

git fetch origin; git checkout feat/skill-optimization-audit
python scripts/canonical_backport.py --canonical "$env:USERPROFILE\.codex\skills\video-autopilot" --workspace <公開 kit 資料夾的上一層> --base b449e7a
python scripts/canonical_backport.py --canonical "$env:USERPROFILE\.codex\skills\video-autopilot" --workspace <同上> --base b449e7a --apply
python scripts/sync_canonical.py --canonical "$env:USERPROFILE\.codex\skills\video-autopilot"
git status   # 應只剩 sync-receipt.json;提交並推上這個分支後 CI 應轉綠
  • 私有 SKILL.md 不會自動回寫。--apply 會在備份資料夾輸出 SKILL.public-delta.diff,需要手動合併。
  • 合併請用 merge commit(不要 squash),保留逐 commit 重播資訊。

已知限制與後續:

  • audit.config.json 有 5 個架構例外在 2026-12-31 到期,2027-01-01 起 CI 會紅,需要重構或延期決定。
  • loop 相關係數門檻 0.6 尚未用真片校準。
  • color_calibration_lab._sample_image 擷取幀時仍未指定色彩矩陣。

回復:

  • 公開 repo:revert merge commit。
  • canonical:--apply 前的原檔在 .video-autopilot/backport/<時間>/,失敗時工具已自動還原。

共同貢獻

Claude Code(AI):稽核、實作、測試與文件。維護者審查待進行。

🤖 Generated with Claude Code

https://claude.ai/code/session_01XLikBpKWqhMahFDuvVj6wh


Generated by Claude Code

claude added 26 commits October 6, 2026 06:28
- scripts/canonical_backport.py (+ self-test): plan public-to-canonical
  backports with three-way merges, style-preserving writes and rollback
- scripts/hao_autopilot.py: one command hub for the kit's entry points
- shorts_gate: restore DEFAULT_RULES, merge_rules and rules= so example 04
  runs again; reading speed counts half-width characters as half units
- teardown: restore rhythm_stats, pace_profile and ocr_status for example 06
- knowledge_lifecycle: learning lives in data/knowledge_state.json, seeded
  once from the shipped state; support counts distinct sources
- context_router: find references in the public layout and route only to
  references that exist in the install
- shorts_autopilot: --platform for scan; usage errors and --help have no
  side effects

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XLikBpKWqhMahFDuvVj6wh
…cation

- review server stamps saved reviews with an HMAC over the exact video sha256
- finalize recomputes the render hash, requires a submitted stamped review,
  archives stale reviews on rebuild and learns each issue once per render
- quality_95 certifies only from a verified review; missing evidence becomes
  an explicit REVIEW gap instead of a silent full score; NaN never scores
- aesthetic/thumbnail scores reject non-finite ratings; flat or low-res
  thumbnails raise review signals; shorts rule overrides must be finite
- silent_vlog_maker imports again on Python 3.9

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XLikBpKWqhMahFDuvVj6wh
…ixtures

- public SKILL.md: bilingual trigger description, start-of-task memory and
  context-packet steps, a task router reaching all 56 references (large files
  by section), definition of done, memory rules and an opt-in remote review
- public agent card rendered from a fixed template (no automatic remote link)
- skeleton validator rejects unlisted, anchored or ./references links
- metric sanitizer keeps fixtures short ('12K') so length-checked self-tests
  and the caption showcase run again; the marker moves to a trailing comment
- canonical_backport treats sanitizer/transform-only changes as already
  applied by projecting the canonical through the head pipeline

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XLikBpKWqhMahFDuvVj6wh
- sync transforms publish knowledge JSON paths under knowledge/runtime/, the
  kit-relative storage_lifecycle command, and a backlog note on wave 6
- canonical_backport replays base..head one first-parent commit at a time on
  a virtual canonical, so a content edit followed by a public-only rewrite of
  the same line merges cleanly; scripts/ are taken from each step's commit

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XLikBpKWqhMahFDuvVj6wh
Replaying intermediate commits against a canonical that already holds the
final head made the first step conflict (x->y merged into a file already at
z). Files whose canonical already publishes exactly as the head, with
consistent mirrors, now settle before the replay. The self-test applies a
multi-commit replay and asserts the second dry run is entirely clean.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XLikBpKWqhMahFDuvVj6wh
…th code

- calibration order now matches visual_master.source_filter: HDR/Log input
  transform first, verified camera correction only for exact SDR matches,
  then one creative LUT (inspect_source reports the same stage order)
- editing-craft LUT strength follows the color-science contract
  (0.25-0.35 typical, 0.50 absolute cap) instead of 50-70%
- quality-95: `serve` binds 127.0.0.1; phone review is the explicit
  one-time `remote-start` link, never a same-Wi-Fi URL
- template-compiler-v2: visual_director has no `selftest` subcommand; the
  motion-kit engine line is marked optional

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XLikBpKWqhMahFDuvVj6wh
Seven docs and templates/audience_vocab.example.json tell creators to call
script_gate.load_vocab(), but the v0.13.1 canonical sync removed it, so the
only way to calibrate the audience-language tables was editing the module.

- load_vocab(path|dict) validates and replaces all four tables;
  reset_vocab() restores the shipped tables; vocab_is_empty() reports state
- an empty vocab returns one lang.no_vocab warning instead of flagging every
  Latin token, as the template documents
- interrupt_schedule docs/report now say re-hook @25/50/75% (the code value)
- README/SETUP: the built-in lists are a generic starter set, not "empty";
  the stale "New in v0.12.0" heading becomes a design-rule section

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XLikBpKWqhMahFDuvVj6wh
- tutorial pacing defers to pace_gate's teaching_longform profile; the old
  "25-40s per cut" mid-section advice would fail that gate. Genre cut rates
  are averages, not timers
- viral-short D1: build perceived loudness in the mix; masters stay at the
  delivery target (-14 LUFS integrated, true peak <= -1 dBTP) instead of
  -10..-8 LUFS, which fails media QA and is normalised down anyway
- visual-art-direction: Signal Grid is a legacy family, no longer the
  source of truth; style families come from `aesthetic_score.py route`
  and a grid opener is a blocker
- autopilot-workflow: sibling skills are optional and not shipped; ask only
  what would otherwise be guessed; drafts without a voice profile and
  samples are marked VOICE_REVIEW_REQUIRED
- thumbnails: low-traffic tests still prepare three variants, test two
- README/architecture: 16 public design DNA seeds ship (not 33); the v6.3
  architecture doc is history, not the current contract

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XLikBpKWqhMahFDuvVj6wh
…an re-verification, TODO placeholders)

- H1: add `resume --reaudit` / reaudit_run: archives the completed audit into
  audit_history and reopens it only while apply is pending (or resolved
  not-applied) and project bytes and the sealed plan are unchanged; upstream
  receipts untouched; re-audit receipts get generation names (audit-002.json).
  Expired audits raise "re-audit required: run `workflow resume <run>
  --reaudit`"; a not-applied resolution marks the single-use receipt spent.
  verify_run is RED for an expired/spent audit while apply is pending.
- M2: state lock records pid/start/host/token, unlinks only its own record,
  judges staleness by owner liveness (age fallback only for unverifiable
  owners), reclaims dead owners atomically; render-phase/verify/reject-render
  hashing moves before the lock; os.replace retries on Windows.
- L1: semantics reject only the issued placeholders or a strict "TODO:" prefix.
- L2: audit/apply instructions, audit binding and verify_run re-verify the plan.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XLikBpKWqhMahFDuvVj6wh
…nd bad evidence)

- H4 interview_gate: typed sources only (url: http(s) / file: existing path,
  relative to base_dir / sha256: 64-hex); placeholder sources rejected; every
  string field scanned for TODO-style residue (I-E); fallbacks mirror gate_core.
  interview_autopilot: stub no longer suggests a placeholder source, plan passes
  base_dir, signed compliance stamp carries today's date and a reviewer
  (--reviewer, default profile HOST_NAME).
- H5 plan_gate: P4 needs a line-anchored stamp with a real, non-future ISO date
  and a human reviewer, rejecting negations/pending/placeholder text; P3 counts
  only distinct, non-placeholder pairs; P5 rejects placeholder cluster keywords.
  PLAN_TEMPLATE.md now ships "合規:待複核" and fails the gate as shipped.
- M1 autonomy_standard: absent or non-bool rights/privacy clearance keeps the
  item out of AUTO_CANDIDATE (evidence_missing:*); status-less transitions are
  downgraded; non-finite/invalid coverage rows score zero.
- M3 pace_gate: rule D-0 rejects missing/None/NaN/inf/<=0/non-numeric durations.
- L1 gate_core: make_assert/raise_if_failed raise on ok=False or a missing
  fails list; selftest_runner with zero checks is RED; shared is_placeholder().
- M4 proof_stage: whitelist by realpath or content sha256, not by file name;
  self-test falls back to a system CJK font or SKIPs only the rendering part.
- M5 editorial_parity_benchmark: score-time contract must match the frozen
  sha256; missing effect decisions and malformed counts block promotion.
- L2 publish_contract: split-battle folders (12-1 -> S012-1) are checked; only
  CERTIFIED_95 counts as certified.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XLikBpKWqhMahFDuvVj6wh
…docs)

- example 05 uses a typed `url:` source, which the interview gate now
  requires; it passes again on 3.12 and 3.9
- publish_hub promotes a Short or long-form cut to "ready" only for
  CERTIFIED_95, matching publish_contract; legacy PASS/GREEN stays review
- SETUP and the interview playbook document `--reviewer` on the
  compliance stamp and the CLUSTER placeholder check

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XLikBpKWqhMahFDuvVj6wh
F4 comparability: add_video rejects duplicate names/video ids and stores a
validated format (shorts/longform/live); record_metrics validates D2/D7/D28,
rejects bool/text/NaN/inf, merges fields and stamps captured_on per field.
outcome_learning groups by (platform, format, window), counts distinct
videos, excludes format_unknown, unknown windows, invalid values and captures
outside [due, due + 1/2/4 days], reporting each in data_quality.

F5 taste model: votes are replayed from the log; ties never count; features
on both sides are ignored; identical comparisons are deduplicated; K is split
over |A|*|B| pairs; preferred/avoided needs min distinct votes plus a
one-sided 95% Wilson margin, so 3-3 splits give NO_CLEAR_PREFERENCE.

F7 integrity: atomic JSON writes (unique mkstemp + fsync + os.replace),
O_CREAT|O_EXCL state lock with stale timeout and edit_state() RMW helper,
STATE_MISSING/STATE_CORRUPT refresh without overwriting the playbook,
owner-agnostic due_report, ops doc points at data/channel_state.json.

F10: migrate-index refuses an unparsable index and keeps index.json.previous;
usage compaction records a counted-prefix marker and rewrites history
atomically, so an interrupted compaction never double counts.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XLikBpKWqhMahFDuvVj6wh
- interview `plan` schedules under channel_tracker.state_lock and records
  the episode as long-form; the hint points at data/channel_state.json
- publish_hub reads data/channel_state.json in the public layout (a
  public-only rewrite, like channel_tracker's path), so published Shorts
  are imported instead of silently skipped
- docs: example state goes to data/; the taste rule is 5 distinct
  comparisons plus a 95% Wilson margin

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XLikBpKWqhMahFDuvVj6wh
system_health now runs the self-tests that CI never reached: gate_core,
script/shorts/plan/pace/grade gates, proof stage, interview gate, autonomy,
editorial parity, channel tracker, taste model, asset usage/index, the
backport tool, the command hub and examples 02/04/05/06 (01 and 03 render
media and run only in full mode).

A static py39-annotations check fails on `X | Y` annotations that
Python 3.9 evaluates at import time (the asset_scanner crash that slipped
through because no 3.9 test imported it). The backport self-test skips
when git is not installed, since the tool cannot run without it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XLikBpKWqhMahFDuvVj6wh
…eceipts

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XLikBpKWqhMahFDuvVj6wh
…transform

- CONTRIBUTING gains the canonical_backport workflow: dry run, --apply,
  re-sync, and the extra --cleanup-helper / --workspace roots
- docs/AUTOPILOT_ARCHITECTURE_V6.md is projected from the private workspace,
  so its public design-DNA wording is now a sync transform instead of an
  edit the next sync would overwrite; the private doc keeps its own count

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XLikBpKWqhMahFDuvVj6wh
The public kit serves any creator, yet 19 synced references (and the
architecture doc) told agents to hand renders to "Hao" for review, taste
calls and approvals. A public-only sync rule now rewrites those role uses
to 創作者 / "the creator"; headings, brand names (Hao Signal Grid, Hao Video
Autopilot), schema ids, quoted values and Hao0321 are untouched.

sync_canonical.public_text() is the single canonical->public projection
(transform, role rule, sanitizer). The rule skips sanitizer-managed
Markdown, which already generalizes identity, so a later real sync
reproduces these files exactly. canonical_backport uses public_text() when a
scripts tree has it, so the rewrite is never written back: every role-only
file replays as ALREADY_APPLIED and the canonical keeps its wording.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XLikBpKWqhMahFDuvVj6wh
…borders, three-state gate)

- media_delivery_qa: per-frame signalstats WCAG 2.3.1 general + red flash gate;
  black runs > 1 s (outside the closing 1 s fade) and mostly-black clips fail;
  cropdetect sampled across the whole duration, no output = UNVERIFIED;
  every requested check is PASS/FAIL/UNVERIFIED and anything but PASS blocks
  with an explicit reason; scene pacing no longer uses lavfi movie= (any
  filename); missing audio = silence for dead air, UNVERIFIED for loudness,
  tail and A/V; '-inf' dB parses as -200 dB; true peak gate has no +0.3 slack.
- delivery_media_ops: stream probe, dB parser, signalstats means, WCAG flash
  math, cropdetect parsing and a tiny lavfi fixture renderer for self-tests.
- shorts_delivery: exact 30/1 fps, parsed true peak <= -1 dBTP, missing
  stream fails, shared flash/black/border/dead-air detectors, loop similarity
  gated when loop_policy requires it; failed_checks names every non-pass.
- quality_check: no audio track while audio is expected is an issue.
- Fixture-based negative self-tests (strobe, black run, all-black, late
  letterbox, true-peak over, -inf tail, special-character filename, missing
  audio, missing faster_whisper) plus a clean control.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XLikBpKWqhMahFDuvVj6wh
The new strobe, black-run, letterbox, true-peak and missing-stream fixtures
for long-form and Shorts delivery never ran in CI: delivery-qa was marked
slow and shorts_delivery.self_test() had no entry point. Both now run in
quick mode (about 5 s and 15 s with ffmpeg, already a kit requirement).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XLikBpKWqhMahFDuvVj6wh
…rchive order

- M1: apply rolls back on BaseException (Ctrl+C/SystemExit) and re-raises.
  check/auto/apply first roll back a PENDING transaction left by a killed
  updater (INTERRUPTED_TRANSACTION_RECOVERED) or refuse with
  INTERRUPTED_TRANSACTION when its evidence is missing/unreadable or a touched
  file matches neither side of the update. Each transaction now saves the
  verified target index before its first mutation. New O_CREAT|O_EXCL
  install-root lock (pid, process start marker, token; stale only when the
  owner process is dead) around apply/rollback/recovery; busy -> LOCKED.
  atomic_json writes a unique exclusive temp file, fsyncs, then os.replace.
- M3: startup re-exec on Windows waits for a list-quoted child and
  propagates its exit status; POSIX keeps os.execv. A recovered rollback
  also re-execs so the process never mixes module versions.
- L5: release zip members and index rows sort by relative POSIX text, so
  archive order no longer depends on host Path ordering.
- L4: CLI/auto-update errors include path-free messages; any message with an
  absolute path still reports the exception type only.

Self-test: replaced the assertion that a Ctrl+C left a PENDING ledger for
manual rollback; added interrupted/killed apply recovery, unsafe recovery,
install lock, atomic_json, archive order, startup re-exec and error-text
stages.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XLikBpKWqhMahFDuvVj6wh
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XLikBpKWqhMahFDuvVj6wh
… shared HDR normaliser

- visual_master: shared colour contract (to_rgb_filter/to_yuv_filter/bt709_filter_chain,
  BT709_TAGS, BT709_ENCODE_ARGS, scale_matrix/source_matrix, rgb_decode_filter); every
  RGB-domain filter now runs between explicit YUV<->RGB conversions (source-tag matrix in,
  automatic range, BT.709 limited out, setparams tags); source_filter/lut_filter_for_plan
  return matrix-explicit chains so the shorts path is fixed without editing it;
  apply_to_video tags its encode; HDR_TO_SDR_FILTER shared with constants (self-test).
- grade_lib: apply_look/load_cube_lut/grade_strip use the explicit chain, blend in gbrp,
  tagged encodes. grade_gate: sampler decodes with an explicit matrix.
- filter_renderers: ffmpeg rawvideo pipes replace cv2 decode + lossy mp4v; lossless x264
  intermediate, CFR fps reader, HDR tone-mapped decode, bt709-tagged final encodes.
- tracked_graphics_render: graphics blended in RGB with explicit conversions, tagged
  output, shared HDR normaliser.
- filter_primitives: scanlines darken (1-o, o); halftone dot area = coverage over the
  full frame (tone preserving); edge-replicating shifts instead of np.roll wrap.
- fx_lib.double_bloom: blurred alpha mask filled with a light-weighted glow colour.
- silent_vlog_maker.effects: Ken Burns s=WxH, centre-anchored, full-duration zoom,
  aspect-correct pan; lavfi self-test. constants: one npl=100 HDR normaliser,
  threads preset tagged -colorspace bt709.
- Regression self-tests (lavfi clips, negative controls on untagged input).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XLikBpKWqhMahFDuvVj6wh
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XLikBpKWqhMahFDuvVj6wh
- Shorts main/sub/hook/addr captions are measured with libass sizing, get one
  kinsoku/word-safe line break when wider than the 864 px text-safe width and
  are then scaled (floor 70 %, else a clear error); adjacent Latin colour
  blocks keep a space ("video-autopilot-kit demo").
- Shared kinsoku/word-safe breaker (caption_director: break_points,
  best_break, wrap_ranges) used by Shorts ASS, caption PNGs, chunking and
  title cards; no silent truncation.
- HOOK/RIBBON text on the accent box picks ink or white by WCAG >= 4.5:1.
- CJK fonts resolve through configured paths then platform_compat (guarded),
  with TTC face selection; load_default() tofu fallback replaced by an error;
  libass family resolved from the found font file.
- One TEXT_SAFE_RECT (108, 384, 972, 1440) for generic, kinetic and drawtext
  overlay captions; overlay presets fixed to end inside it.
- Thumbnail gate uses linearised WCAG contrast of glyphs vs adjacent ring
  (3.0 for the bold headline) and keeps the bottom-right length badge clear.
- caption_director 60 % highlight rule without the max(4, ...) floor; ribbon
  character limit 14.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XLikBpKWqhMahFDuvVj6wh
- shorts_vertical keeps HDR sources at full precision until the grade's
  tone map (the 8-bit format conversion now happens after it), converts
  ungraded clips with visual_master's explicit BT.709 decode, blends
  visual-plan cards and motion cues in RGB instead of through BT.601, and
  tags every intermediate encode BT.709
- thumb_template is reprojected through the current metric sanitizer, the
  form the next canonical sync produces
- changelog entry for the caption and typesetting fixes

Example 01 renders end to end: output tagged BT.709, captions inside the
text-safe rectangle.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XLikBpKWqhMahFDuvVj6wh

Hao0321 commented Oct 6, 2026

Copy link
Copy Markdown
Owner Author

CI 狀態(head f8a06cc):7 個 job(verify ×6、reproducible-release)都停在同一步 sync_canonical.py --verify-receipt,錯誤是 SYNC RECEIPT RED: receipt output hash mismatch。不一致的是 30 個 derived 輸出:SKILL.md、agents/openai.yaml、workflow_contract.py、workflow_audit_binding.py、design_runtime/src/aesthetic_score.py,以及 25 份 references。在這一步之前的 privacy、sanitizer 與 sync self-test,CI 上都是 GREEN。

原因: 這個 PR 改了由私有 canonical 產生的 derived 檔,而 sync-receipt.json 記錄的是上次維護者同步時的 hash。依 CONTRIBUTING,receipt 不能手動修改,只能由維護者從 canonical 同步重新產生,所以這個 PR 內無法修正。這是固定的 hash 不一致,不是 flake,重跑結果不會變,所以我沒有 re-run。

解除方式: 維護者在本機依 PR 說明的「驗收與回復方式」操作:

  1. 執行 canonical_backport.py,先 dry run,再加 --apply。
  2. 執行 sync_canonical.py --canonical ...。
  3. 把重新產生的 sync-receipt.json 提交到這個分支,CI 就會重跑。

本機驗證: 我在 Python 3.12 與 3.9 跑過全部 14 個 CI 步驟,receipt 只在暫存區刷新、沒有提交,結果都是綠的。

維護者本機的新版推上 main 之後,我會用 merge commit 把 main 合進這個分支並重新驗證。


Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants