docassert 0.11.0__tar.gz → 0.12.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 (120) hide show
  1. {docassert-0.11.0/docassert.egg-info → docassert-0.12.1}/PKG-INFO +1 -1
  2. {docassert-0.11.0 → docassert-0.12.1}/docassert/__init__.py +1 -1
  3. {docassert-0.11.0 → docassert-0.12.1}/docassert/_data/consistency.yaml +23 -2
  4. {docassert-0.11.0 → docassert-0.12.1}/docassert/consistency.py +18 -2
  5. {docassert-0.11.0 → docassert-0.12.1/docassert.egg-info}/PKG-INFO +1 -1
  6. {docassert-0.11.0 → docassert-0.12.1}/tests/test_semantic.py +59 -0
  7. {docassert-0.11.0 → docassert-0.12.1}/LICENSE +0 -0
  8. {docassert-0.11.0 → docassert-0.12.1}/NOTICE +0 -0
  9. {docassert-0.11.0 → docassert-0.12.1}/README.md +0 -0
  10. {docassert-0.11.0 → docassert-0.12.1}/docassert/__main__.py +0 -0
  11. {docassert-0.11.0 → docassert-0.12.1}/docassert/_data/criteria/adr.criteria.yaml +0 -0
  12. {docassert-0.11.0 → docassert-0.12.1}/docassert/_data/criteria/benefits-realization.criteria.yaml +0 -0
  13. {docassert-0.11.0 → docassert-0.12.1}/docassert/_data/criteria/brd.criteria.yaml +0 -0
  14. {docassert-0.11.0 → docassert-0.12.1}/docassert/_data/criteria/business-case.criteria.yaml +0 -0
  15. {docassert-0.11.0 → docassert-0.12.1}/docassert/_data/criteria/charter.criteria.yaml +0 -0
  16. {docassert-0.11.0 → docassert-0.12.1}/docassert/_data/criteria/data-migration-plan.criteria.yaml +0 -0
  17. {docassert-0.11.0 → docassert-0.12.1}/docassert/_data/criteria/frnfr.criteria.yaml +0 -0
  18. {docassert-0.11.0 → docassert-0.12.1}/docassert/_data/criteria/hypercare-plan.criteria.yaml +0 -0
  19. {docassert-0.11.0 → docassert-0.12.1}/docassert/_data/criteria/post-implementation-review.criteria.yaml +0 -0
  20. {docassert-0.11.0 → docassert-0.12.1}/docassert/_data/criteria/prd.criteria.yaml +0 -0
  21. {docassert-0.11.0 → docassert-0.12.1}/docassert/_data/criteria/project.criteria.yaml +0 -0
  22. {docassert-0.11.0 → docassert-0.12.1}/docassert/_data/criteria/qa-test-plan.criteria.yaml +0 -0
  23. {docassert-0.11.0 → docassert-0.12.1}/docassert/_data/criteria/raci-stakeholder.criteria.yaml +0 -0
  24. {docassert-0.11.0 → docassert-0.12.1}/docassert/_data/criteria/release-cutover-plan.criteria.yaml +0 -0
  25. {docassert-0.11.0 → docassert-0.12.1}/docassert/_data/criteria/risk-register.criteria.yaml +0 -0
  26. {docassert-0.11.0 → docassert-0.12.1}/docassert/_data/criteria/rollback-plan.criteria.yaml +0 -0
  27. {docassert-0.11.0 → docassert-0.12.1}/docassert/_data/criteria/runbook.criteria.yaml +0 -0
  28. {docassert-0.11.0 → docassert-0.12.1}/docassert/_data/criteria/status-report.criteria.yaml +0 -0
  29. {docassert-0.11.0 → docassert-0.12.1}/docassert/_data/criteria/test-cases.criteria.yaml +0 -0
  30. {docassert-0.11.0 → docassert-0.12.1}/docassert/_data/criteria/user-story.criteria.yaml +0 -0
  31. {docassert-0.11.0 → docassert-0.12.1}/docassert/_data/profiles/agile-delivery.yaml +0 -0
  32. {docassert-0.11.0 → docassert-0.12.1}/docassert/_data/profiles/lean-startup.yaml +0 -0
  33. {docassert-0.11.0 → docassert-0.12.1}/docassert/_data/profiles/regulated-industry.yaml +0 -0
  34. {docassert-0.11.0 → docassert-0.12.1}/docassert/_data/schema/adr.schema.json +0 -0
  35. {docassert-0.11.0 → docassert-0.12.1}/docassert/_data/schema/benefits-realization.schema.json +0 -0
  36. {docassert-0.11.0 → docassert-0.12.1}/docassert/_data/schema/brd.schema.json +0 -0
  37. {docassert-0.11.0 → docassert-0.12.1}/docassert/_data/schema/business-case.schema.json +0 -0
  38. {docassert-0.11.0 → docassert-0.12.1}/docassert/_data/schema/charter.schema.json +0 -0
  39. {docassert-0.11.0 → docassert-0.12.1}/docassert/_data/schema/data-migration-plan.schema.json +0 -0
  40. {docassert-0.11.0 → docassert-0.12.1}/docassert/_data/schema/frnfr.schema.json +0 -0
  41. {docassert-0.11.0 → docassert-0.12.1}/docassert/_data/schema/hypercare-plan.schema.json +0 -0
  42. {docassert-0.11.0 → docassert-0.12.1}/docassert/_data/schema/post-implementation-review.schema.json +0 -0
  43. {docassert-0.11.0 → docassert-0.12.1}/docassert/_data/schema/prd.schema.json +0 -0
  44. {docassert-0.11.0 → docassert-0.12.1}/docassert/_data/schema/project.schema.json +0 -0
  45. {docassert-0.11.0 → docassert-0.12.1}/docassert/_data/schema/qa-test-plan.schema.json +0 -0
  46. {docassert-0.11.0 → docassert-0.12.1}/docassert/_data/schema/raci-stakeholder.schema.json +0 -0
  47. {docassert-0.11.0 → docassert-0.12.1}/docassert/_data/schema/release-cutover-plan.schema.json +0 -0
  48. {docassert-0.11.0 → docassert-0.12.1}/docassert/_data/schema/risk-register.schema.json +0 -0
  49. {docassert-0.11.0 → docassert-0.12.1}/docassert/_data/schema/rollback-plan.schema.json +0 -0
  50. {docassert-0.11.0 → docassert-0.12.1}/docassert/_data/schema/runbook.schema.json +0 -0
  51. {docassert-0.11.0 → docassert-0.12.1}/docassert/_data/schema/status-report.schema.json +0 -0
  52. {docassert-0.11.0 → docassert-0.12.1}/docassert/_data/schema/test-cases.schema.json +0 -0
  53. {docassert-0.11.0 → docassert-0.12.1}/docassert/_data/schema/user-story.schema.json +0 -0
  54. {docassert-0.11.0 → docassert-0.12.1}/docassert/_data/skills/doc-to-pmo/SKILL.md +0 -0
  55. {docassert-0.11.0 → docassert-0.12.1}/docassert/_data/templates/adr.template.md +0 -0
  56. {docassert-0.11.0 → docassert-0.12.1}/docassert/_data/templates/benefits-realization.template.md +0 -0
  57. {docassert-0.11.0 → docassert-0.12.1}/docassert/_data/templates/brd.template.md +0 -0
  58. {docassert-0.11.0 → docassert-0.12.1}/docassert/_data/templates/business-case.template.md +0 -0
  59. {docassert-0.11.0 → docassert-0.12.1}/docassert/_data/templates/charter.template.md +0 -0
  60. {docassert-0.11.0 → docassert-0.12.1}/docassert/_data/templates/data-migration-plan.template.md +0 -0
  61. {docassert-0.11.0 → docassert-0.12.1}/docassert/_data/templates/frnfr.template.md +0 -0
  62. {docassert-0.11.0 → docassert-0.12.1}/docassert/_data/templates/hypercare-plan.template.md +0 -0
  63. {docassert-0.11.0 → docassert-0.12.1}/docassert/_data/templates/post-implementation-review.template.md +0 -0
  64. {docassert-0.11.0 → docassert-0.12.1}/docassert/_data/templates/prd.template.md +0 -0
  65. {docassert-0.11.0 → docassert-0.12.1}/docassert/_data/templates/project.template.md +0 -0
  66. {docassert-0.11.0 → docassert-0.12.1}/docassert/_data/templates/qa-test-plan.template.md +0 -0
  67. {docassert-0.11.0 → docassert-0.12.1}/docassert/_data/templates/raci-stakeholder.template.md +0 -0
  68. {docassert-0.11.0 → docassert-0.12.1}/docassert/_data/templates/release-cutover-plan.template.md +0 -0
  69. {docassert-0.11.0 → docassert-0.12.1}/docassert/_data/templates/risk-register.template.md +0 -0
  70. {docassert-0.11.0 → docassert-0.12.1}/docassert/_data/templates/rollback-plan.template.md +0 -0
  71. {docassert-0.11.0 → docassert-0.12.1}/docassert/_data/templates/runbook.template.md +0 -0
  72. {docassert-0.11.0 → docassert-0.12.1}/docassert/_data/templates/status-report.template.md +0 -0
  73. {docassert-0.11.0 → docassert-0.12.1}/docassert/_data/templates/test-cases.template.md +0 -0
  74. {docassert-0.11.0 → docassert-0.12.1}/docassert/_data/templates/user-story.template.md +0 -0
  75. {docassert-0.11.0 → docassert-0.12.1}/docassert/bridge/__init__.py +0 -0
  76. {docassert-0.11.0 → docassert-0.12.1}/docassert/bridge/board.py +0 -0
  77. {docassert-0.11.0 → docassert-0.12.1}/docassert/bridge/gh.py +0 -0
  78. {docassert-0.11.0 → docassert-0.12.1}/docassert/bridge/ops.py +0 -0
  79. {docassert-0.11.0 → docassert-0.12.1}/docassert/bridge/plan.py +0 -0
  80. {docassert-0.11.0 → docassert-0.12.1}/docassert/cli.py +0 -0
  81. {docassert-0.11.0 → docassert-0.12.1}/docassert/config.py +0 -0
  82. {docassert-0.11.0 → docassert-0.12.1}/docassert/extract.py +0 -0
  83. {docassert-0.11.0 → docassert-0.12.1}/docassert/graph.py +0 -0
  84. {docassert-0.11.0 → docassert-0.12.1}/docassert/loader.py +0 -0
  85. {docassert-0.11.0 → docassert-0.12.1}/docassert/models.py +0 -0
  86. {docassert-0.11.0 → docassert-0.12.1}/docassert/profiles.py +0 -0
  87. {docassert-0.11.0 → docassert-0.12.1}/docassert/projects.py +0 -0
  88. {docassert-0.11.0 → docassert-0.12.1}/docassert/report.py +0 -0
  89. {docassert-0.11.0 → docassert-0.12.1}/docassert/rtm.py +0 -0
  90. {docassert-0.11.0 → docassert-0.12.1}/docassert/scaffold.py +0 -0
  91. {docassert-0.11.0 → docassert-0.12.1}/docassert/semantic.py +0 -0
  92. {docassert-0.11.0 → docassert-0.12.1}/docassert/status/__init__.py +0 -0
  93. {docassert-0.11.0 → docassert-0.12.1}/docassert/status/derive.py +0 -0
  94. {docassert-0.11.0 → docassert-0.12.1}/docassert/status/render.py +0 -0
  95. {docassert-0.11.0 → docassert-0.12.1}/docassert/structural.py +0 -0
  96. {docassert-0.11.0 → docassert-0.12.1}/docassert.egg-info/SOURCES.txt +0 -0
  97. {docassert-0.11.0 → docassert-0.12.1}/docassert.egg-info/dependency_links.txt +0 -0
  98. {docassert-0.11.0 → docassert-0.12.1}/docassert.egg-info/entry_points.txt +0 -0
  99. {docassert-0.11.0 → docassert-0.12.1}/docassert.egg-info/requires.txt +0 -0
  100. {docassert-0.11.0 → docassert-0.12.1}/docassert.egg-info/top_level.txt +0 -0
  101. {docassert-0.11.0 → docassert-0.12.1}/pyproject.toml +0 -0
  102. {docassert-0.11.0 → docassert-0.12.1}/setup.cfg +0 -0
  103. {docassert-0.11.0 → docassert-0.12.1}/tests/test_badge.py +0 -0
  104. {docassert-0.11.0 → docassert-0.12.1}/tests/test_bridge.py +0 -0
  105. {docassert-0.11.0 → docassert-0.12.1}/tests/test_config.py +0 -0
  106. {docassert-0.11.0 → docassert-0.12.1}/tests/test_consistency.py +0 -0
  107. {docassert-0.11.0 → docassert-0.12.1}/tests/test_defects.py +0 -0
  108. {docassert-0.11.0 → docassert-0.12.1}/tests/test_draft_relaxation.py +0 -0
  109. {docassert-0.11.0 → docassert-0.12.1}/tests/test_extract.py +0 -0
  110. {docassert-0.11.0 → docassert-0.12.1}/tests/test_graph.py +0 -0
  111. {docassert-0.11.0 → docassert-0.12.1}/tests/test_json_report.py +0 -0
  112. {docassert-0.11.0 → docassert-0.12.1}/tests/test_kinds_delivery.py +0 -0
  113. {docassert-0.11.0 → docassert-0.12.1}/tests/test_kinds_governance.py +0 -0
  114. {docassert-0.11.0 → docassert-0.12.1}/tests/test_kinds_operate.py +0 -0
  115. {docassert-0.11.0 → docassert-0.12.1}/tests/test_kinds_reporting.py +0 -0
  116. {docassert-0.11.0 → docassert-0.12.1}/tests/test_profiles.py +0 -0
  117. {docassert-0.11.0 → docassert-0.12.1}/tests/test_projects.py +0 -0
  118. {docassert-0.11.0 → docassert-0.12.1}/tests/test_scaffold.py +0 -0
  119. {docassert-0.11.0 → docassert-0.12.1}/tests/test_status.py +0 -0
  120. {docassert-0.11.0 → docassert-0.12.1}/tests/test_structural.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: docassert
