@stage5/lumine 0.3.28 → 0.3.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/lib/admin.js CHANGED
@@ -370,7 +370,7 @@ function buildApprovalOperation({ action, target, options }) {
370
370
  // Code agent passes wrote (no model is called), then review what they could
371
371
  // not settle (Mikey 2026-10-06: bulk AI work runs on Claude Code agents).
372
372
  const ENGLISH_USAGE =
373
- "Use: lumine admin english import <verdicts.json> --pass a|b | adjudicate <verdicts.json> | add-questions <questions.json> | relevel <moves.json> | mastery <userId> --reason <why> | backfill-distractors | summary | review [--limit <n>] | accept|retire <questionId> [--reason <text>] | retag <questionId> --skill <code> [--reason <text>] | build-candidates [--after <questionId>] [--limit <n>] | build-import <verdicts.json> | check-candidates [--after <questionId>] [--limit <n>] | check-import <verdicts.json> | check-broken [--after <questionId>] [--limit <n>]";
373
+ "Use: lumine admin english import <verdicts.json> --pass a|b | adjudicate <verdicts.json> | add-questions <questions.json> | relevel <moves.json> | mastery <userId> --reason <why> | backfill-distractors | summary | review [--limit <n>] | accept|retire <questionId> [--reason <text>] [--fault] | retag <questionId> --skill <code> [--reason <text>] | build-candidates [--after <questionId>] [--limit <n>] | build-import <verdicts.json> | check-candidates [--after <questionId>] [--limit <n>] | check-import <verdicts.json> | check-broken [--after <questionId>] [--limit <n>] | check-apply <fixes.json> | check-verify <checked.json> | check-follow-faulty [--after <next>] [--limit <n>]";
374
374
  const ENGLISH_IMPORT_MAX = 500;
375
375
 
376
376
  function buildEnglishOperation({ action, target, options }) {
@@ -431,6 +431,36 @@ function buildEnglishOperation({ action, target, options }) {
431
431
  ? readOperation("english.check_candidates", withQuery("/cli/admin/english/item-checks/candidates", { after, limit: limitOf(1000, 200) }), { requiresRun: false })
432
432
  : readOperation("english.check_broken", withQuery("/cli/admin/english/item-checks/broken", { after, limit: limitOf(500, 100) }), { requiresRun: false });
433
433
  }
434
+ // Mikey's approved fixes: [{ questionId, version, fix? }] — the stored
435
+ // proposed fix, or one given (a tidy), applied as a new version
436
+ // checks from before fingerprints: [{ questionId, version, question,
437
+ // choices, key }] as the pass saw them; matches are kept, the rest dropped
438
+ if (action === "check-verify") {
439
+ if (!target) throw cliValidationError(ENGLISH_USAGE);
440
+ const raw = readAdminJsonFile(target, "<checked.json>", { maxBytes: 8 * 1024 * 1024 });
441
+ const items = Array.isArray(raw) ? raw : Array.isArray(raw?.items) ? raw.items : null;
442
+ if (!items || !items.length || items.length > ENGLISH_IMPORT_MAX) {
443
+ throw cliValidationError(`The file must hold 1 to ${ENGLISH_IMPORT_MAX} items (an array, or { items: [...] }).`);
444
+ }
445
+ return writeOperation("english.check_verify", "POST", "/cli/admin/english/item-checks/verify", { items }, { requiresRun: false, timeoutMs: 300000 });
446
+ }
447
+ // the round-21 catch-up (boss misses uncounted, versions found at fault
448
+ // broken for every learner, every check followed again): one page per
449
+ // call, repeat with the reply's `next` until it is null
450
+ if (action === "check-follow-faulty") {
451
+ const after = options.adminAfter ? String(options.adminAfter) : "";
452
+ if (after && !/^(?:[ufc]:)?\d+:\d+$/.test(after)) throw cliValidationError("--after takes the last reply's next (<phase:id:version>).");
453
+ return writeOperation("english.check_follow_faulty", "POST", "/cli/admin/english/item-checks/follow-faulty", { after, limit: limitOf(200, 100) }, { requiresRun: false, timeoutMs: 300000 });
454
+ }
455
+ if (action === "check-apply") {
456
+ if (!target) throw cliValidationError(ENGLISH_USAGE);
457
+ const raw = readAdminJsonFile(target, "<fixes.json>", { maxBytes: 4 * 1024 * 1024 });
458
+ const items = Array.isArray(raw) ? raw : Array.isArray(raw?.items) ? raw.items : null;
459
+ if (!items || !items.length || items.length > 200) {
460
+ throw cliValidationError("The file must hold 1 to 200 fixes (an array, or { items: [...] }).");
461
+ }
462
+ return writeOperation("english.check_apply", "POST", "/cli/admin/english/item-checks/apply", { items }, { requiresRun: false, timeoutMs: 300000 });
463
+ }
434
464
  if (action === "check-import") {
435
465
  if (!target) throw cliValidationError(ENGLISH_USAGE);
436
466
  const raw = readAdminJsonFile(target, "<verdicts.json>", { maxBytes: 4 * 1024 * 1024 });
@@ -465,7 +495,14 @@ function buildEnglishOperation({ action, target, options }) {
465
495
  "english.decide",
466
496
  "POST",
467
497
  `/cli/admin/english/review/${ref}`,
468
- { action, skillCode: options.adminSkill || undefined, reason: String(options.adminReason || "").trim() || undefined },
498
+ {
499
+ action,
500
+ skillCode: options.adminSkill || undefined,
501
+ reason: String(options.adminReason || "").trim() || undefined,
502
+ // retire --fault (Mikey 10-11): the question was at fault, so Grammar
503
+ // Quest forgives every miss on it; a duplicate or off-topic retire isn't
504
+ ...(action === "retire" && options.adminFault ? { fault: true } : {}),
505
+ },
469
506
  { requiresRun: false },
470
507
  );
471
508
  }
package/lib/commands.js CHANGED
@@ -2440,6 +2440,7 @@ export function parseArgs(args) {
2440
2440
  const positional = [];
2441
2441
  const booleanFlags = new Set([
2442
2442
  "remove",
2443
+ "fault",
2443
2444
  "noAnnounce",
2444
2445
  "noLeaseKeeper",
2445
2446
  "noOpen",
@@ -2759,6 +2760,8 @@ export function parseArgs(args) {
2759
2760
  twinkles: raw.twinkles ? String(raw.twinkles) : "",
2760
2761
  adminReason: raw.reason ? String(raw.reason) : "",
2761
2762
  adminSkill: raw.skill ? String(raw.skill) : "",
2763
+ // admin english retire --fault: the question was at fault (Grammar Quest forgives its misses)
2764
+ adminFault: Boolean(raw.fault),
2762
2765
  // --branch may repeat (a building two branches share); --branches A,B too
2763
2766
  adminBranch: [raw.branch, raw.branches].filter(Boolean).join(","),
2764
2767
  adminPass: raw.pass ? String(raw.pass) : "",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stage5/lumine",
3
- "version": "0.3.28",
3
+ "version": "0.3.30",
4
4
  "description": "Command line tools for launching Lumine builds on Twinkle.",
5
5
  "type": "module",
6
6
  "bin": {