fix(telemetry): report unless telemetry entry is explicitly disabled
Per ccyu's decision (option A), remove the consent asymmetry in ConsentResolver: telemetry is OFF only when cordis.yml has a telemetry entry with disabled: true. A cordis.yml with no telemetry entry now reports (allowWhenEntryAbsent defaults to true) rather than denying. No cordis.yml, an enabled entry, and DO_NOT_TRACK/CI are unchanged. Both no-config and absent-entry defaults stay configurable. Updates the module/README docs and the unit tests (file-present-but-no-entry and non-object/non-sequence roots now report). Per-file 100% coverage holds.
This commit is contained in:
@@ -10,7 +10,7 @@ Launcher-side telemetry primitives for the dsh-sdk toolchain. This is a plain li
|
||||
| `getOrCreateAnonymousId` | Random UUID persisted in a per-user GLOBAL config file (never in the project, never derived from git). |
|
||||
| `TelemetryReporter` | Fire-and-forget send: `report()` never blocks or throws; delivery resolves on every path; `flush()` optionally drains in-flight sends within a cap. |
|
||||
|
||||
Consent is carried by the telemetry entry in `cordis.yml`, so disabling telemetry is disabling that entry. When `cordis.yml` does not yet exist (first `create`) consent defaults to allowed; when it exists without a telemetry entry consent defaults to denied — both are configurable on `ConsentResolver`.
|
||||
Consent is carried by the telemetry entry in `cordis.yml`, so disabling telemetry is disabling that entry. Telemetry reports by default and is off only when a present telemetry entry is explicitly `disabled`: a missing `cordis.yml` (first `create`), an enabled entry, or a `cordis.yml` with no telemetry entry all report. `DO_NOT_TRACK`/CI always deny. The no-config and absent-entry defaults are configurable on `ConsentResolver`.
|
||||
|
||||
The collection endpoint is a fixed constant (`DSH_TELEMETRY_ENDPOINT`); its `.invalid` placeholder must be replaced with the real endpoint before release.
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
/**
|
||||
* Consent resolution for dsh-sdk telemetry.
|
||||
*
|
||||
* Consent is carried by the telemetry plugin's enabled/disabled state in the
|
||||
* project `cordis.yml`: an enabled entry means opt-in, a `disabled: true` entry
|
||||
* means opt-out. The resolver PARSES `cordis.yml` — it never boots a Cordis
|
||||
* application — because several launcher commands (`build`, `create`) never
|
||||
* boot Cordis at all. `DO_NOT_TRACK` and CI environment signals force a denial
|
||||
* regardless of file state.
|
||||
* Telemetry is OFF only when `cordis.yml` contains a telemetry entry that is
|
||||
* explicitly `disabled`; every other file state reports (no `cordis.yml`, an
|
||||
* enabled entry, or no telemetry entry at all). The resolver PARSES `cordis.yml`
|
||||
* — it never boots a Cordis application — because several launcher commands
|
||||
* (`build`, `create`) never boot Cordis at all. `DO_NOT_TRACK` and CI
|
||||
* environment signals force a denial regardless of file state.
|
||||
*
|
||||
* @module @deepseek-ai/dsh-telemetry/consent-resolver
|
||||
*/
|
||||
@@ -56,7 +56,7 @@ export interface ConsentResolverOptions {
|
||||
honorEnvOptOut?: boolean
|
||||
/** Consent when `cordis.yml` does not exist yet (first `create`). Defaults to `true` (telemetry is default-on). */
|
||||
allowWhenNoConfig?: boolean
|
||||
/** Consent when `cordis.yml` exists but has no telemetry entry. Defaults to `false`. */
|
||||
/** Consent when `cordis.yml` exists but has no telemetry entry. Defaults to `true` (report unless a present entry is disabled). */
|
||||
allowWhenEntryAbsent?: boolean
|
||||
}
|
||||
|
||||
@@ -94,7 +94,7 @@ export class ConsentResolver {
|
||||
this.#env = options.env ?? process.env
|
||||
this.#honorEnvOptOut = options.honorEnvOptOut ?? true
|
||||
this.#allowWhenNoConfig = options.allowWhenNoConfig ?? true
|
||||
this.#allowWhenEntryAbsent = options.allowWhenEntryAbsent ?? false
|
||||
this.#allowWhenEntryAbsent = options.allowWhenEntryAbsent ?? true
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -84,23 +84,23 @@ describe('ConsentResolver cordis.yml state', () => {
|
||||
.toEqual<ConsentDecision>({ allowed: true, reason: 'enabled' })
|
||||
})
|
||||
|
||||
it('reports absent when cordis.yml has no telemetry entry, defaulting to deny', async () => {
|
||||
it('reports (allows) when cordis.yml has no telemetry entry', async () => {
|
||||
const yml = '- id: llm\n name: \'@deepseek-ai/dsh-llm-deepseek\'\n'
|
||||
expect(await resolver.resolve(await projectDir(yml)))
|
||||
.toEqual<ConsentDecision>({ allowed: false, reason: 'absent' })
|
||||
.toEqual<ConsentDecision>({ allowed: true, reason: 'absent' })
|
||||
})
|
||||
|
||||
it('can allow when the entry is absent', async () => {
|
||||
it('can be told to deny when the entry is absent', async () => {
|
||||
const yml = '- id: llm\n name: \'@deepseek-ai/dsh-llm-deepseek\'\n'
|
||||
const decision = await new ConsentResolver({ env: {}, allowWhenEntryAbsent: true }).resolve(await projectDir(yml))
|
||||
expect(decision).toEqual<ConsentDecision>({ allowed: true, reason: 'absent' })
|
||||
const decision = await new ConsentResolver({ env: {}, allowWhenEntryAbsent: false }).resolve(await projectDir(yml))
|
||||
expect(decision).toEqual<ConsentDecision>({ allowed: false, reason: 'absent' })
|
||||
})
|
||||
|
||||
it('skips non-object sequence items and a non-sequence root', async () => {
|
||||
it('skips non-object sequence items and a non-sequence root, still reporting absent', async () => {
|
||||
expect(await resolver.resolve(await projectDir('- just-a-string\n- id: x\n name: y\n')))
|
||||
.toEqual<ConsentDecision>({ allowed: false, reason: 'absent' })
|
||||
.toEqual<ConsentDecision>({ allowed: true, reason: 'absent' })
|
||||
expect(await resolver.resolve(await projectDir('root: not-a-sequence\n')))
|
||||
.toEqual<ConsentDecision>({ allowed: false, reason: 'absent' })
|
||||
.toEqual<ConsentDecision>({ allowed: true, reason: 'absent' })
|
||||
})
|
||||
|
||||
it('honors a custom telemetry plugin name', async () => {
|
||||
|
||||
Reference in New Issue
Block a user