Skip to content

fix(workbook): show the decimals a value actually has - #213

Merged
lamemustafa merged 8 commits into
masterfrom
tapish-codex/workbook-number-format
Aug 24, 2026
Merged

fix(workbook): show the decimals a value actually has#213
lamemustafa merged 8 commits into
masterfrom
tapish-codex/workbook-number-format

Conversation

@lamemustafa

@lamemustafa lamemustafa commented Aug 24, 2026

Copy link
Copy Markdown
Owner

Summary

Closes #167. Every numeric cell in the consolidated workbook was written with a
fixed #,##0.00, so the stored value and the displayed value could disagree.

Root Cause / Decision Record

What failed. 0.001 displayed as 0.00 and 1.234 as 1.23. The exact
value was in the cell and the sheet showed a different one, with nothing on the
page saying so. For an artifact a practitioner reads as a working paper and
files from, a non-zero amount that renders as zero is the worst shape of defect
available: silent, wrong, and in the one output the product exists to produce.

Why not just widen the format. That moves the boundary instead of removing
it. Significant digits do not bound decimal places — 0.0000000000000001 has
one significant digit and sixteen decimals, and exactSpreadsheetNumber
admitted it on the 15-significant-digit rule alone. A wider format would render
that as zero just as the old one did, only for rarer inputs, and the defect
would be harder to find for having been "fixed".

So the writer's format and the caller's acceptance rule are derived from one
constant, XLSX_NUMBER_DECIMAL_PLACES. A value with more decimal places than a
cell can display is refused rather than rounded, taking the same
Precision limit treatment an unrepresentable value already gets. Displayed and
stored agree by construction rather than by the data being well-behaved.

Why two mandatory places. #,##0.00############# keeps the common case
looking like currency — 12.50 stays 12.50 — while # renders a digit only
when the value has one. An optional place before a mandatory one would drop the
currency look from every ordinary amount.

Scope

  • Runtime: src/core/xlsx.ts (the constant, the derived format code) and
    src/connectors/gst/filed-returns-full-year-workbook.ts (the decimal-place
    rule in exactSpreadsheetNumber).
  • Tests: format-shape assertion in tests/core/xlsx.test.ts; the decimal
    ceiling and the ordinary-amount cases in the workbook tests; the rolled
    byte-identical digest with its diff evidence.
  • Docs/governance: none. No public claim describes the number format.
  • Explicitly out of scope: the GSTR-2B workbook's own number handling, the
    exact-total string path, and Deferred review findings from the overnight run #178's deferred findings.

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

  • 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 ships in the one binary but stays out of Store-advertised scope 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 runTests 2077 passed (2077), Test Files 124 passed (124)
  • pnpm exec wxt build
  • node scripts/verify-extension-package.mjs .output/chrome-mv3
  • pnpm exec wxt zip (release-only; not run)
  • node scripts/verify-extension-zip.mjs (release-only; not run)
  • node scripts/write-release-provenance.mjs (release-only; not run)
  • 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 --required-review-author chatgpt-codex-connector before merge, with a missing Codex review recorded as an audit gap if reported. --allow-missing-head-review is dropped deliberately — see Documented review-gate commands are satisfiable without a reviewer #211.

Regenerated-workbook diff, which is the verification #167 asked for. The
workbook was built on master and on this branch from the same fixture, both
unzipped, and compared entry by entry:

  • xl/styles.xml — differs in exactly one attribute, formatCode="#,##0.00"
    becoming "#,##0.00#############".
  • Every other entry — xl/worksheets/sheet1.xml, sheet2.xml,
    sharedStrings.xml, workbook.xml, the rels and content types — byte
    identical
    .

That is the evidence that totals, the Precision limit marker and the
exact-decimal path are unchanged. The byte-identical digest was rolled once as a
consequence, and its new value is only meaningful alongside this diff.

Live run not required for this change, and here is the reasoning rather than
an assumption.
The cell values are byte-identical to the artifact already
validated against real portal data; only the display format differs, and the
format string is asserted directly. A fresh authenticated run would exercise the
same bytes. #167 offered the diff as an acceptable alternative to a fresh run,
and this is that diff.

