@plurnk/plurnk-providers 1.3.12 → 1.5.0

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.
Files changed (139) hide show
  1. package/.env.defaults +47 -38
  2. package/README.md +68 -4
  3. package/SPEC.md +245 -62
  4. package/dist/AiSdkProvider.d.ts +19 -5
  5. package/dist/AiSdkProvider.d.ts.map +1 -1
  6. package/dist/AiSdkProvider.js +264 -156
  7. package/dist/AiSdkProvider.js.map +1 -1
  8. package/dist/Mock.d.ts +15 -17
  9. package/dist/Mock.d.ts.map +1 -1
  10. package/dist/Mock.js +27 -10
  11. package/dist/Mock.js.map +1 -1
  12. package/dist/Pool.d.ts +8 -2
  13. package/dist/Pool.d.ts.map +1 -1
  14. package/dist/Pool.js +41 -8
  15. package/dist/Pool.js.map +1 -1
  16. package/dist/ProviderRegistry.d.ts +4 -1
  17. package/dist/ProviderRegistry.d.ts.map +1 -1
  18. package/dist/ProviderRegistry.js +7 -3
  19. package/dist/ProviderRegistry.js.map +1 -1
  20. package/dist/accounting.d.ts +3 -0
  21. package/dist/accounting.d.ts.map +1 -0
  22. package/dist/accounting.js +84 -0
  23. package/dist/accounting.js.map +1 -0
  24. package/dist/aiSdkTransport.d.ts +5 -2
  25. package/dist/aiSdkTransport.d.ts.map +1 -1
  26. package/dist/aiSdkTransport.js +91 -5
  27. package/dist/aiSdkTransport.js.map +1 -1
  28. package/dist/catalogProvider.d.ts +5 -2
  29. package/dist/catalogProvider.d.ts.map +1 -1
  30. package/dist/catalogProvider.js +24 -11
  31. package/dist/catalogProvider.js.map +1 -1
  32. package/dist/compatibleProvider.d.ts.map +1 -1
  33. package/dist/compatibleProvider.js +11 -4
  34. package/dist/compatibleProvider.js.map +1 -1
  35. package/dist/cost.d.ts +11 -0
  36. package/dist/cost.d.ts.map +1 -0
  37. package/dist/cost.js +61 -0
  38. package/dist/cost.js.map +1 -0
  39. package/dist/discover.d.ts +2 -0
  40. package/dist/discover.d.ts.map +1 -1
  41. package/dist/discover.js +15 -9
  42. package/dist/discover.js.map +1 -1
  43. package/dist/env.d.ts +4 -6
  44. package/dist/env.d.ts.map +1 -1
  45. package/dist/env.js +27 -29
  46. package/dist/env.js.map +1 -1
  47. package/dist/errors.d.ts +27 -0
  48. package/dist/errors.d.ts.map +1 -0
  49. package/dist/errors.js +152 -0
  50. package/dist/errors.js.map +1 -0
  51. package/dist/index.d.ts +12 -6
  52. package/dist/index.d.ts.map +1 -1
  53. package/dist/index.js +8 -5
  54. package/dist/index.js.map +1 -1
  55. package/dist/notices.d.ts +10 -0
  56. package/dist/notices.d.ts.map +1 -0
  57. package/dist/notices.js +11 -0
  58. package/dist/notices.js.map +1 -0
  59. package/dist/ollama.d.ts.map +1 -1
  60. package/dist/ollama.js +3 -3
  61. package/dist/ollama.js.map +1 -1
  62. package/dist/openai.d.ts +1 -1
  63. package/dist/openai.d.ts.map +1 -1
  64. package/dist/promptTokens.d.ts +4 -0
  65. package/dist/promptTokens.d.ts.map +1 -0
  66. package/dist/promptTokens.js +32 -0
  67. package/dist/promptTokens.js.map +1 -0
  68. package/dist/sdkModels.d.ts +2 -0
  69. package/dist/sdkModels.d.ts.map +1 -1
  70. package/dist/sdkModels.js +17 -6
  71. package/dist/sdkModels.js.map +1 -1
  72. package/dist/types.d.ts +52 -16
  73. package/dist/types.d.ts.map +1 -1
  74. package/dist/types.js +1 -1
  75. package/dist/types.js.map +1 -1
  76. package/dist/usage.d.ts +4 -0
  77. package/dist/usage.d.ts.map +1 -1
  78. package/dist/usage.js +64 -19
  79. package/dist/usage.js.map +1 -1
  80. package/dist/warnings.js +0 -0
  81. package/dist/warnings.js.map +1 -1
  82. package/package.json +15 -10
  83. package/src/AiSdkProvider.test.ts +750 -169
  84. package/src/AiSdkProvider.ts +354 -200
  85. package/src/Mock.test.ts +29 -14
  86. package/src/Mock.ts +36 -15
  87. package/src/Pool.test.ts +43 -6
  88. package/src/Pool.ts +56 -10
  89. package/src/ProviderRegistry.test.ts +158 -9
  90. package/src/ProviderRegistry.ts +19 -6
  91. package/src/accounting.test.ts +58 -0
  92. package/src/accounting.ts +88 -0
  93. package/src/aiSdkTransport.ts +101 -8
  94. package/src/boundaries.test.ts +9 -3
  95. package/src/catalogProvider.test.ts +43 -15
  96. package/src/catalogProvider.ts +32 -16
  97. package/src/compatibleProvider.test.ts +96 -0
  98. package/src/compatibleProvider.ts +15 -6
  99. package/src/cost.test.ts +64 -0
  100. package/src/cost.ts +78 -0
  101. package/src/defaults.test.ts +1 -0
  102. package/src/discover.test.ts +48 -7
  103. package/src/discover.ts +31 -21
  104. package/src/env.test.ts +38 -48
  105. package/src/env.ts +43 -40
  106. package/src/errors.test.ts +148 -0
  107. package/src/errors.ts +208 -0
  108. package/src/index.ts +30 -8
  109. package/src/lexicon-guard.test.ts +6 -6
  110. package/src/notices.ts +22 -0
  111. package/src/ollama.test.ts +64 -0
  112. package/src/ollama.ts +6 -3
  113. package/src/openai.ts +3 -0
  114. package/src/promptTokens.ts +41 -0
  115. package/src/sdkModels.test.ts +29 -3
  116. package/src/sdkModels.ts +19 -11
  117. package/src/types.ts +125 -64
  118. package/src/usage.test.ts +24 -5
  119. package/src/usage.ts +72 -21
  120. package/src/warnings.test.ts +10 -10
  121. package/src/warnings.ts +0 -0
  122. package/dist/OpenAICompat.d.ts +0 -76
  123. package/dist/OpenAICompat.d.ts.map +0 -1
  124. package/dist/OpenAICompat.js +0 -555
  125. package/dist/OpenAICompat.js.map +0 -1
  126. package/dist/openaiStream.d.ts +0 -47
  127. package/dist/openaiStream.d.ts.map +0 -1
  128. package/dist/openaiStream.js +0 -280
  129. package/dist/openaiStream.js.map +0 -1
  130. package/dist/standardProviders.d.ts +0 -31
  131. package/dist/standardProviders.d.ts.map +0 -1
  132. package/dist/standardProviders.js +0 -518
  133. package/dist/standardProviders.js.map +0 -1
  134. package/dist/telemetry.d.ts +0 -24
  135. package/dist/telemetry.d.ts.map +0 -1
  136. package/dist/telemetry.js +0 -85
  137. package/dist/telemetry.js.map +0 -1
  138. package/src/telemetry.test.ts +0 -69
  139. package/src/telemetry.ts +0 -116
