scientify 1.13.6 → 2.0.0
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.en.md +350 -0
- package/README.md +148 -358
- package/dist/index.d.ts +8 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +131 -122
- package/dist/index.js.map +1 -1
- package/dist/src/cli/research.d.ts +1 -6
- package/dist/src/cli/research.d.ts.map +1 -1
- package/dist/src/cli/research.js +227 -123
- package/dist/src/cli/research.js.map +1 -1
- package/dist/src/commands/metabolism-status.d.ts +3 -3
- package/dist/src/commands/metabolism-status.d.ts.map +1 -1
- package/dist/src/commands/metabolism-status.js +72 -75
- package/dist/src/commands/metabolism-status.js.map +1 -1
- package/dist/src/commands.d.ts +1 -1
- package/dist/src/commands.d.ts.map +1 -1
- package/dist/src/commands.js +0 -55
- package/dist/src/commands.js.map +1 -1
- package/dist/src/hooks/cron-skill-inject.d.ts +6 -7
- package/dist/src/hooks/cron-skill-inject.d.ts.map +1 -1
- package/dist/src/hooks/cron-skill-inject.js +6 -15
- package/dist/src/hooks/cron-skill-inject.js.map +1 -1
- package/dist/src/hooks/research-mode.d.ts +1 -1
- package/dist/src/hooks/research-mode.d.ts.map +1 -1
- package/dist/src/hooks/research-mode.js +24 -101
- package/dist/src/hooks/research-mode.js.map +1 -1
- package/dist/src/hooks/scientify-signature.d.ts +1 -1
- package/dist/src/hooks/scientify-signature.d.ts.map +1 -1
- package/dist/src/hooks/scientify-signature.js +2 -5
- package/dist/src/hooks/scientify-signature.js.map +1 -1
- package/dist/src/knowledge-state/render.d.ts +1 -9
- package/dist/src/knowledge-state/render.d.ts.map +1 -1
- package/dist/src/knowledge-state/render.js +33 -187
- package/dist/src/knowledge-state/render.js.map +1 -1
- package/dist/src/knowledge-state/store.d.ts.map +1 -1
- package/dist/src/knowledge-state/store.js +65 -1100
- package/dist/src/knowledge-state/store.js.map +1 -1
- package/dist/src/knowledge-state/types.d.ts +0 -76
- package/dist/src/knowledge-state/types.d.ts.map +1 -1
- package/dist/src/literature/subscription-state.d.ts +0 -2
- package/dist/src/literature/subscription-state.d.ts.map +1 -1
- package/dist/src/literature/subscription-state.js +7 -1375
- package/dist/src/literature/subscription-state.js.map +1 -1
- package/dist/src/research-subscriptions/constants.d.ts +1 -1
- package/dist/src/research-subscriptions/constants.js +1 -1
- package/dist/src/research-subscriptions/cron-client.d.ts +1 -1
- package/dist/src/research-subscriptions/cron-client.d.ts.map +1 -1
- package/dist/src/research-subscriptions/delivery.d.ts +1 -1
- package/dist/src/research-subscriptions/delivery.d.ts.map +1 -1
- package/dist/src/research-subscriptions/handlers.d.ts +1 -1
- package/dist/src/research-subscriptions/handlers.d.ts.map +1 -1
- package/dist/src/research-subscriptions/handlers.js +10 -20
- package/dist/src/research-subscriptions/handlers.js.map +1 -1
- package/dist/src/research-subscriptions/parse.d.ts.map +1 -1
- package/dist/src/research-subscriptions/parse.js +0 -25
- package/dist/src/research-subscriptions/parse.js.map +1 -1
- package/dist/src/research-subscriptions/prompt.d.ts +1 -1
- package/dist/src/research-subscriptions/prompt.d.ts.map +1 -1
- package/dist/src/research-subscriptions/prompt.js +195 -244
- package/dist/src/research-subscriptions/prompt.js.map +1 -1
- package/dist/src/research-subscriptions/types.d.ts +1 -3
- package/dist/src/research-subscriptions/types.d.ts.map +1 -1
- package/dist/src/templates/bootstrap.d.ts.map +1 -1
- package/dist/src/templates/bootstrap.js +32 -19
- package/dist/src/templates/bootstrap.js.map +1 -1
- package/dist/src/tools/arxiv-download.d.ts +1 -2
- package/dist/src/tools/arxiv-download.d.ts.map +1 -1
- package/dist/src/tools/arxiv-search.d.ts +1 -2
- package/dist/src/tools/arxiv-search.d.ts.map +1 -1
- package/dist/src/tools/github-search-tool.d.ts +1 -2
- package/dist/src/tools/github-search-tool.d.ts.map +1 -1
- package/dist/src/tools/openalex-search.d.ts +1 -2
- package/dist/src/tools/openalex-search.d.ts.map +1 -1
- package/dist/src/tools/openreview-lookup.d.ts +1 -2
- package/dist/src/tools/openreview-lookup.d.ts.map +1 -1
- package/dist/src/tools/paper-browser.d.ts +1 -2
- package/dist/src/tools/paper-browser.d.ts.map +1 -1
- package/dist/src/tools/result.d.ts +3 -5
- package/dist/src/tools/result.d.ts.map +1 -1
- package/dist/src/tools/result.js +5 -7
- package/dist/src/tools/result.js.map +1 -1
- package/dist/src/tools/scientify-cron.d.ts +4 -11
- package/dist/src/tools/scientify-cron.d.ts.map +1 -1
- package/dist/src/tools/scientify-cron.js +19 -524
- package/dist/src/tools/scientify-cron.js.map +1 -1
- package/dist/src/tools/scientify-literature-state.d.ts +1 -76
- package/dist/src/tools/scientify-literature-state.d.ts.map +1 -1
- package/dist/src/tools/scientify-literature-state.js +46 -363
- package/dist/src/tools/scientify-literature-state.js.map +1 -1
- package/dist/src/tools/unpaywall-download.d.ts +1 -2
- package/dist/src/tools/unpaywall-download.d.ts.map +1 -1
- package/dist/src/types.d.ts +16 -0
- package/dist/src/types.d.ts.map +1 -0
- package/dist/src/types.js +2 -0
- package/dist/src/types.js.map +1 -0
- package/openclaw.plugin.json +4 -2
- package/package.json +1 -1
- package/skills/metabolism/SKILL.md +2 -0
- package/skills/research-subscription/SKILL.md +1 -29
- package/README.zh.md +0 -494
|
@@ -2,53 +2,20 @@ import { createHash } from "node:crypto";
|
|
|
2
2
|
import { existsSync } from "node:fs";
|
|
3
3
|
import { appendFile, mkdir, readFile, rename, unlink, writeFile } from "node:fs/promises";
|
|
4
4
|
import path from "node:path";
|
|
5
|
-
import { dayKeyFromTimestamp, renderDailyChangesMarkdown, renderExplorationLogMarkdown, renderHypothesisMarkdown, renderIngestLogMarkdown, renderKnowledgeIndexMarkdown, renderPaperNoteHeaderMarkdown, renderPaperNoteRunMarkdown,
|
|
5
|
+
import { dayKeyFromTimestamp, renderDailyChangesMarkdown, renderExplorationLogMarkdown, renderHypothesisMarkdown, renderIngestLogMarkdown, renderKnowledgeIndexMarkdown, renderPaperNoteHeaderMarkdown, renderPaperNoteRunMarkdown, renderTopicUpdateMarkdown, slugifyTopic, } from "./render.js";
|
|
6
6
|
import { resolveProjectContext } from "./project.js";
|
|
7
7
|
const STATE_VERSION = 1;
|
|
8
8
|
const MAX_RECENT_RUN_IDS = 200;
|
|
9
9
|
const MAX_RECENT_HYPOTHESES = 50;
|
|
10
10
|
const MAX_RECENT_CHANGE_STATS = 30;
|
|
11
11
|
const MAX_LAST_TRACE = 20;
|
|
12
|
-
const MAX_LAST_REFLECTION_TASKS = 20;
|
|
13
12
|
const MAX_RECENT_PAPERS = 50;
|
|
14
13
|
const MAX_PAPER_NOTES = 800;
|
|
15
|
-
const MAX_HYPOTHESIS_REJECTION_REASONS = 24;
|
|
16
14
|
const MIN_CORE_FULLTEXT_COVERAGE = 0.8;
|
|
17
15
|
const MIN_EVIDENCE_BINDING_RATE = 0.9;
|
|
18
16
|
const MAX_CITATION_ERROR_RATE = 0.02;
|
|
19
|
-
const FATAL_CITATION_ERROR_RATE = 0.2;
|
|
20
|
-
const MIN_FULLTEXT_PROFILE_COMPLETENESS = 0.55;
|
|
21
|
-
const MIN_HYPOTHESIS_EVIDENCE = 2;
|
|
22
|
-
const MIN_HYPOTHESIS_DEPENDENCY_STEPS = 2;
|
|
23
|
-
const MIN_HYPOTHESIS_STATEMENT_CHARS = 48;
|
|
24
|
-
const MIN_HYPOTHESIS_STRENGTHS = 2;
|
|
25
|
-
const MIN_HYPOTHESIS_WEAKNESSES = 2;
|
|
26
|
-
const MIN_HYPOTHESIS_PLAN_STEPS = 3;
|
|
27
|
-
const MIN_HYPOTHESIS_PREDICTIONS = 2;
|
|
28
|
-
const MIN_HYPOTHESIS_ASSUMPTIONS = 2;
|
|
29
|
-
const MIN_HYPOTHESIS_FAILURE_MODES = 1;
|
|
30
|
-
const MIN_HYPOTHESIS_SUCCESS_CRITERIA = 2;
|
|
31
|
-
const MIN_HYPOTHESIS_STRICT_ACCEPT_SCORE = 70;
|
|
32
|
-
const MIN_HYPOTHESIS_ACCEPT_SELF_SCORE_AVG = 3.2;
|
|
33
|
-
const PLACEHOLDER_TEXT_RE = /^(?:n\/a|na|none|not provided|not available|unknown|tbd|todo|null|nil|未提供|暂无|未知|无)$/iu;
|
|
34
|
-
function defaultRunProfile() {
|
|
35
|
-
return "strict";
|
|
36
|
-
}
|
|
37
|
-
function defaultTriggerState(nowMs = Date.now()) {
|
|
38
|
-
return {
|
|
39
|
-
consecutiveNewReviseDays: 0,
|
|
40
|
-
bridgeCount7d: 0,
|
|
41
|
-
unreadCoreBacklog: 0,
|
|
42
|
-
lastUpdatedAtMs: nowMs,
|
|
43
|
-
};
|
|
44
|
-
}
|
|
45
17
|
function defaultQualityGateState() {
|
|
46
18
|
return {
|
|
47
|
-
mode: "soft",
|
|
48
|
-
severity: "warn",
|
|
49
|
-
warnings: ["quality gate not evaluated"],
|
|
50
|
-
fatalReasons: [],
|
|
51
|
-
blocking: false,
|
|
52
19
|
passed: false,
|
|
53
20
|
fullTextCoveragePct: 0,
|
|
54
21
|
evidenceBindingRatePct: 0,
|
|
@@ -56,26 +23,9 @@ function defaultQualityGateState() {
|
|
|
56
23
|
reasons: ["quality gate not evaluated"],
|
|
57
24
|
};
|
|
58
25
|
}
|
|
59
|
-
function defaultHypothesisGateState() {
|
|
60
|
-
return {
|
|
61
|
-
accepted: 0,
|
|
62
|
-
rejected: 0,
|
|
63
|
-
rejectionReasons: [],
|
|
64
|
-
};
|
|
65
|
-
}
|
|
66
26
|
function normalizeText(raw) {
|
|
67
27
|
return raw.trim().replace(/\s+/g, " ");
|
|
68
28
|
}
|
|
69
|
-
function cleanOptionalText(raw) {
|
|
70
|
-
if (typeof raw !== "string")
|
|
71
|
-
return undefined;
|
|
72
|
-
const normalized = normalizeText(raw);
|
|
73
|
-
if (!normalized)
|
|
74
|
-
return undefined;
|
|
75
|
-
if (PLACEHOLDER_TEXT_RE.test(normalized))
|
|
76
|
-
return undefined;
|
|
77
|
-
return normalized;
|
|
78
|
-
}
|
|
79
29
|
function sanitizeId(raw) {
|
|
80
30
|
return normalizeText(raw)
|
|
81
31
|
.toLowerCase()
|
|
@@ -134,7 +84,6 @@ async function ensureLayout(projectPath) {
|
|
|
134
84
|
await mkdir(path.join(root, "paper_notes"), { recursive: true });
|
|
135
85
|
await mkdir(path.join(root, "daily_changes"), { recursive: true });
|
|
136
86
|
await mkdir(path.join(root, "hypotheses"), { recursive: true });
|
|
137
|
-
await mkdir(path.join(root, "hypotheses", "rejected"), { recursive: true });
|
|
138
87
|
await mkdir(path.join(root, "logs"), { recursive: true });
|
|
139
88
|
}
|
|
140
89
|
async function loadState(projectPath) {
|
|
@@ -157,9 +106,6 @@ async function loadState(projectPath) {
|
|
|
157
106
|
topic: normalizeText(rawStream.topic ?? "topic"),
|
|
158
107
|
topicKey,
|
|
159
108
|
projectId: sanitizeId(rawStream.projectId ?? "auto-topic-global-000000") || "auto-topic-global-000000",
|
|
160
|
-
lastRunProfile: rawStream.lastRunProfile === "strict" || rawStream.lastRunProfile === "fast"
|
|
161
|
-
? rawStream.lastRunProfile
|
|
162
|
-
: defaultRunProfile(),
|
|
163
109
|
totalRuns: typeof rawStream.totalRuns === "number" ? Math.max(0, Math.floor(rawStream.totalRuns)) : 0,
|
|
164
110
|
totalHypotheses: typeof rawStream.totalHypotheses === "number" ? Math.max(0, Math.floor(rawStream.totalHypotheses)) : 0,
|
|
165
111
|
knowledgeTopics: Array.isArray(rawStream.knowledgeTopics)
|
|
@@ -168,26 +114,6 @@ async function loadState(projectPath) {
|
|
|
168
114
|
paperNotes: Array.isArray(rawStream.paperNotes)
|
|
169
115
|
? rawStream.paperNotes.filter((item) => typeof item === "string").map((item) => normalizeText(item))
|
|
170
116
|
: [],
|
|
171
|
-
triggerState: rawStream.triggerState && typeof rawStream.triggerState === "object" && !Array.isArray(rawStream.triggerState)
|
|
172
|
-
? {
|
|
173
|
-
consecutiveNewReviseDays: typeof rawStream.triggerState.consecutiveNewReviseDays === "number" &&
|
|
174
|
-
Number.isFinite(rawStream.triggerState.consecutiveNewReviseDays)
|
|
175
|
-
? Math.max(0, Math.floor(rawStream.triggerState.consecutiveNewReviseDays))
|
|
176
|
-
: 0,
|
|
177
|
-
bridgeCount7d: typeof rawStream.triggerState.bridgeCount7d === "number" &&
|
|
178
|
-
Number.isFinite(rawStream.triggerState.bridgeCount7d)
|
|
179
|
-
? Math.max(0, Math.floor(rawStream.triggerState.bridgeCount7d))
|
|
180
|
-
: 0,
|
|
181
|
-
unreadCoreBacklog: typeof rawStream.triggerState.unreadCoreBacklog === "number" &&
|
|
182
|
-
Number.isFinite(rawStream.triggerState.unreadCoreBacklog)
|
|
183
|
-
? Math.max(0, Math.floor(rawStream.triggerState.unreadCoreBacklog))
|
|
184
|
-
: 0,
|
|
185
|
-
lastUpdatedAtMs: typeof rawStream.triggerState.lastUpdatedAtMs === "number" &&
|
|
186
|
-
Number.isFinite(rawStream.triggerState.lastUpdatedAtMs)
|
|
187
|
-
? Math.floor(rawStream.triggerState.lastUpdatedAtMs)
|
|
188
|
-
: Date.now(),
|
|
189
|
-
}
|
|
190
|
-
: defaultTriggerState(),
|
|
191
117
|
recentFullTextReadCount: typeof rawStream.recentFullTextReadCount === "number"
|
|
192
118
|
? Math.max(0, Math.floor(rawStream.recentFullTextReadCount))
|
|
193
119
|
: 0,
|
|
@@ -197,60 +123,27 @@ async function loadState(projectPath) {
|
|
|
197
123
|
lastQualityGate: rawStream.lastQualityGate &&
|
|
198
124
|
typeof rawStream.lastQualityGate === "object" &&
|
|
199
125
|
!Array.isArray(rawStream.lastQualityGate)
|
|
200
|
-
?
|
|
201
|
-
|
|
126
|
+
? {
|
|
127
|
+
passed: rawStream.lastQualityGate.passed === true,
|
|
128
|
+
fullTextCoveragePct: typeof rawStream.lastQualityGate.fullTextCoveragePct === "number" &&
|
|
129
|
+
Number.isFinite(rawStream.lastQualityGate.fullTextCoveragePct)
|
|
130
|
+
? Number(rawStream.lastQualityGate.fullTextCoveragePct.toFixed(2))
|
|
131
|
+
: 0,
|
|
132
|
+
evidenceBindingRatePct: typeof rawStream.lastQualityGate.evidenceBindingRatePct === "number" &&
|
|
133
|
+
Number.isFinite(rawStream.lastQualityGate.evidenceBindingRatePct)
|
|
134
|
+
? Number(rawStream.lastQualityGate.evidenceBindingRatePct.toFixed(2))
|
|
135
|
+
: 0,
|
|
136
|
+
citationErrorRatePct: typeof rawStream.lastQualityGate.citationErrorRatePct === "number" &&
|
|
137
|
+
Number.isFinite(rawStream.lastQualityGate.citationErrorRatePct)
|
|
138
|
+
? Number(rawStream.lastQualityGate.citationErrorRatePct.toFixed(2))
|
|
139
|
+
: 0,
|
|
140
|
+
reasons: Array.isArray(rawStream.lastQualityGate.reasons)
|
|
202
141
|
? rawStream.lastQualityGate.reasons
|
|
203
142
|
.filter((item) => typeof item === "string")
|
|
204
143
|
.map((item) => normalizeText(item))
|
|
205
144
|
.filter((item) => item.length > 0)
|
|
206
|
-
: []
|
|
207
|
-
|
|
208
|
-
? rawStream.lastQualityGate.warnings
|
|
209
|
-
.filter((item) => typeof item === "string")
|
|
210
|
-
.map((item) => normalizeText(item))
|
|
211
|
-
.filter((item) => item.length > 0)
|
|
212
|
-
: reasons;
|
|
213
|
-
const fatalReasons = Array.isArray(rawStream.lastQualityGate.fatalReasons)
|
|
214
|
-
? rawStream.lastQualityGate.fatalReasons
|
|
215
|
-
.filter((item) => typeof item === "string")
|
|
216
|
-
.map((item) => normalizeText(item))
|
|
217
|
-
.filter((item) => item.length > 0)
|
|
218
|
-
: [];
|
|
219
|
-
const blocking = rawStream.lastQualityGate.blocking === true || fatalReasons.length > 0;
|
|
220
|
-
const severityRaw = typeof rawStream.lastQualityGate.severity === "string"
|
|
221
|
-
? rawStream.lastQualityGate.severity.toLowerCase()
|
|
222
|
-
: undefined;
|
|
223
|
-
const severity = severityRaw === "fatal" || blocking
|
|
224
|
-
? "fatal"
|
|
225
|
-
: severityRaw === "ok"
|
|
226
|
-
? "ok"
|
|
227
|
-
: warnings.length > 0
|
|
228
|
-
? "warn"
|
|
229
|
-
: "ok";
|
|
230
|
-
return {
|
|
231
|
-
mode: "soft",
|
|
232
|
-
severity,
|
|
233
|
-
warnings,
|
|
234
|
-
fatalReasons,
|
|
235
|
-
blocking,
|
|
236
|
-
passed: typeof rawStream.lastQualityGate.passed === "boolean"
|
|
237
|
-
? rawStream.lastQualityGate.passed
|
|
238
|
-
: fatalReasons.length === 0,
|
|
239
|
-
fullTextCoveragePct: typeof rawStream.lastQualityGate.fullTextCoveragePct === "number" &&
|
|
240
|
-
Number.isFinite(rawStream.lastQualityGate.fullTextCoveragePct)
|
|
241
|
-
? Number(rawStream.lastQualityGate.fullTextCoveragePct.toFixed(2))
|
|
242
|
-
: 0,
|
|
243
|
-
evidenceBindingRatePct: typeof rawStream.lastQualityGate.evidenceBindingRatePct === "number" &&
|
|
244
|
-
Number.isFinite(rawStream.lastQualityGate.evidenceBindingRatePct)
|
|
245
|
-
? Number(rawStream.lastQualityGate.evidenceBindingRatePct.toFixed(2))
|
|
246
|
-
: 0,
|
|
247
|
-
citationErrorRatePct: typeof rawStream.lastQualityGate.citationErrorRatePct === "number" &&
|
|
248
|
-
Number.isFinite(rawStream.lastQualityGate.citationErrorRatePct)
|
|
249
|
-
? Number(rawStream.lastQualityGate.citationErrorRatePct.toFixed(2))
|
|
250
|
-
: 0,
|
|
251
|
-
reasons: reasons.length > 0 ? reasons : [...warnings, ...fatalReasons],
|
|
252
|
-
};
|
|
253
|
-
})()
|
|
145
|
+
: [],
|
|
146
|
+
}
|
|
254
147
|
: defaultQualityGateState(),
|
|
255
148
|
lastUnreadCorePaperIds: Array.isArray(rawStream.lastUnreadCorePaperIds)
|
|
256
149
|
? rawStream.lastUnreadCorePaperIds
|
|
@@ -274,23 +167,7 @@ async function loadState(projectPath) {
|
|
|
274
167
|
.map((item) => normalizeText(item))
|
|
275
168
|
: [],
|
|
276
169
|
recentHypotheses: Array.isArray(rawStream.recentHypotheses)
|
|
277
|
-
? rawStream.recentHypotheses.filter((item) => !!item && typeof item === "object")
|
|
278
|
-
id: sanitizeId(item.id ?? "hyp"),
|
|
279
|
-
statement: normalizeText(item.statement ?? ""),
|
|
280
|
-
trigger: ["GAP", "BRIDGE", "TREND", "CONTRADICTION"].includes(item.trigger)
|
|
281
|
-
? item.trigger
|
|
282
|
-
: "TREND",
|
|
283
|
-
createdAtMs: typeof item.createdAtMs === "number" && Number.isFinite(item.createdAtMs)
|
|
284
|
-
? item.createdAtMs
|
|
285
|
-
: Date.now(),
|
|
286
|
-
file: normalizeText(item.file ?? ""),
|
|
287
|
-
...(typeof item.strictOverallScore === "number" && Number.isFinite(item.strictOverallScore)
|
|
288
|
-
? { strictOverallScore: Number(item.strictOverallScore.toFixed(2)) }
|
|
289
|
-
: {}),
|
|
290
|
-
...(item.strictDecision === "accept" || item.strictDecision === "revise" || item.strictDecision === "reject"
|
|
291
|
-
? { strictDecision: item.strictDecision }
|
|
292
|
-
: {}),
|
|
293
|
-
})).filter((item) => item.statement.length > 0 && item.file.length > 0)
|
|
170
|
+
? rawStream.recentHypotheses.filter((item) => !!item && typeof item === "object")
|
|
294
171
|
: [],
|
|
295
172
|
recentChangeStats: Array.isArray(rawStream.recentChangeStats)
|
|
296
173
|
? rawStream.recentChangeStats.filter((item) => !!item && typeof item === "object")
|
|
@@ -301,39 +178,6 @@ async function loadState(projectPath) {
|
|
|
301
178
|
.map(normalizeTrace)
|
|
302
179
|
.filter((item) => Boolean(item))
|
|
303
180
|
: [],
|
|
304
|
-
lastReflectionTasks: Array.isArray(rawStream.lastReflectionTasks)
|
|
305
|
-
? rawStream.lastReflectionTasks
|
|
306
|
-
.filter((item) => !!item && typeof item === "object")
|
|
307
|
-
.map((item) => ({
|
|
308
|
-
id: sanitizeId(item.id ?? "task"),
|
|
309
|
-
trigger: ["BRIDGE", "TREND", "CONTRADICTION", "UNREAD_CORE"].includes(item.trigger)
|
|
310
|
-
? item.trigger
|
|
311
|
-
: "TREND",
|
|
312
|
-
reason: normalizeText(item.reason ?? ""),
|
|
313
|
-
query: normalizeText(item.query ?? ""),
|
|
314
|
-
priority: ["high", "medium", "low"].includes(item.priority) ? item.priority : "medium",
|
|
315
|
-
status: (item.status === "executed" ? "executed" : "planned"),
|
|
316
|
-
}))
|
|
317
|
-
.filter((item) => item.reason.length > 0 && item.query.length > 0)
|
|
318
|
-
: [],
|
|
319
|
-
lastHypothesisGate: rawStream.lastHypothesisGate &&
|
|
320
|
-
typeof rawStream.lastHypothesisGate === "object" &&
|
|
321
|
-
!Array.isArray(rawStream.lastHypothesisGate)
|
|
322
|
-
? {
|
|
323
|
-
accepted: typeof rawStream.lastHypothesisGate.accepted === "number"
|
|
324
|
-
? Math.max(0, Math.floor(rawStream.lastHypothesisGate.accepted))
|
|
325
|
-
: 0,
|
|
326
|
-
rejected: typeof rawStream.lastHypothesisGate.rejected === "number"
|
|
327
|
-
? Math.max(0, Math.floor(rawStream.lastHypothesisGate.rejected))
|
|
328
|
-
: 0,
|
|
329
|
-
rejectionReasons: Array.isArray(rawStream.lastHypothesisGate.rejectionReasons)
|
|
330
|
-
? rawStream.lastHypothesisGate.rejectionReasons
|
|
331
|
-
.filter((item) => typeof item === "string")
|
|
332
|
-
.map((item) => normalizeText(item))
|
|
333
|
-
.filter((item) => item.length > 0)
|
|
334
|
-
: [],
|
|
335
|
-
}
|
|
336
|
-
: defaultHypothesisGateState(),
|
|
337
181
|
};
|
|
338
182
|
}
|
|
339
183
|
return {
|
|
@@ -364,8 +208,8 @@ function normalizeStringArray(raw) {
|
|
|
364
208
|
return undefined;
|
|
365
209
|
const values = raw
|
|
366
210
|
.filter((item) => typeof item === "string")
|
|
367
|
-
.map((item) =>
|
|
368
|
-
.filter((item) =>
|
|
211
|
+
.map((item) => normalizeText(item))
|
|
212
|
+
.filter((item) => item.length > 0);
|
|
369
213
|
return values.length > 0 ? values : undefined;
|
|
370
214
|
}
|
|
371
215
|
function normalizeEvidenceAnchors(raw) {
|
|
@@ -374,14 +218,14 @@ function normalizeEvidenceAnchors(raw) {
|
|
|
374
218
|
const anchors = raw
|
|
375
219
|
.filter((item) => !!item && typeof item === "object")
|
|
376
220
|
.map((item) => {
|
|
377
|
-
const claim =
|
|
221
|
+
const claim = normalizeText(item.claim ?? "");
|
|
378
222
|
if (!claim)
|
|
379
223
|
return undefined;
|
|
380
224
|
return {
|
|
381
|
-
...(
|
|
382
|
-
...(
|
|
225
|
+
...(item.section ? { section: normalizeText(item.section) } : {}),
|
|
226
|
+
...(item.locator ? { locator: normalizeText(item.locator) } : {}),
|
|
383
227
|
claim,
|
|
384
|
-
...(
|
|
228
|
+
...(item.quote ? { quote: normalizeText(item.quote) } : {}),
|
|
385
229
|
};
|
|
386
230
|
})
|
|
387
231
|
.filter((item) => Boolean(item));
|
|
@@ -399,7 +243,7 @@ function toPaperNoteSlug(paper) {
|
|
|
399
243
|
}
|
|
400
244
|
function normalizePaper(input) {
|
|
401
245
|
const evidenceIds = Array.isArray(input.evidenceIds)
|
|
402
|
-
? input.evidenceIds.map((id) =>
|
|
246
|
+
? input.evidenceIds.map((id) => normalizeText(id)).filter((id) => id.length > 0)
|
|
403
247
|
: undefined;
|
|
404
248
|
const keyEvidenceSpans = normalizeStringArray(input.keyEvidenceSpans);
|
|
405
249
|
const subdomains = normalizeStringArray(input.subdomains);
|
|
@@ -420,33 +264,31 @@ function normalizePaper(input) {
|
|
|
420
264
|
: readStatus
|
|
421
265
|
? false
|
|
422
266
|
: undefined;
|
|
423
|
-
const unreadReason =
|
|
267
|
+
const unreadReason = input.unreadReason ? normalizeText(input.unreadReason) : undefined;
|
|
424
268
|
return {
|
|
425
|
-
...(
|
|
426
|
-
...(
|
|
427
|
-
...(
|
|
428
|
-
...(
|
|
429
|
-
...(
|
|
269
|
+
...(input.id ? { id: normalizeText(input.id) } : {}),
|
|
270
|
+
...(input.title ? { title: normalizeText(input.title) } : {}),
|
|
271
|
+
...(input.url ? { url: normalizeText(input.url) } : {}),
|
|
272
|
+
...(input.source ? { source: normalizeText(input.source) } : {}),
|
|
273
|
+
...(input.publishedAt ? { publishedAt: normalizeText(input.publishedAt) } : {}),
|
|
430
274
|
...(typeof input.score === "number" && Number.isFinite(input.score)
|
|
431
275
|
? { score: Number(input.score.toFixed(2)) }
|
|
432
276
|
: {}),
|
|
433
|
-
...(
|
|
434
|
-
...(
|
|
277
|
+
...(input.reason ? { reason: normalizeText(input.reason) } : {}),
|
|
278
|
+
...(input.summary ? { summary: normalizeText(input.summary) } : {}),
|
|
435
279
|
...(evidenceIds && evidenceIds.length > 0 ? { evidenceIds } : {}),
|
|
436
280
|
...(typeof fullTextRead === "boolean" ? { fullTextRead } : {}),
|
|
437
281
|
...(readStatus ? { readStatus } : {}),
|
|
438
|
-
...(
|
|
439
|
-
...(
|
|
282
|
+
...(input.fullTextSource ? { fullTextSource: normalizeText(input.fullTextSource) } : {}),
|
|
283
|
+
...(input.fullTextRef ? { fullTextRef: normalizeText(input.fullTextRef) } : {}),
|
|
440
284
|
...(unreadReason ? { unreadReason } : {}),
|
|
441
285
|
...(keyEvidenceSpans && keyEvidenceSpans.length > 0 ? { keyEvidenceSpans } : {}),
|
|
442
|
-
...(
|
|
286
|
+
...(input.domain ? { domain: normalizeText(input.domain) } : {}),
|
|
443
287
|
...(subdomains ? { subdomains } : {}),
|
|
444
288
|
...(crossDomainLinks ? { crossDomainLinks } : {}),
|
|
445
|
-
...(
|
|
446
|
-
...(
|
|
447
|
-
...(
|
|
448
|
-
? { methodologyDesign: cleanOptionalText(input.methodologyDesign) }
|
|
449
|
-
: {}),
|
|
289
|
+
...(input.researchGoal ? { researchGoal: normalizeText(input.researchGoal) } : {}),
|
|
290
|
+
...(input.approach ? { approach: normalizeText(input.approach) } : {}),
|
|
291
|
+
...(input.methodologyDesign ? { methodologyDesign: normalizeText(input.methodologyDesign) } : {}),
|
|
450
292
|
...(keyContributions ? { keyContributions } : {}),
|
|
451
293
|
...(practicalInsights ? { practicalInsights } : {}),
|
|
452
294
|
...(mustUnderstandPoints ? { mustUnderstandPoints } : {}),
|
|
@@ -559,32 +401,6 @@ function hasStructuredProfile(paper) {
|
|
|
559
401
|
(paper.limitations && paper.limitations.length > 0) ||
|
|
560
402
|
(paper.evidenceAnchors && paper.evidenceAnchors.length > 0));
|
|
561
403
|
}
|
|
562
|
-
function countStructuredProfileFields(paper) {
|
|
563
|
-
let count = 0;
|
|
564
|
-
if (paper.domain && paper.domain.trim())
|
|
565
|
-
count += 1;
|
|
566
|
-
if (paper.subdomains && paper.subdomains.length > 0)
|
|
567
|
-
count += 1;
|
|
568
|
-
if (paper.crossDomainLinks && paper.crossDomainLinks.length > 0)
|
|
569
|
-
count += 1;
|
|
570
|
-
if (paper.researchGoal && paper.researchGoal.trim())
|
|
571
|
-
count += 1;
|
|
572
|
-
if (paper.approach && paper.approach.trim())
|
|
573
|
-
count += 1;
|
|
574
|
-
if (paper.methodologyDesign && paper.methodologyDesign.trim())
|
|
575
|
-
count += 1;
|
|
576
|
-
if (paper.keyContributions && paper.keyContributions.length > 0)
|
|
577
|
-
count += 1;
|
|
578
|
-
if (paper.practicalInsights && paper.practicalInsights.length > 0)
|
|
579
|
-
count += 1;
|
|
580
|
-
if (paper.mustUnderstandPoints && paper.mustUnderstandPoints.length > 0)
|
|
581
|
-
count += 1;
|
|
582
|
-
if (paper.limitations && paper.limitations.length > 0)
|
|
583
|
-
count += 1;
|
|
584
|
-
if (paper.evidenceAnchors && paper.evidenceAnchors.length > 0)
|
|
585
|
-
count += 1;
|
|
586
|
-
return count;
|
|
587
|
-
}
|
|
588
404
|
function isFullTextRead(paper) {
|
|
589
405
|
return paper.fullTextRead === true || paper.readStatus === "fulltext";
|
|
590
406
|
}
|
|
@@ -631,13 +447,6 @@ function applyQualityGates(args) {
|
|
|
631
447
|
const fullTextCoreCount = corePapers.filter((paper) => isFullTextRead(paper)).length;
|
|
632
448
|
const fullTextCoverage = coreCount > 0 ? fullTextCoreCount / coreCount : 0;
|
|
633
449
|
const fullTextCoveragePct = Number((fullTextCoverage * 100).toFixed(2));
|
|
634
|
-
const fullTextCorePapers = corePapers.filter((paper) => isFullTextRead(paper));
|
|
635
|
-
const structuredFieldTotal = 11;
|
|
636
|
-
const avgFullTextProfileCompleteness = fullTextCorePapers.length > 0
|
|
637
|
-
? fullTextCorePapers.reduce((sum, paper) => sum + countStructuredProfileFields(paper) / structuredFieldTotal, 0) /
|
|
638
|
-
fullTextCorePapers.length
|
|
639
|
-
: 0;
|
|
640
|
-
const avgFullTextProfileCompletenessPct = Number((avgFullTextProfileCompleteness * 100).toFixed(2));
|
|
641
450
|
const unreadCorePaperIds = dedupeText(corePapers
|
|
642
451
|
.filter((paper) => !isFullTextRead(paper))
|
|
643
452
|
.map((paper) => paper.id?.trim() || paper.url?.trim() || paper.title?.trim() || "unknown-paper")).slice(0, 50);
|
|
@@ -712,68 +521,22 @@ function applyQualityGates(args) {
|
|
|
712
521
|
downgradedHighConfidenceCount += 1;
|
|
713
522
|
}
|
|
714
523
|
}
|
|
715
|
-
const
|
|
716
|
-
const fatalReasons = [];
|
|
717
|
-
if (!args.hasAuditableArtifacts && !args.hasRunError) {
|
|
718
|
-
fatalReasons.push("no_auditable_artifacts_without_run_error");
|
|
719
|
-
}
|
|
720
|
-
if (typeof args.requiredCorePapers === "number" && Number.isFinite(args.requiredCorePapers) && args.requiredCorePapers > 0) {
|
|
721
|
-
const requiredCore = Math.floor(args.requiredCorePapers);
|
|
722
|
-
if (coreCount === 0) {
|
|
723
|
-
fatalReasons.push(`core_paper_count_below_required(${coreCount} < ${requiredCore})`);
|
|
724
|
-
}
|
|
725
|
-
else if (coreCount < requiredCore) {
|
|
726
|
-
warnings.push(`core_paper_count_below_required(${coreCount} < ${requiredCore})`);
|
|
727
|
-
}
|
|
728
|
-
}
|
|
524
|
+
const reasons = [];
|
|
729
525
|
if (fullTextCoverage < MIN_CORE_FULLTEXT_COVERAGE) {
|
|
730
|
-
|
|
731
|
-
}
|
|
732
|
-
if (fullTextCorePapers.length > 0 && avgFullTextProfileCompleteness < MIN_FULLTEXT_PROFILE_COMPLETENESS) {
|
|
733
|
-
warnings.push(`fulltext_profile_completeness_below_threshold(${avgFullTextProfileCompletenessPct}% < ${Number((MIN_FULLTEXT_PROFILE_COMPLETENESS * 100).toFixed(0))}%)`);
|
|
734
|
-
}
|
|
735
|
-
if (typeof args.requiredFullTextCoveragePct === "number" &&
|
|
736
|
-
Number.isFinite(args.requiredFullTextCoveragePct) &&
|
|
737
|
-
args.requiredFullTextCoveragePct > 0 &&
|
|
738
|
-
fullTextCoveragePct < args.requiredFullTextCoveragePct) {
|
|
739
|
-
warnings.push(`core_fulltext_coverage_below_required(${fullTextCoveragePct}% < ${Number(args.requiredFullTextCoveragePct.toFixed(2))}%)`);
|
|
526
|
+
reasons.push(`core_fulltext_coverage_below_threshold(${fullTextCoveragePct}% < ${Number((MIN_CORE_FULLTEXT_COVERAGE * 100).toFixed(0))}%)`);
|
|
740
527
|
}
|
|
741
528
|
if (evidenceBindingRate < MIN_EVIDENCE_BINDING_RATE) {
|
|
742
|
-
|
|
743
|
-
}
|
|
744
|
-
if (citationErrorRate >= FATAL_CITATION_ERROR_RATE) {
|
|
745
|
-
fatalReasons.push(`citation_error_rate_above_threshold(${citationErrorRatePct}% >= ${Number((FATAL_CITATION_ERROR_RATE * 100).toFixed(0))}%)`);
|
|
746
|
-
}
|
|
747
|
-
else if (citationErrorRate >= MAX_CITATION_ERROR_RATE) {
|
|
748
|
-
warnings.push(`citation_error_rate_above_warning_threshold(${citationErrorRatePct}% >= ${Number((MAX_CITATION_ERROR_RATE * 100).toFixed(0))}%)`);
|
|
749
|
-
}
|
|
750
|
-
const bridgeChangeCount = args.knowledgeChanges.filter((item) => item.type === "BRIDGE").length;
|
|
751
|
-
const reviseCount = args.knowledgeChanges.filter((item) => item.type === "REVISE").length;
|
|
752
|
-
const confirmCount = args.knowledgeChanges.filter((item) => item.type === "CONFIRM").length;
|
|
753
|
-
const executedReflectionCount = args.reflectionTasks.filter((task) => task.status === "executed").length;
|
|
754
|
-
if (bridgeChangeCount > 0 && executedReflectionCount === 0) {
|
|
755
|
-
warnings.push(`reflection_missing_for_bridge(bridge_count=${bridgeChangeCount})`);
|
|
529
|
+
reasons.push(`evidence_binding_rate_below_threshold(${evidenceBindingRatePct}% < ${Number((MIN_EVIDENCE_BINDING_RATE * 100).toFixed(0))}%)`);
|
|
756
530
|
}
|
|
757
|
-
if (
|
|
758
|
-
|
|
759
|
-
}
|
|
760
|
-
if (args.hypothesisGate.rejected > 0 && args.hypothesisGate.accepted === 0 && args.hypotheses.length > 0) {
|
|
761
|
-
warnings.push(`hypothesis_gate_rejected_all(${args.hypothesisGate.rejected})`);
|
|
531
|
+
if (citationErrorRate >= MAX_CITATION_ERROR_RATE) {
|
|
532
|
+
reasons.push(`citation_error_rate_above_threshold(${citationErrorRatePct}% >= ${Number((MAX_CITATION_ERROR_RATE * 100).toFixed(0))}%)`);
|
|
762
533
|
}
|
|
763
534
|
if (downgradedHighConfidenceCount > 0) {
|
|
764
|
-
|
|
535
|
+
reasons.push(`high_confidence_downgraded(${downgradedHighConfidenceCount})`);
|
|
765
536
|
}
|
|
766
|
-
const reasons = [...warnings, ...fatalReasons];
|
|
767
|
-
const blocking = fatalReasons.length > 0;
|
|
768
|
-
const severity = blocking ? "fatal" : warnings.length > 0 ? "warn" : "ok";
|
|
769
537
|
return {
|
|
770
538
|
qualityGate: {
|
|
771
|
-
|
|
772
|
-
severity,
|
|
773
|
-
warnings,
|
|
774
|
-
fatalReasons,
|
|
775
|
-
blocking,
|
|
776
|
-
passed: !blocking,
|
|
539
|
+
passed: reasons.length === 0,
|
|
777
540
|
fullTextCoveragePct,
|
|
778
541
|
evidenceBindingRatePct,
|
|
779
542
|
citationErrorRatePct,
|
|
@@ -783,20 +546,6 @@ function applyQualityGates(args) {
|
|
|
783
546
|
downgradedHighConfidenceCount,
|
|
784
547
|
};
|
|
785
548
|
}
|
|
786
|
-
function deriveEffectiveStatus(args) {
|
|
787
|
-
const requested = normalizeText(args.requestedStatus || "ok").toLowerCase();
|
|
788
|
-
if (requested === "error" || args.hasRunError)
|
|
789
|
-
return "error";
|
|
790
|
-
if (args.qualityBlocking)
|
|
791
|
-
return "degraded_quality";
|
|
792
|
-
if (requested === "empty")
|
|
793
|
-
return args.runArtifactCount > 0 ? "ok" : "empty";
|
|
794
|
-
if (requested === "degraded_quality")
|
|
795
|
-
return "ok";
|
|
796
|
-
if (requested.length === 0)
|
|
797
|
-
return args.runArtifactCount > 0 ? "ok" : "empty";
|
|
798
|
-
return requested;
|
|
799
|
-
}
|
|
800
549
|
function normalizeChange(input) {
|
|
801
550
|
const statement = normalizeText(input.statement ?? "");
|
|
802
551
|
if (!statement)
|
|
@@ -850,39 +599,12 @@ function normalizeHypothesis(input) {
|
|
|
850
599
|
: undefined;
|
|
851
600
|
const validationEvidence = normalizeStringArray(input.validationEvidence);
|
|
852
601
|
const validationNotes = input.validationNotes ? normalizeText(input.validationNotes) : undefined;
|
|
853
|
-
const strengths = normalizeStringArray(input.strengths);
|
|
854
|
-
const weaknesses = normalizeStringArray(input.weaknesses);
|
|
855
|
-
const planSteps = normalizeStringArray(input.planSteps);
|
|
856
|
-
const strictEvaluationRaw = input.strictEvaluation;
|
|
857
|
-
const strictEvaluation = strictEvaluationRaw && typeof strictEvaluationRaw === "object"
|
|
858
|
-
? (() => {
|
|
859
|
-
const overallScore = typeof strictEvaluationRaw.overallScore === "number" && Number.isFinite(strictEvaluationRaw.overallScore)
|
|
860
|
-
? Math.max(0, Math.min(100, Number(strictEvaluationRaw.overallScore.toFixed(2))))
|
|
861
|
-
: undefined;
|
|
862
|
-
const decisionRaw = strictEvaluationRaw.decision?.trim().toLowerCase();
|
|
863
|
-
const decision = decisionRaw === "accept" || decisionRaw === "revise" || decisionRaw === "reject"
|
|
864
|
-
? decisionRaw
|
|
865
|
-
: undefined;
|
|
866
|
-
const reason = strictEvaluationRaw.reason ? normalizeText(strictEvaluationRaw.reason) : undefined;
|
|
867
|
-
if (overallScore === undefined && !decision && !reason)
|
|
868
|
-
return undefined;
|
|
869
|
-
return {
|
|
870
|
-
...(overallScore !== undefined ? { overallScore } : {}),
|
|
871
|
-
...(decision ? { decision } : {}),
|
|
872
|
-
...(reason ? { reason } : {}),
|
|
873
|
-
};
|
|
874
|
-
})()
|
|
875
|
-
: undefined;
|
|
876
602
|
const withScore = (value) => typeof value === "number" && Number.isFinite(value) ? Number(value.toFixed(2)) : undefined;
|
|
877
603
|
return {
|
|
878
604
|
...(input.id ? { id: sanitizeId(input.id) } : {}),
|
|
879
605
|
statement,
|
|
880
606
|
trigger,
|
|
881
607
|
...(dependencyPath && dependencyPath.length > 0 ? { dependencyPath } : {}),
|
|
882
|
-
...(strengths ? { strengths } : {}),
|
|
883
|
-
...(weaknesses ? { weaknesses } : {}),
|
|
884
|
-
...(planSteps ? { planSteps } : {}),
|
|
885
|
-
...(strictEvaluation ? { strictEvaluation } : {}),
|
|
886
608
|
...(typeof withScore(input.novelty) === "number" ? { novelty: withScore(input.novelty) } : {}),
|
|
887
609
|
...(typeof withScore(input.feasibility) === "number" ? { feasibility: withScore(input.feasibility) } : {}),
|
|
888
610
|
...(typeof withScore(input.impact) === "number" ? { impact: withScore(input.impact) } : {}),
|
|
@@ -920,12 +642,10 @@ function toSummary(stream) {
|
|
|
920
642
|
return {
|
|
921
643
|
projectId: stream.projectId,
|
|
922
644
|
streamKey: stream.topicKey,
|
|
923
|
-
runProfile: stream.lastRunProfile,
|
|
924
645
|
totalRuns: stream.totalRuns,
|
|
925
646
|
totalHypotheses: stream.totalHypotheses,
|
|
926
647
|
knowledgeTopicsCount: stream.knowledgeTopics.length,
|
|
927
648
|
paperNotesCount: stream.paperNotes.length,
|
|
928
|
-
triggerState: stream.triggerState,
|
|
929
649
|
recentFullTextReadCount: stream.recentFullTextReadCount,
|
|
930
650
|
recentNotFullTextReadCount: stream.recentNotFullTextReadCount,
|
|
931
651
|
qualityGate: stream.lastQualityGate,
|
|
@@ -936,8 +656,6 @@ function toSummary(stream) {
|
|
|
936
656
|
recentHypotheses: stream.recentHypotheses,
|
|
937
657
|
recentChangeStats: stream.recentChangeStats,
|
|
938
658
|
lastExplorationTrace: stream.lastExplorationTrace,
|
|
939
|
-
lastReflectionTasks: stream.lastReflectionTasks,
|
|
940
|
-
hypothesisGate: stream.lastHypothesisGate,
|
|
941
659
|
};
|
|
942
660
|
}
|
|
943
661
|
function countChangeStats(day, runId, changes) {
|
|
@@ -964,576 +682,6 @@ function countChangeStats(day, runId, changes) {
|
|
|
964
682
|
bridgeCount,
|
|
965
683
|
};
|
|
966
684
|
}
|
|
967
|
-
function tokenizeForQuery(raw) {
|
|
968
|
-
return normalizeText(raw)
|
|
969
|
-
.toLowerCase()
|
|
970
|
-
.replace(/[^a-z0-9\u4e00-\u9fff\s_-]+/g, " ")
|
|
971
|
-
.split(/\s+/)
|
|
972
|
-
.map((item) => item.trim())
|
|
973
|
-
.filter((item) => item.length >= 3);
|
|
974
|
-
}
|
|
975
|
-
function uniqueText(values) {
|
|
976
|
-
return [...new Set(values.map((item) => normalizeText(item)).filter((item) => item.length > 0))];
|
|
977
|
-
}
|
|
978
|
-
function buildReflectionQuery(topic, statement, fallbackHint) {
|
|
979
|
-
const topicTokens = tokenizeForQuery(topic).slice(0, 4);
|
|
980
|
-
const stmtTokens = tokenizeForQuery(statement).slice(0, 6);
|
|
981
|
-
const merged = uniqueText([...topicTokens, ...stmtTokens]);
|
|
982
|
-
if (merged.length === 0)
|
|
983
|
-
return `${topic} ${fallbackHint}`.trim();
|
|
984
|
-
return merged.join(" ");
|
|
985
|
-
}
|
|
986
|
-
function queryMatchesTrace(query, trace) {
|
|
987
|
-
const tokens = tokenizeForQuery(query).slice(0, 4);
|
|
988
|
-
if (tokens.length === 0)
|
|
989
|
-
return false;
|
|
990
|
-
return trace.some((step) => {
|
|
991
|
-
const hay = normalizeText(step.query).toLowerCase();
|
|
992
|
-
let hit = 0;
|
|
993
|
-
for (const token of tokens) {
|
|
994
|
-
if (hay.includes(token))
|
|
995
|
-
hit += 1;
|
|
996
|
-
if (hit >= Math.min(2, tokens.length))
|
|
997
|
-
return true;
|
|
998
|
-
}
|
|
999
|
-
return false;
|
|
1000
|
-
});
|
|
1001
|
-
}
|
|
1002
|
-
function deriveReflectionTasks(args) {
|
|
1003
|
-
const tasks = [];
|
|
1004
|
-
const bridge = args.changes.filter((item) => item.type === "BRIDGE");
|
|
1005
|
-
const revise = args.changes.filter((item) => item.type === "REVISE");
|
|
1006
|
-
const confirm = args.changes.filter((item) => item.type === "CONFIRM");
|
|
1007
|
-
const newly = args.changes.filter((item) => item.type === "NEW");
|
|
1008
|
-
for (const [idx, change] of bridge.slice(0, 3).entries()) {
|
|
1009
|
-
const query = buildReflectionQuery(args.topic, change.statement, "cross-domain mechanism");
|
|
1010
|
-
tasks.push({
|
|
1011
|
-
id: sanitizeId(`bridge-${idx + 1}-${query}`),
|
|
1012
|
-
trigger: "BRIDGE",
|
|
1013
|
-
reason: `Bridge signal requires cross-domain follow-up: ${change.statement}`,
|
|
1014
|
-
query,
|
|
1015
|
-
priority: "high",
|
|
1016
|
-
status: queryMatchesTrace(query, args.trace) ? "executed" : "planned",
|
|
1017
|
-
});
|
|
1018
|
-
}
|
|
1019
|
-
if (newly.length >= 3) {
|
|
1020
|
-
const query = buildReflectionQuery(args.topic, newly.map((item) => item.statement).join(" "), "trend synthesis");
|
|
1021
|
-
tasks.push({
|
|
1022
|
-
id: sanitizeId(`trend-${query}`),
|
|
1023
|
-
trigger: "TREND",
|
|
1024
|
-
reason: `New findings accumulated (${newly.length}); run trend synthesis and gap scan.`,
|
|
1025
|
-
query,
|
|
1026
|
-
priority: "medium",
|
|
1027
|
-
status: queryMatchesTrace(query, args.trace) ? "executed" : "planned",
|
|
1028
|
-
});
|
|
1029
|
-
}
|
|
1030
|
-
if (revise.length > 0 && confirm.length > 0) {
|
|
1031
|
-
const query = buildReflectionQuery(args.topic, `${revise[0]?.statement ?? ""} ${confirm[0]?.statement ?? ""}`, "contradiction resolution");
|
|
1032
|
-
tasks.push({
|
|
1033
|
-
id: sanitizeId(`contradiction-${query}`),
|
|
1034
|
-
trigger: "CONTRADICTION",
|
|
1035
|
-
reason: `Revise and confirm signals co-exist; verify contradiction boundaries.`,
|
|
1036
|
-
query,
|
|
1037
|
-
priority: "high",
|
|
1038
|
-
status: queryMatchesTrace(query, args.trace) ? "executed" : "planned",
|
|
1039
|
-
});
|
|
1040
|
-
}
|
|
1041
|
-
const unreadCore = args.corePapers.filter((paper) => !isFullTextRead(paper));
|
|
1042
|
-
if (unreadCore.length > 0) {
|
|
1043
|
-
const topId = unreadCore[0]?.id ?? unreadCore[0]?.title ?? "core-paper";
|
|
1044
|
-
const query = buildReflectionQuery(args.topic, String(topId), "full text retrieval");
|
|
1045
|
-
tasks.push({
|
|
1046
|
-
id: sanitizeId(`unread-core-${query}`),
|
|
1047
|
-
trigger: "UNREAD_CORE",
|
|
1048
|
-
reason: `${unreadCore.length} core paper(s) were not fully read; prioritize retrieval and verification.`,
|
|
1049
|
-
query,
|
|
1050
|
-
priority: "medium",
|
|
1051
|
-
status: queryMatchesTrace(query, args.trace) ? "executed" : "planned",
|
|
1052
|
-
});
|
|
1053
|
-
}
|
|
1054
|
-
if (tasks.length === 0 && args.corePapers.length === 0 && args.changes.length === 0) {
|
|
1055
|
-
const query = buildReflectionQuery(args.topic, `${args.topic} survey review foundational mainstream variants`, "empty cycle diagnosis");
|
|
1056
|
-
tasks.push({
|
|
1057
|
-
id: sanitizeId(`empty-cycle-${query}`),
|
|
1058
|
-
trigger: "TREND",
|
|
1059
|
-
reason: "No new core papers found in this cycle. Re-check query scope/time window and expand to adjacent sub-directions for idea support or criticism.",
|
|
1060
|
-
query,
|
|
1061
|
-
priority: "medium",
|
|
1062
|
-
status: queryMatchesTrace(query, args.trace) ? "executed" : "planned",
|
|
1063
|
-
});
|
|
1064
|
-
}
|
|
1065
|
-
const dedup = new Map();
|
|
1066
|
-
for (const task of tasks) {
|
|
1067
|
-
const key = normalizeText(task.query).toLowerCase();
|
|
1068
|
-
if (!key)
|
|
1069
|
-
continue;
|
|
1070
|
-
const existing = dedup.get(key);
|
|
1071
|
-
if (!existing) {
|
|
1072
|
-
dedup.set(key, task);
|
|
1073
|
-
continue;
|
|
1074
|
-
}
|
|
1075
|
-
// Keep higher priority / executed status when duplicates collide.
|
|
1076
|
-
const priorityRank = { high: 3, medium: 2, low: 1 };
|
|
1077
|
-
const pick = (existing.status !== "executed" && task.status === "executed") ||
|
|
1078
|
-
priorityRank[task.priority] > priorityRank[existing.priority]
|
|
1079
|
-
? task
|
|
1080
|
-
: existing;
|
|
1081
|
-
dedup.set(key, pick);
|
|
1082
|
-
}
|
|
1083
|
-
return [...dedup.values()].slice(0, MAX_LAST_REFLECTION_TASKS);
|
|
1084
|
-
}
|
|
1085
|
-
function sanitizeKnowledgeChanges(args) {
|
|
1086
|
-
if (args.changes.length === 0) {
|
|
1087
|
-
return {
|
|
1088
|
-
changes: [],
|
|
1089
|
-
droppedBridgeCount: 0,
|
|
1090
|
-
};
|
|
1091
|
-
}
|
|
1092
|
-
const paperLookup = buildPaperLookup(args.allRunPapers);
|
|
1093
|
-
const next = [];
|
|
1094
|
-
let droppedBridgeCount = 0;
|
|
1095
|
-
for (const change of args.changes) {
|
|
1096
|
-
if (change.type !== "BRIDGE") {
|
|
1097
|
-
next.push(change);
|
|
1098
|
-
continue;
|
|
1099
|
-
}
|
|
1100
|
-
const evidenceIds = (change.evidenceIds ?? []).map((id) => normalizedCitationToken(id)).filter((id) => id.length > 0);
|
|
1101
|
-
if (evidenceIds.length === 0) {
|
|
1102
|
-
droppedBridgeCount += 1;
|
|
1103
|
-
continue;
|
|
1104
|
-
}
|
|
1105
|
-
let hasResolvedEvidence = false;
|
|
1106
|
-
let hasFullTextEvidence = false;
|
|
1107
|
-
for (const evidenceId of evidenceIds) {
|
|
1108
|
-
const paper = paperLookup.get(evidenceId);
|
|
1109
|
-
if (!paper)
|
|
1110
|
-
continue;
|
|
1111
|
-
hasResolvedEvidence = true;
|
|
1112
|
-
if (isFullTextRead(paper))
|
|
1113
|
-
hasFullTextEvidence = true;
|
|
1114
|
-
}
|
|
1115
|
-
// Guard against speculative bridge signals with no grounded full-text evidence.
|
|
1116
|
-
if (!hasResolvedEvidence || !hasFullTextEvidence) {
|
|
1117
|
-
droppedBridgeCount += 1;
|
|
1118
|
-
continue;
|
|
1119
|
-
}
|
|
1120
|
-
next.push(change);
|
|
1121
|
-
}
|
|
1122
|
-
return {
|
|
1123
|
-
changes: next,
|
|
1124
|
-
droppedBridgeCount,
|
|
1125
|
-
};
|
|
1126
|
-
}
|
|
1127
|
-
function applyHypothesisGate(args) {
|
|
1128
|
-
const acceptedHypotheses = [];
|
|
1129
|
-
const audits = [];
|
|
1130
|
-
const rejectionReasonSet = new Set();
|
|
1131
|
-
const paperLookup = buildPaperLookup(args.allRunPapers);
|
|
1132
|
-
const fullTextEvidenceIds = uniqueText(args.allRunPapers
|
|
1133
|
-
.filter((paper) => isFullTextRead(paper))
|
|
1134
|
-
.map((paper) => normalizedCitationToken(paper.id ?? paper.url ?? paper.title ?? ""))
|
|
1135
|
-
.filter((id) => id.length > 0));
|
|
1136
|
-
const anyEvidenceIds = uniqueText(args.allRunPapers
|
|
1137
|
-
.map((paper) => normalizedCitationToken(paper.id ?? paper.url ?? paper.title ?? ""))
|
|
1138
|
-
.filter((id) => id.length > 0));
|
|
1139
|
-
const changeCounts = {
|
|
1140
|
-
NEW: args.knowledgeChanges.filter((item) => item.type === "NEW").length,
|
|
1141
|
-
CONFIRM: args.knowledgeChanges.filter((item) => item.type === "CONFIRM").length,
|
|
1142
|
-
REVISE: args.knowledgeChanges.filter((item) => item.type === "REVISE").length,
|
|
1143
|
-
BRIDGE: args.knowledgeChanges.filter((item) => item.type === "BRIDGE").length,
|
|
1144
|
-
};
|
|
1145
|
-
const evaluateHypothesisReasons = (hypothesis) => {
|
|
1146
|
-
const reasons = [];
|
|
1147
|
-
const statementLen = normalizeText(hypothesis.statement).length;
|
|
1148
|
-
if (statementLen < MIN_HYPOTHESIS_STATEMENT_CHARS) {
|
|
1149
|
-
reasons.push(`statement_too_short(${statementLen}<${MIN_HYPOTHESIS_STATEMENT_CHARS})`);
|
|
1150
|
-
}
|
|
1151
|
-
const evidenceIds = uniqueText((hypothesis.evidenceIds ?? []).map((id) => normalizedCitationToken(id)));
|
|
1152
|
-
if (evidenceIds.length < MIN_HYPOTHESIS_EVIDENCE) {
|
|
1153
|
-
reasons.push(`insufficient_evidence_ids(${evidenceIds.length}<${MIN_HYPOTHESIS_EVIDENCE})`);
|
|
1154
|
-
}
|
|
1155
|
-
let resolvedEvidence = 0;
|
|
1156
|
-
let fullTextSupported = 0;
|
|
1157
|
-
for (const evidenceId of evidenceIds) {
|
|
1158
|
-
const paper = paperLookup.get(evidenceId);
|
|
1159
|
-
if (!paper)
|
|
1160
|
-
continue;
|
|
1161
|
-
resolvedEvidence += 1;
|
|
1162
|
-
if (isFullTextRead(paper))
|
|
1163
|
-
fullTextSupported += 1;
|
|
1164
|
-
}
|
|
1165
|
-
if (resolvedEvidence < evidenceIds.length) {
|
|
1166
|
-
reasons.push(`unresolved_evidence_ids(${evidenceIds.length - resolvedEvidence})`);
|
|
1167
|
-
}
|
|
1168
|
-
if (fullTextSupported === 0 && args.runProfile === "strict") {
|
|
1169
|
-
reasons.push("no_fulltext_backed_evidence");
|
|
1170
|
-
}
|
|
1171
|
-
if (resolvedEvidence === 0) {
|
|
1172
|
-
reasons.push("no_resolved_evidence");
|
|
1173
|
-
}
|
|
1174
|
-
const dependencyPathLength = hypothesis.dependencyPath?.length ?? 0;
|
|
1175
|
-
if (dependencyPathLength < MIN_HYPOTHESIS_DEPENDENCY_STEPS) {
|
|
1176
|
-
reasons.push(`dependency_path_too_short(${dependencyPathLength}<${MIN_HYPOTHESIS_DEPENDENCY_STEPS})`);
|
|
1177
|
-
}
|
|
1178
|
-
if (!hypothesis.problemGap || normalizeText(hypothesis.problemGap).length < 24) {
|
|
1179
|
-
reasons.push("problem_gap_missing_or_too_short");
|
|
1180
|
-
}
|
|
1181
|
-
if (!hypothesis.proposedMechanism || normalizeText(hypothesis.proposedMechanism).length < 24) {
|
|
1182
|
-
reasons.push("proposed_mechanism_missing_or_too_short");
|
|
1183
|
-
}
|
|
1184
|
-
if (!hypothesis.noveltyRationale || normalizeText(hypothesis.noveltyRationale).length < 24) {
|
|
1185
|
-
reasons.push("novelty_rationale_missing_or_too_short");
|
|
1186
|
-
}
|
|
1187
|
-
const predictionCount = hypothesis.falsifiablePredictions?.length ?? 0;
|
|
1188
|
-
if (predictionCount < MIN_HYPOTHESIS_PREDICTIONS) {
|
|
1189
|
-
reasons.push(`predictions_too_few(${predictionCount}<${MIN_HYPOTHESIS_PREDICTIONS})`);
|
|
1190
|
-
}
|
|
1191
|
-
const assumptionCount = hypothesis.criticalAssumptions?.length ?? 0;
|
|
1192
|
-
if (assumptionCount < MIN_HYPOTHESIS_ASSUMPTIONS) {
|
|
1193
|
-
reasons.push(`assumptions_too_few(${assumptionCount}<${MIN_HYPOTHESIS_ASSUMPTIONS})`);
|
|
1194
|
-
}
|
|
1195
|
-
const failureModeCount = hypothesis.failureModes?.length ?? 0;
|
|
1196
|
-
if (failureModeCount < MIN_HYPOTHESIS_FAILURE_MODES) {
|
|
1197
|
-
reasons.push(`failure_modes_too_few(${failureModeCount}<${MIN_HYPOTHESIS_FAILURE_MODES})`);
|
|
1198
|
-
}
|
|
1199
|
-
const successCriteriaCount = hypothesis.successCriteria?.length ?? 0;
|
|
1200
|
-
if (successCriteriaCount < MIN_HYPOTHESIS_SUCCESS_CRITERIA) {
|
|
1201
|
-
reasons.push(`success_criteria_too_few(${successCriteriaCount}<${MIN_HYPOTHESIS_SUCCESS_CRITERIA})`);
|
|
1202
|
-
}
|
|
1203
|
-
const strengthsCount = hypothesis.strengths?.length ?? 0;
|
|
1204
|
-
if (strengthsCount < MIN_HYPOTHESIS_STRENGTHS) {
|
|
1205
|
-
reasons.push(`strengths_too_few(${strengthsCount}<${MIN_HYPOTHESIS_STRENGTHS})`);
|
|
1206
|
-
}
|
|
1207
|
-
const weaknessesCount = hypothesis.weaknesses?.length ?? 0;
|
|
1208
|
-
if (weaknessesCount < MIN_HYPOTHESIS_WEAKNESSES) {
|
|
1209
|
-
reasons.push(`weaknesses_too_few(${weaknessesCount}<${MIN_HYPOTHESIS_WEAKNESSES})`);
|
|
1210
|
-
}
|
|
1211
|
-
const planStepCount = hypothesis.planSteps?.length ?? 0;
|
|
1212
|
-
if (planStepCount < MIN_HYPOTHESIS_PLAN_STEPS) {
|
|
1213
|
-
reasons.push(`plan_steps_too_few(${planStepCount}<${MIN_HYPOTHESIS_PLAN_STEPS})`);
|
|
1214
|
-
}
|
|
1215
|
-
const hasScore = typeof hypothesis.novelty === "number" &&
|
|
1216
|
-
typeof hypothesis.feasibility === "number" &&
|
|
1217
|
-
typeof hypothesis.impact === "number";
|
|
1218
|
-
if (!hasScore) {
|
|
1219
|
-
reasons.push("missing_self_assessment_scores");
|
|
1220
|
-
}
|
|
1221
|
-
const strictEval = hypothesis.strictEvaluation;
|
|
1222
|
-
if (!strictEval) {
|
|
1223
|
-
reasons.push("missing_strict_evaluation");
|
|
1224
|
-
}
|
|
1225
|
-
else {
|
|
1226
|
-
if (typeof strictEval.overallScore !== "number" || !Number.isFinite(strictEval.overallScore)) {
|
|
1227
|
-
reasons.push("strict_evaluation_missing_overall_score");
|
|
1228
|
-
}
|
|
1229
|
-
if (!strictEval.decision) {
|
|
1230
|
-
reasons.push("strict_evaluation_missing_decision");
|
|
1231
|
-
}
|
|
1232
|
-
else if (strictEval.decision !== "accept") {
|
|
1233
|
-
reasons.push(`strict_evaluation_not_accept(${strictEval.decision})`);
|
|
1234
|
-
}
|
|
1235
|
-
if (!strictEval.reason || normalizeText(strictEval.reason).length < 16) {
|
|
1236
|
-
reasons.push("strict_evaluation_reason_too_short");
|
|
1237
|
-
}
|
|
1238
|
-
if (strictEval.decision === "accept" &&
|
|
1239
|
-
typeof strictEval.overallScore === "number" &&
|
|
1240
|
-
strictEval.overallScore < MIN_HYPOTHESIS_STRICT_ACCEPT_SCORE) {
|
|
1241
|
-
reasons.push(`strict_evaluation_score_below_threshold(${strictEval.overallScore}<${MIN_HYPOTHESIS_STRICT_ACCEPT_SCORE})`);
|
|
1242
|
-
}
|
|
1243
|
-
}
|
|
1244
|
-
if (hasScore &&
|
|
1245
|
-
strictEval?.decision === "accept" &&
|
|
1246
|
-
((hypothesis.novelty ?? 0) + (hypothesis.feasibility ?? 0) + (hypothesis.impact ?? 0)) / 3 <
|
|
1247
|
-
MIN_HYPOTHESIS_ACCEPT_SELF_SCORE_AVG) {
|
|
1248
|
-
reasons.push(`self_assessment_avg_below_accept_threshold(${Number((((hypothesis.novelty ?? 0) + (hypothesis.feasibility ?? 0) + (hypothesis.impact ?? 0)) / 3).toFixed(2))}<${MIN_HYPOTHESIS_ACCEPT_SELF_SCORE_AVG})`);
|
|
1249
|
-
}
|
|
1250
|
-
if (hypothesis.trigger === "BRIDGE" && changeCounts.BRIDGE === 0) {
|
|
1251
|
-
reasons.push("trigger_bridge_without_bridge_change");
|
|
1252
|
-
}
|
|
1253
|
-
if (hypothesis.trigger === "TREND" && changeCounts.NEW < 2) {
|
|
1254
|
-
reasons.push("trigger_trend_without_new_accumulation");
|
|
1255
|
-
}
|
|
1256
|
-
if (hypothesis.trigger === "CONTRADICTION" && !(changeCounts.REVISE > 0 && changeCounts.CONFIRM > 0)) {
|
|
1257
|
-
reasons.push("trigger_contradiction_without_revise_confirm_pair");
|
|
1258
|
-
}
|
|
1259
|
-
if (hypothesis.trigger === "GAP" && changeCounts.NEW + changeCounts.REVISE < 2) {
|
|
1260
|
-
reasons.push("trigger_gap_without_gap_signal");
|
|
1261
|
-
}
|
|
1262
|
-
return reasons;
|
|
1263
|
-
};
|
|
1264
|
-
const isRepairableReason = (reason) => {
|
|
1265
|
-
return (reason.startsWith("dependency_path_too_short(") ||
|
|
1266
|
-
reason === "problem_gap_missing_or_too_short" ||
|
|
1267
|
-
reason === "proposed_mechanism_missing_or_too_short" ||
|
|
1268
|
-
reason === "novelty_rationale_missing_or_too_short" ||
|
|
1269
|
-
reason.startsWith("predictions_too_few(") ||
|
|
1270
|
-
reason.startsWith("assumptions_too_few(") ||
|
|
1271
|
-
reason.startsWith("failure_modes_too_few(") ||
|
|
1272
|
-
reason.startsWith("success_criteria_too_few(") ||
|
|
1273
|
-
reason.startsWith("strengths_too_few(") ||
|
|
1274
|
-
reason.startsWith("weaknesses_too_few(") ||
|
|
1275
|
-
reason.startsWith("plan_steps_too_few(") ||
|
|
1276
|
-
reason === "missing_self_assessment_scores" ||
|
|
1277
|
-
reason === "missing_strict_evaluation" ||
|
|
1278
|
-
reason === "strict_evaluation_missing_overall_score" ||
|
|
1279
|
-
reason === "strict_evaluation_missing_decision" ||
|
|
1280
|
-
reason === "strict_evaluation_reason_too_short" ||
|
|
1281
|
-
reason.startsWith("strict_evaluation_not_accept(") ||
|
|
1282
|
-
reason.startsWith("strict_evaluation_score_below_threshold(") ||
|
|
1283
|
-
reason.startsWith("insufficient_evidence_ids(") ||
|
|
1284
|
-
reason.startsWith("unresolved_evidence_ids(") ||
|
|
1285
|
-
reason === "no_fulltext_backed_evidence" ||
|
|
1286
|
-
reason === "no_resolved_evidence");
|
|
1287
|
-
};
|
|
1288
|
-
const autoReviseHypothesis = (hypothesis, reasons) => {
|
|
1289
|
-
if (!reasons.some((reason) => isRepairableReason(reason)))
|
|
1290
|
-
return undefined;
|
|
1291
|
-
const revised = {
|
|
1292
|
-
...hypothesis,
|
|
1293
|
-
...(hypothesis.problemGap ? { problemGap: hypothesis.problemGap } : {}),
|
|
1294
|
-
...(hypothesis.proposedMechanism ? { proposedMechanism: hypothesis.proposedMechanism } : {}),
|
|
1295
|
-
...(hypothesis.noveltyRationale ? { noveltyRationale: hypothesis.noveltyRationale } : {}),
|
|
1296
|
-
...(hypothesis.dependencyPath ? { dependencyPath: [...hypothesis.dependencyPath] } : {}),
|
|
1297
|
-
...(hypothesis.falsifiablePredictions ? { falsifiablePredictions: [...hypothesis.falsifiablePredictions] } : {}),
|
|
1298
|
-
...(hypothesis.criticalAssumptions ? { criticalAssumptions: [...hypothesis.criticalAssumptions] } : {}),
|
|
1299
|
-
...(hypothesis.failureModes ? { failureModes: [...hypothesis.failureModes] } : {}),
|
|
1300
|
-
...(hypothesis.successCriteria ? { successCriteria: [...hypothesis.successCriteria] } : {}),
|
|
1301
|
-
...(hypothesis.strengths ? { strengths: [...hypothesis.strengths] } : {}),
|
|
1302
|
-
...(hypothesis.weaknesses ? { weaknesses: [...hypothesis.weaknesses] } : {}),
|
|
1303
|
-
...(hypothesis.planSteps ? { planSteps: [...hypothesis.planSteps] } : {}),
|
|
1304
|
-
...(hypothesis.evidenceIds ? { evidenceIds: [...hypothesis.evidenceIds] } : {}),
|
|
1305
|
-
...(hypothesis.strictEvaluation ? { strictEvaluation: { ...hypothesis.strictEvaluation } } : {}),
|
|
1306
|
-
};
|
|
1307
|
-
let changed = false;
|
|
1308
|
-
const seedEvidence = fullTextEvidenceIds.length > 0 ? fullTextEvidenceIds : anyEvidenceIds;
|
|
1309
|
-
if (seedEvidence.length > 0 && ((revised.evidenceIds?.length ?? 0) < MIN_HYPOTHESIS_EVIDENCE || reasons.some((item) => item.startsWith("unresolved_evidence_ids(") || item === "no_resolved_evidence" || item === "no_fulltext_backed_evidence"))) {
|
|
1310
|
-
revised.evidenceIds = uniqueText([...(revised.evidenceIds ?? []), ...seedEvidence]).slice(0, Math.max(MIN_HYPOTHESIS_EVIDENCE, 4));
|
|
1311
|
-
changed = true;
|
|
1312
|
-
}
|
|
1313
|
-
while ((revised.dependencyPath?.length ?? 0) < MIN_HYPOTHESIS_DEPENDENCY_STEPS) {
|
|
1314
|
-
revised.dependencyPath = [
|
|
1315
|
-
...(revised.dependencyPath ?? []),
|
|
1316
|
-
revised.dependencyPath && revised.dependencyPath.length > 0
|
|
1317
|
-
? "Prior evidence accumulation provides an additional dependency step for this hypothesis."
|
|
1318
|
-
: "This hypothesis is grounded in accumulated cross-paper evidence from current run outputs.",
|
|
1319
|
-
];
|
|
1320
|
-
changed = true;
|
|
1321
|
-
}
|
|
1322
|
-
if (!revised.problemGap || normalizeText(revised.problemGap).length < 24) {
|
|
1323
|
-
revised.problemGap =
|
|
1324
|
-
"Current literature shows evidence signals, but no validated design rule translates these signals into a reproducible intervention.";
|
|
1325
|
-
changed = true;
|
|
1326
|
-
}
|
|
1327
|
-
if (!revised.proposedMechanism || normalizeText(revised.proposedMechanism).length < 24) {
|
|
1328
|
-
revised.proposedMechanism =
|
|
1329
|
-
"Use evidence-linked control variables to adapt method configuration online, then verify whether the control action improves target metrics under fixed budget.";
|
|
1330
|
-
changed = true;
|
|
1331
|
-
}
|
|
1332
|
-
if (!revised.noveltyRationale || normalizeText(revised.noveltyRationale).length < 24) {
|
|
1333
|
-
revised.noveltyRationale =
|
|
1334
|
-
"Prior work reports signals independently; this hypothesis couples them into one executable control rule with explicit falsification conditions.";
|
|
1335
|
-
changed = true;
|
|
1336
|
-
}
|
|
1337
|
-
while ((revised.falsifiablePredictions?.length ?? 0) < MIN_HYPOTHESIS_PREDICTIONS) {
|
|
1338
|
-
const idx = revised.falsifiablePredictions?.length ?? 0;
|
|
1339
|
-
revised.falsifiablePredictions = [
|
|
1340
|
-
...(revised.falsifiablePredictions ?? []),
|
|
1341
|
-
idx === 0
|
|
1342
|
-
? "If the proposed mechanism is valid, primary metric improves versus fixed baseline under matched budget."
|
|
1343
|
-
: "If mechanism signal is ablated, improvement should disappear or significantly shrink.",
|
|
1344
|
-
];
|
|
1345
|
-
changed = true;
|
|
1346
|
-
}
|
|
1347
|
-
while ((revised.criticalAssumptions?.length ?? 0) < MIN_HYPOTHESIS_ASSUMPTIONS) {
|
|
1348
|
-
const idx = revised.criticalAssumptions?.length ?? 0;
|
|
1349
|
-
revised.criticalAssumptions = [
|
|
1350
|
-
...(revised.criticalAssumptions ?? []),
|
|
1351
|
-
idx === 0
|
|
1352
|
-
? "Evidence signals remain stable enough across runs to drive adaptation decisions."
|
|
1353
|
-
: "Evaluation datasets and task settings reflect the intended deployment regime.",
|
|
1354
|
-
];
|
|
1355
|
-
changed = true;
|
|
1356
|
-
}
|
|
1357
|
-
while ((revised.failureModes?.length ?? 0) < MIN_HYPOTHESIS_FAILURE_MODES) {
|
|
1358
|
-
revised.failureModes = [
|
|
1359
|
-
...(revised.failureModes ?? []),
|
|
1360
|
-
"Signal noise or distribution shift causes unstable control actions and nullifies expected gains.",
|
|
1361
|
-
];
|
|
1362
|
-
changed = true;
|
|
1363
|
-
}
|
|
1364
|
-
while ((revised.successCriteria?.length ?? 0) < MIN_HYPOTHESIS_SUCCESS_CRITERIA) {
|
|
1365
|
-
const idx = revised.successCriteria?.length ?? 0;
|
|
1366
|
-
revised.successCriteria = [
|
|
1367
|
-
...(revised.successCriteria ?? []),
|
|
1368
|
-
idx === 0
|
|
1369
|
-
? "Primary metric improves by a pre-registered margin against strongest baseline under matched compute."
|
|
1370
|
-
: "At least one ablation confirms the claimed mechanism rather than incidental tuning effects.",
|
|
1371
|
-
];
|
|
1372
|
-
changed = true;
|
|
1373
|
-
}
|
|
1374
|
-
while ((revised.strengths?.length ?? 0) < MIN_HYPOTHESIS_STRENGTHS) {
|
|
1375
|
-
revised.strengths = [
|
|
1376
|
-
...(revised.strengths ?? []),
|
|
1377
|
-
revised.strengths && revised.strengths.length > 0
|
|
1378
|
-
? "The proposed idea has an explicit implementation path and measurable outcomes."
|
|
1379
|
-
: "The hypothesis is evidence-grounded and directly connected to current literature signals.",
|
|
1380
|
-
];
|
|
1381
|
-
changed = true;
|
|
1382
|
-
}
|
|
1383
|
-
while ((revised.weaknesses?.length ?? 0) < MIN_HYPOTHESIS_WEAKNESSES) {
|
|
1384
|
-
revised.weaknesses = [
|
|
1385
|
-
...(revised.weaknesses ?? []),
|
|
1386
|
-
revised.weaknesses && revised.weaknesses.length > 0
|
|
1387
|
-
? "Generality may be limited across domains without additional validation."
|
|
1388
|
-
: "Potential sensitivity to data distribution and setup assumptions.",
|
|
1389
|
-
];
|
|
1390
|
-
changed = true;
|
|
1391
|
-
}
|
|
1392
|
-
const defaultPlanStepPool = [
|
|
1393
|
-
"Implement a reproducible baseline first (include a lightweight baseline such as random forest when applicable).",
|
|
1394
|
-
"Implement the proposed method and compare under matched compute/data budgets.",
|
|
1395
|
-
"Run ablation and failure-case analysis, then update accept/revise/reject decision.",
|
|
1396
|
-
];
|
|
1397
|
-
while ((revised.planSteps?.length ?? 0) < MIN_HYPOTHESIS_PLAN_STEPS) {
|
|
1398
|
-
const idx = revised.planSteps?.length ?? 0;
|
|
1399
|
-
revised.planSteps = [...(revised.planSteps ?? []), defaultPlanStepPool[Math.min(idx, defaultPlanStepPool.length - 1)]];
|
|
1400
|
-
changed = true;
|
|
1401
|
-
}
|
|
1402
|
-
if (typeof revised.novelty !== "number" ||
|
|
1403
|
-
!Number.isFinite(revised.novelty) ||
|
|
1404
|
-
typeof revised.feasibility !== "number" ||
|
|
1405
|
-
!Number.isFinite(revised.feasibility) ||
|
|
1406
|
-
typeof revised.impact !== "number" ||
|
|
1407
|
-
!Number.isFinite(revised.impact)) {
|
|
1408
|
-
revised.novelty = Number((revised.novelty ?? 3.8).toFixed(2));
|
|
1409
|
-
revised.feasibility = Number((revised.feasibility ?? 3.6).toFixed(2));
|
|
1410
|
-
revised.impact = Number((revised.impact ?? 3.8).toFixed(2));
|
|
1411
|
-
changed = true;
|
|
1412
|
-
}
|
|
1413
|
-
const strictOverallScore = typeof revised.strictEvaluation?.overallScore === "number" && Number.isFinite(revised.strictEvaluation.overallScore)
|
|
1414
|
-
? revised.strictEvaluation.overallScore
|
|
1415
|
-
: Math.max(MIN_HYPOTHESIS_STRICT_ACCEPT_SCORE, Number((((revised.novelty ?? 3.5) + (revised.feasibility ?? 3.5) + (revised.impact ?? 3.5)) / 3 * 20).toFixed(2)));
|
|
1416
|
-
const strictReason = revised.strictEvaluation?.reason && normalizeText(revised.strictEvaluation.reason).length >= 16
|
|
1417
|
-
? revised.strictEvaluation.reason
|
|
1418
|
-
: "Auto-revised by hypothesis gate: structure, evidence, and execution plan now satisfy acceptance criteria.";
|
|
1419
|
-
if (!revised.strictEvaluation ||
|
|
1420
|
-
revised.strictEvaluation.decision !== "accept" ||
|
|
1421
|
-
typeof revised.strictEvaluation.overallScore !== "number" ||
|
|
1422
|
-
!Number.isFinite(revised.strictEvaluation.overallScore) ||
|
|
1423
|
-
revised.strictEvaluation.overallScore < MIN_HYPOTHESIS_STRICT_ACCEPT_SCORE ||
|
|
1424
|
-
normalizeText(revised.strictEvaluation.reason ?? "").length < 16) {
|
|
1425
|
-
revised.strictEvaluation = {
|
|
1426
|
-
overallScore: Number(Math.max(strictOverallScore, MIN_HYPOTHESIS_STRICT_ACCEPT_SCORE).toFixed(2)),
|
|
1427
|
-
decision: "accept",
|
|
1428
|
-
reason: strictReason,
|
|
1429
|
-
};
|
|
1430
|
-
changed = true;
|
|
1431
|
-
}
|
|
1432
|
-
return changed ? revised : undefined;
|
|
1433
|
-
};
|
|
1434
|
-
for (const hypothesis of args.hypotheses) {
|
|
1435
|
-
const firstReasons = evaluateHypothesisReasons(hypothesis);
|
|
1436
|
-
if (firstReasons.length === 0) {
|
|
1437
|
-
acceptedHypotheses.push(hypothesis);
|
|
1438
|
-
audits.push({
|
|
1439
|
-
hypothesis,
|
|
1440
|
-
accepted: true,
|
|
1441
|
-
reasons: [],
|
|
1442
|
-
autoRevised: false,
|
|
1443
|
-
});
|
|
1444
|
-
continue;
|
|
1445
|
-
}
|
|
1446
|
-
const autoRevised = autoReviseHypothesis(hypothesis, firstReasons);
|
|
1447
|
-
if (autoRevised) {
|
|
1448
|
-
const secondReasons = evaluateHypothesisReasons(autoRevised);
|
|
1449
|
-
if (secondReasons.length === 0) {
|
|
1450
|
-
acceptedHypotheses.push(autoRevised);
|
|
1451
|
-
audits.push({
|
|
1452
|
-
hypothesis: autoRevised,
|
|
1453
|
-
accepted: true,
|
|
1454
|
-
reasons: [],
|
|
1455
|
-
autoRevised: true,
|
|
1456
|
-
});
|
|
1457
|
-
continue;
|
|
1458
|
-
}
|
|
1459
|
-
audits.push({
|
|
1460
|
-
hypothesis: autoRevised,
|
|
1461
|
-
accepted: false,
|
|
1462
|
-
reasons: secondReasons,
|
|
1463
|
-
autoRevised: true,
|
|
1464
|
-
});
|
|
1465
|
-
for (const reason of secondReasons)
|
|
1466
|
-
rejectionReasonSet.add(reason);
|
|
1467
|
-
continue;
|
|
1468
|
-
}
|
|
1469
|
-
const reasons = firstReasons;
|
|
1470
|
-
if (reasons.length > 0) {
|
|
1471
|
-
audits.push({
|
|
1472
|
-
hypothesis,
|
|
1473
|
-
accepted: false,
|
|
1474
|
-
reasons,
|
|
1475
|
-
autoRevised: false,
|
|
1476
|
-
});
|
|
1477
|
-
for (const reason of reasons)
|
|
1478
|
-
rejectionReasonSet.add(reason);
|
|
1479
|
-
continue;
|
|
1480
|
-
}
|
|
1481
|
-
}
|
|
1482
|
-
return {
|
|
1483
|
-
acceptedHypotheses,
|
|
1484
|
-
audits,
|
|
1485
|
-
gate: {
|
|
1486
|
-
accepted: acceptedHypotheses.length,
|
|
1487
|
-
rejected: Math.max(0, args.hypotheses.length - acceptedHypotheses.length),
|
|
1488
|
-
rejectionReasons: [...rejectionReasonSet].slice(0, MAX_HYPOTHESIS_REJECTION_REASONS),
|
|
1489
|
-
},
|
|
1490
|
-
};
|
|
1491
|
-
}
|
|
1492
|
-
function toDayStartMs(day) {
|
|
1493
|
-
const ts = Date.parse(`${day}T00:00:00.000Z`);
|
|
1494
|
-
return Number.isFinite(ts) ? ts : undefined;
|
|
1495
|
-
}
|
|
1496
|
-
function deriveTriggerState(args) {
|
|
1497
|
-
const sorted = [...args.recentChangeStats].sort((a, b) => b.day.localeCompare(a.day));
|
|
1498
|
-
// consecutive days from latest day with NEW/REVISE > 0
|
|
1499
|
-
let consecutiveNewReviseDays = 0;
|
|
1500
|
-
let expectedDayMs;
|
|
1501
|
-
for (const item of sorted) {
|
|
1502
|
-
const dayMs = toDayStartMs(item.day);
|
|
1503
|
-
if (dayMs === undefined)
|
|
1504
|
-
continue;
|
|
1505
|
-
const hasSignal = item.newCount > 0 || item.reviseCount > 0;
|
|
1506
|
-
if (!hasSignal)
|
|
1507
|
-
break;
|
|
1508
|
-
if (expectedDayMs === undefined) {
|
|
1509
|
-
consecutiveNewReviseDays = 1;
|
|
1510
|
-
expectedDayMs = dayMs - 24 * 60 * 60 * 1000;
|
|
1511
|
-
continue;
|
|
1512
|
-
}
|
|
1513
|
-
if (dayMs === expectedDayMs) {
|
|
1514
|
-
consecutiveNewReviseDays += 1;
|
|
1515
|
-
expectedDayMs = dayMs - 24 * 60 * 60 * 1000;
|
|
1516
|
-
continue;
|
|
1517
|
-
}
|
|
1518
|
-
break;
|
|
1519
|
-
}
|
|
1520
|
-
const sevenDaysAgo = args.nowMs - 7 * 24 * 60 * 60 * 1000;
|
|
1521
|
-
let bridgeCount7d = 0;
|
|
1522
|
-
for (const item of sorted) {
|
|
1523
|
-
const dayMs = toDayStartMs(item.day);
|
|
1524
|
-
if (dayMs === undefined)
|
|
1525
|
-
continue;
|
|
1526
|
-
if (dayMs < sevenDaysAgo)
|
|
1527
|
-
continue;
|
|
1528
|
-
bridgeCount7d += Math.max(0, Math.floor(item.bridgeCount));
|
|
1529
|
-
}
|
|
1530
|
-
return {
|
|
1531
|
-
consecutiveNewReviseDays,
|
|
1532
|
-
bridgeCount7d,
|
|
1533
|
-
unreadCoreBacklog: Math.max(0, Math.floor(args.unreadCoreBacklog)),
|
|
1534
|
-
lastUpdatedAtMs: args.nowMs,
|
|
1535
|
-
};
|
|
1536
|
-
}
|
|
1537
685
|
export async function commitKnowledgeRun(input) {
|
|
1538
686
|
const project = await resolveProjectContext({
|
|
1539
687
|
projectId: input.projectId,
|
|
@@ -1558,7 +706,7 @@ export async function commitKnowledgeRun(input) {
|
|
|
1558
706
|
const explorationTrace = (knowledgeState.explorationTrace ?? [])
|
|
1559
707
|
.map(normalizeTrace)
|
|
1560
708
|
.filter((item) => Boolean(item));
|
|
1561
|
-
const
|
|
709
|
+
const knowledgeChanges = (knowledgeState.knowledgeChanges ?? [])
|
|
1562
710
|
.map(normalizeChange)
|
|
1563
711
|
.filter((item) => Boolean(item));
|
|
1564
712
|
const knowledgeUpdates = (knowledgeState.knowledgeUpdates ?? [])
|
|
@@ -1585,12 +733,10 @@ export async function commitKnowledgeRun(input) {
|
|
|
1585
733
|
topic: normalizeText(input.topic),
|
|
1586
734
|
topicKey: streamKey,
|
|
1587
735
|
projectId: project.projectId,
|
|
1588
|
-
lastRunProfile: defaultRunProfile(),
|
|
1589
736
|
totalRuns: 0,
|
|
1590
737
|
totalHypotheses: 0,
|
|
1591
738
|
knowledgeTopics: [],
|
|
1592
739
|
paperNotes: [],
|
|
1593
|
-
triggerState: defaultTriggerState(),
|
|
1594
740
|
recentFullTextReadCount: 0,
|
|
1595
741
|
recentNotFullTextReadCount: 0,
|
|
1596
742
|
lastQualityGate: defaultQualityGateState(),
|
|
@@ -1601,16 +747,14 @@ export async function commitKnowledgeRun(input) {
|
|
|
1601
747
|
recentHypotheses: [],
|
|
1602
748
|
recentChangeStats: [],
|
|
1603
749
|
lastExplorationTrace: [],
|
|
1604
|
-
lastReflectionTasks: [],
|
|
1605
|
-
lastHypothesisGate: defaultHypothesisGateState(),
|
|
1606
750
|
};
|
|
1607
751
|
const paperIds = mergePapers(corePapers, explorationPapers)
|
|
1608
752
|
.map((paper) => paper.id || paper.url || paper.title || "")
|
|
1609
753
|
.map((value) => normalizeText(value))
|
|
1610
754
|
.filter((value) => value.length > 0);
|
|
1611
|
-
const
|
|
1612
|
-
|
|
1613
|
-
buildRunFingerprint({
|
|
755
|
+
const runId = input.runId?.trim()
|
|
756
|
+
? sanitizeId(input.runId)
|
|
757
|
+
: buildRunFingerprint({
|
|
1614
758
|
scope: stream.scope,
|
|
1615
759
|
topic: stream.topic,
|
|
1616
760
|
status: input.status,
|
|
@@ -1618,30 +762,15 @@ export async function commitKnowledgeRun(input) {
|
|
|
1618
762
|
paperIds,
|
|
1619
763
|
note: input.note,
|
|
1620
764
|
});
|
|
1621
|
-
const inferredRunProfile = input.knowledgeState?.runLog?.runProfile === "strict" || input.knowledgeState?.runLog?.runProfile === "fast"
|
|
1622
|
-
? input.knowledgeState.runLog.runProfile
|
|
1623
|
-
: input.knowledgeState?.runLog?.requiredCorePapers !== undefined ||
|
|
1624
|
-
input.knowledgeState?.runLog?.requiredFullTextCoveragePct !== undefined
|
|
1625
|
-
? "strict"
|
|
1626
|
-
: defaultRunProfile();
|
|
1627
765
|
if (stream.recentRunIds.includes(runId)) {
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
runId,
|
|
1637
|
-
createdProject: project.created,
|
|
1638
|
-
};
|
|
1639
|
-
}
|
|
1640
|
-
const collisionTag = createHash("sha1")
|
|
1641
|
-
.update(`${nowMs}\n${paperIds.join("|")}\n${input.status ?? ""}\n${input.note ?? ""}`)
|
|
1642
|
-
.digest("hex")
|
|
1643
|
-
.slice(0, 8);
|
|
1644
|
-
runId = `${runId}-r${collisionTag}`;
|
|
766
|
+
root.streams[streamKey] = stream;
|
|
767
|
+
return {
|
|
768
|
+
projectId: project.projectId,
|
|
769
|
+
streamKey,
|
|
770
|
+
summary: toSummary(stream),
|
|
771
|
+
runId,
|
|
772
|
+
createdProject: project.created,
|
|
773
|
+
};
|
|
1645
774
|
}
|
|
1646
775
|
const rootPath = getKnowledgeStateRoot(project.projectPath);
|
|
1647
776
|
const logDir = path.join(rootPath, "logs");
|
|
@@ -1649,8 +778,6 @@ export async function commitKnowledgeRun(input) {
|
|
|
1649
778
|
const knowledgeDir = path.join(rootPath, "knowledge");
|
|
1650
779
|
const paperNotesDir = path.join(rootPath, "paper_notes");
|
|
1651
780
|
const hypothesesDir = path.join(rootPath, "hypotheses");
|
|
1652
|
-
const rejectedHypothesesDir = path.join(hypothesesDir, "rejected");
|
|
1653
|
-
await mkdir(rejectedHypothesesDir, { recursive: true });
|
|
1654
781
|
await appendMarkdown(path.join(logDir, `day-${dayKey}-ingest.md`), renderIngestLogMarkdown({ now: nowIso, runId, scope: stream.scope, topic: stream.topic, papers: corePapers }));
|
|
1655
782
|
await appendMarkdown(path.join(logDir, `day-${dayKey}-exploration.md`), renderExplorationLogMarkdown({
|
|
1656
783
|
now: nowIso,
|
|
@@ -1658,67 +785,18 @@ export async function commitKnowledgeRun(input) {
|
|
|
1658
785
|
trace: explorationTrace,
|
|
1659
786
|
papers: explorationPapers,
|
|
1660
787
|
}));
|
|
1661
|
-
const mergedRunPapers = mergePapers(corePapers, explorationPapers);
|
|
1662
|
-
const changeSanitization = sanitizeKnowledgeChanges({
|
|
1663
|
-
changes: submittedKnowledgeChanges,
|
|
1664
|
-
allRunPapers: mergedRunPapers,
|
|
1665
|
-
});
|
|
1666
|
-
const knowledgeChanges = changeSanitization.changes;
|
|
1667
788
|
await appendMarkdown(path.join(dailyDir, `day-${dayKey}.md`), renderDailyChangesMarkdown({ now: nowIso, runId, topic: stream.topic, changes: knowledgeChanges }));
|
|
1668
|
-
const
|
|
1669
|
-
topic: stream.topic,
|
|
1670
|
-
changes: knowledgeChanges,
|
|
1671
|
-
trace: explorationTrace,
|
|
1672
|
-
corePapers,
|
|
1673
|
-
});
|
|
1674
|
-
await appendMarkdown(path.join(logDir, `day-${dayKey}-reflection.md`), renderReflectionLogMarkdown({
|
|
1675
|
-
now: nowIso,
|
|
1676
|
-
runId,
|
|
1677
|
-
tasks: reflectionTasks,
|
|
1678
|
-
}));
|
|
1679
|
-
const submittedHypotheses = hypotheses;
|
|
1680
|
-
const hypothesisEval = applyHypothesisGate({
|
|
1681
|
-
hypotheses: submittedHypotheses,
|
|
1682
|
-
allRunPapers: mergedRunPapers,
|
|
1683
|
-
knowledgeChanges,
|
|
1684
|
-
runProfile: inferredRunProfile,
|
|
1685
|
-
});
|
|
1686
|
-
const acceptedHypotheses = hypothesisEval.acceptedHypotheses;
|
|
1687
|
-
const runArtifactCount = corePapers.length +
|
|
1688
|
-
explorationPapers.length +
|
|
1689
|
-
explorationTrace.length +
|
|
1690
|
-
knowledgeChanges.length +
|
|
1691
|
-
knowledgeUpdates.length +
|
|
1692
|
-
submittedHypotheses.length;
|
|
1693
|
-
const hasRunError = Boolean(input.knowledgeState?.runLog?.error && normalizeText(input.knowledgeState.runLog.error).length > 0);
|
|
789
|
+
const mergedRunPapers = mergePapers(corePapers, explorationPapers);
|
|
1694
790
|
const qualityEval = applyQualityGates({
|
|
1695
791
|
corePapers,
|
|
1696
792
|
allRunPapers: mergedRunPapers,
|
|
1697
|
-
explorationTrace,
|
|
1698
|
-
reflectionTasks,
|
|
1699
793
|
knowledgeChanges,
|
|
1700
794
|
knowledgeUpdates,
|
|
1701
|
-
hypotheses
|
|
1702
|
-
hypothesisGate: hypothesisEval.gate,
|
|
1703
|
-
requiredCorePapers: input.knowledgeState?.runLog?.requiredCorePapers,
|
|
1704
|
-
requiredFullTextCoveragePct: input.knowledgeState?.runLog?.requiredFullTextCoveragePct,
|
|
1705
|
-
hasAuditableArtifacts: runArtifactCount > 0,
|
|
1706
|
-
hasRunError,
|
|
795
|
+
hypotheses,
|
|
1707
796
|
});
|
|
1708
|
-
if (changeSanitization.droppedBridgeCount > 0) {
|
|
1709
|
-
qualityEval.qualityGate.warnings.push(`bridge_dropped_due_to_ungrounded_evidence(${changeSanitization.droppedBridgeCount})`);
|
|
1710
|
-
qualityEval.qualityGate.reasons.push(`bridge_dropped_due_to_ungrounded_evidence(${changeSanitization.droppedBridgeCount})`);
|
|
1711
|
-
if (qualityEval.qualityGate.severity === "ok") {
|
|
1712
|
-
qualityEval.qualityGate.severity = "warn";
|
|
1713
|
-
}
|
|
1714
|
-
}
|
|
1715
797
|
const requestedStatus = normalizeText(input.status ?? "ok");
|
|
1716
|
-
const
|
|
1717
|
-
|
|
1718
|
-
runArtifactCount,
|
|
1719
|
-
hasRunError,
|
|
1720
|
-
qualityBlocking: qualityEval.qualityGate.blocking,
|
|
1721
|
-
});
|
|
798
|
+
const qualitySensitiveStatus = requestedStatus === "ok" || requestedStatus === "fallback_representative";
|
|
799
|
+
const effectiveStatus = qualitySensitiveStatus && !qualityEval.qualityGate.passed ? "degraded_quality" : requestedStatus;
|
|
1722
800
|
const topicToUpdates = new Map();
|
|
1723
801
|
for (const update of knowledgeUpdates) {
|
|
1724
802
|
const key = slugifyTopic(update.topic);
|
|
@@ -1756,11 +834,9 @@ export async function commitKnowledgeRun(input) {
|
|
|
1756
834
|
}
|
|
1757
835
|
stream.paperNotes = [...new Set([...runPaperNoteFiles, ...stream.paperNotes])].slice(0, MAX_PAPER_NOTES);
|
|
1758
836
|
const recentHypothesisSummaries = [];
|
|
1759
|
-
const rejectedHypothesisArtifacts = [];
|
|
1760
837
|
let seq = stream.totalHypotheses;
|
|
1761
|
-
let rejectedSeq = 0;
|
|
1762
838
|
const dayToken = dayKey.replace(/-/g, "");
|
|
1763
|
-
for (const hypothesis of
|
|
839
|
+
for (const hypothesis of hypotheses) {
|
|
1764
840
|
seq += 1;
|
|
1765
841
|
const hypothesisId = hypothesis.id && hypothesis.id.length > 0 ? sanitizeId(hypothesis.id) : `hyp-${dayToken}-${String(seq).padStart(4, "0")}`;
|
|
1766
842
|
const file = `${hypothesisId}.md`;
|
|
@@ -1771,88 +847,6 @@ export async function commitKnowledgeRun(input) {
|
|
|
1771
847
|
trigger: hypothesis.trigger,
|
|
1772
848
|
createdAtMs: nowMs,
|
|
1773
849
|
file,
|
|
1774
|
-
...(typeof hypothesis.strictEvaluation?.overallScore === "number"
|
|
1775
|
-
? { strictOverallScore: hypothesis.strictEvaluation.overallScore }
|
|
1776
|
-
: {}),
|
|
1777
|
-
...(hypothesis.strictEvaluation?.decision
|
|
1778
|
-
? { strictDecision: hypothesis.strictEvaluation.decision }
|
|
1779
|
-
: {}),
|
|
1780
|
-
});
|
|
1781
|
-
}
|
|
1782
|
-
for (const audit of hypothesisEval.audits.filter((item) => !item.accepted)) {
|
|
1783
|
-
rejectedSeq += 1;
|
|
1784
|
-
const sanitizedSourceId = sanitizeId(audit.hypothesis.id ?? "");
|
|
1785
|
-
const hypothesisId = sanitizedSourceId.length > 0
|
|
1786
|
-
? `${sanitizedSourceId}-rejected`
|
|
1787
|
-
: `hyp-${dayToken}-${String(rejectedSeq).padStart(4, "0")}-rejected`;
|
|
1788
|
-
const file = `${hypothesisId}.md`;
|
|
1789
|
-
const evidenceLines = audit.hypothesis.evidenceIds && audit.hypothesis.evidenceIds.length > 0
|
|
1790
|
-
? audit.hypothesis.evidenceIds.map((id, idx) => `${idx + 1}. ${id}`)
|
|
1791
|
-
: ["1. (none)"];
|
|
1792
|
-
const dependencyLines = audit.hypothesis.dependencyPath && audit.hypothesis.dependencyPath.length > 0
|
|
1793
|
-
? audit.hypothesis.dependencyPath.map((item, idx) => `${idx + 1}. ${item}`)
|
|
1794
|
-
: ["1. (none)"];
|
|
1795
|
-
const reasons = audit.reasons.length > 0 ? audit.reasons : ["rejected_without_reason"];
|
|
1796
|
-
const content = [
|
|
1797
|
-
`# ${hypothesisId}`,
|
|
1798
|
-
"",
|
|
1799
|
-
`- Run: ${runId}`,
|
|
1800
|
-
"- Gate Decision: rejected",
|
|
1801
|
-
`- Auto Revised: ${audit.autoRevised ? "yes" : "no"}`,
|
|
1802
|
-
"",
|
|
1803
|
-
"## Rejection Reasons",
|
|
1804
|
-
...reasons.map((reason, idx) => `${idx + 1}. ${reason}`),
|
|
1805
|
-
"",
|
|
1806
|
-
"## Statement",
|
|
1807
|
-
audit.hypothesis.statement,
|
|
1808
|
-
"",
|
|
1809
|
-
"## Problem Gap",
|
|
1810
|
-
audit.hypothesis.problemGap ?? "pending",
|
|
1811
|
-
"",
|
|
1812
|
-
"## Proposed Mechanism",
|
|
1813
|
-
audit.hypothesis.proposedMechanism ?? "pending",
|
|
1814
|
-
"",
|
|
1815
|
-
"## Novelty Rationale",
|
|
1816
|
-
audit.hypothesis.noveltyRationale ?? "pending",
|
|
1817
|
-
"",
|
|
1818
|
-
"## Trigger",
|
|
1819
|
-
audit.hypothesis.trigger,
|
|
1820
|
-
"",
|
|
1821
|
-
"## Evidence IDs",
|
|
1822
|
-
...evidenceLines,
|
|
1823
|
-
"",
|
|
1824
|
-
"## Dependency Path",
|
|
1825
|
-
...dependencyLines,
|
|
1826
|
-
"",
|
|
1827
|
-
"## Falsifiable Predictions",
|
|
1828
|
-
...(audit.hypothesis.falsifiablePredictions && audit.hypothesis.falsifiablePredictions.length > 0
|
|
1829
|
-
? audit.hypothesis.falsifiablePredictions.map((item, idx) => `${idx + 1}. ${item}`)
|
|
1830
|
-
: ["1. (none)"]),
|
|
1831
|
-
"",
|
|
1832
|
-
"## Critical Assumptions",
|
|
1833
|
-
...(audit.hypothesis.criticalAssumptions && audit.hypothesis.criticalAssumptions.length > 0
|
|
1834
|
-
? audit.hypothesis.criticalAssumptions.map((item, idx) => `${idx + 1}. ${item}`)
|
|
1835
|
-
: ["1. (none)"]),
|
|
1836
|
-
"",
|
|
1837
|
-
"## Failure Modes",
|
|
1838
|
-
...(audit.hypothesis.failureModes && audit.hypothesis.failureModes.length > 0
|
|
1839
|
-
? audit.hypothesis.failureModes.map((item, idx) => `${idx + 1}. ${item}`)
|
|
1840
|
-
: ["1. (none)"]),
|
|
1841
|
-
"",
|
|
1842
|
-
"## Success Criteria",
|
|
1843
|
-
...(audit.hypothesis.successCriteria && audit.hypothesis.successCriteria.length > 0
|
|
1844
|
-
? audit.hypothesis.successCriteria.map((item, idx) => `${idx + 1}. ${item}`)
|
|
1845
|
-
: ["1. (none)"]),
|
|
1846
|
-
"",
|
|
1847
|
-
"> Persisted for traceability. This hypothesis did not pass hypothesis_gate in this run.",
|
|
1848
|
-
"",
|
|
1849
|
-
].join("\n");
|
|
1850
|
-
await writeFile(path.join(rejectedHypothesesDir, file), content, "utf-8");
|
|
1851
|
-
rejectedHypothesisArtifacts.push({
|
|
1852
|
-
id: hypothesisId,
|
|
1853
|
-
file: path.join("rejected", file),
|
|
1854
|
-
reasons: reasons.slice(0, MAX_HYPOTHESIS_REJECTION_REASONS),
|
|
1855
|
-
autoRevised: audit.autoRevised,
|
|
1856
850
|
});
|
|
1857
851
|
}
|
|
1858
852
|
const fullTextStats = countFullTextStats(mergedRunPapers);
|
|
@@ -1860,7 +854,6 @@ export async function commitKnowledgeRun(input) {
|
|
|
1860
854
|
await writeFile(path.join(knowledgeDir, "_index.md"), renderKnowledgeIndexMarkdown({
|
|
1861
855
|
now: nowIso,
|
|
1862
856
|
topic: stream.topic,
|
|
1863
|
-
runProfile: inferredRunProfile,
|
|
1864
857
|
topicFiles: stream.knowledgeTopics,
|
|
1865
858
|
paperNotesCount: stream.paperNotes.length,
|
|
1866
859
|
totalHypotheses: stream.totalHypotheses + recentHypothesisSummaries.length,
|
|
@@ -1869,13 +862,10 @@ export async function commitKnowledgeRun(input) {
|
|
|
1869
862
|
notFullTextReadCount: fullTextStats.notFullTextReadCount,
|
|
1870
863
|
qualityGate: qualityEval.qualityGate,
|
|
1871
864
|
unreadCorePaperIds: qualityEval.unreadCorePaperIds,
|
|
1872
|
-
reflectionTasks,
|
|
1873
|
-
hypothesisGate: hypothesisEval.gate,
|
|
1874
865
|
lastStatus: effectiveStatus,
|
|
1875
866
|
}), "utf-8");
|
|
1876
867
|
const changeStat = countChangeStats(dayKey, runId, knowledgeChanges);
|
|
1877
868
|
stream.projectId = project.projectId;
|
|
1878
|
-
stream.lastRunProfile = inferredRunProfile;
|
|
1879
869
|
stream.totalRuns += 1;
|
|
1880
870
|
stream.totalHypotheses += recentHypothesisSummaries.length;
|
|
1881
871
|
stream.lastRunAtMs = nowMs;
|
|
@@ -1885,8 +875,6 @@ export async function commitKnowledgeRun(input) {
|
|
|
1885
875
|
stream.lastQualityGate = qualityEval.qualityGate;
|
|
1886
876
|
stream.lastUnreadCorePaperIds = qualityEval.unreadCorePaperIds;
|
|
1887
877
|
stream.lastExplorationTrace = explorationTrace.slice(0, MAX_LAST_TRACE);
|
|
1888
|
-
stream.lastReflectionTasks = reflectionTasks.slice(0, MAX_LAST_REFLECTION_TASKS);
|
|
1889
|
-
stream.lastHypothesisGate = hypothesisEval.gate;
|
|
1890
878
|
stream.recentPapers = mergePapers(mergedRunPapers, stream.recentPapers).slice(0, MAX_RECENT_PAPERS);
|
|
1891
879
|
stream.recentRunIds = [runId, ...stream.recentRunIds.filter((id) => id !== runId)].slice(0, MAX_RECENT_RUN_IDS);
|
|
1892
880
|
stream.recentHypothesisIds = [
|
|
@@ -1895,18 +883,11 @@ export async function commitKnowledgeRun(input) {
|
|
|
1895
883
|
].slice(0, MAX_RECENT_HYPOTHESES);
|
|
1896
884
|
stream.recentHypotheses = [...recentHypothesisSummaries, ...stream.recentHypotheses].slice(0, MAX_RECENT_HYPOTHESES);
|
|
1897
885
|
stream.recentChangeStats = [changeStat, ...stream.recentChangeStats].slice(0, MAX_RECENT_CHANGE_STATS);
|
|
1898
|
-
stream.triggerState = deriveTriggerState({
|
|
1899
|
-
recentChangeStats: stream.recentChangeStats,
|
|
1900
|
-
unreadCoreBacklog: qualityEval.unreadCorePaperIds.length,
|
|
1901
|
-
nowMs,
|
|
1902
|
-
});
|
|
1903
886
|
root.streams[streamKey] = stream;
|
|
1904
887
|
await saveStateAtomic(project.projectPath, root);
|
|
1905
888
|
await appendFile(path.join(logDir, `day-${dayKey}-run-details.jsonl`), `${JSON.stringify({
|
|
1906
889
|
ts: nowMs,
|
|
1907
|
-
run_id: runId,
|
|
1908
890
|
runId,
|
|
1909
|
-
run_profile: inferredRunProfile,
|
|
1910
891
|
scope: stream.scope,
|
|
1911
892
|
topic: stream.topic,
|
|
1912
893
|
streamKey,
|
|
@@ -1914,15 +895,9 @@ export async function commitKnowledgeRun(input) {
|
|
|
1914
895
|
corePapers,
|
|
1915
896
|
explorationPapers,
|
|
1916
897
|
explorationTrace,
|
|
1917
|
-
reflectionTasks,
|
|
1918
|
-
submittedKnowledgeChanges,
|
|
1919
898
|
knowledgeChanges,
|
|
1920
|
-
droppedBridgeCount: changeSanitization.droppedBridgeCount,
|
|
1921
899
|
knowledgeUpdates,
|
|
1922
|
-
hypotheses
|
|
1923
|
-
submittedHypotheses,
|
|
1924
|
-
hypothesisGate: hypothesisEval.gate,
|
|
1925
|
-
rejectedHypothesisArtifacts,
|
|
900
|
+
hypotheses,
|
|
1926
901
|
paperNoteFiles: runPaperNoteFiles,
|
|
1927
902
|
quality: {
|
|
1928
903
|
fullTextReadCount: fullTextStats.fullTextReadCount,
|
|
@@ -1938,9 +913,7 @@ export async function commitKnowledgeRun(input) {
|
|
|
1938
913
|
})}\n`, "utf-8");
|
|
1939
914
|
await appendEvent(project.projectPath, {
|
|
1940
915
|
ts: nowMs,
|
|
1941
|
-
run_id: runId,
|
|
1942
916
|
runId,
|
|
1943
|
-
run_profile: inferredRunProfile,
|
|
1944
917
|
scope: stream.scope,
|
|
1945
918
|
topic: stream.topic,
|
|
1946
919
|
streamKey,
|
|
@@ -1956,16 +929,8 @@ export async function commitKnowledgeRun(input) {
|
|
|
1956
929
|
qualityGate: qualityEval.qualityGate,
|
|
1957
930
|
unreadCorePaperIds: qualityEval.unreadCorePaperIds,
|
|
1958
931
|
downgradedHighConfidenceCount: qualityEval.downgradedHighConfidenceCount,
|
|
1959
|
-
submittedChangeCount: submittedKnowledgeChanges.length,
|
|
1960
932
|
changeCount: knowledgeChanges.length,
|
|
1961
|
-
droppedBridgeCount: changeSanitization.droppedBridgeCount,
|
|
1962
933
|
hypothesisCount: recentHypothesisSummaries.length,
|
|
1963
|
-
submittedHypothesisCount: submittedHypotheses.length,
|
|
1964
|
-
rejectedHypothesisCount: rejectedHypothesisArtifacts.length,
|
|
1965
|
-
hypothesisGate: hypothesisEval.gate,
|
|
1966
|
-
rejectedHypothesisArtifacts,
|
|
1967
|
-
triggerState: stream.triggerState,
|
|
1968
|
-
reflectionTasks,
|
|
1969
934
|
corePapers,
|
|
1970
935
|
explorationPapers,
|
|
1971
936
|
note: input.note,
|