docassert 0.6.0__tar.gz → 0.7.0__tar.gz
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.
- {docassert-0.6.0/docassert.egg-info → docassert-0.7.0}/PKG-INFO +4 -1
- {docassert-0.6.0 → docassert-0.7.0}/README.md +3 -0
- {docassert-0.6.0 → docassert-0.7.0}/docassert/__init__.py +1 -1
- {docassert-0.6.0 → docassert-0.7.0}/docassert/_data/criteria/adr.criteria.yaml +6 -2
- {docassert-0.6.0 → docassert-0.7.0}/docassert/_data/criteria/benefits-realization.criteria.yaml +6 -2
- {docassert-0.6.0 → docassert-0.7.0}/docassert/_data/criteria/brd.criteria.yaml +5 -1
- {docassert-0.6.0 → docassert-0.7.0}/docassert/_data/criteria/business-case.criteria.yaml +5 -1
- {docassert-0.6.0 → docassert-0.7.0}/docassert/_data/criteria/charter.criteria.yaml +7 -3
- {docassert-0.6.0 → docassert-0.7.0}/docassert/_data/criteria/data-migration-plan.criteria.yaml +6 -2
- {docassert-0.6.0 → docassert-0.7.0}/docassert/_data/criteria/frnfr.criteria.yaml +5 -1
- {docassert-0.6.0 → docassert-0.7.0}/docassert/_data/criteria/hypercare-plan.criteria.yaml +6 -2
- {docassert-0.6.0 → docassert-0.7.0}/docassert/_data/criteria/post-implementation-review.criteria.yaml +5 -1
- {docassert-0.6.0 → docassert-0.7.0}/docassert/_data/criteria/prd.criteria.yaml +5 -1
- {docassert-0.6.0 → docassert-0.7.0}/docassert/_data/criteria/project.criteria.yaml +5 -1
- {docassert-0.6.0 → docassert-0.7.0}/docassert/_data/criteria/qa-test-plan.criteria.yaml +6 -2
- {docassert-0.6.0 → docassert-0.7.0}/docassert/_data/criteria/raci-stakeholder.criteria.yaml +6 -2
- {docassert-0.6.0 → docassert-0.7.0}/docassert/_data/criteria/release-cutover-plan.criteria.yaml +6 -2
- {docassert-0.6.0 → docassert-0.7.0}/docassert/_data/criteria/risk-register.criteria.yaml +6 -2
- {docassert-0.6.0 → docassert-0.7.0}/docassert/_data/criteria/rollback-plan.criteria.yaml +6 -2
- {docassert-0.6.0 → docassert-0.7.0}/docassert/_data/criteria/runbook.criteria.yaml +6 -2
- {docassert-0.6.0 → docassert-0.7.0}/docassert/_data/criteria/status-report.criteria.yaml +6 -2
- {docassert-0.6.0 → docassert-0.7.0}/docassert/_data/criteria/test-cases.criteria.yaml +5 -1
- {docassert-0.6.0 → docassert-0.7.0}/docassert/_data/criteria/user-story.criteria.yaml +6 -2
- {docassert-0.6.0 → docassert-0.7.0}/docassert/structural.py +51 -9
- {docassert-0.6.0 → docassert-0.7.0/docassert.egg-info}/PKG-INFO +4 -1
- {docassert-0.6.0 → docassert-0.7.0}/docassert.egg-info/SOURCES.txt +1 -0
- docassert-0.7.0/tests/test_draft_relaxation.py +138 -0
- {docassert-0.6.0 → docassert-0.7.0}/LICENSE +0 -0
- {docassert-0.6.0 → docassert-0.7.0}/NOTICE +0 -0
- {docassert-0.6.0 → docassert-0.7.0}/docassert/__main__.py +0 -0
- {docassert-0.6.0 → docassert-0.7.0}/docassert/_data/consistency.yaml +0 -0
- {docassert-0.6.0 → docassert-0.7.0}/docassert/_data/profiles/agile-delivery.yaml +0 -0
- {docassert-0.6.0 → docassert-0.7.0}/docassert/_data/profiles/lean-startup.yaml +0 -0
- {docassert-0.6.0 → docassert-0.7.0}/docassert/_data/profiles/regulated-industry.yaml +0 -0
- {docassert-0.6.0 → docassert-0.7.0}/docassert/_data/schema/adr.schema.json +0 -0
- {docassert-0.6.0 → docassert-0.7.0}/docassert/_data/schema/benefits-realization.schema.json +0 -0
- {docassert-0.6.0 → docassert-0.7.0}/docassert/_data/schema/brd.schema.json +0 -0
- {docassert-0.6.0 → docassert-0.7.0}/docassert/_data/schema/business-case.schema.json +0 -0
- {docassert-0.6.0 → docassert-0.7.0}/docassert/_data/schema/charter.schema.json +0 -0
- {docassert-0.6.0 → docassert-0.7.0}/docassert/_data/schema/data-migration-plan.schema.json +0 -0
- {docassert-0.6.0 → docassert-0.7.0}/docassert/_data/schema/frnfr.schema.json +0 -0
- {docassert-0.6.0 → docassert-0.7.0}/docassert/_data/schema/hypercare-plan.schema.json +0 -0
- {docassert-0.6.0 → docassert-0.7.0}/docassert/_data/schema/post-implementation-review.schema.json +0 -0
- {docassert-0.6.0 → docassert-0.7.0}/docassert/_data/schema/prd.schema.json +0 -0
- {docassert-0.6.0 → docassert-0.7.0}/docassert/_data/schema/project.schema.json +0 -0
- {docassert-0.6.0 → docassert-0.7.0}/docassert/_data/schema/qa-test-plan.schema.json +0 -0
- {docassert-0.6.0 → docassert-0.7.0}/docassert/_data/schema/raci-stakeholder.schema.json +0 -0
- {docassert-0.6.0 → docassert-0.7.0}/docassert/_data/schema/release-cutover-plan.schema.json +0 -0
- {docassert-0.6.0 → docassert-0.7.0}/docassert/_data/schema/risk-register.schema.json +0 -0
- {docassert-0.6.0 → docassert-0.7.0}/docassert/_data/schema/rollback-plan.schema.json +0 -0
- {docassert-0.6.0 → docassert-0.7.0}/docassert/_data/schema/runbook.schema.json +0 -0
- {docassert-0.6.0 → docassert-0.7.0}/docassert/_data/schema/status-report.schema.json +0 -0
- {docassert-0.6.0 → docassert-0.7.0}/docassert/_data/schema/test-cases.schema.json +0 -0
- {docassert-0.6.0 → docassert-0.7.0}/docassert/_data/schema/user-story.schema.json +0 -0
- {docassert-0.6.0 → docassert-0.7.0}/docassert/_data/skills/doc-to-pmo/SKILL.md +0 -0
- {docassert-0.6.0 → docassert-0.7.0}/docassert/_data/templates/adr.template.md +0 -0
- {docassert-0.6.0 → docassert-0.7.0}/docassert/_data/templates/benefits-realization.template.md +0 -0
- {docassert-0.6.0 → docassert-0.7.0}/docassert/_data/templates/brd.template.md +0 -0
- {docassert-0.6.0 → docassert-0.7.0}/docassert/_data/templates/business-case.template.md +0 -0
- {docassert-0.6.0 → docassert-0.7.0}/docassert/_data/templates/charter.template.md +0 -0
- {docassert-0.6.0 → docassert-0.7.0}/docassert/_data/templates/data-migration-plan.template.md +0 -0
- {docassert-0.6.0 → docassert-0.7.0}/docassert/_data/templates/frnfr.template.md +0 -0
- {docassert-0.6.0 → docassert-0.7.0}/docassert/_data/templates/hypercare-plan.template.md +0 -0
- {docassert-0.6.0 → docassert-0.7.0}/docassert/_data/templates/post-implementation-review.template.md +0 -0
- {docassert-0.6.0 → docassert-0.7.0}/docassert/_data/templates/prd.template.md +0 -0
- {docassert-0.6.0 → docassert-0.7.0}/docassert/_data/templates/project.template.md +0 -0
- {docassert-0.6.0 → docassert-0.7.0}/docassert/_data/templates/qa-test-plan.template.md +0 -0
- {docassert-0.6.0 → docassert-0.7.0}/docassert/_data/templates/raci-stakeholder.template.md +0 -0
- {docassert-0.6.0 → docassert-0.7.0}/docassert/_data/templates/release-cutover-plan.template.md +0 -0
- {docassert-0.6.0 → docassert-0.7.0}/docassert/_data/templates/risk-register.template.md +0 -0
- {docassert-0.6.0 → docassert-0.7.0}/docassert/_data/templates/rollback-plan.template.md +0 -0
- {docassert-0.6.0 → docassert-0.7.0}/docassert/_data/templates/runbook.template.md +0 -0
- {docassert-0.6.0 → docassert-0.7.0}/docassert/_data/templates/status-report.template.md +0 -0
- {docassert-0.6.0 → docassert-0.7.0}/docassert/_data/templates/test-cases.template.md +0 -0
- {docassert-0.6.0 → docassert-0.7.0}/docassert/_data/templates/user-story.template.md +0 -0
- {docassert-0.6.0 → docassert-0.7.0}/docassert/cli.py +0 -0
- {docassert-0.6.0 → docassert-0.7.0}/docassert/config.py +0 -0
- {docassert-0.6.0 → docassert-0.7.0}/docassert/consistency.py +0 -0
- {docassert-0.6.0 → docassert-0.7.0}/docassert/extract.py +0 -0
- {docassert-0.6.0 → docassert-0.7.0}/docassert/graph.py +0 -0
- {docassert-0.6.0 → docassert-0.7.0}/docassert/loader.py +0 -0
- {docassert-0.6.0 → docassert-0.7.0}/docassert/models.py +0 -0
- {docassert-0.6.0 → docassert-0.7.0}/docassert/profiles.py +0 -0
- {docassert-0.6.0 → docassert-0.7.0}/docassert/projects.py +0 -0
- {docassert-0.6.0 → docassert-0.7.0}/docassert/report.py +0 -0
- {docassert-0.6.0 → docassert-0.7.0}/docassert/rtm.py +0 -0
- {docassert-0.6.0 → docassert-0.7.0}/docassert/scaffold.py +0 -0
- {docassert-0.6.0 → docassert-0.7.0}/docassert/semantic.py +0 -0
- {docassert-0.6.0 → docassert-0.7.0}/docassert/status.py +0 -0
- {docassert-0.6.0 → docassert-0.7.0}/docassert.egg-info/dependency_links.txt +0 -0
- {docassert-0.6.0 → docassert-0.7.0}/docassert.egg-info/entry_points.txt +0 -0
- {docassert-0.6.0 → docassert-0.7.0}/docassert.egg-info/requires.txt +0 -0
- {docassert-0.6.0 → docassert-0.7.0}/docassert.egg-info/top_level.txt +0 -0
- {docassert-0.6.0 → docassert-0.7.0}/pyproject.toml +0 -0
- {docassert-0.6.0 → docassert-0.7.0}/setup.cfg +0 -0
- {docassert-0.6.0 → docassert-0.7.0}/tests/test_badge.py +0 -0
- {docassert-0.6.0 → docassert-0.7.0}/tests/test_config.py +0 -0
- {docassert-0.6.0 → docassert-0.7.0}/tests/test_consistency.py +0 -0
- {docassert-0.6.0 → docassert-0.7.0}/tests/test_defects.py +0 -0
- {docassert-0.6.0 → docassert-0.7.0}/tests/test_extract.py +0 -0
- {docassert-0.6.0 → docassert-0.7.0}/tests/test_graph.py +0 -0
- {docassert-0.6.0 → docassert-0.7.0}/tests/test_json_report.py +0 -0
- {docassert-0.6.0 → docassert-0.7.0}/tests/test_kinds_delivery.py +0 -0
- {docassert-0.6.0 → docassert-0.7.0}/tests/test_kinds_governance.py +0 -0
- {docassert-0.6.0 → docassert-0.7.0}/tests/test_kinds_operate.py +0 -0
- {docassert-0.6.0 → docassert-0.7.0}/tests/test_kinds_reporting.py +0 -0
- {docassert-0.6.0 → docassert-0.7.0}/tests/test_profiles.py +0 -0
- {docassert-0.6.0 → docassert-0.7.0}/tests/test_projects.py +0 -0
- {docassert-0.6.0 → docassert-0.7.0}/tests/test_scaffold.py +0 -0
- {docassert-0.6.0 → docassert-0.7.0}/tests/test_status.py +0 -0
- {docassert-0.6.0 → docassert-0.7.0}/tests/test_structural.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: docassert
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.7.0
|
|
4
4
|
Summary: Unit testing for business documents — validate structured Markdown docs against a configurable audit standard.
|
|
5
5
|
Author: C4G Enterprises Inc.
|
|
6
6
|
License: Apache-2.0
|
|
@@ -117,6 +117,9 @@ kind is adding a trio — no code for the common cases.
|
|
|
117
117
|
- **Structural — deterministic, blocking.** Required fields and sections,
|
|
118
118
|
measurable success criteria, risks with owner + mitigation, resolving
|
|
119
119
|
references, unique ids. Plain Python, reliable enough to gate a merge.
|
|
120
|
+
Within this tier, *integrity* checks (malformed items, bad types, duplicate
|
|
121
|
+
ids) block at any status, while *completeness* checks relax to advisory on
|
|
122
|
+
`status: draft` and gate once a document is proposed — WIP is never punished.
|
|
120
123
|
- **Semantic — AI-graded, advisory.** Scored via the Anthropic API and posted to
|
|
121
124
|
the PR — never blocking. Set `ANTHROPIC_API_KEY` to enable; skipped otherwise.
|
|
122
125
|
|
|
@@ -77,6 +77,9 @@ kind is adding a trio — no code for the common cases.
|
|
|
77
77
|
- **Structural — deterministic, blocking.** Required fields and sections,
|
|
78
78
|
measurable success criteria, risks with owner + mitigation, resolving
|
|
79
79
|
references, unique ids. Plain Python, reliable enough to gate a merge.
|
|
80
|
+
Within this tier, *integrity* checks (malformed items, bad types, duplicate
|
|
81
|
+
ids) block at any status, while *completeness* checks relax to advisory on
|
|
82
|
+
`status: draft` and gate once a document is proposed — WIP is never punished.
|
|
80
83
|
- **Semantic — AI-graded, advisory.** Scored via the Anthropic API and posted to
|
|
81
84
|
the PR — never blocking. Set `ANTHROPIC_API_KEY` to enable; skipped otherwise.
|
|
82
85
|
|
|
@@ -18,9 +18,13 @@ checks:
|
|
|
18
18
|
type: structural
|
|
19
19
|
blocking: true
|
|
20
20
|
description: Frontmatter is valid against schema/adr.schema.json.
|
|
21
|
+
- id: frontmatter-complete
|
|
22
|
+
type: structural
|
|
23
|
+
blocking: once-proposed
|
|
24
|
+
description: Every schema-required frontmatter field is present (advisory while draft).
|
|
21
25
|
- id: required-sections
|
|
22
26
|
type: structural
|
|
23
|
-
blocking:
|
|
27
|
+
blocking: once-proposed
|
|
24
28
|
description: Every required section is present and non-empty.
|
|
25
29
|
- id: items-well-formed
|
|
26
30
|
type: structural
|
|
@@ -28,7 +32,7 @@ checks:
|
|
|
28
32
|
description: Every decision is a valid **ADR-###** item.
|
|
29
33
|
- id: adr-items-have-status
|
|
30
34
|
type: structural
|
|
31
|
-
blocking:
|
|
35
|
+
blocking: once-proposed
|
|
32
36
|
description: Every decision declares a valid Status (proposed | accepted | superseded | deprecated | rejected).
|
|
33
37
|
- id: unique-id
|
|
34
38
|
type: structural
|
{docassert-0.6.0 → docassert-0.7.0}/docassert/_data/criteria/benefits-realization.criteria.yaml
RENAMED
|
@@ -16,13 +16,17 @@ checks:
|
|
|
16
16
|
type: structural
|
|
17
17
|
blocking: true
|
|
18
18
|
description: Frontmatter is valid against schema/benefits-realization.schema.json.
|
|
19
|
+
- id: frontmatter-complete
|
|
20
|
+
type: structural
|
|
21
|
+
blocking: once-proposed
|
|
22
|
+
description: Every schema-required frontmatter field is present (advisory while draft).
|
|
19
23
|
- id: required-sections
|
|
20
24
|
type: structural
|
|
21
|
-
blocking:
|
|
25
|
+
blocking: once-proposed
|
|
22
26
|
description: Every required section is present and non-empty.
|
|
23
27
|
- id: measurable-items
|
|
24
28
|
type: structural
|
|
25
|
-
blocking:
|
|
29
|
+
blocking: once-proposed
|
|
26
30
|
description: Every benefit states a measurable target.
|
|
27
31
|
- id: unique-id
|
|
28
32
|
type: structural
|
|
@@ -16,9 +16,13 @@ checks:
|
|
|
16
16
|
type: structural
|
|
17
17
|
blocking: true
|
|
18
18
|
description: Frontmatter is valid against schema/brd.schema.json.
|
|
19
|
+
- id: frontmatter-complete
|
|
20
|
+
type: structural
|
|
21
|
+
blocking: once-proposed
|
|
22
|
+
description: Every schema-required frontmatter field is present (advisory while draft).
|
|
19
23
|
- id: required-sections
|
|
20
24
|
type: structural
|
|
21
|
-
blocking:
|
|
25
|
+
blocking: once-proposed
|
|
22
26
|
description: Every required section is present and non-empty.
|
|
23
27
|
- id: items-well-formed
|
|
24
28
|
type: structural
|
|
@@ -13,9 +13,13 @@ checks:
|
|
|
13
13
|
type: structural
|
|
14
14
|
blocking: true
|
|
15
15
|
description: Frontmatter is valid against schema/business-case.schema.json.
|
|
16
|
+
- id: frontmatter-complete
|
|
17
|
+
type: structural
|
|
18
|
+
blocking: once-proposed
|
|
19
|
+
description: Every schema-required frontmatter field is present (advisory while draft).
|
|
16
20
|
- id: required-sections
|
|
17
21
|
type: structural
|
|
18
|
-
blocking:
|
|
22
|
+
blocking: once-proposed
|
|
19
23
|
description: Every required section is present and non-empty.
|
|
20
24
|
- id: unique-id
|
|
21
25
|
type: structural
|
|
@@ -26,19 +26,23 @@ checks:
|
|
|
26
26
|
blocking: true
|
|
27
27
|
description: Frontmatter is present and valid against schema/charter.schema.json.
|
|
28
28
|
|
|
29
|
+
- id: frontmatter-complete
|
|
30
|
+
type: structural
|
|
31
|
+
blocking: once-proposed
|
|
32
|
+
description: Every schema-required frontmatter field is present (advisory while draft).
|
|
29
33
|
- id: required-sections
|
|
30
34
|
type: structural
|
|
31
|
-
blocking:
|
|
35
|
+
blocking: once-proposed
|
|
32
36
|
description: Every required section is present and non-empty.
|
|
33
37
|
|
|
34
38
|
- id: measurable-success-criteria
|
|
35
39
|
type: structural
|
|
36
|
-
blocking:
|
|
40
|
+
blocking: once-proposed
|
|
37
41
|
description: Every Success Criteria bullet states a measurable threshold (number, %, currency, or date).
|
|
38
42
|
|
|
39
43
|
- id: risks-have-owner-and-mitigation
|
|
40
44
|
type: structural
|
|
41
|
-
blocking:
|
|
45
|
+
blocking: once-proposed
|
|
42
46
|
description: Every Risks bullet names an Owner and a Mitigation.
|
|
43
47
|
|
|
44
48
|
- id: dates-consistent
|
{docassert-0.6.0 → docassert-0.7.0}/docassert/_data/criteria/data-migration-plan.criteria.yaml
RENAMED
|
@@ -14,13 +14,17 @@ checks:
|
|
|
14
14
|
type: structural
|
|
15
15
|
blocking: true
|
|
16
16
|
description: Frontmatter is valid against schema/data-migration-plan.schema.json.
|
|
17
|
+
- id: frontmatter-complete
|
|
18
|
+
type: structural
|
|
19
|
+
blocking: once-proposed
|
|
20
|
+
description: Every schema-required frontmatter field is present (advisory while draft).
|
|
17
21
|
- id: required-sections
|
|
18
22
|
type: structural
|
|
19
|
-
blocking:
|
|
23
|
+
blocking: once-proposed
|
|
20
24
|
description: Every required section is present and non-empty.
|
|
21
25
|
- id: mapping-table
|
|
22
26
|
type: structural
|
|
23
|
-
blocking:
|
|
27
|
+
blocking: once-proposed
|
|
24
28
|
description: The Field Mapping section contains a mapping table.
|
|
25
29
|
- id: unique-id
|
|
26
30
|
type: structural
|
|
@@ -17,9 +17,13 @@ checks:
|
|
|
17
17
|
type: structural
|
|
18
18
|
blocking: true
|
|
19
19
|
description: Frontmatter is valid against schema/frnfr.schema.json.
|
|
20
|
+
- id: frontmatter-complete
|
|
21
|
+
type: structural
|
|
22
|
+
blocking: once-proposed
|
|
23
|
+
description: Every schema-required frontmatter field is present (advisory while draft).
|
|
20
24
|
- id: required-sections
|
|
21
25
|
type: structural
|
|
22
|
-
blocking:
|
|
26
|
+
blocking: once-proposed
|
|
23
27
|
description: Every required section is present and non-empty.
|
|
24
28
|
- id: items-well-formed
|
|
25
29
|
type: structural
|
|
@@ -13,13 +13,17 @@ checks:
|
|
|
13
13
|
type: structural
|
|
14
14
|
blocking: true
|
|
15
15
|
description: Frontmatter is valid against schema/hypercare-plan.schema.json.
|
|
16
|
+
- id: frontmatter-complete
|
|
17
|
+
type: structural
|
|
18
|
+
blocking: once-proposed
|
|
19
|
+
description: Every schema-required frontmatter field is present (advisory while draft).
|
|
16
20
|
- id: required-sections
|
|
17
21
|
type: structural
|
|
18
|
-
blocking:
|
|
22
|
+
blocking: once-proposed
|
|
19
23
|
description: Every required section is present and non-empty.
|
|
20
24
|
- id: measurable-exit-criteria
|
|
21
25
|
type: structural
|
|
22
|
-
blocking:
|
|
26
|
+
blocking: once-proposed
|
|
23
27
|
description: Every hypercare exit criterion states a measurable threshold.
|
|
24
28
|
- id: unique-id
|
|
25
29
|
type: structural
|
|
@@ -14,9 +14,13 @@ checks:
|
|
|
14
14
|
type: structural
|
|
15
15
|
blocking: true
|
|
16
16
|
description: Frontmatter is valid against schema/post-implementation-review.schema.json.
|
|
17
|
+
- id: frontmatter-complete
|
|
18
|
+
type: structural
|
|
19
|
+
blocking: once-proposed
|
|
20
|
+
description: Every schema-required frontmatter field is present (advisory while draft).
|
|
17
21
|
- id: required-sections
|
|
18
22
|
type: structural
|
|
19
|
-
blocking:
|
|
23
|
+
blocking: once-proposed
|
|
20
24
|
description: Every required section is present and non-empty.
|
|
21
25
|
- id: unique-id
|
|
22
26
|
type: structural
|
|
@@ -17,9 +17,13 @@ checks:
|
|
|
17
17
|
type: structural
|
|
18
18
|
blocking: true
|
|
19
19
|
description: Frontmatter is valid against schema/prd.schema.json.
|
|
20
|
+
- id: frontmatter-complete
|
|
21
|
+
type: structural
|
|
22
|
+
blocking: once-proposed
|
|
23
|
+
description: Every schema-required frontmatter field is present (advisory while draft).
|
|
20
24
|
- id: required-sections
|
|
21
25
|
type: structural
|
|
22
|
-
blocking:
|
|
26
|
+
blocking: once-proposed
|
|
23
27
|
description: Every required section is present and non-empty.
|
|
24
28
|
- id: items-well-formed
|
|
25
29
|
type: structural
|
|
@@ -16,6 +16,10 @@ checks:
|
|
|
16
16
|
blocking: true
|
|
17
17
|
description: Frontmatter is present and valid against schema/project.schema.json.
|
|
18
18
|
|
|
19
|
+
- id: frontmatter-complete
|
|
20
|
+
type: structural
|
|
21
|
+
blocking: once-proposed
|
|
22
|
+
description: Every schema-required frontmatter field is present (advisory while draft).
|
|
19
23
|
- id: project-id-format
|
|
20
24
|
type: structural
|
|
21
25
|
blocking: true
|
|
@@ -23,7 +27,7 @@ checks:
|
|
|
23
27
|
|
|
24
28
|
- id: required-sections
|
|
25
29
|
type: structural
|
|
26
|
-
blocking:
|
|
30
|
+
blocking: once-proposed
|
|
27
31
|
description: Every required section is present and non-empty.
|
|
28
32
|
|
|
29
33
|
- id: unique-id
|
|
@@ -13,13 +13,17 @@ checks:
|
|
|
13
13
|
type: structural
|
|
14
14
|
blocking: true
|
|
15
15
|
description: Frontmatter is valid against schema/qa-test-plan.schema.json.
|
|
16
|
+
- id: frontmatter-complete
|
|
17
|
+
type: structural
|
|
18
|
+
blocking: once-proposed
|
|
19
|
+
description: Every schema-required frontmatter field is present (advisory while draft).
|
|
16
20
|
- id: required-sections
|
|
17
21
|
type: structural
|
|
18
|
-
blocking:
|
|
22
|
+
blocking: once-proposed
|
|
19
23
|
description: Every required section is present and non-empty.
|
|
20
24
|
- id: measurable-exit-criteria
|
|
21
25
|
type: structural
|
|
22
|
-
blocking:
|
|
26
|
+
blocking: once-proposed
|
|
23
27
|
description: Every exit criterion states a measurable threshold.
|
|
24
28
|
- id: unique-id
|
|
25
29
|
type: structural
|
|
@@ -10,13 +10,17 @@ checks:
|
|
|
10
10
|
type: structural
|
|
11
11
|
blocking: true
|
|
12
12
|
description: Frontmatter is valid against schema/raci-stakeholder.schema.json.
|
|
13
|
+
- id: frontmatter-complete
|
|
14
|
+
type: structural
|
|
15
|
+
blocking: once-proposed
|
|
16
|
+
description: Every schema-required frontmatter field is present (advisory while draft).
|
|
13
17
|
- id: required-sections
|
|
14
18
|
type: structural
|
|
15
|
-
blocking:
|
|
19
|
+
blocking: once-proposed
|
|
16
20
|
description: Every required section is present and non-empty.
|
|
17
21
|
- id: raci-one-accountable
|
|
18
22
|
type: structural
|
|
19
|
-
blocking:
|
|
23
|
+
blocking: once-proposed
|
|
20
24
|
description: Every activity in the RACI Matrix has exactly one Accountable (A) role.
|
|
21
25
|
- id: unique-id
|
|
22
26
|
type: structural
|
{docassert-0.6.0 → docassert-0.7.0}/docassert/_data/criteria/release-cutover-plan.criteria.yaml
RENAMED
|
@@ -16,13 +16,17 @@ checks:
|
|
|
16
16
|
type: structural
|
|
17
17
|
blocking: true
|
|
18
18
|
description: Frontmatter is valid against schema/release-cutover-plan.schema.json.
|
|
19
|
+
- id: frontmatter-complete
|
|
20
|
+
type: structural
|
|
21
|
+
blocking: once-proposed
|
|
22
|
+
description: Every schema-required frontmatter field is present (advisory while draft).
|
|
19
23
|
- id: required-sections
|
|
20
24
|
type: structural
|
|
21
|
-
blocking:
|
|
25
|
+
blocking: once-proposed
|
|
22
26
|
description: Every required section is present and non-empty.
|
|
23
27
|
- id: numbered-steps
|
|
24
28
|
type: structural
|
|
25
|
-
blocking:
|
|
29
|
+
blocking: once-proposed
|
|
26
30
|
description: Cutover Steps is an ordered list of at least two numbered steps.
|
|
27
31
|
- id: unique-id
|
|
28
32
|
type: structural
|
|
@@ -14,9 +14,13 @@ checks:
|
|
|
14
14
|
type: structural
|
|
15
15
|
blocking: true
|
|
16
16
|
description: Frontmatter is valid against schema/risk-register.schema.json.
|
|
17
|
+
- id: frontmatter-complete
|
|
18
|
+
type: structural
|
|
19
|
+
blocking: once-proposed
|
|
20
|
+
description: Every schema-required frontmatter field is present (advisory while draft).
|
|
17
21
|
- id: required-sections
|
|
18
22
|
type: structural
|
|
19
|
-
blocking:
|
|
23
|
+
blocking: once-proposed
|
|
20
24
|
description: Every required section is present and non-empty.
|
|
21
25
|
- id: items-well-formed
|
|
22
26
|
type: structural
|
|
@@ -24,7 +28,7 @@ checks:
|
|
|
24
28
|
description: Every risk is a valid **RISK-###** item.
|
|
25
29
|
- id: risk-items-complete
|
|
26
30
|
type: structural
|
|
27
|
-
blocking:
|
|
31
|
+
blocking: once-proposed
|
|
28
32
|
description: Every risk states a Probability, Impact, Owner, and Response.
|
|
29
33
|
- id: unique-id
|
|
30
34
|
type: structural
|
|
@@ -15,13 +15,17 @@ checks:
|
|
|
15
15
|
type: structural
|
|
16
16
|
blocking: true
|
|
17
17
|
description: Frontmatter is valid against schema/rollback-plan.schema.json.
|
|
18
|
+
- id: frontmatter-complete
|
|
19
|
+
type: structural
|
|
20
|
+
blocking: once-proposed
|
|
21
|
+
description: Every schema-required frontmatter field is present (advisory while draft).
|
|
18
22
|
- id: required-sections
|
|
19
23
|
type: structural
|
|
20
|
-
blocking:
|
|
24
|
+
blocking: once-proposed
|
|
21
25
|
description: Every required section is present and non-empty.
|
|
22
26
|
- id: numbered-steps
|
|
23
27
|
type: structural
|
|
24
|
-
blocking:
|
|
28
|
+
blocking: once-proposed
|
|
25
29
|
description: Rollback Steps is an ordered list of at least two numbered steps.
|
|
26
30
|
- id: unique-id
|
|
27
31
|
type: structural
|
|
@@ -16,13 +16,17 @@ checks:
|
|
|
16
16
|
type: structural
|
|
17
17
|
blocking: true
|
|
18
18
|
description: Frontmatter is valid against schema/runbook.schema.json.
|
|
19
|
+
- id: frontmatter-complete
|
|
20
|
+
type: structural
|
|
21
|
+
blocking: once-proposed
|
|
22
|
+
description: Every schema-required frontmatter field is present (advisory while draft).
|
|
19
23
|
- id: required-sections
|
|
20
24
|
type: structural
|
|
21
|
-
blocking:
|
|
25
|
+
blocking: once-proposed
|
|
22
26
|
description: Every required section is present and non-empty.
|
|
23
27
|
- id: numbered-steps
|
|
24
28
|
type: structural
|
|
25
|
-
blocking:
|
|
29
|
+
blocking: once-proposed
|
|
26
30
|
description: Procedures is an ordered list of at least two numbered steps.
|
|
27
31
|
- id: unique-id
|
|
28
32
|
type: structural
|
|
@@ -12,13 +12,17 @@ checks:
|
|
|
12
12
|
type: structural
|
|
13
13
|
blocking: true
|
|
14
14
|
description: Frontmatter is valid (includes a period date and a green/amber/red rag).
|
|
15
|
+
- id: frontmatter-complete
|
|
16
|
+
type: structural
|
|
17
|
+
blocking: once-proposed
|
|
18
|
+
description: Every schema-required frontmatter field is present (advisory while draft).
|
|
15
19
|
- id: required-sections
|
|
16
20
|
type: structural
|
|
17
|
-
blocking:
|
|
21
|
+
blocking: once-proposed
|
|
18
22
|
description: Every required section is present and non-empty.
|
|
19
23
|
- id: references-risk
|
|
20
24
|
type: structural
|
|
21
|
-
blocking:
|
|
25
|
+
blocking: once-proposed
|
|
22
26
|
description: The Risks & Issues section cites at least one RISK-### from the register.
|
|
23
27
|
- id: unique-id
|
|
24
28
|
type: structural
|
|
@@ -14,9 +14,13 @@ checks:
|
|
|
14
14
|
type: structural
|
|
15
15
|
blocking: true
|
|
16
16
|
description: Frontmatter is valid against schema/test-cases.schema.json.
|
|
17
|
+
- id: frontmatter-complete
|
|
18
|
+
type: structural
|
|
19
|
+
blocking: once-proposed
|
|
20
|
+
description: Every schema-required frontmatter field is present (advisory while draft).
|
|
17
21
|
- id: required-sections
|
|
18
22
|
type: structural
|
|
19
|
-
blocking:
|
|
23
|
+
blocking: once-proposed
|
|
20
24
|
description: Every required section is present and non-empty.
|
|
21
25
|
- id: items-well-formed
|
|
22
26
|
type: structural
|
|
@@ -14,9 +14,13 @@ checks:
|
|
|
14
14
|
type: structural
|
|
15
15
|
blocking: true
|
|
16
16
|
description: Frontmatter is valid against schema/user-story.schema.json.
|
|
17
|
+
- id: frontmatter-complete
|
|
18
|
+
type: structural
|
|
19
|
+
blocking: once-proposed
|
|
20
|
+
description: Every schema-required frontmatter field is present (advisory while draft).
|
|
17
21
|
- id: required-sections
|
|
18
22
|
type: structural
|
|
19
|
-
blocking:
|
|
23
|
+
blocking: once-proposed
|
|
20
24
|
description: Every required section is present and non-empty.
|
|
21
25
|
- id: items-well-formed
|
|
22
26
|
type: structural
|
|
@@ -24,7 +28,7 @@ checks:
|
|
|
24
28
|
description: Every story is a valid **US-###** item.
|
|
25
29
|
- id: story-format
|
|
26
30
|
type: structural
|
|
27
|
-
blocking:
|
|
31
|
+
blocking: once-proposed
|
|
28
32
|
description: Every story follows "As a … I want … so that …".
|
|
29
33
|
- id: unique-id
|
|
30
34
|
type: structural
|
|
@@ -4,6 +4,7 @@ from __future__ import annotations
|
|
|
4
4
|
import datetime as dt
|
|
5
5
|
import re
|
|
6
6
|
from collections.abc import Callable
|
|
7
|
+
from pathlib import Path
|
|
7
8
|
|
|
8
9
|
from jsonschema import Draft7Validator, FormatChecker
|
|
9
10
|
|
|
@@ -73,15 +74,31 @@ def _as_date(value) -> dt.date | None:
|
|
|
73
74
|
|
|
74
75
|
|
|
75
76
|
# ── individual checks ──────────────────────────────────────────────────────
|
|
77
|
+
def _schema_errors(doc: Document, ctx: dict) -> list:
|
|
78
|
+
validator = Draft7Validator(ctx["schema"], format_checker=FormatChecker())
|
|
79
|
+
return sorted(validator.iter_errors(_jsonify(doc.frontmatter)), key=str)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def _format_errors(errors) -> str:
|
|
83
|
+
return "; ".join(f"{'/'.join(str(p) for p in e.path) or '(root)'}: {e.message}"
|
|
84
|
+
for e in errors)
|
|
85
|
+
|
|
86
|
+
|
|
76
87
|
def check_frontmatter_schema(doc: Document, ctx: dict) -> tuple[bool, str]:
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
errors =
|
|
88
|
+
"""Frontmatter *wellformedness*: type, format, pattern, and enum errors.
|
|
89
|
+
Missing required fields are completeness, checked by frontmatter-complete."""
|
|
90
|
+
errors = [e for e in _schema_errors(doc, ctx) if e.validator != "required"]
|
|
80
91
|
if not errors:
|
|
81
92
|
return True, "Frontmatter is valid against the schema."
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
93
|
+
return False, f"Frontmatter schema errors: {_format_errors(errors)}"
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def check_frontmatter_complete(doc: Document, ctx: dict) -> tuple[bool, str]:
|
|
97
|
+
"""Frontmatter *completeness*: every schema-required field is present."""
|
|
98
|
+
errors = [e for e in _schema_errors(doc, ctx) if e.validator == "required"]
|
|
99
|
+
if not errors:
|
|
100
|
+
return True, "All required frontmatter fields are present."
|
|
101
|
+
return False, f"Missing required frontmatter: {_format_errors(errors)}"
|
|
85
102
|
|
|
86
103
|
|
|
87
104
|
def check_required_sections(doc: Document, ctx: dict) -> tuple[bool, str]:
|
|
@@ -133,8 +150,12 @@ def check_dates_consistent(doc: Document, ctx: dict) -> tuple[bool, str]:
|
|
|
133
150
|
dates = doc.frontmatter.get("dates") or {}
|
|
134
151
|
created = _as_date(dates.get("created"))
|
|
135
152
|
target = _as_date(dates.get("target"))
|
|
153
|
+
if created is None and dates.get("created") is not None:
|
|
154
|
+
return False, f"dates.created is not a valid ISO date: {dates.get('created')!r}"
|
|
155
|
+
if target is None and dates.get("target") is not None:
|
|
156
|
+
return False, f"dates.target is not a valid ISO date: {dates.get('target')!r}"
|
|
136
157
|
if created is None or target is None:
|
|
137
|
-
return
|
|
158
|
+
return True, "Date(s) not set yet (presence is checked by frontmatter-complete)."
|
|
138
159
|
if target < created:
|
|
139
160
|
return False, f"target ({target}) is before created ({created})."
|
|
140
161
|
return True, f"Dates consistent (created {created} → target {target})."
|
|
@@ -143,7 +164,9 @@ def check_dates_consistent(doc: Document, ctx: dict) -> tuple[bool, str]:
|
|
|
143
164
|
def check_unique_id(doc: Document, ctx: dict) -> tuple[bool, str]:
|
|
144
165
|
if not doc.id:
|
|
145
166
|
return False, "Document has no id."
|
|
146
|
-
|
|
167
|
+
me = Path(doc.path).resolve()
|
|
168
|
+
others = [p for p in ctx.get("id_index", {}).get(doc.id, [])
|
|
169
|
+
if Path(p).resolve() != me]
|
|
147
170
|
if others:
|
|
148
171
|
return False, f"id '{doc.id}' also used by: {', '.join(others)}"
|
|
149
172
|
return True, f"id '{doc.id}' is unique."
|
|
@@ -371,6 +394,7 @@ def check_references_risk(doc: Document, ctx: dict) -> tuple[bool, str]:
|
|
|
371
394
|
|
|
372
395
|
CHECKS: dict[str, Callable[[Document, dict], tuple[bool, str]]] = {
|
|
373
396
|
"frontmatter-schema": check_frontmatter_schema,
|
|
397
|
+
"frontmatter-complete": check_frontmatter_complete,
|
|
374
398
|
"required-sections": check_required_sections,
|
|
375
399
|
"measurable-success-criteria": check_measurable_success_criteria,
|
|
376
400
|
"risks-have-owner-and-mitigation": check_risks_owner_mitigation,
|
|
@@ -390,11 +414,29 @@ CHECKS: dict[str, Callable[[Document, dict], tuple[bool, str]]] = {
|
|
|
390
414
|
}
|
|
391
415
|
|
|
392
416
|
|
|
417
|
+
def _effective_blocking(spec: dict, doc: Document) -> bool:
|
|
418
|
+
"""Interpret the criteria `blocking` value.
|
|
419
|
+
|
|
420
|
+
true/"always" -> blocks at any status (integrity: malformed data)
|
|
421
|
+
"once-proposed" -> blocks once status is proposed or beyond; advisory for
|
|
422
|
+
drafts (completeness: WIP is never punished)
|
|
423
|
+
false/"never" -> advisory
|
|
424
|
+
"""
|
|
425
|
+
b = spec.get("blocking", True)
|
|
426
|
+
if b in (True, "always"):
|
|
427
|
+
return True
|
|
428
|
+
if b in (False, "never"):
|
|
429
|
+
return False
|
|
430
|
+
if b == "once-proposed":
|
|
431
|
+
return str(doc.frontmatter.get("status", "draft")).lower() != "draft"
|
|
432
|
+
return bool(b)
|
|
433
|
+
|
|
434
|
+
|
|
393
435
|
def run_structural(doc: Document, spec: dict, ctx: dict) -> CheckResult:
|
|
394
436
|
"""Run one structural check described by a criteria `spec` dict."""
|
|
395
437
|
check_id = spec["id"]
|
|
396
438
|
fn = CHECKS.get(check_id)
|
|
397
|
-
blocking =
|
|
439
|
+
blocking = _effective_blocking(spec, doc)
|
|
398
440
|
if fn is None:
|
|
399
441
|
return CheckResult(check_id, False, blocking,
|
|
400
442
|
f"Unknown structural check '{check_id}'.", kind="structural")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: docassert
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.7.0
|
|
4
4
|
Summary: Unit testing for business documents — validate structured Markdown docs against a configurable audit standard.
|
|
5
5
|
Author: C4G Enterprises Inc.
|
|
6
6
|
License: Apache-2.0
|
|
@@ -117,6 +117,9 @@ kind is adding a trio — no code for the common cases.
|
|
|
117
117
|
- **Structural — deterministic, blocking.** Required fields and sections,
|
|
118
118
|
measurable success criteria, risks with owner + mitigation, resolving
|
|
119
119
|
references, unique ids. Plain Python, reliable enough to gate a merge.
|
|
120
|
+
Within this tier, *integrity* checks (malformed items, bad types, duplicate
|
|
121
|
+
ids) block at any status, while *completeness* checks relax to advisory on
|
|
122
|
+
`status: draft` and gate once a document is proposed — WIP is never punished.
|
|
120
123
|
- **Semantic — AI-graded, advisory.** Scored via the Anthropic API and posted to
|
|
121
124
|
the PR — never blocking. Set `ANTHROPIC_API_KEY` to enable; skipped otherwise.
|
|
122
125
|
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
"""Tests for check severities: integrity always blocks; completeness relaxes
|
|
2
|
+
to advisory while a document is a draft ("WIP is never punished")."""
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
from docassert.cli import main
|
|
6
|
+
from docassert.loader import parse_sections
|
|
7
|
+
from docassert.models import Document
|
|
8
|
+
from docassert.structural import (
|
|
9
|
+
_effective_blocking,
|
|
10
|
+
check_dates_consistent,
|
|
11
|
+
check_frontmatter_complete,
|
|
12
|
+
check_frontmatter_schema,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
ROOT = Path(__file__).resolve().parent.parent
|
|
16
|
+
|
|
17
|
+
DRAFT_CHARTER = """---
|
|
18
|
+
kind: charter
|
|
19
|
+
project: PRJ-001-TST
|
|
20
|
+
id: TST-charter
|
|
21
|
+
title: T — Draft Charter
|
|
22
|
+
sponsor: jane.doe
|
|
23
|
+
dates:
|
|
24
|
+
created: 2026-01-01
|
|
25
|
+
status: {status}
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## Objective
|
|
29
|
+
Cut cycle time from 10 days to under 2 days.
|
|
30
|
+
|
|
31
|
+
## Success Criteria
|
|
32
|
+
- Median cycle time drops below 48 hours.
|
|
33
|
+
|
|
34
|
+
## Scope
|
|
35
|
+
In scope: the thing.
|
|
36
|
+
|
|
37
|
+
## Milestones
|
|
38
|
+
- TODO: none yet.
|
|
39
|
+
|
|
40
|
+
## Risks
|
|
41
|
+
- Might slip. Owner: jane.doe. Mitigation: buffer.
|
|
42
|
+
|
|
43
|
+
## Approval
|
|
44
|
+
Pending.
|
|
45
|
+
"""
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def _write(tmp_path, status):
|
|
49
|
+
d = tmp_path / "documents" / "PRJ-001-TST"
|
|
50
|
+
d.mkdir(parents=True, exist_ok=True)
|
|
51
|
+
f = d / "charter.md"
|
|
52
|
+
f.write_text(DRAFT_CHARTER.format(status=status), encoding="utf-8")
|
|
53
|
+
return f
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
# ── the Refuge scenario: an incomplete DRAFT merges (advisory only) ──────────
|
|
57
|
+
def test_draft_missing_budget_is_advisory(tmp_path, monkeypatch, capsys):
|
|
58
|
+
f = _write(tmp_path, "draft")
|
|
59
|
+
monkeypatch.chdir(tmp_path)
|
|
60
|
+
assert main(["validate", str(f)]) == 0 # no blocking failures
|
|
61
|
+
out = capsys.readouterr().out
|
|
62
|
+
assert "Missing required frontmatter" in out # ...but the gap is reported
|
|
63
|
+
assert "budget" in out
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def test_proposed_missing_budget_blocks(tmp_path, monkeypatch):
|
|
67
|
+
f = _write(tmp_path, "proposed")
|
|
68
|
+
monkeypatch.chdir(tmp_path)
|
|
69
|
+
assert main(["validate", str(f)]) >= 1 # completeness now gates
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def test_type_error_blocks_even_on_draft(tmp_path, monkeypatch):
|
|
73
|
+
f = _write(tmp_path, "draft")
|
|
74
|
+
f.write_text(f.read_text().replace("sponsor: jane.doe", "sponsor: j"),
|
|
75
|
+
encoding="utf-8") # minLength violation = malformed
|
|
76
|
+
monkeypatch.chdir(tmp_path)
|
|
77
|
+
assert main(["validate", str(f)]) >= 1
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def test_malformed_item_blocks_even_on_draft(tmp_path, monkeypatch):
|
|
81
|
+
d = tmp_path / "documents" / "PRJ-001-TST"
|
|
82
|
+
d.mkdir(parents=True)
|
|
83
|
+
(d / "brd.md").write_text("""---
|
|
84
|
+
kind: brd
|
|
85
|
+
project: PRJ-001-TST
|
|
86
|
+
id: TST-brd
|
|
87
|
+
title: T
|
|
88
|
+
owner: jane.doe
|
|
89
|
+
status: draft
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## Purpose
|
|
93
|
+
p.
|
|
94
|
+
|
|
95
|
+
## Business Requirements
|
|
96
|
+
- **broken bullet** without a valid item id
|
|
97
|
+
|
|
98
|
+
## Out of Scope
|
|
99
|
+
n/a
|
|
100
|
+
""", encoding="utf-8")
|
|
101
|
+
monkeypatch.chdir(tmp_path)
|
|
102
|
+
assert main(["validate", str(d / "brd.md")]) >= 1 # integrity: always blocks
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
# ── the split checks ─────────────────────────────────────────────────────────
|
|
106
|
+
def _doc(fm):
|
|
107
|
+
return Document("x.md", fm, parse_sections(""), "")
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def test_schema_vs_complete_split():
|
|
111
|
+
import json
|
|
112
|
+
schema = json.loads((ROOT / "schema" / "charter.schema.json").read_text())
|
|
113
|
+
ctx = {"schema": schema}
|
|
114
|
+
doc = _doc({"kind": "charter", "id": "TST-charter", "project": "PRJ-001-TST",
|
|
115
|
+
"title": "Test Charter", "sponsor": "jane.doe", "status": "draft"}) # no budget/dates
|
|
116
|
+
ok_schema, _ = check_frontmatter_schema(doc, ctx)
|
|
117
|
+
ok_complete, detail = check_frontmatter_complete(doc, ctx)
|
|
118
|
+
assert ok_schema # nothing malformed
|
|
119
|
+
assert not ok_complete and "budget" in detail
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def test_dates_absent_pass_invalid_fail():
|
|
123
|
+
assert check_dates_consistent(_doc({"dates": {}}), {})[0]
|
|
124
|
+
assert check_dates_consistent(_doc({}), {})[0]
|
|
125
|
+
ok, detail = check_dates_consistent(_doc({"dates": {"created": "soonish"}}), {})
|
|
126
|
+
assert not ok and "soonish" in detail
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
# ── blocking interpretation ──────────────────────────────────────────────────
|
|
130
|
+
def test_effective_blocking_modes():
|
|
131
|
+
draft, proposed = _doc({"status": "draft"}), _doc({"status": "proposed"})
|
|
132
|
+
assert _effective_blocking({"blocking": True}, draft)
|
|
133
|
+
assert _effective_blocking({"blocking": "always"}, draft)
|
|
134
|
+
assert not _effective_blocking({"blocking": False}, proposed)
|
|
135
|
+
assert not _effective_blocking({"blocking": "never"}, proposed)
|
|
136
|
+
assert not _effective_blocking({"blocking": "once-proposed"}, draft)
|
|
137
|
+
assert _effective_blocking({"blocking": "once-proposed"}, proposed)
|
|
138
|
+
assert not _effective_blocking({"blocking": "once-proposed"}, _doc({})) # no status = draft
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{docassert-0.6.0 → docassert-0.7.0}/docassert/_data/schema/post-implementation-review.schema.json
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{docassert-0.6.0 → docassert-0.7.0}/docassert/_data/templates/benefits-realization.template.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{docassert-0.6.0 → docassert-0.7.0}/docassert/_data/templates/data-migration-plan.template.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{docassert-0.6.0 → docassert-0.7.0}/docassert/_data/templates/post-implementation-review.template.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{docassert-0.6.0 → docassert-0.7.0}/docassert/_data/templates/release-cutover-plan.template.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|