@intentset/publisher 0.10.0 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/project.d.ts +9 -3
- package/dist/project.d.ts.map +1 -1
- package/dist/project.js +22 -5
- package/dist/project.js.map +1 -1
- package/dist/review.d.ts +21 -3
- package/dist/review.d.ts.map +1 -1
- package/dist/review.js +32 -6
- package/dist/review.js.map +1 -1
- package/package.json +3 -3
- package/src/index.ts +4 -0
- package/src/project.ts +29 -3
- package/src/review.ts +35 -6
package/dist/index.d.ts
CHANGED
|
@@ -7,10 +7,10 @@ export { bodyLineOffset } from "./body.ts";
|
|
|
7
7
|
export { type Chunk, type ChunkOptions, type ChunkSource, toChunks } from "./chunks.ts";
|
|
8
8
|
export { type GenerateOptions, type GeneratedDocument, PUBLICATION_KEY, PUBLICATION_PROFILE, type PublicationMeta, type SourceStamp, checkGenerated, generateDocument, markerLine, marksetSource, publicationMeta, } from "./generate.ts";
|
|
9
9
|
export { HELP_FILE, HELP_PROFILE, type HelpFile, type HelpKnowledge, type HelpOptions, type HelpTip, helpFile, } from "./help.ts";
|
|
10
|
-
export { EXCLUSION_REASONS, type Exclusion, type ExclusionReason, type ProjectOptions, type Projection, type Snapshot, exclusionReason, project, } from "./project.ts";
|
|
10
|
+
export { EXCLUSION_REASONS, type Exclusion, type ExclusionReason, type ProjectOptions, type Projection, type Snapshot, exclusionReason, plannedSources, project, } from "./project.ts";
|
|
11
11
|
export { type PublicationIndex, type PublishOptions, type PublishResult, type PublishedDocument, REFUSAL_REASONS, type RefusalReason, publish, renderDocument, } from "./publish.ts";
|
|
12
12
|
export { type Reference, type ReferenceKind, checkReferences, checkTitles, findReferences, resolveTarget, titlePattern, } from "./references.ts";
|
|
13
13
|
export { type IndexedRequest, PROJECTION_ADMITS, type PublicationRequest, REQUEST_DIMENSIONS, type RequestDimension, admits, checkRequest, indexedRequest, } from "./request.ts";
|
|
14
|
-
export { CURRENT_PIN, REVIEW_EXTENSION, type ReviewRecord, type ReviewStatus, bindReviewPins, knowledgeReport, readReviewRecord, reviewSources, reviewStatus, } from "./review.ts";
|
|
14
|
+
export { CURRENT_PIN, PIN_KINDS, type PinKind, REVIEW_EXTENSION, type ReviewRecord, type ReviewStatus, bindReviewPins, knowledgeReport, pinHash, readReviewRecord, reviewSources, reviewStatus, } from "./review.ts";
|
|
15
15
|
export { YamlEmitError, type YamlValue, emitYaml } from "./yaml.ts";
|
|
16
16
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,EAAE,KAAK,KAAK,EAAE,KAAK,YAAY,EAAE,KAAK,WAAW,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACxF,OAAO,EACL,KAAK,eAAe,EACpB,KAAK,iBAAiB,EACtB,eAAe,EACf,mBAAmB,EACnB,KAAK,eAAe,EACpB,KAAK,WAAW,EAChB,cAAc,EACd,gBAAgB,EAChB,UAAU,EACV,aAAa,EACb,eAAe,GAChB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,SAAS,EACT,YAAY,EACZ,KAAK,QAAQ,EACb,KAAK,aAAa,EAClB,KAAK,WAAW,EAChB,KAAK,OAAO,EACZ,QAAQ,GACT,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,iBAAiB,EACjB,KAAK,SAAS,EACd,KAAK,eAAe,EACpB,KAAK,cAAc,EACnB,KAAK,UAAU,EACf,KAAK,QAAQ,EACb,eAAe,EACf,OAAO,GACR,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,KAAK,gBAAgB,EACrB,KAAK,cAAc,EACnB,KAAK,aAAa,EAClB,KAAK,iBAAiB,EACtB,eAAe,EACf,KAAK,aAAa,EAClB,OAAO,EACP,cAAc,GACf,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,KAAK,SAAS,EACd,KAAK,aAAa,EAClB,eAAe,EACf,WAAW,EACX,cAAc,EACd,aAAa,EACb,YAAY,GACb,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,KAAK,cAAc,EACnB,iBAAiB,EACjB,KAAK,kBAAkB,EACvB,kBAAkB,EAClB,KAAK,gBAAgB,EACrB,MAAM,EACN,YAAY,EACZ,cAAc,GACf,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,WAAW,EACX,gBAAgB,EAChB,KAAK,YAAY,EACjB,KAAK,YAAY,EACjB,cAAc,EACd,eAAe,EACf,gBAAgB,EAChB,aAAa,EACb,YAAY,GACb,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,aAAa,EAAE,KAAK,SAAS,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,EAAE,KAAK,KAAK,EAAE,KAAK,YAAY,EAAE,KAAK,WAAW,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACxF,OAAO,EACL,KAAK,eAAe,EACpB,KAAK,iBAAiB,EACtB,eAAe,EACf,mBAAmB,EACnB,KAAK,eAAe,EACpB,KAAK,WAAW,EAChB,cAAc,EACd,gBAAgB,EAChB,UAAU,EACV,aAAa,EACb,eAAe,GAChB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,SAAS,EACT,YAAY,EACZ,KAAK,QAAQ,EACb,KAAK,aAAa,EAClB,KAAK,WAAW,EAChB,KAAK,OAAO,EACZ,QAAQ,GACT,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,iBAAiB,EACjB,KAAK,SAAS,EACd,KAAK,eAAe,EACpB,KAAK,cAAc,EACnB,KAAK,UAAU,EACf,KAAK,QAAQ,EACb,eAAe,EACf,cAAc,EACd,OAAO,GACR,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,KAAK,gBAAgB,EACrB,KAAK,cAAc,EACnB,KAAK,aAAa,EAClB,KAAK,iBAAiB,EACtB,eAAe,EACf,KAAK,aAAa,EAClB,OAAO,EACP,cAAc,GACf,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,KAAK,SAAS,EACd,KAAK,aAAa,EAClB,eAAe,EACf,WAAW,EACX,cAAc,EACd,aAAa,EACb,YAAY,GACb,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,KAAK,cAAc,EACnB,iBAAiB,EACjB,KAAK,kBAAkB,EACvB,kBAAkB,EAClB,KAAK,gBAAgB,EACrB,MAAM,EACN,YAAY,EACZ,cAAc,GACf,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,WAAW,EACX,SAAS,EACT,KAAK,OAAO,EACZ,gBAAgB,EAChB,KAAK,YAAY,EACjB,KAAK,YAAY,EACjB,cAAc,EACd,eAAe,EACf,OAAO,EACP,gBAAgB,EAChB,aAAa,EACb,YAAY,GACb,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,aAAa,EAAE,KAAK,SAAS,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -7,10 +7,10 @@ export { bodyLineOffset } from "./body.js";
|
|
|
7
7
|
export { toChunks } from "./chunks.js";
|
|
8
8
|
export { PUBLICATION_KEY, PUBLICATION_PROFILE, checkGenerated, generateDocument, markerLine, marksetSource, publicationMeta, } from "./generate.js";
|
|
9
9
|
export { HELP_FILE, HELP_PROFILE, helpFile, } from "./help.js";
|
|
10
|
-
export { EXCLUSION_REASONS, exclusionReason, project, } from "./project.js";
|
|
10
|
+
export { EXCLUSION_REASONS, exclusionReason, plannedSources, project, } from "./project.js";
|
|
11
11
|
export { REFUSAL_REASONS, publish, renderDocument, } from "./publish.js";
|
|
12
12
|
export { checkReferences, checkTitles, findReferences, resolveTarget, titlePattern, } from "./references.js";
|
|
13
13
|
export { PROJECTION_ADMITS, REQUEST_DIMENSIONS, admits, checkRequest, indexedRequest, } from "./request.js";
|
|
14
|
-
export { CURRENT_PIN, REVIEW_EXTENSION, bindReviewPins, knowledgeReport, readReviewRecord, reviewSources, reviewStatus, } from "./review.js";
|
|
14
|
+
export { CURRENT_PIN, PIN_KINDS, REVIEW_EXTENSION, bindReviewPins, knowledgeReport, pinHash, readReviewRecord, reviewSources, reviewStatus, } from "./review.js";
|
|
15
15
|
export { YamlEmitError, emitYaml } from "./yaml.js";
|
|
16
16
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,EAAmD,QAAQ,EAAE,MAAM,aAAa,CAAC;AACxF,OAAO,EAGL,eAAe,EACf,mBAAmB,EAGnB,cAAc,EACd,gBAAgB,EAChB,UAAU,EACV,aAAa,EACb,eAAe,GAChB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,SAAS,EACT,YAAY,EAKZ,QAAQ,GACT,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,iBAAiB,EAMjB,eAAe,EACf,OAAO,GACR,MAAM,cAAc,CAAC;AACtB,OAAO,EAKL,eAAe,EAEf,OAAO,EACP,cAAc,GACf,MAAM,cAAc,CAAC;AACtB,OAAO,EAGL,eAAe,EACf,WAAW,EACX,cAAc,EACd,aAAa,EACb,YAAY,GACb,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAEL,iBAAiB,EAEjB,kBAAkB,EAElB,MAAM,EACN,YAAY,EACZ,cAAc,GACf,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,WAAW,EACX,gBAAgB,EAGhB,cAAc,EACd,eAAe,EACf,gBAAgB,EAChB,aAAa,EACb,YAAY,GACb,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,aAAa,EAAkB,QAAQ,EAAE,MAAM,WAAW,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,EAAmD,QAAQ,EAAE,MAAM,aAAa,CAAC;AACxF,OAAO,EAGL,eAAe,EACf,mBAAmB,EAGnB,cAAc,EACd,gBAAgB,EAChB,UAAU,EACV,aAAa,EACb,eAAe,GAChB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,SAAS,EACT,YAAY,EAKZ,QAAQ,GACT,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,iBAAiB,EAMjB,eAAe,EACf,cAAc,EACd,OAAO,GACR,MAAM,cAAc,CAAC;AACtB,OAAO,EAKL,eAAe,EAEf,OAAO,EACP,cAAc,GACf,MAAM,cAAc,CAAC;AACtB,OAAO,EAGL,eAAe,EACf,WAAW,EACX,cAAc,EACd,aAAa,EACb,YAAY,GACb,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAEL,iBAAiB,EAEjB,kBAAkB,EAElB,MAAM,EACN,YAAY,EACZ,cAAc,GACf,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,WAAW,EACX,SAAS,EAET,gBAAgB,EAGhB,cAAc,EACd,eAAe,EACf,OAAO,EACP,gBAAgB,EAChB,aAAa,EACb,YAAY,GACb,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,aAAa,EAAkB,QAAQ,EAAE,MAAM,WAAW,CAAC"}
|
package/dist/project.d.ts
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
* not-requested the request names ids and this is not one of them
|
|
9
9
|
* not-knowledge only knowledge is ever published as a document
|
|
10
10
|
* draft, retired Core §7: neither is current publication
|
|
11
|
+
* planned it explains a record whose delivery is planned: work that does not exist yet (ADR 0017)
|
|
11
12
|
* visibility outside what the projection admits
|
|
12
13
|
* audience the request's audience is not one the knowledge is written for
|
|
13
14
|
* availability-missing no availability block: fails closed (Core §4, §7)
|
|
@@ -24,7 +25,7 @@
|
|
|
24
25
|
import { type Artifact, type Diagnostic, type Graph, type Registries } from "@intentset/core";
|
|
25
26
|
import { type PublicationRequest } from "./request.ts";
|
|
26
27
|
import { type ReviewStatus } from "./review.ts";
|
|
27
|
-
export declare const EXCLUSION_REASONS: readonly ["not-requested", "not-knowledge", "draft", "retired", "visibility", "audience", "availability-missing", "product", "release", "role", "edition", "flag", "needs-review"];
|
|
28
|
+
export declare const EXCLUSION_REASONS: readonly ["not-requested", "not-knowledge", "draft", "retired", "planned", "visibility", "audience", "availability-missing", "product", "release", "role", "edition", "flag", "needs-review"];
|
|
28
29
|
export type ExclusionReason = (typeof EXCLUSION_REASONS)[number];
|
|
29
30
|
/** The snapshot a publication is made from (Core §7): the commit, or null when none could be read, and the graph hash. */
|
|
30
31
|
export interface Snapshot {
|
|
@@ -51,6 +52,11 @@ export interface Projection {
|
|
|
51
52
|
}
|
|
52
53
|
/** Core §9: select what this request may publish, before any text is sent to a renderer. */
|
|
53
54
|
export declare function project(graph: Graph, registries: Registries, request: PublicationRequest, options: ProjectOptions): Projection;
|
|
54
|
-
/**
|
|
55
|
-
|
|
55
|
+
/**
|
|
56
|
+
* The first check an artifact fails for this request, or null when it is eligible. Requested-ness is the caller's.
|
|
57
|
+
* Without the graph, the explained records cannot be read, so `planned` is not checked.
|
|
58
|
+
*/
|
|
59
|
+
export declare function exclusionReason(artifact: Artifact, request: PublicationRequest, review: (artifact: Artifact) => ReviewStatus, graph?: Graph): Exclude<ExclusionReason, "not-requested"> | null;
|
|
60
|
+
/** The records a knowledge record explains whose delivery is planned (ADR 0017), sorted. */
|
|
61
|
+
export declare function plannedSources(graph: Graph, artifact: Artifact): string[];
|
|
56
62
|
//# sourceMappingURL=project.d.ts.map
|
package/dist/project.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"project.d.ts","sourceRoot":"","sources":["../src/project.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"project.d.ts","sourceRoot":"","sources":["../src/project.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,OAAO,EAAE,KAAK,QAAQ,EAAE,KAAK,UAAU,EAAE,KAAK,KAAK,EAAE,KAAK,UAAU,EAAa,MAAM,iBAAiB,CAAC;AAEzG,OAAO,EAAE,KAAK,kBAAkB,EAAwB,MAAM,cAAc,CAAC;AAC7E,OAAO,EAAE,KAAK,YAAY,EAAgB,MAAM,aAAa,CAAC;AAE9D,eAAO,MAAM,iBAAiB,YAC5B,eAAe,EACf,eAAe,EACf,OAAO,EACP,SAAS,EACT,SAAS,EACT,YAAY,EACZ,UAAU,EACV,sBAAsB,EACtB,SAAS,EACT,SAAS,EACT,MAAM,EACN,SAAS,EACT,MAAM,EACN,cAAc,CACN,CAAC;AACX,MAAM,MAAM,eAAe,GAAG,CAAC,OAAO,iBAAiB,CAAC,CAAC,MAAM,CAAC,CAAC;AAEjE,0HAA0H;AAC1H,MAAM,WAAW,QAAQ;IACvB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,QAAQ,CAAC;IACnB,mGAAmG;IACnG,OAAO,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;CAC7C;AAED,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,eAAe,CAAC;CACzB;AAED,MAAM,WAAW,UAAU;IACzB,wCAAwC;IACxC,QAAQ,EAAE,QAAQ,EAAE,CAAC;IACrB,0HAA0H;IAC1H,QAAQ,EAAE,SAAS,EAAE,CAAC;IACtB,WAAW,EAAE,UAAU,EAAE,CAAC;IAC1B,iEAAiE;IACjE,OAAO,EAAE,kBAAkB,GAAG,IAAI,CAAC;CACpC;AAID,4FAA4F;AAC5F,wBAAgB,OAAO,CACrB,KAAK,EAAE,KAAK,EACZ,UAAU,EAAE,UAAU,EACtB,OAAO,EAAE,kBAAkB,EAC3B,OAAO,EAAE,cAAc,GACtB,UAAU,CAqDZ;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,kBAAkB,EAC3B,MAAM,EAAE,CAAC,QAAQ,EAAE,QAAQ,KAAK,YAAY,EAC5C,KAAK,CAAC,EAAE,KAAK,GACZ,OAAO,CAAC,eAAe,EAAE,eAAe,CAAC,GAAG,IAAI,CAkBlD;AAED,4FAA4F;AAC5F,wBAAgB,cAAc,CAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,GAAG,MAAM,EAAE,CAIzE"}
|
package/dist/project.js
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
* not-requested the request names ids and this is not one of them
|
|
9
9
|
* not-knowledge only knowledge is ever published as a document
|
|
10
10
|
* draft, retired Core §7: neither is current publication
|
|
11
|
+
* planned it explains a record whose delivery is planned: work that does not exist yet (ADR 0017)
|
|
11
12
|
* visibility outside what the projection admits
|
|
12
13
|
* audience the request's audience is not one the knowledge is written for
|
|
13
14
|
* availability-missing no availability block: fails closed (Core §4, §7)
|
|
@@ -30,6 +31,7 @@ export const EXCLUSION_REASONS = [
|
|
|
30
31
|
"not-knowledge",
|
|
31
32
|
"draft",
|
|
32
33
|
"retired",
|
|
34
|
+
"planned",
|
|
33
35
|
"visibility",
|
|
34
36
|
"audience",
|
|
35
37
|
"availability-missing",
|
|
@@ -73,7 +75,7 @@ export function project(graph, registries, request, options) {
|
|
|
73
75
|
const reasons = new Map();
|
|
74
76
|
for (const id of [...graph.artifacts.keys()].sort(compareStrings)) {
|
|
75
77
|
const artifact = graph.artifacts.get(id);
|
|
76
|
-
const reason = requested !== null && !requested.has(id) ? "not-requested" : exclusionReason(artifact, req, review);
|
|
78
|
+
const reason = requested !== null && !requested.has(id) ? "not-requested" : exclusionReason(artifact, req, review, graph);
|
|
77
79
|
if (reason === null)
|
|
78
80
|
eligible.push(artifact);
|
|
79
81
|
else {
|
|
@@ -86,12 +88,15 @@ export function project(graph, registries, request, options) {
|
|
|
86
88
|
const artifact = graph.artifacts.get(id);
|
|
87
89
|
if (artifact !== undefined && reason === undefined)
|
|
88
90
|
continue;
|
|
89
|
-
diagnostics.push(refusal(id, artifact, reason ?? null, req, artifact === undefined ? null : review(artifact)));
|
|
91
|
+
diagnostics.push(refusal(id, artifact, reason ?? null, req, artifact === undefined ? null : review(artifact), graph));
|
|
90
92
|
}
|
|
91
93
|
return { eligible, excluded, diagnostics, request: req };
|
|
92
94
|
}
|
|
93
|
-
/**
|
|
94
|
-
|
|
95
|
+
/**
|
|
96
|
+
* The first check an artifact fails for this request, or null when it is eligible. Requested-ness is the caller's.
|
|
97
|
+
* Without the graph, the explained records cannot be read, so `planned` is not checked.
|
|
98
|
+
*/
|
|
99
|
+
export function exclusionReason(artifact, request, review, graph) {
|
|
95
100
|
const { meta } = artifact;
|
|
96
101
|
if (meta.type !== "knowledge")
|
|
97
102
|
return "not-knowledge";
|
|
@@ -101,6 +106,8 @@ export function exclusionReason(artifact, request, review) {
|
|
|
101
106
|
return "retired";
|
|
102
107
|
if (!PUBLISHABLE_STATUSES.has(meta.status))
|
|
103
108
|
return "draft";
|
|
109
|
+
if (graph !== undefined && plannedSources(graph, artifact).length > 0)
|
|
110
|
+
return "planned";
|
|
104
111
|
if (!admits(request, meta.visibility))
|
|
105
112
|
return "visibility";
|
|
106
113
|
if (!meta.audiences.includes(request.audience))
|
|
@@ -122,8 +129,14 @@ export function exclusionReason(artifact, request, review) {
|
|
|
122
129
|
return "needs-review";
|
|
123
130
|
return null;
|
|
124
131
|
}
|
|
132
|
+
/** The records a knowledge record explains whose delivery is planned (ADR 0017), sorted. */
|
|
133
|
+
export function plannedSources(graph, artifact) {
|
|
134
|
+
return (artifact.meta.links.explains ?? [])
|
|
135
|
+
.filter((id) => graph.artifacts.get(id)?.meta.delivery === "planned")
|
|
136
|
+
.sort(compareStrings);
|
|
137
|
+
}
|
|
125
138
|
/** CORE008 for one requested ID. */
|
|
126
|
-
function refusal(id, artifact, reason, request, review) {
|
|
139
|
+
function refusal(id, artifact, reason, request, review, graph) {
|
|
127
140
|
if (artifact === undefined || !admits(request, artifact.meta.visibility)) {
|
|
128
141
|
return publicationDiagnostic({
|
|
129
142
|
code: "CORE008",
|
|
@@ -149,6 +162,10 @@ function refusal(id, artifact, reason, request, review) {
|
|
|
149
162
|
return refuse("/intentset/status", `its status is ${meta.status}, and drafts are never published`, "Review the knowledge and set its status to approved or later before publishing it (Core §7, §9).");
|
|
150
163
|
case "retired":
|
|
151
164
|
return refuse("/intentset/status", "it is retired, which is excluded from current publication", "Publish the successor named in replacedBy instead (Core §7).");
|
|
165
|
+
case "planned": {
|
|
166
|
+
const planned = plannedSources(graph, artifact);
|
|
167
|
+
return refuse("/intentset/links/explains", `it explains ${planned.join(", ")}, whose work is planned, and planned work is not current publication`, "Publish it once the work exists and the records say `delivery: built`, reviewing the knowledge against them again (Core §7, ADR 0017).");
|
|
168
|
+
}
|
|
152
169
|
case "audience":
|
|
153
170
|
return refuse("/intentset/audiences", `it is not written for the ${request.audience} audience`, "Request an audience the knowledge lists, or add this one after reviewing the text for it (Core §9).");
|
|
154
171
|
case "availability-missing":
|
package/dist/project.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"project.js","sourceRoot":"","sources":["../src/project.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"project.js","sourceRoot":"","sources":["../src/project.ts"],"names":[],"mappings":"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"}
|
package/dist/review.d.ts
CHANGED
|
@@ -18,17 +18,31 @@
|
|
|
18
18
|
* rules that govern each explained behavior: a rule changing under a behavior
|
|
19
19
|
* changes what the behavior promises, which is catalog case P04.
|
|
20
20
|
*
|
|
21
|
+
* A pin is one of two kinds, named by the record's `hash` (publication §3,
|
|
22
|
+
* ADR 0018). Without `hash`, a pin is the source's `sourceHash`, the bytes of
|
|
23
|
+
* the whole file, which every review made before 0.13.0 holds. With
|
|
24
|
+
* `hash: content-v1`, it is the source's `contentHash`, which leaves out the
|
|
25
|
+
* lifecycle and review fields, so approving or implementing a source, or
|
|
26
|
+
* marking its delivery, leaves the knowledge current. Any other `hash` is a
|
|
27
|
+
* kind this version does not know: every pin reads as changed.
|
|
28
|
+
*
|
|
21
29
|
* A pin of the literal `@current` is a fixture placeholder: `bindReviewPins`
|
|
22
|
-
* replaces it with the source's hash
|
|
23
|
-
* case can say "reviewed against what is there now"
|
|
24
|
-
* hash. Unbound, it never equals a hash, so it reads as
|
|
30
|
+
* replaces it with the source's hash of the record's kind in the snapshot
|
|
31
|
+
* being checked, so a case can say "reviewed against what is there now"
|
|
32
|
+
* without computing a hash. Unbound, it never equals a hash, so it reads as
|
|
33
|
+
* changed.
|
|
25
34
|
*/
|
|
26
35
|
import { type Artifact, type Graph, type KnowledgeReportSection } from "@intentset/core";
|
|
27
36
|
export declare const REVIEW_EXTENSION = "intentset.org/review";
|
|
28
37
|
export declare const CURRENT_PIN = "@current";
|
|
38
|
+
/** The pin kinds a review record can name in `hash` (publication §3). Absent means `source`, the whole file. */
|
|
39
|
+
export declare const PIN_KINDS: readonly ["content-v1"];
|
|
40
|
+
export type PinKind = (typeof PIN_KINDS)[number];
|
|
29
41
|
export interface ReviewRecord {
|
|
30
42
|
/** Source ID -> the source hash it was reviewed against. Entries that are not strings are dropped. */
|
|
31
43
|
sources: Record<string, string>;
|
|
44
|
+
/** What the pins hash: absent for the whole file, `content-v1` for the content hash, anything else unknown. */
|
|
45
|
+
hash?: string;
|
|
32
46
|
snapshot?: string;
|
|
33
47
|
}
|
|
34
48
|
export interface ReviewStatus {
|
|
@@ -37,6 +51,8 @@ export interface ReviewStatus {
|
|
|
37
51
|
changed: string[];
|
|
38
52
|
/** Sources the review record does not pin. */
|
|
39
53
|
missing: string[];
|
|
54
|
+
/** The record's `hash` when this version does not know it, so no pin can match; null otherwise. */
|
|
55
|
+
unknownHash: string | null;
|
|
40
56
|
/** `reviewedBy`, or null when the knowledge names no reviewer. */
|
|
41
57
|
reviewer: string | null;
|
|
42
58
|
/** `reviewedAt`, or null when absent. */
|
|
@@ -48,6 +64,8 @@ export declare function reviewSources(graph: Graph, artifact: Artifact): string[
|
|
|
48
64
|
export declare function readReviewRecord(artifact: Artifact): ReviewRecord | null;
|
|
49
65
|
/** Core §9: whether the knowledge is current against the sources it was reviewed against. */
|
|
50
66
|
export declare function reviewStatus(graph: Graph, artifact: Artifact): ReviewStatus;
|
|
67
|
+
/** The hash a pin of this kind holds for a source, or null for a kind this version does not know. */
|
|
68
|
+
export declare function pinHash(kind: string | undefined): ((source: Artifact) => string) | null;
|
|
51
69
|
/**
|
|
52
70
|
* Bind every `@current` pin to the pinned source's hash in this graph, for
|
|
53
71
|
* fixtures. Returns a new graph; the given one is not modified, and nothing
|
package/dist/review.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"review.d.ts","sourceRoot":"","sources":["../src/review.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"review.d.ts","sourceRoot":"","sources":["../src/review.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,OAAO,EAAE,KAAK,QAAQ,EAAE,KAAK,KAAK,EAAa,KAAK,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AAGpG,eAAO,MAAM,gBAAgB,yBAAyB,CAAC;AACvD,eAAO,MAAM,WAAW,aAAa,CAAC;AACtC,gHAAgH;AAChH,eAAO,MAAM,SAAS,YAAI,YAAY,CAAU,CAAC;AACjD,MAAM,MAAM,OAAO,GAAG,CAAC,OAAO,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC;AAEjD,MAAM,WAAW,YAAY;IAC3B,sGAAsG;IACtG,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,+GAA+G;IAC/G,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,SAAS,GAAG,cAAc,CAAC;IACnC,2FAA2F;IAC3F,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,8CAA8C;IAC9C,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,mGAAmG;IACnG,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,kEAAkE;IAClE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,yCAAyC;IACzC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,oHAAoH;AACpH,wBAAgB,aAAa,CAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,GAAG,MAAM,EAAE,CAQxE;AAED,iHAAiH;AACjH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,QAAQ,GAAG,YAAY,GAAG,IAAI,CAYxE;AAED,6FAA6F;AAC7F,wBAAgB,YAAY,CAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,GAAG,YAAY,CAgB3E;AAED,qGAAqG;AACrG,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,CAAC,CAAC,MAAM,EAAE,QAAQ,KAAK,MAAM,CAAC,GAAG,IAAI,CAIvF;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,KAAK,GAAG,KAAK,CAkBlD;AAUD;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,KAAK,GAAG,sBAAsB,CAoBpE"}
|
package/dist/review.js
CHANGED
|
@@ -18,15 +18,26 @@
|
|
|
18
18
|
* rules that govern each explained behavior: a rule changing under a behavior
|
|
19
19
|
* changes what the behavior promises, which is catalog case P04.
|
|
20
20
|
*
|
|
21
|
+
* A pin is one of two kinds, named by the record's `hash` (publication §3,
|
|
22
|
+
* ADR 0018). Without `hash`, a pin is the source's `sourceHash`, the bytes of
|
|
23
|
+
* the whole file, which every review made before 0.13.0 holds. With
|
|
24
|
+
* `hash: content-v1`, it is the source's `contentHash`, which leaves out the
|
|
25
|
+
* lifecycle and review fields, so approving or implementing a source, or
|
|
26
|
+
* marking its delivery, leaves the knowledge current. Any other `hash` is a
|
|
27
|
+
* kind this version does not know: every pin reads as changed.
|
|
28
|
+
*
|
|
21
29
|
* A pin of the literal `@current` is a fixture placeholder: `bindReviewPins`
|
|
22
|
-
* replaces it with the source's hash
|
|
23
|
-
* case can say "reviewed against what is there now"
|
|
24
|
-
* hash. Unbound, it never equals a hash, so it reads as
|
|
30
|
+
* replaces it with the source's hash of the record's kind in the snapshot
|
|
31
|
+
* being checked, so a case can say "reviewed against what is there now"
|
|
32
|
+
* without computing a hash. Unbound, it never equals a hash, so it reads as
|
|
33
|
+
* changed.
|
|
25
34
|
*/
|
|
26
35
|
import { graphHash } from "@intentset/core";
|
|
27
36
|
import { compareStrings, sortedUnique } from "./diagnostic.js";
|
|
28
37
|
export const REVIEW_EXTENSION = "intentset.org/review";
|
|
29
38
|
export const CURRENT_PIN = "@current";
|
|
39
|
+
/** The pin kinds a review record can name in `hash` (publication §3). Absent means `source`, the whole file. */
|
|
40
|
+
export const PIN_KINDS = ["content-v1"];
|
|
30
41
|
/** The sources a review must pin: everything explained, and the rules governing each explained behavior. Sorted. */
|
|
31
42
|
export function reviewSources(graph, artifact) {
|
|
32
43
|
const ids = [];
|
|
@@ -50,6 +61,8 @@ export function readReviewRecord(artifact) {
|
|
|
50
61
|
sources[id] = pin;
|
|
51
62
|
}
|
|
52
63
|
const record = { sources };
|
|
64
|
+
if (value.hash !== undefined)
|
|
65
|
+
record.hash = typeof value.hash === "string" ? value.hash : JSON.stringify(value.hash);
|
|
53
66
|
if (typeof value.snapshot === "string")
|
|
54
67
|
record.snapshot = value.snapshot;
|
|
55
68
|
return record;
|
|
@@ -57,19 +70,30 @@ export function readReviewRecord(artifact) {
|
|
|
57
70
|
/** Core §9: whether the knowledge is current against the sources it was reviewed against. */
|
|
58
71
|
export function reviewStatus(graph, artifact) {
|
|
59
72
|
const record = readReviewRecord(artifact);
|
|
73
|
+
const hashOf = pinHash(record?.hash);
|
|
74
|
+
const unknownHash = record?.hash !== undefined && hashOf === null ? record.hash : null;
|
|
60
75
|
const changed = [];
|
|
61
76
|
const missing = [];
|
|
62
77
|
for (const id of reviewSources(graph, artifact)) {
|
|
63
78
|
const pin = record?.sources[id];
|
|
79
|
+
const source = graph.artifacts.get(id);
|
|
64
80
|
if (pin === undefined)
|
|
65
81
|
missing.push(id);
|
|
66
|
-
else if (
|
|
82
|
+
else if (source === undefined || hashOf === null || hashOf(source) !== pin)
|
|
67
83
|
changed.push(id);
|
|
68
84
|
}
|
|
69
85
|
const reviewer = nonEmpty(artifact.meta.reviewedBy);
|
|
70
86
|
const reviewedAt = nonEmpty(artifact.meta.reviewedAt);
|
|
71
87
|
const current = changed.length === 0 && missing.length === 0 && reviewer !== null && reviewedAt !== null;
|
|
72
|
-
return { status: current ? "current" : "needs-review", changed, missing, reviewer, reviewedAt };
|
|
88
|
+
return { status: current ? "current" : "needs-review", changed, missing, unknownHash, reviewer, reviewedAt };
|
|
89
|
+
}
|
|
90
|
+
/** The hash a pin of this kind holds for a source, or null for a kind this version does not know. */
|
|
91
|
+
export function pinHash(kind) {
|
|
92
|
+
if (kind === undefined)
|
|
93
|
+
return (source) => source.sourceHash;
|
|
94
|
+
if (kind === "content-v1")
|
|
95
|
+
return (source) => source.contentHash;
|
|
96
|
+
return null;
|
|
73
97
|
}
|
|
74
98
|
/**
|
|
75
99
|
* Bind every `@current` pin to the pinned source's hash in this graph, for
|
|
@@ -85,9 +109,11 @@ export function bindReviewPins(graph) {
|
|
|
85
109
|
artifacts.set(id, artifact);
|
|
86
110
|
continue;
|
|
87
111
|
}
|
|
112
|
+
const hashOf = pinHash(typeof value.hash === "string" || value.hash === undefined ? value.hash : "");
|
|
88
113
|
const sources = {};
|
|
89
114
|
for (const [source, pin] of Object.entries(value.sources)) {
|
|
90
|
-
|
|
115
|
+
const found = graph.artifacts.get(source);
|
|
116
|
+
sources[source] = pin === CURRENT_PIN && found !== undefined && hashOf !== null ? hashOf(found) : pin;
|
|
91
117
|
}
|
|
92
118
|
const extensions = { ...artifact.meta.extensions, [REVIEW_EXTENSION]: { ...value, sources } };
|
|
93
119
|
artifacts.set(id, { ...artifact, meta: { ...artifact.meta, extensions } });
|
package/dist/review.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"review.js","sourceRoot":"","sources":["../src/review.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"review.js","sourceRoot":"","sources":["../src/review.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@intentset/publisher",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.0",
|
|
4
4
|
"description": "Audience and release projection of reviewed knowledge into Markset documents with provenance.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"intentset",
|
|
@@ -35,8 +35,8 @@
|
|
|
35
35
|
}
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@intentset/core": "^0.
|
|
39
|
-
"@intentset/markset-adapter": "^0.
|
|
38
|
+
"@intentset/core": "^0.13.0",
|
|
39
|
+
"@intentset/markset-adapter": "^0.13.0",
|
|
40
40
|
"@markset-lang/parser": "0.4.1",
|
|
41
41
|
"@markset-lang/render-html": "0.4.1"
|
|
42
42
|
}
|
package/src/index.ts
CHANGED
|
@@ -35,6 +35,7 @@ export {
|
|
|
35
35
|
type Projection,
|
|
36
36
|
type Snapshot,
|
|
37
37
|
exclusionReason,
|
|
38
|
+
plannedSources,
|
|
38
39
|
project,
|
|
39
40
|
} from "./project.ts";
|
|
40
41
|
export {
|
|
@@ -68,11 +69,14 @@ export {
|
|
|
68
69
|
} from "./request.ts";
|
|
69
70
|
export {
|
|
70
71
|
CURRENT_PIN,
|
|
72
|
+
PIN_KINDS,
|
|
73
|
+
type PinKind,
|
|
71
74
|
REVIEW_EXTENSION,
|
|
72
75
|
type ReviewRecord,
|
|
73
76
|
type ReviewStatus,
|
|
74
77
|
bindReviewPins,
|
|
75
78
|
knowledgeReport,
|
|
79
|
+
pinHash,
|
|
76
80
|
readReviewRecord,
|
|
77
81
|
reviewSources,
|
|
78
82
|
reviewStatus,
|
package/src/project.ts
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
* not-requested the request names ids and this is not one of them
|
|
9
9
|
* not-knowledge only knowledge is ever published as a document
|
|
10
10
|
* draft, retired Core §7: neither is current publication
|
|
11
|
+
* planned it explains a record whose delivery is planned: work that does not exist yet (ADR 0017)
|
|
11
12
|
* visibility outside what the projection admits
|
|
12
13
|
* audience the request's audience is not one the knowledge is written for
|
|
13
14
|
* availability-missing no availability block: fails closed (Core §4, §7)
|
|
@@ -31,6 +32,7 @@ export const EXCLUSION_REASONS = [
|
|
|
31
32
|
"not-knowledge",
|
|
32
33
|
"draft",
|
|
33
34
|
"retired",
|
|
35
|
+
"planned",
|
|
34
36
|
"visibility",
|
|
35
37
|
"audience",
|
|
36
38
|
"availability-missing",
|
|
@@ -113,7 +115,8 @@ export function project(
|
|
|
113
115
|
const reasons = new Map<string, ExclusionReason>();
|
|
114
116
|
for (const id of [...graph.artifacts.keys()].sort(compareStrings)) {
|
|
115
117
|
const artifact = graph.artifacts.get(id) as Artifact;
|
|
116
|
-
const reason =
|
|
118
|
+
const reason =
|
|
119
|
+
requested !== null && !requested.has(id) ? "not-requested" : exclusionReason(artifact, req, review, graph);
|
|
117
120
|
if (reason === null) eligible.push(artifact);
|
|
118
121
|
else {
|
|
119
122
|
excluded.push({ id, reason });
|
|
@@ -125,22 +128,29 @@ export function project(
|
|
|
125
128
|
const reason = reasons.get(id);
|
|
126
129
|
const artifact = graph.artifacts.get(id);
|
|
127
130
|
if (artifact !== undefined && reason === undefined) continue;
|
|
128
|
-
diagnostics.push(
|
|
131
|
+
diagnostics.push(
|
|
132
|
+
refusal(id, artifact, reason ?? null, req, artifact === undefined ? null : review(artifact), graph),
|
|
133
|
+
);
|
|
129
134
|
}
|
|
130
135
|
return { eligible, excluded, diagnostics, request: req };
|
|
131
136
|
}
|
|
132
137
|
|
|
133
|
-
/**
|
|
138
|
+
/**
|
|
139
|
+
* The first check an artifact fails for this request, or null when it is eligible. Requested-ness is the caller's.
|
|
140
|
+
* Without the graph, the explained records cannot be read, so `planned` is not checked.
|
|
141
|
+
*/
|
|
134
142
|
export function exclusionReason(
|
|
135
143
|
artifact: Artifact,
|
|
136
144
|
request: PublicationRequest,
|
|
137
145
|
review: (artifact: Artifact) => ReviewStatus,
|
|
146
|
+
graph?: Graph,
|
|
138
147
|
): Exclude<ExclusionReason, "not-requested"> | null {
|
|
139
148
|
const { meta } = artifact;
|
|
140
149
|
if (meta.type !== "knowledge") return "not-knowledge";
|
|
141
150
|
if (meta.status === "draft") return "draft";
|
|
142
151
|
if (meta.status === "retired") return "retired";
|
|
143
152
|
if (!PUBLISHABLE_STATUSES.has(meta.status)) return "draft";
|
|
153
|
+
if (graph !== undefined && plannedSources(graph, artifact).length > 0) return "planned";
|
|
144
154
|
if (!admits(request, meta.visibility)) return "visibility";
|
|
145
155
|
if (!meta.audiences.includes(request.audience)) return "audience";
|
|
146
156
|
const availability = meta.availability;
|
|
@@ -154,6 +164,13 @@ export function exclusionReason(
|
|
|
154
164
|
return null;
|
|
155
165
|
}
|
|
156
166
|
|
|
167
|
+
/** The records a knowledge record explains whose delivery is planned (ADR 0017), sorted. */
|
|
168
|
+
export function plannedSources(graph: Graph, artifact: Artifact): string[] {
|
|
169
|
+
return (artifact.meta.links.explains ?? [])
|
|
170
|
+
.filter((id) => graph.artifacts.get(id)?.meta.delivery === "planned")
|
|
171
|
+
.sort(compareStrings);
|
|
172
|
+
}
|
|
173
|
+
|
|
157
174
|
/** CORE008 for one requested ID. */
|
|
158
175
|
function refusal(
|
|
159
176
|
id: string,
|
|
@@ -161,6 +178,7 @@ function refusal(
|
|
|
161
178
|
reason: ExclusionReason | null,
|
|
162
179
|
request: PublicationRequest,
|
|
163
180
|
review: ReviewStatus | null,
|
|
181
|
+
graph: Graph,
|
|
164
182
|
): Diagnostic {
|
|
165
183
|
if (artifact === undefined || !admits(request, artifact.meta.visibility)) {
|
|
166
184
|
return publicationDiagnostic({
|
|
@@ -201,6 +219,14 @@ function refusal(
|
|
|
201
219
|
"it is retired, which is excluded from current publication",
|
|
202
220
|
"Publish the successor named in replacedBy instead (Core §7).",
|
|
203
221
|
);
|
|
222
|
+
case "planned": {
|
|
223
|
+
const planned = plannedSources(graph, artifact);
|
|
224
|
+
return refuse(
|
|
225
|
+
"/intentset/links/explains",
|
|
226
|
+
`it explains ${planned.join(", ")}, whose work is planned, and planned work is not current publication`,
|
|
227
|
+
"Publish it once the work exists and the records say `delivery: built`, reviewing the knowledge against them again (Core §7, ADR 0017).",
|
|
228
|
+
);
|
|
229
|
+
}
|
|
204
230
|
case "audience":
|
|
205
231
|
return refuse(
|
|
206
232
|
"/intentset/audiences",
|
package/src/review.ts
CHANGED
|
@@ -18,20 +18,34 @@
|
|
|
18
18
|
* rules that govern each explained behavior: a rule changing under a behavior
|
|
19
19
|
* changes what the behavior promises, which is catalog case P04.
|
|
20
20
|
*
|
|
21
|
+
* A pin is one of two kinds, named by the record's `hash` (publication §3,
|
|
22
|
+
* ADR 0018). Without `hash`, a pin is the source's `sourceHash`, the bytes of
|
|
23
|
+
* the whole file, which every review made before 0.13.0 holds. With
|
|
24
|
+
* `hash: content-v1`, it is the source's `contentHash`, which leaves out the
|
|
25
|
+
* lifecycle and review fields, so approving or implementing a source, or
|
|
26
|
+
* marking its delivery, leaves the knowledge current. Any other `hash` is a
|
|
27
|
+
* kind this version does not know: every pin reads as changed.
|
|
28
|
+
*
|
|
21
29
|
* A pin of the literal `@current` is a fixture placeholder: `bindReviewPins`
|
|
22
|
-
* replaces it with the source's hash
|
|
23
|
-
* case can say "reviewed against what is there now"
|
|
24
|
-
* hash. Unbound, it never equals a hash, so it reads as
|
|
30
|
+
* replaces it with the source's hash of the record's kind in the snapshot
|
|
31
|
+
* being checked, so a case can say "reviewed against what is there now"
|
|
32
|
+
* without computing a hash. Unbound, it never equals a hash, so it reads as
|
|
33
|
+
* changed.
|
|
25
34
|
*/
|
|
26
35
|
import { type Artifact, type Graph, graphHash, type KnowledgeReportSection } from "@intentset/core";
|
|
27
36
|
import { compareStrings, sortedUnique } from "./diagnostic.ts";
|
|
28
37
|
|
|
29
38
|
export const REVIEW_EXTENSION = "intentset.org/review";
|
|
30
39
|
export const CURRENT_PIN = "@current";
|
|
40
|
+
/** The pin kinds a review record can name in `hash` (publication §3). Absent means `source`, the whole file. */
|
|
41
|
+
export const PIN_KINDS = ["content-v1"] as const;
|
|
42
|
+
export type PinKind = (typeof PIN_KINDS)[number];
|
|
31
43
|
|
|
32
44
|
export interface ReviewRecord {
|
|
33
45
|
/** Source ID -> the source hash it was reviewed against. Entries that are not strings are dropped. */
|
|
34
46
|
sources: Record<string, string>;
|
|
47
|
+
/** What the pins hash: absent for the whole file, `content-v1` for the content hash, anything else unknown. */
|
|
48
|
+
hash?: string;
|
|
35
49
|
snapshot?: string;
|
|
36
50
|
}
|
|
37
51
|
|
|
@@ -41,6 +55,8 @@ export interface ReviewStatus {
|
|
|
41
55
|
changed: string[];
|
|
42
56
|
/** Sources the review record does not pin. */
|
|
43
57
|
missing: string[];
|
|
58
|
+
/** The record's `hash` when this version does not know it, so no pin can match; null otherwise. */
|
|
59
|
+
unknownHash: string | null;
|
|
44
60
|
/** `reviewedBy`, or null when the knowledge names no reviewer. */
|
|
45
61
|
reviewer: string | null;
|
|
46
62
|
/** `reviewedAt`, or null when absent. */
|
|
@@ -68,6 +84,7 @@ export function readReviewRecord(artifact: Artifact): ReviewRecord | null {
|
|
|
68
84
|
if (typeof pin === "string") sources[id] = pin;
|
|
69
85
|
}
|
|
70
86
|
const record: ReviewRecord = { sources };
|
|
87
|
+
if (value.hash !== undefined) record.hash = typeof value.hash === "string" ? value.hash : JSON.stringify(value.hash);
|
|
71
88
|
if (typeof value.snapshot === "string") record.snapshot = value.snapshot;
|
|
72
89
|
return record;
|
|
73
90
|
}
|
|
@@ -75,17 +92,27 @@ export function readReviewRecord(artifact: Artifact): ReviewRecord | null {
|
|
|
75
92
|
/** Core §9: whether the knowledge is current against the sources it was reviewed against. */
|
|
76
93
|
export function reviewStatus(graph: Graph, artifact: Artifact): ReviewStatus {
|
|
77
94
|
const record = readReviewRecord(artifact);
|
|
95
|
+
const hashOf = pinHash(record?.hash);
|
|
96
|
+
const unknownHash = record?.hash !== undefined && hashOf === null ? record.hash : null;
|
|
78
97
|
const changed: string[] = [];
|
|
79
98
|
const missing: string[] = [];
|
|
80
99
|
for (const id of reviewSources(graph, artifact)) {
|
|
81
100
|
const pin = record?.sources[id];
|
|
101
|
+
const source = graph.artifacts.get(id);
|
|
82
102
|
if (pin === undefined) missing.push(id);
|
|
83
|
-
else if (
|
|
103
|
+
else if (source === undefined || hashOf === null || hashOf(source) !== pin) changed.push(id);
|
|
84
104
|
}
|
|
85
105
|
const reviewer = nonEmpty(artifact.meta.reviewedBy);
|
|
86
106
|
const reviewedAt = nonEmpty(artifact.meta.reviewedAt);
|
|
87
107
|
const current = changed.length === 0 && missing.length === 0 && reviewer !== null && reviewedAt !== null;
|
|
88
|
-
return { status: current ? "current" : "needs-review", changed, missing, reviewer, reviewedAt };
|
|
108
|
+
return { status: current ? "current" : "needs-review", changed, missing, unknownHash, reviewer, reviewedAt };
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/** The hash a pin of this kind holds for a source, or null for a kind this version does not know. */
|
|
112
|
+
export function pinHash(kind: string | undefined): ((source: Artifact) => string) | null {
|
|
113
|
+
if (kind === undefined) return (source) => source.sourceHash;
|
|
114
|
+
if (kind === "content-v1") return (source) => source.contentHash;
|
|
115
|
+
return null;
|
|
89
116
|
}
|
|
90
117
|
|
|
91
118
|
/**
|
|
@@ -102,9 +129,11 @@ export function bindReviewPins(graph: Graph): Graph {
|
|
|
102
129
|
artifacts.set(id, artifact);
|
|
103
130
|
continue;
|
|
104
131
|
}
|
|
132
|
+
const hashOf = pinHash(typeof value.hash === "string" || value.hash === undefined ? value.hash : "");
|
|
105
133
|
const sources: Record<string, unknown> = {};
|
|
106
134
|
for (const [source, pin] of Object.entries(value.sources)) {
|
|
107
|
-
|
|
135
|
+
const found = graph.artifacts.get(source);
|
|
136
|
+
sources[source] = pin === CURRENT_PIN && found !== undefined && hashOf !== null ? hashOf(found) : pin;
|
|
108
137
|
}
|
|
109
138
|
const extensions = { ...artifact.meta.extensions, [REVIEW_EXTENSION]: { ...value, sources } };
|
|
110
139
|
artifacts.set(id, { ...artifact, meta: { ...artifact.meta, extensions } });
|