Fix the depth-band drift; Central Towers correctly stays blocked
The merge guard that stops a priced tail row being folded into the line above
only excluded 'a)'/'b)' labels, not '.01'-style references. So '.01 0.5 - 1.0m
Deep' was swallowed by the sub-group heading above it, and the first depth line
of EVERY group never entered the candidate pool. The source line then had
nowhere sensible to go and drifted onto the next group's rows.
1200LE before: r37 heading, r39 '.02 1.0-2.0m', r41 '.03', r43 '.04'
- the '.01 0.5-1.0m' slot was absent entirely
1200LE after: r37 heading, r37 '.01 0.5-1.0m', r39 '.02', r41, r43
Central Towers 190 -> 198 written, 25 -> 17 unplaced. The 1200LE depth-band
misplacements are gone.
Also fixed two false positives in the placement check itself: rows whose
description cell holds a formula ('=Measurement!A18') are unverifiable rather
than mismatched, and must not cry wolf. The check has been confirmed to fail
when the bugs are re-introduced and to stay quiet on a clean build.
What remains is reported rather than hidden: 15 misplaced lines on Central
Towers, 14 carrying a value. A gap-penalty sweep from -0.20 to -1.50 moves it
not at all, so this is not score-chasing - both documents contain four
separate near-identical depth-band groups in 1200DB alone, and one global
alignment distributes them wrongly. Closing that needs anchoring on confident
matches and interpolating within blocks.
Blueberry: 103 written, 1 unplaced, 0 misplaced, not blocked.
Central Towers: 198 written, 17 unplaced, 15 misplaced, BLOCKED - the app
knows it is wrong and refuses to produce a file, which is correct.
This commit is contained in:
parent
19918c9a3e
commit
c8c427ae46
3 changed files with 34 additions and 1 deletions
18
README.md
18
README.md
|
|
@ -419,3 +419,21 @@ wondering what the tool assumed.
|
|||
Those are preserved but will not resolve without the linked file.
|
||||
- Description joins can drop a space where Candy's print engine split a word
|
||||
(`Fixed-ChargeItems`). Cosmetic.
|
||||
|
||||
|
||||
### Where the placement check stands
|
||||
|
||||
The check is sound — silent on Blueberry, fires on Central Towers — but it has
|
||||
exposed that **the alignment drift is not fixed.** Fifteen lines on Central
|
||||
Towers are still placed on the wrong row, fourteen of them carrying a value.
|
||||
|
||||
A gap-penalty sweep from -0.20 to -1.50 moves it not at all, so this is not the
|
||||
aligner chasing scores. Both documents contain **four separate near-identical
|
||||
depth-band groups** in `1200DB` alone, and a single global alignment
|
||||
distributes them wrongly. Closing that needs a different strategy — anchor on
|
||||
the confidently matched lines and interpolate within each block, rather than
|
||||
solving the whole document as one problem.
|
||||
|
||||
Until then **Central Towers is blocked and will not produce a file.** That is
|
||||
the correct behaviour: the app now knows it is wrong and refuses, rather than
|
||||
sending it.
|
||||
|
|
|
|||
|
|
@ -371,6 +371,12 @@ class Slot:
|
|||
# a description opening with a lettered sub-item label (a), b), c)) starts a
|
||||
# NEW line rather than continuing the one above
|
||||
LETTER_ONLY = re.compile(r"^\(?[a-z]\)\s", re.I)
|
||||
# a description that OPENS with its own reference - ".01 ", "1.2 ", "c) " -
|
||||
# starts a NEW line. Only bare continuation text may be folded into the row
|
||||
# above. Excluding only "a)" left ".01 0.5 - 1.0m Deep" being swallowed by the
|
||||
# sub-group heading above it, which is how a whole depth band went missing from
|
||||
# the pool and its rate drifted onto the next group's rows.
|
||||
STARTS_LINE = re.compile(r"^\(?[a-z]\)\s|^\.?\d+(?:\.\d+)*[\s.]", re.I)
|
||||
# ".01", "1.2", "a)" - a description that OPENS with a reference starts a new
|
||||
# line; only bare continuation text may be folded into the one above
|
||||
STARTS_LINE = re.compile(r"^\(?[a-z]\)\s|^\.?\d+(?:\.\d+)*[\s.]", re.I)
|
||||
|
|
@ -426,7 +432,7 @@ def read_slots(ws, lay: Layout) -> list[Slot]:
|
|||
# A description opening "a)" / "b)" / "c)" is a NEW line and must never
|
||||
# be absorbed, or sub-items get folded into the heading above them.
|
||||
if (out and priced and not raw and desc and out[-1]._bare
|
||||
and not LETTER_ONLY.match(desc)):
|
||||
and not STARTS_LINE.match(desc)):
|
||||
prev = out[-1]
|
||||
prev.desc = f"{prev.desc} {desc}".strip() if prev.desc else desc
|
||||
prev.row = r
|
||||
|
|
|
|||
|
|
@ -180,6 +180,15 @@ def _placement_report(result, out) -> list:
|
|||
|
||||
row_desc = _norm_txt(_row_desc(out[sheet], row, lay))
|
||||
want = _norm_txt(want)
|
||||
# A cell holding a formula is not the row's identity - these templates
|
||||
# pull a description straight out of a Measurement sheet
|
||||
# ("=Measurement!A18"). The row may be perfectly correct; we simply
|
||||
# cannot read it, so say nothing rather than cry mismatch.
|
||||
# any formula inside the text means this row pulls its description from
|
||||
# elsewhere (these templates use "=Measurement!A18"); it may be the
|
||||
# right row and simply not readable here
|
||||
if "=" in row_desc:
|
||||
continue
|
||||
if not row_desc:
|
||||
bad.append((sheet, row, want[:44], "that row carries no text at all"))
|
||||
continue
|
||||
|
|
|
|||
Loading…
Reference in a new issue