3
- Version: 0.11.0
3
+ Version: 0.12.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
@@ -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__ = "0.11.0"
8
+ __version__ = "0.12.1"
@@ -39,7 +39,25 @@ coverage:
39
39
  # (0 = no cap).
40
40
  alignment_limit: 25
41
41
 
42
+ # Rules match in order; the first matching rule grades a link. Typed rules
43
+ # (child_type/parent_type) come before the generic ones.
42
44
  alignment:
45
+ - relation: traces
46
+ child_type: PR
47
+ parent_type: BR
48
+ prompt: >
49
+ The PARENT is a business outcome or KPI; the CHILD is a product
50
+ mechanism tracing to it. Judge whether delivering the child would
51
+ plausibly and materially contribute to achieving the parent outcome.
52
+ The child need not restate the metric; penalise only mechanisms that
53
+ would not meaningfully move the parent outcome, or that contradict it.
54
+ - relation: traces
55
+ child_type: US
56
+ prompt: >
57
+ The CHILD is a user story implementing the PARENT requirement. A story
58
+ may deliver one slice of the requirement, with sibling stories covering
59
+ the rest, so do not penalise a story for partial coverage. Penalise
60
+ stories that implement nothing the parent states or contradict it.
43
61
  - relation: traces
44
62
  prompt: >
