Skip to content

feat(airframe): Rev T1 — the tilt spar becomes a structural member of the wing (both halves) - #195

Merged
Stab-Rabbit-coding merged 15 commits into
mainfrom
claude/serenity-wing-nacelle-validation-kvux9w
Aug 31, 2026
Merged

feat(airframe): Rev T1 — the tilt spar becomes a structural member of the wing (both halves)#195
Stab-Rabbit-coding merged 15 commits into
mainfrom
claude/serenity-wing-nacelle-validation-kvux9w

Conversation

@Stab-Rabbit-coding

@Stab-Rabbit-coding Stab-Rabbit-coding commented Aug 31, 2026

Copy link
Copy Markdown
Owner

Summary

This branch carries both halves of Rev T1, in the order they happened.

  1. The wing became the structure. The tilt spar stops being a rotating drive
    shaft and becomes a fixed 20 × 16.3 mm CF tube bonded into the wing over its
    full span — the wing's primary bending member. Everything below is a
    consequence of that. (8 commits, §0.)
  2. The fuselage half of the Rev T1 wing-root joint is built. The wing side has been done since 2026-08-29; the fuselage still carried WING_SPAR_Y = +38.15 and WING_SPAR_BORE_D = 8.3, so tools/wing_root_deconflict.py failed on three findings that were all that one fact.
  3. The nacelle tilt actuator is now a multi-turn device, per owner direction, with the fuselage drive stage that goes with it and a control spec for the loop it closes.
  4. A weight audit of the cargo section and wing roots, asked for as a lightening exercise — which found the real problem is that the BOM understates printed mass by +521.6 g, 13.3 % of AUW.

0 — The wing half (Rev T1 / T1b)

The four 10 AWG ESC feeds had no viable path to the nacelles: they do not fit the
wing's Ø7 conduits, and those conduits sit 17.65 mm forward of the tilt axis, so
every transition dragged the harness through a ~45 mm arc.

A bearing transmits shear, not moment, so the Rev R2 rotating spar was
structurally incapable of reacting the wing-root moment — which is why both
previous root designs (enlarged tenon FOS 0.49, two-rod couple FOS 4.14) existed
only to work around it. A fixed bonded spar carries it directly, and the couple
arm goes from 48 mm of chordwise rod spacing to the full 86.7 mm span.

Spar station / bore 45.15 → 28.0 mm / Ø8.3 → Ø20.4
THICKNESS_SCALE 1.00 → 1.46 — the root OML moves for the first time
THICKNESS_SCALE_TIP 1.56 → 2.20
Root path TENON_LOAD_PATH = "spar_carrythrough"; tie rods retired
Spar bending 33.28 MPa, FOS 9.0 (cantilever bound — skin credited with nothing)

Bore inventory, all constant-mm so taper cannot erode the webs: 8.0 Ø3.2 nav ·
28.0 Ø20.4 spar (now carrying the 4 × 10 AWG on the tilt axis) · 44.5 Ø6.5
AK7455 · 53.6 Ø4.4 drive shaft. The 2 × Ø7 double-D is retired — it could not
carry two 10 AWG conductors at any realistic wire OD, and its 27.5 mm station now
falls inside the spar bore.

Three owner directives that invalidated built geometry

  1. The spar must not penetrate the thrust duct. The stub was 32 mm and
    reached 15 mm inside the duct wall. The spar runs along local X at Y = 0,
    so it clears only if it terminates at |X| ≥ 26 → max 15.7, built 15.0.
    It had been budgeted outward from the bearing stack and never checked against
    the duct — the same class of error as the Rev R2 through-duct spar this
    revision exists to remove. The nacelle's bearing pair, ring gear and ring
    magnet must now all fit inside 15 mm.
  2. The centre of the cargo bay must stay clear. That killed the 55 mm socket:
    only 18.67 mm exists before the bay, where it gives FOS 0.51 on moment,
    and capacity goes as 1/L². Splitting the joint by load type instead — socket
    for shear, bonded 80 × 60 flange for moment — lands FOS 29.2 against the
    4.02
    the long socket gave. The constraint produced a better joint, and the
    bay is untouched.
  3. The shaft turns more than one revolution. This inverts the tip stage to a
    reduction and dissolves an "impossible ring gear" finding that was only
    true under the step-up reading a limited-rotation servo forces. Built 14T/50T
    module 0.8, i = 3.571, C = 25.6 → station 53.6. It voids the 180°/270°
    question
    and makes the encoder load-bearing for control, not telemetry.

The airfoil is no longer an S1223 — and is now described as such

Re-derived from the tabulated UIUC coordinates (REF-CAD-006) at 1/20000 chord,
not quoted. The built sections are designated S1223/t17.7 (root) and
S1223/t26.7 (tip): S1223's camber line with the thickness envelope scaled
×1.46 / ×2.20.

The previous header's chordwise locations were wrong — "22.6 %" and "39.4 %"
against a true 19.8 % and 49.0 %, which match the published S1223
characterisation exactly and were never traceable to the coordinate table the
file actually builds from.

Stated per claim rather than as a blanket disclaimer: camber (8.67 % at 49.0 %)
is exact; zero-lift angle and lift-curve slope partially survive at the
root only
, on thin-airfoil grounds — that theory depends on the camber line
alone, which is why preserving it matters, but 26.71 % t/c is far outside
"thin"; CL_max, L/D and the 7.6 N cruise-lift figure do not survive.
docs/flight_envelope.md now carries a banner saying every aerodynamic result in
it rests on an input that no longer describes the aircraft. LE radius goes as
t_scale² — the tip's nose is 12 % of its own chord.

