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
18 changes: 18 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,24 @@ handed a 0.1 row back to #54's repair. `bc79027` reads ÷10 but spacing rejects
logs 80% overlap against the ~60% window. `bcb98013` frame 52 is a leading-digit typo that no
factor recovers. Neither case moved the rule

- **A same-roll adjacent frame is a third witness, and its tolerance is the catalogue's
storage, not 2%** (#74) — where no logbook settles a roll-height, a frame one number away on the
same roll, lens and scale, itself in band, whose height the catalogue's stands in an
**exact** relation to (×10, ÷10, ÷100, ×10.764, one leading digit) settles it at the
neighbour's height, with spacing agreeing and a logbook vetoing only by naming a different
factor. Rule fixed before running, run over all 521 excluded roll-heights: 5 settle (138
frames), `bc5596` and `bcb98013` plus `bc7675`/`bc87070`/`bcc822` in the lower tail, each
corroborated by a logbook row its own rule could not accept. **The tolerance is load-bearing
in both directions.** `bc5596` 204–211 sit between 2,621 m (×10 to 2 m) and 2,438 m (×10.764
to 30 m, 0.12%), so at 2% the two neighbours name different relations and the generator's
control stops. And the catalogue **truncates** as well as rounds (2,000 ft is 609 on
`bc5449`), so `exact()` is `big − k·small ∈ [−(1 + k/2), k + 1/2]`; the rounding-only form
refused `bc7675`, and a test pins it. That bound covers 0.3048 m/ft conversions only; a
figure converted at 3.28 ft/m (20,000 ft as 6,098) falls outside and refuses, which moves no
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

## 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)

- **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
- **The tolerance is the catalogue's storage, not the logbook's 2%, and that is load-bearing.** `bc5596` 204–211 sit between 2,621 m and 2,438 m. The first is ×10 to 2 m; the second is ×10.764 to 30 m, only 0.12%. At 2% the two neighbours name different relations, and the generator's control stops the run. The first form assumed rounding only. Code review found truncated heights (2,000 ft stored as 609 m), and that form had refused `bc7675`; the corrected form changes that outcome and no other
- `flying_height_rolls.csv` gains **`witness`** (`"logbook"` | `"sibling"`) and **`sibling_frame`**. A sibling row ships the neighbour's catalogued height and has no `logbook_ft`. A leading-digit row's `factor` is the ratio it implies, and its cause is `height_leading_digit_added`. `flying_height_rolls_excluded.csv` gains **`sibling_reason`**. The table now reaches 1,438 frames (1,130 lower, 308 upper), and 1,281 slipped frames stay on ÷10.764. No change to `fly_footprint()`'s logic

## 0.16.0 (2026-09-26)

- **Where a logbook reads #54's slipped frames, their height is ÷10, not ÷10.764, and those roll-heights are now carried in the roll table** ([#71](https://github.com/NewGraphEnvironment/fly/issues/71)). #54 divides `flying_height` by 3.28084² on 1,589 film frames, and ÷10 lands every one of them in the band just as well, so the terrain could not choose. The logbook pages covering the slipped frames of five rolls were fetched and read blind, with the catalogue values withheld from the reader. On four (`bc78078`, `bc79027`, `bc79103`, `bcc00085`), and on the fly#60 control `bc78065`, the crew's height is the catalogue's ÷10: within 0.01%, and 0.9% off on `bc79027`. It sits 6.7–7.6% above ÷10.764 on every one. On the tabled roll-heights #54 was drawing frames **7.6–9.9% narrow** (15–19% in area); width follows height above ground, so the error exceeds the 7.6% gap between the factors
Expand Down
45 changes: 29 additions & 16 deletions R/fly_footprint.R
Original file line number Diff line number Diff line change
Expand Up @@ -205,11 +205,12 @@ fly_dem_coverage_min <- function() 0.95
# choose between them. The logbooks can: on five of the six rolls before 2003 whose
# slipped frames a page covers, the crew's height is the catalogue's divided by 10, to 0.9%
# (the sixth is a one-frame typo no factor fits), and the roll-heights that also pass the
# spacing check are carried in `flying_height_rolls.csv`, which is consulted first. What
# reaches this factor is the 2003-2005 rolls, which have no logbook (the 2003 ones carry
# measured per-frame heights and fit 10.764 better; `bcc05001` is undecided), plus 19
# older frames the table does not reach, each listed with its reason in
# `flying_height_rolls_excluded.csv`.
# spacing check are carried in `flying_height_rolls.csv`, which is consulted first. Two more
# are settled there by the same roll's adjacent frames (fly#74): `bc5596` 204-211, ten times
# frame 203, and that one-frame typo. What reaches this factor is the 2003-2005 rolls, which
# have no logbook (the 2003 ones carry measured per-frame heights and fit 10.764 better;
# `bcc05001` is undecided), plus the 10 frames of `bc79027` whose spacing rejects its
# logbook, each listed with its reason in `flying_height_rolls_excluded.csv`.
fly_height_slip_factor <- function() 3.28084^2

# How far a frame's height above ground may sit from `scale x focal_length` before the DEM
Expand Down Expand Up @@ -254,6 +255,14 @@ fly_flying_height_max <- function() 16000
# which side of the band the roll-height came from. `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
# number on the same roll, lens and scale, itself in band, whose height the catalogue's stands
# in an EXACT relation to (x10, /10, /100 to what storing whole metres of a 0.3048 m/ft
# conversion, rounded or truncated, can move a figure, or one leading digit).
# `witness` says which settled a row; a sibling row ships the sibling's catalogued height,
# names it in `sibling_frame`, and has no `logbook_ft`. A leading-digit row's `factor` is the
# 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
Expand All @@ -266,7 +275,7 @@ fly_height_roll_table <- function() {
stop("`flying_height_rolls.csv` is missing from the installed package.", call. = FALSE)
}
utils::read.csv(path, colClasses = c(film_roll = "character", cause = "character",
tail = "character"))
tail = "character", witness = "character"))
}

