docassert 1.0.0__tar.gz → 1.0.1__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.
Files changed (126) hide show
  1. {docassert-1.0.0/docassert.egg-info → docassert-1.0.1}/PKG-INFO +7 -6
  2. {docassert-1.0.0 → docassert-1.0.1}/README.md +6 -5
  3. {docassert-1.0.0 → docassert-1.0.1}/docassert/__init__.py +1 -1
  4. {docassert-1.0.0 → docassert-1.0.1}/docassert/bridge/ops.py +8 -0
  5. {docassert-1.0.0 → docassert-1.0.1/docassert.egg-info}/PKG-INFO +7 -6
  6. {docassert-1.0.0 → docassert-1.0.1}/tests/test_audit_0_20_2.py +43 -0
  7. {docassert-1.0.0 → docassert-1.0.1}/LICENSE +0 -0
  8. {docassert-1.0.0 → docassert-1.0.1}/NOTICE +0 -0
  9. {docassert-1.0.0 → docassert-1.0.1}/docassert/__main__.py +0 -0
  10. {docassert-1.0.0 → docassert-1.0.1}/docassert/_data/consistency.yaml +0 -0
  11. {docassert-1.0.0 → docassert-1.0.1}/docassert/_data/criteria/adr.criteria.yaml +0 -0
  12. {docassert-1.0.0 → docassert-1.0.1}/docassert/_data/criteria/benefits-realization.criteria.yaml +0 -0
  13. {docassert-1.0.0 → docassert-1.0.1}/docassert/_data/criteria/brd.criteria.yaml +0 -0
  14. {docassert-1.0.0 → docassert-1.0.1}/docassert/_data/criteria/business-case.criteria.yaml +0 -0
  15. {docassert-1.0.0 → docassert-1.0.1}/docassert/_data/criteria/charter.criteria.yaml +0 -0
  16. {docassert-1.0.0 → docassert-1.0.1}/docassert/_data/criteria/data-migration-plan.criteria.yaml +0 -0
  17. {docassert-1.0.0 → docassert-1.0.1}/docassert/_data/criteria/frnfr.criteria.yaml +0 -0
  18. {docassert-1.0.0 → docassert-1.0.1}/docassert/_data/criteria/hypercare-plan.criteria.yaml +0 -0
  19. {docassert-1.0.0 → docassert-1.0.1}/docassert/_data/criteria/operations.criteria.yaml +0 -0
  20. {docassert-1.0.0 → docassert-1.0.1}/docassert/_data/criteria/post-implementation-review.criteria.yaml +0 -0
  21. {docassert-1.0.0 → docassert-1.0.1}/docassert/_data/criteria/prd.criteria.yaml +0 -0
  22. {docassert-1.0.0 → docassert-1.0.1}/docassert/_data/criteria/project.criteria.yaml +0 -0
  23. {docassert-1.0.0 → docassert-1.0.1}/docassert/_data/criteria/qa-test-plan.criteria.yaml +0 -0
  24. {docassert-1.0.0 → docassert-1.0.1}/docassert/_data/criteria/raci-stakeholder.criteria.yaml +0 -0
  25. {docassert-1.0.0 → docassert-1.0.1}/docassert/_data/criteria/release-cutover-plan.criteria.yaml +0 -0
  26. {docassert-1.0.0 → docassert-1.0.1}/docassert/_data/criteria/risk-register.criteria.yaml +0 -0
  27. {docassert-1.0.0 → docassert-1.0.1}/docassert/_data/criteria/rollback-plan.criteria.yaml +0 -0
  28. {docassert-1.0.0 → docassert-1.0.1}/docassert/_data/criteria/runbook.criteria.yaml +0 -0
  29. {docassert-1.0.0 → docassert-1.0.1}/docassert/_data/criteria/status-report.criteria.yaml +0 -0
  30. {docassert-1.0.0 → docassert-1.0.1}/docassert/_data/criteria/test-cases.criteria.yaml +0 -0
  31. {docassert-1.0.0 → docassert-1.0.1}/docassert/_data/criteria/user-story.criteria.yaml +0 -0
  32. {docassert-1.0.0 → docassert-1.0.1}/docassert/_data/profiles/agile-delivery.yaml +0 -0
  33. {docassert-1.0.0 → docassert-1.0.1}/docassert/_data/profiles/lean-startup.yaml +0 -0
  34. {docassert-1.0.0 → docassert-1.0.1}/docassert/_data/profiles/operations.yaml +0 -0
  35. {docassert-1.0.0 → docassert-1.0.1}/docassert/_data/profiles/regulated-industry.yaml +0 -0
  36. {docassert-1.0.0 → docassert-1.0.1}/docassert/_data/schema/adr.schema.json +0 -0
  37. {docassert-1.0.0 → docassert-1.0.1}/docassert/_data/schema/benefits-realization.schema.json +0 -0
  38. {docassert-1.0.0 → docassert-1.0.1}/docassert/_data/schema/brd.schema.json +0 -0
  39. {docassert-1.0.0 → docassert-1.0.1}/docassert/_data/schema/business-case.schema.json +0 -0
  40. {docassert-1.0.0 → docassert-1.0.1}/docassert/_data/schema/charter.schema.json +0 -0
  41. {docassert-1.0.0 → docassert-1.0.1}/docassert/_data/schema/data-migration-plan.schema.json +0 -0
  42. {docassert-1.0.0 → docassert-1.0.1}/docassert/_data/schema/frnfr.schema.json +0 -0
  43. {docassert-1.0.0 → docassert-1.0.1}/docassert/_data/schema/hypercare-plan.schema.json +0 -0
  44. {docassert-1.0.0 → docassert-1.0.1}/docassert/_data/schema/operations.schema.json +0 -0
  45. {docassert-1.0.0 → docassert-1.0.1}/docassert/_data/schema/post-implementation-review.schema.json +0 -0
  46. {docassert-1.0.0 → docassert-1.0.1}/docassert/_data/schema/prd.schema.json +0 -0
  47. {docassert-1.0.0 → docassert-1.0.1}/docassert/_data/schema/project.schema.json +0 -0
  48. {docassert-1.0.0 → docassert-1.0.1}/docassert/_data/schema/qa-test-plan.schema.json +0 -0
  49. {docassert-1.0.0 → docassert-1.0.1}/docassert/_data/schema/raci-stakeholder.schema.json +0 -0
  50. {docassert-1.0.0 → docassert-1.0.1}/docassert/_data/schema/release-cutover-plan.schema.json +0 -0
  51. {docassert-1.0.0 → docassert-1.0.1}/docassert/_data/schema/risk-register.schema.json +0 -0
  52. {docassert-1.0.0 → docassert-1.0.1}/docassert/_data/schema/rollback-plan.schema.json +0 -0
  53. {docassert-1.0.0 → docassert-1.0.1}/docassert/_data/schema/runbook.schema.json +0 -0
  54. {docassert-1.0.0 → docassert-1.0.1}/docassert/_data/schema/status-report.schema.json +0 -0
  55. {docassert-1.0.0 → docassert-1.0.1}/docassert/_data/schema/test-cases.schema.json +0 -0
  56. {docassert-1.0.0 → docassert-1.0.1}/docassert/_data/schema/user-story.schema.json +0 -0
  57. {docassert-1.0.0 → docassert-1.0.1}/docassert/_data/skills/doc-to-pmo/SKILL.md +0 -0
  58. {docassert-1.0.0 → docassert-1.0.1}/docassert/_data/templates/adr.template.md +0 -0
  59. {docassert-1.0.0 → docassert-1.0.1}/docassert/_data/templates/benefits-realization.template.md +0 -0
  60. {docassert-1.0.0 → docassert-1.0.1}/docassert/_data/templates/brd.template.md +0 -0
  61. {docassert-1.0.0 → docassert-1.0.1}/docassert/_data/templates/business-case.template.md +0 -0
  62. {docassert-1.0.0 → docassert-1.0.1}/docassert/_data/templates/charter.template.md +0 -0
  63. {docassert-1.0.0 → docassert-1.0.1}/docassert/_data/templates/data-migration-plan.template.md +0 -0
  64. {docassert-1.0.0 → docassert-1.0.1}/docassert/_data/templates/frnfr.template.md +0 -0
  65. {docassert-1.0.0 → docassert-1.0.1}/docassert/_data/templates/hypercare-plan.template.md +0 -0
  66. {docassert-1.0.0 → docassert-1.0.1}/docassert/_data/templates/operations.template.md +0 -0
  67. {docassert-1.0.0 → docassert-1.0.1}/docassert/_data/templates/post-implementation-review.template.md +0 -0
  68. {docassert-1.0.0 → docassert-1.0.1}/docassert/_data/templates/prd.template.md +0 -0
  69. {docassert-1.0.0 → docassert-1.0.1}/docassert/_data/templates/project.template.md +0 -0
  70. {docassert-1.0.0 → docassert-1.0.1}/docassert/_data/templates/qa-test-plan.template.md +0 -0
  71. {docassert-1.0.0 → docassert-1.0.1}/docassert/_data/templates/raci-stakeholder.template.md +0 -0
  72. {docassert-1.0.0 → docassert-1.0.1}/docassert/_data/templates/release-cutover-plan.template.md +0 -0
  73. {docassert-1.0.0 → docassert-1.0.1}/docassert/_data/templates/risk-register.template.md +0 -0
  74. {docassert-1.0.0 → docassert-1.0.1}/docassert/_data/templates/rollback-plan.template.md +0 -0
  75. {docassert-1.0.0 → docassert-1.0.1}/docassert/_data/templates/runbook.template.md +0 -0
  76. {docassert-1.0.0 → docassert-1.0.1}/docassert/_data/templates/status-report.template.md +0 -0
  77. {docassert-1.0.0 → docassert-1.0.1}/docassert/_data/templates/test-cases.template.md +0 -0
  78. {docassert-1.0.0 → docassert-1.0.1}/docassert/_data/templates/user-story.template.md +0 -0
  79. {docassert-1.0.0 → docassert-1.0.1}/docassert/bridge/__init__.py +0 -0
  80. {docassert-1.0.0 → docassert-1.0.1}/docassert/bridge/board.py +0 -0
  81. {docassert-1.0.0 → docassert-1.0.1}/docassert/bridge/gh.py +0 -0
  82. {docassert-1.0.0 → docassert-1.0.1}/docassert/bridge/plan.py +0 -0
  83. {docassert-1.0.0 → docassert-1.0.1}/docassert/cli.py +0 -0
  84. {docassert-1.0.0 → docassert-1.0.1}/docassert/config.py +0 -0
  85. {docassert-1.0.0 → docassert-1.0.1}/docassert/consistency.py +0 -0
  86. {docassert-1.0.0 → docassert-1.0.1}/docassert/extract.py +0 -0
  87. {docassert-1.0.0 → docassert-1.0.1}/docassert/graph.py +0 -0
  88. {docassert-1.0.0 → docassert-1.0.1}/docassert/loader.py +0 -0
  89. {docassert-1.0.0 → docassert-1.0.1}/docassert/models.py +0 -0
  90. {docassert-1.0.0 → docassert-1.0.1}/docassert/profiles.py +0 -0
  91. {docassert-1.0.0 → docassert-1.0.1}/docassert/projects.py +0 -0
  92. {docassert-1.0.0 → docassert-1.0.1}/docassert/report.py +0 -0
  93. {docassert-1.0.0 → docassert-1.0.1}/docassert/rtm.py +0 -0
  94. {docassert-1.0.0 → docassert-1.0.1}/docassert/scaffold.py +0 -0
  95. {docassert-1.0.0 → docassert-1.0.1}/docassert/semantic.py +0 -0
  96. {docassert-1.0.0 → docassert-1.0.1}/docassert/status/__init__.py +0 -0
  97. {docassert-1.0.0 → docassert-1.0.1}/docassert/status/derive.py +0 -0
  98. {docassert-1.0.0 → docassert-1.0.1}/docassert/status/render.py +0 -0
  99. {docassert-1.0.0 → docassert-1.0.1}/docassert/structural.py +0 -0
  100. {docassert-1.0.0 → docassert-1.0.1}/docassert.egg-info/SOURCES.txt +0 -0
  101. {docassert-1.0.0 → docassert-1.0.1}/docassert.egg-info/dependency_links.txt +0 -0
  102. {docassert-1.0.0 → docassert-1.0.1}/docassert.egg-info/entry_points.txt +0 -0
  103. {docassert-1.0.0 → docassert-1.0.1}/docassert.egg-info/requires.txt +0 -0
  104. {docassert-1.0.0 → docassert-1.0.1}/docassert.egg-info/top_level.txt +0 -0
  105. {docassert-1.0.0 → docassert-1.0.1}/pyproject.toml +0 -0
  106. {docassert-1.0.0 → docassert-1.0.1}/setup.cfg +0 -0
  107. {docassert-1.0.0 → docassert-1.0.1}/tests/test_badge.py +0 -0
  108. {docassert-1.0.0 → docassert-1.0.1}/tests/test_bridge.py +0 -0
  109. {docassert-1.0.0 → docassert-1.0.1}/tests/test_config.py +0 -0
  110. {docassert-1.0.0 → docassert-1.0.1}/tests/test_consistency.py +0 -0
  111. {docassert-1.0.0 → docassert-1.0.1}/tests/test_defects.py +0 -0
  112. {docassert-1.0.0 → docassert-1.0.1}/tests/test_draft_relaxation.py +0 -0
  113. {docassert-1.0.0 → docassert-1.0.1}/tests/test_extract.py +0 -0
  114. {docassert-1.0.0 → docassert-1.0.1}/tests/test_graph.py +0 -0
  115. {docassert-1.0.0 → docassert-1.0.1}/tests/test_json_report.py +0 -0
  116. {docassert-1.0.0 → docassert-1.0.1}/tests/test_kinds_delivery.py +0 -0
  117. {docassert-1.0.0 → docassert-1.0.1}/tests/test_kinds_governance.py +0 -0
  118. {docassert-1.0.0 → docassert-1.0.1}/tests/test_kinds_operate.py +0 -0
  119. {docassert-1.0.0 → docassert-1.0.1}/tests/test_kinds_reporting.py +0 -0
  120. {docassert-1.0.0 → docassert-1.0.1}/tests/test_profiles.py +0 -0
  121. {docassert-1.0.0 → docassert-1.0.1}/tests/test_projects.py +0 -0
  122. {docassert-1.0.0 → docassert-1.0.1}/tests/test_report_extract.py +0 -0
  123. {docassert-1.0.0 → docassert-1.0.1}/tests/test_scaffold.py +0 -0
  124. {docassert-1.0.0 → docassert-1.0.1}/tests/test_semantic.py +0 -0
  125. {docassert-1.0.0 → docassert-1.0.1}/tests/test_status.py +0 -0
  126. {docassert-1.0.0 → docassert-1.0.1}/tests/test_structural.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: docassert
