@ttt-productions/dev-standards 0.0.6 → 0.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ttt-productions/dev-standards",
3
- "version": "0.0.6",
3
+ "version": "0.0.7",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/ttt-productions/ttt-packages.git",
@@ -389,6 +389,10 @@ changes) declares serial mode. `waitForTimeout` is a build-failing guard (step 6
389
389
  **Review clauses:** no assertion whose only evidence is a toast — assert the resulting state; fixtures
390
390
  over inline UI logins; specs never reseed or clear emulator data; and monitoring is a no-op under the
391
391
  emulator (the app's inits gate it).
392
+ **Retries and caught failures:** `<GUARD_SUITE> -t "no end-to-end retry loop repeats a user action"`
393
+ and `-t "no end-to-end action or state read swallows its failure"` pass. Every reviewed entry of
394
+ either is an outcome-verified helper's own loop or the polling of a background result, with a why
395
+ that says so — a loop or catch kept only because it made a run pass is the finding.
392
396
  **Status:** PASS · FAIL · NOT RUN · BLOCKED
393
397
 
394
398
  ### 29. Local config alignment
@@ -985,6 +989,10 @@ never suppressed, and turning a rule off or widening `ignores` to pass failing c
985
989
  is permitted only for a narrow intentional case, with its reason on the line. **Both:** the format check
986
990
  passes (a listed file means a change set skipped the gate); the Prettier-compatibility config is the
987
991
  last entry of every lint config; every `prettier-ignore` carries its reason.
992
+ **Types and line endings:** `<GUARD_SUITE> -t "no cast switches type checking off"` and
993
+ `-t "every text file is LF"` pass. Every reviewed cast entry is the only way or clearly the best way,
994
+ with that reason in its why; a cast a typed fake, the owner's type, or a typed mapping could replace is
995
+ the finding.
988
996
  **Status:** PASS · FAIL · NOT RUN · BLOCKED
989
997
 
990
998
  ### 75. No vacuous commands — every playbook path resolves and every command is honestly scoped
@@ -157,8 +157,8 @@ rule's coverage in its additions; they are not listed here.
157
157
  | RULE-STD-QUALITY-001 | Behavior changes ship with their tests | codebase-hygiene 46, 117, 118, 119; async-workflow 10; auth-boundary 10; callable-functions 10; client-write-security-audit 9; firestore-storage-rules 10; media-pipeline 10; migration 10; testing-coverage 2, 3, 4, 7, 10, 11 | `partialMocks`, `sharedFakes` |
158
158
  | RULE-STD-QUALITY-002 | Verify at the cost of the fix; one full gate | testing-coverage 1, 9 | — |
159
159
  | RULE-STD-QUALITY-003 | E2E is green only at zero failures AND zero retry-passes | testing-coverage 1, 6 | — |
160
- | RULE-STD-QUALITY-004 | E2E tests use the established fixtures and web-first assertions | codebase-hygiene 28; migration 10; testing-coverage 6, 8, 10 | — |
161
- | RULE-STD-QUALITY-006 | Lint and format: zero suppression in apps, reasoned disables in packages; one enforced format | codebase-hygiene 73; package-boundaries 7 | — |
160
+ | RULE-STD-QUALITY-004 | E2E tests use the established fixtures and web-first assertions | codebase-hygiene 28; migration 10; testing-coverage 6, 8, 10 | `retryLoopActions`, `swallowedE2eActions` |
161
+ | RULE-STD-QUALITY-006 | Lint and format: zero suppression in apps, reasoned disables in packages; one enforced format | codebase-hygiene 73; package-boundaries 7 | `blanketCasts`, `lineEndings` |
162
162
  | RULE-STD-QUALITY-007 | Guard tests enforce ownership and boundaries, never inventories | codebase-hygiene 35, 42, 63, 80, 83, 87, 88, 90, 91, 95, 96, 117, 118, 119, 120, 122 | — |
163
163
  | RULE-STD-QUALITY-008 | Rules and E2E run against a fresh dev:e2e | codebase-hygiene 29; dependency-audit 3; firestore-storage-rules 10; testing-coverage 1, 9 | — |
164
164
  | RULE-STD-QUALITY-009 | A test loads the code it tests when its file loads | codebase-hygiene 42, 118; package-boundaries 8 | `testCaseModuleLoads` |
@@ -61,7 +61,7 @@ A test proves the business rule, never the code's current output: its expected v
61
61
  ### RULE-STD-QUALITY-004 — E2E tests use the established fixtures and web-first assertions
62
62
  **Scope.** apps
63
63
 
64
- **Rule.** Tests use the established role fixtures, seed model, and query-cache helpers; assertions are web-first (`getByRole` over CSS selectors, `expect(locator)` which auto-retries) with no `page.waitForTimeout()`. URLs come from the config `baseURL` — zero hardcoded URLs in specs — and each test covers one behavior (multiple related `expect()` calls are fine). A spec runs on the data the seed model provides: it never reseeds or clears emulator data. The UI-login helper is called only in the auth-setup project and the auth specs that exercise login/logout themselves — never in a regular spec. Admin specs, and any lifecycle or build-on-each-other specs, declare `test.describe.configure({ mode: 'serial' })`.
64
+ **Rule.** Tests use the established role fixtures, seed model, and query-cache helpers; assertions are web-first (`getByRole` over CSS selectors, `expect(locator)` which auto-retries) with no `page.waitForTimeout()`. URLs come from the config `baseURL` — zero hardcoded URLs in specs — and each test covers one behavior (multiple related `expect()` calls are fine). A spec runs on the data the seed model provides: it never reseeds or clears emulator data. The UI-login helper is called only in the auth-setup project and the auth specs that exercise login/logout themselves — never in a regular spec. Admin specs, and any lifecycle or build-on-each-other specs, declare `test.describe.configure({ mode: 'serial' })`. A spec acts once and then asserts: a retry loop (`toPass()`, `expect.poll()`) re-reads state but never repeats a click, an input, or a navigation, except the suite's named outcome-verified helpers and the polling of a background result, each a reviewed entry; and no action or state read (`isVisible()`, `isEnabled()`, `isChecked()`) has its failure caught — a strict locator that matches twice must fail, never read as "no". The repo-guards `retryLoopActions` and `swallowedE2eActions` guards enforce it.
65
65
 
66
66
  **Why.** Role fixtures and web-first assertions survive markup and timing changes; a non-web-first assertion (`expect(await locator.textContent())`) does not retry, and parallel admin sessions hang the Auth emulator on concurrent same-admin token validation.
67
67
 
@@ -71,15 +71,19 @@ A test proves the business rule, never the code's current output: its expected v
71
71
  - A hardcoded URL in a spec where `baseURL` covers it.
72
72
  - A spec that reseeds or clears emulator data.
73
73
  - Parallel admin specs (missing serial mode).
74
+ - A click, input, reload, or navigation inside a retry loop outside a reviewed entry.
75
+ - A `.catch()` or try/catch that swallows a failed action or state read.
74
76
 
75
- **References.** RULE-STD-QUALITY-003, RULE-STD-QUALITY-008.
77
+ **References.** RULE-STD-QUALITY-001, RULE-STD-QUALITY-003, RULE-STD-QUALITY-007, RULE-STD-QUALITY-008.
76
78
 
77
79
  ### RULE-STD-QUALITY-006 — Lint and format: zero suppression in apps, reasoned disables in packages; one enforced format
78
80
  **Scope.** both
79
81
 
80
82
  **Rule.** The lint half is split by scope; the format half is the same for both. **Apps** are zero suppression: no `eslint-disable` comment anywhere in the linted trees — source, Functions, E2E, scripts, and config. When a rule fires, fix the root cause, and solve a genuine false positive structurally — rename, refactor, or scope the rule — never by suppressing the line; external-authority state pruning uses the sanctioned render-phase adjustment, not a suppressed effect. A `warn`-level finding is a finding to fix, and a rule is never turned off, nor `ignores` widened, to pass failing code. New app code also follows the conventions the lint config forces, listed below. **Packages** permit an `eslint-disable-next-line` only for a narrow intentional case where no fix works, on DJ's yes, carrying its reason on the line; it is preferred over weakening the rule, and a real violation is fixed at its source.
81
83
 
82
- Every code file — source, tests, scripts, and config — is in the one format Prettier writes from the shared Prettier config (this package's `config/prettier.json`); `test:quiet`'s format stage writes that format and then checks it, a check-only run (a package release preflight, `test:all`) only checks, so a release never publishes formatting nobody committed, and the check fails a file that is not formatted; `eslint-config-prettier` keeps ESLint out of formatting. A file is formatted by running Prettier, never reflowed by hand.
84
+ Every code file — source, tests, scripts, and config — is in the one format Prettier writes from the shared Prettier config (this package's `config/prettier.json`); `test:quiet`'s format stage writes that format and then checks it, a check-only run (a package release preflight, `test:all`) only checks, so a release never publishes formatting nobody committed, and the check fails a file that is not formatted; `eslint-config-prettier` keeps ESLint out of formatting. A file is formatted by running Prettier, never reflowed by hand. Every text file is LF: `.gitattributes` pins `* text=auto eol=lf`, so no checkout writes CRLF, and the repo-guards `lineEndings` guard fails a CRLF or mixed file.
85
+
86
+ A type is never switched off: no `as never` and no `as unknown as X` in any code, tests included — the value gets its real type (a typed fake or builder, the owner's type, a typed mapping between two unions). The one exception is a cast that is the only way or clearly the best way, as a reviewed entry naming that one cast with its why, on DJ's yes; the repo-guards `blanketCasts` guard enforces it.
83
87
 
84
88
  **Why.** A suppression silences the next real violation of that rule on that line: apps chose zero suppression, and a package's reasonless disable does the same damage. A rule switched off or an ignore widened to get past failing code is the same suppression at file scale. Without one enforced format, every edit carries layout churn and line lengths drift with whoever wrote the file.
85
89
 
@@ -93,8 +97,10 @@ Every code file — source, tests, scripts, and config — is in the one format
93
97
  - Straight `'`/`"` in JSX text content (use `&apos;`/`&quot;`).
94
98
  - Suppressing `exhaustive-deps` instead of fixing at the source (destructure the stable `mutate`; memoize a derived dep; destructure the specific prop fields used).
95
99
  - An unformatted code file; a `prettier-ignore` without its reason, or added when a fix works or without DJ's yes; an ESLint formatting rule that fights Prettier.
100
+ - A CRLF or mixed-ending text file; a `.gitattributes` without `eol=lf`.
101
+ - An `as never` or `as unknown as` cast outside a reviewed entry.
96
102
 
97
- **References.** RULE-STD-ENG-008; this package's `node/eslint` bases and `config/prettier.json`; each repo's ESLint config and `.prettierignore`.
103
+ **References.** RULE-STD-ENG-008; RULE-STD-QUALITY-007; this package's `node/eslint` bases and `config/prettier.json`; each repo's ESLint config and `.prettierignore`.
98
104
 
99
105
  ### RULE-STD-QUALITY-007 — Guard tests enforce ownership and boundaries, never inventories
100
106
  **Scope.** both