Artifact Evidence

  • CI run: see checks on this PR
  • ZIP artifact: not produced — no release claim in this PR
  • ZIP SHA-256: n/a
  • Clean source/tag or head SHA: see the latest commit on this branch

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
#167 — number format hides accepted decimals fixed 77305bb; format and rule share one constant, pinned 17a4407
decimal ceiling counted characters, not significant digits fixed 8a25faf; counted after trailing zeros, pinned 86e9090
decimal count blind to exponent spelling (self-review) fixed plain-decimal precondition stated and pinned
precision scan covered unrendered GSTR-2B sections fixed 70df253; descends into SECTION_ORDER, pinned e1439f5
month displayed a small decimal its total called unavailable fixed 5adee30; compared as plain decimals, not as strings
scan judged unrendered itcsumm members rejected probe: refused either way, schema-invalid — see thread

Review round one found a defect in the rule this PR added, and it is the more
serious of the two. The decimal ceiling counted decimal characters, so
1.2300000000000000 — the same value as 1.23, displaying identically — was
refused. Because filed-returns-gstr2b-workbook.ts treats a null from
exactSpreadsheetNumber as unrepresentable and throws, one padded token anywhere
in a year would have refused the entire GSTR-2B workbook rather than marking
one cell. A rule added to stop one number displaying wrongly would have destroyed
the whole artifact.

The tell was four lines up: significantDigits already strips trailing zeros,
and the count I added did not — one value with two treatments inside one
function, which is the duplicate-of-a-canonical-fact shape this repo warns about.
Pinned at both levels, since the unit answer and the consequence are different
failures.

Both halves mutation-checked: reverting the format to two fixed places fails the
format-shape test and the digest; dropping the decimal-place rejection fails the
ceiling test alone.

Screenshots

None. The change is a number format inside an .xlsx part; the format string is
asserted directly in tests/core/xlsx.test.ts and the surrounding bytes are
proven unchanged by the diff above.

DCO

lamemustafa and others added 2 commits August 24, 2026 12:38
Every numeric cell was written with a fixed `#,##0.00`, so a stored `0.001`
displayed `0.00` and `1.234` displayed `1.23`. The exact value was in the cell
and the sheet showed a different one, with nothing on the page saying so -- and
a non-zero amount could read as zero on a working paper someone files from.

Two mandatory decimal places keep the ordinary case looking like currency; the
rest render only when the value has them, so `12.50` is unchanged while `0.001`
shows in full.

Widening the format alone would have moved the boundary rather than removed it,
because significant digits do not bound decimal places: `0.0000000000000001` has
one significant digit and sixteen decimals, and the old rule admitted it. So the
writer's format and the caller's acceptance rule are now derived from one
constant, `XLSX_NUMBER_DECIMAL_PLACES`, and a value with more decimals than a
cell can display is refused rather than rounded silently -- taking the same
`Precision limit` treatment an unrepresentable value already gets.

Displayed and stored now agree by construction rather than by the data being
well-behaved.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The rolled byte-identical digest carries its evidence in a comment: the
regenerated workbook was unzipped and diffed against the previously validated
one, and `xl/styles.xml` differed in exactly one attribute while every sheet,
cell value and shared string stayed byte-identical. That diff is what shows
totals, the `Precision limit` marker and the exact-decimal path are untouched --
a rolled digest asserts nothing by itself.

Both halves mutation-checked. Reverting the format to two fixed places fails the
format-shape test and the digest; dropping the decimal-place rejection fails the
ceiling test alone.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@lamemustafa
lamemustafa marked this pull request as ready for review August 24, 2026 07:09

@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: 17a4407300

ℹ️ 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/filed-returns-full-year-workbook.ts Outdated
lamemustafa and others added 3 commits August 24, 2026 12:55
A zero past the last significant digit cannot change what a cell displays, so
`1.23` and `1.2300000000000000` are the same value and must reach the same
answer. Counting characters refused the second, and the refusal direction is the
dangerous one: it reports as the guard working while withholding correct output.

The blast radius was not one cell. `filed-returns-gstr2b-workbook.ts` treats a
null from `exactSpreadsheetNumber` as unrepresentable and throws, so a single
padded token anywhere in a year would have refused the entire GSTR-2B workbook
rather than marking the value it came from.

The tell was in the two lines: `significantDigits` directly above already
strips trailing zeros, and the new count did not. One value, two treatments,
inside one function.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Two levels, because the unit answer and the consequence are different failures:
`exactSpreadsheetNumber` must accept a padded value, and the GSTR-2B builder must
still produce a workbook when a raw amount carries insignificant zeros.

Reverting the trim fails exactly those two and nothing else.

The artifact-level test asserts the workbook is not null before its length --
the defect refused it outright rather than producing a smaller one, and `tsc`
caught that the original assertion would have passed through a null.

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

The decimal count reads the digits after the point, and an exponent token has
none: `1.5e-20` counts zero decimals, passes every check, and then displays as
`0.000000000000000`. Two spellings of one value would get two answers, and the
one that slips through is the defect this function exists to prevent.

