mirror of
https://github.com/codewhale-hq/Codewhale.git
synced 2026-11-08 08:04:25 -10:00
fix(shell): expect a foreground timeout to keep running
A command still running after its foreground wait moves to the background
and is not killed. The completion hooks were still expecting the old
timed_out failure, which is what Test (ubuntu-latest) failed on 804c63159:
left "call-timeout unset running true", right "call-timeout unset timed_out
false". The after-hook now expects running, and on_error no longer fires
for that case because the result is a success. Nonzero exits stay failures.
The shell description that says this grew every tool surface by 564 schema
bytes and 141 estimated tokens. No tool entered or left a surface. The
runtime-contract ceiling records that growth.
cargo test -p codewhale-tui --lib -- runtime_shell_completion_delivers_exit_code_and_status_to_hooks bash_completion_hooks_get_exit_code_and_status_for_failures:
2 passed, 0 failed. python3 scripts/check-runtime-contract-budget.py:
PASS, all 55 metrics exactly at budget.
This commit is contained in:
1 parent
804c631597
commit
327ad28623
3 files changed
+25
-28
No files matched your search
@@ -22051,9 +22051,9 @@ async fn a_pending_turn_workspace_is_reconciled_on_restart() -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
/// #6582: a Runtime API `bash` completion hands the command's exit code and
|
||||
/// status to `tool_call_after` and `on_error`, as the TUI does. The runtime
|
||||
/// path used to pass `None`; and a failing command, which `bash` reports as a
|
||||
/// `ToolError`, reached hooks with no exit code on either surface.
|
||||
/// status to `tool_call_after` and `on_error`, as the TUI does. A nonzero
|
||||
/// exit is a `ToolError`. A foreground wait that expires is not: the command
|
||||
/// moves to the background and stays running, so `on_error` does not fire.
|
||||
#[cfg(unix)]
|
||||
#[tokio::test]
|
||||
async fn runtime_shell_completion_delivers_exit_code_and_status_to_hooks() -> Result<()> {
|
||||
@@ -22121,7 +22121,7 @@ async fn runtime_shell_completion_delivers_exit_code_and_status_to_hooks() -> Re
|
||||
let (after, errors) = loop {
|
||||
let after = read_lines(&after_log);
|
||||
let errors = read_lines(&error_log);
|
||||
if (after.len() >= 4 && errors.len() >= 3) || Instant::now() >= deadline {
|
||||
if (after.len() >= 4 && errors.len() >= 2) || Instant::now() >= deadline {
|
||||
break (after, errors);
|
||||
}
|
||||
sleep(Duration::from_millis(20)).await;
|
||||
@@ -22132,7 +22132,7 @@ async fn runtime_shell_completion_delivers_exit_code_and_status_to_hooks() -> Re
|
||||
"call-exit-0 0 completed true",
|
||||
"call-exit-1 1 failed false",
|
||||
"call-exit-127 127 failed false",
|
||||
"call-timeout unset timed_out false",
|
||||
"call-timeout unset running true",
|
||||
]
|
||||
);
|
||||
assert_eq!(
|
||||
@@ -22140,7 +22140,6 @@ async fn runtime_shell_completion_delivers_exit_code_and_status_to_hooks() -> Re
|
||||
vec![
|
||||
"call-exit-1 1 failed false",
|
||||
"call-exit-127 127 failed false",
|
||||
"call-timeout unset timed_out false",
|
||||
]
|
||||
);
|
||||
Ok(())
|
||||
|
||||
@@ -2497,10 +2497,9 @@ mod tests {
|
||||
}
|
||||
|
||||
/// #6582: hooks see a `bash` command's real exit code and status, for a
|
||||
/// failing command as well as a passing one. `bash` reports a nonzero
|
||||
/// exit or a timeout as a `ToolError`, and the hook used to read the code
|
||||
/// only from a successful result, so every failing command reached
|
||||
/// `tool_call_after` and `on_error` with no exit code.
|
||||
/// failing command as well as a passing one. A nonzero exit is a
|
||||
/// `ToolError`. A foreground wait that expires is not: the command moves
|
||||
/// to the background and stays running, so `on_error` does not fire for it.
|
||||
#[cfg(unix)]
|
||||
#[test]
|
||||
fn bash_completion_hooks_get_exit_code_and_status_for_failures() {
|
||||
@@ -2553,7 +2552,7 @@ mod tests {
|
||||
}
|
||||
|
||||
let mut after = hook_log_lines_eventually(&after_log, 4);
|
||||
let mut errors = hook_log_lines_eventually(&error_log, 3);
|
||||
let mut errors = hook_log_lines_eventually(&error_log, 2);
|
||||
after.sort();
|
||||
errors.sort();
|
||||
assert_eq!(
|
||||
@@ -2562,7 +2561,7 @@ mod tests {
|
||||
"call-exit-0 0 completed true",
|
||||
"call-exit-1 1 failed false",
|
||||
"call-exit-127 127 failed false",
|
||||
"call-timeout unset timed_out false",
|
||||
"call-timeout unset running true",
|
||||
]
|
||||
);
|
||||
assert_eq!(
|
||||
@@ -2570,7 +2569,6 @@ mod tests {
|
||||
vec![
|
||||
"call-exit-1 1 failed false",
|
||||
"call-exit-127 127 failed false",
|
||||
"call-timeout unset timed_out false",
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
{
|
||||
"_comment": "One-way numeric ceilings and exact structural identities for the provider-free runtime contract. Decreases pass; increases or identity changes fail. Lock in decreases with: python3 scripts/check-runtime-contract-budget.py --update The v0.9.8 child-receipt restore grew every production tool surface by 1496 schema bytes / 374 estimated tokens (agent tool). The v0.9.8 workshop read/tool-result byte fields then grew every production tool surface by 371 schema bytes / 93 estimated tokens. Both raises are explicit maintainer decisions; identities stay on the pre-raise digests only if the name set is unchanged \u2014 re-measure on Linux CI if Lint reports identity drift. The v0.9.8 pinned session prefix added the <context_update> sentence to the base prompt (5848 -> 6084 bytes, every representative stage re-hashed), and the host-side Workflow/Goal verbs plus honest child posture grew the tool catalog (active 16531 -> 16602 bytes, full 71473 -> 72371); both are explicit v0.9.8 maintainer decisions measured from the release train. The v0.9.9 configured-skills change hides only custom configured-root paths, preserves discoverable default-root paths, normalizes Windows prompt separators, and trims 50 redundant skills-prompt bytes. The skill/memory/goal/handoff identities were re-measured without raising any ceiling. Explicit maintainer decision for #5473/#5492. The v0.9.10 full surfaces intentionally add the safe read_media tool; their measured schemas remain below the prior byte/token ceilings. Representative prompt byte metrics now use the same host-independent normalized text as their identities; the normalized base is 6089 bytes. The v0.9.11 model-visible sub-agent surface intentionally retires six legacy agents/* tools in favor of the canonical agent tool; all affected schema and prompt metrics decrease. The v0.9.12 plugin prompt-match slice intentionally adds the request_plugin_install tool to the full tool surfaces (plan full: +518 schema bytes / +130 estimated tokens / 29 -> 30 tools) so a strong prompt match can surface the human review CTA; explicit maintainer decision for #5663/#5579. The v0.9.13 profile pins a non-executed bare bash shell so interpreter guidance is reproducible across hosts. The duplicate tts catalog entry is intentionally hidden; speech remains canonical and the alias remains available for saved-transcript dispatch. Explicit v0.9.13 maintainer decision (2026-09-08): after removing 1426 repeated guidance bytes and pinning the bash-v2 fixture, accept only the measured tool byte/token ceilings from all-features macOS source e27735bb63c897f88061c71567701fd971f5d396, verified libtest SHA-256 5e8cbe213f32c4ecdec63494c4de5e31857b4a40134edf7b21a55bca926b1b38: active 13274/3319 in every mode, Plan full 39885/9972, Act/Operate full 67603/16901, with no margin. Against the prior budget, active +390 bytes is agent -41 plus retained bash command syntax +431. Plan full also retains Git commit_plan +253, update_goal progress +583, github bounded local-report guidance +127, review complete-input refusal +35, and send_later dispatching status +14. Act/Operate full instead has github +2151 and additionally speech +230, hidden tts -2120, and tasks/automation exact model-route fields +274 each. The older budget predates v0.9.12: that tag had already removed 361 agent bytes and added the two 274-byte route fields; the retained initial increase versus the tag is 751 source-attributed bytes (agent +320, bash +431), not the +390 budget delta. Only the seven active definitions form the initial request; full catalogs include deferred tools. Estimated tokens use the existing bytes/4 heuristic, not provider usage or billing. Prompt, representative-context, skill-discovery and tool-name identities/ceilings are unchanged. Explicit v0.9.13 maintainer decision (2026-09-09): source ccc5dadfa2279545bf084d37cff3617e41ceaae2 intentionally exposes create_goal, get_goal and update_goal before continuation, so all three initial surfaces now contain ten tools. Measure exact source 4648d148eea64782be857eda6952af2c539cbfcc with the hosted macOS all-features libtest SHA-256 4485c88c7a8b66b8bb9a135807321e417a1e266457ecb74cffc7dfb92f850fc4: four exact provider-free metric tests pass. Active schemas are exactly 17847 bytes / 4462 estimated tokens (+4573 / +1143 for the three eager goal definitions); Plan full is 40597 / 10150 and Act/Operate full is 68315 / 17079, with no margin. The +712 full-catalog bytes are request_user_input guidance +358, update_goal state-change guidance +98, list_dir home-relative path guidance +56, explicit review max_passes schema +197, and three defer_loading true-to-false values +3. The three active name sets/digests, their counts, and measured active/full byte/token ceilings change; full name identities and all prompt, representative-context and skill-discovery measurements remain unchanged. This updates the earlier seven-tool initial-request receipt; bytes/4 remains an estimate, not measLine truncated
|
||||
"_codex_0101_remeasure": "2026-10-01: lock the composed candidate measurement after the audited composition-required schema repair (46835a2fc, D04-11) and shared finance-timeout documentation (7c36620d4, D03-m3). Their parent-surface causal controls are recorded in 6655b191e. Act/Operate full catalog measured 84151 bytes / 21038 estimated tokens versus stale 83988 / 20997; no tools or surface identities changed. Plan/active surfaces and other budgets use their measured values. Estimate only, not provider usage. Receipt: CW/artifacts/codex-0101-takeover-20260930/root-runtime-contract-receipt.json.",
|
||||
"_comment": "One-way numeric ceilings and exact structural identities for the provider-free runtime contract. Decreases pass; increases or identity changes fail. Lock in decreases with: python3 scripts/check-runtime-contract-budget.py --update The v0.9.8 child-receipt restore grew every production tool surface by 1496 schema bytes / 374 estimated tokens (agent tool). The v0.9.8 workshop read/tool-result byte fields then grew every production tool surface by 371 schema bytes / 93 estimated tokens. Both raises are explicit maintainer decisions; identities stay on the pre-raise digests only if the name set is unchanged \u2014 re-measure on Linux CI if Lint reports identity drift. The v0.9.8 pinned session prefix added the <context_update> sentence to the base prompt (5848 -> 6084 bytes, every representative stage re-hashed), and the host-side Workflow/Goal verbs plus honest child posture grew the tool catalog (active 16531 -> 16602 bytes, full 71473 -> 72371); both are explicit v0.9.8 maintainer decisions measured from the release train. The v0.9.9 configured-skills change hides only custom configured-root paths, preserves discoverable default-root paths, normalizes Windows prompt separators, and trims 50 redundant skills-prompt bytes. The skill/memory/goal/handoff identities were re-measured without raising any ceiling. Explicit maintainer decision for #5473/#5492. The v0.9.10 full surfaces intentionally add the safe read_media tool; their measured schemas remain below the prior byte/token ceilings. Representative prompt byte metrics now use the same host-independent normalized text as their identities; the normalized base is 6089 bytes. The v0.9.11 model-visible sub-agent surface intentionally retires six legacy agents/* tools in favor of the canonical agent tool; all affected schema and prompt metrics decrease. The v0.9.12 plugin prompt-match slice intentionally adds the request_plugin_install tool to the full tool surfaces (plan full: +518 schema bytes / +130 estimated tokens / 29 -> 30 tools) so a strong prompt match can surface the human review CTA; explicit maintainer decision for #5663/#5579. The v0.9.13 profile pins a non-executed bare bash shell so interpreter guidance is reproducible across hosts. The duplicate tts catalog entry is intentionally hidden; speech remains canonical and the alias remains available for saved-transcript dispatch. Explicit v0.9.13 maintainer decision (2026-09-08): after removing 1426 repeated guidance bytes and pinning the bash-v2 fixture, accept only the measured tool byte/token ceilings from all-features macOS source e27735bb63c897f88061c71567701fd971f5d396, verified libtest SHA-256 5e8cbe213f32c4ecdec63494c4de5e31857b4a40134edf7b21a55bca926b1b38: active 13274/3319 in every mode, Plan full 39885/9972, Act/Operate full 67603/16901, with no margin. Against the prior budget, active +390 bytes is agent -41 plus retained bash command syntax +431. Plan full also retains Git commit_plan +253, update_goal progress +583, github bounded local-report guidance +127, review complete-input refusal +35, and send_later dispatching status +14. Act/Operate full instead has github +2151 and additionally speech +230, hidden tts -2120, and tasks/automation exact model-route fields +274 each. The older budget predates v0.9.12: that tag had already removed 361 agent bytes and added the two 274-byte route fields; the retained initial increase versus the tag is 751 source-attributed bytes (agent +320, bash +431), not the +390 budget delta. Only the seven active definitions form the initial request; full catalogs include deferred tools. Estimated tokens use the existing bytes/4 heuristic, not provider usage or billing. Prompt, representative-context, skill-discovery and tool-name identities/ceilings are unchanged. Explicit v0.9.13 maintainer decision (2026-09-09): source ccc5dadfa2279545bf084d37cff3617e41ceaae2 intentionally exposes create_goal, get_goal and update_goal before continuation, so all three initial surfaces now contain ten tools. Measure exact source 4648d148eea64782be857eda6952af2c539cbfcc with the hosted macOS all-features libtest SHA-256 4485c88c7a8b66b8bb9a135807321e417a1e266457ecb74cffc7dfb92f850fc4: four exact provider-free metric tests pass. Active schemas are exactly 17847 bytes / 4462 estimated tokens (+4573 / +1143 for the three eager goal definitions); Plan full is 40597 / 10150 and Act/Operate full is 68315 / 17079, with no margin. The +712 full-catalog bytes are request_user_input guidance +358, update_goal state-change guidance +98, list_dir home-relative path guidance +56, explicit review max_passes schema +197, and three defer_loading true-to-false values +3. The three active name sets/digests, their counts, and measured active/full byte/token ceilings change; full name identities and all prompt, representative-context and skill-discovery measurements remain unchanged. This updates the earlier seven-tool initial-request receipt; bytes/4 remains an estimate, not measLine truncated
|
||||
"document_kind": "codewhale.runtime_contract_budget",
|
||||
"representative_context": {
|
||||
"fixture_id": "representative-v1",
|
||||
@@ -86,9 +87,9 @@
|
||||
"modes": {
|
||||
"act": {
|
||||
"active": {
|
||||
"bytes": 35676,
|
||||
"bytes": 36240,
|
||||
"identity_sha256": "cc8f1f208bcf83261451f1ff67f7bf65534616cfd50be0102f50aba009a9e59d",
|
||||
"tokens_est": 8919,
|
||||
"tokens_est": 9060,
|
||||
"tool_names": [
|
||||
"agent",
|
||||
"bash",
|
||||
@@ -107,9 +108,9 @@
|
||||
"tools": 13
|
||||
},
|
||||
"full": {
|
||||
"bytes": 84151,
|
||||
"bytes": 84715,
|
||||
"identity_sha256": "45e989bbe5ac0bb1f2d9084361c021009f30a06539f132ebd4fd2331a1bb1954",
|
||||
"tokens_est": 21038,
|
||||
"tokens_est": 21179,
|
||||
"tool_names": [
|
||||
"Git",
|
||||
"Run",
|
||||
@@ -170,9 +171,9 @@
|
||||
},
|
||||
"operate": {
|
||||
"active": {
|
||||
"bytes": 35676,
|
||||
"bytes": 36240,
|
||||
"identity_sha256": "cc8f1f208bcf83261451f1ff67f7bf65534616cfd50be0102f50aba009a9e59d",
|
||||
"tokens_est": 8919,
|
||||
"tokens_est": 9060,
|
||||
"tool_names": [
|
||||
"agent",
|
||||
"bash",
|
||||
@@ -191,9 +192,9 @@
|
||||
"tools": 13
|
||||
},
|
||||
"full": {
|
||||
"bytes": 84151,
|
||||
"bytes": 84715,
|
||||
"identity_sha256": "45e989bbe5ac0bb1f2d9084361c021009f30a06539f132ebd4fd2331a1bb1954",
|
||||
"tokens_est": 21038,
|
||||
"tokens_est": 21179,
|
||||
"tool_names": [
|
||||
"Git",
|
||||
"Run",
|
||||
@@ -254,9 +255,9 @@
|
||||
},
|
||||
"plan": {
|
||||
"active": {
|
||||
"bytes": 34146,
|
||||
"bytes": 34710,
|
||||
"identity_sha256": "df6676989a677fb08fecc8bf7ae12caf4fa88e0cae3d143cea6a4da4382b746c",
|
||||
"tokens_est": 8537,
|
||||
"tokens_est": 8678,
|
||||
"tool_names": [
|
||||
"agent",
|
||||
"bash",
|
||||
@@ -274,9 +275,9 @@
|
||||
"tools": 12
|
||||
},
|
||||
"full": {
|
||||
"bytes": 53772,
|
||||
"bytes": 54336,
|
||||
"identity_sha256": "ac8af1f4988199825be7b00b054c258724a44074b1d4e6de6c92ade7c1cffe63",
|
||||
"tokens_est": 13443,
|
||||
"tokens_est": 13584,
|
||||
"tool_names": [
|
||||
"Git",
|
||||
"Web",
|
||||
@@ -314,6 +315,5 @@
|
||||
}
|
||||
},
|
||||
"surface_profile": "production-default-builtins-no-mcp-no-host-interpreters-bash-v2"
|
||||
},
|
||||
"_codex_0101_remeasure": "2026-10-01: lock the composed candidate measurement after the audited composition-required schema repair (46835a2fc, D04-11) and shared finance-timeout documentation (7c36620d4, D03-m3). Their parent-surface causal controls are recorded in 6655b191e. Act/Operate full catalog measured 84151 bytes / 21038 estimated tokens versus stale 83988 / 20997; no tools or surface identities changed. Plan/active surfaces and other budgets use their measured values. Estimate only, not provider usage. Receipt: CW/artifacts/codex-0101-takeover-20260930/root-runtime-contract-receipt.json."
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user