feat: tick-character guidance + three-valued glyph-coverage probe - #193
feat: tick-character guidance + three-valued glyph-coverage probe#193kiki830621 wants to merge 4 commits into
Conversation
A checkbox ticked as U+2611 stops matching the form because no measured font carries that glyph — including Times New Roman and Arial — so the renderer substitutes an emoji face. The run's declared font never changed; the font that actually drew the character did. The probe answers with three values rather than a Bool. CTFontCreateWithName resolves an uninstalled family to Helvetica instead of failing, and Helvetica has no U+25A0 either, so a two-valued probe asked about the recommended tick in an absent CJK family reports "no glyph" for the one character that is actually safe. `unknown` keeps "nothing was measured" from being readable as "the glyph is missing". Font resolution goes through a descriptor match rather than comparing against CTFontCopyFamilyName, which answers in English: a literal comparison calls the installed DFKai-SB missing when it is declared as its localized name. No call site consumes this yet — see the Implementation Complete comment. Refs #189
…ng (#189) Ticking a form by replacing U+25A1 with U+2611 leaves the text layer correct and the appearance wrong: no measured font carries U+2611, so the renderer falls back to a colour emoji face and the box stops matching the form. Cell-by- cell comparison passes, which is why this reached a real document — only a human opening the file could see it. The guidance names U+25A0 instead, and the tests pin the scope rather than the phrasing: it must cite a non-CJK font, because U+2611 is missing from Times New Roman and Arial too. Wording it as a CJK-font caveat would tell callers that Latin-font documents are safe. allTools drops to internal so the tests can assert on the surface that is actually registered rather than on a copy of the string. Refs #189
Cross-model verification found the resolver treating CoreText's best-match as a lookup. CTFontDescriptorCreateMatchingFontDescriptor with no mandatory attributes substitutes: asking for "System Font" hands back the .SF NS family. The probe measured that font and reported hasGlyph/noGlyph as though it had measured the declared one — a confident answer about something the document never named, which is the exact silent-wrong-answer the third value exists to prevent, arriving through the one door it did not cover. Resolution now accepts only a font that answers to the declared name, compared against the resolved font's own name set (family, full, PostScript, localized family) so 標楷體 and differently-cased spellings still resolve while .SF NS does not. Both decided cases carry the family actually measured; without it a caller cannot audit which font a verdict describes. `unknown` carries a reason, because "declared nothing", "not installed" and "landed elsewhere" need different things said about them. Also from the same review: - The surrogate-pair comment described the CoreText contract wrongly. Behaviour was right; the stated reason was not. Measured and corrected, with tests for a non-BMP scalar in both directions. - The localized-name test gated its skip on the function under test, so a regression breaking localized resolution would have skipped rather than failed. It now checks font presence through CoreText directly. - The safe-character test asserted only `!= .noGlyph`, which a substituted font containing U+25A0 would have satisfied. It asserts the full verdict now. - U+2612 was named unsafe in the tool description with no test behind it. - The description predicted emoji fallback as a certainty; it is one of several platform-dependent outcomes, and the font claims hold for measured versions. - The allTools note claimed `internal` widens visibility no further than the test bundle. It is module-wide. Refs #189
Verify Report — PR #193Engine降級 tier,請照此讀這份報告。 本 session 的操作指示禁止在未經使用者要求下使用 Agent tool
所以這不是 6-AI ensemble,是「1 個獨立模型 + 1 個自審協調者」。下方「這次驗證證明了什麼」段 AggregateFAIL — 3 blocking(round 2 後仍未解),已達 unattended 模式的 2 輪自動修復上限。 Frozen snapshot: 這次驗證證明了什麼(而不是形式上的 tier 免責)跨模型 leg 兩輪都推翻了 coordinator 的實證結論,而且是同一種錯誤的兩次發作。
兩次都是同一個病:拿單一機器的樣本當通則。而兩次都是 coordinator 自己看不出來、由另一個模型 #189 — feat: checkbox 勾選的字形覆蓋指引/偵測要求覆蓋率
Findings
Round 1 修正逐項判定(跨模型複核)
Scope Check無超出 issue 範圍的改動。唯一非直接要求的變更是 為什麼停在這裡(而不是繼續修)
建議的最小修復方向(供決策,非已執行)
Next不要合併 PR #193。 Branch |
Refs #189
Summary
勾選表單時把
□換成☑會產生一份文字層完全正確、外觀完全錯誤的文件:逐格比對全過,但沒有任何實測字型帶有 U+2611 的字形,渲染器改用彩色 emoji 字體。工具沒動過 run 的字型宣告
——被換掉的是實際繪製的字型,而那一層文字比對看不到。
兩件事:
replace_text/replace_text_batch的說明改推■(U+25A0)。刻意不寫成 CJK 專屬:實測 U+2611 在 Times New Roman 與 Arial 同樣缺字形,寫成 CJK 注意事項等於告訴呼叫者拉丁
字型的表單是安全的。
GlyphCoverageProbe,回答三值(hasGlyph/noGlyph/unknown)。unknown是重點:
CTFontCreateWithName對未安裝字型回傳 Helvetica 而非失敗,而 Helvetica 連■都沒有字形——兩值探測會指控本文件建議使用的那個字元,同時丟掉真正的發現。
Deliberately out of scope
沒有任何呼叫端使用這個探測。 三種接法都會新增或改變對外 MCP tool surface,那是需要人決定
的事(本次
/idd-all在 unattended 下執行,Plan tier 的 approval gate 沒有跑);其中「附加在回傳字串」另外卡在 #192。本 PR 不新增任何 MCP tool、不更動任何既有 tool 的回傳格式
(
tools/list仍回 245 個)。Verification
swift test→ 358 tests, 11 skipped, 0 failuresunknown塌縮成noGlyph→ 恰好 3 條 unknown 測試失敗;把指引改寫成 CJK-only→ 恰好那條 scope 測試失敗。測試證明抓得到它們存在的理由,不只是通過。
tools/list:兩個 replace 工具的 description 確實帶著指引。swift build -c release逾時未跑完,release 組態本次無證據。Checklist
/idd-verify #189)/idd-close收尾(人工 gate + closing summary,無 auto-close trailer)Do NOT add a GitHub close trailer — IDD 紀律要求合併後手動
/idd-close,以強制 checklist gate 與 closing summary。