Errors found and corrected rather than propagated

  • wing_tip_spar_through_bore() carried rotate([0,90,0]) and was cutting a
    chordwise hole. Harmless at Ø8.3 — the module's real job was simply never
    done — but a 20 mm gash at Ø20.4.
  • Plan 004 KTD4's shaft station implied a 15 mm gear centre distance, which
    returns a ring gear smaller than the spar it encircles.
  • wing_airfoil_integrity.py validated only the t_scale = 1.0 table and never
    read either thickness scale — it would have passed identically at 2.20, so it
    was not covering the risk it was cited for. Now validates the sections
    wing_solid() actually lofts.
  • 14 CFR Part 23.303, cited twice, was removed by the 2017 Amdt. 23-64
    restructure → §23.2230 (new REF-FAA-004, verified verbatim from GovInfo
    CFR XML; eCFR bot-blocks automated retrieval).
  • The FOS 4.0 joint target was described as bare judgment. It has a basis:
    §23.2265 requires a special factor for parts with manufacturing-process
    variability — exactly FDM-printed CF-PETG. The requirement is now cited; the
    numeric value stays the project's own choice.
  • Also recorded to prevent a future fabrication: +3.8 / −1.52 appear nowhere in
    current Part 23
    and must not be cited to it.

New: docs/WING_ATTACH_INTERFACE.md — the single spec for both joints, with a
WA-R1…R15 requirement register; tools/spar_bundle_fit.py; REF-MATH-001
(Melissen 1997) for the exact circle-packing ratios, because the n = 4 case
decided a load-bearing geometry change and the wrong constant (11.0 mm) had
already propagated through two independent documents by being carried in prose
instead of computed.

Unverified, and the FOS numbers should not be read as cleared: the 10 AWG
wire OD is assumed at 5.5 mm (bom_revS.csv records none, and the whole
Ø20.4 bore chain derives from it), and no ASTM D3039/D695 certificate exists for
any CF stock — the 300 MPa spar allowable is a conservative stand-in.

Aerodynamic content produced with the aeronautical-engineering skill, which
carries a standing ENGINEERING REVIEW REQUIRED notice: these are computed
geometric properties and an explicit statement of what is not known, not a
performance substantiation.


1 — Fuselage wing-root joint (WA-R1/R1b/R2/R4/R6)

airframe/blender-scripts/merge_cargo_interior.py now matches the Rev T1 wing:

  • Socket at chord station 28.0 → hull Y +21.00, Z +66.85 (unscaled camber midline), bore Ø8.3 → Ø20.4, boss Ø27.7 → Ø30.1. Shear only, FOS 16.
  • F688ZZ root bearing deleted. Not a tidy-up: a bearing here would let the fixed spar spin under the tilt pinion's gear reaction.
  • Both wing-root tie rods retired — the wing already gates them off, and the forward one now intersects the Ø20.4 spar bore outright.
  • Mortise 30.8 → 12.8 for the 12 mm locating tenon; fit lands at +0.40 mm/side in both axes.
  • Conduits re-cut: nav Ø4.2 @ Y +1.0, AK7455 Ø7.5 @ Y +37.5, drive shaft Ø4.4 @ Y +46.6. The two Ø7 EDF ports are gone — the four 10 AWG feeds now enter through the spar's own bore.

The root flange turned out not to be printable hull material, and measurement is what decided it. Ray-casting the envelope on a 13 × 17 grid (221/221 hits) shows the sidewall skin moving 34.3 mm (port) / 37.0 mm (stbd) of hull X across the 80 × 60 footprint. Filling to a plane gives a 34 mm slab; bounding with a plane leaves that plane tangent to the skin (measured: a 0.46 mm non-manifold edge with 4 incident faces, plus a sliver body). Subtracting a translated envelope from the full 900k-face shell was worse still. Cut locally, in its own generator, it is clean.

New: airframe/stls/fuselage/generate_wing_root_flange.py → 24.3 / 24.4 cm³, both watertight single bodies.

2 — Multi-turn tilt actuator (WA-R15)

DS3225 body + LibreServo_v4, rotation-limit pin removed, run continuous-rotation and closed on the AK7455 — the architecture the cargo winch already uses. Same body, so the Rev S1d pad footprint, bolt pattern and 60 g mass all carry over.

Three things were forced, not chosen:

  • Coaxial drive does not fit — the body overlaps the Ø30.1 socket boss by 13.5 mm in Y at either output-shaft orientation, and relieving the boss would cut into the socket bore. Hence a fuselage spur pair, module 0.8, 38T/38T, C = 30.40, 1:1; both axes run along hull X so no right-angle stage is needed.
  • C is set by the landing-gear bay tops (Z +82.39 + the 3.0 mm budget ⇒ C ≥ 29.80). 36T and 37T fall under budget; 38T clears at 3.60 mm.
  • The root tenon forces the gear plane axially. Its forward face is 4.90 mm from the shaft axis, so clearing it in Y needs a tip radius under 3.90 mm — no gear that can transmit at C = 30.40 qualifies. That costs an 18 mm actuator standoff and 18 mm/side of cargo-bay roof reach.

The stage is 1:1 deliberately: a step-up would trade the 48× torque surplus for slew rate but pull the actuator back to 260°, re-opening the 180-vs-270 question Rev T1 exists to close.

Control spec — docs/TILT_DRIVE_CONTROL_SPEC.md (new)

Cascade: LibreServo_v4 closes the actuator on its own absolute encoder; Pilot closes the nacelle on the AK7455. Sensors, sign conventions, spans, fail states, and the bench programme that would produce a plant model.

No gains, and the document says why — the plant is not identified and dead time is unmeasured. Two findings worth naming:

  • The train is not self-locking (two spur stages, total 3.571) and has no holding provision. Gravity is nulled by the pivot-at-CG, but the aero moment is unquantified, and an unquantified moment on a non-self-locking train is an unbounded rate. TILT-CTL-01 / WA-R16flight-release blocker.
  • Differential tilt needs a trip that is architecturally separate from both position loops. TILT-CTL-02.

3 — Weight audit — docs/MASS_AUDIT_CARGO_WING_ROOT.md (new)

All 23 PRINT-* rows whose description names an existing STL were measured. The BOM understates by +521.6 g.

Row BOM Measured Δ
PRINT-CARGO-SECT 165 g 372.2 g +207
PRINT-BATT-TRAY 22 g 140.2 g +118
PRINT-HEAD-SHELL 83 g 177.6 g +95
PRINT-CARGO-CRADLE 18 g 80.6 g +63
PRINT-MIDDLE-CANONICAL 135 g 190.9 g +56

The cargo-section row is not a Rev T1c regression — the pre-T1c shell already measured 316 g against that same 165 g row. Three rows corrected here; the rest measured and reported for their owning branches rather than edited across a governance boundary.

Foam and voids: cargo-section enclosed cavity 3.183 L, less the 2.135 L cargo bay (which the BOM itself says is not foamed) = 1.048 L foamable → 33.6 g, an upper bound before EPS void formers displace any of it. FOAM-PU-2LB carried 900 g — the A+B kit mass. Its own note says "~0.7 L mixed fill", which at 2 lb/ft³ is 22.4 g. Corrected; procurement quantity unchanged.

Correction to our own Rev T1c figure

Rev T1c is +102.8 g (+2.63 % AUW), not the +77.0 g first recorded. The root flange was costed as RHO_SOLID × 40 % infill. That is the wrong model: at 5 mm thick with 4 perimeters at 0.6 mm the plate is 4.8 mm of wall and 0.2 mm of infill — essentially solid. RHO_PRINT is a bulk figure and must not be re-derived that way.

4 — Weight-reduction plan — docs/plans/2026-08-30-001-... (new)

Eight ranked units. The largest lever is not structural: BATT-6S-4000 is 750 g — 19 % of AUW — and the 2800 mAh pack is 225 g lighter, more than every printed-part optimisation combined. Sized here; the call is the owner's.

# Target Recoverable
W1 Battery down-select −225 g
W2 BOM ⇄ mesh reconciliation — gates everything else 0 g
W3 Battery-tray floor pocket −23.1 g
W4 Actuator standoffs → hollow −32.9 g
W5 Cargo cradle → windowed ~−25 g
W8 Wing root none — CLOSED
  • The tray's 8.5 mm floor is not a strength figure — the SCAD says it is set by RAIL_D = 6.5 so the slot does not breach the cavity. At 3.0 mm it is FOS 55 at limit and FOS 25 at 9 g × 1.5 against 77 MPa flexural, deflecting 0.045 mm under a 750 g pack.
  • The actuator standoff's governing mode is mesh opening, not strength — 2.5 × 10⁻⁵ mm deflection against a 0.05 mm centre-distance budget.
  • The cradle is not over-thick — already 2.5 mm walls; it is a fully-closed 110 × 80 × 60 box for a 250 g payload. Medium confidence, because the auto-latch works by flex-tab compliance and that snap force is uncharacterised.
  • W6 could invert the ranking: PRINT-NACELLE-PORT/STBD name an STL that no longer exists; the two candidates measure 278 g and 658 g against a 132 g row.

Tool defects found while the geometry was being fixed

The gate had been red "by design" for one known cause, which meant its other checks were unexercised. Four real defects surfaced:

  • tenon_params() matched only "two_rod", so the Rev T1 default path fell through to the enlarged 30 mm tenon and reported an 8.60 mm/side mortise foul against a correctly-sized mortise.
  • The spar corridor is stepped (Ø20.4 outboard, Ø16.3 inboard) and was swept at one diameter, reading the intended annulus as "wall not cut".
  • Every route was probed 12 mm past the wall bracket — right for a rigid shaft, wrong for a wire that turns.
  • cargo_bay_envelope.py derived spar OD with the retired 0.15 mm/side rotating clearance and called a fixed bonded tube a "rotating tilt-spar".
  • merge_cargo_interior.py finalize_watertight() dropped sliver bodies before closing slits, so a fresh 2-face zero-area body reached the published STL.

Verification

tools/wing_root_deconflict.py               CLEAR
tools/wing_internal_clearance.py            PASS
tools/wing_airfoil_integrity.py             PASS
tools/wing_spar_carrythrough.py             PASS
tools/spar_bundle_fit.py                    PASS
tools/cargo_bay_envelope.py                 PASS
tools/landing_gear_wing_clearance.py --proud PASS
tools/validate_stls.py                      PASS
tools/precommit_index.py --check            PASS
generate_wing_root_flange.py                PASS

Cargo shell regenerated: watertight, 1 body, 0 boundary and 0 non-manifold edges, CI-valid.

Known blockers carried out of this PR

ID Item
WA-R16 / TILT-CTL-01 Tilt train is not self-locking; no holding provision. Flight release.
WA-R18 Rev T1c is +102.8 g; hover T/W was ~1.19 against a 1.2 minimum. Flight release.
MA-1 BOM understates printed mass by +521.6 g. Blocks any weight statement.
WA-R17 WA-R3 split-collar clamp is still not a part. Blocks wing removal/refit.
WA-R15a Cargo-bay roof band needs re-measuring after the 18 mm standoff.
TILT-CTL-02..06 Plant model, slew rate, differential-tilt trip, LibreServo_v4 encoder part.

Nacelle side (WA-R7…R12) is unchanged and still specification-only.


Analysis and implementation by Claude (Claude Opus 5, Anthropic) under the author's direction, per AGENTS.md §3 "Attribution and Licensing".

🤖 Generated with Claude Code

Stab-Rabbit-coding and others added 13 commits August 29, 2026 15:25
U1 of docs/plans/2026-08-29-003-feat-unified-20mm-spar-trunnion-belt-drive-plan.md.

tools/spar_bundle_fit.py (new) — sizes a hollow spar bore against the
conductor bundle it must swallow, using the EXACT tabulated optimal
circle-packing ratios K(n) for n <= 7 (Melissen 1997) and refusing to
interpolate outside that table.  Reproduces the plan's finding: 4 x D5.5
circumscribe D13.28, so SPAR_BORE_D = 11.0 (proposed independently by both
docs/plans/2026-08-27-nacelle-wiring-plan.md and the external source
conversation) does not fit at all, and of the 16 mm tubes only 16x14 fits —
with 0.36 mm radial, no room to twist.  20x16.3 PASSes at 1.51 mm radial.

The 5.5 mm wire OD is an ASSUMPTION — bom_revS.csv records no OD for
WIRE-10AWG — and the tool prints that caveat on every run rather than
letting the figure harden by repetition (plan 003 DEP-2 / OQ4).

tools/wing_spar_station_fit.py — solve_tip_scale() generalised to
solve_scale() and now run for the ROOT as well.  Through Rev S1b the root
was never at risk (15.60 mm of section against a D8.3 bore), so a tip-only
solver was sufficient; a D20.4 bore breaks the root out by 2.40 mm, and the
old tool would have reported the tip figure and said nothing about it.
Also adds --t-root/--t-tip overrides, reports solved scales as actual t/c
(a bare multiplier hides that the tip stops being an S1223 — plan RISK-1),
and reports the UNSCALED camber midline, which is what spar_bore() centres
on and what the fuselage side must derive SPAR_Z from.  solve_tip_scale()
is kept as an alias — the Rev S1b/U6 notes cite it by name.

