9.5 KiB
9.5 KiB
Tasks — @suaveplan/password-strength (zxcvbn-style password strength estimator)
Every checkbox MUST reflect work actually done in this change. Do not retroactively tick boxes for work that was already in main when this change opened. Do not tick a box for a test that doesn't exist or doesn't pin the requirement it claims to verify.
1. Spec authoring
- 1.1 Read Wheeler 2016 USENIX paper end-to-end; record line-anchored citations into per-pattern
.mdfiles - 1.2 Read
dropbox/zxcvbnreference impl (matching.coffee, scoring.coffee, time_estimates.coffee, feedback.coffee, frequency_lists.coffee, adjacency_graphs.coffee) - 1.3 Read
../suaveplan/enterprise/password-strength.mdend-to-end - 1.4 Read
openspec/AGENTS.mdSections 13 and 14 - 1.5
proposal.mdauthored fromopenspec/templates/proposal.md - 1.6
## Source mappingtable populated; "no source line" justifications written - 1.7
specs/password-strength/spec.mddelta drafted fromopenspec/templates/spec-delta.md - 1.8 Every requirement in the spec delta carries a
**Verified by:**line naming concreteit(...)titles
2. Package scaffold
- 2.1
packages/vault/password-strength/src/{matchers,scoring,assess,feedback,dicts,graphs,errors,schemas,observability,__benchmarks__}/structure - 2.2
package.json—@suaveplan/password-strength@0.0.0,type: module,sideEffects: false, deps viaworkspace:^/catalog:* - 2.3
tsconfig.lib.jsonextends@suaveplan/typescript-config/library - 2.4
vite.config.ts+vitest.config.ts(usescreateTestConfig()) - 2.5
README.mdwith Modules table linking every co-located.md - 2.6 Subpath
exportsmap covers root + every feature subpath listed in the proposal
3. Implementation — pattern matchers
- 3.1
src/matchers/dictionary/dictionary.ts— frequency-ranked lookup, l33t enumeration, reverse-string lookup - 3.2
src/matchers/sequence/sequence.ts— alphabetical + numeric, both directions, length ≥ 2 - 3.3
src/matchers/repeat/repeat.ts— greedy chunk regex; recursivebaseGuesses - 3.4
src/matchers/date/date.ts— separator + no-separator;1900 ≤ year ≤ now + 50 - 3.5
src/matchers/keyboard/keyboard.ts— adjacency-graph walk;turns+shiftedCount; pluggable graph - 3.6
src/matchers/regex/regex.ts— recent-year + registry-pluggable
4. Implementation — bundled dictionaries
- 4.1
src/dicts/en/{passwords,english_wikipedia,male_names,female_names,surnames}.ts— frozenMap<string, number>rank tables - 4.2
src/dicts/de/,src/dicts/fr/,src/dicts/es/,src/dicts/zh-Hans/,src/dicts/ru/— Wikipedia top-30k per locale - 4.3
src/dicts/load-dictionaries.ts— runtime swap returning freshDictionarySet;DICTIONARY_INVALIDon bad rank/token
5. Implementation — keyboard graphs
- 5.1
src/graphs/qwerty/qwerty.ts— QWERTY adjacency table - 5.2
src/graphs/dvorak/dvorak.ts— DVORAK adjacency table - 5.3
src/graphs/azerty/azerty.ts— AZERTY adjacency table - 5.4
src/graphs/validate-graph.ts—GRAPH_INVALIDon self-adjacency / non-symmetric edges
6. Implementation — scoring
- 6.1
src/scoring/most-guessable-match-sequence.ts—n^2DP; lowest-product cover; factorial penalty; fewest-matches tie-break - 6.2
src/scoring/estimate-guesses.ts— per-pattern closed forms (dictionary, sequence, repeat, date, keyboard, regex) - 6.3
src/scoring/crack-times.ts— four scenarios;adjustmentsmultiplier map - 6.4
src/scoring/score.ts— five-bucket score function
7. Implementation — public API
- 7.1
src/assess/assess.ts— full pipeline;userInputs; custom dictionaries; 200-char DoS guard withINPUT_TOO_LONG - 7.2
src/assess/assess-reactive.ts— debounce + cancel-on-newer;AbortSignalthreading;ABORTEDon cancellation - 7.3
src/feedback/feedback.ts— keyed strings via injected resolver; English fallback;RESOLVER_FAILEDon resolver throw
8. Implementation — errors + schemas + observability
- 8.1
src/errors/error-codes.ts—defineCodes("PWSTRENGTH", […])with 6 codes;PasswordStrengthError - 8.2
src/schemas/*.ts—AssessOptionsSchema,FeedbackOptionsSchema,AssessReactiveOptionsSchema,CrackTimeOptionsSchema,MatchSchema,StrengthResultSchema - 8.3
src/observability/metrics.ts—pwstrength.assess_duration_ms,pwstrength.score_distribution_total,pwstrength.errors_total,pwstrength.matchers_run_total
9. Root barrel + subpath exports
- 9.1
src/index.ts— explicit named re-exports (noexport *) - 9.2 Every feature dir has its own barrel using explicit named exports
- 9.3 Subpath export count in
package.jsonmatches feature module count
10. Documentation
- 10.1 Sibling
.mdfor every implementation.ts(≥200 words, basic + advanced examples, full API reference, Wheeler line citation in Implementation Notes) - 10.2 README links every co-located
.mdunder## Modules - 10.3 CLAUDE.md package listing updated under
#### Vault orchestration(or appropriate section)
11. Tests
- 11.1
src/matchers/dictionary/dictionary.test.ts— l33t / reverse / rank / every bundled dict - 11.2
src/matchers/sequence/sequence.test.ts— ascending + descending; lower/upper/digits - 11.3
src/matchers/repeat/repeat.test.ts— single + multi-char chunks; recursivebaseGuesses - 11.4
src/matchers/date/date.test.ts— separator + no-separator; year bounds; ambiguous-parse preference - 11.5
src/matchers/keyboard/keyboard.test.ts— QWERTY walks; turns; shifted-count; DVORAK + AZERTY swap - 11.6
src/matchers/regex/regex.test.ts— recent-year; custom regex registration - 11.7
src/scoring/most-guessable-match-sequence.test.ts— empty / single / multi cover; factorial; fewest-matches tie-break; recursive repeat - 11.8
src/scoring/estimate-guesses.test.ts— closed-form per pattern; corpus agreement ≤1 bit log10 - 11.9
src/scoring/crack-times.test.ts— four scenarios;adjustments; humanized strings - 11.10
src/scoring/score.test.ts— every bucket boundary (1e3 - 1,1e3,1e6 - 1,1e6, …,1e10) - 11.11
src/assess/assess.test.ts— full pipeline;userInputs; custom dictionaries; 199-char accept / 200-char reject - 11.12
src/assess/assess-reactive.test.ts— debounce; cancel-on-newer;AbortSignal - 11.13
src/feedback/feedback.test.ts— resolver dispatch; English fallback;RESOLVER_FAILED - 11.14
src/errors/error-codes.test.ts— every code thrown by ≥1 production path - 11.15
src/observability/metrics.test.ts— every instrument recorded against in-memoryMeterProvider - 11.16
src/schemas/schemas.test.ts— every schema rejects malformed input withINVALID_OPTIONS - 11.17
src/conformance.test.ts— vendored Wheeler corpus (~120 vectors) agrees to ≤1 bit log10 and exactscore - 11.18
src/properties.test.ts— fast-check: matcher commutativity, score-bucket monotonicity,crackTimesmonotonicity, idempotence,INPUT_TOO_LONGboundary - 11.19 Every
it(...)carries{ timeout: 5000 }(or 30000 for genuinely async) - 11.20 Runner-neutral imports —
grepfor directvitest/bun:testimports returns zero
12. Benchmarks
- 12.1
src/__benchmarks__/assess_short_password.bench.ts - 12.2
src/__benchmarks__/assess_long_password.bench.ts - 12.3
src/__benchmarks__/assess_dictionary_heavy.bench.ts - 12.4
src/__benchmarks__/dp_n100.bench.ts - 12.5
src/__benchmarks__/dp_n200.bench.ts - 12.6 README publishes baseline numbers from a single run
13. Pre-archive verification (the 5-gate triple)
- 13.1
bun run check— Biome 0 errors / 0 warnings / 0 info - 13.2
bunx turbo lint typecheck test --filter=@suaveplan/password-strength— green - 13.3
bunx turbo test:coverage --filter=@suaveplan/password-strength— 100/100/100/100 - 13.4
bun scripts/openspec-conformance.ts @suaveplan/password-strength— exit 0, noerrorfindings - 13.5
bunx turbo build --filter=@suaveplan/password-strength— green
14. Pre-archive 7-row checklist (AGENTS.md Section 13)
- 14.1 Generics threaded;
expectTypeOfassertions on every literal-type claim (Match discriminated union, score literal-0|1|2|3|4) - 14.2 Zod schemas wired at every declared boundary (
assess,feedback,assessReactive,crackTimes,loadDictionaries) - 14.3 Every error code in
error-codes.tsthrown by ≥1 production path (asserted inerror-codes.test.ts) - 14.4 Strict-mode behaviors tested both on and off (
escapeHtml,INPUT_TOO_LONGboundary) - 14.5 OTel instruments emitted from production paths and asserted with a real in-memory
MeterProvider - 14.6 Lifecycle dedup tested where claimed —
assessReactivecancel-on-newer dedups in-flight compute - 14.7 No retroactive tick — every box above reflects work done in this change
15. Archive
- 15.1 Fold spec delta into
openspec/specs/password-strength/spec.md - 15.2 Move
openspec/changes/enterprise-password-strength/→openspec/archive/<yyyy-mm-dd>-enterprise-password-strength/ - 15.3 Refresh
MANIFEST.md(bun scripts/folder-reorg/generate-manifest.ts) - 15.4 Refresh
MISSING.yml(bun scripts/generate-missing.ts) - 15.5 Update
STATUS.mdrow fromPending→Completed - 15.6 Update
SUMMARY.mdper-package paragraph - 15.7
bunx markdownlint-cli2 --fixclean across touched files