docassert 0.17.0__tar.gz → 0.18.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.17.0/docassert.egg-info → docassert-0.18.0}/PKG-INFO +1 -1
- {docassert-0.17.0 → docassert-0.18.0}/docassert/__init__.py +1 -1
- {docassert-0.17.0 → docassert-0.18.0}/docassert/_data/criteria/charter.criteria.yaml +5 -0
- {docassert-0.17.0 → docassert-0.18.0}/docassert/bridge/ops.py +17 -0
- {docassert-0.17.0 → docassert-0.18.0}/docassert/cli.py +20 -0
- {docassert-0.17.0 → docassert-0.18.0}/docassert/status/derive.py +49 -0
- docassert-0.18.0/docassert/status/render.py +865 -0
- {docassert-0.17.0 → docassert-0.18.0}/docassert/structural.py +16 -0
- {docassert-0.17.0 → docassert-0.18.0/docassert.egg-info}/PKG-INFO +1 -1
- {docassert-0.17.0 → docassert-0.18.0}/tests/test_badge.py +2 -2
- {docassert-0.17.0 → docassert-0.18.0}/tests/test_status.py +10 -8
- docassert-0.17.0/docassert/status/render.py +0 -397
- {docassert-0.17.0 → docassert-0.18.0}/LICENSE +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/NOTICE +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/README.md +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/docassert/__main__.py +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/docassert/_data/consistency.yaml +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/docassert/_data/criteria/adr.criteria.yaml +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/docassert/_data/criteria/benefits-realization.criteria.yaml +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/docassert/_data/criteria/brd.criteria.yaml +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/docassert/_data/criteria/business-case.criteria.yaml +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/docassert/_data/criteria/data-migration-plan.criteria.yaml +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/docassert/_data/criteria/frnfr.criteria.yaml +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/docassert/_data/criteria/hypercare-plan.criteria.yaml +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/docassert/_data/criteria/operations.criteria.yaml +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/docassert/_data/criteria/post-implementation-review.criteria.yaml +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/docassert/_data/criteria/prd.criteria.yaml +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/docassert/_data/criteria/project.criteria.yaml +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/docassert/_data/criteria/qa-test-plan.criteria.yaml +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/docassert/_data/criteria/raci-stakeholder.criteria.yaml +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/docassert/_data/criteria/release-cutover-plan.criteria.yaml +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/docassert/_data/criteria/risk-register.criteria.yaml +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/docassert/_data/criteria/rollback-plan.criteria.yaml +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/docassert/_data/criteria/runbook.criteria.yaml +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/docassert/_data/criteria/status-report.criteria.yaml +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/docassert/_data/criteria/test-cases.criteria.yaml +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/docassert/_data/criteria/user-story.criteria.yaml +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/docassert/_data/profiles/agile-delivery.yaml +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/docassert/_data/profiles/lean-startup.yaml +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/docassert/_data/profiles/operations.yaml +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/docassert/_data/profiles/regulated-industry.yaml +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/docassert/_data/schema/adr.schema.json +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/docassert/_data/schema/benefits-realization.schema.json +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/docassert/_data/schema/brd.schema.json +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/docassert/_data/schema/business-case.schema.json +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/docassert/_data/schema/charter.schema.json +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/docassert/_data/schema/data-migration-plan.schema.json +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/docassert/_data/schema/frnfr.schema.json +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/docassert/_data/schema/hypercare-plan.schema.json +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/docassert/_data/schema/operations.schema.json +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/docassert/_data/schema/post-implementation-review.schema.json +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/docassert/_data/schema/prd.schema.json +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/docassert/_data/schema/project.schema.json +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/docassert/_data/schema/qa-test-plan.schema.json +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/docassert/_data/schema/raci-stakeholder.schema.json +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/docassert/_data/schema/release-cutover-plan.schema.json +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/docassert/_data/schema/risk-register.schema.json +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/docassert/_data/schema/rollback-plan.schema.json +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/docassert/_data/schema/runbook.schema.json +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/docassert/_data/schema/status-report.schema.json +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/docassert/_data/schema/test-cases.schema.json +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/docassert/_data/schema/user-story.schema.json +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/docassert/_data/skills/doc-to-pmo/SKILL.md +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/docassert/_data/templates/adr.template.md +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/docassert/_data/templates/benefits-realization.template.md +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/docassert/_data/templates/brd.template.md +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/docassert/_data/templates/business-case.template.md +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/docassert/_data/templates/charter.template.md +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/docassert/_data/templates/data-migration-plan.template.md +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/docassert/_data/templates/frnfr.template.md +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/docassert/_data/templates/hypercare-plan.template.md +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/docassert/_data/templates/operations.template.md +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/docassert/_data/templates/post-implementation-review.template.md +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/docassert/_data/templates/prd.template.md +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/docassert/_data/templates/project.template.md +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/docassert/_data/templates/qa-test-plan.template.md +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/docassert/_data/templates/raci-stakeholder.template.md +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/docassert/_data/templates/release-cutover-plan.template.md +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/docassert/_data/templates/risk-register.template.md +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/docassert/_data/templates/rollback-plan.template.md +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/docassert/_data/templates/runbook.template.md +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/docassert/_data/templates/status-report.template.md +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/docassert/_data/templates/test-cases.template.md +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/docassert/_data/templates/user-story.template.md +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/docassert/bridge/__init__.py +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/docassert/bridge/board.py +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/docassert/bridge/gh.py +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/docassert/bridge/plan.py +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/docassert/config.py +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/docassert/consistency.py +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/docassert/extract.py +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/docassert/graph.py +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/docassert/loader.py +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/docassert/models.py +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/docassert/profiles.py +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/docassert/projects.py +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/docassert/report.py +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/docassert/rtm.py +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/docassert/scaffold.py +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/docassert/semantic.py +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/docassert/status/__init__.py +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/docassert.egg-info/SOURCES.txt +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/docassert.egg-info/dependency_links.txt +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/docassert.egg-info/entry_points.txt +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/docassert.egg-info/requires.txt +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/docassert.egg-info/top_level.txt +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/pyproject.toml +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/setup.cfg +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/tests/test_bridge.py +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/tests/test_config.py +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/tests/test_consistency.py +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/tests/test_defects.py +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/tests/test_draft_relaxation.py +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/tests/test_extract.py +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/tests/test_graph.py +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/tests/test_json_report.py +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/tests/test_kinds_delivery.py +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/tests/test_kinds_governance.py +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/tests/test_kinds_operate.py +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/tests/test_kinds_reporting.py +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/tests/test_profiles.py +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/tests/test_projects.py +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/tests/test_report_extract.py +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/tests/test_scaffold.py +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/tests/test_semantic.py +0 -0
- {docassert-0.17.0 → docassert-0.18.0}/tests/test_structural.py +0 -0
|
@@ -21,6 +21,11 @@ required_sections:
|
|
|
21
21
|
- Approval
|
|
22
22
|
|
|
23
23
|
checks:
|
|
24
|
+
- id: milestones-dated
|
|
25
|
+
type: structural
|
|
26
|
+
blocking: false
|
|
27
|
+
description: "At least one Milestones bullet ends with an ISO date (- <label>: YYYY-MM-DD) so timelines can draw it. Advisory only."
|
|
28
|
+
|
|
24
29
|
- id: frontmatter-schema
|
|
25
30
|
type: structural
|
|
26
31
|
blocking: true
|
|
@@ -222,6 +222,19 @@ def status(plan: BridgePlan, gh: G.GhRunner, repo: str) -> dict:
|
|
|
222
222
|
"doc": key})
|
|
223
223
|
out: dict = {"repo": repo, "projects": [],
|
|
224
224
|
"scope": {"unverified": unverified, "orphaned": orphaned}}
|
|
225
|
+
def facts(key):
|
|
226
|
+
"""Real, presentational issue facts (never fed back into derivation)."""
|
|
227
|
+
issue = by_key.get(key) or {}
|
|
228
|
+
return {
|
|
229
|
+
"title": issue.get("title"),
|
|
230
|
+
"state": issue.get("state"),
|
|
231
|
+
"created_at": (issue.get("created_at") or "")[:10] or None,
|
|
232
|
+
"closed_at": (issue.get("closed_at") or "")[:10] or None,
|
|
233
|
+
"url": issue.get("html_url"),
|
|
234
|
+
"assignee": (issue.get("assignee") or {}).get("login"),
|
|
235
|
+
"labels": [lb.get("name") for lb in issue.get("labels") or []],
|
|
236
|
+
}
|
|
237
|
+
|
|
225
238
|
for p in plan.projects:
|
|
226
239
|
feats = []
|
|
227
240
|
for f in p["features"]:
|
|
@@ -229,6 +242,10 @@ def status(plan: BridgePlan, gh: G.GhRunner, repo: str) -> dict:
|
|
|
229
242
|
feats.append({
|
|
230
243
|
"id": f.id,
|
|
231
244
|
"issue": (by_key.get(f.id) or {}).get("number"),
|
|
245
|
+
"facts": facts(f.id),
|
|
246
|
+
"stories": [{"id": s.id,
|
|
247
|
+
"issue": (by_key.get(s.id) or {}).get("number"),
|
|
248
|
+
"facts": facts(s.id)} for s in f.stories],
|
|
232
249
|
"stories_total": len(f.stories),
|
|
233
250
|
"stories_closed": sum(1 for s in states if s == "closed"),
|
|
234
251
|
"closed": (by_key.get(f.id) or {}).get("state") == "closed",
|
|
@@ -240,9 +240,29 @@ def cmd_pages(args: argparse.Namespace) -> int:
|
|
|
240
240
|
execution[proj["id"]] = {**proj, "scope": data.get("scope"),
|
|
241
241
|
"repo": proj.get("repo") or data.get("repo")}
|
|
242
242
|
|
|
243
|
+
def _activity(project_id: str) -> list[dict]:
|
|
244
|
+
"""Recent documents/ commits for one project (best-effort, git only)."""
|
|
245
|
+
import subprocess
|
|
246
|
+
try:
|
|
247
|
+
out = subprocess.run(
|
|
248
|
+
["git", "log", "-n", "6", "--date=short",
|
|
249
|
+
"--pretty=%ad\x1f%s", "--", f"{docs_dir}/{project_id}"],
|
|
250
|
+
capture_output=True, text=True, timeout=10)
|
|
251
|
+
if out.returncode != 0:
|
|
252
|
+
return []
|
|
253
|
+
rows = []
|
|
254
|
+
for line in out.stdout.strip().splitlines():
|
|
255
|
+
when, _, text = line.partition("\x1f")
|
|
256
|
+
if text:
|
|
257
|
+
rows.append({"when": when, "text": text})
|
|
258
|
+
return rows
|
|
259
|
+
except Exception:
|
|
260
|
+
return []
|
|
261
|
+
|
|
243
262
|
plist = projects_mod.load_projects(docs_dir)
|
|
244
263
|
for p in plist:
|
|
245
264
|
model = status_mod.build_status(docs_dir, project=p["id"])
|
|
265
|
+
model["activity"] = _activity(p["id"])
|
|
246
266
|
if p["id"] in execution:
|
|
247
267
|
model["execution"] = execution[p["id"]]
|
|
248
268
|
(out / f"{p['id']}.html").write_text(status_mod.render_html(model))
|
|
@@ -113,6 +113,37 @@ def _broken_references(graph, code=None):
|
|
|
113
113
|
return broken
|
|
114
114
|
|
|
115
115
|
|
|
116
|
+
_MS_RE = re.compile(r"^(?P<label>.+?)[:\u2014\u2013-]\s*(?P<date>\d{4}-\d{2}-\d{2})\.?\s*$")
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def _milestones(docs):
|
|
120
|
+
"""Dated charter milestones as temporal facts (never completion claims)."""
|
|
121
|
+
import datetime
|
|
122
|
+
today = datetime.date.today()
|
|
123
|
+
out = []
|
|
124
|
+
for d in docs:
|
|
125
|
+
if d.kind != "charter":
|
|
126
|
+
continue
|
|
127
|
+
section = d.section("Milestones")
|
|
128
|
+
if section is None:
|
|
129
|
+
continue
|
|
130
|
+
for bullet in section.list_items:
|
|
131
|
+
m = _MS_RE.match(bullet.strip())
|
|
132
|
+
if not m:
|
|
133
|
+
continue
|
|
134
|
+
try:
|
|
135
|
+
due = datetime.date.fromisoformat(m.group("date"))
|
|
136
|
+
except ValueError:
|
|
137
|
+
continue
|
|
138
|
+
delta = (due - today).days
|
|
139
|
+
out.append({"label": m.group("label").strip(),
|
|
140
|
+
"date": due.isoformat(),
|
|
141
|
+
"days": delta,
|
|
142
|
+
"when": ("today" if delta == 0 else
|
|
143
|
+
"elapsed" if delta < 0 else "upcoming")})
|
|
144
|
+
return sorted(out, key=lambda x: x["date"])
|
|
145
|
+
|
|
146
|
+
|
|
116
147
|
def _operations(docs):
|
|
117
148
|
"""Operations documents with their review state."""
|
|
118
149
|
import datetime
|
|
@@ -199,6 +230,7 @@ def build_status(documents_dir=DOCUMENTS_DIR, project: str | None = None) -> dic
|
|
|
199
230
|
"coverage": _coverage(graph, cfg, code),
|
|
200
231
|
"risks": _risks(graph, code),
|
|
201
232
|
"operations": _operations(docs),
|
|
233
|
+
"milestones": _milestones(docs),
|
|
202
234
|
"broken_references": _broken_references(graph, code),
|
|
203
235
|
"latest_report": _latest_report(docs),
|
|
204
236
|
"completeness": completeness,
|
|
@@ -231,6 +263,19 @@ def completeness_report(documents_dir=DOCUMENTS_DIR) -> list[dict]:
|
|
|
231
263
|
return out
|
|
232
264
|
|
|
233
265
|
|
|
266
|
+
def _next_dated(m) -> str | None:
|
|
267
|
+
"""The nearest upcoming dated marker (milestone or operations review)."""
|
|
268
|
+
import datetime
|
|
269
|
+
cands = [x["date"] for x in m.get("milestones", []) if x["days"] >= 0]
|
|
270
|
+
for o in m.get("operations", []):
|
|
271
|
+
try:
|
|
272
|
+
if datetime.date.fromisoformat(o["review_by"]) >= datetime.date.today():
|
|
273
|
+
cands.append(o["review_by"])
|
|
274
|
+
except ValueError:
|
|
275
|
+
pass
|
|
276
|
+
return min(cands) if cands else None
|
|
277
|
+
|
|
278
|
+
|
|
234
279
|
def build_index(documents_dir=DOCUMENTS_DIR) -> dict:
|
|
235
280
|
"""The multi-project view: each project's derived RAG + headline signals,
|
|
236
281
|
plus the whole-repo rollup."""
|
|
@@ -246,6 +291,10 @@ def build_index(documents_dir=DOCUMENTS_DIR) -> dict:
|
|
|
246
291
|
"failing": m["counts"]["failing"],
|
|
247
292
|
"risks": len([r for r in m["risks"] if r.get("disposition", "open") == "open"]),
|
|
248
293
|
"coverage_gaps": sum(len(c["gaps"]) for c in m["coverage"]),
|
|
294
|
+
"coverage_pct": (round(100 * sum(c["covered"] for c in m["coverage"])
|
|
295
|
+
/ max(1, sum(c["total"] for c in m["coverage"])))
|
|
296
|
+
if any(c["total"] for c in m["coverage"]) else 100),
|
|
297
|
+
"next": _next_dated(m),
|
|
249
298
|
"broken": len(m["broken_references"]),
|
|
250
299
|
"completeness": m.get("completeness"),
|
|
251
300
|
})
|