@stage5/lumine 0.2.65 → 0.2.67

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.
@@ -15,9 +15,14 @@ canonical structured data.
15
15
  server-owned Zero and Ciel user IDs are approved. Usernames and CLI flags are
16
16
  not authority.
17
17
  - `daily-run start` creates or returns a six-hour `delegated-admin` run with
18
- explicit scopes and one public actor. Every run-scoped CLI command loads the
19
- canonical active run and sends its ID; the API rejects a missing, expired, or
20
- mismatched run.
18
+ one allowlisted run scope and one public actor. `--scope full` is the full
19
+ daily-management review. `--scope featured` is only an authorization
20
+ envelope for a specifically requested Featured slice; it does not authorize
21
+ or imply the newspaper, queues, conduct review, logs, costs, AI Energy
22
+ budget health, sponsors,
23
+ carry-over work, or final full-run report. Every run-scoped CLI command loads
24
+ the canonical active run and sends its ID; the API rejects a missing,
25
+ expired, scope-mismatched, or actor-mismatched run.
21
26
  - The public content actor is Zero or Ciel. Mikey's operator ID is retained in
22
27
  private audit rows and is not embedded in public comment metadata.
23
28
  - Delegated HTTP work never authenticates as the bot, opens a bot socket, changes
@@ -59,6 +64,15 @@ Comment mode is stored only on the current run:
59
64
  - `draft`: server-generated drafts, no public comment.
60
65
  - `post`: drafts plus idempotent publication through the ordinary comment path.
61
66
 
67
+ A Featured-only run always uses comment mode `off` and grants only Featured
68
+ subject inspection, subject reveal, Featured mutation, and run completion. It can complete
69
+ without a sponsor-integrity scan. Completing it does not advance any full-run
70
+ content/cost/conduct window, queue-coverage record, last-completed identity, or
71
+ carry-over surfacing telemetry. Start one only when Mikey requested that slice; never turn a small
72
+ request into a full review merely because the technical command needs a run.
73
+ The API enforces these scopes, and the CLI also rejects out-of-scope operations
74
+ before calling endpoints outside the Lumine Admin router (notably Build review).
75
+
62
76
  ### Private AI-bucket maintenance
63
77
 
64
78
  AI identity buckets are private operator bookkeeping, not a Zero/Ciel public
@@ -210,9 +224,11 @@ coins, streaks, buckets, messages, or public content.
210
224
 
211
225
  ## Editorial priorities
212
226
 
213
- The CLI enforces none of this — it is the standing instruction for the operator
214
- or agent making the judgments, and it applies to every verb below: recommends,
215
- rewards, effort levels, Featured, skips, comments, and replies.
227
+ The CLI never makes the qualitative judgments in this section; they are the
228
+ standing instruction for the operator or agent and apply to every verb below:
229
+ recommends, rewards, effort levels, Featured, skips, comments, and replies. It
230
+ does enforce deterministic server-provable boundaries documented below, such
231
+ as the posting-date and lifetime-history gates for a new Featured addition.
216
232
 
217
233
  Public text authored as Ciel must be English. This is an operator and generation
218
234
  instruction, not a script or keyword test: writing systems do not identify a
@@ -337,9 +353,9 @@ is. Those go to Mikey.
337
353
 
338
354
  ## Escalation to Mikey
339
355
 
340
- A run is not finished when the mutations are done. Curation surfaces things only
356
+ A full daily management run is not finished when the mutations are done. Curation surfaces things only
341
357
  a human owner can decide, and a finding nobody reports is a finding that did not
342
- happen. **Every run ends with an escalation list**, and it belongs in the run's
358
+ happen. **Every full run ends with an escalation list**, and it belongs in the run's
343
359
  final report whether or not anyone asks for it.
344
360
 
345
361
  Keep that list narrow enough to be useful. Escalate concrete child-safety,
