chipgraph 0.1.0__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.
Files changed (252) hide show
  1. chipgraph/__init__.py +7 -0
  2. chipgraph/adapters/__init__.py +1 -0
  3. chipgraph/adapters/format/__init__.py +6 -0
  4. chipgraph/adapters/format/__main__.py +16 -0
  5. chipgraph/adapters/format/_yaml_lines.py +54 -0
  6. chipgraph/adapters/format/chip_yaml.py +323 -0
  7. chipgraph/adapters/format/qsoc_contract.py +246 -0
  8. chipgraph/adapters/llm/__init__.py +58 -0
  9. chipgraph/adapters/llm/_budget.py +173 -0
  10. chipgraph/adapters/llm/_errors.py +50 -0
  11. chipgraph/adapters/llm/_nda.py +30 -0
  12. chipgraph/adapters/llm/_retry.py +85 -0
  13. chipgraph/adapters/llm/anthropic.py +247 -0
  14. chipgraph/adapters/llm/decide_backend.py +179 -0
  15. chipgraph/adapters/llm/fake.py +87 -0
  16. chipgraph/adapters/llm/guard.py +68 -0
  17. chipgraph/adapters/parser/__init__.py +22 -0
  18. chipgraph/adapters/parser/cocotb.py +304 -0
  19. chipgraph/adapters/parser/generic_regex.py +75 -0
  20. chipgraph/adapters/parser/verible.py +55 -0
  21. chipgraph/adapters/parser/verilator.py +46 -0
  22. chipgraph/adapters/review/__init__.py +7 -0
  23. chipgraph/adapters/review/file.py +123 -0
  24. chipgraph/adapters/review/github.py +886 -0
  25. chipgraph/adapters/runner/__init__.py +7 -0
  26. chipgraph/adapters/runner/local.py +122 -0
  27. chipgraph/adapters/runtime/__init__.py +5 -0
  28. chipgraph/adapters/runtime/claude_code/__init__.py +24 -0
  29. chipgraph/adapters/runtime/claude_code/agents.py +158 -0
  30. chipgraph/adapters/runtime/claude_code/decisions.py +280 -0
  31. chipgraph/adapters/runtime/claude_code/guarded.py +310 -0
  32. chipgraph/adapters/runtime/claude_code/isolation.py +482 -0
  33. chipgraph/adapters/runtime/claude_code/loop.py +342 -0
  34. chipgraph/adapters/runtime/claude_code/previous.py +419 -0
  35. chipgraph/adapters/runtime/claude_code/review.py +492 -0
  36. chipgraph/adapters/runtime/claude_code/runtime.py +192 -0
  37. chipgraph/adapters/runtime/claude_code/service.py +2285 -0
  38. chipgraph/adapters/tool/__init__.py +7 -0
  39. chipgraph/adapters/tool/cmd.py +229 -0
  40. chipgraph/adapters/tool/edalize.py +773 -0
  41. chipgraph/adapters/tool/filelist.py +259 -0
  42. chipgraph/adapters/tool/pyslang.py +485 -0
  43. chipgraph/adapters/vcs/__init__.py +1 -0
  44. chipgraph/adapters/vcs/git.py +521 -0
  45. chipgraph/app/__init__.py +10 -0
  46. chipgraph/app/baseline.py +339 -0
  47. chipgraph/app/build.py +332 -0
  48. chipgraph/app/checks.py +202 -0
  49. chipgraph/app/context.py +191 -0
  50. chipgraph/app/errors.py +11 -0
  51. chipgraph/app/executors.py +79 -0
  52. chipgraph/app/findings.py +203 -0
  53. chipgraph/app/ingest.py +523 -0
  54. chipgraph/checks/__init__.py +52 -0
  55. chipgraph/checks/_cdc_analyze.py +272 -0
  56. chipgraph/checks/_cdc_elaborate.py +455 -0
  57. chipgraph/checks/_common.py +268 -0
  58. chipgraph/checks/_cross.py +96 -0
  59. chipgraph/checks/_model.py +64 -0
  60. chipgraph/checks/_naming_pyslang.py +235 -0
  61. chipgraph/checks/_naming_rules.py +127 -0
  62. chipgraph/checks/_xref_syntax.py +260 -0
  63. chipgraph/checks/cdc_struct.py +235 -0
  64. chipgraph/checks/connect.py +353 -0
  65. chipgraph/checks/cross_chip.py +454 -0
  66. chipgraph/checks/duplicate.py +153 -0
  67. chipgraph/checks/filelist.py +323 -0
  68. chipgraph/checks/format.py +268 -0
  69. chipgraph/checks/generated.py +151 -0
  70. chipgraph/checks/hardcode.py +233 -0
  71. chipgraph/checks/layout.py +155 -0
  72. chipgraph/checks/naming.py +311 -0
  73. chipgraph/checks/plan_check.py +901 -0
  74. chipgraph/checks/ports_diff.py +203 -0
  75. chipgraph/checks/spec_schema.py +277 -0
  76. chipgraph/checks/style.py +910 -0
  77. chipgraph/checks/tb_static.py +599 -0
  78. chipgraph/checks/trace.py +224 -0
  79. chipgraph/checks/vendor_guard.py +369 -0
  80. chipgraph/checks/wrap_check.py +486 -0
  81. chipgraph/cli/__init__.py +1688 -0
  82. chipgraph/cli/next_steps.py +137 -0
  83. chipgraph/core/__init__.py +1 -0
  84. chipgraph/core/config/__init__.py +93 -0
  85. chipgraph/core/config/defaults.py +14 -0
  86. chipgraph/core/config/errors.py +32 -0
  87. chipgraph/core/config/loader.py +766 -0
  88. chipgraph/core/config/models.py +845 -0
  89. chipgraph/core/config/templates.py +340 -0
  90. chipgraph/core/contracts/__init__.py +75 -0
  91. chipgraph/core/contracts/_paths.py +26 -0
  92. chipgraph/core/contracts/agent.py +49 -0
  93. chipgraph/core/contracts/artifact.py +68 -0
  94. chipgraph/core/contracts/check.py +76 -0
  95. chipgraph/core/contracts/event.py +70 -0
  96. chipgraph/core/contracts/export.py +128 -0
  97. chipgraph/core/contracts/finding.py +171 -0
  98. chipgraph/core/contracts/gate.py +50 -0
  99. chipgraph/core/contracts/rule.py +177 -0
  100. chipgraph/core/contracts/types.py +45 -0
  101. chipgraph/core/engine/__init__.py +70 -0
  102. chipgraph/core/engine/agent_rule.py +1362 -0
  103. chipgraph/core/engine/baseline.py +283 -0
  104. chipgraph/core/engine/decide.py +462 -0
  105. chipgraph/core/engine/fanout.py +1358 -0
  106. chipgraph/core/engine/gate.py +170 -0
  107. chipgraph/core/engine/graph.py +647 -0
  108. chipgraph/core/engine/records.py +60 -0
  109. chipgraph/core/engine/rules.py +92 -0
  110. chipgraph/core/engine/scheduler.py +637 -0
  111. chipgraph/core/engine/select.py +1239 -0
  112. chipgraph/core/engine/targets.py +342 -0
  113. chipgraph/core/model/__init__.py +98 -0
  114. chipgraph/core/model/entities.py +244 -0
  115. chipgraph/core/model/export.py +16 -0
  116. chipgraph/core/model/ingest.py +693 -0
  117. chipgraph/core/model/json_value.py +4 -0
  118. chipgraph/core/model/keys.py +95 -0
  119. chipgraph/core/model/model.py +153 -0
  120. chipgraph/core/model/provenance.py +27 -0
  121. chipgraph/core/model/query.py +583 -0
  122. chipgraph/core/model/registry.py +80 -0
  123. chipgraph/core/model/relations.py +61 -0
  124. chipgraph/core/model/store.py +279 -0
  125. chipgraph/core/plugin_api/__init__.py +81 -0
  126. chipgraph/core/plugin_api/local.py +167 -0
  127. chipgraph/core/plugin_api/pack.py +159 -0
  128. chipgraph/core/plugin_api/protocols.py +177 -0
  129. chipgraph/core/plugin_api/registry.py +111 -0
  130. chipgraph/core/plugin_api/types.py +94 -0
  131. chipgraph/core/runtime/__init__.py +41 -0
  132. chipgraph/core/runtime/executor.py +79 -0
  133. chipgraph/core/runtime/queue.py +565 -0
  134. chipgraph/core/runtime/roles/__init__.py +91 -0
  135. chipgraph/core/runtime/roles/data/author.md +41 -0
  136. chipgraph/core/runtime/roles/data/critic.md +56 -0
  137. chipgraph/core/runtime/roles/data/planner.md +38 -0
  138. chipgraph/core/runtime/roles/data/researcher.md +37 -0
  139. chipgraph/core/runtime/roles/data/rtl-author.md +64 -0
  140. chipgraph/core/runtime/roles/data/tb-author.md +48 -0
  141. chipgraph/core/runtime/roles/data/triage.md +34 -0
  142. chipgraph/core/runtime/roles/policy.py +299 -0
  143. chipgraph/core/runtime/roles/registry.py +52 -0
  144. chipgraph/core/runtime/roles/review.py +275 -0
  145. chipgraph/core/runtime/roles/schema.py +82 -0
  146. chipgraph/core/runtime/roles/skills.py +134 -0
  147. chipgraph/core/runtime/roles/spec.py +232 -0
  148. chipgraph/core/state/__init__.py +1 -0
  149. chipgraph/core/state/artifacts.py +156 -0
  150. chipgraph/core/state/backend.py +117 -0
  151. chipgraph/core/state/findings.py +151 -0
  152. chipgraph/core/state/handoff.py +411 -0
  153. chipgraph/core/state/idempotency.py +59 -0
  154. chipgraph/core/state/journal.py +238 -0
  155. chipgraph/core/state/layout.py +82 -0
  156. chipgraph/core/state/lock.py +195 -0
  157. chipgraph/core/state/trace.py +225 -0
  158. chipgraph/learn/__init__.py +96 -0
  159. chipgraph/learn/draft.py +187 -0
  160. chipgraph/learn/infer.py +580 -0
  161. chipgraph/learn/models.py +145 -0
  162. chipgraph/learn/try_run.py +228 -0
  163. chipgraph/mcp/__init__.py +12 -0
  164. chipgraph/mcp/model_tools.py +167 -0
  165. chipgraph/mcp/server.py +787 -0
  166. chipgraph/orgs/qnsc/naming-v1.yml +113 -0
  167. chipgraph/orgs/qnsc/profile.yml +5 -0
  168. chipgraph/packs/__init__.py +8 -0
  169. chipgraph/packs/assist/__init__.py +16 -0
  170. chipgraph/packs/assist/ask/__init__.py +58 -0
  171. chipgraph/packs/assist/ask/_db.py +57 -0
  172. chipgraph/packs/assist/ask/_project.py +230 -0
  173. chipgraph/packs/assist/ask/answer.py +266 -0
  174. chipgraph/packs/assist/ask/check.py +182 -0
  175. chipgraph/packs/assist/ask/contract.py +115 -0
  176. chipgraph/packs/assist/ask/documents.py +157 -0
  177. chipgraph/packs/assist/ask/fts.py +80 -0
  178. chipgraph/packs/assist/ask/retrieve.py +331 -0
  179. chipgraph/packs/assist/audit/__init__.py +383 -0
  180. chipgraph/packs/assist/pack.yml +13 -0
  181. chipgraph/packs/assist/triage/__init__.py +64 -0
  182. chipgraph/packs/assist/triage/contract.py +94 -0
  183. chipgraph/packs/assist/triage/parse.py +371 -0
  184. chipgraph/packs/assist/triage/question.py +384 -0
  185. chipgraph/packs/assist/triage/report.py +160 -0
  186. chipgraph/packs/assist/triage/rules.py +447 -0
  187. chipgraph/packs/assist/triage/run.py +224 -0
  188. chipgraph/packs/digital_rtl/__init__.py +19 -0
  189. chipgraph/packs/digital_rtl/layout.py +144 -0
  190. chipgraph/packs/digital_rtl/pack.yml +25 -0
  191. chipgraph/packs/digital_rtl/plan/__init__.py +34 -0
  192. chipgraph/packs/digital_rtl/plan/__main__.py +16 -0
  193. chipgraph/packs/digital_rtl/plan/context.py +82 -0
  194. chipgraph/packs/digital_rtl/plan/expand.py +94 -0
  195. chipgraph/packs/digital_rtl/plan/model.py +150 -0
  196. chipgraph/packs/digital_rtl/plan/resolver.py +400 -0
  197. chipgraph/packs/digital_rtl/plan/show.py +176 -0
  198. chipgraph/packs/digital_rtl/pr/__init__.py +11 -0
  199. chipgraph/packs/digital_rtl/pr/body.py +165 -0
  200. chipgraph/packs/digital_rtl/pr/gate.py +110 -0
  201. chipgraph/packs/digital_rtl/pr/open.py +397 -0
  202. chipgraph/packs/digital_rtl/rtl/__init__.py +9 -0
  203. chipgraph/packs/digital_rtl/rtl/context.py +272 -0
  204. chipgraph/packs/digital_rtl/rules/open_pr.yml +30 -0
  205. chipgraph/packs/digital_rtl/rules/plan.yml +28 -0
  206. chipgraph/packs/digital_rtl/rules/plan_expand.yml +29 -0
  207. chipgraph/packs/digital_rtl/rules/pr_gate.yml +27 -0
  208. chipgraph/packs/digital_rtl/rules/review.yml +31 -0
  209. chipgraph/packs/digital_rtl/rules/rtl_module.yml +53 -0
  210. chipgraph/packs/digital_rtl/skills/lang-sv-rtl.md +58 -0
  211. chipgraph/packs/digital_rtl/skills/org-naming.md +29 -0
  212. chipgraph/packs/digital_rtl/skills/plan-modules.md +63 -0
  213. chipgraph/packs/digital_rtl/skills/review-diff.md +41 -0
  214. chipgraph/packs/digital_rtl/targets/plan.yml +11 -0
  215. chipgraph/packs/digital_rtl/targets/rtl.yml +20 -0
  216. chipgraph/packs/digital_rtl/wrapper/__init__.py +24 -0
  217. chipgraph/packs/digital_rtl/wrapper/common.py +171 -0
  218. chipgraph/packs/digital_rtl/wrapper/context.py +222 -0
  219. chipgraph/packs/digital_rtl/wrapper/emacs.py +626 -0
  220. chipgraph/packs/digital_rtl/wrapper/expansion.py +304 -0
  221. chipgraph/packs/digital_rtl/wrapper/lisp.py +504 -0
  222. chipgraph/packs/digital_rtl/wrapper/resolver.py +60 -0
  223. chipgraph/packs/digital_rtl/wrapper/rules/wrapper.yml +41 -0
  224. chipgraph/packs/digital_rtl/wrapper/rules/wrapper_gen.yml +35 -0
  225. chipgraph/packs/digital_rtl/wrapper/skills/wrapper-auto.md +120 -0
  226. chipgraph/packs/dv/__init__.py +15 -0
  227. chipgraph/packs/dv/declaration.py +392 -0
  228. chipgraph/packs/dv/interface.py +596 -0
  229. chipgraph/packs/dv/pack.yml +14 -0
  230. chipgraph/packs/dv/rules/tb_module.yml +42 -0
  231. chipgraph/packs/dv/skills/dv/cocotb.md +72 -0
  232. chipgraph/packs/spec_core/__init__.py +9 -0
  233. chipgraph/packs/spec_core/extract/__init__.py +12 -0
  234. chipgraph/packs/spec_core/extract/_markdown.py +371 -0
  235. chipgraph/packs/spec_core/extract/_text.py +116 -0
  236. chipgraph/packs/spec_core/extract/mas.py +975 -0
  237. chipgraph/packs/spec_core/gen/__init__.py +11 -0
  238. chipgraph/packs/spec_core/gen/agents_md/__init__.py +148 -0
  239. chipgraph/packs/spec_core/gen/agents_md/_context.py +239 -0
  240. chipgraph/packs/spec_core/gen/agents_md/_markers.py +131 -0
  241. chipgraph/packs/spec_core/gen/agents_md/agents_md.md.j2 +178 -0
  242. chipgraph/packs/spec_core/gen/diagram/__init__.py +110 -0
  243. chipgraph/packs/spec_core/gen/diagram/__main__.py +44 -0
  244. chipgraph/packs/spec_core/gen/diagram/_diagrams.py +403 -0
  245. chipgraph/packs/spec_core/gen/diagram/_scene.py +163 -0
  246. chipgraph/packs/spec_core/pack.yml +6 -0
  247. chipgraph/py.typed +0 -0
  248. chipgraph-0.1.0.dist-info/METADATA +53 -0
  249. chipgraph-0.1.0.dist-info/RECORD +252 -0
  250. chipgraph-0.1.0.dist-info/WHEEL +4 -0
  251. chipgraph-0.1.0.dist-info/entry_points.txt +61 -0
  252. chipgraph-0.1.0.dist-info/licenses/LICENSE +202 -0
