ReviewOS

also looking at this

stacks/drone

feat: add scoped cargo receiving mission tasks

#102
Merged chris wants to merge codex/cargo-fleet-authority into main
21 files +1186 -15
docs/cargo-station.mdadded+108-0
Changes to docs/cargo-station.md
@@ -0,0 +1,108 @@
1# Modeled cargo station handling
2
3`createCargoStationHandler` in `resources/functions/drone/cargo/station.ts` owns one
4existing point-parcel record through free fall, surface capture, a finite powered rail
5and one departure. This is a software simulation prerequisite for
6[distinct-vehicle cargo handover](cargo-delivery.md#remaining-issue-scope).
7Physical outputs remain disabled.
8
9## Use an actual parcel
10
11Pass the parcel produced by a carrier's actual `separateCarriedLoad()` event, adding
12its declared id. An empty receiving body's `intakePoint()` supplies a possible rail
13endpoint; it does not supply a parcel. The world coordinator must remove the previous
14owner when it creates the station and consume the departure exactly once. Independent
15station instances cannot detect a caller cloning a parcel into multiple worlds.
16
17```ts
18import { createCargoStationHandler } from '../resources/functions/drone/cargo/station'
19
20const station = createCargoStationHandler({
21 atMs: 4,
22 parcel: { id: 'parcel-a', massKg: 0.1, positionM: [0.08, 0, -1], velocityMps: [0, 0, 0] },
23 pickup: { centerM: [0.08, 0, 0], radiusM: 0.1 },
24 destinationM: [1.08, 0, 0],
25 maxSpeedMps: 0.5,
26 maxAccelerationMps2: 1,
27})
28```
29
30The literal parcel above is an isolated numerical example. The integration test uses
31real source separation and real receiving dynamics rather than manufacturing a parcel
32from the receiving joint. All positions, velocities and forces use fixed-origin LOCAL_NED:
33metres, metres per second and newtons, with down positive. Mass is kilograms and time
34is one modeled local clock in milliseconds.
35
36## Lifecycle and clock
37
38The constructor captures strict own-data records and dense finite three-element arrays.
39Unknown fields, accessors and invalid declarations throw `cargo-station-constructor`.
40Later caller mutation cannot alter retained state. Bounds are:
41
42- Safe nonnegative initial epoch aligned to 4 ms, leaving 180,000 ms of safe clock range.
43- Parcel id matching `[a-z][a-z0-9-]{0,39}`, mass greater than zero and at most 0.25 kg.
44- Declared coordinates within +/-1,000 m; initial velocity components within +/-5 m/s.
45- Horizontal pickup radius 0.05 to 2 m. The infinite rough capture plane has down in [-1, 0] m;
46 the parcel starts on that plane or up to 3 m above it.
47- Destination on or up to 1 m above the plane. Center-to-destination distance plus pickup
48 radius is at most 20 m, with worst declared rail duration at most 120,000 ms.
49- Spatial speed 0.05 to 1 m/s and acceleration 0.05 to 2 m/s².
50
51Call `step(previousAtMs + 4)` to advance the actor. Repeated, skipped, backward, fractional
52or exhausted epochs throw `cargo-station-clock` before mutation. The lifetime is at most
53180,000 ms from construction; the owning world must bound its run accordingly.
54
55Free fall uses exact constant-gravity kinematics and a quadratic within-step contact time.
56The ideal rough plane stops all velocity components. The retained impact contains its
57fractional contact epoch, actual point, incoming velocity, impulse and kinetic loss.
58The snapshot epoch is the enclosing 4 ms step endpoint. No force peak or impact duration
59is invented. A point outside the declared horizontal disc becomes `missed` at its actual
60contact location and cannot start transport.
61
62`start()` accepts only `held`, with enough lifetime for the full rail path. It never
63retries, moves a missed point onto the rail or starts during free fall. Rail motion uses
64a rest-to-rest quintic position law with derived duration respecting both declared spatial
65limits. The parcel follows the whole path; its final analytic endpoint is the declared
66position with zero velocity. A zero-length route still has a finite 504 ms duration.
67
68`cancel()` is one-way. A moving parcel enters `braking`, with constant deceleration at
69the declared acceleration limit until it stops at the physically integrated location.
70A falling parcel continues under gravity until plane contact. These requests return
71`cancelling`; `cancelled` means it was already at rest. Snapshots distinguish the request
72epoch, current phase and fractional stop epoch. Cancellation retains the parcel and
73prevents transfer; it does not restore an aircraft's authority or land a vehicle.
74
75`takeReadyParcel()` accepts only `ready`, returns a detached parcel and clears the
76station's owned mass. Further departure attempts are refused. The receiving body's
77`attachParcel()` still independently checks its actual current joint. A stale destination
78can therefore fail intake; the world must retain the departed parcel and an uncertain
79outcome rather than moving or duplicating it to make receipt succeed.
80
81## Mechanical accounting
82
83Snapshots retain current and departed mass/energy, rail force, impact loss and work.
84Mechanical energy is `0.5 * mass * speed² - mass * gravity * down`. Free fall conserves
85that quantity to binary64 accumulation tolerance. Surface capture dissipates the incoming
86kinetic energy. Rail force includes gravity support; lifting increases potential energy.
87`stationNetWorkJ` accumulates the represented mechanical-energy change during rail motion
88and braking. Positive and negative work fields sum positive and signed negative **sampled
89energy increments**, not a continuous actuator-efficiency or power integration.
90
91The residual is `current + departed + planeDissipation - initial - stationNetWork`.
92It exposes numerical accumulation instead of substituting a declared battery budget.
93This model has no motor, gearbox, battery, measured efficiency, station recoil, parcel
94spin, deformation or physical mechanism qualification.
95
96## Evidence and remaining integration
97
98`tests/unit/cargo-station.test.ts` exercises actual source/station/receiver mass transfer,
99finite displacement, a worked midpoint, ballistic contact time/impulse/energy, pickup miss,
100cancellation during rising flight and powered motion, spatial speed/acceleration bounds,
101vertical work, strict admission, detached state and lifetime rejection.
102
103This actor does not grant a mechanism lease, authenticate a recipient, produce a custody
104ACK or coordinate two live vehicle mission engines. Those operations must use each
105vehicle's own sensor, estimator and current authority scope on the common clock. The
106[receiving mission task](cargo-delivery.md#receiving-mission-task-prerequisite) now holds
107a declared pad under the shared engine. Its physical-intake acknowledgement port, the
108two-vehicle custody protocol, cancellation/uncertainty matrix and bounded fleet CLI remain open under [#25](https://github.com/stacksjs/drone/issues/25).