# Knowledge keys deliberately exempted from tools/knowledge_drift.py.
#
# FORMAT -- one per line:
#
#     <category> <dotted.path> -- why this one is fine
#
# categories: unread  undeclared  defaults  surface-only  test-only
#
# THE REASON IS MANDATORY. A line with no ' -- why' is refused and the run
# exits 2, because an unexplained suppression is how a checker quietly stops
# checking. The point of an exception is that the next person can read why it
# was made and decide whether it still holds; a bare path cannot be argued
# with, only inherited.
#
# WHY A FILE AND NOT A YAML COMMENT. Two of the five categories are about keys
# that exist only in Python (a hidden default) or only in a gitignored plant
# or job file that a colleague's clone does not have. A comment convention
# could not express those, so half the exceptions would have nowhere to live
# and would end up as a second, undocumented mechanism. One file, in the repo,
# beside the tool that reads it, greppable, and reviewed like code.
#
# HOW IT STAYS HONEST. Every run prints how many findings this file suppressed,
# so a shrinking report is never mistaken for a shrinking problem. Every run
# also lists entries here that no longer match anything, so a key that was
# fixed or deleted does not leave a permanent blindfold behind.
#
# DO NOT put a real drift here to make the report green. An exception says
# "this key is not meant to be read"; it does not say "we know and have not
# got to it yet". For the second, leave the finding and fix the code.
#
# Example of the shape (commented out -- this is not an active exemption):
#
# unread  nomenclature.view_design_token_re -- derived from design_number_re
#         when left None, so nothing reads the key itself by design.

# ---- active exemptions below this line ----

# ===========================================================================
# GROUP 1 -- the key IS read, by a call shape this detector cannot resolve.
# ===========================================================================
# Every line below was verified by hand on 2026-08-30 by opening the reader
# and reading it. None of them is a deferral: the code acts on the key today.
# Two shapes recur, and the tool's own blind-spot report already names both:
# a knowledge getter passed in as a FUNCTION ARGUMENT (so the call reads
# get(...) / getter(...), not K.get(...)), and a subtree fetched whole and
# then walked by dict access. Where the fix belongs in the detector rather
# than in the code the line says so; the day it lands, the run will call
# these lines stale and they should be deleted.

# takeoffcore.settings(know, get) loops its own module-owned DEFAULTS table
# and calls get(know, 'takeoff.' + key) once per entry. Both halves are
# invisible: `get` is an argument -- injected so the module needs no Revit and
# stays testable off a model -- and the path is concatenated. The takeoff acts
# on all seven; they are what classifies a family as bar / part / shape /
# not-ordered. See takeoffcore.DEFAULTS and takeoffcore.classify().
unread  takeoff.bar_prefixes -- read by takeoffcore.settings() through an injected getter and a concatenated path; classifies bar families in takeoffcore.classify()
unread  takeoff.part_prefixes -- read by takeoffcore.settings() through an injected getter and a concatenated path; classifies part families in takeoffcore.classify()
unread  takeoff.shape_markers -- read by takeoffcore.settings() through an injected getter and a concatenated path; marks a bend-shape row in takeoffcore.classify()
unread  takeoff.not_ordered -- read by takeoffcore.settings() through an injected getter and a concatenated path; drops families the plant does not order
unread  takeoff.family_class -- read by takeoffcore.settings() through an injected getter and a concatenated path; a family named here beats every pattern
unread  takeoff.nested_in -- read by takeoffcore.settings() through an injected getter and a concatenated path; rolls a nested family up into its parent
unread  takeoff.order_attached_bars_separately -- read by takeoffcore.settings() through an injected getter and a concatenated path; decides whether an attached bar is ordered on its own line

# jobreconscan._roles() resolves nine roles in one loop over a literal tuple
# and calls K.param_names(know, role) with the loop variable. The tool sees
# the call and reports it as a blind spot -- 'non-literal key into
# param_names' -- but cannot bind the roles. Job Recon reads all four of
# these off the model on every run.
unread  parameters.member.ticket_created -- resolved in jobreconscan._roles()'s role loop and read off every member by Job Recon; the loop variable hides it from the scan
unread  parameters.member.ticket_detailed -- resolved in jobreconscan._roles()'s role loop and read off every member by Job Recon; the loop variable hides it from the scan
unread  parameters.sheet.total_required -- resolved in jobreconscan._roles()'s role loop; Job Recon compares it against the pieces the model carries
unread  parameters.sheet.sheet_count -- resolved in jobreconscan._roles()'s role loop; Job Recon compares it against the sheets actually placed

# ticketchecks._sheet_param_value(t, know, 'sheet.weight') -> ticketqc.rstr()
# -> K.param_names(). The literal role is right there, but behind two
# wrappers, and only _nomen / param_names / _s are unwrapped by the detector.
# It is deliberately NOT in knowledge.PARAMETER_ROLES: the printed-weight
# check stands down with its own sentence when the plant maps no name for it,
# so Self Check must not nag a plant that never prints a weight.
unread  parameters.sheet.weight -- read by ticketchecks through _sheet_param_value() -> ticketqc.rstr() -> param_names; kept out of PARAMETER_ROLES on purpose, the weight check stands down and says so itself

# ticketpage.muted_checks(know, getter=None) reads it through an injected
# getter, the same shape as takeoffcore. Ticket QC calls it on every run and
# filters checklist rows with the result, so this is behaviour, not display.
surface-only  checks.muted -- read by ticketpage.muted_checks() through an injected getter; Ticket QC mutes checklist rows on it every run

# liftexport fetches handling.dunnage WHOLE at behaviour tier and
# dunnage_supports() walks the dict by hand for mode and fraction -- together
# they decide where the transportation supports go. The detector only skips a
# surface-read path when a behaviour reader sits BELOW it; a covering
# behaviour read of an ANCESTOR is not considered, which is the only reason
# these two fire. Delete both lines when that is fixed in the tool.
surface-only  handling.dunnage.mode -- liftexport reads the whole handling.dunnage subtree at behaviour tier and dunnage_supports() walks it; the tool does not credit a covering behaviour read of an ancestor
surface-only  handling.dunnage.fraction -- liftexport reads the whole handling.dunnage subtree at behaviour tier and dunnage_supports() walks it; the tool does not credit a covering behaviour read of an ancestor

# liftexport._fast_box picks the key by run mode and passes `not batch` as the
# fallback: for handling.fast_lifter_box that expression IS True, and for
# handling.fast_lifter_box_batch it IS False -- exactly what configdump
# passes. The two call sites agree on the value and differ only in source
# text, which is all this category can compare.
defaults  handling.fast_lifter_box -- liftexport._fast_box passes `not batch`, which for this key evaluates to True, the same fallback configdump prints; the two differ in source text only
defaults  handling.fast_lifter_box_batch -- liftexport._fast_box passes `not batch`, which for this key evaluates to False, the same fallback configdump prints; the two differ in source text only

# The two call sites ask different questions and both answers are written
# down. designspec.design_key MUST always return a key, so it falls back to a
# built-in generic pattern. ticketchecks._view_design_token_re would have to
# strip the leading anchor off that pattern and hunt for it UNANCHORED inside
# a view name; guessing there is how a view called 'Elevation Top 2' becomes
# a design. It returns None instead and checklist 1.4 reads NOT RUN, which
# its docstring states outright. Not a disagreement about what unset means.
defaults  nomenclature.design_number_re -- deliberate: designspec.design_key falls back to a built-in pattern because it must always return a key, while ticketchecks._view_design_token_re refuses to guess an unanchored view token and lets checklist 1.4 read NOT RUN

# ===========================================================================
# GROUP 2 -- not knowledge keys at all: a design spec read as a layer
# ===========================================================================
# knowledge_drift._job_files() walks the job folder recursively and takes
# every .yaml in it. A design spec -- designspec.spec_path writes them to
# <job>/specs/<DESIGN>.yaml, first line `schema: 1` -- is a scraped record of
# one design, not a knowledge layer, and merging one plants its whole shape
# as declared paths: schema, source, confidence, unresolved, and the measured
# values under them. Nothing reads them through knowledge.get because nothing
# should; designspec loads a spec by path.
#
# THE FIX IS IN THE TOOL and it is one line: _job_files() must not descend
# into specs/. These thirteen lines live only until it does, and the run will
# name them stale the moment it lands. While they are here they are also a
# small hazard worth knowing about: `source` and `schema` are generic enough
# that a future real knowledge key of either name would be suppressed by them.
unread  schema -- design-spec field, not a knowledge key; _job_files() descends into <job>/specs/ and reads a spec document as a layer
unread  source -- design-spec field (which model, sheet and view it was scraped from), not a knowledge key; _job_files() reads <job>/specs/ as a layer
unread  confidence -- design-spec field, not a knowledge key; _job_files() reads <job>/specs/ as a layer
unread  unresolved -- design-spec field (what the scrape could not settle), not a knowledge key; _job_files() reads <job>/specs/ as a layer
unread  design_number -- design-spec field, not a knowledge key; _job_files() reads <job>/specs/ as a layer
unread  piece_description -- design-spec field, not a knowledge key; _job_files() reads <job>/specs/ as a layer
unread  thickness_in -- design-spec field, not a knowledge key; _job_files() reads <job>/specs/ as a layer
unread  envelope -- design-spec field, not a knowledge key; _job_files() reads <job>/specs/ as a layer
unread  reinforcing -- design-spec field, not a knowledge key; _job_files() reads <job>/specs/ as a layer
unread  concrete.fc_psi -- design-spec field, not a knowledge key; _job_files() reads <job>/specs/ as a layer (the knowledge-layer concrete branch carries min_fci_ratio, which is read)
unread  concrete.fci_psi -- design-spec field, not a knowledge key; _job_files() reads <job>/specs/ as a layer
unread  concrete.unit_weight_pcf -- design-spec field, not a knowledge key; _job_files() reads <job>/specs/ as a layer
unread  concrete.weight_class -- design-spec field, not a knowledge key; _job_files() reads <job>/specs/ as a layer

# ---- declared inert on purpose ----
# A key that is deliberately not wired, ruled on rather than overlooked. Not
# the same thing as muting a CHECKLIST ROW (that is `checks.muted`, a job
# fact, deep-merged, and set from the Project Config window): this changes no
# run on any job, is the same everywhere, and its audience is whoever reads
# this report next.
unread  tolerances.psi -- MUTED, NOT DELETED. Owner's ruling on triage D1, 2026-08-30: neither wire nor delete. Nothing compares a psi against it (3.1 and 3.2 compare the ticket and the design summary exactly), so it decides nothing on any job today; it is kept declared and settable so that the day a tolerance is wanted the number and its name are already there. The engineer-facing half is configform's `inert` row, which shows it with this ruling instead of as a number box that decides nothing.

# ---- the master checklist moved into the public layer, 2026-08-31 --------
unread checklist -- the master checklist is read by ticketpage.load_master, which opens knowledge/catalogue.yaml DIRECTLY at import and parses it; it never goes through knowledge.get on the merged tree, so this detector cannot see the reader. It is the most-read data in the tool -- CHECKLIST_ITEMS is derived from it -- and two tests in test_ticketchecks_host.py pair every entry against the check functions.

# ---- connector knowledge, 2026-08-31 ------------------------------------
unread connectors.what_it_is -- the definition of a connector, in prose, for a person reading the catalogue. Deliberately not a predicate: what a connector IS belongs in the file that publishes the products, and what RECOGNISES one is connectors.marks, which is read.
unread connectors.insulation_note -- the model's own description of these pins as NON-COMPOSITE, quoted and dated. Recorded because it states a design assumption with engineering weight; deliberately read by nothing, and it must not become a check without the owner's word.
unread connectors.recognition_verified_on -- provenance for connectors.recognition_verified, which IS read. A date beside a flag is for the person deciding whether the flag still holds.
unread connectors.recognition_verified_by -- as above: what was measured, so the flag can be argued with rather than inherited.


# ===========================================================================
# GROUP 3 -- LANDED FROM THE PDF LIBRARY, READER PENDING.  2026-08-31.
# ===========================================================================
# Stage 3c of knowledge/library/RUNBOOK.md, executed against library row D1
# (the plant standards manual, 929 pages) whose 25-fact audit had been
# EXTRACTED AND NEVER LANDED.  The owner's ruling that commissioned this pass
# is quoted in that runbook and in knowledge/library/LEDGER.md.
#
# EVERY LINE BELOW IS A FACT IN A KNOWLEDGE LAYER THAT NO CODE READS YET, and
# that is the intended state, not a deferral of a fix.  Knowledge leads and
# readers follow: the alternative is a drift gate that PUNISHES LANDING, and a
# gate that punishes the right behaviour is a gate people route around --
# which is exactly how roughly 150 A-class records ended up in notes instead
# of in YAML.  With these lines the drift list becomes the to-do list: every
# unread key is a reader somebody owes, named, dated, with its cite attached.
#
# ---- AND THIS FILE'S OWN HEADER SAYS THE OPPOSITE, IN AS MANY WORDS -------
# "An exception says 'this key is not meant to be read'; it does not say 'we
# know and have not got to it yet'. For the second, leave the finding and fix
# the code."  THE COMMISSION AND THAT SENTENCE DISAGREE.  The honest
# resolution is either a new category (`reader-pending`, dated) or an
# amendment to the header -- NOT a quiet re-use of `unread` that makes the
# header a lie.  Per RUNBOOK.md stage 3c, until the owner rules: `unread` is
# used, every reason says "reader pending", and THE CONFLICT IS ON HIS LIST
# (QNA/open-questions-2026-08-30.md).  The header was NOT edited here -- that
# is not this pass's call to make.
#
# Cites are PDF page / printed section, the convention the extraction notes
# use.  Both halves always: the PDF page is how the next agent finds it, the
# printed section is how the owner does, and they do not match.  Full
# argument, page cites and confidence marks for every one of these:
# QNA/knowledge-audit-plant-2026-08-30.md, and knowledge/library/LEDGER.md D1.
#
# Three of these are also PARKED CONTRADICTIONS -- a live value the manual
# disagrees with, landed BESIDE it rather than over it, awaiting a ruling.
# They are marked "RULING PENDING" and carry their open-questions number.

unread  beds -- landed 2026-08-31 from the plant standards manual (library D1) p584-600 / 6110-6126, reader pending: the per-bed strand-hole grid, panel width and abutment capacity. 4.6 BED-WIDTH/BED-OFFSET reads the rails.max_bed_width_in scalar today and the manual contradicts it (open-questions A6.1); 4.6 STRAND-GRID does not exist yet
unread  rails.narrow_panel -- landed 2026-08-31 from the plant standards manual p819 / 10315.1 and p804 / 10301.1 notes 27-29, reader pending: a narrow panel is HELD TO THE FIXED RAIL, so 4.6 BED-OFFSET's permitted band is an outer bound and not an expectation, and 4.4's asymmetric pattern is expected rather than a finding
unread  strand.standard_patterns -- landed 2026-08-31 from the plant standards manual p174-178 / 3201-3205 and p873 / 12204, reader pending: the plant's three standard strand chains, so 4.4 STRAND-POS gets a second opinion beside the design summary
unread  strand.edge_strand_in -- landed 2026-08-31 from the plant standards manual p876 / 12210, reader pending: EDGE STRAND @ 3 5/8 in, the first and last segment of every standard chain
unread  strand.both_wythes_same_stations -- landed 2026-08-31 from the plant standards manual p174-178 / 3201-3205, reader pending: STRAND E.L. means both wythes share x-positions, so total strand is 2x the per-wythe count
unread  strand.debond_by_blockout -- landed 2026-08-31 from the plant standards manual p817 / 10306.1, reader pending: 4.7 has the opening geometry and strand.debond_below_continuous_ft, but the L-vs-W ratio rows have no counterpart in the tool at all
unread  strand.deflection -- landed 2026-08-31 from the plant standards manual p804 / 10301.1 note 20C and p817 / 10306.1, reader pending: deflection is the alternative to debonding and is ranked LAST, max 2 in, min cover 1 1/2 in
unread  strand.detensioning -- landed 2026-08-31 from the plant standards manual p628 / 6320, reader pending: nothing in the tool reads a cutting sequence. Landed because knowledge leads readers, audit 3.25
unread  reinforce.panel_standard -- landed 2026-08-31 from the plant standards manual p183-191 / 3280-3288, reader pending: ReinforceSuggest works only from donor pieces today, and this is its first non-donor source. The middle band is PER DESIGN and must never be proposed
unread  reinforce.design_sheet_selector -- landed 2026-08-31 from the plant standards manual p183-191 / 3280-3288, reader pending: which of the nine standard reinforcing sheets applies, from panel geometry alone
unread  reinforce.weight_plf -- landed 2026-08-31 from the plant standards manual p183-191 / 3280-3288, reader pending: a per-linear-foot sanity band for Takeoff and for bar-schedule plausibility
unread  reinforce.master_ticket -- landed 2026-08-31 from the plant standards manual p716 / 8430.1, reader pending: it defines what reinforce.master_token marks. The durations and the submission list are process with no check behind them
unread  lifters.stripping_rows_by_height_ft -- landed 2026-08-31 from the plant standards manual p183 / 3280, reader pending: panellift.layout decides where inserts go and does not know the plant's own row count by panel height
unread  lifters.stripping_rows_gap_at_ft -- landed 2026-08-31 from the plant standards manual p183 / 3280, reader pending: the sheet's own bands leave H = 39 ft exactly unassigned; a reader must pick a side and say which
unread  lifters.stripping_rows_gap_because -- landed 2026-08-31 from the plant standards manual p183 / 3280, reader pending: the sentence a reader must print when it resolves the 39 ft boundary itself
unread  lifters.default_layout -- landed 2026-08-31 from the plant standards manual p713 / 8320.2, reader pending: fifth points is a DEFAULT and the sheet says to verify the insert type with the engineer
unread  lifters.insert_type_verified_with_engineer -- landed 2026-08-31 from the plant standards manual p713 / 8320.2, reader pending: the half of that sentence that stops the default being read as governing
unread  lifters.common_elevation_panel_to_panel -- landed 2026-08-31 from the plant standards manual p804 / 10301.1 note 14, reader pending: lifting inserts at a common elevation panel to panel
unread  lifters.dimension_centre_to_centre_and_both_edges -- landed 2026-08-31 from the plant standards manual p812 / 10303.1, reader pending: a dimensioning rule for lift inserts, checkable once something reads printed insert dimensions
unread  lifters.edge_lifter_centre_matches_cg -- landed 2026-08-31 from the plant standards manual p812 / 10303.1, reader pending: 6.2 LIFT-EDGE has the geometry but not this condition
unread  lifters.side_lifters -- landed 2026-08-31 from the plant standards manual p813 / 10303.2 and p804 / 10301.1 note 10, reader pending: an ADD'L FINISH = YES title block with no side lifters is a new check needing only two title-block reads
unread  lifters.top_pick_count -- landed 2026-08-31 from the plant standards manual p183 / 3280, reader pending: 4 top-pick inserts. The PART is deliberately not landed -- the sheet names M42/M43 and the model uses P76 (audit Q5)
unread  part_numbers.prefix_class -- landed 2026-08-31 from the plant standards manual p406 / 5001, reader pending: the material-type prefix, which gives families.* a fallback that cannot go stale the way a list does
unread  part_numbers.number_bands -- landed 2026-08-31 from the plant standards manual p406 / 5001 and p713 / 8320.2, reader pending: the number range tells a standard part from an erection item from a repair item with no list at all
unread  part_numbers.finish_suffix -- landed 2026-08-31 from the plant standards manual p406 / 5001, reader pending: g/p/z/s/e finish suffixes on a material designation
unread  part_numbers.job_specific_prefixes -- landed 2026-08-31 from the plant standards manual p406 / 5001, reader pending: the printed rule behind the SP-series move to the job layer on 2026-08-30, which this file acted on without holding the rule
unread  part_numbers.rebar_mark -- landed 2026-08-31 from the plant standards manual p536 / 5302, reader pending: 5.6 BARMARK-UNIQUE could catch a mark whose first digit disagrees with the modelled bar size with no geometry at all
unread  panel_types.make_ups -- landed 2026-08-31 from the plant standards manual p174-178 / 3201-3205 and p879 / 12221, reader pending: 2.1 SIZE-* reads panel_type.thickness and has no list of the five thicknesses this plant builds
unread  girders -- landed 2026-08-31 from the plant standards manual p805 / 10301.2 note 3 and p879 / 12221, reader pending: girder depth, the insulation-plus-3in size rule and the opening-proximity rules. The COUNT is deliberately null -- three sources give three answers (audit Q3)
unread  nomenclature.control_numbers -- landed 2026-08-31 from the plant standards manual p693-695 / 8102.3-8102.5, reader pending: JobRecon does the 163-vs-61 reconciliation and does not hold the arithmetic rule that makes it a defect
unread  nomenclature.marks -- landed 2026-08-31 from the plant standards manual p693-695 / 8102.3-8102.5, reader pending: a gap in the mark sequence is EXPECTED, and the renumber trigger reframes 2.1 SIZE-* and 2.2 WGT-* as a piece that should have been renumbered
unread  nomenclature.ticket_set -- landed 2026-08-31 from the plant standards manual p827 / 10340.2 and p807 / 10301.4, reader pending: 1.3 TICKET-SET gathers sheets today but does not know that sheets after the first carry no product data, nor that third-party sheets are legitimately appended
unread  nomenclature.sheet_families_manual_stated -- landed 2026-08-31 from the plant standards manual p819 / 10315.1, p822 / 10330.1, p821 / 10320, p716 / 8430.1, p851 / 10950, reader pending AND RULING PENDING: nomenclature.detail_sheet_prefix is live and unchanged; this is the manual's fuller set, parked beside it as open-questions A6.2
unread  drawings.rebar_placement_manual_stated -- landed 2026-08-31 from the plant standards manual p804 / 10301.1 notes 25, 26, 40, 47 and p805 / 10301.2 note 15C, reader pending AND RULING PENDING: drawings.rebar_must_appear_on is a residual and unchanged; this is the manual's per-bar-class enumeration, parked beside it as open-questions A6.5
unread  drawings.dimension_exceptions -- landed 2026-08-31 from the plant standards manual p804 / 10301.1 notes 6, 33, 46, 48, p816 / 10305, p726 / 8520.1, reader pending: every entry is a place where a MISSING dimension is correct by standard, and a completeness check that does not know them produces a steady drip of false findings
unread  drawings.bom_rebar_has_no_description -- landed 2026-08-31 from the plant standards manual p713 / 8320.2, reader pending: an empty BOM description on a rebar row is CORRECT, and without this 5.1 BOM-MEMBERS would fire on every rebar row of every ticket
unread  drawings.not_printed_on_ticket -- landed 2026-08-31 from the plant standards manual p701 / 8203, reader pending: the manual's own statement of what is deliberately absent from a ticket -- the panel ID and the behind-panel sections
unread  drawings.alternate_datum -- landed 2026-08-31 from the plant standards manual p811 / 10302.2 and p814 / 10304, reader pending: on an angled-top panel embeds are dimensioned to a WORK POINT, a legitimate alternative datum that will confuse a naive datum check
unread  drawings.dimensions -- landed 2026-08-31 from the plant standards manual p804 / 10301.1 note 5, p810 / 10302.1, p814 / 10304, reader pending: centre-of-embed is this plant's universal datum and is a precondition for any check comparing a printed dimension to a modelled position
unread  drawings.orientation_on_sheet -- landed 2026-08-31 from the plant standards manual p804 / 10301.1 notes 2, 3, 12, 13 and p819 / 10315.1, reader pending: drawings.section_a and section_b were measured off crop boxes on three pieces; this is the convention that binding should agree with
unread  drawings.attached_bar_rule -- landed 2026-08-31 from the plant standards manual p413-418 / 5100.1-5100.6 and p701 / 8203, reader pending: the rule behind drawings.annotation_covered_by_parent, which is a two-entry list today and goes stale in silence the way drawings.reinforcing_rule's predecessor did
unread  drawings.cad_layers -- landed 2026-08-31 from the plant standards manual p701 / 8203, reader pending: the layer a thing is drawn on IS its classification, and REBAR-HEAVY / REBAR-MED / REBAR-LIGHT is a reinforcing size split
unread  handling.weight_band_lb -- landed 2026-08-31 from the plant standards manual p800 / 10230.1, reader pending AND RULING PENDING: knowledge.DEFAULTS' weight_tolerance 0.02 is unchanged and 2.2 WGT-* still runs on it; this is the manual's -0/+100 lb band, parked beside it as open-questions A6.4
unread  geometry -- landed 2026-08-31 from the plant standards manual p168-170 / 3040-3042, p814 / 10304, p712 / 8320.1, p278 / 4294.0, p784 / 10150, reader pending: the recessed-plate rule ties a geometric property to a required X-sheet callout, which is checkable against DETAIL-CALLOUT
unread  finishes -- landed 2026-08-31 from the plant standards manual p165-166 / 3010, 3011, reader pending: a closed vocabulary with two checkable obligations -- a raked panel needs a direction on the ticket, and an end finish is checkable against the product type
unread  concrete.wall_panel_default -- landed 2026-08-31 from the plant standards manual p183-191 / 3280-3288, reader pending: f'ci 3500 gives 3.1/3.2/3.3 a plausibility anchor. f'c is null on purpose -- printed 5000, hand-revised 6000 in red, and neither state is settled (audit Q2)
unread  concrete.release_range_psi -- landed 2026-08-31 from the plant standards manual p627 / 6200, reader pending: the release-strength range this plant offers
unread  concrete.release_standard_psi -- landed 2026-08-31 from the plant standards manual p627 / 6200, reader pending: 3500 psi is the standard release, the rest is specialty
unread  concrete.day28_range_psi -- landed 2026-08-31 from the plant standards manual p627 / 6200, reader pending: 5000-7000 psi at 28 days available or more
unread  concrete.mix_role -- landed 2026-08-31 from the plant standards manual p800 / 10230.1, reader pending: FACE = BOTTOM wythe and BASE = TOP, because the panel is cast face-down. A reader that takes FACE MIX for the exterior mix is right by accident; one that takes it for the top wythe is wrong
unread  concrete.single_wythe_uses -- landed 2026-08-31 from the plant standards manual p800 / 10230.1, reader pending: a single-layer piece uses the BASE mix number, not the face one
unread  concrete.named_mixes -- landed 2026-08-31 from the plant standards manual p164 / 3003, reader pending: the plant's named mixes quoted directly. The positional digit decoding an extraction inferred is filed C there and deliberately not landed
unread  material_grades -- landed 2026-08-31 from the plant standards manual p863 / 11301.1 and p412 / 5015, reader pending: a plant CHOICE among published ASTM options, confidence B because it is read off a filled example form. HSS is null -- A513 struck to A500-C in red, neither state settled
unread  openings -- landed 2026-08-31 from the plant standards manual p760 / 9301 and p887 / 12261, reader pending: a void below 100 sq in or 8 in is one the plant does not cast, which filters the population 6.4 DUN-OPENING, 4.7 and liftexport._openings all count
unread  revisions -- landed 2026-08-31 from the plant standards manual p723 / 8511, reader pending: a ticket at revision 3 whose two predecessors are missing is NORMAL, because the sequence advances project-wide. The old-cloud layer name is null -- two spellings in one manual (audit Q10)
unread  connections -- landed 2026-08-31 from the plant standards manual p216-220 / 4201-4205, p231 / 4214, p243 / 4232, p375-403 / 4900-4974, reader pending: base-connection count by seismic category and butt-joint count by panel height are countable findings for 5.1 BOM-MEMBERS. The alignment count is null -- its table is red-marked (audit Q2)