@@ -0,0 +1,178 @@
1
+ {#- The chipgraph-managed block of AGENTS.md (pack spec-core, task M1-15).
2
+
3
+ Rendered by chipgraph.packs.spec_core.gen.agents_md.render_agents_md, which normalizes the
4
+ output: trailing spaces are dropped and runs of blank lines collapse to one. So a tag on a
5
+ line of its own may leave a blank line (fine between paragraphs), while inside a list or a
6
+ table every tag starts the line of the item it guards, so no blank line appears there.
7
+ A project overrides one section with `templates.override: { agents_md_<name>: <file> }`.
8
+ -#}
9
+ ## Project rules for coding agents (chipgraph)
10
+ {% block agents_md_intro %}
11
+
12
+ These rules come from this repository's chipgraph profile and the organization rules it
13
+ extends. Follow them whenever you add or change a file.
14
+ {% endblock %}
15
+ {% block agents_md_project %}
16
+ ### Project and blocks
17
+
18
+ - Project: {{ code(project.name) }}
19
+ {% if project.extends %}- Extends: {% for e in project.extends %}{{ code(e) }}{% if not loop.last %}, {% endif %}{% endfor %}
20
+ {% endif %}{% if project.packs %}- Packs: {% for p in project.packs %}{{ code(p) }}{% if not loop.last %}, {% endif %}{% endfor %}
21
+ {% endif %}{% if project.chip_spec %}- Chip spec: {{ code(project.chip_spec.path) }} (format {{ code(project.chip_spec.format) }})
22
+ {% endif %}{% if project.ip_dir %}- Per-IP specs: {{ code(project.ip_dir) }}
23
+ {% endif %}- Target: {{ project.target_kind }}{% if project.pdk %}, PDK {{ code(project.pdk) }}{% endif %}
24
+ {% if blocks %}
25
+
26
+ Each block is an IP. Its instances are the names the chip's memory map uses for it; a
27
+ block with no instances listed matches the instance of the same name.
28
+
29
+ | Block | Instances |
30
+ |---|---|
31
+ {% for b in blocks %}| {{ code(b.name, cell=True) }} | {% if b.instances %}{% for i in b.instances %}{{ code(i, cell=True) }}{% if not loop.last %}, {% endif %}{% endfor %}{% else %}-{% endif %} |
32
+ {% endfor %}
33
+ {% endif %}
34
+ {% endblock %}
35
+ {% block agents_md_layout %}
36
+ {% if layout or block_layout %}
37
+ ### Where files go
38
+
39
+ Create each kind of file only at the path its template gives; do not invent new
40
+ directories.{% if placeholders %} In a template, {% for p in placeholders %}{{ code(p) }} is the block name{% if p == "{BLOCK}" %} in upper case{% endif %}{% if not loop.last %} and {% endif %}{% endfor %}.{% endif %}
41
+ {% if layout %}
42
+
43
+ | Kind | Path template |
44
+ |---|---|
45
+ {% for row in layout %}| {{ text(row.kind) }} | {% if row.templates %}{% for t in row.templates %}{{ code(t, cell=True) }}{% if not loop.last %}, {% endif %}{% endfor %}{% else %}(none){% endif %} |
46
+ {% endfor %}
47
+ {% endif %}
48
+ {% if block_layout %}
49
+
50
+ Per-block overrides:
51
+
52
+ | Block | Kind | Path template |
53
+ |---|---|---|
54
+ {% for row in block_layout %}| {{ code(row.block, cell=True) }} | {{ text(row.kind) }} | {% if row.templates %}{% for t in row.templates %}{{ code(t, cell=True) }}{% if not loop.last %}, {% endif %}{% endfor %}{% else %}(none){% endif %} |
55
+ {% endfor %}
56
+ {% endif %}
57
+ {% endif %}
58
+ {% endblock %}
59
+ {% block agents_md_naming %}
60
+ {% if naming or naming_checker %}
61
+ ### Naming
62
+ {% for rules in naming %}
63
+
64
+ From {{ code(rules.ref) }} ({{ text(rules.document) }} v{{ text(rules.version) }}). The whole
65
+ name must match the pattern for its kind:
66
+
67
+ | Kind | Pattern | Rule | Message |
68
+ |---|---|---|---|
69
+ {% for row in rules.identifiers %}| {{ text(row.kind) }} | {{ code(row.pattern, cell=True) }} | {{ text(row.rule) }} | {{ text(row.message) }} |
70
+ {% endfor %}
71
+ {% if rules.lexical %}
72
+
73
+ Every declared name also follows:
74
+
75
+ {% for lex in rules.lexical %}- {{ text(lex.rule) }}: {{ text(lex.message) }}
76
+ {% endfor %}
77
+ {% endif %}
78
+ {% if rules.vocabulary %}
79
+
80
+ Words ({{ text(rules.vocabulary.rule) }}): use the project term on the right, never the
81
+ word on the left: {% for pair in rules.vocabulary.pairs %}{{ code(pair[0]) }} -> {{ code(pair[1]) }}{% if not loop.last %}, {% endif %}{% endfor %}.
82
+ {% endif %}
83
+
84
+ A declaration line that ends with the comment {{ code(rules.ignore_comment) }} is exempt;
85
+ use it only with a reason the reviewer accepts.
86
+ {% endfor %}
87
+ {% if naming_checker %}
88
+
89
+ Naming is checked by the {{ code(naming_checker.use) }} checker{% if naming_checker.command %}: {{ code(naming_checker.command) }}{% endif %}.
90
+ {% endif %}
91
+ {% endif %}
92
+ {% endblock %}
93
+ {% block agents_md_checks %}
94
+ ### Before you open a PR
95
+
96
+ Run these from the repository root and fix what they report:
97
+
98
+ ```sh
99
+ chipgraph ingest # build the Design Model; the cross checks read it
100
+ chipgraph check # run every configured check; exits 1 if one fails
101
+ chipgraph audit # every finding, grouped by layer
102
+ ```
103
+
104
+ Scope a run with `chipgraph check --block <block>` or `chipgraph check --only <check>`.
105
+ `chipgraph ingest --strict` and `chipgraph audit --strict` also exit 1, on an error-level
106
+ ingest issue or a blocking finding.
107
+ {% if checks %}
108
+
109
+ Configured checks (a severity caps what the check reports; a command's `{block}` is the
110
+ block name):
111
+
112
+ | Check | Adapter | Severity | Command |
113
+ |---|---|---|---|
114
+ {% for c in checks %}| {{ code(c.id, cell=True) }} | {{ text(c.use) }} | {{ text(c.severity) if c.severity else "-" }} | {{ code(c.command, cell=True) if c.command else "-" }} |
115
+ {% endfor %}
116
+ {% endif %}
117
+ {% if block_checks %}
118
+
119
+ Per-block check overrides:
120
+
121
+ | Block | Check | Adapter | Severity | Command |
122
+ |---|---|---|---|---|
123
+ {% for c in block_checks %}| {{ code(c.block, cell=True) }} | {{ code(c.id, cell=True) }} | {{ text(c.use) }} | {{ text(c.severity) if c.severity else "-" }} | {{ code(c.command, cell=True) if c.command else "-" }} |
124
+ {% endfor %}
125
+ {% endif %}
126
+ {% endblock %}
127
+ {% block agents_md_requirements %}
128
+ ### Requirement IDs
129
+
130
+ - A requirement ID in a spec must match {{ code(requirements.id_pattern) }}{% if requirements.uses_block %}, with `{block}`/`{BLOCK}` replaced by the block name in lower/upper case{% if requirements.example %} (for {{ code(requirements.example.block) }}: {{ code(requirements.example.pattern) }}){% endif %}{% endif %}.
131
+ {% if requirements.trace_check %}- Name the ID in the test that covers it: the {{ code(requirements.trace_check) }} check traces each requirement to a test.
132
+ {% endif %}{% if requirements.infer %}- A spec without IDs is read in a temporary mode: each numbered item of its "{{ text(requirements.infer_heading) }}" section counts as one requirement, keyed by block and content hash. A declared ID always wins; add IDs rather than rely on this.
133
+ {% endif %}
134
+ {% if block_requirements %}
135
+
136
+ Per-block overrides:
137
+
138
+ | Block | ID pattern | Inferred from "{{ text(requirements.infer_heading) }}" |
139
+ |---|---|---|
140
+ {% for r in block_requirements %}| {{ code(r.block, cell=True) }} | {{ code(r.id_pattern, cell=True) }} | {{ "yes" if r.infer else "no" }} |
141
+ {% endfor %}
142
+ {% endif %}
143
+ {% endblock %}
144
+ {% block agents_md_paths %}
145
+ {% if paths %}
146
+ ### Path exceptions
147
+
148
+ These paths follow different rules. Do not write under a path whose write is `deny`,
149
+ and do not add a new exception without a reason the reviewer accepts.
150
+
151
+ | Path | Block | Checks | Write | Reason |
152
+ |---|---|---|---|---|
153
+ {% for p in paths %}| {{ code(p.glob, cell=True) }} | {{ code(p.block, cell=True) if p.block else "-" }} | {{ text(", ".join(p.checks)) if p.checks else "-" }} | {{ p.write }} | {{ text(p.reason) if p.reason else "-" }} |
154
+ {% endfor %}
155
+ {% endif %}
156
+ {% endblock %}
157
+ {% block agents_md_data %}
158
+ {% if nda %}
159
+ ### Data labels
160
+
161
+ Files matching these paths are labeled `nda`. Never send their content to a cloud model
162
+ (do not paste it into a prompt, an issue or a web tool){% if nda.model == "local" %}; only a local model may read them (`nda_model: local`){% else %}; no model may read them (`nda_model: block`){% endif %}.
163
+
164
+ {% for p in nda.paths %}- {{ code(p) }}
165
+ {% endfor %}
166
+ {% endif %}
167
+ {% endblock %}
168
+ {% block agents_md_generated %}
169
+ {% if generated %}
170
+ ### Generated files
171
+
172
+ chipgraph or the project's flow generates these files. Do not edit them by hand: change
173
+ their source and regenerate them.
174
+
175
+ {% for g in generated %}- {{ code(g) }}
176
+ {% endfor %}
177
+ {% endif %}
178
+ {% endblock %}
@@ -0,0 +1,110 @@
1
+ """The ``diagram`` generator (pack ``spec-core``): figures rendered from the Design Model.
2
+
3
+ Public API:
4
+
5
+ - :func:`render` — pure: a :class:`~chipgraph.core.model.DesignModel` in, a
6
+ ``{file name: bytes}`` mapping out. The same model always gives byte-identical bytes.
7
+ - :class:`DiagramGenerator` — the ``chipgraph.adapters.generator`` plugin: rebuilds a model
8
+ from ``facts`` (entity/relation JSON dumps), writes the files under ``out_dir`` and
9
+ returns their paths, sorted.
10
+
11
+ Four figures, each written as an SVG and an uncompressed drawio ``mxfile``:
12
+
13
+ ====================== =========================================
14
+ Kind Files
15
+ ====================== =========================================
16
+ ``blocks`` ``block_diagram.svg`` / ``.drawio``
17
+ ``memory_map`` ``memory_map.svg`` / ``.drawio``
18
+ ``interrupts`` ``interrupt_map.svg`` / ``.drawio``
19
+ ``clocks`` ``clock_reset_tree.svg`` / ``.drawio``
20
+ ====================== =========================================
21
+
22
+ Determinism: everything is sorted by model key (or address, for the memory map), element
23
+ ids come from escaped model keys, coordinates are integers, XML is escaped, line endings
24
+ are ``\\n`` and the drawio ``mxfile`` carries no timestamp/etag/agent attribute. Figures
25
+ are computed from the model, never drawn by an AI (DESIGN.md 4.6).
26
+ """
27
+
28
+ from __future__ import annotations
29
+
30
+ from collections.abc import Iterable, Mapping
31
+ from pathlib import Path
32
+
33
+ from chipgraph.core.model import DEFAULT_ENTITY_KINDS, DesignModel, EntityBase, Relation
34
+ from chipgraph.packs.spec_core.gen.diagram._diagrams import (
35
+ block_diagram,
36
+ clock_reset_tree,
37
+ interrupt_map,
38
+ memory_map,
39
+ )
40
+ from chipgraph.packs.spec_core.gen.diagram._scene import Scene, scene_to_drawio, scene_to_svg
41
+
42
+ DEFAULT_KINDS: tuple[str, ...] = ("blocks", "memory_map", "interrupts", "clocks")
43
+ """The diagram kinds :func:`render` produces by default, in output order."""
44
+
45
+ _BUILDERS = {
46
+ "blocks": ("block_diagram", block_diagram),
47
+ "memory_map": ("memory_map", memory_map),
48
+ "interrupts": ("interrupt_map", interrupt_map),
49
+ "clocks": ("clock_reset_tree", clock_reset_tree),
50
+ }
51
+
52
+
53
+ def render(model: DesignModel, kinds: Iterable[str] = DEFAULT_KINDS) -> dict[str, bytes]:
54
+ """Render `model` into a ``{file name: bytes}`` mapping (SVG and drawio per kind).
55
+
56
+ Raises ``ValueError`` for an unknown kind. The result is deterministic: the same model
57
+ (regardless of entity insertion order) yields byte-identical output.
58
+ """
59
+ files: dict[str, bytes] = {}
60
+ for kind in kinds:
61
+ try:
62
+ stem, builder = _BUILDERS[kind]
63
+ except KeyError:
64
+ raise ValueError(
65
+ f"unknown diagram kind {kind!r}; known kinds: {sorted(_BUILDERS)}"
66
+ ) from None
67
+ scene: Scene = builder(model)
68
+ files[f"{stem}.svg"] = scene_to_svg(scene)
69
+ files[f"{stem}.drawio"] = scene_to_drawio(scene)
70
+ return files
71
+
72
+
73
+ def facts_to_model(facts: Iterable[Mapping[str, object]]) -> DesignModel:
74
+ """Rebuild a `DesignModel` from `facts` (entity and relation JSON dumps, intermixed).
75
+
76
+ A fact with ``src`` and ``dst`` keys is a relation; every other mapping is an entity,
77
+ parsed through the default entity-kind registry (so pack kinds round-trip as ext).
78
+ """
79
+ entities: list[EntityBase] = []
80
+ relations: list[Relation] = []
81
+ for fact in facts:
82
+ if "src" in fact and "dst" in fact:
83
+ relations.append(Relation.model_validate(dict(fact)))
84
+ else:
85
+ entities.append(DEFAULT_ENTITY_KINDS.parse(dict(fact)))
86
+ return DesignModel.build(entities, relations)
87
+
88
+
89
+ class DiagramGenerator:
90
+ """`Generator` plugin ``diagram``: render the Design Model figures to `out_dir`."""
91
+
92
+ name = "diagram"
93
+
94
+ def generate(self, out_dir: Path, facts: Iterable[Mapping[str, object]]) -> tuple[Path, ...]:
95
+ """Rebuild the model from `facts`, write every figure under `out_dir`, return paths.
96
+
97
+ Paths are returned sorted, and files are written with ``\\n`` line endings.
98
+ """
99
+ model = facts_to_model(facts)
100
+ files = render(model)
101
+ out_dir.mkdir(parents=True, exist_ok=True)
102
+ written: list[Path] = []
103
+ for name in sorted(files):
104
+ path = out_dir / name
105
+ path.write_bytes(files[name])
106
+ written.append(path)
107
+ return tuple(sorted(written))
108
+
109
+
110
+ __all__ = ["DEFAULT_KINDS", "DiagramGenerator", "facts_to_model", "render"]
@@ -0,0 +1,44 @@
1
+ """``python -m chipgraph.packs.spec_core.gen.diagram --root <repo> --out <dir>``.
2
+
3
+ Reads the Design Model from the project's model store (``default_model_db_path(root)``)
4
+ and writes the four figures into ``--out``. Prints a clear message and exits 1 when the
5
+ model store does not exist yet (run ``chipgraph ingest`` first).
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import argparse
11
+ import sys
12
+ from pathlib import Path
13
+
14
+ from chipgraph.core.model import default_model_db_path
15
+ from chipgraph.core.model.store import ModelStore
16
+ from chipgraph.packs.spec_core.gen.diagram import render
17
+
18
+
19
+ def main(argv: list[str] | None = None) -> int:
20
+ """Render the model's figures; return a process exit code."""
21
+ parser = argparse.ArgumentParser(prog="python -m chipgraph.packs.spec_core.gen.diagram")
22
+ parser.add_argument("--root", type=Path, default=Path("."), help="project repo root")
23
+ parser.add_argument("--out", type=Path, required=True, help="output directory for figures")
24
+ args = parser.parse_args(argv)
25
+
26
+ db_path = default_model_db_path(args.root)
27
+ if not db_path.is_file():
28
+ print(
29
+ f"no Design Model at {db_path}; run 'chipgraph ingest' to build it first",
30
+ file=sys.stderr,
31
+ )
32
+ return 1
33
+
34
+ model = ModelStore(db_path).read()
35
+ files = render(model)
36
+ args.out.mkdir(parents=True, exist_ok=True)
37
+ for name in sorted(files):
38
+ (args.out / name).write_bytes(files[name])
39
+ print(f"wrote {args.out / name}")
40
+ return 0
41
+
42
+
43
+ if __name__ == "__main__":
44
+ raise SystemExit(main())