Repository navigation
Description
Summary
The Bitwarden extractor added today in PR #2987 (#1111) parses the dated bws counts with bare \d+, so a comma-grouped count is silently truncated to its last group — and the wrong figure then flows into the snapshot store as a permanent record. 1,121 secrets is recorded as 121 (indistinguishable from a real 121 read) and 1,000 projects is recorded as 0.
Evidence (main 74afc26e)
pm-stack/aggregator/src/saas-extract.ts:475-478 (bitwardenMetrics, added by commit 795bbdb4, merged in #2987):
const secrets = /(\d+)\s*secrets?/i.exec(usage);
const projects = /(\d+)\s*projects?/i.exec(usage);\d+ cannot cross the comma, so the regex engine slides forward and matches only the final digit group before the noun: for 1,121 secrets it matches 121 secrets; for 1,000 projects it matches 000 projects → Number("000") = 0.
Verified this run on the laptop with the real extractSaasServices (laptop clone at the same main, saas-extract.ts md5 2b540acdb7924e834941a63b0416cf44 on both clones; probe ~/git/fleet/probe-2026-10-31-laneB-bwcomma/):
Usage bullet: "1,121 secrets, 1,000 projects (bws count-only read 2026-10-26)"
measuredAt 2026-10-26
secrets-count used = 121 ← want 1121
projects-count used = 0 ← want 1000
control ("121 secrets, 1 project"): secrets-count = 121, projects-count = 1
Note the corrupted secrets figure is identical to the control — there is no signal in the output that anything was lost.
Why it matters
- These metrics are not display-only: the extractor's commit message and
recordsFromSaasServices(pm-stack/aggregator/src/snapshot-records.ts:85, called fromscripts/collect-fleet-feed.ts:598andscripts/append-usage-snapshots.ts:67) turnusedinto durable snapshot records keyed by (service, metric, ts, value). A misparsed count becomes wrong history, not a transient render glitch. - Every sibling extractor in this codebase already handles grouped numbers:
parsePriceUsdindns.tsand the DeepSeek ¥ parse insnapshot-records.ts:177use[\d,]+and strip commas; the Cloudflare limits in the same file parse10M-style figures. The new extractor (merged hours ago) is the outlier, and its own test fixture only exercises ungrouped counts (121 secrets, 1 project), so the gap is invisible to the suite. - The Modal extractor added in the same commit has the same
\d+-only shape for its dollar figures (saas-extract.ts:448-455); there the failure is fail-soft (a$1,250 credits usedread matches nothing and stays null). Triage should decide whether to harden it in the same pass or leave it as a noted sibling.
Acceptance criteria
-
bitwardenMetricsparses comma-grouped counts at face value:1,121 secrets→ 1121,1,000 projects→ 1000 (accept the house[\d,]++ strip-commas form, or an equivalent grouped-number parse). - Regression tests in
pm-stack/aggregator/test/usage.test.tscover grouped secrets and projects counts alongside the existing ungrouped case. - Ungrouped reads are unchanged (
121 secrets, 1 project→ 121 / 1), and a bullet with no counts still yields no metrics. - Triage rules on the Modal comma-dollar sibling (same-commit
\d+-only patterns): fix in the same change, or record it as an explicit follow-up — not silently left.
Dedup
Searched open and closed issues for bitwarden, bws count, and comma/thousands parsing in saas-extract on 2026-10-31: no existing issue covers this extractor (it landed today in #2987). The extractor's parent work is #1111 / #2990 (per-credential rows and remainders — different items). Sibling number-reinterpretation issues (#2985 aa.ts num(), #2791 cloudflare-export num()) concern different functions that reinterpret non-decimal strings; this one truncates a grouped decimal.
Activity
dezren39 commentedon Oct 31, 2026
🤖 Agent note · filed
new-issue-creator-code-b)new-issue-creator-code-b, run 2026-10-31T08:50ZextractSaasServices(main74afc26e,saas-extract.tsmd52b540acdb7924e834941a63b0416cf44on both clones) that the Bitwarden extractor added today in feat(usage-hub): modal used-credits + bitwarden bws count extractors (#1111) #2987 parses1,121 secretsas 121 and1,000 projectsas 0 — its bare\d+patterns (saas-extract.ts:477-478) match only the last comma group, while sibling extractors use[\d,]++ strip. The wrong counts flow into snapshot records viarecordsFromSaasServices.~/git/fleet/probe-2026-10-31-laneB-bwcomma/(laptop); evidence body in the goal hidden_files (issue-code-bitwarden-comma-count-body.md)dezren39 commentedon Oct 31, 2026
🤖 Design-architect pass 25 (2026-10-31) — agent note: this issue is ADOPTED as Phase 2 (with #3000) of design #3005 (a measurement is a plain decimal), linked as its sub-issue and labelled
source/design-architect. Triage: do NOT re-file, re-scope, or split it; record the phase structure instead. The design records the prose form of the grammar: count extractions capture the grouped form ([\d,]+, strip commas — the house idiom indns.ts parsePriceUsdandsnapshot-records.ts:177); grouping well-formedness is stripped, not validated. The Modal comma-dollar sibling this issue names for a triage ruling is ruled IN by the design: fix it in this phase — same file, same defect, same probe matrix — not as a follow-up. Flag genuine blockers on #3005.51 remaining items
dezren39 commentedon Nov 2, 2026
agent-note:v1 — holder: repo-worker-code (OpenChamber scheduled lane), at 2026-11-02T14:57:00Z. event: picked-up; task: 5505; queue: repo-health-code-pilot. Fresh metadata: #2997 OPEN; canonical PR #4289 OPEN and authored/assigned to Drew. No PR contents, checks, reviews, branch, worktree, or source inspected.
dezren39 commentedon Nov 2, 2026
agent-note:v1 — holder: repo-worker-code (OpenChamber scheduled lane), at 2026-11-02T14:58:00Z. event: parked; task: 5505; queue: repo-health-code-pilot. Canonical PR #4289 remains OPEN, non-draft, Drew-authored/assigned; hard stop per this runbook. This lane did not inspect/touch PR contents, checks, reviews, branch, worktree, or source and created no competing PR. Resume after PR disposition or explicit ownership handoff, then revalidate fresh.
dezren39 commentedon Nov 2, 2026
🤖 Agent note · done
queue/5505-2997-grouped-numberwith no hard-stop labels — the earlier "Drew-owned" park note was the known shared-account (dezren39) false positive, not a real hard stop.saas-extract.ts(Bitwarden counts and Modal dollar patterns strip comma grouping beforeNumber), with grouped regressions; recorded verification:bun test test/usage.test.ts41 pass, aggregator suite 1017 pass,git diff --checkpass. Codex review on PR fix(aggregator): parse grouped SaaS metrics #4289: completed, no findings.