feat(z01): 낱값 값·설명 가름을 이름표 표시로 갈아끼움 — 잠정 잣대 뺌 · 이름표 role value 는 보임 · note 는 뺌 · 표시 없거나 모르는 낱말은 값으로 보이되 「미판정」 칸으로 드러냄(진짜 이름표 0 을 시험으로 못박음) · 줄 이름 열 @key 는 그 표 열 목록의 제 이름을 먼저 찾음(fx 통화 · masonry_slope 쌓기 방식)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BW6Jdsh18WPtYUR6THZJqn
This commit is contained in:
2026-09-15 19:27:49 +09:00
co-authored by Claude Opus 5
parent e412685bf4
commit df2b62a34e
2 changed files with 80 additions and 29 deletions
+28 -16
View File
@@ -26,14 +26,13 @@ ROW_KEY = "@key"
VALUES_TABLE = "@values"
_CODE_HIDDEN = {"@path"} # 낱값 표의 영문 자리 — 이름표에 없을 때만
# ⚠ 잠정 — 이름표가 값 묶음마다 「값이냐 설명이냐」 표시를 주면 **이 자리만** 갈아끼움(브레인 ④)
_DESCRIPTION_KEYS = {"note", "notes", "policy", "source", "sources", "quote", "why"}
def is_description(group_key: str) -> bool:
"""값 묶음이 설명·방침인가(값이 아님) — 끝 조각으로 가름."""
last = group_key.rsplit("/", 1)[-1]
return last in _DESCRIPTION_KEYS or last.endswith("_note")
# 값 묶음 갈래 — 이름표 `value_groups[].role`(데스크탑 서브) · 낱말이 바뀌면 이 자리만 갈아끼움
ROLE_FIELD = "role"
SHOWN_ROLE = "value" # 원가·수량에 드는 값 — 낱값 표에 보임
HIDDEN_ROLE = "note" # 읽으라고 적은 글 — 안 보임
# 이름표가 안 가른(또는 모르는 낱말) 마디 — 조용히 빼지도 섞지도 않고 값으로 보이되 드러냄(브레인)
UNDECIDED_COLUMN = "@undecided"
UNDECIDED = "미판정"
# 파일 머리 — 표도 값 묶음도 아님(이름표 생성기와 같은 목록)
@@ -106,18 +105,24 @@ def values_of(path: Path) -> dict[str, Any]:
return _scan(str(path), path.stat().st_mtime_ns)[1]
def _value_rows(fid: str, path: Path, labels: dict[str, Any]) -> list[dict[str, Any]]:
"""낱값 표 줄 — 찾는 차례: 「파일id::key」 → 「끝 조각」 → 영문 key."""
def _value_rows(entry: dict[str, Any], path: Path, labels: dict[str, Any]) -> list[dict[str, Any]]:
"""낱값 표 줄 — 이름 찾는 차례: 「파일id::key」 → 「끝 조각」 → 영문 key."""
fid = entry["file_id"]
roles = {g.get("key"): g.get(ROLE_FIELD) for g in entry.get("value_groups") or []}
rows = []
for key, value in values_of(path).items():
if is_description(key):
role = roles.get(key)
if role == HIDDEN_ROLE:
continue
named = (
(labels.get("value_overrides") or {}).get(f"{fid}::{key}")
or (labels.get("value_keys") or {}).get(key.rsplit("/", 1)[-1])
or {}
)
rows.append({"@name": named.get("name_ko") or key, "@value": value, "@path": key})
row = {"@name": named.get("name_ko") or key, "@value": value, "@path": key}
if role != SHOWN_ROLE:
row[UNDECIDED_COLUMN] = UNDECIDED
rows.append(row)
return rows
@@ -153,7 +158,7 @@ def tree() -> dict[str, Any]:
kind = entry.get("kind") or ""
group = groups.setdefault(kind, {"key": kind, "label": kind, "files": []})
counts = {tid: len(rows) for tid, rows in tables_of(path).items()}
value_count = len(_value_rows(entry["file_id"], path, labels))
value_count = len(_value_rows(entry, path, labels))
if value_count:
counts[VALUES_TABLE] = value_count
group["files"].append(
@@ -178,11 +183,13 @@ def rows(
entry = next((f for f in labels["files"] if f["file_id"] == fid), None)
path = _file_path(entry) if entry else None
if path and tid == VALUES_TABLE:
table = _value_rows(fid, path, labels) or None
table = _value_rows(entry, path, labels) or None
else:
table = tables_of(path).get(tid) if path else None
if table is None:
return None
own = next((t for t in entry.get("tables") or [] if t.get("key") == tid), {})
own_columns = {c.get("key"): c for c in own.get("columns") or []}
keys: dict[str, None] = {}
for r in table:
keys.update(dict.fromkeys(r))
@@ -195,8 +202,13 @@ def rows(
size = max(1, min(size, MAX_PAGE_SIZE))
start = (max(page, 1) - 1) * size
columns = []
for key in keys: # 찾는 차례: 「파일id/열key」 → 「열key」 → 영문 key
named = labels["column_overrides"].get(f"{fid}/{key}") or labels["columns"].get(key) or {}
for key in keys: # 찾는 차례: 그 표 열 목록(줄 이름 열 `@key` 는 표마다 제 이름) → 「파일id/열key」 → 「열key」 → 영문 key
named = (
own_columns.get(key)
or labels["column_overrides"].get(f"{fid}/{key}")
or labels["columns"].get(key)
or {}
)
columns.append(
{
"key": key,