sourcebound 1.2.1__py3-none-any.whl
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.
- clean_docs/__init__.py +26 -0
- clean_docs/__main__.py +3 -0
- clean_docs/accessibility.py +182 -0
- clean_docs/adapters/__init__.py +1 -0
- clean_docs/adapters/event_capture.py +56 -0
- clean_docs/adapters/mdx_dependencies.json +714 -0
- clean_docs/adapters/mdx_parser.mjs +29992 -0
- clean_docs/applicability.py +330 -0
- clean_docs/audit.py +1120 -0
- clean_docs/bootstrap.py +507 -0
- clean_docs/capabilities.py +200 -0
- clean_docs/changed.py +452 -0
- clean_docs/claims.py +840 -0
- clean_docs/cli.py +1612 -0
- clean_docs/context.py +307 -0
- clean_docs/corpus.py +377 -0
- clean_docs/demo.py +369 -0
- clean_docs/doctor.py +184 -0
- clean_docs/emit/__init__.py +4 -0
- clean_docs/emit/llms_txt.py +102 -0
- clean_docs/emit/stepwise.py +168 -0
- clean_docs/engine.py +324 -0
- clean_docs/errors.py +20 -0
- clean_docs/evaluation.py +867 -0
- clean_docs/execution.py +138 -0
- clean_docs/explain.py +123 -0
- clean_docs/extractors/__init__.py +19 -0
- clean_docs/extractors/command.py +51 -0
- clean_docs/extractors/inventory.py +176 -0
- clean_docs/extractors/json_pointer.py +84 -0
- clean_docs/extractors/python_literal.py +104 -0
- clean_docs/extractors/static.py +111 -0
- clean_docs/feedback.py +1390 -0
- clean_docs/impact.py +1624 -0
- clean_docs/improvements.py +1178 -0
- clean_docs/inventory.py +474 -0
- clean_docs/isolation.py +157 -0
- clean_docs/manifest.py +898 -0
- clean_docs/mdx.py +272 -0
- clean_docs/migration.py +121 -0
- clean_docs/models.py +194 -0
- clean_docs/outcomes.py +296 -0
- clean_docs/performance.py +123 -0
- clean_docs/phrasing.py +448 -0
- clean_docs/plugins.py +249 -0
- clean_docs/policy.py +536 -0
- clean_docs/projections.py +255 -0
- clean_docs/regions.py +75 -0
- clean_docs/release.py +232 -0
- clean_docs/renderers.py +57 -0
- clean_docs/residue.py +311 -0
- clean_docs/review_contracts.py +862 -0
- clean_docs/review_ledger.py +297 -0
- clean_docs/review_limits.py +9 -0
- clean_docs/sensitivity.py +602 -0
- clean_docs/snapshot.py +212 -0
- clean_docs/standard.py +281 -0
- clean_docs/standards/default.json +309 -0
- clean_docs/standards/exemplars.md +87 -0
- clean_docs/standards/v0-migrations.json +26 -0
- clean_docs/symbols.py +47 -0
- clean_docs/templates.py +96 -0
- clean_docs/verdict.py +1397 -0
- clean_docs/visuals.py +346 -0
- clean_docs/write_gate.py +170 -0
- sourcebound-1.2.1.dist-info/LICENSE +21 -0
- sourcebound-1.2.1.dist-info/METADATA +109 -0
- sourcebound-1.2.1.dist-info/RECORD +71 -0
- sourcebound-1.2.1.dist-info/WHEEL +5 -0
- sourcebound-1.2.1.dist-info/entry_points.txt +2 -0
- sourcebound-1.2.1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import re
|
|
4
|
+
from dataclasses import dataclass
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import Literal, cast
|
|
7
|
+
|
|
8
|
+
from clean_docs.policy import REGISTER_PROFILE
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
DocumentRole = Literal[
|
|
12
|
+
"agent-procedure",
|
|
13
|
+
"architecture",
|
|
14
|
+
"component-overview",
|
|
15
|
+
"evidence",
|
|
16
|
+
"overview",
|
|
17
|
+
"plan",
|
|
18
|
+
"reference",
|
|
19
|
+
"task",
|
|
20
|
+
"template",
|
|
21
|
+
"troubleshooting",
|
|
22
|
+
"tutorial",
|
|
23
|
+
]
|
|
24
|
+
|
|
25
|
+
ROLE_RULES: dict[DocumentRole, frozenset[str]] = {
|
|
26
|
+
"overview": frozenset({
|
|
27
|
+
"code-block-language",
|
|
28
|
+
"diagram-text-equivalent",
|
|
29
|
+
"image-alternative",
|
|
30
|
+
"purpose-contract",
|
|
31
|
+
"purpose-template",
|
|
32
|
+
"preamble-contract",
|
|
33
|
+
"prohibited-booster",
|
|
34
|
+
"sentence-variance",
|
|
35
|
+
"nominalization-density",
|
|
36
|
+
"significance-narration",
|
|
37
|
+
"qualifier-density",
|
|
38
|
+
"doc-length",
|
|
39
|
+
"section-length",
|
|
40
|
+
"readme-routing",
|
|
41
|
+
"readme-reference-depth",
|
|
42
|
+
"elaboration-depth",
|
|
43
|
+
}),
|
|
44
|
+
"component-overview": frozenset({
|
|
45
|
+
"code-block-language",
|
|
46
|
+
"diagram-text-equivalent",
|
|
47
|
+
"image-alternative",
|
|
48
|
+
"prohibited-booster",
|
|
49
|
+
"sentence-variance",
|
|
50
|
+
"nominalization-density",
|
|
51
|
+
"significance-narration",
|
|
52
|
+
}),
|
|
53
|
+
"tutorial": frozenset({
|
|
54
|
+
"code-block-language",
|
|
55
|
+
"diagram-text-equivalent",
|
|
56
|
+
"image-alternative",
|
|
57
|
+
"purpose-contract",
|
|
58
|
+
"purpose-template",
|
|
59
|
+
"prohibited-booster",
|
|
60
|
+
"sentence-variance",
|
|
61
|
+
"nominalization-density",
|
|
62
|
+
"significance-narration",
|
|
63
|
+
"doc-length",
|
|
64
|
+
"section-length",
|
|
65
|
+
"elaboration-depth",
|
|
66
|
+
}),
|
|
67
|
+
"task": frozenset({
|
|
68
|
+
"code-block-language",
|
|
69
|
+
"diagram-text-equivalent",
|
|
70
|
+
"image-alternative",
|
|
71
|
+
"purpose-contract",
|
|
72
|
+
"purpose-template",
|
|
73
|
+
"prohibited-booster",
|
|
74
|
+
"sentence-variance",
|
|
75
|
+
"nominalization-density",
|
|
76
|
+
"significance-narration",
|
|
77
|
+
"doc-length",
|
|
78
|
+
"section-length",
|
|
79
|
+
}),
|
|
80
|
+
"troubleshooting": frozenset({
|
|
81
|
+
"code-block-language",
|
|
82
|
+
"diagram-text-equivalent",
|
|
83
|
+
"image-alternative",
|
|
84
|
+
"purpose-contract",
|
|
85
|
+
"purpose-template",
|
|
86
|
+
"prohibited-booster",
|
|
87
|
+
"sentence-variance",
|
|
88
|
+
"nominalization-density",
|
|
89
|
+
"significance-narration",
|
|
90
|
+
}),
|
|
91
|
+
"architecture": frozenset({
|
|
92
|
+
"code-block-language",
|
|
93
|
+
"diagram-text-equivalent",
|
|
94
|
+
"image-alternative",
|
|
95
|
+
"prohibited-booster",
|
|
96
|
+
"sentence-variance",
|
|
97
|
+
"nominalization-density",
|
|
98
|
+
"significance-narration",
|
|
99
|
+
}),
|
|
100
|
+
"reference": frozenset({
|
|
101
|
+
"code-block-language",
|
|
102
|
+
"diagram-text-equivalent",
|
|
103
|
+
"image-alternative",
|
|
104
|
+
"prohibited-booster",
|
|
105
|
+
"nominalization-density",
|
|
106
|
+
"significance-narration",
|
|
107
|
+
}),
|
|
108
|
+
# These files are inputs, procedures, plans, or records. Rewriting them into a
|
|
109
|
+
# generic reader page can change runtime behavior or erase evidence.
|
|
110
|
+
"agent-procedure": frozenset(),
|
|
111
|
+
"template": frozenset(),
|
|
112
|
+
"evidence": frozenset(),
|
|
113
|
+
"plan": frozenset(),
|
|
114
|
+
}
|
|
115
|
+
ROLE_DESCRIPTIONS: dict[DocumentRole, str] = {
|
|
116
|
+
"overview": "repository entry point for orientation and routing",
|
|
117
|
+
"component-overview": "component-local entry point whose parent supplies context",
|
|
118
|
+
"tutorial": "ordered learning path to a verified result",
|
|
119
|
+
"task": "procedure or explanation for one reader job",
|
|
120
|
+
"troubleshooting": "symptom-to-diagnosis-to-recovery procedure",
|
|
121
|
+
"reference": "lookup surface for exact current facts",
|
|
122
|
+
"architecture": "design boundary, decision, or time-horizon record",
|
|
123
|
+
"plan": "time-scoped work whose live or historical status needs judgment",
|
|
124
|
+
"evidence": "review, result, or longitudinal observation record",
|
|
125
|
+
"agent-procedure": "executable instructions for an agent reader",
|
|
126
|
+
"template": "runtime prompt or generated-content input",
|
|
127
|
+
}
|
|
128
|
+
ROLE_OVERRIDE = re.compile(
|
|
129
|
+
r"(?:<!--|\{/\*)\s*sourcebound:role\s+([a-z][a-z-]+)\s*(?:-->|\*/\})"
|
|
130
|
+
)
|
|
131
|
+
ROLE_MARKER = re.compile(
|
|
132
|
+
r"(?:<!--|\{/\*)\s*sourcebound:role\b.*?(?:-->|\*/\})"
|
|
133
|
+
)
|
|
134
|
+
REGISTER_MARKER = re.compile(
|
|
135
|
+
r"(?:<!--|\{/\*)\s*sourcebound:policy\s+register-v2\s*(?:-->|\*/\})"
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
_TEMPLATE_PARTS = frozenset({"prompts", "prompt", "templates", "template"})
|
|
139
|
+
_EVIDENCE_NAME = re.compile(
|
|
140
|
+
r"(?:^|[-_])(?:review|report|journal|findings|receipt|retro|postmortem|"
|
|
141
|
+
r"evaluation|eval-results?|status|progress|handoff|dispatch|workorder|blocked|"
|
|
142
|
+
r"changelog|changes?|news|release-notes?|history)(?:[-_.]|$)",
|
|
143
|
+
re.IGNORECASE,
|
|
144
|
+
)
|
|
145
|
+
_PLAN_NAME = re.compile(r"(?:^|[-_])plan(?:[-_.]|$)", re.IGNORECASE)
|
|
146
|
+
_REFERENCE_NAME = re.compile(
|
|
147
|
+
r"(reference|standard|spec|schema|surface|commands?|cli|api|configuration|"
|
|
148
|
+
r"policy|contract)",
|
|
149
|
+
re.IGNORECASE,
|
|
150
|
+
)
|
|
151
|
+
_TUTORIAL_NAME = re.compile(
|
|
152
|
+
r"(tutorial|quickstart|quick-start|getting-started|walkthrough)",
|
|
153
|
+
re.IGNORECASE,
|
|
154
|
+
)
|
|
155
|
+
_TROUBLESHOOTING_NAME = re.compile(
|
|
156
|
+
r"(troubleshoot|debug|diagnos|fixing|recovery|runbook|incident)",
|
|
157
|
+
re.IGNORECASE,
|
|
158
|
+
)
|
|
159
|
+
_SUPPORT_NAMES = frozenset({"operations.md", "support.md"})
|
|
160
|
+
_ARCHITECTURE_NAME = re.compile(
|
|
161
|
+
r"(architecture|compromise|design|decision|adr|proposal|rfc)",
|
|
162
|
+
re.IGNORECASE,
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
@dataclass(frozen=True)
|
|
167
|
+
class DocumentProfile:
|
|
168
|
+
path: str
|
|
169
|
+
role: DocumentRole
|
|
170
|
+
reason: str
|
|
171
|
+
registered: bool
|
|
172
|
+
|
|
173
|
+
def applies(self, rule: str) -> bool:
|
|
174
|
+
return rule in ROLE_RULES[self.role]
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
def role_override_error(text: str) -> str | None:
|
|
178
|
+
markers = ROLE_MARKER.findall(text)
|
|
179
|
+
overrides = ROLE_OVERRIDE.findall(text)
|
|
180
|
+
if not markers:
|
|
181
|
+
return None
|
|
182
|
+
if len(markers) != 1 or len(overrides) != 1:
|
|
183
|
+
return "add exactly one complete sourcebound role marker"
|
|
184
|
+
if overrides[0] not in ROLE_RULES:
|
|
185
|
+
return f"unsupported sourcebound role: {overrides[0]}"
|
|
186
|
+
return None
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
def frontmatter_error(text: str) -> str | None:
|
|
190
|
+
lines = text.splitlines()
|
|
191
|
+
if not lines or lines[0] != "---":
|
|
192
|
+
return None
|
|
193
|
+
if "---" not in lines[1:]:
|
|
194
|
+
return "frontmatter opens at the document start but has no closing delimiter"
|
|
195
|
+
return None
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
def _has_frontmatter(text: str) -> bool:
|
|
199
|
+
lines = text.splitlines()
|
|
200
|
+
return bool(lines and lines[0] == "---" and "---" in lines[1:])
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
def classify_document(relative: Path, text: str) -> DocumentProfile:
|
|
204
|
+
"""Classify a Markdown file by the job its current form performs."""
|
|
205
|
+
normalized = relative.as_posix()
|
|
206
|
+
parts = tuple(part.lower() for part in relative.parts)
|
|
207
|
+
name = relative.name.lower()
|
|
208
|
+
title = next(
|
|
209
|
+
(
|
|
210
|
+
line.lstrip("#").strip().lower()
|
|
211
|
+
for line in text.splitlines()
|
|
212
|
+
if line.startswith("#")
|
|
213
|
+
),
|
|
214
|
+
"",
|
|
215
|
+
)
|
|
216
|
+
registered = REGISTER_PROFILE in text or REGISTER_MARKER.search(text) is not None
|
|
217
|
+
if match := ROLE_OVERRIDE.search(text):
|
|
218
|
+
requested = match.group(1)
|
|
219
|
+
if requested in ROLE_RULES:
|
|
220
|
+
role = cast(DocumentRole, requested)
|
|
221
|
+
return DocumentProfile(
|
|
222
|
+
normalized,
|
|
223
|
+
role,
|
|
224
|
+
"explicit sourcebound role marker",
|
|
225
|
+
registered,
|
|
226
|
+
)
|
|
227
|
+
|
|
228
|
+
if (
|
|
229
|
+
name in {"agents.md", "skill.md"}
|
|
230
|
+
or parts[:1] == (".agents",)
|
|
231
|
+
or "skills" in parts
|
|
232
|
+
and _has_frontmatter(text)
|
|
233
|
+
):
|
|
234
|
+
return DocumentProfile(
|
|
235
|
+
normalized,
|
|
236
|
+
"agent-procedure",
|
|
237
|
+
"path or frontmatter identifies an executable agent procedure",
|
|
238
|
+
registered,
|
|
239
|
+
)
|
|
240
|
+
if any(part in _TEMPLATE_PARTS for part in parts[:-1]):
|
|
241
|
+
return DocumentProfile(
|
|
242
|
+
normalized,
|
|
243
|
+
"template",
|
|
244
|
+
"path identifies prompt or generated-content input",
|
|
245
|
+
registered,
|
|
246
|
+
)
|
|
247
|
+
if _EVIDENCE_NAME.search(relative.name) or any(
|
|
248
|
+
part in {"reviews", "reports", "journals", "receipts", "evaluations"}
|
|
249
|
+
for part in parts[:-1]
|
|
250
|
+
):
|
|
251
|
+
return DocumentProfile(
|
|
252
|
+
normalized,
|
|
253
|
+
"evidence",
|
|
254
|
+
"path identifies a review, result, or longitudinal record",
|
|
255
|
+
registered,
|
|
256
|
+
)
|
|
257
|
+
if _PLAN_NAME.search(relative.name):
|
|
258
|
+
return DocumentProfile(
|
|
259
|
+
normalized,
|
|
260
|
+
"plan",
|
|
261
|
+
"filename identifies a time-scoped plan whose status needs judgment",
|
|
262
|
+
registered,
|
|
263
|
+
)
|
|
264
|
+
if (
|
|
265
|
+
name in _SUPPORT_NAMES
|
|
266
|
+
or _TROUBLESHOOTING_NAME.search(normalized)
|
|
267
|
+
or _TROUBLESHOOTING_NAME.search(title)
|
|
268
|
+
):
|
|
269
|
+
return DocumentProfile(
|
|
270
|
+
normalized,
|
|
271
|
+
"troubleshooting",
|
|
272
|
+
"path or title identifies diagnose-fix-verify work",
|
|
273
|
+
registered,
|
|
274
|
+
)
|
|
275
|
+
if _TUTORIAL_NAME.search(normalized) or _TUTORIAL_NAME.search(title):
|
|
276
|
+
return DocumentProfile(
|
|
277
|
+
normalized,
|
|
278
|
+
"tutorial",
|
|
279
|
+
"path or title identifies an ordered learning path",
|
|
280
|
+
registered,
|
|
281
|
+
)
|
|
282
|
+
if (
|
|
283
|
+
"adr" in parts
|
|
284
|
+
or _ARCHITECTURE_NAME.search(relative.name)
|
|
285
|
+
or _ARCHITECTURE_NAME.search(title)
|
|
286
|
+
):
|
|
287
|
+
return DocumentProfile(
|
|
288
|
+
normalized,
|
|
289
|
+
"architecture",
|
|
290
|
+
"path or title identifies a design or decision record",
|
|
291
|
+
registered,
|
|
292
|
+
)
|
|
293
|
+
if (
|
|
294
|
+
"references" in parts
|
|
295
|
+
or _REFERENCE_NAME.search(relative.name)
|
|
296
|
+
or _REFERENCE_NAME.search(title)
|
|
297
|
+
):
|
|
298
|
+
return DocumentProfile(
|
|
299
|
+
normalized,
|
|
300
|
+
"reference",
|
|
301
|
+
"path or title identifies a lookup surface",
|
|
302
|
+
registered,
|
|
303
|
+
)
|
|
304
|
+
if name in {"contributing.md", "contributor-guide.md"}:
|
|
305
|
+
return DocumentProfile(
|
|
306
|
+
normalized,
|
|
307
|
+
"component-overview",
|
|
308
|
+
"filename identifies a contributor entry point with several reader routes",
|
|
309
|
+
registered,
|
|
310
|
+
)
|
|
311
|
+
if name == "readme.md":
|
|
312
|
+
if len(relative.parts) > 1:
|
|
313
|
+
return DocumentProfile(
|
|
314
|
+
normalized,
|
|
315
|
+
"component-overview",
|
|
316
|
+
"nested README identifies a component-local entry point",
|
|
317
|
+
registered,
|
|
318
|
+
)
|
|
319
|
+
return DocumentProfile(
|
|
320
|
+
normalized,
|
|
321
|
+
"overview",
|
|
322
|
+
"README identifies a repository or component entry point",
|
|
323
|
+
registered,
|
|
324
|
+
)
|
|
325
|
+
return DocumentProfile(
|
|
326
|
+
normalized,
|
|
327
|
+
"task",
|
|
328
|
+
"default role for an authored how-to or explanatory page",
|
|
329
|
+
registered,
|
|
330
|
+
)
|