package/.env.defaults CHANGED
@@ -1,6 +1,6 @@
1
1
  # REFERENCE - @plurnk/plurnk-providers' shipped .env.defaults: the operative floor for
2
- # PLURNK_PROVIDERS_* knobs and provider declarations (providers#44: every package owns
3
- # what it reads; the file IS the configuration reference).
2
+ # PLURNK_PROVIDERS_* knobs and provider declarations ({§operator-config-env-defaults});
3
+ # every package owns what it reads, and this file IS the configuration reference.
4
4
  # The daemon assembles every installed member's file into one floor (set-if-unset under the
5
5
  # operator's env) - do NOT edit this file; put YOUR config in ~/.plurnk/.env or ./.env. A key
6
6
  # claimed by two packages crashes boot naming both.
@@ -10,23 +10,31 @@
10
10
  # whose UNSET state is meaningful (derive/auto/off, or a required secret) - uncomment to pin.
11
11
  #
12
12
  # Models.dev supplies cataloged providers' SDK package, endpoint, credential names,
13
- # model metadata, and prices. Operator declarations below cover only facts absent
14
- # from or deliberately overridden over that catalog. Secret VALUES never belong here.
13
+ # and model facts. {§model-fact-resolution} defines precedence per fact; there is
14
+ # no live price fetch. Secret VALUES never belong here.
15
15
 
