sigrank 0.0.182 → 0.0.183

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.
@@ -61,7 +61,7 @@ export function cascade({ input, output, cacheCreate, cacheRead }) {
61
61
  leverage: round(leverage, 1),
62
62
  velocity: round(velocity, 3),
63
63
  dev10x: round(dev10x, 2),
64
- class: classify(yield_, dev10x),
64
+ class: classify(total),
65
65
  mode: detectMode({ input: i, output: o, cacheCreate: cw, cacheRead: cr }),
66
66
  };
67
67
  if (warnings.length > 0) result.warnings = warnings;
@@ -69,43 +69,121 @@ export function cascade({ input, output, cacheCreate, cacheRead }) {
69
69
  }
70
70
 
71
71
  /**
72
- * CLASS_TIERS — the canonical 8-tier dev10x taxonomy. SINGLE SOURCE OF TRUTH.
73
- * Every consumer (presentation/tui.mjs, presentation/cli.mjs, tools/_schemas.mjs,
74
- * resources/class-tiers.md) imports THIS list instead of maintaining its own.
75
- * Order is descending (TRANSMITTER at top, IGNITER at bottom) — matches the
76
- * classify() first-match-wins cut order.
72
+ * CLASS_TIERS — the 8 base tier names (K.01–K.08) for display: glyph, color,
73
+ * meaning. SINGLE SOURCE OF TRUTH for tier-level display info.
74
+ *
75
+ * The permanent class is an EXPERIENCE ladder keyed on TOTAL TOKENS. Each tier
76
+ * has 3 sub-stages (I/II/III) — 24 stages total. The 24 thresholds live in
77
+ * RS05_CLASS_THRESHOLDS below. classify() returns the full sub-stage string
78
+ * (e.g. "REFINER II"). Use tierOf() to extract the base tier name.
79
+ *
80
+ * TRANSMITTER is NOT on this ladder — it is a temporary peak badge (RS.08).
81
+ * The client does not evaluate the badge (owner is still calibrating it);
82
+ * the server does it on read.
83
+ *
84
+ * Mirrors the server's canon-ids.ts CLASS_TIERS (display) + ruleset.ts
85
+ * RS05_CLASS_THRESHOLDS (thresholds). Order is descending (ARCH+ → IGNITER).
77
86
  */
78
87
  export const CLASS_TIERS = [
79
- "TRANSMITTER",
80
88
  "ARCH+",
81
89
  "ARCH",
82
90
  "POWER",
83
91
  "BASE",
84
92
  "SEEKER",
85
93
  "REFINER",
94
+ "BEARER",
86
95
  "IGNITER",
87
96
  ];
88
97
 
89
- /** The degenerate-case class returned when both yield and dev10x are null
90
- * (all-zero / empty session). Distinct from IGNITER (which is a real low
91
- * dev10x bucket) so callers can tell "no data" from "bottom tier". */
98
+ /**
99
+ * SIGNAL_CLASSES — the full 24 sub-stage names (8 tiers × 3 sub-stages I/II/III).
100
+ * Mirrors the server's SIGNAL_CLASSES set in lib/board/mappers.ts. The API
101
+ * returns class_tier as one of these 24 values. classify() returns one of these
102
+ * (or UNCLASSED). Use this for schema enums and validation.
103
+ */
104
+ export const SIGNAL_CLASSES = [
105
+ "ARCH+ I", "ARCH+ II", "ARCH+ III",
106
+ "ARCH I", "ARCH II", "ARCH III",
107
+ "POWER I", "POWER II", "POWER III",
108
+ "BASE I", "BASE II", "BASE III",
109
+ "SEEKER I", "SEEKER II", "SEEKER III",
110
+ "REFINER I", "REFINER II", "REFINER III",
111
+ "BEARER I", "BEARER II", "BEARER III",
112
+ "IGNITER I", "IGNITER II", "IGNITER III",
113
+ ];
114
+
115
+ /**
116
+ * RS05_CLASS_THRESHOLDS — 24 total-token breakpoints (8 tiers × 3 sub-stages).
117
+ * Mirrors the server's lib/analytics/ruleset.ts RS05_CLASS_THRESHOLDS exactly.
118
+ * Calibrated from the HCM cut (1,626 operators) using target distribution
119
+ * (Option C): IGNITER 10%, BEARER 12.5%, REFINER 15%, SEEKER 22.5%, BASE 20%,
120
+ * POWER 15%, ARCH 5%, ARCH+ 0% (aspirational). Each tier split into 3
121
+ * equal-population sub-stages. Update this one constant to stay in parity
122
+ * when the owner tweaks server-side.
123
+ */
124
+ export const RS05_CLASS_THRESHOLDS = [
125
+ { class: "ARCH+ I", totalMin: 7068201104627 },
126
+ { class: "ARCH+ II", totalMin: 7068201104627 },
127
+ { class: "ARCH+ III", totalMin: 7068201104627 },
128
+ { class: "ARCH I", totalMin: 186207267611 },
129
+ { class: "ARCH II", totalMin: 98543134083 },
130
+ { class: "ARCH III", totalMin: 68766193943 },
131
+ { class: "POWER I", totalMin: 39958782379 },
132
+ { class: "POWER II", totalMin: 26955905621 },
133
+ { class: "POWER III", totalMin: 19141226889 },
134
+ { class: "BASE I", totalMin: 13960345961 },
135
+ { class: "BASE II", totalMin: 10189224970 },
136
+ { class: "BASE III", totalMin: 7747041813 },
137
+ { class: "SEEKER I", totalMin: 5446673659 },
138
+ { class: "SEEKER II", totalMin: 4014577247 },
139
+ { class: "SEEKER III", totalMin: 2961798768 },
140
+ { class: "REFINER I", totalMin: 2358346840 },
141
+ { class: "REFINER II", totalMin: 1845750357 },
142
+ { class: "REFINER III", totalMin: 1334876308 },
143
+ { class: "BEARER I", totalMin: 984078167 },
144
+ { class: "BEARER II", totalMin: 714619043 },
145
+ { class: "BEARER III", totalMin: 431702990 },
146
+ { class: "IGNITER I", totalMin: 216393332 },
147
+ { class: "IGNITER II", totalMin: 88999166 },
148
+ { class: "IGNITER III", totalMin: 0 },
149
+ ];
150
+
151
+ /** The degenerate-case class returned when totalTokens is null/undefined
152
+ * (all-zero / empty session). Distinct from IGNITER III (which is a real
153
+ * low-experience tier) so callers can tell "no data" from "bottom tier". */
92
154
  export const UNCLASSED = "UNCLASSED";
