Files
willtools-demo/knowledge/catalogue-rationale.md
T
will 8e6ee31596
ci / test (push) Successful in 6m18s
WillTools 2026-09-09 -- clean snapshot of the development repo for review
History-free snapshot of the private development repository at cbe45c5
(2026-09-09). Code, docs and public catalogue only; no plant or job
knowledge layers, no client or job names (tools/scrub.py clean). The
intro deck is left out of this snapshot because its slide images could
not be checked for job drawings.
2026-09-09 08:32:15 -05:00

1047 lines
53 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# WillTools -- catalogue -- rationale
Why the values in `knowledge.yaml` are what they are. Moved out of
that file so the keys the tool actually reads stay legible. NOTHING
HERE IS PARSED by anything -- it is for the reader, human or model.
Each section is named for the key it explains. The key itself keeps a
`# sources:` stub and a pointer back here, so no number sits in the
layer with its provenance out of sight.
Generated once by tools/layersplit.py; edit freely from here on.
---
## face_designations.frames
The closed set of frames of reference, and THE SIDES EACH ONE CAN NAME.
A vocabulary declaring a frame that is not one of these cannot be
resolved against anything, and neither can a token whose `side` does not
belong to its vocabulary's frame -- `side: near` under `frame: form` is
half an edit, and config_problems reports both.
TWO TOKENS NAME THE SAME FACE WHEN THEY HAVE THE SAME (frame, side).
That pair IS the identity of a face here, which is how a plant whose
near/far is anchored to the FORM can say that its N.F. and T.I.F. are one
face -- both `frame: form`, both `side: top` -- without either vocabulary
having to know about the other.
`both` belongs to every frame: a token like E.L. names all the faces the
vocabulary can name, so no frame is needed to resolve it.
## face_designations.vocabularies.near_far
------------------------------------------------------------------
LAYER POSITION, SEEN FROM THE DRAWING.
WHICH ANCHOR A PRODUCER USES IS NOT PUBLISHED AND IS NOT ASSUMED.
This vocabulary is the view-anchored reading: near and far measured
from the direction the elevation looks. It is a real convention and it
is NOT universal -- a producer may anchor the same two words to the
CASTING BED instead, so that "near face" simply means the face that
ends up on top in the form. That producer declares its own
form-anchored vocabulary in its own plant file (a map, so this one is
untouched) and selects that; it does not half-edit this one.
Which is exactly why `frame` is a field rather than a comment: the same
two tokens mean different things at different plants, and only the
frame says which.
E.L. is the odd one and it is why `side` exists separately from
`means`: "each layer" names BOTH faces at once, so it is symmetric --
flipping the view does not make it wrong. A check that treated it as
a single face and flipped it would invent a finding.
------------------------------------------------------------------
## orientation
==========================================================================
WHICH END OF A PIECE IS UP ONCE IT IS ERECTED.
==========================================================================
Owner, 2026-08-30, asked whether to wire or delete the two plant keys that
had been asking a producer to declare this:
"哪头朝上取决于 assembly origin。也就是 TOT。写入公共知识。
assembly origin 里面有一个朝上的头。"
-- which end is up depends on the ASSEMBLY ORIGIN, also called TOT; write
it into the public knowledge; the assembly origin has an up end in it.
WHY THIS IS PUBLIC AND NOT PLANT KNOWLEDGE. It is how a precast assembly is
built, not a house habit. The origin is placed as part of making the
assembly, and placing it IS the statement of which end goes up -- so there
is nothing for a producer to declare, and a key asking one to declare it is
asking the wrong question. The test this file applies to everything in it
holds: this identifies no client, no job and no producer.
WHAT IT REPLACED, AND WHY THAT MATTERS MORE THAN THE VALUE. The plant layer
used to carry `orientation.top_is_higher_global_z: true` -- "the top is the
end at the higher elevation in the model". That is a different MECHANISM,
not a different answer, and the difference is not cosmetic: global
elevation answers this for a wall panel stood on end and is meaningless for
a piece erected long-ways, where both ends are at the same height and the
winner is whatever the model's rounding happens to be. An origin has a
direction whichever way the piece is erected.
A HIGHER LAYER MAY STILL OVERRIDE. `up_end` is a MAP, so it deep-merges:
a producer whose assemblies genuinely do not carry a usable origin corrects
one field and inherits the rest. What it may not do is state a different
mechanism -- that is code, not data, and `up_end_rule()` reads exactly the
fields below.
## orientation.up_end.origin_up
---- the model-reading half ---------------------------------------
`origin_up` NULL WOULD NOT MEAN "the origin says nothing". It would mean
NOBODY HAS READ ONE YET -- the same distinction, for the same reason, as
`drawings.reinforcing_rule`: guessing which property of an origin
denotes its up end puts every erection anchor on the wrong edge at once,
silently, which is the exact failure this rule exists to end. It shipped
null and unverified for exactly as long as that was true.
IT IS NOW ANSWERED, and by measurement rather than by reasoning.
`AssemblyInstance.GetTransform()` returns a `Transform` whose `BasisY`
is the erected up direction. Read against independently measured
geometry -- extents unioned from each assembly's `GetMemberIds()` member
boxes and projected onto that assembly's own basis, so the correlation
is against the pieces and not against the transform itself:
BasisY exactly global (0,0,1) on 281 of 282 assemblies <- up
BasisZ the SMALLEST extent on 25 of 26 sampled <- face
(0.71 / 1.34 / 2.00 / 2.71 ft -- panel thickness) normal
BasisX the longest extent on 23 of 26; horizontal on all 282
BasisX x BasisY = BasisZ: the frame is right-handed and consistent.
`also_seen_as` below records the owner's colours (green up, purple
top-in-form, red long direction), which map cleanly onto Y / Z / X under
Revit's standard axis colouring. THAT MAPPING IS INFERRED, NOT READ:
the API exposes no colour at all, so it is carried as a separate,
unconfirmed field rather than folded into the sentences above. It is
with the owner.
`AssemblyInstance.get_BoundingBox(None)` returns NONE, which is why the
extents above had to be unioned from member boxes. Worth knowing before
anybody writes the obvious one-liner.
## orientation.up_end.applies_to
---- and the three ways it is wrong on real data ------------------
None of these is hypothetical; each is a piece in front of us. The rule
DECLINES on all three rather than clamping or picking the nearest axis,
because a wrong answer here is silent: the moments still balance, they
are just balanced about the wrong end.
1. ONE ASSEMBLY IN 282 HAS BasisY POINTING SIDEWAYS -- (0,1,0), with
BasisZ up and a BasisZ extent of 9.46 ft, nowhere near a thickness.
On that piece every reading above is simply wrong, so the check for
it is an assertion and not a preference: BasisY must be world up
within `up_tolerance`, or the origin cannot answer and says so.
2. THE RULE IS FOR HORIZONTAL PANELS ONLY. BasisX is the long direction
on 23 of 26 sampled; the other three run longest along BasisY. The
owner has said vertical panels work differently and will explain, so
until he does the rule stands down on anything it cannot confirm is
horizontal rather than assuming the same frame holds.
3. NEAR-SQUARE PIECES CANNOT BE CLASSIFIED AT ALL. The long-vs-up test
separates cleanly at aspect ratios 1.7 to 5.7, and two pieces sit at
1.00 (11.58 x 11.63 ft) and 0.92 (10.71 x 11.63). `near_square_ratio`
is set at 1.25 -- comfortably above the near-square pair and
comfortably below the tightest real horizontal piece, so the band it
declines on is genuinely undecidable rather than merely awkward.
## orientation.up_end.origin_point_meaning
---- one thing this does NOT yet answer, said out loud -----------
`BasisY` is asserted to be world up before it is used, so on every piece
where the rule RUNS it gives the same answer the global-elevation
fallback gives. That is not a bug and it is not nothing -- the whole
value of the rule on those pieces is the three refusals, which catch the
pieces where the old reading was silently wrong -- but it does mean the
ruled mechanism is not yet contributing an INDEPENDENT signal.
The owner's sentence was "assembly origin 里面有一个朝上的头" -- the
origin has an up END in it. `BasisY` is a DIRECTION. Whether he also
means that `Transform.Origin` SITS AT the up end -- which would be an
independent signal, and would answer a near-square or vertical piece
that the direction cannot -- has not been asked or measured. Recorded
here rather than assumed either way.
## catalogue.safety_factors
------------------------------------------------------------------
Safety factors on a lifter's rated capacity.
These are properties of the LIFTER, not of a job, which is why they
live here beside the ratings they divide and not in a per-job rigging
block. Will, 2026-08-30: "这俩参数是不是 lifter 的 tension 或者 shear
capacity? 如果是的话应该从公共知识里面获取参数。" They are.
AND BECAUSE THEY ARE THE LIFTER'S, THEY ARE NOW WRITTEN ON THE LIFTER.
The pair below used to hold `tension_fos: 4.0` / `shear_fos: 2.67` and
applied to every insert in the file, from every manufacturer. Both
halves of that were wrong:
* 2.67 HAD NO SOURCE. Nothing published it, nobody typed it, and no
transcript contains it -- searched 2026-08-31 for `2.67`, `2.67:1`,
`shear_fos`, `安全系数`, `shear` and `SWL`, and the only hits are
the code that carries the number and the documents quoting that
code. A comment justifying it as "the manufacturer's 4:1 tension /
2.67:1 shear" (`panellift/PLAN.md`) was written AFTER the constant
and cites no page. That is a pedigree invented for a number, which
is worse on a safety factor than no comment at all, and it has been
removed rather than reworded.
* THE MANUFACTURER'S PAGE CONTRADICTS IT. ALP catalog p53 (02/2024)
heads the whole capacity table "Capacity in Concrete 4:1 SWL" --
ONE heading spanning BOTH the shear and the tension columns -- and
publishes shear EQUAL to tension on all seven QLPD rows. For these
parts the manufacturer's shear factor is 4:1, not 2.67:1.
SO THERE IS NO GLOBAL VALUE ANY MORE, and these two are null on
purpose rather than corrected to 4.0/4.0. A global 4.0 would be the
same defect in a better disguise: the next manufacturer's insert would
silently inherit a factor read off ALP's page. The evidence that this
is not hypothetical is in this very file -- `QL589SPG` below publishes
4,010 lb shear against 16,000 lb tension (7,690 without its tension bar),
nothing like the 1:1 the QLPD rows show, so whatever governs it is not
the disk anchors' rule.
The factors now live inside each insert entry as its own
`safety_factors:` block, cited to the page that publishes them.
`knowledge.lifter_safety_factor()` resolves them PER PART and refuses
to borrow from another; `panellift.checks.check_insert_capacity`
reports an insert it cannot resolve one for as unjudged instead of
falling back on a number.
THEY APPLY ONLY WHERE THE CATALOGUE QUOTES AN ULTIMATE LOAD. Every
`working_load_lb` below is a published SWL -- the factor is already
inside the number -- so under the default working-load reading they
are not applied at all and dividing by them again would be a double
count. They come into force only where the rating is an ultimate,
which the caller declares with `capacity_is_ultimate` (default False,
and nothing in this repository sets it true).
------------------------------------------------------------------
## catalogue.inserts.QLPD2T3WG
------------------------------------------------------------------
ALP QuikLift Disk Anchor. Datasheet 02/2024, QLPD4T5WG.pdf.
working_load_lb is the published 4:1 SWL, so it ALREADY contains the
safety factor and nothing downstream may apply another.
basis_fc_psi is the concrete the table was derived at. Capacity moves
with sqrt(f'c) BELOW it and does NOT move above it:
factor = min(1, sqrt(f'c actual / basis_fc_psi))
Stronger concrete buys nothing because the anchor's own mechanical
capacity takes over as the governing failure. Releasing at 2500 on a
3500 table costs sqrt(2500/3500) = 0.845.
LWT is the lifting wythe thickness the anchor height is cut for.
Non-insulated panels need 1" cover below the foot of the anchor.
---- WHAT THE PAGE SAYS, VERBATIM (ALP catalog p53, 02/2024) ------
The capacity table's heading is "Capacity in Concrete 4:1 SWL" and it
spans BOTH load columns, so 4:1 is the factor on shear as well as on
tension; every QLPD row prints the same number twice. That is where
each entry's `safety_factors: {tension_fos: 4.0, shear_fos: 4.0}`
comes from, and it is why they are written per part rather than once
for the file.
Two footnotes on the same page, both now landed:
"Insulated Recess Width (IRW) = 2x Minimum Edge Distance"
"Minimum anchor spacing is 2x the published edge distance"
The second is `min_spacing_rule` on each entry below; checklist 6.7
measures it. Nothing in this tool had ever asked the question, so two
8T anchors 20" apart passed every check while the page asked for 28".
AND A WARNING ABOUT THE ULTIMATE ROUTE, because the factors above
make it look safe and it is not. `ultimate_tension_lb / 4.0` is NOT
the published SWL on four of these seven rows -- the page shades
those and says the shading marks where the anchor's own mechanical
capacity governs, so the printed SWL is the LESSER of the 4:1
mechanical figure and what the concrete can hold:
QLPD4T3WG 32000/4 = 8000 vs 6257 published (+28%)
QLPD4T4WG 32000/4 = 8000 vs 7200 published (+11%)
QLPD8T6WG 64000/4 = 16000 vs 11019 published (+45%)
QLPD8T7WG 64000/4 = 16000 vs 14640 published (+9%)
The other three agree exactly. So for these parts the published
working load is the answer and the ultimate is provenance, not an
input: reading an ultimate through a factor here is unconservative
even with the factor right. `working_load_lb` / `shear_load_lb` are
what the checks read, and `capacity_is_ultimate` must stay false.
------------------------------------------------------------------
## catalogue.inserts.LPA4T512G
------------------------------------------------------------------
ALP Lifting Pin Anchor, 4T -- a DIFFERENT clutch family from every
QuikLift entry above (Lifting Pin, not ring clutch). ALP Catalog 2024
p16-18, read 2026-09-07.
RATED AT FOUR CONCRETE STRENGTHS, NOT A BASIS + sqrt(f'c). Every
QuikLift entry above is one number at one basis psi, derated below it
and capped above it (`concrete_derate()`). The LPA page instead prints
four columns -- 1500 / 2500 / 3500 / 5000 psi -- and capacity keeps
RISING past 3,500 (6,950 lb -> 8,000 lb at 5,000 psi, +15%). Running
`concrete_derate()` on a single basis value here would silently cap the
5,000-psi case at the 3,500-psi number -- conservative, but not what the
page says, and not traceable to a cite. So `working_load_lb` and
`basis_fc_psi` are both null with a reason, and the four points land as
`by_fc_psi` instead; nothing reads that list yet (RUNBOOK 3c: land it
anyway).
TWO EDGE DISTANCES, NOT ONE, AND THEY ARE NOT INTERCHANGEABLE. p18
prints "Min. Edge Distances -- Tension / Shear" as two columns, 11in
and 17in for this part. `min_edge_distance_in` (the field
`lifter_edge_distance()` reads) is the TENSION figure; the SHEAR one is
`min_edge_distance_shear_in`, a name no reader consumes yet, on
purpose -- folding 17 into the one field a caller actually reads would
overstate how close a lifter may sit when the load is really shear.
NO SHEAR LOAD IS PUBLISHED FOR THIS PART, ANYWHERE ON THE PAGE. The
17in figure above is an edge distance, not a rating. A plant's own
tested chart may state that a back-cast LPA is rated in shear as its
tension (footnote logic already in `knowledge.py`'s
`_back_cast_shear_from_tension`); that is plant knowledge and belongs
in a plant layer, not here -- this entry answers only what ALP
publishes, which is null with a reason.
ONE ROW LANDED, NOT THE FAMILY. The same two pages tabulate 30 LPA
rows from 1T to 20T; only LPA4T512G is landed, because it is the only
one anything in this repository currently models. The rest are real,
orderable parts with no entry here yet -- adding one is copying a row,
not re-deriving anything.
------------------------------------------------------------------
## catalogue.inserts.QL589SPG
------------------------------------------------------------------
ALP QuikLift Tech Erection Anchor, 8T. ALP Catalog 2024 p35 (the
QL527G / QL548G / QL589G capacity table), read 2026-09-01.
TENSION HAS TWO PUBLISHED COLUMNS AND THEY DIFFER BY 2.1x. The page
rates this anchor with and without a TENSION BAR:
4:1 SWL tension WITHOUT tension bar 7,220 .. 11,680 by thickness
4:1 SWL tension WITH tension bar 16,000 at every thickness
Until 2026-09-01 this entry carried a bare `working_load_lb: 7690`
with no source, no note that 7,690 was the 8 in row of a thickness
table, and no note that the second column existed. Owner's question
("P76 的 tension capacity 在哪个文件里面?哪儿来的这个 7960 的数字?")
is what surfaced it; 7,960 is in no row of the table, and the number
actually recorded was 7,690.
WHICH COLUMN APPLIES IS A PLANT FACT, NOT A PRODUCT FACT, so it is
NOT decided here. A plant states that it welds a tension bar to the
part in its own layer (`lifters.tension_bar_families` /
`parts_shipped_with_tension_bar`); the plant this was traced on does,
via two bars welded to the embed.
`working_load_lb` below is therefore the WITH-BAR rating and is only
correct for a plant that has made that claim.
SHEAR IS THE THICKNESS-DEPENDENT ONE and `shear_load_lb` holds the
THINNEST row (7-1/2 in / 8 in), which is the floor of the table --
conservative for every thicker panel and exact for the two thin ones.
The full table is carried below so a reader that learns the panel
thickness can stop being conservative; nothing reads it yet.
------------------------------------------------------------------
## catalogue.inserts.QL589G
------------------------------------------------------------------
ALP QuikLift Tech Erection Anchor, 8T -- THE BASE ANCHOR, no shear
plate. Same page family as QL589SPG above, same ring clutch (QL003,
8T-12T), a DIFFERENT physical part: no SPW/SPL/SPT dimensions, lighter
(8.44 lb vs 9.64 lb), packed 250/crate against 200/crate. ALP Catalog
2024 p35 (pdf p35, footer "34 QUIKLIFT SYSTEM 02/2024"), read
2026-09-07.
**A FLAG FOR THE OWNER, NOT A SILENT FIX.** The `QL589SPG` entry
immediately above this one is cited to p35 -- QL589G's own page, not
QL589SPG's (p36, "QuikLift Tech Erection Anchor **with Shear Plate**",
footer "35 QUIKLIFT SYSTEM 02/2025") -- and its `by_panel_thickness_in`
table reproduces p35's QL589G row digit for digit (7,220 / 7,690 /
8,640 / 9,580 / 10,610 / 11,680 at 7.5-12in, matching this entry's own
table below exactly). p36's own QL589SPG table is close but not
identical (7,100 / 7,220 / 7,690 / 8,640 / 9,580 / 10,610 / 11,680 at
7-12in -- an extra 7in row, and 6,030 where QL589G's table reads 6,032
at 7.5-8in). So the entry named `QL589SPG` in this file currently
carries QL589G's data, not its own. Nothing here was changed to fix
that -- a landed entry another job may already be reading is not this
pass's to silently rewrite (CLAUDE.md §3, "a contradiction hit mid-work
is the owner's to settle"). What is added instead: this entry, landed
correctly against p35 under the name the page actually prints, so a
model family that says `QL589G` (as at least one real job's does --
`LIFT_QL589G_8T`, confirmed against a live model 2026-09-02) is no
longer forced through the SPG-shaped entry to get a rating at all.
Whether `QL589SPG` should be re-read against p36 and corrected is on
the owner's list.
working_load_lb / shear_load_lb / by_panel_thickness_in below are
QL589G's own numbers, read directly off p35, not copied from the
QL589SPG entry -- the two entries agree because the two anchors'
published capacities are themselves nearly identical, not because one
was derived from the other.
------------------------------------------------------------------
## catalogue.inserts.QL846G · QL847G · QL044G · QL054G
------------------------------------------------------------------
ALP QuikLift Plate Anchors -- back-stripping anchors with a plate
welded to the foot, a different shape from every LPA / QuikLift
ring-clutch entry above. ALP Catalog 2024 p52 (pdf p53, footer "52
QUIKLIFT SYSTEM 02/2025"), read 2026-09-07.
TENSION AND SHEAR ARE THE SAME PUBLISHED NUMBER, on all four rows --
the page's own "Capacity in Concrete 4:1 SWL" table prints one column
of each, and they are equal on every row (3,570 / 4,700 / 4,730 / 6,350
lb both ways). That is a genuine published fact, not a transcription
shortcut: it is the same SHAPE as the LPA-series back-cast footnote
(shear equals tension when a part is cast in the panel's field rather
than at a free edge), and here it is simply what ALP prints as the SWL
for either direction -- no footnote needed, no plant fact required to
reach it.
THE PUBLISHED EDGE DISTANCE IS TENSION ONLY. The page's own footnote:
"Shear edge distances should be based on ACI calculations or testing
in plain concrete." `min_edge_distance_in` on each entry is the
tension figure the table actually prints; `shear_edge_distance_published:
false` says outright that there is no second number to read for shear,
so a caller does not assume `min_edge_distance_in` covers both
directions the way it might for a part where only one distance is ever
published because only one applies.
THE REBAR CAUTION IS PER-PART, NOT PER-PAGE. The dagger note ("rebar
should not be placed between the recess member and the base plate")
is marked on QL846G and QL847G (and QL128G, not landed here) but NOT
on QL044G or QL054G -- landed as a `note:` only where the page's own
dagger marks it, rather than copied onto all four.
WHY THIS MATTERS BEYOND THE FOUR NUMBERS. A plant's own tested chart
can print these same four designations with an unqualified `Zero` in
the shear column and no footnote marking them as the back-cast
exception -- which under the three-state reading in `knowledge.py`
(`_field_rating_state`) is correctly treated as UNRATED, not a real
zero, and stands down rather than answering `Zero`. Before this
landing, that stand-down had nowhere to fall through to: `catalogue.
inserts` held none of these four designations. It does now -- with a
real, equal-to-tension shear rating, from an independent, wholly
public source. Reaching it from a plant layer still needs that layer's
own `lifters.catalogue_alias` line (a plant's own part-numbering habit,
not landed here -- RUNBOOK stage 3d).
------------------------------------------------------------------
## catalogue.inserts.QL184G
------------------------------------------------------------------
ALP Insulated Panel Anchors -- QL184G / QL184SPG. ALP Catalog 2024
p.48-49 (pdf p49-50), judge-verified 2026-09-01 against the rendered
page images (QNA/extraction-benchmark-2026-09-01.md, "QL184G verified
values" section -- a three-way extraction benchmark's ground truth,
not one agent's note). QL184SPG is QL184G with a factory shear plate
added (SPW/SPL/SPT dimensions); both share the same ring clutch class.
A DIFFERENT QL SUB-FAMILY FROM QLPD ABOVE, on a different catalogue
page, with its own capacity shape. QLPD's `working_load_lb` /
`shear_load_lb` do NOT apply here -- these two entries carry only
dimensions and the ultimate mechanical rating; the SWL capacities are
a matrix keyed by panel geometry and part number, not a per-part
scalar, so they are landed separately below as
`insulated_panel_anchor_capacities`. Do not add working_load_lb /
shear_load_lb to these two entries -- read the capacity table instead.
------------------------------------------------------------------
## catalogue.insulated_panel_anchor_capacities
SOURCE: ALP Catalog 2024 p.48-49 (pdf p49-50), judge-verified 2026-09-01
------------------------------------------------------------------
QL184G / QL184SPG -- Capacities in Concrete, insulated panel anchors.
ALP Catalog 2024 p.49 (pdf p50), judge-verified 2026-09-01 (same
benchmark file as above, same "QL184G verified values" section --
every cell here was read individually off the rendered page image and
passed the two identity checks below across all four rows).
WHY A SEPARATE TABLE AND NOT FOUR MORE `inserts:` ENTRIES. The page's
capacity matrix is keyed by PANEL GEOMETRY, not by part number alone --
QL184G and QL184SPG each appear on more than one panel-geometry row,
and the same geometry caption recurs for both parts (both anchors have
a row under the "(3\" x 2\" x 3\")" group). A dict keyed by part number
cannot hold that; a list of rows, each carrying its own part number and
caption, can. Only the four QL184G/QL184SPG rows are landed here -- the
neighbouring QL217SPG / QL077G / QL242G / QL242SPG / QL243G / QL243SPG
rows on the same page were read only as the judge's identity-check
neighbourhood and are not requested for this catalogue.
---- SAFETY-FACTOR SEMANTICS, EXACTLY AS PRINTED ------------------
BOTH columns below are already SWL (working load) values -- the safety
factor is baked into each published number, THE SAME AS QLPD ABOVE AND
UNLIKE THE HK CONNECTOR ENTRIES (`connectors.products.'HK Composites
(ST*)'`), whose `ultimate_tensile_pullout_lb` / `shear_strength_lb` are
ULTIMATES with no stated factor. Do not divide anything below by
another factor, and do not read `ultimate_mechanical_tension_lb` on the
QL184G/QL184SPG entries above as if it were a fifth SWL column -- it is
the mechanical ultimate the shaded reinforced-tension column is capped
at, nothing more.
4:1 SWL -- the standard shear safety factor printed on
the table heading for both shear columns.
2.66:1 SWL -- printed as a second, LOWER-factor column on
the same rows, with this footnote verbatim:
"A shear safety factor of 2.66:1 can be used
at the discretion of the engineer for
one-time lifts." It is not the default; it
is a narrower allowance a designer opts into.
---- IDENTITY CHECKS (asserted at landing, hold on all 4 rows) ---
2.66:1 SWL Shear Parallel / 4:1 SWL Shear Parallel = 1.50 (= 4 / 2.66)
6900/4600 = 1.500 -- 5775/3850 = 1.500 -- 6600/4400 = 1.500 --
5175/3450 = 1.500
4:1 SWL Reinforced Tension = ultimate_mechanical_tension_lb / 4, on
every row below (all four are shaded / mechanically limited):
64000 / 4 = 16000, matches all four rows' reinforced_tension_4_1_lb.
---- NOT LANDED, deliberately (judge's flags, 2026-09-01) --------
- Corner distance / minimum anchor spacing: the p50 insulated-panel
matrix carries neither column, unlike the ordinary erection-anchor
capacity tables on pdf p35-46. Do not borrow QLPD's
`min_spacing_rule` here -- it is a different table on a different
page for a different QL sub-family.
- Rows at any concrete strength other than 4,500 psi -- QL184G and
QL184SPG have no rows at any other basis_fc_psi on this page.
- A PSI -> TL -> D bend-detail lookup subtable for Bend Detail A: the
page prints one only for Bend Detail C (whose rows here are
QL217SPG, not QL184*). Detail A's own illustration carries only
"30 deg" and the label "TL", with no numbers printed on it. The
`bottom_bend_tl_in` / `top_bend_tl_in` columns below are NOT that
subtable -- they are the capacity matrix's own per-row columns and
are landed as printed, including where the bend detail is A.
## catalogue.rebar
---------------------------------------------------------------- rebar
ONE NUMBER FOR EVERY SIZE, AND IT IS A FALLBACK -- read only for a bar
size no layer has listed. Will, 2026-08-30: "rebars come in 40ft stock.
unless overwritten by other knowledge, all rebars pieces must be less
than 40ft." That is a sound industry default and it is not the answer:
REAL STOCK IS PER BAR SIZE, and the small sizes are commonly nothing like
40 ft. One producer's stock list, read 2026-08-30, gives #3 at 23'-4" and
#4 at 20', with 40' from #5 up.
Which means a check comparing every bar against this number passes a
30 ft #4 that its plant cannot cut from 20 ft stock -- a false OK on a
real defect. The per-size table is `rebar.stock_by_size` and it is PLANT
knowledge: which sizes a producer stocks, and how long, is that
producer's, not the trade's, so it is never written here. Resolution
order is per-size first, this number only if the size is unlisted, and
NOTHING if neither -- see `knowledge.rebar_stock()`.
## catalogue.rebar.astm_grades
---- what an ASTM designation says about yield strength -------------
PUBLIC, and it belongs here rather than in a plant file for the same
reason a lifter's rating does: this is what the standard says, the same
for everyone who buys the bar.
THE DESIGNATION DOES NOT DETERMINE fy, and reading it as if it did is
the trap this block exists to close. A stock list saying "A615" has
told you nothing about strength.
grades_ksi the grades the current standard defines
default_fy_ksi what to assume when nothing states the grade, or
NULL where no assumption is defensible
`rebar_fy()` always reports which of the two its answer came from, so a
default can never be mistaken for a stated fact. Where default_fy_ksi
is null the caller gets None and must stand down and say why. Nothing
anywhere quietly falls back to 60.
A PLANT THAT STATES ITS OWN STOCK MATERIAL OUTRANKS THIS. "This plant
stocks A706 Grade 60" is an assertion about a plant; "A706 usually
means Grade 60" is what the designation tends to mean. They can be the
same number and they are not the same claim, so the plant layer's
`rebar.stock_material` is consulted first and `rebar_fy()` reports
`plant stock` rather than `astm default` when it answers.
## catalogue.slotted_inserts
------------------------------------------------------------------
SLOTTED INSERTS -- JVI PSA. Catalogue 2016-5, read 2026-08-31.
------------------------------------------------------------------
A slotted insert is cast into a panel and receives a strap anchor that
ties the panel back to a steel or concrete frame. It is NOT a lifting
insert and nothing in `inserts:` above applies to it: those are rated
for a crane pulling a piece out of a form, these for a wind and gravity
connection that has to tolerate erection tolerance, which is what the
SLOT is for.
WHY PUBLIC. Manufacturer catalogue data -- one manufacturer, one product
line, the same for everyone who buys it. It identifies no client, no job
and no producer, which is the whole test for this file.
---- THE ONE THING A READER MUST NOT DO WITH THESE NUMBERS --------
`ultimate_pull_out_lb` and `ultimate_shear_lb` are ULTIMATES. The page
prints them under the headings "ULTIMATE PULL OUT CAPACITY" and
"ULTIMATE SHEAR CAPACITY", and no safety factor appears anywhere in the
catalogue -- not in a heading, not in a footnote, not on the test-report
list. That is the opposite of the `inserts:` block above, where every
`working_load_lb` is a published 4:1 SWL with the factor already inside
it.
So `safety_factors` here is NULL WITH THE REASON, and it is null in the
way this file's own preamble demands: a part with no factor of its own
is NOT judged on an ultimate rating, it is named as unjudged. Dividing
these by the 4.0 the disk anchors publish would be borrowing one
manufacturer's factor for another manufacturer's part, which is exactly
the failure `catalogue.safety_factors` was emptied to prevent.
The values are also printed as INEQUALITIES -- ">13,400 lbs.", not
"13,400 lbs." -- i.e. minimum guarantees, not test means. `_stated_as`
carries that so a report can print the page's own claim.
## catalogue.slotted_inserts.edge_distance
---- EDGE DISTANCE, AND IT IS DIRECTIONAL -----------------------
This is the fact a one-number edge check would get wrong. The page
prints TWO minimums and they are not "standard" and "reinforced" --
both are the unreinforced minimum, measured in two different
directions, and the drawing shows both cases:
* an insert with its slot VERTICAL: 6" up to the top edge,
10" across to the side edge;
* an insert with its slot HORIZONTAL: 10" up to the top edge,
6" across to the side edge.
The invariant is the same in both: 6 in. is measured ALONG the slot's
long axis and 10 in. PERPENDICULAR to it. Verbatim: "The minimum edge
distance without the use of additional reinforcing steel is 6" and 10"
as shown in the illustration. The edge distance can be reduced if
extra reinforcement is installed (PSA Test Report #2)."
A check that takes 6 as "the minimum" passes an insert 6 in. from the
edge the page wants 10 in. from, and it does it on exactly half the
orientations.
## catalogue.slotted_inserts.unreinforced_top_edge_reduction
---- THE 25% REDUCTION, AND ITS ACTUAL CONDITION ----------------
Verbatim from the note under the strap-anchor connection figure:
"NOTE: Reduce ultimate load by 25% if unreinforced insert is placed at
top edge of panel. Added reinforcement allows insert to attain full
pull-out capacity (PSA Test Report #2)."
THE CONDITION IS NARROWER THAN "AN UNREINFORCED EDGE". It is an
unreinforced insert AT THE TOP EDGE of the panel. An unreinforced
insert in the field of the panel is not covered by this sentence, and
reading it as a general unreinforced-edge penalty would apply a 25%
cut where the page does not ask for one -- conservative, but wrong,
and wrong in a way nobody can trace back to a page.
## catalogue.slotted_inserts.models
---- the models --------------------------------------------------
Two series, three models each. The series differ in LENGTH and in
ADJUSTMENT RANGE; within a series the models differ in DEPTH, and
pull-out rises with depth while shear does not move at all.
The 4500 and 6000 rows with the same last two digits publish IDENTICAL
capacities (4525 and 6025 both >13,400 / >20,000). So the series is
chosen for adjustment, not for strength, and a selector that ranked
6000 above 4500 on capacity would be ranking on a tie.
`available_adjustment_in` is the F dimension on the dimensional
sketch; note it DROPS on the deepest model of each series (2-1/8 from
2-7/8, and 3-5/8 from 4-3/8) -- the deepest insert is the strongest
and the least adjustable, which is the trade-off the table exists to
show.
## catalogue.slotted_inserts.strap_anchors
---- the strap anchor, which is the other half of the connection --
THE SHEAR CAPACITY OF THE CONNECTION IS THE STRAP'S, NOT THE INSERT'S,
once the load is eccentric -- and every real connection is eccentric,
because the strap stands off the panel face. The insert's >20,000 lb
is the insert; these are what a 2 in. wide welded strap delivers at
the eccentricity it is actually installed at, and at 3 in. that is
11.3 kips, a little over half the insert's rating.
Two things follow that a bare insert table would hide: the governing
number is usually the strap's, and it depends on a dimension
(eccentricity) nobody records on a ticket.
## catalogue.shear_grid
------------------------------------------------------------------
SHEAR GRID -- C-GRID carbon-fibre grid for insulated wall panels.
------------------------------------------------------------------
A shear grid crosses the insulation of a sandwich panel and transfers
HORIZONTAL SHEAR between the two wythes, which is what makes the panel
act partly composite. It does the same structural job as the discrete
connectors under `connectors:` below and it is a different object -- a
continuous sheet rather than a set of pins -- so its capacity is a SHEAR
FLOW, force per inch of grid, not a force per part.
WHY PUBLIC. This is published manufacturer test data: Altus's own
double-shear programme for C-GRID, reproduced as Table 4.1 in a 2022
C-GRID insulated-wall-panel design deck. It names a manufacturer and a
product and nothing else -- no client, no job, no producer.
---- WHAT `recommended_nominal_pli` IS, EXACTLY ------------------
The table publishes three columns and only the third is a design value.
The page's own footnotes, verbatim:
** "Maximum is 1.5 times average based on VQ/I shear on the
rectangular test specimens."
*** "The recommended design value has been taken as the average of
the 'average test value' and 'maximum minus 3 standard
deviations.'"
**** "Single test for each spacing. Standard deviation is across
tests." (marked on POLY ISO)
So `recommended_nominal_pli` = round( (average + max_minus_3sd) / 2 ),
rounded half up -- and that identity holds on all 37 rows, which is how
this transcription was checked: every row reproduces its own third
column from its first two.
THE SECOND COLUMN IS "MAXIMUM MINUS 3 STANDARD DEVIATIONS", NOT PLUS.
It is smaller than the average on eight rows (XPS 2"/12" is 212 avg
against 178), which is only possible for a minus. An earlier reading of
this table as "Maximum + 3 Std. Dev." inverted the sign and, with it,
what the column is for.
---- AND THESE ARE NOMINAL, NOT FACTORED -------------------------
No phi is applied here and none may be applied here. Which phi a
designer puts on a grid design value depends on the CHECK (an ultimate
in-place check and a stripping check do not use the same one) and on the
INSULATION (smooth XPS carries an extra one). Those are design practice
and they live in a plant layer, not in a catalogue.
## catalogue.shear_grid.c_grid.shear_flow
---- the table ------------------------------------------------
Keyed insulation type -> thickness (in) -> grid spacing (in).
Units: pounds per inch of grid (pli). Thickness and spacing keys are
the page's own, so a lookup is an exact match and an unlisted pair
has NO value rather than an interpolated one -- these are test
results at discrete spacings and the trend is not monotonic (XPS
sand-blasted 2 in. runs 308 / 599 / 528 across 12 / 24 / 48 in.),
so interpolating between them would invent numbers the programme
did not measure.
## connectors
==========================================================================
CONNECTORS -- what ties the two wythes of an insulated panel together.
==========================================================================
Owner, 2026-08-31: "增加一个公共知识,connector 指的是穿越 insulation, 把两层
混凝土链接起来的东西 ... 公共知识应该有 connector 包含:HK Composites (ST50),
而厂知识应该有 R80=HK Composites (ST50)。"
WHAT A CONNECTOR IS. An insulated (sandwich) wall panel is two concrete
wythes with a layer of insulation between them. A CONNECTOR is the part
that CROSSES THE INSULATION and ties the two wythes together. Without
enough of them the wythes are two slabs travelling in company, which is a
structural condition and not a drafting one.
THIS IS THE PUBLIC HALF: the concept, and the PRODUCTS -- manufacturer and
designation, the same wherever they are bought. The plant's own part
numbers and the mapping onto these products are PLANT knowledge
(`connectors.catalogue_alias`), exactly as `lifters.catalogue_alias` maps a
plant's insert number onto `catalogue.inserts`. Same shape, same reason.
CAPACITIES AND EDGE DISTANCES SHIPPED NULL AND THE CAPACITIES ARE NOW IN.
The owner: "我回头再给你找他们的 capacity 加入公共知识" -- and on 2026-08-30 he
captured the manufacturer's own two product pages. Every capacity below is
read off those pages, and every one of them is an ULTIMATE (see
`safety_factors` below). What is STILL null is a WORKING LOAD and, for
every designation but one, a minimum edge distance: a rating nobody has
read is not a rating, and the checks that need one stand down naming the
missing datum rather than borrowing a number from another product. Dormant
and loud (PROJECT.md 3.2): the shape is right, the value is null, and the
reason is written beside it.
TWO SYSTEMS, AND THEY ARE NOT A RANGE OF ONE PRODUCT. The manufacturer
publishes a STANDARD (non-composite) line and a CA (composite-action) line,
and the difference is a STRUCTURAL DESIGN BASIS, not a size: the Standard
system is designed so the two wythes move independently and the ties flex,
the CA system so the two wythes act together and a thinner panel can be
built. `design_basis` carries it on every entry, because a tie chosen for
one basis is not a substitute for a tie chosen for the other -- and
nothing here decides which basis a given panel was designed on. That is a
statement about the panel, not about the part.
ST50 AND ST100 ARE TWO DIFFERENT PRODUCTS AND ARE NOT INTERCHANGEABLE.
ST50 is the owner's example pairing for the plant's R80; ST100 is
evidenced twice on this job -- in the design summary (`HK ST100'S @1'-4"
O.C.`) and on the model's own connector type. Nothing here folds them
together, and a capacity that arrives for one may not be read onto the
other.
## connectors.design_bases
---- THE TWO DESIGN BASES, IN THE VENDOR'S OWN WORDS ------------------
This is a STRUCTURAL-BEHAVIOUR CLAIM MADE BY THE MANUFACTURER, and it is
recorded as that and not as an engineering conclusion of this tool's.
It is here rather than in a plant file because it is a property of the
PRODUCT LINE, published on the vendor's own page, and it is the same
wherever the part is bought.
WHY IT MATTERS MORE THAN A NUMBER. Whether a sandwich panel's two
wythes act together decides which section a bending calculation is
allowed to use, and it is the single assumption that makes a
sandwich-panel handling or gravity check either right or nonsense. The
tie a panel is built with is EVIDENCE about that assumption -- strong
evidence, and still not the same thing as the designer's own statement.
Nothing in this tool may conclude "this panel is non-composite" from a
part number alone; it may say "the ties on this panel are from a line
the manufacturer designs for non-composite behaviour", which is a
different sentence and the only one the evidence supports.
## connectors.product_line_no_published_capacity
---- THE MODEL NUMBERS THAT HAVE NO PUBLISHED TABLE -------------------
Both pages list their full product line and then tabulate only three
designations each. The rest are real, orderable products with NO
published capacity anywhere on the page -- so they are listed as
EXISTING, with nothing else claimed about them. Listing them is not
decoration: it is what stops a reader meeting a `DP38` or a `CA125` on a
ticket and concluding the mark is a typo. Both pages add: "All ... Ties
can be custom designed per project" and unlisted products are a call to
their engineer.
NOTHING BELOW MAY BE INTERPOLATED. CA125 sits between CA100 and CA150 in
length and its capacity is NOT between theirs -- the CA table's shear
falls with length while its tension is flat, so a linear guess would be
wrong in two directions at once and confident in both.
## connectors.safety_factors
---- THE SAFETY FACTOR THAT IS NOT ON EITHER PAGE --------------------
Said once for every connector above, in the same shape as
`slotted_inserts.safety_factors`, and for the same reason.
EVERY PUBLISHED CONNECTOR FIGURE IS AN ULTIMATE. The Standard page's
columns read "Ultimate Tensile/Pullout", "Shear Strength" and "Ultimate
Panel Shear Capacity/Tie"; the CA page's read "Ultimate Tension" and
"Ultimate Shear". NO SAFETY FACTOR APPEARS ANYWHERE ON EITHER PAGE --
not in a heading, not in a footnote, not in the test citations. That is
the opposite of `inserts:`, where every `working_load_lb` is a published
4:1 SWL with the factor already inside it.
So a working load cannot be derived here, and the 4.0 the disk anchors
publish belongs to a different manufacturer's parts and may not be
borrowed. A check that needs an allowable stands down naming this key.
THE 5% FRACTILE IS NOT A FACTOR EITHER. The CA page's fractile column is
a statistical lower bound on the same ultimate test population at 95%
confidence -- it narrows the uncertainty in the ultimate, it does not
convert it into a service-level capacity.
## connectors.edge_reference
---- WHICH EDGE THE DISTANCE IS MEASURED TO, added 2026-08-31 ---------
Owner, verbatim: "检测 edge 检测的不是 concrete edge,而是 insulation
edge,所以如果 insulation 有 solid zone 被 cut through 而不只是 recess
的话,那么 edge 就是被 cut 之后的 edge。如果只是 recess,则按照原来的
edge 来算。"
HE STATED IT AS HOW THE MEASUREMENT WORKS, not as one plant's habit,
which is why it is here in the public layer beside what a connector IS
rather than in a plant file. A connector ties two wythes together
THROUGH the insulation; where there is no insulation there is nothing
for it to do, so the boundary that matters to it is the insulation's,
and the concrete edge is a coincidence of the two agreeing on a normal
piece.
## checklist
==========================================================================
THE MASTER CHECKLIST -- every question this tool can ask of a shop ticket.
==========================================================================
Owner, 2026-08-31: "做一个总的 checklist 放 public knowledge 里面,然后 plant
里面做一层映射,job 里面用静音按键去控制。"
Three layers, and each owns exactly one thing:
PUBLIC (here) WHAT THE QUESTIONS ARE. The universe, trade-wide. Every
`id` below is a STABLE IDENTITY and nothing renumbers it.
PLANT WHICH questions that plant asks OF WHICH KIND OF MEMBER,
in what order, under what numbers
(`checklists.profiles`). A wall panel and a column do
not get the same checklist, and that is the insight this
architecture was built on.
JOB the mute buttons. Presentation, per job, per piece kind
-- `checks.muted`, edited from the Project Config screen.
WHY THIS IS DATA AND THE CHECKS ARE STILL CODE. What EXISTS, how it is
worded, and what grade it carries is publishable knowledge about shop
tickets -- the same at every plant, and correctable without a release.
What ANSWERS a question is a check function, because a claim has to be
able to be WRONG IN A REVIEWABLE WAY: it needs a skip probe that says why
it stayed silent, a finding code, and a test. A YAML-defined row with no
function behind it would have a number, a sentence, and no way to fail --
a checklist row that always looks fine, which is this project's cardinal
failure with a friendly editor on top.
So `checks:` below NAMES A FUNCTION IN `vibe.ticketchecks`, and the pairing
is enforced: a master entry naming a function that does not exist, or a
registered check function no master entry names, FAILS THE SUITE. That test
is load-bearing in a way nothing was when this list was a Python tuple --
a tuple could not drift from the code beside it, and this can.
---- THE FIELDS ----------------------------------------------------------
id STABLE. Frozen 2026-08-31 as the numbers this tool had
always printed. See below.
name what the row says on the report
grade A pure code | B code plus a plant fact | C code narrows,
a person decides | D a person reads the drawing
owner_codes the finding codes that answer this row, or null
not_run_reason set ONLY on a row a person owns by design -- the reason
string is what makes it FOR ENGINEER rather than unbuilt
(see ticketpage.CHECKLIST_FOR_ENGINEER)
checks one function name, a list of them, or null
---- THE IDs ARE FROZEN, AND WHY THAT MATTERS MORE THAN IT LOOKS ---------
These read like numbers because they WERE the numbers. A plant may now
renumber its own checklist in one YAML edit, and the number it shows is a
DIFFERENT THING from the id here.
Everything that has ever named a check names it by the id: the owner's
mutes, `checks.not_applicable`, the QNA records, `qc-run.json` and its
consumers, and the suite. A renumbering that reached them would either
break those references or -- far worse -- leave them working and pointing
at a different question.
So a reference is now QUALIFIED: `<plant>-<member kind> <number>` names a
position on one plant's board (`sample_plant-wall_panel 3.3`), and a BARE number
means a master id. Every ruling written before 2026-08-31 cites bare
numbers and they all still mean exactly what they meant: master ids.
REMOVING an id is a DELETION, not a renumbering, and it orphans every
ruling that names it. A retired id is never reused.
## catalogue.development_length
---------------------------------------------------------- development_length
ACI 318-19 Chapter 25, §25.4 (development of reinforcement) and §25.5
(splices). PUBLIC for the same reason `catalogue.rebar.astm_grades` is:
this is the model code every producer and every job works under, not a
plant's or a job's own fact, and it identifies nobody.
Read from the code's own text layer (`knowledge/ACI318-19-ch25_decoded.txt`,
cross-checked against the cleaned extraction `knowledge/ACI318-19-ch25.md`),
not from a producer's manual -- so the caution that governs the MC drop
(a 42% page-error rate on cheap-model extraction notes) does not apply the
same way here: there was no independently-audited extraction pass, but
every equation and table landed below was re-read against the raw text
layer directly by the agent that landed it, the same discipline the
library RUNBOOK asks of a landing pass. Full extraction, confidence marks
and the raw-text-fragment reasoning: `knowledge/library/notes/ACI318-19-ch25-development.md`.
---- WHAT THE VERIFICATION PASS CHANGED FROM THE EXTRACTION NOTE ----------
The note flagged four spots `[UNREADABLE]` or `[B]` because no rendered
page image was available and the PDF's own equation font renders a stacked
fraction as an unordered list of glyphs (numerator and denominator symbols
interleaved, not left-to-right). Re-reading the raw text layer directly
resolved three of the four, because this document's fragmentation is
CONSISTENT: every equation's glyph-list contains exactly the symbols the
known Code equation requires, no more and no fewer -- which is how the
note's own Table 25.4.2.3 reconstruction was already confirmed (via the
`psi_s = 0.8` cross-check). Applying the same method elsewhere:
- **Table 25.4.2.3, "No. 6 and smaller / other cases" cell** -- the note
had this at confidence B (self-consistent reconstruction). The raw text
literally contains the digits `3`, `50` (and `3`, `40` for the No. 7
and larger column) in the fraction's glyph list, the same way the
favourable-row cells contain `25` and `20` outright. Landed at A.
- **`wwr.deformed.psi_w.case_b` (5*db/s)** -- the note left both (a) and
(b) of §25.4.6.3 as one unreadable pair. (b)'s glyph list contains only
`5`, `db`, `s` -- unambiguous. Landed at A.
- **`wwr.plain.formula` (§25.4.7.2(b))** -- the note could not confirm
whether `db` and/or `As` appeared in the numerator. The glyph list
contains `fy`, `f'c` (twice, matching the two-fraction-group bracket
structure `(fy/(lambda*sqrt(fc))) * (Ab/s)`), `Ab` (an "A" with a "b"
subscript, not a bare "As"), and `s` -- no `db` anywhere. Landed as
`0.27*(fy*Ab)/(s*lambda*sqrt(fc))` at A, correcting the note's
uncertain "As" to "Ab" (area of the individual wire being developed).
- **`wwr.deformed.psi_w.case_a` ((fy-35000)/fy)** -- NOT fully resolved.
The glyph list has exactly two occurrences of `fy`, one `35,000`, and
one subtraction, which fits `(fy - 35000)/fy` with nothing left over --
but unlike the three facts above, there is no independent cross-check
(no worked example, no self-consistency test) confirming the numerator
and denominator are assigned the way I read them. Landed at confidence
B with the reasoning in the comment, exactly like the note's own
Table 25.4.2.3 cells were landed at B before the psi_s cross-check
existed. Re-verify against a rendered page before treating it as settled.
**A genuine error, corrected**: the note filed the "debonded strand
requires double `ld`" rule under §25.4.8.3. The Code text puts it at
§25.4.8.1(b) instead (conditioned on "bonding does not extend to the end
of the member AND design includes tension at service loads in the
precompressed tension zone" -- the AND is how the zero-tension exception
is already built into the Code sentence, not a separate rule). §25.4.8.3
is a different, related provision: it permits embedment SHORTER than
`ld` at a section, provided the design strand stress there does not
exceed the bilinear Eq. 25.4.8.1 relationship. The "twice `ld`" language
and the explicit zero-tension exception the note quoted are R25.4.8.3
COMMENTARY explaining the §25.4.8.1(b) rule -- not a second Code
requirement. `strand.correction` in the YAML records this so nobody
re-derives the same confusion from the note.
Everything else in the block -- Table 25.4.2.3's favourable-row cells,
all four modification-factor tables (25.4.2.5, 25.4.3.2, 25.4.4.3,
25.4.9.3), the hooked-bar and headed-bar equations, the compression
equation, the excess-reinforcement-reduction rule and its six exclusions
(including the note's own correction of "D, E, or F" to the Code's actual
"C, D, E, or F" for Seismic Design Categories -- confirmed directly off
the raw text), the tension and compression lap-splice tables, and the
WWR lap-splice provisions -- was re-read against the raw text layer
verbatim and matches the note exactly. Confidence A throughout except
`wwr.deformed.psi_w.case_a`, marked as above.
---- WHY NOTHING WAS LEFT OUT ---------------------------------------------
The note's own "must not land" list named three items; two are now
confirmed (Table 25.4.2.3's sub-#6 cells, the WWR-plain formula) and the
third (`psi_w.case_a`) landed anyway at confidence B, which the library
RUNBOOK permits (A and B may land; only C and D must not). Nothing in
this pass was read as ambiguous, contradictory, or a guess, so nothing
went to the owner's question list.