Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 20 additions & 5 deletions cli/bash/commands/basectl/basectl.sh
Original file line number Diff line number Diff line change
Expand Up @@ -509,6 +509,24 @@ basectl_history_recordable_command() {
esac
}

basectl_validate_command() {
local command="${1:-}"

case "$command" in
""|activate|check|test|export-context|devcontainer|devenv-report|build|demo|run|repo|ci|release|prompt|docs|clean|logs|history|config|trust|doctor|gh|onboard|setup|help|projects|workspace|update|update-profile|version)
return 0
;;
*)
if [[ -f "$command" ]]; then
basectl_bare_script_usage_error "$command"
else
basectl_usage_error "Unrecognized command: $command"
fi
return $?
;;
esac
}

basectl_args_request_help() {
local argument
for argument in "$@"; do
Expand Down Expand Up @@ -778,6 +796,7 @@ basectl_main() {
basectl_history_recordable_command "$command" || run_bundle_enabled=0

basectl_get_base_home || return 1
basectl_validate_command "$command" || return $?
if ((keep_temp)); then
export BASE_CLI_KEEP_TEMP=true
fi
Expand Down Expand Up @@ -830,11 +849,7 @@ basectl_main() {
fi
;;
*)
if [[ -f "$command" ]]; then
basectl_bare_script_usage_error "$command"
else
basectl_usage_error "Unrecognized command: $command"
fi
basectl_validate_command "$command"
command_status=$?
;;
esac
Expand Down
43 changes: 43 additions & 0 deletions cli/bash/commands/basectl/tests/runtime-dispatch.bats
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,49 @@ load ./basectl_helpers.bash
}


@test "basectl rejects unknown commands before creating persistent runtime state" {
local cache_root="$TEST_TMPDIR/cache"

run env \
HOME="$TEST_HOME" \
BASE_HOME="$BASE_REPO_ROOT" \
BASE_CACHE_DIR="$cache_root" \
bash -c '
source "$BASE_HOME/cli/bash/commands/basectl/basectl.sh"
basectl_main invalid
'

[ "$status" -eq 2 ]
[[ "$output" == *"Unrecognized command: invalid"* ]]
[ ! -e "$cache_root/base/runs" ]
[ ! -e "$cache_root/base/history/runs.jsonl" ]
}


@test "basectl keeps a run bundle for a recognized command failure" {
local cache_root="$TEST_TMPDIR/cache"
local run_root

run env \
HOME="$TEST_HOME" \
BASE_HOME="$BASE_REPO_ROOT" \
BASE_CACHE_DIR="$cache_root" \
bash -c '
source "$BASE_HOME/cli/bash/commands/basectl/basectl.sh"
log_debug() { :; }
basectl_do_setup() { return 7; }
basectl_history_record() { :; }
basectl_main setup
'

[ "$status" -eq 7 ]
run_root="$(find "$cache_root/base/runs" -mindepth 1 -maxdepth 1 -type d -print -quit)"
[ -n "$run_root" ]
[ -f "$run_root/run.json" ]
[ -f "$run_root/logs/primary.log" ]
}


@test "basectl labels run bundle directories without changing the run ID" {
run env \
BASE_HOME="$BASE_REPO_ROOT" \
Expand Down
9 changes: 7 additions & 2 deletions docs/observability.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,13 @@ History writes are best-effort:
- never fail the user command because the history file cannot be written
- ignore malformed history lines while warning in debug output

`basectl history` shows one record per public invocation. Legacy internal rows
are ignored so old caches do not reintroduce duplicate command entries.
`basectl history` shows one record per accepted public command invocation.
Top-level command and wrapper-syntax errors are rejected before persistent
runtime state is initialized, so they do not create a run bundle or history
record. Once a recognized command is accepted, its run remains observable even
if leaf-level argument validation, environment checks, or execution later
fails. Legacy internal rows are ignored so old caches do not reintroduce
duplicate command entries.

## Record Shape

Expand Down
Loading