mirror of
https://github.com/legop3/MultiRoombaRover.git
synced 2026-11-14 10:42:45 -05:00
slop
This commit is contained in:
@@ -786,3 +786,16 @@ no new training reset or configuration migration is required.
|
||||
- Focused Node syntax and Python worker entry-point checks passed. Targeted card
|
||||
lint is run for the UI change. End-to-end training/promotion, snapshot copying,
|
||||
active-session pinning and browser behavior remain unverified without live data.
|
||||
|
||||
|
||||
### UI cleanup and obsolete models
|
||||
|
||||
User explicitly requested removal of UI narration and deletion of obsolete models.
|
||||
Removed snapshot/threshold explanatory prose and the old commented manual-control
|
||||
note; idle status now says Stopped. Kept operational status/errors and diagnostics.
|
||||
Enabled-service startup now deletes permanent model directories whose validated
|
||||
manifest explicitly identifies policy format 1, even when training is disabled.
|
||||
Format 2 snapshots, Latest/Previous, recordings and current training state remain.
|
||||
This supersedes earlier promises to preserve incompatible format 1 model files.
|
||||
Deletion occurs on the actual server when the updated service starts; no production
|
||||
files were accessed from this development machine.
|
||||
|
||||
@@ -98,6 +98,27 @@ function saveSnapshot(root) {
|
||||
return model;
|
||||
});
|
||||
}
|
||||
// Explicitly retire format 1 models after the wheel-policy replacement. Only
|
||||
// recognized old-format manifests qualify; malformed or future models are kept.
|
||||
function removeObsoleteModels(root) {
|
||||
return serial(async () => {
|
||||
const directory = path.join(root, 'models');
|
||||
let entries;
|
||||
try { entries = await fs.readdir(directory, { withFileTypes: true }); }
|
||||
catch (error) { if (error.code === 'ENOENT') return; throw error; }
|
||||
for (const entry of entries) {
|
||||
if (!entry.isDirectory() || !UUID.test(entry.name)) continue;
|
||||
const target = path.join(directory, entry.name);
|
||||
let model;
|
||||
try { model = await metadata(target); }
|
||||
catch { continue; }
|
||||
if (model.specification?.version === 1 && !leases.has(target)) {
|
||||
await fs.rm(target, { recursive: true });
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function listModels(root) {
|
||||
return serial(async () => {
|
||||
let entries;
|
||||
@@ -116,4 +137,4 @@ function listModels(root) {
|
||||
return models;
|
||||
});
|
||||
}
|
||||
module.exports = { listModels, acquireModel, adoptCheckpoint, saveSnapshot };
|
||||
module.exports = { removeObsoleteModels, listModels, acquireModel, adoptCheckpoint, saveSnapshot };
|
||||
|
||||
@@ -13,6 +13,7 @@ const { createRecording } = require('./recording');
|
||||
const { recoverRecordings, enforceRetention } = require('./storage');
|
||||
const { createTrainer } = require('./training');
|
||||
const { createDriving } = require('./driving');
|
||||
const { removeObsoleteModels } = require('./models');
|
||||
const { createGateway } = require('./socketGateway');
|
||||
|
||||
function createRuntime({ config, logger }) {
|
||||
@@ -221,6 +222,7 @@ function createRuntime({ config, logger }) {
|
||||
async function start() {
|
||||
await fs.mkdir(recordingsRoot, { recursive: true });
|
||||
await recoverRecordings(recordingsRoot);
|
||||
await removeObsoleteModels(root);
|
||||
await trainer.start();
|
||||
running = true;
|
||||
driving.attach();
|
||||
|
||||
@@ -397,6 +397,8 @@ function advanceTurn(roverId) {
|
||||
return;
|
||||
}
|
||||
if (queue.queue.length === 0) {
|
||||
// Empty queues must not expose the departed driver through turn.currentId.
|
||||
queue.current = null;
|
||||
stopRover(roverId);
|
||||
clearTurnTimer(roverId, queue);
|
||||
setActiveDriver(roverId, null);
|
||||
|
||||
@@ -130,7 +130,7 @@ function LearningCard({ roverId }) {
|
||||
return <CardFrame title="Rover learning" className="w-full" bodyClassName="text-sm text-slate-300">
|
||||
<div className="space-y-2">
|
||||
<p className="text-center text-xs text-slate-400">
|
||||
{session ? `${session.modelName} · ${session.status}` : state ? 'Choose a model to control your rover.' : 'Waiting for rover learning status…'}
|
||||
{session ? `${session.modelName} · ${session.status}` : state ? 'Stopped' : 'Waiting for rover learning status…'}
|
||||
</p>
|
||||
<div className="flex flex-wrap items-center justify-center gap-1">
|
||||
<select aria-label="Rover model" className={fieldClass} value={chosen?.id || ''} onChange={(event) => setSelectedId(event.target.value)} disabled={working || !models.length}>
|
||||
@@ -147,7 +147,6 @@ function LearningCard({ roverId }) {
|
||||
</div>
|
||||
{state?.control?.canSnapshot && <div className="text-center">
|
||||
<button type="button" className="button-dark text-sm disabled:opacity-50" disabled={working} onClick={() => act('snapshot')}>Save learner snapshot</button>
|
||||
<p className="mt-1 text-xs text-slate-400">Preserves the latest completed training checkpoint, including experimental results.</p>
|
||||
</div>}
|
||||
{session && <section className="space-y-2" aria-label="Live model actions">
|
||||
<p className="text-center text-xs text-sky-300">{session.predictionStatus || 'Waiting for fresh video and sensors'}</p>
|
||||
@@ -161,7 +160,6 @@ function LearningCard({ roverId }) {
|
||||
value={thresholdDraft ?? session.threshold ?? .7} disabled={working || !state?.control?.canAdjust}
|
||||
onChange={(event) => setThresholdDraft(Number(event.target.value))}
|
||||
onPointerUp={commitThreshold} onKeyUp={commitThreshold} onBlur={commitThreshold} />
|
||||
<span className="block text-slate-400">Lower allows more accessory actions. Wheel speeds are independent.</span>
|
||||
</label>
|
||||
<div className="grid max-h-52 grid-cols-1 gap-1 overflow-y-auto @[28rem]:grid-cols-2">
|
||||
{session.proposals?.map((proposal) => {
|
||||
@@ -178,7 +176,6 @@ function LearningCard({ roverId }) {
|
||||
</div>
|
||||
</section>}
|
||||
{state?.control?.reason && <p className="text-center text-xs text-slate-400">{state.control.reason}</p>}
|
||||
{/* <p className="text-center text-xs text-slate-500">Manual controls stay available and do not stop the model.</p> */}
|
||||
<p className="text-center text-xs text-slate-400">Recording: {recording ? recording.paused ? 'paused for disk space' : `${recording.sessions.filter((item) => item.video === 'Recording human driving').length} driving · ${recording.sessions.filter((item) => item.video === 'Dock lead-in buffer').length} dock buffer(s)` : 'unavailable'} · Training: {training?.status || 'unavailable'}</p>
|
||||
{(error || state?.catalogError) && <p role="alert" className="break-words text-xs text-amber-300">{error || state.catalogError}</p>}
|
||||
<details className="surface-muted text-xs" onToggle={(event) => setDetailsOpen(event.currentTarget.open)}>
|
||||
|
||||
Reference in New Issue
Block a user