From 3c5aa96fc37a6339f5a9660f54652bab1f3d073c Mon Sep 17 00:00:00 2001 From: umsangdon Date: Sun, 13 Sep 2026 15:04:31 +0900 Subject: [PATCH 1/4] =?UTF-8?q?refactor(b07):=20=ED=91=9C=EC=A4=80?= =?UTF-8?q?=EB=8F=84=20=EB=AA=A9=EB=A1=9D=C2=B7=EC=A0=9C=EC=9B=90=20?= =?UTF-8?q?=EC=B9=B8=EC=9D=84=20B07=20=EC=97=90=EC=84=9C=20=EA=B1=B7?= =?UTF-8?q?=EC=96=B4=EB=83=84=20=E2=80=94=20=EA=B5=AC=EC=A1=B0=EB=AC=BC?= =?UTF-8?q?=EB=8F=84=EB=8A=94=20B08=20=ED=83=AD=EC=9C=BC=EB=A1=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 도면 목록·단건 조회·화면 제원 칸·[여기서 고치기]·창구 함수 제거 - 도면 kind 에서 standard 를 뺌. 표·그림 조립(build_standard_drawing·그림)은 B08 상단 그림 일감이 다시 쓸 자리로 남김 - 옛 [여기서 고치기] 시험을 B08 구조물도 탭 폼 자리 확인으로 바꿈 Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq --- .../B07_DesignDetail_Api_Fetch.ts | 52 +---------- ...7_DesignDetail_Engine_Cad_StandardSheet.py | 77 +--------------- B07_DesignDetail/B07_DesignDetail_Router.py | 7 +- .../B07_DesignDetail_Router_Support.py | 17 +--- B07_DesignDetail/B07_DesignDetail_Schema.py | 6 +- B07_DesignDetail/B07_DesignDetail_UI_Page.ts | 90 +------------------ .../B07_DesignDetail_UI_Panels.ts | 2 - .../B08_Quantity_Router_StructureSheet.py | 21 ----- .../B08_Quantity_UI_StructureSheet_Spec.ts | 4 +- .../test_b07_standard_spec_blinding_weep.py | 18 ++-- 10 files changed, 24 insertions(+), 270 deletions(-) diff --git a/B07_DesignDetail/B07_DesignDetail_Api_Fetch.ts b/B07_DesignDetail/B07_DesignDetail_Api_Fetch.ts index 6459d1ce..5ee1eb54 100644 --- a/B07_DesignDetail/B07_DesignDetail_Api_Fetch.ts +++ b/B07_DesignDetail/B07_DesignDetail_Api_Fetch.ts @@ -15,7 +15,6 @@ export interface DesignDrawingItem { | "landuse" | "plan_lidar" | "cross_standard" - | "standard" | "blank"; label: string; chainage_m: number | null; @@ -103,7 +102,6 @@ export interface DesignDrawingResponse { | "landuse" | "plan_lidar" | "cross_standard" - | "standard" | "blank"; label: string; drawing: CadDrawing; @@ -246,51 +244,5 @@ export function resetFrameTemplate(projectId: string): Promise { }); } -/** 표준도 장 목록 — 제원 입력 칸이 쓰는 것만 추린 꼴. */ -export interface StandardSheetsResponse { - status: string; - sheet_count: number; - structure_count: number; - sheets: { - key: string; - title: string; - type_id: string; - member_count: number; - options: Record; - }[]; -} - -// 창구는 B08 구조물도 — 2026-09-13 이관(PLAN 3장). 탭 배선 뒤 B07 표준도와 함께 지움. -export function fetchStandardSheets(projectId: string): Promise { - return requestJson(`/projects/${projectId}/quantity/structure-sheets`); -} - -/** 장 하나의 제원 저장 — 빈 값(null)은 **그 칸을 지우라**는 뜻이다. */ -export function putStandardSheetSpec( - projectId: string, - body: { - sheet_key: string; - base_revision: number; - stone_kind: string | null; - stone_supply: string | null; - back_len_cm: string | null; - face_slope_ratio: string | null; - foundation: string | null; - stone_coeff_basis: string | null; - fill_concrete_mpa: string | null; - thickness_top_m: string | null; - thickness_bottom_m: string | null; - blinding_concrete: string | null; - }, -): Promise<{ status: string; revision: number; changed: number; notes: string[] }> { - return requestJson(`/projects/${projectId}/quantity/structure-sheets/spec`, { - method: "PUT", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify(body), - }); -} - -/** 구조물 정본 판번호 — 제원을 저장할 때 함께 보내야 다른 창 덮어쓰기를 막는다. */ -export function fetchStructureRevision(projectId: string): Promise<{ revision: number }> { - return requestJson(`/projects/${projectId}/route/structures`); -} +// 표준도(구조물도) 장 목록·제원 저장 창구는 2026-09-13 B08 「구조물도」 탭으로 이관 +// (`B08_Quantity_UI_StructureSheet.ts`). diff --git a/B07_DesignDetail/B07_DesignDetail_Engine_Cad_StandardSheet.py b/B07_DesignDetail/B07_DesignDetail_Engine_Cad_StandardSheet.py index 14944c61..0fdbcc22 100644 --- a/B07_DesignDetail/B07_DesignDetail_Engine_Cad_StandardSheet.py +++ b/B07_DesignDetail/B07_DesignDetail_Engine_Cad_StandardSheet.py @@ -12,12 +12,13 @@ ⚠ 값을 여기서 셈하지 않는다 — `B08_Quantity_Engine_StructureSheet.build_standard_sheets` 가 낸 것을 글자로 옮길 뿐이다. 셈이 두 벌이 되면 도면과 수량서가 갈린다(CLAUDE.md 5장). + +⚠ **2026-09-13 B07 도면 목록에서 빠짐**(사용자 확정 ③ — 구조물도는 B08 탭, PLAN 3장 ④). + 목록·라우터 배선은 걷어냈고 표·그림 조립만 남김 — B08 구조물도 상단 그림 일감이 다시 쓸 자리. """ from __future__ import annotations -import logging -from pathlib import Path from typing import Any from B07_DesignDetail.B07_DesignDetail_Engine_Cad import ( @@ -36,18 +37,8 @@ from B07_DesignDetail.B07_DesignDetail_Engine_Cad_StandardFigure import ( from B07_DesignDetail.B07_DesignDetail_Engine_Cad_StandardFigure import build_figure, figure_reason from B07_DesignDetail.B07_DesignDetail_Engine_Template import usable_bbox -logger = logging.getLogger(__name__) - STANDARD_LAYER_ID = "standard" -#: 장 하나가 도면 하나 — 계획평면도와 같은 본을 따른다(`plan_lidar` / `plan_lidar_2`). -SHEET_ID_PREFIX = "standard_sheet" - - -def sheet_drawing_id(number: int, total: int) -> str: - """장이 하나면 `standard_sheet`, 여럿이면 `standard_sheet_2` 처럼 번호를 붙인다.""" - return SHEET_ID_PREFIX if total <= 1 and number <= 1 else f"{SHEET_ID_PREFIX}_{number}" - # 종이 밀리미터. 실무 시트가 「공종 | 산출근거 | 수량 | 단위」 넉 줄이라 그대로 간다. # ⚠ **산출근거 칸을 넓게 잡는다** — 처음 176㎜ 로 냈더니 물구멍관·버림콘크리트처럼 단서가 @@ -223,65 +214,3 @@ def build_standard_drawing(drawing_id: str, label: str, payload: dict[str, Any]) "entities": entities, "layers": [_layer(STANDARD_LAYER_ID, "표준도")], } - - -def standard_payload( - project_root: Path, section_modes: dict[float, str] | None = None -) -> dict[str, Any]: - """프로젝트 구조물을 제원 조합으로 묶은 장 목록. 실패해도 **빈 목록**을 낸다. - - ⚠ 늦게 부른다(함수 안 import) — B08 은 B05 를 부르고 B05 는 다시 B07 을 부를 수 있어 - 모듈 맨 위에서 부르면 맞물린다. - ⚠ 장 목록은 **B08 구조물도 창구와 한 벌**(2026-09-13 이관) — 따로 전개하면 기초잡석 두께가 갈림. - """ - from B08_Quantity.B08_Quantity_Router_StructureSheet import project_structure_sheets - - try: - # ⚠ 단면유형을 넘겨야 성절토가 갈리고 표준경사 판정이 돈다. 안 넘기면 전 구조물이 - # 「가를 근거 없음」으로 떨어져 종전값 1:0.3 으로 선다(2026-09-09 실측). - return project_structure_sheets(str(project_root), section_modes) - except Exception: - logger.exception("B07 표준도 장 목록 실패 — 빈 목록으로 둔다: %s", project_root) - return {"sheets": [], "structure_count": 0} - - -def sheet_items( - project_root: Path, section_modes: dict[float, str] | None = None -) -> list[tuple[str, str]]: - """좌측 목록에 설 `(도면 id, 이름)`. 장이 없으면 **빈 장 하나**를 남긴다. - - 구조물이 없다고 단추가 통째로 사라지면 「없어진 것」처럼 보인다 — 눌러서 사유를 읽게 한다. - """ - sheets = standard_payload(project_root, section_modes).get("sheets") or [] - if not sheets: - return [(SHEET_ID_PREFIX, "표준도")] - total = len(sheets) - return [ - (sheet_drawing_id(index, total), f"표준도 {index}장 ({sheet.get('title') or ''})".strip()) - for index, sheet in enumerate(sheets, start=1) - ] - - -def standard_drawing_for( - project_root: Path, - drawing_id: str, - label: str, - section_modes: dict[float, str] | None = None, -) -> dict[str, Any]: - """프로젝트 구조물을 읽어 표준도 한 장을 만든다 — 라우터가 부르는 문. - - ⚠ 실패해도 도면은 연다 — 구조물 정본을 못 읽었다고 화면이 비면 사용자는 「고장」으로 - 읽는다. 그때는 빈 표 대신 사유가 적힌 한 줄이 뜬다. - ⚠ 늦게 부른다(함수 안 import) — B08 은 B05 를 부르고 B05 는 다시 B07 을 부를 수 있어 - 모듈 맨 위에서 부르면 맞물린다. - """ - payload = standard_payload(project_root, section_modes) - sheets = payload.get("sheets") or [] - # 이 도면 id 가 가리키는 장 하나만 남긴다 — 한 면에 한 장(2026-09-09, 그림이 붙으면서). - total = len(sheets) - picked = [ - sheet - for index, sheet in enumerate(sheets, start=1) - if sheet_drawing_id(index, total) == drawing_id - ] - return build_standard_drawing(drawing_id, label, {**payload, "sheets": picked}) diff --git a/B07_DesignDetail/B07_DesignDetail_Router.py b/B07_DesignDetail/B07_DesignDetail_Router.py index 5a4fea79..9c1bd58d 100644 --- a/B07_DesignDetail/B07_DesignDetail_Router.py +++ b/B07_DesignDetail/B07_DesignDetail_Router.py @@ -31,7 +31,6 @@ from B07_DesignDetail.B07_DesignDetail_Engine_Template import ( use_company_templates, use_title_fields, ) -from B08_Quantity.B08_Quantity_Router_StructureSheet import section_modes_of from B07_DesignDetail.B07_DesignDetail_Router_Support import ( CROSS_STANDARD_ID, LANDUSE_ID, @@ -271,10 +270,7 @@ async def get_design_drawing_list( try: route_id, project_root, longitudinal_path, bypass = await _confirmed_source(project_id) designs = await _designs_by_chainage(route_id) - modes = await section_modes_of(route_id) - drawings = await asyncio.to_thread( - _drawing_list, project_root, longitudinal_path, designs, modes - ) + drawings = await asyncio.to_thread(_drawing_list, project_root, longitudinal_path, designs) return DesignDrawingListResponse( project_id=str(project_id), route_id=route_id, drawings=drawings, dev_bypass=bypass ) @@ -372,7 +368,6 @@ async def get_design_drawing( longitudinal_path, drawing_id, source_design, - await section_modes_of(route_id), ) return DesignDrawingResponse( project_id=str(project_id), diff --git a/B07_DesignDetail/B07_DesignDetail_Router_Support.py b/B07_DesignDetail/B07_DesignDetail_Router_Support.py index 23182542..debe0f24 100644 --- a/B07_DesignDetail/B07_DesignDetail_Router_Support.py +++ b/B07_DesignDetail/B07_DesignDetail_Router_Support.py @@ -48,11 +48,6 @@ from B07_DesignDetail.B07_DesignDetail_Engine_Cad_Standard import ( STANDARD_LABEL, build_standard_cross_drawing, ) -from B07_DesignDetail.B07_DesignDetail_Engine_Cad_StandardSheet import ( - SHEET_ID_PREFIX, - sheet_items, - standard_drawing_for, -) from B07_DesignDetail.B07_DesignDetail_Engine_Cad_Table import ( QUANTITY_VALUE_KEYS, ) @@ -113,7 +108,6 @@ def _drawing_list( project_root: Path, longitudinal_path: Path, designs: dict[int, dict[str, Any]] | None = None, - section_modes: dict[float, str] | None = None, ) -> list[DesignDrawingItem]: longitudinal = _read_json(longitudinal_path) station_by_chainage = _station_map(longitudinal) @@ -205,10 +199,7 @@ def _drawing_list( confirmed=bool(manifest_drawings.get(drawing_id, {}).get("confirmed")), ) ) - # 표준도 — **제원 조합마다 한 장**이라 장이 나뉜다(2026-09-09). 구조물이 없어도 한 장은 - # 남긴다: 단추가 사라지면 「없어진 것」처럼 보이고 사유를 읽을 자리도 없어진다. - for drawing_id, label in sheet_items(project_root, section_modes): - drawings.append(DesignDrawingItem(id=drawing_id, kind="standard", label=label)) + # 표준도(구조물도)는 2026-09-13 B08 「구조물도」 탭으로 이관 — 사용자 확정 ③, PLAN 3장 ④. _store_drawing_numbers(project_root, drawings) return drawings @@ -410,7 +401,6 @@ def _read_drawing( longitudinal_path: Path, drawing_id: str, stored_design: dict[str, Any] | None = None, - section_modes: dict[float, str] | None = None, ) -> tuple[str, str, dict[str, Any], bool, dict[str, float | None] | None]: """(kind, label, drawing, confirmed, quantity_table)를 반환한다. @@ -442,11 +432,6 @@ def _read_drawing( stored_table = manifest_entry.get("quantity_table") table = stored_table if kind == "cross" and isinstance(stored_table, dict) else None return kind, label, saved, True, table - if drawing_id == SHEET_ID_PREFIX or drawing_id.startswith(f"{SHEET_ID_PREFIX}_"): - # 표준도 — 제원 조합 한 벌이 한 장. 도각은 두르지 않는다(2026-09-08 사용자 지시). - label = dict(sheet_items(project_root, section_modes)).get(drawing_id, "표준도") - drawing = standard_drawing_for(project_root, drawing_id, label, section_modes) - return "standard", label, drawing, False, None if drawing_id == COVER_ID: # 표지는 설계 자료를 쓰지 않는다 — 템플릿 한 장이 곧 도면이다. diff --git a/B07_DesignDetail/B07_DesignDetail_Schema.py b/B07_DesignDetail/B07_DesignDetail_Schema.py index eb8efa66..ecd6f96b 100644 --- a/B07_DesignDetail/B07_DesignDetail_Schema.py +++ b/B07_DesignDetail/B07_DesignDetail_Schema.py @@ -20,8 +20,7 @@ class DesignDrawingItem(BaseModel): "landuse", "plan_lidar", "cross_standard", - # standard: 표준도(구조물도) — 제원 조합 하나가 한 장. - "standard", + # 표준도(구조물도)는 2026-09-13 B08 「구조물도」 탭으로 이관 — kind 도 뺌. "blank", ] label: str @@ -59,8 +58,7 @@ class DesignDrawingResponse(BaseModel): "landuse", "plan_lidar", "cross_standard", - # standard: 표준도(구조물도) — 제원 조합 하나가 한 장. - "standard", + # 표준도(구조물도)는 2026-09-13 B08 「구조물도」 탭으로 이관 — kind 도 뺌. "blank", ] label: str diff --git a/B07_DesignDetail/B07_DesignDetail_UI_Page.ts b/B07_DesignDetail/B07_DesignDetail_UI_Page.ts index 0f31bc54..db6ed620 100644 --- a/B07_DesignDetail/B07_DesignDetail_UI_Page.ts +++ b/B07_DesignDetail/B07_DesignDetail_UI_Page.ts @@ -38,23 +38,14 @@ import { exportDrawing, fetchDesignDrawing, fetchDesignDrawingList, - fetchStandardSheets, - fetchStructureRevision, invalidateDesignDrawing, - putStandardSheetSpec, type CadDrawing, type DesignDrawingItem, type DesignDrawingResponse, type QuantityTable, - type StandardSheetsResponse, } from "./B07_DesignDetail_Api_Fetch"; import { appendStructureEntities } from "./B07_DesignDetail_UI_Cad_Structures"; import { createFrameTemplateEditor } from "./B07_DesignDetail_UI_FrameEdit"; -// 제원 칸은 B08 구조물도로 이관(2026-09-13, PLAN 3장) — 탭 배선 뒤 B07 표준도와 함께 뺌. -import { - buildStandardSpecPanel, - type StandardSpecResult, -} from "../B08_Quantity/B08_Quantity_UI_StructureSheet_Spec"; /** CAD 앱 수량 패널로 넘기는 설계 컨텍스트 (openwebcad DesignMeta와 동일 형식). */ interface DesignMeta { @@ -103,10 +94,6 @@ const CAD_TOAST_ACTION_MESSAGE = "aislo:b08:toast-action"; * -------------------------------------------------------------------------- */ export async function renderB07DesignDetail(root: HTMLElement): Promise { const projectId = localStorage.getItem(CURRENT_PROJECT_ID_KEY); - /** 표준도 장 목록 — 제원 폼이 쓰는 값. 진입 때 한 번 받고 저장 뒤 다시 받는다. */ - let standardSheets: StandardSheetsResponse["sheets"] = []; - /** 저장 뒤 폼이 다시 그려질 때 이어서 보여 줄 안내. */ - let specNotes: string[] = []; let workflowState: WorkflowState | undefined; let drawings: DesignDrawingItem[] = []; let drawingError: string | undefined; @@ -120,14 +107,6 @@ export async function renderB07DesignDetail(root: HTMLElement): Promise { if (drawingResult.status === "fulfilled") { drawings = drawingResult.value.drawings; devBypass = drawingResult.value.dev_bypass === true; - if (drawings.some((item) => item.kind === "standard") && projectId) { - // 표준도 제원 폼이 쓸 장 목록 — 실패해도 도면은 열려야 하므로 조용히 넘어간다. - try { - standardSheets = (await fetchStandardSheets(projectId)).sheets; - } catch { - standardSheets = []; - } - } } else drawingError = drawingResult.reason instanceof Error @@ -214,73 +193,8 @@ export async function renderB07DesignDetail(root: HTMLElement): Promise { const infoPanelHost = document.createElement("div"); infoPanelHost.className = "b07-info-host"; - /** - * [여기서 고치기] — 도면 하단표에서 **값을 정하는 자리**로 데려간다(확정 6 ㉮ - * 「한 곳에서 정하고 도면은 비추기만」). 표는 CAD 안에 그려져 단추를 못 달고, 제원 폼은 - * 도면 목록 아래라 장이 많으면 화면 밖으로 밀린다 — 그래서 **고정 액션 줄**에 둔다 - * (떠 있는 띠는 CAD 리본과 겹쳐 2026-09-02 에 걷어낸 자리라 다시 띄우지 않는다). - * ⚠ 값을 여기로 복사하지 않는다 — 폼 한 벌이 그대로 정본 창구다. - */ - const specJumpButton = createButton({ - label: "여기서 고치기", - variant: "ghost", - onClick: () => { - infoPanelHost.scrollIntoView({ behavior: "smooth", block: "nearest" }); - infoPanelHost.querySelector("select, input")?.focus(); - }, - }); - specJumpButton.title = "이 표의 값을 정하는 제원 칸으로 갑니다."; - specJumpButton.hidden = true; - - const showStandardSpec = (drawing: DesignDrawingItem): void => { - const index = Number(/_(\d+)$/.exec(drawing.id)?.[1] ?? "1") - 1; - const sheet = standardSheets[index]; - if (!projectId || !sheet) { - infoPanelHost.replaceChildren(); - specJumpButton.hidden = true; - return; - } - specJumpButton.hidden = false; - // 판정된 기울기는 **칸에 적지 않고 도움말로만** 비춘다 — 적어 두면 「안 정함」이 사라진다. - const judged = /1:([\d.]+)/.exec(drawing.label)?.[1] ?? null; - infoPanelHost.replaceChildren( - buildStandardSpecPanel( - sheet, - judged, - async (result: StandardSpecResult) => { - const { revision } = await fetchStructureRevision(projectId); - const saved = await putStandardSheetSpec(projectId, { - ...result, - base_revision: revision, - }); - // 정본이 바뀌었으니 표·그림을 **다시 받아** 그린다 — 화면이 두 번째 정본이 되면 안 된다. - drawingCache.delete(drawing.id); - standardSheets = (await fetchStandardSheets(projectId)).sheets; - // ⚠ 장 제목에 제원이 들어 있다 — 고쳤으면 **좌측 단추 글자도 따라가야** 한다. - // 목록을 통째로 다시 받지 않고 표준도 줄만 갈아 끼운다(2026-09-09 실화면에서 잡음). - for (const [order, item] of drawings.filter((d) => d.kind === "standard").entries()) { - const fresh = standardSheets[order]; - if (!fresh) continue; - item.label = `표준도 ${order + 1}장 (${fresh.title})`; - const name = findButton(item.id)?.querySelector(".b07-drawing-button__name"); - if (name) name.textContent = item.label; - } - specNotes = [`${saved.changed}개소에 반영했습니다.`, ...(saved.notes ?? [])]; - await loadDrawing(drawing, currentIndex); - return specNotes; - }, - specNotes, - ), - ); - specNotes = []; - }; - + // 표준도 제원 칸·[여기서 고치기]는 2026-09-13 B08 「구조물도」 탭으로 이관(PLAN 3장 ④). const updateInfoPanel = (drawing: DesignDrawingItem, response: DesignDrawingResponse): void => { - if (drawing.kind === "standard") { - showStandardSpec(drawing); - return; - } - specJumpButton.hidden = true; // 표준도 장이 아니면 갈 곳이 없다 if (drawing.kind !== "cross") { infoPanelHost.replaceChildren(); return; @@ -680,7 +594,7 @@ export async function renderB07DesignDetail(root: HTMLElement): Promise { // (2026-09-02 사용자 지시 — CAD 리본과 겹치던 떠 있는 띠를 여기로 옮김). const confirmButtonRow = document.createElement("div"); confirmButtonRow.className = "b07-drawing-actions__row"; - confirmButtonRow.append(specJumpButton, frameEditor.button, confirmButton); + confirmButtonRow.append(frameEditor.button, confirmButton); confirmActions.append(frameEditor.banner, confirmButtonRow); drawingPanel.append(infoPanelHost, confirmActions); diff --git a/B07_DesignDetail/B07_DesignDetail_UI_Panels.ts b/B07_DesignDetail/B07_DesignDetail_UI_Panels.ts index f1791aef..dab77c73 100644 --- a/B07_DesignDetail/B07_DesignDetail_UI_Panels.ts +++ b/B07_DesignDetail/B07_DesignDetail_UI_Panels.ts @@ -37,8 +37,6 @@ export const DRAWING_GROUPS: readonly { { label: "횡단면도", kind: "cross" }, { label: "토적도(유토곡선)", kind: "mass_haul" }, { label: "유역도(배수 유역도)", kind: "watershed" }, - // 표준도는 **제원 조합마다 한 장**이라 장이 나뉜다(2026-09-09) — 계획평면도와 같은 묶음. - { label: "표준도", idPrefix: "standard_sheet" }, { label: "용지도", idPrefix: "landuse" }, ]; diff --git a/B08_Quantity/B08_Quantity_Router_StructureSheet.py b/B08_Quantity/B08_Quantity_Router_StructureSheet.py index 1cf818ed..52a28d64 100644 --- a/B08_Quantity/B08_Quantity_Router_StructureSheet.py +++ b/B08_Quantity/B08_Quantity_Router_StructureSheet.py @@ -39,27 +39,6 @@ async def _project_root(project_id: UUID) -> str | None: return None -async def section_modes_of(route_id: int) -> dict[float, str]: - """측점별 단면유형(`left_cut` 등) — 구조물이 **성토면인가 절토면인가**를 가르는 근거. - - ⚠ 이것을 안 넘기면 판정이 통째로 「가를 근거 없음」으로 떨어져 **전 구조물이 종전값 - 1:0.3 으로 선다**(2026-09-09 실측). 값이 없는 것이 아니라 **안 넘긴 것**이었다. - ⚠ 표를 만드는 셈은 `section_modes_from_designs` 한 벌을 쓴다 — 부르는 쪽마다 다시 - 짜면 B08 과 갈린다. - ⚠ 과도기 — 노선 id 로 부르는 쪽은 B07 표준도 도면뿐임. - 탭 배선 뒤 B07 에서 표준도를 빼면 함께 지움. - """ - from B06_Section.B06_Section_Repository import get_cross_section_designs - from B08_Quantity.B08_Quantity_Engine_UnitQuantity import section_modes_from_designs - - try: - designs = await run_with_connection(get_cross_section_designs, route_id) - except Exception: - logger.exception("B08 구조물도 단면유형 조회 실패: route_id=%s", route_id) - return {} - return section_modes_from_designs(designs) - - def project_structure_sheets( project_root: str, section_modes: dict[float, str] | None, diff --git a/B08_Quantity/B08_Quantity_UI_StructureSheet_Spec.ts b/B08_Quantity/B08_Quantity_UI_StructureSheet_Spec.ts index 8e238b1c..49398984 100644 --- a/B08_Quantity/B08_Quantity_UI_StructureSheet_Spec.ts +++ b/B08_Quantity/B08_Quantity_UI_StructureSheet_Spec.ts @@ -3,7 +3,7 @@ * 표준도 **제원 입력 칸** — 장 하나가 곧 제원 조합 하나이므로 여기서 고치면 그 조합 전부. * * ⚠ 2026-09-13 B07 에서 이관(PLAN 3장) — 옛 자리 `B07_DesignDetail_UI_StandardSpec.ts`. - * B07 표준도 목록이 과도기 동안 이 파일을 함께 씀 — 그래서 모양(CSS)을 **이 파일이 스스로 넣음**. + * 모양(CSS)은 옛 B07 페이지 CSS 에서 옮겨 **이 파일이 스스로 넣음**. * * 왜 여기인가 (PLAN 4-5b) — `phase: "detail"` 칸(돌 종류·조달·뒷길이·전면 기울기)을 그리는 * 화면이 없었다(2026-09-09 실측: B06 구조물 폼은 b05 phase 열 칸만 그림). B06 은 @@ -58,7 +58,7 @@ const THICKNESS_TYPES = new Set(["masonry_wet", "masonry_dry"]); const STYLE_ID = "b08-spec-style"; -/* 옛 B07 페이지 CSS(`B07_DesignDetail_UI_Style.css`)에서 옮긴 것 — 두 페이지가 같은 모양을 보게. */ +/* 옛 B07 페이지 CSS(`B07_DesignDetail_UI_Style.css`)에서 옮긴 것. */ const CSS = ` .b08-spec { display: flex; flex-direction: column; gap: var(--spacing-8); padding: var(--spacing-12); border-radius: var(--radius-lg); } .b08-spec__title { margin: 0; font-size: var(--text-body-sm); font-weight: 600; } diff --git a/resources/tester/test_b07_standard_spec_blinding_weep.py b/resources/tester/test_b07_standard_spec_blinding_weep.py index 61278557..6eea04fb 100644 --- a/resources/tester/test_b07_standard_spec_blinding_weep.py +++ b/resources/tester/test_b07_standard_spec_blinding_weep.py @@ -101,14 +101,18 @@ def test_안_정하면_국가기준_기본이_뜬다() -> None: assert 물구멍 and "Ø50" in 물구멍[0] and "2㎡당" in 물구멍[0], 물구멍 -def test_여기서_고치기_단추가_고정_액션_줄에_있다() -> None: - """확정 6 ㉮ — 표는 CAD 안이라 단추를 못 달아 **고정 액션 줄**에 둔다(값 복사본 없음).""" +def test_제원_칸이_구조물도_탭_표_옆에_있다() -> None: + """확정 6 ㉮ 「한 곳에서 정하고 표는 비추기만」. + + ⓘ 2026-09-13 구조물도가 B08 탭으로 옮겨(PLAN 3장 ④) 표가 CAD 밖 HTML 로 서면서 폼이 + **표 바로 옆**에 붙음 — 옛 B07 [여기서 고치기] 단추(표가 CAD 안이라 필요했던 것)는 걷어냄. + """ page = (ROOT / "B07_DesignDetail" / "B07_DesignDetail_UI_Page.ts").read_text(encoding="utf-8") - assert '"여기서 고치기"' in page - assert "confirmButtonRow.append(specJumpButton" in page - # 표준도 장에서만 뜬다 — 다른 도면에는 갈 곳이 없다. - assert "specJumpButton.hidden = false" in page - assert "specJumpButton.hidden = true" in page + assert "specJumpButton" not in page, "B07 에 표준도 제원 칸 흔적이 남았다" + sheet = (ROOT / "B08_Quantity" / "B08_Quantity_UI_StructureSheet.ts").read_text( + encoding="utf-8" + ) + assert "buildStandardSpecPanel(" in sheet # 폼에 버림 칸이 섰다 — 끄는 자리가 화면에 있다(확정 8-2). form = (ROOT / "B08_Quantity" / "B08_Quantity_UI_StructureSheet_Spec.ts").read_text( encoding="utf-8" From 533187e87555745de70ee709a18837b17317ba7b Mon Sep 17 00:00:00 2001 From: umsangdon Date: Sun, 13 Sep 2026 15:04:39 +0900 Subject: [PATCH 2/4] =?UTF-8?q?chore(plan):=20=EB=B0=9B=EA=B8=B0=20?= =?UTF-8?q?=EC=95=9E=20=EA=B3=B5=EC=9A=A9=20=EB=AA=85=EC=84=B8=EB=A5=BC=20?= =?UTF-8?q?dev=20=EC=99=80=20=EA=B0=99=EC=9D=80=20=EB=82=B4=EC=9A=A9?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EB=93=B1=EB=A1=9D=20(blob=206aaac6ab=20?= =?UTF-8?q?=EB=8C=80=EC=A1=B0=20=EC=9D=BC=EC=B9=98)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq --- docs/raw/verification/2026-09-13_축C_명세.md | 105 ++++++++++++++++--- 1 file changed, 89 insertions(+), 16 deletions(-) diff --git a/docs/raw/verification/2026-09-13_축C_명세.md b/docs/raw/verification/2026-09-13_축C_명세.md index a0e7dc79..6aaac6ab 100644 --- a/docs/raw/verification/2026-09-13_축C_명세.md +++ b/docs/raw/verification/2026-09-13_축C_명세.md @@ -31,26 +31,36 @@ | 무엇 | 자리 | 상태 | | --- | --- | --- | -| 공종 축 마스터 | `resources/data_work_item_master/work_item_master_2026-01-01.json` | ✅ 섬 | -| 자원 축 산출물 | `resources/data_cost_resource_axis/resource_axis_2026-01-01.json` | ✅ **418줄** | -| 못 맞춘 목록 | `resources/data_cost_resource_axis/unmatched_2026-01-01.json` | ⚠ **497줄** | -| 뒤 패스 코드 | `B09_Estimation/B09_Estimation_ResourceAxis*.py` (6파일) | ✅ 섬 | +| 공종 축 마스터 | `resources/data_work_item_master/work_item_master_2026-01-01.json` | ✅ 섬 (477공종·456표) | +| 뒤 패스 코드 | `B09_Estimation/B09_Estimation_ResourceAxis*.py` (6파일) | ✅ 섬 — **매번 메모리에서 새로 돎** | +| `data_cost_resource_axis/*.json` | 418줄·못맞춤 497 | ⛔ **옛 산출물. 정본 아님** | -**`stats` 실측** +### ⚠⚠ 2026-09-13 정정 — 앞서 적은 418/497 은 **죽은 파일**이었음 + +**브레인이 틀렸음.** `write_resource_axis` 는 **정의만 있고 부르는 곳이 한 군데도 없음**(확인 완료). +그 JSON 둘은 옛 마스터로 한 번 돌려 남긴 자취이고, **B09 는 실행할 때마다 메모리에서 새로 맞춤.** + +**살아 있는 실측** (랩탑 메인 조사, 지금 코드로 돌린 값) ``` -rows 418 · unmatched 497 -skipped_forms : coefficient 19 · reference 64 · undetermined 75 -policy : axis=resource_only · work_item_axis_owner=B08 - material_amounts_are_before_surcharge=true +맞춘 줄 575 노임 532 · 기계 43 · 자재 0 ⚠ 자재 축이 통째로 안 섬 +못 맞춤 508 +건너뛴 표 참조 63 · 미판정 73 · 계수 19 ``` -**⇒ 남은 일은 「만들기」가 아니라 「채우기」임.** +**⇒ 못 맞춘 508 은 한 덩어리가 아니라 둘임.** -못 맞춘 497줄의 주된 사유는 파일 안에 그대로 적혀 있음 — -**「카탈로그에 없는 이름 (기계·자재 카탈로그 미확보 포함)」.** -즉 막힌 것은 **단가가 아니라 이름·코드 목록조차 없는 것**임. -(예: `보통휘발유 (주연료)` · `체인오일 (일반오일)` — 이름은 품셈에 있는데 받을 코드가 없음) +| 갈래 | 수 | 무엇이 필요한가 | +| --- | ---: | --- | +| 카탈로그에 없는 이름 | 271 | **STmate 목록 894개로 풀릴 후보** (11장) | +| 뭉친 줄 이름 못 풂 등 | 약 230 | **표 읽기 문제** — 목록이 와도 안 풀림 | + +일감을 **둘로 갈라 잡을 것.** 「목록이 오면 다 풀린다」는 틀림. + +⭐ **제일 큰 구멍은 자재 0** — 자재 축이 아예 안 서고 있음. 여기부터 볼 것. + +**산출물 파일의 자리** — 정본은 **메모리 실행**임. `write_resource_axis` 는 **시험·조사용 덤프**로만 +두고 **정본으로 읽지 말 것.** 옛 JSON 둘은 지우지 말고 그대로 두되 **근거로 쓰지 말 것.** --- @@ -64,8 +74,17 @@ FP-<절>-<절>-<절> 예) FP-04-02-02 (벌목, 5m 미만) - 정본은 **품셈 절 번호**. 표의 행은 그 절의 **조건별 변형**(`variant` 칸)임 - **이름은 표시용, 잇기는 코드로.** 이름으로 맞추는 코드가 남아 있으면 그것이 곧 결함임 -- 부모·잎이 있음 — `FP-09-15` 는 부모이고 잎이 답구간·답외구간임. - **부모 코드에 수량을 붙이지 말 것** +- 부모·잎이 있음. ⚠ **「부모에 수량 금지」는 반쪽만 맞았음** — 2026-09-13 정정. + **부모가 두 모양이고 규칙이 다름**(랩탑 메인 실측). + + | 모양 | 보기 | 규칙 | + | --- | --- | --- | + | **갈래 고르기형** | `FP-10-12`(덤프·사토·표토 운반) · `FP-09-15`(표토제거) · `FP-05-24` · `FP-09-13` | **부모에 붙이지 말 것.** 잎 하나를 골라야 함. **못 고르면 오류로 세울 것** — 조용히 부모에 붙이면 금액 0 이 됨 | + | **단계 합산형** | `FP-09-04`(파쇄+집토) · `FP-09-05`(절취10%+깍기90%+집토) · `FP-12-38`(유로폼) | **내역 한 줄이 곧 부모임.** 부모에 수량을 붙이되 일위대가는 **잎들의 합**으로 조립 — 부모가 곧 조합 일위대가 | + + ⚠ **가름은 자동 판정하지 말 것.** 마스터에 `parent_mode` 칸을 두고 + 기본 `choose_one`, **합산형만 사람이 명시**. 표 모양으로 짐작하면 조용히 틀림. + ⇒ 지금 `FP-09-04`·`FP-10-12`·`FP-09-15` 는 일위대가 제목이 아예 없어 **금액 0** 임(실측). ### ⭐ 코드 체계 — 브레인 확정 (2026-09-13, 사용자 지시) @@ -195,6 +214,25 @@ AR-<종류>-<8자리 16진> 카탈로그에 없는 자원 - 방향은 **양쪽 다** — 우리 이름으로도, 실무·품셈 이름으로도 코드를 찾을 수 있어야 함 - **한 이름이 두 코드에 걸리면 오류로 세울 것.** 조용히 첫째를 고르면 안 됨 +### ⚠⚠ 2026-09-13 정정 — 별칭에 **범위** 칸이 있어야 함 + +**전역 양방향 사전은 틀림.** 별칭은 **표 범위에서만 참**임. + +`리핑암 = 파쇄암` 은 **산림품셈 10-11 f 표 안에서만** 성립함 — 우리 「리핑암」은 지반유형 +(캘 수 있는가)이고 품셈 「파쇄암」은 운반할 때의 상태(부서졌는가)라 **발파암도 캐고 나면 +파쇄암**임. 그 표가 토사·파쇄암·발파암을 따로 두었고 10-12 [주]③ 의 토량환산계수가 +**파쇄암 1/1.35 = 암절취(리핑)** 이라 그 표 안에서만 이어짐 (근거는 `B09_Estimation_UnitPrice.py:464~477` 주석). + +``` +별칭 한 줄 = { from , to , scope } + scope = 이 별칭이 참인 코드 범위 예) "FP-10-11" + ⛔ scope 없는 별칭은 오류로 세울 것 +``` + +흩어진 세 벌(`Handoff_Mapping` 의 파쇄암·암절취 · B09 의 파쇄암만 · +B08 인계본 `ground_class_aliases` — **B09 가 안 읽음**)을 한 벌로 모으되 +**범위를 붙여 옮길 것.** 범위 없이 합치면 발파암이 리핑암으로 조용히 섞임. + --- ## 6. 이중계상 경계 — 축으로 판정 @@ -422,6 +460,41 @@ STmate 코드는 `B00001`·`M00042` 꼴로 **층 글자 + 다섯 자리**이고 --- +## 14. `#갈래` 는 무엇인가 — 2026-09-13 판정 + +랩탑 메인 지적이 맞음. 일위대가 제목 446 중 **202 가 `B-<코드>#<한글이름>`** 이고, +지금 B09 는 그 한글을 **정규화해 맞추고** 있음(`normalize_variant_key`). +2장 「이름으로 맞추면 결함」과 부딪혀 보임. + +**가름** — 둘은 **다른 자리**임. + +| | 무엇 | 이름으로 맞춰도 되나 | +| --- | --- | --- | +| 공종 축 ↔ 자원 축 | **서로 다른 표를 잇는 것** | ⛔ 안 됨. 코드로만 | +| `#갈래` | **한 공종 안의 조건 딱지**(토질·암종·규격) | ⚠ 지금은 이름으로 맞추고 있어 약함 | + +**⇒ 판정 — 마스터의 `variant_key` 를 정본으로 삼을 것.** + +- 마스터 **456표 전부에 `variant_key` 가 이미 있음**(브레인 확인). 그런데 **B09 가 안 읽고** + 변형 문자열에서 매번 다시 만들어 씀 +- B09 가 **`variant_key` 를 읽게** 고칠 것. 문자열 재파생은 **폴백으로만** 남김 +- 폴백이 실제로 쓰이면 **로그로 남길 것** — 조용히 다른 갈래에 붙는 것을 잡으려는 것임 + +--- + +## 15. ⏸ 판정 보류 — 사용자 확인이 필요한 것 + +### 콘크리트가 어느 축으로 가나 (랩탑 메인 ⓔ) + +- **전개식**은 `material` 로 보내고, **관측 원단위 JSON** 은 `unit_price` 로 되어 있어 **두 벌**임 +- 브레인이 근거를 찾지 못함 — 지목된 「확정 3차 ⑥」은 백업 원문에서 **막자갈 식** 건이라 이 건이 아님 +- 한편 코드 주석은 「콘크리트는 `unit_price` 로 감 — **B09 가 배합을 분해**」, + 「배합 성분은 산출물에 나타나면 안 됨」이라 **`unit_price` 쪽으로 기울어 보임** +- ⛔ **임의로 고르지 않음.** 틀리면 **시멘트·모래·자갈이 두 번 세어지거나 통째로 빠짐** +- ⇒ **사용자 확인 대기.** 그때까지 양쪽을 **그대로 두고 기록만** 할 것 + +--- + ## 10. 고칠 때 이 문서는 **브레인이 관리함.** 코드 창이 계약을 바꿔야 하면 **고치지 말고 브레인에게 알릴 것** — From 78b5ba0b71720efa2770ccc7b5589ee158786b85 Mon Sep 17 00:00:00 2001 From: umsangdon Date: Sun, 13 Sep 2026 15:09:54 +0900 Subject: [PATCH 3/4] =?UTF-8?q?knowledge(=EC=B6=95C):=20=EC=8B=9D=20?= =?UTF-8?q?=EC=96=B8=EC=96=B4=20=ED=99=95=EC=A0=95(=EB=B9=84=EA=B5=90?= =?UTF-8?q?=C2=B7SUM=C2=B7LOOKUP=20=EA=B7=BC=EC=82=AC=C2=B7round=20?= =?UTF-8?q?=EC=82=AC=EC=82=AC=EC=98=A4=EC=9E=85)=20=C2=B7=20=EB=B3=84?= =?UTF-8?q?=EC=B9=AD=EA=B3=BC=20=EB=8C=80=EC=B2=B4=20=EA=B0=80=EB=A6=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_0154EMdwPYNPuKc9eZv8SLEX --- docs/raw/verification/2026-09-13_축C_명세.md | 30 ++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/docs/raw/verification/2026-09-13_축C_명세.md b/docs/raw/verification/2026-09-13_축C_명세.md index 6aaac6ab..d920e7d8 100644 --- a/docs/raw/verification/2026-09-13_축C_명세.md +++ b/docs/raw/verification/2026-09-13_축C_명세.md @@ -229,6 +229,18 @@ AR-<종류>-<8자리 16진> 카탈로그에 없는 자원 ⛔ scope 없는 별칭은 오류로 세울 것 ``` +### ⚠ 별칭과 **대체**는 다른 것 — 섞지 말 것 (2026-09-13) + +| | 무엇 | 어떻게 | +| --- | --- | --- | +| **별칭** | **같은 것을 다르게 부름** — 단가가 같음 | 별칭표에 `scope` 와 함께 | +| **대체** | **대응하는 것이 아예 없어 다른 것으로 갈음** — 단가가 다를 수 있음 | ⛔ 별칭표에 넣지 말 것. **설계가 고르게** 드러낼 것 | + +가르는 법 — **카탈로그에 원래 이름이 있나** 보면 됨. +보기) 노임 카탈로그에 `화약취급공` 은 있고 `화약공` 은 없음 ⇒ **표기 차이(별칭 후보)**. +`소운반인부` 는 **카탈로그에 아예 없음** ⇒ 보통인부로 붙이는 것은 **대체**이지 별칭이 아님. +**대체는 도메인 판단이라 사용자 확인 자리임.** + 흩어진 세 벌(`Handoff_Mapping` 의 파쇄암·암절취 · B09 의 파쇄암만 · B08 인계본 `ground_class_aliases` — **B09 가 안 읽음**)을 한 벌로 모으되 **범위를 붙여 옮길 것.** 범위 없이 합치면 발파암이 리핑암으로 조용히 섞임. @@ -424,14 +436,25 @@ STmate 코드는 `B00001`·`M00042` 꼴로 **층 글자 + 다섯 자리**이고 | `rounding` | **줄마다 다름** — 아래 | | `source` | `auto` · `user` · `library` — 줄마다 출처 표시 | -### 식 언어 — 최소로 정함 +### 식 언어 — 확정 (2026-09-13 보강, 소광리 53탭 전수 실측 반영) ``` 연산 + - * / ^ ( ) -함수 SQRT · MIN · MAX · IF · LOOKUP(표이름, 키, 열이름) +비교 = <> < <= > >= ← IF 조건에 씀 +함수 SQRT · MIN · MAX · SUM · IF(조건, 참, 거짓) + LOOKUP(표이름, 키, 열이름) 근사 일치 (기본) + LOOKUP_EXACT(표이름, 키, 열이름) 정확 일치 참조 refs 의 이름(앞 줄) · vars 의 이름(제원) ``` +**실측 근거** — ROUND 105 · INT×100/100 36 · ROUNDDOWN 25 · ROUNDUP 9 · +IF 36(비교식 11) · VLOOKUP 13(**전부 근사**) · SUM 47. +⇒ `SUM` 과 **비교 연산**이 빠져 있었음. 넣음. + +**`LOOKUP` 은 근사 일치가 기본** — 실무 13건이 전부 근사이고 뒷길이표가 +35/45/55/60 **구간 표**라 그것이 맞음. ⚠ **표는 키 오름차순으로 저장할 것** — +근사 일치는 정렬을 전제로 함. 정확 일치가 필요하면 `LOOKUP_EXACT` 를 쓸 것. + ⚠ **LOOKUP 은 반드시 있어야 함** — 실무 표가 뒷길이별 원단위표를 `VLOOKUP` 으로 참조함 (35/45/55/60 → 채움콘크리트·고임돌·돌중량). 표는 양식과 **한 벌로** 저장할 것. @@ -445,6 +468,9 @@ STmate 코드는 `B00001`·`M00042` 꼴로 **층 글자 + 다섯 자리**이고 mode : floor(버림) · round(반올림) · ceil(올림) · none 실무 한 표 안에 INT(x*100)/100 · ROUND(,2) · ROUNDUP(,2) · 없음이 섞여 있었음 ``` + ⭐ **`round` = 사사오입(HALF_UP)** 으로 못 박음 — 구조물도는 **실무 엑셀을 본뜨는 표**이고 + 엑셀 `ROUND` 가 사사오입임. ⚠ **B09 내부 계산의 은행가 반올림과 헷갈리지 말 것** — + 자리가 다름(7장). 은행가가 필요하면 `round_half_even` 을 따로 쓸 것 4. **식을 버리지 말 것.** 값만 저장하면 납품 규격(`적용산식`·`적용산식설명`)을 못 맞추고, 라이브러리 양식형도 못 만듦 (12장) From 6a4507e5961d653e7a9f9d905f5cab3b859bad91 Mon Sep 17 00:00:00 2001 From: umsangdon Date: Sun, 13 Sep 2026 15:10:56 +0900 Subject: [PATCH 4/4] =?UTF-8?q?chore(plan):=20=EB=B0=9B=EA=B8=B0=20?= =?UTF-8?q?=EC=95=9E=20=EA=B3=B5=EC=9A=A9=20=EC=A7=84=EB=8B=A8=20=EB=AC=B8?= =?UTF-8?q?=EC=84=9C=EB=A5=BC=20dev=20=EC=99=80=20=EA=B0=99=EC=9D=80=20?= =?UTF-8?q?=EB=82=B4=EC=9A=A9=EC=9C=BC=EB=A1=9C=20=EB=93=B1=EB=A1=9D=20(bl?= =?UTF-8?q?ob=209ed418e8=20=EB=8C=80=EC=A1=B0=20=EC=9D=BC=EC=B9=98)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq --- .../2026-09-13_축C_자재0과_못맞춘줄_진단.md | 121 ++++++++++++++++++ 1 file changed, 121 insertions(+) create mode 100644 docs/raw/verification/2026-09-13_축C_자재0과_못맞춘줄_진단.md diff --git a/docs/raw/verification/2026-09-13_축C_자재0과_못맞춘줄_진단.md b/docs/raw/verification/2026-09-13_축C_자재0과_못맞춘줄_진단.md new file mode 100644 index 00000000..9ed418e8 --- /dev/null +++ b/docs/raw/verification/2026-09-13_축C_자재0과_못맞춘줄_진단.md @@ -0,0 +1,121 @@ +# 축 C 1장 — 자재 0 과 못 맞춘 줄 진단 + +작성 2026-09-13 · **랩탑 메인** · 읽기 전용 진단(코드 무변경) · 앞 조사 `2026-09-13_축C_공종이름잇기_전수조사.md` 의 이어짐 + +> **방법** — 지금 코드·지금 마스터로 `build_resource_axis` 를 메모리에서 돌림(쓰기 없음). +> 진단 스크립트는 세션 임시 폴더에만 두었음 — 같은 수치를 다시 내려면 이 문서의 기준을 따르면 됨. +> **기준** — 공종 마스터 477공종·456표 · 카탈로그 = 노임 132 + 기계 613 + 관급 자재 6,999 · +> STmate 목록 `…/STmate 분석/30_원자료/stmate_code_name_list.csv`(M 228 · X 96 · L 37). + +--- + +## 0. 한눈에 + +| 물음 | 답 | +| --- | --- | +| 자재가 왜 0 인가 | **사급 자재 카탈로그가 아예 없음.** 합친 카탈로그의 자재는 **관급(나라장터) 6,999건뿐**이고 품셈 자재(종자·비료·결속선·못·폭약)는 사급이라 이름부터 없음 | +| 못 맞춘 508 중 임도가 쓰는 공종 몫 | **138줄 · 42공종** (임도가 쓰는 코드 60개 기준). 나머지 370줄은 조림·방제·벌채 장 | +| 138 중 진짜 자원 이름 | **약 40종** — 나머지는 표의 갈래 딱지(보통암·깨기·치즐소모량·토질 이름)를 이름으로 읽은 것 = **표 읽기 문제** | +| STmate 목록이 풀어 주는 몫 | 40종 중 **이름이 겹치는 것 13종**, 그중 품셈 칸 규격만으로 1건이 정해지는 것 **거의 없음** — 규격은 **설계가 골라야 함** | + +**⇒ 명세 1장 「카탈로그에 없는 이름 271 = STmate 로 풀릴 후보」는 너무 넓음.** +271 대부분(체인오일·예취기·농약·벌채산물)은 **임도 밖 공종**이고, 임도 안 몫도 절반은 표 읽기 문제임. + +--- + +## 1. 자재 0 — 뿌리 넷 + +| # | 뿌리 | 실측 | 풀 길 | +| --- | --- | --- | --- | +| 1 | **사급 자재 원천 없음** | `load_combined_catalog()` = 노임+기계+관급. `B09_Estimation_MaterialCatalog.py` 머리말 「사급 = 없다(유료 물가지 미결 No.18)」 · 관급 파일도 철근·레미콘·아스콘 **빠짐** | 사급 자재 **이름·규격·단위 목록**(`AR-M`) — 단가는 보류(명세 §2③) | +| 2 | **품셈 칸에 규격이 없음** | 관급에 이름이 있어도(각재 8 · 철선 13 · 박리제 4 · 아스팔트 6) 품셈 칸은 「각재」 뿐 → `ResourceCatalog.resolve` 가 None | 규격은 **설계·라이브러리가 고름**. 매칭은 「규격 미정 — 후보 N」으로 드러냄(성공 아님) | +| 3 | **자재 칸에 자재 아닌 것이 섞임** | 공구손료(버켓손료·와이어손료) · 운반비 · 연료비 · 작업 단계(단끊기·골파기·씨덮기·새채집·모래부설·유공관설치·철근가공조립) | 자원 종류 가름(경비·하위 공종) — **이름 목록으로는 안 풀림** | +| 4 | **구조물 표는 값 없이 이름만** | 12장 측구·집수정·맨홀·날개벽 표 — 「콘크리트 \| 펌프차타설 \| ㎥ \| (빈칸)」. 숫자가 없어 머리 줄로 걸러짐(자원 0줄) | 수량은 **B08 구조물도 원단위**에서 옴 — 3장 구조물도가 이 자리를 채움 | + +**품셈 전체의 자재 후보 줄**(분류 딱지 「자재·재료·잡재료」 또는 자재 단위 + 숫자) — 약 90줄, 그중 값이 있고 +공종 형태가 쓸 수 있는 줄 **71줄(65종) 전부 못 맞춤 목록에 올라 있음**. 조용히 사라진 자재 줄은 없음(값 없는 머리 줄 제외). + +--- + +## 2. 임도 범위로 좁힌 못 맞춘 줄 — 138줄 + +**임도가 쓰는 코드** = 매핑표(`resources/data_work_item_mapping/…`) + B08·B09 소스에 박힌 `FP-` 60개와 그 잎. + +| 사유 | 줄 | +| --- | ---: | +| 카탈로그에 없는 이름 | 91 | +| 뭉친 자원 줄의 이름을 못 풂 | 27 | +| 자원은 알아봤으나 값을 못 읽음 | 12 | +| 규격이 없어 같은 이름 여럿 중 못 고름 | 3 | +| 값 묶음·갈래 수 안 맞음 · 장비 규격×갈래 · 작업조 표 | 5 | + +**맞춘 줄(임도 범위)** 244 = 노임 218 · 기계 26 · **자재 0**. + +### 2-1. 「카탈로그에 없는 이름」 91 의 속 — 둘로 갈림 + +| 갈래 | 예 | 공종 | 어느 일감 | +| --- | --- | --- | --- | +| **진짜 자원** | 종자·비료·피복제·침식안정제·색소 | FP-05-24-01/02 | **이름·규격 목록** | +| | 폭약·뇌관·비트·착암기·화약공 | FP-09-05-01 | 〃 | +| | 콘크리트커트·브레이드·잡자재 | FP-09-11-01 | 〃 | +| | 공기압축기(3.5㎥/min)·소형브레이커·어어호스(3/4인치) | FP-09-19-03 | 〃 | +| | VR관·고무링·지수활제·기초콘크리트·거푸집 · 흄관·접합몰탈·크레인 · 파형강관·커플링밴드 | FP-12-11-01/02/03 | 〃 | +| | 유공관설치·소운반인부 · 봉상후렉시블 다짐기·설치비 | FP-12-10 · FP-12-15 | 〃 (설치비는 경비) | +| **표 딱지를 이름으로 읽음** | 보통암·경암·연암·풍화암 | FP-09-04-01 · 09-05-02 · 09-19-01 | **표 읽기** | +| | 깨기 · 치즐소모량(본/hr) | FP-09-13-07~18 (12공종) | 〃 | +| | 모래ㆍ사질토ㆍ점토… (토질 갈래) | FP-09-19-01 | 〃 | +| | 단목·전간목·전목 | FP-04-01-01 | 〃 | +| | 대형브레이커+유압식백호우(무한…) (조합 딱지) | FP-09-04-01 | 〃 | + +### 2-2. 「뭉친 줄」 27 · 「값 못 읽음」 12 — 전부 표 읽기 + +- FP-04-02-01 100본당(흉고 구간 13줄) · FP-12-04 합판거푸집(합판·각재·철선·못·박리제) · FP-12-09-02/03 측구 · FP-13-04-04 찰쌓기 +- FP-09-13-02~18 「장비(90%) \| 유압식백호우…」 · 「들어내기 \| 유압식백호우…」 — **배분율·단계 딱지 줄의 값**을 못 읽음 + +⚠ **FP-12-04 합판거푸집은 두 일감에 걸림** — 뭉친 줄을 풀어도(표 읽기) 합판·각재·철선·못·박리제가 +사급이라 목록이 있어야 섬(자재 0 뿌리 1·2). + +--- + +## 3. 진짜 자원 약 40종 — 어디서 코드를 받을 수 있나 + +| 이름(품셈) | 우리 카탈로그 | STmate 목록 (`name 〔size〕`) | 판단 | +| --- | --- | --- | --- | +| 대형브레이커 | 기계 정확 6규격 | 대형브레이커 〔0.7㎥〕 | 규격을 **옆 칸·조합에서** 받으면 섬 | +| 소형브레이커 | 기계 「소형브레이커(공압식)/(전기식)」 | 없음 | **범위 별칭**(형식 고르기) | +| 공기압축기(3.5㎥/min) | 기계 「공기압축기(이동식)」 | 없음 | **범위 별칭** + 규격 | +| 크레인 | 기계 크레인(무한궤도/타이어) 45 | 크레인(타이어) 〔10톤〕 · 트럭탑재형 크레인 〔5톤·10톤〕 | 설계 고르기 | +| 화약공 | 없음 | L 목록에 **화약취급공** | **범위 별칭** — 근거 확인 필요 | +| 소운반인부 | 없음 | 없음 | 보통인부로 볼지 **답 필요** | +| 종자 | 없음 | 종자 〔생태복원형,초본류 / 목본류〕 6 | `AR-M` + **규격 설계 고르기** | +| 비료 | 없음 | 복합비료 〔21-17-17〕 · 인산질비료 | `AR-M` + 규격 | +| 폭약 · 뇌관 | 없음 | 폭약 〔28mm(메가마이트Ⅰ)〕 · 전기뇌관 〔3.5m〕 | `AR-M` | +| 합판 · 각재 · 철선 · 못 · 박리제 | 관급에 이름 있음(규격 여럿) | 합판(내수) 〔12×1220×2440〕 · 각재 〔외송〕 · 결속선(철선) 〔#20, 0.9mm〕 · 철못 〔N 50〕 | 관급 코드 또는 `AR-M` — **규격 고르기** | +| 파형강관 | 없음 | 파형강관 〔Φ800·Φ1000, 2.7t〕 7 | `AR-M` + 관경은 **B08 관 정본**에서 | +| 모래 | 없음 | 모래 〔지역별 상차가 6〕 | `AR-M` — 규격이 **지역**임 | +| 이형철근 | 없음(관급에서 빠짐) | 이형철근 D13 · SD400 15 | `AR-M` + 규격 | +| 치즐 | 없음 | 치즐 〔0.7m3〕 3 | `AR-M` | +| 피복제·침식안정제·색소·착암기·콘크리트커트·브레이드·잡자재·에어호스·VR관·고무링·지수활제·흄관·접합몰탈·커플링밴드·다짐기·유공관 | 없음 | **없음** | `AR-M/X` 새로 — 이름·단위는 **품셈 원문**에서 | + +⇒ **STmate 가 이름·규격을 대 주는 것 13종**, 나머지 약 27종은 **품셈 원문 이름으로 `AR-` 를 새로 냄**. +**규격은 대부분 한 벌로 안 정해짐** — 명세 §11 「(이름 + 규격) 한 쌍이 키」에 따라 품셈 칸만으로는 성공 아님. + +--- + +## 4. 곁 발견 + +- **기계 카탈로그 이름 5건에 표 머리글이 붙어 있음** — `5220-0015 소형브레이커(전기식)시 간 당(10-7)분류번호…` · + `6532-0220` · `7101-0450` · `7120-0746` · `7995-0050`. 원천 `mach_base_2026.json` 파싱 흔적. 이름으로 찾으면 안 걸림 +- **품셈 원문 오기가 이름으로 들어옴** — 「어어호스」(에어호스) · 「뿜어뿥이기」(FP-05-24-01) +- **요소·인산의 「46%·20%」** (FP-05-10 F0115) — 소요량이 아니라 **성분비**. 값으로 읽으면 틀림 + +--- + +## 5. 판정·답이 필요한 것 + +| # | 물음 | 누구 | +| --- | --- | --- | +| 1 | 못 맞춘 줄 일감의 **범위를 임도 60코드로 좁혀도 되나** (370줄은 뒤로) | 브레인 | +| 2 | 품셈 칸에 규격이 없는 자원 — **「규격 미정 · 후보 N」으로 드러내고 설계·라이브러리가 고르게** 두는가 | 브레인 | +| 3 | 범위 별칭 후보 — 화약공→화약취급공 · 소형브레이커→(공압식) · 공기압축기→(이동식) · 소운반인부→보통인부 | **사용자 확인** (도메인 판단) | +| 4 | 사급 자재 `AR-M` 목록의 자리 — 새 폴더 한 벌(이름·규격·단위·출처·STmate 코드) | 브레인 |