@knights-eye-chess/ai-analysis 0.0.0-stage → 0.1.0-dev.17
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/LICENSE +235 -0
- package/LICENSING.md +26 -0
- package/NOTICE +5 -0
- package/NPM-PUBLISHING.md +28 -0
- package/README.md +139 -2
- package/SOURCE-ORIGIN.json +16 -0
- package/THIRD_PARTY_NOTICES.md +18 -0
- package/build.mjs +22 -0
- package/dist/answer-pipeline.test.mjs +375 -0
- package/dist/chunk-PLKNJRPF.js +10662 -0
- package/dist/chunk-XQDZJOYD.js +2515 -0
- package/dist/index.js +146 -0
- package/dist/owner-tests/chess-reasoning-compact-search-preparation.test.mjs +963 -0
- package/dist/owner-tests/mechanism-encoding.test.mjs +529 -0
- package/dist/owner-tests/move-mechanism-facts.test.mjs +396 -0
- package/dist/owner-tests/pipeline-host-preparation.test.mjs +10556 -0
- package/dist/owner-tests/position-preparation.test.mjs +625 -0
- package/dist/owner-tests/preparation-consolidation.test.mjs +1052 -0
- package/dist/owner-tests/prose-reference-admission.test.mjs +1770 -0
- package/dist/owner-tests/score-comparison-notices.test.mjs +240 -0
- package/dist/owner-tests/simple-engine-presentation.test.mjs +233 -0
- package/dist/owner-tests/tool-input-loop-guard.test.mjs +78 -0
- package/dist/research.js +2274 -0
- package/dist/runtime-closure.json +103 -0
- package/dist/shared-runtime-closure.json +39 -0
- package/dist/shared.js +152 -0
- package/dist/types/ai-request-failure.d.ts +14 -0
- package/dist/types/ai-request-limits.d.ts +4 -0
- package/dist/types/ai-routing-diagnostics.d.ts +14 -0
- package/dist/types/chess-reasoning/ablation-adaptive-evidence-loop.d.ts +127 -0
- package/dist/types/chess-reasoning/ablation-adaptive-runtime.d.ts +178 -0
- package/dist/types/chess-reasoning/ablation-direct-synthesis.d.ts +1030 -0
- package/dist/types/chess-reasoning/ablation-evidence-bundle.d.ts +185 -0
- package/dist/types/chess-reasoning/ablation-evidence-capture.d.ts +37 -0
- package/dist/types/chess-reasoning/ablation-lean-direct-runtime.d.ts +193 -0
- package/dist/types/chess-reasoning/ablation-model-facing-evidence.d.ts +38 -0
- package/dist/types/chess-reasoning/ablation-transport-correction.d.ts +13 -0
- package/dist/types/chess-reasoning/ai-sdk-runtime-support.d.ts +93 -0
- package/dist/types/chess-reasoning/answer-host-contracts.d.ts +59 -0
- package/dist/types/chess-reasoning/answer-model-connector.d.ts +68 -0
- package/dist/types/chess-reasoning/answer-pipeline-exports.d.ts +98 -0
- package/dist/types/chess-reasoning/answer-pipeline.d.ts +41 -0
- package/dist/types/chess-reasoning/answer-reference-validation.d.ts +40 -0
- package/dist/types/chess-reasoning/answer-tool-host.d.ts +8 -0
- package/dist/types/chess-reasoning/branch-expansion-policy.d.ts +13 -0
- package/dist/types/chess-reasoning/branch-expansion.d.ts +39 -0
- package/dist/types/chess-reasoning/causal-claim-checks.d.ts +21 -0
- package/dist/types/chess-reasoning/chess-reference-dictionary.d.ts +13 -0
- package/dist/types/chess-reasoning/classification-question-target.d.ts +22 -0
- package/dist/types/chess-reasoning/classification-reassessment.d.ts +31 -0
- package/dist/types/chess-reasoning/compact-search-preparation.d.ts +7 -0
- package/dist/types/chess-reasoning/concept-registry.d.ts +99 -0
- package/dist/types/chess-reasoning/conversation-context.d.ts +12 -0
- package/dist/types/chess-reasoning/engine-search-failure.d.ts +7 -0
- package/dist/types/chess-reasoning/evidence-citation-normalization.d.ts +9 -0
- package/dist/types/chess-reasoning/evidence-licenses.d.ts +57 -0
- package/dist/types/chess-reasoning/evidence-selector-contract.d.ts +5 -0
- package/dist/types/chess-reasoning/existing-analysis-context.d.ts +104 -0
- package/dist/types/chess-reasoning/fact-observation-provider.d.ts +15 -0
- package/dist/types/chess-reasoning/fact-provider.d.ts +111 -0
- package/dist/types/chess-reasoning/fresh-engine-pv-witnesses.d.ts +67 -0
- package/dist/types/chess-reasoning/historical-prose.d.ts +23 -0
- package/dist/types/chess-reasoning/idea-graph.d.ts +34 -0
- package/dist/types/chess-reasoning/initial-search-plan.d.ts +37 -0
- package/dist/types/chess-reasoning/lossless-evidence-sharing.d.ts +18 -0
- package/dist/types/chess-reasoning/matched-comparison.d.ts +10 -0
- package/dist/types/chess-reasoning/material-accounting.d.ts +80 -0
- package/dist/types/chess-reasoning/material-format.d.ts +4 -0
- package/dist/types/chess-reasoning/mechanical-fact-provider.d.ts +33 -0
- package/dist/types/chess-reasoning/mechanical-ray-facts.d.ts +19 -0
- package/dist/types/chess-reasoning/mechanism-presentation.d.ts +9 -0
- package/dist/types/chess-reasoning/move-mechanism-facts.d.ts +45 -0
- package/dist/types/chess-reasoning/native-answer-connector.d.ts +4 -0
- package/dist/types/chess-reasoning/opening-source-contracts.d.ts +54 -0
- package/dist/types/chess-reasoning/opening-source-credits.d.ts +16 -0
- package/dist/types/chess-reasoning/opponent-threat-preparation.d.ts +7 -0
- package/dist/types/chess-reasoning/piece-identities.d.ts +11 -0
- package/dist/types/chess-reasoning/poc-contracts.d.ts +1026 -0
- package/dist/types/chess-reasoning/poc-hypotheses.d.ts +74 -0
- package/dist/types/chess-reasoning/poc-move-witnesses.d.ts +13 -0
- package/dist/types/chess-reasoning/poc-observations.d.ts +23 -0
- package/dist/types/chess-reasoning/poc-piece-refs.d.ts +12 -0
- package/dist/types/chess-reasoning/poc-plan-model.d.ts +45 -0
- package/dist/types/chess-reasoning/poc-semantic-text.d.ts +8 -0
- package/dist/types/chess-reasoning/poc-tools.d.ts +81 -0
- package/dist/types/chess-reasoning/portable-answer-runtime.d.ts +291 -0
- package/dist/types/chess-reasoning/position-analysis-contracts.d.ts +31 -0
- package/dist/types/chess-reasoning/position-analysis-scope.d.ts +3 -0
- package/dist/types/chess-reasoning/preparation-consolidation.d.ts +21 -0
- package/dist/types/chess-reasoning/production-observation-provider.d.ts +16 -0
- package/dist/types/chess-reasoning/question-routing.d.ts +326 -0
- package/dist/types/chess-reasoning/recorded-main-line.d.ts +37 -0
- package/dist/types/chess-reasoning/recorded-position-tools.d.ts +11 -0
- package/dist/types/chess-reasoning/recorded-reference-context.d.ts +13 -0
- package/dist/types/chess-reasoning/recorded-selected-classification.d.ts +36 -0
- package/dist/types/chess-reasoning/reference-limits.d.ts +2 -0
- package/dist/types/chess-reasoning/research-exports.d.ts +197 -0
- package/dist/types/chess-reasoning/saved-score-presentation.d.ts +14 -0
- package/dist/types/chess-reasoning/score-comparison-notices.d.ts +33 -0
- package/dist/types/chess-reasoning/server-simple-policy.d.ts +31 -0
- package/dist/types/chess-reasoning/simple-agent-config.d.ts +73 -0
- package/dist/types/chess-reasoning/simple-board-analysis.d.ts +85 -0
- package/dist/types/chess-reasoning/simple-compact-evidence.d.ts +7 -0
- package/dist/types/chess-reasoning/simple-completion.d.ts +23 -0
- package/dist/types/chess-reasoning/simple-engine-presentation.d.ts +3 -0
- package/dist/types/chess-reasoning/simple-evidence-preparation.d.ts +17 -0
- package/dist/types/chess-reasoning/simple-evidence-view.d.ts +17 -0
- package/dist/types/chess-reasoning/simple-explanation-coverage.d.ts +90 -0
- package/dist/types/chess-reasoning/simple-fact-delivery.d.ts +43 -0
- package/dist/types/chess-reasoning/simple-fallback-premise.d.ts +5 -0
- package/dist/types/chess-reasoning/simple-prose-references.d.ts +108 -0
- package/dist/types/chess-reasoning/simple-runtime-version.d.ts +1 -0
- package/dist/types/chess-reasoning/stable.d.ts +2 -0
- package/dist/types/chess-reasoning/tool-input-loop-guard.d.ts +5 -0
- package/dist/types/chess-reasoning/types.d.ts +180 -0
- package/dist/types/chess-reasoning/visible-support-lines.d.ts +12 -0
- package/dist/types/chess-reasoning/wikibooks-index.d.ts +30 -0
- package/dist/types/chess-reasoning/wikibooks-tool-context.d.ts +10 -0
- package/dist/types/player-perspective.d.ts +16 -0
- package/dist/types/shared-exports.d.ts +22 -0
- package/docs/API.md +82 -0
- package/docs/OWNERSHIP-ADOPTION.md +35 -0
- package/docs/OWNERSHIP-DRIFT.json +55 -0
- package/docs/RESEARCH-API.md +28 -0
- package/licenses/third-party/INVENTORY.json +202 -0
- package/licenses/third-party/ai-7.0.85/LICENSE +13 -0
- package/licenses/third-party/ai-sdk--gateway-4.0.69/LICENSE +13 -0
- package/licenses/third-party/ai-sdk--provider-4.0.9/LICENSE +13 -0
- package/licenses/third-party/ai-sdk--provider-utils-5.0.34/APACHE-2.0.txt +73 -0
- package/licenses/third-party/ai-sdk--provider-utils-5.0.34/src/to-json-schema/zod3-to-json-schema/LICENSE +16 -0
- package/licenses/third-party/chess.js-1.4.0/LICENSE +23 -0
- package/licenses/third-party/eventsource-parser-3.1.1/LICENSE +21 -0
- package/licenses/third-party/json-schema-0.4.0/LICENSE +195 -0
- package/licenses/third-party/standard-schema--spec-1.1.0/LICENSE +21 -0
- package/licenses/third-party/types--json-schema-7.0.15/LICENSE +21 -0
- package/licenses/third-party/types--node-22.19.19/LICENSE +21 -0
- package/licenses/third-party/undici-7.30.0/LICENSE +21 -0
- package/licenses/third-party/undici-7.30.0/lib/web/fetch/LICENSE +21 -0
- package/licenses/third-party/undici-types-6.21.0/LICENSE +21 -0
- package/licenses/third-party/vercel--oidc-3.2.0/LICENSE +202 -0
- package/licenses/third-party/workflow--serde-4.1.0/APACHE-2.0.txt +73 -0
- package/licenses/third-party/workflow--serde-4.1.0/LICENSE.md +3 -0
- package/licenses/third-party/zod-4.6.5/LICENSE +21 -0
- package/npm-release.json +5 -0
- package/package.json +72 -4
- package/scripts/check-release-tooling.mjs +22 -0
- package/scripts/pack.mjs +68 -0
- package/scripts/publish-reviewed.mjs +85 -0
- package/scripts/release-tooling.json +13 -0
- package/scripts/update-dependency.mjs +44 -0
- package/scripts/verify-release.mjs +52 -0
- package/src/ai-request-failure.ts +34 -0
- package/src/ai-request-limits.ts +4 -0
- package/src/ai-routing-diagnostics.ts +33 -0
- package/src/chess-reasoning/ablation-adaptive-evidence-loop.ts +515 -0
- package/src/chess-reasoning/ablation-adaptive-runtime.ts +924 -0
- package/src/chess-reasoning/ablation-direct-synthesis.ts +1128 -0
- package/src/chess-reasoning/ablation-evidence-bundle.ts +726 -0
- package/src/chess-reasoning/ablation-evidence-capture.ts +513 -0
- package/src/chess-reasoning/ablation-lean-direct-runtime.ts +670 -0
- package/src/chess-reasoning/ablation-model-facing-evidence.ts +212 -0
- package/src/chess-reasoning/ablation-transport-correction.ts +106 -0
- package/src/chess-reasoning/ai-sdk-runtime-support.ts +381 -0
- package/src/chess-reasoning/answer-host-contracts.ts +10 -0
- package/src/chess-reasoning/answer-model-connector.ts +83 -0
- package/src/chess-reasoning/answer-pipeline-exports.ts +98 -0
- package/src/chess-reasoning/answer-pipeline.ts +195 -0
- package/src/chess-reasoning/answer-reference-validation.ts +124 -0
- package/src/chess-reasoning/answer-tool-host.ts +10 -0
- package/src/chess-reasoning/branch-expansion-policy.ts +32 -0
- package/src/chess-reasoning/branch-expansion.ts +80 -0
- package/src/chess-reasoning/causal-claim-checks.ts +256 -0
- package/src/chess-reasoning/chess-reference-dictionary.ts +21 -0
- package/src/chess-reasoning/classification-question-target.ts +30 -0
- package/src/chess-reasoning/classification-reassessment.ts +34 -0
- package/src/chess-reasoning/compact-search-preparation.ts +125 -0
- package/src/chess-reasoning/concept-registry.ts +275 -0
- package/src/chess-reasoning/conversation-context.ts +29 -0
- package/src/chess-reasoning/engine-search-failure.ts +11 -0
- package/src/chess-reasoning/evidence-citation-normalization.ts +15 -0
- package/src/chess-reasoning/evidence-licenses.ts +166 -0
- package/src/chess-reasoning/evidence-selector-contract.ts +5 -0
- package/src/chess-reasoning/existing-analysis-context.ts +544 -0
- package/src/chess-reasoning/fact-observation-provider.ts +134 -0
- package/src/chess-reasoning/fact-provider.ts +250 -0
- package/src/chess-reasoning/fresh-engine-pv-witnesses.ts +128 -0
- package/src/chess-reasoning/historical-prose.ts +116 -0
- package/src/chess-reasoning/idea-graph.ts +224 -0
- package/src/chess-reasoning/initial-search-plan.ts +115 -0
- package/src/chess-reasoning/lossless-evidence-sharing.ts +135 -0
- package/src/chess-reasoning/matched-comparison.ts +40 -0
- package/src/chess-reasoning/material-accounting.ts +55 -0
- package/src/chess-reasoning/material-format.ts +47 -0
- package/src/chess-reasoning/mechanical-fact-provider.ts +1602 -0
- package/src/chess-reasoning/mechanical-ray-facts.ts +123 -0
- package/src/chess-reasoning/mechanism-presentation.ts +94 -0
- package/src/chess-reasoning/move-mechanism-facts.ts +185 -0
- package/src/chess-reasoning/native-answer-connector.ts +13 -0
- package/src/chess-reasoning/opening-source-contracts.ts +47 -0
- package/src/chess-reasoning/opening-source-credits.ts +53 -0
- package/src/chess-reasoning/opponent-threat-preparation.ts +98 -0
- package/src/chess-reasoning/piece-identities.ts +159 -0
- package/src/chess-reasoning/poc-contracts.ts +1097 -0
- package/src/chess-reasoning/poc-hypotheses.ts +759 -0
- package/src/chess-reasoning/poc-move-witnesses.ts +170 -0
- package/src/chess-reasoning/poc-observations.ts +611 -0
- package/src/chess-reasoning/poc-piece-refs.ts +62 -0
- package/src/chess-reasoning/poc-plan-model.ts +345 -0
- package/src/chess-reasoning/poc-semantic-text.ts +10 -0
- package/src/chess-reasoning/poc-tools.ts +978 -0
- package/src/chess-reasoning/portable-answer-runtime.ts +684 -0
- package/src/chess-reasoning/position-analysis-contracts.ts +88 -0
- package/src/chess-reasoning/position-analysis-scope.ts +20 -0
- package/src/chess-reasoning/preparation-consolidation.ts +91 -0
- package/src/chess-reasoning/production-observation-provider.ts +41 -0
- package/src/chess-reasoning/question-routing.ts +332 -0
- package/src/chess-reasoning/recorded-main-line.ts +55 -0
- package/src/chess-reasoning/recorded-position-tools.ts +78 -0
- package/src/chess-reasoning/recorded-reference-context.ts +44 -0
- package/src/chess-reasoning/recorded-selected-classification.ts +54 -0
- package/src/chess-reasoning/reference-limits.ts +2 -0
- package/src/chess-reasoning/research-exports.ts +197 -0
- package/src/chess-reasoning/saved-score-presentation.ts +6 -0
- package/src/chess-reasoning/score-comparison-notices.ts +115 -0
- package/src/chess-reasoning/server-simple-policy.ts +75 -0
- package/src/chess-reasoning/simple-agent-config.ts +58 -0
- package/src/chess-reasoning/simple-board-analysis.ts +57 -0
- package/src/chess-reasoning/simple-compact-evidence.ts +79 -0
- package/src/chess-reasoning/simple-completion.ts +37 -0
- package/src/chess-reasoning/simple-engine-presentation.ts +95 -0
- package/src/chess-reasoning/simple-evidence-preparation.ts +32 -0
- package/src/chess-reasoning/simple-evidence-view.ts +69 -0
- package/src/chess-reasoning/simple-explanation-coverage.ts +118 -0
- package/src/chess-reasoning/simple-fact-delivery.ts +52 -0
- package/src/chess-reasoning/simple-fallback-premise.ts +65 -0
- package/src/chess-reasoning/simple-prose-references.ts +528 -0
- package/src/chess-reasoning/simple-runtime-version.ts +2 -0
- package/src/chess-reasoning/stable.ts +18 -0
- package/src/chess-reasoning/tool-input-loop-guard.ts +38 -0
- package/src/chess-reasoning/types.ts +195 -0
- package/src/chess-reasoning/visible-support-lines.ts +44 -0
- package/src/chess-reasoning/wikibooks-index.ts +56 -0
- package/src/chess-reasoning/wikibooks-tool-context.ts +91 -0
- package/src/player-perspective.ts +41 -0
- package/src/shared-exports.ts +23 -0
- package/test/answer-pipeline.test.mjs +375 -0
- package/test/owner/chess-reasoning-compact-search-preparation.test.mjs +111 -0
- package/test/owner/mechanism-encoding.test.mjs +78 -0
- package/test/owner/move-mechanism-facts.test.mjs +105 -0
- package/test/owner/pipeline-host-preparation.test.mjs +115 -0
- package/test/owner/position-preparation.test.mjs +22 -0
- package/test/owner/preparation-consolidation.test.mjs +74 -0
- package/test/owner/prose-reference-admission.test.mjs +26 -0
- package/test/owner/score-comparison-notices.test.mjs +116 -0
- package/test/owner/simple-engine-presentation.test.mjs +50 -0
- package/test/owner/tool-input-loop-guard.test.mjs +25 -0
- package/test-types.mts +23 -0
- package/tsconfig.json +22 -0
|
@@ -0,0 +1,963 @@
|
|
|
1
|
+
// test/owner/chess-reasoning-compact-search-preparation.test.mjs
|
|
2
|
+
import test from "node:test";
|
|
3
|
+
import assert from "node:assert/strict";
|
|
4
|
+
|
|
5
|
+
// src/chess-reasoning/mechanism-presentation.ts
|
|
6
|
+
var object = (v) => !!v && typeof v === "object" && !Array.isArray(v);
|
|
7
|
+
var COLUMNS = {
|
|
8
|
+
mover: ["pieceId", "pieceIdAfter", "fromSquare", "toSquare", "color", "pieceTypeBefore", "pieceTypeAfter", "attackersBefore", "attackersAfter"],
|
|
9
|
+
unmoved: ["pieceId", "square", "pieceType", "attackersBefore", "attackersAfter"],
|
|
10
|
+
rays: ["pieceId", "fromSquare", "color", "pieceType", "direction", "gainedSquares", "lostSquares"],
|
|
11
|
+
control: ["square", "color", "attackersBefore", "attackersAfter"]
|
|
12
|
+
};
|
|
13
|
+
function exactKeys(value, columns) {
|
|
14
|
+
return object(value) && Object.keys(value).length === columns.length && columns.every((column) => Object.hasOwn(value, column));
|
|
15
|
+
}
|
|
16
|
+
function encodeRows(value, columns) {
|
|
17
|
+
return columns.map((column) => value[column]);
|
|
18
|
+
}
|
|
19
|
+
function compactMechanism(value, targetSquares) {
|
|
20
|
+
if (!object(value) || !Array.isArray(value.controlDelta)) return value;
|
|
21
|
+
const targets = [...new Set(targetSquares)].filter((s) => /^[a-h][1-8]$/.test(s));
|
|
22
|
+
const controlDelta = value.controlDelta.filter((d) => object(d) && targets.includes(String(d.square)));
|
|
23
|
+
const rays = Array.isArray(value.stationarySliderRays) ? value.stationarySliderRays.map((ray) => {
|
|
24
|
+
if (!object(ray)) return ray;
|
|
25
|
+
const { beforeSquares: _before, afterSquares: _after, ...changes } = ray;
|
|
26
|
+
void _before;
|
|
27
|
+
void _after;
|
|
28
|
+
return changes;
|
|
29
|
+
}) : value.stationarySliderRays;
|
|
30
|
+
const projected = {
|
|
31
|
+
...value,
|
|
32
|
+
stationarySliderRays: rays,
|
|
33
|
+
controlDelta,
|
|
34
|
+
presentation: {
|
|
35
|
+
controlSquares: targets,
|
|
36
|
+
omittedControlDeltaCount: value.controlDelta.length - controlDelta.length,
|
|
37
|
+
scope: "All changed stationary rays and mover/unmoved attack measurements retained. Control deltas shown only for controlSquares; an omitted square is not checked-negative in this view. Full ray extents and all control deltas are retrievable."
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
if (!exactKeys(value, ["mover", "attackedUnmovedFriendlyPieces", "stationarySliderRays", "controlDelta", "checksRun", "scope"]) || !exactKeys(projected.mover, COLUMNS.mover) || !Array.isArray(projected.attackedUnmovedFriendlyPieces) || !projected.attackedUnmovedFriendlyPieces.every((item) => exactKeys(item, COLUMNS.unmoved)) || !Array.isArray(rays) || !rays.every((item) => exactKeys(item, COLUMNS.rays)) || !controlDelta.every((item) => exactKeys(item, COLUMNS.control))) return projected;
|
|
41
|
+
return {
|
|
42
|
+
encoding: "move-mechanism/1",
|
|
43
|
+
columns: COLUMNS,
|
|
44
|
+
rows: {
|
|
45
|
+
mover: encodeRows(projected.mover, COLUMNS.mover),
|
|
46
|
+
unmoved: projected.attackedUnmovedFriendlyPieces.map((item) => encodeRows(item, COLUMNS.unmoved)),
|
|
47
|
+
rays: rays.map((item) => encodeRows(item, COLUMNS.rays)),
|
|
48
|
+
control: controlDelta.map((item) => encodeRows(item, COLUMNS.control))
|
|
49
|
+
},
|
|
50
|
+
checksRun: projected.checksRun,
|
|
51
|
+
scope: projected.scope,
|
|
52
|
+
presentation: projected.presentation
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
function presentMoveMechanisms(moves, inspectPlies = [], inspectSquares = []) {
|
|
56
|
+
return moves.flatMap((fact, index) => {
|
|
57
|
+
if (!object(fact) || !object(fact.mechanism)) return [];
|
|
58
|
+
if (index >= 2 && !inspectPlies.includes(index + 1) && !inspectSquares.includes(String(fact.to))) return [];
|
|
59
|
+
const targets = [...inspectSquares, ...moves.slice(index, index + 3).flatMap((m) => object(m) && typeof m.to === "string" ? [m.to] : [])];
|
|
60
|
+
return [{ ply: index + 1, uci: fact.uci, san: fact.san, mechanism: compactMechanism(fact.mechanism, targets) }];
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// src/chess-reasoning/compact-search-preparation.ts
|
|
65
|
+
import { Chess as Chess9 } from "chess.js";
|
|
66
|
+
|
|
67
|
+
// src/chess-reasoning/simple-engine-presentation.ts
|
|
68
|
+
import { Chess } from "chess.js";
|
|
69
|
+
var object2 = (v) => !!v && typeof v === "object" && !Array.isArray(v);
|
|
70
|
+
function projectEnginePresentation(value, fullGeometry = false) {
|
|
71
|
+
const visit = (v) => {
|
|
72
|
+
if (Array.isArray(v)) return v.map(visit);
|
|
73
|
+
if (!object2(v)) return v;
|
|
74
|
+
if (typeof v.id !== "string" || !object2(v.data)) {
|
|
75
|
+
return Object.fromEntries(Object.entries(v).map(([k, child]) => [k, visit(child)]));
|
|
76
|
+
}
|
|
77
|
+
const nested = object2(v.data.details) && (Array.isArray(v.data.details.lines) || Array.isArray(v.data.details.moveFacts));
|
|
78
|
+
const d = nested ? v.data.details : v.data;
|
|
79
|
+
if (Object.hasOwn(d, "modelPresentation")) return v;
|
|
80
|
+
if (object2(d.selectedMoveMechanism) && Array.isArray(d.selectedMoveMechanism.controlDelta) && !fullGeometry) {
|
|
81
|
+
const squares = d.selectedMoveMechanism.controlDelta.flatMap((delta) => object2(delta) && typeof delta.square === "string" ? [delta.square] : []);
|
|
82
|
+
const projected2 = { ...d, selectedMoveMechanism: compactMechanism(d.selectedMoveMechanism, squares) };
|
|
83
|
+
return { ...v, data: nested ? { ...v.data, details: projected2 } : projected2 };
|
|
84
|
+
}
|
|
85
|
+
if (Array.isArray(d.moveFacts) && !fullGeometry) {
|
|
86
|
+
const inspection = object2(d.mechanismInspection) ? d.mechanismInspection : {};
|
|
87
|
+
const { moveFacts, ...rest } = d;
|
|
88
|
+
const projected2 = {
|
|
89
|
+
...rest,
|
|
90
|
+
mechanismFacts: presentMoveMechanisms(
|
|
91
|
+
moveFacts,
|
|
92
|
+
Array.isArray(inspection.inspectPlies) ? inspection.inspectPlies : [],
|
|
93
|
+
Array.isArray(inspection.inspectSquares) ? inspection.inspectSquares : []
|
|
94
|
+
),
|
|
95
|
+
modelPresentation: {
|
|
96
|
+
mechanismThroughPly: 2,
|
|
97
|
+
explicitInspection: inspection,
|
|
98
|
+
retrieveFullEvidenceId: v.id,
|
|
99
|
+
geometryNotice: "Mechanisms shown for first two plies, explicit inspectPlies and moves landing on inspectSquares. Other plies omitted, not absent; retrieve full evidence for all replayed move facts."
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
return { ...v, data: nested ? { ...v.data, details: projected2 } : projected2 };
|
|
103
|
+
}
|
|
104
|
+
if (!Array.isArray(d.lines)) return v;
|
|
105
|
+
const rootFen = object2(d.searchScope) && typeof d.searchScope.fen === "string" ? d.searchScope.fen : void 0;
|
|
106
|
+
let omittedGeometry = 0, omittedRaw = false, referencedFen = false;
|
|
107
|
+
const lines = d.lines.map((line2) => {
|
|
108
|
+
if (!object2(line2) || !Array.isArray(line2.pv)) return line2;
|
|
109
|
+
const next = { ...line2 };
|
|
110
|
+
if (!Object.hasOwn(line2, "rawPvSameAsPv") && Array.isArray(line2.rawPv) && JSON.stringify(line2.rawPv) === JSON.stringify(line2.pv)) {
|
|
111
|
+
delete next.rawPv;
|
|
112
|
+
next.rawPvSameAsPv = true;
|
|
113
|
+
omittedRaw = true;
|
|
114
|
+
}
|
|
115
|
+
if (rootFen && object2(line2.pvCompletion) && Array.isArray(line2.pvCompletion.segments)) {
|
|
116
|
+
const fens = [];
|
|
117
|
+
try {
|
|
118
|
+
const chess = new Chess(rootFen);
|
|
119
|
+
fens.push(chess.fen());
|
|
120
|
+
for (const move2 of line2.pv) {
|
|
121
|
+
if (typeof move2 !== "string" || !/^[a-h][1-8][a-h][1-8][qrbn]?$/.test(move2)) break;
|
|
122
|
+
chess.move({ from: move2.slice(0, 2), to: move2.slice(2, 4), promotion: move2.slice(4) || void 0 });
|
|
123
|
+
fens.push(chess.fen());
|
|
124
|
+
}
|
|
125
|
+
} catch {
|
|
126
|
+
}
|
|
127
|
+
next.pvCompletion = { ...line2.pvCompletion, segments: line2.pvCompletion.segments.map((segment2) => {
|
|
128
|
+
if (!object2(segment2) || !Number.isInteger(segment2.startPly) || segment2.startPly < 0 || typeof segment2.fen !== "string" || fens[segment2.startPly] !== segment2.fen || Object.hasOwn(segment2, "fenFromLinePvPly")) return segment2;
|
|
129
|
+
const { fen: _fen, ...rest } = segment2;
|
|
130
|
+
void _fen;
|
|
131
|
+
referencedFen = true;
|
|
132
|
+
return { ...rest, fenFromLinePvPly: segment2.startPly };
|
|
133
|
+
}) };
|
|
134
|
+
}
|
|
135
|
+
return next;
|
|
136
|
+
});
|
|
137
|
+
const continuations = !fullGeometry && Array.isArray(d.continuationMoveFacts) ? d.continuationMoveFacts.map((c) => {
|
|
138
|
+
if (!object2(c) || !Array.isArray(c.moves)) return c;
|
|
139
|
+
const compact = presentMoveMechanisms(c.moves);
|
|
140
|
+
return { ...c, moves: c.moves.map((m, i) => {
|
|
141
|
+
if (!object2(m)) return m;
|
|
142
|
+
const next = { ...m };
|
|
143
|
+
if (i >= 2 && Object.hasOwn(next, "captureGeometry")) {
|
|
144
|
+
delete next.captureGeometry;
|
|
145
|
+
omittedGeometry++;
|
|
146
|
+
}
|
|
147
|
+
if (Object.hasOwn(next, "mechanism")) {
|
|
148
|
+
const delivered = compact.find((f) => object2(f) && f.ply === i + 1);
|
|
149
|
+
if (object2(delivered)) next.mechanism = delivered.mechanism;
|
|
150
|
+
else {
|
|
151
|
+
delete next.mechanism;
|
|
152
|
+
omittedGeometry++;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
return next;
|
|
156
|
+
}) };
|
|
157
|
+
}) : d.continuationMoveFacts;
|
|
158
|
+
const roots = !fullGeometry && Array.isArray(d.rootMoveFacts) ? d.rootMoveFacts.map((f) => !object2(f) || !f.mechanism ? f : { ...f, mechanism: compactMechanism(f.mechanism, [String(f.to)]) }) : d.rootMoveFacts;
|
|
159
|
+
if (!omittedGeometry && !omittedRaw && !referencedFen && !Array.isArray(d.rootMoveFacts)) return v;
|
|
160
|
+
const projected = {
|
|
161
|
+
...d,
|
|
162
|
+
lines,
|
|
163
|
+
...roots !== void 0 ? { rootMoveFacts: roots } : {},
|
|
164
|
+
...d.continuationMoveFacts !== void 0 ? { continuationMoveFacts: continuations } : {},
|
|
165
|
+
modelPresentation: {
|
|
166
|
+
...omittedGeometry ? {
|
|
167
|
+
captureGeometryThroughPly: 2,
|
|
168
|
+
omittedCaptureGeometry: omittedGeometry,
|
|
169
|
+
retrieveFullEvidenceId: v.id,
|
|
170
|
+
geometryNotice: "Deeper capture and mechanism geometry omitted, not absent. Retrieve this evidence ID for full geometry; basic move and capture facts remain complete."
|
|
171
|
+
} : {},
|
|
172
|
+
...referencedFen ? { segmentFenReference: "fenFromLinePvPly=N is the exact position after N moves of this line.pv, legally replayed from this engine result\u2019s searchScope.fen. Segment scores, depth and search provenance still apply only to that segment." } : {}
|
|
173
|
+
}
|
|
174
|
+
};
|
|
175
|
+
return { ...v, data: nested ? { ...v.data, details: projected } : projected };
|
|
176
|
+
};
|
|
177
|
+
return visit(value);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// src/chess-reasoning/material-format.ts
|
|
181
|
+
var DEFAULT_MATERIAL_FORMAT = "hybrid";
|
|
182
|
+
var order = ["pawn", "knight", "bishop", "rook", "queen"];
|
|
183
|
+
var obj = (v) => !!v && typeof v === "object" && !Array.isArray(v);
|
|
184
|
+
var keys = (v, expected) => Object.keys(v).every((k) => expected.includes(k));
|
|
185
|
+
var counts = (v) => obj(v) && keys(v, [...order]) && order.every((k) => Number.isInteger(v[k]));
|
|
186
|
+
var snapshot = (v) => obj(v) && keys(v, ["white", "black", "whiteMinusBlack", "balance"]) && counts(v.white) && counts(v.black) && counts(v.whiteMinusBlack) && typeof v.balance === "string";
|
|
187
|
+
var row = (v) => order.map((k) => v[k]);
|
|
188
|
+
var inventory = (v) => order.map((k) => `${v[k]} ${k}${v[k] === 1 ? "" : "s"}`).join(", ");
|
|
189
|
+
var textSnapshot = (v) => `White: ${inventory(v.white)}. Black: ${inventory(v.black)}. ${v.balance}`;
|
|
190
|
+
var hybridSnapshot = (v) => ({ white: row(v.white), black: row(v.black), balance: v.balance });
|
|
191
|
+
function formattedMaterial(v, format) {
|
|
192
|
+
if (snapshot(v)) return format === "text" ? { encoding: "material-text/1", position: textSnapshot(v) } : { encoding: "material-table/1", pieceOrder: order.join(" "), ...hybridSnapshot(v) };
|
|
193
|
+
if (!obj(v) || v.authority !== "legal-replay-piece-counts" || !keys(v, ["authority", "startFen", "plies", "start", "changes", "endFen", "end", "balanceChangeFromStart", "scope"]) || typeof v.startFen !== "string" || typeof v.endFen !== "string" || !Number.isInteger(v.plies) || !snapshot(v.start) || !snapshot(v.end) || !counts(v.balanceChangeFromStart) || typeof v.scope !== "string" || !Array.isArray(v.changes) || v.changes.some((c) => !obj(c) || !keys(c, ["ply", "san", "whiteMinusBlack", "balance"]) || !Number.isInteger(c.ply) || typeof c.san !== "string" || !counts(c.whiteMinusBlack) || typeof c.balance !== "string")) return v;
|
|
194
|
+
const balanceChangeFromStart = v.balanceChangeFromStart;
|
|
195
|
+
const shared = { authority: v.authority, startFen: v.startFen, plies: v.plies, endFen: v.endFen, scope: v.scope };
|
|
196
|
+
if (format === "hybrid") return {
|
|
197
|
+
encoding: "material-table/1",
|
|
198
|
+
...shared,
|
|
199
|
+
pieceOrder: order.join(" "),
|
|
200
|
+
start: hybridSnapshot(v.start),
|
|
201
|
+
checkpointColumns: "ply san pawn knight bishop rook queen; absolute White minus Black",
|
|
202
|
+
checkpoints: v.changes.map((c) => [c.ply, c.san, ...row(c.whiteMinusBlack)]),
|
|
203
|
+
end: hybridSnapshot(v.end),
|
|
204
|
+
balanceChangeFromStart: row(v.balanceChangeFromStart)
|
|
205
|
+
};
|
|
206
|
+
return {
|
|
207
|
+
encoding: "material-text/1",
|
|
208
|
+
...shared,
|
|
209
|
+
convention: "Balances list all differences; unmentioned piece types have equal counts.",
|
|
210
|
+
start: textSnapshot(v.start),
|
|
211
|
+
checkpoints: Object.fromEntries(v.changes.map((c) => [`After ply ${c.ply} (${c.san})`, c.balance])),
|
|
212
|
+
end: textSnapshot(v.end),
|
|
213
|
+
balanceChangeFromStart: `Change only, White minus Black: ${order.map((k) => `${k} ${balanceChangeFromStart[k] >= 0 ? "+" : ""}${balanceChangeFromStart[k]}`).join(", ")}.`
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
function projectMaterial(value, format = DEFAULT_MATERIAL_FORMAT) {
|
|
217
|
+
if (!["raw", "hybrid", "text"].includes(format)) throw Error("invalid-material-format");
|
|
218
|
+
if (format === "raw") return value;
|
|
219
|
+
const visit = (v) => Array.isArray(v) ? v.map(visit) : obj(v) ? Object.fromEntries(Object.entries(v).map(([k, x]) => [k, k === "material" ? formattedMaterial(x, format) : visit(x)])) : v;
|
|
220
|
+
return visit(value);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// src/chess-reasoning/material-accounting.ts
|
|
224
|
+
import { Chess as Chess2 } from "chess.js";
|
|
225
|
+
|
|
226
|
+
// src/chess-reasoning/simple-evidence-view.ts
|
|
227
|
+
import { Chess as Chess8 } from "chess.js";
|
|
228
|
+
|
|
229
|
+
// src/chess-reasoning/poc-contracts.ts
|
|
230
|
+
import { Chess as Chess6 } from "chess.js";
|
|
231
|
+
|
|
232
|
+
// src/chess-reasoning/poc-piece-refs.ts
|
|
233
|
+
import { Chess as Chess4, SQUARES as SQUARES2 } from "chess.js";
|
|
234
|
+
|
|
235
|
+
// src/chess-reasoning/piece-identities.ts
|
|
236
|
+
import { Chess as Chess3, SQUARES } from "chess.js";
|
|
237
|
+
|
|
238
|
+
// src/chess-reasoning/move-mechanism-facts.ts
|
|
239
|
+
import { Chess as Chess5, SQUARES as SQUARES3 } from "chess.js";
|
|
240
|
+
|
|
241
|
+
// src/chess-reasoning/evidence-licenses.ts
|
|
242
|
+
var EVIDENCE_LICENSE = Object.freeze({
|
|
243
|
+
CHESS_LEGALITY: "chess.legality",
|
|
244
|
+
CHESS_IDENTITY: "chess.identity",
|
|
245
|
+
CHESS_POSITION_FACT: "chess.position-fact",
|
|
246
|
+
ENGINE_BOUNDED_CONTINUATION: "engine.bounded-continuation",
|
|
247
|
+
ENGINE_BOUNDED_COMPARISON: "engine.bounded-comparison",
|
|
248
|
+
ENGINE_BOUNDED_SCORE: "engine.bounded-score",
|
|
249
|
+
ENGINE_BOUNDED_RESPONSE_COVERAGE: "engine.bounded-response-coverage",
|
|
250
|
+
COVERAGE_EXHAUSTIVE: "coverage.exhaustive",
|
|
251
|
+
ATTENTION_AFFORDANCE: "attention.affordance",
|
|
252
|
+
SEMANTIC_REVIEWED_STATE: "semantic.reviewed-state",
|
|
253
|
+
WORKFLOW_AUDIT: "workflow.audit"
|
|
254
|
+
});
|
|
255
|
+
var LICENSES = new Set(Object.values(EVIDENCE_LICENSE));
|
|
256
|
+
|
|
257
|
+
// src/chess-reasoning/poc-contracts.ts
|
|
258
|
+
var DEFAULT_REASONING_RUN_CONTROLS = Object.freeze({
|
|
259
|
+
maxModelSteps: 15,
|
|
260
|
+
maxToolCalls: 16,
|
|
261
|
+
maxProbeCalls: 5,
|
|
262
|
+
maxEvidenceRecords: 48,
|
|
263
|
+
maxObservationRecords: 48,
|
|
264
|
+
maxObservationsPresented: 16,
|
|
265
|
+
maxHypotheses: 16,
|
|
266
|
+
maxOutputChars: 2400,
|
|
267
|
+
maxProviderOutputChars: 64e3,
|
|
268
|
+
maxWallTimeMs: 3e4
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
// src/chess-reasoning/ablation-adaptive-evidence-loop.ts
|
|
272
|
+
import { Output, generateText, jsonSchema } from "ai";
|
|
273
|
+
|
|
274
|
+
// src/chess-reasoning/concept-registry.ts
|
|
275
|
+
var ENTITY_TYPES = {
|
|
276
|
+
IDEA: "idea",
|
|
277
|
+
PLAN: "plan",
|
|
278
|
+
ROLE: "role-assignment",
|
|
279
|
+
CONDITION: "condition",
|
|
280
|
+
TRANSFORMATION: "transformation",
|
|
281
|
+
OUTCOME: "outcome"
|
|
282
|
+
};
|
|
283
|
+
var PARTICIPANT_ROLES = {
|
|
284
|
+
ACTOR: "actor",
|
|
285
|
+
SUBJECT: "subject",
|
|
286
|
+
TARGET: "target",
|
|
287
|
+
GOAL: "goal",
|
|
288
|
+
RESOURCE: "resource",
|
|
289
|
+
DEFENDER: "defender",
|
|
290
|
+
DESTINATION: "destination"
|
|
291
|
+
};
|
|
292
|
+
var CONCEPT_KEYS = {
|
|
293
|
+
OFFER: "material.offer",
|
|
294
|
+
MATERIAL_CLAIM: "material.claim",
|
|
295
|
+
FORK: "tactic.fork",
|
|
296
|
+
TRAPPED_TARGET: "tactic.trapped-target",
|
|
297
|
+
PROMOTION: "tactic.promotion",
|
|
298
|
+
MATING_ATTACK: "attack.mating",
|
|
299
|
+
PERPETUAL_CHECK: "attack.perpetual-check",
|
|
300
|
+
POSITIONAL_CLAIM: "position.claim",
|
|
301
|
+
KING_ATTACK_PLAN: "plan.king-attack",
|
|
302
|
+
PIECE_ROLE: "role.piece-function",
|
|
303
|
+
CHANGED_CONSTRAINT: "condition.changed-constraint",
|
|
304
|
+
POSITIONAL_TRANSFORMATION: "position.transformation"
|
|
305
|
+
};
|
|
306
|
+
var COMMON_TERMINAL_STATES = ["converted", "refuted", "abandoned", "expired"];
|
|
307
|
+
function claimLifecycle(capturedBy) {
|
|
308
|
+
return {
|
|
309
|
+
initialState: "created",
|
|
310
|
+
retainedState: "retained",
|
|
311
|
+
terminalStates: [...COMMON_TERMINAL_STATES],
|
|
312
|
+
trackedParticipantRole: PARTICIPANT_ROLES.TARGET,
|
|
313
|
+
expireWhenTrackedUnavailable: true,
|
|
314
|
+
onTrackedCapture: {
|
|
315
|
+
capturedBy,
|
|
316
|
+
matchingState: "converted",
|
|
317
|
+
matchingAnnotation: "converted",
|
|
318
|
+
otherState: "refuted",
|
|
319
|
+
otherAnnotation: "refuted"
|
|
320
|
+
}
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
function createConceptRegistry(definitions) {
|
|
324
|
+
const registry = {};
|
|
325
|
+
for (const definition of definitions) {
|
|
326
|
+
if (!definition.key.trim()) throw new Error("Concept keys must not be empty");
|
|
327
|
+
if (registry[definition.key]) throw new Error(`Duplicate concept key: ${definition.key}`);
|
|
328
|
+
registry[definition.key] = Object.freeze({
|
|
329
|
+
...definition,
|
|
330
|
+
lifecycle: definition.lifecycle ? Object.freeze({
|
|
331
|
+
...definition.lifecycle,
|
|
332
|
+
terminalStates: Object.freeze([...definition.lifecycle.terminalStates]),
|
|
333
|
+
onTrackedCapture: definition.lifecycle.onTrackedCapture ? Object.freeze({ ...definition.lifecycle.onTrackedCapture }) : void 0
|
|
334
|
+
}) : void 0
|
|
335
|
+
});
|
|
336
|
+
}
|
|
337
|
+
return Object.freeze(registry);
|
|
338
|
+
}
|
|
339
|
+
var DEFAULT_CONCEPT_REGISTRY = createConceptRegistry([
|
|
340
|
+
{
|
|
341
|
+
key: CONCEPT_KEYS.OFFER,
|
|
342
|
+
label: "Material offer",
|
|
343
|
+
category: "tactical",
|
|
344
|
+
description: "A material liability the opponent may choose to accept.",
|
|
345
|
+
defaultEntityType: ENTITY_TYPES.IDEA,
|
|
346
|
+
acceptancePolicy: "material-offer-liability/1",
|
|
347
|
+
lifecycle: claimLifecycle("opponent")
|
|
348
|
+
},
|
|
349
|
+
{
|
|
350
|
+
key: CONCEPT_KEYS.MATERIAL_CLAIM,
|
|
351
|
+
label: "Material claim",
|
|
352
|
+
category: "tactical",
|
|
353
|
+
description: "An evidence-backed entitlement to win material.",
|
|
354
|
+
defaultEntityType: ENTITY_TYPES.IDEA,
|
|
355
|
+
lifecycle: claimLifecycle("owner")
|
|
356
|
+
},
|
|
357
|
+
{
|
|
358
|
+
key: CONCEPT_KEYS.FORK,
|
|
359
|
+
label: "Fork",
|
|
360
|
+
category: "tactical",
|
|
361
|
+
description: "One resource attacks multiple targets.",
|
|
362
|
+
defaultEntityType: ENTITY_TYPES.IDEA,
|
|
363
|
+
lifecycle: claimLifecycle("owner")
|
|
364
|
+
},
|
|
365
|
+
{
|
|
366
|
+
key: CONCEPT_KEYS.TRAPPED_TARGET,
|
|
367
|
+
label: "Trapped target",
|
|
368
|
+
category: "tactical",
|
|
369
|
+
description: "A target lacks an adequate escape or defensive resource.",
|
|
370
|
+
defaultEntityType: ENTITY_TYPES.IDEA,
|
|
371
|
+
lifecycle: claimLifecycle("owner")
|
|
372
|
+
},
|
|
373
|
+
{
|
|
374
|
+
key: CONCEPT_KEYS.PROMOTION,
|
|
375
|
+
label: "Promotion",
|
|
376
|
+
category: "tactical",
|
|
377
|
+
description: "A promotion event or promotion claim.",
|
|
378
|
+
defaultEntityType: ENTITY_TYPES.IDEA
|
|
379
|
+
},
|
|
380
|
+
{
|
|
381
|
+
key: CONCEPT_KEYS.MATING_ATTACK,
|
|
382
|
+
label: "Mating attack",
|
|
383
|
+
category: "tactical",
|
|
384
|
+
description: "A coordinated plan whose concrete target is mate.",
|
|
385
|
+
defaultEntityType: ENTITY_TYPES.PLAN
|
|
386
|
+
},
|
|
387
|
+
{
|
|
388
|
+
key: CONCEPT_KEYS.PERPETUAL_CHECK,
|
|
389
|
+
label: "Perpetual check",
|
|
390
|
+
category: "tactical",
|
|
391
|
+
description: "A claim to a repeatable checking sequence.",
|
|
392
|
+
defaultEntityType: ENTITY_TYPES.IDEA
|
|
393
|
+
},
|
|
394
|
+
{
|
|
395
|
+
key: CONCEPT_KEYS.POSITIONAL_CLAIM,
|
|
396
|
+
label: "Positional claim",
|
|
397
|
+
category: "positional",
|
|
398
|
+
description: "A measured, evidence-bounded positional interpretation.",
|
|
399
|
+
defaultEntityType: ENTITY_TYPES.IDEA
|
|
400
|
+
},
|
|
401
|
+
{
|
|
402
|
+
key: CONCEPT_KEYS.KING_ATTACK_PLAN,
|
|
403
|
+
label: "King attack plan",
|
|
404
|
+
category: "plan",
|
|
405
|
+
description: "A goal-directed sequence intended to attack the king.",
|
|
406
|
+
defaultEntityType: ENTITY_TYPES.PLAN
|
|
407
|
+
},
|
|
408
|
+
{
|
|
409
|
+
key: CONCEPT_KEYS.PIECE_ROLE,
|
|
410
|
+
label: "Piece role",
|
|
411
|
+
category: "role",
|
|
412
|
+
description: "A context-dependent function performed by a piece.",
|
|
413
|
+
defaultEntityType: ENTITY_TYPES.ROLE
|
|
414
|
+
},
|
|
415
|
+
{
|
|
416
|
+
key: CONCEPT_KEYS.CHANGED_CONSTRAINT,
|
|
417
|
+
label: "Changed constraint",
|
|
418
|
+
category: "condition",
|
|
419
|
+
description: "A condition whose importance changed after a move or sequence.",
|
|
420
|
+
defaultEntityType: ENTITY_TYPES.CONDITION
|
|
421
|
+
},
|
|
422
|
+
{
|
|
423
|
+
key: CONCEPT_KEYS.POSITIONAL_TRANSFORMATION,
|
|
424
|
+
label: "Positional transformation",
|
|
425
|
+
category: "transformation",
|
|
426
|
+
description: "A causal change in the meaning of a positional feature.",
|
|
427
|
+
defaultEntityType: ENTITY_TYPES.TRANSFORMATION
|
|
428
|
+
}
|
|
429
|
+
]);
|
|
430
|
+
|
|
431
|
+
// src/chess-reasoning/poc-move-witnesses.ts
|
|
432
|
+
import { Chess as Chess7 } from "chess.js";
|
|
433
|
+
|
|
434
|
+
// src/chess-reasoning/ablation-evidence-bundle.ts
|
|
435
|
+
import { SQUARES as SQUARES4 } from "chess.js";
|
|
436
|
+
var PRECOMMITTED_PROBE_ATTRIBUTION_CATEGORIES = Object.freeze([
|
|
437
|
+
"fact-unavailable",
|
|
438
|
+
"fact-available-not-presented",
|
|
439
|
+
"fact-presented-ignored",
|
|
440
|
+
"fact-recognized-not-probed",
|
|
441
|
+
"hypothesis-formed-later-discarded",
|
|
442
|
+
"correct-graph-poor-rendering",
|
|
443
|
+
"unsupported-claim-admitted",
|
|
444
|
+
"safe-fail-closed-termination"
|
|
445
|
+
]);
|
|
446
|
+
|
|
447
|
+
// src/chess-reasoning/ai-sdk-runtime-support.ts
|
|
448
|
+
import { NoOutputGeneratedError, RetryError } from "ai";
|
|
449
|
+
import { APICallError, EmptyResponseBodyError, NoContentGeneratedError } from "@ai-sdk/provider";
|
|
450
|
+
var encoder = new TextEncoder();
|
|
451
|
+
var OBSERVABLE_TRACE_EXCLUSIONS = Object.freeze([
|
|
452
|
+
"provider credentials and authorization headers",
|
|
453
|
+
"raw HTTP request and response bodies",
|
|
454
|
+
"hidden chain-of-thought and provider reasoning details"
|
|
455
|
+
]);
|
|
456
|
+
|
|
457
|
+
// src/chess-reasoning/ablation-adaptive-evidence-loop.ts
|
|
458
|
+
var ABLATION_ADAPTIVE_EVIDENCE_LOOP_VERSION = "architecture-ablation-adaptive-evidence-loop/2";
|
|
459
|
+
var ADAPTIVE_EVIDENCE_DECISION_SCHEMA = Object.freeze({
|
|
460
|
+
type: "object",
|
|
461
|
+
additionalProperties: false,
|
|
462
|
+
required: ["schemaVersion", "decision"],
|
|
463
|
+
properties: {
|
|
464
|
+
schemaVersion: { const: ABLATION_ADAPTIVE_EVIDENCE_LOOP_VERSION },
|
|
465
|
+
decision: {
|
|
466
|
+
oneOf: [
|
|
467
|
+
{
|
|
468
|
+
type: "object",
|
|
469
|
+
additionalProperties: false,
|
|
470
|
+
required: ["type", "tool", "input", "selectionRationale", "modelStatedRationale"],
|
|
471
|
+
properties: {
|
|
472
|
+
type: { const: "tool" },
|
|
473
|
+
tool: { type: "string", minLength: 1, maxLength: 120 },
|
|
474
|
+
input: { type: "object" },
|
|
475
|
+
selectionRationale: { type: "string", minLength: 1, maxLength: 1e3 },
|
|
476
|
+
modelStatedRationale: { type: "string", minLength: 1, maxLength: 1e3 }
|
|
477
|
+
}
|
|
478
|
+
},
|
|
479
|
+
{
|
|
480
|
+
type: "object",
|
|
481
|
+
additionalProperties: false,
|
|
482
|
+
required: ["type", "rationale", "modelStatedRationale"],
|
|
483
|
+
properties: {
|
|
484
|
+
type: { const: "finish" },
|
|
485
|
+
rationale: { type: "string", minLength: 1, maxLength: 1e3 },
|
|
486
|
+
modelStatedRationale: { type: "string", minLength: 1, maxLength: 1e3 }
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
]
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
});
|
|
493
|
+
|
|
494
|
+
// src/chess-reasoning/simple-compact-evidence.ts
|
|
495
|
+
var COMPACT_ENGINE_VERSION = "simple-engine-evidence/1";
|
|
496
|
+
var object3 = (x) => !!x && typeof x === "object" && !Array.isArray(x);
|
|
497
|
+
var uci = /^[a-h][1-8][a-h][1-8][qrbn]?$/;
|
|
498
|
+
function projectCompactEngineEvidence(value) {
|
|
499
|
+
const pieces = {}, pieceIds = /* @__PURE__ */ new Map();
|
|
500
|
+
let changed = false;
|
|
501
|
+
const visit = (x) => {
|
|
502
|
+
if (Array.isArray(x)) {
|
|
503
|
+
const entries = x.map(visit);
|
|
504
|
+
if (entries.length >= 3 && entries.every(object3)) {
|
|
505
|
+
const columns = Object.keys(entries[0]);
|
|
506
|
+
if (columns.length >= 2 && entries.every((e) => JSON.stringify(Object.keys(e)) === JSON.stringify(columns) && columns.every((k) => e[k] !== void 0))) {
|
|
507
|
+
const table = { $table: { columns, rows: entries.map((e) => columns.map((k) => e[k])) } };
|
|
508
|
+
if (JSON.stringify(table).length < JSON.stringify(entries).length) {
|
|
509
|
+
changed = true;
|
|
510
|
+
return table;
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
return entries;
|
|
515
|
+
}
|
|
516
|
+
if (!object3(x)) return x;
|
|
517
|
+
if (typeof x.pieceId === "string" && typeof x.square === "string" && typeof x.color === "string" && typeof x.pieceType === "string") {
|
|
518
|
+
const { square, ...identity } = x;
|
|
519
|
+
const key = JSON.stringify(identity);
|
|
520
|
+
let id = pieceIds.get(key);
|
|
521
|
+
if (!id) {
|
|
522
|
+
id = `p${pieceIds.size}`;
|
|
523
|
+
pieceIds.set(key, id);
|
|
524
|
+
pieces[id] = identity;
|
|
525
|
+
}
|
|
526
|
+
changed = true;
|
|
527
|
+
return { $piece: id, square };
|
|
528
|
+
}
|
|
529
|
+
if (typeof x.uci === "string" && uci.test(x.uci) && typeof x.san === "string" && x.mover && x.from === x.uci.slice(0, 2) && x.to === x.uci.slice(2, 4) && x.capture !== void 0 && x.captureGeometry !== null && x.promotion === (x.uci.slice(4) || null) && x.givesCheck === /[+#]$/.test(x.san)) {
|
|
530
|
+
const { uci: move2, san, mover, capture, captureGeometry, from: _from, to: _to, promotion: _promotion, givesCheck: _check, ...extra } = x;
|
|
531
|
+
void _from;
|
|
532
|
+
void _to;
|
|
533
|
+
void _promotion;
|
|
534
|
+
void _check;
|
|
535
|
+
const row2 = [move2, san, visit(mover), visit(capture)];
|
|
536
|
+
if (captureGeometry !== void 0 || Object.keys(extra).length) row2.push(visit(captureGeometry ?? null));
|
|
537
|
+
if (Object.keys(extra).length) row2.push(visit(extra));
|
|
538
|
+
while (row2.length > 3 && row2.at(-1) === null) row2.pop();
|
|
539
|
+
changed = true;
|
|
540
|
+
return { $move: row2 };
|
|
541
|
+
}
|
|
542
|
+
return Object.fromEntries(Object.entries(x).map(([k, v]) => [k, visit(v)]));
|
|
543
|
+
};
|
|
544
|
+
const reserved = (x) => Array.isArray(x) ? x.some(reserved) : object3(x) ? Object.keys(x).some((k) => ["$piece", "$move", "$table"].includes(k)) || Object.values(x).some(reserved) : false;
|
|
545
|
+
if (reserved(value)) return value;
|
|
546
|
+
const content = visit(value);
|
|
547
|
+
return changed ? { encoding: COMPACT_ENGINE_VERSION, pieces, content } : value;
|
|
548
|
+
}
|
|
549
|
+
function expandCompactEngineEvidence(value) {
|
|
550
|
+
if (!object3(value) || value.encoding !== COMPACT_ENGINE_VERSION || !object3(value.pieces)) return value;
|
|
551
|
+
const pieces = value.pieces;
|
|
552
|
+
const visit = (x) => {
|
|
553
|
+
if (Array.isArray(x)) return x.map(visit);
|
|
554
|
+
if (!object3(x)) return x;
|
|
555
|
+
if (typeof x.$piece === "string") return { ...pieces[x.$piece], square: x.square };
|
|
556
|
+
if (object3(x.$table)) {
|
|
557
|
+
const { columns, rows } = x.$table;
|
|
558
|
+
return rows.map((row2) => visit(Object.fromEntries(columns.map((key, i) => [key, row2[i]]))));
|
|
559
|
+
}
|
|
560
|
+
if (Array.isArray(x.$move)) {
|
|
561
|
+
const [move2, san, mover, capture = null, geometry = null, extra = {}] = x.$move;
|
|
562
|
+
return {
|
|
563
|
+
uci: move2,
|
|
564
|
+
san,
|
|
565
|
+
from: move2.slice(0, 2),
|
|
566
|
+
to: move2.slice(2, 4),
|
|
567
|
+
mover: visit(mover),
|
|
568
|
+
capture: visit(capture),
|
|
569
|
+
...geometry !== null ? { captureGeometry: visit(geometry) } : {},
|
|
570
|
+
promotion: move2.slice(4) || null,
|
|
571
|
+
givesCheck: /[+#]$/.test(san),
|
|
572
|
+
...visit(extra)
|
|
573
|
+
};
|
|
574
|
+
}
|
|
575
|
+
return Object.fromEntries(Object.entries(x).map(([k, v]) => [k, visit(v)]));
|
|
576
|
+
};
|
|
577
|
+
return visit(value.content);
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
// src/chess-reasoning/simple-evidence-view.ts
|
|
581
|
+
function compactSimpleEngineResult(value, format = DEFAULT_MATERIAL_FORMAT, fullGeometry = false) {
|
|
582
|
+
value = projectMaterial(projectEnginePresentation(value, fullGeometry), format);
|
|
583
|
+
const baseline = compactSimpleToolResult(value);
|
|
584
|
+
const candidate = compactSimpleToolResult(projectCompactEngineEvidence(value));
|
|
585
|
+
return JSON.stringify(candidate).length < JSON.stringify(baseline).length ? candidate : baseline;
|
|
586
|
+
}
|
|
587
|
+
function compactSimpleToolResult(value) {
|
|
588
|
+
const counts2 = /* @__PURE__ */ new Map();
|
|
589
|
+
let reservedKeyPresent = false;
|
|
590
|
+
const visit = (item, replace) => {
|
|
591
|
+
if (!item || typeof item !== "object") return item;
|
|
592
|
+
const encoded = JSON.stringify(item);
|
|
593
|
+
if (Object.hasOwn(item, "$metadata")) reservedKeyPresent = true;
|
|
594
|
+
if (encoded.length >= 80) {
|
|
595
|
+
if (!replace) counts2.set(encoded, (counts2.get(encoded) || 0) + 1);
|
|
596
|
+
else if ((counts2.get(encoded) || 0) > 1) {
|
|
597
|
+
let id = ids.get(encoded);
|
|
598
|
+
if (!id) {
|
|
599
|
+
id = `m${ids.size}`;
|
|
600
|
+
ids.set(encoded, id);
|
|
601
|
+
metadata[id] = item;
|
|
602
|
+
}
|
|
603
|
+
return { $metadata: id };
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
return Array.isArray(item) ? item.map((entry) => visit(entry, replace)) : Object.fromEntries(Object.entries(item).map(([childKey, entry]) => [childKey, visit(entry, replace)]));
|
|
607
|
+
};
|
|
608
|
+
const ids = /* @__PURE__ */ new Map(), metadata = {};
|
|
609
|
+
visit(value, false);
|
|
610
|
+
if (reservedKeyPresent) return value;
|
|
611
|
+
const content = visit(value, true);
|
|
612
|
+
const compact = { metadata, content };
|
|
613
|
+
return ids.size && JSON.stringify(compact).length < JSON.stringify(value).length ? compact : value;
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
// src/chess-reasoning/compact-search-preparation.ts
|
|
617
|
+
var object4 = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
|
|
618
|
+
var known = (value, keys2) => Object.keys(value).every((key) => keys2.includes(key));
|
|
619
|
+
var detailsKeys = [
|
|
620
|
+
"phase",
|
|
621
|
+
"rootMoves",
|
|
622
|
+
"rootSelection",
|
|
623
|
+
"bestMove",
|
|
624
|
+
"engine",
|
|
625
|
+
"engineBuild",
|
|
626
|
+
"searchScope",
|
|
627
|
+
"rootMoveFacts",
|
|
628
|
+
"continuationMoveFacts",
|
|
629
|
+
"lines",
|
|
630
|
+
"minimumPvPlies",
|
|
631
|
+
"requestedPvCoverage",
|
|
632
|
+
"authority",
|
|
633
|
+
"branchExpansion"
|
|
634
|
+
];
|
|
635
|
+
var lineKeys = [
|
|
636
|
+
"multipv",
|
|
637
|
+
"rootMove",
|
|
638
|
+
"pv",
|
|
639
|
+
"depth",
|
|
640
|
+
"nodes",
|
|
641
|
+
"scoreCp",
|
|
642
|
+
"matePly",
|
|
643
|
+
"scoreScope",
|
|
644
|
+
"scoreProvenance",
|
|
645
|
+
"rawPv",
|
|
646
|
+
"pvCompletion",
|
|
647
|
+
"material"
|
|
648
|
+
];
|
|
649
|
+
var completionKeys = ["requestedPlies", "actualPlies", "status", "conditional", "segments"];
|
|
650
|
+
var segmentKeys = [
|
|
651
|
+
"fen",
|
|
652
|
+
"startPly",
|
|
653
|
+
"depth",
|
|
654
|
+
"pv",
|
|
655
|
+
"scoreCp",
|
|
656
|
+
"matePly",
|
|
657
|
+
"scoreScope",
|
|
658
|
+
"scoreProvenance",
|
|
659
|
+
"command",
|
|
660
|
+
"engine",
|
|
661
|
+
"engineBuild",
|
|
662
|
+
"cacheProvenance"
|
|
663
|
+
];
|
|
664
|
+
function compactSearchRecord(record2, playedMove) {
|
|
665
|
+
const data = record2.data;
|
|
666
|
+
if (!known(data, ["recordedPosition", "details"]) || !object4(data.recordedPosition) || !object4(data.details)) return null;
|
|
667
|
+
const recordedPosition = data.recordedPosition;
|
|
668
|
+
const details = data.details;
|
|
669
|
+
if (!known(details, detailsKeys) || !object4(details.searchScope) || typeof details.searchScope.fen !== "string" || !Array.isArray(details.lines) || !details.lines.length || !Array.isArray(details.continuationMoveFacts)) return null;
|
|
670
|
+
const positionKeys = ["recordHash", "ply", "startFen", "fen", "historyUci", "rootContextHash", "nextRecordedMove", "scope"];
|
|
671
|
+
if (!known(recordedPosition, positionKeys) || !Number.isInteger(recordedPosition.ply) || typeof recordedPosition.fen !== "string") return null;
|
|
672
|
+
const strongestOther = details.lines.find((line2) => object4(line2) && line2.rootMove !== playedMove);
|
|
673
|
+
const mechanismAlternative = details.bestMove && details.bestMove !== playedMove ? details.bestMove : object4(strongestOther) ? strongestOther.rootMove : details.bestMove;
|
|
674
|
+
const lines = [];
|
|
675
|
+
for (const line2 of details.lines) {
|
|
676
|
+
if (!object4(line2) || !known(line2, lineKeys) || !Array.isArray(line2.pv) || !line2.pv.every((move2) => typeof move2 === "string") || typeof line2.rootMove !== "string" || !object4(line2.pvCompletion) || !known(line2.pvCompletion, completionKeys) || !Array.isArray(line2.pvCompletion.segments)) return null;
|
|
677
|
+
let pvSan;
|
|
678
|
+
try {
|
|
679
|
+
const board = new Chess9(details.searchScope.fen);
|
|
680
|
+
pvSan = line2.pv.map((move2) => {
|
|
681
|
+
if (!/^[a-h][1-8][a-h][1-8][qrbn]?$/.test(move2)) throw Error("invalid PV move");
|
|
682
|
+
const replayed = board.move({ from: move2.slice(0, 2), to: move2.slice(2, 4), promotion: move2.slice(4) || void 0 });
|
|
683
|
+
if (!replayed) throw Error("illegal PV move");
|
|
684
|
+
return replayed.san;
|
|
685
|
+
});
|
|
686
|
+
} catch {
|
|
687
|
+
return null;
|
|
688
|
+
}
|
|
689
|
+
const segments = [];
|
|
690
|
+
for (const segment2 of line2.pvCompletion.segments) {
|
|
691
|
+
if (!object4(segment2) || !known(segment2, segmentKeys) || !Array.isArray(segment2.pv) || !Number.isInteger(segment2.startPly)) return null;
|
|
692
|
+
const start = segment2.startPly;
|
|
693
|
+
const same = start >= 0 && JSON.stringify(line2.pv.slice(start, start + segment2.pv.length)) === JSON.stringify(segment2.pv);
|
|
694
|
+
const { pv: _pv, ...remaining } = segment2;
|
|
695
|
+
void _pv;
|
|
696
|
+
segments.push(same ? { ...remaining, pvFromLinePly: start, pvLength: segment2.pv.length } : { ...remaining, pv: segment2.pv });
|
|
697
|
+
}
|
|
698
|
+
const { segments: _segments, ...completion } = line2.pvCompletion;
|
|
699
|
+
void _segments;
|
|
700
|
+
const material2 = object4(line2.material) && object4(line2.material.start) && object4(line2.material.end) ? {
|
|
701
|
+
authority: line2.material.authority,
|
|
702
|
+
startBalance: line2.material.start.balance,
|
|
703
|
+
endBalance: line2.material.end.balance,
|
|
704
|
+
balanceChangeFromStart: line2.material.balanceChangeFromStart,
|
|
705
|
+
scope: line2.material.scope
|
|
706
|
+
} : void 0;
|
|
707
|
+
const separateRawPv = Array.isArray(line2.rawPv) && JSON.stringify(line2.rawPv) !== JSON.stringify(line2.pv) ? { rawPv: line2.rawPv } : {};
|
|
708
|
+
const continuation = details.continuationMoveFacts.find((f) => object4(f) && f.rootMove === line2.rootMove);
|
|
709
|
+
const mechanismRelevant = line2.rootMove === playedMove || line2.rootMove === mechanismAlternative || !mechanismAlternative && lines.length === 0;
|
|
710
|
+
const mechanismFacts = mechanismRelevant && object4(continuation) && Array.isArray(continuation.moves) ? presentMoveMechanisms(continuation.moves) : [];
|
|
711
|
+
lines.push({
|
|
712
|
+
...object4(continuation) && Array.isArray(continuation.moves) ? { mechanismAvailablePlies: continuation.moves.length } : {},
|
|
713
|
+
...mechanismFacts.length ? { mechanismFacts } : {},
|
|
714
|
+
...line2.multipv !== void 0 ? { multipv: line2.multipv } : {},
|
|
715
|
+
rootMove: line2.rootMove,
|
|
716
|
+
...playedMove ? { playedMove: playedMove === line2.rootMove } : {},
|
|
717
|
+
pv: line2.pv,
|
|
718
|
+
pvSan,
|
|
719
|
+
depth: line2.depth,
|
|
720
|
+
scoreCp: line2.scoreCp,
|
|
721
|
+
matePly: line2.matePly,
|
|
722
|
+
scoreScope: line2.scoreScope,
|
|
723
|
+
...line2.scoreProvenance ? { scoreProvenance: line2.scoreProvenance } : {},
|
|
724
|
+
pvCompletion: { ...completion, segments },
|
|
725
|
+
...material2 ? { materialSummary: material2 } : {},
|
|
726
|
+
...separateRawPv
|
|
727
|
+
});
|
|
728
|
+
}
|
|
729
|
+
const { historyUci: _historyUci, ...root } = recordedPosition;
|
|
730
|
+
void _historyUci;
|
|
731
|
+
const { rootMoveFacts: _rootMoveFacts, continuationMoveFacts: _continuationMoveFacts, lines: _lines, ...search2 } = details;
|
|
732
|
+
void _rootMoveFacts;
|
|
733
|
+
void _continuationMoveFacts;
|
|
734
|
+
void _lines;
|
|
735
|
+
const projection = {
|
|
736
|
+
...record2,
|
|
737
|
+
data: { recordedPosition: root, details: {
|
|
738
|
+
...search2,
|
|
739
|
+
lines,
|
|
740
|
+
modelPresentation: {
|
|
741
|
+
scope: "compact initial preparation only; supplied PVs are complete, mechanismFacts cover first two plies for played and strongest roots with scoped control targets; deeper geometry remains retrievable",
|
|
742
|
+
mechanismRoots: lines.filter((line2) => Array.isArray(line2.mechanismFacts)).map((line2) => line2.rootMove),
|
|
743
|
+
omitted: ["otherRootMechanisms", "rootMoveFacts", "continuationMoveFacts", "captureGeometry", "materialCheckpoints", "duplicatePvSegmentMoves"],
|
|
744
|
+
retrieveFullEvidenceId: record2.id,
|
|
745
|
+
segmentPvReference: "A segment with pvFromLinePly=N and pvLength=L repeats exactly L moves of that line.pv starting at zero-based index N; its own depth, score, FEN, command and cache provenance remain specific to that segment.",
|
|
746
|
+
instruction: "For deeper or omitted geometry, other control squares, piece identities or material checkpoints, call retrieve_evidence with this evidence ID. This reuses the acquired record without another engine search. mechanismAvailablePlies states the retained geometry horizon; inspect later moves with test_game_line/inspectPlies."
|
|
747
|
+
}
|
|
748
|
+
} },
|
|
749
|
+
// replay duplicates the full PV arrays. The PVs above remain available for
|
|
750
|
+
// game links, while the immutable replay stays in the authoritative record.
|
|
751
|
+
replay: null
|
|
752
|
+
};
|
|
753
|
+
return projection;
|
|
754
|
+
}
|
|
755
|
+
function compactPreparedSearchResult(result, playedMove, format) {
|
|
756
|
+
const packet = {
|
|
757
|
+
contextHash: result.contextHash,
|
|
758
|
+
evidence: result.evidence.map((record2) => compactSearchRecord(record2, playedMove) ?? record2),
|
|
759
|
+
limitations: [
|
|
760
|
+
...result.limitations,
|
|
761
|
+
"Initial preparation shows complete supplied PV moves and bounded scores, with first-two-ply mechanism measurements for played/strongest roots, but omits deeper geometry and material checkpoints. retrieve_evidence(evidenceIds) returns the already acquired full records without a new search."
|
|
762
|
+
]
|
|
763
|
+
};
|
|
764
|
+
return compactSimpleEngineResult(packet, format);
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
// test/owner/chess-reasoning-compact-search-preparation.test.mjs
|
|
768
|
+
var fen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
|
|
769
|
+
var scope = {
|
|
770
|
+
fen,
|
|
771
|
+
requestedDepth: 18,
|
|
772
|
+
minimumPvPlies: 10,
|
|
773
|
+
cacheProvenance: "widget-cache",
|
|
774
|
+
sourceCacheProvenance: "widget-cache",
|
|
775
|
+
requestedRootMoves: ["e2e4", "d2d4"],
|
|
776
|
+
requestedMultiPv: null,
|
|
777
|
+
history: "FEN-root search; prior repetition history not sent to engine"
|
|
778
|
+
};
|
|
779
|
+
var scoreScope = {
|
|
780
|
+
fen,
|
|
781
|
+
perspective: "white",
|
|
782
|
+
positiveMeans: "advantage for perspective color",
|
|
783
|
+
scoreCpUnit: "centipawns",
|
|
784
|
+
matePlyUnit: "signed mate-in-moves (legacy field name, not plies)"
|
|
785
|
+
};
|
|
786
|
+
var longPv = ["e2e4", "e7e5", "g1f3", "b8c6"];
|
|
787
|
+
var segment = (pv, startPly, scoreCp) => ({
|
|
788
|
+
fen,
|
|
789
|
+
startPly,
|
|
790
|
+
depth: 18,
|
|
791
|
+
pv,
|
|
792
|
+
scoreCp,
|
|
793
|
+
matePly: null,
|
|
794
|
+
scoreScope: { ...scoreScope, fen },
|
|
795
|
+
command: "go depth 18",
|
|
796
|
+
engine: "Stockfish",
|
|
797
|
+
engineBuild: "test-build",
|
|
798
|
+
cacheProvenance: "widget-cache"
|
|
799
|
+
});
|
|
800
|
+
var move = (uci2, san) => ({
|
|
801
|
+
uci: uci2,
|
|
802
|
+
san,
|
|
803
|
+
from: uci2.slice(0, 2),
|
|
804
|
+
to: uci2.slice(2, 4),
|
|
805
|
+
mover: { pieceId: `piece-${uci2}`, color: "w", pieceType: "p", square: uci2.slice(0, 2) },
|
|
806
|
+
capture: null,
|
|
807
|
+
promotion: null,
|
|
808
|
+
givesCheck: false,
|
|
809
|
+
captureGeometry: { attackers: [{ square: "e4" }] }
|
|
810
|
+
});
|
|
811
|
+
var material = {
|
|
812
|
+
authority: "legal-replay-piece-counts",
|
|
813
|
+
startFen: fen,
|
|
814
|
+
plies: 4,
|
|
815
|
+
start: { balance: "Equal piece counts." },
|
|
816
|
+
end: { balance: "Equal piece counts." },
|
|
817
|
+
changes: [{ ply: 1, san: "e4", whiteMinusBlack: { pawn: 0, knight: 0, bishop: 0, rook: 0, queen: 0 }, balance: "Equal piece counts." }],
|
|
818
|
+
endFen: fen,
|
|
819
|
+
balanceChangeFromStart: { pawn: 0, knight: 0, bishop: 0, rook: 0, queen: 0 },
|
|
820
|
+
scope: "Conditional variation."
|
|
821
|
+
};
|
|
822
|
+
var line = (rootMove, pv, scoreCp, matePly = null) => ({
|
|
823
|
+
rootMove,
|
|
824
|
+
pv,
|
|
825
|
+
depth: 18,
|
|
826
|
+
nodes: 100,
|
|
827
|
+
scoreCp,
|
|
828
|
+
matePly,
|
|
829
|
+
scoreScope,
|
|
830
|
+
rawPv: pv,
|
|
831
|
+
pvCompletion: {
|
|
832
|
+
requestedPlies: 10,
|
|
833
|
+
actualPlies: pv.length,
|
|
834
|
+
status: "short-budget",
|
|
835
|
+
conditional: true,
|
|
836
|
+
segments: [segment(pv, 0, scoreCp)]
|
|
837
|
+
},
|
|
838
|
+
material
|
|
839
|
+
});
|
|
840
|
+
var record = () => ({
|
|
841
|
+
schemaVersion: "conceptual-explanation-poc/57",
|
|
842
|
+
id: "evidence:game:test-search",
|
|
843
|
+
contextHash: "test-hash",
|
|
844
|
+
kind: "probe",
|
|
845
|
+
source: "Stockfish/compare_moves",
|
|
846
|
+
proofStrength: "engine-bounded",
|
|
847
|
+
summary: "Bounded two-root comparison",
|
|
848
|
+
data: {
|
|
849
|
+
recordedPosition: {
|
|
850
|
+
recordHash: "game-hash",
|
|
851
|
+
ply: 0,
|
|
852
|
+
startFen: fen,
|
|
853
|
+
fen,
|
|
854
|
+
historyUci: [],
|
|
855
|
+
rootContextHash: "root-hash",
|
|
856
|
+
nextRecordedMove: "e4",
|
|
857
|
+
scope: "position after exactly ply recorded moves"
|
|
858
|
+
},
|
|
859
|
+
details: {
|
|
860
|
+
phase: "after",
|
|
861
|
+
rootMoves: ["e2e4", "d2d4"],
|
|
862
|
+
rootSelection: { modelRequested: ["e2e4", "d2d4"], automaticallyAdded: [], scope: "restricted roots" },
|
|
863
|
+
bestMove: "e2e4",
|
|
864
|
+
engine: "Stockfish",
|
|
865
|
+
engineBuild: "test-build",
|
|
866
|
+
searchScope: scope,
|
|
867
|
+
rootMoveFacts: [move("e2e4", "e4")],
|
|
868
|
+
continuationMoveFacts: [{ rootMove: "e2e4", moves: longPv.map((v, i) => move(v, ["e4", "e5", "Nf3", "Nc6"][i])) }],
|
|
869
|
+
lines: [line("e2e4", longPv, 32), line("d2d4", ["d2d4", "d7d5"], 21)],
|
|
870
|
+
minimumPvPlies: 10,
|
|
871
|
+
requestedPvCoverage: { requestedPlies: 10, satisfied: [], short: ["e2e4", "d2d4"] },
|
|
872
|
+
authority: "bounded-engine"
|
|
873
|
+
}
|
|
874
|
+
},
|
|
875
|
+
coverage: { complete: true, covered: ["e2e4", "d2d4"], unresolved: [] },
|
|
876
|
+
replay: { fen, command: "go depth 18", linesUci: [longPv, ["d2d4", "d7d5"]] },
|
|
877
|
+
licenses: ["engine.bounded-score"]
|
|
878
|
+
});
|
|
879
|
+
var search = () => ({
|
|
880
|
+
schemaVersion: "conceptual-explanation-poc/57",
|
|
881
|
+
callId: "initial-search-1",
|
|
882
|
+
tool: "analyze_game_position",
|
|
883
|
+
contextHash: "test-hash",
|
|
884
|
+
support: "supported",
|
|
885
|
+
data: {},
|
|
886
|
+
evidence: [record()],
|
|
887
|
+
limitations: [],
|
|
888
|
+
durationMs: 10
|
|
889
|
+
});
|
|
890
|
+
var decode = (v) => {
|
|
891
|
+
if (v?.metadata && v?.content) {
|
|
892
|
+
const expand = (x) => Array.isArray(x) ? x.map(expand) : x && typeof x === "object" ? x.$metadata ? expand(v.metadata[x.$metadata]) : Object.fromEntries(Object.entries(x).map(([k, a]) => [k, expand(a)])) : x;
|
|
893
|
+
return expandCompactEngineEvidence(expand(v.content));
|
|
894
|
+
}
|
|
895
|
+
return expandCompactEngineEvidence(v);
|
|
896
|
+
};
|
|
897
|
+
test("KE-REASON-016/021/024/026: initial search projection preserves both scoped comparisons and all PV moves", () => {
|
|
898
|
+
const original = search(), copy = structuredClone(original);
|
|
899
|
+
const projected = decode(compactPreparedSearchResult(original, "d2d4"));
|
|
900
|
+
assert.deepEqual(original, copy, "the authoritative record remains immutable for retrieval");
|
|
901
|
+
const e = projected.evidence[0];
|
|
902
|
+
assert.equal(e.id, original.evidence[0].id);
|
|
903
|
+
assert.equal(e.data.recordedPosition.ply, 0);
|
|
904
|
+
assert.equal(e.data.recordedPosition.fen, fen);
|
|
905
|
+
assert.deepEqual(e.data.details.searchScope, scope);
|
|
906
|
+
assert.deepEqual(e.data.details.rootSelection, original.evidence[0].data.details.rootSelection);
|
|
907
|
+
assert.deepEqual(e.data.details.lines.map((x) => x.pv), [longPv, ["d2d4", "d7d5"]]);
|
|
908
|
+
assert.deepEqual(e.data.details.lines[0].pvSan, ["e4", "e5", "Nf3", "Nc6"]);
|
|
909
|
+
assert.deepEqual(e.data.details.lines.map((x) => x.playedMove), [false, true]);
|
|
910
|
+
assert.deepEqual(e.data.details.lines.map((x) => x.scoreCp), [32, 21]);
|
|
911
|
+
assert.deepEqual(e.data.details.lines.map((x) => x.scoreScope), [scoreScope, scoreScope]);
|
|
912
|
+
assert.equal(e.data.details.lines[0].pvCompletion.status, "short-budget");
|
|
913
|
+
assert.equal(e.data.details.lines[0].pvCompletion.conditional, true);
|
|
914
|
+
assert.equal(e.data.details.lines[0].pvCompletion.segments[0].cacheProvenance, "widget-cache");
|
|
915
|
+
assert.deepEqual(e.data.details.lines[0].pvCompletion.segments[0].pvFromLinePly, 0);
|
|
916
|
+
assert.equal(e.data.details.lines[0].pvCompletion.segments[0].pvLength, longPv.length);
|
|
917
|
+
assert.equal(e.data.details.lines[0].materialSummary.endBalance, "Equal piece counts.");
|
|
918
|
+
assert.equal(e.data.details.modelPresentation.retrieveFullEvidenceId, e.id);
|
|
919
|
+
assert.equal(e.data.details.continuationMoveFacts, void 0);
|
|
920
|
+
assert.equal(e.data.details.rootMoveFacts, void 0);
|
|
921
|
+
assert.equal(e.replay, null);
|
|
922
|
+
assert.equal(JSON.stringify(projected).includes("captureGeometry"), true, "retrieval instructions disclose the omitted detail");
|
|
923
|
+
assert.ok(JSON.stringify(compactPreparedSearchResult(original, "d2d4")).length < JSON.stringify(original).length);
|
|
924
|
+
});
|
|
925
|
+
test("KE-REASON-016/021/024/026: distinct raw or segment PV and mate fields are not mistaken for duplicates", () => {
|
|
926
|
+
const original = search();
|
|
927
|
+
const lines = original.evidence[0].data.details.lines;
|
|
928
|
+
lines[0].rawPv = ["d2d4", "d7d5"];
|
|
929
|
+
lines[0].matePly = 3;
|
|
930
|
+
lines[0].scoreCp = null;
|
|
931
|
+
lines[0].pvCompletion.segments.push(segment(["d2d4"], 1, null));
|
|
932
|
+
const projected = decode(compactPreparedSearchResult(original, "e2e4"));
|
|
933
|
+
const a = projected.evidence[0].data.details.lines[0];
|
|
934
|
+
assert.deepEqual(a.rawPv, ["d2d4", "d7d5"]);
|
|
935
|
+
assert.equal(a.matePly, 3);
|
|
936
|
+
assert.equal(a.scoreCp, null);
|
|
937
|
+
assert.deepEqual(a.pvCompletion.segments[1].pv, ["d2d4"]);
|
|
938
|
+
assert.equal(a.playedMove, true);
|
|
939
|
+
});
|
|
940
|
+
test("KE-REASON-016/021/024/026: unfamiliar engine evidence stays complete", () => {
|
|
941
|
+
const original = search();
|
|
942
|
+
original.evidence[0].data.details.lines[0].newEngineData = { future: "keep" };
|
|
943
|
+
const projected = decode(compactPreparedSearchResult(original, "e2e4"));
|
|
944
|
+
const standard = decode(compactSimpleEngineResult({ contextHash: original.contextHash, evidence: original.evidence, limitations: original.limitations }));
|
|
945
|
+
assert.deepEqual(projected.evidence[0].data.details.lines[0].newEngineData, { future: "keep" });
|
|
946
|
+
assert.deepEqual(
|
|
947
|
+
projected.evidence[0].data.details.continuationMoveFacts,
|
|
948
|
+
standard.evidence[0].data.details.continuationMoveFacts
|
|
949
|
+
);
|
|
950
|
+
});
|
|
951
|
+
test("KE-REASON-016/026: unknown played move is not represented as a negative match", () => {
|
|
952
|
+
const projected = decode(compactPreparedSearchResult(search()));
|
|
953
|
+
assert.ok(projected.evidence[0].data.details.lines.every((line2) => !Object.hasOwn(line2, "playedMove")));
|
|
954
|
+
});
|
|
955
|
+
test("KE-REASON-016/021/026: compact preparation retains line and continuation score origins", () => {
|
|
956
|
+
const original = search(), line2 = original.evidence[0].data.details.lines[0];
|
|
957
|
+
line2.scoreProvenance = { kind: "legacy-unknown", originatingDepth: null, reportedDepth: 18 };
|
|
958
|
+
line2.pvCompletion.segments[0].scoreProvenance = { kind: "root-search", fen, originatingDepth: 22 };
|
|
959
|
+
const output = decode(compactPreparedSearchResult(original, "d2d4")).evidence[0].data.details;
|
|
960
|
+
assert.ok(output.modelPresentation, "recognized provenance does not force full geometry presentation");
|
|
961
|
+
assert.deepEqual(output.lines[0].scoreProvenance, line2.scoreProvenance);
|
|
962
|
+
assert.deepEqual(output.lines[0].pvCompletion.segments[0].scoreProvenance, line2.pvCompletion.segments[0].scoreProvenance);
|
|
963
|
+
});
|