00Plan
Issue: ty5dx-add-per-service-default-actions-so-awsquery-ec2-runs-without-an-action · Generated 2026-09-08
01Strategy
Resolve the default action before argparse sees the tokens, not after.
One pure list → list function spliced into the raw argv at
cli.py:752, so every downstream stage sees exactly the argv the user
would have typed.
nargs="?", so argparse eats the
-- separator and promotes the first column filter into the action slot.
ec2 -- InstanceId parses byte-identically to
ec2 InstanceId. A post-parse patch keyed on args.action is None
therefore leaves awsquery ec2 -- InstanceId running a bogus operation named
InstanceId. The information exists only in the raw token list.
is_readonly_operation only PascalCases input that
contains a hyphen. Given describe_instances it returns false, falls through to
the unsafe-operation prompt and blocks on input()
— awsquery ec2 would hang in a pipe. The decision document's illustrative
snake_case example is overridden.
service → action → {columns}
shape; a sibling string key inside default_filters.yaml would raise
AttributeError in both. Hence a new
src/awsquery/default_actions.yaml — which must also be registered in the
package-data list, or the wheel ships with no defaults at all.
iam, ssm, sagemaker, glue,
backup and athena. Each is a one-line YAML change.
The research agent could not run the test suite — its interpreter lacked
boto3, botocore, argcomplete and pytest.
The executor must actually run make test, make lint and
make format-check rather than assume the suite is green.
02Flow
Tasks run sequentially; task N may assume 1..N−1 are complete. Tasks 1 and 2 are the data/loader foundation, task 3 is the behavioural change, tasks 4–6 verify and document it.
03Decisions
Chosen: a pure _inject_default_action(argv) called on
sys.argv[1:] at cli.py:752, after
argcomplete.autocomplete() and without ever mutating sys.argv.
Rejected — post-parse substitution on args.action is None
(what the issue text implies): provably insufficient, since argparse makes
ec2 -- InstanceId and ec2 InstanceId indistinguishable after
parsing. It fails an acceptance criterion silently.
Rejected — look the second positional up in botocore and demote
non-operations to value filters (which would also make
awsquery ec2 prod default): a typo such as
describe-instance would then silently run describe-instances
with a spurious filter and print zero rows instead of erroring, and it adds a service-model
load to the hot path.
Snake_case values were executed against the real readonly validator and returned
is_readonly=False for every entry, routing the command into a blocking
interactive prompt. Kebab-case in the file, plus a defensive
to_kebab_case(to_snake_case(v)) at the injection boundary, and a test that
pins the file as already canonical.
A default_action: key inside default_filters.yaml would break the
audit script and two existing structure tests, which walk every service value as a dict.
The separate file leaves them untouched — but it must be added to the package-data
list in the same commit, since there is no MANIFEST.in and the unit tests read
from the source tree and cannot catch a missing wheel entry.
The highest-disagreement curated pick. list-users chosen because Users is the
console landing page and IAM's primary noun; list-roles is the more
infra-centric answer and a defensible override. Five further judgement calls
(ssm, sagemaker, glue, backup,
athena) are tabulated in the plan. Every one is a one-line change.
application-autoscaling, budgets, ce,
cognito-identity and cognito-idp have zero readonly operations
with no required parameters, so the locked "single immediate call" rule excludes
them. They intentionally exercise the stderr fallback, which is what the rewritten
end-to-end test asserts against.
tests/integration/test_end_to_end.py:889 guards its assertions behind a string
this change removes. Left alone it stays green while main() proceeds to attempt
real AWS work under a partially-mocked session — a CI hang or credential error that
looks like a passing test. Task 5 rewrites it into two unconditional assertions.
04Detail
05Provenance
Generated from the canonical .md. This HTML is never
hand-edited — if the .md changes, regenerate with
/issue:view.