- Add assertA31 page-side orchestrator after assertA30: opens fresh
https://example.com probe tab via chrome.tabs.create, injects a
synthetic <input type="password" id="probe-password"> + a control
<input type="text" id="probe-control"> into the probe tab DOM via
chrome.scripting.executeScript world:'ISOLATED', types
A31_PASSWORD_SENTINEL='secret-do-not-log-123' + A31_CONTROL_SENTINEL
into each, dispatches input events, settles, SAVEs while the probe
tab is active, finally-cleanup with silent-ignore (T-02-04-04
parity).
- Add 8 module-local constants: A31_SAVE_ARCHIVE_TIMEOUT_MS=15s,
A31_SEGMENT_SETTLE_MS=11s, A31_TRIGGER_SETTLE_MS=1s,
A31_TAB_NAVIGATION_WAIT_MS=1.5s, A31_PROBE_TAB_URL,
A31_PASSWORD_SENTINEL, A31_CONTROL_SENTINEL,
A31_PASSWORD_SELECTOR='#probe-password',
A31_PASSWORD_INPUT_ID, A31_CONTROL_INPUT_ID.
- Extend declare global Window.__mokoshHarness interface with assertA31
+ add assertA31 to window.__mokoshHarness object literal + update
statusEl banner + closing console.log to A31.
- 1 page-side check: A31.1 (SAVE_ARCHIVE ack). Host-side driveA31
(Task 2) will append A31.2 (sentinel-value-absent) + A31.3
(zero-events-targeting-password-selector) + A31.4 (control event
present — defense-in-depth proof the listener is alive, so A31.2
and A31.3 GREEN actually mean the filter fired rather than a
tautological pass from no events at all).
Rule 3 — Auto-fix blocking (cs-injection-world adaptation):
- The plan's <action> drove document.querySelector('#probe-password')
on the harness page (chrome-extension://...harness.html). Plan
03-02 empirically established that <all_urls> content_scripts does
NOT cover chrome-extension scheme (Chrome match-pattern spec
permits http/https/file/ftp/urn only). With no content script on
the harness page, A31.2/A31.3 would pass tautologically (no events
captured regardless of input type — would not empirically verify
the line-82 filter "fires").
- A31 reuses the Plan 03-02 cs-injection-world pattern: probe tab on
https://example.com (where the content script attaches normally)
+ executeScript ISOLATED-world injection so production
setupInputLogging at src/content/index.ts:78 actually sees the
password input event AND its line-82 filter early-returns.
- A31.4 control-event check is added as defense-in-depth per
T-03-03-04: proves the listener IS alive, so the absence assertions
A31.2/A31.3 are not vacuously satisfied.
- Plan's binding contract (sentinel absent from logs/events.json +
zero events targeting password selector) preserved verbatim; only
the trigger mechanism changes.
FORBIDDEN_HOOK_STRINGS impact: NONE. A31 rides production
setupInputLogging + line-82 filter + chrome.tabs + chrome.scripting
(scripting perm already in manifest) + existing
setupFreshRecording/sendMessageWithTimeout helpers. Tier-1 unchanged
at 12.