16
16
  # --- Side-channel reasoning (SPEC §4, #32/#33/#399) ---
17
17
  # ACTIVATION and BUDGET are separate so a numeric can never silently flip wire flags.
18
18
  # off | adaptive | on. The provider maps intent to each backend's native mechanism
19
- # (reasoning_effort, enable_thinking, think, ...). Default ADAPTIVE (owner ruling,
20
- # #399): reasoning ACTIVE on a fresh install, each backend's own adaptive depth,
19
+ # (reasoning_effort, enable_thinking, think, ...). Default ADAPTIVE (#399):
20
+ # reasoning ACTIVE on a fresh install, each backend's own adaptive depth,
21
21
  # no shipped magnitude - a reasoning model that ships un-reasoning blind-edits and
22
- # declares done (svc#396 A/B: 25 EXECs -> 0, build broken, confident SEND[200]).
22
+ # declares done.
23
23
  PLURNK_PROVIDERS_REASONING=adaptive
24
- # Positive int, REQUIRED iff REASONING=on - the magnitude for tier/budget mapping. On
25
- # llama.cpp the ENFORCEMENT is the box's --reasoning-budget LAUNCH flag (per-request
26
- # numerics are ignored): env budget and launch flag are the same number, changed together.
24
+ # Positive int, REQUIRED iff REASONING=on - the magnitude for tier/budget mapping.
25
+ # On llama-server it is a request-scoped reasoning allowance and may tighten, but
26
+ # cannot exceed, the resolved PLURNK_PROVIDERS_REASONING_RESERVE.
27
27
  # PLURNK_PROVIDERS_REASONING_BUDGET=4096
28
28
 
29
- # --- Decode tuning (measured canonical values; bench/TUNING-EPIC.md F1/F6; #9/#30) ---
29
+ # Response-content interpretation ({§provider-tagged-reasoning}) is independent
30
+ # from request-side reasoning activation. The portable floor trusts only
31
+ # structured provider/SDK reasoning fields and leaves visible content verbatim.
32
+ # Set think-tags only on an alias whose exact model/endpoint contract emits one
33
+ # leading <think> envelope; it is never inferred from generic reasoning capability.
34
+ PLURNK_PROVIDERS_REASONING_RESPONSE_STYLE=verbatim
35
+ # PLURNK_PROVIDERS_REASONING_RESPONSE_STYLE_cfds1=think-tags
36
+
37
+ # --- Decode tuning (measured canonical values; #9/#30) ---
30
38
  # TEMPERATURE is the default for EVERY request (under caller sampling); REPEAT_PENALTY is
31
39
  # the floor the provider manages wherever a grammar rides (greedy-under-mask loops without it).
32
40
  PLURNK_PROVIDERS_TEMPERATURE=0.2
@@ -44,28 +52,32 @@ PLURNK_PROVIDERS_FREQUENCY_PENALTY=0
44
52
  # stable worker id for replica-local prefix affinity. Official native SDKs own
45
53
  # their cache mechanisms and do not receive this compatible extension.
46
54
  PLURNK_PROVIDERS_PROMPT_CACHE_KEY=1
47
- # #567: DRY loop-breaker - llama.cpp-only (grammarStyle "none" paths skip it). MULTIPLIER=0
48
- # disables DRY at the general floor: the #567 sweep showed L=2 is WORSE than DRY-off on both
49
- # runaways AND corruption; L=32 is the measured plurnk-safe threshold (0 corruption fails,
50
- # ~6% runaways vs 19% off). Enable per-alias: DRY_MULTIPLIER_<alias>=0.8, ALLOWED_LENGTH_<alias>=32.
55
+ # #567: DRY is a llama.cpp-only repeated-sequence penalty. It can reduce
56
+ # degenerate loops, but it can also corrupt exact source, identifiers, quoted
57
+ # evidence, and other repetition required by PLURNK operations. The portable
58
+ # server-wide default is off. A nonzero alias override is an explicit fidelity
59
+ # tradeoff; DRY_BASE_<alias> and DRY_ALLOWED_LENGTH_<alias> tune that opt-in.
51
60
  PLURNK_PROVIDERS_DRY_MULTIPLIER=0
