@stage5/lumine 0.2.28 → 0.2.30
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/package.json +1 -1
- package/sdk/LUMINE_ADMIN.md +202 -4
package/package.json
CHANGED
package/sdk/LUMINE_ADMIN.md
CHANGED
|
@@ -139,6 +139,17 @@ Escalate, with the canonical `https://www.twin-kle.com/subjects/<id>` or
|
|
|
139
139
|
pay-me-to-win contests, and anything that teaches other children a method for
|
|
140
140
|
any of these. Note the recommendation count: a manipulation how-to that other
|
|
141
141
|
kids are recommending is spreading, and that is the urgent part.
|
|
142
|
+
- **AI-cost exploits** — patterns that convert free AI allowances into farmable
|
|
143
|
+
value: clusters of young accounts with heavy AI/battery usage, one person
|
|
144
|
+
operating many accounts that feed a single build through team branches,
|
|
145
|
+
plus-tagged or dot-variant email families (`kid+1@`, `k.id@`) behind multiple
|
|
146
|
+
active accounts, repeated first exchanges across accounts already linked by
|
|
147
|
+
independent evidence, or a rescue claim by an account created under 30 days
|
|
148
|
+
ago (the API maturity gate should make that last case impossible). A new
|
|
149
|
+
member's one first exchange is intended onboarding and is not suspicious by
|
|
150
|
+
itself. The daily battery is real provider money; treat farming signatures
|
|
151
|
+
with the same seriousness as coin farming. Escalate the account list and
|
|
152
|
+
evidence; never auto-enforce.
|
|
142
153
|
- **Bug reports** the run encountered, even secondhand in a comment thread.
|
|
143
154
|
|
|
144
155
|
Two rules that keep the list worth reading:
|
|
@@ -1052,7 +1063,8 @@ end every run report with an **"Insights for Mikey"** section carrying only
|
|
|
1052
1063
|
the deltas and anomalies worth his time, next to the escalation list. Never
|
|
1053
1064
|
dump raw sections at him.
|
|
1054
1065
|
|
|
1055
|
-
|
|
1066
|
+
Nine sections (Mikey's chosen cut 2026-08-10; behavioral-insight and
|
|
1067
|
+
farm-signal sections added the same day):
|
|
1056
1068
|
|
|
1057
1069
|
- `economy` — `topGainers` (coin-ledger aggregation over the window: gained,
|
|
1058
1070
|
spent, net, current balance per user, Zero/Ciel excluded) and `topBalances`
|
|
@@ -1068,7 +1080,16 @@ Four sections (Mikey's chosen cut, 2026-08-10):
|
|
|
1068
1080
|
report period can begin up to one day before or after the exact brief window,
|
|
1069
1081
|
so use those bounds when describing it. Flag accounts that jumped tiers or
|
|
1070
1082
|
dominate that report period. May be `{ unavailable: true }` if the cost
|
|
1071
|
-
report fails; say so rather than guessing.
|
|
1083
|
+
report fails; say so rather than guessing. This section is also the run's
|
|
1084
|
+
AI-cost exploit watch: while reading it, actively look for the signatures the
|
|
1085
|
+
brief actually exposes — one risk group spanning several user IDs, repeated
|
|
1086
|
+
plus-tag or dot-variant email families among top accounts, or heavy spend by
|
|
1087
|
+
accounts that `economy.topGainers` or `notableCandidates` independently marks
|
|
1088
|
+
as recent signups. Cross-check those signals against the escalation
|
|
1089
|
+
categories. Missing join-date or community data is unknown, not evidence that
|
|
1090
|
+
an account is young or empty. A run that reads the spending report without
|
|
1091
|
+
asking "could any of this be one person with many accounts?" has skipped a
|
|
1092
|
+
duty.
|
|
1072
1093
|
- `notableCandidates` — kids (never bots, staff `userType`s, or users already
|
|
1073
1094
|
on the Notable Users list) ranked by authored activity in the window, with
|
|
1074
1095
|
`isNewUser` marking window-new signups. Use it to find the overlooked and
|
|
@@ -1097,14 +1118,62 @@ Four sections (Mikey's chosen cut, 2026-08-10):
|
|
|
1097
1118
|
calendar day before the exact `window.sinceTs`.
|
|
1098
1119
|
Report the contrast between the buckets, and treat `genuinelyInterested` as
|
|
1099
1120
|
notable-users-but-for-teachers.
|
|
1121
|
+
- `engagementPulse` — distinct users per surface (activeUsers, subjects,
|
|
1122
|
+
comments, recommendations, wordle, reflections, dailyTasks, aiChat,
|
|
1123
|
+
lumineBuildChat, buildsEdited, buildsPlayed) for the current window vs the
|
|
1124
|
+
equal-length previous window, each as `{ current, previous, delta }`.
|
|
1125
|
+
Presence, build edits, and build plays come from durable action/version/view
|
|
1126
|
+
events, not mutable `lastActive`/`updatedAt` snapshots. Zero/Ciel are excluded
|
|
1127
|
+
from authored surfaces. Wordle, daily tasks, and AI chat use the equal
|
|
1128
|
+
calendar-bucket ranges in `dayWindow`; those can begin before the exact
|
|
1129
|
+
timestamp window but always compare the same number of days. This is the
|
|
1130
|
+
"where do users actually live, and is it shifting?" section: report only the
|
|
1131
|
+
deltas that mean something, and read a surface's absolute size before
|
|
1132
|
+
dramatizing a small delta.
|
|
1133
|
+
- `launchMetrics` — readouts for recently shipped features so nothing ships
|
|
1134
|
+
unmeasured. v1 carries `firstBuildRescue` (offers recorded and redemptions
|
|
1135
|
+
in the window, each `{ total, byEventType }`, plus first-Lumine-exchange
|
|
1136
|
+
claims) and `wordleSkipShield` (`startDayIndex`, `active`, judged dodges,
|
|
1137
|
+
and skip covers split `earned` vs `fromRescue`). Wordle metrics cover only
|
|
1138
|
+
completed, actually judged days in `judgedWindow`; today's in-progress game
|
|
1139
|
+
is never called a dodge. Offers without redemptions are a reason to inspect
|
|
1140
|
+
sample size, event type, and offer age — not proof of a broken funnel by
|
|
1141
|
+
themselves.
|
|
1142
|
+
- `goneQuiet` — the inverse of `notableCandidates`: users whose `lastActive`
|
|
1143
|
+
fell in the 14 days before the window (so they were around, then stopped),
|
|
1144
|
+
ranked by how regular they were in the prior 30 days (daily tasks and
|
|
1145
|
+
Wordle), capped at 15 with `daysQuiet`. Use it for product signal (what did
|
|
1146
|
+
they stop doing?) and gentle outreach candidates; never guilt a child in
|
|
1147
|
+
public about absence.
|
|
1148
|
+
- `newUserFunnel` — signups in the window with `activeOnDayOne` (any
|
|
1149
|
+
XP-ledger event within 24h of joining) and `returnedAfterDayOne`
|
|
1150
|
+
(`lastActive` beyond their first day), plus the newest few accounts.
|
|
1151
|
+
Deliberately coarse: it is an onboarding health check, not per-child
|
|
1152
|
+
session tracking.
|
|
1153
|
+
- `farmSignals` — AI-cost farm signatures derivable with ZERO new data
|
|
1154
|
+
collection: `inboxFamilies` (verified emails from accounts active in the
|
|
1155
|
+
last `inboxFamilyActivityDays`, with only Gmail/googlemail's documented
|
|
1156
|
+
plus-tag and dot aliases collapsed, flagging inboxes behind 3+ accounts) and
|
|
1157
|
+
`youngAccountAiUsage` (accounts under 30 days old drawing battery in the
|
|
1158
|
+
whole-day `aiUsageDayWindow`). SIGNAL ONLY: siblings legitimately share a
|
|
1159
|
+
parent inbox, so an inbox family is a reason to look, never proof or grounds
|
|
1160
|
+
for action. Feed real suspicions to the AI-cost escalation category. Shared
|
|
1161
|
+
AI device/IP risk evidence is already in `aiSpending.topRiskGroups`; do not
|
|
1162
|
+
guess it from inbox similarity.
|
|
1100
1163
|
|
|
1101
1164
|
The command needs only an active run's `content:read` scope and mutates
|
|
1102
1165
|
nothing; reading the brief is not audited content action. Window boundaries
|
|
1103
1166
|
on the big append-only ledgers are found by binary-searching the PRIMARY key
|
|
1104
1167
|
(several tables have no timeStamp index), avoiding lifetime scans; aggregation
|
|
1105
|
-
is still bounded to the selected 1–30 day window.
|
|
1168
|
+
is still bounded to the selected 1–30 day window. The optional sections run
|
|
1169
|
+
serially around the existing core report so this low-frequency command cannot
|
|
1170
|
+
occupy the production reader pool; one unavailable section does not suppress
|
|
1171
|
+
the others.
|
|
1106
1172
|
|
|
1107
1173
|
```ts
|
|
1174
|
+
type InsightUnavailable = { unavailable: true; error: string };
|
|
1175
|
+
type WindowDelta = { current: number; previous: number; delta: number };
|
|
1176
|
+
|
|
1108
1177
|
type TeacherInsight = {
|
|
1109
1178
|
userId: number;
|
|
1110
1179
|
username: string | null;
|
|
@@ -1180,7 +1249,115 @@ type InsightsBrief = Success<{
|
|
|
1180
1249
|
topAccounts: unknown[];
|
|
1181
1250
|
topRiskGroups: unknown[];
|
|
1182
1251
|
}
|
|
1183
|
-
|
|
|
1252
|
+
| InsightUnavailable;
|
|
1253
|
+
engagementPulse:
|
|
1254
|
+
| {
|
|
1255
|
+
windowDays: number;
|
|
1256
|
+
dayWindow: {
|
|
1257
|
+
currentStartDayIndex: number;
|
|
1258
|
+
currentEndDayIndex: number;
|
|
1259
|
+
previousStartDayIndex: number;
|
|
1260
|
+
previousEndDayIndex: number;
|
|
1261
|
+
dayCount: number;
|
|
1262
|
+
};
|
|
1263
|
+
surfaces: {
|
|
1264
|
+
activeUsers: WindowDelta;
|
|
1265
|
+
subjects: WindowDelta;
|
|
1266
|
+
comments: WindowDelta;
|
|
1267
|
+
recommendations: WindowDelta;
|
|
1268
|
+
wordle: WindowDelta;
|
|
1269
|
+
reflections: WindowDelta;
|
|
1270
|
+
dailyTasks: WindowDelta;
|
|
1271
|
+
aiChat: WindowDelta;
|
|
1272
|
+
lumineBuildChat: WindowDelta;
|
|
1273
|
+
buildsEdited: WindowDelta;
|
|
1274
|
+
buildsPlayed: WindowDelta;
|
|
1275
|
+
};
|
|
1276
|
+
}
|
|
1277
|
+
| InsightUnavailable;
|
|
1278
|
+
launchMetrics:
|
|
1279
|
+
| {
|
|
1280
|
+
firstBuildRescue: {
|
|
1281
|
+
offersRecorded: {
|
|
1282
|
+
total: number;
|
|
1283
|
+
byEventType: Record<string, number>;
|
|
1284
|
+
};
|
|
1285
|
+
redemptions: {
|
|
1286
|
+
total: number;
|
|
1287
|
+
byEventType: Record<string, number>;
|
|
1288
|
+
};
|
|
1289
|
+
firstLumineExchangeClaims: number;
|
|
1290
|
+
};
|
|
1291
|
+
wordleSkipShield: {
|
|
1292
|
+
startDayIndex: number;
|
|
1293
|
+
active: boolean;
|
|
1294
|
+
judgedWindow: {
|
|
1295
|
+
startDayIndex: number;
|
|
1296
|
+
endDayIndex: number;
|
|
1297
|
+
} | null;
|
|
1298
|
+
judgedDodges: number;
|
|
1299
|
+
skipCovers: { earned: number; fromRescue: number };
|
|
1300
|
+
};
|
|
1301
|
+
}
|
|
1302
|
+
| InsightUnavailable;
|
|
1303
|
+
goneQuiet:
|
|
1304
|
+
| {
|
|
1305
|
+
users: Array<{
|
|
1306
|
+
userId: number;
|
|
1307
|
+
username: string | null;
|
|
1308
|
+
lastActive: number | null;
|
|
1309
|
+
daysQuiet: number | null;
|
|
1310
|
+
dailyTasksPrior30d: number;
|
|
1311
|
+
wordlePlaysPrior30d: number;
|
|
1312
|
+
regularityScore: number;
|
|
1313
|
+
}>;
|
|
1314
|
+
totals: { wentQuiet: number; previouslyRegular: number };
|
|
1315
|
+
}
|
|
1316
|
+
| InsightUnavailable;
|
|
1317
|
+
newUserFunnel:
|
|
1318
|
+
| {
|
|
1319
|
+
totals: {
|
|
1320
|
+
signups: number;
|
|
1321
|
+
activeOnDayOne: number;
|
|
1322
|
+
returnedAfterDayOne: number;
|
|
1323
|
+
};
|
|
1324
|
+
newest: Array<{
|
|
1325
|
+
userId: number;
|
|
1326
|
+
username: string | null;
|
|
1327
|
+
joinedAt: number | null;
|
|
1328
|
+
activeOnDayOne: boolean;
|
|
1329
|
+
returnedAfterDayOne: boolean;
|
|
1330
|
+
}>;
|
|
1331
|
+
}
|
|
1332
|
+
| InsightUnavailable;
|
|
1333
|
+
farmSignals:
|
|
1334
|
+
| {
|
|
1335
|
+
inboxFamilyActivityDays: number;
|
|
1336
|
+
inboxFamilies: Array<{
|
|
1337
|
+
inbox: string;
|
|
1338
|
+
accounts: Array<{
|
|
1339
|
+
userId: number;
|
|
1340
|
+
username: string | null;
|
|
1341
|
+
joinedAt: number | null;
|
|
1342
|
+
lastActive: number | null;
|
|
1343
|
+
}>;
|
|
1344
|
+
accountCount: number;
|
|
1345
|
+
youngAccounts: number;
|
|
1346
|
+
}>;
|
|
1347
|
+
aiUsageDayWindow: {
|
|
1348
|
+
startDayIndex: number;
|
|
1349
|
+
endDayIndex: number;
|
|
1350
|
+
};
|
|
1351
|
+
youngAccountAiUsage: Array<{
|
|
1352
|
+
userId: number;
|
|
1353
|
+
username: string | null;
|
|
1354
|
+
joinedAt: number | null;
|
|
1355
|
+
energyUnits: number;
|
|
1356
|
+
replies: number;
|
|
1357
|
+
}>;
|
|
1358
|
+
notes: string;
|
|
1359
|
+
}
|
|
1360
|
+
| InsightUnavailable;
|
|
1184
1361
|
}>;
|
|
1185
1362
|
```
|
|
1186
1363
|
|
|
@@ -1314,6 +1491,27 @@ tried it — ask the author about it instead. This is the standing rule for
|
|
|
1314
1491
|
every composed comment, applied to apps: never claim an experience the
|
|
1315
1492
|
session did not actually have.
|
|
1316
1493
|
|
|
1494
|
+
**Offer a Lumine prompt when the moment invites it (Mikey's direction,
|
|
1495
|
+
2026-08-10).** Zero and Ciel may include one concrete, copy-pasteable Lumine
|
|
1496
|
+
prompt in a comment or reply — a genuinely powerful one, tailored to what the
|
|
1497
|
+
kid is already doing — when the occasion naturally calls for it. Appropriate
|
|
1498
|
+
occasions: a kid describes an idea they wish existed, asks how something on
|
|
1499
|
+
the site was made, hits the edge of what a post/drawing/story can do, shares
|
|
1500
|
+
a Build app that could grow a specific feature, or shows an interest (space,
|
|
1501
|
+
cats, chess, comics) that maps cleanly onto something Lumine could build with
|
|
1502
|
+
them. On those occasions, the prompt IS the helpful answer: quote it so it
|
|
1503
|
+
can be copied as-is, keep it specific to their interest, and mention it works
|
|
1504
|
+
in the Build workspace chat. Restraint rules: never more than one prompt per
|
|
1505
|
+
comment; never in condolence, conflict, wellbeing, or moderation-adjacent
|
|
1506
|
+
threads; never as a reflex closing line on ordinary comments — if the comment
|
|
1507
|
+
is complete without the prompt, post it without the prompt. A run where only
|
|
1508
|
+
a few comments carry a prompt is healthy; a run where most do is shameless
|
|
1509
|
+
plugging, which is exactly what Mikey asked to avoid. SDK-aware prompt ideas
|
|
1510
|
+
are especially good ("ask Lumine to make a magazine that pulls real Twinkle
|
|
1511
|
+
posts with Twinkle.subjects.search") because kids do not know the content
|
|
1512
|
+
APIs exist — but only suggest SDK capabilities that actually exist; check
|
|
1513
|
+
TWINKLE_BUILD_SDK.md if unsure.
|
|
1514
|
+
|
|
1317
1515
|
A composed draft (`--file`, plain UTF-8 text, at most the website's 10,000
|
|
1318
1516
|
character comment limit) flows through the identical draft lifecycle —
|
|
1319
1517
|
reservation, idempotency, context-revision CAS, publish fencing, audit
|