From 0c3340e523f77f086afa78125adfd91034d746b3 Mon Sep 17 00:00:00 2001 From: Marcus Chandra Date: Mon, 14 Sep 2026 17:02:41 -0700 Subject: [PATCH 1/2] docs(run-workflow): explain that {{KEY}} in run output is a redaction Sim resolves a {{KEY}} reference at execution, then masks the value out of the log-facing copy that `workflows runs get` and `logs get` return, writing it back as the {{KEY}} label itself. Agents reading a run read that as an unresolved reference and "fix" a workflow that already works - rewriting {{KEY}} into environmentVariables.KEY, hardcoding a literal, or printing the value to prove resolution. The skill had nothing on this. It also cannot simply say "it's masked", because an unknown name is passed through unchanged and renders the same way, so the check has to key on the name rather than the rendering: `secrets list` returns names plus an `unredacted` flag. Also notes that a --follow stream is not a log copy and is not masked. --- skills/run-workflow/SKILL.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/skills/run-workflow/SKILL.md b/skills/run-workflow/SKILL.md index c741c86..f3c6f73 100644 --- a/skills/run-workflow/SKILL.md +++ b/skills/run-workflow/SKILL.md @@ -61,6 +61,19 @@ workflow and contains the state the selected block needs. 4. Correct the graph with the build skill. Do not hide a deterministic failure behind retries or a different execution mode. +## `{{KEY}}` in run output is a mask, not a failure + +Sim resolves the secret at execution, then masks the value out of the log-facing copy that +`workflows runs get` and `logs get` return, writing it back as `{{KEY}}` - or `[REDACTED_SECRET]` +when it cannot pin the value to one name. The block ran with the real value. A `--follow` stream is +not a log copy and is not masked, so never quote one back. + +An unresolved name looks identical in a log, because an unknown reference passes through unchanged. +Check the name, not the rendering: `sim --output json secrets list` returns names and an +`unredacted` flag, so a listed name with `unredacted: false` is a mask, not a failure. Never rewrite +a working `{{KEY}}` into `environmentVariables.KEY`, hardcode a literal, or print the value to prove +resolution. + Report which mode ran, the terminal status, and the relevant output or error. Include the run id when the selected execution mode returns one; `--follow` streams omit it. Never print profile credentials or raw secrets from block inputs. From c8754f811f9a4ff0b82fa383d9cf9bce6bf79dcd Mon Sep 17 00:00:00 2001 From: Marcus Chandra Date: Mon, 14 Sep 2026 18:38:21 -0700 Subject: [PATCH 2/2] docs(run-workflow): correct three wrong claims in the masking section An adversarial review found the first draft wrong in the unsafe direction on three counts, all verified in the sim source: 1. It said a listed name with `unredacted: false` is a mask, not a failure. Unsound: MIN_SUBSTITUTABLE_LITERAL_LENGTH is 8, so a secret shorter than 8 characters is never masked at all and its {{KEY}} is ALWAYS an unresolved reference. `secrets list` proves a name exists, never that it resolved in this run. The old line told an agent to leave a genuinely broken reference in place. 2. Singling out `--follow` as "not a log copy" implied the default run output IS masked. It is not - a plain run and a --follow stream both POST the same executeWorkflow operation, and the execute route contains no redaction call at all. Now says every live run response is unmasked and only runs get / logs get return the masked copy. 3. "An unknown reference passes through unchanged" is wrong for one of three languages: in a shell block an unresolved placeholder becomes the empty string (shell.ts `resolved ? shellExpansion(...) : ''`), while JavaScript and Python do leave it literal. Net effect is a weaker but true claim: a {{KEY}} in a masked log is usually a resolved secret, not proof of one. --- skills/run-workflow/SKILL.md | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/skills/run-workflow/SKILL.md b/skills/run-workflow/SKILL.md index 5f206bc..b8f8c14 100644 --- a/skills/run-workflow/SKILL.md +++ b/skills/run-workflow/SKILL.md @@ -92,18 +92,20 @@ Four properties of runs and run records that mislead diagnosis when unknown: in-workflow logs block reports the same run's cost in credits. Never compare or store the two as one number. -## `{{KEY}}` in run output is a mask, not a failure - -Sim resolves the secret at execution, then masks the value out of the log-facing copy that -`workflows runs get` and `logs get` return, writing it back as `{{KEY}}` - or `[REDACTED_SECRET]` -when it cannot pin the value to one name. The block ran with the real value. A `--follow` stream is -not a log copy and is not masked, so never quote one back. - -An unresolved name looks identical in a log, because an unknown reference passes through unchanged. -Check the name, not the rendering: `sim --output json secrets list` returns names and an -`unredacted` flag, so a listed name with `unredacted: false` is a mask, not a failure. Never rewrite -a working `{{KEY}}` into `environmentVariables.KEY`, hardcode a literal, or print the value to prove -resolution. +## `{{KEY}}` in run output is usually a mask, not a failure + +Only `workflows runs get` and `logs get` return the masked copy, where a resolved secret is written +back as `{{KEY}}` - or `[REDACTED_SECRET]` when it cannot be pinned to one name. Live run output is +never masked: a plain run and a `--follow` stream hit the same endpoint and both carry real values, +so never quote either back. + +So a `{{KEY}}` in a masked log is usually a resolved secret rather than a broken reference - but it +is not proof. An unresolved name survives too: JavaScript and Python leave it literal, shell +resolves it to the empty string, and a secret shorter than 8 characters is never masked at all, so +its `{{KEY}}` is always unresolved. `sim --output json secrets list` proves only that a name exists, +not that it resolved in this run. When a block behaves as though the credential were literal text, +check the spelling there first - but never "fix" a working reference by rewriting it into +`environmentVariables.KEY` or hardcoding a literal. Report which mode ran, the terminal status, and the relevant output or error. Include the run id when the selected execution mode returns one; `--follow` streams omit it. Never print profile credentials