amsd-pipeline-shared 0.5.43 → 0.5.45
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/docs/gateway-baseline-2.0.80.md5 +3 -0
- package/docs/gateway-files.txt +6 -0
- package/orchestrations/config/llm-defaults.claude.json +236 -0
- package/orchestrations/config/llm-defaults.mockserver.json +295 -0
- package/orchestrations/config/llm-defaults.openrouter.json +279 -0
- package/orchestrations/prompts/templates/plan-execute.json +16 -0
- package/orchestrations/prompts/templates/plan-pass.json +24 -0
- package/orchestrations/scripts/lib/llm-settings-resolve.js +17 -1
- package/orchestrations/scripts/lib/plan-mode.js +36 -0
- package/orchestrations/scripts/llm-handler.sh +79 -62
- package/orchestrations/scripts/spec-mode-runner.js +22 -27
- package/package.json +1 -1
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
5349c655265a56795c62a0327ba4e73b config/llm-defaults.claude.json
|
|
2
|
+
5c2b348dbf4860aa6ad999eb7b882757 config/llm-defaults.mockserver.json
|
|
3
|
+
c90ae290edde83ae4e13236edb1e8fb5 config/llm-defaults.openrouter.json
|
|
1
4
|
33364f057aa890497019737c7004db57 config/model-pricing.json
|
|
2
5
|
8a1bb4df2d1b6e7fd135f757423fb2f2 config/repo-artifacts.json
|
|
3
6
|
7ab104b57abcbc8cb3cd890c753d5d67 config/resume-preserves.json
|
package/docs/gateway-files.txt
CHANGED
|
@@ -2,6 +2,9 @@ config/call-policy.json
|
|
|
2
2
|
config/doctor-heavy-jobs.json
|
|
3
3
|
config/doctor-signatures.json
|
|
4
4
|
config/finding-contracts.json
|
|
5
|
+
config/llm-defaults.claude.json
|
|
6
|
+
config/llm-defaults.mockserver.json
|
|
7
|
+
config/llm-defaults.openrouter.json
|
|
5
8
|
config/model-pricing.json
|
|
6
9
|
config/repo-artifacts.json
|
|
7
10
|
config/resume-preserves.json
|
|
@@ -62,6 +65,8 @@ prompts/templates/phase-assessment-header.json
|
|
|
62
65
|
prompts/templates/pipeline-tools-command.json
|
|
63
66
|
prompts/templates/pipeline-tools-hosted.json
|
|
64
67
|
prompts/templates/plan-corrective.json
|
|
68
|
+
prompts/templates/plan-execute.json
|
|
69
|
+
prompts/templates/plan-pass.json
|
|
65
70
|
prompts/templates/plan-producer.json
|
|
66
71
|
prompts/templates/plan-reviewer.json
|
|
67
72
|
prompts/templates/post-failure-analyst.json
|
|
@@ -236,6 +241,7 @@ scripts/lib/pipeline-commit.sh
|
|
|
236
241
|
scripts/lib/pipeline-tools-mcp.js
|
|
237
242
|
scripts/lib/pipeline-tools.js
|
|
238
243
|
scripts/lib/plan-hash.js
|
|
244
|
+
scripts/lib/plan-mode.js
|
|
239
245
|
scripts/lib/plan-of-record.sh
|
|
240
246
|
scripts/lib/plan-scope.js
|
|
241
247
|
scripts/lib/prd-change-review.sh
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$comment": "THE CLAUDE PROVIDER SET — plain Claude Code on the operator's own tokens. The default stack.",
|
|
3
|
+
"$proven": "2026-08-25: plain `claude` honours ANTHROPIC_BASE_URL, reaches MockServer (POST /v1/messages in its request log) and PARSES the SSE it serves — is_error:false, result:'OK', stop_reason:'end_turn', RC=0.",
|
|
4
|
+
"$whyNotTheWrapper": "Plain `claude`, never codemie-claude. The wrapper authenticates through CodeMie SSO and spends CodeMie tokens; this set exists precisely because those are scarce and the operator has their own.",
|
|
5
|
+
"$whyTheSameLadders": "Deliberately identical to the codemie set. A rehearsal on different models proves the harness, not the run. Sharing the ladder means a mocked run climbs the chain a paid run would.",
|
|
6
|
+
"ladderTierOrder": [
|
|
7
|
+
"medium",
|
|
8
|
+
"high",
|
|
9
|
+
"highest"
|
|
10
|
+
],
|
|
11
|
+
"ladders": {
|
|
12
|
+
"medium": {
|
|
13
|
+
"$why": "Enters cheap and tops out at Sonnet-5. A `mid` seam never reaches Opus: 14 seams resolve here, and measured turn counts are p50 4, p90 24 — work that does not need a frontier model.",
|
|
14
|
+
"startModel": "claude-haiku-4-5-20251001",
|
|
15
|
+
"modelLadder": [
|
|
16
|
+
{
|
|
17
|
+
"from": "claude-haiku-4-5-20251001",
|
|
18
|
+
"to": "claude-sonnet-5"
|
|
19
|
+
}
|
|
20
|
+
],
|
|
21
|
+
"rungs": [
|
|
22
|
+
{
|
|
23
|
+
"rung": 0,
|
|
24
|
+
"maxIterations": 40,
|
|
25
|
+
"reasoningEffort": "medium"
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"rung": 1,
|
|
29
|
+
"maxIterations": 120,
|
|
30
|
+
"reasoningEffort": "high"
|
|
31
|
+
}
|
|
32
|
+
]
|
|
33
|
+
},
|
|
34
|
+
"high": {
|
|
35
|
+
"$why": "Same ENTRY as medium, higher CEILING. That is the 'different entry, same ceiling' rule applied between high and highest: what separates the tiers is how far they may climb, not where they start.",
|
|
36
|
+
"startModel": "claude-haiku-4-5-20251001",
|
|
37
|
+
"modelLadder": [
|
|
38
|
+
{
|
|
39
|
+
"from": "claude-haiku-4-5-20251001",
|
|
40
|
+
"to": "claude-sonnet-5"
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"from": "claude-sonnet-5",
|
|
44
|
+
"to": "claude-opus-5-5"
|
|
45
|
+
}
|
|
46
|
+
],
|
|
47
|
+
"rungs": [
|
|
48
|
+
{
|
|
49
|
+
"rung": 0,
|
|
50
|
+
"maxIterations": 40,
|
|
51
|
+
"reasoningEffort": "medium"
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
"rung": 1,
|
|
55
|
+
"maxIterations": 250,
|
|
56
|
+
"reasoningEffort": "high"
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
"rung": 2,
|
|
60
|
+
"maxIterations": 300,
|
|
61
|
+
"reasoningEffort": "high"
|
|
62
|
+
}
|
|
63
|
+
]
|
|
64
|
+
},
|
|
65
|
+
"highest": {
|
|
66
|
+
"$why": "Skips Haiku. 25 seams resolve here and would waste a rung proving a small model cannot do the work. Same ceiling as high, entered two rungs up.",
|
|
67
|
+
"startModel": "claude-sonnet-5",
|
|
68
|
+
"modelLadder": [
|
|
69
|
+
{
|
|
70
|
+
"from": "claude-sonnet-5",
|
|
71
|
+
"to": "claude-opus-5-5"
|
|
72
|
+
}
|
|
73
|
+
],
|
|
74
|
+
"rungs": [
|
|
75
|
+
{
|
|
76
|
+
"rung": 0,
|
|
77
|
+
"maxIterations": 250,
|
|
78
|
+
"reasoningEffort": "high"
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
"rung": 1,
|
|
82
|
+
"maxIterations": 250,
|
|
83
|
+
"reasoningEffort": "high"
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
"rung": 2,
|
|
87
|
+
"maxIterations": 300,
|
|
88
|
+
"reasoningEffort": "xhigh"
|
|
89
|
+
}
|
|
90
|
+
]
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
"modelOverrides": {
|
|
94
|
+
"$whyAutoCompress": "150000 against a 200000 window is an OVERFLOW GUARD near the ceiling, never a token-saving device: compaction rewrites the prefix and destroys the prompt cache. Measured input is p50 13.3k, p90 19k, max 25.9k — about 13% of the window — so this should never fire. If it does, something has gone wrong upstream and that is worth knowing.",
|
|
95
|
+
"$whyNoTemperature": "codemie-claude exposes no temperature flag and Claude Code has no supported lever for it. Declaring one would be decoration. Deliberation is controlled by reasoningEffort and thinking instead.",
|
|
96
|
+
"$whyAdaptive": "Thinking is held STABLE per model. Anthropic's docs list effort and thinking-parameter changes as cache invalidators, so a config that changes between attempts discards the cache every retry — the opposite of what a 1h TTL is for.",
|
|
97
|
+
"claude-haiku-4-5": {
|
|
98
|
+
"matchOn": "model",
|
|
99
|
+
"matchSubstring": "claude-haiku-4-5",
|
|
100
|
+
"thinking": "adaptive",
|
|
101
|
+
"promptCacheTtl": "1h",
|
|
102
|
+
"autoCompressAt": 150000,
|
|
103
|
+
"maxOutputTokens": 32000,
|
|
104
|
+
"miniTier": true,
|
|
105
|
+
"charsPerToken": 4
|
|
106
|
+
},
|
|
107
|
+
"claude-sonnet-5": {
|
|
108
|
+
"matchOn": "model",
|
|
109
|
+
"matchSubstring": "claude-sonnet-5",
|
|
110
|
+
"thinking": "adaptive",
|
|
111
|
+
"promptCacheTtl": "1h",
|
|
112
|
+
"autoCompressAt": 150000,
|
|
113
|
+
"maxOutputTokens": 64000,
|
|
114
|
+
"charsPerToken": 4
|
|
115
|
+
},
|
|
116
|
+
"claude-opus-5-5": {
|
|
117
|
+
"matchOn": "model",
|
|
118
|
+
"matchSubstring": "claude-opus-5-5",
|
|
119
|
+
"thinking": "adaptive",
|
|
120
|
+
"promptCacheTtl": "1h",
|
|
121
|
+
"autoCompressAt": 150000,
|
|
122
|
+
"maxOutputTokens": 64000,
|
|
123
|
+
"charsPerToken": 4,
|
|
124
|
+
"$why": "Explicit, and BEFORE claude-opus-5: matching is by first substring hit, and 'claude-opus-5' is a substring of 'claude-opus-5-5' — without this entry Opus 5.5 silently took Opus 5's settings. Values as Opus 5; not vendor-checked."
|
|
125
|
+
},
|
|
126
|
+
"claude-opus-4-8": {
|
|
127
|
+
"matchOn": "model",
|
|
128
|
+
"matchSubstring": "claude-opus-4-8",
|
|
129
|
+
"thinking": "adaptive",
|
|
130
|
+
"promptCacheTtl": "1h",
|
|
131
|
+
"autoCompressAt": 150000,
|
|
132
|
+
"maxOutputTokens": 64000,
|
|
133
|
+
"charsPerToken": 4
|
|
134
|
+
},
|
|
135
|
+
"claude-opus-5": {
|
|
136
|
+
"matchOn": "model",
|
|
137
|
+
"matchSubstring": "claude-opus-5",
|
|
138
|
+
"thinking": "adaptive",
|
|
139
|
+
"promptCacheTtl": "1h",
|
|
140
|
+
"autoCompressAt": 150000,
|
|
141
|
+
"maxOutputTokens": 64000,
|
|
142
|
+
"charsPerToken": 4
|
|
143
|
+
},
|
|
144
|
+
"$miniTierWhy": "miniTier marks the cheap, fast rung — the models that are quick but limited in generation capacity. It was decided in engine code by sniffing vendor naming habits (-mini, -flash, -haiku, minimax-m2), which breaks in both directions: a cheap model named differently read as capable, and a capable model containing -flash read as cheap. The set that declares the model declares its tier.",
|
|
145
|
+
"$whyCharsPerToken": "INPUT CAPACITY IN CHARACTERS. autoCompressAt is the models input ceiling in TOKENS; callers that must size a payload measure it in characters. The ratio belongs with the model, because it is a property of that models tokenizer, not of any caller. Declared so a caller derives its budget instead of inventing one: the roster review carried a literal 60000 in code, which split a 276KB roster into six calls and failed the whole review whenever any one of them answered off-schema."
|
|
146
|
+
},
|
|
147
|
+
"finalFallback": {
|
|
148
|
+
"$why": "Applies after ladder exhaustion — the one point where the ladder has nothing left to say. Sonnet-5 differs from the top rung on high and highest, so it is a real second answer rather than a retry of the model that just failed.",
|
|
149
|
+
"model": "claude-sonnet-5",
|
|
150
|
+
"provider": "claude"
|
|
151
|
+
},
|
|
152
|
+
"runners": {
|
|
153
|
+
"claude": {
|
|
154
|
+
"siChannel": {
|
|
155
|
+
"flag": "--append-system-prompt-file"
|
|
156
|
+
},
|
|
157
|
+
"$whySiChannel": "Claude Code's own --append-system-prompt-file (claude --help, 2.1.282): the agent's SI as a system prompt, separate from the task on stdin.",
|
|
158
|
+
"$why": "Plain Claude Code. No CodeMie, no SSO, no spend.",
|
|
159
|
+
"alwaysFlags": [
|
|
160
|
+
"--setting-sources",
|
|
161
|
+
"",
|
|
162
|
+
"--strict-mcp-config",
|
|
163
|
+
"--disable-slash-commands",
|
|
164
|
+
"--settings",
|
|
165
|
+
"{\"includeGitInstructions\":false}"
|
|
166
|
+
],
|
|
167
|
+
"$whyAlwaysFlags": "The agent receives the pipeline's SI and task, nothing of the host — through Claude Code's own interface, each piece by its own switch (proven on 2.1.310, 2026-10-24, with a CLAUDE.md canary in the working folder): --setting-sources \"\" loads no user, project or local settings (so none of the host's hooks, permissions or CLAUDE.md); CLAUDE_CODE_DISABLE_CLAUDE_MDS and CLAUDE_CODE_DISABLE_AUTO_MEMORY (env below) keep the working folder's CLAUDE.md and the host's auto-memory out; --disable-slash-commands drops the skills; includeGitInstructions:false drops the git status; --strict-mcp-config makes the pipeline's MCP server (hostedToolPlugins, lib/pipeline-tools-mcp.js) the ONLY server. --safe-mode did all of this in one switch and ALSO dropped every MCP server, --mcp-config included (proven: the tool was absent), so the pipeline's tools could not be the agent's tools under it. Sign-in survives (the subscription, not an API key); --bare would not.",
|
|
168
|
+
"env": {
|
|
169
|
+
"CLAUDE_CODE_DISABLE_CLAUDE_MDS": "hostClaudeMdOff",
|
|
170
|
+
"CLAUDE_CODE_DISABLE_AUTO_MEMORY": "hostAutoMemoryOff",
|
|
171
|
+
"CLAUDE_CODE_PROMPT_CACHE_TTL": "promptCacheTtl",
|
|
172
|
+
"CLAUDE_CODE_SUBAGENT_PROMPT_CACHE_TTL": "promptCacheTtl"
|
|
173
|
+
},
|
|
174
|
+
"flags": {
|
|
175
|
+
"--effort": "reasoningEffort",
|
|
176
|
+
"--autocompact": "autoCompressAt"
|
|
177
|
+
},
|
|
178
|
+
"$whyFlags": "Checked against the installed CLI's own --help, not assumed: --effort takes (low, medium, high, xhigh, max) and --autocompact takes auto or a token count. These were declared as CLAUDE_CODE_* env vars that the CLI does not document and that nothing exported.",
|
|
179
|
+
"$whyNoTurnCap": "maxIterations is deliberately absent. It binds the ReAct loop in src/agent/AgentRunner.ts, which only the `epam run` arm enters; a --print call has no turn cap and the loop is Claude Code's own. Declaring one here would name a knob nothing can turn.",
|
|
180
|
+
"$whyNoOutputCap": "maxOutputTokens is deliberately unmapped: the installed CLI documents no flag or env for it. It stays declared in modelOverrides so the intent is visible, and is not routed anywhere pretending to work.",
|
|
181
|
+
"$whyNoSilentFlag": "-s is codemie-claude's silent flag and plain `claude` REJECTS it: `echo x | claude -s --print` exits 1 with \"error: unknown option '-s'\". Proven by running it, 2026-08-26, after a --help probe proved nothing (--help and --version short-circuit before option validation, so an invalid flag exits 0 there too). With -s declared, the hub passed it to plain claude, the call failed, and the arm's 2>/dev/null hid the reason — codeline-discovery reported only 'Empty response from ai-run.sh' and the mock3 run aborted with 'codeline scope could not be resolved'. The codemie runner keeps -s: codemie-claude --help documents it as -s, --silent.",
|
|
182
|
+
"unsetEnv": [
|
|
183
|
+
"ANTHROPIC_API_KEY",
|
|
184
|
+
"ANTHROPIC_AUTH_TOKEN"
|
|
185
|
+
],
|
|
186
|
+
"$whyUnsetEnv": "THE SUBSCRIPTION PAYS, AND THAT IS WHY THIS PIPELINE SHELLS OUT TO THE CLI INSTEAD OF THE SDK. Claude Code prefers ANTHROPIC_API_KEY over the OAuth credentials at ~/.claude/.credentials.json. The repo .env declares ANTHROPIC_API_KEY and run-agent-orchestration.sh loads .env, so every run on this stack billed API CREDITS — the exact outcome invoking the CLI was meant to avoid. It surfaced on 2026-08-26 only when the credits ran out mid-run: \"No JSON in LLM response: Credit balance is too low\". Seven runs had already billed the wrong account.\n\nDeclared per RUNNER rather than scrubbed globally: openrouter needs its key, and the free-run guard only scrubs when a run is declared free — a PAID run on this stack had no equivalent because nobody expected the key to be present at all.",
|
|
187
|
+
"emitsTraces": true,
|
|
188
|
+
"toolNames": {
|
|
189
|
+
"read_file": [
|
|
190
|
+
"Read"
|
|
191
|
+
],
|
|
192
|
+
"list_files": [
|
|
193
|
+
"Glob"
|
|
194
|
+
],
|
|
195
|
+
"search": [
|
|
196
|
+
"Grep"
|
|
197
|
+
],
|
|
198
|
+
"fetch_url": [
|
|
199
|
+
"WebFetch"
|
|
200
|
+
],
|
|
201
|
+
"bash": [
|
|
202
|
+
"Bash"
|
|
203
|
+
],
|
|
204
|
+
"write_file": [
|
|
205
|
+
"Write",
|
|
206
|
+
"Edit"
|
|
207
|
+
]
|
|
208
|
+
},
|
|
209
|
+
"$whyToolNames": "A SEAM'S TOOL GRANT IS BOUND AT THE RUNNER, LIKE ITS SCHEMA AND ITS BUDGET. Every seam declares a grant kind (none, read-only, execute, write-file...) and it travels as EPAM_ALLOWED_TOOLS; that variable was read in ONE place, src/agent/AgentRunner.ts on the `epam run` arm, so on this runner it bound NOTHING and every seam ran `--print --dangerously-skip-permissions` with the CLI's whole tool set. Run 20260916T225207Z (skyscanner): project-roster-review, declared read-only, ran `find / -iname prd.json` and read five earlier runs' cassettes out of the pipeline repo, then refused the roster for disagreeing with them. The 2026-09-12 roster specialiser, declared write-file, spent ~350 shell calls copying a repository. This map is the runner's own vocabulary for the pipeline's tool names (`claude --help`: --tools takes built-in tool names; \"\" disables all). llm-handler.sh translates the grant through it and passes --tools when the installed CLI advertises the flag. A pipeline tool with no entry here does not exist on this runner and is dropped from the list, said aloud on stderr. A seam with NO grant (kind none) is passed nothing and keeps the CLI's default set: --tools \"\" may also remove the StructuredOutput tool --json-schema requires, and that has not been proven either way, so it is not done blind.",
|
|
210
|
+
"$emitsTraces": "Whether model calls made through this runner reach Langfuse. TRUE for every runner: traces are emitted by lib/cost-emitter.js at the cost seam — the point every arm passes through with its model, tokens, cost and timing resolved — not by the TypeScript provider decorator, which only the epam arm reaches. Verified end-to-end 2026-09-04 by driving the real emitter and reading the session back out of Langfuse.",
|
|
211
|
+
"$whyEnv": "Each name is a top-level setting of this stack (hostClaudeMdOff, hostAutoMemoryOff, promptCacheTtl), resolved by lib/llm-settings-resolve.js runnerValues and exported for the CLI; an operator overrides one with EPAM_RUNNER_VALUE_<name>. The cache TTL: Claude Code's subagent and workflow calls default to a 5-minute prompt cache; the pipeline's calls repeat the same SI and context for an hour or more, so the documented 1h TTL is declared for both (docs: prompt-caching).",
|
|
212
|
+
"hostedToolPlugins": [
|
|
213
|
+
"plugins/codegraph-plugin.js",
|
|
214
|
+
"plugins/codeline-context-plugin.js",
|
|
215
|
+
"plugins/dependency-contract-plugin.js",
|
|
216
|
+
"plugins/dependency-scan-plugin.js",
|
|
217
|
+
"plugins/secret-scan-plugin.js",
|
|
218
|
+
"plugins/verification-plugin.js"
|
|
219
|
+
],
|
|
220
|
+
"mcpServer": "pipeline",
|
|
221
|
+
"$whyHostedToolPlugins": "The pipeline's own tool plugins — the same modules the codemie-web runner hosts — served to this runner's agents as Claude Code tools over MCP (lib/pipeline-tools-mcp.js; the hub passes --mcp-config). Before this an agent on this runner reached codegraph, the search and the package-symbol resolver only as shell scripts through Bash: a read-only seam could not call them at all, and plan mode denies such Bash calls. A 'safe' plugin tool is annotated read-only, which is what lets plan mode run it.",
|
|
222
|
+
"planModeChannel": {
|
|
223
|
+
"modeFlag": "--permission-mode",
|
|
224
|
+
"planValue": "plan",
|
|
225
|
+
"sessionFlag": "--session-id",
|
|
226
|
+
"resumeFlag": "--resume"
|
|
227
|
+
},
|
|
228
|
+
"$whyPlanModeChannel": "How a plan pass is made on this runner (llm-handler.sh; lib/plan-mode.js decides WHETHER a seam plans): Claude Code's own plan mode. Proven on 2.1.310 (2026-10-24): `--permission-mode plan` under --print returns the plan as the result and writes nothing — the agent may read, search and call read-only tools, so the plan is grounded; the answer is then made in the same session with `--resume <session-id>` and the ordinary permissions. A runner that declares no channel gets the hub's prose pass (the plan written with no tools)."
|
|
229
|
+
}
|
|
230
|
+
},
|
|
231
|
+
"$why": "Built from the mockserver set by REMOVING the redirect, because that set was already a plain-`claude` stack pointed at localhost — same ladders, same budgets, same runner. Its header records the proof: plain `claude` honours ANTHROPIC_BASE_URL, reaches the endpoint it is given, and parses the SSE served back (is_error:false, RC=0). Taking the endpoint away is the whole difference between rehearsing and running.",
|
|
232
|
+
"hostClaudeMdOff": "1",
|
|
233
|
+
"hostAutoMemoryOff": "1",
|
|
234
|
+
"promptCacheTtl": "1h",
|
|
235
|
+
"$whyHostContextOff": "Values for the claude runner's env declaration (see runners.claude.$whyEnv): the host's CLAUDE.md and auto-memory stay out of every agent call; the prompt cache lives 1h."
|
|
236
|
+
}
|
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$comment": "THE MOCKSERVER PROVIDER SET — the CodeMie stack, answered by MockServer instead of a model. Same ladders and same budgets, so a rehearsal exercises the chain a paid run would climb; only the ENDPOINT differs.",
|
|
3
|
+
"$proven": "2026-08-25: plain `claude` honours ANTHROPIC_BASE_URL, reaches MockServer (POST /v1/messages in its request log) and PARSES the SSE it serves — is_error:false, result:'OK', stop_reason:'end_turn', RC=0.",
|
|
4
|
+
"$whyNotTheWrapper": "This runs PLAIN `claude`, not codemie-claude. The wrapper's --base-url selects an SSO PROFILE rather than redirecting, and fails with 'SSO credentials not found' for any URL it has no credentials for. A mocked run must authenticate against NOTHING, so it bypasses the wrapper entirely.",
|
|
5
|
+
"$whyTheSameLadders": "Deliberately identical to the codemie set. A rehearsal on different models proves the harness, not the run. Sharing the ladder means a mocked run climbs the chain a paid run would.",
|
|
6
|
+
"ladderTierOrder": [
|
|
7
|
+
"medium",
|
|
8
|
+
"high",
|
|
9
|
+
"highest"
|
|
10
|
+
],
|
|
11
|
+
"ladders": {
|
|
12
|
+
"medium": {
|
|
13
|
+
"$why": "Enters cheap and tops out at Sonnet-5. A `mid` seam never reaches Opus: 14 seams resolve here, and measured turn counts are p50 4, p90 24 — work that does not need a frontier model.",
|
|
14
|
+
"startModel": "claude-haiku-4-5-20251001",
|
|
15
|
+
"modelLadder": [
|
|
16
|
+
{
|
|
17
|
+
"from": "claude-haiku-4-5-20251001",
|
|
18
|
+
"to": "claude-sonnet-5"
|
|
19
|
+
}
|
|
20
|
+
],
|
|
21
|
+
"rungs": [
|
|
22
|
+
{
|
|
23
|
+
"rung": 0,
|
|
24
|
+
"maxIterations": 40,
|
|
25
|
+
"reasoningEffort": "medium"
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"rung": 1,
|
|
29
|
+
"maxIterations": 120,
|
|
30
|
+
"reasoningEffort": "high"
|
|
31
|
+
}
|
|
32
|
+
]
|
|
33
|
+
},
|
|
34
|
+
"high": {
|
|
35
|
+
"$why": "Same ENTRY as medium, higher CEILING. That is the 'different entry, same ceiling' rule applied between high and highest: what separates the tiers is how far they may climb, not where they start.",
|
|
36
|
+
"startModel": "claude-haiku-4-5-20251001",
|
|
37
|
+
"modelLadder": [
|
|
38
|
+
{
|
|
39
|
+
"from": "claude-haiku-4-5-20251001",
|
|
40
|
+
"to": "claude-sonnet-5"
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"from": "claude-sonnet-5",
|
|
44
|
+
"to": "claude-opus-5"
|
|
45
|
+
}
|
|
46
|
+
],
|
|
47
|
+
"rungs": [
|
|
48
|
+
{
|
|
49
|
+
"rung": 0,
|
|
50
|
+
"maxIterations": 40,
|
|
51
|
+
"reasoningEffort": "medium"
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
"rung": 1,
|
|
55
|
+
"maxIterations": 250,
|
|
56
|
+
"reasoningEffort": "high"
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
"rung": 2,
|
|
60
|
+
"maxIterations": 300,
|
|
61
|
+
"reasoningEffort": "high"
|
|
62
|
+
}
|
|
63
|
+
]
|
|
64
|
+
},
|
|
65
|
+
"highest": {
|
|
66
|
+
"$why": "Skips Haiku. 25 seams resolve here and would waste a rung proving a small model cannot do the work. Same ceiling as high, entered two rungs up.",
|
|
67
|
+
"startModel": "claude-sonnet-5",
|
|
68
|
+
"modelLadder": [
|
|
69
|
+
{
|
|
70
|
+
"from": "claude-sonnet-5",
|
|
71
|
+
"to": "claude-opus-4-8"
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
"from": "claude-opus-4-8",
|
|
75
|
+
"to": "claude-opus-5"
|
|
76
|
+
}
|
|
77
|
+
],
|
|
78
|
+
"rungs": [
|
|
79
|
+
{
|
|
80
|
+
"rung": 0,
|
|
81
|
+
"maxIterations": 250,
|
|
82
|
+
"reasoningEffort": "high"
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
"rung": 1,
|
|
86
|
+
"maxIterations": 250,
|
|
87
|
+
"reasoningEffort": "high"
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
"rung": 2,
|
|
91
|
+
"maxIterations": 300,
|
|
92
|
+
"reasoningEffort": "xhigh"
|
|
93
|
+
}
|
|
94
|
+
]
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
"modelOverrides": {
|
|
98
|
+
"$whyAutoCompress": "150000 against a 200000 window is an OVERFLOW GUARD near the ceiling, never a token-saving device: compaction rewrites the prefix and destroys the prompt cache. Measured input is p50 13.3k, p90 19k, max 25.9k — about 13% of the window — so this should never fire. If it does, something has gone wrong upstream and that is worth knowing.",
|
|
99
|
+
"$whyNoTemperature": "codemie-claude exposes no temperature flag and Claude Code has no supported lever for it. Declaring one would be decoration. Deliberation is controlled by reasoningEffort and thinking instead.",
|
|
100
|
+
"$whyAdaptive": "Thinking is held STABLE per model. Anthropic's docs list effort and thinking-parameter changes as cache invalidators, so a config that changes between attempts discards the cache every retry — the opposite of what a 1h TTL is for.",
|
|
101
|
+
"claude-haiku-4-5": {
|
|
102
|
+
"matchOn": "model",
|
|
103
|
+
"matchSubstring": "claude-haiku-4-5",
|
|
104
|
+
"thinking": "adaptive",
|
|
105
|
+
"promptCacheTtl": "1h",
|
|
106
|
+
"autoCompressAt": 150000,
|
|
107
|
+
"maxOutputTokens": 32000,
|
|
108
|
+
"miniTier": true,
|
|
109
|
+
"charsPerToken": 4
|
|
110
|
+
},
|
|
111
|
+
"claude-sonnet-5": {
|
|
112
|
+
"matchOn": "model",
|
|
113
|
+
"matchSubstring": "claude-sonnet-5",
|
|
114
|
+
"thinking": "adaptive",
|
|
115
|
+
"promptCacheTtl": "1h",
|
|
116
|
+
"autoCompressAt": 150000,
|
|
117
|
+
"maxOutputTokens": 64000,
|
|
118
|
+
"charsPerToken": 4
|
|
119
|
+
},
|
|
120
|
+
"claude-opus-4-8": {
|
|
121
|
+
"matchOn": "model",
|
|
122
|
+
"matchSubstring": "claude-opus-4-8",
|
|
123
|
+
"thinking": "adaptive",
|
|
124
|
+
"promptCacheTtl": "1h",
|
|
125
|
+
"autoCompressAt": 150000,
|
|
126
|
+
"maxOutputTokens": 64000,
|
|
127
|
+
"charsPerToken": 4
|
|
128
|
+
},
|
|
129
|
+
"claude-opus-5": {
|
|
130
|
+
"matchOn": "model",
|
|
131
|
+
"matchSubstring": "claude-opus-5",
|
|
132
|
+
"thinking": "adaptive",
|
|
133
|
+
"promptCacheTtl": "1h",
|
|
134
|
+
"autoCompressAt": 150000,
|
|
135
|
+
"maxOutputTokens": 64000,
|
|
136
|
+
"charsPerToken": 4
|
|
137
|
+
},
|
|
138
|
+
"$miniTierWhy": "miniTier marks the cheap, fast rung — the models that are quick but limited in generation capacity. It was decided in engine code by sniffing vendor naming habits (-mini, -flash, -haiku, minimax-m2), which breaks in both directions: a cheap model named differently read as capable, and a capable model containing -flash read as cheap. The set that declares the model declares its tier.",
|
|
139
|
+
"$whyCharsPerToken": "INPUT CAPACITY IN CHARACTERS. autoCompressAt is the models input ceiling in TOKENS; callers that must size a payload measure it in characters. The ratio belongs with the model, because it is a property of that models tokenizer, not of any caller. Declared so a caller derives its budget instead of inventing one: the roster review carried a literal 60000 in code, which split a 276KB roster into six calls and failed the whole review whenever any one of them answered off-schema."
|
|
140
|
+
},
|
|
141
|
+
"finalFallback": {
|
|
142
|
+
"$why": "Applies after ladder exhaustion. The PROVIDER is plain `claude`, not codemie-claude, matching every other call this set makes — see $whyNotTheWrapper. That is CORRECT, not a paid escape: this set never talks to real Anthropic. runners.claude below declares ANTHROPIC_BASE_URL redirecting to MockServer and unsetEnv scrubbing every other vendor's credentials, and that redirect applies to every call routed under this set's own provider:\"claude\", finalFallback included — it never has a real endpoint to reach. Mockserver is a mock-LLM, no-pay testing mechanism by construction, not merely by convention (change-log/SEAM-CONSISTENCY-ANALYSIS.md Section 6, corrected 2026-09-03: the prior wording here mischaracterized this as an unresolved paid-escape risk).",
|
|
143
|
+
"$whyNotYetLive": "As of this writing, nothing in the runtime ladder-exhaustion path (llm-handler.sh, claude.sh, brownfield-repro-test-writer.sh) reads finalFallback — exhaustion retries the same rung instead. agent-check.js's dry-run cost estimator is the only reader, and even there this is unreachable while any ladder tier has a startModel (all of them do). Declared for correctness and for whenever that wiring exists.",
|
|
144
|
+
"model": "claude-sonnet-5",
|
|
145
|
+
"provider": "claude"
|
|
146
|
+
},
|
|
147
|
+
"runners": {
|
|
148
|
+
"claude": {
|
|
149
|
+
"siChannel": {
|
|
150
|
+
"flag": "--append-system-prompt-file"
|
|
151
|
+
},
|
|
152
|
+
"$whySiChannel": "Claude Code's own --append-system-prompt-file (claude --help, 2.1.282): the agent's SI as a system prompt, separate from the task on stdin.",
|
|
153
|
+
"$why": "Plain Claude Code. No CodeMie, no SSO, no spend.",
|
|
154
|
+
"$whyNoBaseUrlFlag": "--base-url is ABSENT on purpose: on the wrapper it means 'use this SSO profile'. The redirect is ANTHROPIC_BASE_URL, which plain claude honours.",
|
|
155
|
+
"alwaysFlags": [
|
|
156
|
+
"--setting-sources",
|
|
157
|
+
"",
|
|
158
|
+
"--strict-mcp-config",
|
|
159
|
+
"--disable-slash-commands",
|
|
160
|
+
"--settings",
|
|
161
|
+
"{\"includeGitInstructions\":false}"
|
|
162
|
+
],
|
|
163
|
+
"$whyAlwaysFlags": "The agent receives the pipeline's SI and task, nothing of the host — through Claude Code's own interface, each piece by its own switch (proven on 2.1.310, 2026-10-24, with a CLAUDE.md canary in the working folder): --setting-sources \"\" loads no user, project or local settings (so none of the host's hooks, permissions or CLAUDE.md); CLAUDE_CODE_DISABLE_CLAUDE_MDS and CLAUDE_CODE_DISABLE_AUTO_MEMORY (env below) keep the working folder's CLAUDE.md and the host's auto-memory out; --disable-slash-commands drops the skills; includeGitInstructions:false drops the git status; --strict-mcp-config makes the pipeline's MCP server (hostedToolPlugins, lib/pipeline-tools-mcp.js) the ONLY server. --safe-mode did all of this in one switch and ALSO dropped every MCP server, --mcp-config included (proven: the tool was absent), so the pipeline's tools could not be the agent's tools under it. Sign-in survives (the subscription, not an API key); --bare would not.",
|
|
164
|
+
"env": {
|
|
165
|
+
"ANTHROPIC_BASE_URL": "mockBaseUrl",
|
|
166
|
+
"CLAUDE_CODE_DISABLE_CLAUDE_MDS": "hostClaudeMdOff",
|
|
167
|
+
"CLAUDE_CODE_DISABLE_AUTO_MEMORY": "hostAutoMemoryOff",
|
|
168
|
+
"CLAUDE_CODE_PROMPT_CACHE_TTL": "promptCacheTtl",
|
|
169
|
+
"CLAUDE_CODE_SUBAGENT_PROMPT_CACHE_TTL": "promptCacheTtl"
|
|
170
|
+
},
|
|
171
|
+
"flags": {
|
|
172
|
+
"--effort": "reasoningEffort",
|
|
173
|
+
"--autocompact": "autoCompressAt"
|
|
174
|
+
},
|
|
175
|
+
"$whyFlags": "Checked against the installed CLI's own --help, not assumed: --effort takes (low, medium, high, xhigh, max) and --autocompact takes auto or a token count. These were declared as CLAUDE_CODE_* env vars that the CLI does not document and that nothing exported.",
|
|
176
|
+
"$whyNoTurnCap": "maxIterations is deliberately absent. It binds the ReAct loop in src/agent/AgentRunner.ts, which only the `epam run` arm enters; a --print call has no turn cap and the loop is Claude Code's own. Declaring one here would name a knob nothing can turn.",
|
|
177
|
+
"$whyNoOutputCap": "maxOutputTokens is deliberately unmapped: the installed CLI documents no flag or env for it. It stays declared in modelOverrides so the intent is visible, and is not routed anywhere pretending to work.",
|
|
178
|
+
"$whyEnvKept": "ANTHROPIC_BASE_URL is a real, load-bearing env var: it is the mock redirect. It was declared here and never exported, so a free run would have looked redirected and reached the paid endpoint.",
|
|
179
|
+
"$whyNoSilentFlag": "-s is codemie-claude's silent flag and plain `claude` REJECTS it: `echo x | claude -s --print` exits 1 with \"error: unknown option '-s'\". Proven by running it, 2026-08-26, after a --help probe proved nothing (--help and --version short-circuit before option validation, so an invalid flag exits 0 there too). With -s declared, the hub passed it to plain claude, the call failed, and the arm's 2>/dev/null hid the reason — codeline-discovery reported only 'Empty response from ai-run.sh' and the mock3 run aborted with 'codeline scope could not be resolved'. The codemie runner keeps -s: codemie-claude --help documents it as -s, --silent.",
|
|
180
|
+
"unsetEnv": [
|
|
181
|
+
"CODEMIE_API_KEY",
|
|
182
|
+
"CODEMIE_AUTH_TOKEN",
|
|
183
|
+
"CODEMIE_KEY",
|
|
184
|
+
"CODEMIE_TOKEN",
|
|
185
|
+
"COPILOT_API_KEY",
|
|
186
|
+
"COPILOT_AUTH_TOKEN",
|
|
187
|
+
"COPILOT_KEY",
|
|
188
|
+
"COPILOT_TOKEN",
|
|
189
|
+
"CURSOR_API_KEY",
|
|
190
|
+
"CURSOR_AUTH_TOKEN",
|
|
191
|
+
"CURSOR_KEY",
|
|
192
|
+
"CURSOR_TOKEN",
|
|
193
|
+
"DASHSCOPE_API_KEY",
|
|
194
|
+
"DASHSCOPE_AUTH_TOKEN",
|
|
195
|
+
"DASHSCOPE_KEY",
|
|
196
|
+
"DASHSCOPE_TOKEN",
|
|
197
|
+
"EPAM_API_KEY_ANTHROPIC",
|
|
198
|
+
"EPAM_API_KEY_CLAUDE",
|
|
199
|
+
"EPAM_API_KEY_CODEMIE",
|
|
200
|
+
"EPAM_API_KEY_COPILOT",
|
|
201
|
+
"EPAM_API_KEY_CURSOR",
|
|
202
|
+
"EPAM_API_KEY_DASHSCOPE",
|
|
203
|
+
"EPAM_API_KEY_GEMINI",
|
|
204
|
+
"EPAM_API_KEY_MINIMAX",
|
|
205
|
+
"EPAM_API_KEY_OPENAI",
|
|
206
|
+
"EPAM_API_KEY_OPENROUTER",
|
|
207
|
+
"GEMINI_API_KEY",
|
|
208
|
+
"GEMINI_AUTH_TOKEN",
|
|
209
|
+
"GEMINI_KEY",
|
|
210
|
+
"GEMINI_TOKEN",
|
|
211
|
+
"MINIMAX_API_KEY",
|
|
212
|
+
"MINIMAX_AUTH_TOKEN",
|
|
213
|
+
"MINIMAX_KEY",
|
|
214
|
+
"MINIMAX_TOKEN",
|
|
215
|
+
"OPENAI_API_KEY",
|
|
216
|
+
"OPENAI_AUTH_TOKEN",
|
|
217
|
+
"OPENAI_KEY",
|
|
218
|
+
"OPENAI_TOKEN",
|
|
219
|
+
"OPENROUTER_API_KEY",
|
|
220
|
+
"OPENROUTER_AUTH_TOKEN",
|
|
221
|
+
"OPENROUTER_KEY",
|
|
222
|
+
"OPENROUTER_TOKEN"
|
|
223
|
+
],
|
|
224
|
+
"$whyUnsetEnv": "A REHEARSAL MUST NOT BE ABLE TO SPEND SOMEWHERE ELSE. Under this set the writer once ran provider=minimax with MINIMAX_API_KEY present: the mockBaseUrl redirect covers Anthropic traffic and nothing else, so any other vendor's credential is a live route out. Those are removed. ANTHROPIC_API_KEY and CLAUDE_* are deliberately NOT removed: Claude Code falls back to the OAuth credentials on disk when it finds no key, and that bills for real — the exact inversion this is meant to prevent, recorded in seam-the-subscription-pays-not-the-api-key. The operator's fake key stays, and the redirect is what makes it harmless. The vendors come from llm-channel.json's credentialPattern, so one added there is covered without editing this.",
|
|
225
|
+
"emitsTraces": true,
|
|
226
|
+
"$emitsTraces": "Whether model calls made through this runner reach Langfuse. TRUE for every runner: traces are emitted by lib/cost-emitter.js at the cost seam — the point every arm passes through with its model, tokens, cost and timing resolved — not by the TypeScript provider decorator, which only the epam arm reaches. Verified end-to-end 2026-09-04 by driving the real emitter and reading the session back out of Langfuse.",
|
|
227
|
+
"toolNames": {
|
|
228
|
+
"read_file": [
|
|
229
|
+
"Read"
|
|
230
|
+
],
|
|
231
|
+
"list_files": [
|
|
232
|
+
"Glob"
|
|
233
|
+
],
|
|
234
|
+
"search": [
|
|
235
|
+
"Grep"
|
|
236
|
+
],
|
|
237
|
+
"fetch_url": [
|
|
238
|
+
"WebFetch"
|
|
239
|
+
],
|
|
240
|
+
"bash": [
|
|
241
|
+
"Bash"
|
|
242
|
+
],
|
|
243
|
+
"write_file": [
|
|
244
|
+
"Write",
|
|
245
|
+
"Edit"
|
|
246
|
+
]
|
|
247
|
+
},
|
|
248
|
+
"$whyToolNames": "A SEAM'S TOOL GRANT IS BOUND AT THE RUNNER, LIKE ITS SCHEMA AND ITS BUDGET. Every seam declares a grant kind (none, read-only, execute, write-file...) and it travels as EPAM_ALLOWED_TOOLS; that variable was read in ONE place, src/agent/AgentRunner.ts on the `epam run` arm, so on this runner it bound NOTHING and every seam ran `--print --dangerously-skip-permissions` with the CLI's whole tool set. Run 20260916T225207Z (skyscanner): project-roster-review, declared read-only, ran `find / -iname prd.json` and read five earlier runs' cassettes out of the pipeline repo, then refused the roster for disagreeing with them. The 2026-09-12 roster specialiser, declared write-file, spent ~350 shell calls copying a repository. This map is the runner's own vocabulary for the pipeline's tool names (`claude --help`: --tools takes built-in tool names; \"\" disables all). llm-handler.sh translates the grant through it and passes --tools when the installed CLI advertises the flag. A pipeline tool with no entry here does not exist on this runner and is dropped from the list, said aloud on stderr. A seam with NO grant (kind none) is passed nothing and keeps the CLI's default set: --tools \"\" may also remove the StructuredOutput tool --json-schema requires, and that has not been proven either way, so it is not done blind.",
|
|
249
|
+
"writeTool": {
|
|
250
|
+
"name": "Write",
|
|
251
|
+
"path": "file_path",
|
|
252
|
+
"content": "content"
|
|
253
|
+
},
|
|
254
|
+
"$whyWriteTool": "The rehearsal's stand-in writer delivers by calling the runner's own file-writing tool, and this is that tool's vocabulary for plain Claude Code (recorded sessions: 'Write' {file_path, content}). Declared here so the harness never spells a tool name.",
|
|
255
|
+
"readTool": {
|
|
256
|
+
"name": "Read",
|
|
257
|
+
"path": "file_path"
|
|
258
|
+
},
|
|
259
|
+
"$whyReadTool": "Plain Claude Code's Write refuses a file the session has not read ('File has not been read yet. Read it first before writing to it.', £0 brownfield harness run 10, 2026-09-14): a brownfield story's deliverables exist, so the stand-in writer reads each existing one through this tool before it writes, as a model does. Declared beside writeTool so the harness never spells this name either.",
|
|
260
|
+
"structuredOutputTool": "StructuredOutput",
|
|
261
|
+
"$whyStructuredOutputTool": "Under --json-schema plain Claude Code declares a tool of this name and REQUIRES the reply to call it ('[structured-output-enforce] You MUST call the StructuredOutput tool', recorded 2026-09-14); a text reply costs a second, enforcement turn per seam and never exercises the runner's structured-output path — the one a real model takes. The rehearsal answers a request that declares this tool by calling it with the seam's stand-in payload.",
|
|
262
|
+
"$whyEnv": "Each name is a top-level setting of this stack (hostClaudeMdOff, hostAutoMemoryOff, promptCacheTtl), resolved by lib/llm-settings-resolve.js runnerValues and exported for the CLI; an operator overrides one with EPAM_RUNNER_VALUE_<name>. The cache TTL: Claude Code's subagent and workflow calls default to a 5-minute prompt cache; the pipeline's calls repeat the same SI and context for an hour or more, so the documented 1h TTL is declared for both (docs: prompt-caching).",
|
|
263
|
+
"hostedToolPlugins": [
|
|
264
|
+
"plugins/codegraph-plugin.js",
|
|
265
|
+
"plugins/codeline-context-plugin.js",
|
|
266
|
+
"plugins/dependency-contract-plugin.js",
|
|
267
|
+
"plugins/dependency-scan-plugin.js",
|
|
268
|
+
"plugins/secret-scan-plugin.js",
|
|
269
|
+
"plugins/verification-plugin.js"
|
|
270
|
+
],
|
|
271
|
+
"mcpServer": "pipeline",
|
|
272
|
+
"$whyHostedToolPlugins": "The pipeline's own tool plugins — the same modules the codemie-web runner hosts — served to this runner's agents as Claude Code tools over MCP (lib/pipeline-tools-mcp.js; the hub passes --mcp-config). Before this an agent on this runner reached codegraph, the search and the package-symbol resolver only as shell scripts through Bash: a read-only seam could not call them at all, and plan mode denies such Bash calls. A 'safe' plugin tool is annotated read-only, which is what lets plan mode run it.",
|
|
273
|
+
"planModeChannel": {
|
|
274
|
+
"modeFlag": "--permission-mode",
|
|
275
|
+
"planValue": "plan",
|
|
276
|
+
"sessionFlag": "--session-id",
|
|
277
|
+
"resumeFlag": "--resume"
|
|
278
|
+
},
|
|
279
|
+
"$whyPlanModeChannel": "How a plan pass is made on this runner (llm-handler.sh; lib/plan-mode.js decides WHETHER a seam plans): Claude Code's own plan mode. Proven on 2.1.310 (2026-10-24): `--permission-mode plan` under --print returns the plan as the result and writes nothing — the agent may read, search and call read-only tools, so the plan is grounded; the answer is then made in the same session with `--resume <session-id>` and the ordinary permissions. A runner that declares no channel gets the hub's prose pass (the plan written with no tools)."
|
|
280
|
+
}
|
|
281
|
+
},
|
|
282
|
+
"mockBaseUrl": "http://localhost:1080",
|
|
283
|
+
"$mockBaseUrl": "Where MockServer listens. Declared here so no script spells it — the same rule every other value in this layer follows.",
|
|
284
|
+
"rehearsal": true,
|
|
285
|
+
"$rehearsalWhy": "A run on this set spends nothing and answers from recordings and stand-ins. Every recorder stamps its traces rehearsal:true (lib/langfuse-emit.js), and the mock loader never replays a rehearsal's own traces as captures — on 2026-09-13 a stand-in reply recorded by one rehearsal was served to the next as a 'recorded' turn, and the roster stage failed on its own echo three launches running.",
|
|
286
|
+
"wire": {
|
|
287
|
+
"$comment": "HOW THE STAND-IN PUTS A TOOL CALL ON THE WIRE. A vendor streams a tool call as many `function.arguments` (or `input_json_delta`) fragments, and the body reaches the client in HTTP chunks that end wherever the socket ends them — inside an event as often as not. Until 2026-09-15 the stand-in served every call whole, in one read: a shape no vendor sends and the one shape the client's stream parser could never fail on. Run 20260915T101555Z lost 32 write_file calls' arguments to exactly that parser ($4.18, nothing delivered) while every harness cell was green. argumentDeltaChars is the fragment size; chunkBytes is the HTTP chunk size. Both are deliberately unaligned with any event length so boundaries fall inside events.",
|
|
288
|
+
"argumentDeltaChars": 97,
|
|
289
|
+
"chunkBytes": 333
|
|
290
|
+
},
|
|
291
|
+
"hostClaudeMdOff": "1",
|
|
292
|
+
"hostAutoMemoryOff": "1",
|
|
293
|
+
"promptCacheTtl": "1h",
|
|
294
|
+
"$whyHostContextOff": "Values for the claude runner's env declaration (see runners.claude.$whyEnv): the host's CLAUDE.md and auto-memory stay out of every agent call; the prompt cache lives 1h."
|
|
295
|
+
}
|