ReviewOS

also looking at this

stacks/drone

feat: add owned VTOL hover development

#76
Merged chris wants to merge codex/owned-vtol-lift-and-cruise into main
30 files +780 -111
app/Commands/VtolHover.tsadded+27-0
Changes to app/Commands/VtolHover.ts
@@ -0,0 +1,27 @@
1import { defineCommand } from '@stacksjs/cli'
2import { print, printError } from '@stacksjs/cli/output'
3import { createVtolHoverProfile, vtolHoverScenarios } from '../../resources/functions/drone/vehicles/vtol'
4import { runVehicleSimulation } from '../../resources/functions/drone/vehicles/runtime'
5
6export default defineCommand({
7 name: 'vtol:hover',
8 description: 'Exercise the fictional lift-and-cruise airframe in hover only; no wing transition or physical control',
9 options: {
10 '--scenario <name>': { description: vtolHoverScenarios.join(', '), default: 'hover' },
11 '--seconds <n>': { description: 'Maximum virtual duration, 2..180 seconds', default: '60' },
12 },
13 handle(options) {
14 try {
15 const result = runVehicleSimulation(createVtolHoverProfile(options.scenario), { scenario: options.scenario, seconds: Number(options.seconds) })
16 const { trace, path, ...report } = result
17 const expectedStatus = options.scenario === 'hover' ? 'completed' : options.scenario === 'host-loss' ? 'host-lost' : 'blocked'
18 const observedFlight = path.some(row => row.truthPositionM[2] < -1 && row.actuators.slice(0, 4).some(n => n > 0))
19 const boardNeutral = result.board.actuators.every(n => n === 0) && result.board.expiresAtMs === null
20 const hoverOnly = path.every(row => row.actuators.slice(4).every(n => n === 0))
21 const demonstrationMatched = result.status === expectedStatus && observedFlight && boardNeutral && hoverOnly
22 print(JSON.stringify({ ...report, scope: 'development-hover-only', transitionsImplemented: false, expectedStatus, demonstrationMatched, observedFlight, boardNeutral, hoverOnly, recordedMissionRows: trace.rows.length, evaluatedPathRows: path.length }, (_key, value) => typeof value === 'bigint' ? String(value) : value, 2))
23 if (!demonstrationMatched) process.exitCode = 1
24 }
25 catch (error) { printError(error instanceof Error ? error.message : String(error)); process.exitCode = 1 }
26 },
27})