feat(785-6): 블록 칠 새 판정 — Marks 가 Make.judged 저장본을 읽음 · SheetMap 제안 칠

- M02_Hopyo_Marks.py: 블록 판정 = M02_Hopyo_Make.judged(folder, key) 파생 저장본(785-5) · 고를수 실음 · 저장본 없으면 옛 맞춤셈 판정(785-7 에서 걷음)
- logic/Hopyo_SheetMap.ts: 기초로 풂 · 기초+덧 = 초록 · 줄 조합 · 고를 것 n = 파랑 · 일위대가 밖 글
- test_642_6_screen.py: 블록 칠 새 판정 · Marks 옛 길 대체 시험

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-11-04 22:45:49 +09:00
co-authored by Claude Opus 5.5
parent 0117dbdf2e
commit fa50fe05d3
3 changed files with 74 additions and 3 deletions
+19 -3
View File
@@ -1,7 +1,9 @@
"""M02 불러오기 엑셀 보기 하이라이트 재료(PLAN 779-2 · 요구서 621 3장 5) — 읽기만(파일 · storage 변화 0).
블록 `[{번, 판정, SK, 갈래, 못옮김, 부름}]` = 단가산출 만들기 결과(`Sangeun.made`) + 맞춤셈 캐시(`Fit.result`)를 읽기만.
- `판정` = 그 블록을 부르는 첫 줄의 맞춤셈 판정 상태(맞음 · 다른 점 · 후보 …) · 안 불리거나 셈 전이면 None
블록 `[{번, 판정, 고를수, SK, 갈래, 못옮김, 부름}]` = 단가산출 만들기 결과(`Sangeun.made`) + 블록 판정을 읽기만.
- `판정` = 새 블록 판정(785-6 · `M02_Hopyo_Make.judged` 파생 저장본 = 기초로 풂 · 기초+덧 · 줄 조합 · 고를 것 ·
`고를수`) · 그 저장본이 없으면(785-5 전 · 셈 전) 옛 판정 = 부르는 첫 줄의 맞춤셈 상태(맞음 · 다른 점 · 후보 …) ·
안 불리거나 셈 전이면 None
- `부름` = 부르는 호표 번 [] = 일위대가 밖(780-1) · `어긋남` · `줄` = 모든 블록(밖 포함)
- `SK` = 만든 SK 키 · 없으면 None / `갈래` · `못옮김` = 그 SK 본뜬(출처별) · 없으면 None · []
줄 상태는 `Match.view` 호표마다 `줄상태 [[차례, 상태, 체크]]` · `만든`(SC 키)로 실려 감.
@@ -120,6 +122,16 @@ def lines(block: dict[str, Any], units: hunits.Units) -> list[list[Any]]:
return out
def _judged(folder: Path, key: str) -> dict[int, dict[str, Any]] | None:
"""새 블록 판정 `{번: {판정, 고를수}}`(785-5 파생 저장본) · 없으면 None(셈 전 · 785-5 전)."""
try:
from M02_MasterTemplete import M02_Hopyo_Make as make
except ImportError: # ponytail: 785-5 Make 오기 전 = 옛 맞춤셈 판정 · 785-7 에서 걷음
return None
got = make.judged(folder, key)
return None if got is None else {int(k): v for k, v in got.items()}
def blocks(folder: Path, key: str, to: Path | None = None) -> list[dict[str, Any]]:
"""블록마다 `{번, 판정, SK, 갈래, 못옮김, 어긋남, 줄}` — `to` = 만든 SK 를 볼 층(없으면 파일 층)."""
folder, to = Path(folder), Path(to or folder)
@@ -130,6 +142,7 @@ def blocks(folder: Path, key: str, to: Path | None = None) -> list[dict[str, Any
all_, first = sangeun.calls(hp)
units = hunits.Units() if all_ else None
call = sangeun.callers(hp)
judge = _judged(folder, key)
out = []
for no in sorted(all_):
line = first.get(no)
@@ -137,10 +150,13 @@ def blocks(folder: Path, key: str, to: Path | None = None) -> list[dict[str, Any
mark = sangeun.mark(key, no)
sk = have.get(mark)
origin = _origin(to, sk, mark, here) if sk else {}
new = (judge or {}).get(no) or {}
old = ((entry or {}).get("판정") or {}).get("상태")
out.append(
{
"번": no,
"판정": ((entry or {}).get("판정") or {}).get("상태"),
"판정": new.get("판정") if judge is not None else old,
"고를수": new.get("고를수"),
"SK": sk,
"갈래": origin.get("갈래"),
"못옮김": origin.get("못옮김") or [],
@@ -43,7 +43,10 @@ export interface BriefMarks {
}
export interface BlockMark {
번: number;
/** 새 블록 판정(785-6 · 기초로 풂 · 기초+덧 · 줄 조합 · 고를 것) › 옛 부르는 첫 줄 맞춤셈 상태 */
판정: string | null;
고를수?: number | null;
부름?: number[];
SK: string | null;
갈래: string | null;
못옮김: unknown[];
@@ -115,6 +118,9 @@ export function lineTone(
export const worst = (tones: Tone[]): Tone =>
tones.reduce<Tone>((a, b) => (RANK[b] > RANK[a] ? b : a), "muted");
/** 새 블록 판정 칠(785-6) — 확인 전이라 제안 칠만(확인함 = 만든 SK) */
const BLOCK_TONE: Record<string, Tone> = { "기초로 풂": "success", "기초+덧": "success", "줄 조합": "info", "고를 것": "info" }; // prettier-ignore
/** 블록 칠 — 만든 SK 갈래 › 없으면 부르는 첫 줄 판정 「예상」 · 판정 없음 = 「일위대가 밖」 */
export function blockTone(m: BlockMark | undefined): { tone: Tone; 글: string } {
if (!m) return { tone: "muted", 글: "안 불림" };
@@ -124,6 +130,12 @@ export function blockTone(m: BlockMark | undefined): { tone: Tone; 글: string }
return { tone, 글: `${m.SK} · ${m.갈래 ?? ""}${lost ? ` · 못옮김 ${lost}` : ""}` };
}
if (!m.판정) return { tone: "muted", 글: "일위대가 밖" }; // 부르는 일위대가 줄 없음(780-2)
const fresh = BLOCK_TONE[m.판정];
if (fresh) {
const n = m.판정 === "고를 것" && m.고를수 ? ` ${m.고를수}` : "";
const out = m.부름 && !m.부름.length ? " · 일위대가 밖" : "";
return { tone: fresh, 글: `제안 — ${m.판정}${n}${out}` };
}
const tone: Tone = m.판정 === "맞음" ? "success" : m.판정 === "다른 점" ? "warning" : "info";
return { tone, 글: `예상 — 부르는 첫 줄 ${m.판정}` };
}
+43
View File
@@ -224,3 +224,46 @@ def test_고름바꾸면_확인풀림_칠(judged):
assert got[3] == "success"
assert got[4]["호표"]["1"]["0"]["확인"] is False
assert got[5] == "danger" and got[6] == "info"
def test_블록칠_새판정(monkeypatch):
"""SheetMap 블록 칠 = 새 판정(제안 칠) · Marks = `Make.judged` 저장본 › 없으면 옛 판정."""
from M02_MasterTemplete import M02_Hopyo_Marks as mk
from resources.tester.test_779_4_sheet_map import _node
def mark(v, n=None, call=(1,)):
return {
"번": 1,
"판정": v,
"고를수": n,
"부름": list(call),
"SK": None,
"갈래": None,
"못옮김": [],
}
got = _node(
{
"blockTones": [
mark("기초로 풂"),
mark("고를 것", 3),
mark("줄 조합", call=()),
{**mark("고를 것", 2), "SK": "SK-1", "갈래": "기초"},
mark("맞음"),
]
}
)["blocks"]
assert [b["tone"] for b in got] == ["success", "info", "info", "success", "success"]
assert got[1]["글"] == "제안 — 고를 것 3" and got[2]["글"] == "제안 — 줄 조합 · 일위대가 밖"
assert mk._judged(Path("."), "x") is None # 785-5 Make 전 = 옛 길
class Make:
@staticmethod
def judged(folder, key):
return {"10": {"판정": "기초로 풂", "고를수": 0}}
import sys
monkeypatch.setitem(sys.modules, "M02_MasterTemplete.M02_Hopyo_Make", Make)
monkeypatch.setattr(sys.modules["M02_MasterTemplete"], "M02_Hopyo_Make", Make, raising=False)
assert mk._judged(Path("."), "x") == {10: {"판정": "기초로 풂", "고를수": 0}}