{"record":{"id":"7e11a92de3605e60","repo":"JuliusBrussee/caveman","slug":"usage-caveman-proxy-learn-simulate-sink-id-sink-id-sources","errorCode":null,"errorMessage":"usage: caveman-proxy learn simulate <sink_id> [<sink_id>...] [--sources <list>] [--since <window>]","messagePattern":"usage: caveman-proxy learn simulate <sink_id> \\[<sink_id>\\.\\.\\.\\] \\[--sources <list>\\] \\[--since <window>\\]","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"proxy/cmd/caveman-proxy/main.go","lineNumber":753,"sourceCode":"\t\tapplyLearnSink(logger, home, sinkID, hasArg(args, \"--dry-run\"), plan)\n\tcase \"applied\":\n\t\tsinkID := firstPositional(args)\n\t\tif sinkID == \"\" {\n\t\t\tfatalJSON(logger, fmt.Errorf(\"usage: caveman-proxy learn applied <sink_id> [--fix-kind <k>] [--note <s>]\"))\n\t\t}\n\t\tplan, err := spend.BuildLearnPlanFilteredWithRetro(cwd, sources, since, store.RetroOptions{}, repoFilter)\n\t\tif err != nil {\n\t\t\tfatalJSON(logger, err)\n\t\t}\n\t\trecorded, err := spend.RecordAppliedFix(plan, sinkID, argFlag(args, \"--fix-kind\", \"\"), argFlag(args, \"--note\", \"\"))\n\t\tif err != nil {\n\t\t\tfatalJSON(logger, err)\n\t\t}\n\t\tprintJSON(recorded)\n\tcase \"simulate\":\n\t\tsinkIDs := learnSinkPositionals(args)\n\t\tif len(sinkIDs) == 0 {\n\t\t\tfatalJSON(logger, fmt.Errorf(\"usage: caveman-proxy learn simulate <sink_id> [<sink_id>...] [--sources <list>] [--since <window>]\"))\n\t\t}\n\t\tsimulation, err := spend.BuildLearnSimulationFiltered(cwd, sources, since, sinkIDs, repoFilter)\n\t\tif err != nil {\n\t\t\tfatalJSON(logger, err)\n\t\t}\n\t\tprintJSON(simulation)\n\tdefault:\n\t\tfatalJSON(logger, fmt.Errorf(\"unknown learn subcommand: %s\", sub))\n\t}\n}\n\nvar positionalValueFlags = map[string]bool{\n\t\"--agent\": true, \"--behavior-budget-ms\": true, \"--build\": true,\n\t\"--command\": true, \"--decision\": true, \"--exit-code\": true,\n\t\"--fix-kind\": true, \"--note\": true, \"--out\": true, \"--path\": true,\n\t\"--plan\": true, \"--port\": true, \"--recent\": true, \"--repo\": true,\n\t\"--retro-budget-ms\": true, \"--session\": true, \"--since\": true,\n\t\"--sources\": true, \"--trial-id\": true, \"--write-report-token\": true,","sourceCodeStart":735,"sourceCodeEnd":771,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/proxy/cmd/caveman-proxy/main.go#L735-L771","documentation":"Thrown by runLearn's `simulate` branch when learnSinkPositionals(args) yields no ids: `learn simulate <sink_id> [<sink_id>...] [--sources <list>] [--since <window>]`. Simulation evaluates estimated savings for one or more sinks, so at least one positional id is required.","triggerScenarios":"`caveman-proxy learn simulate` bare; `learn simulate --sources claude --since 30d` where all args are flags; accidentally quoting ids into the flag values so no bare positionals remain.","commonSituations":"Batch-simulating sinks in a pipeline where the id list variable expanded to empty; forgetting that flag values like `--sources claude` are skipped by learnSinkPositionals and only bare words count as ids.","solutions":["Pass at least one bare sink id: `caveman-proxy learn simulate <sink_id>`.","Pass multiple ids space-separated after the subcommand, flags can come before or after: `learn simulate id1 id2 --sources claude --since 30d`.","Verify the id list is non-empty in scripts before calling the CLI."],"exampleFix":"// before\ncaveman-proxy learn simulate --sources claude\n// after\ncaveman-proxy learn simulate context-overload-7f3a pixel-sink-9b1c --sources claude --since 30d","handlingStrategy":"validation","validationCode":"// shell\nIDS=$(learnSinkPositionals \"$@\")   # bare non-flag args only\nif [ -z \"$IDS\" ]; then echo \"learn simulate needs at least one sink_id\" >&2; exit 2; fi\ncaveman-proxy learn simulate $IDS --sources claude --since 30d","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Only bare words count as ids; flag values like --sources claude are ignored by the positional parser.","In batch pipelines assert the id array is non-empty before invoking.","Pass multiple ids space-separated."],"tags":["cli","missing-argument","learn","simulation"],"backgroundTag":"missing-cli-argument","analyzedSha":"3ee70a102609e550bd2e68004bf5990a9341c851","analyzedAt":"2026-09-20T15:53:39.229Z","contentChangedAt":"2026-09-20T15:53:39.229Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}