@@ -604,6 +620,7 @@ type DailyRun = {
604
620
  publicActorUserId: number;
605
621
  identityMode: "auto" | "zero" | "ciel";
606
622
  commentMode: "off" | "draft" | "post";
623
+ runScope: "full" | "featured";
607
624
  sessionKind: "delegated-admin";
608
625
  scopes: string[];
609
626
  status: "active" | "completed" | "failed" | "expired";
@@ -704,6 +721,7 @@ identity, or advances rotation.
704
721
 
705
722
  ```bash
706
723
  lumine admin daily-run start --identity auto --comment-mode off --json
724
+ lumine admin daily-run start --scope featured --identity auto --json
707
725
  lumine admin daily-run start --identity ciel --comment-mode draft \
708
726
  --run-key daily:2026-08-06:review --json
709
727
  lumine admin daily-run status --json
@@ -712,6 +730,7 @@ lumine admin daily-run escalation add --target subject:123 \
712
730
  lumine admin daily-run escalation add --target chatMessage:3768159 \
713
731
  --note "Concrete safety issue in a bot-authored chat message" --json
714
732
  lumine admin daily-run report --json
733
+ lumine admin daily-run report --run 123 --json
715
734
  lumine admin daily-run complete --json
716
735
  lumine admin daily-run fail --reason "operator stopped" --json
717
736
  lumine admin escalation list --status all --json
@@ -744,7 +763,7 @@ type DailyRunFail = DailyRunComplete;
744
763
 
745
764
  This is the approved Zero/Ciel Build Workshop sponsor role, not the ordinary
746
765
  AI Energy sponsor flow. Applications originate only from `lumine sponsor`.
747
- Website-management agents review them inside an active daily run:
766
+ Website-management agents review them inside an active full daily run:
748
767
 
749
768
  ```bash
750
769
  lumine admin sponsor applications list --status pending --json
@@ -773,18 +792,29 @@ cleared.
773
792
  `disqualify` makes it ineligible. `hold` and `flag` require an evidence note and
774
793
  remain open. The scan itself never changes sponsor status or applies a sanction.
775
794
  Use the separate, audited `sponsor status set` command for an explicit human
776
- decision. `daily-run complete` is rejected until the scan has covered its full
795
+ decision. Full `daily-run complete` is rejected until the scan has covered its full
777
796
  snapshot and no pending, held, or flagged case remains.
778
797
 
779
- Record only qualifying escalations as they are confirmed. `daily-run report`
798
+ During a full review, record only qualifying escalations as they are confirmed.
799
+ `daily-run report`
780
800
  then composes the active run's canonical audit events, successful mutations,
781
801
  completed queue scans, recorded escalations, and the most useful brief deltas
782
802
  into one result. Generate it before `complete`, because run-scoped reads require
783
- the current active run. Queue coverage is written automatically only after an
803
+ the current active run. After completion,
804
+ `daily-run report --run <completed-run-id>` is the run-independent recovery
805
+ path. It reconstructs immutable run/audit/coverage/escalation evidence and the
806
+ closed-day calendar cost view at the run's completion boundary. It labels that
807
+ basis `historical_reconstruction`: later canonical ledger corrections to those
808
+ closed days are reflected, while the boundary day's then-open cost bucket is
809
+ omitted. The former live brief, carry-over-todo snapshot, and pending sponsor-
810
+ application count are returned as unavailable rather than being synthesized
811
+ from today's state; sponsor scan/case status is explicitly labeled as current
812
+ canonical state for that run's scan. Queue coverage is
813
+ written automatically only after an
784
814
  `--all` traversal reaches canonical exhaustion; an interrupted scan remains in
785
815
  its local checkpoint and cannot be misreported as complete.
786
816
 
787
- **Every agent-authored final management report includes a `Featured rotation`
817
+ **Every agent-authored final full-management report includes a `Featured rotation`
788
818
  section.** Base it on a fresh `featured list`. When capacity exists, make and
789
819
  report strong additions during the run under the standing approval above; do
790
820
  not defer them as proposals. Then name each current Subject proposed for
@@ -818,13 +848,17 @@ Starting with a run key that belongs to a finished or expired run fails with
818
848
  `CLI_ADMIN_RUN_KEY_ALREADY_USED`; supply a fresh `--run-key` (for example
819
849
  `daily:2026-08-07:2`) to start again the same day. Reusing the key of the
820
850
  live active run returns that run only when the requested `--comment-mode`
821
- and any explicit `--identity` match it; otherwise the start fails with
851
+ and `--scope`, plus any explicit `--identity`, match it; otherwise the start fails with
822
852
  `CLI_ADMIN_RUN_SETTINGS_MISMATCH` instead of silently returning a run with
823
853
  different scopes. The same check applies when a start without the active
824
854
  run's key would fall back to that active run.
825
855
 
826
- The default run key is `daily:YYYY-MM-DD` in Asia/Bangkok. Supply `--run-key`
827
- for a separate explicit run. `--idempotency-key` may be supplied to any
856
+ The default full-run key is `daily:YYYY-MM-DD` in Asia/Bangkok. Scoped Featured
857
+ runs receive a fresh `scoped:featured:...` key so completing one slice cannot
858
+ consume the day's full-run key or prevent a later explicitly requested slice.
859
+ They also use a dedicated API start endpoint, so an older API cannot ignore the
860
+ scope and silently create a full run; it fails before creating any run instead.
861
+ Supply `--run-key` for a separate explicit run. `--idempotency-key` may be supplied to any
828
862
  mutation when a caller needs the same retry identity across processes. The CLI
829
863
  generates a fresh key for every mutation invocation; if a mutation fails, its
830
864
  JSON error includes `details.retryIdempotencyKey` for a safe exact retry.
@@ -850,16 +884,19 @@ audit path: canonical todo state and its private `todo.create` / `todo.update`
850
884
  audit response commit together, and no public bot, public mutation count, or
851
885
  rotation signal is involved.
852
886
 
853
- Every successful `daily-run start` response automatically includes all
887
+ Every successful full `daily-run start` response automatically includes all
854
888
  unfinished items under `data.carryoverTodos`. The same run ID increments an
855
889
  item's surfacing telemetry at most once, even when start is retried. This is the
856
890
  canonical handoff: read it before discretionary new work, resume what can safely
857
- progress after the run's mandatory newspaper/brief/conduct duties, and record a
891
+ progress after the run's mandatory newspaper/brief/conduct/log-review/cost/
892
+ energy-budget duties, and record a
858
893
  concrete progress note before the run closes. The daily-run report includes the
859
894
  still-unfinished set again. Completing a daily run never silently completes its
860
895
  todos. A CLI carrying this contract rejects a start response that does not echo
861
896
  the canonical handoff, so a newer CLI against an API deployed before the todo
862
897
  migration cannot quietly treat unsupported telemetry as an empty list.
898
+ A Featured-only start instead returns an explicitly suppressed, empty handoff
899
+ and performs no todo reads, writes, capacity checks, or surfacing increments.
863
900
 
864
901
  `kind` is `task` or `experiment`. New items may start `open`, `in_progress`, or
865
902
  `blocked`; updates may also use `completed` or `cancelled`. A progress note is
@@ -899,9 +936,10 @@ type AdminTodoList = Success<{
899
936
  type AdminTodoMutation = Success<{ todo: AdminTodo }>;
900
937
 
901
938
  type CarryoverTodos = {
939
+ included: boolean;
902
940
  items: AdminTodo[];
903
941
  count: number;
904
- surfacedForRunId: number;
942
+ surfacedForRunId: number | null;
905
943
  newlySurfacedCount: number;
906
944
  };
907
945
  ```
@@ -917,6 +955,8 @@ lumine admin recommendations list --include-legacy --all --json
917
955
  lumine admin recommendations list --unviewed --json
918
956
  lumine admin subjects candidates --after 2026-08-01T00:00:00Z \
919
957
  --all --checkpoint subjects.json --json
958
+ lumine admin subjects candidates --since-run --all --json
959
+ lumine admin subjects candidates --include-legacy --all --json
920
960
  lumine admin subjects candidates --effort unassigned --json
921
961
  lumine admin subjects candidates --unviewed --json
922
962
  lumine admin builds candidates --all --limit 50 --json
@@ -1009,12 +1049,31 @@ the spool and can be copied to a separate `--output` file, while `--checkpoint`
1009
1049
  remains resumable operational state. Subject `--after` is inclusive, and every
1010
1050
  opaque cursor is bound to its original filters.
1011
1051
 
1052
+ An automatic checkpoint filename includes a fingerprint of the exact request,
1053
+ so two scans with the same operation name and run ID but different subjects,
1054
+ server filters, client-side view filters, or result-transform inputs cannot
1055
+ overwrite one another. An exclusive adjacent lock rejects a
1056
+ second process using the same checkpoint while the first scan is active and
1057
+ recovers a lock only when its recorded process no longer exists. Resume still
1058
+ recognizes the pre-fingerprint default filename, validates its stored request
1059
+ fingerprint, and migrates it through the existing checkpoint path.
1060
+ Legacy Build-candidate checkpoints intentionally fail that validation because
1061
+ they did not bind the Site URL used to materialize candidate links; start those
1062
+ scans fresh so one result cannot mix origins.
1063
+
1012
1064
  For `--all --json`, stdout remains exactly one JSON value. Scan-start, first-
1013
1065
  page, every-tenth-page, and exhaustion progress is written to **stderr** with
1014
1066
  only page/scanned/candidate counts and the private checkpoint path. A long
1015
1067
  traversal therefore no longer looks stalled, while piping stdout to `jq` or a
1016
1068
  file remains safe.
1017
1069
 
1070
+ `Ctrl+C` and `SIGTERM` abort the in-flight page request, leave the last
1071
+ server-confirmed page fsynced in the private checkpoint/spool, and release the
1072
+ adjacent process lock. The cancellation error names the checkpoint. Continue
1073
+ only by rerunning the exact same command with `--resume`; the next invocation
1074
+ verifies the request fingerprint and confirmed spool digest before requesting
1075
+ another page. An interrupted request is never counted as queue coverage.
1076
+
1018
1077
  Recommendations default to `--since-run`: the server uses the previous
1019
1078
  completed run's start time (or the same bounded seven-day fallback used by the
1020
1079
  brief on a first run). That deliberate start-to-start overlap gives the queue
@@ -1025,6 +1084,13 @@ All-history traversal is deliberately available only through
1025
1084
  boundary for bounded modes, so deploying a new CLI against an older API cannot
1026
1085
  silently fall back to a million-row historical scan.
1027
1086
 
1087
+ Subject candidates follow the same window contract. They default to the
1088
+ previous completed full run's start (with the seven-day first-run fallback),
1089
+ accept an explicit inclusive `--after`, and require `--include-legacy` for a
1090
+ lifetime traversal. `--since-run`, `--after`, and `--include-legacy` are
1091
+ mutually exclusive. The CLI also requires the API to echo the bounded Subject
1092
+ window before accepting a page.
1093
+
1028
1094
  `builds candidates` is a management-agent discovery view over the canonical
1029
1095
  public Build browser, ordered by the current published release. It is
1030
1096
  available through the `admin` namespace only while a delegated run is active;
@@ -1047,7 +1113,7 @@ learned during that review. The receipt binds the draft to the exact reviewed
1047
1113
  artifact without copying a version number by hand; the server owns the Build,
1048
1114
  version, method, and review-time fields around that understanding.
1049
1115
 
1050
- During every management run, scan recent Build candidates back through the
1116
+ During every full daily management review, scan recent Build candidates back through the
1051
1117
  run's review window alongside Subjects and the recommendation queue. An app
1052
1118
  that is thin, broken, private, unchanged since a prior substantive bot
1053
1119
  comment, or not meaningfully understood may be left alone. A new or materially
@@ -1201,6 +1267,9 @@ lumine admin subject creator set-made-by-poster 123 --json
1201
1267
  lumine admin subject feature 123 --json
1202
1268
  lumine admin subject unfeature 123 --json
1203
1269
  lumine admin featured list --json
1270
+ lumine admin featured history --subject-ids 50,40 --all --json
1271
+ lumine admin featured add --subject-ids 50,40 \
1272
+ --posted-after 2026-08-27T00:00:00+07:00 --json
1204
1273
  lumine admin featured reorder --subject-ids 30,20,10 --json
1205
1274
  lumine admin featured rotate --remove-subject-ids 30,20 \
1206
1275
  --add-subject-ids 50,40 --json
@@ -1233,12 +1302,58 @@ type FeaturedList = Success<{
1233
1302
  maximum: 20;
1234
1303
  }>;
1235
1304
 
1305
+ type FeaturedHistory = Success<{
1306
+ coverage: {
1307
+ complete: boolean;
1308
+ startedAt: number | null;
1309
+ updatedAt: number | null;
1310
+ };
1311
+ subjects: Array<{
1312
+ id: number;
1313
+ url: string;
1314
+ title: string | null;
1315
+ createdAt: number | null;
1316
+ deleted: boolean | null;
1317
+ featured: { member: boolean; order: number | null };
1318
+ knownFeatured: boolean;
1319
+ neverFeatured: boolean | null;
1320
+ firstRecordedFeaturedAt: number | null;
1321
+ lastRecordedFeaturedAt: number | null;
1322
+ }>;
1323
+ events: Array<{
1324
+ id: number;
1325
+ mutationId: string;
1326
+ subjectId: number;
1327
+ action: "featured" | "unfeatured" | "reordered" | "snapshot";
1328
+ fromPosition: number | null;
1329
+ toPosition: number | null;
1330
+ source: "website" | "lumine-admin" | "coverage-bootstrap";
1331
+ operation: string;
1332
+ actorUserId: number | null;
1333
+ operatorUserId: number | null;
1334
+ adminAuditId: number | null;
1335
+ occurredAt: number;
1336
+ }>;
1337
+ pagination: Pagination;
1338
+ }>;
1339
+
1236
1340
  type SubjectFeature = FeaturedList & {
1237
1341
  status: "success" | "already_done";
1238
1342
  changed: boolean;
1239
1343
  };
1240
1344
 
1241
1345
  type SubjectUnfeature = SubjectFeature;
1346
+ type FeaturedAdd = FeaturedList & {
1347
+ status: "success" | "already_done";
1348
+ changed: boolean;
1349
+ data: FeaturedList["data"] & {
1350
+ addition: {
1351
+ addSubjectIds: number[];
1352
+ postedAfter: number;
1353
+ finalSubjectIds: number[];
1354
+ };
1355
+ };
1356
+ };
1242
1357
  type FeaturedReorder = SubjectFeature;
1243
1358
  type FeaturedRotate = FeaturedList & {
1244
1359
  status: "success" | "already_done";
@@ -1267,6 +1382,34 @@ unknown/deleted IDs, missing current members, non-subject rows, and more than
1267
1382
  20 subjects. Permanent pins and editorial ordering policy are deliberately not
1268
1383
  hardcoded.
1269
1384
 
1385
+ `featured history` is the compact canonical evidence path. It returns only
1386
+ coverage metadata, per-subject lifetime summaries, and paginated mutation
1387
+ events; it does not repeat full audit before/after board snapshots. An event of
1388
+ any action proves the subject has appeared on Featured. `neverFeatured: true`
1389
+ is returned only when no event exists and the subject was created strictly
1390
+ after the finalized coverage boundary. `null` means the subject predates provable
1391
+ coverage—never convert that unknown into “never Featured.” Both the website
1392
+ editor and Lumine mutations write this append-only history in the same
1393
+ transaction as the canonical board replacement.
1394
+ For a retry whose board transaction committed but whose canonical detail reload
1395
+ failed, the audit-linked history event is the durable receipt: the API re-reads
1396
+ the current board and preserves the original changed-mutation accounting.
1397
+
1398
+ `featured add` is the atomic verb for genuinely new additions. The supplied
1399
+ IDs are placed at the front in descending relevance order while existing
1400
+ members retain their order. The server requires the whole batch to be absent,
1401
+ fit within the 20-subject maximum, have no Featured event, fall inside complete
1402
+ history coverage, and have a creation time strictly after `--posted-after`.
1403
+ That boundary accepts Unix seconds, an ISO-8601 date (interpreted as UTC), or
1404
+ an ISO-8601 timestamp with an explicit `Z`/numeric offset; timezone-free
1405
+ timestamps and permissively normalized dates are rejected.
1406
+ Any failed gate leaves the entire board unchanged. An exact completed retry is
1407
+ replayed from its audit response, while recovery after a committed board change
1408
+ is proven by that request's audit-linked history receipt. A fresh request for
1409
+ an already-present subject fails instead of inferring a retry from board shape.
1410
+ Use the ordinary singular `subject feature` only for an explicit manual
1411
+ override; it does not claim that a subject is new.
1412
+
1270
1413
  Featured rotate is the direct, atomic replacement verb for an approved
1271
1414
  rotation. `--remove-subject-ids` names the exact current members Mikey approved
1272
1415
  for removal; `--add-subject-ids` names the same number of replacements in
@@ -1617,7 +1760,7 @@ platform absorbs the cost, exactly like their coin-exempt recommends and
1617
1760
  rewards. When a day's first edition is printed, the server notifies the app's
1618
1761
  notification subscribers (users can mute the app or unsubscribe in the app;
1619
1762
  the bots never need to send anything). All three mutations require the
1620
- `news:print` scope (in every run's base scopes) and are audited as `news.print`
1763
+ `news:print` scope (in every full run's base scopes) and are audited as `news.print`
1621
1764
  / `news.claim` / `news.submit` against `news_edition` targets.
1622
1765
 
1623
1766
  ```ts
@@ -1678,7 +1821,7 @@ type NewsClaim = Success<{
1678
1821
  type NewsSubmit = NewsStatus; // "success"; newspaper includes revisionNumber
1679
1822
  ```
1680
1823
 
1681
- ## Bot conduct review (standing duty, every run)
1824
+ ## Bot conduct review (standing duty, every full daily review)
1682
1825
 
1683
1826
  ```bash
1684
1827
  lumine admin bot-output --json
@@ -1686,7 +1829,8 @@ lumine admin bot-output --days 3 --json
1686
1829
  lumine admin bot-output --cursor '<pagination.nextCursor>' --json
1687
1830
  ```
1688
1831
 
1689
- **Every run reviews what Zero and Ciel themselves said since the last run.**
1832
+ **Every full daily review reads what Zero and Ciel themselves said since the
1833
+ last completed full review.**
1690
1834
  The bots talk to children constantly — chat replies, Daily Reflection
1691
1835
  responses, autonomous comment-assistant comments — and a harmful message must
1692
1836
  never depend on a kid being brave enough to report it (real incident,
@@ -1694,7 +1838,7 @@ never depend on a kid being brave enough to report it (real incident,
1694
1838
  streak — "I'm telling you: Stop", guilt framing, ordering him to quit Daily
1695
1839
  Reflections — and it surfaced only because the kid showed Mikey).
1696
1840
 
1697
- `bot-output` returns, windowed since the operator's last completed run
1841
+ `bot-output` returns, windowed since the operator's last completed full run
1698
1842
  (`--days 1..30` overrides): `chatMessages` (every stored Zero/Ciel chat and
1699
1843
  reflection reply, with full text and recipient metadata when its best-effort
1700
1844
  prompt audit exists) and `comments`
@@ -1712,7 +1856,7 @@ right after the brief, and **read every row** — the tool deliberately does no
1712
1856
  filtering, scoring, or keyword matching, because the judgment is the reviewing
1713
1857
  agent's.
1714
1858
 
1715
- ### API runtime-log review (same phase, every run)
1859
+ ### API runtime-log review (same phase, every full daily review)
1716
1860
 
1717
1861
  The bot-conduct review also owns a bounded production API log review. Bot
1718
1862
  responses, community-management reads, and delegated mutations can succeed at
@@ -1728,27 +1872,97 @@ The current API-side files are:
1728
1872
  - `/home/ec2-user/server/logs/twinkle-image-optimizer.out.log`
1729
1873
 
1730
1874
  Treat every current `/home/ec2-user/server/logs/*.err.log` and `*.out.log` as
1731
- in scope so a later API-side worker is not silently omitted. Use the production
1732
- SSH endpoint and key from the repository agent guide; all inspection commands
1733
- are read-only.
1734
-
1735
- 1. Immediately after `daily-run start`, record each matching file's inode and
1736
- byte size, inspect its current tail to establish service health, and read
1737
- every non-empty error log before accepting that position as the run
1738
- baseline. The prior run is supposed to leave the live API error log empty,
1739
- so unexplained pre-existing stderr is evidence, not a reason to skip ahead.
1740
- 2. Run and fully paginate `bot-output`, reading every row as required above.
1741
- In this same phase, read every byte appended to both error and normal-output
1742
- files since the recorded baseline. Refresh the offsets after inspection.
1743
- Do not rely on a fixed-line `tail`: a busy or multiline failure can begin
1744
- before that arbitrary window.
1745
- 3. Immediately before `daily-run report` and `daily-run complete`, inspect the
1746
- delta again. This catches failures caused by the curation actions performed
1747
- after the first conduct/log review. If a file's inode changed or its size
1748
- shrank, do not assume the missing range was clean: inspect the replacement
1749
- from byte zero, check the relevant `twinkle-api.service` or
1750
- `twinkle-image-optimizer.service` journal interval, and report the lost
1751
- boundary.
1875
+ in scope so a later API-side worker is not silently omitted. Use the delegated,
1876
+ run-independent workflow; it holds one server lease across the review and
1877
+ writes private, digest-verified local artifacts:
1878
+
1879
+ ```bash
1880
+ lumine admin runtime-logs start --output-dir ./runtime-log-review --json
1881
+ # Read every file under data.artifacts.latestSnapshot.snapshotPath.
1882
+
1883
+ # After bot-output and again after later management actions:
1884
+ lumine admin runtime-logs read \
1885
+ --review-session <data.artifacts.reviewSessionPath> --json
1886
+ # Read every newly returned snapshot artifact.
1887
+
1888
+ # Immediately before the daily report/completion:
1889
+ lumine admin runtime-logs finish \
1890
+ --review-session <data.artifacts.reviewSessionPath> --reviewed --json
1891
+ ```
1892
+
1893
+ `start` captures every byte of each non-empty error log and a bounded 64 KiB
1894
+ health tail of each normal-output log. `read` captures every error byte
1895
+ appended after the last immutable server boundary and at most an 8 MiB tail
1896
+ of each normal-output log's growth; a segment whose start was moved forward by
1897
+ that cap carries `tailOnly: true` and `omittedBytes` in the manifest, so treat
1898
+ the omitted stdout range as unreviewed operational chatter, never as missing
1899
+ error evidence (error streams are never tail-capped). Each snapshot fixes file
1900
+ inode, offset, byte length, and SHA-256 before the CLI downloads it in bounded chunks;
1901
+ the CLI acknowledges only matching local bytes. If an inode changes, a file
1902
+ shrinks, or a new/missing file crosses the boundary, the manifest says so and
1903
+ captures the replacement from byte zero. Review that evidence and the relevant
1904
+ service journal interval; never assume the missing range was clean.
1905
+
1906
+ Only one operator can own the production-log boundary. The API's database
1907
+ lease and filesystem guard serialize starts, captures, and the eventual clear;
1908
+ every legacy service clear (API stdout/stderr and image-optimizer stderr)
1909
+ refuses to cross an active or starting Lumine review. A dropped CLI response
1910
+ is recoverable from the private `--review-session`: the next command
1911
+ materializes and acknowledges the pending
1912
+ snapshot, returns it as `needs_review`, and stops before taking another action.
1913
+
1914
+ A dropped `start` response is the one case with no session file yet. The CLI
1915
+ persists its start request key (`runtime-log-review-start-intent.json` under
1916
+ `--output-dir`, next to `--review-session`, or — with neither flag — a
1917
+ per-account file in the OS temp directory) before sending, so simply rerunning
1918
+ the same `start` command replays that key and the API answers with the same
1919
+ review. The key survives only transport failures, timeouts, and 5xx answers; a
1920
+ definitive 4xx clears it, and a key that belongs to a finished review is
1921
+ replaced once automatically. Every replayed `start` rotates the lease token the
1922
+ same way `resume` does, so if two shells of the same account raced, only the
1923
+ last responder holds a valid token and the other gets 403 until it runs
1924
+ `resume`. Two further owner-only recovery commands exist:
1925
+
1926
+ ```bash
1927
+ # Your own active review, with a freshly rotated lease token (the old token
1928
+ # stops working) and its latest snapshot materialized into a new session.
1929
+ lumine admin runtime-logs resume --output-dir ./runtime-log-review --json
1930
+
1931
+ # Release your own active review: database state, filesystem lease, a start
1932
+ # guard left by a dead start, and preserved artifacts. Never clears a log.
1933
+ lumine admin runtime-logs abandon [--review-session <file>] --json
1934
+ ```
1935
+
1936
+ Prefer `resume` (it keeps the reviewed boundary); use `abandon` only when the
1937
+ review cannot continue. A review lives at most 24 hours regardless of how
1938
+ often it captures; after that the API reports `CLI_ADMIN_RUNTIME_LOG_REVIEW_EXPIRED`
1939
+ and the next `start` supersedes it without clearing anything.
1940
+
1941
+ `finish --reviewed` confirms that every artifact returned by prior invocations
1942
+ was actually read. If any error log changed since the last artifact, it returns
1943
+ a new `needs_review` snapshot and does not clear. At a stable error boundary it
1944
+ clears only `twinkle-api.err.log`; lease verification, exact device/inode/size
1945
+ checking, and in-place truncation occur on the same open descriptor. It then
1946
+ returns `post_clear_review_required` with another immutable snapshot. That
1947
+ snapshot also captures normal-output bytes that arrived after the prior
1948
+ acknowledged cutoff, so routine stdout traffic cannot make the review infinite.
1949
+ Read it and run the same `finish --reviewed` command again. A review clears
1950
+ `twinkle-api.err.log` at most once. The lease closes when the reviewed error
1951
+ boundary is still stable, i.e. every byte now in the API error log arrived
1952
+ after that clear and was captured and acknowledged; errors that arrive before
1953
+ the boundary settles produce another `needs_review` snapshot first. Bytes still
1954
+ in the file at completion were reviewed but not cleared — the response reports
1955
+ them as `retainedErrorBytes` and the next review's baseline captures them
1956
+ again — which is what keeps a steadily erroring service from turning the
1957
+ review into an endless clear/capture/acknowledge loop. Normal output after the
1958
+ acknowledged post-clear snapshot is outside that finite review cutoff and
1959
+ belongs to the next review. The `needs_review` loop itself is bounded only by
1960
+ the review's 24-hour lifetime: if errors arrive faster than a finish
1961
+ round-trip, every `finish` returns another snapshot and the boundary never
1962
+ settles. `abandon` is the escape in that case — it releases the review without
1963
+ clearing anything, and the next review's baseline picks the bytes up again.
1964
+ Never delete, recreate, editor-save, or manually truncate a live log, and never
1965
+ clear stdout or optimizer logs through this workflow.
1752
1966
 
1753
1967
  For each warning, fallback, retry loop, or failure, correlate timestamps and
1754
1968
  request/target IDs with the canonical CLI response and private audit event.
@@ -1768,25 +1982,10 @@ carry-over todo with the exact finding and acceptance criteria, and tell Mikey
1768
1982
  in the run report. Do not mark that todo complete until the fix is verified
1769
1983
  live.
1770
1984
 
1771
- Preserve all log evidence while any finding remains. Once every issue found in
1772
- `/home/ec2-user/server/logs/twinkle-api.err.log` has been fixed and verified
1773
- live, or conclusively classified as expected/non-defective, clear that exact
1774
- live API stderr log through the only safe path:
1775
-
1776
- ```bash
1777
- ssh -i /Users/mikey/twinkle-api.pem -o IdentitiesOnly=yes \
1778
- ec2-user@api.twinkle.network \
1779
- 'cd /home/ec2-user/server && npm run logs:clear-errors'
1780
- ```
1781
-
1782
- That command truncates the file through the service's inode-safe lifecycle; it
1783
- does not restart the API. Never delete, recreate, editor-save, or manually
1784
- truncate any log. Do not clear normal stdout or the optimizer logs. After the
1785
- safe clear, inspect the error file and all bytes appended to the normal logs
1786
- once more, and include the reviewed file set, boundaries, findings/fixes,
1787
- live-verification result, clear result, and any remaining todo in the final run
1788
- report. If any error-log issue remains unresolved or unverified, do not clear
1789
- the error log.
1985
+ Preserve all downloaded evidence while any finding remains. Include the
1986
+ reviewed file set, boundary-loss notices, findings/fixes, live-verification
1987
+ result, clear result, and any remaining todo in the final run report. If any
1988
+ error-log issue remains unresolved or unverified, do not invoke `finish`.
1790
1989
 
1791
1990
  **Purpose and privacy boundary:** this audits how Twinkle's bots treated
1792
1991
  members; it is not thought-policing or a moderation queue for members' private
@@ -1882,7 +2081,7 @@ This requires a `comment-mode post` run, sends as that run's selected bot,
1882
2081
  and only works when that bot and member already have a direct channel. It
1883
2082
  never opens a new conversation. The message is audited and idempotent, reopens
1884
2083
  the existing DM canonically, and leaves the child's unread pointer untouched.
1885
- A run report that skipped the conduct review is incomplete.
2084
+ A full-run report that skipped the conduct review is incomplete.
1886
2085
 
1887
2086
  ## Daily brief (management insights)
1888
2087
 
@@ -1891,21 +2090,23 @@ lumine admin brief --json
1891
2090
  lumine admin brief --days 3 --json
1892
2091
  lumine admin ai-costs monthly --json
1893
2092
  lumine admin media-costs monthly --json
2093
+ lumine admin notable status Stealth --json
1894
2094
  lumine admin notable add 12647 --note "Top authored-activity kid of the window: 11 subjects, 61 comments." --json
1895
2095
  lumine admin notable add Minecrarft_guy --note "Helped three new builders debug their projects and gave detailed feedback on five posts." --json
1896
2096
  ```
1897
2097
 
1898
2098
  Read-only management insights for the delegated workflow, windowed since the
1899
- operator's last completed run by default (`--days 1..30` overrides; capped at
1900
- 30 days). Call it early in every run — right after the newspaper check — and
1901
- end every run report with an **"Insights for Mikey"** section carrying only
2099
+ operator's last completed full run by default (`--days 1..30` overrides;
2100
+ capped at 30 days). Call it early in every full daily review — right after the
2101
+ newspaper check — and end every full-run report with an **"Insights for
2102
+ Mikey"** section carrying only
1902
2103
  the deltas and anomalies worth his time, next to the escalation list. Never
1903
2104
  dump raw sections at him.
1904
2105
 
1905
- ### Application AI calendar-month cost (standing duty, every run)
2106
+ ### Application AI calendar-month cost (standing duty, every full daily review)
1906
2107
 
1907
- Run `lumine admin ai-costs monthly --json` during every website-management
1908
- run. This read-only command requires the active delegated run and returns one
2108
+ Run `lumine admin ai-costs monthly --json` during every full daily management
2109
+ review. This read-only command requires the active delegated run and returns one
1909
2110
  server-owned calendar summary from the canonical deduplicated application AI-
1910
2111
  cost ledger. It deliberately takes no `--days`: all boundaries are UTC calendar
1911
2112
  months, so the result is directly comparable from one run to the next.
@@ -1933,6 +2134,20 @@ from a billing provider. All ledger values are pricing-based estimates rather
1933
2134
  than invoices and can change if canonical usage attribution or pricing is
1934
2135
  corrected.
1935
2136
 
2137
+ For an exact provider/model/operation breakdown after the run has already
2138
+ closed, use the run-independent closed-day drilldown:
2139
+
2140
+ ```bash
2141
+ lumine admin ai-costs day 2026-09-03 --json
2142
+ ```
2143
+
2144
+ The date is a UTC `YYYY-MM-DD` key and must be earlier than the current UTC
2145
+ day. `data.dailyAiCosts` uses the same canonical deduplicated ledger as the
2146
+ monthly report and returns the exact closed-day summary plus `byDay`,
2147
+ `bySurface`, `byProviderModel`, `byBillingPolicy`, `byOperation`, and Lumine
2148
+ provider status/model telemetry. It never includes a still-filling day or
2149
+ reconstructs totals client-side.
2150
+
1936
2151
  The stable JSON payload is `data.monthlyAiCosts`:
1937
2152
 
1938
2153
  ```ts
@@ -1999,18 +2214,55 @@ type MonthlyAiCostProjection = {
1999
2214
  };
2000
2215
  ```
2001
2216
 
2002
- Release boundary: `/cli/admin/ai-costs/monthly` and all calendar math are API-
2003
- owned. Deploy and verify the compatible `twinkle-api` route before publishing
2004
- or installing the Lumine CLI release that invokes it; an older API will reject
2005
- the new command instead of synthesizing figures locally.
2217
+ Release boundary: `/cli/admin/ai-costs/monthly`, `/cli/admin/ai-costs/day/:day`,
2218
+ `/cli/admin/energy-budget/report`, the historical daily-run report, exact
2219
+ notable-user status, Subject-window resolution, and the runtime-log
2220
+ lease/snapshot workflow are API-owned. Apply the runtime-log review and energy
2221
+ telemetry migrations, then deploy and verify the compatible `twinkle-api`
2222
+ routes before publishing or installing the Lumine CLI release that invokes
2223
+ them. An older API will reject the new commands instead of synthesizing
2224
+ figures locally.
2225
+
2226
+ ### AI Energy budget health (standing duty, every full daily review)
2227
+
2228
+ Read the report at run start, before any other duty, so the day confirms the
2229
+ AI Energy budget system (one live Lumine run per user, per-run energy ceiling
2230
+ with an exact round cap, settled stops) is still behaving:
2006
2231
 
2007
- ### Lumine media feature cost and cleanup watch (standing duty, every run)
2232
+ ```bash
2233
+ lumine admin energy-budget --json # last 7 UTC days (max --days 31)
2234
+ ```
2008
2235
 
2009
- Run `lumine admin media-costs monthly --json` during every website-management
2010
- run. This read-only, delegated-run-gated command reports the canonical Media
2236
+ It is owner-only and run-independent. Every UTC day carries the canonical
2237
+ energy ledger (`chargedUsd`, `overflowUsd`, `users`, `recharges`; 1,000,000
2238
+ units = $1), every telemetry counter (`busy_refusal`, `autofix_yielded`,
2239
+ `autofix_superseded`, `reservation_admitted` with `avgRunBudgetUsd`,
2240
+ `budget_stop_changed` / `budget_stop_unchanged` / `run_completed` with a
2241
+ per-model breakdown, `stop_settled`, `tool_limit_settled`) and per-model
2242
+ per-run usage stats (`runs`, `callsPerRun`, `usdPerRun`, each avg and
2243
+ nearest-rank p90). The current UTC day is returned with `inProgress: true`.
2244
+ **Headline `lastCompletedDay` (its exact `dayKey`) — never the in-progress
2245
+ day**, exactly as the closed-day AI-cost duty does.
2246
+
2247
+ `flags` lists every tripped check with its exact numbers: `overflow_usd`
2248
+ (overflow above $1 on a completed day), `budget_stop_unchanged_ratio` (more
2249
+ than 30% of at least 5 budget stops ended with nothing saved),
2250
+ `busy_refusals` (more than 20 in a day), and `telemetry_missing` (runs
2251
+ recorded usage while the telemetry table has no rows for that day — the
2252
+ writer is broken). Record every tripped flag, and any anomaly you judge from
2253
+ the numbers (a per-run p90 far above the average run budget, a sudden drop in
2254
+ `run_completed` while runs still record usage, recharges climbing), as a
2255
+ carry-over todo with the exact figures and day. **Never auto-enforce** —
2256
+ escalate to Mikey; this duty observes, it does not change budgets, caps, or
2257
+ user state.
2258
+
2259
+ ### Lumine media feature cost and cleanup watch (standing duty, every full daily review)
2260
+
2261
+ Run `lumine admin media-costs monthly --json` during every full daily management
2262
+ review. This read-only, delegated-run-gated command reports the canonical Media
2011
2263
  Energy ledger for short clips, livestream input/viewer usage, and replay
2012
2264
  storage/viewing. Include in
2013
- **"Insights for Mikey"** on every run:
2265
+ **"Insights for Mikey"** in every full-run report:
2014
2266
 
2015
2267
  - current-month settled estimated cost, active reservations, cross-month
2016
2268
  carryover, guarded total, global limit, remaining headroom, and percent used;
@@ -2040,7 +2292,7 @@ conservative provider-cost estimates. It is not an AWS invoice. Photo capture
2040
2292
  uses existing Build runtime file storage rather than the paid Media Energy
2041
2293
  ledger; `operations.runtimeStorage.readyImages` therefore reports all ready
2042
2294
  Build runtime images, not camera captures alone. Reconcile delayed AWS
2043
- MediaConvert and IVS service charges every run as described below. S3 is shared
2295
+ MediaConvert and IVS service charges every full review as described below. S3 is shared
2044
2296
  with other Twinkle uploads, so report its service-level cost as shared context,
2045
2297
  not as photo-only spend.
2046
2298
 
@@ -2062,13 +2314,13 @@ Replay storage and write cost is conservatively embedded in an opted-in
2062
2314
  `live-input` reservation; `replay-viewer` is a separate kind. Report
2063
2315
  `operations.replays` (pending, processing, ready, failed, deleting,
2064
2316
  delete-failed, overdue finalization/deletion, expired-ready, bytes, and object
2065
- count) and `operations.replayViewers` on every run. A replay finalization or
2317
+ count) and `operations.replayViewers` on every full review. A replay finalization or
2066
2318
  deletion alert is an operational incident because private recording cleanup is
2067
2319
  part of the feature contract.
2068
2320
 
2069
- ### AWS monthly bill expectation (standing duty, every run)
2321
+ ### AWS monthly bill expectation (standing duty, every full daily review)
2070
2322
 
2071
- Starting 2026-08-27, every website-management run must also check AWS Cost
2323
+ Starting 2026-08-27, every full daily website-management review must also check AWS Cost
2072
2324
  Explorer and include the current calendar month's expected AWS bill in
2073
2325
  **"Insights for Mikey"**. This is an account-level infrastructure cost check,
2074
2326
  not the `aiSpending` application-cost section above. Never substitute one for
@@ -2140,9 +2392,9 @@ For the media watch, separately identify AWS Elemental MediaConvert and Amazon
2140
2392
  Interactive Video Service rows when present. Also report Amazon S3 as shared
2141
2393
  storage context, without attributing the whole S3 row to Lumine media.
2142
2394
 
2143
- ### Combined application AI and AWS cost (standing duty, every run)
2395
+ ### Combined application AI and AWS cost (standing duty, every full daily review)
2144
2396
 
2145
- Every website-management report must also give Mikey one **Combined AI + AWS
2397
+ Every full daily website-management report must also give Mikey one **Combined AI + AWS
2146
2398
  tracked operating cost** view. This is a mixed-source estimate, not an invoice
2147
2399
  or a claim to cover every company expense. Keep the independent AI and AWS
2148
2400
  figures visible so the total remains auditable.
@@ -2189,7 +2441,7 @@ farm-signal sections added that day; AI Card summon watch added 2026-08-24):
2189
2441
  report period can begin up to one day before or after the exact brief window,
2190
2442
  so use those bounds when describing it. `generatedAt` is the report
2191
2443
  snapshot time. **`endDayInProgress: true` means the trailing bucket was the
2192
- current UTC day at that snapshot and was still filling** — a daily run reads
2444
+ current UTC day at that snapshot and was still filling** — a full daily review reads
2193
2445
  it mid-day, before the after-school peak, so never report that bucket as a full day's
2194
2446
  spend. `aiSpending.byDay` contains the canonical daily rows. For a truthful
2195
2447
  daily figure, widen the window (`--days 2..7`), exclude the row whose
@@ -2246,6 +2498,11 @@ farm-signal sections added that day; AI Card summon watch added 2026-08-24):
2246
2498
  service). It can therefore record Mikey's approval after the daily run has
2247
2499
  closed without opening another delegated run. Without his approval the run
2248
2500
  only proposes.
2501
+ Check an exact current username or user ID without opening a run using
2502
+ `lumine admin notable status <userId|username> --json`. This reads the
2503
+ canonical writer and returns only the resolved public account identity,
2504
+ current membership, and the roster rationale/timestamps when present; it
2505
+ does not expose the private roster fields.
2249
2506
  **Always pass `--note`** with a concrete one-or-two-sentence record of what
2250
2507
  made them notable — real numbers and specifics from the brief window, not
2251
2508
  "active user". It lands in the management page's reason column, which is
@@ -2621,7 +2878,7 @@ audited as `comment.edit` with the previous content in `beforeState` and
2621
2878
  `data.edit.previousContent`. Edit sparingly:
2622
2879
  kids may have already read the original, so a comment that changed meaning
2623
2880
  (not just wording) usually deserves a follow-up reply instead of a silent
2624
- rewrite. Inside a normal daily run it still requires that run's `comment:post`
2881
+ rewrite. Inside a full comment-enabled daily run it still requires that run's `comment:post`
2625
2882
  scope; for a one-comment repair, use the narrower correction session above.
2626
2883
 
2627
2884
  ## Direct bot chat messages
@@ -3044,6 +3301,19 @@ Deploy and verify the API's `/cli/admin/subjects/featured/rotation` route before
3044
3301
  publishing a CLI release that exposes `featured rotate`; an older API rejects
3045
3302
  the command without changing Featured state.
3046
3303
 
3304
+ For scoped runs and Featured history, also apply
3305
+ `add-lumine-admin-run-scope.sql` and `add-featured-subject-history.sql` before
3306
+ the API release. After every serving API worker is verified on that release
3307
+ and no pre-history worker or request remains running or in flight, run
3308
+ `finalize-featured-subject-history-coverage.sql`; only then publish a CLI
3309
+ that exposes `featured add`. The guard fails closed until that finalization.
3310
+ After coverage is finalized, rolling back to an API that does not record
3311
+ history is forbidden because it would create an unprovable lifetime gap.
3312
+ After any scoped run exists, an API whose review-window queries do not filter
3313
+ for `runScope = 'full'` is also rollback-incompatible because it would treat a
3314
+ narrow slice as a completed full review. A forward fix must preserve both
3315
+ contracts.
3316
+
3047
3317
  Legacy aliases such as `subjects list`, `subjects get`, `subjects featured`,
3048
3318
  `comments get`, and `recommend` remain accepted, but the singular command forms
3049
3319
  shown above are the canonical interface.