Files
willtools-demo/docs/ticket-knowledge-deltas.md
T
will 25592fa6c2
ci / test (push) Successful in 6m14s
WillTools 2026-09-09 -- clean snapshot of the development repo for review
History-free snapshot of the private development repository at 77a82eb.
Code, docs and the public catalogue only: no plant or job knowledge
layers, no client, job or producer names (tools/scrub.py clean against
the widened term list; a second word-level grep clean). The intro deck is
left out because its slide images cannot be checked for job drawings.
2026-09-09 08:35:15 -05:00

7.3 KiB
Raw Blame History

What this audit learned, sorted by where it belongs

Three scales. The test for which scale a lesson belongs to is: who would have to change for this to stop being true?

  • Plant — a different plant would answer differently. Goes in the knowledge file, never in code. Nothing here should be defaulted, because a wrong default reads as a missing value and the check then quietly does not run.
  • Tool — the code has the wrong model of the world. Goes in the repo.
  • Method — how to go about looking at all. Goes in the skill.

Plant — entries for the knowledge file

Each is stated with the evidence, because a plant setting nobody can trace back is one nobody dares change.

legend.printed_strand_count_is_per_piece — already false, and correctly so

The design summary for WP1 says (14) 1/2" 270K @ 28,920. The pieces print their own counts: WP210's section A-A prints (10), WP200's (6), WP199's (14). The 14 is the design family's figure.

I first wrote this up as a setting to change. It is already false, set at the job layer — checked against the merged config. So the five STR-QTY entries are not a misconfiguration: with the flag false the check reports them as WARN rather than FAIL, which is the intended soft signal that a piece carries fewer strands than its design family's maximum. Reading a WARN as a defect was my error, not the tool's.

legend.pattern_prefixes — the concept does not apply here

No sheet in this model carries a view named STRAND PATTERN… or REINFORCING PATTERN…. 0 of 204. The reinforcing schedule is the bill of materials table on sheet 1, and the per-piece strand count is inside section A-A. Until the check is repointed, LGD-MISSING fires on every WP ticket in the job and takes FC, FCI, PCF-NOTE and STR-NOTE down with it.

The BOM's strand row is linear feet

321 | 0010001 | M392 - 1/2" 270ksi Low Lax Strand on a 22'-11" piece is a length. Verified on two pieces:

piece BOM panel BOM / length section prints
WP199 321 22.9167 ft 14.007 (14)
WP210 249 24.9167 ft 9.993 (10)

A checker that reads that row as a quantity reports a 23x error on a correct ticket. This needs to be stated somewhere the tool can read it, because nothing in the row's text says "feet".

interference — P136 is exempt from everything, and a plant group went missing

Decided and applied. exempt_families: [P136] is now in the plant knowledge file. The reason, in Will's words: the disk anchor is placed to a nominal position and the crew rotates it on the form to suit, so the modelled orientation is a starting point rather than the built one. Anything it overlaps in the model is a consequence of that freedom, not a defect. This is separate from insert_bars, which exempts the bars belonging to a P136 — that entry already existed and is correct, and it works by symmetry rather than distance.

But the edit does not take effect yet, and the reason matters more than the edit. The generated project config is the last layer and it writes out every key at its merged-at-generation-time value, including exempt_families: []. So it freezes the past and overrides any later change made upstream. A plant edit is invisible until the project config is regenerated. Regenerating is Will's to do, from Revit.

The same mechanism has already lost something: the plant file defines

component_groups:
  - name: EMBED P76
    families: [SAMPLE_CLIENT_EMBED_P76, SR5602, SR6999]
    interferes: within_group

and the merged config carries only the job layer's CONNX TOP OF PANEL TO COLUMN group. Lists replace rather than merge, so the job layer's single entry deleted the plant's. The generated config even prints the substitution in its own header comments — the tool knows, and says so where nobody reads it.

Worth deciding separately: whether component_groups should merge by name instead of replacing wholesale. As it stands, any layer that wants to add one group silently discards every group defined above it.

interference.tolerance_in / min_thickness_in

Currently 0.125" with min_thickness_in unset, so thickness defaults to the same. The recurring overlap is 0.21–0.23". Whether that is acceptance or defect is a plant answer, and it decides nine findings.


Tool — the code has the wrong model

A ticket is more than one sheet

97 of the tickets in this job are 1 OF 2 + 2 OF 2 under the same sheet name; 9 are 1 OF 1. collect_context resolves a mark to a single sheet and returns whichever wins. Every ticket read this way is half a ticket, and everything on the other sheet is reported as missing. On twelve pieces this produced sixty findings from one cause; across the job it would produce roughly a thousand.

Fix: collect every sheet whose name equals the mark and treat the union as the ticket.

ValueString is not what prints

The handling dimensions carry ValueOverride = U+200E and still print their value. Any check that decides what the ticket says by reading ValueString, or by reading ValueOverride and finding it blank, will be wrong in one direction or the other. What the override is for is not established.

read_ticket field problems

  • thickness is returned in feet (0.667) under a name that reads as inches.
  • lifters come back with x and y as None — retracted, this was my error. Each lifter carries local, an (X, Y, Z) tuple in the panel's own frame; there are no x/y keys, and my probe asked for the ones that do not exist. local[0] is measured from the panel centre, so station = length / 2 + local[0]. Verified: WP200's four P136 sit at local[0] = ±7.208 on a 22.917 ft piece, giving 4.25 ft from the end, and the ticket's PICKING/STRIPPING diagram prints 4'-3". They agree exactly. The comparison that finds real defects was available the whole time.
  • What is genuinely missing is a named accessor: local[0] plus an undocumented centre-origin convention is how this went wrong. A station_ft(lifter, panel) helper would have made the mistake impossible.

tools/rvt.py crashes on hidden characters

Printing a result containing U+200E raises UnicodeEncodeError on a cp1252 console. Force UTF-8 on stdout in the tool rather than making every caller set PYTHONIOENCODING.

The scrub cannot read a PDF

Exported tickets carry the job name and the client's name in the title block, and scrub.py scans text. sample data/ and *.pdf are now gitignored, which is the containment, but the gate itself is blind to them.


Method — how to look

These are in docs/ticket-check.skill.md in full. In short:

  1. Render the page and look at it. Extracting a drawing's text stream drops dimensions without saying so, and produces confident wrong findings.
  2. Both values and both sources, or it is not a finding.
  3. Separate "they disagree" from "I could not find it" — and do not pad the second list. Three items reported as uncheckable were printed on sheet 1.
  4. One root cause is one finding, however many codes it fans into.
  5. A repeated family pair is one pattern, not one defect per piece.
  6. Arithmetic before alarm. 321 against 14 looks like a 23x error until you divide by the panel length.