Since the role moved to n8n 2 (2.42.3 on 2026-10-05, now 2.44.0),
POST /rest/workflows/:id/run accepts a manual run only with a trigger to
start from or a destination node; any other key, `workflowData` among them,
is dropped. The LiteLLM gateway test still sent only `workflowData`, so every
attempt failed with HTTP 400 "To run the workflow manually, specify either a
trigger to start from or a destination node." (PR #912, run 38455633497,
job 115523214958). On main the test sat behind the MCP provisioning failure of
n8n#0 that e4078c05fd fixed, so the next main run would have hit it.
The test now runs the stored probe workflow from its manual trigger.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The rule read the character after `timeout:` and objected to a digit, so a
duration bypassed the helper the moment it was given a name. That was already
reachable before, and it became easy to reach now that a poll interval is
allowed to stay unscaled: the two look identical at the call site and only one
of them is correct.
They are opposites, and the rule now says so. An upper bound must scale, because
the answer over a Tor circuit arrives later and a fixed cap expires before it
does. A poll interval must not, because scaling one makes a slow target notice
its element later rather than sooner, which is the reverse of the tolerance the
scaling exists to buy. So `timeout:` rejects a CONSTANT_CASE name as well as a
digit, while `waitForTimeout` and `setTimeout` keep matching on a leading digit
only and accept a named interval.
Across the 1307 `timeout:` sites in scope the sharpened rule finds exactly one,
and it is a true positive that wanted saying out loud. The n8n LiteLLM spec
passes a completion timeout into an `n8n-nodes-base.httpRequest` node: not a
Playwright wait at all, but a parameter for a request n8n makes to LiteLLM
inside the deployment, which never crosses a circuit. Leaving it unscaled is
right and was invisible; it now carries the sanctioned marker and its reason.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Twenty-five specs called the Playwright APIs with default or hardcoded
timeouts. Routed over Tor those budgets are too small, so a spec fails on
transport latency rather than on the behaviour it asserts.
Route the waits through resolveTimeout and reach pages via gotoOnion, the
helpers the tor branch introduced for exactly this. The remaining changes in
the diff are import wrapping around those calls.
The repository lint enforces this: a raw numeric timeout in a role spec is
rejected with a pointer to resolveTimeout, which is how a hardcoded 500ms
wait added during this session was caught.
Merge work rather than authored here; not deployed.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
AI Agent nodes read their endpoint from a stored credential, not from the
environment, so the gateway base URL and this role's virtual key have to land in
n8n's credential store. files/provision_ai.py logs in as the owner and upserts an
openAiApi credential under the deterministic name infinito:litellm.
The write goes through the internal /rest routes because that is the only place
the pinned 1.95.3 exposes credential creation: the public /api/v1 key this role
already mints for MCP carries workflow scopes and cannot create a credential.
That is why this is a second script rather than another call inside
provision_mcp.py.
n8n encrypts credential data at rest and never returns it, so there is nothing
to compare against and the managed credential is overwritten rather than
reconciled. The script prints CHANGED or OK so the task can report change state
without pretending to have diffed a value it cannot read.
env.j2 sets only N8N_AI_ENABLED. An earlier revision of this work templated
N8N_INSTANCE_AI_MODEL_URL, which does not exist in 1.95.3 -- it was invented
rather than measured, and has been removed along with the requirement table row
that repeated it. The one real AI environment variable in that release,
N8N_AI_ASSISTANT_BASE_URL, expects n8n's own assistant service rather than an
OpenAI-compatible endpoint, so the credential store is the only usable surface.
vars/main.yml also carries N8N_MCP_CREDENTIAL_NAME. It belongs to the MCP work
rather than to this change, but a file cannot be split across commits and this
order is the safe one: the MCP tasks land later and find the constant already
present, where the reverse would reference a variable that does not exist yet.
Verified: the spec runs rather than skipping -- it appears in the variant-2
JUnit as "administrator: the managed openAiApi credential answers a prompt
through the in-cluster gateway".
Not verified: I confirmed it executed, not its verdict. The owner-cookie login
is also unexercised on an sso-only variant, and because the credential is
rewritten every run, an operator's manual edit is replaced without notice.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>