filegrc 0.14.0 → 0.15.1
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/model/index.js +2 -1
- package/model/v11.json +5 -5
- package/package.json +1 -1
- package/src/agent.js +1 -1
- package/src/audit-preparation.js +16 -4
- package/src/audit-selection.js +33 -0
- package/src/cli.js +6 -3
- package/src/collection-review.js +61 -2
- package/src/collection-revision.js +3 -1
- package/src/collection-scope.js +45 -1
- package/src/index.js +1 -1
- package/src/program-path.js +59 -14
- package/src/program-readiness.js +217 -30
- package/src/retention-schedule-approval.js +121 -0
- package/src/retention.js +87 -12
- package/src/state.js +19 -22
- package/src/validate.js +46 -0
- package/src/web.js +509 -139
- package/src/workflow-history-integrity.js +5 -1
- package/src/workflow.js +2 -0
package/src/validate.js
CHANGED
|
@@ -19,6 +19,7 @@ import {
|
|
|
19
19
|
validCalendarRecurrence
|
|
20
20
|
} from "./recurrence.js";
|
|
21
21
|
import { resourceReviewRevisions, retentionReviewResourceIds } from "./retention.js";
|
|
22
|
+
import { retentionScheduleApprovalIssues } from "./retention-schedule-approval.js";
|
|
22
23
|
import { obligationIsEnabled } from "./program-lifecycle.js";
|
|
23
24
|
import { currentPartyPeople, partyPeople } from "./parties.js";
|
|
24
25
|
import { isMarkdownChoice, markdownEntries } from "./resource-markdown.js";
|
|
@@ -1296,6 +1297,32 @@ function validateCollectionReview(record, loaded, byId, path, diagnostics) {
|
|
|
1296
1297
|
));
|
|
1297
1298
|
}
|
|
1298
1299
|
}
|
|
1300
|
+
if (current && record.resourceType === "retention-schedule-item" && modelSupports(model, "retention-schedule-approval")) {
|
|
1301
|
+
const rows = scopedCollectionRecords(loaded, record.resourceType, program);
|
|
1302
|
+
for (const issue of retentionScheduleApprovalIssues(loaded, program || {}, rows, {
|
|
1303
|
+
informationTypesReviewed: collectionReviewIsCurrent(loaded, "information-type", program)
|
|
1304
|
+
})) {
|
|
1305
|
+
diagnostics.push(error(issue.code, path, issue.message));
|
|
1306
|
+
}
|
|
1307
|
+
const owners = new Set();
|
|
1308
|
+
for (const candidate of loaded.resources.filter((candidate) => (
|
|
1309
|
+
candidate.type === "document"
|
|
1310
|
+
&& candidate.documentKind === "schedule"
|
|
1311
|
+
&& candidate.workflowScope === "program"
|
|
1312
|
+
&& !["superseded", "retired"].includes(candidate.status)
|
|
1313
|
+
|| rows.includes(candidate)
|
|
1314
|
+
))) {
|
|
1315
|
+
for (const id of currentPartyPeople(candidate.ownerIds || [], byId)) owners.add(id);
|
|
1316
|
+
}
|
|
1317
|
+
const conflictedReviewers = (record.reviewedByIds || []).filter((id) => owners.has(id));
|
|
1318
|
+
if (conflictedReviewers.length) {
|
|
1319
|
+
diagnostics.push(error(
|
|
1320
|
+
"conflicted-retention-schedule-reviewer",
|
|
1321
|
+
path,
|
|
1322
|
+
`A Data Retention Schedule reviewer cannot own its governing document or an included schedule row: ${conflictedReviewers.join(", ")}.`
|
|
1323
|
+
));
|
|
1324
|
+
}
|
|
1325
|
+
}
|
|
1299
1326
|
if (modelSupports(model, "temporal-collection-reviews")) {
|
|
1300
1327
|
const temporalValues = [record.coverage, record.knowledgeCutoffAt, record.populationResourceIds];
|
|
1301
1328
|
const hasTemporalBinding = temporalValues.every((value) => value !== undefined && value !== null);
|
|
@@ -1364,6 +1391,25 @@ function validateCollectionReview(record, loaded, byId, path, diagnostics) {
|
|
|
1364
1391
|
}
|
|
1365
1392
|
}
|
|
1366
1393
|
|
|
1394
|
+
function collectionReviewIsCurrent(loaded, resourceType, program) {
|
|
1395
|
+
const review = loaded.resources.find((record) => (
|
|
1396
|
+
record.type === "collection-review"
|
|
1397
|
+
&& record.resourceType === resourceType
|
|
1398
|
+
&& record.status === "active"
|
|
1399
|
+
&& (!modelSupports(loaded.model, "program-scope") || (record.scopeResourceIds || []).includes(program?.id))
|
|
1400
|
+
));
|
|
1401
|
+
if (!review || !(loaded.model.collectionReviews?.[resourceType]?.decisions || ["complete"]).includes(review.decision)) return false;
|
|
1402
|
+
const records = scopedCollectionRecords(loaded, resourceType, program);
|
|
1403
|
+
const revisionMatches = collectionRevisionMatches(loaded, resourceType, review.collectionRevision, { program });
|
|
1404
|
+
if (!modelSupports(loaded.model, "temporal-collection-reviews")) return revisionMatches;
|
|
1405
|
+
return revisionMatches
|
|
1406
|
+
&& review.coverage?.kind === "as-of"
|
|
1407
|
+
&& review.coverage.on === review.reviewedOn
|
|
1408
|
+
&& Boolean(review.knowledgeCutoffAt)
|
|
1409
|
+
&& Array.isArray(review.populationResourceIds)
|
|
1410
|
+
&& JSON.stringify([...review.populationResourceIds].sort()) === JSON.stringify(records.map(({ id }) => id).sort());
|
|
1411
|
+
}
|
|
1412
|
+
|
|
1367
1413
|
function validateCollectionReviewSet(resources, pathById, diagnostics) {
|
|
1368
1414
|
const current = new Map();
|
|
1369
1415
|
for (const review of resources.filter((record) => record.type === "collection-review" && record.status !== "retired")) {
|