@stage5/lumine 0.2.40 → 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 +78 -13
- package/lib/admin-news.js +236 -0
- package/lib/admin-workflows.js +434 -0
- package/lib/admin.js +644 -45
- package/lib/agent/mcp-server.js +138 -0
- package/lib/agent/providers/claude-code.js +214 -0
- package/lib/agent/providers/codex.js +522 -0
- package/lib/agent/providers/environment.js +40 -0
- package/lib/agent/providers/index.js +38 -0
- package/lib/agent/tool-session.js +301 -0
- package/lib/agent/trace.js +138 -0
- package/lib/agent.js +453 -0
- package/lib/api.js +81 -1
- package/lib/build-review.js +493 -0
- package/lib/commands.js +86 -9
- package/lib/constants.js +2 -0
- package/package.json +1 -1
- package/sdk/BUILD_SDK_INDEX.md +24 -3
- package/sdk/LUMINE_ADMIN.md +271 -32
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.
|
|
4
|
-
Updated: 2026-08-
|
|
5
|
-
Generated: 2026-08-
|
|
3
|
+
Version: 1.33.0
|
|
4
|
+
Updated: 2026-08-15
|
|
5
|
+
Generated: 2026-08-15T03:00:24.685Z
|
|
6
6
|
|
|
7
7
|
## Notes
|
|
8
8
|
- This SDK is injected into Build iframes via the Build preview/runtime.
|
|
@@ -76,6 +76,27 @@ files:read, user:read, users:read, dailyReflections:read, content:read, content:
|
|
|
76
76
|
- Returns: Canonical shareable deep-link URL string, or null when app info is unavailable
|
|
77
77
|
- Builds a canonical shareable deep link into this app, e.g. https://www.twin-kle.com/app/884/432-the-great-gatsby.
|
|
78
78
|
- Example: await Twinkle.app.getShareUrl('432-the-great-gatsby');
|
|
79
|
+
- history.getState() | scopes: none
|
|
80
|
+
- Returns: The current app-owned history state object, or null
|
|
81
|
+
- Read the current Build app view state stored through Twinkle.app.history.
|
|
82
|
+
- History state is local to this iframe session and never changes the parent Twinkle URL.
|
|
83
|
+
- Use this for archive/detail/page state inside one Build document; use navigate() to load another project file.
|
|
84
|
+
- history.push(state) | scopes: none
|
|
85
|
+
- Returns: A JSON-cloned copy of the stored state
|
|
86
|
+
- Add a confirmed in-app view transition to browser history so Back stays inside the Build app.
|
|
87
|
+
- State must be a JSON-serializable object no larger than 16 KB.
|
|
88
|
+
- Push only after the requested view has loaded successfully; do not synthesize server-owned state.
|
|
89
|
+
- Example: Twinkle.app.history.push({ view: 'edition', dayIndex: 2080, page: 'scores' });
|
|
90
|
+
- history.replace(state) | scopes: none
|
|
91
|
+
- Returns: A JSON-cloned copy of the stored state
|
|
92
|
+
- Replace the current in-app history entry without adding a Back step.
|
|
93
|
+
- Use this to establish the initial confirmed view or reconcile a loading-only change.
|
|
94
|
+
- history.subscribe(listener, { immediate } = {}) | scopes: none
|
|
95
|
+
- Returns: unsubscribe function
|
|
96
|
+
- Restore app views when the viewer moves through browser Back or Forward history.
|
|
97
|
+
- The listener receives a cloned app state object, or null for an entry not owned by this app.
|
|
98
|
+
- The listener is called immediately by default; pass { immediate: false } to wait for Back or Forward.
|
|
99
|
+
- Example: const off = Twinkle.app.history.subscribe((state) => restoreView(state), { immediate: false });
|
|
79
100
|
- async navigate(target) | scopes: none
|
|
80
101
|
- Returns: { success, src }
|
|
81
102
|
- Navigate to another Build preview route through the parent bridge without dropping Twinkle SDK access.
|
package/sdk/LUMINE_ADMIN.md
CHANGED
|
@@ -89,12 +89,52 @@ 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
|
|
95
129
|
or agent making the judgments, and it applies to every verb below: recommends,
|
|
96
130
|
rewards, effort levels, Featured, skips, comments, and replies.
|
|
97
131
|
|
|
132
|
+
Public text authored as Ciel must be English. This is an operator and generation
|
|
133
|
+
instruction, not a script or keyword test: writing systems do not identify a
|
|
134
|
+
language reliably, and the API must not pretend otherwise. This is a
|
|
135
|
+
presentation rule, not an invitation to correct or lecture a member who writes
|
|
136
|
+
in another language; reply naturally in concise English.
|
|
137
|
+
|
|
98
138
|
**Twinkle is not Reddit.** Do not rank a run's attention by popularity,
|
|
99
139
|
recommendation count, or polish. Most users here are young children, and the
|
|
100
140
|
posts that most need Zero or Ciel are the ones nobody else answered.
|
|
@@ -168,6 +208,13 @@ a human owner can decide, and a finding nobody reports is a finding that did not
|
|
|
168
208
|
happen. **Every run ends with an escalation list**, and it belongs in the run's
|
|
169
209
|
final report whether or not anyone asks for it.
|
|
170
210
|
|
|
211
|
+
Keep that list narrow enough to be useful. Escalate concrete child-safety,
|
|
212
|
+
exploitation, privacy, targeted harassment, or platform/system-abuse risk — not
|
|
213
|
+
ordinary children experimenting, arguing, making rumors, proposing informal
|
|
214
|
+
in-site loans or contests, asking where media can be found, or making an
|
|
215
|
+
unverified ownership claim. Those may merit a normal age-appropriate response,
|
|
216
|
+
but they are not escalations without credible harmful conduct or a real victim.
|
|
217
|
+
|
|
171
218
|
Escalate, with the canonical `https://www.twin-kle.com/subjects/<id>` or
|
|
172
219
|
`/comments/<id>` URL, a one-line summary, and why it needs him:
|
|
173
220
|
|
|
@@ -178,11 +225,10 @@ Escalate, with the canonical `https://www.twin-kle.com/subjects/<id>` or
|
|
|
178
225
|
happened. These outrank every other category.
|
|
179
226
|
- **Account integrity** — someone posting from another person's account,
|
|
180
227
|
impersonation, shared logins, or a user operating a set of alternate accounts.
|
|
181
|
-
- **Economy
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
kids are recommending is spreading, and that is the urgent part.
|
|
228
|
+
- **Economy exploitation** — coordinated coin or XP farming across alternate
|
|
229
|
+
accounts, coercive or deceptive arrangements, or a repeatable abuse of the
|
|
230
|
+
platform economy with concrete evidence. A child offering a voluntary loan,
|
|
231
|
+
repayment, prize, or contest is not enough by itself.
|
|
186
232
|
- **AI-cost exploits** — patterns that convert free AI allowances into farmable
|
|
187
233
|
value: clusters of young accounts with heavy AI/battery usage, one person
|
|
188
234
|
operating many accounts that feed a single build through team branches,
|
|
@@ -224,6 +270,29 @@ Two rules that keep the list worth reading:
|
|
|
224
270
|
design. Do not delete, hide, argue with, or publicly accuse anyone, and do not
|
|
225
271
|
warn a child that they are in trouble. Report it and let Mikey decide.
|
|
226
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
|
+
|
|
227
296
|
## Common JSON types
|
|
228
297
|
|
|
229
298
|
All `--json` success output is one uncolored JSON value:
|
|
@@ -237,7 +306,9 @@ type Success<D> = {
|
|
|
237
306
|
};
|
|
238
307
|
```
|
|
239
308
|
|
|
240
|
-
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:
|
|
241
312
|
|
|
242
313
|
```ts
|
|
243
314
|
type Failure = {
|
|
@@ -418,6 +489,8 @@ lumine admin identity status --json
|
|
|
418
489
|
lumine admin identity use zero --json
|
|
419
490
|
lumine admin identity use ciel --json
|
|
420
491
|
lumine admin identity use auto --json
|
|
492
|
+
lumine admin identity inspect Jay1216 \
|
|
493
|
+
--reason "Confirm the account family before a bucket change" --json
|
|
421
494
|
```
|
|
422
495
|
|
|
423
496
|
Schemas:
|
|
@@ -436,6 +509,51 @@ type IdentityStatus = Success<{
|
|
|
436
509
|
}>;
|
|
437
510
|
|
|
438
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
|
+
};
|
|
439
557
|
```
|
|
440
558
|
|
|
441
559
|
`identity use` changes only the preference for a future start. It never changes
|
|
@@ -446,8 +564,16 @@ lumine admin daily-run start --identity auto --comment-mode off --json
|
|
|
446
564
|
lumine admin daily-run start --identity ciel --comment-mode draft \
|
|
447
565
|
--run-key daily:2026-08-06:review --json
|
|
448
566
|
lumine admin daily-run status --json
|
|
567
|
+
lumine admin daily-run escalation add --target subject:123 \
|
|
568
|
+
--note "Public contact details need owner review" --severity urgent --json
|
|
569
|
+
lumine admin daily-run escalation add --target chatMessage:3768159 \
|
|
570
|
+
--note "Concrete safety issue in a bot-authored chat message" --json
|
|
571
|
+
lumine admin daily-run report --json
|
|
449
572
|
lumine admin daily-run complete --json
|
|
450
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
|
|
451
577
|
```
|
|
452
578
|
|
|
453
579
|
Schemas:
|
|
@@ -465,6 +591,18 @@ type DailyRunComplete = Success<{
|
|
|
465
591
|
type DailyRunFail = DailyRunComplete;
|
|
466
592
|
```
|
|
467
593
|
|
|
594
|
+
Record only qualifying escalations as they are confirmed. `daily-run report`
|
|
595
|
+
then composes the active run's canonical audit events, successful mutations,
|
|
596
|
+
completed queue scans, recorded escalations, and the most useful brief deltas
|
|
597
|
+
into one result. Generate it before `complete`, because run-scoped reads require
|
|
598
|
+
the current active run. Queue coverage is written automatically only after an
|
|
599
|
+
`--all` traversal reaches canonical exhaustion; an interrupted scan remains in
|
|
600
|
+
its local checkpoint and cannot be misreported as complete.
|
|
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
|
+
|
|
468
606
|
`lastRun` makes a lost-response retry of `complete` or `fail` possible after
|
|
469
607
|
the active pointer has been cleared. Other run-scoped commands accept only the
|
|
470
608
|
current unexpired `active` run. Completion first finalizes any mutation whose
|
|
@@ -498,13 +636,17 @@ JSON error includes `details.retryIdempotencyKey` for a safe exact retry.
|
|
|
498
636
|
|
|
499
637
|
```bash
|
|
500
638
|
lumine admin recommendations list --kind recommend \
|
|
501
|
-
--content-types comment,dailyReflection --
|
|
639
|
+
--content-types comment,dailyReflection --all --json
|
|
640
|
+
lumine admin recommendations list --after 2026-08-14T00:00:00Z \
|
|
641
|
+
--all --checkpoint recommendations.json --json
|
|
642
|
+
lumine admin recommendations list --include-legacy --all --json
|
|
502
643
|
lumine admin recommendations list --unviewed --json
|
|
503
644
|
lumine admin subjects candidates --after 2026-08-01T00:00:00Z \
|
|
504
|
-
--
|
|
645
|
+
--all --checkpoint subjects.json --json
|
|
505
646
|
lumine admin subjects candidates --effort unassigned --json
|
|
506
647
|
lumine admin subjects candidates --unviewed --json
|
|
507
|
-
lumine admin builds candidates --
|
|
648
|
+
lumine admin builds candidates --all --limit 50 --json
|
|
649
|
+
lumine admin builds review build:884 --output-dir ./build-review --json
|
|
508
650
|
```
|
|
509
651
|
|
|
510
652
|
Schemas:
|
|
@@ -575,12 +717,34 @@ type BuildCandidates = Success<{
|
|
|
575
717
|
}>;
|
|
576
718
|
```
|
|
577
719
|
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
720
|
+
Subject cursors freeze a primary-key high-water mark and traverse descending
|
|
721
|
+
IDs. Bounded recommendation cursors freeze both the feed-ID high-water mark and
|
|
722
|
+
the server timestamp, then traverse the indexed `(timeStamp, id)` order; this
|
|
723
|
+
also catches a Daily Reflection whose old feed row moved forward when it was
|
|
724
|
+
reshared. Explicit legacy scans retain the descending primary-key walk. A page
|
|
725
|
+
can be empty while `hasMore` remains true; continue until `exhausted`. `--all`
|
|
726
|
+
does that automatically and writes a private checkpoint after every
|
|
727
|
+
server-confirmed page; `--resume` continues only when the checkpoint belongs to
|
|
728
|
+
the same API, run, and exact request. The final result can be copied to
|
|
729
|
+
`--output`, while `--checkpoint` is resumable operational state. Subject
|
|
730
|
+
`--after` is inclusive, and every opaque cursor is bound to its original
|
|
731
|
+
filters.
|
|
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
|
+
|
|
739
|
+
Recommendations default to `--since-run`: the server uses the previous
|
|
740
|
+
completed run's start time (or the same bounded seven-day fallback used by the
|
|
741
|
+
brief on a first run). That deliberate start-to-start overlap gives the queue
|
|
742
|
+
at-least-once coverage when content arrives after the prior snapshot but before
|
|
743
|
+
that run completes. `--after` supplies an explicit inclusive timestamp.
|
|
744
|
+
All-history traversal is deliberately available only through
|
|
745
|
+
`--include-legacy`. The CLI requires the API to echo the canonical `after`
|
|
746
|
+
boundary for bounded modes, so deploying a new CLI against an older API cannot
|
|
747
|
+
silently fall back to a million-row historical scan.
|
|
584
748
|
|
|
585
749
|
`builds candidates` is a management-agent discovery view over the canonical
|
|
586
750
|
public Build browser, ordered by the current published release. It is
|
|
@@ -592,6 +756,15 @@ genuinely try the published runtime, or pull and read an open-source project,
|
|
|
592
756
|
before making that judgment. Direct API/persona automation is never a review
|
|
593
757
|
substitute.
|
|
594
758
|
|
|
759
|
+
`builds review` is the managed runtime path: it fetches the current published
|
|
760
|
+
artifact identity, launches the app in an isolated temporary Chromium profile,
|
|
761
|
+
captures a screenshot and bounded console evidence, then fetches the identity
|
|
762
|
+
again. It writes `review.json` in a unique per-review subdirectory only when
|
|
763
|
+
the browser completed, the screenshot exists, and the artifact did not change
|
|
764
|
+
mid-review. Attach the returned `receiptPath` with
|
|
765
|
+
`comment draft ... --review-receipt review.json`; this binds the draft to the
|
|
766
|
+
exact reviewed artifact without copying a version number by hand.
|
|
767
|
+
|
|
595
768
|
During every management run, scan recent Build candidates back through the
|
|
596
769
|
run's review window alongside Subjects and the recommendation queue. An app
|
|
597
770
|
that is thin, broken, private, unchanged since a prior substantive bot
|
|
@@ -919,6 +1092,10 @@ If recommendation succeeds but reward fails, the command exits nonzero with
|
|
|
919
1092
|
```bash
|
|
920
1093
|
lumine admin post skip dailyReflection:99 --json
|
|
921
1094
|
lumine admin post skip comment:456 --reason "one-line answer, nothing to add" --json
|
|
1095
|
+
lumine admin post skip-batch --target-file skip-targets.json \
|
|
1096
|
+
--checkpoint skip-progress.json --json
|
|
1097
|
+
lumine admin post skip-batch --target-file skip-targets.json \
|
|
1098
|
+
--checkpoint skip-progress.json --resume --json
|
|
922
1099
|
```
|
|
923
1100
|
|
|
924
1101
|
A skip records that the management rotation has judged a recommend-queue item
|
|
@@ -937,6 +1114,13 @@ metadata — it is the agent's memory of the judgment, not public content.
|
|
|
937
1114
|
The skip requires the `recommendation:write` scope and is audited like every
|
|
938
1115
|
other mutation.
|
|
939
1116
|
|
|
1117
|
+
`skip-batch` accepts either a JSON array (strings or `{ "target", "reason" }`
|
|
1118
|
+
objects), `{ "targets": [...] }`, or one target per text line. It deduplicates
|
|
1119
|
+
targets, submits them sequentially through the same canonical audited endpoint,
|
|
1120
|
+
and checkpoints only after each response is confirmed. `--resume` verifies the
|
|
1121
|
+
exact target-set fingerprint and run ID before continuing; it never guesses
|
|
1122
|
+
which writes succeeded.
|
|
1123
|
+
|
|
940
1124
|
```ts
|
|
941
1125
|
type PostSkip = Success<{
|
|
942
1126
|
skip: {
|
|
@@ -953,9 +1137,10 @@ type PostSkip = Success<{
|
|
|
953
1137
|
|
|
954
1138
|
```bash
|
|
955
1139
|
lumine admin news --json
|
|
956
|
-
lumine admin news claim --json
|
|
957
|
-
lumine admin news
|
|
958
|
-
|
|
1140
|
+
lumine admin news claim --output claim.json --scaffold editorial.json --json
|
|
1141
|
+
lumine admin news validate --claim claim.json --file editorial.json --json
|
|
1142
|
+
lumine admin news submit --claim claim.json --file editorial.json \
|
|
1143
|
+
--model "Ciel" --json
|
|
959
1144
|
lumine admin news print --json
|
|
960
1145
|
```
|
|
961
1146
|
|
|
@@ -968,9 +1153,18 @@ the run, and if `printedToday` is false with no edition `pending` or
|
|
|
968
1153
|
**Preferred: write the editorial yourself.** `news claim` reserves today's
|
|
969
1154
|
edition under the server's generation lease and returns the exact canonical
|
|
970
1155
|
event digest the server would otherwise send to its own model, so no provider
|
|
971
|
-
API credits are spent.
|
|
972
|
-
|
|
973
|
-
|
|
1156
|
+
API credits are spent. With `--output` and `--scaffold`, the CLI writes that
|
|
1157
|
+
lease/digest to a private claim file and creates an editable editorial shell.
|
|
1158
|
+
`news validate` runs locally, before authentication or a network request, and
|
|
1159
|
+
checks the complete citation graph plus byte-exact quote boundaries. Submit the
|
|
1160
|
+
validated pair with `news submit --claim`; the CLI reads the edition and lease
|
|
1161
|
+
from the claim file and validates again immediately before the request. The
|
|
1162
|
+
explicit `--edition-id` / `--lease-token` form remains available for backwards
|
|
1163
|
+
compatibility.
|
|
1164
|
+
|
|
1165
|
+
Write a `GeneratedEditorial` JSON and send it back within the ten-minute lease.
|
|
1166
|
+
The server still treats the editorial as untrusted regardless of author: every
|
|
1167
|
+
story must cite an exact `eventKey`
|
|
974
1168
|
from the digest, front-page `sourceQuote`s must be verbatim contiguous
|
|
975
1169
|
passages of the cited event's summary (invalid quotes are replaced with
|
|
976
1170
|
canonical text), section and page layout are server-enforced, announcements
|
|
@@ -1189,6 +1383,22 @@ rows per source — retry with a narrower `--days` window, and do not complete
|
|
|
1189
1383
|
the run while either flag remains true. Run it right after the
|
|
1190
1384
|
brief, and **read every row** — the tool deliberately does no filtering,
|
|
1191
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
|
+
|
|
1192
1402
|
Judge against the same values the editorial priorities encode:
|
|
1193
1403
|
|
|
1194
1404
|
- **premises must be real.** The 08-11 message didn't merely choose a bad
|
|
@@ -1272,11 +1482,16 @@ farm-signal sections added the same day):
|
|
|
1272
1482
|
("$X so far today; complete days run ~$Y/day"). Real
|
|
1273
1483
|
incident: a run report quoted a ~15%-complete day bucket ($5) as the site's
|
|
1274
1484
|
daily AI spend (complete days were running ~$40-50). Flag accounts that jumped tiers or
|
|
1275
|
-
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
|
|
1276
1491
|
report fails; say so rather than guessing. This section is also the run's
|
|
1277
1492
|
AI-cost exploit watch: while reading it, actively look for the signatures the
|
|
1278
1493
|
brief actually exposes — one risk group spanning several user IDs, repeated
|
|
1279
|
-
|
|
1494
|
+
account groups in `farmSignals.inboxFamilies`, or heavy spend by
|
|
1280
1495
|
accounts that `economy.topGainers` or `notableCandidates` independently marks
|
|
1281
1496
|
as recent signups. Cross-check those signals against the escalation
|
|
1282
1497
|
categories. Missing join-date or community data is unknown, not evidence that
|
|
@@ -1291,9 +1506,11 @@ farm-signal sections added the same day):
|
|
|
1291
1506
|
execute them with
|
|
1292
1507
|
`lumine admin notable add <userId|username> --note "<specific rationale>"`
|
|
1293
1508
|
(idempotent —
|
|
1294
|
-
an existing member returns `already_done`;
|
|
1295
|
-
|
|
1296
|
-
|
|
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.
|
|
1297
1514
|
**Always pass `--note`** with a concrete one-or-two-sentence record of what
|
|
1298
1515
|
made them notable — real numbers and specifics from the brief window, not
|
|
1299
1516
|
"active user". It lands in the management page's reason column, which is
|
|
@@ -1353,12 +1570,14 @@ farm-signal sections added the same day):
|
|
|
1353
1570
|
Deliberately coarse: it is an onboarding health check, not per-child
|
|
1354
1571
|
session tracking.
|
|
1355
1572
|
- `farmSignals` — AI-cost farm signatures derivable with ZERO new data
|
|
1356
|
-
collection: `inboxFamilies` (
|
|
1357
|
-
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
|
|
1358
1576
|
plus-tag and dot aliases collapsed, flagging inboxes behind 3+ accounts) and
|
|
1359
1577
|
`youngAccountAiUsage` (accounts under 30 days old drawing battery in the
|
|
1360
|
-
whole-day `aiUsageDayWindow`).
|
|
1361
|
-
|
|
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
|
|
1362
1581
|
for action. Feed real suspicions to the AI-cost escalation category. Shared
|
|
1363
1582
|
AI device/IP risk evidence is already in `aiSpending.topRiskGroups`; do not
|
|
1364
1583
|
guess it from inbox similarity.
|
|
@@ -1451,7 +1670,28 @@ type InsightsBrief = Success<{
|
|
|
1451
1670
|
endDayInProgress: boolean;
|
|
1452
1671
|
summary: unknown;
|
|
1453
1672
|
byDay: unknown[];
|
|
1454
|
-
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
|
+
}>;
|
|
1455
1695
|
topRiskGroups: unknown[];
|
|
1456
1696
|
}
|
|
1457
1697
|
| InsightUnavailable;
|
|
@@ -1539,7 +1779,6 @@ type InsightsBrief = Success<{
|
|
|
1539
1779
|
| {
|
|
1540
1780
|
inboxFamilyActivityDays: number;
|
|
1541
1781
|
inboxFamilies: Array<{
|
|
1542
|
-
inbox: string;
|
|
1543
1782
|
accounts: Array<{
|
|
1544
1783
|
userId: number;
|
|
1545
1784
|
username: string | null;
|