@quandev104/pi-style 0.1.5 → 0.1.6

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
@@ -491,7 +395,7 @@ function createFallbackRecord(
491
395
  method: spec.method,
492
396
  originalIdentity: Reflect.get(spec.target, spec.method),
493
397
  piVersion: piVersion ?? "unknown",
494
- versionRange: PI_VERSION_RANGE,
398
+ versionRange: SUPPORTED_VERSION_RANGE,
495
399
  shape: "unsupported",
496
400
  diagnostic: reason,
497
401
  generation,
@@ -500,10 +404,10 @@ function createFallbackRecord(
500
404
  };
501
405
  }
502
406
 
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";
407
+ function probeDiagnostic(spec: TargetSpec, identity: unknown): string {
505
408
  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";
409
+ if (identity === undefined)
410
+ return "runtime native identity (name, arity, or source fingerprint) matched no recorded Pi surface";
507
411
  return "exact native identity verified; certified guarded decoration enabled";
508
412
  }
509
413
 
@@ -528,8 +432,8 @@ function probeSpec(options: {
528
432
  toolOwner: ReturnType<typeof createToolDecorationOwner> | undefined;
529
433
  }) {
530
434
  const { spec, piVersion, generation, markers, config, toolOwner, messageSnapshot } = options;
531
- const identity = trustedNativeIdentity(spec, piVersion);
532
- const diagnostic = probeDiagnostic(spec, piVersion, identity);
435
+ const identity = trustedNativeIdentity(spec);
436
+ const diagnostic = probeDiagnostic(spec, identity);
533
437
  const disabled = surfaceDisabled(spec, config);
534
438
  if (disabled) {
535
439
  const reason = "native fallback: surface disabled by normalized configuration";
@@ -541,8 +445,8 @@ function probeSpec(options: {
541
445
  target: spec.target,
542
446
  method: spec.method,
543
447
  piVersion: piVersion ?? "unknown",
544
- versionRange: PI_VERSION_RANGE,
545
- shape: identity !== undefined && versionInRange(piVersion) && shape(spec),
448
+ versionRange: SUPPORTED_VERSION_RANGE,
449
+ shape: identity !== undefined && shape(spec),
546
450
  generation,
547
451
  expectedIdentity: identity,
548
452
  hasExpectedIdentity: true,
@@ -578,6 +482,153 @@ function probeSpec(options: {
578
482
  };
579
483
  }
580
484
 
485
+ export const targetSpecs: readonly TargetSpec[] = [
486
+ {
487
+ feature: "messages",
488
+ subtype: "native-assistant-message",
489
+ target: AssistantMessageComponent.prototype,
490
+ method: "render",
491
+ adapterId: "message-prefix-osc133-v1",
492
+ status: "certified",
493
+ },
494
+ {
495
+ feature: "messages",
496
+ subtype: "native-assistant-message",
497
+ target: AssistantMessageComponent.prototype,
498
+ method: "updateContent",
499
+ adapterId: "message-thinking-collapse-v1",
500
+ status: "certified",
501
+ },
502
+ {
503
+ feature: "messages",
504
+ subtype: "native-compaction-message",
505
+ target: CompactionSummaryMessageComponent.prototype,
506
+ method: "updateDisplay",
507
+ adapterId: "message-block-boxed-v1",
508
+ status: "certified",
509
+ },
510
+ {
511
+ feature: "messages",
512
+ subtype: "native-branch-message",
513
+ target: BranchSummaryMessageComponent.prototype,
514
+ method: "updateDisplay",
515
+ adapterId: "message-block-boxed-v1",
516
+ status: "certified",
517
+ },
518
+ {
519
+ feature: "messages",
520
+ subtype: "native-skill-message",
521
+ target: SkillInvocationMessageComponent.prototype,
522
+ method: "updateDisplay",
523
+ adapterId: "message-block-boxed-v1",
524
+ status: "certified",
525
+ },
526
+ {
527
+ feature: "messages",
528
+ subtype: "native-custom-message",
529
+ target: CustomMessageComponent.prototype,
530
+ method: "rebuild",
531
+ adapterId: "message-block-boxed-v1",
532
+ status: "certified",
533
+ },
534
+ {
535
+ feature: "tools",
536
+ subtype: "tool-call-renderer",
537
+ target: ToolExecutionComponent.prototype,
538
+ method: "getCallRenderer",
539
+ adapterId: "tool-renderer-component-v1",
540
+ status: "certified",
541
+ },
542
+ {
543
+ feature: "tools",
544
+ subtype: "tool-result-renderer",
545
+ target: ToolExecutionComponent.prototype,
546
+ method: "getResultRenderer",
547
+ adapterId: "tool-renderer-component-v1",
548
+ status: "certified",
549
+ },
550
+ {
551
+ feature: "tools",
552
+ subtype: "native-bash-execution",
553
+ target: BashExecutionComponent.prototype,
554
+ method: "render",
555
+ kind: "add-method",
556
+ identityName: "BashExecutionComponent",
557
+ arity: 2,
558
+ adapterId: "bash-execution-box-v1",
559
+ status: "certified",
560
+ },
561
+ ];
562
+
563
+ /**
564
+ * Version → surface → recorded certified identity (informational). Certification
565
+ * itself is decided per-surface by the runtime identity; this table only documents
566
+ * which identity each supported Pi version is known to carry.
567
+ */
568
+ export const CERTIFICATION_TABLE: Readonly<
569
+ Record<
570
+ string,
571
+ Readonly<
572
+ Record<
573
+ string,
574
+ Readonly<{
575
+ feature: CompatibilityRecord["feature"];
576
+ subtype: CompatibilityRecord["subtype"];
577
+ target: object;
578
+ method: string;
579
+ writable: boolean;
580
+ configurable: boolean;
581
+ name: string;
582
+ arity: number;
583
+ fingerprint: string;
584
+ adapterId: string | undefined;
585
+ status: "certified";
586
+ }>
587
+ >
588
+ >
589
+ >
590
+ > = Object.freeze(
591
+ Object.fromEntries(
592
+ SUPPORTED_PI_VERSIONS.map((version) => [
593
+ version,
594
+ Object.freeze(
595
+ Object.fromEntries(
596
+ targetSpecs.flatMap((spec) => {
597
+ const key = `${spec.subtype}:${spec.method}`;
598
+ const identity = (KNOWN_NATIVE_IDENTITIES[key] ?? []).find((candidate) =>
599
+ candidate.versions.includes(version),
600
+ );
601
+ if (!identity) return [];
602
+ return [
603
+ [
604
+ key,
605
+ Object.freeze({
606
+ feature: spec.feature,
607
+ subtype: spec.subtype,
608
+ target: spec.target,
609
+ method: spec.method,
610
+ writable: true,
611
+ configurable: true,
612
+ name: identity.name,
613
+ arity: identity.arity,
614
+ fingerprint: identity.fingerprint,
615
+ adapterId: spec.adapterId,
616
+ status: "certified" as const,
617
+ }),
618
+ ],
619
+ ];
620
+ }),
621
+ ),
622
+ ),
623
+ ]),
624
+ ),
625
+ );
626
+
627
+ const reportStates = new WeakMap<
628
+ object,
629
+ { records: CompatibilityRecord[]; toolOwner: ReturnType<typeof createToolDecorationOwner> | undefined }
630
+ >();
631
+
581
632
  export function probePiCompatibility(
582
633
  piVersion: string | undefined,
583
634
  options: Set<string> | CompatibilityProbeOptions = new Set(),
@@ -587,7 +638,7 @@ export function probePiCompatibility(
587
638
  const toolSpecs = targetSpecs.filter((spec) => spec.feature === "tools");
588
639
  let toolOwner: ReturnType<typeof createToolDecorationOwner> | undefined;
589
640
  if (
590
- toolSpecs.some((spec) => trustedNativeIdentity(spec, piVersion) !== undefined) &&
641
+ toolSpecs.some((spec) => trustedNativeIdentity(spec) !== undefined) &&
591
642
  (options instanceof Set || options.config?.tools.enabled !== false)
592
643
  ) {
593
644
  toolOwner = createToolDecorationOwner(options instanceof Set ? {} : options.toolSnapshot);
@@ -610,6 +661,9 @@ export function probePiCompatibility(
610
661
  for (const spec of targetSpecs) {
611
662
  const captured = evidenceByKey.get(`${spec.subtype}:${String(spec.method)}`);
612
663
  const preinstallDescriptor = captured?.descriptor;
664
+ // Captured before install: the runtime identity is still the pristine native
665
+ // method (or class constructor for additive installs) at this point.
666
+ const matchedIdentity = matchedNativeIdentity(spec);
613
667
  const result = probeSpec({
614
668
  messageSnapshot: options instanceof Set ? undefined : options.messageSnapshot,
615
669
  spec,
@@ -620,15 +674,10 @@ export function probePiCompatibility(
620
674
  toolOwner,
621
675
  });
622
676
  records.push(result.record);
623
- const certificate = certificationRecord(spec, piVersion, preinstallDescriptor);
677
+ const certificate = certificationRecord(spec, piVersion, matchedIdentity, preinstallDescriptor);
624
678
  certification.push({
625
679
  ...certificate,
626
680
  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
681
  actualPreinstall: descriptorSnapshot(preinstallDescriptor),
633
682
  status: result.fallback ? "native-fallback" : "certified",
634
683
  ...(result.fallback ? { fallbackReason: result.reason } : {}),
@@ -637,10 +686,10 @@ export function probePiCompatibility(
637
686
  }
638
687
  const report: CompatibilityProbeReport = {
639
688
  attemptedVersion: piVersion ?? "unknown",
640
- matchedCertifiedVersion: piVersion === TRUSTED_PI_VERSION ? TRUSTED_PI_VERSION : undefined,
689
+ supportedVersions: SUPPORTED_PI_VERSIONS,
641
690
  certificationTable: CERTIFICATION_TABLE,
642
691
  piVersion: piVersion ?? "unknown",
643
- versionRange: PI_VERSION_RANGE,
692
+ versionRange: SUPPORTED_VERSION_RANGE,
644
693
  generation: currentGeneration(),
645
694
  recordSnapshots: Object.freeze(
646
695
  records.map((record) =>
@@ -659,14 +708,7 @@ export function probePiCompatibility(
659
708
  ),
660
709
  unsupported: Object.freeze(unsupported.map((item) => Object.freeze({ ...item }))),
661
710
  delegationMarkers: Object.freeze([...markers]),
662
- certification: Object.freeze(
663
- certification.map((item) =>
664
- Object.freeze({
665
- ...item,
666
- actualPreinstall: item.actualPreinstall,
667
- }),
668
- ),
669
- ),
711
+ certification: Object.freeze(certification.map((item) => Object.freeze({ ...item }))),
670
712
  getRuntimeDiagnostics: () => toolOwner?.getDiagnostics() ?? new Map(),
671
713
  getFinalDiagnostics: () => toolOwner?.getFinalArchive(),
672
714
  getActiveToolRecordCount: () => toolOwner?.getActiveRecordCount() ?? 0,