Ship v0.1.1–v0.1.5: first-live-run fixes and dashboard viewer

- v0.1.1: config persistence — FileHelper paths made absolute
  (/media/startos/volumes/main/...); relative paths resolved into the JS
  runtime's ephemeral cwd so action saves never reached /data
- v0.1.2: preJobStopContainers (Configure Grading) — docker-stop resident
  vLLM containers on the head Spark at job start, no auto-restart
- v0.1.3: preflight auth (LiteLLM master_key gates /models),
  poll-until-loaded, crash fast-fail (restarting counts as dead)
- v0.1.4: HF_HUB_OFFLINE/TRANSFORMERS_OFFLINE in airgapped serving
  (--internal network has no DNS); grader _post timeout 600→1800s for
  ~3.6 tok/s GB10 generation
- v0.1.5: dashboard viewer survives the periodic background refresh;
  download buttons for deck reports, deck JSON, and SCORECARD.md
- .gitignore: .startos/ build workspace, start-technologies/

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Jonathan Kirkwood
2026-07-30 09:14:24 -05:00
co-authored by Claude Fable 5
parent 1d1074b625
commit 91212322c1
16 changed files with 262 additions and 46 deletions
+14
View File
@@ -84,6 +84,18 @@ const inputSpec = InputSpec.of({
'land in the inbox. Off by default so you trigger grading explicitly.',
default: false,
}),
preJobStopContainers: Value.text({
name: 'Stop These Containers Before Grading (optional)',
description:
'Space- or comma-separated docker container names stopped on the HEAD ' +
'Spark at the start of every grading job, so the job gets the GPU to ' +
'itself (e.g. an always-on vLLM another service runs). They are NOT ' +
'restarted afterwards — the service that owns them reloads its own ' +
'models (e.g. the Gazette\'s Fleet job). Empty = stop nothing.',
required: false,
default: null,
placeholder: 'vllm-gemma4-clerk',
}),
// --- Deterministic-scorer weights (composite = quant 60 + qual 40 - flags) ---
profitabilityKpi: Value.number({
name: 'Weight: Profitability KPIs',
@@ -204,6 +216,7 @@ export const configureGrading = sdk.Action.withInput(
adjudicatorPersona: cfg.adjudicatorPersona || undefined,
wipeRemoteDocs: cfg.wipeRemoteDocs,
autoRunOnDrop: cfg.autoRunOnDrop,
preJobStopContainers: cfg.preJobStopContainers || undefined,
profitabilityKpi: cfg.weights.profitabilityKpi,
otherKpi: cfg.weights.otherKpi,
forecastIntegrity: cfg.weights.forecastIntegrity,
@@ -228,6 +241,7 @@ export const configureGrading = sdk.Action.withInput(
adjudicatorPersona: input.adjudicatorPersona ?? '',
wipeRemoteDocs: input.wipeRemoteDocs,
autoRunOnDrop: input.autoRunOnDrop,
preJobStopContainers: input.preJobStopContainers ?? '',
weights: {
profitabilityKpi: input.profitabilityKpi,
otherKpi: input.otherKpi,
+12 -1
View File
@@ -172,6 +172,10 @@ export const configShape = z.object({
autoRunOnDrop: z.boolean().default(false),
// Name of the per-job Docker network created on the head Spark.
networkName: z.string().default('boardroom-net'),
// Space/comma-separated docker container names stopped on the head Spark at
// the start of every job to free GPU memory (e.g. an always-on vLLM another
// service runs). NOT restarted afterwards — their owner reloads them.
preJobStopContainers: z.string().default(''),
// --- Portfolio companies ---
// The authoritative source of pinned KPI targets and KPI-name aliases. Decks
@@ -212,4 +216,11 @@ export const configShape = z.object({
export type Config = z.infer<typeof configShape>
export const configFile = FileHelper.json('./config.json', configShape)
// Absolute path into the `main` volume (mounted at /media/startos/volumes/main
// in the JS runtime, /data in the orchestrator container). A relative path here
// resolves against the JS runtime's EPHEMERAL working directory and silently
// loses the config on restart.
export const configFile = FileHelper.json(
'/media/startos/volumes/main/config.json',
configShape,
)
+7 -3
View File
@@ -5,9 +5,13 @@ import { FileHelper } from '@start9labs/start-sdk'
* `main` volume. Kept out of config.json so it is never returned in plaintext
* config reads. The container copies it to a 600 path at runtime.
*
* Volume path './ssh/id_spark' -> /data/ssh/id_spark inside the container.
* Volume path (absolute — a relative path would resolve against the JS
* runtime's ephemeral cwd, not the volume) -> /data/ssh/id_spark inside the
* orchestrator container.
*/
export const sshKeyFile = FileHelper.string('./ssh/id_spark')
export const sshKeyFile = FileHelper.string(
'/media/startos/volumes/main/ssh/id_spark',
)
/**
* Optional Hugging Face token (for gated/private model pulls on the Sparks).
@@ -15,7 +19,7 @@ export const sshKeyFile = FileHelper.string('./ssh/id_spark')
* network mode models are served from a pre-pulled cache, so this is only used
* the first time you warm a model (or in local_services mode).
*
* Volume path './secrets/hf_token' -> /data/secrets/hf_token.
* Volume path (absolute, see above) -> /data/secrets/hf_token.
*
* NOTE: Boardroom Map has NO frontier/cloud key. There is deliberately no Anthropic
* key and no Gitea token — the whole point is that confidential documents and
+7 -2
View File
@@ -1,8 +1,13 @@
import { VersionGraph } from '@start9labs/start-sdk'
import { v_0_1_0 } from './v_0_1_0'
import { v_0_1_1 } from './v_0_1_1'
import { v_0_1_2 } from './v_0_1_2'
import { v_0_1_3 } from './v_0_1_3'
import { v_0_1_4 } from './v_0_1_4'
import { v_0_1_5 } from './v_0_1_5'
/** The current version MUST be the first argument (`current`). */
export const versions = VersionGraph.of({
current: v_0_1_0,
other: [],
current: v_0_1_5,
other: [v_0_1_4, v_0_1_3, v_0_1_2, v_0_1_1, v_0_1_0],
})
+16
View File
@@ -0,0 +1,16 @@
import { VersionInfo } from '@start9labs/start-sdk'
/**
* Packaging fix. ExVer form `<upstream>:<downstream>` — we track our own
* packaging revision since Boardroom Map has no separate upstream semver.
*/
export const v_0_1_1 = VersionInfo.of({
version: '0.1.1:0',
releaseNotes:
'Fix: persist config.json, the Spark SSH key, and the optional HF token ' +
'to the main volume (absolute volume paths in the file models). ' +
'Previously the Configure actions wrote to an ephemeral runtime directory, ' +
'so the orchestrator never saw /data/config.json and configuration was ' +
'lost on restart. Re-run the Configure actions after updating.',
migrations: {},
})
+15
View File
@@ -0,0 +1,15 @@
import { VersionInfo } from '@start9labs/start-sdk'
/**
* GPU co-residency support. ExVer form `<upstream>:<downstream>`.
*/
export const v_0_1_2 = VersionInfo.of({
version: '0.1.2:0',
releaseNotes:
'New "Stop These Containers Before Grading" setting (Configure Grading): ' +
'container names listed there are docker-stopped on the head Spark at the ' +
'start of every grading job, so the job gets the GPU to itself when ' +
'another service keeps an always-on vLLM resident. They are deliberately ' +
'not restarted afterwards — the owning service reloads its own models.',
migrations: {},
})
+13
View File
@@ -0,0 +1,13 @@
import { VersionInfo } from '@start9labs/start-sdk'
/** Serving-readiness fix. ExVer form `<upstream>:<downstream>`. */
export const v_0_1_3 = VersionInfo.of({
version: '0.1.3:0',
releaseNotes:
'Fix wave preflight: the model-proxy probe now authenticates (the router ' +
'requires its master key even on /models) and both the proxy check and the ' +
'per-model completion check poll until ready instead of failing on a ' +
'single early attempt — a 31B model takes minutes to load into GPU ' +
'memory. Crashed containers fail fast with their log tail.',
migrations: {},
})
+13
View File
@@ -0,0 +1,13 @@
import { VersionInfo } from '@start9labs/start-sdk'
/** Air-gapped serving fix. ExVer form `<upstream>:<downstream>`. */
export const v_0_1_4 = VersionInfo.of({
version: '0.1.4:0',
releaseNotes:
'Air-gapped mode now serves models with HF_HUB_OFFLINE/TRANSFORMERS_OFFLINE ' +
'set: the per-job --internal network has no DNS, so without offline mode ' +
'the HF hub client crashed on name resolution even with the model fully ' +
'cached. Preflight also treats a crash-looping (restarting) vLLM container ' +
'as dead and fails fast with its logs instead of waiting out the timeout.',
migrations: {},
})
+14
View File
@@ -0,0 +1,14 @@
import { VersionInfo } from '@start9labs/start-sdk'
/** Dashboard viewer fixes. ExVer form `<upstream>:<downstream>`. */
export const v_0_1_5 = VersionInfo.of({
version: '0.1.5:0',
releaseNotes:
'Dashboard: an open deck report / JSON / scorecard viewer now stays open ' +
'across the periodic background refresh (previously it silently closed ' +
'within ~20s) — it closes only via its close button or when switching ' +
'companies. Added ⬇ download buttons: per-deck report downloads in the ' +
'deck-history table, plus a download link in the viewer header for ' +
'reports, deck JSON records, and SCORECARD.md.',
migrations: {},
})