docassert 0.12.1__tar.gz → 0.13.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.
Files changed (120) hide show
  1. {docassert-0.12.1/docassert.egg-info → docassert-0.13.0}/PKG-INFO +1 -1
  2. {docassert-0.12.1 → docassert-0.13.0}/docassert/__init__.py +1 -1
  3. {docassert-0.12.1 → docassert-0.13.0}/docassert/status/derive.py +15 -0
  4. {docassert-0.12.1 → docassert-0.13.0}/docassert/status/render.py +22 -4
  5. {docassert-0.12.1 → docassert-0.13.0/docassert.egg-info}/PKG-INFO +1 -1
  6. {docassert-0.12.1 → docassert-0.13.0}/tests/test_status.py +33 -0
  7. {docassert-0.12.1 → docassert-0.13.0}/LICENSE +0 -0
  8. {docassert-0.12.1 → docassert-0.13.0}/NOTICE +0 -0
  9. {docassert-0.12.1 → docassert-0.13.0}/README.md +0 -0
  10. {docassert-0.12.1 → docassert-0.13.0}/docassert/__main__.py +0 -0
  11. {docassert-0.12.1 → docassert-0.13.0}/docassert/_data/consistency.yaml +0 -0
  12. {docassert-0.12.1 → docassert-0.13.0}/docassert/_data/criteria/adr.criteria.yaml +0 -0
  13. {docassert-0.12.1 → docassert-0.13.0}/docassert/_data/criteria/benefits-realization.criteria.yaml +0 -0
  14. {docassert-0.12.1 → docassert-0.13.0}/docassert/_data/criteria/brd.criteria.yaml +0 -0
  15. {docassert-0.12.1 → docassert-0.13.0}/docassert/_data/criteria/business-case.criteria.yaml +0 -0
  16. {docassert-0.12.1 → docassert-0.13.0}/docassert/_data/criteria/charter.criteria.yaml +0 -0
  17. {docassert-0.12.1 → docassert-0.13.0}/docassert/_data/criteria/data-migration-plan.criteria.yaml +0 -0
  18. {docassert-0.12.1 → docassert-0.13.0}/docassert/_data/criteria/frnfr.criteria.yaml +0 -0
  19. {docassert-0.12.1 → docassert-0.13.0}/docassert/_data/criteria/hypercare-plan.criteria.yaml +0 -0
  20. {docassert-0.12.1 → docassert-0.13.0}/docassert/_data/criteria/post-implementation-review.criteria.yaml +0 -0
  21. {docassert-0.12.1 → docassert-0.13.0}/docassert/_data/criteria/prd.criteria.yaml +0 -0
  22. {docassert-0.12.1 → docassert-0.13.0}/docassert/_data/criteria/project.criteria.yaml +0 -0
  23. {docassert-0.12.1 → docassert-0.13.0}/docassert/_data/criteria/qa-test-plan.criteria.yaml +0 -0
  24. {docassert-0.12.1 → docassert-0.13.0}/docassert/_data/criteria/raci-stakeholder.criteria.yaml +0 -0
  25. {docassert-0.12.1 → docassert-0.13.0}/docassert/_data/criteria/release-cutover-plan.criteria.yaml +0 -0
  26. {docassert-0.12.1 → docassert-0.13.0}/docassert/_data/criteria/risk-register.criteria.yaml +0 -0
  27. {docassert-0.12.1 → docassert-0.13.0}/docassert/_data/criteria/rollback-plan.criteria.yaml +0 -0
  28. {docassert-0.12.1 → docassert-0.13.0}/docassert/_data/criteria/runbook.criteria.yaml +0 -0
  29. {docassert-0.12.1 → docassert-0.13.0}/docassert/_data/criteria/status-report.criteria.yaml +0 -0
  30. {docassert-0.12.1 → docassert-0.13.0}/docassert/_data/criteria/test-cases.criteria.yaml +0 -0
  31. {docassert-0.12.1 → docassert-0.13.0}/docassert/_data/criteria/user-story.criteria.yaml +0 -0
  32. {docassert-0.12.1 → docassert-0.13.0}/docassert/_data/profiles/agile-delivery.yaml +0 -0
  33. {docassert-0.12.1 → docassert-0.13.0}/docassert/_data/profiles/lean-startup.yaml +0 -0
  34. {docassert-0.12.1 → docassert-0.13.0}/docassert/_data/profiles/regulated-industry.yaml +0 -0
  35. {docassert-0.12.1 → docassert-0.13.0}/docassert/_data/schema/adr.schema.json +0 -0
  36. {docassert-0.12.1 → docassert-0.13.0}/docassert/_data/schema/benefits-realization.schema.json +0 -0
  37. {docassert-0.12.1 → docassert-0.13.0}/docassert/_data/schema/brd.schema.json +0 -0
  38. {docassert-0.12.1 → docassert-0.13.0}/docassert/_data/schema/business-case.schema.json +0 -0
  39. {docassert-0.12.1 → docassert-0.13.0}/docassert/_data/schema/charter.schema.json +0 -0
  40. {docassert-0.12.1 → docassert-0.13.0}/docassert/_data/schema/data-migration-plan.schema.json +0 -0
  41. {docassert-0.12.1 → docassert-0.13.0}/docassert/_data/schema/frnfr.schema.json +0 -0
  42. {docassert-0.12.1 → docassert-0.13.0}/docassert/_data/schema/hypercare-plan.schema.json +0 -0
  43. {docassert-0.12.1 → docassert-0.13.0}/docassert/_data/schema/post-implementation-review.schema.json +0 -0
  44. {docassert-0.12.1 → docassert-0.13.0}/docassert/_data/schema/prd.schema.json +0 -0
  45. {docassert-0.12.1 → docassert-0.13.0}/docassert/_data/schema/project.schema.json +0 -0
  46. {docassert-0.12.1 → docassert-0.13.0}/docassert/_data/schema/qa-test-plan.schema.json +0 -0
  47. {docassert-0.12.1 → docassert-0.13.0}/docassert/_data/schema/raci-stakeholder.schema.json +0 -0
  48. {docassert-0.12.1 → docassert-0.13.0}/docassert/_data/schema/release-cutover-plan.schema.json +0 -0
  49. {docassert-0.12.1 → docassert-0.13.0}/docassert/_data/schema/risk-register.schema.json +0 -0
  50. {docassert-0.12.1 → docassert-0.13.0}/docassert/_data/schema/rollback-plan.schema.json +0 -0
  51. {docassert-0.12.1 → docassert-0.13.0}/docassert/_data/schema/runbook.schema.json +0 -0
  52. {docassert-0.12.1 → docassert-0.13.0}/docassert/_data/schema/status-report.schema.json +0 -0
  53. {docassert-0.12.1 → docassert-0.13.0}/docassert/_data/schema/test-cases.schema.json +0 -0
  54. {docassert-0.12.1 → docassert-0.13.0}/docassert/_data/schema/user-story.schema.json +0 -0
  55. {docassert-0.12.1 → docassert-0.13.0}/docassert/_data/skills/doc-to-pmo/SKILL.md +0 -0
  56. {docassert-0.12.1 → docassert-0.13.0}/docassert/_data/templates/adr.template.md +0 -0
  57. {docassert-0.12.1 → docassert-0.13.0}/docassert/_data/templates/benefits-realization.template.md +0 -0
  58. {docassert-0.12.1 → docassert-0.13.0}/docassert/_data/templates/brd.template.md +0 -0
  59. {docassert-0.12.1 → docassert-0.13.0}/docassert/_data/templates/business-case.template.md +0 -0
  60. {docassert-0.12.1 → docassert-0.13.0}/docassert/_data/templates/charter.template.md +0 -0
  61. {docassert-0.12.1 → docassert-0.13.0}/docassert/_data/templates/data-migration-plan.template.md +0 -0
  62. {docassert-0.12.1 → docassert-0.13.0}/docassert/_data/templates/frnfr.template.md +0 -0
  63. {docassert-0.12.1 → docassert-0.13.0}/docassert/_data/templates/hypercare-plan.template.md +0 -0
  64. {docassert-0.12.1 → docassert-0.13.0}/docassert/_data/templates/post-implementation-review.template.md +0 -0
  65. {docassert-0.12.1 → docassert-0.13.0}/docassert/_data/templates/prd.template.md +0 -0
  66. {docassert-0.12.1 → docassert-0.13.0}/docassert/_data/templates/project.template.md +0 -0
  67. {docassert-0.12.1 → docassert-0.13.0}/docassert/_data/templates/qa-test-plan.template.md +0 -0
  68. {docassert-0.12.1 → docassert-0.13.0}/docassert/_data/templates/raci-stakeholder.template.md +0 -0
  69. {docassert-0.12.1 → docassert-0.13.0}/docassert/_data/templates/release-cutover-plan.template.md +0 -0
  70. {docassert-0.12.1 → docassert-0.13.0}/docassert/_data/templates/risk-register.template.md +0 -0
  71. {docassert-0.12.1 → docassert-0.13.0}/docassert/_data/templates/rollback-plan.template.md +0 -0
  72. {docassert-0.12.1 → docassert-0.13.0}/docassert/_data/templates/runbook.template.md +0 -0
  73. {docassert-0.12.1 → docassert-0.13.0}/docassert/_data/templates/status-report.template.md +0 -0
  74. {docassert-0.12.1 → docassert-0.13.0}/docassert/_data/templates/test-cases.template.md +0 -0
  75. {docassert-0.12.1 → docassert-0.13.0}/docassert/_data/templates/user-story.template.md +0 -0
  76. {docassert-0.12.1 → docassert-0.13.0}/docassert/bridge/__init__.py +0 -0
  77. {docassert-0.12.1 → docassert-0.13.0}/docassert/bridge/board.py +0 -0
  78. {docassert-0.12.1 → docassert-0.13.0}/docassert/bridge/gh.py +0 -0
  79. {docassert-0.12.1 → docassert-0.13.0}/docassert/bridge/ops.py +0 -0
  80. {docassert-0.12.1 → docassert-0.13.0}/docassert/bridge/plan.py +0 -0
  81. {docassert-0.12.1 → docassert-0.13.0}/docassert/cli.py +0 -0
  82. {docassert-0.12.1 → docassert-0.13.0}/docassert/config.py +0 -0
  83. {docassert-0.12.1 → docassert-0.13.0}/docassert/consistency.py +0 -0
  84. {docassert-0.12.1 → docassert-0.13.0}/docassert/extract.py +0 -0
  85. {docassert-0.12.1 → docassert-0.13.0}/docassert/graph.py +0 -0
  86. {docassert-0.12.1 → docassert-0.13.0}/docassert/loader.py +0 -0
  87. {docassert-0.12.1 → docassert-0.13.0}/docassert/models.py +0 -0
  88. {docassert-0.12.1 → docassert-0.13.0}/docassert/profiles.py +0 -0
  89. {docassert-0.12.1 → docassert-0.13.0}/docassert/projects.py +0 -0
  90. {docassert-0.12.1 → docassert-0.13.0}/docassert/report.py +0 -0
  91. {docassert-0.12.1 → docassert-0.13.0}/docassert/rtm.py +0 -0
  92. {docassert-0.12.1 → docassert-0.13.0}/docassert/scaffold.py +0 -0
  93. {docassert-0.12.1 → docassert-0.13.0}/docassert/semantic.py +0 -0
  94. {docassert-0.12.1 → docassert-0.13.0}/docassert/status/__init__.py +0 -0
  95. {docassert-0.12.1 → docassert-0.13.0}/docassert/structural.py +0 -0
  96. {docassert-0.12.1 → docassert-0.13.0}/docassert.egg-info/SOURCES.txt +0 -0
  97. {docassert-0.12.1 → docassert-0.13.0}/docassert.egg-info/dependency_links.txt +0 -0
  98. {docassert-0.12.1 → docassert-0.13.0}/docassert.egg-info/entry_points.txt +0 -0
  99. {docassert-0.12.1 → docassert-0.13.0}/docassert.egg-info/requires.txt +0 -0
  100. {docassert-0.12.1 → docassert-0.13.0}/docassert.egg-info/top_level.txt +0 -0
  101. {docassert-0.12.1 → docassert-0.13.0}/pyproject.toml +0 -0
  102. {docassert-0.12.1 → docassert-0.13.0}/setup.cfg +0 -0
  103. {docassert-0.12.1 → docassert-0.13.0}/tests/test_badge.py +0 -0
  104. {docassert-0.12.1 → docassert-0.13.0}/tests/test_bridge.py +0 -0
  105. {docassert-0.12.1 → docassert-0.13.0}/tests/test_config.py +0 -0
  106. {docassert-0.12.1 → docassert-0.13.0}/tests/test_consistency.py +0 -0
  107. {docassert-0.12.1 → docassert-0.13.0}/tests/test_defects.py +0 -0
  108. {docassert-0.12.1 → docassert-0.13.0}/tests/test_draft_relaxation.py +0 -0
  109. {docassert-0.12.1 → docassert-0.13.0}/tests/test_extract.py +0 -0
  110. {docassert-0.12.1 → docassert-0.13.0}/tests/test_graph.py +0 -0
  111. {docassert-0.12.1 → docassert-0.13.0}/tests/test_json_report.py +0 -0
  112. {docassert-0.12.1 → docassert-0.13.0}/tests/test_kinds_delivery.py +0 -0
  113. {docassert-0.12.1 → docassert-0.13.0}/tests/test_kinds_governance.py +0 -0
  114. {docassert-0.12.1 → docassert-0.13.0}/tests/test_kinds_operate.py +0 -0
  115. {docassert-0.12.1 → docassert-0.13.0}/tests/test_kinds_reporting.py +0 -0
  116. {docassert-0.12.1 → docassert-0.13.0}/tests/test_profiles.py +0 -0
  117. {docassert-0.12.1 → docassert-0.13.0}/tests/test_projects.py +0 -0
  118. {docassert-0.12.1 → docassert-0.13.0}/tests/test_scaffold.py +0 -0
  119. {docassert-0.12.1 → docassert-0.13.0}/tests/test_semantic.py +0 -0
  120. {docassert-0.12.1 → docassert-0.13.0}/tests/test_structural.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: docassert
