Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 13 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -266,8 +266,8 @@ legitimate height is 14,630 m, so no bound separates them — `fly_flying_height
backstop for digital frames (whose `scale` is not an image scale; 94% would be refused on it)
and catches nothing in today's catalogue. The rule is **per frame, never per roll**: 1,208 clean
frames share a slipped roll. The band's **upper edge sits in a trough** before a mass at r = 2
that is a 305 mm lens catalogued as 153, which the DEM route drew at twice its width and nominal
gets right — the lower edge is the same factor by symmetry, not a trough. And the slip's
— half of it a 305 mm lens catalogued as 153, which the DEM route drew at twice its width and
nominal gets right, and half a wrong `scale`, which fly#72 tables — the lower edge is the same factor by symmetry, not a trough. And the slip's
apparent mirror image is **deliberately not repaired**: x10.764, x10 and x2 each bring ~730-800
of the lower tail into the band and the terrain cannot choose (fly#60). Do not "finish" that by
picking one, and do not re-derive the band without the sweep. Classification happens after the
Expand Down Expand Up @@ -330,6 +330,17 @@ outcome today. ×10.764 is named so a neighbour confirming #54
*can* contradict one naming ×10 — without it the tolerance guarded nothing. Blind to a roll
whose every frame carries the defect, which is most of the upper tail

- **The r ≈ 2 mass is two defects that `r` cannot separate, and neither is applied unwitnessed**
(v0.18.0, #72) — a 305 mm lens catalogued as 153 and a right height beside a `scale` at half its
denominator both put a frame at r = 2. Settled per roll-height over the 252 sampled frames beyond
the band: 24 roll-heights (120 frames; keys reaching at most 3,227 in the catalogue — terrain lowers r, so
some are already in band) table at factor 1 under
`tail = "near_upper"`; 21 carry a logbook writing a 12" lens and stay on nominal. **The logbook
height is not a discriminator here** — both readings predict the crew flew the catalogued height —
so the near_upper rule also requires spacing to **reject** nominal, fixed before the run. Logbook
`focal_mm` on these pages is filled only where a focal length is written, never inferred from a
camera model. A sample, not a census; read `inst/notes/terrain-correction.md`

## Gotchas

- `.lintr` must be single-line DCF format — multi-line breaks newer lintr versions
Expand Down
4 changes: 4 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# fly (development version)

- **Half the r ≈ 2 mass was a wrong scale, not a mislabelled lens, and it is now drawn at its true width** ([#72](https://github.com/NewGraphEnvironment/fly/issues/72)). v0.12.0 said the film frames around twice their nominal scale were a 305 mm lens catalogued as 153, so falling back to nominal scale was right. The flight logbooks and the spacing between adjacent frames, read per roll-height over all 252 sampled frames beyond the band, split it: **24 roll-heights (120 sampled frames; their keys reach at most 3,227 catalogue frames, fewer once terrain brings some inside the band, where they were already sized from their height) carry the height the crew flew beside a `scale` recorded too small** — mostly 1972–76 rolls at half the true denominator — and ship in `flying_height_rolls.csv` at factor 1, `scale_wrong`, under a new `tail` value, `"near_upper"`. The fallback drew them at 1/r of their width, half at r = 2; they are now `"corrected_roll_table"` and sized from their height. On 21 roll-heights (82 frames) the logbook writes a 12" lens, which confirms the lens reading there, and those stay on nominal scale, as do the rest; each is listed in `flying_height_rolls_excluded.csv` with its reason.
- **The logbook height alone cannot tell the two defects apart** — a wrong lens and a wrong scale both mean the crew flew the catalogued height — so for this tail the rule, fixed before the run, also requires the spacing to *reject* nominal scale, not merely fit the reported height. The near_upper set is a 600-frame sample, not a census; `inst/notes/terrain-correction.md` states what it does not reach.
- `data-raw/flying_height_logbooks.csv` gains 185 rows from 142 newly read page files covering 54 roll labels. The readers worked blind; two things were added at merge and say so in their `note`: the 18 heights on 1984–86 sheets that write whole feet rather than thousands, and two rows marking the interior of a strip whose height changes along it as covered but unread. On these pages `focal_mm` is filled only where a focal length is written, never inferred from the camera model.

## 0.17.0 (2026-09-27)

- **A frame beside a disputed roll-height on the same roll is now a third witness, and it settles five roll-heights no logbook does** ([#74](https://github.com/NewGraphEnvironment/fly/issues/74)). The rule was fixed before it was run. A neighbour one frame away, on the same roll, lens and scale, must itself sit in the band, and the catalogue's height must stand in an **exact** named relation to it: ×10, ÷10, ÷100, ×10.764 or one leading digit. Exact means within what storing whole metres of a 0.3048 m/ft conversion can move a figure, and the catalogue both rounds and truncates. A figure converted at 3.28 ft/m can only be refused by it, never wrongly accepted. Every neighbour naming a relation must name the same one, and spacing must agree. A logbook vetoes it only by naming a different factor. The rule was run over all 521 roll-heights the logbook leaves excluded, in both tails. `bc5596` 204–211 (26,212 m, ten times frame 203) and `bcb98013` frame 52 (97,924 m, a leading 9 on its neighbours' 7,924) leave #54's ÷10.764, which drew them 10.3–11.2% narrow and 17.1% wide in linear size. Three lower-tail roll-heights beyond the issue come out of `"implausible"`: `bc7675` 609 → 6,096 m, `bc87070` 396 → 3,962 m and `bcc822` 701 → 7,010 m. The logbook corroborates each in rows its own rule could not accept
Expand Down
42 changes: 27 additions & 15 deletions R/fly_footprint.R
Original file line number Diff line number Diff line change
Expand Up @@ -220,13 +220,17 @@ fly_height_slip_factor <- function() 3.28084^2
# whose reported height is at most twice what their scale implies sit inside this band
# (98.7% of all 1.44 million, weighting in the strata above that), and the 1,589 slipped
# frames land at 0.80-1.32 once repaired against 10.0-15.8 before. The UPPER edge sits in
# the trough between that mass and the next one out, centred on 2.0, which is a 305 mm lens
# catalogued as 153 — a frame the DEM route would draw at twice its true width, and the
# nominal route gets right because it never reads `focal_length`. For about half of that
# mass: fly#60's frame spacing shows 105 of its 209 sampled frames carry the right height
# and a wrong scale, which the nominal route draws at half width (fly#72). The lower edge is that
# factor inverted, because the error is a ratio either way; it is set by symmetry and not
# by a trough, since ordinary frames simply thin out below 0.8 with no second mass at 0.5.
# the trough between that mass and the next one out, centred on 2.0. That mass is two
# defects that read alike here (fly#72). On some rolls it is a 305 mm lens catalogued as
# 153, which the DEM route would draw at twice its true width and the nominal route gets
# right because it never reads `focal_length`: the logbooks write a 12" lens on 21 sampled
# roll-heights. On others the height and lens are right and `scale` is recorded at half its
# denominator, which the nominal route draws at half width: those roll-heights, settled by
# the logbooks and frame spacing, are carried in `flying_height_rolls.csv` at factor 1.
# Neither reading is safe to apply unwitnessed, so the band stays where it is and the
# table decides per roll. The lower edge is that factor inverted, because the error is a
# ratio either way; it is set by symmetry and not by a trough, since ordinary frames
# simply thin out below 0.8 with no second mass at 0.5.
# See `inst/notes/terrain-correction.md`.
fly_height_ratio_band <- function() c(1 / 1.6, 1.6)

Expand All @@ -252,7 +256,9 @@ fly_flying_height_max <- function() 16000
# logbook "20.0", thousands of feet, catalogued as 2,000 ft), 1 where the logbook confirms
# the height and the SCALE is the wrong field, and 0.1 where the height is ten times too
# LARGE. That last case is fly#71: rolls flown before 2003 that #54 divides by 10.764. `tail` records
# which side of the band the roll-height came from. `height_m` is the height used — the logbook's,
# which side of the band the roll-height came from: `lower`, `upper` (#54's slipped frames), or
# `near_upper` (fly#72) — the r ~ 2 mass, where a factor of 1 is the same `scale_wrong` cause
# reached from above the band, and the only factor named there. `height_m` is the height used — the logbook's,
# converted, since the catalogue's rounding survives multiplying by the factor.
#
# fly#74 added a third witness where no logbook settles a roll-height: a frame adjacent by
Expand All @@ -264,9 +270,10 @@ fly_flying_height_max <- function() 16000
# ratio it implies rather than a named slip; only `factor != 1` is read from it here.
#
# Keyed on roll, height, lens and scale together, so the table reaches only the frames it
# was measured on. Every lower-tail roll-height it does not correct, and every #54-slipped one
# it does not reach, is listed with its reason in `flying_height_rolls_excluded.csv`: an
# unlisted roll is unmeasured, not clean.
# was measured on. Every lower-tail roll-height it does not correct, every #54-slipped one
# it does not reach, and every sampled near_upper one it leaves on nominal scale, is listed
# with its reason in `flying_height_rolls_excluded.csv`: an unlisted roll is unmeasured, not
# clean. The near_upper rows come from a 600-frame sample of that stratum, not a census.
# Produced by `data-raw/height_calibrate-lower_tail_rolls.R`; see
# `inst/notes/terrain-correction.md`.
fly_height_roll_table <- function() {
Expand Down Expand Up @@ -714,16 +721,20 @@ fly_is_square <- function(footprints) {
#' the roll-heights in `inst/extdata/flying_height_rolls.csv`, which the
#' province's flight logbooks, or failing them an adjacent frame on the same
#' roll in an exact named relation, together with the spacing between adjacent
#' frames, settled (fly#60, fly#71, fly#74): a height with one or two digits dropped (a logbook "20.0",
#' frames, settled (fly#60, fly#71, fly#72, fly#74): a height with one or two digits dropped (a logbook "20.0",
#' thousands of feet, catalogued as 2,000 ft), a height recorded ten times too
#' large, a leading digit added, or a correct height beside a wrong `scale`. Checked before the
#' large, a leading digit added, or a correct height beside a wrong `scale` —
#' on either side of the band, including frames around twice their nominal
#' scale whose `scale` is recorded at half its denominator. Checked before the
#' 10.76 slip above. Sized from the measured height; matched on `film_roll`,
#' `flying_height`, `focal_length` and `scale` together, so it needs a
#' `film_roll` column. As with the slip, `flying_height` is not overwritten}
#' \item{`"implausible"`}{they disagree some other way, or `flying_height` is
#' above 16,000 m or below the terrain. Nothing can say whether the height, the
#' scale or the focal length is the wrong one — a 305 mm lens catalogued as
#' 153 looks the same from here — so the height is not used: a film frame
#' 153 and a scale recorded at half its denominator look the same from here,
#' and the roll table separates them only where it was measured — so the
#' height is not used: a film frame
#' falls back to nominal scale, and a digital frame with no other route has no
#' footprint}
#' \item{`NA`}{no height was judged: no `dem`, a frame the DEM route does not
Expand All @@ -735,7 +746,8 @@ fly_is_square <- function(footprints) {
#'
#' Measured over the whole catalogue, the two corrections for a height that is too
#' large apply to those 1,589 frames and to nothing else: 308 by the roll table,
#' the rest by 10.76. A digital frame's `scale` is a nominal figure, not
#' the rest by 10.76. (The table's factor-1 rows correct a scale, not a height, so
#' they are not among them.) A digital frame's `scale` is a nominal figure, not
#' its image scale, so it is not compared: only the 16,000 m ceiling, or terrain at
#' or above the aircraft, can refuse one. To list the frames worth a second look:
#' `dplyr::filter(fp, height_source != "reported")`.
Expand Down
Loading
Loading