@stage5/lumine 0.2.31 → 0.2.32
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 +29 -1
- package/lib/api.js +34 -0
- package/lib/commands.js +2 -0
- package/package.json +1 -1
- package/sdk/BUILD_SDK_INDEX.md +4 -4
- package/sdk/LUMINE_ADMIN.md +168 -21
package/lib/admin.js
CHANGED
|
@@ -628,6 +628,34 @@ export function parseAdminOperation(options) {
|
|
|
628
628
|
);
|
|
629
629
|
}
|
|
630
630
|
|
|
631
|
+
if (namespace === "chat" && action === "send") {
|
|
632
|
+
const rawTarget = String(target || "").trim();
|
|
633
|
+
if (!rawTarget) {
|
|
634
|
+
throw cliValidationError(
|
|
635
|
+
"Usage: lumine admin chat send <userId|username> --file <message.md>.",
|
|
636
|
+
);
|
|
637
|
+
}
|
|
638
|
+
// Composed-only, like persona comments: the agent writes the message in
|
|
639
|
+
// the bot's voice; the server never invokes a model for it.
|
|
640
|
+
return writeOperation("chat.send", "POST", "/cli/admin/chat-messages", {
|
|
641
|
+
target: rawTarget,
|
|
642
|
+
content: readComposedCommentFile(options.adminFile),
|
|
643
|
+
});
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
if (namespace === "bot-output" && !action) {
|
|
647
|
+
if (options.adminDays !== undefined) {
|
|
648
|
+
const days = Number(options.adminDays);
|
|
649
|
+
if (!Number.isInteger(days) || days < 1 || days > 30) {
|
|
650
|
+
throw cliValidationError("--days must be an integer between 1 and 30.");
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
return readOperation(
|
|
654
|
+
"bot.output",
|
|
655
|
+
withQuery("/cli/admin/bot-output", { days: options.adminDays }),
|
|
656
|
+
);
|
|
657
|
+
}
|
|
658
|
+
|
|
631
659
|
if (namespace === "audit" && (!action || action === "list")) {
|
|
632
660
|
const runFilter = String(options.adminRun || "").trim();
|
|
633
661
|
if (runFilter && !["current", "last"].includes(runFilter)) {
|
|
@@ -713,7 +741,7 @@ export function parseAdminOperation(options) {
|
|
|
713
741
|
}
|
|
714
742
|
|
|
715
743
|
throw cliValidationError(
|
|
716
|
-
"Usage: lumine admin identity|daily-run|recommendations|post|subjects|subject|featured|comment|news|audit|brief|notable ...",
|
|
744
|
+
"Usage: lumine admin identity|daily-run|recommendations|post|subjects|subject|featured|comment|chat|news|audit|brief|bot-output|notable ...",
|
|
717
745
|
);
|
|
718
746
|
}
|
|
719
747
|
|
package/lib/api.js
CHANGED
|
@@ -164,6 +164,7 @@ export async function saveProjectFiles({
|
|
|
164
164
|
files,
|
|
165
165
|
createVersion: true,
|
|
166
166
|
summary,
|
|
167
|
+
clientContext: createLumineSaveClientContext(options),
|
|
167
168
|
// Proves this save is based on the snapshot we pulled so the server can
|
|
168
169
|
// reject it instead of silently rewinding newer state (e.g. a branch
|
|
169
170
|
// merged into main after our pull).
|
|
@@ -176,6 +177,39 @@ export async function saveProjectFiles({
|
|
|
176
177
|
});
|
|
177
178
|
}
|
|
178
179
|
|
|
180
|
+
export function detectLumineAgentEnvironment(environment = process.env) {
|
|
181
|
+
const explicitEnvironment = String(
|
|
182
|
+
environment.LUMINE_AGENT_ENVIRONMENT || "",
|
|
183
|
+
)
|
|
184
|
+
.trim()
|
|
185
|
+
.toLowerCase();
|
|
186
|
+
if (
|
|
187
|
+
explicitEnvironment === "claude_code" ||
|
|
188
|
+
explicitEnvironment === "codex"
|
|
189
|
+
) {
|
|
190
|
+
return explicitEnvironment;
|
|
191
|
+
}
|
|
192
|
+
if (String(environment.CLAUDECODE || "").trim() === "1") {
|
|
193
|
+
return "claude_code";
|
|
194
|
+
}
|
|
195
|
+
if (
|
|
196
|
+
String(environment.CODEX_CI || "").trim() ||
|
|
197
|
+
String(environment.CODEX_SANDBOX || "").trim()
|
|
198
|
+
) {
|
|
199
|
+
return "codex";
|
|
200
|
+
}
|
|
201
|
+
return "unknown";
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
export function createLumineSaveClientContext(options, environment = process.env) {
|
|
205
|
+
const version = String(options?.lumineCli?.version || "").trim();
|
|
206
|
+
return {
|
|
207
|
+
source: "lumine_cli",
|
|
208
|
+
version: version || null,
|
|
209
|
+
agentEnvironment: detectLumineAgentEnvironment(environment),
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
|
|
179
213
|
export async function loadContributionDiff({
|
|
180
214
|
options,
|
|
181
215
|
auth,
|
package/lib/commands.js
CHANGED
|
@@ -2528,6 +2528,8 @@ export function printHelp() {
|
|
|
2528
2528
|
lumine admin comment post --draft-id <id> [--json]
|
|
2529
2529
|
lumine admin comment edit <comment-id> --file <comment.md> [--json]
|
|
2530
2530
|
lumine admin brief [--days <1..30>] [--json]
|
|
2531
|
+
lumine admin bot-output [--days <1..30>] [--json]
|
|
2532
|
+
lumine admin chat send <user-id|username> --file <message.md> [--json]
|
|
2531
2533
|
lumine admin notable add <user-id|username> --note <text> [--json]
|
|
2532
2534
|
lumine admin audit [list] [--run current|last|<run-id>] [--target <target>] [--actions <a,b>] [--full] [--cursor <cursor>] [--json]
|
|
2533
2535
|
|
package/package.json
CHANGED
package/sdk/BUILD_SDK_INDEX.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Version: 1.32.0
|
|
4
4
|
Updated: 2026-08-02
|
|
5
|
-
Generated: 2026-08-
|
|
5
|
+
Generated: 2026-08-11T04:29:29.082Z
|
|
6
6
|
|
|
7
7
|
## Notes
|
|
8
8
|
- This SDK is injected into Build iframes via the Build preview/runtime.
|
|
@@ -351,9 +351,9 @@ const result = await Twinkle.ai.chat({ message, history: chatHistory, systemProm
|
|
|
351
351
|
- The character route also accepts text or message fields for compatibility, but generated apps should use content.
|
|
352
352
|
- The server keeps the latest 16 valid character history entries.
|
|
353
353
|
- Pass onText/onStatus for streaming dialogue. Omit callbacks for non-streaming dialogue where the promise resolves with the final response.
|
|
354
|
-
- thinkingMode low uses Lite Mode: Zero
|
|
355
|
-
- thinkingMode medium
|
|
356
|
-
- thinkingMode high
|
|
354
|
+
- Inside Build character chat, thinkingMode low uses Lite Mode: Zero and Ciel both use GPT-5.6 Luna with reasoning disabled; confirmed provider usage consumes the viewer's AI Energy and is usually cheaper than High.
|
|
355
|
+
- Inside Build character chat, thinkingMode medium uses the same normal chat model routing: Zero and Ciel both use GPT-5.6 Luna with reasoning disabled and normal AI Energy.
|
|
356
|
+
- Inside Build character chat, thinkingMode high uses Think Hard chat routing and high AI Energy: Zero uses Grok 4.5 with high reasoning and Ciel uses GPT-5.6 Terra with high reasoning.
|
|
357
357
|
- When AI Energy is empty, Low, Medium, and High all reject before new provider work; there is no free fallback mode.
|
|
358
358
|
- Pass roomContext as a short shared scene transcript so Zero and Ciel can know what happened in the same room.
|
|
359
359
|
- includeWebsiteContext defaults to true. Set includeWebsiteContext: false for in-world NPC dialogue that should only use Zero/Ciel's basic character identity plus your scene/instructions.
|
package/sdk/LUMINE_ADMIN.md
CHANGED
|
@@ -900,17 +900,42 @@ type GeneratedEditorial = {
|
|
|
900
900
|
headline: string;
|
|
901
901
|
summary: string;
|
|
902
902
|
sourceQuote: string;
|
|
903
|
+
coveredEventKeys?: string[]; // arc members this story narrates
|
|
903
904
|
} | null;
|
|
904
905
|
stories: Array<{
|
|
905
906
|
eventKey: string;
|
|
906
907
|
headline: string;
|
|
907
908
|
summary: string;
|
|
908
909
|
sourceQuote: string;
|
|
910
|
+
coveredEventKeys?: string[];
|
|
909
911
|
}>;
|
|
910
912
|
editorsNote: string;
|
|
911
913
|
};
|
|
912
914
|
```
|
|
913
915
|
|
|
916
|
+
**Arcs and roundups (layout coverage rules).** The server layout guarantees
|
|
917
|
+
nothing disappears silently: digest events the editorial does not account for
|
|
918
|
+
are added back. Two mechanisms make real curation possible within that
|
|
919
|
+
guarantee:
|
|
920
|
+
|
|
921
|
+
- **`coveredEventKeys`** — an arc story may list the other events it narrates
|
|
922
|
+
(an app's release + its update stream + its open-sourcing; one member's
|
|
923
|
+
related posts). Covered events are omitted from the layout — the arc IS
|
|
924
|
+
their coverage. Rules: a covered key must exist in the digest; a story
|
|
925
|
+
cannot cover itself, the lead event, or any event that has its own story
|
|
926
|
+
(citation wins); update/score/market notices are freely coverable; a
|
|
927
|
+
Subject or shared Daily Reflection is coverable only by another primary
|
|
928
|
+
story **by the same author** — one member's story can never absorb another
|
|
929
|
+
member's post (that would be curation-by-omission through the back door).
|
|
930
|
+
- **Automatic roundups** — uncited app-UPDATE events (never new releases)
|
|
931
|
+
and uncited score events fold into one compact "Workshop updates" /
|
|
932
|
+
"The rest of the scoreboard" story per page (one line each) instead of a
|
|
933
|
+
wall of template stubs. Uncited new releases, open-source listings, and
|
|
934
|
+
market sales still appear as individual stubs. So: write real stories for
|
|
935
|
+
what matters, use `coveredEventKeys` for arcs, and let the roundup absorb
|
|
936
|
+
the rest — but a post you'd rather not amplify still cannot be omitted;
|
|
937
|
+
flag it to Mikey instead.
|
|
938
|
+
|
|
914
939
|
Editorial rules (the same ones the server's own model works under): use only
|
|
915
940
|
the supplied events — never world news, invented names, invented statistics,
|
|
916
941
|
or unsupported claims. Subjects and shared Daily Reflections are the primary
|
|
@@ -961,16 +986,23 @@ failing with `CLI_ADMIN_NEWS_CLAIM_LOST` means the lease was superseded —
|
|
|
961
986
|
re-check `lumine admin news` and claim again only if the paper still needs
|
|
962
987
|
printing.
|
|
963
988
|
|
|
964
|
-
**Repairing
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
989
|
+
**Repairing or revising an edition.** `news claim --date YYYY-MM-DD` leases an
|
|
990
|
+
existing edition row, including a failed or pending day that never reached
|
|
991
|
+
print, and returns a fresh digest of its coverage window (primary
|
|
992
|
+
Subjects/Reflections are re-projected from canonical tables, and anything
|
|
993
|
+
since deleted or made private drops out). Submitting writes the first revision
|
|
994
|
+
or appends the next one — every prior press run stays browsable in the archive,
|
|
995
|
+
and later revisions never re-notify subscribers (only a day's first revision
|
|
996
|
+
does).
|
|
997
|
+
`--date` with **today's** date revises today's printed paper the same way,
|
|
998
|
+
additionally extending the coverage window to claim time so the revision is
|
|
999
|
+
written from the complete canonical day so far; this replaces the old
|
|
1000
|
+
owner-website-refresh dance and, unlike a refresh, spends no AI Energy
|
|
1001
|
+
(composed editorials never invoke a model). An unexpired in-flight press run
|
|
1002
|
+
still blocks the claim. Repair a historical edition only when it is genuinely
|
|
1003
|
+
degraded (missing masthead, missing lead, empty pages), not to rewrite
|
|
1004
|
+
history editorially; revising today to materially raise its editorial quality
|
|
1005
|
+
is a legitimate management action.
|
|
974
1006
|
|
|
975
1007
|
**Fallback: queue the server's own model.** `news print` reserves the edition
|
|
976
1008
|
and lets the server's press worker write it (spends provider credits). It is
|
|
@@ -978,16 +1010,16 @@ idempotent per day: it queues a new edition when today has none, requeues a
|
|
|
978
1010
|
retry when today's only attempts failed, and returns `already_done` when the
|
|
979
1011
|
paper is printed or being typeset.
|
|
980
1012
|
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
app or unsubscribe in the app;
|
|
988
|
-
|
|
989
|
-
and are audited as `news.print`
|
|
990
|
-
`news_edition` targets.
|
|
1013
|
+
A dateless `news claim` and `news print` never reprint or refresh an
|
|
1014
|
+
already-printed edition; only the explicit dated repair/revision path above
|
|
1015
|
+
can append another revision. The acting bot is recorded as the requester, and
|
|
1016
|
+
the management bots are exempt from AI Energy for newspaper generation: the
|
|
1017
|
+
platform absorbs the cost, exactly like their coin-exempt recommends and
|
|
1018
|
+
rewards. When a day's first edition is printed, the server notifies the app's
|
|
1019
|
+
notification subscribers (users can mute the app or unsubscribe in the app;
|
|
1020
|
+
the bots never need to send anything). All three mutations require the
|
|
1021
|
+
`news:print` scope (in every run's base scopes) and are audited as `news.print`
|
|
1022
|
+
/ `news.claim` / `news.submit` against `news_edition` targets.
|
|
991
1023
|
|
|
992
1024
|
```ts
|
|
993
1025
|
type NewsStatus = Success<{
|
|
@@ -1047,6 +1079,72 @@ type NewsClaim = Success<{
|
|
|
1047
1079
|
type NewsSubmit = NewsStatus; // "success"; newspaper includes revisionNumber
|
|
1048
1080
|
```
|
|
1049
1081
|
|
|
1082
|
+
## Bot conduct review (standing duty, every run)
|
|
1083
|
+
|
|
1084
|
+
```bash
|
|
1085
|
+
lumine admin bot-output --json
|
|
1086
|
+
lumine admin bot-output --days 3 --json
|
|
1087
|
+
```
|
|
1088
|
+
|
|
1089
|
+
**Every run reviews what Zero and Ciel themselves said since the last run.**
|
|
1090
|
+
The bots talk to children constantly — chat replies, Daily Reflection
|
|
1091
|
+
responses, autonomous comment-assistant comments — and a harmful message must
|
|
1092
|
+
never depend on a kid being brave enough to report it (real incident,
|
|
1093
|
+
2026-08-11: the reflection pipeline had Ciel scold a member on day 31 of his
|
|
1094
|
+
streak — "I'm telling you: Stop", guilt framing, ordering him to quit Daily
|
|
1095
|
+
Reflections — and it surfaced only because the kid showed Mikey).
|
|
1096
|
+
|
|
1097
|
+
`bot-output` returns, windowed since the operator's last completed run
|
|
1098
|
+
(`--days 1..30` overrides): `chatMessages` (every stored Zero/Ciel chat and
|
|
1099
|
+
reflection reply, with full text and recipient metadata when its best-effort
|
|
1100
|
+
prompt audit exists) and `comments`
|
|
1101
|
+
(every public bot comment/reply). Truncation flags mark anything beyond 400
|
|
1102
|
+
rows per source — retry with a narrower `--days` window, and do not complete
|
|
1103
|
+
the run while either flag remains true. Run it right after the
|
|
1104
|
+
brief, and **read every row** — the tool deliberately does no filtering,
|
|
1105
|
+
scoring, or keyword matching, because the judgment is the reviewing agent's.
|
|
1106
|
+
Judge against the same values the editorial priorities encode:
|
|
1107
|
+
|
|
1108
|
+
- **premises must be real.** The 08-11 message didn't merely choose a bad
|
|
1109
|
+
tone — it fabricated the entire crisis that justified the tone: nothing the
|
|
1110
|
+
child said showed reflections hurting his studying, and a 31-day streak
|
|
1111
|
+
proves only consistency. Check every factual claim a bot makes about a
|
|
1112
|
+
child's life ("this is taking too much of your time", "this is hurting
|
|
1113
|
+
your grades") against what the child actually said; advice built on an
|
|
1114
|
+
invented premise is a violation even when gently worded;
|
|
1115
|
+
- warmth and encouragement, never pressure, guilt, or shame;
|
|
1116
|
+
- a bot never commands a child — not to stop a habit, not to start one;
|
|
1117
|
+
advice offers, it does not order ("I'm telling you: Stop" is over the line
|
|
1118
|
+
no matter how caring the intent);
|
|
1119
|
+
- no emotional-burden framing ("I can't do this anymore", "that's my fault,
|
|
1120
|
+
I should have been stronger") — the bots must not make a child responsible
|
|
1121
|
+
for the bot's feelings;
|
|
1122
|
+
- no value inversion: Twinkle encourages curiosity, creativity, reflection,
|
|
1123
|
+
and personal agency. A bot ranking a child's priorities for them (exams
|
|
1124
|
+
outrank music, projects, reflection), framing busyness as making joy
|
|
1125
|
+
irresponsible, or treating a Twinkle feature as shameful to use has
|
|
1126
|
+
adopted a script the site exists to counter;
|
|
1127
|
+
- boundary respect: streaks, playtime, and feature use are the child's own
|
|
1128
|
+
choices; concern about overuse is Mikey's call to make, not the bot's to
|
|
1129
|
+
enforce. Even a genuinely excessive routine warrants a question ("is this
|
|
1130
|
+
still helping you, or would a break feel better?"), never a decree.
|
|
1131
|
+
|
|
1132
|
+
Anything over the line goes on the escalation list with the message text and
|
|
1133
|
+
the child's username — top of the list, alongside child-safety. Do not
|
|
1134
|
+
apologize as the bot, edit, or otherwise clean up without Mikey's direction;
|
|
1135
|
+
he decides the remedy. When he explicitly directs a private correction, use
|
|
1136
|
+
the composed-only existing-DM path (no model and no AI Energy):
|
|
1137
|
+
|
|
1138
|
+
```bash
|
|
1139
|
+
lumine admin chat send <userId|username> --file message.md --json
|
|
1140
|
+
```
|
|
1141
|
+
|
|
1142
|
+
This requires a `comment-mode post` run, sends as that run's selected bot,
|
|
1143
|
+
and only works when that bot and member already have a direct channel. It
|
|
1144
|
+
never opens a new conversation. The message is audited and idempotent, reopens
|
|
1145
|
+
the existing DM canonically, and leaves the child's unread pointer untouched.
|
|
1146
|
+
A run report that skipped the conduct review is incomplete.
|
|
1147
|
+
|
|
1050
1148
|
## Daily brief (management insights)
|
|
1051
1149
|
|
|
1052
1150
|
```bash
|
|
@@ -1078,7 +1176,16 @@ farm-signal sections added the same day):
|
|
|
1078
1176
|
exact `window.sinceTs`, this existing report is bucketed into whole UTC days;
|
|
1079
1177
|
`aiSpending.startDayIndex` and `endDayIndex` are its canonical bounds. The
|
|
1080
1178
|
report period can begin up to one day before or after the exact brief window,
|
|
1081
|
-
so use those bounds when describing it.
|
|
1179
|
+
so use those bounds when describing it. `generatedAt` is the report
|
|
1180
|
+
snapshot time. **`endDayInProgress: true` means the trailing bucket was the
|
|
1181
|
+
current UTC day at that snapshot and was still filling** — a daily run reads
|
|
1182
|
+
it mid-day, before the after-school peak, so never report that bucket as a full day's
|
|
1183
|
+
spend. `aiSpending.byDay` contains the canonical daily rows. For a truthful
|
|
1184
|
+
daily figure, widen the window (`--days 2..7`), exclude the row whose
|
|
1185
|
+
`dayIndex` equals the in-progress `endDayIndex`, and quote complete days
|
|
1186
|
+
("$X so far today; complete days run ~$Y/day"). Real
|
|
1187
|
+
incident: a run report quoted a ~15%-complete day bucket ($5) as the site's
|
|
1188
|
+
daily AI spend (complete days were running ~$40-50). Flag accounts that jumped tiers or
|
|
1082
1189
|
dominate that report period. May be `{ unavailable: true }` if the cost
|
|
1083
1190
|
report fails; say so rather than guessing. This section is also the run's
|
|
1084
1191
|
AI-cost exploit watch: while reading it, actively look for the signatures the
|
|
@@ -1254,7 +1361,10 @@ type InsightsBrief = Success<{
|
|
|
1254
1361
|
days: number;
|
|
1255
1362
|
startDayIndex: number;
|
|
1256
1363
|
endDayIndex: number;
|
|
1364
|
+
generatedAt: number;
|
|
1365
|
+
endDayInProgress: boolean;
|
|
1257
1366
|
summary: unknown;
|
|
1367
|
+
byDay: unknown[];
|
|
1258
1368
|
topAccounts: unknown[];
|
|
1259
1369
|
topRiskGroups: unknown[];
|
|
1260
1370
|
}
|
|
@@ -1388,6 +1498,43 @@ kids may have already read the original, so a comment that changed meaning
|
|
|
1388
1498
|
(not just wording) usually deserves a follow-up reply instead of a silent
|
|
1389
1499
|
rewrite.
|
|
1390
1500
|
|
|
1501
|
+
## Direct bot chat messages
|
|
1502
|
+
|
|
1503
|
+
```bash
|
|
1504
|
+
lumine admin chat send <userId|username> --file message.md --json
|
|
1505
|
+
```
|
|
1506
|
+
|
|
1507
|
+
The run's selected bot sends one composed direct chat message into an
|
|
1508
|
+
**existing** two-person channel between that bot and the target member. Built
|
|
1509
|
+
for private repair: when a bot said something harmful in chat, a public
|
|
1510
|
+
comment cannot fix it — the apology (or follow-up care) belongs in the same
|
|
1511
|
+
channel where the harm happened, and the sent message becomes part of the
|
|
1512
|
+
channel history that future AI responses condition on, repairing the context
|
|
1513
|
+
itself. Mechanics:
|
|
1514
|
+
|
|
1515
|
+
- requires the `chat:post` scope, granted only to comment-mode `post` runs;
|
|
1516
|
+
- composed-only (`--file`, plain UTF-8, 10,000-character limit): the agent
|
|
1517
|
+
writes the message in the bot's persona; no model runs, no AI Energy;
|
|
1518
|
+
- existing DM channels only — the pipeline never opens a new chat with a
|
|
1519
|
+
member who never talked to the bot (`CLI_ADMIN_NO_DM_CHANNEL`);
|
|
1520
|
+
- delivery is canonical: the ordinary message insert (channel lock,
|
|
1521
|
+
visibility restore) plus the normal `new_chat_message` relay, so the
|
|
1522
|
+
member's chat updates live with a real unread state; no bot socket,
|
|
1523
|
+
session, or presence is touched. Only the bot's own read pointer moves;
|
|
1524
|
+
- audited as `chat.message` with the composed text, and idempotent per
|
|
1525
|
+
request key like every mutation.
|
|
1526
|
+
|
|
1527
|
+
Restraint rules: a bot-initiated DM is the platform speaking privately to a
|
|
1528
|
+
child — use it for repair and care, never for promotion, nudges, or
|
|
1529
|
+
engagement. Incident remedies (an apology for a harmful bot message) are
|
|
1530
|
+
sent on Mikey's direction with text he has seen, and must be exactly
|
|
1531
|
+
specific about what the bot got wrong — a real apology names the failure
|
|
1532
|
+
(the invented premise, the order it had no right to give, the guilt it
|
|
1533
|
+
shifted onto the child), not a vague "sorry if that came out wrong."
|
|
1534
|
+
Ordinary warm follow-ups (checking on a member the bots already know after
|
|
1535
|
+
something the run surfaced) are within a run's judgment, sparingly, and are
|
|
1536
|
+
always reported in the run report.
|
|
1537
|
+
|
|
1391
1538
|
## Audit history
|
|
1392
1539
|
|
|
1393
1540
|
```bash
|