diff --git a/apps/website/content/docs/telemetry/guides/node.mdx b/apps/website/content/docs/telemetry/guides/node.mdx index 6d2a0a1f5..bf6463880 100644 --- a/apps/website/content/docs/telemetry/guides/node.mdx +++ b/apps/website/content/docs/telemetry/guides/node.mdx @@ -80,8 +80,6 @@ The postinstall entry point reads package name and version from npm lifecycle en It skips local top-level installs by default. Dependency installs under `node_modules` and global installs can be eligible unless disabled. -Postinstall payloads include `install_context` with one of `ci`, `dependency`, `global`, or `workspace`. CI environments are disabled before sending; the `ci` value exists as a defensive classification if a CI install is intentionally forced through for diagnostics. - When `DEBUG` includes `ngaf:telemetry`, `ngaf:*`, or `*`, the script prints the payload shape it attempted to send. It prints the normal install telemetry notice only when the ingest endpoint accepted the event. ## Failure behavior diff --git a/apps/website/content/docs/telemetry/reference/events.mdx b/apps/website/content/docs/telemetry/reference/events.mdx index 0111aea4a..a7f26b179 100644 --- a/apps/website/content/docs/telemetry/reference/events.mdx +++ b/apps/website/content/docs/telemetry/reference/events.mdx @@ -17,13 +17,13 @@ type NgafNodeEvent = | 'ngaf:stream_errored'; ``` -| Event | Source | Properties from source | -| ------------------------------- | -------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | -| `ngaf:postinstall` | package postinstall script | `pkg`, `version`, `node`, `node_version`, `os`, `arch`, `global_install`, `install_context`, package-manager fields when npm exposes them | -| `ngaf:runtime_instance_created` | Node adapter helper | `transport`, `provider`, `model`, `angularVersion`; `apiKey` is removed | -| `ngaf:stream_started` | Node adapter helper | `provider`, `model`, optional fields in the input object | -| `ngaf:stream_ended` | Node adapter helper | `provider`, `model`, `durationMs` when supplied | -| `ngaf:stream_errored` | Node adapter helper | stream properties plus `errorClass` | +| Event | Source | Properties from source | +| ------------------------------- | -------------------------- | ---------------------------------------------------------------------------------------------------------------------- | +| `ngaf:postinstall` | package postinstall script | `pkg`, `version`, `node`, `node_version`, `os`, `arch`, `global_install`, package-manager fields when npm exposes them | +| `ngaf:runtime_instance_created` | Node adapter helper | `transport`, `provider`, `model`, `angularVersion`; `apiKey` is removed | +| `ngaf:stream_started` | Node adapter helper | `provider`, `model`, optional fields in the input object | +| `ngaf:stream_ended` | Node adapter helper | `provider`, `model`, `durationMs` when supplied | +| `ngaf:stream_errored` | Node adapter helper | stream properties plus `errorClass` | `captureEvent()` also adds `sample_weight` to sent event properties. diff --git a/docs/gtm/taxonomy.md b/docs/gtm/taxonomy.md index c22eb30de..a2a312db5 100644 --- a/docs/gtm/taxonomy.md +++ b/docs/gtm/taxonomy.md @@ -88,23 +88,22 @@ Browser events never fire unless the consumer explicitly opts in. See `libs/tele ### `ngaf:postinstall` properties -| Property | Type | Notes | -| ------------------------------ | ------ | ---------------------------------------------------------------------------------- | -| `pkg` | string | Published `@ngaf/*` package name. | -| `version` | string | Published package version. | -| `node` | string | Current `process.version`; kept for existing dashboards. | -| `node_version` | string | Current `process.version`. | -| `os` | string | Current `process.platform`. | -| `arch` | string | Current `process.arch`. | -| `install_context` | enum | `ci`, `dependency`, `global`, or `workspace`; dashboards exclude `ci` defensively. | -| `package_manager` | string | Parsed from npm's package-manager user agent when available. | -| `package_manager_version` | string | Parsed from npm's package-manager user agent when available. | -| `package_manager_node_version` | string | Installer-reported Node version when available. | -| `package_manager_os` | string | Installer-reported OS token when available. | -| `package_manager_arch` | string | Installer-reported architecture token when available. | -| `package_manager_workspaces` | bool | Installer-reported workspace flag when available. | -| `global_install` | bool | Whether npm reports a global install. | -| `sample_weight` | number | Inverse sample rate for weighted counts. | +| Property | Type | Notes | +| ------------------------------ | ------ | ------------------------------------------------------------ | +| `pkg` | string | Published `@ngaf/*` package name. | +| `version` | string | Published package version. | +| `node` | string | Current `process.version`; kept for existing dashboards. | +| `node_version` | string | Current `process.version`. | +| `os` | string | Current `process.platform`. | +| `arch` | string | Current `process.arch`. | +| `package_manager` | string | Parsed from npm's package-manager user agent when available. | +| `package_manager_version` | string | Parsed from npm's package-manager user agent when available. | +| `package_manager_node_version` | string | Installer-reported Node version when available. | +| `package_manager_os` | string | Installer-reported OS token when available. | +| `package_manager_arch` | string | Installer-reported architecture token when available. | +| `package_manager_workspaces` | bool | Installer-reported workspace flag when available. | +| `global_install` | bool | Whether npm reports a global install. | +| `sample_weight` | number | Inverse sample rate for weighted counts. | ### Runtime telemetry properties @@ -189,4 +188,3 @@ This file is human-edited. When events are added/renamed/removed, update the aff | 2026-05-15 | Drop cockpit:install_command_copied, rename cockpit:six_signals_complete → cockpit:activation_complete (Spec 1C). | | 2026-05-15 | Cockpit shell events: rename `recipe_start` → `recipe_opened`; add `mode_switched` and `code_copied` (Spec 1C implementation). | | 2026-05-17 | Add `blog:cta_click` + `blog:copy_code_click` events; add `'blog'` to `AnalyticsSurface` (Spec 5). | -| 2026-05-18 | Add `install_context` to `ngaf:postinstall` and filter package telemetry dashboard insights away from `ci` context. | diff --git a/libs/telemetry/src/node/client.spec.ts b/libs/telemetry/src/node/client.spec.ts index 22683a9d4..ca5c76f43 100644 --- a/libs/telemetry/src/node/client.spec.ts +++ b/libs/telemetry/src/node/client.spec.ts @@ -123,23 +123,18 @@ describe('node client', () => { expect(body.properties).not.toHaveProperty('init_cwd'); }); - test('createPostinstallProperties classifies CI installs for dashboard filtering', () => { - expect( - createPostinstallProperties( - { pkg: '@ngaf/chat', version: '0.0.31' }, - { CI: 'true' } - ) - ).toEqual(expect.objectContaining({ install_context: 'ci' })); - + test('createPostinstallProperties does not include derived install context', () => { expect( createPostinstallProperties( { pkg: '@ngaf/chat', version: '0.0.31' }, { + CI: 'true', + npm_config_global: 'true', npm_config_user_agent: - 'npm/10.9.2 node/v22.14.0 darwin arm64 workspaces/false', + 'npm/10.9.2 node/v22.14.0 darwin arm64 workspaces/true', } ) - ).toEqual(expect.objectContaining({ install_context: 'dependency' })); + ).not.toHaveProperty('install_context'); }); test('capturePostinstall awaits fetch before resolving', async () => { diff --git a/libs/telemetry/src/node/client.ts b/libs/telemetry/src/node/client.ts index 1ef4d6107..b71da461b 100644 --- a/libs/telemetry/src/node/client.ts +++ b/libs/telemetry/src/node/client.ts @@ -32,16 +32,6 @@ function readBooleanToken(value: string | undefined): boolean | undefined { return undefined; } -function isCiEnv(env: NodeJS.ProcessEnv = process.env): boolean { - return [ - env.CI, - env.GITHUB_ACTIONS, - env.CONTINUOUS_INTEGRATION, - env.BUILDKITE, - env.CIRCLECI, - ].some((value) => readBooleanToken(value) === true); -} - function getPackageManager( env: NodeJS.ProcessEnv = process.env ): Record { @@ -79,21 +69,6 @@ function getPackageManager( return out; } -function getInstallContext( - env: NodeJS.ProcessEnv = process.env -): 'ci' | 'dependency' | 'global' | 'workspace' { - if (isCiEnv(env)) return 'ci'; - if ( - readBooleanToken(env.npm_config_global) === true || - env.npm_config_location === 'global' - ) { - return 'global'; - } - const packageManager = getPackageManager(env); - if (packageManager.package_manager_workspaces === true) return 'workspace'; - return 'dependency'; -} - // @internal export function createPostinstallProperties( input: PostinstallInput, @@ -109,7 +84,6 @@ export function createPostinstallProperties( global_install: readBooleanToken(env.npm_config_global) === true || env.npm_config_location === 'global', - install_context: getInstallContext(env), ...getPackageManager(env), }; } diff --git a/tools/posthog/dashboards/package-telemetry.json b/tools/posthog/dashboards/package-telemetry.json index fc61a37b3..b6f91f861 100644 --- a/tools/posthog/dashboards/package-telemetry.json +++ b/tools/posthog/dashboards/package-telemetry.json @@ -2,7 +2,7 @@ "slug": "package-telemetry", "posthog_id": 1590768, "name": "GTM · Package telemetry", - "description": "Published @ngaf/* install telemetry from ngaf:postinstall. Package install insights exclude CI install context.", + "description": "Published @ngaf/* install telemetry from ngaf:postinstall.", "tags": ["gtm", "package-telemetry", "phase-1"], "tiles": [ { diff --git a/tools/posthog/insights/package-installs-by-installer-os.json b/tools/posthog/insights/package-installs-by-installer-os.json index 93d1bcfb1..1ed8022ec 100644 --- a/tools/posthog/insights/package-installs-by-installer-os.json +++ b/tools/posthog/insights/package-installs-by-installer-os.json @@ -6,14 +6,7 @@ "events": [ { "event": "ngaf:postinstall", - "math": "total", - "properties": [ - { - "key": "install_context", - "value": "ci", - "operator": "is_not" - } - ] + "math": "total" } ], "breakdown": "package_manager_os", diff --git a/tools/posthog/insights/package-installs-by-package-manager.json b/tools/posthog/insights/package-installs-by-package-manager.json index 6a3902e49..005e57a86 100644 --- a/tools/posthog/insights/package-installs-by-package-manager.json +++ b/tools/posthog/insights/package-installs-by-package-manager.json @@ -6,14 +6,7 @@ "events": [ { "event": "ngaf:postinstall", - "math": "total", - "properties": [ - { - "key": "install_context", - "value": "ci", - "operator": "is_not" - } - ] + "math": "total" } ], "breakdown": "package_manager", diff --git a/tools/posthog/insights/package-installs-by-package.json b/tools/posthog/insights/package-installs-by-package.json index fef9cf2b2..d367f6ae2 100644 --- a/tools/posthog/insights/package-installs-by-package.json +++ b/tools/posthog/insights/package-installs-by-package.json @@ -6,14 +6,7 @@ "events": [ { "event": "ngaf:postinstall", - "math": "total", - "properties": [ - { - "key": "install_context", - "value": "ci", - "operator": "is_not" - } - ] + "math": "total" } ], "breakdown": "pkg", diff --git a/tools/posthog/insights/package-installs-by-workspace-flag.json b/tools/posthog/insights/package-installs-by-workspace-flag.json index 31487605a..ccf645c4d 100644 --- a/tools/posthog/insights/package-installs-by-workspace-flag.json +++ b/tools/posthog/insights/package-installs-by-workspace-flag.json @@ -6,14 +6,7 @@ "events": [ { "event": "ngaf:postinstall", - "math": "total", - "properties": [ - { - "key": "install_context", - "value": "ci", - "operator": "is_not" - } - ] + "math": "total" } ], "breakdown": "package_manager_workspaces", diff --git a/tools/posthog/telemetry-contract.spec.ts b/tools/posthog/telemetry-contract.spec.ts index f861253f2..2d4c26ef6 100644 --- a/tools/posthog/telemetry-contract.spec.ts +++ b/tools/posthog/telemetry-contract.spec.ts @@ -108,7 +108,13 @@ test('insight property filters are allowed by the event contract', async () => { ); }); -test('package telemetry dashboard filters install insights away from CI context', async () => { +test('postinstall telemetry contract does not expose derived install context', () => { + const contract = TELEMETRY_EVENT_CONTRACT['ngaf:postinstall']; + assert(!contract.allowedProperties.includes('install_context')); + assert(!contract.allowedBreakdowns.includes('install_context')); +}); + +test('package telemetry dashboard does not filter by derived install context', async () => { const dashboard = await readJson<{ tiles: Array<{ insight: string }> }>( join(HERE, 'dashboards', 'package-telemetry.json') ); @@ -129,20 +135,17 @@ test('package telemetry dashboard filters install insights away from CI context' for (const item of insight.events ?? []) { if (item.event !== 'ngaf:postinstall') continue; - const excludesCiContext = (item.properties ?? []).some( - (property) => - property.key === 'install_context' && - property.value === 'ci' && - property.operator === 'is_not' + const usesInstallContext = (item.properties ?? []).some( + (property) => property.key === 'install_context' ); - if (!excludesCiContext) violations.push(insight.slug); + if (usesInstallContext) violations.push(insight.slug); } } assert.deepEqual( violations, [], - `Package telemetry insights must exclude install_context=ci:\n${violations.join( + `Package telemetry insights must not filter by install_context:\n${violations.join( '\n' )}` ); diff --git a/tools/posthog/telemetry-contract.ts b/tools/posthog/telemetry-contract.ts index 8cd7a1f51..b1f04a568 100644 --- a/tools/posthog/telemetry-contract.ts +++ b/tools/posthog/telemetry-contract.ts @@ -26,7 +26,6 @@ type TelemetryEventContract = { const installProperties = [ 'arch', 'global_install', - 'install_context', 'node', 'node_version', 'os', @@ -150,7 +149,6 @@ export const TELEMETRY_EVENT_CONTRACT: Record = allowedProperties: installProperties, allowedBreakdowns: [ 'global_install', - 'install_context', 'os', 'package_manager', 'package_manager_os',