ops-wiki-agent-kit 0.1.0
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.
- package/.github/agents/docs-target-catalog.agent.md +52 -0
- package/.github/agents/docs-target-queue-from-catalog.agent.md +34 -0
- package/.github/agents/source-code-to-spec-documenter.agent.md +39 -0
- package/.github/agents/source-code-to-spec-reviewer.agent.md +51 -0
- package/.github/agents/source-code-to-system-ops-overview.agent.md +39 -0
- package/.github/prompts/00-generate-target-all-spec.prompt.md +35 -0
- package/.github/prompts/01-generate-target-foundation-spec.prompt.md +35 -0
- package/.github/prompts/02-generate-target-architecture-spec.prompt.md +35 -0
- package/.github/prompts/03-generate-target-ops-spec.prompt.md +35 -0
- package/.github/prompts/04-review-target-spec.prompt.md +24 -0
- package/.github/prompts/docs-target-catalog.prompt.md +32 -0
- package/.github/prompts/docs-target-queue-from-catalog.prompt.md +28 -0
- package/.github/prompts/generate-system-ops-overview.prompt.md +62 -0
- package/.github/skills/database-query/SKILL.md +140 -0
- package/.github/skills/database-query/references/client-commands.md +189 -0
- package/.github/skills/database-query/references/query-safety.md +109 -0
- package/.github/skills/database-query/scripts/find_db_config.py +273 -0
- package/.github/skills/docs-target-catalog/SKILL.md +194 -0
- package/.github/skills/docs-target-catalog/references/docs-target-queue-conversion.md +164 -0
- package/.github/skills/docs-target-catalog/references/entrypoint-source-patterns.md +83 -0
- package/.github/skills/docs-target-catalog/references/output-templates.md +168 -0
- package/.github/skills/docs-target-queue-from-catalog/SKILL.md +255 -0
- package/.github/skills/docs-target-queue-from-catalog/references/docs-target-queue-contract.md +125 -0
- package/.github/skills/docs-target-queue-from-catalog/references/metadata-acquisition-patterns.md +149 -0
- package/.github/skills/docs-target-queue-from-catalog/scripts/write_documentation_target_queue.py +527 -0
- package/.github/skills/source-code-to-ops-spec-guidelines/SKILL.md +128 -0
- package/.github/skills/source-code-to-ops-spec-guidelines/references/01-system-overview-and-business-scenarios-guideline.md +172 -0
- package/.github/skills/source-code-to-ops-spec-guidelines/references/02-core-architecture-flow-data-logic-guideline.md +637 -0
- package/.github/skills/source-code-to-ops-spec-guidelines/references/03-error-ops-scenario-coverage-guideline.md +533 -0
- package/.github/skills/source-code-to-ops-spec-guidelines/references/supporting-output-format-diagram-and-example-reference.md +523 -0
- package/.github/skills/source-code-to-spec-documenter/SKILL.md +80 -0
- package/.github/skills/source-code-to-spec-documenter/references/generation-handoff-contract.md +155 -0
- package/.github/skills/source-code-to-spec-documenter/references/generation-workflow.md +184 -0
- package/.github/skills/source-code-to-spec-documenter/references/source-tracing-rules.md +271 -0
- package/.github/skills/source-code-to-spec-documenter/references/target-queue-contract.md +78 -0
- package/.github/skills/source-code-to-spec-documenter/scripts/spec_queue.py +222 -0
- package/.github/skills/source-code-to-spec-tools/SKILL.md +117 -0
- package/.github/skills/source-code-to-spec-tools/references/repository-artifact-contract.md +122 -0
- package/.github/skills/source-code-to-spec-tools/references/target-queue-schema-contract.md +116 -0
- package/.github/skills/source-code-to-spec-tools/references/terminology-contract.md +121 -0
- package/.github/skills/source-code-to-spec-tools/scripts/catalog_query.py +324 -0
- package/.github/skills/source-code-to-spec-tools/scripts/queue_contract.py +210 -0
- package/.github/skills/source-code-to-spec-tools/scripts/source_lookup.py +360 -0
- package/.github/skills/source-code-to-spec-tools/scripts/target_query.py +407 -0
- package/.github/skills/source-code-to-system-ops-overview/SKILL.md +82 -0
- package/.github/skills/source-code-to-system-ops-overview/references/system-operations-overview-guideline.md +332 -0
- package/README.md +116 -0
- package/ops-wiki-agent-kit.js +173 -0
- package/package.json +22 -0
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
import sys
|
|
3
|
+
|
|
4
|
+
sys.dont_write_bytecode = True
|
|
5
|
+
|
|
6
|
+
import argparse
|
|
7
|
+
import json
|
|
8
|
+
import re
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
PREFERRED_SECTIONS = {
|
|
13
|
+
"handoff": "Authoritative Target Source Handoff",
|
|
14
|
+
"direct": "Direct Target Rows",
|
|
15
|
+
"hardcoded": "Hardcoded Target Rows",
|
|
16
|
+
"coverage": "Coverage Review",
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def configure_stdio():
|
|
21
|
+
for stream_name in ("stdout", "stderr"):
|
|
22
|
+
stream = getattr(sys, stream_name, None)
|
|
23
|
+
reconfigure = getattr(stream, "reconfigure", None)
|
|
24
|
+
if callable(reconfigure):
|
|
25
|
+
reconfigure(encoding="utf-8")
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def normalize_text(value):
|
|
29
|
+
if value is None:
|
|
30
|
+
return ""
|
|
31
|
+
return re.sub(r"\s+", " ", str(value)).strip()
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def normalize_key(value):
|
|
35
|
+
return normalize_text(value).casefold()
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def split_markdown_row(line):
|
|
39
|
+
line = line.strip()
|
|
40
|
+
if not line.startswith("|") or not line.endswith("|"):
|
|
41
|
+
return []
|
|
42
|
+
cells = []
|
|
43
|
+
current = []
|
|
44
|
+
escaped = False
|
|
45
|
+
for char in line[1:-1]:
|
|
46
|
+
if escaped:
|
|
47
|
+
current.append(char)
|
|
48
|
+
escaped = False
|
|
49
|
+
elif char == "\\":
|
|
50
|
+
escaped = True
|
|
51
|
+
elif char == "|":
|
|
52
|
+
cells.append("".join(current).strip())
|
|
53
|
+
current = []
|
|
54
|
+
else:
|
|
55
|
+
current.append(char)
|
|
56
|
+
cells.append("".join(current).strip())
|
|
57
|
+
return cells
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def is_separator(cells):
|
|
61
|
+
return bool(cells) and all(re.fullmatch(r":?-{3,}:?", cell.strip()) for cell in cells)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def markdown_escape(value):
|
|
65
|
+
return normalize_text(value).replace("|", "\\|")
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def iter_markdown_tables(lines):
|
|
69
|
+
current_heading = ""
|
|
70
|
+
current_level = 0
|
|
71
|
+
for index, line in enumerate(lines):
|
|
72
|
+
heading = re.match(r"^(#{1,6})\s+(.+?)\s*$", line)
|
|
73
|
+
if heading:
|
|
74
|
+
current_level = len(heading.group(1))
|
|
75
|
+
current_heading = heading.group(2).strip()
|
|
76
|
+
continue
|
|
77
|
+
|
|
78
|
+
header = split_markdown_row(line)
|
|
79
|
+
if not header or index + 1 >= len(lines):
|
|
80
|
+
continue
|
|
81
|
+
separator = split_markdown_row(lines[index + 1])
|
|
82
|
+
if len(separator) != len(header) or not is_separator(separator):
|
|
83
|
+
continue
|
|
84
|
+
|
|
85
|
+
rows = []
|
|
86
|
+
end_line = index + 2
|
|
87
|
+
for data_index in range(index + 2, len(lines)):
|
|
88
|
+
values = split_markdown_row(lines[data_index])
|
|
89
|
+
if len(values) != len(header):
|
|
90
|
+
break
|
|
91
|
+
rows.append(dict(zip(header, values)))
|
|
92
|
+
end_line = data_index + 1
|
|
93
|
+
yield {
|
|
94
|
+
"section": current_heading,
|
|
95
|
+
"section_level": current_level,
|
|
96
|
+
"columns": header,
|
|
97
|
+
"rows": rows,
|
|
98
|
+
"start_line": index + 1,
|
|
99
|
+
"end_line": end_line,
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def read_catalog(path):
|
|
104
|
+
path = Path(path)
|
|
105
|
+
lines = path.read_text(encoding="utf-8-sig").splitlines()
|
|
106
|
+
tables = list(iter_markdown_tables(lines))
|
|
107
|
+
if not tables:
|
|
108
|
+
raise SystemExit(f"No Markdown tables found in {path}")
|
|
109
|
+
return {"path": str(path), "tables": tables}
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def table_metadata(table):
|
|
113
|
+
return {
|
|
114
|
+
"section": table["section"],
|
|
115
|
+
"section_level": table["section_level"],
|
|
116
|
+
"columns": table["columns"],
|
|
117
|
+
"row_count": len(table["rows"]),
|
|
118
|
+
"start_line": table["start_line"],
|
|
119
|
+
"end_line": table["end_line"],
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def section_matches(actual, expected):
|
|
124
|
+
if not expected:
|
|
125
|
+
return True
|
|
126
|
+
return normalize_key(expected) in normalize_key(actual)
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def row_matches(row, query=None, column_filters=None):
|
|
130
|
+
if query and normalize_key(query) not in normalize_key(" ".join(row.values())):
|
|
131
|
+
return False
|
|
132
|
+
for column_name, expected in column_filters or []:
|
|
133
|
+
matched_key = None
|
|
134
|
+
for key in row.keys():
|
|
135
|
+
if normalize_key(key) == normalize_key(column_name):
|
|
136
|
+
matched_key = key
|
|
137
|
+
break
|
|
138
|
+
if matched_key is None:
|
|
139
|
+
return False
|
|
140
|
+
if normalize_key(expected) not in normalize_key(row.get(matched_key)):
|
|
141
|
+
return False
|
|
142
|
+
return True
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
def parse_column_filters(values):
|
|
146
|
+
filters = []
|
|
147
|
+
for value in values or []:
|
|
148
|
+
if "=" not in value:
|
|
149
|
+
raise SystemExit(f"Invalid --where value: {value}. Expected column=value.")
|
|
150
|
+
column_name, expected = value.split("=", 1)
|
|
151
|
+
column_name = normalize_text(column_name)
|
|
152
|
+
expected = normalize_text(expected)
|
|
153
|
+
if not column_name:
|
|
154
|
+
raise SystemExit(f"Invalid --where value: {value}. Missing column name.")
|
|
155
|
+
filters.append((column_name, expected))
|
|
156
|
+
return filters
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def collect_rows(catalog, section=None, query=None, column_filters=None, limit=None):
|
|
160
|
+
results = []
|
|
161
|
+
for table in catalog["tables"]:
|
|
162
|
+
if not section_matches(table["section"], section):
|
|
163
|
+
continue
|
|
164
|
+
for row in table["rows"]:
|
|
165
|
+
if not row_matches(row, query=query, column_filters=column_filters):
|
|
166
|
+
continue
|
|
167
|
+
item = dict(row)
|
|
168
|
+
item["_section"] = table["section"]
|
|
169
|
+
item["_line"] = table["start_line"]
|
|
170
|
+
results.append(item)
|
|
171
|
+
if limit is not None and len(results) >= limit:
|
|
172
|
+
return results
|
|
173
|
+
return results
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
def render_table(rows):
|
|
177
|
+
if not rows:
|
|
178
|
+
return "(no rows)"
|
|
179
|
+
columns = list(rows[0].keys())
|
|
180
|
+
for row in rows[1:]:
|
|
181
|
+
for column in row.keys():
|
|
182
|
+
if column not in columns:
|
|
183
|
+
columns.append(column)
|
|
184
|
+
lines = []
|
|
185
|
+
lines.append("| " + " | ".join(columns) + " |")
|
|
186
|
+
lines.append("| " + " | ".join("---" for _ in columns) + " |")
|
|
187
|
+
for row in rows:
|
|
188
|
+
lines.append("| " + " | ".join(markdown_escape(row.get(column, "")) for column in columns) + " |")
|
|
189
|
+
return "\n".join(lines)
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
def print_output(payload, output_format):
|
|
193
|
+
if output_format == "json":
|
|
194
|
+
print(json.dumps(payload, ensure_ascii=False, indent=2))
|
|
195
|
+
return
|
|
196
|
+
if isinstance(payload, dict) and "rows" in payload:
|
|
197
|
+
print(render_table(payload["rows"]))
|
|
198
|
+
return
|
|
199
|
+
if isinstance(payload, dict) and "tables" in payload:
|
|
200
|
+
print(render_table(payload["tables"]))
|
|
201
|
+
return
|
|
202
|
+
if isinstance(payload, list):
|
|
203
|
+
print(render_table(payload))
|
|
204
|
+
return
|
|
205
|
+
print(json.dumps(payload, ensure_ascii=False, indent=2))
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
def command_tables(args):
|
|
209
|
+
catalog = read_catalog(args.catalog)
|
|
210
|
+
tables = [table_metadata(table) for table in catalog["tables"]]
|
|
211
|
+
if args.section:
|
|
212
|
+
tables = [table for table in tables if section_matches(table["section"], args.section)]
|
|
213
|
+
print_output({"catalog": catalog["path"], "count": len(tables), "tables": tables}, args.output)
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
def command_rows(args):
|
|
217
|
+
catalog = read_catalog(args.catalog)
|
|
218
|
+
rows = collect_rows(
|
|
219
|
+
catalog,
|
|
220
|
+
section=args.section,
|
|
221
|
+
query=args.query,
|
|
222
|
+
column_filters=parse_column_filters(args.where),
|
|
223
|
+
limit=args.limit,
|
|
224
|
+
)
|
|
225
|
+
print_output({"catalog": catalog["path"], "count": len(rows), "rows": rows}, args.output)
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
def command_handoff(args):
|
|
229
|
+
catalog = read_catalog(args.catalog)
|
|
230
|
+
filters = parse_column_filters(args.where)
|
|
231
|
+
if args.action:
|
|
232
|
+
filters.append(("target_queue_action", args.action))
|
|
233
|
+
if args.target_scope:
|
|
234
|
+
filters.append(("target_scope", args.target_scope))
|
|
235
|
+
if args.authority:
|
|
236
|
+
filters.append(("final_row_authority", args.authority))
|
|
237
|
+
rows = collect_rows(
|
|
238
|
+
catalog,
|
|
239
|
+
section=PREFERRED_SECTIONS["handoff"],
|
|
240
|
+
query=args.query,
|
|
241
|
+
column_filters=filters,
|
|
242
|
+
limit=args.limit,
|
|
243
|
+
)
|
|
244
|
+
print_output({"catalog": catalog["path"], "count": len(rows), "rows": rows}, args.output)
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
def command_coverage(args):
|
|
248
|
+
catalog = read_catalog(args.catalog)
|
|
249
|
+
rows = collect_rows(
|
|
250
|
+
catalog,
|
|
251
|
+
section=PREFERRED_SECTIONS["coverage"],
|
|
252
|
+
query=args.query,
|
|
253
|
+
column_filters=parse_column_filters(args.where),
|
|
254
|
+
limit=args.limit,
|
|
255
|
+
)
|
|
256
|
+
print_output({"catalog": catalog["path"], "count": len(rows), "rows": rows}, args.output)
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
def command_search(args):
|
|
260
|
+
catalog = read_catalog(args.catalog)
|
|
261
|
+
rows = collect_rows(catalog, query=args.query, limit=args.limit)
|
|
262
|
+
print_output({"catalog": catalog["path"], "count": len(rows), "rows": rows}, args.output)
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
def build_parser():
|
|
266
|
+
parser = argparse.ArgumentParser(
|
|
267
|
+
description="Parse and query docs-target-catalog Markdown tables as reusable source handoff data."
|
|
268
|
+
)
|
|
269
|
+
subparsers = parser.add_subparsers(dest="command", required=True)
|
|
270
|
+
|
|
271
|
+
tables = subparsers.add_parser("tables", help="List Markdown tables with section, columns, row count, and lines.")
|
|
272
|
+
tables.add_argument("--catalog", default="docs/docs-target-catalog.md")
|
|
273
|
+
tables.add_argument("--section")
|
|
274
|
+
tables.add_argument("--output", choices=("json", "markdown"), default="json")
|
|
275
|
+
tables.set_defaults(func=command_tables)
|
|
276
|
+
|
|
277
|
+
rows = subparsers.add_parser("rows", help="Query rows from a named catalog section.")
|
|
278
|
+
rows.add_argument("--catalog", default="docs/docs-target-catalog.md")
|
|
279
|
+
rows.add_argument("--section", required=True)
|
|
280
|
+
rows.add_argument("--query")
|
|
281
|
+
rows.add_argument("--where", action="append", default=[], help="Column contains filter in column=value form.")
|
|
282
|
+
rows.add_argument("--limit", type=int)
|
|
283
|
+
rows.add_argument("--output", choices=("json", "markdown"), default="json")
|
|
284
|
+
rows.set_defaults(func=command_rows)
|
|
285
|
+
|
|
286
|
+
handoff = subparsers.add_parser("handoff", help="Query Authoritative Target Source Handoff rows.")
|
|
287
|
+
handoff.add_argument("--catalog", default="docs/docs-target-catalog.md")
|
|
288
|
+
handoff.add_argument("--query")
|
|
289
|
+
handoff.add_argument("--action", help="Filter target_queue_action, e.g. direct_rows or query/export.")
|
|
290
|
+
handoff.add_argument("--target-scope")
|
|
291
|
+
handoff.add_argument("--authority", help="Filter final_row_authority.")
|
|
292
|
+
handoff.add_argument("--where", action="append", default=[], help="Column contains filter in column=value form.")
|
|
293
|
+
handoff.add_argument("--limit", type=int)
|
|
294
|
+
handoff.add_argument("--output", choices=("json", "markdown"), default="json")
|
|
295
|
+
handoff.set_defaults(func=command_handoff)
|
|
296
|
+
|
|
297
|
+
coverage = subparsers.add_parser("coverage", help="Query catalog Coverage Review rows.")
|
|
298
|
+
coverage.add_argument("--catalog", default="docs/docs-target-catalog.md")
|
|
299
|
+
coverage.add_argument("--query")
|
|
300
|
+
coverage.add_argument("--where", action="append", default=[], help="Column contains filter in column=value form.")
|
|
301
|
+
coverage.add_argument("--limit", type=int)
|
|
302
|
+
coverage.add_argument("--output", choices=("json", "markdown"), default="json")
|
|
303
|
+
coverage.set_defaults(func=command_coverage)
|
|
304
|
+
|
|
305
|
+
search = subparsers.add_parser("search", help="Search every parsed catalog table row.")
|
|
306
|
+
search.add_argument("--catalog", default="docs/docs-target-catalog.md")
|
|
307
|
+
search.add_argument("--query", required=True)
|
|
308
|
+
search.add_argument("--limit", type=int)
|
|
309
|
+
search.add_argument("--output", choices=("json", "markdown"), default="json")
|
|
310
|
+
search.set_defaults(func=command_search)
|
|
311
|
+
return parser
|
|
312
|
+
|
|
313
|
+
|
|
314
|
+
def main():
|
|
315
|
+
configure_stdio()
|
|
316
|
+
args = build_parser().parse_args()
|
|
317
|
+
args.func(args)
|
|
318
|
+
|
|
319
|
+
|
|
320
|
+
if __name__ == "__main__":
|
|
321
|
+
try:
|
|
322
|
+
main()
|
|
323
|
+
except BrokenPipeError:
|
|
324
|
+
sys.exit(1)
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Shared documentation target queue schema and normalization helpers."""
|
|
3
|
+
|
|
4
|
+
import sys
|
|
5
|
+
|
|
6
|
+
sys.dont_write_bytecode = True
|
|
7
|
+
|
|
8
|
+
import re
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
MAIN_COLUMNS = [
|
|
12
|
+
"id",
|
|
13
|
+
"source_type",
|
|
14
|
+
"original_id",
|
|
15
|
+
"group",
|
|
16
|
+
"name",
|
|
17
|
+
"entrypoint",
|
|
18
|
+
"document_path",
|
|
19
|
+
"keyword",
|
|
20
|
+
"doc_profile",
|
|
21
|
+
"foundation_doc_status",
|
|
22
|
+
"architecture_doc_status",
|
|
23
|
+
"ops_doc_status",
|
|
24
|
+
"review_status",
|
|
25
|
+
"document_completed_flag(Y/N)",
|
|
26
|
+
"last_handoff",
|
|
27
|
+
"notes",
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
SUMMARY_COLUMNS = [
|
|
31
|
+
"target_scope",
|
|
32
|
+
"source_kind",
|
|
33
|
+
"authoritative_source",
|
|
34
|
+
"acquisition_method",
|
|
35
|
+
"selected_fields",
|
|
36
|
+
"filter_or_scope",
|
|
37
|
+
"raw_count",
|
|
38
|
+
"eligible_count",
|
|
39
|
+
"excluded_count",
|
|
40
|
+
"gap_count",
|
|
41
|
+
"validation_status",
|
|
42
|
+
]
|
|
43
|
+
|
|
44
|
+
SUMMARY_SCOPE_COLUMNS = [
|
|
45
|
+
"target_scope",
|
|
46
|
+
"source_kind",
|
|
47
|
+
]
|
|
48
|
+
|
|
49
|
+
COVERAGE_COLUMNS = [
|
|
50
|
+
"item",
|
|
51
|
+
"reason_not_in_table",
|
|
52
|
+
"evidence",
|
|
53
|
+
"recommended_next_step",
|
|
54
|
+
]
|
|
55
|
+
|
|
56
|
+
DOC_STATUSES = {"pending", "in_progress", "generated", "partial", "blocked", "failed", "n/a"}
|
|
57
|
+
FOUNDATION_DOC_STATUSES = DOC_STATUSES
|
|
58
|
+
ARCHITECTURE_DOC_STATUSES = DOC_STATUSES
|
|
59
|
+
OPS_DOC_STATUSES = DOC_STATUSES
|
|
60
|
+
REVIEW_STATUSES = {"not_started", "pending", "passed", "failed", "blocked", "waived"}
|
|
61
|
+
DOC_PROFILES = {"lite", "standard", "full"}
|
|
62
|
+
|
|
63
|
+
SOURCE_TYPE_REGISTRY = {
|
|
64
|
+
"Function": {
|
|
65
|
+
"prefix": "F",
|
|
66
|
+
"path_pattern": "docs/feature/{group}/{name}",
|
|
67
|
+
"default_doc_profile": "standard",
|
|
68
|
+
"scope_hints": ["function", "menu", "navigation", "screen", "ui"],
|
|
69
|
+
"use_for": "user-facing menu/navigation/business capabilities that are not better represented by a specific channel",
|
|
70
|
+
},
|
|
71
|
+
"Job": {
|
|
72
|
+
"prefix": "J",
|
|
73
|
+
"path_pattern": "docs/job/{name}",
|
|
74
|
+
"default_doc_profile": "standard",
|
|
75
|
+
"scope_hints": ["job", "batch", "scheduler", "worker", "cron"],
|
|
76
|
+
"use_for": "scheduled jobs, workers, batch jobs, DB jobs, background processors",
|
|
77
|
+
},
|
|
78
|
+
"API": {
|
|
79
|
+
"prefix": "A",
|
|
80
|
+
"path_pattern": "docs/api/{name}",
|
|
81
|
+
"default_doc_profile": "lite",
|
|
82
|
+
"scope_hints": ["api", "endpoint", "route", "servlet", "service"],
|
|
83
|
+
"use_for": "independently activated REST/SOAP/RPC/service endpoints or service operations",
|
|
84
|
+
},
|
|
85
|
+
"Report": {
|
|
86
|
+
"prefix": "R",
|
|
87
|
+
"path_pattern": "docs/report/{group}/{name}",
|
|
88
|
+
"default_doc_profile": "lite",
|
|
89
|
+
"scope_hints": ["report", "download", "export"],
|
|
90
|
+
"use_for": "independent reports, exports, dashboards, report scheduler identities",
|
|
91
|
+
},
|
|
92
|
+
"File": {
|
|
93
|
+
"prefix": "FI",
|
|
94
|
+
"path_pattern": "docs/file-process/{name}",
|
|
95
|
+
"default_doc_profile": "standard",
|
|
96
|
+
"scope_hints": ["file", "import", "export", "watcher", "etl"],
|
|
97
|
+
"use_for": "file import, export, watcher, transfer, archive processes",
|
|
98
|
+
},
|
|
99
|
+
"External": {
|
|
100
|
+
"prefix": "X",
|
|
101
|
+
"path_pattern": "docs/external/{name}",
|
|
102
|
+
"default_doc_profile": "standard",
|
|
103
|
+
"scope_hints": ["external", "integration", "webhook", "partner"],
|
|
104
|
+
"use_for": "external integrations, webhooks, partner/system interfaces, message contracts",
|
|
105
|
+
},
|
|
106
|
+
"ERP": {
|
|
107
|
+
"prefix": "E",
|
|
108
|
+
"path_pattern": "docs/erp/{group}/{name}",
|
|
109
|
+
"default_doc_profile": "standard",
|
|
110
|
+
"scope_hints": ["erp", "program", "responsibility", "form", "transaction"],
|
|
111
|
+
"use_for": "ERP or platform metadata, forms, responsibilities, programs, transactions",
|
|
112
|
+
},
|
|
113
|
+
"DatabaseProgram": {
|
|
114
|
+
"prefix": "DBP",
|
|
115
|
+
"path_pattern": "docs/database-program/{group}/{name}",
|
|
116
|
+
"default_doc_profile": "standard",
|
|
117
|
+
"scope_hints": [
|
|
118
|
+
"database program",
|
|
119
|
+
"stored procedure",
|
|
120
|
+
"stored function",
|
|
121
|
+
"routine",
|
|
122
|
+
"package",
|
|
123
|
+
"trigger",
|
|
124
|
+
"plsql",
|
|
125
|
+
],
|
|
126
|
+
"use_for": "database-side packages, stored procedures/functions, triggers, routine tasks, and DB-owned program units",
|
|
127
|
+
},
|
|
128
|
+
"Command": {
|
|
129
|
+
"prefix": "C",
|
|
130
|
+
"path_pattern": "docs/command/{name}",
|
|
131
|
+
"default_doc_profile": "lite",
|
|
132
|
+
"scope_hints": ["command", "cli", "console", "script", "admin"],
|
|
133
|
+
"use_for": "CLI/operator commands, console tasks, scripted commands, admin commands",
|
|
134
|
+
},
|
|
135
|
+
"Workflow": {
|
|
136
|
+
"prefix": "W",
|
|
137
|
+
"path_pattern": "docs/workflow/{name}",
|
|
138
|
+
"default_doc_profile": "standard",
|
|
139
|
+
"scope_hints": ["workflow", "bpmn", "approval", "state", "process"],
|
|
140
|
+
"use_for": "BPMN/process definitions, approval flows, state-machine workflows, orchestrated business processes",
|
|
141
|
+
},
|
|
142
|
+
"MobileScreen": {
|
|
143
|
+
"prefix": "M",
|
|
144
|
+
"path_pattern": "docs/mobile/{group}/{name}",
|
|
145
|
+
"default_doc_profile": "standard",
|
|
146
|
+
"scope_hints": ["mobile", "screen", "tab", "activity", "fragment", "deep link"],
|
|
147
|
+
"use_for": "mobile screens, tabs, activities/fragments, deep links, mobile navigation destinations",
|
|
148
|
+
},
|
|
149
|
+
"DesktopAction": {
|
|
150
|
+
"prefix": "D",
|
|
151
|
+
"path_pattern": "docs/desktop/{group}/{name}",
|
|
152
|
+
"default_doc_profile": "standard",
|
|
153
|
+
"scope_hints": ["desktop", "menu", "toolbar", "shortcut", "window", "form"],
|
|
154
|
+
"use_for": "desktop menu/toolbar actions, shortcut commands, form/window actions, command bindings",
|
|
155
|
+
},
|
|
156
|
+
"LibraryAPI": {
|
|
157
|
+
"prefix": "L",
|
|
158
|
+
"path_pattern": "docs/library-api/{name}",
|
|
159
|
+
"default_doc_profile": "lite",
|
|
160
|
+
"scope_hints": ["library", "sdk", "package", "export", "module"],
|
|
161
|
+
"use_for": "public library/package APIs, SDK entrypoints, exported module contracts",
|
|
162
|
+
},
|
|
163
|
+
"DataPipeline": {
|
|
164
|
+
"prefix": "DP",
|
|
165
|
+
"path_pattern": "docs/data-pipeline/{name}",
|
|
166
|
+
"default_doc_profile": "standard",
|
|
167
|
+
"scope_hints": ["data", "pipeline", "dag", "etl", "elt", "stream"],
|
|
168
|
+
"use_for": "DAGs, ETL/ELT pipelines, stream processors, data product refreshes",
|
|
169
|
+
},
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
DEFAULT_PREFIXES = {source_type: values["prefix"] for source_type, values in SOURCE_TYPE_REGISTRY.items()}
|
|
173
|
+
DEFAULT_PATH_PATTERNS = {
|
|
174
|
+
source_type: values["path_pattern"] for source_type, values in SOURCE_TYPE_REGISTRY.items()
|
|
175
|
+
}
|
|
176
|
+
DEFAULT_DOC_PROFILE_BY_SOURCE_TYPE = {
|
|
177
|
+
source_type: values["default_doc_profile"]
|
|
178
|
+
for source_type, values in SOURCE_TYPE_REGISTRY.items()
|
|
179
|
+
if values["default_doc_profile"] != "standard"
|
|
180
|
+
}
|
|
181
|
+
SOURCE_TYPE_SCOPE_HINTS = {
|
|
182
|
+
source_type.casefold(): values["scope_hints"] for source_type, values in SOURCE_TYPE_REGISTRY.items()
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
def normalize_text(value):
|
|
187
|
+
if value is None:
|
|
188
|
+
return ""
|
|
189
|
+
return re.sub(r"\s+", " ", str(value)).strip()
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
def normalize_key(value):
|
|
193
|
+
return normalize_text(value).casefold()
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
def normalize_status(value, allowed, default):
|
|
197
|
+
value = normalize_text(value).lower()
|
|
198
|
+
return value if value in allowed else default
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
def normalize_completed_flag(value):
|
|
202
|
+
value = normalize_text(value).upper()
|
|
203
|
+
return value if value in {"Y", "N"} else "N"
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
def normalize_doc_profile(value, source_type=""):
|
|
207
|
+
value = normalize_text(value).lower()
|
|
208
|
+
if value in DOC_PROFILES:
|
|
209
|
+
return value
|
|
210
|
+
return DEFAULT_DOC_PROFILE_BY_SOURCE_TYPE.get(normalize_text(source_type), "standard")
|