3
- Version: 1.0.0
3
+ Version: 1.0.1
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
@@ -55,7 +55,7 @@ derived from the documents rather than self-reported.
55
55
 
56
56
  docassert is the reference implementation of **[PMO as Code](https://c4g-john.github.io/pmo-as-code/)** —
57
57
  a vendor-neutral standard for running a PMO from version-controlled, declarative
58
- files. It implements the [PMO as Code specification](https://github.com/c4g-john/pmo-as-code-spec) **v0.3** and passes its [conformance suite](https://github.com/c4g-john/pmo-as-code-spec/tree/main/conformance) in CI.
58
+ files. It implements the [PMO as Code specification](https://github.com/c4g-john/pmo-as-code-spec) **v0.8** and passes its [conformance suite](https://github.com/c4g-john/pmo-as-code-spec/tree/main/conformance) (73 cases) in CI.
59
59
 
60
60
  ## Install
61
61
 
@@ -103,19 +103,20 @@ flagged as TODOs, never invented). The skill's source is
103
103
  | `docassert extract <file>` | Extract plain text from a source `.docx` / `.pdf` / `.md` / `.txt` (the first step of doc-to-pmo conversion). Needs the `convert` extra: `pip install "docassert[convert]"`. |
104
104
 
105
105
  Every document-reading command accepts `--documents-dir` (default `documents/`).
106
- The full flag-by-flag reference, and what 1.x does and does not promise to
107
- keep stable, live in [STABILITY.md](STABILITY.md).
106
+ The full flag-by-flag reference, and the 1.x stability guarantees (binding
107
+ since 1.0.0), live in [STABILITY.md](STABILITY.md).
108
108
  AI alignment grades at most `alignment_limit` links per run (default 25; set it
109
109
  in `consistency.yaml`, `0` = no cap) so API cost stays bounded on large graphs.
110
110
 
111
111
  ## Document kinds
112
112
 
113
- Twenty kinds, each a `templates/<kind>.template.md` + `schema/<kind>.schema.json`
113
+ Twenty-one kinds, each a `templates/<kind>.template.md` + `schema/<kind>.schema.json`
114
114
  + `criteria/<kind>.criteria.yaml` trio: `project`, `charter`, `business-case`,
115
115
  `brd`, `prd`, `frnfr`, `user-story`, `test-cases`, `adr`, `risk-register`,
116
116
  `raci-stakeholder`, `qa-test-plan`, `data-migration-plan`,
117
117
  `release-cutover-plan`, `rollback-plan`, `hypercare-plan`, `runbook`,
118
- `status-report`, `post-implementation-review`, `benefits-realization`. Adding a
118
+ `operations`, `status-report`, `post-implementation-review`,
119
+ `benefits-realization`. Adding a
119
120
  kind is adding a trio — no code for the common cases.
120
121
 
121
122
  ## Two tiers of checks
@@ -14,7 +14,7 @@ derived from the documents rather than self-reported.
14
14
 
15
15
  docassert is the reference implementation of **[PMO as Code](https://c4g-john.github.io/pmo-as-code/)** —
16
16
  a vendor-neutral standard for running a PMO from version-controlled, declarative
17
- files. It implements the [PMO as Code specification](https://github.com/c4g-john/pmo-as-code-spec) **v0.3** and passes its [conformance suite](https://github.com/c4g-john/pmo-as-code-spec/tree/main/conformance) in CI.
17
+ files. It implements the [PMO as Code specification](https://github.com/c4g-john/pmo-as-code-spec) **v0.8** and passes its [conformance suite](https://github.com/c4g-john/pmo-as-code-spec/tree/main/conformance) (73 cases) in CI.
18
18
 
19
19
  ## Install
20
20
 
@@ -62,19 +62,20 @@ flagged as TODOs, never invented). The skill's source is
62
62
  | `docassert extract <file>` | Extract plain text from a source `.docx` / `.pdf` / `.md` / `.txt` (the first step of doc-to-pmo conversion). Needs the `convert` extra: `pip install "docassert[convert]"`. |
63
63
 
64
64
  Every document-reading command accepts `--documents-dir` (default `documents/`).
65
- The full flag-by-flag reference, and what 1.x does and does not promise to
66
- keep stable, live in [STABILITY.md](STABILITY.md).
65
+ The full flag-by-flag reference, and the 1.x stability guarantees (binding
66
+ since 1.0.0), live in [STABILITY.md](STABILITY.md).
67
67
  AI alignment grades at most `alignment_limit` links per run (default 25; set it
68
68
  in `consistency.yaml`, `0` = no cap) so API cost stays bounded on large graphs.
69
69
 
70
70
  ## Document kinds
71
71
 
72
- Twenty kinds, each a `templates/<kind>.template.md` + `schema/<kind>.schema.json`
72
+ Twenty-one kinds, each a `templates/<kind>.template.md` + `schema/<kind>.schema.json`
73
73
  + `criteria/<kind>.criteria.yaml` trio: `project`, `charter`, `business-case`,
74
74
  `brd`, `prd`, `frnfr`, `user-story`, `test-cases`, `adr`, `risk-register`,
75
75
  `raci-stakeholder`, `qa-test-plan`, `data-migration-plan`,
76
76
  `release-cutover-plan`, `rollback-plan`, `hypercare-plan`, `runbook`,
77
- `status-report`, `post-implementation-review`, `benefits-realization`. Adding a
77
+ `operations`, `status-report`, `post-implementation-review`,
78
+ `benefits-realization`. Adding a
78
79
  kind is adding a trio — no code for the common cases.
79
80
 
80
81
  ## Two tiers of checks
@@ -5,4 +5,4 @@ standard: deterministic structural checks that gate a merge, plus optional
5
5
  AI-graded semantic checks that advise.
6
6
  """
7
7
 
8
- __version__ = "1.0.0"
8
+ __version__ = "1.0.1"
@@ -23,6 +23,10 @@ from .plan import (
23
23
 
24
24
  MARKER_RE = re.compile(r"<!-- docassert-bridge: ([A-Za-z0-9-]+) -->")
25
25
  SCOPE_REPORT_KEY = "scope-report"
26
+ # Spec v0.8.1: items carrying this label are excluded from scope
27
+ # classification entirely. The label is a human decision; the bridge never
28
+ # applies it (it only creates its own bridge:*/scope:* labels below).
29
+ EXEMPT_LABEL = "scope:exempt"
26
30
  LABELS = {
27
31
  "bridge:feature": ("1d76db", "Feature scaffolded from a product requirement"),
28
32
  "bridge:story": ("0e8a16", "Story scaffolded from an approved user story"),
@@ -162,6 +166,8 @@ def reconcile(plan: BridgePlan, gh: G.GhRunner, repo: str) -> tuple[list[str], i
162
166
  if key == SCOPE_REPORT_KEY:
163
167
  continue
164
168
  labels = {lb["name"] for lb in issue.get("labels", [])}
169
+ if EXEMPT_LABEL in labels:
170
+ continue
165
171
  number = issue["number"]
166
172
 
167
173
  if key is None:
@@ -221,6 +227,8 @@ def status(plan: BridgePlan, gh: G.GhRunner, repo: str) -> dict:
221
227
  key = _marker_of(issue)
222
228
  if key == SCOPE_REPORT_KEY:
223
229
  continue
230
+ if EXEMPT_LABEL in {lb.get("name") for lb in issue.get("labels") or []}:
231
+ continue
224
232
  if key is None:
225
233
  unverified.append({"number": issue["number"], "title": issue["title"]})
226
234
  elif key not in managed:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: docassert
3
- Version: 1.0.0
3
+ Version: 1.0.1
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
@@ -55,7 +55,7 @@ derived from the documents rather than self-reported.
55
55
 
56
56
  docassert is the reference implementation of **[PMO as Code](https://c4g-john.github.io/pmo-as-code/)** —
57
57
  a vendor-neutral standard for running a PMO from version-controlled, declarative
58
- files. It implements the [PMO as Code specification](https://github.com/c4g-john/pmo-as-code-spec) **v0.3** and passes its [conformance suite](https://github.com/c4g-john/pmo-as-code-spec/tree/main/conformance) in CI.
58
+ files. It implements the [PMO as Code specification](https://github.com/c4g-john/pmo-as-code-spec) **v0.8** and passes its [conformance suite](https://github.com/c4g-john/pmo-as-code-spec/tree/main/conformance) (73 cases) in CI.
59
59
 
60
60
  ## Install
61
61
 
@@ -103,19 +103,20 @@ flagged as TODOs, never invented). The skill's source is
103
103
  | `docassert extract <file>` | Extract plain text from a source `.docx` / `.pdf` / `.md` / `.txt` (the first step of doc-to-pmo conversion). Needs the `convert` extra: `pip install "docassert[convert]"`. |
104
104
 
105
105
  Every document-reading command accepts `--documents-dir` (default `documents/`).
106
- The full flag-by-flag reference, and what 1.x does and does not promise to
107
- keep stable, live in [STABILITY.md](STABILITY.md).
106
+ The full flag-by-flag reference, and the 1.x stability guarantees (binding
107
+ since 1.0.0), live in [STABILITY.md](STABILITY.md).
108
108
  AI alignment grades at most `alignment_limit` links per run (default 25; set it
109
109
  in `consistency.yaml`, `0` = no cap) so API cost stays bounded on large graphs.
110
110
 
111
111
  ## Document kinds
112
112
 
113
- Twenty kinds, each a `templates/<kind>.template.md` + `schema/<kind>.schema.json`
113
+ Twenty-one kinds, each a `templates/<kind>.template.md` + `schema/<kind>.schema.json`
114
114
  + `criteria/<kind>.criteria.yaml` trio: `project`, `charter`, `business-case`,
115
115
  `brd`, `prd`, `frnfr`, `user-story`, `test-cases`, `adr`, `risk-register`,
116
116
  `raci-stakeholder`, `qa-test-plan`, `data-migration-plan`,
117
117
  `release-cutover-plan`, `rollback-plan`, `hypercare-plan`, `runbook`,
118
- `status-report`, `post-implementation-review`, `benefits-realization`. Adding a
118
+ `operations`, `status-report`, `post-implementation-review`,
119
+ `benefits-realization`. Adding a
119
120
  kind is adding a trio — no code for the common cases.
120
121
 
121
122
  ## Two tiers of checks
@@ -216,3 +216,46 @@ def test_board_get_project_falls_back_to_organization():
216
216
  project = board.get_project(OrgOnlyGh(), "acme", 3)
217
217
  assert project["id"] == "P1"
218
218
  assert project["fields"]["Type"]["options"]["Feature"] == "O1"
219
+
220
+
221
+ # ── spec v0.8.1: scope:exempt items are invisible to the scope guard ─────────
222
+ def test_scope_exempt_label_excluded_from_classification():
223
+ from docassert.bridge.plan import BridgePlan
224
+ exempt = {"number": 90, "state": "open", "title": "CI health: failures detected",
225
+ "body": "no marker here", "labels": [{"name": "scope:exempt"}]}
226
+ stray = {"number": 91, "state": "open", "title": "Add dark mode",
227
+ "body": "no marker here", "labels": []}
228
+ plan = BridgePlan(projects=[{"id": "P", "code": "P", "repo": "o/r", "features": []}])
229
+
230
+ class ReadOnlyGh:
231
+ def run(self, args, input_=None):
232
+ import json
233
+ if "issues?" in args[1]:
234
+ return json.dumps([exempt, stray])
235
+ return "{}"
236
+
237
+ data = ops.status(plan, ReadOnlyGh(), "o/r")
238
+ nums = [i["number"] for i in data["scope"]["unverified"]]
239
+ assert nums == [91], f"exempt issue leaked into scope: {nums}"
240
+
241
+ lines, code = ops.reconcile(plan, ReadOnlyGh(), "o/r")
242
+ assert code == 1 # the real stray still alarms
243
+ assert not any("#90" in ln for ln in lines)
244
+ assert any("#91" in ln for ln in lines)
245
+
246
+
247
+ def test_scope_exempt_alone_exits_zero():
248
+ from docassert.bridge.plan import BridgePlan
249
+ exempt = {"number": 90, "state": "open", "title": "CI health: failures detected",
250
+ "body": "no marker here", "labels": [{"name": "scope:exempt"}]}
251
+ plan = BridgePlan(projects=[{"id": "P", "code": "P", "repo": "o/r", "features": []}])
252
+
253
+ class ReadOnlyGh:
254
+ def run(self, args, input_=None):
255
+ import json
256
+ if "issues?" in args[1]:
257
+ return json.dumps([exempt])
258
+ return "{}"
259
+
260
+ lines, code = ops.reconcile(plan, ReadOnlyGh(), "o/r")
261
+ assert code == 0, f"exempt-only board must not alarm: {lines}"
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