feat(arch): arch_plan_from_spec, three arch_* critique focuses, the arch pack, lean 64 and the counts
The three track-F branches are merged; this is the integration that makes the
twelve SECTION 25 tools one surface.
- engineering/arch/spec.py: a whole plan from one document - walls with their
openings, stairs, room labels measured off the walls just drawn, the
exterior chains and the schedules - inside one transaction. Everything the
model, the wall engine or the stair symbol can refuse is refused before the
transaction opens, by path; a room point in no closed face rolls it back,
and so does a cancelled request, under the anyio shield of pid/spec.py.
EXAMPLE_SPEC's rooms measure 4825 x 5750 and 3825 x 5750 - the net floor,
computed by hand in the tests.
- engineering/arch/critique.py: arch_room_unlabelled, arch_wall_gap (50 mm,
one issue per pair of walls, measured to the wall body so an L corner and a
T stem both read as joined) and arch_opening_clash. One index per critique
run; a drawing without an ACADMCP_ARCH record yields nothing. Each focus
has a positive and a negative fixture.
- TOOL_PACK_NAMES gains "arch" (the twelve SECTION 25 tools); lean gains
arch_wall, arch_opening, arch_room and arch_plan_from_spec and reaches 64;
the arch tag ranks after mech, so SECTION 25 files as one `architecture`
group - 241 tools in 26 groups.
- Six golden tuning cases, two of them Turkish, the arch_plan_from_spec alias
record, the shared-command allowlist reconciled with what the merged records
claim, the inventory regenerated, the registry snapshot retaken, and the
README figures taken from check_doc_numbers rather than typed.
- Two more Turkish golden cases close the reconciliation's alias gaps
("vaziyet planı çiz" -> arch_plan_from_spec, "oda alanlarını hesapla" ->
arch_rooms_detect); the arch records carry vaziyet / alan / oda / kat planı
in diacritic and ASCII-folded spellings, because the search tokenizer splits
on a non-ASCII letter. BOUNDARY and AREA stay with boundary_trace and
analysis_measure_entity on purpose, recorded in the arch alias comment.
Tuning top-1 73/84, top-3 83/84; holdout top-3 15/15.
- tests/test_token_suite.py: TOOL_PACKS=core,mech now drops the arch pack
too (measured 193 = 236 - 9 - 22 - 12).
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FKFStjEFzpGyLq5bMpWxTd
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
ad5a32a34a
commit
6e004cc658
@@ -964,6 +964,15 @@ LEAN_TOOL_NAMES = frozenset(
|
||||
"mech_dimension_part",
|
||||
"sheet_frame",
|
||||
"titleblock_apply",
|
||||
# Architecture (track F) - the four a lean client needs to draw a
|
||||
# plan: walls, the openings they host, a measured room label, and the
|
||||
# whole plan in one call. `arch`-pack tools, so TOOL_PACKS=core hides
|
||||
# them from a lean surface too; with the five mechanical/sheet ones
|
||||
# above, lean is 64.
|
||||
"arch_wall",
|
||||
"arch_opening",
|
||||
"arch_room",
|
||||
"arch_plan_from_spec",
|
||||
}
|
||||
)
|
||||
|
||||
@@ -977,7 +986,7 @@ SOLID_TOOL_NAMES = frozenset(
|
||||
# mechanically should not pay for the P&ID surface, and a client that never
|
||||
# talks to a live seat should not pay for the environment surface. Styles and
|
||||
# page setup (SECTION 18/19) are drafting essentials and stay in core.
|
||||
TOOL_PACK_NAMES = ("core", "pid", "settings", "mech")
|
||||
TOOL_PACK_NAMES = ("core", "pid", "settings", "mech", "arch")
|
||||
PACK_TOOL_NAMES: dict[str, frozenset[str]] = {
|
||||
"pid": frozenset(
|
||||
{
|
||||
@@ -1041,6 +1050,26 @@ PACK_TOOL_NAMES: dict[str, frozenset[str]] = {
|
||||
"hatch_material",
|
||||
}
|
||||
),
|
||||
# SECTION 25 - the architectural plan: the wall network with its openings,
|
||||
# stairs, rooms and their reader, schedules, grid and symbols, the
|
||||
# furniture / sanitary catalogue, the exterior chains and the whole plan
|
||||
# from one spec (track F spec §8).
|
||||
"arch": frozenset(
|
||||
{
|
||||
"arch_wall",
|
||||
"arch_opening",
|
||||
"arch_stair",
|
||||
"arch_room",
|
||||
"arch_rooms_detect",
|
||||
"arch_schedule",
|
||||
"arch_grid",
|
||||
"arch_symbol",
|
||||
"arch_catalogue_list",
|
||||
"arch_catalogue_insert",
|
||||
"arch_dimension_chains",
|
||||
"arch_plan_from_spec",
|
||||
}
|
||||
),
|
||||
}
|
||||
|
||||
_active_tool_profile: dict | None = None
|
||||
@@ -5715,7 +5744,9 @@ async def drawing_finalize(
|
||||
pid_unconnected_equipment — silent on a sheet with no P&ID symbols, plus the
|
||||
mechanical focuses mech_missing_centreline, mech_unhatched_section,
|
||||
mech_view_misaligned, mech_duplicate_dimension, mech_thread_unrepresented,
|
||||
mech_bom_balloon_mismatch — silent on a sheet with no mechanical part),
|
||||
mech_bom_balloon_mismatch — silent on a sheet with no mechanical part, plus the
|
||||
architectural focuses arch_room_unlabelled, arch_wall_gap, arch_opening_clash —
|
||||
silent on a sheet with no ACADMCP_ARCH record),
|
||||
then saves to disk, exports a screenshot, and returns the DWG path.
|
||||
|
||||
Raises ToolError if any validator 'error' finding is present, or if critique reports an
|
||||
@@ -5976,7 +6007,9 @@ async def drawing_critique(
|
||||
"(silent on a drawing with no P&ID symbols), and the mechanical focuses "
|
||||
"mech_missing_centreline, mech_unhatched_section, mech_view_misaligned, "
|
||||
"mech_duplicate_dimension, mech_thread_unrepresented, "
|
||||
"mech_bom_balloon_mismatch (silent on a drawing with no mechanical part). "
|
||||
"mech_bom_balloon_mismatch (silent on a drawing with no mechanical part), and "
|
||||
"the architectural focuses arch_room_unlabelled, arch_wall_gap, "
|
||||
"arch_opening_clash (silent on a drawing with no ACADMCP_ARCH record). "
|
||||
"None = run all.",
|
||||
),
|
||||
] = None,
|
||||
@@ -9783,7 +9816,7 @@ async def drawing_export_dwg(
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# ── SECTION 25: Architecture (11 tools) ─────────────────────────────────────
|
||||
# ── SECTION 25: Architecture (12 tools) ─────────────────────────────────────
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
@@ -10461,6 +10494,66 @@ async def arch_symbol(
|
||||
raise ToolError(str(exc)) from exc
|
||||
|
||||
|
||||
# ── arch: the whole plan (integration) ──
|
||||
|
||||
|
||||
@cad_tool(
|
||||
summary="Draw a whole floor plan - walls, doors, windows, stairs, rooms, chains, schedules - in one transaction.",
|
||||
cost="mutate",
|
||||
)
|
||||
@mcp.tool(
|
||||
annotations={"title": "Architecture: Plan From Spec", "destructiveHint": False},
|
||||
tags={"arch", "create"},
|
||||
)
|
||||
async def arch_plan_from_spec(
|
||||
spec: Annotated[
|
||||
dict,
|
||||
Field(
|
||||
description=(
|
||||
"{sheet: {intent, sheet_size, scale (denominator, 50 = 1:50)}, lang: 'en'|'tr', "
|
||||
"poche: bool, walls: [{id, axis: [[x,y],...], thickness, justification, "
|
||||
"material, closed}], openings: [{id, wall, kind: 'door'|'window', offset, "
|
||||
"width, swing, hand, sill, height, tag}], stairs: [{id, start, direction_deg, "
|
||||
"width, risers, riser_height, going, kind, turn}], rooms: [{id, name, number, "
|
||||
"at}], chains: {sides: ['bottom','left']}, schedules: [{kind: "
|
||||
"'doors'|'windows'|'rooms', at: [x,y]}]}"
|
||||
)
|
||||
),
|
||||
],
|
||||
ctx: Context = None,
|
||||
) -> dict:
|
||||
"""A whole plan drawn inside one transaction: walls with their hosted doors and
|
||||
windows, stairs, room labels whose areas are measured off the walls just drawn,
|
||||
the exterior dimension chains and the door / window / room schedules.
|
||||
|
||||
Every item is validated before the transaction opens, so a refusal leaves the
|
||||
drawing untouched and names its path (`walls[1].thickness: ...`,
|
||||
`rooms[0].area: ...`). What only the drawing can refuse - a room point in no
|
||||
closed face - rolls the transaction back, and so does a cancelled request (the
|
||||
rollback runs under an anyio shield). The result carries each step's own
|
||||
result, the wall engine's `omitted` list and the three `arch_*` critique
|
||||
focuses run over the committed plan.
|
||||
|
||||
Refused by name: an unknown key, no walls, an unknown language or material, a
|
||||
non-finite or non-positive number, an arc segment in a wall axis, an opening
|
||||
that overlaps another or runs past its wall segment (both ids named), a typed
|
||||
room `area` (areas are measured, never typed), an unknown chain side or
|
||||
schedule kind, and a transaction that cannot be opened. Catalogue furniture,
|
||||
the grid and symbols are separate tools (`arch_catalogue_insert`, `arch_grid`,
|
||||
`arch_symbol`).
|
||||
"""
|
||||
from engineering.arch.spec import draw_plan_from_spec
|
||||
|
||||
await ctx.info(
|
||||
f"arch_plan_from_spec: {len((spec or {}).get('walls') or [])} wall(s), "
|
||||
f"{len((spec or {}).get('openings') or [])} opening(s)"
|
||||
)
|
||||
try:
|
||||
return await draw_plan_from_spec(_backend(ctx), spec)
|
||||
except ValueError as exc:
|
||||
raise ToolError(str(exc)) from exc
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# ── RESOURCES ───────────────────────────────────────────────────────────────
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user