93
155
 
94
- /** MVP class tiering from Υ + 10xDEV (canon assigns from cascade SNR + 10xDEV; this
95
- * is the open-MVP approximation — proprietary threshold cuts stay server-side). */
96
- export function classify(yieldVal, dev10x) {
97
- // Degenerate: all-null (empty session / no pillars) → UNCLASSED, not IGNITER.
98
- // Falling through to IGNITER here would mislabel a no-data operator as the
99
- // bottom tier; UNCLASSED lets the TUI / narrate surface "no data" instead.
100
- if (yieldVal == null && dev10x == null) return UNCLASSED;
101
- if (yieldVal >= 1000 || dev10x >= 3) return "TRANSMITTER";
102
- if (dev10x >= 1.45) return "ARCH+";
103
- if (dev10x >= 1.35) return "ARCH";
104
- if (dev10x >= 1.2) return "POWER";
105
- if (dev10x >= 1.0) return "BASE";
106
- if (dev10x >= 0) return "SEEKER";
107
- if (dev10x >= -0.3) return "REFINER";
108
- return "IGNITER";
156
+ /** Extract the base tier name from a sub-stage string (e.g. "ARCH+ I" → "ARCH+").
157
+ * Mirrors the server's tierOf() in components/sigrank/types.ts. Returns the
158
+ * input as-is if it's not a sub-stage string (e.g. UNCLASSED). */
159
+ export function tierOf(cls) {
160
+ if (cls === UNCLASSED || cls == null) return cls;
161
+ const parts = String(cls).split(" ");
162
+ if (parts.length >= 2 && ["I", "II", "III"].includes(parts[parts.length - 1])) {
163
+ return parts.slice(0, -1).join(" ");
164
+ }
165
+ return cls;
166
+ }
167
+
168
+ /** Extract the sub-stage from a sub-stage string (e.g. "ARCH+ I" → "I").
169
+ * Mirrors the server's stageOf(). Returns null for non-sub-stage strings. */
170
+ export function stageOf(cls) {
171
+ if (cls === UNCLASSED || cls == null) return null;
172
+ const parts = String(cls).split(" ");
173
+ const stage = parts[parts.length - 1];
174
+ return stage === "I" || stage === "II" || stage === "III" ? stage : null;
175
+ }
176
+
177
+ /** Classify an operator's experience stage from total tokens (input + output +
178
+ * cacheCreate + cacheRead). Descending first-match-wins scan over
179
+ * RS05_CLASS_THRESHOLDS — mirrors the server's assignClass(totalTokens).
180
+ * Returns a full sub-stage string (e.g. "REFINER II") or UNCLASSED. */
181
+ export function classify(totalTokens) {
182
+ if (totalTokens == null || !Number.isFinite(totalTokens)) return UNCLASSED;
183
+ for (const t of RS05_CLASS_THRESHOLDS) {
184
+ if (totalTokens >= t.totalMin) return t.class;
185
+ }
186
+ return "IGNITER III";
109
187
  }
110
188
 
111
189
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sigrank",
3
- "version": "0.0.182",
3
+ "version": "0.0.183",
4
4
  "author": "SunrisesIllNeverSee (https://github.com/SunrisesIllNeverSee)",
5
5
  "description": "SigRank MCP server — the yield cascade + live leaderboard as MCP tools any agent can call",
6
6
  "mcpName": "io.github.SunrisesIllNeverSee/sigrank-mcp",
@@ -15,7 +15,7 @@
15
15
  * npx sigrank watch --window 7d watch one window only (optional filter)
16
16
  *
17
17
  * Color palette mirrors the SigRank web dark theme:
18
- * gold = class TRANSMITTER headline + rank #1
18
+ * gold = rank #1 headline
19
19
  * cyan = active metrics / your row highlight
20
20
  * dim = secondary data, separators
21
21
  * red = negative movement / delta
@@ -23,7 +23,7 @@
23
23
  */
24
24
 
25
25
  import { callTool, DEFAULT_API_BASE, pullActivePlatforms } from "../tools.mjs";
26
- import { cascade, classify, CLASS_TIERS, UNCLASSED } from "../cascade.mjs";
26
+ import { cascade, classify, CLASS_TIERS, UNCLASSED, tierOf } from "../cascade.mjs";
27
27
  import { ALL_PLATFORMS } from "../adapters.mjs";
28
28
  import { ensureIdentity, keystorePath } from "../keystore.mjs";
29
29
  import { submitSignedWindow } from "../submit.mjs";
@@ -90,21 +90,21 @@ const green = (str) => paint(c.green, str);
90
90
  const red = (str) => paint(c.red, str);
91
91
 
92
92
  // ── Class tier → color ─────────────────────────────────────────────────────
93
- // Built from the canonical CLASS_TIERS list (single source of truth). The dead
94
- // BEARER entry (no tier by that name exists) was removed; UNCLASSED added for
95
- // the degenerate no-data case.
93
+ // Color is keyed on the BASE TIER (8 entries in CLASS_TIERS). classify() returns
94
+ // a full sub-stage string (e.g. "REFINER II") — tierOf() extracts the base tier
95
+ // for color lookup. TRANSMITTER is not a class. UNCLASSED for no-data.
96
96
  const CLASS_COLOR = {
97
- TRANSMITTER: (s) => paint(c.boldGold, s),
98
97
  "ARCH+": (s) => paint(c.boldCyan, s),
99
98
  ARCH: (s) => paint(c.cyan, s),
100
99
  POWER: (s) => paint(c.boldWhite, s),
101
100
  BASE: (s) => paint(c.white, s),
102
101
  SEEKER: (s) => paint(c.magenta, s),
103
102
  REFINER: (s) => paint(c.blue, s),
103
+ BEARER: (s) => paint(c.dim, s),
104
104
  IGNITER: (s) => paint(c.dim, s),
105
105
  [UNCLASSED]: (s) => paint(c.dim, s),
106
106
  };
107
- const colorClass = (cls) => (CLASS_COLOR[cls] ?? ((s) => s))(cls);
107
+ const colorClass = (cls) => (CLASS_COLOR[tierOf(cls)] ?? CLASS_COLOR[UNCLASSED] ?? ((s) => s))(cls);
108
108
  // Guard: every canonical tier must have a color here.
109
109
  for (const t of CLASS_TIERS) {
110
110
  if (!CLASS_COLOR[t]) {
@@ -14,7 +14,7 @@
14
14
 
15
15
  import { callTool, DEFAULT_API_BASE, pullActivePlatforms } from "../tools.mjs";
16
16
  import { ALL_PLATFORMS } from "../adapters.mjs";
17
- import { cascade, CLASS_TIERS, UNCLASSED } from "../cascade.mjs";
17
+ import { cascade, CLASS_TIERS, UNCLASSED, tierOf } from "../cascade.mjs";
18
18
  import { freshVerifierPillars } from "../tokenpull.mjs";
19
19
  import { isSignedIn, isCodeChar } from "../connect.mjs";
20
20
  import { loadIdentity, clearIdentity } from "../keystore.mjs";
@@ -201,21 +201,21 @@ const fmtMov = (n) =>
201
201
  n == null || n === 0 ? dim("—") : n > 0 ? green(`+${n}`) : red(`${n}`);
202
202
 
203
203
  // ── Class tier colors ────────────────────────────────────────────────────────
204
- // Built from the canonical CLASS_TIERS list (single source of truth) so a new
205
- // tier added in analytics/cascade.mjs can't silently lack a color here. The
206
- // dead BEARER entry (no tier by that name exists) was removed.
204
+ // Color is keyed on the BASE TIER (8 entries in CLASS_TIERS). classify() returns
205
+ // a full sub-stage string (e.g. "REFINER II") — tierOf() extracts the base tier
206
+ // for color lookup. TRANSMITTER is not a class — it's a temporary peak badge.
207
207
  const CLS = {
208
- TRANSMITTER: (s) => paint(c.boldGold, s),
209
208
  "ARCH+": (s) => paint(c.boldCyan, s),
210
209
  ARCH: (s) => paint(c.cyan, s),
211
210
  POWER: (s) => paint(c.boldWhite, s),
212
211
  BASE: (s) => paint(c.white, s),
213
212
  SEEKER: (s) => paint(c.magenta, s),
214
213
  REFINER: (s) => paint(c.blue, s),
214
+ BEARER: (s) => paint(c.dim, s),
215
215
  IGNITER: (s) => paint(c.dim, s),
216
216
  [UNCLASSED]: (s) => paint(c.dim, s),
217
217
  };
218
- const colorCls = (cls) => (CLS[cls] ?? ((s) => s))(cls);
218
+ const colorCls = (cls) => (CLS[tierOf(cls)] ?? CLS[UNCLASSED] ?? ((s) => s))(cls);
219
219
 
220
220
  // Guard: every canonical tier must have a color, so a new tier added in
221
221
  // analytics/cascade.mjs can't silently render uncolored here.
@@ -1,62 +1,81 @@
1
1
  # SigRank Class Tiers
2
2
 
3
- Every operator is classified into one of eight tiers (the **dev10x** taxonomy)
4
- based on their Yield (Υ = Cache Reads × Output / Input²) and 10xDEV score
5
- (`log10(T × C × R)` where T = output/input, C = cacheCreate/output,
6
- R = cacheRead/cacheCreate). The classifier is `classify()` in
7
- `analytics/cascade.mjs` — the canonical source of truth. The TUI, CLI, MCP
8
- output schemas, and this doc all read from that one list.
9
-
10
- A ninth value, **UNCLASSED**, is returned when both Υ and 10xDEV are null
11
- (empty / all-zero session). It is distinct from IGNITER so callers can tell
12
- "no data" from "bottom tier".
13
-
14
- ## TRANSMITTER (Υ ≥ 1000 or 10xDEV ≥ 3)
15
- - **Profile:** Cascade-optimized operators. High cache reads, minimal input, efficient output.
16
- - **Behavior:** Surgical — minimal new input, maximum cache reuse, high-yield output.
17
- - **Typical:** Power users with long-running sessions, tight context windows, and aggressive cache strategies.
18
- - **Maintain:** Keep cache hit rate high. Avoid context bloat. Monitor with watch_tokenpull.
19
-
20
- ## ARCH+ (10xDEV ≥ 1.45)
21
- - **Profile:** High-leverage architect. Strong compounding loop.
22
- - **Behavior:** Builds forward aggressively while reusing prior context.
23
- - **Fix:** Push cache reads higher to cross into TRANSMITTER.
24
-
25
- ## ARCH (1.35 ≤ 10xDEV < 1.45)
26
- - **Profile:** Established architect. Solid compounding, room to tighten.
27
- - **Behavior:** Reliable reuse + generation balance.
28
- - **Fix:** Increase cacheCreate quality (better summaries, tighter prompts) to reach ARCH+.
29
-
30
- ## POWER (1.2 ≤ 10xDEV < 1.35)
31
- - **Profile:** Productive operator with a forming compounding loop.
32
- - **Behavior:** Moderate cache leverage, decent output efficiency.
33
- - **Fix:** Reuse sessions more aggressively to lift cache reads.
34
-
35
- ## BASE (1.0 ≤ 10xDEV < 1.2)
36
- - **Profile:** Balanced operator. Some cache, decent output efficiency.
37
- - **Behavior:** Productive — reasonable input-to-output ratio, some cache leverage.
38
- - **Typical:** Experienced AI coders who use CLAUDE.md, project context, and session continuity.
39
- - **Fix:** Increase cache reads by reusing sessions. Reduce input by trimming unnecessary context.
40
-
41
- ## SEEKER (0 ≤ 10xDEV < 1.0)
42
- - **Profile:** Learning operator. Compounding loop not yet formed.
43
- - **Behavior:** Exploring — input-heavy, building toward reuse.
44
- - **Fix:** Commit context to cache (longer sessions, --continue) to start compounding.
45
-
46
- ## REFINER (-0.3 ≤ 10xDEV < 0)
47
- - **Profile:** Raw volume operators. High input tokens, low cache reuse.
48
- - **Behavior:** Brute-force — lots of context fed in, relatively little output back.
49
- - **Typical:** New AI users, verbose prompters, no session continuity.
50
- - **Fix:** Build cache across sessions. Stop re-explaining context. Use --continue.
51
-
52
- ## IGNITER (10xDEV < -0.3)
53
- - **Profile:** Sub-baseline. Negative compounding — context is being lost faster than it's built.
54
- - **Behavior:** Each turn re-ingests more than it reuses; the loop runs in reverse.
55
- - **Fix:** Stop starting fresh sessions. Commit context once and reuse it.
3
+ Every operator is classified into one of **24 experience stages** — 8 tiers ×
4
+ 3 sub-stages (I/II/III) — based on their **total tokens** (input + output +
5
+ cacheCreate + cacheRead). The ladder mirrors the server's
6
+ `RS05_CLASS_THRESHOLDS` (`lib/analytics/ruleset.ts` in sigrank-app) — the
7
+ client's `classify()` in `analytics/cascade.mjs` is the canonical local source
8
+ of truth. The TUI, CLI, MCP output schemas, and this doc all read from that
9
+ one list.
10
+
11
+ The class is an **experience** axis — it measures how much volume the operator
12
+ has accumulated. It is separate from the **cascade archetype** (the operator's
13
+ token-flow shape: kinetic loop, archival sponge, volatile ingestor, etc.) and
14
+ from the **TRANSMITTER peak badge** (a temporary state — see below).
15
+
16
+ A 25th value, **UNCLASSED**, is returned when total tokens are null or
17
+ non-finite (empty / all-zero session). It is distinct from IGNITER III so
18
+ callers can tell "no data" from "bottom tier".
19
+
20
+ ## The 8 base tiers (K.01–K.08)
21
+
22
+ Each tier has 3 sub-stages (I/II/III) split by total-token thresholds. The
23
+ sub-stage is the granular experience level; the base tier is the display
24
+ grouping (color, glyph, meaning).
25
+
26
+ ### ARCH+ (K.01) — total ≥ 7.07T
27
+ - **Sub-stages:** ARCH+ I (≥ 7.07T), ARCH+ II (≥ 7.07T), ARCH+ III (≥ 7.07T)
28
+ - **Profile:** Deepest field experience. Volume that became architecture.
29
+ - **Note:** Aspirational — currently 1 operator in the static board.
30
+
31
+ ### ARCH (K.02) — total ≥ 68.8B
32
+ - **Sub-stages:** ARCH I (≥ 186B), ARCH II (≥ 98.5B), ARCH III (≥ 68.8B)
33
+ - **Profile:** System builders. Sustained volume, coherent output.
34
+
35
+ ### POWER (K.03) — total ≥ 19.1B
36
+ - **Sub-stages:** POWER I (≥ 40.0B), POWER II (≥ 27.0B), POWER III (≥ 19.1B)
37
+ - **Profile:** Above the center. Volume compounding.
38
+
39
+ ### BASE (K.04) — total ≥ 7.7B
40
+ - **Sub-stages:** BASE I (≥ 14.0B), BASE II (≥ 10.2B), BASE III (≥ 7.7B)
41
+ - **Profile:** The center of the field. The average operator's experience.
42
+
43
+ ### SEEKER (K.05) — total ≥ 3.0B
44
+ - **Sub-stages:** SEEKER I (≥ 5.4B), SEEKER II (≥ 4.0B), SEEKER III (≥ 3.0B)
45
+ - **Profile:** Approaching the center. Experience accumulating.
46
+
47
+ ### REFINER (K.06) — total ≥ 1.3B
48
+ - **Sub-stages:** REFINER I (≥ 2.4B), REFINER II (≥ 1.8B), REFINER III (≥ 1.3B)
49
+ - **Profile:** Practicing with purpose. Early sustained volume.
50
+
51
+ ### BEARER (K.07) — total ≥ 432M
52
+ - **Sub-stages:** BEARER I (≥ 984M), BEARER II (≥ 715M), BEARER III (≥ 432M)
53
+ - **Profile:** Quiet accumulation. The first real volume.
54
+
55
+ ### IGNITER (K.08) — total ≥ 0
56
+ - **Sub-stages:** IGNITER I (≥ 216M), IGNITER II (≥ 89.0M), IGNITER III (≥ 0)
57
+ - **Profile:** Dormant potential. The still soul. Waiting.
56
58
 
57
59
  ## UNCLASSED (no data)
58
60
  - **Profile:** Empty session — all four pillars are zero.
59
- - **Behavior:** No tokens recorded for this window.
60
- - **Fix:** Run some sessions; the tier will resolve once there is data.
61
+ - **Fix:** Run some sessions; the stage will resolve once there is data.
62
+
63
+ ## TRANSMITTER (peak badge, not a class)
64
+
65
+ TRANSMITTER is **not** on the experience ladder. It is a temporary peak badge
66
+ (RS.08) that any experience tier can earn during a high-frequency,
67
+ high-resonance window. An operator "transmits" when they hit both:
68
+
69
+ - **High frequency:** token throughput (total tokens in window) ≥ 1B
70
+ - **High resonance:** SIGNA RATE (composite signal quality) ≥ 85
71
+
72
+ The badge is per-window (daily/weekly) and lapses when frequency or resonance
73
+ drops. The server evaluates it via `evaluateTransmitterBadge()` in
74
+ `lib/analytics/transmitter-badge.ts`; the client does not evaluate the badge
75
+ locally (the owner is still calibrating the thresholds). The server is the
76
+ authority.
77
+
78
+ ---
61
79
 
62
- Tiers are recalculated on every submission. Your tier can change between windows (7d, 30d, 90d, all-time).
80
+ Tiers are recalculated on every submission. Your stage can change between
81
+ windows (7d, 30d, 90d, all-time) as total tokens accumulate.
@@ -15,28 +15,27 @@
15
15
  */
16
16
 
17
17
  import { DEFAULT_API_BASE } from "./_helpers.mjs";
18
- import { CLASS_TIERS, UNCLASSED } from "../analytics/cascade.mjs";
18
+ import { CLASS_TIERS, UNCLASSED, tierOf } from "../analytics/cascade.mjs";
19
19
 
20
20
  /**
21
- * Map a class tier to a power-user band. The 8 dev10x tiers collapse into 5
21
+ * Map a class tier to a power-user band. The 8 experience tiers collapse into 5
22
22
  * behavioral bands + UNCLASSED so the framing stays short without writing 8
23
23
  * bespoke messages. Band order matches CLASS_TIERS cut order (descending).
24
24
  *
25
- * TRANSMITTER → apex (the rare closed-loop operator)
26
- * ARCH+, ARCH → high (power-user archetype)
25
+ * ARCH+, ARCH → high (deep experience, power-user archetype)
27
26
  * POWER, BASE → mid (building momentum)
28
- * SEEKER, REFINER → early (compounding, not yet compounding well)
29
- * IGNITER → entry (tokens burned, not compounded)
27
+ * SEEKER, REFINER → early (accumulating volume, finding patterns)
28
+ * BEARER, IGNITER → entry (first volume, or dormant)
30
29
  * UNCLASSED / unknown → nodata
31
30
  */
32
31
  const BAND = {
33
- TRANSMITTER: "apex",
34
32
  "ARCH+": "high",
35
33
  ARCH: "high",
36
34
  POWER: "mid",
37
35
  BASE: "mid",
38
36
  SEEKER: "early",
39
37
  REFINER: "early",
38
+ BEARER: "entry",
40
39
  IGNITER: "entry",
41
40
  [UNCLASSED]: "nodata",
42
41
  };
@@ -46,10 +45,12 @@ const BAND = {
46
45
  * silently relabeling every no-data operator as the bottom legacy tier. */
47
46
  export const FALLBACK_CLASS = UNCLASSED;
48
47
 
49
- /** Map a class tier to its power-user band. Exported so tool handlers can
50
- * branch on band without re-deriving the tier→band mapping. */
48
+ /** Map a class tier (full sub-stage string or base tier) to its power-user
49
+ * band. Exported so tool handlers can branch on band without re-deriving the
50
+ * tier→band mapping. Uses tierOf() to extract the base tier from sub-stage
51
+ * strings (e.g. "REFINER II" → "REFINER" → "early"). */
51
52
  export function bandOf(klass) {
52
- return BAND[klass] ?? "nodata";
53
+ return BAND[tierOf(klass)] ?? "nodata";
53
54
  }
54
55
 
55
56
  /**
@@ -2,7 +2,7 @@
2
2
  * tools/_schemas.mjs — MCP tool annotation + input/output schema objects.
3
3
  */
4
4
 
5
- import { CLASS_TIERS, UNCLASSED } from "../analytics/cascade.mjs";
5
+ import { SIGNAL_CLASSES, UNCLASSED } from "../analytics/cascade.mjs";
6
6
 
7
7
  // Smithery quality: output schemas + annotations
8
8
  // MCP tool annotations hint to clients about side-effects, read-only status, etc.
@@ -15,13 +15,13 @@ export const ANNOTATIONS = {
15
15
 
16
16
  // The canonical class-tier enum, single-sourced from analytics/cascade.mjs.
17
17
  // Every output schema that exposes a `class` field uses this so the enum can
18
- // never drift between tools (the old schemas each inlined ["Burner","Builder",
19
- // "10xer"] — a 3-tier legacy that didn't match the 8-tier dev10x classifier
20
- // the cascade actually emits). UNCLASSED is included for the degenerate
21
- // no-data case. Exported so tool files that declare their own output schema
22
- // (optimize-efficiency.mjs, describe-power-user.mjs) import the same enum
23
- // instead of re-inlining a stale tier list.
24
- export const CLASS_ENUM = [...CLASS_TIERS, UNCLASSED];
18
+ // never drift between tools. SIGNAL_CLASSES is the 24 sub-stage names (8 tiers
19
+ // × 3 sub-stages I/II/III) that classify() emits and the API returns.
20
+ // UNCLASSED is included for the degenerate no-data case. Exported so tool
21
+ // files that declare their own output schema (optimize-efficiency.mjs,
22
+ // describe-power-user.mjs) import the same enum instead of re-inlining a
23
+ // stale tier list.
24
+ export const CLASS_ENUM = [...SIGNAL_CLASSES, UNCLASSED];
25
25
 
26
26
  // Common output schema for cascade results (rank_paste, simulate_change, etc.)
27
27
  // Field names match the actual cascade() output in analytics/cascade.mjs:
@@ -9,7 +9,7 @@ import { DEFAULT_API_BASE } from "./_helpers.mjs";
9
9
  export const TOOL_DEF = {
10
10
  name: "describe_power_user",
11
11
  description:
12
- "Returns an explanatory description of what makes an AI power user, anchored in SigRank's metrics and operator classes. Explains the yield metric, leverage, velocity, and how the 8 class tiers (TRANSMITTER / ARCH+ / ARCH / POWER / BASE / SEEKER / REFINER / IGNITER, plus UNCLASSED for no-data) map to power-user behavior patterns. Use this when users ask 'what is an AI power user?' or 'what makes a good AI user?' or 'describe advanced AI user behavior'. Intent: DESCRIBE_POWER_USER (Informational).",
12
+ "Returns an explanatory description of what makes an AI power user, anchored in SigRank's metrics and operator classes. Explains the yield metric, leverage, velocity, and how the 8 experience tiers (ARCH+ / ARCH / POWER / BASE / SEEKER / REFINER / BEARER / IGNITER, each with 3 sub-stages I/II/III, plus UNCLASSED for no-data) map to power-user behavior patterns. Use this when users ask 'what is an AI power user?' or 'what makes a good AI user?' or 'describe advanced AI user behavior'. Intent: DESCRIBE_POWER_USER (Informational).",
13
13
  annotations: { title: "Describe power user", ...ANNOTATIONS.readOnlyHint, ...ANNOTATIONS.idempotentHint },
14
14
  inputSchema: {
15
15
  type: "object",
@@ -57,20 +57,19 @@ export async function handleDescribePowerUser() {
57
57
  leverage: "Leverage (Cr/I) measures how much you reuse prior work vs starting fresh. High leverage = you're building on cached results, not re-explaining everything.",
58
58
  velocity: "Velocity (O/I) measures how much output you get per token spent. High velocity = you're productive, not just active.",
59
59
  },
60
- // The 8-tier dev10x taxonomy + UNCLASSED, in descending cut order
61
- // (matches analytics/cascade.mjs CLASS_TIERS). Each tier carries a
62
- // one-line power-user meaning. The legacy 3-tier Burner/Builder/10xer
63
- // list is retired — the classifier never emitted those names.
60
+ // The 8 base tiers + UNCLASSED, in descending cut order (matches
61
+ // analytics/cascade.mjs CLASS_TIERS). Each tier has 3 sub-stages (I/II/III)
62
+ // — 24 stages total. TRANSMITTER is a peak badge, not a class.
64
63
  class_tiers: [
65
- { class: "TRANSMITTER", meaning: "Apex power user — both leverage and velocity held at once. The rare closed-loop operator." },
66
- { class: "ARCH+", meaning: "AI power user archetype — disciplined, system-level reuse, high output per input." },
67
- { class: "ARCH", meaning: "Power user — heavy cache reuse and strong output velocity." },
68
- { class: "POWER", meaning: "Building momentum — moderate-to-high cache reuse, approaching the ARCH band." },
69
- { class: "BASE", meaning: "Building momentum — cache reuse starting, velocity solid. Increase reuse to climb." },
70
- { class: "SEEKER", meaning: "Compounding, not yet compounding well — cache reuse beginning but input still dominates." },
71
- { class: "REFINER", meaning: "Early compounding — low leverage, refining context reuse habits." },
72
- { class: "IGNITER", meaning: "Entry — tokens burned more than compounded. The shift: reuse prior context." },
73
- { class: UNCLASSED, meaning: "No cascade data yet — run sessions and re-rank to see your tier." },
64
+ { class: "ARCH+", sub_stages: ["ARCH+ I", "ARCH+ II", "ARCH+ III"], meaning: "Deepest field experience — volume that became architecture. The AI power user archetype." },
65
+ { class: "ARCH", sub_stages: ["ARCH I", "ARCH II", "ARCH III"], meaning: "System builder — sustained volume, coherent output, heavy cache reuse." },
66
+ { class: "POWER", sub_stages: ["POWER I", "POWER II", "POWER III"], meaning: "Above the center — volume compounding, building momentum." },
67
+ { class: "BASE", sub_stages: ["BASE I", "BASE II", "BASE III"], meaning: "The center of the field — the average operator's experience. Building momentum." },
68
+ { class: "SEEKER", sub_stages: ["SEEKER I", "SEEKER II", "SEEKER III"], meaning: "Approaching the center — experience accumulating, reuse patterns forming." },
69
+ { class: "REFINER", sub_stages: ["REFINER I", "REFINER II", "REFINER III"], meaning: "Practicing with purpose — early sustained volume, refining context reuse." },
70
+ { class: "BEARER", sub_stages: ["BEARER I", "BEARER II", "BEARER III"], meaning: "Quiet accumulation — the first real volume. Session continuity starting." },
71
+ { class: "IGNITER", sub_stages: ["IGNITER I", "IGNITER II", "IGNITER III"], meaning: "Entry — dormant potential. First sessions, minimal accumulated volume." },
72
+ { class: UNCLASSED, sub_stages: null, meaning: "No cascade data yet — run sessions and re-rank to see your tier." },
74
73
  ],
75
74
  link: "https://signalaf.com/score — check your class tier and yield",
76
75
  shareable_url: `${DEFAULT_API_BASE}/score`,
@@ -55,7 +55,7 @@ export async function handleDiagnoseCascade(args) {
55
55
  diagnosis.push({
56
56
  metric: "cache_leverage",
57
57
  severity: "critical",
58
- finding: `Cache leverage is ${leverage}× — you're reading only ${leverage}× your fresh input from cache. TRANSMITTER-class operators hit 200×+.`,
58
+ finding: `Cache leverage is ${leverage}× — you're reading only ${leverage}× your fresh input from cache. Top-tier operators hit 200×+.`,
59
59
  recommendation:
60
60
  "Increase context reuse: load prior session context, use longer conversation threads, reference earlier outputs.",
61
61
  estimated_yield_impact: `+${Math.round((1 - leverage / 50) * 100)}% Υ potential`,
@@ -8,7 +8,7 @@ import { LEADERBOARD_METRIC } from "../lib/constants.mjs";
8
8
  export const TOOL_DEF = {
9
9
  name: "get_leaderboard",
10
10
  description:
11
- "Fetches the live public SigRank leaderboard from signalaf.com. Reads all ranked operators sorted by yield (Υ = Cache Reads × Output / Input²) and returns an array of operator summaries. Each entry contains: codename (public display name), yield (Υ, the headline efficiency metric), leverage ratio (Cr/I = cache reads divided by input), velocity (O/I = output divided by input), class tier (one of the 8 dev10x tiers: TRANSMITTER / ARCH+ / ARCH / POWER / BASE / SEEKER / REFINER / IGNITER), and rank position (integer, 1-based). Returns an empty array if no operators have submitted yet. Use this to see where operators stand overall, to find specific codenames for get_operator lookups, or to display the current rankings. Do NOT use this to check your own rank if you already know your codename — use get_operator instead for a single-operator profile with per-window breakdowns. After calling this, follow up with get_operator to get detailed metrics for any operator of interest.",
11
+ "Fetches the live public SigRank leaderboard from signalaf.com. Reads all ranked operators sorted by yield (Υ = Cache Reads × Output / Input²) and returns an array of operator summaries. Each entry contains: codename (public display name), yield (Υ, the headline efficiency metric), leverage ratio (Cr/I = cache reads divided by input), velocity (O/I = output divided by input), class tier (one of 24 experience stages: 8 tiers × 3 sub-stages, e.g. ARCH+ I, REFINER II, IGNITER III), and rank position (integer, 1-based). Returns an empty array if no operators have submitted yet. Use this to see where operators stand overall, to find specific codenames for get_operator lookups, or to display the current rankings. Do NOT use this to check your own rank if you already know your codename — use get_operator instead for a single-operator profile with per-window breakdowns. After calling this, follow up with get_operator to get detailed metrics for any operator of interest.",
12
12
  annotations: { title: "Get leaderboard", ...ANNOTATIONS.readOnlyHint, ...ANNOTATIONS.openWorldHint },
13
13
  inputSchema: {
14
14
  type: "object",
@@ -7,7 +7,7 @@ import { OPERATOR_OUTPUT, ANNOTATIONS } from "./_schemas.mjs";
7
7
  export const TOOL_DEF = {
8
8
  name: "get_operator",
9
9
  description:
10
- "Fetches one operator's live profile from the SigRank board by their codename. Reads the operator's current submission data from signalaf.com and returns their detailed metrics: yield (Υ), leverage ratio (Cr/I), velocity (O/I), class tier (one of the 8 dev10x tiers: TRANSMITTER / ARCH+ / ARCH / POWER / BASE / SEEKER / REFINER / IGNITER), rank position (integer, 1-based), and per-window breakdowns for each time range (7d, 30d, 90d, all-time) with the four canonical pillars (input, output, cacheCreate, cacheRead) per window. Returns an error if the codename is not found on the board. Use this to look up any operator who has submitted to the board — codenames are public and visible on the leaderboard. Do NOT use this to browse all operators — use get_leaderboard for that. After calling this, you can use simulate_change to model what would happen if the operator adjusted their token mix.",
10
+ "Fetches one operator's live profile from the SigRank board by their codename. Reads the operator's current submission data from signalaf.com and returns their detailed metrics: yield (Υ), leverage ratio (Cr/I), velocity (O/I), class tier (one of 24 experience stages: 8 tiers × 3 sub-stages, e.g. ARCH+ I, REFINER II, IGNITER III), rank position (integer, 1-based), and per-window breakdowns for each time range (7d, 30d, 90d, all-time) with the four canonical pillars (input, output, cacheCreate, cacheRead) per window. Returns an error if the codename is not found on the board. Use this to look up any operator who has submitted to the board — codenames are public and visible on the leaderboard. Do NOT use this to browse all operators — use get_leaderboard for that. After calling this, you can use simulate_change to model what would happen if the operator adjusted their token mix.",
11
11
  annotations: { title: "Get operator profile", ...ANNOTATIONS.readOnlyHint, ...ANNOTATIONS.openWorldHint },
12
12
  inputSchema: {
13
13
  type: "object",
@@ -10,7 +10,7 @@ import { MAX_INPUT, withParseWarnings } from "./_helpers.mjs";
10
10
  export const TOOL_DEF = {
11
11
  name: "rank_paste",
12
12
  description:
13
- 'Computes the SigRank yield cascade from a paste of token counts. Parses the input, runs the full cascade math locally (no network calls), and returns: yield (Υ, the headline efficiency metric, Υ = Cache Reads × Output / Input²), snr (signal-to-noise ratio), leverage (Cr/I = cache reads divided by input), velocity (O/I = output divided by input), dev10x (10xDEV score), class (operator class tier — the 8-tier dev10x taxonomy: TRANSMITTER / ARCH+ / ARCH / POWER / BASE / SEEKER / REFINER / IGNITER, or UNCLASSED for empty input), mode (detected working mode), and a deterministic prose "card" summarizing the result in plain English. Accepts two input formats: (1) JSON object {"input":N,"output":N,"cacheCreate":N,"cacheRead":N} or (2) four whitespace-separated numbers in order: input output cacheCreate cacheRead. Returns an error if the input is malformed or has negative values. Use this for a quick one-off ranking without submitting to the board. Do NOT use this to submit your score — use submit_paste instead, which both ranks and publishes. Do NOT use this if you want to rank all four time windows at once — use rank_windows for that. After calling this, use submit_paste to publish the result if you want to appear on the leaderboard.',
13
+ 'Computes the SigRank yield cascade from a paste of token counts. Parses the input, runs the full cascade math locally (no network calls), and returns: yield (Υ, the headline efficiency metric, Υ = Cache Reads × Output / Input²), snr (signal-to-noise ratio), leverage (Cr/I = cache reads divided by input), velocity (O/I = output divided by input), dev10x (10xDEV score), class (operator experience stage — 24 stages = 8 tiers × 3 sub-stages I/II/III, e.g. ARCH+ I, REFINER II, IGNITER III, or UNCLASSED for empty input), mode (detected working mode), and a deterministic prose "card" summarizing the result in plain English. Accepts two input formats: (1) JSON object {"input":N,"output":N,"cacheCreate":N,"cacheRead":N} or (2) four whitespace-separated numbers in order: input output cacheCreate cacheRead. Returns an error if the input is malformed or has negative values. Use this for a quick one-off ranking without submitting to the board. Do NOT use this to submit your score — use submit_paste instead, which both ranks and publishes. Do NOT use this if you want to rank all four time windows at once — use rank_windows for that. After calling this, use submit_paste to publish the result if you want to appear on the leaderboard.',
14
14
  annotations: {
15
15
  title: "Rank a paste",
16
16
  ...ANNOTATIONS.readOnlyHint,
@@ -159,7 +159,7 @@ export async function handleSelfImprove(args, ctx) {
159
159
  diagnosis.push({
160
160
  metric: "cache_leverage",
161
161
  severity: "critical",
162
- finding: `Cache leverage is ${leverage}× — TRANSMITTER-class operators hit 200×+.`,
162
+ finding: `Cache leverage is ${leverage}× — top-tier operators hit 200×+.`,
163
163
  recommendation:
164
164
  "Increase context reuse: load prior session context, use longer threads.",
165
165
  });