3
- Version: 0.12.1
3
+ Version: 0.13.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
@@ -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.12.1"
8
+ __version__ = "0.13.0"
@@ -5,6 +5,7 @@ lives in docassert.status.render.
5
5
  """
6
6
  from __future__ import annotations
7
7
 
8
+ import re
8
9
  from pathlib import Path
9
10
 
10
11
  from .. import config as config_mod
@@ -63,6 +64,10 @@ def _coverage(graph, config, code=None):
63
64
  return out
64
65
 
65
66
 
67
+ _RISK_FIELD_RE = re.compile(
68
+ r"\s*(?:Probability|Impact|Owner|Response)\s*:", re.IGNORECASE)
69
+
70
+
66
71
  def _risks(graph, code=None):
67
72
  risks = []
68
73
  for item in graph.by_type.get("RISK", []):
@@ -70,11 +75,21 @@ def _risks(graph, code=None):
70
75
  continue
71
76
  prob = (_field_value(item.text, "probability") or "").lower()
72
77
  impact = (_field_value(item.text, "impact") or "").lower()
78
+ # The description is the item text up to the first metadata field;
79
+ # the response runs from its label to the end (it may hold clauses
80
+ # that _field_value would truncate at a sentence break).
81
+ m = _RISK_FIELD_RE.search(item.text)
82
+ description = (item.text[:m.start()] if m else item.text).strip()
83
+ rm = re.search(r"Response\s*:\s*(.+)$", item.text,
84
+ re.IGNORECASE | re.DOTALL)
73
85
  risks.append({
74
86
  "id": item.id,
87
+ "description": description,
88
+ "threatens": item.links.get("threatens", []),
75
89
  "probability": prob or "?",
76
90
  "impact": impact or "?",
77
91
  "owner": _field_value(item.text, "owner") or "?",
92
+ "response": rm.group(1).strip() if rm else "",
78
93
  "score": _SEVERITY.get(prob, 0) * _SEVERITY.get(impact, 0),
79
94
  })
80
95
  return sorted(risks, key=lambda r: -r["score"])
@@ -143,9 +143,27 @@ def render_html(model) -> str:
143
143
  + (";background:var(--amber)" if cov["gaps"] else "") + '"></div></div></div>'
144
144
  for cov in model["coverage"])
145
145
 
146
- risks = "".join(
147
- f'<li><code>{esc(r["id"])}</code> — {esc(r["probability"])}/{esc(r["impact"])}'
148
- f' · owner {esc(r["owner"])}</li>' for r in model["risks"]) or "<li>None open.</li>"
146
+ def sev(value):
147
+ color = {"critical": "var(--bad)", "high": "var(--bad)",
148
+ "medium": "var(--amber)", "low": "var(--ok)"}.get(
149
+ value, "var(--muted)")
150
+ return f'<td style="color:{color};font-weight:600;">{esc(value)}</td>'
151
+
152
+ if model["risks"]:
153
+ risk_rows = "".join(
154
+ f'<tr><td><code>{esc(r["id"])}</code></td>'
155
+ f'<td>{esc(r["description"])}</td>'
156
+ f'<td>{", ".join(f"<code>{esc(b)}</code>" for b in r["threatens"]) or "—"}</td>'
157
+ + sev(r["probability"]) + sev(r["impact"])
158
+ + f'<td>{esc(r["owner"])}</td>'
159
+ f'<td>{esc(r["response"]) or "—"}</td></tr>'
160
+ for r in model["risks"])
161
+ risks = ('<table><thead><tr><th>ID</th><th>Risk</th><th>Threatens</th>'
162
+ '<th>Probability</th><th>Impact</th><th>Owner</th>'
163
+ '<th>Response</th></tr></thead>'
164
+ f'<tbody>{risk_rows}</tbody></table>')
165
+ else:
166
+ risks = "<p>None open.</p>"
149
167
 
150
168
  problems = ""
151
169
  if model["broken_references"]:
@@ -262,7 +280,7 @@ def render_html(model) -> str:
262
280
  {document_set}
263
281
  {execution_html}
264
282
  {problems}
265
- <section><h2>Open risks ({len(model['risks'])})</h2><ul>{risks}</ul></section>
283
+ <section><h2>Open risks ({len(model['risks'])})</h2>{risks}</section>
266
284
  <section><h2>Latest status report</h2><p>{report}</p></section>
267
285
  <section><h2>Documents ({c['total']})</h2>
268
286
  <table><thead><tr><th>Kind</th><th>ID</th><th>Status</th><th>Audit</th></tr></thead>
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: docassert
3
- Version: 0.12.1
3
+ Version: 0.13.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
@@ -129,3 +129,36 @@ def test_render_project_page_has_back_link_and_scoped_title():
129
129
  assert 'href="index.html"' in out # back to the portfolio index
130
130
  assert "Atlas" in out and "AMBER" in out
131
131
  assert "http://" not in out and "https://" not in out
132
+
133
+
134
+ # ── the risk model carries the full story ────────────────────────────────────
135
+ def test_risks_carry_description_threatens_and_response():
136
+ _cd_root()
137
+ m = S.build_status(ROOT / "documents")
138
+ r = next(r for r in m["risks"] if r["id"] == "AUR-RISK-001")
139
+ assert r["description"] and "Probability" not in r["description"]
140
+ assert r["threatens"] # links to the BRs at stake
141
+ assert r["response"] # the full mitigation text
142
+ assert r["probability"] in {"low", "medium", "high", "critical", "?"}
143
+
144
+
145
+ def test_risks_tolerate_missing_fields():
146
+ from docassert.graph import Graph
147
+ from docassert.models import Item
148
+ from docassert.status.derive import _risks
149
+ g = Graph()
150
+ g.add(Item("XX-RISK-001", "XX", "RISK", "Bare risk with no fields yet.",
151
+ {}, "d.md", "risk-register", "draft", "S"))
152
+ (r,) = _risks(g)
153
+ assert r["description"] == "Bare risk with no fields yet."
154
+ assert r["response"] == "" and r["probability"] == "?"
155
+
156
+
157
+ def test_render_html_risk_table():
158
+ _cd_root()
159
+ out = S.render_html(S.build_status(ROOT / "documents"))
160
+ assert "<th>Risk</th>" in out and "<th>Response</th>" in out
161
+ assert "<th>Threatens</th>" in out and "<th>Owner</th>" in out
162
+ # severity cells are colored
163
+ assert 'style="color:var(--bad);font-weight:600;">high</td>' in out \
164
+ or 'style="color:var(--amber);font-weight:600;">medium</td>' in out
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes