Skip to content

Mechanical design: rigorous proof-out + vendor tender package - #107

Merged
THOClabs merged 5 commits into
mainfrom
design/mechanical-tender
Aug 6, 2026
Merged

Mechanical design: rigorous proof-out + vendor tender package#107
THOClabs merged 5 commits into
mainfrom
design/mechanical-tender

Conversation

@THOClabs

@THOClabs THOClabs commented Aug 6, 2026

Copy link
Copy Markdown
Owner

Summary

Turns the proven mechanical design (PR #105) into an official, modular vendor tender package under design/mechanical/tender/ — documents a machine shop, turning shop, steel fabricator, and concrete contractor can bid on and build, in parts or whole. Every number is generated from the validated calc/params.py (single source of truth); a consistency test suite guards it. 127/127 tests pass.

Based on design/mechanical-proveout so the diff is tender-only; retarget to main after #105 merges.

Type of Change

  • New feature (non-breaking, additive under design/mechanical/tender/)
  • Documentation update

What's in it

Generators (source → vendor docs), all driven by calc/params.py:

  • gen/partspec.py — parts registry: 30 line items across BP-01…05, dims traced to params, the 5 proof-out remediations baked in, stock masses computed.
  • gen/bom.pymaster_bom.csv, cut_list.csv (dual mm/in), cots_schedule.csv.
  • gen/drawing.py15 dimensioned control drawings (SVG, ASME Y14.1 title block, dual units, material/finish/tolerance blocks).
  • gen/xlsx_export.pyExcel BOM workbook · gen/htmlset.py → print-to-PDF drawing set · gen/docx_export.py → whole tender as one Word RFQ.

Bid packages — one per trade (biddable in parts or whole):

Pkg Scope Trade Items
BP-00 Master dossier: ITB, SOW, standards register, drawing register, ITP, bid form, T&Cs, turret-variant appendix
BP-01 Mount head machining CNC 6061-T6 3
BP-02 Precision turned parts Turning, 303 SS 3
BP-03 Pier & foundation (PE-gate) RC + steel 4
BP-04 Roll-off roof "disappearing turret" (PE-gate) Steel fab + rail/drive 6
BP-05 COTS procurement schedule Purchase 14

Follows the real standards vendors expect — MIL-STD-31000A (TDP), ASME Y14.5 GD&T + Y14.1 title blocks, AWS A2.4/D1.1/D1.2 welding, MIL-A-8625F anodize, ACI 318 foundation, ISO 286 H7/js6 fits — and bakes in all five proof-out remediations (angular-contact 7008/7006 bearings, on-axis absolute encoder, 4× wind hold-down anchors, temp-comp focuser, 48 V pack).

Safety Checklist

  • Adds a procurement-documentation package only; does not touch runtime control, safety, or enclosure code.

Testing

  • pytest design/mechanical/tests/127 passed (incl. 6 tender consistency gates: dims trace to registry; BOM ↔ cut-list ↔ drawings agree; remediations present, deep-groove baseline absent; well-formed drawings; PE-gate flagged).
  • Adversarial QA workflow run; all real findings fixed (roof-steel over-count, non-length drawing callouts, a stale deflection figure).
  • XLSX / DOCX / HTML deliverables generated and validated.

Documentation

  • tender/README.md index + BP-00 master dossier; every doc headed "ISSUED FOR BID / FOR PE REVIEW — NOT FOR CONSTRUCTION."

Additional Notes

Issued for bid / PE review, not for construction: BP-03 pier and BP-04 roof are structural (ASCE 7 wind/snow/seismic) and require a licensed PE stamp before construction — stated prominently, not replaced. Values the design doesn't yet fix (weld/member sizing, rail/drive product, GD&T values, surface-finish Ra) are marked ASSUMED design-intent — bidder/PE to confirm, never presented as final. Left as draft for your review.

🤖 Generated with Claude Code


Generated by Claude Code


Note

Low Risk
Documentation and design-calculator additions only; no changes to observatory runtime, safety interlocks, or firmware. Main risk is engineering assumptions (wind, snow, DGX power) being treated as build truth without PE/vendor validation.

Overview
Adds a computed mechanical design under design/mechanical/: a single SI source of truth in calc/params.py, eleven proof modules (torque, stiffness, dynamics, encoder tracking, balance, bearings, wind, pier, thermal, enclosure roof drive/snow, night power) that each return a shared BudgetResult, and a regenerated MECHANICAL_DESIGN.md wired through calc/report.py with test_report.py so narrative numbers cannot drift from code.

The report documents resolved repo contradictions (MN76 vs MN78, encoder PPR, bearing type), fills assumed survival wind/snow/seismic loads, and states blunt outcomes—six proofs pass, five fail (bearing-limited pointing deflection, baseline encoder ~5″ RMS vs 1″ target, roof uplift without anchors, passive thermal focus, 12 V off-grid autonomy)—with remediations and a weighted trade-study / v1–v2 roadmap.

Phase D CAD adds OpenSCAD housings, pier adapter, counterweight shaft, and assembly.scad, plus svg_preview.py and committed preview_assembly.svg driven live from params.py (test_cad.py).

Reviewed by Cursor Bugbot for commit c26cb55. Bugbot is set up for automated code reviews on this repo. Configure here.

claude added 5 commits August 2, 2026 08:11
… torque proof

First slice of the mechanical-design proof-out. Establishes the single-source-of-
truth parameter set (params.py) with sourced/derived/assumed provenance tags, the
SI units layer, the common BudgetResult type, and the exemplar axis-torque budget.

The torque proof already lands the boldest result: MN78 counterweight-FREE needs
49.9 Nm at RA vs the CSF-32 127 Nm rating (SF 2.5) and 26.5 Nm at DEC vs 70 Nm
(SF 2.6) — deleting the ~9 kg of counterweights is quantitatively feasible, the
same principle the ZWO AM5 / RST-135 exploit. 5/5 tests green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SKZMQ755R7q38SKqJsCQsg
…nerated report

Completes the rigorous mechanical-design proof-out. Turns the repo's asserted-but-
uncomputed design into 11 first-principles budgets (torque, stiffness, dynamics,
encoder tracking, balance, bearings, wind, pier, thermal, enclosure, power), each a
calc module + pytest asserting its margin. A weighted-Pugh trade study runs the
selection permutations with a sensitivity pass, parametric OpenSCAD + an SVG preview
fill the empty CAD appendix, and report.py generates MECHANICAL_DESIGN.md from the
calculator (a diff-test forbids drift). 121/121 tests green.

Honest tally: 6 PASS / 5 FAIL — the FAILs are real findings the repo's prose hid:
- stiffness 43.5" vs 5": the deep-groove 6008/6006 bearings (not the walls) are 98%
  of the error -> angular-contact 7008/7006 pairs required.
- tracking: baseline dual-encoder chain 5.02" RMS vs 1" -> on-axis high-res absolute
  encoder REQUIRED (proposed ring reaches 0.54").
- survival wind: 9.2 kN roof uplift, SF 0.19 -> hold-down anchors mandatory (unspecced).
- thermal: 22 K diurnal swing walks focus ~10x depth-of-focus -> temp-comp focuser.
- off-grid power: 12 V pack 3.3 h vs 10 h night -> 48 V pack (13.4 h) or DGX duty-cycle.

Selected build banks two won bold picks (counterweight-FREE GEM, active-thermal roof)
plus the mandatory on-axis encoder; keeps baselines where they already pass. Every
input tagged sourced/derived/assumed; the three governing voids the repo omits
(survival wind, snow, seismic) are filled as labelled assumptions.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SKZMQ755R7q38SKqJsCQsg
Foundation of the vendor tender package that turns the proven mechanical design
into biddable fabrication documents. Additive under design/mechanical/tender/;
does not touch the proof-out modules.

- gen/partspec.py: parts registry (single source of truth) — 30 line items across
  BP-01..05, every fabricated dimension traced to calc/params.py; the 5 proof-out
  remediations baked in (angular-contact 7008/7006, on-axis absolute encoder, 4x
  wind hold-down anchors, temp-comp focuser, 48 V pack); counterweight flagged
  optional for the CW-free build; stock masses computed.
- gen/bom.py: master_bom.csv, cut_list.csv (dual mm/in), cots_schedule.csv.
- gen/drawing.py: 15 dimensioned SVG control drawings (Y14.1 title block, dual
  units, material/finish/tolerance blocks, "ISSUED FOR BID / FOR PE REVIEW").
- gen/xlsx_export.py: Excel BOM workbook (needs openpyxl; CSVs are source of truth).
- gen/htmlset.py: print-to-PDF drawing set bundling all 15 sheets.
- tests/test_tender.py: 6 consistency gates (full-spec, BOM coverage, cut/COTS
  split, remediations-present/baseline-absent, well-formed drawings, PE-gate flag).

Bid-package SOWs (BP-00..05) + adversarial QA land in a follow-up commit.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SKZMQ755R7q38SKqJsCQsg
Vendor-grade tender documents authored against the parts registry (one stream per
package). All dual-unit (mm [in]), standards cited by number, dimensions pulled
from partspec.py (no invented numbers), headed "ISSUED FOR BID / FOR PE REVIEW".

- BP-00 master dossier: instructions to bidders, general SOW, standards register,
  drawing register, inspection/test plan, pricing/bid form, T&Cs, index with
  bid-in-parts-or-whole guidance + roll-off/turret-variant appendix.
- BP-01 mount machining: CNC 6061-T6, H7 bearing seats (ISO 286) sized for the
  angular-contact 7008/7006 remediation, Type III anodize (MIL-A-8625F), GD&T
  (ASME Y14.5), CMM acceptance.
- BP-02 turned parts: 303 SS spindles/shaft, journals to fit 7008/7006, passivation.
- BP-03 pier & foundation: RC pier (ACI 318/301), rebar + anchor (F1554), galv top
  plate — with the PE-STAMP GATE stated prominently.

BP-04 roll-off roof, BP-05 COTS schedule, and vendor DOCX/XLSX land next.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SKZMQ755R7q38SKqJsCQsg
Completes the vendor tender package and applies the adversarial-QA fixes.

New bid packages:
- BP-04 roll-off roof "disappearing turret": welded steel (AWS D1.1, symbols per
  A2.4), box-track rail run = 2x roof length, gate-operator drive sized to the 235 N
  move force, MANDATORY 4x wind hold-down anchors + snow interlock; weld map +
  acceptance; PE-stamp gate stated.
- BP-05 COTS schedule: harmonic drives, angular-contact 7008/7006, on-axis absolute
  encoder, motors/drivers, temp-comp focuser, rail/drive/roofing, 48 V pack,
  consolidated fastener schedule; remediations vs optional (counterweights) marked.

QA fixes (all real findings from the adversarial review):
- partspec: corrected BP-04 roof-steel over-count — NW-RR-001/002/003 now carry
  per-piece length x piece qty (purlins 52.2 kg not 261; rails 89.7 kg not 179).
- drawing.py: only dual-format true linear dimensions; counts/angles/f'c/torque no
  longer rendered as "mm [in]" (fixed 7 of 15 sheets).
- docs: 43.3" -> 43.5" to match the 8 mm-wall selected configuration everywhere.

Vendor deliverables (generated from calc/params.py):
- bom/NIGHTWATCH_tender_BOM.xlsx (Excel BOM/cut-list/COTS)
- drawings/DRAWING_SET.html (print-to-PDF set of all 15 control drawings)
- docs/NIGHTWATCH_tender_RFQ.docx (whole tender as one Word RFQ)
- tender/README.md index. Full suite: 127 passed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SKZMQ755R7q38SKqJsCQsg
@THOClabs THOClabs changed the title Vendor tender package — mount + roll-off "turret" (fabrication RFQ) Mechanical design: rigorous proof-out + vendor tender package Aug 6, 2026
@THOClabs
THOClabs changed the base branch from design/mechanical-proveout to main August 6, 2026 15:58
@THOClabs
THOClabs marked this pull request as ready for review August 6, 2026 15:58
@THOClabs
THOClabs merged commit 88440c3 into main Aug 6, 2026
1 check passed

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 3 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit c26cb55. Configure here.

res.add("-- tilt (35 mph gust) --", 0.0, "", "")
res.add("OTA drag @ 35 mph", f_wind, "N", "from wind.py")
res.add("Pier tip deflection", delta * 1e6, "um", "F L^3/3EI")
res.add("Pier pointing tilt", tilt, "arcsec", "tip slope F L^2/2EI")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pier tilt note mismatches formula

Medium Severity

evaluate() sets pier pointing tilt to pier_tilt_arcsec(F) plus an extra moment term F·h_head·L/(EI), but the budget line note and assumptions still describe only tip slope F·L²/(2EI). The published value (~0.70″) matches the sum, not the labeled formula (~0.33″), so hand checks and downstream docs can disagree with the calculator.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit c26cb55. Configure here.

def shaft_mass_kg(cw: P.CounterweightSystem = P.COUNTERWEIGHTS) -> float:
"""Mass of the solid 303-SS counterweight shaft = rho * A * L. DERIVED."""
area = math.pi / 4.0 * cw.shaft_dia_m ** 2
return cw.material.rho * area * cw.shaft_len_m

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Duplicate counterweight shaft mass

Low Severity

shaft_mass_kg in balance.py and counterweight_shaft_mass_kg in pier.py both compute 303-SS shaft mass from rho·A·L on P.COUNTERWEIGHTS. Two copies of the same derived value risk diverging if one path is updated later.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit c26cb55. Configure here.

f_rock = rocking_mode_hz(ota, ra_h, dec_h)

# Governing = lowest of every mode/mass case we examined.
f_governing = min(f_bounce_free, f_bounce_cw, f_rock)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rocking mode ignores counterweight mass

Low Severity

evaluate() takes the governing first mode as the minimum of CW-free bounce, counterweighted bounce, and rocking modes, but rocking_mode_hz() always uses payload-only inertia while the counterweighted bounce case includes 12.5 kg of weights. The compared modes do not use the same modal mass.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit c26cb55. Configure here.

@THOClabs
THOClabs deleted the design/mechanical-tender branch August 7, 2026 04:22
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