45
63
  Judge whether the CHILD requirement genuinely refines or implements the
@@ -47,8 +65,11 @@ alignment:
47
65
  related. Penalise links that don't actually follow from the parent.
48
66
  - relation: verifies
49
67
  prompt: >
50
- Judge whether the acceptance criterion actually verifies the requirement
51
- it targets: testable, and covering the requirement's intent.
68
+ Judge whether the acceptance criterion concretely and testably verifies
69
+ some aspect of the requirement it targets. Several criteria may share
70
+ one requirement, each covering a slice, so do not penalise a criterion
71
+ for leaving other clauses to its siblings. Penalise criteria that are
72
+ untestable, verify nothing the requirement states, or contradict it.
52
73
  - relation: tests
53
74
  prompt: >
54
75
  Judge whether the test case actually exercises the acceptance criterion
@@ -143,13 +143,29 @@ DEFAULT_ALIGNMENT_LIMIT = 25
143
143
 
144
144
  def run_alignment_checks(graph, config) -> list[CheckResult]:
145
145
  edges = [] # (prompt, parent, child, relation)
146
+ seen: set[tuple[str, str, str]] = set()
147
+ # Rules match in order and the first matching rule grades a link, so a
148
+ # typed rule (child_type/parent_type) placed before the generic one can
149
+ # give e.g. PR->BR traces a contribution rubric while other traces keep
150
+ # the refinement rubric.
146
151
  for rule in config.get("alignment", []):
