{"record":{"id":"dd81e52ef22f2bc4","repo":"can1357/oh-my-pi","slug":"experiment-experimentid-has-no-runs-to-inheri","errorCode":null,"errorMessage":"experiment '${experimentId}' has no runs to inherit from","messagePattern":"experiment '(.+?)' has no runs to inherit from","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/metaharness/src/server.ts","lineNumber":123,"sourceCode":"\t\treturn true;\n\t} catch {\n\t\treturn false;\n\t}\n}\n\n/**\n * Resolve the launch request for a new arm added to an existing experiment.\n * Inherits the experiment's benchmark, dataset, and — crucially — the exact\n * task sample from a sibling arm (its recorded `include`, else its observed\n * trial tasks) so the arm is directly comparable. Only per-arm knobs (model,\n * prewalk, role, note, extra args) come from `req`. Throws if the experiment has\n * no runs to inherit from or the arm name is taken.\n */\nexport function resolveArmLaunch(store: RunStore, experimentId: string, req: AddArmRequest): LaunchRequest {\n\tif (!req.arm || /[^\\w.-]/.test(req.arm)) throw new Error(\"arm must be a non-empty [A-Za-z0-9_.-] token\");\n\tif (!req.model) throw new Error(\"model is required\");\n\tconst siblings = store.listRuns().filter(r => experimentOf(r.jobName) === experimentId);\n\tif (siblings.length === 0) throw new Error(`experiment '${experimentId}' has no runs to inherit from`);\n\t// Template = the sibling whose recorded `include` list is the longest (the\n\t// fullest expression of the experiment's sample — partial re-run arms\n\t// record subsets); among include-less siblings, the most observed trials.\n\t// listRuns is newest-first so ties keep the newest.\n\tconst strings = (v: unknown): string[] =>\n\t\tArray.isArray(v) ? v.filter((x): x is string => typeof x === \"string\") : [];\n\tconst recordedInclude = (r: RunRow): string[] => strings((r.config as Partial<LaunchRequest>).include);\n\tconst score = (r: RunRow): [number, number] => {\n\t\tconst recorded = recordedInclude(r).length;\n\t\treturn recorded > 0 ? [1, recorded] : [0, store.listTraces(r.jobName).length];\n\t};\n\tlet template = siblings[0];\n\tlet templateScore = score(template);\n\tfor (const r of siblings.slice(1)) {\n\t\tconst s = score(r);\n\t\tif (s[0] > templateScore[0] || (s[0] === templateScore[0] && s[1] > templateScore[1])) {\n\t\t\t[template, templateScore] = [r, s];\n\t\t}","sourceCodeStart":105,"sourceCodeEnd":141,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/metaharness/src/server.ts#L105-L141","documentation":"resolveArmLaunch builds a new arm by inheriting the task sample (include list / trial tasks) from existing runs of the same experiment. If store.listRuns() contains no runs whose jobName maps to this experimentId, there is nothing to inherit from, so it refuses rather than inventing a sample. This error means the experiment does not exist yet or has no recorded runs.","triggerScenarios":"Calling addArm for an experimentId that was never launched; a typo in experimentId so experimentOf(jobName) matches nothing; all runs of the experiment were deleted from the store; calling addArm before the first launch has registered its run.","commonSituations":"Starting a new experiment with addArm instead of an initial launch; renaming an experiment and using the old id; wiping the jobs directory while keeping old experiment ids in scripts.","solutions":["Launch the first run of the experiment via server.launch() (or record a run) before adding arms.","Verify experimentId matches the prefix used at launch: arms inherit from runs named `<experimentId>-<arm>`.","List existing runs (store.listRuns()) and confirm the experiment's runs are present.","If the store was wiped, re-register the experiment's original runs or restart the experiment from scratch."],"exampleFix":"// before\nserver.addArm(\"myexp\", { arm: \"arm-b\", model: \"m2\" }); // no runs yet\n// after\nserver.launch({ benchmark: \"harbor\", model: \"m1\", jobName: \"myexp-arm-a\" });\nserver.addArm(\"myexp\", { arm: \"arm-b\", model: \"m2\" });","handlingStrategy":"validation","validationCode":"const siblings = store.listRuns().filter(r => experimentOf(r.jobName) === experimentId);\nif (siblings.length === 0) {\n  throw new Error(`launch the experiment '${experimentId}' first; addArm needs sibling runs`);\n}","typeGuard":null,"tryCatchPattern":"try {\n  server.addArm(expId, req);\n} catch (err) {\n  if (err instanceof Error && err.message.includes(\"no runs to inherit\")) {\n    server.launch({ model: baselineModel, jobName: `${expId}-arm-a` });\n    server.addArm(expId, req);\n  } else throw err;\n}","preventionTips":["Establish the workflow: launch baseline run first, then add comparison arms.","Centralize experimentId construction so the prefix always matches job names.","Before scripting addArm, print store.listRuns() and confirm the experiment exists.","Don't delete job directories without accounting for dependent scripts."],"tags":["state","experiment-design","missing-data"],"backgroundTag":"experiment-has-no-baseline-runs","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}