@stage5/lumine 0.3.0 → 0.3.1
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 +83 -1
- package/lib/commands.js +1 -0
- package/package.json +1 -1
- package/sdk/LUMINE_ADMIN.md +10 -0
package/lib/admin.js
CHANGED
|
@@ -2417,7 +2417,7 @@ export function parseAdminOperation(options) {
|
|
|
2417
2417
|
// long as two GPT-6 Sol calls, so it gets its own timeout. The daily
|
|
2418
2418
|
// website management run calls it in a bounded loop (Mikey, 2026-09-28).
|
|
2419
2419
|
const usage =
|
|
2420
|
-
"Usage: lumine admin reward-bank coverage <buildId> [--max-step 3] | seed <buildId> [--max-step 3].";
|
|
2420
|
+
"Usage: lumine admin reward-bank coverage <buildId> [--max-step 3] | seed <buildId> [--max-step 3] | report <buildId> [--days 1].";
|
|
2421
2421
|
const buildId = parseRequiredInteger(
|
|
2422
2422
|
target || options.adminBuild,
|
|
2423
2423
|
"Build ID",
|
|
@@ -2427,6 +2427,20 @@ export function parseAdminOperation(options) {
|
|
|
2427
2427
|
? parseRequiredInteger(options.adminMaxStep, "--max-step", 1)
|
|
2428
2428
|
: 3;
|
|
2429
2429
|
if (maxStep > 10) throw cliValidationError("--max-step must be at most 10.");
|
|
2430
|
+
if (action === "report") {
|
|
2431
|
+
const days = options.adminDays
|
|
2432
|
+
? parseRequiredInteger(options.adminDays, "--days", 1)
|
|
2433
|
+
: 1;
|
|
2434
|
+
if (days > 31) throw cliValidationError("--days must be at most 31.");
|
|
2435
|
+
return readOperation(
|
|
2436
|
+
"reward-bank.report",
|
|
2437
|
+
withQuery("/cli/admin/reward-bank/report", {
|
|
2438
|
+
buildId: String(buildId),
|
|
2439
|
+
days: String(days),
|
|
2440
|
+
}),
|
|
2441
|
+
{ requiresRun: false },
|
|
2442
|
+
);
|
|
2443
|
+
}
|
|
2430
2444
|
if (action === "coverage" || action === "status") {
|
|
2431
2445
|
return readOperation(
|
|
2432
2446
|
"reward-bank.coverage",
|
|
@@ -5390,6 +5404,70 @@ function printReviewRequestResult({ operation, data, result }) {
|
|
|
5390
5404
|
printReviewEvents(data.events);
|
|
5391
5405
|
}
|
|
5392
5406
|
|
|
5407
|
+
// Human view of `lumine admin reward-bank report`; --json has everything.
|
|
5408
|
+
function printRewardBankReport(data) {
|
|
5409
|
+
const pct = (value) =>
|
|
5410
|
+
value === null || value === undefined ? "–" : `${Math.round(value * 100)}%`;
|
|
5411
|
+
console.log(`Question bank report · build #${data.buildId} · last ${data.days} day(s)`);
|
|
5412
|
+
if (data.coverage) {
|
|
5413
|
+
console.log(
|
|
5414
|
+
`Seeding coverage (steps 1-3): ${data.coverage.filled} / ${data.coverage.total}`,
|
|
5415
|
+
);
|
|
5416
|
+
}
|
|
5417
|
+
if (!data.generation) {
|
|
5418
|
+
console.log("Generation: no telemetry table yet.");
|
|
5419
|
+
} else {
|
|
5420
|
+
for (const row of data.generation.bySource) {
|
|
5421
|
+
if (!row.rounds) continue;
|
|
5422
|
+
console.log(
|
|
5423
|
+
`Generation (${row.source}): ${row.rounds} rounds · ${row.accepted} accepted (${pct(row.acceptRate)}) · off-brief ${row.offBrief} · answer mismatch ${row.answerMismatch} · malformed ${row.malformed} · errors ${row.errors} · $${row.costUsd} · avg ${row.avgSeconds ?? "–"}s (max ${row.maxSeconds ?? "–"}s)`,
|
|
5424
|
+
);
|
|
5425
|
+
}
|
|
5426
|
+
for (const row of data.generation.recentRejections.slice(0, 5)) {
|
|
5427
|
+
console.log(
|
|
5428
|
+
` rejected ${row.outcome} ${row.ruleId}/${row.topicKey} step ${row.step}: ${row.problems || "(no reason given)"}`,
|
|
5429
|
+
);
|
|
5430
|
+
}
|
|
5431
|
+
}
|
|
5432
|
+
console.log(`Learners: ${data.learners.total}`);
|
|
5433
|
+
for (const row of data.learners.byRuleStep) {
|
|
5434
|
+
console.log(
|
|
5435
|
+
` ${row.ruleId} step ${row.step}: served ${row.served} · answered ${row.answered} · first-try ${pct(row.firstTryRate)} · solved ${row.solved} · skipped ${row.skipped}`,
|
|
5436
|
+
);
|
|
5437
|
+
}
|
|
5438
|
+
const paid = data.payouts.reduce(
|
|
5439
|
+
(sum, row) => ({ xp: sum.xp + row.xp, coins: sum.coins + row.coins, receipts: sum.receipts + row.receipts }),
|
|
5440
|
+
{ xp: 0, coins: 0, receipts: 0 },
|
|
5441
|
+
);
|
|
5442
|
+
console.log(
|
|
5443
|
+
`Payouts: ${paid.receipts} receipts · ${paid.xp.toLocaleString()} XP · ${paid.coins.toLocaleString()} Coins`,
|
|
5444
|
+
);
|
|
5445
|
+
for (const row of data.payouts) {
|
|
5446
|
+
console.log(
|
|
5447
|
+
` ${row.ruleId} step ${row.step}: ${row.receipts} (${row.firstTry} first try) · ${row.earners} earners · ${row.xp.toLocaleString()} XP · ${row.coins.toLocaleString()} Coins`,
|
|
5448
|
+
);
|
|
5449
|
+
}
|
|
5450
|
+
if (data.ladder.length) {
|
|
5451
|
+
console.log(
|
|
5452
|
+
`Ladder now: ${data.ladder.map((row) => `${row.ruleId} s${row.step}:${row.topicLadders}`).join(", ")}`,
|
|
5453
|
+
);
|
|
5454
|
+
}
|
|
5455
|
+
const hidden = data.bank.filter((row) => row.status === "hidden");
|
|
5456
|
+
console.log(
|
|
5457
|
+
`Bank: ${data.bank.filter((row) => row.status === "active").reduce((n, row) => n + row.questions, 0)} active · ${hidden.reduce((n, row) => n + row.questions, 0)} hidden${hidden.length ? ` (${hidden.map((row) => `${row.hiddenReason}: ${row.questions}`).join(", ")})` : ""} · ${data.bank.reduce((n, row) => n + row.createdInWindow, 0)} new in window`,
|
|
5458
|
+
);
|
|
5459
|
+
for (const row of data.questionsToReview.reported) {
|
|
5460
|
+
console.log(
|
|
5461
|
+
` reported #${row.id} (${row.reports}, ${row.status}) ${row.ruleId}/${row.topicKey} s${row.step}: ${row.reasons}`,
|
|
5462
|
+
);
|
|
5463
|
+
}
|
|
5464
|
+
for (const row of data.questionsToReview.hardest) {
|
|
5465
|
+
console.log(
|
|
5466
|
+
` hardest #${row.id} ${row.ruleId}/${row.topicKey} s${row.step}: solved ${pct(row.solveRate)} of ${row.learners}`,
|
|
5467
|
+
);
|
|
5468
|
+
}
|
|
5469
|
+
}
|
|
5470
|
+
|
|
5393
5471
|
function printAdminResult({ operation, result }) {
|
|
5394
5472
|
const data = result?.data || {};
|
|
5395
5473
|
if (printChatSafetyResult({ operation, data })) return;
|
|
@@ -5397,6 +5475,10 @@ function printAdminResult({ operation, result }) {
|
|
|
5397
5475
|
printRewardActivity(data);
|
|
5398
5476
|
return;
|
|
5399
5477
|
}
|
|
5478
|
+
if (operation.name === "reward-bank.report") {
|
|
5479
|
+
printRewardBankReport(data);
|
|
5480
|
+
return;
|
|
5481
|
+
}
|
|
5400
5482
|
if (operation.name.startsWith("reward-bank.")) {
|
|
5401
5483
|
if (operation.name === "reward-bank.seed") {
|
|
5402
5484
|
console.log(
|
package/lib/commands.js
CHANGED
|
@@ -3060,6 +3060,7 @@ export function printHelp() {
|
|
|
3060
3060
|
lumine admin post reward <target> [--type subject|comment|aiStory|dailyReflection] --twinkles 3 [--json]
|
|
3061
3061
|
lumine admin reward-bank coverage <buildId> [--max-step 3] [--json]
|
|
3062
3062
|
lumine admin reward-bank seed <buildId> [--max-step 3] [--json] (daily run: writes ONE missing seed question, lowest step first, billed to Zero/Ciel's AI Energy)
|
|
3063
|
+
lumine admin reward-bank report <buildId> [--days 1] [--json] (question-bank telemetry: generation outcomes, learners, payouts, ladder, questions to review)
|
|
3063
3064
|
lumine admin comment draft <target> [--type subject|comment|build|aiStory|dailyReflection] [--file <comment.md>] [--review-receipt <review.json>|--reviewed-version <id> --reviewed-via runtime|code] [--review-context <context.json>] [--identity zero|ciel|auto] [--json]
|
|
3064
3065
|
lumine admin comment reply comment:<id> [--file <reply.md>] [--reviewed-version <id> --reviewed-via runtime|code] [--review-context <context.json>] [--identity zero|ciel|auto] [--json]
|
|
3065
3066
|
lumine admin comment post --draft-id <id> [--json]
|
package/package.json
CHANGED
package/sdk/LUMINE_ADMIN.md
CHANGED
|
@@ -1304,8 +1304,18 @@ them so the first learner on a unit never waits or pays.
|
|
|
1304
1304
|
```bash
|
|
1305
1305
|
lumine admin reward-bank coverage <buildId> [--max-step 3] [--json] # read-only, no run
|
|
1306
1306
|
lumine admin reward-bank seed <buildId> [--max-step 3] [--json] # delegated full run
|
|
1307
|
+
lumine admin reward-bank report <buildId> [--days 1] [--json] # read-only telemetry
|
|
1307
1308
|
```
|
|
1308
1309
|
|
|
1310
|
+
`report` covers the last `--days` (1-31): generation rounds by source
|
|
1311
|
+
(learner or seed) with outcomes (`accepted`, `off_brief`: the checker judged
|
|
1312
|
+
the question outside the brief's language, level or LaTeX rule;
|
|
1313
|
+
`answer_mismatch`; `malformed`; `error`), cost and time, and recent rejection
|
|
1314
|
+
reasons; learners served/answered/first-try/solved/skipped per rule and step;
|
|
1315
|
+
payouts; the current ladder distribution; active/hidden questions; the
|
|
1316
|
+
hardest questions (3+ learners) and every reported question with reasons;
|
|
1317
|
+
and seeding coverage for steps 1-3 once the app is approved.
|
|
1318
|
+
|
|
1309
1319
|
- `seed` writes ONE question per call into the first missing slot, lowest
|
|
1310
1320
|
step first across every topic of every generated-quiz rule, up to
|
|
1311
1321
|
`--max-step` (default 3, at most 10). A slot is a (rule, topic, step) with
|