@stage5/lumine 0.2.80 → 0.2.81
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/lib/admin.js +2 -2
- package/lib/rewards.js +1 -1
- package/package.json +1 -1
- package/sdk/BUILD_SDK_INDEX.md +3 -3
- package/sdk/LUMINE_ADMIN.md +25 -6
package/lib/admin.js
CHANGED
|
@@ -221,7 +221,7 @@ export function readRewardConfigFile(filePath) {
|
|
|
221
221
|
const normalizedPath = String(filePath || "").trim();
|
|
222
222
|
if (!normalizedPath) {
|
|
223
223
|
throw cliValidationError(
|
|
224
|
-
"Pass the earning rules with --config <rules.json> (
|
|
224
|
+
"Pass the earning rules with --config <rules.json> (userDailyXP, userDailyCoins, optional userDailyClaims, rules[]).",
|
|
225
225
|
);
|
|
226
226
|
}
|
|
227
227
|
let contents;
|
|
@@ -3944,7 +3944,7 @@ function printRewardReviewResult({ operation, data }) {
|
|
|
3944
3944
|
const config = review.config || {};
|
|
3945
3945
|
if (Array.isArray(config.rules)) {
|
|
3946
3946
|
console.log(
|
|
3947
|
-
`Budgets:
|
|
3947
|
+
`Budgets: per user/day ${config.userDailyXP} XP/${config.userDailyCoins} Coins${config.userDailyClaims ? ` · ${config.userDailyClaims} claim(s)` : ""}`,
|
|
3948
3948
|
);
|
|
3949
3949
|
for (const rule of config.rules)
|
|
3950
3950
|
console.log(` ${formatRewardRuleLine(rule)}`);
|
package/lib/rewards.js
CHANGED
|
@@ -214,7 +214,7 @@ function printRewardsHelp() {
|
|
|
214
214
|
lumine rewards sheet --show Summarize the sheet on file (never prints answer keys)
|
|
215
215
|
|
|
216
216
|
rewards.json (project root) declares the economy the reviewer approves:
|
|
217
|
-
{ "
|
|
217
|
+
{ "userDailyXP", "userDailyCoins", "userDailyClaims"?,
|
|
218
218
|
"rules": [{ "id", "title", "xp", "coins", "verifier": "numeric-quiz" | "completion",
|
|
219
219
|
"maxAttempts"?, "retry"?: { "xpPercent", "coinsPercent", "paidAttempts"? }, "minSeconds"? (completion), "progression"?: "dated" | "until-earned" (quiz) }] }
|
|
220
220
|
Questions and answer keys never go in project files; they belong in the sheet.`);
|
package/package.json
CHANGED
package/sdk/BUILD_SDK_INDEX.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# Build SDK Index
|
|
2
2
|
|
|
3
|
-
Version: 1.45.
|
|
3
|
+
Version: 1.45.2
|
|
4
4
|
Updated: 2026-09-14
|
|
5
|
-
Generated: 2026-09-
|
|
5
|
+
Generated: 2026-09-19T04:22:12.342Z
|
|
6
6
|
|
|
7
7
|
## Notes
|
|
8
8
|
- This SDK is injected into Build iframes via the Build preview/runtime.
|
|
@@ -33,7 +33,7 @@ Generated: 2026-09-15T02:06:06.654Z
|
|
|
33
33
|
- Use Twinkle.live for one-way app livestreams and Twinkle.chat for the accompanying thread. Free livestreams require a verified host, end after at most 15 minutes, and issue at most 10 private viewer grants. Twinkle keeps platform-owned live-status/end controls above active hosts, so app code cannot hide or replace the broadcaster's Stop path.
|
|
34
34
|
- Media Energy is separate from AI Energy. Replace Media Energy UI only from canonical mediaEnergy/getUsage responses; never decrement, reserve, or synthesize it in app code.
|
|
35
35
|
- Twinkle.rewards awards real XP and Coins only in the current approved published release. Drafts, local previews, private apps and superseded releases cannot earn. The server supplies a published-runtime grant; app code cannot choose a recipient or award amount.
|
|
36
|
-
- The creator's agent designs the rewards. Declare the economy in a project file `rewards.json` at the root: budgets (
|
|
36
|
+
- The creator's agent designs the rewards. Declare the economy in a project file `rewards.json` at the root: budgets (userDailyXP, userDailyCoins, optional userDailyClaims; there is no app-wide daily or lifetime budget, only what one learner can earn per day) and rules [{ id, title, xp, coins, verifier: 'numeric-quiz' | 'completion', maxAttempts?, retry?: { xpPercent, coinsPercent, paidAttempts? }, minSeconds? (completion), progression?: 'dated' | 'until-earned' (quiz) }]. Wire the matching Twinkle.rewards calls with those literal rule ids. Questions and answer keys NEVER go in project files (published source is readable by every player): quiz rules get them from the private question sheet uploaded with `lumine rewards sheet <file.json>` ({ rules: { <ruleId>: { questions?, sets? } } }); `lumine rewards check` validates both together. A review request freezes the code and proposes rewards.json merged with the sheet; the administrator reads the code, checks the amounts and whether the app is exploitable, may change any amount, and approves. Creators are kids and teens: show approval status and one Send for review action; do not ask them to fill in technical forms. Every code update that retains rewards needs a new approval before publishing. Removing the SDK automatically clears its gate. Apps read amounts, tries and sets from getStatus, never from their own file.
|
|
37
37
|
- Verifiers: 'numeric-quiz' pays for server-checked numeric answers (retry share, attempt limits, dated sets or until-earned sets that stay up until somebody earns them, after-answer guides). 'completion' pays when the app reports an activity finished — a cleared stage, a finished round — at least minSeconds after start({ ruleId }); the server checks only the elapsed time, once per learner per site day (UTC midnight), and the budgets. Call start when the activity begins and claim({ challengeId }) with no answers when it ends; keep completion amounts and userDailyXP small enough that a player scripting the calls would not matter, because nothing else is verified.
|
|
38
38
|
- Numeric quiz answers are verified on the server; client scores, privateDb state, timers and completion booleans are not verified reward evidence. Limits reset at UTC midnight. Rules are earned once per viewer per UTC day; attempt limits and retry payouts come from the approved rule. Challenges expire at the UTC day boundary. Budgets apply across release changes.
|
|
39
39
|
|
package/sdk/LUMINE_ADMIN.md
CHANGED
|
@@ -1143,17 +1143,18 @@ Review questions to settle with Mikey before approving:
|
|
|
1143
1143
|
it, then the next one comes up the following site day (UTC midnight, 9:00 AM Korea)) keep them honest.
|
|
1144
1144
|
- Do the rule IDs in `rewards.json` match what the code starts? Unknown IDs
|
|
1145
1145
|
simply never pay.
|
|
1146
|
-
- Are the amounts and the per-
|
|
1147
|
-
|
|
1146
|
+
- Are the amounts and the per-learner daily budgets right for what the app
|
|
1147
|
+
actually asks of people? There is no app-wide budget, per day or lifetime:
|
|
1148
|
+
a good app keeps paying everyone who plays it. Older configs may still
|
|
1149
|
+
carry `dailyXP`/`dailyCoins`/`lifetimeXP`/`lifetimeCoins`; the API accepts
|
|
1150
|
+
and ignores them, so never add or tune them.
|
|
1148
1151
|
|
|
1149
1152
|
`rules.json` (what `--config` takes, and what the app's `rewards.json` plus
|
|
1150
1153
|
sheet compose into):
|
|
1151
1154
|
|
|
1152
1155
|
```json
|
|
1153
1156
|
{
|
|
1154
|
-
"dailyXP": 2000000, "dailyCoins": 0,
|
|
1155
1157
|
"userDailyXP": 10000, "userDailyCoins": 0,
|
|
1156
|
-
"lifetimeXP": 200000000, "lifetimeCoins": 0,
|
|
1157
1158
|
"rules": [
|
|
1158
1159
|
{ "id": "stage-1", "title": "Clear Stage 1", "xp": 300, "coins": 0,
|
|
1159
1160
|
"verifier": "completion", "minSeconds": 20 },
|
|
@@ -1191,8 +1192,8 @@ day, elementary 50,000 XP + 1,000 Coins, middle 70,000 + 5,000, high
|
|
|
1191
1192
|
`userDailyClaims` 1; until-earned sets authored from the Korean curriculum.
|
|
1192
1193
|
Arcade Typing (Mikey, 2026-09-12): XP for clearing campaign stages, up to
|
|
1193
1194
|
10,000 XP per learner per day, no Coins. Platform ceilings: 100,000 XP /
|
|
1194
|
-
10,000 Coins per rule and per learner per day
|
|
1195
|
-
per
|
|
1195
|
+
10,000 Coins per rule and per learner per day. No app-wide ceiling exists,
|
|
1196
|
+
per day or lifetime.
|
|
1196
1197
|
|
|
1197
1198
|
Approval freezes these rules with the reviewed snapshot and publishes that
|
|
1198
1199
|
snapshot immediately (the result carries `published.version`); an approval
|
|
@@ -2670,6 +2671,24 @@ Read every line, and put these in the daily report verbatim:
|
|
|
2670
2671
|
line;
|
|
2671
2672
|
- the `day-over-day … worker_heap=…` delta.
|
|
2672
2673
|
|
|
2674
|
+
**The memory report looks back only 24 hours; the run's window is often longer.**
|
|
2675
|
+
On 2026-09-19 a four-day window hid two heap-OOM aborts (09-16 and 09-17) that
|
|
2676
|
+
`memory-daily` no longer showed. In every full review, also search the reviewed
|
|
2677
|
+
error log for `[cluster] worker exited` lines that are not planned or operator
|
|
2678
|
+
recycles, across the whole window since the last completed full run, and treat
|
|
2679
|
+
each one exactly like a non-zero `oom_aborts` / `unexpected_worker_exits`.
|
|
2680
|
+
|
|
2681
|
+
Each unexpected exit is followed by a `[cluster] worker last work slot=… pid=…
|
|
2682
|
+
in_flight=[…] recent=[…]` line (added 2026-09-19). The worker writes that trail
|
|
2683
|
+
synchronously as each piece of work begins and ends, so it survives an abort
|
|
2684
|
+
inside a single synchronous burst. `in_flight` names the requests or socket
|
|
2685
|
+
events that were running when the process died; `recent` lists the last
|
|
2686
|
+
sixteen begin/label/end records with their age before exit. Quote both lists
|
|
2687
|
+
verbatim in the report and in the todo: they are the evidence that pinpoints
|
|
2688
|
+
the code path. `unavailable (no trail file)` means the worker died before its
|
|
2689
|
+
trail existed or an older generation is still running; say so rather than
|
|
2690
|
+
guessing.
|
|
2691
|
+
|
|
2673
2692
|
Escalate in the report (a todo, and a note for Mikey) when any of these hold:
|
|
2674
2693
|
`oom_aborts` > 0, `service_restarts` > 0, `unexpected_worker_exits` > 0, any
|
|
2675
2694
|
worker `heap_high_water_pct` ≥ 95, or `heap_recycles` ≥ 4 in a day (the
|