docassert 0.20.0__tar.gz → 0.20.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.
- {docassert-0.20.0/docassert.egg-info → docassert-0.20.1}/PKG-INFO +1 -1
- {docassert-0.20.0 → docassert-0.20.1}/docassert/__init__.py +1 -1
- {docassert-0.20.0 → docassert-0.20.1}/docassert/status/render.py +56 -10
- {docassert-0.20.0 → docassert-0.20.1/docassert.egg-info}/PKG-INFO +1 -1
- {docassert-0.20.0 → docassert-0.20.1}/tests/test_status.py +12 -0
- {docassert-0.20.0 → docassert-0.20.1}/LICENSE +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/NOTICE +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/README.md +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert/__main__.py +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert/_data/consistency.yaml +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert/_data/criteria/adr.criteria.yaml +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert/_data/criteria/benefits-realization.criteria.yaml +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert/_data/criteria/brd.criteria.yaml +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert/_data/criteria/business-case.criteria.yaml +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert/_data/criteria/charter.criteria.yaml +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert/_data/criteria/data-migration-plan.criteria.yaml +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert/_data/criteria/frnfr.criteria.yaml +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert/_data/criteria/hypercare-plan.criteria.yaml +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert/_data/criteria/operations.criteria.yaml +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert/_data/criteria/post-implementation-review.criteria.yaml +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert/_data/criteria/prd.criteria.yaml +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert/_data/criteria/project.criteria.yaml +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert/_data/criteria/qa-test-plan.criteria.yaml +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert/_data/criteria/raci-stakeholder.criteria.yaml +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert/_data/criteria/release-cutover-plan.criteria.yaml +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert/_data/criteria/risk-register.criteria.yaml +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert/_data/criteria/rollback-plan.criteria.yaml +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert/_data/criteria/runbook.criteria.yaml +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert/_data/criteria/status-report.criteria.yaml +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert/_data/criteria/test-cases.criteria.yaml +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert/_data/criteria/user-story.criteria.yaml +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert/_data/profiles/agile-delivery.yaml +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert/_data/profiles/lean-startup.yaml +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert/_data/profiles/operations.yaml +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert/_data/profiles/regulated-industry.yaml +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert/_data/schema/adr.schema.json +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert/_data/schema/benefits-realization.schema.json +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert/_data/schema/brd.schema.json +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert/_data/schema/business-case.schema.json +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert/_data/schema/charter.schema.json +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert/_data/schema/data-migration-plan.schema.json +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert/_data/schema/frnfr.schema.json +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert/_data/schema/hypercare-plan.schema.json +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert/_data/schema/operations.schema.json +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert/_data/schema/post-implementation-review.schema.json +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert/_data/schema/prd.schema.json +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert/_data/schema/project.schema.json +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert/_data/schema/qa-test-plan.schema.json +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert/_data/schema/raci-stakeholder.schema.json +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert/_data/schema/release-cutover-plan.schema.json +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert/_data/schema/risk-register.schema.json +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert/_data/schema/rollback-plan.schema.json +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert/_data/schema/runbook.schema.json +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert/_data/schema/status-report.schema.json +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert/_data/schema/test-cases.schema.json +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert/_data/schema/user-story.schema.json +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert/_data/skills/doc-to-pmo/SKILL.md +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert/_data/templates/adr.template.md +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert/_data/templates/benefits-realization.template.md +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert/_data/templates/brd.template.md +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert/_data/templates/business-case.template.md +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert/_data/templates/charter.template.md +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert/_data/templates/data-migration-plan.template.md +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert/_data/templates/frnfr.template.md +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert/_data/templates/hypercare-plan.template.md +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert/_data/templates/operations.template.md +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert/_data/templates/post-implementation-review.template.md +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert/_data/templates/prd.template.md +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert/_data/templates/project.template.md +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert/_data/templates/qa-test-plan.template.md +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert/_data/templates/raci-stakeholder.template.md +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert/_data/templates/release-cutover-plan.template.md +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert/_data/templates/risk-register.template.md +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert/_data/templates/rollback-plan.template.md +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert/_data/templates/runbook.template.md +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert/_data/templates/status-report.template.md +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert/_data/templates/test-cases.template.md +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert/_data/templates/user-story.template.md +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert/bridge/__init__.py +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert/bridge/board.py +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert/bridge/gh.py +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert/bridge/ops.py +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert/bridge/plan.py +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert/cli.py +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert/config.py +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert/consistency.py +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert/extract.py +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert/graph.py +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert/loader.py +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert/models.py +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert/profiles.py +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert/projects.py +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert/report.py +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert/rtm.py +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert/scaffold.py +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert/semantic.py +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert/status/__init__.py +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert/status/derive.py +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert/structural.py +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert.egg-info/SOURCES.txt +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert.egg-info/dependency_links.txt +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert.egg-info/entry_points.txt +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert.egg-info/requires.txt +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/docassert.egg-info/top_level.txt +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/pyproject.toml +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/setup.cfg +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/tests/test_badge.py +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/tests/test_bridge.py +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/tests/test_config.py +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/tests/test_consistency.py +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/tests/test_defects.py +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/tests/test_draft_relaxation.py +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/tests/test_extract.py +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/tests/test_graph.py +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/tests/test_json_report.py +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/tests/test_kinds_delivery.py +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/tests/test_kinds_governance.py +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/tests/test_kinds_operate.py +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/tests/test_kinds_reporting.py +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/tests/test_profiles.py +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/tests/test_projects.py +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/tests/test_report_extract.py +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/tests/test_scaffold.py +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/tests/test_semantic.py +0 -0
- {docassert-0.20.0 → docassert-0.20.1}/tests/test_structural.py +0 -0
|
@@ -142,6 +142,31 @@ def _today():
|
|
|
142
142
|
return datetime.date.today()
|
|
143
143
|
|
|
144
144
|
|
|
145
|
+
def _verdict_causes(model) -> list[str]:
|
|
146
|
+
"""The raw cause strings behind the verdict (also the verdict tooltip)."""
|
|
147
|
+
causes = []
|
|
148
|
+
gaps = [c for c in model["coverage"] if c["gaps"]]
|
|
149
|
+
if gaps:
|
|
150
|
+
causes.append(f"{len(gaps)} coverage chain(s) with gaps")
|
|
151
|
+
failing = [d for d in model["documents"] if not d["passing"]]
|
|
152
|
+
if failing:
|
|
153
|
+
causes.append(f"{len(failing)} document(s) failing audit")
|
|
154
|
+
if model["broken_references"]:
|
|
155
|
+
causes.append(f"{len(model['broken_references'])} broken reference(s)")
|
|
156
|
+
comp = model.get("completeness")
|
|
157
|
+
if comp and comp.get("blocks"):
|
|
158
|
+
causes.append("required documents missing under an enforced profile")
|
|
159
|
+
thr = model.get("risk_amber_score", 6)
|
|
160
|
+
open_r = [r for r in model["risks"] if r.get("disposition", "open") == "open"
|
|
161
|
+
and (thr == 0 or r.get("score", 0) >= thr)]
|
|
162
|
+
if open_r:
|
|
163
|
+
causes.append(f"{len(open_r)} open risk(s) at or above the appetite (score ≥ {thr})")
|
|
164
|
+
stale = [o for o in model.get("operations", []) if not o["fresh"]]
|
|
165
|
+
if stale:
|
|
166
|
+
causes.append(f"operations review overdue since {stale[0]['review_by']}")
|
|
167
|
+
return causes
|
|
168
|
+
|
|
169
|
+
|
|
145
170
|
def _verdict(model) -> str:
|
|
146
171
|
"""One decision-grade sentence composed only from recorded causes."""
|
|
147
172
|
rag = model["rag"]
|
|
@@ -259,8 +284,16 @@ def render_html(model) -> str:
|
|
|
259
284
|
(f"{esc(nxt[1])} · {nxt[2]}" if nxt else "no dated milestone")),
|
|
260
285
|
("DOC SET", docset_v, docset_c, docset_sub),
|
|
261
286
|
]
|
|
287
|
+
stat_tips = {
|
|
288
|
+
"HEALTH": "Derived RAG. Red: failing approved docs, broken references, or enforced profile gaps. Amber: coverage gaps, open risks at or above the risk appetite, stale operations review, or an amber/red status report. Green: none of those.",
|
|
289
|
+
"DOCS APPROVED": "Documents with approved or baselined status, of all documents in this project. The sub-line counts documents passing every blocking structural check.",
|
|
290
|
+
"COVERAGE": "Traceability links present over links required, across every configured chain (BR→PR, PR→AC, AC→TC, and any others).",
|
|
291
|
+
"OPEN RISKS": "Risks with disposition open. Dispositioned risks (mitigated, accepted, closed) stay on the register as record but do not count here.",
|
|
292
|
+
"NEXT MILESTONE": "Days to the nearest upcoming dated marker: a dated charter milestone or the operations review. Temporal fact only.",
|
|
293
|
+
"DOC SET": "Profile completeness: required kinds complete (approved and passing audit) over required kinds expected.",
|
|
294
|
+
}
|
|
262
295
|
stat_html = "".join(
|
|
263
|
-
f'<div style="padding:22px 20px;border-left:1px solid {_C["line"]};">'
|
|
296
|
+
f'<div title="{esc(stat_tips.get(k, ""))}" style="cursor:help;padding:22px 20px;border-left:1px solid {_C["line"]};">'
|
|
264
297
|
f'<div class="chiplabel" style="margin-bottom:14px;">{k}</div>'
|
|
265
298
|
f'<div style="font-family:Archivo,system-ui,sans-serif;font-weight:800;font-size:30px;letter-spacing:-.02em;'
|
|
266
299
|
f'line-height:1;color:{col};font-variant-numeric:tabular-nums;">{esc(v)}</div>'
|
|
@@ -278,8 +311,11 @@ def render_html(model) -> str:
|
|
|
278
311
|
f'{_C["green"] if i < filled else _C["line"]};"></span>'
|
|
279
312
|
for i in range(cells))
|
|
280
313
|
ratio_c = _C["green"] if covered == total else _C["amberT"]
|
|
314
|
+
tip = ("all links traced" if not cov["gaps"] else
|
|
315
|
+
"gaps: " + ", ".join(cov["gaps"]))
|
|
281
316
|
meters.append(
|
|
282
|
-
f'<div
|
|
317
|
+
f'<div title="{esc(tip)}" style="cursor:help;">'
|
|
318
|
+
f'<div style="display:flex;justify-content:space-between;align-items:baseline;margin-bottom:11px;">'
|
|
283
319
|
f'<span style="font-size:12.5px;color:{_C["soft"]};">{esc(cov["label"])}</span>'
|
|
284
320
|
f'<span style="font-family:Archivo,system-ui,sans-serif;font-weight:700;font-size:13px;color:{ratio_c};">'
|
|
285
321
|
f'{covered}/{total}</span></div><div style="display:flex;gap:4px;">{cell_html}</div></div>')
|
|
@@ -342,8 +378,11 @@ def render_html(model) -> str:
|
|
|
342
378
|
if m["when"] == "elapsed":
|
|
343
379
|
return f'color:{_C["muted"]};background:#14181b;'
|
|
344
380
|
return f'color:{_C["muted"]};background:#14181b;'
|
|
381
|
+
ms_tip = ("Temporal fact only: elapsed means the date passed, "
|
|
382
|
+
"not that the milestone completed (spec §13.2).")
|
|
345
383
|
cols = "".join(
|
|
346
|
-
f'<div
|
|
384
|
+
f'<div title="{esc(m["label"])} · {esc(m["date"])} · {esc(ms_tip)}" '
|
|
385
|
+
f'style="cursor:help;display:flex;flex-direction:column;align-items:flex-start;">'
|
|
347
386
|
f'<span style="display:block;width:14px;height:14px;border-radius:50%;'
|
|
348
387
|
f'border:2px solid {_C["bg"]};{_dot(m)}"></span>'
|
|
349
388
|
f'<div style="font-family:Archivo,system-ui,sans-serif;font-weight:700;font-size:13px;color:{_C["text"]};'
|
|
@@ -392,8 +431,13 @@ def render_html(model) -> str:
|
|
|
392
431
|
width = max(6.0, (f["points"] / maxp) * (colw - 3))
|
|
393
432
|
left = f["layer"] * colw + 1
|
|
394
433
|
dep = f' · after {", ".join(esc(d) for d in f["after"])}' if f["after"] else ""
|
|
434
|
+
bar_tip = (f'{f["text"]} — {f["points"]} scope point(s) = '
|
|
435
|
+
f'{f["stories"]} story(ies) + {f["acs"]} acceptance criteria. '
|
|
436
|
+
+ (f'Sequenced after {", ".join(f["after"])}. ' if f["after"] else "")
|
|
437
|
+
+ ("State from the bridge issue." if f["id"] in ex_state
|
|
438
|
+
else "No execution data yet: scoped only."))
|
|
395
439
|
rows_html.append(
|
|
396
|
-
f'<div style="display:grid;grid-template-columns:186px 1fr;align-items:center;'
|
|
440
|
+
f'<div title="{esc(bar_tip)}" style="cursor:help;display:grid;grid-template-columns:186px 1fr;align-items:center;'
|
|
397
441
|
f'border-bottom:1px solid #14181b;">'
|
|
398
442
|
f'<div style="padding-right:14px;"><div style="font-size:12px;color:{_C["soft"]};'
|
|
399
443
|
f'line-height:1.3;">{esc(f["text"])[:52]}</div>'
|
|
@@ -490,6 +534,8 @@ def render_html(model) -> str:
|
|
|
490
534
|
work_aside = (f"{ex.get('stories_closed', 0)}/{ex.get('stories_total', 0)} stories closed"
|
|
491
535
|
if ex else "bridge-managed issues")
|
|
492
536
|
verdict = _verdict(model)
|
|
537
|
+
causes = _verdict_causes(model)
|
|
538
|
+
verdict_tip = ("Causes: " + "; ".join(causes)) if causes else "No amber or red causes recorded."
|
|
493
539
|
payload = _json_embed({"risks": risks_data, "docs": docs_data, "work": work_data,
|
|
494
540
|
"C": _C})
|
|
495
541
|
|
|
@@ -524,7 +570,7 @@ def render_html(model) -> str:
|
|
|
524
570
|
|
|
525
571
|
<div style="display:flex;gap:18px;margin:28px 0 44px;padding:20px 22px;background:rgba(255,178,36,.06);border-left:3px solid {rc};">
|
|
526
572
|
<span style="font-family:Archivo,system-ui,sans-serif;font-weight:900;font-size:12px;letter-spacing:.16em;color:{rt};writing-mode:vertical-rl;transform:rotate(180deg);">VERDICT</span>
|
|
527
|
-
<p style="margin:0;font-family:Archivo,system-ui,sans-serif;font-weight:500;font-size:17.5px;line-height:1.5;color:#DDE1E5;max-width:88ch;">{esc(verdict)}</p>
|
|
573
|
+
<p title="{esc(verdict_tip)}" style="cursor:help;margin:0;font-family:Archivo,system-ui,sans-serif;font-weight:500;font-size:17.5px;line-height:1.5;color:#DDE1E5;max-width:88ch;">{esc(verdict)}</p>
|
|
528
574
|
</div>
|
|
529
575
|
|
|
530
576
|
<div style="display:grid;grid-template-columns:repeat(6,1fr);border-top:1px solid {_C['line']};border-bottom:1px solid {_C['line']};margin-bottom:56px;">{stat_html}</div>
|
|
@@ -609,7 +655,7 @@ function matrix(){
|
|
|
609
655
|
probs.forEach(pr => {
|
|
610
656
|
const inCell = DATA.risks.filter(r => r.disposition==='open' && r.prob===pr && (r.impact===im || (r.impact==='critical' && im==='high')));
|
|
611
657
|
const z = zone(PV[pr]*PV[im]); const occ = inCell.length>0;
|
|
612
|
-
const chips = inCell.map(r => `<span style="font-size:11px;font-weight:600;padding:2px 6px;border-radius:3px;border:1px solid ${z.b};color:${S.sel===r.id?C.bg:z.t};background:${S.sel===r.id?z.t:'transparent'};">${esc(r.short)}</span>`).join('');
|
|
658
|
+
const chips = inCell.map(r => `<span title="${esc(r.id)}: ${esc(r.desc)}" style="cursor:help;font-size:11px;font-weight:600;padding:2px 6px;border-radius:3px;border:1px solid ${z.b};color:${S.sel===r.id?C.bg:z.t};background:${S.sel===r.id?z.t:'transparent'};">${esc(r.short)}</span>`).join('');
|
|
613
659
|
h += `<div data-risk="${occ?inCell[0].id:''}" style="min-height:56px;border:1px solid ${occ?z.b:'#191d21'};background:${occ?z.s:z.f};border-radius:3px;display:flex;gap:4px;align-items:center;justify-content:center;flex-wrap:wrap;cursor:${occ?'pointer':'default'};">${chips}</div>`;
|
|
614
660
|
});
|
|
615
661
|
});
|
|
@@ -674,7 +720,7 @@ function docs(){
|
|
|
674
720
|
<span style="font-size:12.5px;color:${C.text};">${esc(d.kind)}</span>
|
|
675
721
|
<span class="mono-tag" style="justify-self:start;">${esc(d.id)}</span>
|
|
676
722
|
<span style="font-size:12px;color:${d.status==='active'?C.amberT:C.muted};">${esc(d.status)}</span>
|
|
677
|
-
<span style="text-align:right;color:${d.passing?C.green:C.red};font-size:14px;">${d.passing?'✓':'✗'}</span></div>`).join('');
|
|
723
|
+
<span title="${d.passing?'passes every blocking structural check':'failing one or more blocking checks'}" style="cursor:help;text-align:right;color:${d.passing?C.green:C.red};font-size:14px;">${d.passing?'✓':'✗'}</span></div>`).join('');
|
|
678
724
|
}
|
|
679
725
|
|
|
680
726
|
function work(){
|
|
@@ -700,7 +746,7 @@ function work(){
|
|
|
700
746
|
<div><div style="font-size:13px;color:${C.text};line-height:1.45;">${w.url?`<a style="text-decoration:none;" href="${esc(w.url)}">${esc(w.title)}</a>`:esc(w.title)}</div>
|
|
701
747
|
<div style="font-size:10.5px;color:${C.dim};margin-top:6px;">linked ${esc(w.link)}</div></div>
|
|
702
748
|
<span style="font-size:11.5px;color:${C.muted};">${esc(w.assignee)}</span>
|
|
703
|
-
<span style="text-align:right;font-size:11.5px;color:${stC(w.state)};">${w.state==='done'?'done ✓':esc(w.state)}</span></div>`).join('');
|
|
749
|
+
<span title="state read from the bridge-managed issue; presentation never alters the derived RAG" style="cursor:help;text-align:right;font-size:11.5px;color:${stC(w.state)};">${w.state==='done'?'done ✓':esc(w.state)}</span></div>`).join('');
|
|
704
750
|
}
|
|
705
751
|
|
|
706
752
|
function render(){ matrix(); riskCtl(); riskTable(); docs(); work(); }
|
|
@@ -722,12 +768,12 @@ def _index_row(p) -> str:
|
|
|
722
768
|
f'<div><div style="font-family:Archivo,system-ui,sans-serif;font-weight:700;font-size:15px;color:#F1F3F5;line-height:1.2;">{esc(p["name"])}</div>'
|
|
723
769
|
f'<div style="font-size:10.5px;color:{_C["dim"]};margin-top:5px;display:flex;gap:10px;">'
|
|
724
770
|
f'<span>{esc(p["id"])}</span><span>·</span><span>{esc(p["sponsor"])}</span></div></div>'
|
|
725
|
-
f'<div style="text-align:center;"><div style="font-size:12.5px;color:{covc};">{cov}%</div>'
|
|
771
|
+
f'<div title="traceability links traced over required, all chains" style="cursor:help;text-align:center;"><div style="font-size:12.5px;color:{covc};">{cov}%</div>'
|
|
726
772
|
f'<div style="height:4px;background:#16191c;margin-top:7px;border-radius:2px;overflow:hidden;">'
|
|
727
773
|
f'<span style="display:block;height:100%;width:{cov}%;background:{covc};"></span></div></div>'
|
|
728
774
|
f'<span style="text-align:center;font-size:12.5px;color:{_C["soft"]};">{esc(p["docs"])}</span>'
|
|
729
775
|
f'<span style="text-align:center;font-size:12px;color:{_C["amberT"] if p["risks"] else _C["faint"]};">{risks}</span>'
|
|
730
|
-
f'<span style="text-align:right;font-size:11.5px;color:{_C["muted"]};">{esc(p["next"])}</span></a>')
|
|
776
|
+
f'<span title="nearest upcoming dated marker (milestone or operations review)" style="cursor:help;text-align:right;font-size:11.5px;color:{_C["muted"]};">{esc(p["next"])}</span></a>')
|
|
731
777
|
|
|
732
778
|
|
|
733
779
|
def render_index_html(index) -> str:
|
|
@@ -367,3 +367,15 @@ def test_after_cycle_blocks(tmp_path):
|
|
|
367
367
|
g = build_graph(_seq_tree(tmp_path, cyclic=True))
|
|
368
368
|
r = check_sequence_acyclic(g)
|
|
369
369
|
assert not r.passed and r.blocking and "after-cycle" in r.detail
|
|
370
|
+
|
|
371
|
+
|
|
372
|
+
def test_report_tooltips_present(tmp_path):
|
|
373
|
+
_cd_root()
|
|
374
|
+
m = S.build_status(_seq_tree(tmp_path), project="PRJ-001-SQ")
|
|
375
|
+
out = S.render_html(m)
|
|
376
|
+
assert 'title="Derived RAG.' in out # stat derivation
|
|
377
|
+
assert "not that the milestone completed" in out or "Temporal fact" in out
|
|
378
|
+
assert "scope point(s) = " in out # bar breakdown tooltip
|
|
379
|
+
assert 'title="Causes:' in out or "No amber or red causes" in out
|
|
380
|
+
idx = S.render_index_html(S.build_index(ROOT / "documents"))
|
|
381
|
+
assert "nearest upcoming dated marker" in idx
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{docassert-0.20.0 → docassert-0.20.1}/docassert/_data/criteria/benefits-realization.criteria.yaml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{docassert-0.20.0 → docassert-0.20.1}/docassert/_data/criteria/data-migration-plan.criteria.yaml
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
|
{docassert-0.20.0 → docassert-0.20.1}/docassert/_data/criteria/raci-stakeholder.criteria.yaml
RENAMED
|
File without changes
|
{docassert-0.20.0 → docassert-0.20.1}/docassert/_data/criteria/release-cutover-plan.criteria.yaml
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
|
{docassert-0.20.0 → docassert-0.20.1}/docassert/_data/schema/benefits-realization.schema.json
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{docassert-0.20.0 → docassert-0.20.1}/docassert/_data/schema/data-migration-plan.schema.json
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{docassert-0.20.0 → docassert-0.20.1}/docassert/_data/schema/post-implementation-review.schema.json
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{docassert-0.20.0 → docassert-0.20.1}/docassert/_data/schema/release-cutover-plan.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
|
{docassert-0.20.0 → docassert-0.20.1}/docassert/_data/templates/benefits-realization.template.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{docassert-0.20.0 → docassert-0.20.1}/docassert/_data/templates/data-migration-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
|
{docassert-0.20.0 → docassert-0.20.1}/docassert/_data/templates/raci-stakeholder.template.md
RENAMED
|
File without changes
|
{docassert-0.20.0 → docassert-0.20.1}/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
|
|
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
|