@evomap/evolver-adapter-public 2.0.0-beta.6 → 2.0.0-beta.8

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.
@@ -81,6 +81,12 @@ export interface PublicHelloResult {
81
81
  httpStatus?: number;
82
82
  secretDiverged?: boolean;
83
83
  }
84
+ export interface PublicHelloOptions {
85
+ rotate: boolean;
86
+ evolverVersion?: string;
87
+ /** Keep trust probes from adopting or clearing local credential state. */
88
+ preserveCredentials?: boolean;
89
+ }
84
90
  export interface PublicHeartbeatOptions {
85
91
  evolverVersion?: string;
86
92
  lastUpdate?: PublicLastUpdatePayload;
@@ -129,10 +135,7 @@ export declare class PublicHubCapability implements hub.HubCapability {
129
135
  readonly auth: hub.AuthProvider;
130
136
  readonly recipes: hub.RecipeCapability;
131
137
  constructor(opts: PublicHubOptions);
132
- hello(opts: {
133
- rotate: boolean;
134
- evolverVersion?: string;
135
- }): Promise<PublicHelloResult>;
138
+ hello(opts: PublicHelloOptions): Promise<PublicHelloResult>;
136
139
  heartbeat(opts?: PublicHeartbeatOptions): Promise<PublicHeartbeatResult>;
137
140
  private heartbeatMeta;
138
141
  publish(bundle: hub.AssetRecord[]): Promise<hub.PublishReceipt>;
@@ -120,10 +120,12 @@ export class PublicHubCapability {
120
120
  // cleanly; retrying with the diverged secret never can. Signals the caller NOT to arm reauth
121
121
  // backoff. Only legacy node_secret auth exposes this hook — enterprise_token is a no-op.
122
122
  if (isSecretDivergenceRejection(body, payload)) {
123
- this.auth.notifyNodeSecretDiverged?.();
123
+ if (!opts.preserveCredentials) {
124
+ this.auth.notifyNodeSecretDiverged?.();
125
+ }
124
126
  return {
125
127
  ok: false,
126
- error: 'secret_diverged_cleared',
128
+ error: opts.preserveCredentials ? 'secret_diverged' : 'secret_diverged_cleared',
127
129
  secretDiverged: true,
128
130
  ...(rateLimitUntilMs !== undefined ? { rateLimitUntilMs } : {}),
129
131
  ...(retryAfterMs !== undefined ? { retryAfterMs } : {}),
@@ -139,11 +141,13 @@ export class PublicHubCapability {
139
141
  ?? this.opts.senderId();
140
142
  const nodeSecret = stringField(payload, 'node_secret') ?? stringField(payload, 'nodeSecret');
141
143
  const nodeSecretVersion = parseNodeSecretVersion(payload['node_secret_version'] ?? payload['nodeSecretVersion']);
142
- if (nodeSecret && isNodeSecret(nodeSecret)) {
143
- this.auth.adoptNodeSecret?.(nodeSecret, nodeSecretVersion);
144
- }
145
- else {
146
- this.auth.adoptNodeSecretVersion?.(nodeSecretVersion);
144
+ if (!opts.preserveCredentials) {
145
+ if (nodeSecret && isNodeSecret(nodeSecret)) {
146
+ this.auth.adoptNodeSecret?.(nodeSecret, nodeSecretVersion);
147
+ }
148
+ else {
149
+ this.auth.adoptNodeSecretVersion?.(nodeSecretVersion);
150
+ }
147
151
  }
148
152
  return {
149
153
  ok: payload['ok'] !== false && Boolean(nodeId),
@@ -715,7 +719,38 @@ function assetsFromBody(body) {
715
719
  ...(Array.isArray(payload?.['assets']) ? payload['assets'] : []),
716
720
  ...(Array.isArray(payload?.['results']) ? payload['results'] : []),
717
721
  ];
718
- return candidates.filter((candidate) => Boolean(candidate && typeof candidate === 'object' && !Array.isArray(candidate)));
722
+ return candidates
723
+ .filter((candidate) => Boolean(candidate && typeof candidate === 'object' && !Array.isArray(candidate)))
724
+ .map(unwrapFetchDeliveryRow);
725
+ }
726
+ // Delivery-row ranking metadata carried over onto the unwrapped GEP record: hubReuse's candidate
727
+ // ranking reads these from the row (toRankedCandidate), and reuse's ingest strips them before
728
+ // hashing, so carrying them is both useful and integrity-safe. Do not carry `confidence`: it is
729
+ // transport metadata on Gene rows but canonical content on Capsules, so overloading it here can
730
+ // either poison a Gene hash or overwrite the meaning of Capsule content (#565).
731
+ const FETCH_ROW_CARRYOVER_KEYS = ['gdi_score', 'success_rate', 'reuse_count', 'source_node_id'];
732
+ /**
733
+ * The live hub's /a2a/fetch results are DELIVERY ROWS, not raw GEP records (#565, observed on
734
+ * evomap.ai 2026-07-22): the record itself nests under `payload`, while the row's own keys are
735
+ * delivery metadata (asset_type, bundle_id, confidence, gdi_score_mean, callable, …). Treating the
736
+ * row as the asset made reuse's integrity check (computeAssetId over the row) fail on every
737
+ * delivered asset. A GEP record always carries a string `type`; delivery rows carry `asset_type`
738
+ * instead — so unwrap exactly when the row has no `type` and nests an object payload that looks
739
+ * like a GEP record. Rows that already ARE raw records (older hubs, tests) pass through unchanged.
740
+ */
741
+ function unwrapFetchDeliveryRow(row) {
742
+ const record = row;
743
+ if (typeof record['type'] === 'string')
744
+ return row;
745
+ const inner = asRecord(record['payload']);
746
+ if (!inner || typeof inner['type'] !== 'string' || typeof inner['asset_id'] !== 'string')
747
+ return row;
748
+ const carryover = {};
749
+ for (const key of FETCH_ROW_CARRYOVER_KEYS) {
750
+ if (record[key] !== undefined && inner[key] === undefined)
751
+ carryover[key] = record[key];
752
+ }
753
+ return { ...inner, ...carryover };
719
754
  }
720
755
  function accountAssetsFromPayload(payload) {
721
756
  const candidates = [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@evomap/evolver-adapter-public",
3
- "version": "2.0.0-beta.6",
3
+ "version": "2.0.0-beta.8",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "公版 hub 适配器 (积分/治理)",
@@ -14,7 +14,7 @@
14
14
  },
15
15
  "dependencies": {
16
16
  "@evomap/atp-sdk": "^0.1.0",
17
- "@evomap/evolver-core": "2.0.0-beta.6",
17
+ "@evomap/evolver-core": "2.0.0-beta.8",
18
18
  "undici": "^6.27.0"
19
19
  },
20
20
  "optionalDependencies": {