Skip to content

fix(gst): bind a GSTR-2B refusal to the period on screen - #355

Closed
lamemustafa wants to merge 14 commits into
tapish-codex/gstr2b-not-generated-outcomefrom
tapish-codex/gstr2b-refusal-period-binding
Closed

fix(gst): bind a GSTR-2B refusal to the period on screen#355
lamemustafa wants to merge 14 commits into
tapish-codex/gstr2b-not-generated-outcomefrom
tapish-codex/gstr2b-refusal-period-binding

Conversation

@lamemustafa

@lamemustafa lamemustafa commented Sep 11, 2026

Copy link
Copy Markdown
Owner

Summary

The GSTR-2B refusal is now bound to the period visible on screen, and the page-identity signals it
carries are registered as durable.

The summary route does not change per period and keeps rendering whichever period it last loaded. Read
without its header, one period's refusal answered for every later period: a live run reported twelve periods
processed after a single navigation, while the page still read April.

Root Cause / Decision Record

What failed, twice.

First, the refusal was recognised without checking the visible header. For a taxpayer with a statement in
some months and not others, that silently marks drafted months absent and skips their downloads — a
confident wrong answer rather than a stall.

Second, once the refusal was recorded the step became terminal, so its signals were persisted for the
first time. One of them had never been registered — it had only ever ridden a transient ready step, whose
signals never reach durable state. One unregistered member rejects the entire array, so every period the
portal declined was stored as needing review instead.

Why this is the smallest safe fix. The guard already existed and already failed closed; it simply was not
consulted on this path. Both the refusal branch and the download-ready branch asked the same question in the
same six lines, so it now has a name. The signals are registered rather than suppressed, because they are the
evidence that the period was verified before the refusal was recorded.

Also here. Two hand-written status-to-outcome mappers in the all-returns path each ended in a
needs-review default, so the same period read as resolved in one run type and as needing a person in the
other. Both now call the exhaustive record the single-return path already used.

Scope

  • Runtime: GSTR-2B flow period binding and shared page guard, summary-route predicate, durable signal registration, all-returns outcome mapping, panel pause labelling.
  • Tests: Refusal bound to the visible period, stale-page recovery, fail-closed on an unreadable header, terminal-step signal durability, both run types reporting a declined period alike.
  • Docs/governance: docs/PORTAL_INTEGRATION_FINDINGS.md — the refusal panel outliving the period it was loaded for.
  • Explicitly out of scope: Adding GSTR-1 and GSTR-2A JSON to the artifact catalogue; recording coverage inside the ZIP. Both are follow-ups.

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

  • 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.

Sensitive Surface Review

Target binding is intentionally strengthened: a portal refusal is recorded only when the visible header confirms the requested period, and an unreadable header fails closed to navigation rather than to a recorded outcome. Signals reaching durable state for the first time are registered, and a test asserts every terminal step's signals survive the durable parser.

  • 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.
  • 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

No release artifact in this PR; it ships no ZIP and changes no release metadata.
Verification above was run on this branch in an isolated worktree, so the result is the branch's own and not
the stack tip's.

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
r3985761177 — redact authenticated route and filing status part fixed, part rejected 708f12e — the filing status is removed (this file publishes no such value on master; count is zero), plus a third instance of the same class the review did not flag. The route is rejected with evidence: /returns/auth/gstr1 is already published in this file on master alongside four other routes, and is exported as GSTR1_DETAIL_PATH in src/connectors/gst/portal-artifact-endpoints.ts:19. Reasoning on the thread.
r3985761185 — remove taxpayer filing metadata fixed 708f12e — the claim about the return is replaced by the portal's rule, with its own advisory quoted as the evidence for it

One P1 finding was partly rejected. The route half of r3985761177 is not redacted, on the
grounds that the repository already publishes that path in this same file and as an exported
source constant, and that a finding about which surface carries a control cannot be recorded
without naming the surface. That judgement is flagged here rather than left inside a resolved
thread, so it can be overridden before merge if the narrower reading was intended.

Screenshots

Use synthetic data only.

Stacking

Stacked on #354 (tapish-codex/gstr2b-not-generated-outcome), which is stacked on #353. Review in
order: 353, then 354, then this.

The summary route does not change per period and keeps rendering whichever period it last loaded, so a refusal read without its header answered for every later period in a fiscal-year run. One live run reported twelve periods processed after a single navigation, while the page still read April. For a taxpayer with a statement in some months and not others, that silently marks drafted months as absent and skips their downloads.

The refusal is now recorded only when the visible header confirms the requested period, and the guard fails closed: an unreadable header is could not determine, never matches. A page showing some other period is left rather than answered for.

Both the refusal branch and the download-ready branch asked that same question in the same six lines, so it has a name now.

