Move the checklist library here from junco, and resolve the two projects into one - #1
Merged
Merged
Conversation
Design proposal for Open Checklists, a machine-readable aircraft checklist corpus. Research and design only — no site, no pipeline, no corpus. docs/01-legal-research.md Copyright doctrine (102(b)/Baker v. Selden, the blank-forms rule, the recipe cases as closest analogy, ADA v. Delta Dental as the adverse authority on taxonomies), the public-domain lanes, and a survey of existing collections and prior open-source attempts. Two findings that change the plan. Product liability is the larger exposure than copyright: US courts treat aeronautical charts as products for strict liability, and Winter v. G.P. Putnam's Sons distinguishes books from charts on grounds that put a checklist on the chart side. And a blanket corpus licence would assert rights the project does not hold for POH-derived files, so rights are per file. docs/02-format-decision.md Recommends canonical JSON, argues the decisive reason is embedded consumers rather than tooling, and pushes back on four points: a published JSON Schema cannot express the rules that keep the corpus safe, JSON diffs need semantic rendering in review, a lossy CSV export must never silently drop a warning, and the licence compatibility constraint between efis-editor's Apache-2.0 and GPL-2.0. docs/03-verification-model.md Replaces the machine/reviewed/verified ladder with two independent axes. Flying behind a checklist cannot detect a dropped item, so operational review never lifts a file out of quarantine. Adds evidence requirements, automatic demotion on content change, presentation rules, and a takedown process. docs/04-roadmap.md OCR pipeline with source admissibility as a gate separate from transcription accuracy, dual-pass transcription for disagreement mapping, and a first milestone restricted to public-domain sources with no website. schema/open-checklist-1.0.schema.json JSON Schema 2020-12. Semantic phase vocabulary, challenge/response items, non-tickable note/caution/warning types, memory items, and per-file provenance, verification and rights blocks. tools/ Reference validator running the schema then seven policy checks, with 27 negative cases covering the safety rules. examples/ Four files exercising different rights and verification corners, including a Part 103 ultralight and a glider. One is grounded in FAA-H-8083-3C; the rest are authored and marked as such. None is airworthy. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JRrL2B6zmM3jxkTRt2DTVB
…g question Follows the clarification that the goal is a phone checklist you tick off during preflight, a log proving you did it, and printing at arbitrary paper sizes — with the corpus as fuel for the tool rather than the deliverable. docs/05-product-and-sourcing.md freechecklists.net was reachable this time and was read. It is owned by Dauntless Software, a commercial vendor, holds 760 resources, and its DO NOT terms state verbatim: "Copy the material from this page and put it on your web page. You do not have permission to do this," alongside a prohibition on direct-linking files. dauntless-soft.com's robots.txt blocks ia_archiver specifically, so mirroring is a considered position rather than an oversight. Bulk-scraping therefore fails on three independent grounds: the terms forbid it, Dauntless cannot grant permission for contributor-authored material it merely hosts, and ingesting 760 files of unresolved provenance would defeat the verification model by construction. The workable route uses the site as an index — facts about which documents exist are not protected — and obtains each document from its real source. Their own listing points at the best lane: T-34B NATOPS publications are US Navy works, public domain at source. Priority order, permission-request strategy, and revised M1-M6 sequencing included. Also records the two-edged nature of the log: Part 91 requires no preflight record, so once one exists it can be read against the pilot. Design responses are no bulk-complete, tick-time timestamps, explicit recording mode, and making skips expressible rather than hidden. schema/open-checklist-log-1.0.schema.json Completion log format. checklist.content_hash binds a log to an exact checklist version; recording.mode separates live from retrospective; skipped and failed states require a reason; aircraft_rejected is a first-class outcome; previous_log_hash chains a series so backdating breaks later links. tools/render.py One checklist in, one self-contained HTML out: phone tick-off, selectable paper size for print, log export. No external requests, so it works with no signal. Information items get no checkbox and there is deliberately no check-all. tools/validate_log.py Schema plus policy: entry references resolved against the checklist, information items rejected as completed, timestamps bounded by the session, and an implied-working-rate check that declines to treat a physically implausible run as evidence of an inspection. Verified end to end in Chromium at a 390px viewport: 48 tickable items, zero checkboxes on information items, no horizontal overflow, prints to a 4-page kneeboard PDF, and the exported log validates. The rate check caught the automated test run at 0.07s per item, which is what it is for. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JRrL2B6zmM3jxkTRt2DTVB
…l transcription Acts on "pull down as much public domain stuff as we can", and answers the manufacturer question. tools/acquire.py + sources/public-domain.json Manifest-driven acquisition with SHA-256 recorded per asset and a provenance sidecar written per document. A `discover` subcommand searches the Internet Archive and prints candidates without downloading anything, keeping the admissibility decision human per the Stage 0 gate. The host allowlist is the sourcing policy expressed as code: freechecklists.net and dauntless-soft.com are in the denylist with the terms quoted as the reason, so the refusal survives the memory of the conversation that produced it. Any host not on the allowlist is refused rather than silently fetched. Both behaviours are exercised. examples/beechcraft-t-34a-usaf.ocl.json First genuinely type-specific transcription, from USAF T.O. 1T-34A-1 (10 February 1958) — a US Government work with no copyright, for a type civilians still fly in the restricted and experimental categories. 117 tickable items, 27 memory items, across preflight, interior inspection and ten emergency procedures. Left at source_fidelity=unreviewed, and sections that fell on unreadable pages are omitted rather than reconstructed. Measured OCR finding worth keeping: 12 of 164 pages extract as inverted mojibake, three of them inside the block marked CUT ON LINE. The cause is the original print design rather than the scan — the condensed checklist is a cut-out card whose alternating panels are printed upside down so they read correctly once folded. So the least reliably OCR'd pages are exactly the ones holding the checklist, and /Rotate is 0 on all 164 pages, meaning rotation detection has to be per-page and content-based. docs/05-product-and-sourcing.md section 4 On manufacturers. The instinct that safety information should reach pilots is widely shared and several manufacturers already publish POHs free, but obtaining a document lawfully grants no right to republish it: first sale covers the copy, not the contents, so scanning solves acquisition and not redistribution. Their actual reasons for controlling distribution are revision control, product liability and the fact that an approved AFM is part of the type certificate — not secrecy. Currency is their strongest objection and this format's strongest feature, since source.revision, supersedes and content_hash let every derived copy be marked stale the day a revision lands. Reframes the ask accordingly. All five checklist files validate, 27 negative cases still fire, the log validates, and the schema caught an over-length provenance field in the new file during authoring. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JRrL2B6zmM3jxkTRt2DTVB
…al premise Responds to the point that the real differentiator is letting people report a stale checklist so it can be fixed. That mechanism did not exist in the proposal and should have. schema/open-checklist-report-1.0.schema.json, tools/validate_report.py, tools/test_reports.py, two worked reports in examples/ A report is structured rather than free text for one reason: a comment thread cannot demote a file and a report can. Types cover transcription_error, stale_item, source_revision_available, airframe_variation, procedural_concern, rights_concern and improvement. Three enforced rules give it teeth. A report pins the exact content_hash it was filed against, so a report against a superseded version is recognised as history rather than a live defect. A confirmed transcription_error or stale_item against a file claiming single_reviewed or dual_reviewed errors unless the resolution records demoted_verification, because a review of content known to be wrong is not evidence. And an open safety_critical report requires a matching safety_defect in the file's own known_issues, so the concern travels inside the downloaded JSON or printed PDF instead of living only on a website. 14 cases, including the positive case that the demotion rule accepts the situation once the demotion is actually recorded. This makes verification a live state that degrades when someone finds a problem and recovers when it is fixed, rather than a judgement made once at transcription. That is the part a PDF library structurally cannot do. docs/06-community-currency.md Concedes two points. Staleness parity: a transcription made today is exactly as current as freechecklists', and the earlier currency section was about why manufacturers control distribution, not a comparison against the incumbent. And the observed enforcement rate for this activity is approximately zero, which is real information about risk even though it is not a legal defence. Corrects one premise that points the wrong way: copyright attaches on fixation, with no publication, registration, notice or book required. Formal publication is where pre-1978 copyrights were lost, not where copyright is gained. The stronger argument is available and is the one to stand on: the document is copyrighted, but procedure, functional directions and merged expression are not protected by that copyright. Locates precisely where the flight-club analogy stops. Typing your own checklist is not the problem, it is the recommended posture and is what rights.status=original_expression means. Personal use is strong, club sharing is plausible, and what moves is distribution scale rather than authorship. States the remaining disagreement narrowly: transcribing from POHs in your own words is supported, covering the same aircraft as freechecklists is fine, and the only refused act is bulk-copying another site's files, which rests on their stated terms rather than on a copyright judgement. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JRrL2B6zmM3jxkTRt2DTVB
…d CI The website, wired to the corpus already in the repo. The rights rules are already encoded in the tooling, so the site inherits them rather than restating them: acquire.py refuses non-allowlisted hosts, and the validator refuses to publish a file whose rights are unresolved. tools/export.py Converters to json, csv, tsv, md, txt, xml, docx and html. DOCX is written directly as OOXML with no dependency, because Word is where people take a checklist to edit it. CSV is one row per item with a type column, deliberately not phase-as-column, since that shape cannot represent a warning. The safety-preserving export contract from docs/02 is enforced rather than intended: verify_export re-reads each generated artifact and fails if a warning, caution or memory marker went missing. Proven by feeding it an exporter that strips warnings — all seven formats catch it. Two false positives found and fixed along the way, both escaping artefacts in the checker rather than real drops: JSON and XML mark memory items as fields rather than labels, and HTML escapes the apostrophe in "aircraft's". tools/build_site.py Static site, no server, no database, no build-time network access. Filterable catalogue, a page per checklist, every download format, a machine catalogue at api/index.json with no key or rate limit, stable plain-HTTP paths, a SHA-256 manifest so a mirror can be verified, separate reviewed and unreviewed bundle listings, robots.txt and sitemap.xml. Two verification-model rules are enforced here rather than left to templates, because a site generator is where they get quietly forgotten: a quarantined file carries .UNREVIEWED in its download filenames, and quarantined files are kept out of the default bundle listing. .github/workflows/open-checklists.yml Path-filtered to open-checklists/** so it does not run on unrelated Junco work. Runs the validators, both negative-test suites, the export contract and the site build, and uploads the site as an artifact. This is the point at which the corpus rules stop being a document and start being enforced. Verified in Chromium: 5 cards render, search narrows to 1 on "t-34", the category and verification filters work, reviewed-only correctly returns 0 of 5, all 35 download links resolve, no console errors. All five files are quarantined, which is correct — none has been reviewed by a second person. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JRrL2B6zmM3jxkTRt2DTVB
…browser editor Builds out what the corpus is actually for in the experimental and ultralight world: engine swaps and panel rebuilds are the norm, so a builder's checklist is most useful to the next person when they can see what changed and why. schema: aircraft.airframe_family, aircraft.modifications[], derived_from airframe_family groups every variation of one airframe regardless of engine, so browsing "what did others flying this do" works. modifications[] records the swaps with a kind, an affects_procedures flag and how they were approved (part103_none is an honest option, not a gap). derived_from records lineage by attribution rather than inheritance. A forked file stays complete and standalone, so a pilot always holds the whole checklist and never a composition resolved at render time. That was the reason I deferred this in 1.0; attribution gives the same discoverability without the ambiguity. It stores the parent's hash at fork time, which lets tooling distinguish "the parent has since changed" from "this fork diverged". validate.py: derivation policy A variant that names neither a modification nor a changes_summary is rejected — a duplicate with no stated reason is corpus noise. An airframe_specific_copy must identify its aircraft. A variant must share its parent's family. Warns when the parent has moved on and diverged is unset, and when modifications are recorded without a family slug, since that file will not surface where people look for it. tools/diff.py Semantic diff, not a text diff: matches sections by id and items by id or text, then ranks findings so warnings and cautions come first, then memory items, then changed control settings. A JSON diff of two checklists buries the line where a response went from 2,000 to 2,400 RPM; this leads with it. site: family pages and the editor f/<family>/ lists every variation of an airframe with each fork's diff inline. editor.html creates or forks a checklist entirely client-side — no account, nothing uploaded. Forking fills in derived_from and computes the parent hash in the browser, and information items structurally cannot be given a response or made tickable, so the rule that matters most cannot be broken by the editing UI. Files it produces are always marked authored, unreviewed and not airworthy; those states are earned by someone else checking the file, not claimed by writing it. examples/aerolite-103-kawasaki-340-n512jm.ocl.json The worked lineage case: same airframe, Kawasaki 340 twin in place of the Hirth single, electric start added. The diff reports 22 procedural differences and the changes_summary explains what the swap forced. Verified in Chromium over HTTP: the family page renders 22 diff findings with the warnings group first; index search finds files by modification kind and by engine; the editor forks the baseline, loads 6 sections and 48 tickable items, and its downloaded file passes the full validator with no errors and no warnings. Two real defects found by testing rather than assumed away. The browser's SHA-256 of the parent matches the Python content_hash exactly, confirming the canonical serialization agrees across languages. And the validator caught the editor emitting memory items without the required id, which is now derived from the item text and de-duplicated per section. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JRrL2B6zmM3jxkTRt2DTVB
…cy pages Turns the site into something a builder can actually use: write a checklist, keep it, fork anyone else's, print it to fit a kneeboard, and install it on a phone. Saving, and one design call worth stating "Save onto the website" has two meanings and they need different answers. Your own checklists now persist in browser storage — a My Checklists list with save, open, download, delete, import/export of the whole library, and an autosaved draft so a closed tab does not cost an hour of typing. Nothing is uploaded, which is what makes the privacy policy short and true. Writing into the public corpus stays a reviewed path: Contribute downloads the file, saves it locally and points at the pull-request steps. Anonymous direct writes into a safety library would defeat the verification model entirely, so that one is deliberate rather than unfinished. Forking from anywhere editor.html?fork=<id> deep links, a dropdown of the whole catalogue, and a "Fork this in the editor" button on every checklist page alongside links to the other variations of that airframe. Printing and phones Ten preset paper sizes plus a custom width/height, and a text scale control for poor cockpit light: Letter, Legal, A4, A5, A6, kneeboard 5.5x8.5, small kneeboard 4.25x5.5, index card 5x8, small index card 3x5, half-letter landscape. A web app manifest and generated PNG icons make it installable on a phone, and a service worker precaches the shell and every checklist page so it opens in a hangar with no signal. The worker is network-first so a corrected checklist is never served stale from cache. Branding A wordmark and logo — a checkbox whose tick sweeps up like a wing, inline SVG in currentColor so it works in both themes — plus a favicon, theme colour, Open Graph tags, a landing page at index.html, and the catalogue moved to catalogue.html. Tagline: free aircraft checklists that tell you where they came from. Policy pages privacy, terms, takedown, contribute and contact. The privacy policy is short because there is genuinely almost nothing to disclose: no analytics, no cookies, no accounts, no third-party requests, and everything the visitor writes stays on their device. Terms lead with the safety notice and set out per-file licensing rather than implying one licence covers the corpus. Takedown publishes the unpublish-first process, including what the project can offer a manufacturer that their own PDF distribution cannot. Contribute carries the contributor warranty and says plainly that every submission arrives marked authored, unreviewed and not airworthy, because verification is earned by someone else checking it. Verified over HTTP in Chromium: all eight pages return 200, the landing page and wordmark render, a checklist saves to the library and survives a reload, the deep-link fork resolves and computes the parent hash, the fork and variations links appear on checklist pages, custom paper size produces the expected @page rule, the text scale changes the computed font size, the service worker registers, and there are no page errors. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JRrL2B6zmM3jxkTRt2DTVB
…r-month currency There is no interchange standard for pilot logbooks. ForeFlight, LogTen, Garmin Pilot, MyFlightbook and Safelog each define their own CSV template, so moving between them is lossy hand work and a flight history is effectively hostage to a vendor. Same gap shape as checklists, so the same answer: a documented format the data can live in and be converted out of. schema/open-logbook-1.0.schema.json Fields follow 14 CFR 61.51 for what must be recorded, plus what 61.56 and 61.57 need to compute currency. Time buckets are deliberately not mutually exclusive, because the regulations are not — the same hour can be PIC and dual received and night and cross-country at once. Approaches are objects with a type and location rather than a bare count, because 61.51(g)(3) requires the location and type of each approach and a number alone neither satisfies the rule nor can be audited. Safety pilot name is capturable for 91.109. carried_forward keeps imported paper totals separate from real entries so currency is never computed from a lump sum. checklist_log_id joins a flight to the preflight completion log recorded for it, which is the link no other logbook can make. tools/logbook.py — validate, totals, currency, import, export The arithmetic is checked: day + night cannot exceed total, PIC and SIC cannot overlap, no component can exceed total, solo and dual on one flight is contradictory, full-stop landings cannot exceed landings, and a Hobbs span that disagrees with logged time by more than 0.2 is flagged. Currency is computed in calendar months, not rolling days. 61.57(c) says "the preceding 6 calendar months", which means through the end of that month; a rolling-183-day implementation gives the wrong answer near month boundaries and gives it in the unsafe direction. Tested at the boundary in both directions, plus the fly-to-regain window and the point at which an IPC becomes necessary. Import preserves what it cannot map. Unrecognised columns go into imported_from.unmapped and are reported, because a silent lossy import is how somebody loses a decade of flying. It also skips vendor preamble rows to find the real header, parses 1:18 as well as 1.3, and defaults aircraft make and category to placeholders while saying so, since currency depends on them. Currency output is framed as an aid, not an authority: it cannot see an IPC, a type-specific requirement, or whether a landing was truly to a full stop. Two correctness bugs found by running it rather than reasoning about it. Tailwheel and tricycle aeroplanes were being merged because they share a category_class, so tricycle touch-and-goes appeared to satisfy tailwheel currency under 61.57(a)(2) — now grouped by class and tailwheel separately. And 61.57 was being reported for Part 103 vehicles, which it does not reach at all, since it governs acting as pilot in command under Part 61; those now report no requirement with the reason. 26/26 logbook checks pass, and CI runs them. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JRrL2B6zmM3jxkTRt2DTVB
19,426 US airports, heliports, seaplane bases, gliderports and ultralight strips from the FAA's 28 Day NASR Subscription, a public-domain government dataset: runways with surfaces and condition, 37,537 radio frequencies with callsigns and tower hours, fuel, pattern altitude, field elevation, magnetic variation and sectional. Includes the 14,259 private strips most apps leave out, which matter for exactly this project's audience. tools/airports.py Reads the inner CSV_Data bundle rather than the 232 MB fixed-width APT.txt. Emits a lean search index plus 35 detail shards keyed on the first character of the identifier, because 19,426 individual pages would make the build slow and the deploy heavy. Frequency use codes are translated to labels a pilot reads, with unknown codes passed through rather than dropped. Two things found by testing: NASR keys on the FAA identifier, so KFDK is stored as FDK and lives in a different shard than its ICAO id implies — there is now a shipped ICAO-to-ident map rather than leaving every consumer to rediscover that. And remarks were a third of the payload, so they are capped at eight per airport. The ingested output is ~30 MB, so data/ is gitignored and the site build ships airport pages only when it is present. NASR is in the acquisition manifest with a note to re-ingest every 28 days. Staleness is handled rather than ignored: the AIRAC effective date is carried through into cycle.json, and the page shows how old the data is and says SUPERSEDED once a newer cycle has been published. A stale frequency is worse than no frequency. Weather, and why there is a Worker Live weather cannot be done from a static page: aviationweather.gov serves its API to a server but sends no Access-Control-Allow-Origin header, which I confirmed in a browser. Rather than abandon the static architecture, the site ships worker/weather-proxy.js — a one-file Cloudflare Worker, which adds no new infrastructure given the site is going behind Cloudflare anyway. It restricts itself to that one upstream host and a fixed set of products, caches for 60 seconds because weather cached longer lies, and logs no identifiers so the privacy promise stays true. Until it is deployed the page says exactly what is missing and links to the official source instead of silently showing nothing. Weather is deliberately excluded from the service worker precache. Everything else here degrades gracefully when stale; a METAR does not. Verified in Chromium: the cycle notice reports the data as 4 days old, searching KFDK resolves to FDK and opens Frederick Muni with 16 frequencies including tower hours, both runways render, the deep link ?a=W29 opens a private strip, and there are no page errors. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JRrL2B6zmM3jxkTRt2DTVB
Completes the feature set: a searchable public-domain document library with cited results, a registry for the documents that cannot be hosted, a projects page, and an honest answer on charts. tools/library.py + search.html Full-text index over public-domain maintenance documents, currently AC 43.13-1B (Acceptable Methods, Techniques and Practices) and the AMT General Handbook — 1,342 pages, 5,164 passages, 14,807 terms. BM25 scoring, an inverted index sharded by first letter, and passages sharded in buckets of 500 so a query fetches a few hundred KB rather than the 4 MB store. The browser implements the same tokeniser and scoring as the CLI, so results match: "magneto timing" returns AC 43.13-1B paragraph 8-20 on page 397 in both. It cites, it does not diagnose. Every result is a passage with document, revision and page, and the page says so above the search box rather than in a footnote. A generated answer would be the only thing on this site with no provenance, and "your problem is probably X" is the claim that hurts somebody when it is wrong. Retrieval is also more useful, because it hands over the actual text. If an LLM is added later this is the correct substrate: retrieve first, summarise these passages with these citations, never answer from memory. Ingest enforces the same admissibility gate as the checklist corpus, reading the provenance sidecar acquire.py writes and refusing anything not public_domain — so a manufacturer manual cannot be indexed by accident. Manufacturer and engine manuals are instead a registry of ten entries: what the document is, its part number where known, whether it is free or purchased, and where to get it. Listing what exists is a fact about the world, not a copy. Rotax, Cirrus, Hartzell and Jabiru publish freely; Lycoming, Continental, Textron and Piper sell theirs, and the page says which is which. charts.html Explains why the project links to FAA charts rather than re-cutting them, and the reason is liability rather than copyright: FAA charts are government works you may freely copy, but courts have treated aeronautical charts as products subject to strict liability, and a customised chart a pilot navigates from is the exact fact pattern. Every other artifact here can carry a verification state; a chart you fly by cannot be made safe with a label. Links to all five FAA digital product lines and to SkyVector, and points out that the airport pages already carry the field data you would otherwise read off a chart. projects.html Open Checklists, Junco and the flight simulator, framed around the thing that actually connects them: the formats. A checklist only this website could read would be worth little, which is why the schemas are permissive enough for closed products to adopt. Verified in Chromium: all seven pages return 200, the search returns 12 ranked hits with correct citations and term highlighting, the deep link ?q= works, the registry renders ten entries, and there are no page errors. Full suite still green. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JRrL2B6zmM3jxkTRt2DTVB
…from a logbook Serves student through commercial, and the second half is the part nothing free does well. tools/training.py + training.html — progress toward a certificate Encodes the aeronautical experience requirements from 14 CFR part 61 for sport, private, instrument, commercial, CFI and ATP, then reads a real logbook against them. Runs client-side on the site, so a logbook never leaves the device, and the browser implements the same arithmetic as the CLI — verified identical on the example logbook: 4 met, 6 short, 1 undetermined, 3 to confirm. Three rules keep it honest, because a student will act on it. Every line cites its CFR paragraph, not just an hour count. If the tool and the regulation disagree the regulation wins, and the citation is how you find out. What a logbook cannot answer is left unchecked rather than guessed. Whether an airport had an operating control tower is not a logged field, so 61.109(a)(5)(iii) reports "cannot be determined from a logbook" instead of failing someone who has met it. Instructor endorsements and knowledge tests are listed as confirm-manually and never counted toward a total that would look complete. Where a logbook records night cross-country flights but no distances, that reads as undetermined rather than short. Intersected buckets understate rather than overstate. A logbook records cross-country and PIC hours but not their overlap, so the tool takes the smaller of the two per entry. It also discloses when carried-forward totals had to be excluded from an intersected requirement — 78.9 hours in the example — rather than silently dropping them, because a student would otherwise think the tool had lost their hours. It reports; it does not certify. Study library Sixteen entries covering what the FAA publishes free: PHAK, the Airplane, Instrument, Instrument Procedures, Weather, Risk Management, Weight and Balance and Instructor handbooks, the handbooks for glider, helicopter, balloon, powered parachute and weight-shift control, the ACS documents, the knowledge-test figure supplements, the Chart User's Guide, advisory circulars, FAA Safety Briefing and WINGS. Plus a suggested reading order that puts the ACS second rather than last, since it tells you what you will actually be tested on. Library now indexes 11,469 passages across 12 documents Added PHAK (522 pages), the Instrument Flying Handbook (370), the Weight and Balance Handbook (112) and five ACS documents, on top of AC 43.13-1B and the AMT General Handbook. All US Government works, so full text is publishable. PHAK needed a retry — the first fetch truncated at 67 of 77 MB, which the manifest hash then caught. Verified in Chromium: six certificate tabs, sixteen study cards, a saved logbook loads from browser storage, progress bars and per-requirement notes render, tab switching recomputes, and the carried-forward disclosure appears. CI now emits the requirement data and checks progress on every run. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JRrL2B6zmM3jxkTRt2DTVB
Ingests the two documents I flagged as the highest-value gaps in the library: the Aviation Weather Handbook (FAA-H-8083-28B, not the 28 the FAA landing page is named for) and the Risk Management Handbook (FAA-H-8083-2A). Both are US Government works. The library goes from 12 documents to 14 and from 11,469 passages to 13,518. Indexing them exposed a real bug. The T-34A directory holds two renderings of one handbook -- the scan and an OCR text layer -- and ingest looped over paths, so that document was indexed twice, the second pass overwrote the first's metadata, and 402 passages sat in the store attributed to a document whose recorded count did not include them. Per-document counts no longer summed to the total. Ingest now groups assets by directory, deduplicates identical passages within a document, and reports pages as the longest rendering rather than the sum of both. That grouping also makes each document's passage ids contiguous, which buys a per-document search filter for free: limiting a search to one handbook is a range test on the passage id, with no extra fetches and no change to the shard layout. The study cards on the training page link straight into it, so "Aviation Weather Handbook" now goes to a search scoped to that handbook. An unknown or stale doc parameter falls back to searching everything rather than returning nothing, and a scoped search that finds nothing offers to widen instead of dead-ending. tools/test_library.py asserts the parts that a correct-looking search result cannot show you: that the admissibility gate rejects rather than flags, that one directory is one document, and that passage id ranges partition the store with no gaps or overlaps. A gap there would print one document's text under another document's citation, which is worse than no result. Wired into CI. acquire.py gains --pin, and every asset in the manifest is now pinned. Without a recorded hash a later fetch cannot distinguish a corrected document from one silently replaced at the same URL, and agencies do reissue PDFs in place. The provenance sidecar records the digests too, since it travels with the bytes and is what the index reads. nfdc.faa.gov joins the host allowlist, with a note -- it publishes the NASR data the airport pages already ship. Verified in Chromium against the built site: the deep link, the widen fallback, the unknown-parameter fallback, and the training-card links, with no console errors. Python and browser agree on match counts for the same query. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JRrL2B6zmM3jxkTRt2DTVB
Moving this to another machine surfaced a gap: pymupdf is required by the library ingest and was documented nowhere except the SystemExit message that fires when it is missing. The 640 MB of downloaded sources, generated indexes and built site are all gitignored, so a clone needs the pipeline spelled out rather than scattered across the tool reference. Records two things a new machine needs to know. The site builds with no downloads at all -- checklists, editor, exporters and policy pages come from examples/, and the airport, weather and search pages explain that their data is missing rather than breaking; verified from a fresh clone, 14 pages and the whole test suite green with nothing fetched. And the NASR manifest entry names a specific 28-day cycle, so once that cycle passes the fetch 404s and the URL needs updating, which is not obvious from a bare "not found". Also states what hash pinning is for at the point where someone will hit it: a MISMATCH means the document changed upstream, and re-pinning is a deliberate decision after checking what changed, not a way to clear the error. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JRrL2B6zmM3jxkTRt2DTVB
Brings the Open Checklists work out of allenmcghan/junco, where it was commissioned, into the repository the project is actually served from. Done with git subtree split, so all 13 commits of history come with it rather than landing as one opaque import. What arrives: the checklist, completion-log, field-report and pilot-logbook schemas; the validators and their negative-case suites; the semantic diff; exporters to eight formats; the public-domain acquisition tooling with pinned hashes; the FAA NASR airport ingest; the BM25 document library; the part 61 certificate requirements; and the static site generator that produces the whole 14-page site including the browser editor. Two projects had grown the same name, so this resolves them into one with a split by kind rather than by repository. Checklists stay JSON: they are documents with a source to cite and a verification state that has to survive conversion to every other format. Aircraft profiles stay TOML: they are hand-edited hardware configuration with no upstream document and no provenance to record, and someone will edit one in a text editor at a hangar. Forcing either into the other's format would make one of them worse, so the README now states the division and why. Three things had to be reconciled rather than merged: The repo-wide CC-BY-4.0 claim is replaced with per-file rights. It holds while every file is authored here, and breaks the moment a transcription of a manufacturer's procedure lands -- that is not ours to license out, and a US Government work needs no licence from us at all. The validator already refuses to publish a file whose rights are unresolved or upstream_reserved. The README also no longer links a LICENSE file that does not exist; the authored profiles and PM-2 checklists are still CC-BY-4.0 and now say so specifically. The placeholder index.html is removed, because a static host pointed at the repository root would serve it instead of the generated landing page -- a site that looks fine while serving a stub. Nothing it carried is lost: its Nuthatch link and its PM-2 profile and spec links are now on the generated projects page, which had no aircraft-profile section at all before this, and the README records that the deploy target is build/site with the Cloudflare Pages settings spelled out. The CI workflow is re-rooted: no path filter and no working-directory, since the corpus is now the repository rather than a subdirectory of one. The PM-2 checklists are deliberately left as Markdown for now. They carry their "not validated against the PM-2 POH" caveat as prose in a header, which no consumer can act on; converting them to .ocl.json turns that into a structured verification state. That is the first task after this move, and until it happens those three files are readable by people but invisible to every tool in tools/. Verified from this root: 6/6 checklists, 27/27 negative cases, 1/1 log, 2/2 reports, 14/14 report cases, 1/1 logbook, 26/26 logbook checks, 20/20 library checks, certificate data emitted, 0 export contract violations, and the site builds to 81 files with Nuthatch and the PM-2 profile present on the projects page. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JRrL2B6zmM3jxkTRt2DTVB
allenmcghan
pushed a commit
to allenmcghan/junco
that referenced
this pull request
Aug 10, 2026
The aircraft profile spec already redirected to the openchecklists repository. The checklist library has now moved there as well (allenmcghan/openchecklists#1), so the reference should cover it: the checklist, preflight-log and pilot-logbook schemas are all defined there and consumed here. Records the split by kind, because a reader who sees TOML profiles and JSON checklists in one project will otherwise assume one of them is a mistake. Profiles are hand-edited hardware configuration with no upstream document to cite; a checklist carries a source and a verification state that has to survive conversion into every other format. Different problems, different formats. Also names the property Junco actually depends on rather than leaving it implicit: checklist phase identifiers are stable and semantic, which is what lets the app map a section to a moment in flight instead of to a page number. No functional change to firmware, app, BLE spec, or log format. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JRrL2B6zmM3jxkTRt2DTVB
Rework the central CSS tokens/components in build_site.py (sticky pill nav, tinted hero, elevated cards, pill badges, modern inputs; remove dark-mode auto-switch so the background is always white) and align the standalone checklist renderer in render.py (larger tap targets, refreshed toolbar, soft-tinted safety banners). Mobile-first throughout; sub-pages inherit the shared CSS variables. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
allenmcghan
pushed a commit
that referenced
this pull request
Aug 17, 2026
…name) The council's #1 next feature. Closes the plan→fly→log loop. - D1: logbook_entries table (date, dep/arr, route, aircraft, total/PIC time, landings, remarks, source, source_ref) with a unique (user_id, source_ref) index for import de-duplication. - Worker: GET /api/me/logbook (entries + running totals), POST /api/me/logbook (add/edit), POST /api/me/logbook/import (pulls saved plans → entries, deduped), DELETE /api/me/logbook/:id. Auth-gated like the rest of /me/*. - Profile "My logbook": running totals (flights, total hrs, PIC, landings), one-tap "Import from my saved plans", add-a-flight form, delete, and a clear 61.51 "this is a convenience record, not your legal logbook" note. - Renamed "Recent preflights" → "Recent checklist completions" with a note that they are NOT the flight logbook (per council: avoid 61.51 confusion). - SkyWatch per-flight insurance leadgen: an honest external CTA (we don't sell or underwrite; unverified pre-check data is not a basis for coverage) — keeps us out of the underwriting/liability chain the council warned about. Drop the real leadgen/affiliate URL into #ins-link. Verified: routes deploy + auth-gate (401); logbook SQL validated on live D1 (import dedup, totals, ordering); profile JS syntax-clean, section deployed. Signed-in click-through not completed (Zitadel reset email did not reach the test mailbox); logic mirrors the proven /me/aircraft + /me/airports handlers. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Brings the Open Checklists work out of
allenmcghan/junco, where it was commissioned, into the repository the project is served from. Done withgit subtree split, so all 13 commits of history come with it rather than landing as one opaque import —git loghere now has 15 commits across both lineages.The companion change is junco#3, which reduces Junco to a reference.
What arrives
The checklist, completion-log, field-report and pilot-logbook schemas; the validators and their negative-case suites; the semantic diff; exporters to eight formats; the public-domain acquisition tooling with pinned hashes; the FAA NASR airport ingest (19,426 airports); the BM25 document library (14 public-domain handbooks); the 14 CFR part 61 certificate requirements; and the static site generator that produces the whole 14-page site including the browser editor.
Start at
README.md, thendocs/01–docs/06for the legal, format and verification reasoning.Two projects had grown the same name
This resolves them into one, split by kind rather than by repository:
Forcing either into the other's format would make one of them worse, so the README states the division and the reason.
Three things needed reconciling rather than merging
Repo-wide CC-BY-4.0 → per-file rights. A blanket licence holds while every file is authored here and breaks the moment a transcription of a manufacturer's procedure lands: that is not ours to license out, and a US Government work needs no licence from us at all. The validator already refuses to publish a file whose rights are
unresolvedorupstream_reserved. The README also no longer links aLICENSEfile that does not exist in the repo. The authored profiles and PM-2 checklists remain CC-BY-4.0 and now say so specifically rather than by implication.The placeholder
index.htmlis removed. A static host pointed at the repository root would serve it instead of the generated landing page — a site that looks fine while serving a stub, which is the kind of failure nobody notices. Nothing it carried is lost: its Nuthatch link and its PM-2 profile and spec links are now on the generated projects page, which had no aircraft-profile section at all before this. The README records that the deploy target isbuild/site, with the Cloudflare Pages settings spelled out.CI is re-rooted. No path filter and no
working-directory, since the corpus is now the repository rather than a subdirectory of one.Left deliberately undone
The three PM-2 checklists stay Markdown for now. They carry their "not validated against the PM-2 POH" caveat as prose in a header, which no consumer can act on; converting them to
.ocl.jsonturns that into a structured verification state the site, the exporters and any other software can read. That is the first task after this move — until it happens those files are readable by people but invisible to every tool intools/.Verified from this root
6/6 checklists, 27/27 checklist negative cases, 1/1 completion log, 2/2 field reports, 14/14 report cases, 1/1 logbook, 26/26 logbook checks, 20/20 library checks, certificate data emitted and checked against the example logbook, 0 export contract violations, and the site builds to 81 files with Nuthatch and the PM-2 profile present on the projects page.
Note that
reviewed: 0is correct rather than a bug: no checklist here has yet been checked against its source by a second person, and none of the six examples is airworthy — each says so in its ownknown_issues.🤖 Generated with Claude Code
https://claude.ai/code/session_01JRrL2B6zmM3jxkTRt2DTVB
Generated by Claude Code