## main is red
`workflow-optional-role-param-caller-audit-live-e2e.pg.test.ts` fails on
`origin/main` in `engine-default`:
```
AssertionError: expected 4 to be 2
expect(parkedConverted.length).toBe(2);
```
Found by running the whole live-E2E corpus rather than trusting that it
passes — 27 files, 159 tests, 1 red. Not in the merge gate, so it has
been sitting there. The alarm fired **downward**, exactly as that file
was written to: two more call sites started passing `parkedColumns`, and
a counter fails when someone *closes* a gap as well as when someone
widens it.
## Why I did not just write 4
Re-recording it at 4 would have laundered an inert conversion through
the audit written to catch inert conversions. Walking all six sites
before touching the number:
| site | `parkedColumns` provenance | verdict |
| --- | --- | --- |
| `agent-heartbeat.ts:1267` | — | unconverted |
| `agent-heartbeat.ts:3796` | — | unconverted |
| `self-healing.ts:13184` | `await resolveProjectColumnsForRoles`
(:13170) | async-resolved |
| `self-healing.ts:13294` | `await resolveProjectColumnsForRoles`
(:13293) | async-resolved |
| `task-agent-sync.ts:243` | `await resolveLinkSyncColumnRoles` (:225) |
async-resolved |
| `scheduler.ts:1798` | `resolveTaskParkedColumnsSync` (:1797) | **SYNC
— INERT** |
`scheduler.ts:1798` resolves through `resolveTaskParkedColumnsSync` →
`getTaskWorkflowSelectionImpl`, which is `undefined` for every task
under PostgreSQL. The resolver then takes its `!workflowId` branch and
returns the **default builtin IR** — not `undefined` falling through to
a legacy arm, but a real IR resolving real traits, with full confidence.
It answers `hold`/`intake` as `todo`/`triage` on every board, exactly as
the literal did. Driven proof:
`workflow-scheduler-sync-role-conversion-inert-live-e2e.pg.test.ts`.
**The shape count (4) and the live count (3) are different numbers, and
only the second is about behaviour.** Both are now asserted, plus the
sync-resolved site by name so it cannot quietly become "just one of the
four".
## A mistake worth recording, because the test caught it
My first draft keyed on `await` appearing inside the call window. The
argument is nearly always a variable (`[...driftedParkedColumns]`,
`roles.parked`) and the `await` lives in that variable's **assignment**,
several lines above. That draft classified all four sites as inert — and
it **would have passed** had I written the expected number to match what
it measured. It failed only because I asserted 2 live from reading the
source first, and the mismatch exposed the detector.
Classification is now by provenance: take the root identifier, find
where the file assigns it, ask whether *that* is awaited. The same bug
recurred in my named-site check and failed the same way.
That is the whole hazard of this program in miniature — a source-text
audit that measures nothing looks exactly like one that measures
everything, and it is the *number you expected* that catches it, not the
green.
## Not asserted, deliberately
`self-healing.ts:13184` is inert for an unrelated reason: its gate is
`hasFreshRun || hasActiveExecution` and never reads
`shouldPreserveParkedLink`, so its correctly-resolved set decides
nothing today. Its own FNXC note says so. Resolution path is
mechanically checkable; "the gate never reads the answer" is not, and
asserting it on a string match would produce a number nobody could
maintain. Recorded as prose in the header.
I also did not touch `scheduler.ts`. It is a real defect, not a
deferral, but converting it is not this file's job — it is named in the
test so the next person converting it is sent here to move it from the
inert list to the live one.
## Verification
Mutation-verified — a passing audit proves nothing until it has been
seen to fail:
| mutation | expected | result |
| --- | --- | --- |
| convert the scheduler site to the async resolver | fail (3/1 → 4/0) |
exit 1 ✅ |
| drop `parkedColumns` from a converted site | fail (shape 4 → 3) | exit
1 ✅ |
| add a new unconverted caller | fail (calls 6 → 7) | exit 1 ✅ |
| clean tree | pass | exit 0 ✅ |
Full 27-file live-E2E corpus green (159 tests). Ratchets exit 0.
Test-only; no changeset.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Tests**
* Expanded end-to-end audit coverage for workflows with optional role
parameters.
* Improved validation of caller resolution paths, including asynchronous
and synchronous scheduling scenarios.
* Updated expectations to reflect all supported conversion paths and
strengthened verification of scheduler behavior.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->