Registering the page-identity signals is the other half. They were transient while the only step carrying them was the ready hand-off, whose signals never reach durable state; recording the refusal made them terminal. One unregistered token rejects the whole array, so every period the portal declined was stored as needing review instead.
The transient ready step carried an unregistered token harmlessly for months, so the guard asserts the property that actually matters: a step whose signals get persisted must produce signals the durable parser accepts.
Both pause reasons can render at once, and unlabelled they read as one contradictory statement: a live run showed could not start a full fiscal year run, the all-year plan's reason, directly above a single-return run that had started and processed twelve periods.
The single-return fiscal-year path maps a target status to an outcome through an exhaustive record, so a status it has not been told about fails to compile. The all-returns path kept two hand-written copies of that mapping, each ending in a needs-review default that silently absorbed one.

A period the portal declined to generate therefore read as resolved in one run type and as needing a person in the other, and a run of everything stopped on periods that could never change while the same year run for one return completed and exported its ZIP.

Both copies now call the shared record.
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 11, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-12T00:15:18.172345Z e881215 New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0e6fe9e31d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread docs/PORTAL_INTEGRATION_FINDINGS.md Outdated
Comment thread docs/PORTAL_INTEGRATION_FINDINGS.md Outdated
Comment thread docs/PORTAL_INTEGRATION_FINDINGS.md
Comment thread src/connectors/gst/gstr2b-summary.ts
Comment thread src/connectors/gst/gstr2b-flow.ts
Two review findings, both correct on the values and one over-broad on the route.

A filing status read from a live authenticated page, and a statement that the taxpayer reports no e-invoices, are both facts about a return rather than about the portal. Neither is needed: the findings are that the detail route can carry the control, and that the portal returns an unavailable-workbook modal when a period has no e-invoice records. Both now state the portal's rule, with its own advisory quoted as the evidence for it.

A third of the same class was not flagged and is gone too -- a period name quoted from the stale header. The finding is that the panel keeps rendering whichever period it last loaded, which does not need the period named.

The route itself stays. It is already published in this file on master and exported from src/connectors/gst/portal-artifact-endpoints.ts as GSTR1_DETAIL_PATH, so it discloses nothing this repository does not already state, and the finding cannot be recorded without naming the surface it is about.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 708f12e4fe

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/connectors/gst/gstr2b-flow.ts
Comment thread docs/PORTAL_INTEGRATION_FINDINGS.md Outdated
`verifyVisibleGstr2bPeriod` accepted the page's own inline configuration in
place of the header a reader can see. Two callers reach it and they are not
alike: a download click may lean on that configuration, because the file it
produces is correlated to the target before the target counts as complete; a
refusal may not, because it resolves the target outright and no artifact
follows to corroborate it.

So an unlabelled refusal panel whose inline config happened to match resolved
a period as not-generated and advanced a fiscal-year run, emitting
`gstr2b-visible-period-verified` for an identity nothing visible confirmed.

The refusal path now asks for visible evidence and the signal tells the truth.
The branch ordering also collapses: complete labels or the statement heading
pass, inline config passes only where it is allowed to.
Fails without the guard: the unlabelled panel records the period instead of
leaving it.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a2316bdf9e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread tests/connectors/filed-returns-flow-gstr2b-not-generated.test.ts Outdated
…d-outcome' into tapish-codex/gstr2b-refusal-period-binding
The post-click path inherits the binding from its base; this holds it to the
stricter reading introduced here. A refusal resolves its target outright and no
artifact follows to corroborate it, so the page's own inline configuration
cannot stand in for a header a reader can see -- on either path.

Both refusal paths now pass `requireVisibleEvidence`. The download path still
does not, because its file is correlated to the target before the target counts.
Fails when the flag is dropped at that call site.
…efect

The comment named how many periods one live run found unavailable, which is a
fact about that taxpayer's returns rather than about the persistence bug it was
explaining. The bug is that every declined period came back as needs-review; the
count was never part of it.
…codex/gstr2b-refusal-period-binding

The GSTR-1 findings entry existed on both sides. Kept the base's: it describes
the control row structurally instead of reproducing captured portal copy, and
it drops a sentence about the captured return's own filing state, which is a
fact about a taxpayer rather than about the portal's surfaces.

The sections below it are this branch's and are unaffected.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e881215e75

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread docs/PORTAL_INTEGRATION_FINDINGS.md
Comment thread src/connectors/gst/gstr2b-flow.ts
@lamemustafa

Copy link
Copy Markdown
Owner Author

The corrected consolidated candidate is #359, based directly on master. This PR is retained as draft with its commits and review history intact; its unchanged head is not independently merge-ready. The #359 body maps every original automated ask to specific source/test evidence or an explicit held follow-up. Authenticated runtime qualification remains required before merging the replacement.

@lamemustafa
lamemustafa marked this pull request as draft September 12, 2026 11:12
@lamemustafa

Copy link
Copy Markdown
Owner Author

Superseded by #359. Its disposition register records the final status of this draft’s review asks. This draft is being closed; resolving its remaining threads marks them superseded, not fixed on this unchanged branch.

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