noteconnection 1.8.0 → 1.9.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.md +257 -1803
- package/dist/src/agent_workspace.contract.parity.test.js +105 -421
- package/dist/src/agent_workspace.frontend.test.js +410 -11
- package/dist/src/android.knowledgebase.picker.contract.test.js +102 -0
- package/dist/src/appimage.patchelf.test.js +113 -0
- package/dist/src/appimage.portability.test.js +156 -0
- package/dist/src/backend/FileLoader.js +18 -4
- package/dist/src/backend/FileLoader.test.js +125 -0
- package/dist/src/backend/GraphBuilder.identity.test.js +86 -0
- package/dist/src/backend/GraphBuilder.js +66 -18
- package/dist/src/backend/GraphBuilder.matching.test.js +127 -0
- package/dist/src/backend/GraphMetrics.js +0 -3
- package/dist/src/backend/ResourceIdentity.js +155 -0
- package/dist/src/backend/ResourceIdentity.test.js +113 -0
- package/dist/src/backend/algorithms/CycleDetection.js +0 -1
- package/dist/src/backend/algorithms/HybridEngine.js +0 -3
- package/dist/src/backend/algorithms/LayoutEngine.js +0 -1
- package/dist/src/backend/algorithms/StatisticalAnalyzer.js +0 -4
- package/dist/src/backend/algorithms/TopologicalSort.js +0 -2
- package/dist/src/backend/build_dag.js +0 -1
- package/dist/src/capacitor.bridge.serialization.contract.test.js +3 -0
- package/dist/src/capacitor.runtime.contract.test.js +11 -2
- package/dist/src/core/Graph.js +138 -42
- package/dist/src/core/Graph.test.js +74 -0
- package/dist/src/core/NoteConnection.js +2 -2
- package/dist/src/core/PathBridge.js +265 -2
- package/dist/src/core/ResourceReference.js +17 -0
- package/dist/src/desktop.godot.pack.test.js +142 -0
- package/dist/src/desktop.runtime.graph.test.js +66 -0
- package/dist/src/export/WorkspaceExportBundle.js +44 -0
- package/dist/src/export/WorkspaceExportBundle.test.js +61 -0
- package/dist/src/foundation.release.evidence.contract.test.js +127 -9
- package/dist/src/foundation.sqlite.runtime.contract.test.js +6 -0
- package/dist/src/frontend/README.md +257 -1803
- package/dist/src/frontend/agent_workspace.js +665 -7
- package/dist/src/frontend/index.html +31 -2
- package/dist/src/frontend/knowledge_projection_contract.js +230 -0
- package/dist/src/frontend/knowledge_projection_store.js +214 -0
- package/dist/src/frontend/libs/path_core.js +158 -42
- package/dist/src/frontend/locales/en.json +32 -0
- package/dist/src/frontend/locales/zh.json +32 -0
- package/dist/src/frontend/mobile_budget_runtime.js +33 -0
- package/dist/src/frontend/mobile_exact_analyzer.js +393 -0
- package/dist/src/frontend/mobile_identity_contract.js +221 -0
- package/dist/src/frontend/mobile_semantic_comparator.js +264 -0
- package/dist/src/frontend/path.html +6 -2
- package/dist/src/frontend/simulationWorker.js +1 -1
- package/dist/src/frontend/source_manager.js +110 -4
- package/dist/src/frontend/storage_provider.js +661 -71
- package/dist/src/frontend/styles.css +107 -13
- package/dist/src/frontend/workspace_panes.js +111 -7
- package/dist/src/frontend.runtime.assets.contract.test.js +81 -0
- package/dist/src/graph.answer.operator.contract.test.js +72 -0
- package/dist/src/index.js +6 -2
- package/dist/src/index.knowledge-root.test.js +118 -0
- package/dist/src/indexing/IndexLifecycle.js +22 -0
- package/dist/src/indexing/IndexLifecycle.test.js +24 -0
- package/dist/src/knowledge.api.contract.test.js +4 -2
- package/dist/src/knowledge_projection.contract.test.js +134 -0
- package/dist/src/knowledge_projection_store.test.js +200 -0
- package/dist/src/learning/AnswerQualityEvaluation.js +153 -0
- package/dist/src/learning/AnswerQualityEvaluation.test.js +118 -0
- package/dist/src/learning/KnowledgeLearningPlatform.js +4687 -3892
- package/dist/src/learning/KnowledgeLearningPlatform.persistence.test.js +418 -0
- package/dist/src/learning/KnowledgeLearningPlatform.test.js +243 -6
- package/dist/src/learning/KnowledgeWorkspaceConversationRegression.js +25 -1
- package/dist/src/learning/KnowledgeWorkspaceConversationRegression.test.js +13 -5
- package/dist/src/learning/MeasurementEvidenceConflicts.test.js +78 -0
- package/dist/src/learning/PublicAnswerContract.test.js +85 -0
- package/dist/src/learning/PublicEvidenceSelection.test.js +94 -0
- package/dist/src/learning/PublicMeasurementDisclosure.test.js +54 -0
- package/dist/src/learning/agentConversationExecution.js +211 -0
- package/dist/src/learning/agentConversationExecution.test.js +209 -0
- package/dist/src/learning/agentConversationSerialization.js +266 -0
- package/dist/src/learning/agentConversationSerialization.test.js +165 -0
- package/dist/src/learning/agentResponseBudget.js +179 -0
- package/dist/src/learning/agentResponseBudget.test.js +97 -0
- package/dist/src/learning/agentWorkspaceCapabilityContracts.js +65 -0
- package/dist/src/learning/answerReleaseReview.js +1191 -250
- package/dist/src/learning/answerReleaseReview.test.js +1293 -7
- package/dist/src/learning/answerTaskPlan.js +473 -0
- package/dist/src/learning/conversationComposer.js +627 -386
- package/dist/src/learning/conversationComposer.test.js +1403 -0
- package/dist/src/learning/evidenceContextAssembler.js +312 -120
- package/dist/src/learning/graphAnswerCoverage.js +37 -0
- package/dist/src/learning/graphAnswerCoverage.test.js +93 -0
- package/dist/src/learning/graphAnswerCoverageCalibration.js +59 -0
- package/dist/src/learning/graphAnswerCoverageCalibration.test.js +46 -0
- package/dist/src/learning/graphAnswerFacts.js +94 -0
- package/dist/src/learning/graphAnswerFacts.test.js +39 -0
- package/dist/src/learning/graphAnswerPlan.js +908 -0
- package/dist/src/learning/graphAnswerPlan.test.js +907 -0
- package/dist/src/learning/graphAnswerQualityCalibration.js +255 -0
- package/dist/src/learning/graphAnswerQualityCalibration.test.js +72 -0
- package/dist/src/learning/graphAnswerQualityPolicy.js +30 -0
- package/dist/src/learning/graphClaimMatcher.js +104 -0
- package/dist/src/learning/graphConditionedContext.js +109 -0
- package/dist/src/learning/graphConditionedContext.test.js +99 -0
- package/dist/src/learning/graphContextAssembler.js +3 -13
- package/dist/src/learning/graphContextAssembler.test.js +2 -2
- package/dist/src/learning/graphExpansionPolicy.js +22 -0
- package/dist/src/learning/graphExpansionPolicy.test.js +33 -0
- package/dist/src/learning/identityMetadata.test.js +26 -0
- package/dist/src/learning/index.js +1 -0
- package/dist/src/learning/mobileAnswerProjection.js +104 -0
- package/dist/src/learning/mobileAnswerProjection.test.js +102 -0
- package/dist/src/learning/queryBackend.js +34 -10
- package/dist/src/learning/queryBackend.test.js +21 -0
- package/dist/src/learning/ragContextPack.js +115 -16
- package/dist/src/learning/ragContextPack.test.js +151 -0
- package/dist/src/learning/ragEvidenceQuality.js +96 -0
- package/dist/src/learning/ragEvidenceQuality.test.js +29 -0
- package/dist/src/learning/ragPublicText.js +67 -4
- package/dist/src/learning/ragPublicText.test.js +57 -0
- package/dist/src/learning/ragSufficiencyJudge.js +11 -1
- package/dist/src/learning/ragSufficiencyProviderJudge.js +16 -26
- package/dist/src/learning/ragSufficiencyProviderJudge.test.js +51 -0
- package/dist/src/learning/requestNormalization.js +106 -0
- package/dist/src/learning/requestNormalization.test.js +101 -0
- package/dist/src/learning/store.js +116 -12
- package/dist/src/learning/store.test.js +299 -0
- package/dist/src/learning/vectorAccelerationAdapter.js +22 -6
- package/dist/src/learning/vectorAccelerationAdapter.test.js +30 -0
- package/dist/src/learning/workspaceHydration.js +168 -0
- package/dist/src/learning/workspaceHydration.test.js +30 -0
- package/dist/src/license.policy.contract.test.js +9 -4
- package/dist/src/markdown/MarkdownGateway.js +4 -0
- package/dist/src/markdown/MarkdownGateway.test.js +59 -0
- package/dist/src/middleware/SseResponseWriter.js +122 -0
- package/dist/src/middleware/SseResponseWriter.test.js +54 -0
- package/dist/src/middleware/auth.js +28 -7
- package/dist/src/middleware/auth.test.js +33 -0
- package/dist/src/middleware/index.js +2 -1
- package/dist/src/mobile.android.evidence.contract.test.js +146 -0
- package/dist/src/mobile.android.signing.contract.test.js +66 -0
- package/dist/src/mobile.artifact.contract.test.js +144 -0
- package/dist/src/mobile.budget.contract.test.js +90 -0
- package/dist/src/mobile.canonical-id.readiness.test.js +54 -0
- package/dist/src/mobile.graph.parity.contract.test.js +207 -0
- package/dist/src/mobile.identity.contract.test.js +66 -0
- package/dist/src/mobile.identity.corpus.manifest.test.js +72 -0
- package/dist/src/mobile.identity.corpus.test.js +40 -0
- package/dist/src/mobile.native.recovery.contract.test.js +64 -0
- package/dist/src/mobile.pipeline.test.js +11 -1
- package/dist/src/mobile.profile.contract.test.js +225 -0
- package/dist/src/mobile.semantic.parity.test.js +92 -0
- package/dist/src/mobile_exact_analyzer.test.js +113 -0
- package/dist/src/notemd/ContentGenerator.js +4 -9
- package/dist/src/notemd/FileProcessor.js +4 -9
- package/dist/src/notemd/NotemdService.js +12 -17
- package/dist/src/notemd/Translator.js +4 -9
- package/dist/src/notemd/progressReporter.js +9 -0
- package/dist/src/notemd.server.integration.test.js +119 -4
- package/dist/src/notemd.workflow.pipeline.test.js +1 -1
- package/dist/src/pathbridge.handshake.contract.test.js +29 -0
- package/dist/src/pathbridge.host-adapter.contract.test.js +133 -0
- package/dist/src/pathcore.bundle.contract.test.js +8 -0
- package/dist/src/platform/ExportProfile.js +28 -0
- package/dist/src/platform/MobileBudget.js +11 -0
- package/dist/src/platform/PlatformCapabilities.js +14 -0
- package/dist/src/platform/PlatformCapabilities.test.js +6 -0
- package/dist/src/query_backend.external_http.integration.test.js +2 -2
- package/dist/src/release.godot.mirror.contract.test.js +28 -4
- package/dist/src/resources/ResourceRegistry.js +40 -0
- package/dist/src/resources/ResourceRegistry.test.js +36 -0
- package/dist/src/routes/index.js +0 -4
- package/dist/src/routes/knowledge.js +46 -33
- package/dist/src/routes/knowledgePayload.js +185 -0
- package/dist/src/routes/knowledgePayload.test.js +53 -0
- package/dist/src/routes/markdown.js +8 -0
- package/dist/src/routes/notemd.js +990 -234
- package/dist/src/routes/registry.contract.test.js +5 -2
- package/dist/src/routes/registry.shadow.contract.test.js +22 -0
- package/dist/src/routes/render.js +14 -51
- package/dist/src/runtime.capabilities.test.js +18 -2
- package/dist/src/server.js +566 -1090
- package/dist/src/server.migration.test.js +417 -15
- package/dist/src/sidecar.build.lock.contract.test.js +201 -0
- package/dist/src/sidecar.freshness.contract.test.js +184 -0
- package/dist/src/sidecar.replacement.boundary.contract.test.js +6 -3
- package/dist/src/sidecar.supply.readiness.contract.test.js +11 -0
- package/dist/src/simulation.worker.offline.test.js +104 -0
- package/dist/src/storage.provider.capacitor.content.contract.test.js +4 -1
- package/dist/src/storage.provider.contract.test.js +152 -1
- package/dist/src/tauri.frontend.build.contract.test.js +8 -0
- package/dist/src/tauri.window.evidence.execution.test.js +68 -0
- package/dist/src/utils/RuntimePaths.js +6 -0
- package/dist/src/utils/RuntimePaths.test.js +27 -0
- package/dist/src/windows.installer.build.test.js +109 -0
- package/dist/src/windows.installer.payload.test.js +76 -0
- package/dist/src/windows.installer.runtime.test.js +69 -0
- package/dist/src/workspace/WorkspaceRegistry.js +13 -0
- package/package.json +32 -10
- package/dist/src/routes/data.js +0 -267
- package/dist/src/routes/diagnostics.js +0 -51
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const answerReleaseReview_1 = require("./answerReleaseReview");
|
|
4
|
+
const graphAnswerPlan_1 = require("./graphAnswerPlan");
|
|
4
5
|
const scopedWaterglass = {
|
|
5
6
|
source: 'scoped',
|
|
6
7
|
workspaceId: 'waterglass',
|
|
@@ -202,6 +203,228 @@ function makeComparisonGraphContext(relationKind, leftTitle, rightTitle, overrid
|
|
|
202
203
|
};
|
|
203
204
|
}
|
|
204
205
|
describe('answerReleaseReview', () => {
|
|
206
|
+
test('does not treat standalone mathematical variable definitions as subject conflicts', () => {
|
|
207
|
+
const point = makeKnowledgePoint({
|
|
208
|
+
summary: 'The VFT model describes supercooled liquid viscosity as temperature changes.',
|
|
209
|
+
evidenceSnippet: 'The VFT model describes supercooled liquid viscosity as temperature changes.',
|
|
210
|
+
});
|
|
211
|
+
const review = (0, answerReleaseReview_1.reviewAnswerRelease)({
|
|
212
|
+
message: 'what is water glass?',
|
|
213
|
+
draftAnswer: 'Water glass is a transparent container. The VFT model describes supercooled liquid viscosity as temperature changes. $\\eta(T)$ is the viscosity at temperature T.',
|
|
214
|
+
knowledgePoints: [point],
|
|
215
|
+
citations: [point.citation],
|
|
216
|
+
usedScope: scopedWaterglass,
|
|
217
|
+
graphContext: makeGraphContext(),
|
|
218
|
+
ragContextPack: {
|
|
219
|
+
query: 'what is water glass?',
|
|
220
|
+
generatedAt: '2026-07-12T00:00:00.000Z',
|
|
221
|
+
sourceBoundary: 'direct_span_only',
|
|
222
|
+
budget: { maxFragments: 2, maxCharsPerFragment: 500, maxTotalChars: 900 },
|
|
223
|
+
fragments: [{
|
|
224
|
+
fragmentId: 'vft_context',
|
|
225
|
+
role: 'direct_support',
|
|
226
|
+
text: 'The VFT model describes supercooled liquid viscosity as temperature changes. $\\eta(T)$ is the viscosity at temperature T.',
|
|
227
|
+
atomId: point.atomId,
|
|
228
|
+
documentId: point.documentId || '',
|
|
229
|
+
sourcePath: point.sourcePath || '',
|
|
230
|
+
title: point.title,
|
|
231
|
+
headingPath: [point.title],
|
|
232
|
+
charCount: 120,
|
|
233
|
+
tokenEstimate: 30,
|
|
234
|
+
truncated: false,
|
|
235
|
+
citationIds: [point.citation?.citationId || 'citation_water_glass'],
|
|
236
|
+
relationEdgeIds: [],
|
|
237
|
+
sourceBoundary: 'direct_span_only',
|
|
238
|
+
}],
|
|
239
|
+
sourceDecisions: [],
|
|
240
|
+
totalCharCount: 120,
|
|
241
|
+
tokenEstimate: 30,
|
|
242
|
+
},
|
|
243
|
+
reviewedAt: '2026-07-12T00:00:00.000Z',
|
|
244
|
+
});
|
|
245
|
+
expect(review.failedGateIds).not.toContain('claim_subject_consistency');
|
|
246
|
+
});
|
|
247
|
+
test('does not treat a formula variable sentence with multiple math spans as an entity subject conflict', () => {
|
|
248
|
+
const point = makeKnowledgePoint({
|
|
249
|
+
title: '核心概念与数学基础',
|
|
250
|
+
summary: '描述过冷液体粘度随温度变化的常用模型。',
|
|
251
|
+
evidenceSnippet: '描述过冷液体粘度随温度变化的常用模型。',
|
|
252
|
+
sourcePath: 'Knowledge_Base/waterglass/Amorphous ice.md',
|
|
253
|
+
});
|
|
254
|
+
const review = (0, answerReleaseReview_1.reviewAnswerRelease)({
|
|
255
|
+
message: '什么是非晶冰?我应该通过哪些知识点学习?',
|
|
256
|
+
draftAnswer: '描述过冷液体粘度随温度变化的常用模型。$\\eta(T)$ 是在温度 $T$ 下的粘度。',
|
|
257
|
+
knowledgePoints: [point],
|
|
258
|
+
citations: [point.citation],
|
|
259
|
+
usedScope: scopedWaterglass,
|
|
260
|
+
graphContext: makeGraphContext({ anchorTitle: '非晶冰' }),
|
|
261
|
+
ragContextPack: {
|
|
262
|
+
query: '什么是非晶冰?我应该通过哪些知识点学习?',
|
|
263
|
+
generatedAt: '2026-07-12T00:00:00.000Z',
|
|
264
|
+
sourceBoundary: 'direct_span_only',
|
|
265
|
+
budget: { maxFragments: 1, maxCharsPerFragment: 500, maxTotalChars: 500 },
|
|
266
|
+
fragments: [{
|
|
267
|
+
fragmentId: 'amorphous_math_variable',
|
|
268
|
+
role: 'direct_support',
|
|
269
|
+
atomId: point.atomId,
|
|
270
|
+
documentId: point.documentId || '',
|
|
271
|
+
sourcePath: point.sourcePath || '',
|
|
272
|
+
title: point.title,
|
|
273
|
+
headingPath: [point.title],
|
|
274
|
+
text: '描述过冷液体粘度随温度变化的常用模型。$\\eta(T)$ 是在温度 $T$ 下的粘度。',
|
|
275
|
+
charCount: 80,
|
|
276
|
+
tokenEstimate: 20,
|
|
277
|
+
truncated: false,
|
|
278
|
+
citationIds: [point.citation?.citationId || 'citation_water_glass'],
|
|
279
|
+
relationEdgeIds: [],
|
|
280
|
+
sourceBoundary: 'direct_span_only',
|
|
281
|
+
}],
|
|
282
|
+
sourceDecisions: [],
|
|
283
|
+
totalCharCount: 80,
|
|
284
|
+
tokenEstimate: 20,
|
|
285
|
+
},
|
|
286
|
+
reviewedAt: '2026-07-12T00:00:00.000Z',
|
|
287
|
+
});
|
|
288
|
+
expect(review.failedGateIds).not.toContain('claim_subject_consistency');
|
|
289
|
+
});
|
|
290
|
+
test('does not release a definition-only draft for a compound learning request', () => {
|
|
291
|
+
const point = makeKnowledgePoint({
|
|
292
|
+
atomId: 'atom_amorphous_ice',
|
|
293
|
+
atomIds: ['atom_amorphous_ice', 'atom_water_structure', 'atom_rdf'],
|
|
294
|
+
documentId: 'doc_amorphous_ice',
|
|
295
|
+
sourcePath: 'Knowledge_Base/waterglass/Amorphous ice.md',
|
|
296
|
+
title: 'Amorphous Ice',
|
|
297
|
+
summary: 'Amorphous ice is a solid form of water without long-range crystalline order.',
|
|
298
|
+
evidenceSnippet: 'Amorphous ice is a solid form of water without long-range crystalline order.',
|
|
299
|
+
matchedSpans: [
|
|
300
|
+
{
|
|
301
|
+
atomId: 'atom_amorphous_ice',
|
|
302
|
+
title: 'Amorphous Ice',
|
|
303
|
+
snippet: 'Amorphous ice is a solid form of water without long-range crystalline order.',
|
|
304
|
+
sourcePath: 'Knowledge_Base/waterglass/Amorphous ice.md',
|
|
305
|
+
score: 0.94,
|
|
306
|
+
citation: null,
|
|
307
|
+
},
|
|
308
|
+
{
|
|
309
|
+
atomId: 'atom_water_structure',
|
|
310
|
+
title: 'Water Molecular Structure',
|
|
311
|
+
snippet: 'Water molecules and hydrogen bonding explain the local structure of ice.',
|
|
312
|
+
sourcePath: 'Knowledge_Base/waterglass/Amorphous ice.md',
|
|
313
|
+
score: 0.86,
|
|
314
|
+
citation: null,
|
|
315
|
+
},
|
|
316
|
+
{
|
|
317
|
+
atomId: 'atom_rdf',
|
|
318
|
+
title: 'Radial Distribution Function',
|
|
319
|
+
snippet: 'The radial distribution function g(r) distinguishes short-range from long-range order.',
|
|
320
|
+
sourcePath: 'Knowledge_Base/waterglass/Amorphous ice.md',
|
|
321
|
+
score: 0.84,
|
|
322
|
+
citation: null,
|
|
323
|
+
},
|
|
324
|
+
],
|
|
325
|
+
});
|
|
326
|
+
const message = 'what is amorphous ice? Which knowledge points should I learn?';
|
|
327
|
+
const graphContext = makeGraphContext({
|
|
328
|
+
anchorAtomId: 'atom_amorphous_ice',
|
|
329
|
+
anchorTitle: 'Amorphous Ice',
|
|
330
|
+
});
|
|
331
|
+
const graphAnswerPlan = (0, graphAnswerPlan_1.buildGraphAnswerPlan)({
|
|
332
|
+
message,
|
|
333
|
+
knowledgePoints: [point],
|
|
334
|
+
graphContext,
|
|
335
|
+
});
|
|
336
|
+
const review = (0, answerReleaseReview_1.reviewAnswerRelease)({
|
|
337
|
+
message,
|
|
338
|
+
draftAnswer: 'Amorphous ice is a solid form of water without long-range crystalline order.',
|
|
339
|
+
knowledgePoints: [point],
|
|
340
|
+
citations: [],
|
|
341
|
+
usedScope: scopedWaterglass,
|
|
342
|
+
graphContext,
|
|
343
|
+
graphAnswerPlan,
|
|
344
|
+
reviewedAt: '2026-07-12T00:00:00.000Z',
|
|
345
|
+
});
|
|
346
|
+
expect(review.draftAnswerTaskCoverage).toEqual(expect.objectContaining({
|
|
347
|
+
passed: false,
|
|
348
|
+
missingRequiredSubtaskIds: expect.arrayContaining(['learning_route']),
|
|
349
|
+
}));
|
|
350
|
+
expect(review.failedGateIds).toContain('subtask_coverage');
|
|
351
|
+
expect(review.failedGateIds).toContain('deliverable_completeness');
|
|
352
|
+
expect(review.decision).toBe('revise');
|
|
353
|
+
expect(review.answerTaskCoverage?.passed).toBe(true);
|
|
354
|
+
});
|
|
355
|
+
test('abstains when grounded evidence belongs to a different requested subject', () => {
|
|
356
|
+
const waterGlassPoint = makeKnowledgePoint({
|
|
357
|
+
title: 'Water Glass',
|
|
358
|
+
summary: 'Water glass is a transparent container filled with water.',
|
|
359
|
+
evidenceSnippet: 'Water glass is a transparent container filled with water.',
|
|
360
|
+
});
|
|
361
|
+
const review = (0, answerReleaseReview_1.reviewAnswerRelease)({
|
|
362
|
+
message: '什么是非晶冰?我应该通过哪些知识点学习?',
|
|
363
|
+
draftAnswer: '水杯是一个用于盛水的透明容器。',
|
|
364
|
+
knowledgePoints: [waterGlassPoint],
|
|
365
|
+
citations: [waterGlassPoint.citation],
|
|
366
|
+
usedScope: scopedWaterglass,
|
|
367
|
+
graphContext: makeGraphContext({
|
|
368
|
+
anchorTitle: 'Water Glass',
|
|
369
|
+
supportingTitles: ['Amorphous Ice'],
|
|
370
|
+
supportingAtomIds: ['atom_amorphous_ice'],
|
|
371
|
+
}),
|
|
372
|
+
ragContextPack: {
|
|
373
|
+
query: '什么是非晶冰?我应该通过哪些知识点学习?',
|
|
374
|
+
generatedAt: '2026-07-08T00:00:00.000Z',
|
|
375
|
+
sourceBoundary: 'full_document',
|
|
376
|
+
budget: {
|
|
377
|
+
maxFragments: 4,
|
|
378
|
+
maxCharsPerFragment: 600,
|
|
379
|
+
maxTotalChars: 1600,
|
|
380
|
+
},
|
|
381
|
+
fragments: [{
|
|
382
|
+
fragmentId: 'rag_water_glass',
|
|
383
|
+
role: 'direct_support',
|
|
384
|
+
text: '水杯是一个用于盛水的透明容器。',
|
|
385
|
+
atomId: 'atom_water_glass',
|
|
386
|
+
documentId: 'doc_water_glass',
|
|
387
|
+
sourcePath: 'Knowledge_Base/waterglass/water-glass.md',
|
|
388
|
+
title: 'Water Glass',
|
|
389
|
+
headingPath: ['Water Glass'],
|
|
390
|
+
charCount: 20,
|
|
391
|
+
tokenEstimate: 10,
|
|
392
|
+
truncated: false,
|
|
393
|
+
citationIds: ['citation_water_glass'],
|
|
394
|
+
sourceBoundary: 'direct_span_only',
|
|
395
|
+
}],
|
|
396
|
+
sourceDecisions: [],
|
|
397
|
+
totalCharCount: 20,
|
|
398
|
+
tokenEstimate: 10,
|
|
399
|
+
},
|
|
400
|
+
ragSufficiencyReview: {
|
|
401
|
+
reviewedAt: '2026-07-08T00:00:00.000Z',
|
|
402
|
+
status: 'sufficient',
|
|
403
|
+
score: 0.9,
|
|
404
|
+
reasons: [],
|
|
405
|
+
deterministic: true,
|
|
406
|
+
},
|
|
407
|
+
reviewedAt: '2026-07-08T00:00:01.000Z',
|
|
408
|
+
});
|
|
409
|
+
expect(review.decision).toBe('abstain');
|
|
410
|
+
expect(review.failedGateIds).toContain('query_subject_alignment');
|
|
411
|
+
expect(review.publicAnswer).toContain('非晶冰');
|
|
412
|
+
expect(review.publicAnswer).not.toContain('水杯是一个用于盛水的透明容器');
|
|
413
|
+
});
|
|
414
|
+
test('keeps definition answers when the requested subject is supported by the evidence title', () => {
|
|
415
|
+
const review = (0, answerReleaseReview_1.reviewAnswerRelease)({
|
|
416
|
+
message: 'what is water glass?',
|
|
417
|
+
draftAnswer: 'A water glass is a transparent container filled with water.',
|
|
418
|
+
knowledgePoints: [makeKnowledgePoint()],
|
|
419
|
+
citations: [makeKnowledgePoint().citation],
|
|
420
|
+
usedScope: scopedWaterglass,
|
|
421
|
+
graphContext: makeGraphContext(),
|
|
422
|
+
reviewedAt: '2026-07-08T00:01:00.000Z',
|
|
423
|
+
});
|
|
424
|
+
expect(review.decision).toBe('release');
|
|
425
|
+
expect(review.failedGateIds).not.toContain('query_subject_alignment');
|
|
426
|
+
expect(review.publicAnswer).toContain('water glass');
|
|
427
|
+
});
|
|
205
428
|
test('downgrades unsupported debug-style answers into concise abstentions', () => {
|
|
206
429
|
const review = (0, answerReleaseReview_1.reviewAnswerRelease)({
|
|
207
430
|
message: '什么是waterglass?',
|
|
@@ -427,7 +650,39 @@ describe('answerReleaseReview', () => {
|
|
|
427
650
|
expect(review.publicAnswer).toContain('紧邻前置节点包括 材料科学');
|
|
428
651
|
expect(review.publicAnswer).toContain('后续分支包括 热量传递模型');
|
|
429
652
|
});
|
|
430
|
-
test('
|
|
653
|
+
test('does not cut a public evidence highlight through a mathematical expression', () => {
|
|
654
|
+
const longFormulaClause = [
|
|
655
|
+
'The thermal field has a grounded physical interpretation',
|
|
656
|
+
...Array.from({ length: 12 }, () => 'with a stable source-backed description'),
|
|
657
|
+
'and is governed by $$\\frac{\\partial T}{\\partial t}=\\alpha\\nabla^2 T$$, where alpha is the thermal diffusivity and the complete clause remains readable for the public answer.',
|
|
658
|
+
].join(' ');
|
|
659
|
+
expect(longFormulaClause.length).toBeGreaterThan(480);
|
|
660
|
+
const thermalCitation = {
|
|
661
|
+
...makeKnowledgePoint().citation,
|
|
662
|
+
citationId: 'citation_thermal_formula',
|
|
663
|
+
atomId: 'atom_thermal_formula',
|
|
664
|
+
title: 'Thermal Model',
|
|
665
|
+
snippet: longFormulaClause,
|
|
666
|
+
};
|
|
667
|
+
const point = makeKnowledgePoint({
|
|
668
|
+
citations: [makeKnowledgePoint().citation, thermalCitation],
|
|
669
|
+
});
|
|
670
|
+
const review = (0, answerReleaseReview_1.reviewAnswerRelease)({
|
|
671
|
+
message: 'what is water glass',
|
|
672
|
+
draftAnswer: 'This technical document analyzes water glass as a physical system.',
|
|
673
|
+
knowledgePoints: [point],
|
|
674
|
+
citations: [point.citation, thermalCitation],
|
|
675
|
+
usedScope: scopedWaterglass,
|
|
676
|
+
graphContext: makeGraphContext(),
|
|
677
|
+
reviewedAt: '2026-07-12T00:05:00.000Z',
|
|
678
|
+
});
|
|
679
|
+
expect(review.decision).toBe('revise');
|
|
680
|
+
expect(review.publicAnswer).toContain('$$\n\\frac{\\partial T}{\\partial t}=\\alpha\\nabla^2 T\n$$');
|
|
681
|
+
expect(review.publicAnswer).toContain('the complete clause remains readable for the public answer.');
|
|
682
|
+
expect(review.publicAnswer).not.toContain('...');
|
|
683
|
+
expect((review.publicAnswer.match(/\$\$/gu) || []).length % 2).toBe(0);
|
|
684
|
+
});
|
|
685
|
+
test('releases a complete definition draft without replacing its natural answer shape', () => {
|
|
431
686
|
const baseCitation = makeKnowledgePoint().citation;
|
|
432
687
|
const thermalCitation = {
|
|
433
688
|
...baseCitation,
|
|
@@ -515,18 +770,770 @@ describe('answerReleaseReview', () => {
|
|
|
515
770
|
reviewedAt: '2026-07-04T08:20:00.000Z',
|
|
516
771
|
});
|
|
517
772
|
expect(review.decision).toBe('release');
|
|
518
|
-
expect(review.revised).toBe(
|
|
773
|
+
expect(review.revised).toBe(false);
|
|
519
774
|
expect(review.publicAnswer).toContain('Water glass is a transparent container filled with water.');
|
|
520
|
-
expect(review.publicAnswer).toContain('The same knowledge point also covers Thermal Model.');
|
|
521
|
-
expect(review.publicAnswer).toContain('Evidence highlights: Thermal Model');
|
|
522
|
-
expect(review.publicAnswer).toContain('Water Glass has 1 incoming and 1 outgoing links');
|
|
523
|
-
expect(review.publicAnswer).toContain('its immediate predecessors include Container Physics');
|
|
524
|
-
expect(review.publicAnswer).toContain('likely next nodes include Thermal Model');
|
|
775
|
+
expect(review.publicAnswer).not.toContain('The same knowledge point also covers Thermal Model.');
|
|
776
|
+
expect(review.publicAnswer).not.toContain('Evidence highlights: Thermal Model');
|
|
777
|
+
expect(review.publicAnswer).not.toContain('Water Glass has 1 incoming and 1 outgoing links');
|
|
778
|
+
expect(review.publicAnswer).not.toContain('its immediate predecessors include Container Physics');
|
|
779
|
+
expect(review.publicAnswer).not.toContain('likely next nodes include Thermal Model');
|
|
525
780
|
expect(review.publicAnswer).not.toContain('predecessors include Water Glass');
|
|
526
781
|
expect(review.publicAnswer).not.toContain('next nodes include Water Glass');
|
|
527
782
|
expect(review.publicAnswer).not.toContain('(mermaid block)');
|
|
528
783
|
expect(review.publicAnswer).not.toContain('```');
|
|
529
784
|
});
|
|
785
|
+
test('does not reject an evidence-grounded answer merely because it exceeds 900 characters', () => {
|
|
786
|
+
const point = makeKnowledgePoint();
|
|
787
|
+
const groundedSentence = 'Water glass is a transparent container filled with water and its wall separates the liquid from the surrounding environment.';
|
|
788
|
+
const longGroundedAnswer = Array.from({ length: 9 }, (_, index) => `${groundedSentence} Detail ${index + 1}.`).join(' ');
|
|
789
|
+
const review = (0, answerReleaseReview_1.reviewAnswerRelease)({
|
|
790
|
+
message: 'what is water glass',
|
|
791
|
+
draftAnswer: longGroundedAnswer,
|
|
792
|
+
knowledgePoints: [point],
|
|
793
|
+
citations: [point.citation],
|
|
794
|
+
usedScope: scopedWaterglass,
|
|
795
|
+
graphContext: makeGraphContext(),
|
|
796
|
+
reviewedAt: '2026-07-11T09:00:00.000Z',
|
|
797
|
+
});
|
|
798
|
+
expect(longGroundedAnswer.length).toBeGreaterThan(900);
|
|
799
|
+
expect(review.failedGateIds).not.toContain('public_surface_contraction');
|
|
800
|
+
});
|
|
801
|
+
test('deduplicates a formula-only definition claim already carried by contextual evidence', () => {
|
|
802
|
+
const point = makeKnowledgePoint({
|
|
803
|
+
title: 'Water Glass',
|
|
804
|
+
summary: 'Water glass is a transparent vessel designed to hold water.',
|
|
805
|
+
evidenceSnippet: 'Water glass is a transparent vessel designed to hold water.',
|
|
806
|
+
});
|
|
807
|
+
const documentId = point.documentId || 'doc_water_glass';
|
|
808
|
+
const sourcePath = point.sourcePath || 'Knowledge_Base/waterglass/water-glass.md';
|
|
809
|
+
const equation = '$$\\frac{\\partial T}{\\partial t}=\\alpha\\nabla^2 T$$';
|
|
810
|
+
const graphAnswerPlan = {
|
|
811
|
+
intent: 'definition',
|
|
812
|
+
depth: 'standard',
|
|
813
|
+
anchorAtomId: point.atomId,
|
|
814
|
+
leadClaimId: 'claim_definition',
|
|
815
|
+
requiredRoles: ['definition'],
|
|
816
|
+
omittedCandidates: [],
|
|
817
|
+
claims: [
|
|
818
|
+
{
|
|
819
|
+
claimId: 'claim_definition',
|
|
820
|
+
role: 'definition',
|
|
821
|
+
required: true,
|
|
822
|
+
priority: 1,
|
|
823
|
+
statement: 'Water glass is a transparent vessel designed to hold water.',
|
|
824
|
+
subjectAtomId: point.atomId,
|
|
825
|
+
supportingAtomIds: [],
|
|
826
|
+
supportingEdgeIds: [],
|
|
827
|
+
evidenceRefs: [{
|
|
828
|
+
evidenceId: 'citation_water_glass',
|
|
829
|
+
atomId: point.atomId,
|
|
830
|
+
sourcePath,
|
|
831
|
+
citationIds: ['citation_water_glass'],
|
|
832
|
+
text: point.evidenceSnippet,
|
|
833
|
+
}],
|
|
834
|
+
confidence: 0.96,
|
|
835
|
+
},
|
|
836
|
+
{
|
|
837
|
+
claimId: 'claim_thermal_context',
|
|
838
|
+
role: 'definition',
|
|
839
|
+
required: true,
|
|
840
|
+
priority: 2,
|
|
841
|
+
statement: `Its thermal field is modeled by ${equation} where T is temperature and alpha is thermal diffusivity.`,
|
|
842
|
+
subjectAtomId: point.atomId,
|
|
843
|
+
supportingAtomIds: [],
|
|
844
|
+
supportingEdgeIds: [],
|
|
845
|
+
evidenceRefs: [{
|
|
846
|
+
evidenceId: 'citation_thermal_context',
|
|
847
|
+
atomId: point.atomId,
|
|
848
|
+
sourcePath,
|
|
849
|
+
citationIds: ['citation_thermal_context'],
|
|
850
|
+
text: `Its thermal field is modeled by ${equation} where T is temperature and alpha is thermal diffusivity.`,
|
|
851
|
+
}],
|
|
852
|
+
confidence: 0.95,
|
|
853
|
+
},
|
|
854
|
+
{
|
|
855
|
+
claimId: 'claim_thermal_formula',
|
|
856
|
+
role: 'definition',
|
|
857
|
+
required: true,
|
|
858
|
+
priority: 3,
|
|
859
|
+
statement: equation,
|
|
860
|
+
subjectAtomId: point.atomId,
|
|
861
|
+
supportingAtomIds: [],
|
|
862
|
+
supportingEdgeIds: [],
|
|
863
|
+
evidenceRefs: [{
|
|
864
|
+
evidenceId: 'citation_thermal_formula',
|
|
865
|
+
atomId: point.atomId,
|
|
866
|
+
sourcePath,
|
|
867
|
+
citationIds: ['citation_thermal_formula'],
|
|
868
|
+
text: equation,
|
|
869
|
+
}],
|
|
870
|
+
confidence: 0.94,
|
|
871
|
+
},
|
|
872
|
+
],
|
|
873
|
+
};
|
|
874
|
+
const ragContextPack = {
|
|
875
|
+
query: 'what is water glass?',
|
|
876
|
+
generatedAt: '2026-08-24T00:00:00.000Z',
|
|
877
|
+
sourceBoundary: 'direct_span_only',
|
|
878
|
+
budget: { maxFragments: 3, maxCharsPerFragment: 600, maxTotalChars: 1200 },
|
|
879
|
+
fragments: [{
|
|
880
|
+
fragmentId: 'water_glass_formula_context',
|
|
881
|
+
role: 'direct_support',
|
|
882
|
+
text: `Water glass is a transparent vessel designed to hold water. Its thermal field is modeled by ${equation} where T is temperature and alpha is thermal diffusivity.`,
|
|
883
|
+
atomId: point.atomId,
|
|
884
|
+
documentId,
|
|
885
|
+
sourcePath,
|
|
886
|
+
title: point.title,
|
|
887
|
+
headingPath: ['Water Glass'],
|
|
888
|
+
startLine: 1,
|
|
889
|
+
endLine: 5,
|
|
890
|
+
charCount: 180,
|
|
891
|
+
tokenEstimate: 45,
|
|
892
|
+
truncated: false,
|
|
893
|
+
citationIds: ['citation_water_glass', 'citation_thermal_context'],
|
|
894
|
+
sourceBoundary: 'direct_span_only',
|
|
895
|
+
}],
|
|
896
|
+
sourceDecisions: [],
|
|
897
|
+
totalCharCount: 180,
|
|
898
|
+
tokenEstimate: 45,
|
|
899
|
+
};
|
|
900
|
+
const review = (0, answerReleaseReview_1.reviewAnswerRelease)({
|
|
901
|
+
message: 'what is water glass?',
|
|
902
|
+
draftAnswer: [
|
|
903
|
+
'Water glass is a transparent vessel designed to hold water.',
|
|
904
|
+
`Its thermal field is modeled by ${equation} where T is temperature and alpha is thermal diffusivity.`,
|
|
905
|
+
equation,
|
|
906
|
+
].join(' '),
|
|
907
|
+
knowledgePoints: [point],
|
|
908
|
+
citations: [point.citation],
|
|
909
|
+
usedScope: scopedWaterglass,
|
|
910
|
+
graphContext: makeGraphContext(),
|
|
911
|
+
graphAnswerPlan,
|
|
912
|
+
ragContextPack,
|
|
913
|
+
ragSufficiencyReview: {
|
|
914
|
+
reviewedAt: '2026-08-24T00:00:00.000Z',
|
|
915
|
+
status: 'sufficient',
|
|
916
|
+
score: 0.95,
|
|
917
|
+
reasons: [],
|
|
918
|
+
deterministic: true,
|
|
919
|
+
recoveryAttempted: false,
|
|
920
|
+
llmJudgeUsed: false,
|
|
921
|
+
degradationState: 'none',
|
|
922
|
+
},
|
|
923
|
+
reviewedAt: '2026-08-24T00:00:00.000Z',
|
|
924
|
+
});
|
|
925
|
+
expect((review.publicAnswer.match(/\\frac\{\\partial T\}\{\\partial t\}=\\alpha\\nabla\^2 T/gu) || [])).toHaveLength(1);
|
|
926
|
+
expect(review.publicAnswer).toContain('where T is temperature and alpha is thermal diffusivity.');
|
|
927
|
+
});
|
|
928
|
+
test('projects every eligible definition claim without a RAG pack and records coverage on the final public answer', () => {
|
|
929
|
+
const point = makeKnowledgePoint({
|
|
930
|
+
title: 'Water Glass',
|
|
931
|
+
summary: 'A water glass is a transparent vessel used to hold water.',
|
|
932
|
+
evidenceSnippet: 'A water glass is a transparent vessel used to hold water.',
|
|
933
|
+
});
|
|
934
|
+
const sourcePath = point.sourcePath || 'Knowledge_Base/waterglass/water-glass.md';
|
|
935
|
+
const graphAnswerPlan = {
|
|
936
|
+
intent: 'definition',
|
|
937
|
+
depth: 'standard',
|
|
938
|
+
anchorAtomId: point.atomId,
|
|
939
|
+
leadClaimId: 'claim_definition',
|
|
940
|
+
requiredRoles: ['definition', 'composition', 'boundary', 'mechanism', 'application', 'contrast'],
|
|
941
|
+
omittedCandidates: [],
|
|
942
|
+
claims: [
|
|
943
|
+
{
|
|
944
|
+
claimId: 'claim_definition',
|
|
945
|
+
role: 'definition',
|
|
946
|
+
required: true,
|
|
947
|
+
priority: 1,
|
|
948
|
+
statement: 'A water glass is a transparent vessel used to hold water.',
|
|
949
|
+
subjectAtomId: point.atomId,
|
|
950
|
+
supportingAtomIds: [],
|
|
951
|
+
supportingEdgeIds: [],
|
|
952
|
+
evidenceRefs: [{ evidenceId: 'definition', atomId: point.atomId, sourcePath, citationIds: [], text: point.evidenceSnippet }],
|
|
953
|
+
confidence: 0.98,
|
|
954
|
+
},
|
|
955
|
+
{
|
|
956
|
+
claimId: 'claim_composition',
|
|
957
|
+
role: 'composition',
|
|
958
|
+
required: true,
|
|
959
|
+
priority: 2,
|
|
960
|
+
statement: 'It combines a glass vessel with the water it contains.',
|
|
961
|
+
subjectAtomId: point.atomId,
|
|
962
|
+
supportingAtomIds: [],
|
|
963
|
+
supportingEdgeIds: [],
|
|
964
|
+
evidenceRefs: [{ evidenceId: 'composition', atomId: point.atomId, sourcePath, citationIds: [], text: 'It combines a glass vessel with the water it contains.' }],
|
|
965
|
+
confidence: 0.97,
|
|
966
|
+
},
|
|
967
|
+
{
|
|
968
|
+
claimId: 'claim_boundary',
|
|
969
|
+
role: 'boundary',
|
|
970
|
+
required: true,
|
|
971
|
+
priority: 3,
|
|
972
|
+
statement: 'Its wall separates the liquid from the surrounding air.',
|
|
973
|
+
subjectAtomId: point.atomId,
|
|
974
|
+
supportingAtomIds: [],
|
|
975
|
+
supportingEdgeIds: [],
|
|
976
|
+
evidenceRefs: [{ evidenceId: 'boundary', atomId: point.atomId, sourcePath, citationIds: [], text: 'Its wall separates the liquid from the surrounding air.' }],
|
|
977
|
+
confidence: 0.96,
|
|
978
|
+
},
|
|
979
|
+
{
|
|
980
|
+
claimId: 'claim_mechanism',
|
|
981
|
+
role: 'mechanism',
|
|
982
|
+
required: true,
|
|
983
|
+
priority: 4,
|
|
984
|
+
statement: 'Light refracts at the air-glass-water interfaces.',
|
|
985
|
+
subjectAtomId: point.atomId,
|
|
986
|
+
supportingAtomIds: [],
|
|
987
|
+
supportingEdgeIds: [],
|
|
988
|
+
evidenceRefs: [{ evidenceId: 'mechanism', atomId: point.atomId, sourcePath, citationIds: [], text: 'Light refracts at the air-glass-water interfaces.' }],
|
|
989
|
+
confidence: 0.95,
|
|
990
|
+
},
|
|
991
|
+
{
|
|
992
|
+
claimId: 'claim_application',
|
|
993
|
+
role: 'application',
|
|
994
|
+
required: true,
|
|
995
|
+
priority: 5,
|
|
996
|
+
statement: 'Its thermal field can be modeled by $$\\frac{\\partial T}{\\partial t}=\\alpha\\nabla^2 T$$, where T is temperature.',
|
|
997
|
+
subjectAtomId: point.atomId,
|
|
998
|
+
supportingAtomIds: [],
|
|
999
|
+
supportingEdgeIds: [],
|
|
1000
|
+
evidenceRefs: [{ evidenceId: 'thermal', atomId: point.atomId, sourcePath, citationIds: [], text: 'Its thermal field can be modeled by $$\\frac{\\partial T}{\\partial t}=\\alpha\\nabla^2 T$$, where T is temperature.' }],
|
|
1001
|
+
confidence: 0.94,
|
|
1002
|
+
},
|
|
1003
|
+
{
|
|
1004
|
+
claimId: 'claim_contrast',
|
|
1005
|
+
role: 'contrast',
|
|
1006
|
+
required: true,
|
|
1007
|
+
priority: 6,
|
|
1008
|
+
statement: 'Plastic cups are a different category of container.',
|
|
1009
|
+
subjectAtomId: point.atomId,
|
|
1010
|
+
supportingAtomIds: [],
|
|
1011
|
+
supportingEdgeIds: [],
|
|
1012
|
+
evidenceRefs: [{ evidenceId: 'contrast', atomId: point.atomId, sourcePath, citationIds: [], text: 'Plastic cups are a different category of container.' }],
|
|
1013
|
+
confidence: 0.93,
|
|
1014
|
+
},
|
|
1015
|
+
],
|
|
1016
|
+
};
|
|
1017
|
+
const review = (0, answerReleaseReview_1.reviewAnswerRelease)({
|
|
1018
|
+
message: 'what is water glass?',
|
|
1019
|
+
draftAnswer: 'A water glass is a transparent vessel used to hold water. Plastic cups are a different category of container.',
|
|
1020
|
+
knowledgePoints: [point],
|
|
1021
|
+
citations: [point.citation],
|
|
1022
|
+
usedScope: scopedWaterglass,
|
|
1023
|
+
graphContext: makeGraphContext(),
|
|
1024
|
+
graphAnswerPlan,
|
|
1025
|
+
reviewedAt: '2026-08-24T00:10:00.000Z',
|
|
1026
|
+
});
|
|
1027
|
+
expect(review.publicAnswer).toContain('It combines a glass vessel with the water it contains.');
|
|
1028
|
+
expect(review.publicAnswer).toContain('Its wall separates the liquid from the surrounding air.');
|
|
1029
|
+
expect(review.publicAnswer).toContain('Light refracts at the air-glass-water interfaces.');
|
|
1030
|
+
expect(review.publicAnswer).toContain('$$\n\\frac{\\partial T}{\\partial t}=\\alpha\\nabla^2 T\n$$');
|
|
1031
|
+
expect(review.publicAnswer).not.toContain('Plastic cups');
|
|
1032
|
+
expect(review.publicGraphAnswerPlan.claims.map((claim) => claim.claimId)).toEqual([
|
|
1033
|
+
'claim_definition',
|
|
1034
|
+
'claim_composition',
|
|
1035
|
+
'claim_boundary',
|
|
1036
|
+
'claim_mechanism',
|
|
1037
|
+
'claim_application',
|
|
1038
|
+
]);
|
|
1039
|
+
expect(review.graphAnswerCoverage).toEqual(expect.objectContaining({
|
|
1040
|
+
passed: true,
|
|
1041
|
+
missingRequiredClaimIds: [],
|
|
1042
|
+
}));
|
|
1043
|
+
});
|
|
1044
|
+
test('keeps distinct complete formula contexts in a full-document definition projection', () => {
|
|
1045
|
+
const point = makeKnowledgePoint({
|
|
1046
|
+
title: '水杯 (water glass)',
|
|
1047
|
+
summary: '此处的“水杯”被定义为一个由水和玻璃杯组成的物理系统。',
|
|
1048
|
+
evidenceSnippet: '此处的“水杯”被定义为一个由水和玻璃杯组成的物理系统。',
|
|
1049
|
+
});
|
|
1050
|
+
const sourcePath = point.sourcePath || 'Knowledge_Base/waterglass/water-glass.md';
|
|
1051
|
+
const thermalEquation = '$$\\frac{\\partial T}{\\partial t}=\\alpha\\nabla^2 T$$';
|
|
1052
|
+
const opticalEquation = '$$n_1\\sin(\\theta_1)=n_2\\sin(\\theta_2)$$';
|
|
1053
|
+
const claim = (claimId, role, statement, priority) => ({
|
|
1054
|
+
claimId,
|
|
1055
|
+
role,
|
|
1056
|
+
required: true,
|
|
1057
|
+
priority,
|
|
1058
|
+
statement,
|
|
1059
|
+
subjectAtomId: point.atomId,
|
|
1060
|
+
supportingAtomIds: [],
|
|
1061
|
+
supportingEdgeIds: [],
|
|
1062
|
+
evidenceRefs: [{
|
|
1063
|
+
evidenceId: claimId,
|
|
1064
|
+
atomId: point.atomId,
|
|
1065
|
+
sourcePath,
|
|
1066
|
+
citationIds: [point.citation?.citationId || 'citation_water_glass'],
|
|
1067
|
+
text: statement,
|
|
1068
|
+
}],
|
|
1069
|
+
confidence: 0.96,
|
|
1070
|
+
});
|
|
1071
|
+
const graphAnswerPlan = {
|
|
1072
|
+
intent: 'definition',
|
|
1073
|
+
depth: 'deep',
|
|
1074
|
+
anchorAtomId: point.atomId,
|
|
1075
|
+
leadClaimId: 'definition',
|
|
1076
|
+
requiredRoles: ['definition', 'mechanism'],
|
|
1077
|
+
omittedCandidates: [],
|
|
1078
|
+
claims: [
|
|
1079
|
+
claim('definition', 'definition', '此处的“水杯”被定义为一个由水和玻璃杯组成的物理系统。', 100),
|
|
1080
|
+
claim('thermal_context', 'definition', `系统内部的温度分布由热传导方程描述:${thermalEquation} 其中 $T$ 是温度场。`, 100),
|
|
1081
|
+
claim('optical_context', 'definition', `折射现象由斯涅尔定律描述:${opticalEquation} 其中 $n_1$ 和 $n_2$ 是介质折射率。`, 100),
|
|
1082
|
+
claim('thermal_alpha', 'mechanism', '$\\alpha = \\frac{k}{\\rho c_p}$ 是热扩散率。', 360),
|
|
1083
|
+
claim('thermal_k', 'mechanism', '$k$ 是热导率。', 360),
|
|
1084
|
+
claim('thermal_cp', 'mechanism', '$c_p$ 是比热容。', 360),
|
|
1085
|
+
claim('thermal_exchange', 'mechanism', '水杯系统与环境之间通过传导、对流和辐射进行热交换。', 360),
|
|
1086
|
+
claim('chapter_marker', 'definition', '4. 热力学:热量传递', 100),
|
|
1087
|
+
],
|
|
1088
|
+
};
|
|
1089
|
+
const review = (0, answerReleaseReview_1.reviewAnswerRelease)({
|
|
1090
|
+
message: '什么是waterglass?',
|
|
1091
|
+
draftAnswer: [
|
|
1092
|
+
'此处的“水杯”被定义为一个由水和玻璃杯组成的物理系统。',
|
|
1093
|
+
`系统内部的温度分布由热传导方程描述:${thermalEquation} 其中 $T$ 是温度场。`,
|
|
1094
|
+
`折射现象由斯涅尔定律描述:${opticalEquation} 其中 $n_1$ 和 $n_2$ 是介质折射率。`,
|
|
1095
|
+
'本技术文档还包含技术规格和比较章节。',
|
|
1096
|
+
].join(' '),
|
|
1097
|
+
knowledgePoints: [point],
|
|
1098
|
+
citations: [point.citation],
|
|
1099
|
+
usedScope: scopedWaterglass,
|
|
1100
|
+
graphContext: makeGraphContext(),
|
|
1101
|
+
graphAnswerPlan,
|
|
1102
|
+
ragContextPack: {
|
|
1103
|
+
query: '什么是waterglass?',
|
|
1104
|
+
generatedAt: '2026-08-25T00:00:00.000Z',
|
|
1105
|
+
sourceBoundary: 'full_document',
|
|
1106
|
+
budget: { maxFragments: 14, maxCharsPerFragment: 1400, maxTotalChars: 5600 },
|
|
1107
|
+
fragments: [{
|
|
1108
|
+
fragmentId: 'full_document_waterglass',
|
|
1109
|
+
role: 'direct_support',
|
|
1110
|
+
text: [
|
|
1111
|
+
'此处的“水杯”被定义为一个由水和玻璃杯组成的物理系统。',
|
|
1112
|
+
`系统内部的温度分布由热传导方程描述:${thermalEquation} 其中 $T$ 是温度场。`,
|
|
1113
|
+
`折射现象由斯涅尔定律描述:${opticalEquation} 其中 $n_1$ 和 $n_2$ 是介质折射率。`,
|
|
1114
|
+
].join(' '),
|
|
1115
|
+
atomId: point.atomId,
|
|
1116
|
+
documentId: point.documentId || 'doc_water_glass',
|
|
1117
|
+
sourcePath,
|
|
1118
|
+
title: point.title,
|
|
1119
|
+
headingPath: [point.title],
|
|
1120
|
+
charCount: 240,
|
|
1121
|
+
tokenEstimate: 60,
|
|
1122
|
+
truncated: false,
|
|
1123
|
+
citationIds: [point.citation?.citationId || 'citation_water_glass'],
|
|
1124
|
+
sourceBoundary: 'full_document',
|
|
1125
|
+
}],
|
|
1126
|
+
sourceDecisions: [],
|
|
1127
|
+
totalCharCount: 240,
|
|
1128
|
+
tokenEstimate: 60,
|
|
1129
|
+
},
|
|
1130
|
+
ragSufficiencyReview: {
|
|
1131
|
+
reviewedAt: '2026-08-25T00:00:00.000Z',
|
|
1132
|
+
status: 'sufficient',
|
|
1133
|
+
score: 0.95,
|
|
1134
|
+
reasons: [],
|
|
1135
|
+
deterministic: true,
|
|
1136
|
+
recoveryAttempted: false,
|
|
1137
|
+
llmJudgeUsed: false,
|
|
1138
|
+
degradationState: 'none',
|
|
1139
|
+
},
|
|
1140
|
+
reviewedAt: '2026-08-25T00:00:00.000Z',
|
|
1141
|
+
});
|
|
1142
|
+
const publicClaims = review.publicGraphAnswerPlan?.claims || [];
|
|
1143
|
+
expect(publicClaims.map((entry) => entry.claimId)).toEqual([
|
|
1144
|
+
'definition',
|
|
1145
|
+
'thermal_context',
|
|
1146
|
+
'optical_context',
|
|
1147
|
+
]);
|
|
1148
|
+
expect(review.publicAnswer).toContain('$$\n\\frac{\\partial T}{\\partial t}=\\alpha\\nabla^2 T\n$$');
|
|
1149
|
+
expect(review.publicAnswer).toContain('$$\nn_1\\sin(\\theta_1)=n_2\\sin(\\theta_2)\n$$');
|
|
1150
|
+
expect((review.publicAnswer.match(/\\frac\{\\partial T\}\{\\partial t\}=\\alpha\\nabla\^2 T/gu) || [])).toHaveLength(1);
|
|
1151
|
+
expect((review.publicAnswer.match(/n_1\\sin\(\\theta_1\)=n_2\\sin\(\\theta_2\)/gu) || [])).toHaveLength(1);
|
|
1152
|
+
expect(review.publicAnswer).not.toContain('$k$ 是热导率');
|
|
1153
|
+
expect(review.publicAnswer).not.toContain('4. 热力学');
|
|
1154
|
+
expect(review.publicAnswer).not.toContain('热交换');
|
|
1155
|
+
});
|
|
1156
|
+
test('does not reintroduce comparison or duplicate formula claims through conflict supplements', () => {
|
|
1157
|
+
const point = makeKnowledgePoint({
|
|
1158
|
+
title: 'Water Glass',
|
|
1159
|
+
summary: 'Water glass is a transparent vessel designed to hold water.',
|
|
1160
|
+
evidenceSnippet: 'Water glass is a transparent vessel designed to hold water.',
|
|
1161
|
+
});
|
|
1162
|
+
const sourcePath = point.sourcePath || 'Knowledge_Base/waterglass/water-glass.md';
|
|
1163
|
+
const equation = '$$\\frac{\\partial T}{\\partial t}=\\alpha\\nabla^2 T$$';
|
|
1164
|
+
const graphAnswerPlan = {
|
|
1165
|
+
intent: 'definition',
|
|
1166
|
+
depth: 'standard',
|
|
1167
|
+
anchorAtomId: point.atomId,
|
|
1168
|
+
leadClaimId: 'definition',
|
|
1169
|
+
requiredRoles: ['definition'],
|
|
1170
|
+
omittedCandidates: [],
|
|
1171
|
+
claims: [
|
|
1172
|
+
{
|
|
1173
|
+
claimId: 'definition', role: 'definition', required: true, priority: 1,
|
|
1174
|
+
statement: 'Water glass is a transparent vessel designed to hold water.',
|
|
1175
|
+
subjectAtomId: point.atomId, supportingAtomIds: [], supportingEdgeIds: [],
|
|
1176
|
+
evidenceRefs: [{ evidenceId: 'definition', atomId: point.atomId, sourcePath, citationIds: [], text: point.evidenceSnippet }], confidence: 0.98,
|
|
1177
|
+
},
|
|
1178
|
+
{
|
|
1179
|
+
claimId: 'formula_context', role: 'mechanism', required: true, priority: 2,
|
|
1180
|
+
statement: `Its thermal field follows ${equation}, where T is temperature.`,
|
|
1181
|
+
subjectAtomId: point.atomId, supportingAtomIds: [], supportingEdgeIds: [],
|
|
1182
|
+
evidenceRefs: [{ evidenceId: 'formula_context', atomId: point.atomId, sourcePath, citationIds: [], text: `Its thermal field follows ${equation}, where T is temperature.` }], confidence: 0.97,
|
|
1183
|
+
},
|
|
1184
|
+
{
|
|
1185
|
+
claimId: 'formula_only', role: 'mechanism', required: false, priority: 3,
|
|
1186
|
+
statement: equation,
|
|
1187
|
+
subjectAtomId: point.atomId, supportingAtomIds: [], supportingEdgeIds: [],
|
|
1188
|
+
evidenceRefs: [{ evidenceId: 'formula_only', atomId: point.atomId, sourcePath, citationIds: [], text: equation }], confidence: 0.96,
|
|
1189
|
+
},
|
|
1190
|
+
{
|
|
1191
|
+
claimId: 'comparison_artifact', role: 'contrast', required: false, priority: 4,
|
|
1192
|
+
statement: 'Water glass transparent vessel comparison with plastic cup has 20 cm reference height.',
|
|
1193
|
+
subjectAtomId: point.atomId, supportingAtomIds: [], supportingEdgeIds: [],
|
|
1194
|
+
evidenceRefs: [{ evidenceId: 'comparison_artifact', atomId: point.atomId, sourcePath, citationIds: [], text: 'Water glass transparent vessel comparison with plastic cup has 20 cm reference height.' }], confidence: 0.95,
|
|
1195
|
+
},
|
|
1196
|
+
],
|
|
1197
|
+
};
|
|
1198
|
+
const review = (0, answerReleaseReview_1.reviewAnswerRelease)({
|
|
1199
|
+
message: 'what is water glass?',
|
|
1200
|
+
draftAnswer: `Water glass is a transparent vessel designed to hold water. Its thermal field follows ${equation}, where T is temperature.`,
|
|
1201
|
+
knowledgePoints: [point],
|
|
1202
|
+
citations: [point.citation],
|
|
1203
|
+
usedScope: scopedWaterglass,
|
|
1204
|
+
graphContext: makeGraphContext(),
|
|
1205
|
+
graphAnswerPlan,
|
|
1206
|
+
ragContextPack: {
|
|
1207
|
+
query: 'what is water glass?',
|
|
1208
|
+
generatedAt: '2026-08-24T00:20:00.000Z',
|
|
1209
|
+
sourceBoundary: 'direct_span_only',
|
|
1210
|
+
budget: { maxFragments: 1, maxCharsPerFragment: 600, maxTotalChars: 600 },
|
|
1211
|
+
fragments: [{
|
|
1212
|
+
fragmentId: 'direct', role: 'direct_support', text: point.evidenceSnippet,
|
|
1213
|
+
atomId: point.atomId, documentId: point.documentId || 'doc_water_glass', sourcePath, title: point.title,
|
|
1214
|
+
headingPath: ['Water Glass'], charCount: point.evidenceSnippet.length, tokenEstimate: 16,
|
|
1215
|
+
truncated: false, citationIds: ['definition'], sourceBoundary: 'direct_span_only',
|
|
1216
|
+
}],
|
|
1217
|
+
sourceDecisions: [], totalCharCount: point.evidenceSnippet.length, tokenEstimate: 16,
|
|
1218
|
+
},
|
|
1219
|
+
ragSufficiencyReview: {
|
|
1220
|
+
reviewedAt: '2026-08-24T00:20:00.000Z', status: 'borderline', score: 0.6,
|
|
1221
|
+
reasons: [], deterministic: true, degradationState: 'conflict',
|
|
1222
|
+
},
|
|
1223
|
+
reviewedAt: '2026-08-24T00:20:00.000Z',
|
|
1224
|
+
});
|
|
1225
|
+
expect(review.publicAnswer).not.toContain('plastic cup');
|
|
1226
|
+
expect((review.publicAnswer.match(/\\frac\{\\partial T\}\{\\partial t\}=\\alpha\\nabla\^2 T/gu) || [])).toHaveLength(1);
|
|
1227
|
+
});
|
|
1228
|
+
test('rejects a math-bearing definition plan claim that ends in incomplete prose', () => {
|
|
1229
|
+
const point = makeKnowledgePoint({
|
|
1230
|
+
title: 'Water Glass',
|
|
1231
|
+
summary: 'Water glass is a bounded physical system.',
|
|
1232
|
+
evidenceSnippet: 'Water glass is a bounded physical system.',
|
|
1233
|
+
});
|
|
1234
|
+
const sourcePath = point.sourcePath || 'Knowledge_Base/waterglass/water-glass.md';
|
|
1235
|
+
const equation = '$$\\frac{\\partial T}{\\partial t}=\\alpha\\nabla^2 T$$';
|
|
1236
|
+
const fullStatement = `Water glass is a bounded physical system whose temperature field follows ${equation}, where T is temperature and alpha is thermal diffusivity across the interface.`;
|
|
1237
|
+
const incompleteStatement = fullStatement.replace('the interface.', 't');
|
|
1238
|
+
const graphAnswerPlan = {
|
|
1239
|
+
intent: 'definition',
|
|
1240
|
+
depth: 'compact',
|
|
1241
|
+
anchorAtomId: point.atomId,
|
|
1242
|
+
leadClaimId: 'incomplete_formula_claim',
|
|
1243
|
+
requiredRoles: ['definition'],
|
|
1244
|
+
omittedCandidates: [],
|
|
1245
|
+
claims: [
|
|
1246
|
+
{
|
|
1247
|
+
claimId: 'incomplete_formula_claim',
|
|
1248
|
+
role: 'definition',
|
|
1249
|
+
required: true,
|
|
1250
|
+
priority: 2,
|
|
1251
|
+
statement: incompleteStatement,
|
|
1252
|
+
subjectAtomId: point.atomId,
|
|
1253
|
+
supportingAtomIds: [],
|
|
1254
|
+
supportingEdgeIds: [],
|
|
1255
|
+
evidenceRefs: [{
|
|
1256
|
+
evidenceId: 'parent_context',
|
|
1257
|
+
atomId: point.atomId,
|
|
1258
|
+
sourcePath,
|
|
1259
|
+
citationIds: [],
|
|
1260
|
+
text: incompleteStatement,
|
|
1261
|
+
}],
|
|
1262
|
+
confidence: 0.94,
|
|
1263
|
+
},
|
|
1264
|
+
{
|
|
1265
|
+
claimId: 'complete_formula_claim',
|
|
1266
|
+
role: 'definition',
|
|
1267
|
+
required: true,
|
|
1268
|
+
priority: 1,
|
|
1269
|
+
statement: fullStatement,
|
|
1270
|
+
subjectAtomId: point.atomId,
|
|
1271
|
+
supportingAtomIds: [],
|
|
1272
|
+
supportingEdgeIds: [],
|
|
1273
|
+
evidenceRefs: [{
|
|
1274
|
+
evidenceId: 'direct_support',
|
|
1275
|
+
atomId: point.atomId,
|
|
1276
|
+
sourcePath,
|
|
1277
|
+
citationIds: [],
|
|
1278
|
+
text: fullStatement,
|
|
1279
|
+
}],
|
|
1280
|
+
confidence: 0.95,
|
|
1281
|
+
},
|
|
1282
|
+
],
|
|
1283
|
+
};
|
|
1284
|
+
const review = (0, answerReleaseReview_1.reviewAnswerRelease)({
|
|
1285
|
+
message: 'what is waterglass?',
|
|
1286
|
+
draftAnswer: fullStatement,
|
|
1287
|
+
knowledgePoints: [point],
|
|
1288
|
+
citations: [point.citation],
|
|
1289
|
+
usedScope: scopedWaterglass,
|
|
1290
|
+
graphContext: makeGraphContext(),
|
|
1291
|
+
graphAnswerPlan,
|
|
1292
|
+
ragContextPack: {
|
|
1293
|
+
query: 'what is waterglass?',
|
|
1294
|
+
generatedAt: '2026-08-25T00:00:00.000Z',
|
|
1295
|
+
sourceBoundary: 'direct_span_only',
|
|
1296
|
+
budget: { maxFragments: 2, maxCharsPerFragment: 600, maxTotalChars: 1200 },
|
|
1297
|
+
fragments: [
|
|
1298
|
+
{
|
|
1299
|
+
fragmentId: 'direct_support', role: 'direct_support', text: fullStatement,
|
|
1300
|
+
atomId: point.atomId, documentId: point.documentId || 'doc_water_glass', sourcePath, title: point.title,
|
|
1301
|
+
headingPath: ['Water Glass'], charCount: fullStatement.length, tokenEstimate: 60,
|
|
1302
|
+
truncated: false, citationIds: ['citation_water_glass'], sourceBoundary: 'direct_span_only',
|
|
1303
|
+
},
|
|
1304
|
+
{
|
|
1305
|
+
fragmentId: 'parent_context', role: 'parent_context', text: incompleteStatement,
|
|
1306
|
+
atomId: point.atomId, documentId: point.documentId || 'doc_water_glass', sourcePath, title: point.title,
|
|
1307
|
+
headingPath: ['Water Glass'], charCount: incompleteStatement.length, tokenEstimate: 60,
|
|
1308
|
+
truncated: false, citationIds: ['citation_water_glass'], sourceBoundary: 'direct_span_only',
|
|
1309
|
+
},
|
|
1310
|
+
],
|
|
1311
|
+
sourceDecisions: [], totalCharCount: fullStatement.length + incompleteStatement.length, tokenEstimate: 120,
|
|
1312
|
+
},
|
|
1313
|
+
ragSufficiencyReview: {
|
|
1314
|
+
reviewedAt: '2026-08-25T00:00:00.000Z', status: 'sufficient', score: 0.95,
|
|
1315
|
+
reasons: [], deterministic: true, recoveryAttempted: false, llmJudgeUsed: false, degradationState: 'none',
|
|
1316
|
+
},
|
|
1317
|
+
reviewedAt: '2026-08-25T00:00:00.000Z',
|
|
1318
|
+
});
|
|
1319
|
+
expect(review.publicGraphAnswerPlan?.claims.map((claim) => claim.claimId)).toEqual([
|
|
1320
|
+
'complete_formula_claim',
|
|
1321
|
+
]);
|
|
1322
|
+
expect((review.publicAnswer.match(/Water glass is a bounded physical system/gu) || [])).toHaveLength(1);
|
|
1323
|
+
expect(review.publicAnswer).not.toContain('across t Water glass');
|
|
1324
|
+
});
|
|
1325
|
+
test('does not publish an unrelated CFL variable glossary in a waterglass definition', () => {
|
|
1326
|
+
const point = makeKnowledgePoint({
|
|
1327
|
+
title: '水杯 (water glass)',
|
|
1328
|
+
summary: '此处的“水杯”被定义为一个由水和玻璃杯组成的物理系统。',
|
|
1329
|
+
evidenceSnippet: '此处的“水杯”被定义为一个由水和玻璃杯组成的物理系统。',
|
|
1330
|
+
});
|
|
1331
|
+
const sourcePath = point.sourcePath || 'Knowledge_Base/waterglass/water-glass.md';
|
|
1332
|
+
const graphAnswerPlan = {
|
|
1333
|
+
intent: 'definition',
|
|
1334
|
+
depth: 'standard',
|
|
1335
|
+
anchorAtomId: point.atomId,
|
|
1336
|
+
leadClaimId: 'waterglass_definition',
|
|
1337
|
+
requiredRoles: ['definition', 'attribute'],
|
|
1338
|
+
omittedCandidates: [],
|
|
1339
|
+
claims: [
|
|
1340
|
+
{
|
|
1341
|
+
claimId: 'waterglass_definition',
|
|
1342
|
+
role: 'definition',
|
|
1343
|
+
required: true,
|
|
1344
|
+
priority: 100,
|
|
1345
|
+
statement: '此处的“水杯”被定义为一个由水和玻璃杯组成的物理系统。',
|
|
1346
|
+
subjectAtomId: point.atomId,
|
|
1347
|
+
supportingAtomIds: [],
|
|
1348
|
+
supportingEdgeIds: [],
|
|
1349
|
+
evidenceRefs: [{
|
|
1350
|
+
evidenceId: 'waterglass_definition',
|
|
1351
|
+
atomId: point.atomId,
|
|
1352
|
+
sourcePath,
|
|
1353
|
+
citationIds: [],
|
|
1354
|
+
text: '此处的“水杯”被定义为一个由水和玻璃杯组成的物理系统。',
|
|
1355
|
+
}],
|
|
1356
|
+
confidence: 0.99,
|
|
1357
|
+
},
|
|
1358
|
+
{
|
|
1359
|
+
claimId: 'cfl_variable_glossary',
|
|
1360
|
+
role: 'attribute',
|
|
1361
|
+
required: true,
|
|
1362
|
+
priority: 88,
|
|
1363
|
+
statement: '其中 $C$ 是库朗数,$u$ 是特征速度,$\\Delta x$ 是网格尺寸。',
|
|
1364
|
+
subjectAtomId: point.atomId,
|
|
1365
|
+
supportingAtomIds: [],
|
|
1366
|
+
supportingEdgeIds: [],
|
|
1367
|
+
evidenceRefs: [{
|
|
1368
|
+
evidenceId: 'cfl_variable_glossary',
|
|
1369
|
+
atomId: point.atomId,
|
|
1370
|
+
sourcePath,
|
|
1371
|
+
citationIds: [],
|
|
1372
|
+
text: '其中 $C$ 是库朗数,$u$ 是特征速度,$\\Delta x$ 是网格尺寸。',
|
|
1373
|
+
}],
|
|
1374
|
+
confidence: 0.98,
|
|
1375
|
+
},
|
|
1376
|
+
],
|
|
1377
|
+
};
|
|
1378
|
+
const review = (0, answerReleaseReview_1.reviewAnswerRelease)({
|
|
1379
|
+
message: '什么是waterglass?',
|
|
1380
|
+
draftAnswer: '此处的“水杯”被定义为一个由水和玻璃杯组成的物理系统。',
|
|
1381
|
+
knowledgePoints: [point],
|
|
1382
|
+
citations: [point.citation],
|
|
1383
|
+
usedScope: scopedWaterglass,
|
|
1384
|
+
graphContext: makeGraphContext(),
|
|
1385
|
+
graphAnswerPlan,
|
|
1386
|
+
ragContextPack: {
|
|
1387
|
+
query: '什么是waterglass?',
|
|
1388
|
+
generatedAt: '2026-08-25T00:00:00.000Z',
|
|
1389
|
+
sourceBoundary: 'full_document',
|
|
1390
|
+
budget: { maxFragments: 2, maxCharsPerFragment: 600, maxTotalChars: 1200 },
|
|
1391
|
+
fragments: [{
|
|
1392
|
+
fragmentId: 'waterglass_full_document',
|
|
1393
|
+
role: 'direct_support',
|
|
1394
|
+
text: '此处的“水杯”被定义为一个由水和玻璃杯组成的物理系统。实现考量中的CFL变量 glossary 不属于定义。',
|
|
1395
|
+
atomId: point.atomId,
|
|
1396
|
+
documentId: point.documentId || 'doc_water_glass',
|
|
1397
|
+
sourcePath,
|
|
1398
|
+
title: point.title,
|
|
1399
|
+
headingPath: [point.title],
|
|
1400
|
+
charCount: 100,
|
|
1401
|
+
tokenEstimate: 25,
|
|
1402
|
+
truncated: false,
|
|
1403
|
+
citationIds: [point.citation?.citationId || 'citation_water_glass'],
|
|
1404
|
+
sourceBoundary: 'full_document',
|
|
1405
|
+
}],
|
|
1406
|
+
sourceDecisions: [],
|
|
1407
|
+
totalCharCount: 100,
|
|
1408
|
+
tokenEstimate: 25,
|
|
1409
|
+
},
|
|
1410
|
+
ragSufficiencyReview: {
|
|
1411
|
+
reviewedAt: '2026-08-25T00:00:00.000Z',
|
|
1412
|
+
status: 'sufficient',
|
|
1413
|
+
score: 0.95,
|
|
1414
|
+
reasons: [],
|
|
1415
|
+
deterministic: true,
|
|
1416
|
+
recoveryAttempted: false,
|
|
1417
|
+
llmJudgeUsed: false,
|
|
1418
|
+
degradationState: 'none',
|
|
1419
|
+
},
|
|
1420
|
+
reviewedAt: '2026-08-25T00:00:00.000Z',
|
|
1421
|
+
});
|
|
1422
|
+
expect(review.publicAnswer).toContain('水杯”被定义');
|
|
1423
|
+
expect(review.publicAnswer).not.toContain('库朗数');
|
|
1424
|
+
expect(review.publicAnswer).not.toContain('网格尺寸');
|
|
1425
|
+
expect(review.publicGraphAnswerPlan?.claims.map((claim) => claim.claimId)).toEqual([
|
|
1426
|
+
'waterglass_definition',
|
|
1427
|
+
]);
|
|
1428
|
+
});
|
|
1429
|
+
test('keeps a CFL variable glossary when the query explicitly asks about CFL', () => {
|
|
1430
|
+
const point = makeKnowledgePoint({
|
|
1431
|
+
title: 'CFL stability condition',
|
|
1432
|
+
summary: 'The CFL stability condition bounds the time step.',
|
|
1433
|
+
evidenceSnippet: 'The CFL stability condition bounds the time step.',
|
|
1434
|
+
});
|
|
1435
|
+
const sourcePath = point.sourcePath || 'Knowledge_Base/waterglass/water-glass.md';
|
|
1436
|
+
const glossary = 'where $C$ is the Courant number, $u$ is the characteristic velocity, and $\\Delta x$ is the grid size.';
|
|
1437
|
+
const review = (0, answerReleaseReview_1.reviewAnswerRelease)({
|
|
1438
|
+
message: 'What is the CFL stability condition?',
|
|
1439
|
+
draftAnswer: `The CFL stability condition bounds the time step. ${glossary}`,
|
|
1440
|
+
knowledgePoints: [point],
|
|
1441
|
+
citations: [point.citation],
|
|
1442
|
+
usedScope: scopedWaterglass,
|
|
1443
|
+
graphContext: makeGraphContext({ anchorTitle: 'CFL stability condition' }),
|
|
1444
|
+
graphAnswerPlan: {
|
|
1445
|
+
intent: 'definition',
|
|
1446
|
+
depth: 'standard',
|
|
1447
|
+
anchorAtomId: point.atomId,
|
|
1448
|
+
leadClaimId: 'cfl_definition',
|
|
1449
|
+
requiredRoles: ['definition', 'attribute'],
|
|
1450
|
+
omittedCandidates: [],
|
|
1451
|
+
claims: [
|
|
1452
|
+
{
|
|
1453
|
+
claimId: 'cfl_definition',
|
|
1454
|
+
role: 'definition',
|
|
1455
|
+
required: true,
|
|
1456
|
+
priority: 100,
|
|
1457
|
+
statement: 'The CFL stability condition bounds the time step.',
|
|
1458
|
+
subjectAtomId: point.atomId,
|
|
1459
|
+
supportingAtomIds: [],
|
|
1460
|
+
supportingEdgeIds: [],
|
|
1461
|
+
evidenceRefs: [{ evidenceId: 'cfl_definition', atomId: point.atomId, sourcePath, citationIds: [], text: 'The CFL stability condition bounds the time step.' }],
|
|
1462
|
+
confidence: 0.99,
|
|
1463
|
+
},
|
|
1464
|
+
{
|
|
1465
|
+
claimId: 'cfl_glossary',
|
|
1466
|
+
role: 'attribute',
|
|
1467
|
+
required: true,
|
|
1468
|
+
priority: 88,
|
|
1469
|
+
statement: glossary,
|
|
1470
|
+
subjectAtomId: point.atomId,
|
|
1471
|
+
supportingAtomIds: [],
|
|
1472
|
+
supportingEdgeIds: [],
|
|
1473
|
+
evidenceRefs: [{ evidenceId: 'cfl_glossary', atomId: point.atomId, sourcePath, citationIds: [], text: glossary }],
|
|
1474
|
+
confidence: 0.98,
|
|
1475
|
+
},
|
|
1476
|
+
],
|
|
1477
|
+
},
|
|
1478
|
+
ragContextPack: {
|
|
1479
|
+
query: 'What is the CFL stability condition?',
|
|
1480
|
+
generatedAt: '2026-08-25T00:00:00.000Z',
|
|
1481
|
+
sourceBoundary: 'full_document',
|
|
1482
|
+
budget: { maxFragments: 1, maxCharsPerFragment: 600, maxTotalChars: 600 },
|
|
1483
|
+
fragments: [{
|
|
1484
|
+
fragmentId: 'cfl_full_document',
|
|
1485
|
+
role: 'direct_support',
|
|
1486
|
+
text: `The CFL stability condition bounds the time step. ${glossary}`,
|
|
1487
|
+
atomId: point.atomId,
|
|
1488
|
+
documentId: point.documentId || 'doc_water_glass',
|
|
1489
|
+
sourcePath,
|
|
1490
|
+
title: point.title,
|
|
1491
|
+
headingPath: [point.title],
|
|
1492
|
+
charCount: 140,
|
|
1493
|
+
tokenEstimate: 35,
|
|
1494
|
+
truncated: false,
|
|
1495
|
+
citationIds: [point.citation?.citationId || 'citation_water_glass'],
|
|
1496
|
+
sourceBoundary: 'full_document',
|
|
1497
|
+
}],
|
|
1498
|
+
sourceDecisions: [],
|
|
1499
|
+
totalCharCount: 140,
|
|
1500
|
+
tokenEstimate: 35,
|
|
1501
|
+
},
|
|
1502
|
+
ragSufficiencyReview: {
|
|
1503
|
+
reviewedAt: '2026-08-25T00:00:00.000Z',
|
|
1504
|
+
status: 'sufficient',
|
|
1505
|
+
score: 0.95,
|
|
1506
|
+
reasons: [],
|
|
1507
|
+
deterministic: true,
|
|
1508
|
+
recoveryAttempted: false,
|
|
1509
|
+
llmJudgeUsed: false,
|
|
1510
|
+
degradationState: 'none',
|
|
1511
|
+
},
|
|
1512
|
+
reviewedAt: '2026-08-25T00:00:00.000Z',
|
|
1513
|
+
});
|
|
1514
|
+
expect(review.publicAnswer).toContain('Courant number');
|
|
1515
|
+
expect(review.publicAnswer).toContain('grid size');
|
|
1516
|
+
expect(review.publicGraphAnswerPlan?.claims.map((claim) => claim.claimId)).toEqual([
|
|
1517
|
+
'cfl_definition',
|
|
1518
|
+
'cfl_glossary',
|
|
1519
|
+
]);
|
|
1520
|
+
});
|
|
1521
|
+
test('honors an explicit Chinese answer language for English no-evidence abstentions', () => {
|
|
1522
|
+
const review = (0, answerReleaseReview_1.reviewAnswerRelease)({
|
|
1523
|
+
message: 'what is water glass?',
|
|
1524
|
+
answerLanguage: 'zh',
|
|
1525
|
+
draftAnswer: 'No scoped knowledge points matched "what is water glass?".',
|
|
1526
|
+
knowledgePoints: [],
|
|
1527
|
+
citations: [],
|
|
1528
|
+
usedScope: scopedWaterglass,
|
|
1529
|
+
graphContext: null,
|
|
1530
|
+
reviewedAt: '2026-08-24T00:30:00.000Z',
|
|
1531
|
+
});
|
|
1532
|
+
expect(review.decision).toBe('abstain');
|
|
1533
|
+
expect(review.publicAnswer).toContain('当前范围');
|
|
1534
|
+
expect(review.publicAnswer).toContain('我暂时不能');
|
|
1535
|
+
expect(review.publicAnswer).not.toContain('I cannot give a grounded answer');
|
|
1536
|
+
});
|
|
530
1537
|
test('keeps RAG evidence in revised definition answers after public-surface contraction', () => {
|
|
531
1538
|
const baseCitation = makeKnowledgePoint({
|
|
532
1539
|
title: 'Water Glass',
|
|
@@ -1357,6 +2364,33 @@ describe('answerReleaseReview', () => {
|
|
|
1357
2364
|
}),
|
|
1358
2365
|
]));
|
|
1359
2366
|
});
|
|
2367
|
+
test('does not treat a scope-qualified heading and its source sentence as different subjects', () => {
|
|
2368
|
+
const point = makeKnowledgePoint({
|
|
2369
|
+
title: 'Staging Owner',
|
|
2370
|
+
summary: '## Staging Owner The deployment owner is Release Ops in the staging environment.',
|
|
2371
|
+
evidenceSnippet: '## Staging Owner The deployment owner is Release Ops in the staging environment.',
|
|
2372
|
+
citation: {
|
|
2373
|
+
...makeKnowledgePoint().citation,
|
|
2374
|
+
title: 'Staging Owner',
|
|
2375
|
+
snippet: '## Staging Owner The deployment owner is Release Ops in the staging environment.',
|
|
2376
|
+
},
|
|
2377
|
+
citations: [{
|
|
2378
|
+
...makeKnowledgePoint().citation,
|
|
2379
|
+
title: 'Staging Owner',
|
|
2380
|
+
snippet: '## Staging Owner The deployment owner is Release Ops in the staging environment.',
|
|
2381
|
+
}],
|
|
2382
|
+
});
|
|
2383
|
+
const review = (0, answerReleaseReview_1.reviewAnswerRelease)({
|
|
2384
|
+
message: 'compare staging and production deployment owners',
|
|
2385
|
+
draftAnswer: 'Cross environment staging owner source records that the deployment owner is Release Ops in the staging environment.',
|
|
2386
|
+
knowledgePoints: [point],
|
|
2387
|
+
citations: point.citations || [],
|
|
2388
|
+
usedScope: scopedWaterglass,
|
|
2389
|
+
graphContext: makeGraphContext(),
|
|
2390
|
+
reviewedAt: '2026-08-24T00:34:00.000Z',
|
|
2391
|
+
});
|
|
2392
|
+
expect(review.failedGateIds).not.toContain('claim_subject_consistency');
|
|
2393
|
+
});
|
|
1360
2394
|
test('revises grounded answers when same-subject attribute claims conflict with cited support', () => {
|
|
1361
2395
|
const point = makeKnowledgePoint({
|
|
1362
2396
|
title: 'Water Glass',
|
|
@@ -2110,6 +3144,28 @@ describe('answerReleaseReview', () => {
|
|
|
2110
3144
|
}),
|
|
2111
3145
|
]));
|
|
2112
3146
|
});
|
|
3147
|
+
test('still rejects an unsupported polarity assertion written as a heading', () => {
|
|
3148
|
+
const review = (0, answerReleaseReview_1.reviewAnswerRelease)({
|
|
3149
|
+
message: 'what is water glass', responseMode: 'full',
|
|
3150
|
+
draftAnswer: '# Water glass is not a transparent container filled with water.',
|
|
3151
|
+
knowledgePoints: [makeKnowledgePoint()],
|
|
3152
|
+
citations: [makeKnowledgePoint().citation],
|
|
3153
|
+
usedScope: scopedWaterglass, graphContext: makeGraphContext(),
|
|
3154
|
+
});
|
|
3155
|
+
expect(review.failedGateIds).toContain('claim_polarity_consistency');
|
|
3156
|
+
expect(review.publicAnswer).not.toContain('is not a transparent container');
|
|
3157
|
+
});
|
|
3158
|
+
test('does not trust a source label attached to an unsupported assertion', () => {
|
|
3159
|
+
const review = (0, answerReleaseReview_1.reviewAnswerRelease)({
|
|
3160
|
+
message: 'what is water glass',
|
|
3161
|
+
draftAnswer: 'Water Glass: Water glass is not a transparent container filled with water.',
|
|
3162
|
+
knowledgePoints: [makeKnowledgePoint()],
|
|
3163
|
+
citations: [makeKnowledgePoint().citation],
|
|
3164
|
+
usedScope: scopedWaterglass, graphContext: makeGraphContext(),
|
|
3165
|
+
});
|
|
3166
|
+
expect(review.failedGateIds).toContain('claim_polarity_consistency');
|
|
3167
|
+
expect(review.publicAnswer).not.toContain('is not a transparent container');
|
|
3168
|
+
});
|
|
2113
3169
|
test('does not raise a polarity conflict when support includes an unrelated negative sentence', () => {
|
|
2114
3170
|
const point = makeKnowledgePoint({
|
|
2115
3171
|
summary: 'Water glass is not plastic. Water glass is a transparent container filled with water.',
|
|
@@ -2854,6 +3910,236 @@ describe('answerReleaseReview', () => {
|
|
|
2854
3910
|
}),
|
|
2855
3911
|
]));
|
|
2856
3912
|
});
|
|
3913
|
+
test('does not restore a containment-conflicting graph plan after revising the answer', () => {
|
|
3914
|
+
const point = makeKnowledgePoint({
|
|
3915
|
+
title: 'Water Glass',
|
|
3916
|
+
summary: 'Water Glass contains water.',
|
|
3917
|
+
evidenceSnippet: 'Water Glass contains water.',
|
|
3918
|
+
citation: {
|
|
3919
|
+
...makeKnowledgePoint().citation,
|
|
3920
|
+
title: 'Water Glass',
|
|
3921
|
+
snippet: 'Water Glass contains water.',
|
|
3922
|
+
},
|
|
3923
|
+
citations: [{
|
|
3924
|
+
...makeKnowledgePoint().citation,
|
|
3925
|
+
title: 'Water Glass',
|
|
3926
|
+
snippet: 'Water Glass contains water.',
|
|
3927
|
+
}],
|
|
3928
|
+
});
|
|
3929
|
+
const unsafePlan = {
|
|
3930
|
+
intent: 'definition',
|
|
3931
|
+
depth: 'compact',
|
|
3932
|
+
anchorAtomId: point.atomId,
|
|
3933
|
+
leadClaimId: 'claim_unsafe_containment',
|
|
3934
|
+
requiredRoles: ['definition'],
|
|
3935
|
+
omittedCandidates: [],
|
|
3936
|
+
claims: [{
|
|
3937
|
+
claimId: 'claim_unsafe_containment',
|
|
3938
|
+
role: 'definition',
|
|
3939
|
+
required: true,
|
|
3940
|
+
priority: 1,
|
|
3941
|
+
statement: 'Water Glass contains mercury.',
|
|
3942
|
+
subjectAtomId: point.atomId,
|
|
3943
|
+
supportingAtomIds: [],
|
|
3944
|
+
supportingEdgeIds: [],
|
|
3945
|
+
evidenceRefs: [{
|
|
3946
|
+
evidenceId: 'unsafe_containment',
|
|
3947
|
+
atomId: point.atomId,
|
|
3948
|
+
sourcePath: point.sourcePath || 'Knowledge_Base/waterglass/water-glass.md',
|
|
3949
|
+
citationIds: ['citation_water_glass'],
|
|
3950
|
+
text: 'Water Glass contains mercury.',
|
|
3951
|
+
}],
|
|
3952
|
+
confidence: 0.9,
|
|
3953
|
+
}],
|
|
3954
|
+
};
|
|
3955
|
+
const review = (0, answerReleaseReview_1.reviewAnswerRelease)({
|
|
3956
|
+
message: 'what does water glass contain?',
|
|
3957
|
+
draftAnswer: 'Water Glass contains mercury.',
|
|
3958
|
+
knowledgePoints: [point],
|
|
3959
|
+
citations: point.citations || [],
|
|
3960
|
+
usedScope: scopedWaterglass,
|
|
3961
|
+
graphContext: makeGraphContext(),
|
|
3962
|
+
graphAnswerPlan: unsafePlan,
|
|
3963
|
+
ragContextPack: {
|
|
3964
|
+
query: 'what does water glass contain?',
|
|
3965
|
+
generatedAt: '2026-08-24T00:30:00.000Z',
|
|
3966
|
+
sourceBoundary: 'direct_span_only',
|
|
3967
|
+
budget: { maxFragments: 1, maxCharsPerFragment: 600, maxTotalChars: 600 },
|
|
3968
|
+
fragments: [{
|
|
3969
|
+
fragmentId: 'unsafe_plan_rag_context',
|
|
3970
|
+
role: 'direct_support',
|
|
3971
|
+
text: 'Water Glass contains water.',
|
|
3972
|
+
atomId: point.atomId,
|
|
3973
|
+
documentId: point.documentId || 'doc_water_glass',
|
|
3974
|
+
sourcePath: point.sourcePath || 'Knowledge_Base/waterglass/water-glass.md',
|
|
3975
|
+
title: point.title,
|
|
3976
|
+
headingPath: ['Water Glass'],
|
|
3977
|
+
charCount: 27,
|
|
3978
|
+
tokenEstimate: 7,
|
|
3979
|
+
truncated: false,
|
|
3980
|
+
citationIds: ['citation_water_glass'],
|
|
3981
|
+
sourceBoundary: 'direct_span_only',
|
|
3982
|
+
}],
|
|
3983
|
+
sourceDecisions: [],
|
|
3984
|
+
totalCharCount: 27,
|
|
3985
|
+
tokenEstimate: 7,
|
|
3986
|
+
},
|
|
3987
|
+
ragSufficiencyReview: {
|
|
3988
|
+
reviewedAt: '2026-08-24T00:30:00.000Z',
|
|
3989
|
+
status: 'sufficient',
|
|
3990
|
+
score: 0.9,
|
|
3991
|
+
reasons: [],
|
|
3992
|
+
deterministic: true,
|
|
3993
|
+
recoveryAttempted: false,
|
|
3994
|
+
llmJudgeUsed: false,
|
|
3995
|
+
degradationState: 'none',
|
|
3996
|
+
},
|
|
3997
|
+
reviewedAt: '2026-08-24T00:30:00.000Z',
|
|
3998
|
+
});
|
|
3999
|
+
expect(review.decision).toBe('revise');
|
|
4000
|
+
expect(review.failedGateIds).toContain('claim_containment_consistency');
|
|
4001
|
+
expect(review.publicAnswer).toContain('Water Glass contains water.');
|
|
4002
|
+
expect(review.publicAnswer).not.toContain('mercury');
|
|
4003
|
+
expect(review.publicGraphAnswerPlan?.claims).toEqual([]);
|
|
4004
|
+
expect(review.auditGraphAnswerPlan).toEqual(unsafePlan);
|
|
4005
|
+
expect(review.graphAnswerCoverage).toEqual(expect.objectContaining({
|
|
4006
|
+
applicable: false,
|
|
4007
|
+
}));
|
|
4008
|
+
});
|
|
4009
|
+
test('drops a newly introduced unsafe plan claim during final public-answer validation', () => {
|
|
4010
|
+
const point = makeKnowledgePoint({
|
|
4011
|
+
title: 'Water Glass',
|
|
4012
|
+
summary: 'Water Glass contains water.',
|
|
4013
|
+
evidenceSnippet: 'Water Glass contains water.',
|
|
4014
|
+
citation: {
|
|
4015
|
+
...makeKnowledgePoint().citation,
|
|
4016
|
+
title: 'Water Glass',
|
|
4017
|
+
snippet: 'Water Glass contains water.',
|
|
4018
|
+
},
|
|
4019
|
+
});
|
|
4020
|
+
const unsafePlan = {
|
|
4021
|
+
intent: 'definition',
|
|
4022
|
+
depth: 'compact',
|
|
4023
|
+
anchorAtomId: point.atomId,
|
|
4024
|
+
leadClaimId: 'unsafe_plan_claim',
|
|
4025
|
+
requiredRoles: ['definition'],
|
|
4026
|
+
omittedCandidates: [],
|
|
4027
|
+
claims: [{
|
|
4028
|
+
claimId: 'unsafe_plan_claim',
|
|
4029
|
+
role: 'definition',
|
|
4030
|
+
required: true,
|
|
4031
|
+
priority: 1,
|
|
4032
|
+
statement: 'Water Glass contains mercury.',
|
|
4033
|
+
subjectAtomId: point.atomId,
|
|
4034
|
+
supportingAtomIds: [],
|
|
4035
|
+
supportingEdgeIds: [],
|
|
4036
|
+
evidenceRefs: [{
|
|
4037
|
+
evidenceId: 'unsafe_plan_claim',
|
|
4038
|
+
atomId: point.atomId,
|
|
4039
|
+
sourcePath: point.sourcePath || 'Knowledge_Base/waterglass/water-glass.md',
|
|
4040
|
+
citationIds: [],
|
|
4041
|
+
text: 'Water Glass contains mercury.',
|
|
4042
|
+
}],
|
|
4043
|
+
confidence: 0.9,
|
|
4044
|
+
}],
|
|
4045
|
+
};
|
|
4046
|
+
const review = (0, answerReleaseReview_1.reviewAnswerRelease)({
|
|
4047
|
+
message: 'what does water glass contain?',
|
|
4048
|
+
draftAnswer: 'Water Glass contains water.',
|
|
4049
|
+
knowledgePoints: [point],
|
|
4050
|
+
citations: [point.citation],
|
|
4051
|
+
usedScope: scopedWaterglass,
|
|
4052
|
+
graphContext: makeGraphContext(),
|
|
4053
|
+
graphAnswerPlan: unsafePlan,
|
|
4054
|
+
ragContextPack: {
|
|
4055
|
+
query: 'what does water glass contain?',
|
|
4056
|
+
generatedAt: '2026-08-24T00:32:00.000Z',
|
|
4057
|
+
sourceBoundary: 'direct_span_only',
|
|
4058
|
+
budget: { maxFragments: 1, maxCharsPerFragment: 600, maxTotalChars: 600 },
|
|
4059
|
+
fragments: [{
|
|
4060
|
+
fragmentId: 'safe_support',
|
|
4061
|
+
role: 'direct_support',
|
|
4062
|
+
text: 'Water Glass contains water.',
|
|
4063
|
+
atomId: point.atomId,
|
|
4064
|
+
documentId: point.documentId || 'doc_water_glass',
|
|
4065
|
+
sourcePath: point.sourcePath || 'Knowledge_Base/waterglass/water-glass.md',
|
|
4066
|
+
title: point.title,
|
|
4067
|
+
headingPath: ['Water Glass'],
|
|
4068
|
+
charCount: 27,
|
|
4069
|
+
tokenEstimate: 7,
|
|
4070
|
+
truncated: false,
|
|
4071
|
+
citationIds: ['citation_water_glass'],
|
|
4072
|
+
sourceBoundary: 'direct_span_only',
|
|
4073
|
+
}],
|
|
4074
|
+
sourceDecisions: [],
|
|
4075
|
+
totalCharCount: 27,
|
|
4076
|
+
tokenEstimate: 7,
|
|
4077
|
+
},
|
|
4078
|
+
ragSufficiencyReview: {
|
|
4079
|
+
reviewedAt: '2026-08-24T00:32:00.000Z',
|
|
4080
|
+
status: 'sufficient',
|
|
4081
|
+
score: 0.9,
|
|
4082
|
+
reasons: [],
|
|
4083
|
+
deterministic: true,
|
|
4084
|
+
recoveryAttempted: false,
|
|
4085
|
+
llmJudgeUsed: false,
|
|
4086
|
+
degradationState: 'none',
|
|
4087
|
+
},
|
|
4088
|
+
reviewedAt: '2026-08-24T00:32:00.000Z',
|
|
4089
|
+
});
|
|
4090
|
+
expect(review.publicAnswer).toBe('Water Glass contains water.');
|
|
4091
|
+
expect(review.publicAnswer).not.toContain('mercury');
|
|
4092
|
+
expect(review.publicGraphAnswerPlan?.claims).toEqual([]);
|
|
4093
|
+
expect(review.graphAnswerCoverage).toEqual(expect.objectContaining({ applicable: false }));
|
|
4094
|
+
});
|
|
4095
|
+
test('abstains when a required definition plan projects to zero public claims', () => {
|
|
4096
|
+
const point = makeKnowledgePoint({
|
|
4097
|
+
title: 'Water Glass',
|
|
4098
|
+
summary: 'Water Glass is compared with a PET Plastic Cup.',
|
|
4099
|
+
evidenceSnippet: 'Water Glass is compared with a PET Plastic Cup.',
|
|
4100
|
+
});
|
|
4101
|
+
const comparisonOnlyPlan = {
|
|
4102
|
+
intent: 'definition',
|
|
4103
|
+
depth: 'compact',
|
|
4104
|
+
anchorAtomId: point.atomId,
|
|
4105
|
+
leadClaimId: 'comparison_only',
|
|
4106
|
+
requiredRoles: ['contrast'],
|
|
4107
|
+
omittedCandidates: [],
|
|
4108
|
+
claims: [{
|
|
4109
|
+
claimId: 'comparison_only',
|
|
4110
|
+
role: 'contrast',
|
|
4111
|
+
required: true,
|
|
4112
|
+
priority: 1,
|
|
4113
|
+
statement: 'Water Glass is compared with a PET Plastic Cup.',
|
|
4114
|
+
subjectAtomId: point.atomId,
|
|
4115
|
+
supportingAtomIds: [],
|
|
4116
|
+
supportingEdgeIds: [],
|
|
4117
|
+
evidenceRefs: [{
|
|
4118
|
+
evidenceId: 'comparison_only',
|
|
4119
|
+
atomId: point.atomId,
|
|
4120
|
+
sourcePath: point.sourcePath || 'Knowledge_Base/waterglass/water-glass.md',
|
|
4121
|
+
citationIds: [],
|
|
4122
|
+
text: 'Water Glass is compared with a PET Plastic Cup.',
|
|
4123
|
+
}],
|
|
4124
|
+
confidence: 0.91,
|
|
4125
|
+
}],
|
|
4126
|
+
};
|
|
4127
|
+
const review = (0, answerReleaseReview_1.reviewAnswerRelease)({
|
|
4128
|
+
message: 'what is water glass?',
|
|
4129
|
+
draftAnswer: 'Water Glass is compared with a PET Plastic Cup.',
|
|
4130
|
+
knowledgePoints: [point],
|
|
4131
|
+
citations: [point.citation],
|
|
4132
|
+
usedScope: scopedWaterglass,
|
|
4133
|
+
graphContext: makeGraphContext(),
|
|
4134
|
+
graphAnswerPlan: comparisonOnlyPlan,
|
|
4135
|
+
reviewedAt: '2026-08-24T00:35:00.000Z',
|
|
4136
|
+
});
|
|
4137
|
+
expect(review.decision).toBe('abstain');
|
|
4138
|
+
expect(review.failedGateIds).toContain('definition_projection_integrity');
|
|
4139
|
+
expect(review.publicAnswer).not.toContain('PET Plastic Cup');
|
|
4140
|
+
expect(review.publicGraphAnswerPlan?.claims).toEqual([]);
|
|
4141
|
+
expect(review.auditGraphAnswerPlan).toEqual(comparisonOnlyPlan);
|
|
4142
|
+
});
|
|
2857
4143
|
test('revises grounded answers when a DAG analogy pair is incorrectly released as a Chinese contrast claim', () => {
|
|
2858
4144
|
const point = makeKnowledgePoint({
|
|
2859
4145
|
title: '层流',
|