sigrank 1.0.32 → 1.0.34
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.
- package/manifest.json +1 -1
- package/package.json +1 -1
- package/submit/index.mjs +52 -2
- package/tools/submit-verified.mjs +2 -0
package/manifest.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"$schema": "https://raw.githubusercontent.com/anthropics/mcpb/main/schemas/mcpb-manifest-v0.4.schema.json",
|
|
3
3
|
"manifest_version": "0.4",
|
|
4
4
|
"name": "sigrank",
|
|
5
|
-
"version": "1.0.
|
|
5
|
+
"version": "1.0.32",
|
|
6
6
|
"description": "Ranks AI coding operators by token cascade efficiency (Yield = cache_read \u00d7 output / input\u00b2). 25 tools including SigRank Standard record, yield calculation, local token usage pulls, signed submission, and tokscale-powered analytics (market share, developer profiles, model trends, cost analysis, device profiles, MCP usage, competitive intelligence). Privacy-first: runs locally, only four token counts leave the machine.",
|
|
7
7
|
"author": {
|
|
8
8
|
"name": "SunrisesIllNeverSee",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sigrank",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.34",
|
|
4
4
|
"author": "SunrisesIllNeverSee (https://github.com/SunrisesIllNeverSee)",
|
|
5
5
|
"description": "Upsilon measurement engine distributed through the sigrank CLI/MCP compatibility package, with SigRank public leaderboard tools.",
|
|
6
6
|
"mcpName": "io.github.SunrisesIllNeverSee/sigrank-mcp",
|
package/submit/index.mjs
CHANGED
|
@@ -35,6 +35,24 @@ const PLATFORM_ENUM = new Set([
|
|
|
35
35
|
const RULESET_VERSION = "sigrank-token-1";
|
|
36
36
|
const DAY_MS = 86_400_000;
|
|
37
37
|
|
|
38
|
+
// ─── Idempotent actuation (HRN-004 principle 8) ──────────────────────────────
|
|
39
|
+
// snapshot_hash is the natural idempotency key: it is the SHA-256 of the
|
|
40
|
+
// canonical payload bytes. A retried POST (network error, user retry) carries
|
|
41
|
+
// the same hash, so the server can dedup on it. The client also keeps a
|
|
42
|
+
// short-lived in-memory cache so a rapid double-submit never hits the network.
|
|
43
|
+
//
|
|
44
|
+
// Server contract: POST /api/v1/snapshots MUST treat snapshot_hash as an
|
|
45
|
+
// idempotency key. A second POST with the same hash returns 200 with the
|
|
46
|
+
// original result (not 201, not a duplicate row). See sigrank-app ingest gates.
|
|
47
|
+
const DEDUP_TTL_MS = 5 * 60_000; // 5 minutes — covers retries + brief loops
|
|
48
|
+
const _dedupCache = new Map(); // hash → { submittedAt, result }
|
|
49
|
+
|
|
50
|
+
function _dedupEvict(now) {
|
|
51
|
+
for (const [k, v] of _dedupCache) {
|
|
52
|
+
if (now - v.submittedAt > DEDUP_TTL_MS) _dedupCache.delete(k);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
38
56
|
const clamp = (x, lo, hi) => Math.max(lo, Math.min(hi, x));
|
|
39
57
|
const round = (n, dp) => {
|
|
40
58
|
const f = 10 ** dp;
|
|
@@ -212,6 +230,23 @@ export async function submitSignedWindow(
|
|
|
212
230
|
opts,
|
|
213
231
|
);
|
|
214
232
|
|
|
233
|
+
// Idempotent actuation: if we already submitted this exact snapshot_hash
|
|
234
|
+
// within the dedup window, return the cached result instead of re-POSTing.
|
|
235
|
+
// The server also dedups on snapshot_hash, but this avoids the network round
|
|
236
|
+
// trip and makes the client-side retry safe. opts.force bypasses the cache
|
|
237
|
+
// (use when the operator explicitly wants to re-submit after a server fix).
|
|
238
|
+
const now = Date.now();
|
|
239
|
+
_dedupEvict(now);
|
|
240
|
+
const hash = payload.agent.snapshot_hash;
|
|
241
|
+
if (!opts.force && _dedupCache.has(hash)) {
|
|
242
|
+
const cached = _dedupCache.get(hash);
|
|
243
|
+
return {
|
|
244
|
+
...cached.result,
|
|
245
|
+
idempotent: true,
|
|
246
|
+
detail: `Duplicate submit of snapshot ${hash} within ${DEDUP_TTL_MS / 1000}s window — returning cached result. Use force:true to bypass.`,
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
|
|
215
250
|
// Preflight: run the same anti-gaming checks the server will run, locally.
|
|
216
251
|
// If the payload would be rejected or downgraded, warn the operator BEFORE
|
|
217
252
|
// submitting. The server always runs its own checks — this is a preview.
|
|
@@ -251,6 +286,7 @@ export async function submitSignedWindow(
|
|
|
251
286
|
payload,
|
|
252
287
|
signature,
|
|
253
288
|
preflight: pre,
|
|
289
|
+
idempotencyKey: hash,
|
|
254
290
|
detail:
|
|
255
291
|
"By submitting, you agree to the SignalAF Terms of Service and Privacy Policy. Nothing sent. Re-run without dry_run to publish.",
|
|
256
292
|
};
|
|
@@ -282,7 +318,7 @@ export async function submitSignedWindow(
|
|
|
282
318
|
};
|
|
283
319
|
}
|
|
284
320
|
|
|
285
|
-
|
|
321
|
+
const result = {
|
|
286
322
|
status: res.ok ? ack.status || "received" : "error",
|
|
287
323
|
httpStatus: res.status,
|
|
288
324
|
window: WINDOW_TYPE[windowKey] || windowKey,
|
|
@@ -291,9 +327,23 @@ export async function submitSignedWindow(
|
|
|
291
327
|
// ranked = actually on the board (verified + written), not just "received".
|
|
292
328
|
// An unenrolled/revoked device gets HTTP 202 received but is NEVER ranked.
|
|
293
329
|
ranked: isRankedAck(res, ack),
|
|
294
|
-
snapshot_hash:
|
|
330
|
+
snapshot_hash: hash,
|
|
331
|
+
idempotencyKey: hash,
|
|
295
332
|
reason: res.ok ? null : ack.reason || ack.status || `http_${res.status}`,
|
|
296
333
|
detail: ack.detail ?? null,
|
|
297
334
|
preflight: pre,
|
|
298
335
|
};
|
|
336
|
+
|
|
337
|
+
// Cache successful and received submissions for dedup. Don't cache errors
|
|
338
|
+
// (network failures, preflight rejections) — those should be retried.
|
|
339
|
+
if (res.ok) {
|
|
340
|
+
_dedupCache.set(hash, { submittedAt: now, result });
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
return result;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
// Test-only: clear the dedup cache between test cases.
|
|
347
|
+
export function _clearDedupCache() {
|
|
348
|
+
_dedupCache.clear();
|
|
299
349
|
}
|
|
@@ -111,6 +111,7 @@ export async function handleSubmitVerified(args, ctx) {
|
|
|
111
111
|
platform: "multi",
|
|
112
112
|
now: ctx.opts.now,
|
|
113
113
|
dryRun: !!args?.dry_run,
|
|
114
|
+
force: !!ctx.opts.force,
|
|
114
115
|
report,
|
|
115
116
|
});
|
|
116
117
|
out.push({ window: wk, pillars: sum, ...r });
|
|
@@ -139,6 +140,7 @@ export async function handleSubmitVerified(args, ctx) {
|
|
|
139
140
|
platform: pulled.platform,
|
|
140
141
|
now: ctx.opts.now,
|
|
141
142
|
dryRun: !!args?.dry_run,
|
|
143
|
+
force: !!ctx.opts.force,
|
|
142
144
|
report,
|
|
143
145
|
});
|
|
144
146
|
out.push({ window: w.window, pillars: w.pillars, ...r });
|