Commit Graph
351 Commits
Author SHA1 Message Date
pj 9dbc8f7c9a docs(skills): defaultActions bundles five of the eight generators 2026-08-16 01:08:47 +05:30
pj 41c6c1e4b9 test(ci): cover the folio classifier's verdicts
21 cases through a stubbed sanderling: every exit path, the drift check,
a missing trace, a zero-byte trace, an empty glob and a truncated line.
Asserts the flags that reached the binary, not just the exit code.

Invoked as bash -eo pipefail -c, which is what a run: block does. Running
folio-run.sh itself under -e would kill it at the first non-zero
sanderling test, which is the exit code it exists to read.
2026-08-16 01:08:45 +05:30
pj cd3bc51a0d fix(ci): fail folio when a gated property is not in the spec
Nothing tied GATED_PROPERTIES to the spec it gates. Renaming a property
left the classifier matching nothing: ios and web blamed the spec for
finding a different bug, and android silently reclassified a real
conviction as 'judging health only' and stayed green.

replay-ui-summary.sh already makes this check for its own list. The spec
path becomes SPEC-overridable the same way, so the check is testable.
2026-08-16 01:08:40 +05:30
pj 6263aa4c6c fix(ci): a run that wrote no trace is not evidence about folio
run_dir is empty when the run produced no output directory, and the
fallback made trace ./trace.jsonl. A stray trace in the working directory
was then read as this run's, so a run that wrote nothing reported 'found
the submit bug' and exited 0, defeating the missing-trace check below it.
2026-08-16 01:08:27 +05:30
pj 7c085c8c9d docs(skills): web selectors are exact, native ones are substrings 2026-08-16 01:08:19 +05:30
pj 906759dc15 docs(skills): substring selector matching is native only 2026-08-16 01:08:07 +05:30
pj 392e8dd445 docs(skills): screen= is the chrome driver's url, web only 2026-08-16 01:07:58 +05:30
pj 9172d1c378 docs(skills): quote the doctor the binary actually prints 2026-08-16 01:07:49 +05:30
pj 46aba1654f docs(skills): name the balance predicate that still exists 2026-08-16 01:06:59 +05:30
pj ef7466e61e docs(skills): both shipped balance forms are bounds now 2026-08-16 01:06:49 +05:30
pj cb45508e72 test(ios): a device driver can bring a runner up 2026-08-16 01:05:59 +05:30
pj 01f9ea942c fix(ios): one address picker for every bring-up
bringUpRunner reads the picker from a field, and NewDevice only ever set
the device one, so a device driver that reached bringUpRunner would call
nil. The two fields held the same function; keeping one leaves no path
that can be wired without it.
2026-08-16 01:05:59 +05:30
pj 4d14e9ca54 docs(manual): the flagship property is a bound, and say what that costs 2026-08-16 01:05:15 +05:30
pj d124354379 test(ios): a clear-state launch for an uncleared bundle is refused 2026-08-16 01:04:58 +05:30
pj 6beea91046 fix(ios): the clear-state guard checks the bundle that was cleared
A bool only said that something was cleared, so Launch(ctx, otherBundle,
clearState=true) passed the guard and reported a reset that had reached a
different app. Record what was cleared and compare against the bundle
being launched.
2026-08-16 01:04:58 +05:30
pj 8fbdc0296f docs(ci): the balance property demands a bound, not an equality 2026-08-16 01:04:12 +05:30
pj 18074e3bdd docs(skills): the stock properties each cover one platform 2026-08-16 01:04:05 +05:30
pj 99b9fe23f5 test(ios): a device clear-state without an app path ends the run 2026-08-16 01:03:48 +05:30
pj 220c7fe1d7 fix(ios): a device clear-state that cannot happen must fail
--clear-data on a physical device with no --ios-app-path warned and then
ran anyway, so the run started on the previous run's data while the flag
said it started clean. There is no data-container wipe on a device, so
there is nothing to fall back to.
2026-08-16 01:03:48 +05:30
pj be9cc78479 docs(skills): noUncaughtExceptions only fires on web 2026-08-16 01:03:47 +05:30
pj 45568f656b docs(skills): an unreached eventually convicts at run end 2026-08-16 01:03:35 +05:30
pj fea42e2899 docs(spec): an unbounded eventually is violated at run end 2026-08-16 01:03:25 +05:30
pj 9ede9dc3e2 test(ios): pin the stop that has to precede a clear
The ordering probe now records the stop, and a scripted xcrun holds what
reaches the tool: terminate before get_app_container, with the previous
run's files gone after. A simctl terminate that finds nothing to stop
still leaves the clear a success.
2026-08-16 01:03:02 +05:30
pj 119877c78a fix(ios): stop the app before clearing its state
Launch terminated and then cleared; the clear moved to construction and
left nothing stopping the app first. The container wipe deletes files a
live app still holds open, and the CI ios leg passes no app path so the
wipe is the path it takes. simctl stops it, since the clear now runs
before any automation session exists. On a device the uninstall that is
its only clear takes the running app with it.
2026-08-16 01:02:57 +05:30
pj 33c585de7b fix(testrun): a run that judged nothing is not a green run
every step skipped means no property ever evaluated, so no violations is the
absence of a verdict rather than a clean one. the hold makes that reachable
now, so the run says it instead of exiting 0.
2026-08-16 01:02:29 +05:30
pj 8e37be2afd test(runner): pin both guard writes to what the spec reads
deleting lastAction.Relaunched or lastAction.Applied left the whole suite
green, so the only producer of the two fields every spec-side guard reads
had nothing holding it. both now assert the value out of the trace.
2026-08-16 01:01:03 +05:30
pj f911079e32 test(ios): drive the launch recovery with what the transports return
The wedged-session fake answered with ctx.Err() raw, which is the one
shape the guard already matched. The recovery now runs against the error
each transport really produces for the same expiry, taken from a runner
and a legacy companion that never answer.
2026-08-16 01:00:49 +05:30
pj f1a5db886e fix(ios): recognise every shape a blown launch bound arrives in
The runner transport reports a blown budget two ways, its own comment says
so: the context's error once cancellation has landed, and the connection's
i/o timeout when the deadline armed from that context fires first. The
legacy transport reports it as a gRPC status. errors.Is against
context.DeadlineExceeded only matches the first, so the session restart
never fired for the other two and a wedged session stayed wedged.
2026-08-16 01:00:45 +05:30
pj 7f9c5df7db fix(ci): close shell injection into the npm publish job
A refname is attacker-controlled and git permits backtick, $, (, ; and |
in it. Three sites substituted it into a run: block, and NODE_AUTH_TOKEN
sat at job level, so a pushed tag ran arbitrary commands with the publish
credential in reach.

The tag now goes through env:, is validated against an anchored version
pattern before anything consumes it, and reaches the other jobs as a job
output. The token is scoped to the publish step. release-npm declares
contents: read instead of inheriting the repo default.
2026-08-16 01:00:40 +05:30
pj 0a7afbabec test(runner): pin what the two reads are compared on
structuralShape excluding text and bounds is the decision separating this
feature from a run that verifies nothing, and only prose held it. adding
either field back now turns a case red.
2026-08-16 00:59:13 +05:30
pj 86da6ed8ee fix(runner): a bounded hold puts the swallow back one step later
the hold carries one action; letting the runner act again while the verifier
is still skipped overwrites it, so the carried action reaches no spec. hold
for as long as the verifier is skipped, and settle on a held step so the
reread pair is not tighter than the window the detector was measured over.
2026-08-16 00:57:36 +05:30
pj 5b6816956f docs(ci): the cross-fade wait does not fire on ci, say so 2026-08-16 00:50:06 +05:30
pj 71134a3347 docs(ci): the ios leg convicts on the runner now, and why it did not before 2026-08-16 00:23:56 +05:30
pj d977265b30 Merge branch 'clear-state-must-happen' into correctness-and-spec-skills 2026-08-16 00:22:59 +05:30
pj ea952378fe test(android): name the uninstall failure for what it says, not why 2026-08-16 00:07:58 +05:30
pj 87aa7d9284 docs(android): say why the uninstall text cannot be read 2026-08-16 00:07:12 +05:30
pj 6234bf5ba0 fix(ios): a failed devicectl uninstall must fail the reinstall
same hole as the simulator path: devicectl install over an app keeps its data, and the discarded uninstall error hid it. Uninstalling a bundle id that is not installed exits 0 with 'App uninstalled.' on a paired iPhone, so a failure here is always real.
2026-08-16 00:02:36 +05:30
pj abc5e7db3e fix(ios): a failed simctl uninstall must fail the reinstall
simctl install over an installed app carries its data container across, so discarding the uninstall error reported a clear-state that never happened. Uninstalling an app that is not installed exits 0 on a booted simulator, so every failure here is a real one.
2026-08-16 00:01:40 +05:30
pj 1ec6eb3847 fix(android): a refused uninstall must not pass for clear-state
adb uninstall answers Failure [DELETE_FAILED_INTERNAL_ERROR] both when the package was never installed and when it refuses to remove one, so the failure text cannot say which happened and the old code installed over the top either way, keeping the data clear-state was asked to drop. Ask pm path instead, and fall back to pm clear when the app is still there.
2026-08-16 00:00:36 +05:30
pj 17f0a020fa Merge branch 'spec-authoring-skills' into trial-merge 2026-08-15 23:04:37 +05:30
pj 112d347432 refactor(folio): name the balance property for the bound it asserts
it stopped being an equality and became |delta| <= typed, so the old name
demanded more than the property does. renamed with the ci gate's
GATED_PROPERTIES in the same commit so the gate never sees a name it does
not know.
2026-08-15 23:04:15 +05:30
pj 6a7764eac7 Merge branch 'folio-spec-attribution' into trial-merge 2026-08-15 23:03:50 +05:30
pj 8ad68b278f docs(folio): record why a banked card reading can be trusted as current
The freshness rule rests on the app popping one entry back to the ledger,
not on anything the frame carries, so the assumption and the measurements
behind it belong next to it.
2026-08-15 23:02:42 +05:30
pj 4027aa1e44 test(folio): pin that a commit stays in the window until Home reads it
The interaction that keeps a stale Home card list from ever banking counts
the budget has already forgotten: a submit lands on the ledger, so the
reading that resets the window is a whole action later and the submit is
still in it. Characterization, not a regression: no code changed and it
cannot go red first.
2026-08-15 23:02:37 +05:30
pj b554a9ecee docs(manual): correct the flags the cli reference gets wrong
--launcher-activity does not exist in cmd/sanderling/main.go. --device,
--android-app-path and --arm do and were undocumented. runs.md still listed
--max-steps and --exit-on-violation as unshipped, and described --clear-data
as opt-in when the default is already true, contradicting itself ten lines on.
2026-08-15 23:00:16 +05:30
pj b241a2cc64 Merge branch 'trial-merge' into spec-authoring-skills 2026-08-15 22:59:47 +05:30
pj 1adbb35305 Merge branch 'skills-setup-and-triage' into spec-authoring-skills 2026-08-15 22:59:47 +05:30
pj fb1b482ab1 docs(skills): point the setup skill at its siblings 2026-08-15 22:58:41 +05:30
pj ffc857f58f Merge branch 'spec-authoring-skills' into skills-setup-and-triage 2026-08-15 22:58:07 +05:30
pj a51c8cb742 docs(skills): add a run triage skill 2026-08-15 22:57:42 +05:30