52
- PLURNK_PROVIDERS_DRY_BASE=1.75
53
- PLURNK_PROVIDERS_DRY_ALLOWED_LENGTH=32
54
- # REPEAT_LAST_N widens the older repeat_penalty window past the box's 64; optional (DRY's
55
- # whole-context window makes it secondary). Set per-alias if a model wants it.
61
+ # PLURNK_PROVIDERS_DRY_BASE_<alias>=
62
+ # PLURNK_PROVIDERS_DRY_ALLOWED_LENGTH_<alias>=
63
+ # REPEAT_LAST_N widens the older repeat_penalty window past the box's default.
64
+ # Set it per alias only from measured model behavior.
56
65
  # PLURNK_PROVIDERS_REPEAT_LAST_N_<alias>=512
57
66
 
58
67
  # --- Transport budgets (§4, #18) ---
59
68
  # Total generation-operation timeout (ms), including retries; caller cancellation also spans the operation.
60
69
  PLURNK_PROVIDERS_FETCH_TIMEOUT=600000
61
70
  # Maximum silence (ms) between streamed response-body chunks after response
62
- # streaming begins. Disabled at the portable floor: slow local inference may
63
- # pause legitimately. Enable per alias only from measured endpoint behavior.
64
- PLURNK_PROVIDERS_STREAM_IDLE_TIMEOUT=0
65
- # PLURNK_PROVIDERS_STREAM_IDLE_TIMEOUT_firefast=120000
66
- # Transient-failure retries: 0 = surface the first failure; N = retries on 429/5xx/timeout
67
- # with exponential backoff (Retry-After wins). RETRY_DELAY is the backoff base (ms).
71
+ # streaming begins. Two minutes: generous for slow local inference, fast enough
72
+ # to catch a dead connection before the total timeout. A detected stall consumes
73
+ # the same configured retry budget as every other retryable transport failure.
74
+ PLURNK_PROVIDERS_STREAM_IDLE_TIMEOUT=120000
75
+ # Transient-failure retries: 0 = surface the first failure; N = retries on
76
+ # 429/5xx/stream-idle timeout with the AI SDK's backoff (Retry-After wins).
68
77
  PLURNK_PROVIDERS_RETRY_ATTEMPTS=3
78
+ # Maximum characters retained from an upstream provider diagnostic in the
79
+ # public Problem detail. Structured failure facts are not truncated.
80
+ PLURNK_PROVIDERS_ERROR_DETAIL_LIMIT=512
69
81
 
70
82
  # --- Endpoint probe (#34) ---
71
83
  # GET /v1/models at construction (context window + llama-server fingerprint). One failure
@@ -82,20 +94,13 @@ PLURNK_PROVIDERS_PROBE_DELAY=250
82
94
  # unconstrained output's divergence. Development aid; leave unset in production.
83
95
  # PLURNK_PROVIDERS_GBNF_DEBUG=0
84
96
 
85
- # --- Window (SPEC §11) ---
86
- # Unset = derive: env -> live endpoint probe (n_ctx) -> models.dev catalog -> null (surfaced
87
- # once via PLURNK_CONTEXT_UNKNOWN naming the model). Set to pin the window deliberately -
88
- # per-alias (_<alias>) for a box whose model the catalog doesn't know.
97
+ # --- Window ({§model-fact-resolution}) ---
98
+ # Physical provider context only. Unset derives from a live endpoint probe (n_ctx) or
99
+ # models.dev, else null (surfaced once via PLURNK_CONTEXT_UNKNOWN). A configured value
100
+ # caps detected physics or declares it when unknown. Prompt packing and model-facing
101
+ # pressure are consumer policy, not provider configuration.
89
102
  # PLURNK_PROVIDERS_CONTEXT_WINDOW=200000
90
103
 
91
- # --- Model pricing override (USD per million tokens; SPEC §4) ---
92
- # Models.dev owns catalog rates. Set these together for a model absent from the
93
- # snapshot or to deliberately override its rates. Cached input defaults to the
94
- # input rate when omitted. All three knobs are per-alias scopable.
95
- # PLURNK_PROVIDERS_INPUT_USD_PER_MILLION=1
96
- # PLURNK_PROVIDERS_CACHE_READ_USD_PER_MILLION=0.1
97
- # PLURNK_PROVIDERS_OUTPUT_USD_PER_MILLION=5
98
-
99
104
  # --- llama-server detection pin (#34) ---