# The DEM-aligned grid a single footprint is counted against.
Expand Down Expand Up @@ -688,7 +697,8 @@ fly_is_square <- function(footprints) {
#' 1974 and 2005 — a feet-to-metres conversion applied the wrong way round, which
#' draws a 1:35000 frame 110 km across. On six roll-heights flown 1978-2000 the flight
#' logbooks show the factor is exactly 10 instead (fly#71), and those frames are
#' carried in the roll table below. A film frame states its height above
#' carried in the roll table below, as are two more that the same roll's
#' adjacent frames settle (fly#74). A film frame states its height above
#' ground twice, as `flying_height` minus terrain and as scale times focal length,
#' so the two are compared, and `height_source` records the outcome:
#'
Expand All @@ -702,10 +712,11 @@ fly_is_square <- function(footprints) {
#' elevation}
#' \item{`"corrected_roll_table"`}{they disagree, and the frame sits on one of
#' the roll-heights in `inst/extdata/flying_height_rolls.csv`, which the
#' province's flight logbooks and the spacing between adjacent frames settled
#' (fly#60, fly#71): a height with one or two digits dropped (a logbook "20.0",
#' 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",
#' thousands of feet, catalogued as 2,000 ft), a height recorded ten times too
#' large, or a correct height beside a wrong `scale`. Checked before the
#' large, a leading digit added, or a correct height beside a wrong `scale`. 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}
Expand All @@ -723,7 +734,7 @@ 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: 299 by the roll table,
#' 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
#' 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:
Expand Down Expand Up @@ -1108,8 +1119,9 @@ fly_footprint <- function(centroids_sf, negative_size = 9, format_size = NULL,
# two are compared, and a frame outside `fly_height_ratio_band()` is not sized from
# its `flying_height` as it stands. Where dividing by `fly_height_slip_factor()` brings
# it back inside, that is the slip and the corrected height is used; measured over the
# whole catalogue the repair fires on the 1,589 and on nothing else, less the 299 on
# 1978-2000 rolls whose logbooks say x10, which the roll table takes first (fly#71).
# whole catalogue the repair fires on the 1,589 and on nothing else, less the 308 the
# roll table takes first: 299 on 1978-2000 rolls whose logbooks say x10 (fly#71), and 9
# an adjacent frame on the same roll settles (fly#74).
# Anywhere else the two disagree and nothing here can say which is wrong, so the frame
# falls back to nominal scale, exactly as one with unusable metadata does.
#
Expand Down Expand Up @@ -1316,9 +1328,10 @@ fly_footprint <- function(centroids_sf, negative_size = 9, format_size = NULL,
if (any(roll_tabled)) {
warning(
sum(roll_tabled), " of ", sum(dem_eligible), " frames sit on a roll whose ",
"`flying_height` disagreement was settled by the flight logbooks and the spacing ",
"between frames (`flying_height_rolls.csv`): a height with dropped digits or ",
"recorded ten times too large, or a ",
"`flying_height` disagreement was settled by the flight logbooks or an adjacent ",
"frame on the same roll, and the spacing between frames ",
"(`flying_height_rolls.csv`): a height with dropped digits, recorded ten times ",
"too large or with a leading digit added, or a ",
"correct height beside a wrong `scale`. Sized from the measured height; ",
"`flying_height` is left as supplied and `height_agl` is the height used. ",
"See `height_source`.",
Expand Down
Loading
Loading