@quandev104/pi-style 0.1.5 → 0.1.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.
@@ -25,142 +25,130 @@ import {
25
25
  nextGeneration,
26
26
  } from "./compatibility-registry.js";
27
27
 
28
- const PI_VERSION_RANGE = ">=0.83.0 <0.84.0";
29
- const TRUSTED_PI_VERSION = "0.83.0";
30
- const reportStates = new WeakMap<
31
- object,
32
- { records: CompatibilityRecord[]; toolOwner: ReturnType<typeof createToolDecorationOwner> | undefined }
33
- >();
34
- // These fingerprints are coupled to the installed 0.83.0 package source. A matching
35
- // name/arity/hash is evidence of the shipped native method, not a cryptographic proof:
36
- // code loaded before this module could spoof the same function source. We therefore
37
- // fail closed on every unrecorded Pi build and never use module-load capture as trust.
38
- export const TRUSTED_NATIVE_FINGERPRINTS: Readonly<Record<string, string>> = Object.freeze({
39
- "native-assistant-message:render": "2a39243f",
40
- "native-assistant-message:updateContent": "4a2f15ff",
41
- "native-compaction-message:updateDisplay": "f8c44e78",
42
- "native-branch-message:updateDisplay": "415d57b7",
43
- "native-skill-message:updateDisplay": "48099ea6",
44
- "native-custom-message:rebuild": "76ae2e3a",
45
- "tool-call-renderer:getCallRenderer": "951ea0e0",
46
- "tool-result-renderer:getResultRenderer": "8a25cd71",
47
- "native-bash-execution:render": "a5b5abca",
48
- });
28
+ /**
29
+ * Certification is identity-first, never version-pinned: a surface is certified
30
+ * when the runtime method (or class constructor, for additive installs) matches a
31
+ * recorded name/arity/source-fingerprint identity. Pi version strings are
32
+ * informational only (diagnostics, doctor output) and never gate installation — a
33
+ * version drift that preserves the native identity keeps working, and a drift that
34
+ * changes the identity degrades that single surface to its native fallback while
35
+ * every other surface continues.
36
+ */
37
+ export const SUPPORTED_VERSION_RANGE = ">=0.83.0 <0.85.0";
38
+ export const SUPPORTED_PI_VERSIONS: readonly string[] = Object.freeze(["0.83.0", "0.84.0"]);
39
+
40
+ /** A recorded native identity for one certified surface. */
41
+ export interface KnownNativeIdentity {
42
+ readonly name: string;
43
+ readonly arity: number;
44
+ readonly fingerprint: string;
45
+ /** Pi versions known to carry this exact identity (informational only). */
46
+ readonly versions: readonly string[];
47
+ }
49
48
 
