docs(pid): track A shipped — CLAUDE.md, README, changelog with the live COM smoke record

scripts/smoke_pid_com.py runs the whole track against the live AutoCAD in
a new document. ComBackend.connect() is lazy by design, so the script reads
reachability from system_status()["connected"] rather than from connect()
as the plan sketched, and closes its document without saving unless --keep
is passed. On this machine (AutoCAD 2026, "25.1s (LMS Tech)") it exits 0:
5 nodes, 4 edges, 0 dangling, confidence_min 1.0, 0 critique issues,
2 XDATA chunks — identical to the headless engine on the same spec. The
first attempt exited 2 on a stale win32com gen_py cache (a package folder
holding only __pycache__); an environment fault, no backend change needed.

A/B against v1.5.1 published as ab-v1.5.1-vs-v1.6.0-dev.json: 26/29 ->
29/29, three miss -> pass, zero regressed. check_doc_numbers.py now names
the report and the two row labels in one place (AB_REPORT, AB_*_LABEL),
and README.md / benchmarks/README.md carry the new rows; the v1.5.0 and
v1.4.0 tables stay as history.

README: P&ID row, the showcase and catalogue images, the token table
re-measured (161 / 44,930 by default, 152 / 41,420 with TOOL_PACKS=core,
lean 50 / 14,007), every stale count reconciled (154 -> 166 registered,
149 -> 161 advertised, corpus 158/672 -> 162/731 by the same count, 19 ->
20 groups, 6 -> 8 resources, six-task matrix with pid_roundtrip), a
"Known limitations of the P&ID track" subsection, and the snapshot line at
this machine's 2423 collected tests (CI has not run on this tree; noted in
the changelog with the pre-existing 1369 vs 1363 drift).

CLAUDE.md: section 17, sections 5 and 7 counts, TOOL_PACKS, the two 1.6
contracts and the reader rules. Spec status -> implemented. The plan and
spec markdown were reformatted by ruff (fenced Python only) because
`ruff format --check .` was already red on them at HEAD and the gate
requires the whole tree clean.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FKFStjEFzpGyLq5bMpWxTd
This commit is contained in:
Umut CAN
2026-09-16 13:34:06 +03:00
co-authored by Claude Opus 5
parent 8d9c444b76
commit 2be5e4180d
9 changed files with 2604 additions and 789 deletions
@@ -1,7 +1,7 @@
# v1.6 Track A — P&ID expert and reader
**Date:** 2026-09-15 · **Status:** approved; implementation plan at
`docs/superpowers/plans/2026-09-15-v1.6-pid-implementation.md` · **Parent:** `2026-09-15-v1.6-roadmap-design.md` (track A) ·
**Date:** 2026-09-15 · **Status:** implemented 2026-09-16 (21 tasks of
`docs/superpowers/plans/2026-09-15-v1.6-pid-implementation.md`; live COM smoke on AutoCAD 2026 recorded in `CHANGELOG.md` Unreleased; A/B vs v1.5.1 29 / 29) · **Parent:** `2026-09-15-v1.6-roadmap-design.md` (track A) ·
**Baseline:** v1.5.1
## 1. Summary
@@ -104,25 +104,28 @@ get the whole track for the price of the two new contracts.
```python
@dataclass(frozen=True)
class Port:
name: str # "in", "out", "suction", "discharge", "N1", "signal"
name: str # "in", "out", "suction", "discharge", "N1", "signal"
x: float
y: float
direction_deg: float | None # outward direction a line leaves along; None = radial
direction_deg: float | None # outward direction a line leaves along; None = radial
kind: Literal["process", "signal"]
radius: float = 0.0 # radial ports only (bubbles): line starts on the circle
radius: float = 0.0 # radial ports only (bubbles): line starts on the circle
@dataclass(frozen=True)
class SymbolSpec:
name: str # block name, see 4.5
family: Literal["valve", "rotating", "vessel", "heat", "misc", "instrument", "connector", "marker"]
primitives: tuple[dict, ...] # block_define entity specs (section 5.1)
attdefs: tuple[dict, ...] # block_define attdef specs
name: str # block name, see 4.5
family: Literal[
"valve", "rotating", "vessel", "heat", "misc", "instrument", "connector", "marker"
]
primitives: tuple[dict, ...] # block_define entity specs (section 5.1)
attdefs: tuple[dict, ...] # block_define attdef specs
ports: tuple[Port, ...]
bbox: tuple[float, float, float, float] # xmin, ymin, xmax, ymax — declared, tested
bbox: tuple[float, float, float, float] # xmin, ymin, xmax, ymax — declared, tested
layer_class: Literal["PROCESS-VALVES", "PROCESS-EQUIPMENT", "INSTRUMENT-SYMBOL", "line"]
source: str
parametric: bool = False
params: dict = field(default_factory=dict) # the parameters a parametric spec was built from
params: dict = field(default_factory=dict) # the parameters a parametric spec was built from
```
`CATALOG_VERSION = "1"` is written into every INSERT's XDATA. A change to any
@@ -253,6 +256,7 @@ cost `mutate`, aliases `acad=("BLOCK", "BEDIT", "ATTDEF")`.
async def entity_get_xdata(self, handle: str, app_name: str | None = None) -> dict:
"""→ {"handle", "xdata": {app: [value, ...]}, "backend"}; unknown app → {} not an error"""
@abstractmethod
async def entity_set_xdata(self, handle: str, app_name: str, values: list) -> dict:
"""→ {"ok": True, "handle", "app_name", "value_count", "bytes", "backend"}"""