Skip to content

Commit 9d3d21e

Browse files
committed
docs: Reset .lore.md with latest state
1 parent 8f9fd0c commit 9d3d21e

1 file changed

Lines changed: 7 additions & 16 deletions

File tree

‎.lore.md‎

Lines changed: 7 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
* **Consola chosen as CLI logger with Sentry createConsolaReporter integration**: Consola is the CLI logger with Sentry \`createConsolaReporter\` integration. Two reporters: FancyReporter (stderr) + Sentry structured logs. Level via \`SENTRY\_LOG\_LEVEL\`. \`buildCommand\` injects hidden \`--log-level\`/\`--verbose\` flags. \`withTag()\` creates independent instances; \`setLogLevel()\` propagates via registry. All user-facing output must use consola, not raw stderr. \`HandlerContext\` intentionally omits stderr. Telemetry invariants (\`src/lib/telemetry.ts\`): (1) \`initSentry()\` ALWAYS removes \`currentBeforeExitHandler\` before registering new one. (2) \`isOwnedByRoot()\` returns \`false\` immediately on Windows. (3) NEVER block CLI — all drains are best-effort, wrapped in try/catch. (4) \`SENSITIVE\_ARGV\_FLAGS\` (\`token\`, \`auth-token\`) NEVER sent — \`redactArgv()\` handles both \`--flag=value\` and \`--flag \<value>\` forms. \`runCompletion()\` sets \`SENTRY\_CLI\_NO\_TELEMETRY=1\`. Opt-out priority: (1) \`SENTRY\_CLI\_NO\_TELEMETRY=1\`, (2) \`DO\_NOT\_TRACK=1\`, (3) \`metadata.defaults.telemetry\`, (4) default on. \`ENV\_VAR\_REGISTRY\` in \`src/lib/env-registry.ts\` is single source for all honored env vars; \`topLevel: true\` + \`briefDescription\` surfaces in \`--help\`.
1818

1919
<!-- lore:019e51e9-4aa6-7594-b179-bb737ba727d4 -->
20-
* **E2E test infrastructure: fixture.ts, helpers.ts, mocks/, and test:e2e script**: E2E test infrastructure: \`test/fixture.ts\`: \`getCliCommand()\` returns \`\[SENTRY\_CLI\_BINARY]\` or \`\[process.execPath, 'run', 'src/bin.ts']\`. \`createE2EContext(configDir, serverUrl)\` sets env \`SENTRY\_AUTH\_TOKEN: ''\`, \`SENTRY\_TOKEN: ''\`, \`SENTRY\_CLI\_NO\_TELEMETRY: '1'\`, \`SENTRY\_URL: serverUrl\`. \`setAuthToken(token)\` calls \`dbSetAuthToken(token, undefined, undefined, { host: serverUrl })\` then \`closeDatabase()\`, scoped to mock server URL for host-scoping fetch-layer guard. \`test/mocks/server.ts\`: \`createMockServer(routes, options?)\` uses Node \`http.createServer\`. \`test/mocks/multiregion.ts\`: \`createMultiRegionMockServer()\` — US+EU regions + control silo; \`selfHostedMode\`, \`singleRegionMode\`. \`telemetry-exit.test.ts\` verifies \`@sentry/core\` patch adds \`.unref()\` to flush timers.
20+
* **E2E test infrastructure: fixture.ts, helpers.ts, mocks/, and test:e2e script**: E2E test infrastructure: \`test/fixture.ts\`: \`getCliCommand()\` returns \`\[SENTRY\_CLI\_BINARY]\` or \`\[process.execPath, 'run', 'src/bin.ts']\`. \`createE2EContext(configDir, serverUrl)\` sets env \`SENTRY\_AUTH\_TOKEN: ''\`, \`SENTRY\_TOKEN: ''\`, \`SENTRY\_CLI\_NO\_TELEMETRY: '1'\`, \`SENTRY\_URL: serverUrl\`. \`setAuthToken(token)\` calls \`dbSetAuthToken(token, undefined, undefined, { host: serverUrl })\` then \`closeDatabase()\`, scoped to mock server URL for host-scoping fetch-layer guard. \`test/mocks/server.ts\`: \`createMockServer(routes, options?)\` uses Node \`http.createServer\`. \`test/mocks/multiregion.ts\`: \`createMultiRegionMockServer()\` — US+EU regions + control silo; \`selfHostedMode\`, \`singleRegionMode\`. \`telemetry-exit.test.ts\` verifies \`@sentry/core\` patch adds \`.unref()\` to flush timers. Workflow: switch to \`main\`, pull latest, create \`feat/\<name>\` branch. New command: create file + update \`index.ts\` route registry + \`src/app.ts\` (alphabetical) in same step. Internal flags: \`hidden: true as const\`; hide commands via \`hideRoute\` in \`app.ts\`. Create docs fragment in \`docs/\` for each new command. Regex literals hoisted to module-level constants. Test temp dirs cleaned in \`afterEach\`.
2121

2222
<!-- lore:019dc168-adb2-7bed-900e-cab5d3716099 -->
2323
* **Host-scoped token model: auth.host column + three-layer enforcement**: Host-scoped token model (schema v16): every token bound to issuing host via \`auth.host\` column, lazy-migrated from boot-env. Trust established ONLY via \`sentry auth login --url\` or shell-exported \`SENTRY\_HOST\`/\`SENTRY\_URL\` at boot — \`.sentryclirc\` URL never a trust source. Three enforcement layers: (1) \`applySentryUrlContext\` throws on URL-arg mismatch; (2) \`applySentryCliRcEnvShim\` throws on rc-url mismatch (auth login/logout bypass via \`skipUrlTrustCheck\`); (3) fetch-layer \`isRequestOriginTrusted\`. Region trust: in-process Set in \`db/regions.ts\`, auto-synced by \`setOrgRegion(s)\`. \`clearTrustedHostState\` must NOT clear login anchor (breaks IAP re-auth). \`HostScopeError\` has overloads \`(message)\` and \`(source, destinationUrl, tokenHost)\`. Test helpers: \`resetHostScopingState()\` bundles \`resetEnvTokenHostForTesting\` + \`resetLoginTrustAnchorForTesting\` + \`resetTrustedRegionUrlsForTesting\`. E2E: pass \`--url ${ctx.serverUrl}\` to \`auth login --token\`; \`SENTRY\_URL\` alone doesn't anchor. Multi-region tests need \`registerTrustedRegionUrls\`.
@@ -59,33 +59,24 @@
5959
<!-- lore:019e51e9-4a9c-7dde-814e-7c8904ee2833 -->
6060
* **useTestConfigDir afterEach: never delete CONFIG\_DIR\_ENV\_VAR — always restore previous value**: Trap: deleting \`process.env.SENTRY\_CONFIG\_DIR\` in \`afterEach\` looks like proper cleanup. But \`preload.ts\` always sets \`SENTRY\_CONFIG\_DIR\`, so \`savedConfigDir\` is always defined — deleting it causes subsequent test files' module-level code or \`beforeEach\` hooks to read \`undefined\`. Fix: always restore the previous value, never delete. The \`else { delete process.env\[CONFIG\_DIR\_ENV\_VAR] }\` branch is intentionally omitted in \`test/helpers.ts\` \`useTestConfigDir\`. Same principle applies in \`test/fixture.ts\` \`setAuthToken()\` finally block — the delete there is acceptable only because it's a scoped try/finally restore, not a test lifecycle hook.
6161

62-
<!-- lore:019e4b91-b3fb-7e62-b607-8d1ec425a6a0 -->
63-
* **Vitest worker pool requires pool:forks + UV\_USE\_IO\_URING=0 on GitHub Actions**: Vitest/CI gotchas: (1) GitHub Actions io\_uring crashes Node.js workers (exit 134/SIGABRT) — fix: \`pool: 'forks'\` in \`vitest.config.ts\` AND \`UV\_USE\_IO\_URING=0\` in CI. (2) Vitest 4: options must be second arg: \`test(name, { timeout }, fn)\`. (3) \`http.createServer(async ...)\` — unhandled rejections crash test server; wrap body in try/catch. (4) \`node:sqlite\` requires \`--experimental-sqlite\` on Node 22. (5) Lazy \`require()\` in test fixtures bypasses Vite's \`.js→.ts\` resolver — use top-level \`import\`. (6) \`spawn(process.execPath, \[workerScript.ts])\` fails under vitest/Node — use \`spawn('tsx', \[workerScript.ts])\`. (7) ALL test files MUST import from \`'vitest'\` — NEVER \`'bun:test'\`. \`test:e2e\` runs WITHOUT \`--isolate --parallel\`; \`test:unit\` runs WITH. \`mock.module()\` pollutes module registry — put in \`test/isolated/\`.
64-
6562
<!-- lore:019db0c9-9cc7-7352-b1f2-61b34b87b252 -->
6663
* **Whole-buffer matchAll slower than split+test when aggregated over many files**: Grep/scan traps in \`src/lib/scan/\`: (1) Literal prefilter is FILE-LEVEL gate; per-line verify breaks cross-newline patterns. (2) \`hasTopLevelAlternation\`+\`skipGroup\` must call \`skipCharacterClass\`. (3) Wake-latch race: use latched \`pendingWake\` flag. (4) \`mapFilesConcurrent\` filters \`null\` but NOT \`\[]\` — return \`null\` for no-op files. (5) \`collectGlob\`/\`collectGrep\` must NOT forward \`maxResults\` to iterator. Worker pool: lazy singleton, size \`min(8, max(2, availableParallelism()))\`. Matches encoded as \`Uint32Array\` quads (~40% faster). \`new Worker(new URL(...))\` HANGS in SEA binaries — use Blob+URL.createObjectURL. \`ref()\`/\`unref()\` idempotent — only unref when \`inflight\` drops to 0. Disable via \`SENTRY\_SCAN\_DISABLE\_WORKERS=1\`.
6764

6865
### Pattern
6966

7067
<!-- lore:019d49bf-65f3-7d79-bede-9f76e3e1ce1f -->
71-
* **Sentry SDK tree-shaking patches must be regenerated via bun patch workflow**: Sentry SDK tree-shaking via pnpm patch: \`patchedDependencies\` in \`package.json\` under \`pnpm\` config block strips unused exports from \`@sentry/core\` and \`@sentry/node-core\`. Always import from \`@sentry/node-core/light\`. Bumping SDK: remove old patches, \`pnpm patch @sentry/core\`, edit, \`pnpm patch-commit\`; repeat for node-core. \`check:patches\` validates version alignment AND content (greps installed files for known-bad strings). \`@stricli/core\` patch targets \`dist/index.js\` (ESM) only — \`dist/index.cjs\` intentionally unpatched. When bumping \`@stricli/core\`, patch line numbers shift — always verify offsets against the new \`dist/index.js\`. KNOWN: Stricli \`-H\` removal patch is fragile — any Stricli version bump will break it; upstream fix will NOT be accepted.
68+
* **Sentry SDK tree-shaking patches must be regenerated via bun patch workflow**: Sentry SDK tree-shaking via pnpm patch: \`patchedDependencies\` in \`package.json\` under \`pnpm\` config block strips unused exports from \`@sentry/core\` and \`@sentry/node-core\`. Always import from \`@sentry/node-core/light\`. Bumping SDK: remove old patches, \`pnpm patch @sentry/core\`, edit, \`pnpm patch-commit\`; repeat for node-core. \`check:patches\` validates version alignment AND content. \`@stricli/core\` patch targets \`dist/index.js\` (ESM) only — \`dist/index.cjs\` intentionally unpatched. When bumping \`@stricli/core\`, patch line numbers shift — always verify offsets. KNOWN: Stricli \`-H\` removal patch is fragile — any Stricli version bump will break it; upstream fix will NOT be accepted. Chunk-upload wire format: zstd → \`Content-Encoding: zstd\` + \`file\` field; gzip → \`file\_gzip\` field, NO \`Content-Encoding\` header (servers reject \`Content-Encoding: gzip\` + \`file\_gzip\` with 400); plain → \`file\` field, no encoding header. NEVER emit \`Content-Encoding: gzip\` alongside \`file\_gzip\`.
7269

7370
<!-- lore:019cb162-d3ad-7b05-ab4f-f87892d517a6 -->
7471
* **Shared pagination infrastructure: buildPaginationContextKey and parseCursorFlag**: Pagination infrastructure + org flag injection: Bidirectional pagination via cursor stack in \`src/lib/db/pagination.ts\`. \`resolveCursor(flag, key, contextKey)\` maps keywords (next/prev/first/last) to \`{cursor, direction}\`. \`advancePaginationState\` manages stack — back-then-forward truncates stale entries. Critical: \`resolveCursor()\` must be called INSIDE \`org-all\` override closures, not before \`dispatchOrgScopedList\`. \`issue list --limit\` is global total: \`fetchWithBudget\` Phase 1 divides evenly, Phase 2 redistributes surplus. \`trimWithProjectGuarantee\` ensures ≥1 issue per project. Compound cursor (pipe-separated) enables \`-c last\` for multi-target pagination. JSON output wraps in \`{ data, hasMore }\` with optional \`errors\` array. Hidden global \`--org\`/\`--project\` flags: defined in \`GLOBAL\_FLAGS\`, \`mergeGlobalFlags()\` injects hidden flag shapes, \`applyOrgProjectFlags()\` writes to \`SENTRY\_ORG\`/\`SENTRY\_PROJECT\` before auth guard. \`applyGroupLimitAutoDefault\` helper keeps \`buildCommand\` under Biome's cognitive complexity limit of 15.
7572

7673
<!-- lore:019cc43d-e651-7154-a88e-1309c4a2a2b6 -->
77-
* **Testing Stricli command func() bodies via spyOn mocking**: Testing Stricli command func() bodies: \`const func = await cmd.loader(); func.call(mockContext, flags, ...args)\` with mock \`stdout\`, \`stderr\`, \`cwd\`, \`setContext\`. \`.call()\` LSP false-positives pass \`tsc --noEmit\`. When API functions are renamed, update both spy target AND mock return shape. \`normalizeSlug\` replaces \`\_\`→\`-\` but does NOT lowercase. Vitest: use \`vi.spyOn\` / mock fetch via \`globalThis.fetch\`. \`mock.module()\` pollutes module registry — put in \`test/isolated/\`. ALL test files MUST import from \`'vitest'\` — NEVER \`'bun:test'\`. Variadic flag pattern: \`kind: 'parsed', parse: String, variadic: true, optional: true\`. Aliases: \`aliases: { s: 'scope' }\` — place INSIDE \`parameters\` (sibling to \`flags\`), NOT at top-level of \`buildCommand\` options (causes TS2353). \`-s\` is free in \`auth/login.ts\`.
74+
* **Testing Stricli command func() bodies via spyOn mocking**: Testing Stricli command func() bodies: \`const func = await cmd.loader(); func.call(mockContext, flags, ...args)\` with mock \`stdout\`, \`stderr\`, \`cwd\`, \`setContext\`. \`.call()\` LSP false-positives pass \`tsc --noEmit\`. When API functions are renamed, update both spy target AND mock return shape. \`normalizeSlug\` replaces \`\_\`→\`-\` but does NOT lowercase. Vitest: use \`vi.spyOn\` / mock fetch via \`globalThis.fetch\`. \`mock.module()\` pollutes module registry — put in \`test/isolated/\`. ALL test files MUST import from \`'vitest'\` — NEVER \`'bun:test'\`. Variadic flag pattern: \`kind: 'parsed', parse: String, variadic: true, optional: true\`. Aliases: \`aliases: { s: 'scope' }\` — place INSIDE \`parameters\` (sibling to \`flags\`), NOT at top-level of \`buildCommand\` options (causes TS2353). \`-s\` is free in \`auth/login.ts\`. Biome formatter enforces specific line-break style for \`func.call(ctx, { ... }, arg)\` — run \`biome format --write\` after generating test files. Bun→Node.js: \`Bun.spawn\`→\`node:child\_process\`, \`bun:sqlite\`→\`node:sqlite\`, \`bun run\`→\`pnpm run\`/\`tsx\`, \`Bun.randomUUIDv7()\`→\`uuidv7\`. \`new Worker(new URL(...))\` HANGS in SEA — use Blob+URL.createObjectURL.
7875

7976
### Preference
8077

81-
<!-- lore:019ea9dc-bdfe-7a4f-a5f9-f5c4d4acc42e -->
82-
* **Always fix lint errors immediately after they are flagged, even if it overrides prior directives**: When Biome (or any linter) flags an error in modified files, the user expects it to be fixed right away — even if a prior directive said otherwise (e.g., 'keep handleScriptOutput async' was overridden when the linter flagged useAwait). The user does not defer lint fixes or leave them as known issues. After applying a fix, always re-run the linter to confirm a clean result before considering the task done. Pre-existing lint errors in unmodified files are noted but not fixed unless they are in files the current work touches.
83-
84-
<!-- lore:019ea9aa-ed29-75b9-b397-aeeafbfb5cd0 -->
85-
* **Always import \`buildCommand\` from \`lib/command\`, never from \`@stricli/core\`**: When implementing CLI commands in the getsentry/cli codebase, the user consistently requires that \`buildCommand\` be imported from \`src/lib/command\` (the project's own wrapper), never directly from \`@stricli/core\`. This wrapper auto-injects hidden flags (\`--log-level\`, \`--verbose\`, \`--org\`, \`--project\`), handles auth guards, telemetry, output rendering, and other cross-cutting concerns. Using \`@stricli/core\` directly bypasses all of this infrastructure. Always use \`import { buildCommand } from "../../lib/command"\` (or appropriate relative path) in any new command file.
86-
87-
<!-- lore:019e517a-f897-7dbd-8c96-a96ee5b9abaa -->
88-
* **Always migrate Bun-specific APIs and tooling to Node.js equivalents**: Bun→Node.js migration complete. Replace Bun APIs: \`Bun.spawn\`→\`node:child\_process\`, \`Bun.sleep\`→\`node:timers/promises\`, \`bun:sqlite\`→\`node:sqlite\`, \`bun run\`→\`pnpm run\`/\`tsx\`, \`Bun.file().text()\`→\`readFile(path,'utf-8')\`, \`Bun.write()\`→\`writeFile()\`, \`Bun.which()\`→Node-compatible pkg, \`Bun.Glob\`→\`tinyglobby\`/\`picomatch\`, \`Bun.randomUUIDv7()\`→\`uuidv7\`, \`Bun.semver.order()\`→\`semver.compare()\`, \`Bun.zstdCompressSync()\`→zlib/\`zstd-napi\`. Exception: \`script/build.ts\` uses fossilize (not \`Bun.build\`) and stays on Bun for build-binary CI job. \`script/bundle.ts\` uses esbuild via tsx. \`packageManager\`: \`pnpm@10.11.0\`. bun.lock deleted, vitest.config.ts added. \`.npmrc\`: \`node-linker=hoisted\`. \`patchedDependencies\` moved to \`pnpm\` config block. \`NODE\_VERSION='lts'\`. \`new Worker(new URL(...))\` HANGS in SEA — use Blob+URL.createObjectURL. \`textImportPlugin\` handles \`with { type: 'text' }\` (inline as string) and \`with { type: 'file' }\` (pre-bundle sidecar) for esbuild. Prefer \`import { setTimeout } from 'node:timers/promises'\` over \`new Promise((r) => setTimeout(r, ms))\` — the latter is used in chunk-upload.ts/proguard.ts but is inconsistent with broader project direction.
78+
<!-- lore:019eaf41-e98e-7ad0-84a2-d3383054870e -->
79+
* **Always request a final critical review before considering a PR complete**: Pre-merge and pre-edit checklist: (1) Always read relevant source files before applying fixes or writing tests — never assume file contents. (2) Before merging PRs, request structured review covering: correctness, security, convention compliance (AGENTS.md), test quality, PR description accuracy. Issues rated Critical/High/Medium/Low. (3) Run \`tsc --noEmit\` after any substantive code change; distinguish pre-existing errors from new ones. (4) Fix all Biome errors: hoist inline regexes to module-level constants, add block statements to single-line \`if\` bodies, replace \`++\`/\`--\` with \`+= 1\`/\`-= 1\`, remove non-null assertions, annotate uninitialized \`let\` with explicit types, convert unnecessary template literals to plain strings. (5) Import test utilities from \`vitest\` (never \`bun:test\`). Use \`.js\` extensions in import paths. (6) Apply bot review comments (cursor\[bot], sentry\[bot]) before merging.
8980

90-
<!-- lore:019ead59-db61-71ae-9e62-24a3b5fd994f -->
91-
* **Always verify fixes by running tests and confirming all pass**: After applying any code fix or change, the user consistently runs the relevant test suite and expects confirmation that all tests pass (with exact counts and duration). The user also expects new tests to be added for each non-trivial fix to verify the specific behavior changed. Test results should be reported with file names, test counts, and timing. If tests fail, the session is not considered complete. This pattern applies to bug fixes, refactors, and feature additions alike.
81+
<!-- lore:019eaec4-01cc-7e97-8221-0e3b24483ee7 -->
82+
* **Always request pre-merge code review with specific quality criteria before merging PRs**: Before merging PRs, request a structured review covering: correctness, security, convention compliance (AGENTS.md), test quality, PR description accuracy, and reviewer rejection risk. Issues rated Critical/High/Medium/Low. Applies to completed feature PRs, especially new CLI commands. Review must examine all changed files: API modules, command implementations, index/route files, app.ts modifications, and test files. Incorporate bot review comments (cursor\[bot], sentry\[bot]). Verdict: 'Ship it' or blocking issues listed. Apply bot-suggested fixes directly to source files. After fixes, confirm no stale references and attempt type check.

0 commit comments

Comments
 (0)