50
- export const CERTIFICATION_TABLE = Object.freeze({
51
- "0.83.0": Object.freeze({
52
- "native-assistant-message:render": Object.freeze({
53
- feature: "messages",
54
- subtype: "native-assistant-message",
55
- target: AssistantMessageComponent.prototype,
56
- method: "render",
57
- writable: true,
58
- configurable: true,
49
+ /**
50
+ * Registry of recorded native identities per surface. A surface matches when the
51
+ * runtime function has the same name, arity, and source fingerprint as one of its
52
+ * identities; the `versions` list only documents where that identity was observed.
53
+ * A matching name/arity/hash is evidence of the shipped native method, not a
54
+ * cryptographic proof: code loaded before this module could spoof the same
55
+ * function source. Unrecorded identities therefore fall back natively per surface.
56
+ */
57
+ export const KNOWN_NATIVE_IDENTITIES: Readonly<Record<string, readonly KnownNativeIdentity[]>> = Object.freeze({
58
+ "native-assistant-message:render": Object.freeze([
59
+ Object.freeze({
59
60
  name: "render",
60
61
  arity: 1,
61
- fingerprint: TRUSTED_NATIVE_FINGERPRINTS["native-assistant-message:render"],
62
- adapterId: "message-prefix-osc133-v1",
63
- status: "certified" as const,
62
+ fingerprint: "2a39243f",
63
+ versions: Object.freeze(["0.83.0", "0.84.0"]),
64
64
  }),
65
- "tool-call-renderer:getCallRenderer": Object.freeze({
66
- feature: "tools",
67
- subtype: "tool-call-renderer",
68
- target: ToolExecutionComponent.prototype,
69
- method: "getCallRenderer",
70
- writable: true,
71
- configurable: true,
72
- name: "getCallRenderer",
73
- arity: 0,
74
- fingerprint: TRUSTED_NATIVE_FINGERPRINTS["tool-call-renderer:getCallRenderer"],
75
- adapterId: "tool-renderer-component-v1",
76
- status: "certified" as const,
77
- }),
78
- "tool-result-renderer:getResultRenderer": Object.freeze({
79
- feature: "tools",
80
- subtype: "tool-result-renderer",
81
- target: ToolExecutionComponent.prototype,
82
- method: "getResultRenderer",
83
- writable: true,
84
- configurable: true,
85
- name: "getResultRenderer",
86
- arity: 0,
87
- fingerprint: TRUSTED_NATIVE_FINGERPRINTS["tool-result-renderer:getResultRenderer"],
88
- adapterId: "tool-renderer-component-v1",
89
- status: "certified" as const,
65
+ ]),
66
+ "native-assistant-message:updateContent": Object.freeze([
67
+ Object.freeze({
68
+ name: "updateContent",
69
+ arity: 1,
70
+ fingerprint: "4a2f15ff",
71
+ versions: Object.freeze(["0.83.0"]),
90
72
  }),
91
- "native-assistant-message:updateContent": Object.freeze({
92
- feature: "messages",
93
- subtype: "native-assistant-message",
94
- target: AssistantMessageComponent.prototype,
95
- method: "updateContent",
96
- writable: true,
97
- configurable: true,
73
+ // 0.84.0 adds an `isStreaming` default parameter and per-part markdown
74
+ // transforms; default parameters do not count toward Function.length, so
75
+ // the arity stays 1 while the source fingerprint changes.
76
+ Object.freeze({
98
77
  name: "updateContent",
99
78
  arity: 1,
100
- fingerprint: TRUSTED_NATIVE_FINGERPRINTS["native-assistant-message:updateContent"],
101
- adapterId: "message-thinking-collapse-v1",
102
- status: "certified" as const,
79
+ fingerprint: "d2114491",
80
+ versions: Object.freeze(["0.84.0"]),
103
81
  }),
104
- "native-compaction-message:updateDisplay": Object.freeze({
105
- feature: "messages",
106
- subtype: "native-compaction-message",
107
- target: CompactionSummaryMessageComponent.prototype,
108
- method: "updateDisplay",
109
- writable: true,
110
- configurable: true,
111
- adapterId: "message-block-boxed-v1",
112
- status: "certified" as const,
82
+ ]),
83
+ "native-compaction-message:updateDisplay": Object.freeze([
84
+ Object.freeze({
85
+ name: "updateDisplay",
86
+ arity: 0,
87
+ fingerprint: "f8c44e78",
88
+ versions: Object.freeze(["0.83.0", "0.84.0"]),
113
89
  }),
114
- "native-branch-message:updateDisplay": Object.freeze({
115
- feature: "messages",
116
- subtype: "native-branch-message",
117
- target: BranchSummaryMessageComponent.prototype,
118
- method: "updateDisplay",
119
- writable: true,
120
- configurable: true,
121
- adapterId: "message-block-boxed-v1",
122
- status: "certified" as const,
90
+ ]),
91
+ "native-branch-message:updateDisplay": Object.freeze([
92
+ Object.freeze({
93
+ name: "updateDisplay",
94
+ arity: 0,
95
+ fingerprint: "415d57b7",
96
+ versions: Object.freeze(["0.83.0", "0.84.0"]),
123
97
  }),
124
- "native-skill-message:updateDisplay": Object.freeze({
125
- feature: "messages",
126
- subtype: "native-skill-message",
127
- target: SkillInvocationMessageComponent.prototype,
128
- method: "updateDisplay",
129
- writable: true,
130
- configurable: true,
131
- adapterId: "message-block-boxed-v1",
132
- status: "certified" as const,
98
+ ]),
99
+ "native-skill-message:updateDisplay": Object.freeze([
100
+ Object.freeze({
101
+ name: "updateDisplay",
102
+ arity: 0,
103
+ fingerprint: "48099ea6",
104
+ versions: Object.freeze(["0.83.0", "0.84.0"]),
133
105
  }),
134
- "native-custom-message:rebuild": Object.freeze({
135
- feature: "messages",
136
- subtype: "native-custom-message",
137
- target: CustomMessageComponent.prototype,
138
- method: "rebuild",
139
- writable: true,
140
- configurable: true,
141
- adapterId: "message-block-boxed-v1",
142
- status: "certified" as const,
106
+ ]),
107
+ "native-custom-message:rebuild": Object.freeze([
108
+ Object.freeze({
109
+ name: "rebuild",
110
+ arity: 0,
111
+ fingerprint: "76ae2e3a",
112
+ versions: Object.freeze(["0.83.0", "0.84.0"]),
113
+ }),
114
+ ]),
115
+ "tool-call-renderer:getCallRenderer": Object.freeze([
116
+ Object.freeze({
117
+ name: "getCallRenderer",
118
+ arity: 0,
119
+ fingerprint: "951ea0e0",
120
+ versions: Object.freeze(["0.83.0", "0.84.0"]),
143
121
  }),
144
- "native-bash-execution:render": Object.freeze({
145
- feature: "tools",
146
- subtype: "native-bash-execution",
147
- target: BashExecutionComponent.prototype,
148
- method: "render",
149
- writable: true,
150
- configurable: true,
122
+ ]),
123
+ "tool-result-renderer:getResultRenderer": Object.freeze([
124
+ Object.freeze({
125
+ name: "getResultRenderer",
126
+ arity: 0,
127
+ fingerprint: "8a25cd71",
128
+ versions: Object.freeze(["0.83.0", "0.84.0"]),
129
+ }),
130
+ ]),
131
+ "native-bash-execution:render": Object.freeze([
132
+ Object.freeze({
151
133
  // The additive render patch is certified by the class constructor identity
152
134
  // (name/arity/source fingerprint): the class defines no own `render`, so
153
135
  // the installed own method is the only one and the inherited Container
154
136
  // render is the native fallback.
155
137
  name: "BashExecutionComponent",
156
138
  arity: 2,
157
- fingerprint: TRUSTED_NATIVE_FINGERPRINTS["native-bash-execution:render"],
158
- adapterId: "bash-execution-box-v1",
159
- status: "certified" as const,
139
+ fingerprint: "a5b5abca",
140
+ versions: Object.freeze(["0.83.0", "0.84.0"]),
160
141
  }),
161
- }),
142
+ ]),
162
143
  });
163
144
 
145
+ /** Primary (first-recorded) fingerprint per surface, for diagnostics and back-compat. */
146
+ export const TRUSTED_NATIVE_FINGERPRINTS: Readonly<Record<string, string>> = Object.freeze(
147
+ Object.fromEntries(
148
+ Object.entries(KNOWN_NATIVE_IDENTITIES).map(([key, identities]) => [key, identities[0]!.fingerprint]),
149
+ ),
150
+ );
151
+
164
152
  export interface CompatibilityDescriptorSnapshot {
165
153
  readonly kind: "data" | "accessor";
166
154
  readonly value?: unknown;
@@ -185,7 +173,7 @@ export interface CompatibilityRecordSnapshot {
185
173
 
186
174
  export interface CompatibilityProbeReport {
187
175
  attemptedVersion: string;
188
- matchedCertifiedVersion: string | undefined;
176
+ supportedVersions: readonly string[];
189
177
  certificationTable: typeof CERTIFICATION_TABLE;
190
178
  piVersion: string;
191
179
  versionRange: string;
@@ -196,9 +184,8 @@ export interface CompatibilityProbeReport {
196
184
  certification: readonly {
197
185
  readonly version: string;
198
186
  readonly attemptedVersion: string;
199
- readonly matchedCertifiedVersion: string | undefined;
200
- readonly expected: unknown;
201
- readonly actualPreinstall: CompatibilityDescriptorSnapshot | undefined;
187
+ readonly matchedIdentity: KnownNativeIdentity | undefined;
188
+ readonly knownIdentities: readonly KnownNativeIdentity[];
202
189
  readonly feature: CompatibilityRecord["feature"];
203
190
  readonly subtype: CompatibilityRecord["subtype"];
204
191
  readonly target: object;
@@ -210,6 +197,7 @@ export interface CompatibilityProbeReport {
210
197
  readonly adapterId: string | undefined;
211
198
  readonly status: "certified" | "native-fallback";
212
199
  readonly fallbackReason?: string;
200
+ readonly actualPreinstall: CompatibilityDescriptorSnapshot | undefined;
213
201
  }[];
214
202
  getRuntimeDiagnostics: () => ReadonlyMap<string, number>;
215
203
  getFinalDiagnostics: () => Readonly<import("../features/tools/index.js").ToolDiagnosticArchive> | undefined;
@@ -243,118 +231,38 @@ export function fingerprint(value: unknown): string | undefined {
243
231
  return hash.toString(16).padStart(8, "0");
244
232
  }
245
233
 
246
- function trustedNativeIdentity(spec: TargetSpec, piVersion: string | undefined): unknown {
247
- if (piVersion !== TRUSTED_PI_VERSION) return undefined;
234
+ function knownIdentityMatches(spec: TargetSpec, value: unknown): KnownNativeIdentity | undefined {
235
+ if (typeof value !== "function") return undefined;
236
+ const hash = fingerprint(value);
237
+ const key = `${spec.subtype}:${spec.method}`;
238
+ return (KNOWN_NATIVE_IDENTITIES[key] ?? []).find(
239
+ (identity) => value.name === identity.name && value.length === identity.arity && hash === identity.fingerprint,
240
+ );
241
+ }
242
+
243
+ function matchedNativeIdentity(spec: TargetSpec): KnownNativeIdentity | undefined {
248
244
  if (spec.kind === "add-method") {
249
245
  // Additive install: the prototype must not already own the method (it is
250
- // inherited), the class constructor identity must match the recorded build,
246
+ // inherited), the class constructor identity must match a recorded build,
251
247
  // and the inherited method becomes the native fallback for the delegate.
252
248
  if (Object.getOwnPropertyDescriptor(spec.target, spec.method)) return undefined;
253
249
  const ctor = Object.getOwnPropertyDescriptor(spec.target, "constructor")?.value;
254
- const key = `${spec.subtype}:${spec.method}`;
255
- if (
256
- typeof ctor !== "function" ||
257
- ctor.name !== (spec.identityName ?? spec.method) ||
258
- ctor.length !== (spec.arity ?? 0) ||
259
- fingerprint(ctor) !== TRUSTED_NATIVE_FINGERPRINTS[key]
260
- )
261
- return undefined;
262
- const inherited = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(spec.target), spec.method)?.value;
263
- return typeof inherited === "function" ? inherited : undefined;
250
+ return knownIdentityMatches(spec, ctor);
264
251
  }
265
252
  const descriptor = Object.getOwnPropertyDescriptor(spec.target, spec.method);
266
- const value = descriptor?.value;
267
- const key = `${spec.subtype}:${spec.method}`;
268
- const expectedArity = spec.arity ?? (spec.method === "render" || spec.method === "updateContent" ? 1 : 0);
269
- if (
270
- descriptor?.writable !== true ||
271
- descriptor.configurable !== true ||
272
- typeof value !== "function" ||
273
- value.name !== (spec.identityName ?? spec.method) ||
274
- value.length !== expectedArity ||
275
- fingerprint(value) !== TRUSTED_NATIVE_FINGERPRINTS[key]
276
- )
277
- return undefined;
278
- return value;
253
+ if (descriptor?.writable !== true || descriptor.configurable !== true) return undefined;
254
+ return knownIdentityMatches(spec, descriptor.value);
279
255
  }
280
256
 
281
- export const targetSpecs: readonly TargetSpec[] = [
282
- {
283
- feature: "messages",
284
- subtype: "native-assistant-message",
285
- target: AssistantMessageComponent.prototype,
286
- method: "render",
287
- adapterId: "message-prefix-osc133-v1",
288
- status: "certified",
289
- },
290
- {
291
- feature: "messages",
292
- subtype: "native-assistant-message",
293
- target: AssistantMessageComponent.prototype,
294
- method: "updateContent",
295
- adapterId: "message-thinking-collapse-v1",
296
- status: "certified",
297
- },
298
- {
299
- feature: "messages",
300
- subtype: "native-compaction-message",
301
- target: CompactionSummaryMessageComponent.prototype,
302
- method: "updateDisplay",
303
- adapterId: "message-block-boxed-v1",
304
- status: "certified",
305
- },
306
- {
307
- feature: "messages",
308
- subtype: "native-branch-message",
309
- target: BranchSummaryMessageComponent.prototype,
310
- method: "updateDisplay",
311
- adapterId: "message-block-boxed-v1",
312
- status: "certified",
313
- },
314
- {
315
- feature: "messages",
316
- subtype: "native-skill-message",
317
- target: SkillInvocationMessageComponent.prototype,
318
- method: "updateDisplay",
319
- adapterId: "message-block-boxed-v1",
320
- status: "certified",
321
- },
322
- {
323
- feature: "messages",
324
- subtype: "native-custom-message",
325
- target: CustomMessageComponent.prototype,
326
- method: "rebuild",
327
- adapterId: "message-block-boxed-v1",
328
- status: "certified",
329
- },
330
- {
331
- feature: "tools",
332
- subtype: "tool-call-renderer",
333
- target: ToolExecutionComponent.prototype,
334
- method: "getCallRenderer",
335
- adapterId: "tool-renderer-component-v1",
336
- status: "certified",
337
- },
338
- {
339
- feature: "tools",
340
- subtype: "tool-result-renderer",
341
- target: ToolExecutionComponent.prototype,
342
- method: "getResultRenderer",
343
- adapterId: "tool-renderer-component-v1",
344
- status: "certified",
345
- },
346
- {
347
- feature: "tools",
348
- subtype: "native-bash-execution",
349
- target: BashExecutionComponent.prototype,
350
- method: "render",
351
- kind: "add-method",
352
- identityName: "BashExecutionComponent",
353
- arity: 2,
354
- adapterId: "bash-execution-box-v1",
355
- status: "certified",
356
- },
357
- ];
257
+ function trustedNativeIdentity(spec: TargetSpec): unknown {
258
+ const identity = matchedNativeIdentity(spec);
259
+ if (!identity) return undefined;
260
+ if (spec.kind === "add-method") {
261
+ const inherited = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(spec.target), spec.method)?.value;
262
+ return typeof inherited === "function" ? inherited : undefined;
263
+ }
264
+ return Object.getOwnPropertyDescriptor(spec.target, spec.method)?.value;
265
+ }
358
266
 
359
267
  export interface PiVersionResolution {
360
268
  resolvePackageEntry?: (packageName: string) => string;
@@ -426,6 +334,7 @@ function descriptorSnapshot(descriptor: PropertyDescriptor | undefined): Compati
426
334
  function certificationRecord(
427
335
  spec: TargetSpec,
428
336
  attemptedVersion: string | undefined,
337
+ matchedIdentity: KnownNativeIdentity | undefined,
429
338
  evidence = Object.getOwnPropertyDescriptor(spec.target, spec.method),
430
339
  ) {
431
340
  const descriptor = evidence;
@@ -433,9 +342,8 @@ function certificationRecord(
433
342
  return {
434
343
  version: attemptedVersion ?? "unknown",
435
344
  attemptedVersion: attemptedVersion ?? "unknown",
436
- matchedCertifiedVersion: attemptedVersion === TRUSTED_PI_VERSION ? TRUSTED_PI_VERSION : undefined,
437
- expected: undefined,
438
- actualPreinstall: descriptorSnapshot(descriptor),
345
+ matchedIdentity,
346
+ knownIdentities: KNOWN_NATIVE_IDENTITIES[`${spec.subtype}:${spec.method}`] ?? [],
439
347
  feature: spec.feature,
440
348
  subtype: spec.subtype,
441
349
  target: spec.target,
@@ -450,10 +358,6 @@ function certificationRecord(
450
358
  };
451
359
  }
452
360
 
453
- function versionInRange(version: string | undefined): boolean {
454
- return version === TRUSTED_PI_VERSION;
455
- }
456
-
457
361
  function shape(spec: TargetSpec): boolean {
458
362
  const descriptor = Object.getOwnPropertyDescriptor(spec.target, spec.method);
459
363
  // Additive installs need an unowned slot (the method is inherited); every
@@ -465,7 +369,13 @@ function shape(spec: TargetSpec): boolean {
465
369
  export interface CompatibilityProbeOptions {
466
370
  markers?: Set<string>;
467
371
  config?: Readonly<{
468
- messages: { enabled: boolean; assistantPrefix: boolean; specialBlocks: boolean; hideThinkingLabel: boolean };
372
+ messages: {
373
+ enabled: boolean;
374
+ assistantPrefix: boolean;
375
+ specialBlocks: boolean;
376
+ hideThinkingLabel: boolean;
377
+ hideInterimText: boolean;
378
+ };
469
379
  tools: { enabled: boolean; style: string; maxCollapsedLines: number; maxExpandedLines: number; dimOutput: boolean };
470
380
  preset: string;
471
381
  }>;
@@ -491,7 +401,7 @@ function createFallbackRecord(
491
401
  method: spec.method,
492
402
  originalIdentity: Reflect.get(spec.target, spec.method),
493
403
  piVersion: piVersion ?? "unknown",
494
- versionRange: PI_VERSION_RANGE,
404
+ versionRange: SUPPORTED_VERSION_RANGE,
495
405
  shape: "unsupported",
496
406
  diagnostic: reason,
497
407
  generation,
@@ -500,10 +410,10 @@ function createFallbackRecord(
500
410
  };
501
411
  }
502
412
 
503
- function probeDiagnostic(spec: TargetSpec, piVersion: string | undefined, identity: unknown): string {
504
- if (!versionInRange(piVersion)) return "Pi version is unknown or outside the recorded 0.83.0 support build";
413
+ function probeDiagnostic(spec: TargetSpec, identity: unknown): string {
505
414
  if (!shape(spec)) return "target method shape is not an own writable/configurable function";
506
- if (identity === undefined) return "recorded 0.83.0 native fingerprint, name, or arity did not match";
415
+ if (identity === undefined)
416
+ return "runtime native identity (name, arity, or source fingerprint) matched no recorded Pi surface";
507
417
  return "exact native identity verified; certified guarded decoration enabled";
508
418
  }
509
419
 
@@ -513,7 +423,7 @@ function surfaceDisabled(spec: TargetSpec, config: CompatibilityProbeOptions["co
513
423
  if (!config.messages.enabled) return true;
514
424
  if (spec.subtype === "native-assistant-message" && spec.method === "render") return !config.messages.assistantPrefix;
515
425
  if (spec.subtype === "native-assistant-message" && spec.method === "updateContent")
516
- return !config.messages.hideThinkingLabel;
426
+ return !config.messages.hideThinkingLabel && !config.messages.hideInterimText;
517
427
  if (isSpecialBlock(spec)) return !config.messages.specialBlocks;
518
428
  return true;
519
429
  }
@@ -528,8 +438,8 @@ function probeSpec(options: {
528
438
  toolOwner: ReturnType<typeof createToolDecorationOwner> | undefined;
529
439
  }) {
530
440
  const { spec, piVersion, generation, markers, config, toolOwner, messageSnapshot } = options;
531
- const identity = trustedNativeIdentity(spec, piVersion);
532
- const diagnostic = probeDiagnostic(spec, piVersion, identity);
441
+ const identity = trustedNativeIdentity(spec);
442
+ const diagnostic = probeDiagnostic(spec, identity);
533
443
  const disabled = surfaceDisabled(spec, config);
534
444
  if (disabled) {
535
445
  const reason = "native fallback: surface disabled by normalized configuration";
@@ -541,8 +451,8 @@ function probeSpec(options: {
541
451
  target: spec.target,
542
452
  method: spec.method,
543
453
  piVersion: piVersion ?? "unknown",
544
- versionRange: PI_VERSION_RANGE,
545
- shape: identity !== undefined && versionInRange(piVersion) && shape(spec),
454
+ versionRange: SUPPORTED_VERSION_RANGE,
455
+ shape: identity !== undefined && shape(spec),
546
456
  generation,
547
457
  expectedIdentity: identity,
548
458
  hasExpectedIdentity: true,
@@ -578,6 +488,153 @@ function probeSpec(options: {
578
488
  };
579
489
  }
580
490
 
491
+ export const targetSpecs: readonly TargetSpec[] = [
492
+ {
493
+ feature: "messages",
494
+ subtype: "native-assistant-message",
495
+ target: AssistantMessageComponent.prototype,
496
+ method: "render",
497
+ adapterId: "message-prefix-osc133-v1",
498
+ status: "certified",
499
+ },
500
+ {
501
+ feature: "messages",
502
+ subtype: "native-assistant-message",
503
+ target: AssistantMessageComponent.prototype,
504
+ method: "updateContent",
505
+ adapterId: "message-thinking-collapse-v1",
506
+ status: "certified",
507
+ },
508
+ {
509
+ feature: "messages",
510
+ subtype: "native-compaction-message",
511
+ target: CompactionSummaryMessageComponent.prototype,
512
+ method: "updateDisplay",
513
+ adapterId: "message-block-boxed-v1",
514
+ status: "certified",
515
+ },
516
+ {
517
+ feature: "messages",
518
+ subtype: "native-branch-message",
519
+ target: BranchSummaryMessageComponent.prototype,
520
+ method: "updateDisplay",
521
+ adapterId: "message-block-boxed-v1",
522
+ status: "certified",
523
+ },
524
+ {
525
+ feature: "messages",
526
+ subtype: "native-skill-message",
527
+ target: SkillInvocationMessageComponent.prototype,
528
+ method: "updateDisplay",
529
+ adapterId: "message-block-boxed-v1",
530
+ status: "certified",
531
+ },
532
+ {
533
+ feature: "messages",
534
+ subtype: "native-custom-message",
535
+ target: CustomMessageComponent.prototype,
536
+ method: "rebuild",
537
+ adapterId: "message-block-boxed-v1",
538
+ status: "certified",
539
+ },
540
+ {
541
+ feature: "tools",
542
+ subtype: "tool-call-renderer",
543
+ target: ToolExecutionComponent.prototype,
544
+ method: "getCallRenderer",
545
+ adapterId: "tool-renderer-component-v1",
546
+ status: "certified",
547
+ },
548
+ {
549
+ feature: "tools",
550
+ subtype: "tool-result-renderer",
551
+ target: ToolExecutionComponent.prototype,
552
+ method: "getResultRenderer",
553
+ adapterId: "tool-renderer-component-v1",
554
+ status: "certified",
555
+ },
556
+ {
557
+ feature: "tools",
558
+ subtype: "native-bash-execution",
559
+ target: BashExecutionComponent.prototype,
560
+ method: "render",
561
+ kind: "add-method",
562
+ identityName: "BashExecutionComponent",
563
+ arity: 2,
564
+ adapterId: "bash-execution-box-v1",
565
+ status: "certified",
566
+ },
567
+ ];
568
+
569
+ /**
570
+ * Version → surface → recorded certified identity (informational). Certification
571
+ * itself is decided per-surface by the runtime identity; this table only documents
572
+ * which identity each supported Pi version is known to carry.
573
+ */
574
+ export const CERTIFICATION_TABLE: Readonly<
575
+ Record<
576
+ string,
577
+ Readonly<
578
+ Record<
579
+ string,
580
+ Readonly<{
581
+ feature: CompatibilityRecord["feature"];
582
+ subtype: CompatibilityRecord["subtype"];
583
+ target: object;
584
+ method: string;
585
+ writable: boolean;
586
+ configurable: boolean;
587
+ name: string;
588
+ arity: number;
589
+ fingerprint: string;
590
+ adapterId: string | undefined;
591
+ status: "certified";
592
+ }>
593
+ >
594
+ >
595
+ >
596
+ > = Object.freeze(
597
+ Object.fromEntries(
598
+ SUPPORTED_PI_VERSIONS.map((version) => [
599
+ version,
600
+ Object.freeze(
601
+ Object.fromEntries(
602
+ targetSpecs.flatMap((spec) => {
603
+ const key = `${spec.subtype}:${spec.method}`;
604
+ const identity = (KNOWN_NATIVE_IDENTITIES[key] ?? []).find((candidate) =>
605
+ candidate.versions.includes(version),
606
+ );
607
+ if (!identity) return [];
608
+ return [
609
+ [
610
+ key,
611
+ Object.freeze({
612
+ feature: spec.feature,
613
+ subtype: spec.subtype,
614
+ target: spec.target,
615
+ method: spec.method,
616
+ writable: true,
617
+ configurable: true,
618
+ name: identity.name,
619
+ arity: identity.arity,
620
+ fingerprint: identity.fingerprint,
621
+ adapterId: spec.adapterId,
622
+ status: "certified" as const,
623
+ }),
624
+ ],
625
+ ];
626
+ }),
627
+ ),
628
+ ),
629
+ ]),
630
+ ),
631
+ );
632
+
633
+ const reportStates = new WeakMap<
634
+ object,
635
+ { records: CompatibilityRecord[]; toolOwner: ReturnType<typeof createToolDecorationOwner> | undefined }
636
+ >();
637
+
581
638
  export function probePiCompatibility(
582
639
  piVersion: string | undefined,
583
640
  options: Set<string> | CompatibilityProbeOptions = new Set(),
@@ -587,7 +644,7 @@ export function probePiCompatibility(
587
644
  const toolSpecs = targetSpecs.filter((spec) => spec.feature === "tools");
588
645
  let toolOwner: ReturnType<typeof createToolDecorationOwner> | undefined;
589
646
  if (
590
- toolSpecs.some((spec) => trustedNativeIdentity(spec, piVersion) !== undefined) &&
647
+ toolSpecs.some((spec) => trustedNativeIdentity(spec) !== undefined) &&
591
648
  (options instanceof Set || options.config?.tools.enabled !== false)
592
649
  ) {
593
650
  toolOwner = createToolDecorationOwner(options instanceof Set ? {} : options.toolSnapshot);
@@ -610,6 +667,9 @@ export function probePiCompatibility(
610
667
  for (const spec of targetSpecs) {
611
668
  const captured = evidenceByKey.get(`${spec.subtype}:${String(spec.method)}`);
612
669
  const preinstallDescriptor = captured?.descriptor;
670
+ // Captured before install: the runtime identity is still the pristine native
671
+ // method (or class constructor for additive installs) at this point.
672
+ const matchedIdentity = matchedNativeIdentity(spec);
613
673
  const result = probeSpec({
614
674
  messageSnapshot: options instanceof Set ? undefined : options.messageSnapshot,
615
675
  spec,
@@ -620,15 +680,10 @@ export function probePiCompatibility(
620
680
  toolOwner,
621
681
  });
622
682
  records.push(result.record);
623
- const certificate = certificationRecord(spec, piVersion, preinstallDescriptor);
683
+ const certificate = certificationRecord(spec, piVersion, matchedIdentity, preinstallDescriptor);
624
684
  certification.push({
625
685
  ...certificate,
626
686
  attemptedVersion: piVersion ?? "unknown",
627
- matchedCertifiedVersion: piVersion === TRUSTED_PI_VERSION ? TRUSTED_PI_VERSION : undefined,
628
- expected:
629
- CERTIFICATION_TABLE[TRUSTED_PI_VERSION][
630
- `${spec.subtype}:${spec.method}` as keyof (typeof CERTIFICATION_TABLE)["0.83.0"]
631
- ],
632
687
  actualPreinstall: descriptorSnapshot(preinstallDescriptor),
633
688
  status: result.fallback ? "native-fallback" : "certified",
634
689
  ...(result.fallback ? { fallbackReason: result.reason } : {}),
@@ -637,10 +692,10 @@ export function probePiCompatibility(
637
692
  }
638
693
  const report: CompatibilityProbeReport = {
639
694
  attemptedVersion: piVersion ?? "unknown",
640
- matchedCertifiedVersion: piVersion === TRUSTED_PI_VERSION ? TRUSTED_PI_VERSION : undefined,
695
+ supportedVersions: SUPPORTED_PI_VERSIONS,
641
696
  certificationTable: CERTIFICATION_TABLE,
642
697
  piVersion: piVersion ?? "unknown",
643
- versionRange: PI_VERSION_RANGE,
698
+ versionRange: SUPPORTED_VERSION_RANGE,
644
699
  generation: currentGeneration(),
645
700
  recordSnapshots: Object.freeze(
646
701
  records.map((record) =>
@@ -659,14 +714,7 @@ export function probePiCompatibility(
659
714
  ),
660
715
  unsupported: Object.freeze(unsupported.map((item) => Object.freeze({ ...item }))),
661
716
  delegationMarkers: Object.freeze([...markers]),
662
- certification: Object.freeze(
663
- certification.map((item) =>
664
- Object.freeze({
665
- ...item,
666
- actualPreinstall: item.actualPreinstall,
667
- }),
668
- ),
669
- ),
717
+ certification: Object.freeze(certification.map((item) => Object.freeze({ ...item }))),
670
718
  getRuntimeDiagnostics: () => toolOwner?.getDiagnostics() ?? new Map(),
671
719
  getFinalDiagnostics: () => toolOwner?.getFinalArchive(),
672
720
  getActiveToolRecordCount: () => toolOwner?.getActiveRecordCount() ?? 0,