147
152
  relation, prompt = rule["relation"], rule.get("prompt", "").strip()
153
+ child_type = rule.get("child_type")
154
+ parent_type = rule.get("parent_type")
148
155
  for child in graph.all_items():
156
+ if child_type and child.type != child_type:
157
+ continue
149
158
  for target in child.targets(relation):
150
159
  parent = graph.canonical(target)
151
- if parent is not None:
152
- edges.append((prompt, parent, child, relation))
160
+ if parent is None:
161
+ continue
162
+ if parent_type and parent.type != parent_type:
163
+ continue
164
+ key = (child.id, relation, parent.id)
165
+ if key in seen:
166
+ continue
167
+ seen.add(key)
168
+ edges.append((prompt, parent, child, relation))
153
169
 
154
170
  if not edges:
155
171
  return []
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: docassert
3
- Version: 0.11.0
3
+ Version: 0.12.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
@@ -120,3 +120,62 @@ def test_alignment_limit_zero_grades_everything(tmp_path, monkeypatch):
120
120
  "alignment_limit": 0}
121
121
  consistency.run_alignment_checks(graph, config)
122
122
  assert len(calls) == 4
123
+
124
+
125
+ # ── typed rules: first match grades the link ─────────────────────────────────
126
+ def _typed_graph():
127
+ from docassert.graph import Graph
128
+ g = Graph()
129
+ g.add(Item("TST-BR-001", "TST", "BR", "the business outcome", {},
130
+ "d.md", "brd", "approved", "S"))
131
+ g.add(Item("TST-PR-001", "TST", "PR", "the product mechanism",
132
+ {"traces": ["TST-BR-001"]}, "d.md", "prd", "approved", "S"))
133
+ g.add(Item("TST-US-001", "TST", "US", "the story",
134
+ {"traces": ["TST-PR-001"]}, "d.md", "user-story",
135
+ "approved", "S"))
136
+ return g
137
+
138
+
139
+ TYPED_CONFIG = {"alignment": [
140
+ {"relation": "traces", "child_type": "PR", "parent_type": "BR",
141
+ "prompt": "contribution rubric"},
142
+ {"relation": "traces", "prompt": "refinement rubric"},
143
+ ], "alignment_limit": 0}
144
+
145
+
146
+ def test_typed_rule_grades_matching_links_first(tmp_path, monkeypatch):
147
+ _use_tmp_cache(tmp_path, monkeypatch)
148
+ prompts = []
149
+ monkeypatch.setattr(semantic, "_grade", lambda p, c, m: (
150
+ prompts.append(p) or {"score": 1.0, "pass": True, "rationale": "ok"}))
151
+ results = consistency.run_alignment_checks(_typed_graph(), TYPED_CONFIG)
152
+ graded = {r.check_id for r in results if r.check_id.startswith("align:")}
153
+ assert graded == {"align:TST-PR-001-traces-TST-BR-001",
154
+ "align:TST-US-001-traces-TST-PR-001"}
155
+ assert sorted(prompts) == ["contribution rubric", "refinement rubric"]
156
+
157
+
158
+ def test_typed_rule_does_not_double_grade(tmp_path, monkeypatch):
159
+ _use_tmp_cache(tmp_path, monkeypatch)
160
+ calls = []
161
+ monkeypatch.setattr(semantic, "_grade", lambda p, c, m: (
162
+ calls.append((p, c)) or {"score": 1.0, "pass": True, "rationale": "ok"}))
163
+ consistency.run_alignment_checks(_typed_graph(), TYPED_CONFIG)
164
+ assert len(calls) == 2 # one grade per link, despite two matching relations
165
+
166
+
167
+ def test_packaged_defaults_carry_typed_rules():
168
+ from docassert import config as config_mod
169
+ cfg = config_mod.read_consistency_config()
170
+ rules = cfg.get("alignment", [])
171
+ typed = [r for r in rules if r.get("child_type") == "PR"
172
+ and r.get("parent_type") == "BR"]
173
+ assert typed and rules.index(typed[0]) < len(rules) - 1
174
+ assert "contribute" in typed[0]["prompt"]
175
+ verifies = [r for r in rules if r["relation"] == "verifies"][0]
176
+ assert "slice" in verifies["prompt"]
177
+ story = [r for r in rules if r.get("child_type") == "US"][0]
178
+ assert "slice" in story["prompt"]
179
+ assert rules.index(story) < rules.index(
180
+ [r for r in rules if r["relation"] == "traces"
181
+ and not r.get("child_type") and not r.get("parent_type")][0])
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes