sheetgraph: read what real sets actually draw (#87 phase 3b) - #266
Merged
Conversation
Five bid sets across five GCs, run through scripts/graph-audit.mjs. Every fix here ships with a fixture reproducing the real failure; none was reachable from synthetic tests. - Two-tier headers: WALLS (PLAN DIRECTION) over N|E|S|W. Sub-labels are single letters, not vocabulary, so they anchored nothing and the wall columns banded to whichever neighbour was nearest -- N/E into BASE, S/W into CEILING. BASE read 'VWB-1 - FRP-1, FRP-1A, PT' instead of 'VWB-1'; a polluted base column is a wrong number in the bid. A run of >=2 adjacent non-vocab tokens inside the header span is a sub-tier, the parent is the span above that covers the run, and sub-anchors carry real BOUNDS (equal-width by drafting convention) rather than centers -- a bounded anchor claims only what falls inside it. No parent, no sub-tier. - DOOR/WINDOW/PARTITION schedules are refused as finish tables by title (they carry MARK too, and a finish code chaining to a door mark is a confidently wrong product). Kept when the title also says FINISH or MATERIAL; the drop is named in graph.notes. - The right band edge is generous only for prose-shaped last columns; a legend 300px away no longer bleeds into CEILING. - SYMBOL/COMMENTS join the finish vocabulary -- a set headed SYMBOL | MATERIAL DESCRIPTION | MANUFACTURER extracted nothing and chained zero definitions; it now chains 165 of 273 finish cells. - Room names with apostrophes (KID'S CRUNCH) read as names again. Named, not papered over: keynote bubbles still read as room tags and refuse with 'no schedule row' -- honest, but the tag was never a room. That needs the bubble's geometry; tracked on #87. opentakeoff-mcp 0.9.45. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
✅ Deploy Preview for opentakeoff ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Five real bid sets across five general contractors, run through
scripts/graph-audit.mjs. Every fix ships with a fixture reproducing the real failure — none of these were reachable from synthetic tests, which is the point of the field harness.The one that would have cost money
Two-tier headers.
WALLS (PLAN DIRECTION)is a merged parent overN | E | S | W. The sub-labels are single letters, not vocabulary words, so they anchored nothing and every wall column banded to whichever neighbour was nearest — N and E into BASE, S and W into CEILING. BASE readVWB-1 - FRP-1, FRP-1A, PTinstead ofVWB-1. A polluted base column is a wrong number in the bid.A run of ≥2 adjacent non-vocabulary tokens inside the header's own span is now a sub-tier; the parent is the span above that actually covers the run; sub-anchors are labelled
WALLS Nso the column keeps both halves of its meaning. Crucially they carry real bounds, not centers — sub-columns under a merged parent are equal-width by drafting convention, and a bounded anchor claims only what falls inside it. Center-based banding was not enough: a wall code left-aligned at its rule line still sat nearer the narrow BASE header. No parent above the run, no sub-tier.The one that would have been confidently wrong
A DOOR SCHEDULE is not a finish schedule. Those tables carry a MARK column, so the finish hunt indexed one as 54 finish rows on a real grocery set — and a finish code colliding with a door mark chains to a door. Refused by title, only when the title doesn't also say FINISH or MATERIAL (when in doubt, keep), drop named in
graph.notes. The test asserts the collision case directly: a DOOR SCHEDULE loaded first with a markCPT-1, and room 101's floor still chains to Shaw carpet tile.The rest
SC-1 TL-3 CERAMIC TILE. Generous only for prose-shaped last columns now.SYMBOL-headed finish tables — a set headedSYMBOL | MATERIAL DESCRIPTION | MANUFACTURER | PRODUCTextracted nothing and chained zero definitions. Now chains 165 of 273 finish cells.KID'S CRUNCHreads as a name again.Numbers
Scored fixtures unchanged at 1.000/1.000 across all three phases (9/9, 33/33, 18/18); 26 lib tests, 166 MCP tests green. On the gym set that drove this: 39/43 rooms resolved, 273 finish cells, 165 chained to a product definition, 4 refusals all correctly named.
Named, not papered over
Keynote and detail bubbles still read as room tags — bare 2-digit numbers (
11–23on one set,10–27on another) come back refusing with "no schedule row". The refusal is honest but the tag was never a room. Distinguishing them needs the bubble's geometry, not its text; staying on #87.Ships as opentakeoff-mcp 0.9.45.
🤖 Generated with Claude Code