@evo-dev/core 0.0.1-alpha.15 → 0.0.1-alpha.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/dist/config/index.js +45 -2
- package/dist/index.js +12899 -11408
- package/package.json +1 -1
- package/src/config/settings.ts +45 -7
- package/src/evolution/candidates/index.ts +50 -0
- package/src/evolution/evidence/session-memory/retention.ts +2 -1
- package/src/evolution/knowledge/change-store.ts +558 -0
- package/src/evolution/knowledge/changes.ts +453 -0
- package/src/evolution/knowledge/freshness.ts +109 -0
- package/src/evolution/knowledge/index.ts +471 -55
- package/src/evolution/knowledge/review.ts +446 -0
- package/src/evolution/processor/process.ts +5 -1
- package/src/evolution/schema.ts +29 -1
- package/src/evolution/shared.ts +108 -0
- package/src/index.ts +4 -0
- package/src/team/index.ts +6 -0
|
@@ -3,6 +3,7 @@ import { existsSync, readFileSync, readdirSync } from "node:fs";
|
|
|
3
3
|
import { mkdir, readFile, readdir, rename, rm, stat, writeFile } from "node:fs/promises";
|
|
4
4
|
import { dirname, isAbsolute, join, relative, resolve } from "node:path";
|
|
5
5
|
import { resolveEvoDevPaths } from "../../config/paths.ts";
|
|
6
|
+
import { readRuntimeInjectionSettings } from "../../config/settings.ts";
|
|
6
7
|
import {
|
|
7
8
|
canonicalizeProjectKey,
|
|
8
9
|
listEquivalentProjectKeys,
|
|
@@ -21,6 +22,24 @@ import type {
|
|
|
21
22
|
EvolutionKnowledgeRecord,
|
|
22
23
|
} from "../schema.ts";
|
|
23
24
|
import { REVIEW_STATES } from "../shared.ts";
|
|
25
|
+
import {
|
|
26
|
+
type OkfKnowledgeChangeCandidateV1,
|
|
27
|
+
createOkfKnowledgeChangeCandidate,
|
|
28
|
+
readOkfKnowledgeChangeCandidate,
|
|
29
|
+
writeOkfKnowledgeChangeCandidate,
|
|
30
|
+
} from "./change-store.ts";
|
|
31
|
+
import {
|
|
32
|
+
type OkfKnowledgeChangeClassificationResult,
|
|
33
|
+
classifyOkfKnowledgeCandidate,
|
|
34
|
+
createOkfKnowledgeRevision,
|
|
35
|
+
createOkfKnowledgeRuntimeProjectionFromConcept,
|
|
36
|
+
} from "./changes.ts";
|
|
37
|
+
import {
|
|
38
|
+
type OkfKnowledgeFreshness,
|
|
39
|
+
type OkfKnowledgeVerificationSnapshotV1,
|
|
40
|
+
createOkfKnowledgeVerificationSnapshot,
|
|
41
|
+
deriveOkfKnowledgeFreshness,
|
|
42
|
+
} from "./freshness.ts";
|
|
24
43
|
|
|
25
44
|
export type OkfKnowledgeDecision =
|
|
26
45
|
| "auto-accept"
|
|
@@ -28,7 +47,8 @@ export type OkfKnowledgeDecision =
|
|
|
28
47
|
| "create"
|
|
29
48
|
| "update"
|
|
30
49
|
| "skip"
|
|
31
|
-
| "needs-human"
|
|
50
|
+
| "needs-human"
|
|
51
|
+
| "revoke";
|
|
32
52
|
export type OkfKnowledgeTargetStore = "okf" | "repo-asset-proposal" | "evo-eval-set" | "none";
|
|
33
53
|
export type OkfKnowledgeReviewState =
|
|
34
54
|
| "auto-accepted"
|
|
@@ -221,6 +241,7 @@ export interface OkfKnowledgeActivationResult {
|
|
|
221
241
|
overlayPaths: string[];
|
|
222
242
|
skippedCandidates: string[];
|
|
223
243
|
needsHumanCandidates: string[];
|
|
244
|
+
pendingChangeIds: string[];
|
|
224
245
|
indexPaths: string[];
|
|
225
246
|
derivedIndexPaths: string[];
|
|
226
247
|
logPaths: string[];
|
|
@@ -258,6 +279,7 @@ export interface OkfKnowledgeConcept {
|
|
|
258
279
|
reviewState: OkfKnowledgeReviewState;
|
|
259
280
|
lifecycle: OkfKnowledgeLifecycle;
|
|
260
281
|
lifecyclePersisted: boolean;
|
|
282
|
+
verificationSnapshot: OkfKnowledgeVerificationSnapshotV1 | null;
|
|
261
283
|
title: string;
|
|
262
284
|
description: string;
|
|
263
285
|
tags: string[];
|
|
@@ -294,6 +316,8 @@ export interface OkfKnowledgeContextItem {
|
|
|
294
316
|
score?: number;
|
|
295
317
|
title: string;
|
|
296
318
|
summary: string;
|
|
319
|
+
freshness: OkfKnowledgeFreshness;
|
|
320
|
+
runtimeExcerpt: string | null;
|
|
297
321
|
matchReasons: string[];
|
|
298
322
|
}
|
|
299
323
|
|
|
@@ -337,6 +361,20 @@ export interface ScopedKnowledgeContextPackItem {
|
|
|
337
361
|
section: OkfKnowledgeContextSection;
|
|
338
362
|
rank: number;
|
|
339
363
|
title: string;
|
|
364
|
+
freshness: OkfKnowledgeFreshness;
|
|
365
|
+
loader:
|
|
366
|
+
| {
|
|
367
|
+
kind: "knowledge-show";
|
|
368
|
+
conceptId: string;
|
|
369
|
+
}
|
|
370
|
+
| {
|
|
371
|
+
kind: "none";
|
|
372
|
+
conceptId: null;
|
|
373
|
+
};
|
|
374
|
+
delivery: {
|
|
375
|
+
mode: "inline" | "reference";
|
|
376
|
+
excerpt: string | null;
|
|
377
|
+
};
|
|
340
378
|
matchReasons: string[];
|
|
341
379
|
}
|
|
342
380
|
|
|
@@ -478,6 +516,7 @@ const OKF_DECISIONS: readonly OkfKnowledgeDecision[] = [
|
|
|
478
516
|
"update",
|
|
479
517
|
"skip",
|
|
480
518
|
"needs-human",
|
|
519
|
+
"revoke",
|
|
481
520
|
];
|
|
482
521
|
const ACTIVE_OKF_DECISIONS: readonly OkfKnowledgeDecision[] = ["auto-accept", "create", "update"];
|
|
483
522
|
const BEHAVIOR_CHANGE_KINDS = new Set([
|
|
@@ -642,7 +681,7 @@ export function finalizeCuratedKnowledgePlan(input: {
|
|
|
642
681
|
};
|
|
643
682
|
const candidates = input.plan.candidates.map((candidate) => {
|
|
644
683
|
if (candidate.decision === "no_write" || candidate.decision === "skip") return candidate;
|
|
645
|
-
if (candidate.decision === "needs-human") return candidate;
|
|
684
|
+
if (candidate.decision === "needs-human" || candidate.decision === "revoke") return candidate;
|
|
646
685
|
return decideOkfKnowledgeCandidate(
|
|
647
686
|
{
|
|
648
687
|
...candidate,
|
|
@@ -773,7 +812,7 @@ export function parseKnowledgeDistillationOutput(
|
|
|
773
812
|
|
|
774
813
|
export function validateOkfKnowledgePlanContract(
|
|
775
814
|
plan: OkfKnowledgePlan,
|
|
776
|
-
|
|
815
|
+
options: { homeDir?: string; allowReviewedHighRisk?: boolean } = {},
|
|
777
816
|
): OkfKnowledgePlanValidationResult {
|
|
778
817
|
const findings: OkfKnowledgePlanValidationFinding[] = [];
|
|
779
818
|
const add = (
|
|
@@ -825,7 +864,9 @@ export function validateOkfKnowledgePlanContract(
|
|
|
825
864
|
add("candidates", "plan.candidates", "Plan candidates must be an array.");
|
|
826
865
|
} else {
|
|
827
866
|
plan.candidates.forEach((candidate, index) =>
|
|
828
|
-
validateCandidateContract(candidate, `candidates[${index}]`, evalSetIds, add
|
|
867
|
+
validateCandidateContract(candidate, `candidates[${index}]`, evalSetIds, add, {
|
|
868
|
+
allowReviewedHighRisk: options.allowReviewedHighRisk === true,
|
|
869
|
+
}),
|
|
829
870
|
);
|
|
830
871
|
}
|
|
831
872
|
|
|
@@ -877,7 +918,7 @@ export function validateOkfKnowledgePlanContract(
|
|
|
877
918
|
|
|
878
919
|
export function assertOkfKnowledgePlanContract(
|
|
879
920
|
plan: OkfKnowledgePlan,
|
|
880
|
-
options: { homeDir?: string } = {},
|
|
921
|
+
options: { homeDir?: string; allowReviewedHighRisk?: boolean } = {},
|
|
881
922
|
): void {
|
|
882
923
|
const result = validateOkfKnowledgePlanContract(plan, options);
|
|
883
924
|
if (!result.ok) {
|
|
@@ -948,6 +989,7 @@ function validateCandidateContract(
|
|
|
948
989
|
path: string,
|
|
949
990
|
evalSetIds: Set<string>,
|
|
950
991
|
add: (path: string, code: string, message: string, severity?: "error" | "warning") => void,
|
|
992
|
+
options: { allowReviewedHighRisk: boolean },
|
|
951
993
|
): void {
|
|
952
994
|
if (!isRecord(candidate)) {
|
|
953
995
|
add(path, "candidate.object", "Candidate must be an object.");
|
|
@@ -1035,7 +1077,7 @@ function validateCandidateContract(
|
|
|
1035
1077
|
"Active writes require metadata-only evidence.",
|
|
1036
1078
|
);
|
|
1037
1079
|
}
|
|
1038
|
-
if (hasHighRiskHumanReviewSignal(candidate)) {
|
|
1080
|
+
if (hasHighRiskHumanReviewSignal(candidate) && !options.allowReviewedHighRisk) {
|
|
1039
1081
|
add(
|
|
1040
1082
|
path,
|
|
1041
1083
|
"candidate.active.highRiskHumanReview",
|
|
@@ -1094,6 +1136,47 @@ function validateCandidateContract(
|
|
|
1094
1136
|
);
|
|
1095
1137
|
}
|
|
1096
1138
|
}
|
|
1139
|
+
if (decision === "revoke") {
|
|
1140
|
+
if (candidate.targetStore !== "okf") {
|
|
1141
|
+
add(
|
|
1142
|
+
`${path}.targetStore`,
|
|
1143
|
+
"candidate.revoke.targetStore",
|
|
1144
|
+
"Knowledge revocation must target OKF.",
|
|
1145
|
+
);
|
|
1146
|
+
}
|
|
1147
|
+
if (candidate.reviewState !== "needs-human") {
|
|
1148
|
+
add(
|
|
1149
|
+
`${path}.reviewState`,
|
|
1150
|
+
"candidate.revoke.reviewState",
|
|
1151
|
+
"Knowledge revocation must enter human review.",
|
|
1152
|
+
);
|
|
1153
|
+
}
|
|
1154
|
+
if (candidate.metadataOnlyEvidence !== true) {
|
|
1155
|
+
add(
|
|
1156
|
+
`${path}.metadataOnlyEvidence`,
|
|
1157
|
+
"candidate.revoke.metadataOnlyEvidence",
|
|
1158
|
+
"Knowledge revocation requires metadata-only evidence.",
|
|
1159
|
+
);
|
|
1160
|
+
}
|
|
1161
|
+
if (!Array.isArray(candidate.evidenceRefs) || candidate.evidenceRefs.length === 0) {
|
|
1162
|
+
add(
|
|
1163
|
+
`${path}.evidenceRefs`,
|
|
1164
|
+
"candidate.revoke.evidenceRefs",
|
|
1165
|
+
"Knowledge revocation requires evidenceRefs.",
|
|
1166
|
+
);
|
|
1167
|
+
}
|
|
1168
|
+
const verification =
|
|
1169
|
+
isRecord(candidate.bodySections) && Array.isArray(candidate.bodySections.verification)
|
|
1170
|
+
? candidate.bodySections.verification
|
|
1171
|
+
: [];
|
|
1172
|
+
if (verification.length === 0 && !isNonEmptyString(candidate.verificationNotApplicableReason)) {
|
|
1173
|
+
add(
|
|
1174
|
+
`${path}.bodySections.verification`,
|
|
1175
|
+
"candidate.revoke.verification",
|
|
1176
|
+
"Knowledge revocation requires verification or an explicit not-applicable reason.",
|
|
1177
|
+
);
|
|
1178
|
+
}
|
|
1179
|
+
}
|
|
1097
1180
|
if (noOp && (!isNonEmptyString(candidate.id) || !isNonEmptyString(candidate.decisionReason))) {
|
|
1098
1181
|
add(path, "candidate.noop.metadata", "No-op candidates require safe skip metadata.");
|
|
1099
1182
|
}
|
|
@@ -1638,9 +1721,8 @@ export function findCandidateConflictOrDuplicate(
|
|
|
1638
1721
|
const targetPath = candidate.targetPath.replace(/^\/+/u, "");
|
|
1639
1722
|
const duplicate = index.concepts.find(
|
|
1640
1723
|
(concept) =>
|
|
1641
|
-
concept.stableKey
|
|
1642
|
-
concept.targetPath === targetPath ||
|
|
1643
|
-
concept.sourceLink === `/${targetPath}`,
|
|
1724
|
+
concept.stableKey !== candidate.stableKey &&
|
|
1725
|
+
(concept.targetPath === targetPath || concept.sourceLink === `/${targetPath}`),
|
|
1644
1726
|
);
|
|
1645
1727
|
if (duplicate !== undefined) {
|
|
1646
1728
|
return {
|
|
@@ -1655,6 +1737,7 @@ export function findCandidateConflictOrDuplicate(
|
|
|
1655
1737
|
);
|
|
1656
1738
|
const semanticDuplicate = index.concepts.find(
|
|
1657
1739
|
(concept) =>
|
|
1740
|
+
concept.stableKey !== candidate.stableKey &&
|
|
1658
1741
|
candidateFingerprint !== "" &&
|
|
1659
1742
|
candidateFingerprint === concept.semanticFingerprint &&
|
|
1660
1743
|
scopesOverlap(candidate.repoTags, concept.repoTags),
|
|
@@ -1808,12 +1891,22 @@ export function decideOkfKnowledgeCandidate(
|
|
|
1808
1891
|
}
|
|
1809
1892
|
|
|
1810
1893
|
if (highRiskRequiresHuman) {
|
|
1894
|
+
const reviewEligible =
|
|
1895
|
+
!originalUnsafe &&
|
|
1896
|
+
hasReusableSemanticShape(sanitized) &&
|
|
1897
|
+
localActiveTarget &&
|
|
1898
|
+
sanitized.metadataOnlyEvidence &&
|
|
1899
|
+
hasVerification &&
|
|
1900
|
+
hasScopeTags &&
|
|
1901
|
+
scores.privacyRisk <= 2;
|
|
1811
1902
|
return {
|
|
1812
1903
|
...sanitized,
|
|
1813
|
-
decision: "no_write",
|
|
1904
|
+
decision: reviewEligible ? "needs-human" : "no_write",
|
|
1814
1905
|
scores,
|
|
1815
|
-
reviewState: "auto-stored/unreviewed",
|
|
1816
|
-
decisionReason:
|
|
1906
|
+
reviewState: reviewEligible ? "needs-human" : "auto-stored/unreviewed",
|
|
1907
|
+
decisionReason: reviewEligible
|
|
1908
|
+
? "Needs human review: the candidate changes a sensitive engineering domain."
|
|
1909
|
+
: "No write: high-risk knowledge did not pass the privacy, verification, or scope gates.",
|
|
1817
1910
|
};
|
|
1818
1911
|
}
|
|
1819
1912
|
|
|
@@ -1849,19 +1942,103 @@ export function decideOkfKnowledgeCandidate(
|
|
|
1849
1942
|
};
|
|
1850
1943
|
}
|
|
1851
1944
|
|
|
1945
|
+
async function readAuthorizedReviewedKnowledgeChange(input: {
|
|
1946
|
+
homeDir: string;
|
|
1947
|
+
plan: OkfKnowledgePlan;
|
|
1948
|
+
changeId: string;
|
|
1949
|
+
}): Promise<OkfKnowledgeChangeCandidateV1> {
|
|
1950
|
+
const { change } = await readOkfKnowledgeChangeCandidate({
|
|
1951
|
+
homeDir: input.homeDir,
|
|
1952
|
+
changeId: input.changeId,
|
|
1953
|
+
});
|
|
1954
|
+
if (change.state !== "accepted" || change.decision?.state !== "accepted") {
|
|
1955
|
+
throw new Error("Reviewed knowledge change must be accepted before activation.");
|
|
1956
|
+
}
|
|
1957
|
+
if (change.operation === "revoke") {
|
|
1958
|
+
throw new Error("Reviewed knowledge revocation must use the lifecycle decision path.");
|
|
1959
|
+
}
|
|
1960
|
+
if (
|
|
1961
|
+
input.plan.projectKey !== change.projectKey ||
|
|
1962
|
+
input.plan.runId !== change.runId ||
|
|
1963
|
+
input.plan.evidenceWindowId !== change.provenance.evidenceWindowId
|
|
1964
|
+
) {
|
|
1965
|
+
throw new Error("Reviewed knowledge change identity does not match the activation plan.");
|
|
1966
|
+
}
|
|
1967
|
+
if (input.plan.candidates.length !== 1) {
|
|
1968
|
+
throw new Error("Reviewed knowledge activation must contain exactly one candidate.");
|
|
1969
|
+
}
|
|
1970
|
+
const candidate = input.plan.candidates[0] as OkfKnowledgePlanCandidate;
|
|
1971
|
+
const expectedCandidate: OkfKnowledgePlanCandidate = {
|
|
1972
|
+
...change.candidate.planCandidate,
|
|
1973
|
+
decision: change.operation === "update" ? "update" : "create",
|
|
1974
|
+
reviewState: "accepted",
|
|
1975
|
+
targetPath:
|
|
1976
|
+
change.operation === "update" && change.base !== null
|
|
1977
|
+
? change.base.sourceLink.replace(/^\/+/u, "")
|
|
1978
|
+
: change.targetPath,
|
|
1979
|
+
};
|
|
1980
|
+
if (stableJsonStringify(candidate) !== stableJsonStringify(expectedCandidate)) {
|
|
1981
|
+
throw new Error("Reviewed knowledge candidate does not match the accepted change.");
|
|
1982
|
+
}
|
|
1983
|
+
if (
|
|
1984
|
+
stableJsonStringify(input.plan.evoEvalSets) !== stableJsonStringify(change.candidate.evalSets)
|
|
1985
|
+
) {
|
|
1986
|
+
throw new Error("Reviewed knowledge eval sets do not match the accepted change.");
|
|
1987
|
+
}
|
|
1988
|
+
const expectedEvidenceRefs = change.provenance.evidenceRefs.map((id) => ({
|
|
1989
|
+
id,
|
|
1990
|
+
kind: "knowledge-change-evidence",
|
|
1991
|
+
source: `knowledge-change:${change.id}`,
|
|
1992
|
+
rawContentStored: false,
|
|
1993
|
+
externalContentCopied: false,
|
|
1994
|
+
}));
|
|
1995
|
+
if (
|
|
1996
|
+
stableJsonStringify(input.plan.evidenceRefs) !== stableJsonStringify(expectedEvidenceRefs) ||
|
|
1997
|
+
stableJsonStringify(input.plan.privacyCheck) !==
|
|
1998
|
+
stableJsonStringify(expectedCandidate.privacyCheck)
|
|
1999
|
+
) {
|
|
2000
|
+
throw new Error("Reviewed knowledge provenance does not match the accepted change.");
|
|
2001
|
+
}
|
|
2002
|
+
return change;
|
|
2003
|
+
}
|
|
2004
|
+
|
|
2005
|
+
function assertReviewedKnowledgeClassification(
|
|
2006
|
+
change: OkfKnowledgeChangeCandidateV1,
|
|
2007
|
+
classification: OkfKnowledgeChangeClassificationResult,
|
|
2008
|
+
): void {
|
|
2009
|
+
if (
|
|
2010
|
+
classification.classification !== change.operation ||
|
|
2011
|
+
classification.baseRevision !== (change.base?.revision ?? null) ||
|
|
2012
|
+
classification.candidateRevision !== change.candidate.revision
|
|
2013
|
+
) {
|
|
2014
|
+
throw new Error("Reviewed knowledge classification changed before activation.");
|
|
2015
|
+
}
|
|
2016
|
+
}
|
|
2017
|
+
|
|
1852
2018
|
export async function activateOkfKnowledgePlan(input: {
|
|
1853
2019
|
homeDir: string;
|
|
1854
2020
|
plan: OkfKnowledgePlan;
|
|
1855
2021
|
overwrite?: boolean;
|
|
1856
2022
|
evidenceWindowPath?: string | null;
|
|
2023
|
+
reviewedChangeId?: string;
|
|
1857
2024
|
}): Promise<OkfKnowledgeActivationResult> {
|
|
1858
|
-
const validation = validateOkfKnowledgePlanContract(input.plan);
|
|
1859
2025
|
const projectKey =
|
|
1860
2026
|
isRecord(input.plan) && isNonEmptyString(input.plan.projectKey)
|
|
1861
2027
|
? input.plan.projectKey
|
|
1862
2028
|
: "unknown";
|
|
1863
2029
|
const runId =
|
|
1864
2030
|
isRecord(input.plan) && isNonEmptyString(input.plan.runId) ? input.plan.runId : "unknown";
|
|
2031
|
+
const reviewedChange =
|
|
2032
|
+
input.reviewedChangeId === undefined
|
|
2033
|
+
? null
|
|
2034
|
+
: await readAuthorizedReviewedKnowledgeChange({
|
|
2035
|
+
homeDir: input.homeDir,
|
|
2036
|
+
plan: input.plan,
|
|
2037
|
+
changeId: input.reviewedChangeId,
|
|
2038
|
+
});
|
|
2039
|
+
const validation = validateOkfKnowledgePlanContract(input.plan, {
|
|
2040
|
+
allowReviewedHighRisk: reviewedChange !== null,
|
|
2041
|
+
});
|
|
1865
2042
|
if (!validation.ok) {
|
|
1866
2043
|
await writeFailedOkfKnowledgePlanArtifact({
|
|
1867
2044
|
homeDir: input.homeDir,
|
|
@@ -1874,7 +2051,7 @@ export async function activateOkfKnowledgePlan(input: {
|
|
|
1874
2051
|
});
|
|
1875
2052
|
throw new Error("OKF knowledge plan contract validation failed.");
|
|
1876
2053
|
}
|
|
1877
|
-
validateOkfKnowledgePlan(input.plan);
|
|
2054
|
+
validateOkfKnowledgePlan(input.plan, { allowReviewedHighRisk: reviewedChange !== null });
|
|
1878
2055
|
const paths = resolveOkfKnowledgePaths(input.homeDir);
|
|
1879
2056
|
const tmpRunDir = join(paths.tmpDir, `${input.plan.projectKey}-${input.plan.runId}`);
|
|
1880
2057
|
const planPath = join(tmpRunDir, "knowledge-plan.json");
|
|
@@ -1891,24 +2068,146 @@ export async function activateOkfKnowledgePlan(input: {
|
|
|
1891
2068
|
const overlayPaths: string[] = [];
|
|
1892
2069
|
const skippedCandidates: string[] = [];
|
|
1893
2070
|
const needsHumanCandidates: string[] = [];
|
|
2071
|
+
const pendingChangeIds: string[] = [];
|
|
1894
2072
|
const affectedDirectories = new Set<string>([paths.okfDir]);
|
|
1895
2073
|
|
|
1896
2074
|
try {
|
|
1897
|
-
const
|
|
2075
|
+
const settings = await readRuntimeInjectionSettings(input.homeDir);
|
|
2076
|
+
const existingConcepts = await listOkfKnowledgeConcepts({ homeDir: input.homeDir });
|
|
2077
|
+
const existingByStableKey = new Map(
|
|
2078
|
+
existingConcepts
|
|
2079
|
+
.filter(
|
|
2080
|
+
(concept) =>
|
|
2081
|
+
isActiveOkfReviewState(concept.reviewState) && concept.lifecycle.status === "active",
|
|
2082
|
+
)
|
|
2083
|
+
.map((concept) => [concept.stableKey, concept]),
|
|
2084
|
+
);
|
|
2085
|
+
const writeCandidates: OkfKnowledgePlanCandidate[] = [];
|
|
2086
|
+
const existingByCandidateId = new Map<string, OkfKnowledgeConcept>();
|
|
1898
2087
|
for (const candidate of input.plan.candidates) {
|
|
1899
2088
|
if (candidate.decision === "no_write" || candidate.decision === "skip") {
|
|
1900
2089
|
skippedCandidates.push(candidate.id);
|
|
1901
2090
|
continue;
|
|
1902
2091
|
}
|
|
1903
|
-
if (candidate.
|
|
1904
|
-
|
|
2092
|
+
if (candidate.targetStore !== "okf") {
|
|
2093
|
+
skippedCandidates.push(candidate.id);
|
|
1905
2094
|
continue;
|
|
1906
2095
|
}
|
|
1907
|
-
|
|
2096
|
+
const existing = existingByStableKey.get(candidate.stableKey) ?? null;
|
|
2097
|
+
const classification = classifyOkfKnowledgeCandidate({
|
|
2098
|
+
candidate,
|
|
2099
|
+
existingConcept: existing,
|
|
2100
|
+
});
|
|
2101
|
+
if (reviewedChange !== null) {
|
|
2102
|
+
assertReviewedKnowledgeClassification(reviewedChange, classification);
|
|
2103
|
+
}
|
|
2104
|
+
const needsReview =
|
|
2105
|
+
reviewedChange === null &&
|
|
2106
|
+
(candidate.decision === "needs-human" ||
|
|
2107
|
+
classification.classification === "revoke" ||
|
|
2108
|
+
classification.classification === "supersede" ||
|
|
2109
|
+
(classification.classification === "update" && settings.reviewKnowledgeUpdates));
|
|
2110
|
+
if (needsReview) {
|
|
2111
|
+
const operation =
|
|
2112
|
+
classification.classification === "supersede" ||
|
|
2113
|
+
classification.classification === "revoke"
|
|
2114
|
+
? classification.classification
|
|
2115
|
+
: existing === null
|
|
2116
|
+
? "create"
|
|
2117
|
+
: "update";
|
|
2118
|
+
const beforeFreshness =
|
|
2119
|
+
existing === null ? null : deriveOkfKnowledgeFreshness({ concept: existing }).freshness;
|
|
2120
|
+
const verificationSnapshot = createOkfKnowledgeVerificationSnapshot({
|
|
2121
|
+
candidate,
|
|
2122
|
+
verifiedAt: input.plan.createdAt,
|
|
2123
|
+
projectKey: input.plan.projectKey,
|
|
2124
|
+
});
|
|
2125
|
+
const change = createOkfKnowledgeChangeCandidate({
|
|
2126
|
+
projectKey: input.plan.projectKey,
|
|
2127
|
+
runId: input.plan.runId,
|
|
2128
|
+
operation,
|
|
2129
|
+
stableKey: candidate.stableKey,
|
|
2130
|
+
targetPath: candidate.targetPath,
|
|
2131
|
+
base:
|
|
2132
|
+
existing === null || classification.baseProjection === null
|
|
2133
|
+
? null
|
|
2134
|
+
: {
|
|
2135
|
+
conceptId: existing.id,
|
|
2136
|
+
sourceLink: existing.sourceLink,
|
|
2137
|
+
revision:
|
|
2138
|
+
classification.baseRevision ??
|
|
2139
|
+
createOkfKnowledgeRevision(
|
|
2140
|
+
createOkfKnowledgeRuntimeProjectionFromConcept(existing),
|
|
2141
|
+
),
|
|
2142
|
+
runtimeProjection: classification.baseProjection,
|
|
2143
|
+
},
|
|
2144
|
+
candidateRevision: classification.candidateRevision,
|
|
2145
|
+
planCandidate: candidate,
|
|
2146
|
+
evalSets: input.plan.evoEvalSets.filter((evalSet) =>
|
|
2147
|
+
(candidate.evalSetRefs ?? []).includes(evalSet.id),
|
|
2148
|
+
),
|
|
2149
|
+
diff: classification.diff,
|
|
2150
|
+
freshness: {
|
|
2151
|
+
before: beforeFreshness,
|
|
2152
|
+
after:
|
|
2153
|
+
classification.classification === "revoke"
|
|
2154
|
+
? "stale"
|
|
2155
|
+
: verificationSnapshot === null
|
|
2156
|
+
? "unknown"
|
|
2157
|
+
: "verified",
|
|
2158
|
+
reason:
|
|
2159
|
+
candidate.decision === "needs-human" || candidate.decision === "revoke"
|
|
2160
|
+
? candidate.decisionReason
|
|
2161
|
+
: classification.reason,
|
|
2162
|
+
},
|
|
2163
|
+
evidenceWindowId: input.plan.evidenceWindowId,
|
|
2164
|
+
evidenceRefs: candidate.evidenceRefs,
|
|
2165
|
+
createdAt: input.plan.createdAt,
|
|
2166
|
+
});
|
|
2167
|
+
await writeOkfKnowledgeChangeCandidate({ homeDir: input.homeDir, change });
|
|
2168
|
+
pendingChangeIds.push(change.id);
|
|
2169
|
+
if (candidate.decision === "needs-human" || candidate.decision === "revoke") {
|
|
2170
|
+
needsHumanCandidates.push(candidate.id);
|
|
2171
|
+
}
|
|
2172
|
+
continue;
|
|
2173
|
+
}
|
|
2174
|
+
if (classification.classification === "no_write") {
|
|
1908
2175
|
skippedCandidates.push(candidate.id);
|
|
1909
2176
|
continue;
|
|
1910
2177
|
}
|
|
2178
|
+
if (classification.classification === "supersede") {
|
|
2179
|
+
writeCandidates.push({
|
|
2180
|
+
...candidate,
|
|
2181
|
+
decision: "create",
|
|
2182
|
+
reviewState: "accepted",
|
|
2183
|
+
});
|
|
2184
|
+
continue;
|
|
2185
|
+
}
|
|
2186
|
+
if (classification.classification === "revoke") {
|
|
2187
|
+
throw new Error("Knowledge revocation must be applied through its reviewed change.");
|
|
2188
|
+
}
|
|
2189
|
+
if (
|
|
2190
|
+
classification.classification === "update" ||
|
|
2191
|
+
classification.classification === "refresh"
|
|
2192
|
+
) {
|
|
2193
|
+
if (existing === null) {
|
|
2194
|
+
throw new Error(`Knowledge ${classification.classification} requires an active concept.`);
|
|
2195
|
+
}
|
|
2196
|
+
const effectiveCandidate: OkfKnowledgePlanCandidate = {
|
|
2197
|
+
...candidate,
|
|
2198
|
+
decision: "update",
|
|
2199
|
+
targetPath: existing.sourceLink.replace(/^\/+/u, ""),
|
|
2200
|
+
reviewState: candidate.reviewState === "auto-accepted" ? "auto-accepted" : "accepted",
|
|
2201
|
+
};
|
|
2202
|
+
writeCandidates.push(effectiveCandidate);
|
|
2203
|
+
existingByCandidateId.set(effectiveCandidate.id, existing);
|
|
2204
|
+
continue;
|
|
2205
|
+
}
|
|
2206
|
+
writeCandidates.push(candidate);
|
|
2207
|
+
}
|
|
1911
2208
|
|
|
2209
|
+
const targetStates = await preflightOkfConceptTargets(paths.okfDir, writeCandidates);
|
|
2210
|
+
for (const candidate of writeCandidates) {
|
|
1912
2211
|
const targetPath = resolveOkfTargetPath(paths.okfDir, candidate.targetPath);
|
|
1913
2212
|
const targetState = targetStates.get(targetPath);
|
|
1914
2213
|
if (targetState?.action === "skip-existing") {
|
|
@@ -1921,7 +2220,11 @@ export async function activateOkfKnowledgePlan(input: {
|
|
|
1921
2220
|
}
|
|
1922
2221
|
|
|
1923
2222
|
await mkdir(dirname(targetPath), { recursive: true });
|
|
1924
|
-
await writeFile(
|
|
2223
|
+
await writeFile(
|
|
2224
|
+
targetPath,
|
|
2225
|
+
renderOkfConcept(candidate, input.plan, existingByCandidateId.get(candidate.id)),
|
|
2226
|
+
"utf8",
|
|
2227
|
+
);
|
|
1925
2228
|
conceptPaths.push(targetPath);
|
|
1926
2229
|
affectedDirectories.add(dirname(targetPath));
|
|
1927
2230
|
|
|
@@ -1962,6 +2265,7 @@ export async function activateOkfKnowledgePlan(input: {
|
|
|
1962
2265
|
overlayPaths,
|
|
1963
2266
|
skippedCandidates,
|
|
1964
2267
|
needsHumanCandidates,
|
|
2268
|
+
pendingChangeIds,
|
|
1965
2269
|
indexPaths,
|
|
1966
2270
|
derivedIndexPaths,
|
|
1967
2271
|
logPaths,
|
|
@@ -2500,17 +2804,26 @@ export async function queryOkfKnowledge(input: {
|
|
|
2500
2804
|
return left.concept.id.localeCompare(right.concept.id);
|
|
2501
2805
|
})
|
|
2502
2806
|
.slice(0, limit)
|
|
2503
|
-
.map<OkfKnowledgeContextItem>((candidate, index) =>
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
|
|
2807
|
+
.map<OkfKnowledgeContextItem>((candidate, index) => {
|
|
2808
|
+
const freshness = deriveOkfKnowledgeFreshness({
|
|
2809
|
+
concept: candidate.concept,
|
|
2810
|
+
now,
|
|
2811
|
+
}).freshness;
|
|
2812
|
+
return {
|
|
2813
|
+
id: candidate.concept.id,
|
|
2814
|
+
sourceType: "okf",
|
|
2815
|
+
sourceLink: candidate.concept.sourceLink,
|
|
2816
|
+
section: candidate.section,
|
|
2817
|
+
rank: index + 1,
|
|
2818
|
+
score: candidate.score,
|
|
2819
|
+
title: candidate.concept.title,
|
|
2820
|
+
summary: candidate.concept.description || candidate.concept.title,
|
|
2821
|
+
freshness,
|
|
2822
|
+
runtimeExcerpt:
|
|
2823
|
+
freshness === "verified" ? createBoundedOkfRuntimeExcerpt(candidate.concept) : null,
|
|
2824
|
+
matchReasons: candidate.matchReasons.length === 0 ? ["generic"] : candidate.matchReasons,
|
|
2825
|
+
};
|
|
2826
|
+
});
|
|
2514
2827
|
|
|
2515
2828
|
return {
|
|
2516
2829
|
projectKey: scope.projectKey,
|
|
@@ -2788,6 +3101,10 @@ export function mergeAcceptedEvosCasesIntoKnowledgeQuery(
|
|
|
2788
3101
|
score: structuredScore + lexical.score,
|
|
2789
3102
|
title: evosCase.title,
|
|
2790
3103
|
summary: evosCase.expectedFutureBehavior || evosCase.result.summary || evosCase.title,
|
|
3104
|
+
freshness: "verified",
|
|
3105
|
+
runtimeExcerpt: sanitizeOkfText(
|
|
3106
|
+
evosCase.expectedFutureBehavior || evosCase.result.summary || evosCase.title,
|
|
3107
|
+
).slice(0, 1_200),
|
|
2791
3108
|
matchReasons:
|
|
2792
3109
|
lexical.reasons.length === 0
|
|
2793
3110
|
? structuredReasons
|
|
@@ -2830,6 +3147,15 @@ export async function createScopedKnowledgeContextPack(input: {
|
|
|
2830
3147
|
section: item.section,
|
|
2831
3148
|
rank: item.rank,
|
|
2832
3149
|
title: sanitizeOkfText(item.title),
|
|
3150
|
+
freshness: item.freshness,
|
|
3151
|
+
loader:
|
|
3152
|
+
item.sourceType === "okf"
|
|
3153
|
+
? { kind: "knowledge-show", conceptId: item.id }
|
|
3154
|
+
: { kind: "none", conceptId: null },
|
|
3155
|
+
delivery: {
|
|
3156
|
+
mode: item.runtimeExcerpt === null ? "reference" : "inline",
|
|
3157
|
+
excerpt: item.runtimeExcerpt,
|
|
3158
|
+
},
|
|
2833
3159
|
matchReasons: uniqueStrings(item.matchReasons.map(sanitizeLexicalReason)),
|
|
2834
3160
|
}));
|
|
2835
3161
|
const okfIndexRevision = createKnowledgeContextRevision(items);
|
|
@@ -2843,7 +3169,9 @@ export async function createScopedKnowledgeContextPack(input: {
|
|
|
2843
3169
|
sourceType: item.sourceType,
|
|
2844
3170
|
sourceLink: item.sourceLink,
|
|
2845
3171
|
section: item.section,
|
|
2846
|
-
|
|
3172
|
+
freshness: item.freshness,
|
|
3173
|
+
loader: item.loader,
|
|
3174
|
+
delivery: item.delivery,
|
|
2847
3175
|
matchReasons: item.matchReasons,
|
|
2848
3176
|
})),
|
|
2849
3177
|
});
|
|
@@ -2875,10 +3203,20 @@ export function formatScopedKnowledgePromptBlock(pack: ScopedKnowledgeContextPac
|
|
|
2875
3203
|
...(pack.queryText === undefined ? [] : [`Query: ${sanitizeOkfText(pack.queryText)}`]),
|
|
2876
3204
|
`Paths: ${pack.scope.paths.length === 0 ? "all" : pack.scope.paths.join(", ")}`,
|
|
2877
3205
|
"Raw content stored: false",
|
|
3206
|
+
"Freshness is determined by EvoDev lifecycle and verification metadata; do not infer validity from timestamps.",
|
|
2878
3207
|
"",
|
|
2879
3208
|
"Applicable items:",
|
|
2880
3209
|
...pack.items.flatMap((item) => [
|
|
2881
|
-
`- ${item.rank}. ${sanitizeOkfText(item.
|
|
3210
|
+
`- ${item.rank}. ${sanitizeOkfText(item.title)} (${item.section}; ${item.sourceType})`,
|
|
3211
|
+
` Identity: ${sanitizeOkfText(item.id)}`,
|
|
3212
|
+
` Freshness: ${item.freshness}`,
|
|
3213
|
+
` Delivery: ${item.delivery.mode}`,
|
|
3214
|
+
...(item.delivery.excerpt === null
|
|
3215
|
+
? [" Guidance: load on demand; do not treat this reference as a standing constraint."]
|
|
3216
|
+
: [` Guidance: ${sanitizeOkfText(item.delivery.excerpt)}`]),
|
|
3217
|
+
...(item.loader.kind === "knowledge-show"
|
|
3218
|
+
? [` Load: evodev knowledge show ${sanitizeOkfText(item.loader.conceptId)}`]
|
|
3219
|
+
: []),
|
|
2882
3220
|
` Source: ${sanitizeOkfText(item.sourceLink)}`,
|
|
2883
3221
|
` Match: ${item.matchReasons.length === 0 ? "generic" : item.matchReasons.join(", ")}`,
|
|
2884
3222
|
]),
|
|
@@ -3293,7 +3631,7 @@ export function formatOkfKnowledgeQuery(result: OkfKnowledgeQueryResult): string
|
|
|
3293
3631
|
? ["- none"]
|
|
3294
3632
|
: items.map(
|
|
3295
3633
|
(item) =>
|
|
3296
|
-
`- ${item.summary}\n Source: ${item.sourceLink}\n Match: ${item.matchReasons.join(", ")}\n Rank: ${item.rank}`,
|
|
3634
|
+
`- ${item.summary}\n Freshness: ${item.freshness}\n ${item.sourceType === "okf" ? `Load: evodev knowledge show ${item.id}\n ` : ""}Source: ${item.sourceLink}\n Match: ${item.matchReasons.join(", ")}\n Rank: ${item.rank}`,
|
|
3297
3635
|
)),
|
|
3298
3636
|
"",
|
|
3299
3637
|
];
|
|
@@ -3699,6 +4037,19 @@ function extractSummarySection(body: string): string {
|
|
|
3699
4037
|
return body.match(/(?:^|\n)# Summary\s*\n+([\s\S]*?)(?=\n# |$)/u)?.[1]?.trim() ?? "";
|
|
3700
4038
|
}
|
|
3701
4039
|
|
|
4040
|
+
function createBoundedOkfRuntimeExcerpt(concept: OkfKnowledgeConcept): string {
|
|
4041
|
+
const projection = createOkfKnowledgeRuntimeProjectionFromConcept(concept);
|
|
4042
|
+
return sanitizeOkfText(
|
|
4043
|
+
[
|
|
4044
|
+
projection.summary || concept.description,
|
|
4045
|
+
...projection.guidance.map((item) => `- ${item}`),
|
|
4046
|
+
...projection.verification.map((item) => `Verification: ${item}`),
|
|
4047
|
+
]
|
|
4048
|
+
.filter((item) => item.trim() !== "")
|
|
4049
|
+
.join("\n"),
|
|
4050
|
+
).slice(0, 1_200);
|
|
4051
|
+
}
|
|
4052
|
+
|
|
3702
4053
|
function scopesOverlap(left: string[], right: string[]): boolean {
|
|
3703
4054
|
if (left.length === 0 || right.length === 0) return true;
|
|
3704
4055
|
return left.some((tag) => right.includes(tag));
|
|
@@ -3827,8 +4178,41 @@ async function ensureOverlayConcept(input: {
|
|
|
3827
4178
|
);
|
|
3828
4179
|
}
|
|
3829
4180
|
|
|
3830
|
-
function renderOkfConcept(
|
|
4181
|
+
function renderOkfConcept(
|
|
4182
|
+
candidate: OkfKnowledgePlanCandidate,
|
|
4183
|
+
plan: OkfKnowledgePlan,
|
|
4184
|
+
existing?: OkfKnowledgeConcept,
|
|
4185
|
+
): string {
|
|
3831
4186
|
const scores = resolveCandidateScoresForWrite(candidate);
|
|
4187
|
+
const reviewState = resolveCandidateReviewStateForWrite(candidate);
|
|
4188
|
+
const nextLifecycle = createDefaultOkfLifecycle({
|
|
4189
|
+
type: candidate.okfType,
|
|
4190
|
+
path: candidate.targetPath,
|
|
4191
|
+
tags: [
|
|
4192
|
+
"evodev",
|
|
4193
|
+
candidate.kind,
|
|
4194
|
+
...candidate.roleTags.map((tag) => `role:${tag}`),
|
|
4195
|
+
...candidate.repoTags.map((tag) => `repo:${tag}`),
|
|
4196
|
+
...candidate.workflowTags.map((tag) => `workflow:${tag}`),
|
|
4197
|
+
],
|
|
4198
|
+
title: candidate.title,
|
|
4199
|
+
reviewState,
|
|
4200
|
+
createdAt: plan.createdAt,
|
|
4201
|
+
});
|
|
4202
|
+
const lifecycle =
|
|
4203
|
+
existing === undefined
|
|
4204
|
+
? nextLifecycle
|
|
4205
|
+
: {
|
|
4206
|
+
...nextLifecycle,
|
|
4207
|
+
createdAt: existing.lifecycle.createdAt,
|
|
4208
|
+
supersedes: existing.lifecycle.supersedes,
|
|
4209
|
+
supersededBy: existing.lifecycle.supersededBy,
|
|
4210
|
+
};
|
|
4211
|
+
const verificationSnapshot = createOkfKnowledgeVerificationSnapshot({
|
|
4212
|
+
candidate,
|
|
4213
|
+
verifiedAt: plan.createdAt,
|
|
4214
|
+
projectKey: plan.projectKey,
|
|
4215
|
+
});
|
|
3832
4216
|
return [
|
|
3833
4217
|
"---",
|
|
3834
4218
|
`type: ${yamlString(candidate.okfType)}`,
|
|
@@ -3847,24 +4231,9 @@ function renderOkfConcept(candidate: OkfKnowledgePlanCandidate, plan: OkfKnowled
|
|
|
3847
4231
|
"evodev:",
|
|
3848
4232
|
` schema: ${yamlString("knowledge/v1")}`,
|
|
3849
4233
|
` stableKey: ${yamlString(candidate.stableKey)}`,
|
|
3850
|
-
` reviewState: ${yamlString(
|
|
3851
|
-
renderLifecycleYaml(
|
|
3852
|
-
|
|
3853
|
-
createDefaultOkfLifecycle({
|
|
3854
|
-
type: candidate.okfType,
|
|
3855
|
-
path: candidate.targetPath,
|
|
3856
|
-
tags: [
|
|
3857
|
-
"evodev",
|
|
3858
|
-
candidate.kind,
|
|
3859
|
-
...candidate.roleTags.map((tag) => `role:${tag}`),
|
|
3860
|
-
...candidate.repoTags.map((tag) => `repo:${tag}`),
|
|
3861
|
-
...candidate.workflowTags.map((tag) => `workflow:${tag}`),
|
|
3862
|
-
],
|
|
3863
|
-
title: candidate.title,
|
|
3864
|
-
reviewState: resolveCandidateReviewStateForWrite(candidate),
|
|
3865
|
-
createdAt: plan.createdAt,
|
|
3866
|
-
}),
|
|
3867
|
-
),
|
|
4234
|
+
` reviewState: ${yamlString(reviewState)}`,
|
|
4235
|
+
renderLifecycleYaml(" ", lifecycle),
|
|
4236
|
+
renderVerificationSnapshotYaml(" ", verificationSnapshot),
|
|
3868
4237
|
" source:",
|
|
3869
4238
|
` kind: ${yamlString("trace-distillation")}`,
|
|
3870
4239
|
` projectKey: ${yamlString(plan.projectKey)}`,
|
|
@@ -3895,17 +4264,27 @@ function renderOkfConcept(candidate: OkfKnowledgePlanCandidate, plan: OkfKnowled
|
|
|
3895
4264
|
"",
|
|
3896
4265
|
candidate.bodySections.summary,
|
|
3897
4266
|
"",
|
|
4267
|
+
"# Claim",
|
|
4268
|
+
"",
|
|
4269
|
+
candidate.claim,
|
|
4270
|
+
"",
|
|
3898
4271
|
"# Applies When",
|
|
3899
4272
|
"",
|
|
3900
4273
|
renderMarkdownList(candidate.bodySections.appliesWhen),
|
|
3901
4274
|
"",
|
|
4275
|
+
"# How to Apply",
|
|
4276
|
+
"",
|
|
4277
|
+
candidate.howToApply,
|
|
4278
|
+
"",
|
|
3902
4279
|
"# Guidance",
|
|
3903
4280
|
"",
|
|
3904
4281
|
renderMarkdownList(candidate.bodySections.guidance),
|
|
3905
4282
|
"",
|
|
3906
4283
|
"# Anti-Criteria",
|
|
3907
4284
|
"",
|
|
3908
|
-
renderMarkdownList(
|
|
4285
|
+
renderMarkdownList(
|
|
4286
|
+
uniqueStrings([...candidate.antiCriteria, ...candidate.bodySections.antiCriteria]),
|
|
4287
|
+
),
|
|
3909
4288
|
"",
|
|
3910
4289
|
"# Verification",
|
|
3911
4290
|
"",
|
|
@@ -4131,6 +4510,7 @@ function parseOkfConceptFile(
|
|
|
4131
4510
|
reviewState,
|
|
4132
4511
|
lifecycle: lifecycleParsed.lifecycle,
|
|
4133
4512
|
lifecyclePersisted: lifecycleParsed.persisted,
|
|
4513
|
+
verificationSnapshot: parseOkfVerificationSnapshot(frontmatter),
|
|
4134
4514
|
title,
|
|
4135
4515
|
description,
|
|
4136
4516
|
tags,
|
|
@@ -4142,6 +4522,22 @@ function parseOkfConceptFile(
|
|
|
4142
4522
|
};
|
|
4143
4523
|
}
|
|
4144
4524
|
|
|
4525
|
+
function parseOkfVerificationSnapshot(
|
|
4526
|
+
frontmatter: string,
|
|
4527
|
+
): OkfKnowledgeVerificationSnapshotV1 | null {
|
|
4528
|
+
const block = extractNestedYamlBlock(frontmatter, "evodev", "verificationSnapshot");
|
|
4529
|
+
if (block === null) return null;
|
|
4530
|
+
const schemaVersion = readIndentedYamlScalar(block, "schemaVersion");
|
|
4531
|
+
const verifiedAt = normalizeIsoDateString(readIndentedYamlScalar(block, "verifiedAt"));
|
|
4532
|
+
if (schemaVersion !== "1" || verifiedAt === null) return null;
|
|
4533
|
+
return {
|
|
4534
|
+
schemaVersion: 1,
|
|
4535
|
+
verifiedAt,
|
|
4536
|
+
evidenceRefs: readYamlList(block, "evidenceRefs"),
|
|
4537
|
+
repository: null,
|
|
4538
|
+
};
|
|
4539
|
+
}
|
|
4540
|
+
|
|
4145
4541
|
function matchesConceptFilters(
|
|
4146
4542
|
concept: OkfKnowledgeConcept,
|
|
4147
4543
|
input: { projectKey?: string; roleId?: string; workflowId?: string; paths?: string[] },
|
|
@@ -4241,6 +4637,9 @@ function createKnowledgeContextRevision(items: ScopedKnowledgeContextPackItem[])
|
|
|
4241
4637
|
sourceLink: item.sourceLink,
|
|
4242
4638
|
section: item.section,
|
|
4243
4639
|
title: item.title,
|
|
4640
|
+
freshness: item.freshness,
|
|
4641
|
+
loader: item.loader,
|
|
4642
|
+
delivery: item.delivery,
|
|
4244
4643
|
matchReasons: item.matchReasons,
|
|
4245
4644
|
})),
|
|
4246
4645
|
),
|
|
@@ -4668,8 +5067,11 @@ function readIndentedYamlBoolean(frontmatter: string, key: string): boolean | nu
|
|
|
4668
5067
|
return null;
|
|
4669
5068
|
}
|
|
4670
5069
|
|
|
4671
|
-
function validateOkfKnowledgePlan(
|
|
4672
|
-
|
|
5070
|
+
function validateOkfKnowledgePlan(
|
|
5071
|
+
plan: OkfKnowledgePlan,
|
|
5072
|
+
options: { allowReviewedHighRisk?: boolean } = {},
|
|
5073
|
+
): void {
|
|
5074
|
+
assertOkfKnowledgePlanContract(plan, options);
|
|
4673
5075
|
}
|
|
4674
5076
|
|
|
4675
5077
|
function validateFailedPlanArtifact(artifact: OkfKnowledgeFailedPlanArtifact): void {
|
|
@@ -4887,6 +5289,20 @@ function renderLifecycleYaml(indent: string, lifecycle: OkfKnowledgeLifecycle):
|
|
|
4887
5289
|
].join("\n");
|
|
4888
5290
|
}
|
|
4889
5291
|
|
|
5292
|
+
function renderVerificationSnapshotYaml(
|
|
5293
|
+
indent: string,
|
|
5294
|
+
snapshot: OkfKnowledgeVerificationSnapshotV1 | null,
|
|
5295
|
+
): string {
|
|
5296
|
+
if (snapshot === null) return `${indent}verificationSnapshot: null`;
|
|
5297
|
+
return [
|
|
5298
|
+
`${indent}verificationSnapshot:`,
|
|
5299
|
+
`${indent} schemaVersion: 1`,
|
|
5300
|
+
`${indent} verifiedAt: ${yamlString(snapshot.verifiedAt)}`,
|
|
5301
|
+
renderYamlList(`${indent} evidenceRefs`, snapshot.evidenceRefs),
|
|
5302
|
+
`${indent} repository: null`,
|
|
5303
|
+
].join("\n");
|
|
5304
|
+
}
|
|
5305
|
+
|
|
4890
5306
|
function lifecycleStatusFromReviewState(
|
|
4891
5307
|
reviewState: OkfKnowledgeReviewState,
|
|
4892
5308
|
): OkfKnowledgeLifecycleStatus {
|