100
105
  # Unset = auto-detect from the /v1/models fingerprint. 1 = pin llama-server capabilities
101
106
  # (grammar transport, slot pinning, /tokenize) WITHOUT trusting the probe; 0 = force plain
@@ -122,6 +127,8 @@ PLURNK_PROVIDERS_PROVIDER_CLOUDFLARE_API_KEY_ENV=CLOUDFLARE_API_TOKEN,CLOUDFLARE
122
127
  # Fireworks reasoners default on when reasoning_effort is omitted; explicit
123
128
  # "none" is its off switch. This is a declared wire exception, not a registry.
124
129
  PLURNK_PROVIDERS_PROVIDER_FIREWORKS_REASONING_STYLE=effort_explicit
130
+ # Direct DeepSeek reasoning follows {§deepseek-reasoning-request}.
131
+ PLURNK_PROVIDERS_PROVIDER_DEEPSEEK_REASONING_STYLE=thinking_effort
125
132
  PLURNK_PROVIDERS_PROVIDER_VOLCENGINE_NPM=@ai-sdk/openai-compatible
126
133
  PLURNK_PROVIDERS_PROVIDER_VOLCENGINE_BASE_URL=https://ark.ap-southeast.bytepluses.com/api/v3
127
134
  PLURNK_PROVIDERS_PROVIDER_VOLCENGINE_API_KEY_ENV=ARK_API_KEY
@@ -156,11 +163,13 @@ OPENAI_BASE_URL=https://api.openai.com/v1
156
163
  PLURNK_BASE_URL=https://plurnk.ai/v1
157
164
  # PLURNK_BASE_URL=http://plurnksnr2kihuukt6v22ko72r34dxeatbsfhgow3hvnlw6btanxphad.onion/v1 # Tor
158
165
 
159
- # --- Generation envelope (#507, owner-ruled) - sane defaults from the DETECTED window ---
166
+ # --- Generation envelope (#507) - sane defaults from the DETECTED window ---
160
167
  # When a backend advertises its context window (llama-server n_ctx, the plurnk.ai router,
161
168
  # a cataloged cloud model), the reserves derive from it automatically - ZERO operator
162
169
  # tuning. Each accepts a percentage of the window ("10%") or an absolute token count
163
170
  # ("4096"; absolutes win outright, alias-scopable for measured envelopes). The prompt
164
171
  # budget is window - reasoning - completion - the consumer's own safety margin.
172
+ # On llama-server, the resolved reasoning reserve is also the adaptive per-response
173
+ # reasoning ceiling. It is one cumulative allowance across every reasoning block.
165
174
  PLURNK_PROVIDERS_REASONING_RESERVE=10%
166
175
  PLURNK_PROVIDERS_COMPLETION_RESERVE=25%
package/README.md CHANGED
@@ -5,13 +5,21 @@ PLURNK's stable model-provider contract and its adapter to the
5
5
 
6
6
  Ordinary provider behavior is intentionally not reimplemented here:
7
7
 
8
- - Models.dev supplies provider package, endpoint, credential, context-window,
9
- output-limit, and pricing metadata at build time.
8
+ - A release-time Models.dev snapshot supplies provider package, endpoint, and
9
+ credential names, plus context-window, output-limit, reasoning-capability,
10
+ and pricing metadata.
10
11
  - Official AI SDK providers own vendor request and response protocols.
11
12
  - PLURNK owns aliases, generation envelopes, normalized usage and errors,
12
13
  evidence capture, first-party metadata, and local endpoint capabilities.
13
14
 
14
15
  See `SPEC.md` for the contract and `.env.defaults` for every operational knob.
16
+ The package-owned `PLURNK_PROVIDERS_ERROR_DETAIL_LIMIT` bounds upstream
17
+ diagnostic text in public provider Problems.
18
+
19
+ Model facts do not share one fallback chain. Context windows, output envelopes,
20
+ reasoning activation, and estimated prices resolve independently
21
+ ({§model-fact-resolution}). PLURNK does not fetch live per-token prices, and the
22
+ local estimate is not an authoritative relay-settled charge.
15
23
 
16
24
  ## Configure a model
17
25
 
@@ -60,10 +68,15 @@ It may use any npm scope. Its package manifest declares the PLURNK name:
60
68
  The default export is an AI SDK provider with
61
69
  `languageModel(modelId)`. PLURNK adapts that language model into its own
62
70
  contract, so plugins do not reproduce retries, usage normalization, envelopes,
63
- or telemetry.
71
+ notices, or RFC 9457 failure normalization.
72
+
73
+ The manifest may declare always-on `plurnk.attribution`. The default export may
74
+ also implement synchronous `attributions(context)` and decide per provider
75
+ attempt whether to return no, one, or many additional opaque tags
76
+ ({§plugin-attribution}).
64
77
 
65
78
  Discovery is scope-agnostic and rejects duplicate names.
66
- `PLURNK_PLUGINS_TRUSTED_ONLY` restricts third-party discovery.
79
+ Third-party discovery uses the shared pre-import trust contract ({§plugin-trust-boundary}).
67
80
 
68
81
  ## Local endpoints
69
82
 
@@ -75,9 +88,60 @@ The `plurnk` provider retains the compatible transport because it carries
75
88
  first-party attribution and loop metadata and leaves model tuning to the
76
89
  endpoint.
77
90
 
91
+ ## Configured-provider packet conformance matrix
92
+
93
+ Every configured model alias is exercised through a real PLURNK loop — the
94
+ production packet, a model-selected operation, its materialized result, and
95
+ completion — never a transport-only completion. Provider-exposed reasoning must
96
+ survive in the durable assistant packet and digest; a provider with no private
97
+ reasoning is valid when the observable operation cycle succeeds.
98
+
99
+ One specimen at a time, deterministically:
100
+
101
+ ```sh
102
+ cd plurnk-core
103
+ npm run test:live:specimen -- "<test-name-pattern>"
104
+ ```
105
+
106
+ The selector inserts `--test-name-pattern` before the expanded live file list in
107
+ the exact standard `test:live` invocation; trailing npm arguments alone cannot
108
+ narrow the suite. This procedure is `plurnk-core`'s own; the ledger below is
109
+ maintained with the evidence for every alias it names.
110
+
111
+ ### Classifications
112
+
113
+ | Class | Meaning |
114
+ |---|---|
115
+ | pass | Full packet cycle completed; durable packet and digest verified |
116
+ | auth/credential | The route is blocked before the model by authorization or credential handling |
117
+ | transport | The route fails at a transport/capability boundary, not the model |
118
+ | op:stable-fail | An operation-level failure repeated on replay; assertion unweakened |
119
+ | op:stochastic | An operation-level failure did not repeat on a later roll |
120
+ | unreachable | The endpoint cannot be reached from this machine |
121
+
122
+ Authorization and credential failures are reported as their own class, never as
123
+ model failures. Repeated stochastic and stable operation failures are reported
124
+ separately in the ledger's specimens.
125
+
126
+ ### Ledger
127
+
128
+ | Alias | Route (snapshot) | Class | Evidence |
129
+ |---|---|---|---|
130
+ | 38 configured aliases — 2026-07 sweep | — | 20 × pass; 14 × auth/credential/transport; 4 × operation-level | Initial READ line-slice sweep (`#7`) |
131
+ | `cfgpt120b`, `grok` | — | op:stochastic → pass on replay | `#7` |
132
+ | `cfkimi27`, `kimi` | — | op:stable-fail (unresolved, unweakened assertion) | `#7` |
133
+ | `cfds1` | `cloudflare/@cf/deepseek-ai/deepseek-r1-distill-qwen-32b` | op:stable-fail — READ repeated 13 turns to the 508 strike threshold; retrieval materialization verified (`2:beta` present, exact 409 recovery given) | `/home/hyzen/benchmarks/live-contract-read-L-TIgart/digest/` (`#7`) |
134
+
135
+ The full current classifications of every configured alias are refreshed by the
136
+ frozen-candidate live drill's honest reporting; this ledger is the maintained
137
+ record of that procedure, never a substitute for it.
138
+
78
139
  ## Development
79
140
 
80
141
  ```sh
81
142
  npm run test:lint -w @plurnk/plurnk-providers
82
143
  npm run test:unit -w @plurnk/plurnk-providers
83
144
  ```
145
+
146
+ `npm run test:providersPing` is an explicit paid diagnostic; it calls each
147
+ keyed provider once and prints the retained sanitized evidence directory.