dbbb051ebd
Build & push images / images (push) Successful in 4m22s
The wash stream is small; the entry camera photographs every car in exactly the view the classifier is trained on. The booth can now queue entry vehicle reads as pure training material — crop + the camera's class, no order, no operator, no category. - Core announces every vehicle read (deviceEvents.emitVehicleRead from snapshot.ts); the Car Wash module listens, samples entry reads in-process (sampleEntry: exactly one in N) and queues them (enqueueEntry). CARWASH_REVIEW_ENTRY_SAMPLE=N; 1 = every entry (storage and bandwidth are not the limit — user); 0/unset = off. Forwarded by compose. - Packages carry kind: "wash" | "entry". Collector: kind column, entry meta validated without the operator fields, review screen shows an entry sample as such, export has a kind column, operator agreement computed from wash items only. Setup line shows "1 in N entries sampled"; status carries entrySample. - komodo: park-2's four review lines enabled (collector URL by Netbird DNS name, booth-2, the shared per-booth secret, every entry sampled) — the collector is up on the overlay. - Tests on both sides. Wiki: vision-review-outbox (entry stream + the internet-feed assessment), log. Claude-Session: https://claude.ai/code/session_01FWncR69HgGPuei1dLrW3cU
37 lines
2.1 KiB
TypeScript
37 lines
2.1 KiB
TypeScript
import { deviceEvents } from "../../device-events.js";
|
|
import type { ServerModule } from "../index.js";
|
|
import { ReviewOutbox, reviewUploadConfigFromEnv } from "./review-outbox.js";
|
|
import { carwashRoutes } from "./routes.js";
|
|
import { CarwashService } from "./service.js";
|
|
|
|
// Car Wash — the pilot venue module (wiki/decisions/venue-modules.md). Everything the
|
|
// module is lives in this folder: its service (master data, the order queue, the bay
|
|
// payment, the parking sponsorship + settlement), its routes, and the booth charge
|
|
// provider it registers with the core's PayStation. The core knows it only through the
|
|
// registry line in ../index.ts and the manifest in @parking/shared.
|
|
export const carwashModule: ServerModule = {
|
|
id: "carwash",
|
|
async register(app, deps) {
|
|
// The review outbox (wiki/concepts/vision-review-outbox.md): on when the stack env
|
|
// names a collector URL, a per-booth token and a pseudonymous booth id; off = no
|
|
// queueing at all. One-way, background, never on the intake path.
|
|
const cfg = reviewUploadConfigFromEnv();
|
|
const outbox = new ReviewOutbox(deps.db, app.log, cfg);
|
|
app.log.info(cfg ? `carwash review upload: on → ${new URL(cfg.url).host} as ${cfg.boothId}` : "carwash review upload: off");
|
|
outbox.start();
|
|
// Entry-stream sampling: one in N entry vehicle reads goes to the reviewer as pure
|
|
// training material (the gate view, no order attached). The core announces the read;
|
|
// the module decides. Off unless CARWASH_REVIEW_ENTRY_SAMPLE is set.
|
|
const offVehicleRead = deviceEvents.onVehicleRead((e) => {
|
|
if (e.direction === "entry" && outbox.sampleEntry()) void outbox.enqueueEntry(e.read);
|
|
});
|
|
app.addHook("onClose", async () => offVehicleRead());
|
|
app.addHook("onClose", async () => outbox.stop());
|
|
const service = new CarwashService(deps, app.log, outbox);
|
|
// A wash ordered with payAt = "booth" is a charge line on the parking settlement;
|
|
// the core calls back after the payment is signed so the order is marked paid.
|
|
deps.payStation.registerChargeProvider(service.chargeProvider());
|
|
await carwashRoutes(app, deps, service, outbox);
|
|
},
|
|
};
|