Repository navigation
yaml: args matches only a with: block — inputs: declarations are invisible and a block counts as one argument #2753
Description
Found by the #2669 pass over every non-green cell in the keyword-rosetta bias report (2026-09-05, engine 0e521e8). yaml/args reads 0 against a median of 13 and avg_func_args 0.0 against 1.0; both are ledgered as args-no-parameter-surface-morphology because the rule "matches a with: block, which binds to uses: and never to the corpus's run: steps". The rule is narrower than the language on two axes.
1. with: is the call-site argument block; the declarations are inputs:
yaml.py's args matches only
r"^[ \t]*with:[ \t]*(?:#.*)?\n(?:[ \t]*(?:#.*)?\n){0,10}[ \t]+[a-zA-Z0-9_-]+:[ \t]*.*"with: supplies arguments to an action. The parameter surface a YAML file declares — the thing every other language's args rule reads off the def/function/sub line — is inputs::
on: workflow_dispatch: inputs:/on: workflow_call: inputs:— a workflow's parameters (workflow_call is the reusable-workflow API fix(core-engine): give the api rule a stated contract and audit all 46 languages against it (#2730) #2743 added to theapitrigger set; itsinputs:block is that API's signature);- top-level
inputs:inaction.yml— a composite action's parameters.
None of these match today. On language-crucible's yaml corpus (8 Ansible task files, 77bc85e) with: fires 0 times, so the rule is also unexercised by the golden master (the caveat #2646/#2647 recorded as language-crucible#23). Ansible's own parameter blocks — vars: on include_role/include_tasks (5 in crucible) and module args: — are likewise unseen.
2. It counts blocks, not parameters
The regex consumes the block header through its first key as one match, so with: carrying five inputs is args 1. yaml defines none of the _args_* capture helpers, so nothing splits the list. Every other language records one hit per parameter; a with: block with five keys is five arguments by the same definition.
Candidate shape
# Parameter surfaces: a declared inputs: block (workflow_dispatch / workflow_call /
# action.yml) or a supplied with: / args: block. One hit per key, not per block.
"args": re.compile(
r"^[ \t]*(?:with|inputs|args):[ \t]*(?:#.*)?\n"
r"(?:[ \t]*(?:#.*)?\n){0,10}[ \t]+([a-zA-Z0-9_-]+):",
re.M,
),plus an _args_pattern_list_groups-style helper (or an indentation walk) to count every key at the block's child indentation rather than the first. Whether Ansible vars: is a parameter block or a variable block is the design question — it is both, depending on the task.
Overlap, measured (screen_plant.py)
An inputs: block under the corpus's existing on: workflow_dispatch: fires nothing new (the api hit shown is the pre-existing trigger). The plant must use required:/default: only — a description: under an input is a doc hit (yaml's doc rule matches every description: line). A with: under a uses: step is the ledger's rejected form (it needs a uses: line = import + a DAG edge); an inputs: declaration needs neither.
Corpus pairing
a.yml already carries on: workflow_dispatch:; an inputs: block with one key per probe (12 keys) reads args 12 under a per-key count, or 1 under today's per-block count. Either ends the 0; the ledger entry narrows or retires for yaml.
Part of #2669 (rosetta[yaml] is #2606).
Filed together on 2026-09-05: jcl api #2748 · jcl cleanup #2749 · jcl globals #2750 · jcl high_risk_execution #2751 · css io #2752 · yaml args #2753. Corpus-side pairings: squid-protocol/keyword-rosetta#59.
Activity
fix(core-engine): yaml args reads declared inputs: and counts paramet…
fix(cobol): sentence-anchored paragraph headers (#3197) + census iden…