PICurv 0.1.0
A Parallel Particle-In-Cell Solver for Curvilinear LES
 
Loading...
Searching...
No Matches
Functions | Variables
scaffold_documentation Namespace Reference

Functions

str identifier_slug (str value)
 Build a safe Doxygen/file identifier from a free-form title.
 
str slug (str value)
 Anchor slug for a selector value.
 
int next_page_number ()
 Lowest unused page number in docs/pages.
 
str capability_entry (str family_id, str value)
 Render a Tier-2 capability entry carrying every required contract part.
 
str alias_stub (str family_id, str value, str canonical)
 Render a deprecated-alias stub, which owes three parts rather than eight.
 
str suggested_filename (str title, int number)
 Filename for a scaffolded page, using the same sanitized identifier as the page ID.
 
str page (str kind, str title, int number)
 Render a page skeleton shaped to its document type's contract.
 
str subsystem_record (str identifier, str title)
 Render the machine-readable lifecycle record a planned subsystem owes.
 
str subsystem_charter (str identifier, str title)
 Render a subsystem charter at the planned lifecycle stage.
 
int main ()
 Emit a documentation skeleton for the requested kind.
 

Variables

 REPO_ROOT = Path(__file__).resolve().parents[2]
 
str PAGES_DIR = REPO_ROOT / "docs" / "pages"
 
str FAMILIES_PATH = REPO_ROOT / "tests" / "tooling" / "capability_families.json"
 
dict PAGE_TYPES
 
str INCOMPLETE_MARKER = "@par SCAFFOLD-INCOMPLETE"
 
tuple INCOMPLETE_NOTE
 
dict PAGE_SECTIONS
 

Detailed Description

Generate documentation skeletons that satisfy the repository's own contracts.

Function Documentation

◆ identifier_slug()

str scaffold_documentation.identifier_slug ( str  value)

Build a safe Doxygen/file identifier from a free-form title.

Titles may contain characters that are illegal in a Doxygen identifier or that would imply a nested path in a filename. The display title is kept intact; only the identifier is sanitized.

Parameters
[in]valueFree-form title.
Returns
Safe identifier.
Exceptions
SystemExitwhen nothing usable remains.

Definition at line 39 of file scaffold_documentation.py.

39def identifier_slug(value: str) -> str:
40 """!
41 @brief Build a safe Doxygen/file identifier from a free-form title.
42
43 @details Titles may contain characters that are illegal in a Doxygen identifier or
44 that would imply a nested path in a filename. The display title is kept
45 intact; only the identifier is sanitized.
46 @param[in] value Free-form title.
47 @return Safe identifier.
48 @throws SystemExit when nothing usable remains.
49 """
50 cleaned = re.sub(r"[^A-Za-z0-9]+", "_", value).strip("_")
51 cleaned = re.sub(r"_{2,}", "_", cleaned)
52 if not cleaned:
53 raise SystemExit(
54 f"Title {value!r} contains no characters usable in an identifier; "
55 f"choose a title with letters or digits."
56 )
57 if cleaned[0].isdigit():
58 cleaned = f"p_{cleaned}"
59 return cleaned
60
61
Here is the caller graph for this function:

◆ slug()

str scaffold_documentation.slug ( str  value)

Anchor slug for a selector value.

Parameters
[in]valuePublic selector value.
Returns
Lowercase underscore slug.

Definition at line 62 of file scaffold_documentation.py.

62def slug(value: str) -> str:
63 """!
64 @brief Anchor slug for a selector value.
65 @param[in] value Public selector value.
66 @return Lowercase underscore slug.
67 """
68 return re.sub(r"[^a-z0-9]+", "_", value.lower()).strip("_")
69
70
Here is the caller graph for this function:

◆ next_page_number()

int scaffold_documentation.next_page_number ( )

Lowest unused page number in docs/pages.

Returns
Next available page number.

Definition at line 71 of file scaffold_documentation.py.

71def next_page_number() -> int:
72 """!
73 @brief Lowest unused page number in docs/pages.
74 @return Next available page number.
75 """
76 used = {
77 int(match.group(1))
78 for path in PAGES_DIR.glob("*.md")
79 if (match := re.match(r"(\d+)_", path.name))
80 }
81 return max(used) + 1 if used else 1
82
83
Here is the caller graph for this function:

◆ capability_entry()

str scaffold_documentation.capability_entry ( str  family_id,
str  value 
)

Render a Tier-2 capability entry carrying every required contract part.

Parameters
[in]family_idCapability family identifier.
[in]valuePublic selector value.
Returns
Markdown text for the entry.

Definition at line 84 of file scaffold_documentation.py.

84def capability_entry(family_id: str, value: str) -> str:
85 """!
86 @brief Render a Tier-2 capability entry carrying every required contract part.
87 @param[in] family_id Capability family identifier.
88 @param[in] value Public selector value.
89 @return Markdown text for the entry.
90 """
91 families = {f["id"]: f for f in json.loads(FAMILIES_PATH.read_text(encoding="utf-8"))["families"]}
92 family = families.get(family_id)
93 if family is None:
94 raise SystemExit(
95 f"Unknown family '{family_id}'. Known: {', '.join(sorted(families))}"
96 )
97 anchor = family["entry_anchor_prefix"] + slug(value)
98 return f"""@subsection {anchor}_sub {value}
99
100@anchor {anchor}
101
102{INCOMPLETE_NOTE}
103
104**Identity.** `{family['selector']}` = `{value}` -> TODO: generated flag -> TODO: C enum
105-> @ref TODO_implementing_function.
106
107**What it does.** TODO: the behavior, in a short paragraph.
108
109**When to choose it.** TODO: compare explicitly against its siblings in this family.
110An entry that does not compare is a description, not guidance.
111
112**Parameters it owns.** TODO: options exclusive to this value, required and optional
113separated. Options shared across the family belong on the family page.
114
115**Interactions.** TODO: what it requires, conflicts with, or implies, including
116anything enforced by validation.
117
118**Diagnostics.** TODO: what it logs, and how a reader tells it is working. Name the
119failure signature, not only the success one.
120
121**Evidence.** TODO: facets with sources, or state "Implemented only." Record the same
122sources in `value_metadata["{value}"]["evidence"]` in
123`tests/tooling/capability_families.json` - the audit checks they match.
124
125**Limitations.** TODO: what it cannot do.
126"""
127
128
Here is the call graph for this function:
Here is the caller graph for this function:

◆ alias_stub()

str scaffold_documentation.alias_stub ( str  family_id,
str  value,
str  canonical 
)

Render a deprecated-alias stub, which owes three parts rather than eight.

Parameters
[in]family_idCapability family identifier.
[in]valueDeprecated selector value.
[in]canonicalCanonical value it resolves to.
Returns
Markdown text for the stub.

Definition at line 129 of file scaffold_documentation.py.

129def alias_stub(family_id: str, value: str, canonical: str) -> str:
130 """!
131 @brief Render a deprecated-alias stub, which owes three parts rather than eight.
132 @param[in] family_id Capability family identifier.
133 @param[in] value Deprecated selector value.
134 @param[in] canonical Canonical value it resolves to.
135 @return Markdown text for the stub.
136 """
137 families = {f["id"]: f for f in json.loads(FAMILIES_PATH.read_text(encoding="utf-8"))["families"]}
138 family = families.get(family_id)
139 if family is None:
140 raise SystemExit(f"Unknown family '{family_id}'. Known: {', '.join(sorted(families))}")
141 known = set(family.get("value_metadata", {}))
142 if known and canonical not in known:
143 raise SystemExit(
144 f"Canonical target '{canonical}' is not a declared value of '{family_id}'. "
145 f"Known: {', '.join(sorted(known))}"
146 )
147 anchor = family["entry_anchor_prefix"] + slug(value)
148 return f"""@subsection {anchor}_sub {value} (deprecated)
149
150@anchor {anchor}
151
152{INCOMPLETE_NOTE}
153
154**Identity.** `{value}` - a **deprecated alias** that normalizes to `{canonical}`.
155
156**Status.** Deprecated. TODO: why it still parses.
157
158**Migration.** TODO: the exact edits to move to `{canonical}`.
159"""
160
161
Here is the call graph for this function:
Here is the caller graph for this function:

◆ suggested_filename()

str scaffold_documentation.suggested_filename ( str  title,
int  number 
)

Filename for a scaffolded page, using the same sanitized identifier as the page ID.

Parameters
[in]titleFree-form page title.
[in]numberPage number.
Returns
Safe filename.

Definition at line 195 of file scaffold_documentation.py.

195def suggested_filename(title: str, number: int) -> str:
196 """!
197 @brief Filename for a scaffolded page, using the same sanitized identifier as the page ID.
198 @param[in] title Free-form page title.
199 @param[in] number Page number.
200 @return Safe filename.
201 """
202 return f"{number:02d}_{identifier_slug(title)}.md"
203
204

◆ page()

str scaffold_documentation.page ( str  kind,
str  title,
int  number 
)

Render a page skeleton shaped to its document type's contract.

Each type gets the sections it actually owes, not a generic outline. A tutorial that does not state its outcome, or a reference that does not declare its scope, is not the type it claims to be.

Parameters
[in]kindPage type key.
[in]titleHuman-readable page title.
[in]numberPage number.
Returns
Markdown text for the page.

Definition at line 205 of file scaffold_documentation.py.

205def page(kind: str, title: str, number: int) -> str:
206 """!
207 @brief Render a page skeleton shaped to its document type's contract.
208
209 @details Each type gets the sections it actually owes, not a generic outline. A
210 tutorial that does not state its outcome, or a reference that does not
211 declare its scope, is not the type it claims to be.
212 @param[in] kind Page type key.
213 @param[in] title Human-readable page title.
214 @param[in] number Page number.
215 @return Markdown text for the page.
216 """
217 safe = identifier_slug(title)
218 identifier = f"{number:02d}_{safe}"
219 owes = {
220 "tutorial": "a working outcome: every command runs as written, from a stated starting state",
221 "how-to": "a completed task, assuming the reader can already run PICurv",
222 "reference": "accuracy and completeness within its declared scope",
223 "explanation": "understanding: why it is like this, and what the alternatives were",
224 "hub": "complete and current routing, and nothing else",
225 }[kind]
226
227 body = [
228 f"@page {identifier} {title}",
229 "",
230 f"@anchor _{safe}",
231 "",
232 f"@pagemeta{{{PAGE_TYPES[kind]}, TODO audience, TODO status}}",
233 "",
234 INCOMPLETE_NOTE,
235 "",
236 "TODO: one paragraph saying what this page is for.",
237 "",
238 f"This page owes the reader {owes}. See **@subpage 63_Page_Type_Contract** for what a",
239 f"{PAGE_TYPES[kind]} must refuse to do.",
240 "",
241 "@tableofcontents",
242 "",
243 ]
244 for index, (heading, guidance) in enumerate(PAGE_SECTIONS[kind], start=1):
245 section = identifier_slug(heading).lower()
246 body += [f"@section p{number}_{section}_sec {index}. {heading}", "", guidance, ""]
247 last = len(PAGE_SECTIONS[kind]) + 1
248 body += [
249 f"@section p{number}_related_sec {last}. Related Documentation",
250 "",
251 "- **@subpage 47_Documentation_Catalog**",
252 "",
253 ]
254 return "\n".join(body)
255
256
Here is the call graph for this function:
Here is the caller graph for this function:

◆ subsystem_record()

str scaffold_documentation.subsystem_record ( str  identifier,
str  title 
)

Render the machine-readable lifecycle record a planned subsystem owes.

The charter is prose; this is the record make audit-subsystems reads. A planned subsystem owes only four obligations, so the stub is short by design - the gate grows with the status, not with the scaffold.

Parameters
[in]identifierSubsystem id.
[in]titleHuman-readable subsystem name.
Returns
JSON text to paste into tests/tooling/subsystem_records.json.

Definition at line 257 of file scaffold_documentation.py.

257def subsystem_record(identifier: str, title: str) -> str:
258 """!
259 @brief Render the machine-readable lifecycle record a `planned` subsystem owes.
260
261 @details The charter is prose; this is the record `make audit-subsystems` reads.
262 A planned subsystem owes only four obligations, so the stub is short by
263 design - the gate grows with the status, not with the scaffold.
264 @param[in] identifier Subsystem id.
265 @param[in] title Human-readable subsystem name.
266 @return JSON text to paste into tests/tooling/subsystem_records.json.
267 """
268 record = {
269 "id": identifier,
270 "title": title,
271 "status": "planned",
272 "visibility": "public",
273 "previous_status": None,
274 "capability_families": [],
275 "obligations": {
276 "purpose": {"page": "TODO_page_id", "anchor": "TODO_anchor"},
277 "intended_scope": {"page": "TODO_page_id", "anchor": "TODO_anchor"},
278 "design_owner": {"value": "TODO: name"},
279 "not_implemented_status": {"page": "TODO_page_id", "anchor": "TODO_anchor"},
280 },
281 "concerns": {},
282 }
283 return json.dumps(record, indent=2)
284
285
Here is the caller graph for this function:

◆ subsystem_charter()

str scaffold_documentation.subsystem_charter ( str  identifier,
str  title 
)

Render a subsystem charter at the planned lifecycle stage.

Requirements grow with the status a subsystem claims, so this scaffold asks only what planned owes. The later stages are listed so the author can see what each promotion will require.

Parameters
[in]identifierSubsystem identifier.
[in]titleHuman-readable subsystem name.
Returns
Markdown text for the charter.

Definition at line 286 of file scaffold_documentation.py.

286def subsystem_charter(identifier: str, title: str) -> str:
287 """!
288 @brief Render a subsystem charter at the `planned` lifecycle stage.
289
290 @details Requirements grow with the status a subsystem claims, so this scaffold
291 asks only what `planned` owes. The later stages are listed so the author
292 can see what each promotion will require.
293 @param[in] identifier Subsystem identifier.
294 @param[in] title Human-readable subsystem name.
295 @return Markdown text for the charter.
296 """
297 return f"""# Subsystem charter: {title}
298
299{INCOMPLETE_MARKER} - replace every TODO, then delete this line.
300
301Identifier: `{identifier}`
302Lifecycle status: **planned**
303
304## Purpose
305
306TODO: what problem this solves, and for whom.
307
308## Intended scope
309
310TODO: what it will cover.
311
312## Explicitly out of scope
313
314TODO: what it will not cover. This is the most useful section to write early.
315
316## Design owner
317
318TODO: name.
319
320## Not implemented
321
322This subsystem is `planned`. Nothing here describes working behavior, and it must not
323appear in user-facing reference until it reaches `public experimental`.
324
325## Concern modules
326
327Declare which apply, per **64_Documentation_Extension_Framework**. A concern may be
328marked not applicable **with a stated reason**; an empty heading is not an answer.
329
330- [ ] Numerical method
331- [ ] User selector
332- [ ] Units and nondimensionalization
333- [ ] Artifact topology and storage lifecycle
334- [ ] Persistent/restart state
335- [ ] Determinism and reproducibility
336- [ ] MPI/distributed execution
337- [ ] External service
338- [ ] Security/credentials
339- [ ] Generated artifact
340- [ ] File format
341- [ ] Concurrency, permissions, destructive scope
342- [ ] Backward compatibility
343- [ ] Scientific verification and validation
344
345## What each promotion will require
346
347| To reach | Add |
348|---|---|
349| `internal` | Scope boundary, architecture boundary, dependencies, developer entry points |
350| `public experimental` | Configuration, selection guidance, observability, limitations, safe-use boundaries |
351| `supported` | Evidence, lifecycle and restart behavior, operations, troubleshooting, examples, complete reference |
352"""
353
354
Here is the caller graph for this function:

◆ main()

int scaffold_documentation.main ( )

Emit a documentation skeleton for the requested kind.

Returns
Process status code.

Definition at line 355 of file scaffold_documentation.py.

355def main() -> int:
356 """!
357 @brief Emit a documentation skeleton for the requested kind.
358 @return Process status code.
359 """
360 parser = argparse.ArgumentParser(
361 description="Generate documentation skeletons that satisfy the repository's contracts.",
362 epilog=(
363 "Examples:\n"
364 " scaffold_documentation.py capability --family boundary.handler --value slip_wall\n"
365 " scaffold_documentation.py alias --family momentum.solver --value 'Old Name' "
366 "--canonical 'New Name'\n"
367 " scaffold_documentation.py page --type how-to --title 'Running On A Cluster'\n"
368 " scaffold_documentation.py subsystem --id ibm --title 'Immersed Boundaries'\n"
369 ),
370 formatter_class=argparse.RawTextHelpFormatter,
371 )
372 sub = parser.add_subparsers(dest="kind", required=True)
373
374 p_cap = sub.add_parser("capability", help="A Tier-2 entry for a new selector value.")
375 p_cap.add_argument("--family", required=True)
376 p_cap.add_argument("--value", required=True)
377
378 p_alias = sub.add_parser("alias", help="A deprecated-alias stub.")
379 p_alias.add_argument("--family", required=True)
380 p_alias.add_argument("--value", required=True)
381 p_alias.add_argument("--canonical", required=True)
382
383 p_page = sub.add_parser("page", help="A new documentation page of a declared type.")
384 p_page.add_argument("--type", required=True, choices=sorted(PAGE_TYPES))
385 p_page.add_argument("--title", required=True)
386
387 p_sub = sub.add_parser("subsystem", help="A subsystem charter at the planned stage.")
388 p_sub.add_argument("--id", required=True)
389 p_sub.add_argument("--title", required=True)
390
391 args = parser.parse_args()
392
393 if args.kind == "capability":
394 print(capability_entry(args.family, args.value))
395 print("# Next: paste into the family page, then run 'make audit-capability'.", file=sys.stderr)
396 elif args.kind == "alias":
397 print(alias_stub(args.family, args.value, args.canonical))
398 print("# Next: declare alias_of in capability_families.json.", file=sys.stderr)
399 elif args.kind == "page":
400 number = next_page_number()
401 print(page(args.type, args.title, number))
402 print(
403 f"# Next: save as docs/pages/{suggested_filename(args.title, number)}, "
404 f"then adopt it with @subpage from a hub page or it will be reported as orphaned.",
405 file=sys.stderr,
406 )
407 else:
408 print(subsystem_charter(args.id, args.title))
409 print("\n<!-- Paste into the \"subsystems\" list of "
410 "tests/tooling/subsystem_records.json:\n")
411 print(subsystem_record(args.id, args.title))
412 print("-->")
413 print("# Next: add the record above to tests/tooling/subsystem_records.json and run\n"
414 "# make audit-subsystems. Record it in the contract registry too if it\n"
415 "# introduces invariants.", file=sys.stderr)
416 return 0
417
418
int main(int argc, char **argv)
Entry point for the postprocessor executable.
Here is the call graph for this function:
Here is the caller graph for this function:

Variable Documentation

◆ REPO_ROOT

scaffold_documentation.REPO_ROOT = Path(__file__).resolve().parents[2]

Definition at line 13 of file scaffold_documentation.py.

◆ PAGES_DIR

str scaffold_documentation.PAGES_DIR = REPO_ROOT / "docs" / "pages"

Definition at line 14 of file scaffold_documentation.py.

◆ FAMILIES_PATH

str scaffold_documentation.FAMILIES_PATH = REPO_ROOT / "tests" / "tooling" / "capability_families.json"

Definition at line 15 of file scaffold_documentation.py.

◆ PAGE_TYPES

dict scaffold_documentation.PAGE_TYPES
Initial value:
1= {
2 "tutorial": "Tutorial",
3 "how-to": "How-to",
4 "reference": "Reference",
5 "explanation": "Explanation",
6 "hub": "Hub",
7}

Definition at line 17 of file scaffold_documentation.py.

◆ INCOMPLETE_MARKER

str scaffold_documentation.INCOMPLETE_MARKER = "@par SCAFFOLD-INCOMPLETE"

Definition at line 30 of file scaffold_documentation.py.

◆ INCOMPLETE_NOTE

tuple scaffold_documentation.INCOMPLETE_NOTE
Initial value:
1= (
2 f"{INCOMPLETE_MARKER}\n"
3 "This was generated from a scaffold and is not finished. Replace every TODO, then\n"
4 "delete this block. Publication gates reject the marker, so an untouched scaffold\n"
5 "cannot ship."
6)

Definition at line 31 of file scaffold_documentation.py.

◆ PAGE_SECTIONS

dict scaffold_documentation.PAGE_SECTIONS

Definition at line 162 of file scaffold_documentation.py.