Verified: --bore 20.4 --station 28 gives root 1.456 / tip 2.190 (KTD2's
frozen figures) and midline +8.84 (SPAR_Z = 58.01 + 8.84 = 66.85);
regression --bore 8.3 --station 45.15 still reproduces the as-built 1.550.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Plan 003 U2/U3/U5 + plan 004 U3, wing side only.  The spar stops being a
rotating drive shaft riding bearings and becomes a BONDED STRUCTURAL MEMBER
OF THE WING, which is what re-routes everything else here.

Airfoil (KTD2, tool-solved, not hand-tuned):
  SPAR_BORE_STATION  45.15 -> 28.00 mm
  SPAR_BORE_OD         8.3 -> 20.4 mm
  THICKNESS_SCALE     1.00 -> 1.46   root t/c 12.14 -> 17.72 %
  THICKNESS_SCALE_TIP 1.56 -> 2.20   tip  t/c 18.93 -> 26.70 %
THE ROOT OML MOVES FOR THE FIRST TIME in this design's history — at 1.00 a
D20.4 bore breaks out of the root skin by 2.40 mm.  tools/wing_spar_station_fit.py
solved the tip only until this revision and would have said nothing about it.

Root load path — the substantive change.  A bearing transmits shear, not
moment, so the Rev R2 rotating spar was structurally incapable of reacting the
root moment; the enlarged tenon (FOS 0.49) and then the two-rod couple (FOS
4.14) both existed to work around that.  A fixed bonded spar carries moment
directly: nacelle -> trunnion -> spar -> fuselage socket, with the couple arm
going from 48 mm (chordwise rod spacing) to the full 86.7 mm span.
  spar bending, cantilever bound  33.28 MPa, FOS 9.0 vs the 300 MPa stand-in
  TENON_LOAD_PATH default -> "spar_carrythrough"; tenon locates only
  tie rods RETIRED — the fwd rod (9.9..18.1) now intersects the spar bore
  (17.80..38.20) outright, and the aft rod's only remaining job would be wing
  torsion, which is 0.41 N.m ultimate -> bond shear 0.016 MPa, FOS 306
  PUBLISHED TO THE FUSELAGE: >= 55 mm socket reach for FOS 4.0 at the repo's
  standing 5 MPa figure (17 mm if the LG-11 coupon lands REF-MAT-001's 47 MPa)

Bore inventory, all constant-mm so taper cannot erode the webs:
   8.0 D3.2  nav 3-core (new; the light rotates, the spar does not)
  28.0 D20.4 bonded CF spar — now carries the 4x 10 AWG feeds on the tilt axis
  44.5 D6.5  AK7455 SPI quad + power pair (was D3.5 @ 54.0, sized for 4-wire I2C)
  54.0 D4.4  tilt drive shaft (new)
The 2x D7 EDF double-D is RETIRED: it could not carry two 10 AWG conductors at
any realistic wire OD, and its 27.5 mm station now falls inside the spar bore.

Two errors found and corrected rather than propagated:
 * wing_tip_spar_through_bore() carried rotate([0,90,0]), cutting a CHORDWISE
   hole. Harmless at D8.3 (the module's real job was simply never done); at
   D20.4 it would gash the tip. Its sibling had the right convention all along.
 * plan 004 KTD4's shaft station 43 implies a 15 mm gear centre distance. The
   tilt ring gear is concentric with the spar, so at C=15 the algebra returns a
   ring PD of 10.5 mm — smaller than the spar it encircles. Real minimum C is
   23.1; 26.0 is used, putting the shaft at station 54.

Also closes the long-open WBS 1.1.3.6 item: the encoder pocket was still
7x7 mm, dimensioned around the MT6701 3x3 QFN rejected on 2026-07-19, with a
D3.5 conduit labelled 4-wire I2C.  Now AK7455 QFN24 4x4 on a 10x8 board, ring
magnet grown ID 27/OD 41 (ID 10 could not pass over a D20 spar), HALL_SENS_R
11 -> 17 so the IC still reads mid-annulus.

Wingtip: bearing seat retired (a bearing here would let the spar spin under
the pinion's reaction).  Plan 003's wingtip pinch collar and garage are moved
with cause, both recorded in-file: a D30 collar cannot exist in a 22.83 mm
section and has nothing to do against a 5,492 mm^2 bond, and the tip has no
volume for 10 AWG disconnects (section falls 17.50 -> 3.43 mm aft of the spar).

Mass: printed wing shell 101.9 -> 110.0 g/side; spar 96.2 -> 58.2 g/pair.

Gates: validate_stls 61/61, wing_internal_clearance PASS, wing_airfoil_integrity
PASS (now validating the sections at their ACTUAL scales, closing RISK-2),
cargo_bay_envelope PASS, landing_gear_wing_clearance --proud CLEAR.
wing_root_deconflict FAILS with 3 findings, all fuselage-side staleness against
the new station — the fuselage is deliberately untouched this pass and the
deltas are published to its plan.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…m figures

Adds docs/WING_ATTACH_INTERFACE.md as the single specification for both wing
joints, because the Rev T1 load path now crosses two joints owned by three
different WBS files and the numbers were about to be stated three times.  The
wing side is BUILT; the fuselage and nacelle sides build to this.

Root -> fuselage.  A bonded spar socket carries the whole joint; the tenon
locates and there are no tie rods.  Hull Y +21.00 / Z +66.85 / D20.4, both
stations DERIVED (LE root bakes to Y -7.0 + station 28.0; chord line Z +58.01 +
the UNSCALED camber midline 8.84 -- applying THICKNESS_SCALE to the midline
would lift the socket 4.07 mm above the spar it receives).  Socket reach >= 55 mm
for FOS 4.02: bearing stress goes as 1/L^2, so length is the only real lever.

Tip -> nacelle.  Spar stub 32 mm proud, bearings on the nacelle trunnion, ring
gear PD 33.8 at C 26.0, ring magnet ID 27 / OD 41.

Four upstream figures corrected, each with its derivation rather than a swap:

 * plan 004 KTD4's shaft station 43 implies a 15 mm gear centre distance.  The
   ring gear is concentric with the spar, so the algebra returns a ring PD of
   10.5 mm -- smaller than the spar it encircles.  Built at C 26.0 / station 54.
   This escalates OQ1 (servo range) to BLOCKING: 180 deg needs station 58.5,
   which collides with the root tenon at 58.5 mm.
 * TILT_ENCODER_WIRING_EMI_SPEC.md 6.1's premise ("the tilt spar is 4130 steel,
   ferromagnetic") is now false -- the spar is CF.  Corrected in place; the
   mitigations are retained with a changed target (the drive shaft and pinion
   ARE steel and ARE nearby), so the zero-calibration stays mandatory.
 * wings-nacelles WBS 1.1.4 still read "PIVOT_Z STAYS 111.5" and quoted the
   withdrawn station-22 pick, both contradicting the FROZEN block six lines
   above them.  Reconciled to 116.1 / 28.0, and OQ5 closed as RESOLVED (the
   trunnion is concentric with the spar; no tip-rib bracket is needed).
 * plan 005 OQ5 asked whether the station move should be re-sequenced; it is
   done, so the question is void -- but its +9.8 mm clearance margin is
   owner-accepted and that plan is the last thing that can silently spend it.

TILT_SPAR_ANALYSIS.md 3.6 re-derives the section for a FIXED spar and marks
3.2/3.5's torsion, keyability and bearing-journal discriminators VOID -- all
three were consequences of the spar rotating, not of its loads.  CF was rejected
there on the functional gate, explicitly not on strength; with no keyway and no
journal the gate is gone, and the larger spar is 38.0 g/pair LIGHTER than the
small steel one at 10.3x the section modulus.

REFERENCES.md REF-MATH-001 (Melissen 1997) catalogues the circle-packing ratios,
because the n=4 case decided a load-bearing geometry change and the wrong
constant (11.0 mm) had already propagated through two independent documents by
being carried in prose instead of computed.

TODO 0.8/0.8.1 carries the open gates: CF spar certificate, measured wire OD,
servo range, the LG-11 coupon, aero revalidation, WA-R1..R13, and the owner
decision on the 36 mm cargo-bay intrusion.

Gates: 8 of 9 green; wing_root_deconflict RED by design until WA-R1/R6 land.
flake8 clean.  precommit_index --check clean.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…itability

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…airfoil

Three owner directives, each of which invalidated something I had built.

1. THE SPAR MUST NOT PENETRATE THE THRUST DUCT.  The stub was 32.0 mm, budgeted
   outward from the bearing stack and never checked against the duct.  The duct
   is a cylinder r=25 about the nacelle's local Z; the spar runs along local X at
   Y=0, so every point of it sits |X| from the duct axis and it clears only if it
   TERMINATES at |X| >= 26.  With the tip face at |X| = 41.7 the maximum stub is
   15.7 mm.  The 32 mm stub reached |X| = 9.7 -- fifteen millimetres inside the
   duct wall, through the thrust column between the EDFs.  Same class of error as
   the Rev R2 through-duct spar this revision exists to remove.  Now 15.0 mm, and
   the nacelle's bearing pair must fit inside it (2x 6804 = 14.0 mm does).

2. THE CENTRE OF THE CARGO BAY MUST STAY CLEAR.  That kills the 55 mm socket:
   the bay's clear span starts at hull X -100 and the wall skin is at -81.33, so
   only 18.67 mm of socket depth exists.  At that depth the socket gives FOS 0.51
   on the moment, and since stress goes as 1/L^2 no socket can recover it.
   THE JOINT SPLITS: the socket keeps the SHEAR (0.31 MPa, FOS 16 -- shear never
   needed depth), and the moment moves to a bonded ROOT FLANGE on the inner
   sidewall, 80 x 60 mm, FOS 29.2.  A flange trades an unfavourable 1/L^2 depth
   term for a linear area term, so this is better than the socket it replaces,
   not a compromise -- and it protrudes only its own ~5 mm to X ~ -86 against a
   bay edge at -100.  It also demotes the LG-11 coupon from a gate to a
   packaging convenience here.

3. THE SERVO DRIVES THE SHAFT MORE THAN ONE REVOLUTION.  This inverts the tip
   stage from a step-UP to a REDUCTION and dissolves the impossibility I flagged
   last pass: as a reduction the ring is the LARGER member, so it clears the spar
   easily.  Module 0.8, 14T pinion / 50T ring, i = 3.571, shaft turns 1.389 rev
   per 140 deg of nacelle, C = 25.6 -> shaft station 54.0 -> 53.6.  36T turns
   exactly one revolution (not "more than"); 54T pushes the bore to 55.2 and
   leaves 1.1 mm to the root tenon, under the 1.16 mm floor.
   CONSEQUENCE: the actuator is no longer a limited-rotation servo but a
   continuous-rotation gearmotor or stepper closed on the AK7455's absolute
   angle.  That retires the 180-vs-270 question, which was BLOCKING an hour ago.
   Encoder follows: HALL_SENS_R 17.0 -> 16.8, ring ID 26 / OD 41.2, board 9 x 8.

AIRFOIL RE-DERIVED FROM THE TABULATED UIUC COORDINATES (REF-CAD-006), not
quoted.  The header claimed max thickness "at 22.6% chord" and max camber "at
39.4% chord"; both LOCATIONS were wrong and neither was traceable to the table
this file actually builds from.  Sampling at 1/20000 chord returns 19.8% and
49.0% -- exactly the published S1223 characterisation.

The built sections are now named for what they are: S1223/t17.7 (root) and
S1223/t26.7 (tip) -- S1223's camber line with the thickness envelope scaled
x1.46 and x2.20.  Camber is identical in all three (8.67% at 49.0%) because
s1223_section() scales thickness about an unscaled camber line.  LE radius goes
as t_scale^2, verified numerically: 0.02502c -> 0.05333c -> 0.12110c, so the
tip's nose is 12% of its own chord.

What survives, what does not, stated per-claim in the header: the camber figures
are exact; zero-lift angle and lift-curve slope partially survive at the root on
thin-airfoil grounds (they depend on the camber line alone) and not at all at
the tip, which is far outside that theory's range; every performance number
(CL 1.55, CL_max 2.0, L/D 30-35, the 7.6 N cruise lift) does NOT survive and is
marked history-only at each use.  Re is unchanged at 1.3e5-1.8e5 -- all
low-Reynolds, where polars do not transfer between Re let alone between sections.

Also fixes a stale comment: HALL_CABLE_STATION read 44.5 while its own comment
still said 44.0 and quoted the 44.0 webs, from an edit that silently missed.

Gates: 7 of 8 green; wing_root_deconflict RED by design until the fuselage moves.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sweeps the three owner directives through every place the repo describes this
wing, and corrects two citation defects found on the way.

AIRFOIL, DESCRIBED ACCURATELY THROUGHOUT.  The built sections are named for what
they are -- S1223/t17.7 (root) and S1223/t26.7 (tip): S1223's CAMBER LINE with
the thickness envelope scaled x1.46 / x2.20.  Updated in wings_s1223_revo.scad
(new "SECTION DESIGNATION AND DATA" block), docs/flight_envelope.md,
docs/WING_ATTACH_INTERFACE.md S4A, wings-nacelles/WBS.md, bom_revS.csv/.json,
and TODO S0.8.  Every figure is re-derived from the tabulated UIUC coordinates
(REF-CAD-006) at 1/20000 chord, not quoted.

Per-claim, rather than a blanket disclaimer:
  camber 8.67% at 49.0% chord   EXACT for the built sections (camber is unscaled)
  zero-lift angle, dCl/dalpha   PARTIALLY survives at the ROOT only -- thin-airfoil
                                theory makes both depend on the camber line alone,
                                which is why preserving it matters; but 17.7% is
                                already outside "thin" and 26.7% emphatically is
  CL 1.55 / CL_max 2.0 / L/D    DOES NOT survive; marked history-only at each use
  7.6 N cruise lift, "22% AUW"  DOES NOT survive (derived from the above)
  printed surface finish        NEVER characterised -- FDM layer lines are a
                                de-facto trip strip at these Re
Re is unchanged at 1.3-1.8e5, all below 5e5, where polars do not transfer between
Reynolds numbers let alone between sections.  flight_envelope.md carries a banner
saying plainly that every aerodynamic result in it now rests on an input that no
longer describes the aircraft.

CITATION DEFECT 1 -- structural_analysis.md cited "14 CFR Part 23.303" twice.
That section belonged to the PRE-2017 Part 23 and does not exist in the current
rule; the Amdt. 23-64 restructure moved limit/ultimate to S23.2230.  Same class
of defect REFERENCES.md already recorded for S23.1401.  Corrected, and Part 23
added as REF-FAA-004 with S23.2230 and S23.2265 quoted verbatim from GovInfo's
CFR XML (eCFR's HTML endpoint bot-blocks automated retrieval; GovInfo is the
same authority).

CITATION DEFECT 2, in the other direction -- the FOS 4.0 joint target was
described as "a design-team judgment value" with no basis.  It has one:
S23.2265 requires a SPECIAL factor beyond the basic 1.5 for parts "subject to
appreciable variability because of uncertainties in manufacturing processes or
inspection methods", which is exactly FDM-printed CF-PETG.  The requirement is
now cited; the numeric value stays the project's own choice.  Also recorded, to
prevent a future fabrication: +3.8/-1.52 appear NOWHERE in current Part 23 and
must not be cited to it.

Geometry figures swept to the Rev T1b values: stub 32 -> 15.0 mm (duct-bounded),
shaft station 54.0 -> 53.6, ring/pinion 50T/14T module 0.8 at C 25.6,
HALL_SENS_R 17.0 -> 16.8, ring magnet ID 26 / OD 41.2, root socket 55 mm ->
18.5 mm socket + 80x60 bonded flange.  BOM: PRINT-WINGS-S1223 mass 118 -> 124
g/side and re-noted; BRG-MF128ZZ to QTY 0 (no wingtip bearing exists any more --
one there would let the spar spin under the pinion's gear reaction).

Closed: the cargo-bay intrusion owner decision (the bay stays clear and the joint
got better, 4.02 -> 29.2), the 180-vs-270 servo question (void under a multi-turn
drive), and WA-R5.  Opened: actuator re-select, and trunnion packaging -- the
bearing pair, ring gear and ring magnet must now all fit inside 15 mm.

Aerodynamic content produced with the aeronautical-engineering skill; it carries
a standing ENGINEERING REVIEW REQUIRED notice -- these are computed geometric
properties and a statement of what is NOT known, not a performance substantiation.

Gates: 7 of 8 green, flake8 clean, index clean; wing_root_deconflict RED by
design until the fuselage side moves.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
… last pass

ID 27 / OD 41 -> ID 26 / OD 41.2 and HALL_SENS_R 17 -> 16.8 in the EMI spec, the
attach interface, plan 004, plan 005 and the wings-nacelles WBS.  The encoder
geometry moved with the drive-shaft station in e887b66 and these five citations
of it did not follow -- exactly the stale-figure class this revision has been
correcting elsewhere, so leaving them would have been self-defeating.

Also corrects a derived figure that was wrong in both revisions: an IC left at
R = 11 sits 2.0 mm inboard of the ring's inner edge (r 13.0), not 2.5 mm.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…t drive

The wing side of Rev T1 has been built since 2026-08-29; the fuselage side
still carried WING_SPAR_Y = +38.15 and WING_SPAR_BORE_D = 8.3, so
tools/wing_root_deconflict.py failed on three findings that were all that one
fact.  This lands the fuselage half and the actuator that goes with it.

Fuselage joint (WA-R1/R1b/R2/R4/R6, airframe/blender-scripts/merge_cargo_interior.py)
- Spar socket moved to chord station 28.0 -> hull Y +21.00, Z +66.85 (unscaled
  camber midline), bore 8.3 -> 20.4, boss 27.7 -> 30.1.  Shear only, FOS 16.
- F688ZZ root bearing DELETED.  Not a tidy-up: a bearing here would let the
  fixed spar spin under the tilt pinion's gear reaction.
- Both wing-root tie rods retired -- the wing already gates them off, and the
  forward one now intersects the O20.4 spar bore.
- Mortise 30.8 -> 12.8 for the 12 mm locating tenon (fit +0.40 mm/side).
- Conduits re-cut: nav O4.2 @ Y +1.0, AK7455 O7.5 @ Y +37.5, drive shaft O4.4
  @ Y +46.6.  The two O7 EDF ports are gone; the four 10 AWG feeds now enter
  through the spar's own bore.

The root flange is a bonded PART, not printed hull, and measurement decided it:
ray-casting the envelope on a 13x17 grid (221/221 hits) shows the sidewall skin
moving 34.3 mm (port) / 37.0 mm (stbd) across the 80x60 footprint.  Filling to a
plane makes it 34 mm thick; bounding it with a plane leaves that plane tangent
to the skin (measured: a 0.46 mm non-manifold edge, 4 incident faces, plus a
sliver body).  Cut locally instead, in its own generator.

Tilt actuator (WA-R15) -- multi-turn, per owner direction
- DS3225 body + LibreServo_v4, rotation-limit pin removed, run continuous
  rotation and closed on the AK7455.  Same body, so the Rev S1d pad footprint,
  bolt pattern and 60 g mass carry over; the mode, position and stage are new.
- Coaxial direct drive does NOT fit: the body overlaps the O30.1 socket boss by
  13.5 mm in Y at either output-shaft orientation.  Fuselage spur pair instead,
  m 0.8, 38T/38T, C 30.40, 1:1 -- both axes are along hull X so no right-angle
  stage is needed.  C is set by the landing-gear bay tops, not chosen.
- 1:1 deliberately: a step-up would trade the 48x torque surplus for slew rate
  but pull the actuator back to 260 deg, re-opening the question Rev T1 closed.
- The gear plane is forced 11 mm inboard of X -100/-240 by the root tenon --
  no gear that can transmit at C = 30.40 clears it in Y -- which costs the
  actuator an 18 mm standoff and 18 mm/side of cargo-bay roof reach.

Control (docs/TILT_DRIVE_CONTROL_SPEC.md, new)
Cascade: LibreServo_v4 closes the actuator on its own absolute encoder; Pilot
closes the nacelle on the AK7455.  Sensors, sign conventions, spans, fail
states, and the bench programme that would produce a plant model.  No gains:
the plant is not identified, and dead time is unmeasured.  Two findings worth
naming -- the train is NOT self-locking and has no holding provision
(TILT-CTL-01), and differential tilt needs a trip that is architecturally
separate from both position loops (TILT-CTL-02).

Tool defects found while the geometry was being fixed (they were masked by it)
- wing_root_deconflict.py tenon_params() matched only "two_rod", so the Rev T1
  default path fell through to the enlarged 30 mm tenon and reported an
  8.60 mm/side mortise foul against a correctly-sized mortise.
- The spar corridor is stepped (O20.4 outboard, O16.3 inboard) and was swept at
  one diameter, reading the intended annulus as "wall not cut".
- Every route was probed 12 mm past the wall bracket, correct for a shaft and
  wrong for a wire.
- cargo_bay_envelope.py derived spar OD with the retired 0.15 mm/side rotating
  clearance and called it a "rotating tilt-spar".
- merge_cargo_interior.py finalize_watertight() dropped sliver bodies before
  closing slits, so a fresh 2-face zero-area body reached the published STL.

Mass: +77.0 g (+0.170 lbm), +1.97 % of AUW.  Hover T/W was ~1.19 against a 1.2
minimum, so this is tracked as a blocker (WA-R18), not absorbed.

Gates: wing_root_deconflict, wing_internal_clearance, wing_airfoil_integrity,
wing_spar_carrythrough, spar_bundle_fit, cargo_bay_envelope,
landing_gear_wing_clearance --proud, validate_stls, precommit_index --check --
all green.  Cargo shell regenerated: watertight, 1 body, 0 boundary and 0
non-manifold edges, CI_valid.

Analysis and implementation by Claude (Claude Opus 5, Anthropic) under the
author's direction, per AGENTS.md §3 "Attribution and Licensing".

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…d auditability

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ass errors

The audit was asked for as a lightening exercise.  The lightening is real but
small; the bookkeeping error is large, so it leads.

BOM vs mesh -- 23 PRINT-* rows measured against the STL they name
The BOM understates printed mass by +521.6 g, 13.3 % of the 3,911 g AUW.
Worst rows: PRINT-CARGO-SECT +207.2, PRINT-BATT-TRAY +118.2, PRINT-HEAD-SHELL
+94.6, PRINT-CARGO-CRADLE +62.6, PRINT-MIDDLE-CANONICAL +55.9.  Three are
corrected here; the rest are measured and reported for their owning branches
rather than edited across a governance boundary.

Corrected
- PRINT-CARGO-SECT 165 -> 372 g.  NOT a Rev T1c regression: the pre-Rev-T1c
  shell already measured 316 g against the same row.  It predates the Rev R6
  landing-gear bay features, the actuator pads, the O30.1 sockets and the CF
  thwart pockets.
- FOAM-PU-2LB 900 -> 22 g.  900 g was the KIT mass, not installed foam.  The
  row's own note says ~0.7 L mixed fill, which at 2 lb/ft^3 is 22.4 g.
  Independently bounded: the cargo section's enclosed cavity is 3.183 L, less
  the 2.135 L cargo bay (explicitly not foamed) = 1.048 L foamable = 33.6 g
  before the EPS void formers displace any of it.
- PRINT-WING-ROOT-FLANGE 12.7 -> 25.6 g/ea.  Our own error at Rev T1c: costed
  as RHO_SOLID x 40 % infill.  At 5 mm thick with 4 perimeters at 0.6 mm the
  plate is 4.8 mm of wall and 0.2 mm of infill -- essentially solid.  RHO_PRINT
  is a BULK figure and must not be re-derived as RHO_SOLID x infill.

That last correction revises Rev T1c from +77.0 g to +102.8 g (+2.63 % AUW).

Where the cargo-section mass is
Base shell 389.0 g before features; 372.2 g as built (the duct, aperture and
mating-face cuts take out more than the bosses add).  The two actuator pads are
109.5 g -- 29 % of the shell and the heaviest discretionary feature on it.

Lightening
- Actuator standoffs: 109.5 g of solid block reacting a 5.0 N worst-case
  combined load (3.47 N gear separation + 3.53 N actuator inertia at 4g x 1.5).
  The governing mode is mesh opening, not strength: cantilever deflection is
  1.4e-5 mm solid, 2.5e-5 mm hollow, 9.5e-5 mm on four posts, against a 0.05 mm
  centre-distance budget.  Hollowing to a 2.5 mm wall saves 32.9 g with no
  structural question.  Rejected: shrinking NSVMT_STANDOFF (11 + 6 + 1, all
  accounted) and thinning the 6 mm gear face (already 7.5 x module).
- Wing roots: nothing to take.  The spanwise distribution is a clean taper with
  no local pile-up, WALL_T 2.5 is four perimeters at 0.6 (the floor), and
  THICKNESS_SCALE 1.46 is the solved figure leaving 1.19 mm of skin over the
  O20.4 bore against a 1.16 mm floor.  The 33.7 g the retired tie rods gave back
  is the whole of what this structure had.

Also noted: summing the BOM mass column returns 12.7 kg, which is the mass of
nothing -- it mixes installed hardware, consumable stock and ground equipment.
An Installed flag is needed before it can back a weight statement.

Analysis by Claude (Claude Opus 5, Anthropic) under the author's direction,
per AGENTS.md SS3 "Attribution and Licensing".

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
… carried mass

Follows docs/MASS_AUDIT_CARGO_WING_ROOT.md.  Eight units, ranked by measured
mass, each with the check that gates it.

The ranking has an uncomfortable shape and the plan says so up front: the single
largest lever is not structural.  BATT-6S-4000 is 750 g -- 19 % of AUW and the
heaviest item on the aircraft -- and BATT-6S-2800 is 225 g lighter, more than
every printed-part optimisation in the plan combined.  That is a mission trade,
not an engineering one, so the plan sizes it and leaves the call to the owner.

W2 (BOM reconciliation) gates everything else, because the BOM understates
printed mass by +521.6 g and shaving 30 g off a part whose row is 118 g wrong is
decoration, not weight reduction.

Targets, measured:
- W3 battery-tray floor pocket, -23.1 g.  FLOOR = 8.5 mm is NOT a strength
  figure -- the SCAD says it is set by RAIL_D = 6.5 so the slot does not breach
  the cavity.  That constraint exists only at the rails.  At 3.0 mm the floor is
  FOS 55 at limit and FOS 25 at 9 g x 1.5 against 77 MPa flexural (REF-MAT-002),
  deflecting 0.045 mm on a 56 mm span under a 750 g pack.
- W4 hollow the actuator standoffs, -32.9 g.  Governing mode is gear-mesh
  deflection, not strength: 2.5e-5 mm against a 0.05 mm centre-distance budget.
- W5 cargo cradle windowed frame, ~-25 g.  The cradle is NOT over-thick -- it is
  already 2.5 mm walls; it is a fully-closed 110 x 80 x 60 box for a 250 g
  payload.  Medium confidence, because the auto-latch works by flex-tab
  compliance and that snap force is uncharacterised, so the tabs and the rim
  within 10 mm of them are exclusion zones.
- W6 nacelle pod STL identity.  PRINT-NACELLE-PORT/STBD name an STL that no
  longer exists (the s_ prefix was dropped); the two candidates measure 278 g
  and 658 g against a 132 g row.  Listed as a target because the answer could
  make it the largest one and invert the ranking (RISK-3).
- W7 landing-gear bay bosses, 126 g raw, unquantified -- assume nothing is free
  until the bolt bearing check is redone.
- W8 wing root CLOSED, recorded so it is not re-litigated: clean taper with no
  local pile-up, WALL_T 2.5 is the 4-perimeter floor, and THICKNESS_SCALE 1.46
  is the solved value leaving 1.19 mm of skin over the bore against 1.16.

Also states three rules the audit learned the hard way: RHO_PRINT is a bulk
figure and must not be re-derived as RHO_SOLID x infill; consumable stock is not
installed mass; and bounding-box fill fraction is a signal, not an answer -- the
wing and the tray look alike in that column and are entirely different findings.

Analysis by Claude (Claude Opus 5, Anthropic) under the author's direction,
per AGENTS.md SS3 "Attribution and Licensing".

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
mode 5 MPa was written to bound -- so this socket is very likely far more
conservative than it looks. It is NOT re-based here: overturning a
standing repo allowable is an owner decision gated on the LG-11 coupon
(root TODO SS1.1.4), not a side effect of a geometry change. The sweep
@Stab-Rabbit-coding Stab-Rabbit-coding changed the title feat(fuselage): Rev T1c wing-root joint, multi-turn tilt drive, and a weight audit that found the BOM wrong by 522 g feat(airframe): Rev T1 — the tilt spar becomes a structural member of the wing (both halves) Aug 31, 2026
The local .venv is 351 MB of third-party packages and has never been tracked, so
this is a guard rather than a cleanup — but the guard matters more than it looks.

.github/workflows/ci.yml runs flake8 with an explicit --exclude list that does
NOT name .venv.  Lint passes today only because CI checks out a fresh tree with
no virtualenv in it; a single `git add -A` from a working copy would commit one
and the lint job would fail immediately on thousands of findings in vendored
code.  Cheaper to ignore the directory than to grow the exclude list.

Also records, where someone will actually see it, that this .venv SHADOWS
system Python packages several tools depend on (manifold3d, sympy, matplotlib
are installed system-wide) -- hence the /usr/bin/python3 invocation used
throughout the tooling docs.

venv/, env/ and ENV/ are covered too.  Verified no tracked path at any depth
matches them (0 files), and the tracked-but-ignored count is unchanged at 9 --
all of those come from the pre-existing *.pre-g351x and named-file rules, none
from this change.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@Stab-Rabbit-coding
Stab-Rabbit-coding merged commit 5dd3fe5 into main Aug 31, 2026
16 checks passed
@Stab-Rabbit-coding
Stab-Rabbit-coding deleted the claude/serenity-wing-nacelle-validation-kvux9w branch August 31, 2026 00:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants