Commit Graph
4 Commits
Author SHA1 Message Date
Umut CANandClaude Opus 5.5 db5b4d3ef8 fix(understand): the bare Russian "to" before a panel is a wiring callout
A Russian P&ID often closes a load's text with the panel it is wired to:
'... кВт' on one line, then 'к CP1' ('to CP1') or 'к щиту CP-2' ('to
switchboard CP-2') on the next. wiring_target knew 'подключение к ...' but
not the bare preposition. On the field P&ID most loads therefore had no
panel and no measurable cable.

The preposition к / ко now counts when it is a whole word and the panel is
the next word, optionally after щиту / шкафу / панели. The к of кВт is
never read as the preposition. The new test failed before the change.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FKFStjEFzpGyLq5bMpWxTd
2026-09-24 16:10:24 +03:00
Umut CANandClaude Opus 5.5 ac32700ba8 fix(understand): what the field test found — P&ID lengths need no equipment, caret notation, numbered rooms
Run on a real P&ID pair (kept outside the repository), the pipe takeoff wrote
an empty table. Three causes, each fixed with a test that failed first:

- Measured on the P&ID, a run still needed equipment tags at both ends,
  which only routing on the layout needs. Few pipes on a field P&ID end on
  a tagged outline. On the P&ID each piece now goes to the room it lies in:
  cut at the room outlines when the P&ID has room faces, else to the
  nearest room label. Diameters are kept piece by piece. On the layout a
  takeoff that could not route every run now says how many, why, the drawn
  length left to the control rows, and that length_source='pid' with
  force=True measures on the P&ID instead.
- A TEXT stores its line breaks in caret notation ('6^JROOM'), which
  plain() left as it was, so a room label's number read as '6^J...'.
  plain() now decodes ^J, ^M, ^I and '^ ', leaving MTEXT stacks
  ('\S1^2;') alone.
- Labels that only mention a room were read as rooms: a control cabinet
  naming the room it serves, or a note pointing into a room. An unnumbered
  label that names equipment is no room. Without room faces, when the
  drawing numbers its rooms, only numbered labels take pieces.

On the field pair the takeoff now fills its table, and every room key is a
real room number. The comparison with the hand-made workbook stays with
the user's files. README collected tests: 4981. The suite passes (4980, 1
xfailed).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FKFStjEFzpGyLq5bMpWxTd
2026-09-24 15:57:18 +03:00
Umut CANandClaude Opus 5.5 fb2953c324 fix(understand): a line number is not an equipment tag
parse_tag started a token at the first letter, so '100-P-001', a line
number that begins with its size, read as the pump tag P-001. The review of
the network engine found this. On a P&ID the phantom tag can capture a
valve beside the line as equipment, or collide with the real pump P-001.

A token that is the tail of a word beginning with a digit is no longer a
tag. The same text still yields T101 in 'LINE 100-P-001 TO T101', and
P-001 alone is still a tag. The new test failed before this change; the
label, network, describe, scale, cable and plant-pair suites all pass
(160 tests).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FKFStjEFzpGyLq5bMpWxTd
2026-09-24 12:48:56 +03:00
Umut CANandClaude Opus 5.5 9ab0ae1773 feat(understand): the snapshot, the vocabulary and the label parsers; MAX_DXF_BYTES 512 MB; the office extra
Track H's foundation, landed on main before its three groups branch.

- engineering/understand/snapshot.py: one bulk read of a drawing into frozen
  WCS records (OCS translated through backends/ocs.py, text decoded, an
  INSERT boxed by its block geometry without its attribute texts). A DXF is
  read with ezdxf after the size check; the headless engine's document is
  read under its own lock; the live engine exports the active document with
  Document.Export(<tmp>/snap, "DXF", <set of all>) - never renamed, deleted
  afterwards - and a DWG is opened read-only, exported and closed. Measured on
  AutoCAD 2026: ".dxf" is refused with Invalid argument, the file lands as
  snap.DXF, model space, paper space and unused block definitions all reach
  it, and the selection set does not narrow a DXF export.
- engineering/understand/labels.py: %%c, \U+2205, the U+2300 sign, o-stroke
  and MTEXT format runs all read as one diameter spelling; sizes are kept as
  drawn and never equated; Cyrillic look-alike capitals fold into Latin tags;
  panels, wiring callouts and electrical data (kW, phases, volts, N, VFD) in
  EN / TR / RU / NL / DE. A power that is not written stays None.
- engineering/understand/vocab.py: layer classification with a confidence and
  the deciding keyword, supply / return words, room labels and block kinds in
  five languages. A CIP layer without a direction word is not guessed.
- MAX_DXF_BYTES defaults to 512 MB (a real layout was 188 MB); the refusal
  names the size and the variable. New `office` extra (openpyxl), also in
  `full`; uv.lock regenerated.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FKFStjEFzpGyLq5bMpWxTd
2026-09-24 11:38:59 +03:00