# FOUR FACTS THIS PASS LANDED HAVE NO LINE HERE, AND THE REASON IS A BLIND
# SPOT RATHER THAN A READER: notes.handling_views_on_sheet,
# notes.handling_view_order, face_designations.carried_by_hatch and
# face_designations.insulation_hatch all sit under a subtree that some caller
# fetches WHOLE. The detector credits a covering read of an ancestor, so it
# never reports them and an allowlist line for them is refused as stale. They
# are as unread as everything below -- nothing acts on any of the four -- and
# they are recorded in knowledge/library/LEDGER.md D1 instead. If the covering
# read is ever narrowed, four findings appear at once and they are these.


# ---- two owner rulings landed the same day, 2026-08-31 -------------------
# Not from the library; from the owner directly, landed in the same pass
# because it holds the plant file. See knowledge/library/LEDGER.md D1's row
# for the pass and QNA/will-owes-2026-08-31.md for the open consequence.
unread  lifters.min_edge_distance_in_by_panel_type -- landed 2026-08-31 from the owner directly ("insulated panel minimum edge distance is 2ft, plant knowledge"), reader pending: knowledge.families_for() resolves a *_by_panel_type map for a LIST role only and there is no scalar resolver, so 6.2 still runs on the published-first order in ticketchecks._edge_limit(). The composition a reader must implement is LARGER-OF with the provenance named -- the plant's 24 in exceeds every published part minimum, so published-first would silently discard it
unread  panel_types.detect_verified_on -- provenance for panel_types.detect_verified, which IS read and was armed 2026-08-31. A date beside a flag is for the person deciding whether the flag still holds; same shape as connectors.recognition_verified_on above
unread  panel_types.detect_verified_by -- as above: what the arming rested on (three signals at 100% separation over 282 panels, a 1,951-mark connector census, and the owner's ruling), and the one thing it did NOT rest on -- a live press -- so the flag can be argued with rather than inherited


# ---- the live-model guard, 2026-09-01 ------------------------------------
# Both ARE read, on every single bridge request, by
# `vibe/bridgeguard.config_from()`. The detector cannot see it: that function
# is deliberately given `knowledge.get` as an ARGUMENT rather than importing
# it, so the module stays free of anything that reads a file and can be unit
# tested off-Revit (tests/test_bridgeguard.py). The literal paths are there,
# one line apart -- they just arrive through a parameter named `getter`.
unread  bridge.refuse_titles -- read every request via bridgeguard.config_from(know, knowledge.get); the path literal is passed to an injected getter, not to knowledge.get by name, which is the wrapper shape this detector says it does not follow
unread  bridge.allow_roots -- as above, same call, same line pair


# ===========================================================================
# GROUP 4 -- LANDED FROM THE PDF LIBRARY, READER PENDING.  2026-09-07.
# ===========================================================================
# Stage 3c of knowledge/library/RUNBOOK.md, run against library row P1 -- the
# PCI Design Handbook, 9th ed. (MNL-120-25), read live in the owner's Chrome
# via the Apryse WebViewer (licensed, viewed online, not downloaded). This is
# the PUBLIC layer's own pass, unlike GROUP 3's plant-layer D1 pass: every
# value below identifies no producer, no job and no client, so it landed in
# knowledge/catalogue.yaml rather than a plant file. Same rule as GROUP 3
# applies: `unread` is used, every reason says "reader pending", and the
# tension with this file's own header is the same one GROUP 3 already
# raised and not re-argued here.
#
# Cites are PDF VIEWER page / printed page (footer), same convention as
# GROUP 3. Full extraction, confidence marks and screen-verification notes:
# knowledge/library/notes/PCI9-5.8-losses.md, PCI9-5.12-insulated.md,
# PCI9-5.17-design-aids.md, PCI9-ch8-handling.md, PCI9-ch15-reference.md.
# Ledger row: knowledge/library/LEDGER.md P1.
#
# The reason this is FIVE lines and not fifty: the detector reports the
# HIGHEST unread ancestor, not every leaf -- same shape as the pre-existing
# `catalogue.shear_grid` / `catalogue.slotted_inserts` findings, which this
# pass did not touch and which are still unread themselves (see the plain
# findings list, not this file).

unread  catalogue.prestress_losses -- landed 2026-09-07 from PCI Design Handbook 9th ed. Section 5.8 "Loss of Prestress", viewer p293-296 / printed 5-42 to 5-45, reader pending: this is what will/REVIT #24 needs -- the panellift/liftexport engine today assumes a lump-sum prestress-loss percentage, and the owner ruled the tool must compute losses per the PCI/Zia method instead of assuming one. The ES/CR/SH/RE equations and the Kre/J/C coefficient tables are landed; nothing calls them yet.
unread  catalogue.strand -- landed 2026-09-07 from PCI Design Handbook 9th ed. Section 15.2, Design Aids 15-9/15-10/15-11/15-12, viewer p862-863 / printed 15-31/15-32, reader pending: nominal diameter -> area/weight/fpu for ASTM A416 strand (incl. 1/2" SPECIAL at 0.167 in^2), A421 wire and A722 bars, plus the design stress-strain curve. No product-family module currently reads a strand area from this table; ticket QC's own strand count/spacing checks read the model's own strand matrix (strand-matrix-geometry-read), not a published property table.
unread  catalogue.camber_and_bowing -- landed 2026-09-07 from PCI Design Handbook 9th ed. Section 5.9 and Design Aids 5-1/5-2, viewer p293-300 / printed 5-45 to 5-49 and p448-449 / printed 5-197/5-198, reader pending: the PCI multiplier-method table (1.85/1.80/2.70/2.45/3.00/2.30), the three camber-vs-strand-pattern formulas, and the bowing-restraint-force design aid (including the 0.75*Ec short-term effective-modulus fact). Nothing in this tool currently computes camber or bowing.
unread  catalogue.insulated_panel -- landed 2026-09-07 from PCI Design Handbook 9th ed. Section 5.12, viewer p304-309 / printed 5-53 to 5-58, reader pending: insulation max-use-temperatures, the four composite/noncomposite/partially-composite/semicomposite structural design assumptions, and wythe/strand/connector-spacing limits (24 in o.c., 12-14 gauge). Distinct from `insulation.*` (a plant/job-layer namespace already read for the current job's recess/hatch geometry) -- this is the published PCI design-method layer, not this job's drafted geometry.
unread  catalogue.handling -- landed 2026-09-07 from PCI Design Handbook 9th ed. Chapter 8 "Component Handling and Erection Bracing", viewer p620-642 / printed 8-3 to 8-23, reader pending: Table 8.3.1's stripping/handling/transport load multipliers, the 4x/5x/2x lifting/hardware/bracing safety factors (OSHA 1926.704), Table 8.3.3's aircraft-cable/wire-rope safe loads, the strand-loop capacity defaults (10 kip base, 1.7x/2.2x for double/triple loops), and Figure 8.6.1's rotation-pick moment/reaction coefficients. NAMING NOTE for whoever picks this up: there is an UNRELATED, already-read top-level `handling.*` namespace (`handling.connectors.declared_action`, `handling.ignore_lateral_prestress` in liftexport.py) that is panellift's OWN per-job handling-analysis config -- a different dotted path (`catalogue.handling.*` vs `handling.*`) so no collision today, but close enough in name to confuse a reader; consider renaming one of the two before wiring a check to either.


# ===========================================================================
# GROUP 5 -- LANDED FROM THE PDF LIBRARY, READER PENDING.  2026-09-07.
# ===========================================================================
# Stage 3 of knowledge/library/RUNBOOK.md, run against ACI 318-19 Chapter 25
# "Reinforcement Details" (§25.4 Development of reinforcement, §25.5
# Splices), read from the code's own text layer, not a producer's manual --
# PUBLIC, same as GROUP 4: it identifies no producer, no job, no client.
# Full extraction, confidence marks and the raw-text-fragment cross-checks:
# knowledge/library/notes/ACI318-19-ch25-development.md. Ledger row: C1 in
# knowledge/library/LEDGER.md.

unread  catalogue.development_length -- landed 2026-09-07 from ACI 318-19 Chapter 25 §25.4/§25.5, printed p.471-491, reader pending: development-length and lap-splice formulas, minimums and modification factors for deformed bars/wires in tension and compression, standard hooks, headed bars, pretensioned strand, welded wire reinforcement, and the excess-reinforcement reduction with its six exclusions. No product-family module currently checks a bar's or a strand's development length against a formula -- ticket QC reads dimension strings and bar counts off the model today, not an embedment length. The reader this is for: a future rebar/strand embedment check (would sit beside ticketchecks.py's existing bar checks) and the strand transfer-length assumption panellift/liftexport currently treats as a plant-layer default rather than computing from Eq. 25.4.8.1.
