feat: connector verification loop — evidence claims, run-and-watch, scenario record/replay - #140
feat: connector verification loop — evidence claims, run-and-watch, scenario record/replay#140tnunamak wants to merge 797 commits into
Conversation
Assisted-by: AI Signed-off-by: Tim Nunamaker <tnunamak@gmail.com>
Assisted-by: AI Signed-off-by: Tim Nunamaker <tnunamak@gmail.com>
Limit the expanded subprocess budget to the two behavioral cases that actually launch more than 50 fake gmcli processes. Assisted-by: AI Signed-off-by: Tim Nunamaker <tnunamak@gmail.com>
Assisted-by: AI Signed-off-by: Tim Nunamaker <tnunamak@gmail.com>
Fence the legacy SQLite writer during migration reconciliation, preserve explicit queue paths, make state filenames injective, and route maintenance commands through saved-profile queue resolution. Assisted-by: AI Signed-off-by: Tim Nunamaker <tnunamak@gmail.com>
Assisted-by: AI Signed-off-by: Tim Nunamaker <tnunamak@gmail.com>
Assisted-by: AI Signed-off-by: Tim Nunamaker <tnunamak@gmail.com>
Assisted-by: AI Signed-off-by: Tim Nunamaker <tnunamak@gmail.com>
Assisted-by: AI Signed-off-by: Tim Nunamaker <tnunamak@gmail.com>
Add scrubbed metadata-only rows for every remaining manifest-declared Codex inventory stream, using production source-inventory paths, hashes, classifications, and reasons.\n\nAssisted-by: AI Assisted-by: AI Signed-off-by: Tim Nunamaker <tnunamak@gmail.com>
Compare fixture stream stems rather than suffix-bearing filenames so manifest inventory checks use the same ordering authority as declared stream names without changing connector emission order.\n\nAssisted-by: AI Assisted-by: AI Signed-off-by: Tim Nunamaker <tnunamak@gmail.com>
Assisted-by: AI Signed-off-by: Tim Nunamaker <tnunamak@gmail.com>
Assisted-by: AI Signed-off-by: Tim Nunamaker <tnunamak@gmail.com>
Treat the browser disconnected event as an observation for both diagnostic timestamps, and make the regression event-first without timer sleeps. Assisted-by: AI Signed-off-by: Tim Nunamaker <tnunamak@gmail.com>
Assisted-by: AI Signed-off-by: Tim Nunamaker <tnunamak@gmail.com>
Preserve canonical writes while rebuilding summary evidence under the connector-instance fence. Assisted-by: AI Signed-off-by: Tim Nunamaker <tnunamak@gmail.com>
Split expensive evidence construction from the short canonical receipt compare-and-publish fence. Remove terminal trigger lock cycles, disposable bootstrap projection writes, and fleet-global terminal folds. Assisted-by: AI Signed-off-by: Tim Nunamaker <tnunamak@gmail.com>
Assisted-by: AI Signed-off-by: Tim Nunamaker <tnunamak@gmail.com>
Assisted-by: AI Signed-off-by: Tim Nunamaker <tnunamak@gmail.com>
Allow a current-revision repair failure to publish its durable failure receipt, and stabilize the PostgreSQL cooperative-deadline restart oracle without changing production deadline semantics. Assisted-by: AI Signed-off-by: Tim Nunamaker <tnunamak@gmail.com>
Assisted-by: AI Signed-off-by: Tim Nunamaker <tnunamak@gmail.com>
Assisted-by: AI Signed-off-by: Tim Nunamaker <tnunamak@gmail.com>
Assisted-by: AI Signed-off-by: Tim Nunamaker <tnunamak@gmail.com>
Assisted-by: AI Signed-off-by: Tim Nunamaker <tnunamak@gmail.com>
Assisted-by: AI Signed-off-by: Tim Nunamaker <tnunamak@gmail.com>
Assisted-by: AI Signed-off-by: Tim Nunamaker <tnunamak@gmail.com>
Assisted-by: AI Signed-off-by: Tim Nunamaker <tnunamak@gmail.com>
Assisted-by: AI Signed-off-by: Tim Nunamaker <tnunamak@gmail.com>
Assisted-by: AI Signed-off-by: Tim Nunamaker <tnunamak@gmail.com>
Assisted-by: AI Signed-off-by: Tim Nunamaker <tnunamak@gmail.com>
…idation Eighth-review closure plus pre-submission audit findings. ops is now required on every stream expectation - validateScenario rejects missing, misaligned, or invalid entries with named reasons, and verifyStreamOps always compares; the legacy tier is deleted rather than gated (the format is unmerged and scenarios are local-only, so no real legacy corpus exists - one fewer state to maintain). STATE gets the wire validator symmetric with RECORD/INTERACTION: nonempty stream (grounded in every real emission site; the wire type alone does not annotate it), cursor property presence via Object.hasOwn preserving deliberate value opacity, malformed STATE fails recording and replay instead of disappearing. Internal closure-matrix audit before submission found one stale backward-compat comment (fixed) and one trust-by-convention soft spot: verify's emit now enforces STATE stream validity itself, so a future RunCollector bypassing the shared projection cannot silently reopen the gap. Assisted-by: AI Signed-off-by: Tim Nunamaker <tnunamak@gmail.com>
Assisted-by: AI Signed-off-by: Tim Nunamaker <tnunamak@gmail.com>
|
Closure packet — final delta (head Round-8 disposition: P1 (legacy ops-less scenarios could earn the canonical claim) → closed via the review's blessed simpler option: Pre-submission internal audit (the reviewer's own closure matrix applied to the delta before this push): one P2 found and fixed (a stale comment still describing ops as backward-compatible-optional), one P3 hardened (verify's Verification: 233-test focused batch (231 pass, 2 environment-gated skips), both real-connector spikes green under mandatory ops. Exact-head workflow runs (manually dispatched after a push-trigger drop; results are head-exact): polyfill-connectors https://github.com/PDP-Connect/pdpp/actions/runs/31829065426 ✓, reference-implementation https://github.com/PDP-Connect/pdpp/actions/runs/31829081713 ✓, docker-images in progress at packet time (passed on the content-identical prior head Deferred list unchanged. Ready for final closure review. Assisted-by: AI |
quiet: true suppresses only the library's injected tip/ad line; env loading behavior is unchanged. The three pre-existing bin scripts that share the banner (orchestrate, register-all, amazon-request-export) are base-branch files left untouched here. Assisted-by: AI Signed-off-by: Tim Nunamaker <tnunamak@gmail.com>
|
Post-approval cosmetic delta: Assisted-by: AI |
Credentials-kind fields and OTP codes now render as asterisks instead of echoing to the terminal (and thence scrollback/pane captures). Non-secret prompts are unchanged. Found by the owner during the first live browser-connector dev run. Assisted-by: AI Signed-off-by: Tim Nunamaker <tnunamak@gmail.com>
…nel on TTY The first live browser-connector run surfaced three UX defects: the readline masking hack redrew the line and erased the question text, so the operator typed into an unlabeled prompt; every credentials field masked, including usernames; and the file-drop instructions printed directly above a live terminal prompt with no indication which channel to use. Masking is now a raw-mode reader that keeps the question visible and applies only to secret-named fields; the file-drop channel prints in full only on non-TTY runs, where it is the only way in. Assisted-by: AI Signed-off-by: Tim Nunamaker <tnunamak@gmail.com>
A terminal failure line names what broke, not what to do about it. The first live browser run of this tool ended on 'venmo_probe_transport_error: Failed to fetch' after 78 seconds, with nothing to distinguish bad credentials from a stale profile, provider blocking, or a connector defect. connector-dev now prints derived next steps per failure class (transport/auth/rate-limit, with a generic fallback), including the exact PDPP_CAPTURE_ON_FAILURE invocation that retains DOM/ARIA/screenshots/traces for the failing run. Guidance is derived from the failure text, never invented. Assisted-by: AI Signed-off-by: Tim Nunamaker <tnunamak@gmail.com>
A total duration cannot tell an author where a long run went. A real ynab run took 75 minutes across 11 streams; the dominant cost was one stream (month_categories: 140 monthly windows against the connector's audited ~20s/request pacing ceiling), and the summary reported only record counts and a total. Stream summaries now carry first/last record timestamps and derived elapsed_ms - from timestamps the protocol already emits - and connector-dev prints streams slowest-first with human-scaled durations. Assisted-by: AI Signed-off-by: Tim Nunamaker <tnunamak@gmail.com>
ensureVenmoOrigin swallowed page.goto errors, leaving the page on about:blank so the auth probe fetched from an opaque origin and reported the symptom (venmo_probe_transport_error: Failed to fetch) with the cause discarded. Observed live: capture checkpoints showed the probe at about:blank with a 39-byte DOM, the page reaching venmo.com 75ms later. Navigation failure now throws venmo_origin_navigation_failed with the real error, and the landed origin is verified before returning. Note: in the observed runs the underlying cause was an unusable display (0x0 viewport) - addressed separately in browser-launch - but a swallowed goto can mask any navigation failure and is wrong independently. Assisted-by: AI Signed-off-by: Tim Nunamaker <tnunamak@gmail.com>
cfb62da to
24dacf8
Compare
Two features, entangled in connector-dev.ts by concurrent development. Iteration flags (ergonomics over existing protocol semantics - no new concepts, per the essential-complexity review of the bounded-capture idea this replaces): --streams a,b,c filters the START scope on connector-dev and scenario-record (a real ynab run took 75 minutes dominated by one paced stream; scoping makes iteration minutes), and --seed-last-state reuses the prior run's committed cursors from runs/<connector>/last-state.json for naturally short incremental live runs. scenario-verify already replayed the recorded scope verbatim - confirmed, not changed. Failure evidence (per the failure-diagnosis prior-art research): capture-on-failure is now the default in connector-dev (--no-capture or explicit PDPP_CAPTURE_ON_FAILURE=0 to opt out) - every leading tool retains by default, and opt-in retention meant the first failure was always evidence-free. The speculative free-text hints are gone, replaced by evidence pointers (failing checkpoint's URL and DOM size from the capture just written) and a closed two-rule classifier (viewport_zero, navigation_incomplete) that stays silent when no rule matches. browser-launch fails fast with named remedies when the headed browser comes up with a definitively 0x0 viewport (DISPLAY set but unusable - the four-run venmo hunt this session) instead of running toward a misleading transport error. Assisted-by: AI Signed-off-by: Tim Nunamaker <tnunamak@gmail.com>
Passing a run-summary file to scenario-verify produced a FATAL stack trace for a mistake the validator had already precisely diagnosed - and the mistake was structurally guaranteed: summaries and scenarios share runs/<connector>/, and an operator who has only used connector-dev has a directory containing exactly one file, the wrong kind. Validation rejections now print as plain verdicts; the summary-vs-scenario confusion specifically gets told what the file is, what scenarios exist in that directory, or the exact scenario-record command when none do. Assisted-by: AI Signed-off-by: Tim Nunamaker <tnunamak@gmail.com>
…outs A real scoped ynab capture died at 9m20s: run 2 was executing correctly - ynab's audited ~20s/request pacing lawfully needs ~4.5 minutes - and was SIGKILLed by a fixed 300s total-duration ceiling that assumed fast connectors. Both scenario CLIs now use an inactivity watchdog (reset on any subprocess output; --timeout <seconds> overrides the 300s window; suspended while a recording interaction waits on the operator - thinking at a prompt is not a hang). Firing produces a plain verdict with partial evidence (per-stream counts, last message seen and when) instead of a stack trace with empty stderr, and the capture is marked incomplete by rule. The run-2 progress line summarizes seeded state per stream instead of interpolating the full cursor blob into the terminal. Unit tests caught a disposal race in the watchdog itself (post-close data events could re-arm a kill against an exited subprocess). Assisted-by: AI Signed-off-by: Tim Nunamaker <tnunamak@gmail.com>
Replay wall-time was bounded by connector self-pacing running in real time - a scoped ynab replay cost the same ~4-5 minutes as its live capture, against the iterate-in-seconds goal. The first design (an env check in the shared governor) was rejected in review as concern-mixing: production machinery learning a consumer's execution mode, and covering only governor pacing while inline page-delay sleeps escaped. Time is an effect the replay environment already virtualizes (Date.now is pinned there); the replay preload now also scales setTimeout/setInterval delays by 100x - scaling, not skipping, so backoff-before-retry semantics and relative timer orderings survive (proven by an ordering fixture). Recording is untouched and paces for real. Known gap, flagged not hidden: the connector spikes carry pre-extraction inline copies of the preload and still pay real pacing - dedup debt. Assisted-by: AI Signed-off-by: Tim Nunamaker <tnunamak@gmail.com>
d89d8cb to
f537163
Compare
Settled state — exact head
f6a1eea43(33 commits), substantive suites green head-exact (polyfill-connectors and reference-implementation via dispatched runs after a push-trigger drop; prior content-identical head92f6ea8f4was 11/11 green including the full suite). Based oncodex/uat-health-candidate-0812(#125 train); retargets to main when #125 merges.What this delivers
The connector verification loop: evidence-claims vocabulary (
docs/reference/connector-evidence-claims.md), run-and-watch (bin/connector-dev.ts,pdpp.run-summary/1), scenario record/strict-replay (pdpp.connector-scenario/1,bin/scenario-record.ts/bin/scenario-verify.ts), fixture provenance labels + enforcement,connector-initscaffolding,observe-schemaobservation reports,generate-validatorsspike, and workflow docs. Proven end-to-end on the unmodified oura and spotify connectors against synthetic in-test providers (synthetic-spikeevidence class by the tools' own grounding rules — the firstnon_loopback_contact_observedcapture requires a machine with real accounts).Verification at head
Claim eligibility (all conditions independent, each with its own limitation string and negative test)
Canonical
recorded_replayrequires: registered connector identity · capture-time declaration digest · capture-time source digest · current declaration digest computed · current source digest computed · supported environment driver on every run · protocol trace on every run · OS-namespace descendant isolation · no unsupported evidence surface (ASSISTANCE) · driver evidence (recorded-http: ≥1 recorded interaction; consumption enforced by the matcher). Anything less:diagnostic_replay: PASS/recorded_replay: WITHHELD/ named limitations, plus machine-readableclaim:andscenario status: candidate oraclelines.Wire and trace contract
Untrusted subprocess output is validated before normalization: unknown message types reject on record and verify sides; RECORD requires stream/key/object-data/emitted_at with the
opdirective validated, captured, and compared (delete↔upsert mutations fail); INTERACTION prompts compare field-exactly (kind/message/canonical schema/timeout;request_idvolatile); RECORD ops are mandatory in the v1 format and STATE has symmetric wire validation.TRACE_POLICYdispositions all 13 runtime message kinds under asatisfiesclause (compile-time exhaustive); tracked kinds get field-level dispositions (compared / digested / excluded-volatile) with continuation evidence via the runtime's own validator (parity-tested on 16 curated malformed cases). Evidence labels state observed facts only:non_loopback_contact_observeduntil provider-authority policy exists;author_livewithheld by all tooling; secrets redact by default (--persist-otpopt-in).Review history
Seven independent external review rounds plus two internal adversarial passes; every P0–P2 across all rounds repaired in-branch with per-finding disposition comments. Every strictness increase caught at least one real pre-existing bug (test-order dependence, silent trace field drops, JSON-path rooting mismatch, untracked fixture labels).
Honestly deferred (per the reviews' own disposition tables)
Provider-authority policy (labels already narrowed so nothing overclaims meanwhile) · browser HAR replay driver · gmail IMAP seedable fake · subprocess-output driver (slackdump/gmcli class) · overlap/dedup/idempotence scenario fixtures · built-package digest binding (publication pipeline) · response-body field-level secret handling (scenarios remain local-only).
Assisted-by: AI