Not reachable today, and that is the reason to pin it rather than to skip it.
Every caller already converts -- the flattener runs `jsonNumberTokenToPlainDecimal`
as it parses, and the GSTR-2B scan passes the converted form -- so the guard
rejects nothing that occurs now. What it removes is an unstated precondition on
an exported function, where the next caller's mistake would be a silent zero in
a filed working paper rather than a visible refusal.

Refused rather than converted, because converting here would put a second
exponent parser beside the real one and the two would drift.

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

@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: b02260a25a

ℹ️ 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/filed-returns-full-year-workbook.ts
lamemustafa and others added 2 commits August 24, 2026 13:33
The precision scan covered the whole of `docdata`, so a value in a section this
build does not recognise reached it. Those sections are excluded from the
workbook and named in the coverage footer -- none of their values become cells --
and with the new decimal ceiling one such figure would refuse the entire
artifact over a number that is never displayed.

This is #204's shape again at one level down, and worth naming as such: that
issue was "precision refusal rejects on values the workbook never renders", and
scoping the scan to `docdata` and `itcsumm` fixed it for the siblings of those
keys while leaving the same problem inside one of them. A tighter rule made the
remaining gap reachable rather than creating it.

The scan now descends into `SECTION_ORDER` -- the same list the sheets are built
from, so a section cannot become renderable without the scan following it -- and
`itcsumm` stays whole because it is rendered whole. Written as a table of how far
to descend per subtree rather than a special case for `docdata`, so a third
rendered subtree has to state its own answer.

The fail-closed rule for a key the parser can reach and the scan cannot now
applies at the section level too.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Two cases, because the narrowing must not become a hole: an unrecognised section
carrying an unrepresentable value still builds, and an unrepresentable value
inside a rendered section is still refused.

Restoring the whole-subtree scan fails the first and only the first.

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

@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: e1439f5628

ℹ️ 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/filed-returns-gstr2b-workbook.ts
Comment thread src/connectors/gst/filed-returns-full-year-workbook.ts
`String(value)` is the shortest decimal that round-trips to the same double, and
below `1e-6` JavaScript writes that in exponent form. So `0.0000001`
stringified as `1e-7`, the lexical comparison against the plain `exactText`
failed, and the total reported itself unavailable at spreadsheet precision for a
value the double holds exactly and the widened format now displays.

The month showed the figure and the total said it could not. That is the same
stored-versus-shown disagreement this branch exists to remove, one column over,
and this change is what made it reachable: seven decimal places only became
displayable here.

Compared as plain decimals through `jsonNumberTokenToPlainDecimal` rather than
as strings, so two spellings of one value stop giving two answers -- the same
correction as the trailing-zero round, in the other direction.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@lamemustafa
lamemustafa merged commit 01e3582 into master Aug 24, 2026
14 checks passed
@lamemustafa
lamemustafa deleted the tapish-codex/workbook-number-format branch August 24, 2026 09:05
@lamemustafa

Copy link
Copy Markdown
Owner Author

Recording the audit gap for the merged head, per docs/AGENT_REVIEW_RECTIFY.md.

5adee308 was merged without a bot review of that head. The reviewer examined 17a44073, b02260a2 and e1439f56 across three rounds, and did not see 5adee30 — the fix for its own final finding, where a month displayed a small decimal its total called unavailable. The only reviews at the merged head are my own thread replies, which is #211 and not evidence.

Verified on merged master 01e3582, in a clean tree: Tests 2077 passed (2077), Test Files 124 passed (124), plus tsc, eslint, prettier, wxt build and verify-extension-package all clean.

A correction to how that was measured, because the first attempt was wrong. I ran those gates in the primary checkout, which turned out to hold ~900 lines of another session's uncommitted work across 17 files. It reported Tests 2086 (2086) over 125 files — nine tests and one file that are not on master and would never run in CI. The numbers above are from a tree whose content is byte-identical to origin/master. The conclusion did not change; the measurement did, and a verification run in a dirty tree is not a verification of what merged.

Not covered by any of this. No live authenticated run was performed for #213, and the reasoning is in the PR body rather than assumed: the regenerated workbook was diffed entry by entry against the previously validated artifact, and every sheet, cell value and shared string was byte-identical — only xl/styles.xml differed, in the one format attribute. #167 offered that diff as an acceptable alternative to a fresh run.

The rejected finding is recorded in its thread with the probe that refuted it, not as an assertion.

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.

Workbook number format hides accepted decimals beyond two places

1 participant