* feat(maestro): support assertTrue phase 1 - literal/${VAR} truthiness (#1295)
Adds the assertTrue command, scoped to literal values and bare ${VAR}
lookups per the #1292 lookup-only decision; JS expressions keep
failing loud at parse time with a runScript hint. Truthiness on a
looked-up value is evaluated against a pinned falsy-string table
("", "false", "0", "null", "undefined") since flow config/env/
runScript-output values are always stored as strings, rather than
native JS truthiness (which would treat "false" as truthy).
Wires assertTrue through the parser, interpreter, optional/warning
composition, and the layer-1 conformance oracle, narrowing the
067_assertTrue_pass divergence to the JS-expression case and removing
the now-satisfied 076_optional_assertion entry. Also materializes
scrollUntilVisible's default direction in the conformance canonical
projection, a latent gap only exposed once 076 could fully compare.
* fix(maestro): correct assertTrue truthiness claim in CLI help/docs
The support-matrix text said assertTrue is "evaluated with JS
truthiness", but the engine actually uses a pinned falsy-string table
("", "false", "0", "null", "undefined") since looked-up values always
arrive as strings — native JS truthiness would treat "false" as
truthy. Spell out the actual rule instead of the misleading claim.
* fix(maestro): fix oxfmt quote-style violation in expected-divergence.ts
CI's format gate failed on a single-quoted string containing an
apostrophe; oxfmt prefers double quotes there.
* fix(maestro): bump eager-closure-budget pin for the new truthiness module
engine-truthiness.ts is a genuinely new module on the core interpreter
path (assertTrue is dispatched unconditionally by
replay-plan-step-execution.ts), so packages/maestro/src/index.ts now
eagerly evaluates 105 modules instead of 104 — a deliberate growth,
not a laziness regression.
---------
Co-authored-by: Claude <noreply@anthropic.com>
`ignorePatterns: ["packages/**"]` landed in #1494 W0 with the recorded
reason "its resolver cannot follow workspace specifiers". That was either
wrong at the time or never re-checked: the fallow version has not moved
(^2.95.0 then and now) and it resolves @agent-device/* through each
package's exports map today. packages/kernel alone exposes 8 subpaths and
~110 exports reachable only via workspace specifiers, and scanning it
reports zero findings — a resolver that could not follow the specifier
would report all of them.
The cost of the ignore is that every package extraction silently removes
its code from dead-code analysis. #1589 moved the selector engine into
packages/selectors/ and shipped a façade with 15 zero-consumer exports,
including `selectorUsesKey`, written in that PR and never called. A
follow-up commit removed them by hand; nothing would have caught them.
Removing the pattern surfaced 43 findings, driven to zero by deleting the
dead code rather than by baselining or excluding it (fallow-baselines/*.json
are empty on purpose — the posture is fix-or-document-the-exemption, so a
first baseline entry would be a policy change):
- 38 are deleted. 24 façade type re-exports whose only claim was that a
consumer might one day want to name them — typecheck is green without
every one, so the claim was theoretical; 5 façade value re-exports; 9
`export` keywords on symbols used only inside their own file. Every
deleted façade symbol comes off scripts/layering/facade-symbols.ts (and
ad-replay's inline pin in package-boundaries.test.ts) in the same change,
so R11 is narrowed with the façade, never weakened around it.
- 4 stale suppressions in src/provider-limrun-runtime.ts existed only
because packages/ was invisible.
- 5 have consumers analysis genuinely cannot see, and get an
`ignoreExports` entry naming the consumer per the existing `comment`
convention: four test-tree importers that --production does not walk, and
`LimrunIosCommandExecution`, which src/sdk/limrun.ts republishes as
agent-device/limrun — its only importer compiles in a temp checkout, so
no static edge reaches it. test/integration/limrun-public-types.test.ts
is the standing proof that one is real API.
Three doc comments named types their façade no longer exports and are
corrected rather than left asserting something false — including #1555's
claim in session-replay-target-verification.ts that the daemon imports
`AdReplayVerifiedTargetGuard` directly. It does not; it reaches that shape
through `AdReplayTargetClassification`/`AdReplayDispatchGuard`, which is
why the name read as dead.
`scripts/maestro-conformance/**` was ignored wholesale to cover its corpus
data. Narrowed to `corpus/**`, which un-hides the tooling beside it and
turned up one more file-local export (`buildManifest`); regenerate.mjs's
importer of `fixtureContentHash` becomes visible, so that needs no
exemption at all.
scripts/check-affected/model.ts deliberately did not select the `fallow`
check for packages/*/src/**, carrying the same stale rationale as a
comment. Without that selection the new scope would never run in the
affected-driven lane, so the ignore removal would have bought nothing.
model.test.ts now pins the selection.
Verified: check:fallow and check:production-exports green with packages in
scope; full-repo `fallow dead-code` back to its one pre-existing finding;
typecheck, layering (R11), lint, format, build, check:package, and the
limrun published-types integration test all pass. Probed by adding a fresh
zero-consumer export to the xml façade — check:production-exports reports
it, so the #1589 case now fails the gate.
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>