@stage5/lumine 0.2.41 → 0.2.42
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/README.md +13 -1
- package/lib/admin-workflows.js +15 -0
- package/lib/admin.js +149 -1
- package/lib/commands.js +6 -0
- package/package.json +1 -1
- package/sdk/LUMINE_ADMIN.md +176 -12
package/README.md
CHANGED
|
@@ -214,6 +214,8 @@ events.
|
|
|
214
214
|
|
|
215
215
|
```bash
|
|
216
216
|
lumine admin identity list --json
|
|
217
|
+
lumine admin identity inspect Jay1216 \
|
|
218
|
+
--reason "Confirm account family before a quota-bucket change" --json
|
|
217
219
|
lumine admin daily-run start --identity auto --comment-mode off --json
|
|
218
220
|
lumine admin recommendations list --all --checkpoint recommendations.json --json
|
|
219
221
|
lumine admin recommendations list --after 2026-08-14T00:00:00Z --all --json
|
|
@@ -248,6 +250,9 @@ lumine admin daily-run escalation add --target subject:123 \
|
|
|
248
250
|
--note "Concrete privacy issue requiring owner review" --json
|
|
249
251
|
lumine admin daily-run report --json
|
|
250
252
|
lumine admin daily-run complete --json
|
|
253
|
+
lumine admin escalation list --status all --json
|
|
254
|
+
lumine admin escalation set 123 --status resolved \
|
|
255
|
+
--note "Final owner decision" --json
|
|
251
256
|
```
|
|
252
257
|
|
|
253
258
|
Numeric recommendation targets default to subjects. Use `comment:<id>`,
|
|
@@ -280,7 +285,8 @@ resumed with the exact generated key.
|
|
|
280
285
|
Subject and queue listings use opaque, stable snapshot cursors. `--all`
|
|
281
286
|
follows them automatically, saves a checkpoint after every canonical page,
|
|
282
287
|
and records completed queue coverage in the run audit; `--resume` continues
|
|
283
|
-
the exact same request.
|
|
288
|
+
the exact same request. With `--all --json`, bounded progress goes to stderr so
|
|
289
|
+
stdout remains one pipe-safe JSON value. Recommendation scans default to the previous completed
|
|
284
290
|
run's start boundary for at-least-once coverage. Use `--after` for an explicit
|
|
285
291
|
timestamp or `--include-legacy`
|
|
286
292
|
for an intentional all-history scan. Subject `--after` is inclusive and
|
|
@@ -293,6 +299,12 @@ the claim file. `daily-run report` summarizes confirmed mutations, completed
|
|
|
293
299
|
queue coverage, explicitly recorded escalations, and the run brief before the
|
|
294
300
|
run is completed.
|
|
295
301
|
|
|
302
|
+
Identity inspection, escalation dispositions, AI-bucket maintenance, and
|
|
303
|
+
approved Notable User additions are private operator bookkeeping and do not
|
|
304
|
+
require a delegated daily run. Identity inspection always requires an audited
|
|
305
|
+
`--reason`; raw email/DOB evidence additionally requires
|
|
306
|
+
`--include-private-evidence`. Routine briefs omit raw email identities.
|
|
307
|
+
|
|
296
308
|
The complete run lifecycle, command contracts, nullable fields, Karma approval
|
|
297
309
|
behavior, pagination semantics, secret-subject behavior, presence isolation,
|
|
298
310
|
and retry rules are documented in
|
package/lib/admin-workflows.js
CHANGED
|
@@ -92,6 +92,7 @@ export async function runAutomaticPagination({
|
|
|
92
92
|
fetchPage,
|
|
93
93
|
transformPage,
|
|
94
94
|
recordCoverage,
|
|
95
|
+
reportProgress = (message) => process.stderr.write(`${message}\n`),
|
|
95
96
|
}) {
|
|
96
97
|
if (!operation.pagination) {
|
|
97
98
|
throw validationError("--all is supported only by paginated admin listings.");
|
|
@@ -152,6 +153,12 @@ export async function runAutomaticPagination({
|
|
|
152
153
|
}
|
|
153
154
|
state = { ...state, ...saved, resumed: true };
|
|
154
155
|
}
|
|
156
|
+
const progressEnabled = options.json === true;
|
|
157
|
+
if (progressEnabled) {
|
|
158
|
+
reportProgress(
|
|
159
|
+
`Lumine admin ${operation.name}: ${state.resumed ? "resuming" : "starting"} canonical scan; checkpoint ${checkpointPath}.`,
|
|
160
|
+
);
|
|
161
|
+
}
|
|
155
162
|
const pages = [];
|
|
156
163
|
while (!state.exhausted) {
|
|
157
164
|
if (state.pages >= MAX_AUTOMATIC_PAGES) {
|
|
@@ -230,6 +237,14 @@ export async function runAutomaticPagination({
|
|
|
230
237
|
privateFile: true,
|
|
231
238
|
maxBytes: MAX_ADMIN_CHECKPOINT_BYTES,
|
|
232
239
|
});
|
|
240
|
+
if (
|
|
241
|
+
progressEnabled &&
|
|
242
|
+
(pages.length === 1 || state.pages % 10 === 0 || state.exhausted)
|
|
243
|
+
) {
|
|
244
|
+
reportProgress(
|
|
245
|
+
`Lumine admin ${operation.name}: ${state.pages} page(s), ${state.scannedCount} row(s) scanned, ${state.items.length} candidate(s)${state.exhausted ? "; canonical snapshot exhausted." : "; continuing."}`,
|
|
246
|
+
);
|
|
247
|
+
}
|
|
233
248
|
}
|
|
234
249
|
const result = aggregatePageResult({
|
|
235
250
|
operation,
|
package/lib/admin.js
CHANGED
|
@@ -21,6 +21,8 @@ const MAX_EDITORIAL_FILE_BYTES = 256 * 1024;
|
|
|
21
21
|
const MAX_COMPOSED_TEXT_FILE_BYTES = 64 * 1024;
|
|
22
22
|
const MAX_COMPOSED_TEXT_LENGTH = 10_000;
|
|
23
23
|
const MAX_NOTABLE_NOTE_LENGTH = 2_000;
|
|
24
|
+
const MAX_IDENTITY_INSPECTION_REASON_LENGTH = 500;
|
|
25
|
+
const MAX_ESCALATION_DECISION_NOTE_LENGTH = 2_000;
|
|
24
26
|
|
|
25
27
|
// Operator-composed persona text (plain UTF-8, not JSON). The agent writes
|
|
26
28
|
// the content in the bot's persona itself; the server never invokes
|
|
@@ -498,8 +500,12 @@ function adminOperationRequiresRun(operation) {
|
|
|
498
500
|
"identity.list",
|
|
499
501
|
"identity.status",
|
|
500
502
|
"identity.use",
|
|
503
|
+
"identity.inspect",
|
|
501
504
|
"daily-run.start",
|
|
502
505
|
"daily-run.status",
|
|
506
|
+
"escalation.list",
|
|
507
|
+
"escalation.set",
|
|
508
|
+
"notable.add",
|
|
503
509
|
].includes(operation.name) && !operation.name.startsWith("ai-bucket.")
|
|
504
510
|
);
|
|
505
511
|
}
|
|
@@ -540,6 +546,35 @@ export function parseAdminOperation(options) {
|
|
|
540
546
|
{ identity: parseIdentity(target) },
|
|
541
547
|
);
|
|
542
548
|
}
|
|
549
|
+
if (action === "inspect") {
|
|
550
|
+
const inspectionTarget = String(target || "").trim();
|
|
551
|
+
const reason = String(options.adminReason || "").trim();
|
|
552
|
+
if (!inspectionTarget) {
|
|
553
|
+
throw cliValidationError(
|
|
554
|
+
"Usage: lumine admin identity inspect <userId|username> --reason <management reason> [--include-private-evidence].",
|
|
555
|
+
);
|
|
556
|
+
}
|
|
557
|
+
if (!reason) {
|
|
558
|
+
throw cliValidationError(
|
|
559
|
+
"Explain why private identity evidence is needed with --reason <management reason>.",
|
|
560
|
+
);
|
|
561
|
+
}
|
|
562
|
+
if (reason.length > MAX_IDENTITY_INSPECTION_REASON_LENGTH) {
|
|
563
|
+
throw cliValidationError(
|
|
564
|
+
`An identity-inspection reason must be at most ${MAX_IDENTITY_INSPECTION_REASON_LENGTH} characters.`,
|
|
565
|
+
);
|
|
566
|
+
}
|
|
567
|
+
return writeOperation(
|
|
568
|
+
"identity.inspect",
|
|
569
|
+
"POST",
|
|
570
|
+
"/cli/admin/identity/inspect",
|
|
571
|
+
{
|
|
572
|
+
target: inspectionTarget,
|
|
573
|
+
reason,
|
|
574
|
+
includePrivateEvidence: options.adminIncludePrivateEvidence === true,
|
|
575
|
+
},
|
|
576
|
+
);
|
|
577
|
+
}
|
|
543
578
|
}
|
|
544
579
|
|
|
545
580
|
if (namespace === "ai-bucket" || namespace === "ai-buckets") {
|
|
@@ -639,6 +674,47 @@ export function parseAdminOperation(options) {
|
|
|
639
674
|
}
|
|
640
675
|
}
|
|
641
676
|
|
|
677
|
+
if (namespace === "escalation" || namespace === "escalations") {
|
|
678
|
+
if (!action || action === "list") {
|
|
679
|
+
const status = parseEscalationListStatus(options.adminStatus || "open");
|
|
680
|
+
return readOperation(
|
|
681
|
+
"escalation.list",
|
|
682
|
+
withQuery("/cli/admin/escalations", {
|
|
683
|
+
status,
|
|
684
|
+
limit: options.limit,
|
|
685
|
+
}),
|
|
686
|
+
);
|
|
687
|
+
}
|
|
688
|
+
if (action === "set") {
|
|
689
|
+
const escalationAuditId = parseRequiredInteger(
|
|
690
|
+
target,
|
|
691
|
+
"Escalation audit ID",
|
|
692
|
+
1,
|
|
693
|
+
);
|
|
694
|
+
const status = parseEscalationStatus(options.adminStatus);
|
|
695
|
+
const note = String(options.note || "").trim();
|
|
696
|
+
if (!note) {
|
|
697
|
+
throw cliValidationError(
|
|
698
|
+
"Record the decision or next step with --note <text>.",
|
|
699
|
+
);
|
|
700
|
+
}
|
|
701
|
+
if (note.length > MAX_ESCALATION_DECISION_NOTE_LENGTH) {
|
|
702
|
+
throw cliValidationError(
|
|
703
|
+
`An escalation decision note must be at most ${MAX_ESCALATION_DECISION_NOTE_LENGTH} characters.`,
|
|
704
|
+
);
|
|
705
|
+
}
|
|
706
|
+
return writeOperation(
|
|
707
|
+
"escalation.set",
|
|
708
|
+
"PUT",
|
|
709
|
+
`/cli/admin/escalations/${escalationAuditId}`,
|
|
710
|
+
{ status, note },
|
|
711
|
+
);
|
|
712
|
+
}
|
|
713
|
+
throw cliValidationError(
|
|
714
|
+
"Usage: lumine admin escalation list [--status open|acknowledged|resolved|all] | escalation set <auditId> --status <status> --note <decision>.",
|
|
715
|
+
);
|
|
716
|
+
}
|
|
717
|
+
|
|
642
718
|
if (
|
|
643
719
|
(namespace === "recommend-queue" && (!action || action === "list")) ||
|
|
644
720
|
(namespace === "recommendations" && action === "list")
|
|
@@ -1164,7 +1240,7 @@ export function parseAdminOperation(options) {
|
|
|
1164
1240
|
}
|
|
1165
1241
|
|
|
1166
1242
|
throw cliValidationError(
|
|
1167
|
-
"Usage: lumine admin identity|daily-run|recommendations|builds|post|subjects|subject|featured|comment|announcement|chat|news|audit|brief|bot-output|notable ...",
|
|
1243
|
+
"Usage: lumine admin identity|daily-run|escalation|recommendations|builds|post|subjects|subject|featured|comment|announcement|chat|news|audit|brief|bot-output|notable ...",
|
|
1168
1244
|
);
|
|
1169
1245
|
}
|
|
1170
1246
|
|
|
@@ -1543,6 +1619,30 @@ function parseCommentMode(value) {
|
|
|
1543
1619
|
return mode;
|
|
1544
1620
|
}
|
|
1545
1621
|
|
|
1622
|
+
function parseEscalationStatus(value) {
|
|
1623
|
+
const status = String(value || "")
|
|
1624
|
+
.trim()
|
|
1625
|
+
.toLowerCase();
|
|
1626
|
+
if (!["open", "acknowledged", "resolved"].includes(status)) {
|
|
1627
|
+
throw cliValidationError(
|
|
1628
|
+
"--status must be open, acknowledged, or resolved.",
|
|
1629
|
+
);
|
|
1630
|
+
}
|
|
1631
|
+
return status;
|
|
1632
|
+
}
|
|
1633
|
+
|
|
1634
|
+
function parseEscalationListStatus(value) {
|
|
1635
|
+
const status = String(value || "open")
|
|
1636
|
+
.trim()
|
|
1637
|
+
.toLowerCase();
|
|
1638
|
+
if (!["open", "acknowledged", "resolved", "all"].includes(status)) {
|
|
1639
|
+
throw cliValidationError(
|
|
1640
|
+
"--status must be open, acknowledged, resolved, or all.",
|
|
1641
|
+
);
|
|
1642
|
+
}
|
|
1643
|
+
return status;
|
|
1644
|
+
}
|
|
1645
|
+
|
|
1546
1646
|
function parseOrderedIds(value) {
|
|
1547
1647
|
const ids = String(value || "")
|
|
1548
1648
|
.split(",")
|
|
@@ -1713,6 +1813,54 @@ function printAdminResult({ operation, result }) {
|
|
|
1713
1813
|
console.log(`Notable-user candidates in this brief: ${notableCount}.`);
|
|
1714
1814
|
return;
|
|
1715
1815
|
}
|
|
1816
|
+
if (data.inspection) {
|
|
1817
|
+
const inspection = data.inspection;
|
|
1818
|
+
console.log(
|
|
1819
|
+
`Identity inspection for user #${inspection.targetUserId}: ${inspection.accounts?.length || 0} candidate account(s); oldest #${inspection.oldestAccount?.userId || "unknown"}.`,
|
|
1820
|
+
);
|
|
1821
|
+
if (inspection.manualBucket) {
|
|
1822
|
+
console.log(
|
|
1823
|
+
`AI bucket #${inspection.manualBucket.id} (${inspection.manualBucket.label}); ${inspection.manualBucket.memberCount} canonical member(s).`,
|
|
1824
|
+
);
|
|
1825
|
+
}
|
|
1826
|
+
for (const account of inspection.accounts || []) {
|
|
1827
|
+
console.log(
|
|
1828
|
+
` #${account.userId} ${account.username || "(no username)"} — joined ${account.joinedAt || "unknown"}; ${account.relationBasis.join(", ") || "no relation evidence"}${account.hasDateOfBirth ? "; DOB on file" : "; no DOB on file"}.`,
|
|
1829
|
+
);
|
|
1830
|
+
if (account.privateEvidence) {
|
|
1831
|
+
console.log(
|
|
1832
|
+
` Private evidence: DOB ${account.privateEvidence.dateOfBirth || "none"}; verified email(s) ${account.privateEvidence.verifiedEmails.join(", ") || "none"}.`,
|
|
1833
|
+
);
|
|
1834
|
+
}
|
|
1835
|
+
}
|
|
1836
|
+
return;
|
|
1837
|
+
}
|
|
1838
|
+
if (Array.isArray(data.escalations)) {
|
|
1839
|
+
console.log(`${data.escalations.length} escalation(s):`);
|
|
1840
|
+
for (const escalation of data.escalations) {
|
|
1841
|
+
const target =
|
|
1842
|
+
escalation.url ||
|
|
1843
|
+
`${escalation.targetType || "target"}:${escalation.targetId || "?"}`;
|
|
1844
|
+
console.log(
|
|
1845
|
+
` #${escalation.auditId} ${String(escalation.status || "open").toUpperCase()} ${target} — ${escalation.summary}`,
|
|
1846
|
+
);
|
|
1847
|
+
if (escalation.decisionNote) {
|
|
1848
|
+
console.log(` Decision: ${escalation.decisionNote}`);
|
|
1849
|
+
}
|
|
1850
|
+
}
|
|
1851
|
+
if (data.truncated) {
|
|
1852
|
+
console.log(
|
|
1853
|
+
"More matching escalations exist than the requested limit; raise --limit or narrow --status.",
|
|
1854
|
+
);
|
|
1855
|
+
}
|
|
1856
|
+
return;
|
|
1857
|
+
}
|
|
1858
|
+
if (data.escalation?.decisionNote) {
|
|
1859
|
+
console.log(
|
|
1860
|
+
`Escalation #${data.escalation.auditId}: ${String(data.escalation.status).toUpperCase()} — ${data.escalation.decisionNote}`,
|
|
1861
|
+
);
|
|
1862
|
+
return;
|
|
1863
|
+
}
|
|
1716
1864
|
if (data.bucket && Array.isArray(data.memberUserIds)) {
|
|
1717
1865
|
const added = Array.isArray(data.accounts)
|
|
1718
1866
|
? `; added ${data.accounts.length} explicit account(s)`
|
package/lib/commands.js
CHANGED
|
@@ -2226,6 +2226,7 @@ export function parseArgs(args) {
|
|
|
2226
2226
|
"resume",
|
|
2227
2227
|
"sinceRun",
|
|
2228
2228
|
"includeLegacy",
|
|
2229
|
+
"includePrivateEvidence",
|
|
2229
2230
|
"noReviewLoop",
|
|
2230
2231
|
]);
|
|
2231
2232
|
|
|
@@ -2328,6 +2329,7 @@ export function parseArgs(args) {
|
|
|
2328
2329
|
adminAfter: raw.after ? String(raw.after) : "",
|
|
2329
2330
|
adminSinceRun: Boolean(raw.sinceRun),
|
|
2330
2331
|
adminIncludeLegacy: Boolean(raw.includeLegacy),
|
|
2332
|
+
adminIncludePrivateEvidence: parseBoolean(raw.includePrivateEvidence, false),
|
|
2331
2333
|
adminAll: Boolean(raw.all),
|
|
2332
2334
|
adminResume: Boolean(raw.resume),
|
|
2333
2335
|
adminCheckpoint: raw.checkpoint ? String(raw.checkpoint) : "",
|
|
@@ -2338,6 +2340,7 @@ export function parseArgs(args) {
|
|
|
2338
2340
|
adminTargetFile: raw.targetFile ? String(raw.targetFile) : "",
|
|
2339
2341
|
adminReviewReceipt: raw.reviewReceipt ? String(raw.reviewReceipt) : "",
|
|
2340
2342
|
adminSeverity: raw.severity ? String(raw.severity) : "",
|
|
2343
|
+
adminStatus: raw.status ? String(raw.status) : "",
|
|
2341
2344
|
adminWaitMs: raw.waitMs ? String(raw.waitMs) : "",
|
|
2342
2345
|
adminBrowserPath: raw.browserPath ? String(raw.browserPath) : "",
|
|
2343
2346
|
adminEffort: raw.effort ? String(raw.effort) : "",
|
|
@@ -2707,6 +2710,7 @@ export function printHelp() {
|
|
|
2707
2710
|
lumine thumbnail generate ["<prompt>"] --model <gpt-image-2|nano-banana>
|
|
2708
2711
|
lumine doctor runtime-assets
|
|
2709
2712
|
lumine admin identity list|status|use <zero|ciel|auto> [--json]
|
|
2713
|
+
lumine admin identity inspect <user-id|username> --reason <management-reason> [--include-private-evidence] [--json]
|
|
2710
2714
|
lumine admin ai-bucket create --label <name> --note <text> [--json]
|
|
2711
2715
|
lumine admin ai-bucket get --bucket-id <id> [--json]
|
|
2712
2716
|
lumine admin ai-bucket accounts add --bucket-id <id> --user-ids <id,id,...> [--note <text>] [--json]
|
|
@@ -2714,6 +2718,8 @@ export function printHelp() {
|
|
|
2714
2718
|
lumine admin daily-run start [--identity zero|ciel|auto] [--comment-mode off|draft|post] [--run-key <key>] [--json]
|
|
2715
2719
|
lumine admin daily-run status|report|complete|fail [--reason <text>] [--json]
|
|
2716
2720
|
lumine admin daily-run escalation add --target <target> --note <summary> [--severity attention|urgent] [--json]
|
|
2721
|
+
lumine admin escalation list [--status open|acknowledged|resolved|all] [--limit <number>] [--json]
|
|
2722
|
+
lumine admin escalation set <audit-id> --status open|acknowledged|resolved --note <decision> [--json]
|
|
2717
2723
|
lumine admin recommendations list [--since-run|--after <date>|--include-legacy] [--all --checkpoint <file> [--resume]] [--content-types comment,dailyReflection] [--unviewed|--viewed] [--cursor <cursor>] [--json]
|
|
2718
2724
|
lumine admin builds candidates [--all --checkpoint <file> [--resume]] [--cursor <cursor>] [--limit <number>] [--json]
|
|
2719
2725
|
lumine admin builds review <build-url-or-id> [--output-dir <dir>] [--wait-ms <ms>] [--browser-path <path>] [--json]
|
package/package.json
CHANGED
package/sdk/LUMINE_ADMIN.md
CHANGED
|
@@ -89,6 +89,40 @@ Mikey; routine administrator runs still escalate suspected alternate accounts
|
|
|
89
89
|
and never auto-enforce. `accounts add` and `note set` still accept only an
|
|
90
90
|
existing **unbanned** bucket.
|
|
91
91
|
|
|
92
|
+
### Audited identity inspection
|
|
93
|
+
|
|
94
|
+
Account-family evidence is private operator work, never a Zero/Ciel public
|
|
95
|
+
action and never a reason to browse unrelated user activity. Use the dedicated
|
|
96
|
+
lookup instead of direct database queries:
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
lumine admin identity inspect Jay1216 \
|
|
100
|
+
--reason "Confirm the account family before updating its quota bucket" --json
|
|
101
|
+
lumine admin identity inspect Jay1216 \
|
|
102
|
+
--reason "Mikey requested DOB and email evidence for this decision" \
|
|
103
|
+
--include-private-evidence --json
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
The default result resolves the exact username or user ID from the writer,
|
|
107
|
+
returns the canonical current AI bucket, orders candidate accounts oldest
|
|
108
|
+
first, identifies the oldest account within the strongest canonical family
|
|
109
|
+
boundary (bucket before email; never device alone) when that family fits in the
|
|
110
|
+
bounded evidence set, reports whether each
|
|
111
|
+
account has a DOB, and explains whether the link
|
|
112
|
+
came from explicit bucket membership, a verified-email match, or bounded exact-
|
|
113
|
+
device evidence. It does **not** reveal email addresses, DOB values, device IDs,
|
|
114
|
+
IP evidence, private messages, or unrelated activity. `--include-private-evidence`
|
|
115
|
+
adds DOB values and verified email addresses only; exact device IDs are never
|
|
116
|
+
returned.
|
|
117
|
+
|
|
118
|
+
Every inspection requires a concrete `--reason`. Before loading the evidence,
|
|
119
|
+
the API commits a private `identity.inspect` audit receipt containing the real
|
|
120
|
+
operator, requested target, reason, and whether private evidence was requested.
|
|
121
|
+
The evidence itself is deliberately not copied into the audit log. Inspection
|
|
122
|
+
is run-independent and has no public actor. Results are **candidate accounts
|
|
123
|
+
for human judgment**, not an automatic ownership finding and never automatic
|
|
124
|
+
grounds for moderation, bans, or bucket changes.
|
|
125
|
+
|
|
92
126
|
## Editorial priorities
|
|
93
127
|
|
|
94
128
|
The CLI enforces none of this — it is the standing instruction for the operator
|
|
@@ -236,6 +270,29 @@ Two rules that keep the list worth reading:
|
|
|
236
270
|
design. Do not delete, hide, argue with, or publicly accuse anyone, and do not
|
|
237
271
|
warn a child that they are in trouble. Report it and let Mikey decide.
|
|
238
272
|
|
|
273
|
+
Mikey's decision must remain attached after the originating run closes. These
|
|
274
|
+
commands are private, run-independent bookkeeping:
|
|
275
|
+
|
|
276
|
+
```bash
|
|
277
|
+
lumine admin escalation list --json
|
|
278
|
+
lumine admin escalation list --status all --json
|
|
279
|
+
lumine admin escalation set 123 --status acknowledged \
|
|
280
|
+
--note "Mikey is reviewing the bot response" --json
|
|
281
|
+
lumine admin escalation set 123 --status resolved \
|
|
282
|
+
--note "No user fault; this audit concerned Zero's response" --json
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
`list` defaults to unresolved `open` items. `--status` also accepts
|
|
286
|
+
`acknowledged`, `resolved`, or `all`. The number passed to `set` is the original
|
|
287
|
+
`run.escalation` audit ID returned by the run report/list. Every disposition is
|
|
288
|
+
an immutable private `escalation.status.set` audit event. A revision allocated
|
|
289
|
+
while the original escalation is locked orders concurrent decisions, so the
|
|
290
|
+
last applied decision is the canonical status and annotation even if request
|
|
291
|
+
audit IDs were reserved in another order. `--status open` can deliberately
|
|
292
|
+
reopen an item with an explanatory note. Status filters walk indexed escalation
|
|
293
|
+
history rather than a fixed latest-event window. No active run or public bot
|
|
294
|
+
identity is used.
|
|
295
|
+
|
|
239
296
|
## Common JSON types
|
|
240
297
|
|
|
241
298
|
All `--json` success output is one uncolored JSON value:
|
|
@@ -249,7 +306,9 @@ type Success<D> = {
|
|
|
249
306
|
};
|
|
250
307
|
```
|
|
251
308
|
|
|
252
|
-
Failures print one JSON value
|
|
309
|
+
Failures print one JSON value to stdout and exit nonzero. A failing `--all`
|
|
310
|
+
scan may already have written bounded page progress to stderr; stdout remains
|
|
311
|
+
protocol-clean:
|
|
253
312
|
|
|
254
313
|
```ts
|
|
255
314
|
type Failure = {
|
|
@@ -430,6 +489,8 @@ lumine admin identity status --json
|
|
|
430
489
|
lumine admin identity use zero --json
|
|
431
490
|
lumine admin identity use ciel --json
|
|
432
491
|
lumine admin identity use auto --json
|
|
492
|
+
lumine admin identity inspect Jay1216 \
|
|
493
|
+
--reason "Confirm the account family before a bucket change" --json
|
|
433
494
|
```
|
|
434
495
|
|
|
435
496
|
Schemas:
|
|
@@ -448,6 +509,51 @@ type IdentityStatus = Success<{
|
|
|
448
509
|
}>;
|
|
449
510
|
|
|
450
511
|
type IdentityUse = IdentityStatus;
|
|
512
|
+
|
|
513
|
+
type IdentityInspection = Success<{
|
|
514
|
+
inspection: {
|
|
515
|
+
targetUserId: number;
|
|
516
|
+
privateEvidenceIncluded: boolean;
|
|
517
|
+
manualBucket: {
|
|
518
|
+
id: number;
|
|
519
|
+
label: string;
|
|
520
|
+
memberCount: number;
|
|
521
|
+
isBanned: boolean;
|
|
522
|
+
} | null;
|
|
523
|
+
oldestAccount: IdentityCandidate | null;
|
|
524
|
+
oldestAccountBasis: "manual_bucket" | "verified_email" | "target_only";
|
|
525
|
+
oldestAccountComplete: boolean;
|
|
526
|
+
candidateAltCount: number;
|
|
527
|
+
accounts: IdentityCandidate[];
|
|
528
|
+
evidenceCoverage: {
|
|
529
|
+
deviceLookbackDays: number;
|
|
530
|
+
targetDeviceEvidenceRows: number;
|
|
531
|
+
targetDeviceIdsConsidered: number;
|
|
532
|
+
relatedDeviceEvidenceRows: number;
|
|
533
|
+
candidateLimit: number;
|
|
534
|
+
truncated: boolean;
|
|
535
|
+
};
|
|
536
|
+
};
|
|
537
|
+
}>;
|
|
538
|
+
|
|
539
|
+
type IdentityCandidate = {
|
|
540
|
+
userId: number;
|
|
541
|
+
username: string | null;
|
|
542
|
+
joinedAt: number | null;
|
|
543
|
+
isTarget: boolean;
|
|
544
|
+
isOldestAccount: boolean;
|
|
545
|
+
hasDateOfBirth: boolean;
|
|
546
|
+
banned: boolean;
|
|
547
|
+
deleted: boolean;
|
|
548
|
+
relationBasis: Array<
|
|
549
|
+
"target" | "manual_bucket" | "verified_email" | "exact_device"
|
|
550
|
+
>;
|
|
551
|
+
sharedDeviceCount: number;
|
|
552
|
+
privateEvidence?: {
|
|
553
|
+
dateOfBirth: string | null;
|
|
554
|
+
verifiedEmails: string[];
|
|
555
|
+
};
|
|
556
|
+
};
|
|
451
557
|
```
|
|
452
558
|
|
|
453
559
|
`identity use` changes only the preference for a future start. It never changes
|
|
@@ -465,6 +571,9 @@ lumine admin daily-run escalation add --target chatMessage:3768159 \
|
|
|
465
571
|
lumine admin daily-run report --json
|
|
466
572
|
lumine admin daily-run complete --json
|
|
467
573
|
lumine admin daily-run fail --reason "operator stopped" --json
|
|
574
|
+
lumine admin escalation list --status all --json
|
|
575
|
+
lumine admin escalation set 123 --status resolved \
|
|
576
|
+
--note "Final owner decision" --json
|
|
468
577
|
```
|
|
469
578
|
|
|
470
579
|
Schemas:
|
|
@@ -490,6 +599,10 @@ the current active run. Queue coverage is written automatically only after an
|
|
|
490
599
|
`--all` traversal reaches canonical exhaustion; an interrupted scan remains in
|
|
491
600
|
its local checkpoint and cannot be misreported as complete.
|
|
492
601
|
|
|
602
|
+
Creating an escalation belongs to the active run; acknowledging, annotating,
|
|
603
|
+
resolving, or reopening it does not. Use the run-independent `escalation`
|
|
604
|
+
commands after Mikey responds instead of starting a follow-up delegated run.
|
|
605
|
+
|
|
493
606
|
`lastRun` makes a lost-response retry of `complete` or `fail` possible after
|
|
494
607
|
the active pointer has been cleared. Other run-scoped commands accept only the
|
|
495
608
|
current unexpired `active` run. Completion first finalizes any mutation whose
|
|
@@ -617,6 +730,12 @@ the same API, run, and exact request. The final result can be copied to
|
|
|
617
730
|
`--after` is inclusive, and every opaque cursor is bound to its original
|
|
618
731
|
filters.
|
|
619
732
|
|
|
733
|
+
For `--all --json`, stdout remains exactly one JSON value. Scan-start, first-
|
|
734
|
+
page, every-tenth-page, and exhaustion progress is written to **stderr** with
|
|
735
|
+
only page/scanned/candidate counts and the private checkpoint path. A long
|
|
736
|
+
traversal therefore no longer looks stalled, while piping stdout to `jq` or a
|
|
737
|
+
file remains safe.
|
|
738
|
+
|
|
620
739
|
Recommendations default to `--since-run`: the server uses the previous
|
|
621
740
|
completed run's start time (or the same bounded seven-day fallback used by the
|
|
622
741
|
brief on a first run). That deliberate start-to-start overlap gives the queue
|
|
@@ -1264,6 +1383,22 @@ rows per source — retry with a narrower `--days` window, and do not complete
|
|
|
1264
1383
|
the run while either flag remains true. Run it right after the
|
|
1265
1384
|
brief, and **read every row** — the tool deliberately does no filtering,
|
|
1266
1385
|
scoring, or keyword matching, because the judgment is the reviewing agent's.
|
|
1386
|
+
|
|
1387
|
+
**Privacy boundary:** this is an audit of how Twinkle's bots treated members,
|
|
1388
|
+
not a moderation queue for members' private use of the tool. Treat private
|
|
1389
|
+
human messages and creative work as confidential context. Read every
|
|
1390
|
+
bot-authored row, but inspect adjacent human messages only when the minimum
|
|
1391
|
+
necessary context is needed to judge the bot's response; never browse the rest
|
|
1392
|
+
of a private conversation out of curiosity. Do not characterize or escalate a
|
|
1393
|
+
member's lawful private creative writing — including a teenager's romance
|
|
1394
|
+
fiction — merely because its subject is intimate or romantic. An escalation
|
|
1395
|
+
must identify what **Zero or Ciel** did (for example, an invented premise,
|
|
1396
|
+
pressure, sexualization, abuse, or a failed boundary), include only the narrow
|
|
1397
|
+
context needed for Mikey to decide a remedy, and never reuse private material
|
|
1398
|
+
for public editorial judgment, Notable User selection, or unrelated identity
|
|
1399
|
+
investigation. A separate concrete risk to a member may still be escalated,
|
|
1400
|
+
but it does not authorize a broader review of their private activity.
|
|
1401
|
+
|
|
1267
1402
|
Judge against the same values the editorial priorities encode:
|
|
1268
1403
|
|
|
1269
1404
|
- **premises must be real.** The 08-11 message didn't merely choose a bad
|
|
@@ -1347,11 +1482,16 @@ farm-signal sections added the same day):
|
|
|
1347
1482
|
("$X so far today; complete days run ~$Y/day"). Real
|
|
1348
1483
|
incident: a run report quoted a ~15%-complete day bucket ($5) as the site's
|
|
1349
1484
|
daily AI spend (complete days were running ~$40-50). Flag accounts that jumped tiers or
|
|
1350
|
-
dominate that report period.
|
|
1485
|
+
dominate that report period. Routine `topAccounts` rows identify the account
|
|
1486
|
+
by user ID/username and expose only an `identitySummary` count/manual-bucket
|
|
1487
|
+
flag; raw identity strings and verified email addresses are deliberately
|
|
1488
|
+
omitted. Use reason-required `identity inspect`, with
|
|
1489
|
+
`--include-private-evidence` only when Mikey's concrete decision needs the
|
|
1490
|
+
addresses or DOB values. May be `{ unavailable: true }` if the cost
|
|
1351
1491
|
report fails; say so rather than guessing. This section is also the run's
|
|
1352
1492
|
AI-cost exploit watch: while reading it, actively look for the signatures the
|
|
1353
1493
|
brief actually exposes — one risk group spanning several user IDs, repeated
|
|
1354
|
-
|
|
1494
|
+
account groups in `farmSignals.inboxFamilies`, or heavy spend by
|
|
1355
1495
|
accounts that `economy.topGainers` or `notableCandidates` independently marks
|
|
1356
1496
|
as recent signups. Cross-check those signals against the escalation
|
|
1357
1497
|
categories. Missing join-date or community data is unknown, not evidence that
|
|
@@ -1366,9 +1506,11 @@ farm-signal sections added the same day):
|
|
|
1366
1506
|
execute them with
|
|
1367
1507
|
`lumine admin notable add <userId|username> --note "<specific rationale>"`
|
|
1368
1508
|
(idempotent —
|
|
1369
|
-
an existing member returns `already_done`;
|
|
1370
|
-
|
|
1371
|
-
|
|
1509
|
+
an existing member returns `already_done`; run-independent, privately audited
|
|
1510
|
+
as `notable.add`, and writes through the management page's own canonical
|
|
1511
|
+
service). It can therefore record Mikey's approval after the daily run has
|
|
1512
|
+
closed without opening another delegated run. Without his approval the run
|
|
1513
|
+
only proposes.
|
|
1372
1514
|
**Always pass `--note`** with a concrete one-or-two-sentence record of what
|
|
1373
1515
|
made them notable — real numbers and specifics from the brief window, not
|
|
1374
1516
|
"active user". It lands in the management page's reason column, which is
|
|
@@ -1428,12 +1570,14 @@ farm-signal sections added the same day):
|
|
|
1428
1570
|
Deliberately coarse: it is an onboarding health check, not per-child
|
|
1429
1571
|
session tracking.
|
|
1430
1572
|
- `farmSignals` — AI-cost farm signatures derivable with ZERO new data
|
|
1431
|
-
collection: `inboxFamilies` (
|
|
1432
|
-
last `inboxFamilyActivityDays`, with only
|
|
1573
|
+
collection: `inboxFamilies` (account groups formed from verified emails of
|
|
1574
|
+
accounts active in the last `inboxFamilyActivityDays`, with only
|
|
1575
|
+
Gmail/googlemail's documented
|
|
1433
1576
|
plus-tag and dot aliases collapsed, flagging inboxes behind 3+ accounts) and
|
|
1434
1577
|
`youngAccountAiUsage` (accounts under 30 days old drawing battery in the
|
|
1435
|
-
whole-day `aiUsageDayWindow`).
|
|
1436
|
-
|
|
1578
|
+
whole-day `aiUsageDayWindow`). The raw canonical inbox is never returned in
|
|
1579
|
+
the routine brief. SIGNAL ONLY: siblings legitimately share a parent inbox,
|
|
1580
|
+
so an inbox family is a reason to look, never proof or grounds
|
|
1437
1581
|
for action. Feed real suspicions to the AI-cost escalation category. Shared
|
|
1438
1582
|
AI device/IP risk evidence is already in `aiSpending.topRiskGroups`; do not
|
|
1439
1583
|
guess it from inbox similarity.
|
|
@@ -1526,7 +1670,28 @@ type InsightsBrief = Success<{
|
|
|
1526
1670
|
endDayInProgress: boolean;
|
|
1527
1671
|
summary: unknown;
|
|
1528
1672
|
byDay: unknown[];
|
|
1529
|
-
topAccounts:
|
|
1673
|
+
topAccounts: Array<{
|
|
1674
|
+
userId: number;
|
|
1675
|
+
username: string;
|
|
1676
|
+
eventCount: number;
|
|
1677
|
+
requestCount: number;
|
|
1678
|
+
estimatedCostUsd: number;
|
|
1679
|
+
inputTokens: number;
|
|
1680
|
+
cachedInputTokens: number;
|
|
1681
|
+
cacheEligibleInputTokens: number;
|
|
1682
|
+
outputTokens: number;
|
|
1683
|
+
totalTokens: number;
|
|
1684
|
+
imageCount: number;
|
|
1685
|
+
audioSeconds: number;
|
|
1686
|
+
energyUnits: number;
|
|
1687
|
+
energyChargedUnits: number;
|
|
1688
|
+
energyOverflowUnits: number;
|
|
1689
|
+
coinCharged: number;
|
|
1690
|
+
identitySummary: {
|
|
1691
|
+
observedIdentityCount: number;
|
|
1692
|
+
manualBucketObserved: boolean;
|
|
1693
|
+
};
|
|
1694
|
+
}>;
|
|
1530
1695
|
topRiskGroups: unknown[];
|
|
1531
1696
|
}
|
|
1532
1697
|
| InsightUnavailable;
|
|
@@ -1614,7 +1779,6 @@ type InsightsBrief = Success<{
|
|
|
1614
1779
|
| {
|
|
1615
1780
|
inboxFamilyActivityDays: number;
|
|
1616
1781
|
inboxFamilies: Array<{
|
|
1617
|
-
inbox: string;
|
|
1618
1782
|
accounts: Array<{
|
|
1619
1783
|
userId: number;
|
|
1620
1784
|
username: string | null;
|