mirror of
https://github.com/legop3/MultiRoombaRover.git
synced 2026-11-15 03:02:17 -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
|
- 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,
|
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.
|
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;
|
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) {
|
function listModels(root) {
|
||||||
return serial(async () => {
|
return serial(async () => {
|
||||||
let entries;
|
let entries;
|
||||||
@@ -116,4 +137,4 @@ function listModels(root) {
|
|||||||
return models;
|
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 { recoverRecordings, enforceRetention } = require('./storage');
|
||||||
const { createTrainer } = require('./training');
|
const { createTrainer } = require('./training');
|
||||||
const { createDriving } = require('./driving');
|
const { createDriving } = require('./driving');
|
||||||
|
const { removeObsoleteModels } = require('./models');
|
||||||
const { createGateway } = require('./socketGateway');
|
const { createGateway } = require('./socketGateway');
|
||||||
|
|
||||||
function createRuntime({ config, logger }) {
|
function createRuntime({ config, logger }) {
|
||||||
@@ -221,6 +222,7 @@ function createRuntime({ config, logger }) {
|
|||||||
async function start() {
|
async function start() {
|
||||||
await fs.mkdir(recordingsRoot, { recursive: true });
|
await fs.mkdir(recordingsRoot, { recursive: true });
|
||||||
await recoverRecordings(recordingsRoot);
|
await recoverRecordings(recordingsRoot);
|
||||||
|
await removeObsoleteModels(root);
|
||||||
await trainer.start();
|
await trainer.start();
|
||||||
running = true;
|
running = true;
|
||||||
driving.attach();
|
driving.attach();
|
||||||
|
|||||||
@@ -397,6 +397,8 @@ function advanceTurn(roverId) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (queue.queue.length === 0) {
|
if (queue.queue.length === 0) {
|
||||||
|
// Empty queues must not expose the departed driver through turn.currentId.
|
||||||
|
queue.current = null;
|
||||||
stopRover(roverId);
|
stopRover(roverId);
|
||||||
clearTurnTimer(roverId, queue);
|
clearTurnTimer(roverId, queue);
|
||||||
setActiveDriver(roverId, null);
|
setActiveDriver(roverId, null);
|
||||||
|
|||||||
@@ -130,7 +130,7 @@ function LearningCard({ roverId }) {
|
|||||||
return <CardFrame title="Rover learning" className="w-full" bodyClassName="text-sm text-slate-300">
|
return <CardFrame title="Rover learning" className="w-full" bodyClassName="text-sm text-slate-300">
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<p className="text-center text-xs text-slate-400">
|
<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>
|
</p>
|
||||||
<div className="flex flex-wrap items-center justify-center gap-1">
|
<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}>
|
<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>
|
</div>
|
||||||
{state?.control?.canSnapshot && <div className="text-center">
|
{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>
|
<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>}
|
</div>}
|
||||||
{session && <section className="space-y-2" aria-label="Live model actions">
|
{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>
|
<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}
|
value={thresholdDraft ?? session.threshold ?? .7} disabled={working || !state?.control?.canAdjust}
|
||||||
onChange={(event) => setThresholdDraft(Number(event.target.value))}
|
onChange={(event) => setThresholdDraft(Number(event.target.value))}
|
||||||
onPointerUp={commitThreshold} onKeyUp={commitThreshold} onBlur={commitThreshold} />
|
onPointerUp={commitThreshold} onKeyUp={commitThreshold} onBlur={commitThreshold} />
|
||||||
<span className="block text-slate-400">Lower allows more accessory actions. Wheel speeds are independent.</span>
|
|
||||||
</label>
|
</label>
|
||||||
<div className="grid max-h-52 grid-cols-1 gap-1 overflow-y-auto @[28rem]:grid-cols-2">
|
<div className="grid max-h-52 grid-cols-1 gap-1 overflow-y-auto @[28rem]:grid-cols-2">
|
||||||
{session.proposals?.map((proposal) => {
|
{session.proposals?.map((proposal) => {
|
||||||
@@ -178,7 +176,6 @@ function LearningCard({ roverId }) {
|
|||||||
</div>
|
</div>
|
||||||
</section>}
|
</section>}
|
||||||
{state?.control?.reason && <p className="text-center text-xs text-slate-400">{state.control.reason}</p>}
|
{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>
|
<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>}
|
{(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)}>
|
<details className="surface-muted text-xs" onToggle={(event) => setDetailsOpen(event.currentTarget.open)}>
|
||||||
|
|||||||
Reference in New Issue
Block a user