Skip to content

fix(capture): stop waiting when the portal shows the GSTR-1 no-details dialog - #390

Merged
lamemustafa merged 5 commits into
masterfrom
tapish-codex/gstr1-no-details-early
Sep 21, 2026
Merged

lamemustafa merged 5 commits into
masterfrom
tapish-codex/gstr1-no-details-early

Conversation

@lamemustafa

@lamemustafa lamemustafa commented Sep 17, 2026

Copy link
Copy Markdown
Owner

Summary

Part of #386 (approved by the owner). A live timing probe on 2026-09-17 showed every GSTR-1 Excel capture in a full-year run ended in generation-timeout at 20003–20006 ms, 5 of 5, while GSTR-1 PDFs took 40–160 ms. The portal shows a no e-invoice details dialog instead of creating a file, and the capture waited out the full 20 s before the post-click inspection recognised the dialog. One run spent 100 s of pure waiting on GSTR-1 alone.

The capture now stops waiting as soon as the portal's no-details dialog opens after its click, finishing with the same generation-timeout reason. Everything downstream is unchanged: checkpoint retention, the post-click inspection, and the refusal binding to the exact target (bindGstr1DetailRefusal), which is what actually decides the period has no Excel.

Root Cause / Decision Record

  • The detection already existed and was sound; it ran 20 s late. detectGstr1ExcelNoDetails matched two text patterns and bound the refusal. Those two patterns move to a leaf, src/connectors/gst/gstr1-excel-no-details-text.ts, read by both the inspection and the capture, so there is one definition.
  • Passed as regex sources in the capture's arguments. capturePortalPdfBlob is serialised into the page by scripting.executeScript, so it can import nothing; the existing rebuildInMainWorld test exercises the early stop through that serialisation.
  • Only a dialog that appears after the click counts. The inspection's own comment warns that a dialog left standing by an earlier target can still be on screen. If the patterns already match before the click, early stopping is disabled and the timer decides, as today.
  • The same reason, deliberately. A new reason would widen the reason union, the retention list, messages and the durable signal allowlist. Stopping early changes when the existing path runs, not what it concludes. If the dialog cannot be bound to the target, the failure stands exactly as it would have at 20 s.
  • Only GSTR-1 Excel watches. GSTR-1 PDF and every GSTR-2B and GSTR-3B capture pass no patterns and behave exactly as before.
  • Scoped to the open dialog, from a live capture. Review of the first version found it matched page-wide text, so wording elsewhere could stop a capture early. A structural capture on 2026-09-21 (recorded as finding fix(release): make release PRs pass Pack gates #36, structure only) shows the answer is a Bootstrap modal: div.modal.fade.fade-scale.in[role="dialog"] > .modal-dialog.sweet > .modal-content > .modal-body > p. The early stop now reads only visible elements matching [role="dialog"].modal.in (GSTR1_EXCEL_NO_DETAILS_DIALOG_SELECTOR, beside the text patterns). Text outside such a dialog, a closed modal, a hidden one, or one carrying only one phrase does not stop it.
  • Polling, not a MutationObserver. A 250 ms interval, cleared on settle. Background-tab throttling can only make it later, never earlier than the dialog.
  • Not in this PR: the GSTR-3B timeout value. The same run had one GSTR-3B timeout among five captures (others 0.25–2.1 s); more samples first, as recorded on fix(capture): the 20s portal PDF generation timeout is unmeasured and forces repeated retries #386.

Scope

  • Runtime: portal-blob-shim.ts (optional stopWhenDialogShows: { selector, textPatterns }, pre-click guard, poll); filed-returns-post-click-blocked-state.ts (reads the shared patterns); new leaf gstr1-excel-no-details-text.ts; gstr2b-artifact-acquisition.ts (passes the patterns for GSTR-1 Excel only).
  • Tests: shim early stop (through the main-world rebuild), no early stop for a pre-existing dialog, a file arriving while watching still captures, one pattern alone does not stop; acquisition passes the patterns only for GSTR-1 Excel.
  • Docs/governance: docs/PORTAL_INTEGRATION_FINDINGS.md fix(release): make release PRs pass Pack gates #36, the captured dialog structure and the measured timings (no page text, identifiers or HTML).
  • Explicitly out of scope: GSTR-3B timeout sizing (fix(capture): the 20s portal PDF generation timeout is unmeasured and forces repeated retries #386), the qualification timing probe (branch only).

Live verification

Needed. On the qualification build, run a GSTR-1 full year: periods without e-invoice details should settle in about a second instead of 20 s, still reading Saved · some formats not on portal, and the probe's GSTR-1 Excel rows should show short elapsed times.

Pack Workflow Preflight

  • pnpm workflow:preflight was run before editing/push, or the skip reason is documented.
  • This PR was opened from a Pack branch, not master.
  • I checked latest master Pack AGENTS guidance or recorded the stale-guidance warning.
  • PR body keeps the required Pack privacy/review/verification checklist visible.

Sanchika Adoption Gate

Not applicable: no Sanchika adoption.

  • If this PR consumes @sanchika/* packages or copied Sanchika guidance, I
    read sanchika/docs/adoption-pack.md in the coordinated parent worktree.
  • If this PR consumes Sanchika, it links ComplyEaze and Axal completion evidence
    and records the Sanchika commit or copied guidance used.
  • This PR does not import ../sanchika, sanchika/packages/*/src, or parent
    source paths.

Privacy And Data-Flow Impact

  • No new browser permissions.
  • No new host permissions.
  • No new network calls.
  • No analytics, telemetry, ads, or session replay.
  • No credential, OTP, CAPTCHA, cookie, token, GST file, or taxpayer-data capture.
  • Public copy and privacy declarations are updated if behaviour changed — no user-facing copy changed.

Sensitive Surface Review

  • Current tab / portal target binding is preserved or intentionally changed.
  • Download completion remains evidence-backed and fail-closed.
  • Ambiguous side-effect delivery cannot be reported as confirmed success.
  • Service-worker durability impact is understood and documented.
  • Real taxpayer data, local paths, raw URLs/referrers, and portal HTML are absent from the diff.

Chrome Web Store Impact

  • This PR does not expand beyond the existing Chrome Web Store V0 listing unless every gate in docs/PUBLICATION_READINESS.md is checked.
  • Full fiscal year remains source-only and excluded from the next packaged Store build until its evidence gates are recorded.
  • Store copy, README status, Privacy QA, and reviewer instructions were reviewed if user-facing behavior changed — no user-facing copy changed.
  • CI ZIP creation, provenance, and protected publishing are treated as release evidence, not manual store-submission sign-off.
  • PR title uses Conventional Commits so Release Please can bump Pack after merge.

Verification

  • pnpm install --frozen-lockfile
  • pnpm audit --audit-level high
  • pnpm exec wxt prepare
  • pnpm exec prettier --check .
  • pnpm exec eslint . --max-warnings 0
  • pnpm exec tsc --noEmit
  • pnpm exec vitest run
  • pnpm exec wxt build
  • node scripts/verify-extension-package.mjs .output/chrome-mv3
  • pnpm exec wxt zip
  • node scripts/verify-extension-zip.mjs
  • node scripts/write-release-provenance.mjs
  • node scripts/verify-github-release-assets.mjs --tag <tag> --zip <zip> --checksum <sha256> --provenance <json> when release assets exist
  • node scripts/publish-chrome-web-store.mjs --zip .output/<zip> --provenance .output/pack-release-provenance.v1.json --publisher-id <id> --dry-run true
  • git diff --check
  • pnpm review:gate -- --strict-head-review --wait-head-review-ms 180000 before merge/readiness claim; a missing Codex review blocks readiness:

Artifact Evidence

  • CI run:
  • ZIP artifact:
  • ZIP SHA-256:
  • Clean source/tag or head SHA:

PR Review Follow-Up

  • GitHub Actions completed.
  • Autogenerated Codex/bot review comments inspected after checks completed for the latest head SHA.
  • Inline review threads are resolved, outdated, or answered with evidence.
  • No commits were pushed after the last required human/bot review without re-review.
  • Any follow-up PRs or issues are listed here instead of being left implicit.
Thread/comment Disposition Commit or evidence
Local Sonnet re-review: scoping, .in as Bootstrap 3's open marker (removed at hide-start), serialisation via the main-world rebuild test, docs entry #36 carries no sensitive data, one test per guard confirmed 43/43 in the shim suite
Local Sonnet re-review, note: a full-year run does not dismiss the previous period's dialog, so if it is still open at the next click the pre-click guard disables the early stop for that period accepted, measure live falls back to the old 20 s timer (never a wrong early stop); the qualification probe's GSTR-1 Excel timings will show whether only the first period benefits, in which case dismissing the portal's own dialog is a follow-up
Local Sonnet review, Medium: early stop matched page-wide text fixed live structural capture (finding #36); scoped to visible [role="dialog"].modal.in; commits dc0c9fa, 8fbb597, 000c5ec

Screenshots

Use synthetic data only.

Verification detail

Exit codes captured directly: prettier 0 · eslint 0 · tsc 0 · build 0 · package verification 0 · git diff --check 0 · workflow preflight passed.

All tests related to the four changed modules: Test Files 25 passed (25), Tests 1014 passed (1014).

Driven to failure, each on its own: matching the whole page instead of the dialog selector fails the text-outside-a-dialog test; removing the pre-click guard fails the already-open test; everysome fails the one-phrase test; removing the visibility check fails the hidden-dialog test; watching for every GSTR-1 artifact fails the wiring test for GSTR-1 PDF.

One test fixture note: jsdom has no innerText, and its textContent joins the button's text to the dialog's ("DownloadNo details"), which defeats the word boundary; the fixtures separate them with a newline, as a browser's innerText does.

🤖 Generated with Claude Code

lamemustafa and others added 2 commits September 17, 2026 11:48
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…s dialog

A GSTR-1 period without e-invoice details spent the full 20 s generation
timeout waiting for a file the portal never creates. The capture now
stops as soon as the no-details text newly appears after its click, with
the same reason, so the bound post-click inspection decides as before.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@lamemustafa

Copy link
Copy Markdown
Owner Author

Review round 1 (local Sonnet): held as draft

Confirmed safe: serialisation (self-contained; only globalThis timers, document, regexes built from arguments), timer hygiene (interval created after every early return, cleared on settle), refactor parity (String.raw sources identical to the removed literals), privacy (no new egress, logging or persistence).

Medium, accepted as the reason to hold: the early stop matches the two patterns against the whole page's innerText, not a specific dialog. Text newly visible after the click that is not this click's answer would stop the capture at once. The bound post-click inspection still prevents a false no Excel outcome (the target stays a failure, with review and retry), but a real file arriving afterwards would land as an unobserved browser download.

Correction to part of the review's reasoning: the download safety net would not have caught that on today's path either. installPortalBlobDownloadSafetyNet cancels only downloads matching a captured blob's fingerprint, and bind runs only on a successful capture, so after any failed capture, the 20 s timeout included, a late file is equally unobserved. The exposure is the same kind; what changes is how cheaply a non-answer can trigger it.

Next: scope the match to the portal's dialog element rather than page text. Per AGENTS (capture before spec), that needs a live structural capture of the dialog: element chain, roles and visibility only, no text or portal HTML pasted anywhere. Until then this stays draft.

lamemustafa and others added 3 commits September 21, 2026 14:40
…rap modal

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
… dialog

Review of the first version found it matched page-wide text, so wording
elsewhere could stop a capture early. A live capture shows the answer is
an open Bootstrap modal; the early stop now reads only visible
[role=dialog].modal.in elements.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@lamemustafa
lamemustafa marked this pull request as ready for review September 21, 2026 09:20
@lamemustafa
lamemustafa merged commit 4a61744 into master Sep 21, 2026
13 checks passed
@lamemustafa
lamemustafa deleted the tapish-codex/gstr1-no-details-early branch September 21, 2026 09:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant