@stage5/lumine 0.3.11 → 0.3.12
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 +79 -0
- package/lib/commands.js +1 -0
- package/package.json +1 -1
- package/sdk/LUMINE_ADMIN.md +13 -1
package/lib/admin.js
CHANGED
|
@@ -2021,6 +2021,32 @@ export function parseAdminOperation(options) {
|
|
|
2021
2021
|
}
|
|
2022
2022
|
}
|
|
2023
2023
|
|
|
2024
|
+
if (namespace === "identity" && action === "network") {
|
|
2025
|
+
const networkTarget = String(target || "").trim();
|
|
2026
|
+
const reason = String(options.adminReason || "").trim();
|
|
2027
|
+
if (!networkTarget || !reason) {
|
|
2028
|
+
throw cliValidationError(
|
|
2029
|
+
"Usage: lumine admin identity network <userId|username> --reason <management reason> [--include-private-evidence].",
|
|
2030
|
+
);
|
|
2031
|
+
}
|
|
2032
|
+
if (reason.length > MAX_IDENTITY_INSPECTION_REASON_LENGTH) {
|
|
2033
|
+
throw cliValidationError(
|
|
2034
|
+
`A network-evidence reason must be at most ${MAX_IDENTITY_INSPECTION_REASON_LENGTH} characters.`,
|
|
2035
|
+
);
|
|
2036
|
+
}
|
|
2037
|
+
return writeOperation(
|
|
2038
|
+
"identity.network",
|
|
2039
|
+
"POST",
|
|
2040
|
+
"/cli/admin/identity/network",
|
|
2041
|
+
{
|
|
2042
|
+
target: networkTarget,
|
|
2043
|
+
reason,
|
|
2044
|
+
includePrivateEvidence: options.adminIncludePrivateEvidence === true,
|
|
2045
|
+
},
|
|
2046
|
+
{ requiresRun: false },
|
|
2047
|
+
);
|
|
2048
|
+
}
|
|
2049
|
+
|
|
2024
2050
|
if (namespace === "economy" && action === "trace") {
|
|
2025
2051
|
const traceTarget = String(target || "").trim();
|
|
2026
2052
|
const reason = String(options.adminReason || "").trim();
|
|
@@ -5661,6 +5687,46 @@ const APPROVAL_LABELS = { dob: "birthdate", mentor: "teacher", meetup: "meetup"
|
|
|
5661
5687
|
const approvalDate = (seconds) =>
|
|
5662
5688
|
seconds ? new Date(Number(seconds) * 1000).toISOString().slice(0, 10) : "?";
|
|
5663
5689
|
|
|
5690
|
+
// Network evidence (users_actions addresses): a shared network (academy,
|
|
5691
|
+
// school) is only counted; a small one lists who shares it.
|
|
5692
|
+
function printNetwork(network, indent = "") {
|
|
5693
|
+
const addresses = network?.addresses || [];
|
|
5694
|
+
if (!network) return;
|
|
5695
|
+
if (network.unavailable) {
|
|
5696
|
+
console.log(`${indent}Network: could not be read this time (try again)`);
|
|
5697
|
+
return;
|
|
5698
|
+
}
|
|
5699
|
+
if (!addresses.length) {
|
|
5700
|
+
console.log(`${indent}Network: no recorded addresses`);
|
|
5701
|
+
return;
|
|
5702
|
+
}
|
|
5703
|
+
console.log(`${indent}Network: ${addresses.length} recent address(es)`);
|
|
5704
|
+
for (const a of addresses) {
|
|
5705
|
+
const span = `${approvalDate(a.firstAt)}..${approvalDate(a.lastAt)}`;
|
|
5706
|
+
const older = a.olderHistoryNotRead ? " · older history not read" : "";
|
|
5707
|
+
if (a.kind === "shared_network") {
|
|
5708
|
+
console.log(
|
|
5709
|
+
`${indent} - ${a.address} [${a.addressId}] · shared network: ${a.otherAccountsAtLeast}+ other accounts (not listed) · ${a.actions} actions ${span}${older}`,
|
|
5710
|
+
);
|
|
5711
|
+
continue;
|
|
5712
|
+
}
|
|
5713
|
+
if (a.kind === "only_this_account") {
|
|
5714
|
+
console.log(
|
|
5715
|
+
`${indent} - ${a.address} [${a.addressId}] · only this account · ${a.actions} actions ${span}${older}`,
|
|
5716
|
+
);
|
|
5717
|
+
continue;
|
|
5718
|
+
}
|
|
5719
|
+
console.log(
|
|
5720
|
+
`${indent} - ${a.address} [${a.addressId}] · small network shared with ${a.accounts.length} account(s) · ${a.actions} actions ${span}${older}`,
|
|
5721
|
+
);
|
|
5722
|
+
for (const o of a.accounts) {
|
|
5723
|
+
console.log(
|
|
5724
|
+
`${indent} ${o.username || "?"} (#${o.userId})${o.linked ? " · their linked account" : ""}${o.exists === false ? " · deleted" : ""} · age ${o.age ?? "?"} · ${o.isTeacherOrStaff ? "teacher/staff" : "member"}${o.userType ? ` · type ${o.userType}` : ""}${o.banned ? " · BANNED" : ""} · ${o.actions} actions ${approvalDate(o.firstAt)}..${approvalDate(o.lastAt)}`,
|
|
5725
|
+
);
|
|
5726
|
+
}
|
|
5727
|
+
}
|
|
5728
|
+
}
|
|
5729
|
+
|
|
5664
5730
|
function printEvidence(evidence) {
|
|
5665
5731
|
if (!evidence) return;
|
|
5666
5732
|
const a = evidence.account || {};
|
|
@@ -5689,6 +5755,7 @@ function printEvidence(evidence) {
|
|
|
5689
5755
|
` - ${l.username} (#${l.userId}) via ${(l.linkedBy || []).join("+")}${l.sharedDeviceCount ? ` (${l.sharedDeviceCount} device)` : ""} · age ${l.age ?? "?"} · ${l.isTeacherOrStaff ? "teacher/staff" : "member"} · joined ${approvalDate(l.joinedAt)}${l.banned ? " · BANNED" : ""}`,
|
|
5690
5756
|
);
|
|
5691
5757
|
}
|
|
5758
|
+
printNetwork(evidence.network);
|
|
5692
5759
|
console.log(
|
|
5693
5760
|
`Flags: ${(evidence.flags || []).length ? evidence.flags.join(", ") : "none"}`,
|
|
5694
5761
|
);
|
|
@@ -5907,6 +5974,18 @@ function printAdminResult({ operation, result }) {
|
|
|
5907
5974
|
}
|
|
5908
5975
|
return;
|
|
5909
5976
|
}
|
|
5977
|
+
if (operation.name === "identity.network") {
|
|
5978
|
+
const account = data.account || {};
|
|
5979
|
+
console.log(`${account.username} (#${account.userId})`);
|
|
5980
|
+
printNetwork(data.network);
|
|
5981
|
+
console.log(
|
|
5982
|
+
`Flags: ${(data.network?.flags || []).length ? data.network.flags.join(", ") : "none"}`,
|
|
5983
|
+
);
|
|
5984
|
+
console.log(
|
|
5985
|
+
"An address many accounts share (an academy, a school) links strangers and is only counted; a small one lists who shares it. Facts, not a finding.",
|
|
5986
|
+
);
|
|
5987
|
+
return;
|
|
5988
|
+
}
|
|
5910
5989
|
if (operation.name.startsWith("approvals.") || operation.name.startsWith("teachers.")) {
|
|
5911
5990
|
printApprovalResult({ operation, data });
|
|
5912
5991
|
return;
|
package/lib/commands.js
CHANGED
|
@@ -2989,6 +2989,7 @@ export function printHelp() {
|
|
|
2989
2989
|
lumine doctor runtime-assets
|
|
2990
2990
|
lumine admin identity list|status|use <zero|ciel|auto> [--json]
|
|
2991
2991
|
lumine admin identity inspect <user-id|username> --reason <management-reason> [--include-private-evidence] [--json]
|
|
2992
|
+
lumine admin identity network <user-id|username> --reason <management-reason> [--include-private-evidence] [--json] (addresses this account used; who shares the small ones)
|
|
2992
2993
|
lumine admin economy trace <user-id|username> --reason <management-reason> [--days <1..30>] [--json]
|
|
2993
2994
|
lumine admin rescue wordle-audit --reason <management-reason> [--days <1..30>] [--json]
|
|
2994
2995
|
lumine admin ai-bucket create --label <name> --note <text> [--json]
|
package/package.json
CHANGED
package/sdk/LUMINE_ADMIN.md
CHANGED
|
@@ -1162,7 +1162,7 @@ lumine admin review propose rewards:70 --dir /private/tmp/reward-review-70 --con
|
|
|
1162
1162
|
|
|
1163
1163
|
### Management approvals and the teacher audit (any time; also a full-daily-review duty; added 2026-10-04)
|
|
1164
1164
|
|
|
1165
|
-
Birthdate, teacher-signup (`mentor`) and meetup-achievement requests, each with its evidence: the account, the request, who invited them, accounts linked by verified email, exact device or a manual identity bucket (with each one's age and role), activity, and flags. These are Mikey-only and need no daily run.
|
|
1165
|
+
Birthdate, teacher-signup (`mentor`) and meetup-achievement requests, each with its evidence: the account, the request, who invited them, accounts linked by verified email, exact device or a manual identity bucket (with each one's age and role), the internet addresses the account acted from (network evidence, below), activity, and flags. These are Mikey-only and need no daily run.
|
|
1166
1166
|
|
|
1167
1167
|
```bash
|
|
1168
1168
|
lumine admin approvals list [--status pending|approved|rejected|all] [--type dob|mentor|meetup]
|
|
@@ -1170,8 +1170,20 @@ lumine admin approvals show <id>
|
|
|
1170
1170
|
lumine admin approvals approve|reject <id> [--reason <text>]
|
|
1171
1171
|
lumine admin teachers audit [--limit 1-100]
|
|
1172
1172
|
lumine admin teachers revoke <userId> --reason <text>
|
|
1173
|
+
lumine admin identity network <userId|username> --reason <text> [--include-private-evidence]
|
|
1173
1174
|
```
|
|
1174
1175
|
|
|
1176
|
+
**Network evidence** (`users_actions` addresses, added 2026-10-04): the account's most recently used addresses (up to 8), and for each one who else acted from it.
|
|
1177
|
+
- An address more than 8 other accounts use is a **shared network** (an academy, a school, a café): it is only counted, never listed, because it links strangers. Teachers and students at the same academy share one.
|
|
1178
|
+
- An address 8 or fewer other accounts use is a **small network** (a home): every account on it is listed with its age, role and account type. The person's own linked accounts (email, device, bucket) are marked `their linked account` and never raise a flag; logged-out visits are not accounts. If the addresses cannot be read (time cap), the pack still answers, with `network_evidence_unavailable`.
|
|
1179
|
+
- Addresses are masked (`58.151.x.59`) with a stable `addressId` for comparing reports; `--include-private-evidence` on `identity network` shows the full address. `identity network` commits an access receipt with your reason before reading anything, like `identity inspect`.
|
|
1180
|
+
- Only each address's newest 5,000 actions and each person's newest 5,000 are read (index-bounded, replica, time-capped), so `older history not read` can appear.
|
|
1181
|
+
|
|
1182
|
+
**Flags.** A linked account counts as a *minor* only with a recorded age under 18, and as a *member* when it holds no teacher/staff role (most accounts record no age, so "member" does not mean student):
|
|
1183
|
+
- `shares_device_with_minor_account` / `shares_device_with_member_account`, the same for `shares_email_…` and `same_identity_bucket_…`;
|
|
1184
|
+
- `shares_small_network_with_minor_account`, `shares_small_network_with_member_account`, `shares_small_network_with_banned_account`;
|
|
1185
|
+
- `linked_account_is_minor`, `own_birthdate_is_minor`, `new_account_with_linked_accounts`, `real_name_differs_from_profile`, `banned_account_in_family`.
|
|
1186
|
+
|
|
1175
1187
|
- Flags are pointers, not verdicts: a school device can link strangers. Judge each case, recommend, and act only on Mikey's decision.
|
|
1176
1188
|
- `teachers audit` lists approved teachers, riskiest first.
|
|
1177
1189
|
- `teachers revoke` removes a teacher status cleanly:
|