Everything written this session that has not been through the device: rounds 43 to 48 (each patch adversarially verified, 43's transient-notice expectation fixed), a partial round 49, the pipeline scripts, the Android Auto design and the icon comparison mock. Also the two harness changes that were never A/B'd — adaptive waits, which may only shorten a declared wait and never lengthen it, and a ship that runs the mock walk and the deploy at the same time. The A/B and its 255-step baseline are in handoff/tools; main stays at what the phone has actually walked.
113 lines
7.0 KiB
JavaScript
113 lines
7.0 KiB
JavaScript
// Round forty: what the device has never seen. No product code — this round
|
|
// only changes what the walks CLAIM. The phone walk carried 88 named steps
|
|
// against the mock walk's 252, four of its own were named and screenshotted
|
|
// with no expectation at all (the driver reads `expect[s.name] ? ... : true`,
|
|
// so a missing key is a silent pass), and nobody had written down which
|
|
// features were proven on the device and which were only ever proven against
|
|
// an object in memory. So: those four given their first assertion, thirty-three
|
|
// more steps moved onto the device — the ones that can be proven there without
|
|
// downloading, joining, sending, signing in or writing to Kyle's library — and
|
|
// the map itself, in ANDROID.md beside Verifying, in four lists: what the
|
|
// device proves, what is mock-only and why, what is conditional on his own
|
|
// data, and what still needs a person. Four edits to smoke.mjs, all inside
|
|
// PHONE_STEPS and PHONE_EXPECT; one insert in ANDROID.md. Nothing in the
|
|
// PROBE, nothing in MOCK_STEPS or MOCK_EXPECT, no CSS, no Rust, no Kotlin.
|
|
const fs = require('fs');
|
|
const root = process.env.SS_ROOT || 'F:/Coding/SoulStream/';
|
|
const scratch = 'C:/Users/Kyle/AppData/Local/Temp/claude/F--Coding-SoulStream/5488514a-11e8-482a-b0a0-20cb511ee110/scratchpad/';
|
|
const ins = (name) => fs.readFileSync(scratch + name, 'utf8').replace(/\s+$/, '');
|
|
let p, s;
|
|
const load = (file) => { p = file; s = fs.readFileSync(root + p, 'utf8'); };
|
|
const save = () => fs.writeFileSync(root + p, s);
|
|
const once = (a) => {
|
|
const i = s.indexOf(a);
|
|
if (i < 0) throw new Error('missing in ' + p + ': ' + a.slice(0, 90));
|
|
if (s.indexOf(a, i + 1) >= 0) throw new Error('ambiguous in ' + p + ': ' + a.slice(0, 90));
|
|
return i;
|
|
};
|
|
const rep = (a, b) => { once(a); s = s.replace(a, () => b); };
|
|
const NL = String.fromCharCode(10);
|
|
|
|
/* Three of the four smoke.mjs inserts re-emit their own anchor, so a second
|
|
run would double-write where `once` cannot see it coming and would only
|
|
throw further down, leaving half a tree. Refuse one here, before anything
|
|
is touched: `wifi-restored` exists nowhere in the repo today and is a name
|
|
this round creates. */
|
|
if (fs.readFileSync(root + 'tests/mobile/smoke.mjs', 'utf8').includes('"wifi-restored"')) {
|
|
throw new Error('round 40 is already applied in ' + root + ' — reset the tree rather than re-running');
|
|
}
|
|
|
|
// ── the walk ──────────────────────────────────────────────────────────
|
|
load('tests/mobile/smoke.mjs');
|
|
|
|
/* 0. The background check, which this round's own new steps broke. It asserts
|
|
that ten seconds with the app backgrounded advances the position by at
|
|
least eight seconds — true until the walk grew long enough to land that
|
|
window on a TRACK BOUNDARY. Then the position legitimately goes 221 → 3
|
|
as the queue moves on, which is playback continuing in the background,
|
|
the very thing being tested, scored as a failure. Crossing a boundary
|
|
with the screen off is the stronger proof of the two, so take it. */
|
|
rep(` const posBefore = (await cdp.evaluate(PLAYER))?.pos ?? 0;
|
|
cdp.close();`,
|
|
` const bgBefore = await cdp.evaluate(PLAYER);
|
|
const posBefore = bgBefore?.pos ?? 0;
|
|
cdp.close();`);
|
|
rep(` const posAfter = (await cdp.evaluate(PLAYER))?.pos ?? 0;
|
|
const bgOk = stillPlaying && posAfter >= posBefore + 8;
|
|
if (!bgOk) problems.push("EXPECT background " + JSON.stringify({ posBefore, posAfter, stillPlaying }));
|
|
console.log((bgOk ? " ok " : " FAIL ") + "background".padEnd(16) + " " + JSON.stringify({ posBefore, posAfter, stillPlaying }));`,
|
|
` const bgAfter = await cdp.evaluate(PLAYER);
|
|
const posAfter = bgAfter?.pos ?? 0;
|
|
const crossed = !!(bgBefore && bgAfter && bgBefore.title !== bgAfter.title);
|
|
const bgOk = stillPlaying && (crossed || posAfter >= posBefore + 8);
|
|
const bgSeen = { posBefore, posAfter, stillPlaying, crossed, from: bgBefore?.title ?? null, to: bgAfter?.title ?? null };
|
|
if (!bgOk) problems.push("EXPECT background " + JSON.stringify(bgSeen));
|
|
console.log((bgOk ? " ok " : " FAIL ") + "background".padEnd(16) + " " + JSON.stringify(bgSeen));`);
|
|
|
|
/* 1. the walk's own playlist, while it is still "Walk test" and still in
|
|
the order the drags above it restored. The mock's same-named step is
|
|
`[1]` and waits 1200, so this anchor is the phone's alone. */
|
|
rep(` { do: \`document.querySelectorAll('.pl-rows .trk')[0].click()\`, name: "playlist-playing", wait: 3000 },`,
|
|
ins('ins-r40-phone-playlist.txt') + NL
|
|
+ ` { do: \`document.querySelectorAll('.pl-rows .trk')[0].click()\`, name: "playlist-playing", wait: 3000 },`);
|
|
|
|
/* 2. the import review's Keep switch, restored before the draft is created
|
|
so `import-created` still counts its three rows. The mock's twin of
|
|
this anchor waits 1500. */
|
|
rep(` { do: \`__click('.imp-foot .btn-fill', 'Create playlist')\`, name: "import-created", wait: 2000 },`,
|
|
ins('ins-r40-phone-keep.txt') + NL
|
|
+ ` { do: \`__click('.imp-foot .btn-fill', 'Create playlist')\`, name: "import-created", wait: 2000 },`);
|
|
|
|
/* 3. the block that carries the rest. It navigates itself, so it needs one
|
|
anchor and no particular screen: round thirty-nine's own comment, the
|
|
last thing before the transfer face at the end of the list. Siblings
|
|
appending phone steps reach for the `name: "end"` line, which this
|
|
round deliberately leaves alone, so their block sits below this one
|
|
and neither moves. */
|
|
rep(` /* the one face of the six that a real build can show without arming`,
|
|
ins('ins-r40-phone-block.txt') + NL
|
|
+ ` /* the one face of the six that a real build can show without arming`);
|
|
|
|
/* 4. every new expectation in one insert. Round thirty-nine anchored its
|
|
phone expectations on the `end:` line; this one stays away from it. */
|
|
rep(` "artist-cold": (i) => i.screen.includes("has-hero"),`,
|
|
` "artist-cold": (i) => i.screen.includes("has-hero"),` + NL + ins('ins-r40-phone-expect.txt'));
|
|
save();
|
|
|
|
// ── the doc ───────────────────────────────────────────────────────────
|
|
/* anchored on the closing sentence of Verifying rather than on the
|
|
`## Not done yet` heading, because a sibling round adding to the map
|
|
would reach for the heading. Nothing already in the file is re-worded —
|
|
in particular not the sentences carrying a step count, which two earlier
|
|
rounds both bumped. */
|
|
load('ANDROID.md');
|
|
rep(`\`--only-lock\` takes just that still of whatever is on the bar (resuming it if
|
|
paused) without the walk.`,
|
|
`\`--only-lock\` takes just that still of whatever is on the bar (resuming it if
|
|
paused) without the walk.
|
|
|
|
` + ins('ins-r40-doc-map.txt'));
|
|
save();
|
|
|
|
console.log('round 40 wired');
|