qcoder 0.1.0a1__tar.gz → 0.2.0a1__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.
Files changed (123) hide show
  1. qcoder-0.2.0a1/CHANGELOG.md +28 -0
  2. {qcoder-0.1.0a1 → qcoder-0.2.0a1}/MANIFEST.in +1 -0
  3. {qcoder-0.1.0a1/src/qcoder.egg-info → qcoder-0.2.0a1}/PKG-INFO +23 -5
  4. qcoder-0.2.0a1/README.md +80 -0
  5. qcoder-0.2.0a1/docs/architecture.md +23 -0
  6. {qcoder-0.1.0a1 → qcoder-0.2.0a1}/pyproject.toml +4 -1
  7. {qcoder-0.1.0a1 → qcoder-0.2.0a1}/src/qcoder/__init__.py +1 -1
  8. qcoder-0.2.0a1/src/qcoder/cli.py +222 -0
  9. qcoder-0.2.0a1/src/qcoder/engines/context/__init__.py +7 -0
  10. qcoder-0.2.0a1/src/qcoder/engines/context/bundle.py +86 -0
  11. qcoder-0.2.0a1/src/qcoder/engines/context/markdown.py +90 -0
  12. qcoder-0.2.0a1/src/qcoder/engines/feature_extraction/features/glossary_v0.py +87 -0
  13. qcoder-0.2.0a1/src/qcoder/engines/guidance/__init__.py +6 -0
  14. qcoder-0.2.0a1/src/qcoder/engines/guidance/resource.py +229 -0
  15. qcoder-0.2.0a1/src/qcoder/engines/review/__init__.py +14 -0
  16. qcoder-0.2.0a1/src/qcoder/engines/review/bundle.py +202 -0
  17. qcoder-0.2.0a1/src/qcoder/engines/review/counts_v0.py +73 -0
  18. qcoder-0.2.0a1/src/qcoder/engines/review/markdown.py +100 -0
  19. qcoder-0.2.0a1/src/qcoder/engines/review/qiskit_counts.py +25 -0
  20. {qcoder-0.1.0a1 → qcoder-0.2.0a1}/src/qcoder/pipelines/analyze.py +15 -3
  21. {qcoder-0.1.0a1 → qcoder-0.2.0a1}/src/qcoder/pipelines/batch.py +2 -1
  22. qcoder-0.2.0a1/src/qcoder/pipelines/context.py +62 -0
  23. qcoder-0.2.0a1/src/qcoder/pipelines/review.py +63 -0
  24. {qcoder-0.1.0a1 → qcoder-0.2.0a1}/src/qcoder/tools/batch.py +2 -0
  25. {qcoder-0.1.0a1 → qcoder-0.2.0a1/src/qcoder.egg-info}/PKG-INFO +23 -5
  26. {qcoder-0.1.0a1 → qcoder-0.2.0a1}/src/qcoder.egg-info/SOURCES.txt +22 -0
  27. {qcoder-0.1.0a1 → qcoder-0.2.0a1}/tests/test_analyze_pipeline.py +23 -0
  28. {qcoder-0.1.0a1 → qcoder-0.2.0a1}/tests/test_batch_pipeline.py +17 -0
  29. qcoder-0.2.0a1/tests/test_cli_context_review.py +146 -0
  30. qcoder-0.2.0a1/tests/test_cli_help.py +164 -0
  31. qcoder-0.2.0a1/tests/test_context_bundle.py +123 -0
  32. qcoder-0.2.0a1/tests/test_feature_glossary.py +23 -0
  33. qcoder-0.2.0a1/tests/test_resource_guidance.py +126 -0
  34. qcoder-0.2.0a1/tests/test_review_bundle.py +171 -0
  35. qcoder-0.2.0a1/tests/test_review_counts_v0.py +30 -0
  36. qcoder-0.2.0a1/tests/test_review_qiskit_counts.py +27 -0
  37. qcoder-0.1.0a1/README.md +0 -62
  38. qcoder-0.1.0a1/docs/architecture.md +0 -10
  39. qcoder-0.1.0a1/src/qcoder/cli.py +0 -116
  40. {qcoder-0.1.0a1 → qcoder-0.2.0a1}/LICENSE +0 -0
  41. {qcoder-0.1.0a1 → qcoder-0.2.0a1}/NOTICE +0 -0
  42. {qcoder-0.1.0a1 → qcoder-0.2.0a1}/setup.cfg +0 -0
  43. {qcoder-0.1.0a1 → qcoder-0.2.0a1}/src/qcoder/__main__.py +0 -0
  44. {qcoder-0.1.0a1 → qcoder-0.2.0a1}/src/qcoder/core/__init__.py +0 -0
  45. {qcoder-0.1.0a1 → qcoder-0.2.0a1}/src/qcoder/core/context.py +0 -0
  46. {qcoder-0.1.0a1 → qcoder-0.2.0a1}/src/qcoder/core/qasm2/__init__.py +0 -0
  47. {qcoder-0.1.0a1 → qcoder-0.2.0a1}/src/qcoder/core/qasm2/adjoint_eligibility.py +0 -0
  48. {qcoder-0.1.0a1 → qcoder-0.2.0a1}/src/qcoder/core/qasm2/mirror_build.py +0 -0
  49. {qcoder-0.1.0a1 → qcoder-0.2.0a1}/src/qcoder/core/run_config.py +0 -0
  50. {qcoder-0.1.0a1 → qcoder-0.2.0a1}/src/qcoder/core/schema.py +0 -0
  51. {qcoder-0.1.0a1 → qcoder-0.2.0a1}/src/qcoder/engines/feature_extraction/adapters/__init__.py +0 -0
  52. {qcoder-0.1.0a1 → qcoder-0.2.0a1}/src/qcoder/engines/feature_extraction/adapters/qiskit_intake.py +0 -0
  53. {qcoder-0.1.0a1 → qcoder-0.2.0a1}/src/qcoder/engines/feature_extraction/extractor.py +0 -0
  54. {qcoder-0.1.0a1 → qcoder-0.2.0a1}/src/qcoder/engines/feature_extraction/features/compute_v0.py +0 -0
  55. {qcoder-0.1.0a1 → qcoder-0.2.0a1}/src/qcoder/engines/feature_extraction/features/schema_v0.py +0 -0
  56. {qcoder-0.1.0a1 → qcoder-0.2.0a1}/src/qcoder/engines/feature_extraction/ir.py +0 -0
  57. {qcoder-0.1.0a1 → qcoder-0.2.0a1}/src/qcoder/engines/feature_extraction/labeling.py +0 -0
  58. {qcoder-0.1.0a1 → qcoder-0.2.0a1}/src/qcoder/engines/feature_extraction/parsers/__init__.py +0 -0
  59. {qcoder-0.1.0a1 → qcoder-0.2.0a1}/src/qcoder/engines/feature_extraction/qasm2_regex_parser.py +0 -0
  60. {qcoder-0.1.0a1 → qcoder-0.2.0a1}/src/qcoder/engines/feature_extraction/reps/cut_profile.py +0 -0
  61. {qcoder-0.1.0a1 → qcoder-0.2.0a1}/src/qcoder/engines/feature_extraction/reps/depth.py +0 -0
  62. {qcoder-0.1.0a1 → qcoder-0.2.0a1}/src/qcoder/engines/feature_extraction/reps/entangling_layers.py +0 -0
  63. {qcoder-0.1.0a1 → qcoder-0.2.0a1}/src/qcoder/engines/feature_extraction/reps/gate_set_stats.py +0 -0
  64. {qcoder-0.1.0a1 → qcoder-0.2.0a1}/src/qcoder/engines/feature_extraction/reps/interaction_graph.py +0 -0
  65. {qcoder-0.1.0a1 → qcoder-0.2.0a1}/src/qcoder/engines/feature_extraction/reps/interaction_graph_metrics.py +0 -0
  66. {qcoder-0.1.0a1 → qcoder-0.2.0a1}/src/qcoder/engines/feature_extraction/reps/spans.py +0 -0
  67. {qcoder-0.1.0a1 → qcoder-0.2.0a1}/src/qcoder/engines/prediction_model/__init__.py +0 -0
  68. {qcoder-0.1.0a1 → qcoder-0.2.0a1}/src/qcoder/engines/prediction_model/artifact.py +0 -0
  69. {qcoder-0.1.0a1 → qcoder-0.2.0a1}/src/qcoder/engines/prediction_model/engine.py +0 -0
  70. {qcoder-0.1.0a1 → qcoder-0.2.0a1}/src/qcoder/engines/prediction_model/models.py +0 -0
  71. {qcoder-0.1.0a1 → qcoder-0.2.0a1}/src/qcoder/engines/prediction_model/policy.py +0 -0
  72. {qcoder-0.1.0a1 → qcoder-0.2.0a1}/src/qcoder/engines/prediction_model/schema_alignment.py +0 -0
  73. {qcoder-0.1.0a1 → qcoder-0.2.0a1}/src/qcoder/engines/quantumness/__init__.py +0 -0
  74. {qcoder-0.1.0a1 → qcoder-0.2.0a1}/src/qcoder/engines/quantumness/scorer.py +0 -0
  75. {qcoder-0.1.0a1 → qcoder-0.2.0a1}/src/qcoder/tools/analyze.py +0 -0
  76. {qcoder-0.1.0a1 → qcoder-0.2.0a1}/src/qcoder/tools/analyze_shot_scaling.py +0 -0
  77. {qcoder-0.1.0a1 → qcoder-0.2.0a1}/src/qcoder/tools/generate_corpus.py +0 -0
  78. {qcoder-0.1.0a1 → qcoder-0.2.0a1}/src/qcoder/tools/harness.py +0 -0
  79. {qcoder-0.1.0a1 → qcoder-0.2.0a1}/src/qcoder/tools/inspect_corpus_features.py +0 -0
  80. {qcoder-0.1.0a1 → qcoder-0.2.0a1}/src/qcoder/tools/join_runs_features.py +0 -0
  81. {qcoder-0.1.0a1 → qcoder-0.2.0a1}/src/qcoder/tools/mirror.py +0 -0
  82. {qcoder-0.1.0a1 → qcoder-0.2.0a1}/src/qcoder/tools/predict_baseline.py +0 -0
  83. {qcoder-0.1.0a1 → qcoder-0.2.0a1}/src/qcoder/tools/qr_dll_bootstrap.py +0 -0
  84. {qcoder-0.1.0a1 → qcoder-0.2.0a1}/src/qcoder/tools/runner.py +0 -0
  85. {qcoder-0.1.0a1 → qcoder-0.2.0a1}/src/qcoder/tools/runners/__init__.py +0 -0
  86. {qcoder-0.1.0a1 → qcoder-0.2.0a1}/src/qcoder/tools/runners/quantum_rings/__init__.py +0 -0
  87. {qcoder-0.1.0a1 → qcoder-0.2.0a1}/src/qcoder/tools/runners/quantum_rings/v12/__init__.py +0 -0
  88. {qcoder-0.1.0a1 → qcoder-0.2.0a1}/src/qcoder/tools/runners/quantum_rings/v12/harness.py +0 -0
  89. {qcoder-0.1.0a1 → qcoder-0.2.0a1}/src/qcoder/tools/runners/quantum_rings/v12/mirror.py +0 -0
  90. {qcoder-0.1.0a1 → qcoder-0.2.0a1}/src/qcoder/tools/runners/quantum_rings/v12/runner.py +0 -0
  91. {qcoder-0.1.0a1 → qcoder-0.2.0a1}/src/qcoder/tools/train_baseline_models.py +0 -0
  92. {qcoder-0.1.0a1 → qcoder-0.2.0a1}/src/qcoder/tools/validate_baseline.py +0 -0
  93. {qcoder-0.1.0a1 → qcoder-0.2.0a1}/src/qcoder.egg-info/dependency_links.txt +0 -0
  94. {qcoder-0.1.0a1 → qcoder-0.2.0a1}/src/qcoder.egg-info/entry_points.txt +0 -0
  95. {qcoder-0.1.0a1 → qcoder-0.2.0a1}/src/qcoder.egg-info/requires.txt +0 -0
  96. {qcoder-0.1.0a1 → qcoder-0.2.0a1}/src/qcoder.egg-info/top_level.txt +0 -0
  97. {qcoder-0.1.0a1 → qcoder-0.2.0a1}/tests/__init__.py +0 -0
  98. {qcoder-0.1.0a1 → qcoder-0.2.0a1}/tests/test_adjoint_eligibility.py +0 -0
  99. {qcoder-0.1.0a1 → qcoder-0.2.0a1}/tests/test_analyze_prediction_integration.py +0 -0
  100. {qcoder-0.1.0a1 → qcoder-0.2.0a1}/tests/test_analyze_shot_scaling.py +0 -0
  101. {qcoder-0.1.0a1 → qcoder-0.2.0a1}/tests/test_cli_batch_nested_discovery.py +0 -0
  102. {qcoder-0.1.0a1 → qcoder-0.2.0a1}/tests/test_cut_profile.py +0 -0
  103. {qcoder-0.1.0a1 → qcoder-0.2.0a1}/tests/test_entangling_layers.py +0 -0
  104. {qcoder-0.1.0a1 → qcoder-0.2.0a1}/tests/test_gate_set_stats.py +0 -0
  105. {qcoder-0.1.0a1 → qcoder-0.2.0a1}/tests/test_generate_corpus.py +0 -0
  106. {qcoder-0.1.0a1 → qcoder-0.2.0a1}/tests/test_harness_schema_labels.py +0 -0
  107. {qcoder-0.1.0a1 → qcoder-0.2.0a1}/tests/test_inspect_corpus_features.py +0 -0
  108. {qcoder-0.1.0a1 → qcoder-0.2.0a1}/tests/test_interaction_graph_metrics.py +0 -0
  109. {qcoder-0.1.0a1 → qcoder-0.2.0a1}/tests/test_join_runs_features.py +0 -0
  110. {qcoder-0.1.0a1 → qcoder-0.2.0a1}/tests/test_mirror_build.py +0 -0
  111. {qcoder-0.1.0a1 → qcoder-0.2.0a1}/tests/test_parse_qasm2_text.py +0 -0
  112. {qcoder-0.1.0a1 → qcoder-0.2.0a1}/tests/test_predict_baseline.py +0 -0
  113. {qcoder-0.1.0a1 → qcoder-0.2.0a1}/tests/test_prediction_artifact_io.py +0 -0
  114. {qcoder-0.1.0a1 → qcoder-0.2.0a1}/tests/test_prediction_fidelity_curve.py +0 -0
  115. {qcoder-0.1.0a1 → qcoder-0.2.0a1}/tests/test_prediction_policy.py +0 -0
  116. {qcoder-0.1.0a1 → qcoder-0.2.0a1}/tests/test_prediction_schema_alignment.py +0 -0
  117. {qcoder-0.1.0a1 → qcoder-0.2.0a1}/tests/test_qiskit_intake.py +0 -0
  118. {qcoder-0.1.0a1 → qcoder-0.2.0a1}/tests/test_quantumness_scorer.py +0 -0
  119. {qcoder-0.1.0a1 → qcoder-0.2.0a1}/tests/test_schema_stability.py +0 -0
  120. {qcoder-0.1.0a1 → qcoder-0.2.0a1}/tests/test_smoke.py +0 -0
  121. {qcoder-0.1.0a1 → qcoder-0.2.0a1}/tests/test_temporal_spans.py +0 -0
  122. {qcoder-0.1.0a1 → qcoder-0.2.0a1}/tests/test_train_baseline_models.py +0 -0
  123. {qcoder-0.1.0a1 → qcoder-0.2.0a1}/tests/test_validate_baseline.py +0 -0
@@ -0,0 +1,28 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on common practice for pre-1.0 semantic versioning: **`MAJOR.MINOR.PATCH`** with **`aN`** for alpha prereleases.
6
+
7
+ ## 0.2.0a1 (alpha)
8
+
9
+ Local-only deterministic CLI tooling for quantum circuit analysis and LLM-ready workflow artifacts.
10
+
11
+ ### Added
12
+
13
+ - **CLI help fixes** — consistent subcommands and help text (`analyze`, `batch`, `context`, `review`).
14
+ - **`feature_map`** — derived `name → value` view alongside canonical nested `features` in machine-readable analyze output for readability.
15
+ - **`--guidance`** — optional heuristic resource guidance on `qcoder analyze` and `qcoder batch` for shot budgets and simulator / MPS starting points (deterministic from structure only; non-guaranteed).
16
+ - **`qcoder context`** — preflight artifacts as **Markdown + JSON** (optional `--guidance`, optional **`--full-features`** glossary appendix).
17
+ - **`qcoder review`** — post-execution artifacts as **Markdown + JSON** from user-supplied counts; optional linkage to preflight JSON.
18
+ - **`qcoder.counts.v0`** counts schema and **`qiskit_counts`** normalization into the same deterministic review pipeline.
19
+ - **Feature glossary** — short deterministic definitions aligned with schema v0 feature names; surfaced in context bundles and **`--full-features`** appendix.
20
+ - **Conservative `shots_total` handling** — when declared `shots_total` disagrees with `sum(counts)`, review-derived probabilities use the observed sum, with explicit **`shots_total_match` check**, warning text, and `declared_shots_total` / `shots_total_basis` fields.
21
+
22
+ ### Behaviour
23
+
24
+ - **Local-only** — no LLM calls, no telemetry, no network, no retrieval or embeddings, no simulator or hardware execution within these CLI flows. Artifacts are files for you to attach or paste into tools of your choice.
25
+
26
+ ### Unchanged
27
+
28
+ - Canonical circuit feature schema (version, order, and vector layout in `features`) is unchanged for this release.
@@ -1,6 +1,7 @@
1
1
  include LICENSE
2
2
  include NOTICE
3
3
  include README.md
4
+ include CHANGELOG.md
4
5
  include pyproject.toml
5
6
  graft src
6
7
  graft tests
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: qcoder
3
- Version: 0.1.0a1
3
+ Version: 0.2.0a1
4
4
  Summary: Quantum circuit analysis and structured feature extraction tools.
5
5
  Author-email: Quantum Ready Solutions <support@qcoder.ai>
6
6
  Maintainer-email: Quantum Ready Solutions <support@qcoder.ai>
@@ -28,7 +28,7 @@ Dynamic: license-file
28
28
 
29
29
  **qCoder** helps developers **inspect quantum circuits before they run them.** It reads **OpenQASM** circuits, extracts **repeatable structural features**, and emits **structured JSON** (single file) or **JSONL** (batches)—useful for **notebooks**, **CI**, **pull-request review**, and **AI coding assistants** when you attach or paste deterministic context next to circuit text.
30
30
 
31
- **CLI:** **`qcoder analyze`** and **`qcoder batch`**. Optional **Qiskit** intake: **`pip install "qcoder[qiskit]"`**.
31
+ **CLI:** **`qcoder analyze`**, **`qcoder batch`**, **`qcoder context`**, and **`qcoder review`**. Optional **Qiskit** intake: **`pip install "qcoder[qiskit]"`**.
32
32
 
33
33
  **Company / legal:** Quantum Ready Solutions. **Product docs:** [qcoder.ai](https://qcoder.ai) · [manual](https://qcoder.ai/manual/). **Source:** [github.com/QuantumReadySolutions/qCoder](https://github.com/QuantumReadySolutions/qCoder). **Support:** [support@qcoder.ai](mailto:support@qcoder.ai).
34
34
 
@@ -42,10 +42,14 @@ For **this release**, treat the **supported surface** as:
42
42
 
43
43
  - **`qcoder analyze`** — single-circuit extraction (human or `--json`).
44
44
  - **`qcoder batch`** — directory batch to **JSONL**.
45
+ - **Optional `--guidance`** on `analyze` / `batch` — deterministic heuristic starting points (shots and simulator/MPS settings) derived from circuit structure.
46
+ - **`qcoder context`** — deterministic preflight context artifacts (**JSON + Markdown**), including optional `--guidance` and optional `--full-features` glossary appendix.
47
+ - **`qcoder review`** — deterministic post-run review artifacts (**JSON + Markdown**) from user-provided counts.
48
+ - **Counts intake normalization** — `qcoder.counts.v0` and `qiskit_counts` normalization into the same deterministic review path.
45
49
  - **`qcoder[qiskit]`** — optional `QuantumCircuit` intake into the **same extractor** as OpenQASM.
46
50
  - **Documented feature output** — see [qcoder.ai — Feature reference](https://qcoder.ai/manual/feature-reference/) and `engines/feature_extraction/features/schema_v0.py`; JSON carries a **`schema_version`** alongside named fields.
47
51
 
48
- Other modules under **`src/qcoder`** may exist for prototyping (extra tooling or engines outside the commands above). Unless documented here, **`docs/`**, or **qcoder.ai**, they do **not** share the same stability expectations as **`analyze`** / **`batch`** and documented output.
52
+ Other modules under **`src/qcoder`** may exist for prototyping (extra tooling or engines outside the commands above). Unless documented here, **`docs/`**, or **qcoder.ai**, they do **not** share the same stability expectations as the commands and artifact formats listed above.
49
53
 
50
54
  Brief notes live in **`docs/architecture.md`**.
51
55
 
@@ -55,7 +59,7 @@ Brief notes live in **`docs/architecture.md`**.
55
59
  pip install qcoder
56
60
  ```
57
61
 
58
- Pre-release lines on PyPI use segments such as **`0.1.0a1`**.
62
+ Pre-release lines on PyPI use segments such as **`0.2.0a1`**.
59
63
 
60
64
  Optional Qiskit adapter:
61
65
 
@@ -65,16 +69,30 @@ pip install "qcoder[qiskit]"
65
69
 
66
70
  Requires **Python 3.11+**. Runtime dependency: **NumPy**.
67
71
 
72
+ Machine-readable JSON from **`qcoder analyze --json`** includes a derived **`feature_map`** object (`name → value`) for easier reading. The canonical circuit feature bundle remains the nested **`features`** object (`schema_version`, **`feature_names`**, **`features`**).
73
+
74
+ Optional **`--guidance`** adds heuristic shot-count and simulator/MPS starting-point suggestions derived from structural features. These suggestions are transparent, non-guaranteed starting points only; qCoder performs no backend execution and includes no telemetry/upload in this flow.
75
+
76
+ `qcoder context` and `qcoder review` generate deterministic local artifacts (JSON + Markdown) intended for user-controlled AI-assisted planning/review workflows. "LLM-ready/RAG-ready" in this project means users can attach or paste these artifacts manually; qCoder itself performs no retrieval, embeddings, network calls, or telemetry/upload in this flow.
77
+
68
78
  ## CLI quickstart
69
79
 
70
80
  ```bash
71
81
  qcoder analyze path/to/circuit.qasm
72
82
  qcoder analyze path/to/circuit.qasm --json
73
- qcoder batch path/to/qasm_dir/ --out features.jsonl
83
+ qcoder analyze path/to/circuit.qasm --json --guidance
84
+ qcoder context path/to/circuit.qasm --out-json preflight.context.json --out-md preflight.context.md --guidance
85
+ qcoder batch circuits --out batch.features.jsonl --pattern "*.qasm"
86
+ qcoder batch circuits --out batch.features.jsonl --pattern "*.qasm" --guidance
87
+ qcoder review --counts-json counts.json --format qiskit_counts --preflight-json preflight.context.json --out-json execution.review.json --out-md execution.review.md
74
88
  ```
75
89
 
90
+ **Batch:** JSONL records are written to **`--out`**. Status lines (for example record counts) may go to **stderr**, so prefer **`--out`** over shell stdout redirection for the JSONL stream.
91
+
76
92
  ## Develop / test (from a clone)
77
93
 
94
+ If you use **pyenv**, select the intended Python before creating the venv (for example `pyenv local 3.11.x` or `pyenv shell 3.11.x`) so `python -m venv` uses that interpreter.
95
+
78
96
  ```bash
79
97
  python -m venv .venv
80
98
  source .venv/bin/activate
@@ -0,0 +1,80 @@
1
+ # qCoder
2
+
3
+ **qCoder** helps developers **inspect quantum circuits before they run them.** It reads **OpenQASM** circuits, extracts **repeatable structural features**, and emits **structured JSON** (single file) or **JSONL** (batches)—useful for **notebooks**, **CI**, **pull-request review**, and **AI coding assistants** when you attach or paste deterministic context next to circuit text.
4
+
5
+ **CLI:** **`qcoder analyze`**, **`qcoder batch`**, **`qcoder context`**, and **`qcoder review`**. Optional **Qiskit** intake: **`pip install "qcoder[qiskit]"`**.
6
+
7
+ **Company / legal:** Quantum Ready Solutions. **Product docs:** [qcoder.ai](https://qcoder.ai) · [manual](https://qcoder.ai/manual/). **Source:** [github.com/QuantumReadySolutions/qCoder](https://github.com/QuantumReadySolutions/qCoder). **Support:** [support@qcoder.ai](mailto:support@qcoder.ai).
8
+
9
+ ## What qCoder analyzes
10
+
11
+ qCoder summarizes **circuit structure** from declarations in your source files. Pair its JSON output with simulator or hardware run data whenever you need **execution evidence**.
12
+
13
+ ## Package layout (supported public surface)
14
+
15
+ For **this release**, treat the **supported surface** as:
16
+
17
+ - **`qcoder analyze`** — single-circuit extraction (human or `--json`).
18
+ - **`qcoder batch`** — directory batch to **JSONL**.
19
+ - **Optional `--guidance`** on `analyze` / `batch` — deterministic heuristic starting points (shots and simulator/MPS settings) derived from circuit structure.
20
+ - **`qcoder context`** — deterministic preflight context artifacts (**JSON + Markdown**), including optional `--guidance` and optional `--full-features` glossary appendix.
21
+ - **`qcoder review`** — deterministic post-run review artifacts (**JSON + Markdown**) from user-provided counts.
22
+ - **Counts intake normalization** — `qcoder.counts.v0` and `qiskit_counts` normalization into the same deterministic review path.
23
+ - **`qcoder[qiskit]`** — optional `QuantumCircuit` intake into the **same extractor** as OpenQASM.
24
+ - **Documented feature output** — see [qcoder.ai — Feature reference](https://qcoder.ai/manual/feature-reference/) and `engines/feature_extraction/features/schema_v0.py`; JSON carries a **`schema_version`** alongside named fields.
25
+
26
+ Other modules under **`src/qcoder`** may exist for prototyping (extra tooling or engines outside the commands above). Unless documented here, **`docs/`**, or **qcoder.ai**, they do **not** share the same stability expectations as the commands and artifact formats listed above.
27
+
28
+ Brief notes live in **`docs/architecture.md`**.
29
+
30
+ ## Install
31
+
32
+ ```bash
33
+ pip install qcoder
34
+ ```
35
+
36
+ Pre-release lines on PyPI use segments such as **`0.2.0a1`**.
37
+
38
+ Optional Qiskit adapter:
39
+
40
+ ```bash
41
+ pip install "qcoder[qiskit]"
42
+ ```
43
+
44
+ Requires **Python 3.11+**. Runtime dependency: **NumPy**.
45
+
46
+ Machine-readable JSON from **`qcoder analyze --json`** includes a derived **`feature_map`** object (`name → value`) for easier reading. The canonical circuit feature bundle remains the nested **`features`** object (`schema_version`, **`feature_names`**, **`features`**).
47
+
48
+ Optional **`--guidance`** adds heuristic shot-count and simulator/MPS starting-point suggestions derived from structural features. These suggestions are transparent, non-guaranteed starting points only; qCoder performs no backend execution and includes no telemetry/upload in this flow.
49
+
50
+ `qcoder context` and `qcoder review` generate deterministic local artifacts (JSON + Markdown) intended for user-controlled AI-assisted planning/review workflows. "LLM-ready/RAG-ready" in this project means users can attach or paste these artifacts manually; qCoder itself performs no retrieval, embeddings, network calls, or telemetry/upload in this flow.
51
+
52
+ ## CLI quickstart
53
+
54
+ ```bash
55
+ qcoder analyze path/to/circuit.qasm
56
+ qcoder analyze path/to/circuit.qasm --json
57
+ qcoder analyze path/to/circuit.qasm --json --guidance
58
+ qcoder context path/to/circuit.qasm --out-json preflight.context.json --out-md preflight.context.md --guidance
59
+ qcoder batch circuits --out batch.features.jsonl --pattern "*.qasm"
60
+ qcoder batch circuits --out batch.features.jsonl --pattern "*.qasm" --guidance
61
+ qcoder review --counts-json counts.json --format qiskit_counts --preflight-json preflight.context.json --out-json execution.review.json --out-md execution.review.md
62
+ ```
63
+
64
+ **Batch:** JSONL records are written to **`--out`**. Status lines (for example record counts) may go to **stderr**, so prefer **`--out`** over shell stdout redirection for the JSONL stream.
65
+
66
+ ## Develop / test (from a clone)
67
+
68
+ If you use **pyenv**, select the intended Python before creating the venv (for example `pyenv local 3.11.x` or `pyenv shell 3.11.x`) so `python -m venv` uses that interpreter.
69
+
70
+ ```bash
71
+ python -m venv .venv
72
+ source .venv/bin/activate
73
+ pip install -e ".[qiskit]"
74
+ pip install pytest
75
+ pytest -q
76
+ ```
77
+
78
+ ## License
79
+
80
+ Licensed under the **Apache License 2.0**. See `LICENSE` and `NOTICE`.
@@ -0,0 +1,23 @@
1
+ # qCoder architecture notes (public)
2
+
3
+ **qCoder** maps circuit sources onto **repeatable structured output**: a **`schema_version`**, **`feature_names`**, and paired numeric **`features`** consumed from the extractor.
4
+
5
+ - Primary path: **OpenQASM / QASM** text analyzed on the developer machine.
6
+ - Optional path: **`qcoder[qiskit]`** can ingest **Qiskit `QuantumCircuit`** objects into the **same extractor** as OpenQASM.
7
+
8
+ The field glossary is defined in **`src/qcoder/engines/feature_extraction/features/schema_v0.py`** (`FEATURE_NAMES_V0`). The [qcoder.ai manual — Feature reference](https://qcoder.ai/manual/feature-reference/) summarizes each field name.
9
+
10
+ The supported product surface described in **`README.md`** (**Package layout**) is:
11
+
12
+ - **`qcoder analyze`** and **`qcoder batch`** for deterministic structural extraction output.
13
+ - Optional **`--guidance`** for deterministic heuristic starting points derived from `feature_map`.
14
+ - **`qcoder context`** for deterministic preflight artifacts (**JSON + Markdown**), with optional `--full-features` glossary appendix.
15
+ - **`qcoder review`** for deterministic post-run review artifacts (**JSON + Markdown**) from user-provided counts.
16
+ - Counts normalization from **`qcoder.counts.v0`** and **`qiskit_counts`** into one deterministic review path.
17
+ - Optional **`qcoder[qiskit]`** ingestion into the same extractor as OpenQASM.
18
+
19
+ The canonical circuit feature schema remains the existing `features` payload (`schema_version`, `feature_names`, `features`) produced by extraction. Guidance/context/review outputs are additive artifact layers and do not change canonical feature schema/version/order.
20
+
21
+ When requested via CLI flags, qCoder may emit an additional top-level `guidance` block built deterministically from `feature_map`. This guidance is outside the canonical feature schema (`features`) and is intended as transparent heuristic starting points rather than execution-validated recommendations.
22
+
23
+ The `context` and `review` commands generate deterministic local artifacts (Markdown/JSON) for user-controlled planning and post-run analysis workflows. "LLM-ready/RAG-ready" in this context means users can attach/paste artifacts manually; qCoder itself makes no LLM calls and performs no retrieval, embeddings, network calls, telemetry upload, or database writes. qCoder also does not execute simulators or hardware backends in these flows.
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "qcoder"
7
- version = "0.1.0a1"
7
+ version = "0.2.0a1"
8
8
  description = "Quantum circuit analysis and structured feature extraction tools."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
@@ -44,5 +44,8 @@ package-dir = {"" = "src"}
44
44
  [tool.setuptools.packages.find]
45
45
  where = ["src"]
46
46
 
47
+ [tool.pytest.ini_options]
48
+ pythonpath = ["src"]
49
+
47
50
  [tool.ruff]
48
51
  line-length = 100
@@ -1,3 +1,3 @@
1
1
  __all__ = []
2
- __version__ = "0.1.0a1"
2
+ __version__ = "0.2.0a1"
3
3
  file = __file__
@@ -0,0 +1,222 @@
1
+ from __future__ import annotations
2
+
3
+ import argparse
4
+ import json
5
+ import sys
6
+
7
+ from qcoder.pipelines.analyze import analyze_qasm
8
+ from qcoder.tools.batch import analyze_qasm_dir_to_jsonl
9
+ from qcoder.pipelines.context import write_preflight_context
10
+ from qcoder.pipelines.review import write_execution_review
11
+
12
+
13
+ def _cmd_analyze(argv: list[str]) -> int:
14
+ p = argparse.ArgumentParser(prog="qcoder analyze", add_help=True)
15
+ p.add_argument("qasm", help="Path to a .qasm file")
16
+
17
+ # Circuit identity / metadata
18
+ p.add_argument("--id", dest="circuit_id", default=None, help="Optional circuit id")
19
+ p.add_argument("--name", dest="circuit_name", default=None, help="Optional circuit name")
20
+
21
+ # Run config (conditioning vars for predictors; not used by feature extraction)
22
+ p.add_argument(
23
+ "--processor",
24
+ "--backend",
25
+ dest="processor",
26
+ default="CPU",
27
+ help='Processor/backend label (aliases: Scarlet/Amber, CPU/GPU)',
28
+ )
29
+ p.add_argument("--precision", default="single", help="Precision: single|double (aliases: fp32/fp64)")
30
+ p.add_argument("--threshold", type=float, default=None, help="Optional threshold/bond-dim conditioning value")
31
+ p.add_argument("--mirror-artifacts-dir", default=None, metavar="DIR", help="If set, write mirror QASM to DIR and add adjoint_supported/adjoint_reason/mirror_qasm_ref to output")
32
+ p.add_argument("--guidance", action="store_true", help="Include heuristic resource guidance (shots and simulator/MPS starting points)")
33
+
34
+ p.add_argument("--json", action="store_true", help="Emit machine-readable JSON")
35
+ args = p.parse_args(argv)
36
+
37
+ report = analyze_qasm(
38
+ args.qasm,
39
+ circuit_id=args.circuit_id,
40
+ circuit_name=args.circuit_name,
41
+ processor=args.processor,
42
+ precision=args.precision,
43
+ threshold=args.threshold,
44
+ mirror_artifacts_dir=args.mirror_artifacts_dir or None,
45
+ )
46
+
47
+ if args.json:
48
+ print(json.dumps(report.to_json_dict(include_guidance=args.guidance), indent=2, sort_keys=True))
49
+ return 0
50
+
51
+ ex = report.example
52
+ rc = report.run_config
53
+ print(f"file: {ex.qasm_path}")
54
+ print(f"format: {ex.ir.source_format}")
55
+ if ex.name:
56
+ print(f"name: {ex.name}")
57
+ print(f"function_hint: {ex.function_hint} ({ex.function_source})")
58
+ print(f"processor: {rc.processor} backend: {rc.backend} precision: {rc.precision} threshold: {rc.threshold}")
59
+ print(f"n_qubits: {ex.ir.n_qubits}")
60
+ print(f"n_ops: {ex.ir.n_ops}")
61
+ fv = ex.global_features
62
+ print(f"schema: {fv.schema_version}")
63
+ print(f"n_features: {len(fv.features)}")
64
+ if args.guidance:
65
+ out = report.to_json_dict(include_guidance=True)
66
+ guidance = out.get("guidance", {})
67
+ shot = guidance.get("shot_guidance", {})
68
+ sim = guidance.get("simulation_guidance", {})
69
+ mps = sim.get("mps_bond_dimension", {})
70
+ print("guidance: non-guaranteed heuristic starting points only; no backend execution")
71
+ print(
72
+ f"shots: applicability={shot.get('applicability')} "
73
+ f"starting={shot.get('starting_shots', [])}"
74
+ )
75
+ print(
76
+ f"simulator starting points: statevector_scale={sim.get('statevector', {}).get('scale')} "
77
+ f"mps_pressure={mps.get('pressure')} "
78
+ f"mps_starting_points={mps.get('starting_points', [])}"
79
+ )
80
+ return 0
81
+
82
+
83
+ def _cmd_batch(argv: list[str]) -> int:
84
+ p = argparse.ArgumentParser(prog="qcoder batch", add_help=True)
85
+ p.add_argument("circuits_dir", help="Directory containing QASM files")
86
+ p.add_argument("--out", required=True, help="Output JSONL path")
87
+ p.set_defaults(recursive=True)
88
+ p.add_argument("--recursive", dest="recursive", action="store_true", help="Discover files recursively (default)")
89
+ p.add_argument("--non-recursive", dest="recursive", action="store_false", help="Only discover top-level files")
90
+ p.add_argument("--pattern", default="*.qasm", help="Glob pattern for files (default: *.qasm)")
91
+ p.add_argument("--skip-errors", action="store_true", help="Continue on error, emit error records (default: fail-fast)")
92
+ p.add_argument("--processor", default=None, help="Processor/backend label for run_config")
93
+ p.add_argument("--backend", default=None, help="Backend label (CPU/GPU, etc.)")
94
+ p.add_argument("--precision", default=None, help="Precision: single|double|fp32|fp64")
95
+ p.add_argument("--threshold", type=float, default=None, help="Optional threshold for run_config")
96
+ p.add_argument("--mirror-artifacts-dir", default=None, metavar="DIR", help="If set, write mirror QASM to DIR and add adjoint_supported/adjoint_reason/mirror_qasm_ref to each record")
97
+ p.add_argument("--guidance", action="store_true", help="Include heuristic resource guidance block in each successful JSONL record")
98
+ args = p.parse_args(argv)
99
+
100
+ n = analyze_qasm_dir_to_jsonl(
101
+ args.circuits_dir,
102
+ args.out,
103
+ processor=args.processor,
104
+ backend=args.backend,
105
+ precision=args.precision,
106
+ threshold=args.threshold,
107
+ recursive=args.recursive,
108
+ pattern=args.pattern,
109
+ fail_fast=not args.skip_errors,
110
+ mirror_artifacts_dir=args.mirror_artifacts_dir or None,
111
+ include_guidance=args.guidance,
112
+ )
113
+ print(f"Wrote {n} records to {args.out}", file=sys.stderr)
114
+ return 0
115
+
116
+
117
+ def _cmd_context(argv: list[str]) -> int:
118
+ p = argparse.ArgumentParser(prog="qcoder context", add_help=True)
119
+ p.add_argument("qasm", help="Path to a .qasm file")
120
+ p.add_argument("--out-json", required=True, help="Output preflight JSON context path")
121
+ p.add_argument("--out-md", required=True, help="Output preflight Markdown context path")
122
+ p.add_argument("--id", dest="circuit_id", default=None, help="Optional circuit id")
123
+ p.add_argument("--name", dest="circuit_name", default=None, help="Optional circuit name")
124
+ p.add_argument("--guidance", action="store_true", help="Include heuristic resource guidance in context artifacts")
125
+ p.add_argument(
126
+ "--full-features",
127
+ action="store_true",
128
+ help="Include full feature glossary/appendix in context artifacts (default: selected structural features only)",
129
+ )
130
+ args = p.parse_args(argv)
131
+
132
+ write_preflight_context(
133
+ args.qasm,
134
+ out_json=args.out_json,
135
+ out_md=args.out_md,
136
+ include_guidance=args.guidance,
137
+ include_full_features=args.full_features,
138
+ circuit_id=args.circuit_id,
139
+ circuit_name=args.circuit_name,
140
+ )
141
+ print(f"Wrote preflight context JSON to {args.out_json}", file=sys.stderr)
142
+ print(f"Wrote preflight context Markdown to {args.out_md}", file=sys.stderr)
143
+ return 0
144
+
145
+
146
+ def _cmd_review(argv: list[str]) -> int:
147
+ p = argparse.ArgumentParser(prog="qcoder review", add_help=True)
148
+ p.add_argument("--counts-json", required=True, help="Input counts JSON path")
149
+ p.add_argument(
150
+ "--format",
151
+ dest="counts_format",
152
+ choices=["qcoder", "qiskit_counts"],
153
+ default="qcoder",
154
+ help="Input counts format (default: qcoder)",
155
+ )
156
+ p.add_argument("--preflight-json", default=None, help="Optional preflight context JSON path for linkage/checks")
157
+ p.add_argument("--out-json", required=True, help="Output execution review JSON path")
158
+ p.add_argument("--out-md", required=True, help="Output execution review Markdown path")
159
+ args = p.parse_args(argv)
160
+
161
+ write_execution_review(
162
+ counts_json=args.counts_json,
163
+ counts_format=args.counts_format,
164
+ preflight_json=args.preflight_json,
165
+ out_json=args.out_json,
166
+ out_md=args.out_md,
167
+ )
168
+ print(f"Wrote execution review JSON to {args.out_json}", file=sys.stderr)
169
+ print(f"Wrote execution review Markdown to {args.out_md}", file=sys.stderr)
170
+ return 0
171
+
172
+
173
+ def _print_root_help() -> None:
174
+ """Top-level help (subcommand parsers own analyze/batch --help)."""
175
+ print(
176
+ "usage: qcoder [--version | -V] [-h] {analyze,batch,context,review} ...\n\n"
177
+ "Quantum circuit analysis CLI.\n\n"
178
+ "positional arguments:\n"
179
+ " {analyze,batch,context,review} subcommand\n\n"
180
+ " analyze Analyze a QASM file (feature extraction + metadata + run config).\n"
181
+ " batch Batch extract a directory to JSONL (requires --out).\n\n"
182
+ " context Build deterministic preflight context artifacts.\n"
183
+ " review Build deterministic execution review artifacts from counts.\n\n"
184
+ "Run `qcoder <subcommand> --help` for subcommand options.",
185
+ end="",
186
+ )
187
+
188
+
189
+ def main(argv: list[str] | None = None) -> int:
190
+ if argv is None:
191
+ argv = sys.argv[1:]
192
+
193
+ if argv in (["--version"], ["-V"]):
194
+ from qcoder import __version__
195
+
196
+ print(__version__)
197
+ return 0
198
+
199
+ if not argv or argv in (["-h"], ["--help"]):
200
+ _print_root_help()
201
+ return 0
202
+
203
+ cmd, *rest = argv
204
+ if cmd == "analyze":
205
+ return _cmd_analyze(rest)
206
+ if cmd == "batch":
207
+ return _cmd_batch(rest)
208
+ if cmd == "context":
209
+ return _cmd_context(rest)
210
+ if cmd == "review":
211
+ return _cmd_review(rest)
212
+
213
+ print(
214
+ f"qcoder: unknown subcommand {cmd!r} (expected analyze, batch, context, or review)",
215
+ file=sys.stderr,
216
+ )
217
+ print("Run `qcoder --help` for usage.", file=sys.stderr)
218
+ return 2
219
+
220
+
221
+ if __name__ == "__main__":
222
+ raise SystemExit(main())
@@ -0,0 +1,7 @@
1
+ from __future__ import annotations
2
+
3
+ from .bundle import build_context_bundle
4
+ from .markdown import render_context_markdown
5
+
6
+ __all__ = ["build_context_bundle", "render_context_markdown"]
7
+
@@ -0,0 +1,86 @@
1
+ from __future__ import annotations
2
+
3
+ import hashlib
4
+ import json
5
+ from datetime import datetime, timezone
6
+ from pathlib import Path
7
+ from typing import Any
8
+
9
+ from qcoder.engines.feature_extraction.features.glossary_v0 import (
10
+ STRUCTURAL_SUMMARY_FEATURES,
11
+ full_feature_definitions,
12
+ selected_feature_definitions,
13
+ )
14
+
15
+
16
+ def utc_now_iso() -> str:
17
+ return datetime.now(timezone.utc).replace(microsecond=0).isoformat().replace("+00:00", "Z")
18
+
19
+
20
+ def qasm_sha256(path: str) -> str:
21
+ data = Path(path).read_bytes()
22
+ return hashlib.sha256(data).hexdigest()
23
+
24
+
25
+ def analysis_fingerprint(analysis: dict[str, Any]) -> str:
26
+ canonical = {
27
+ "features": analysis.get("features", {}),
28
+ "feature_map": analysis.get("feature_map", {}),
29
+ }
30
+ raw = json.dumps(canonical, sort_keys=True, separators=(",", ":")).encode("utf-8")
31
+ return hashlib.sha256(raw).hexdigest()
32
+
33
+
34
+ def build_context_bundle(
35
+ *,
36
+ qasm_path: str,
37
+ analysis: dict[str, Any],
38
+ qcoder_version: str,
39
+ generated_utc: str | None = None,
40
+ include_full_features: bool = False,
41
+ ) -> dict[str, Any]:
42
+ circuit = {
43
+ "qasm_path": analysis.get("qasm_path", qasm_path),
44
+ "circuit_id": analysis.get("circuit_id"),
45
+ "circuit_name": analysis.get("circuit_name"),
46
+ "source_format": analysis.get("source_format"),
47
+ "n_qubits": analysis.get("n_qubits"),
48
+ "n_cbits": analysis.get("n_cbits"),
49
+ "n_ops": analysis.get("n_ops"),
50
+ }
51
+ defs = full_feature_definitions() if include_full_features else selected_feature_definitions(STRUCTURAL_SUMMARY_FEATURES)
52
+ defs_scope = "full" if include_full_features else "selected"
53
+ analysis_block: dict[str, Any] = {
54
+ "features": analysis.get("features", {}),
55
+ "feature_map": analysis.get("feature_map", {}),
56
+ "feature_definitions": defs,
57
+ "feature_definitions_scope": defs_scope,
58
+ }
59
+ if "guidance" in analysis:
60
+ analysis_block["guidance"] = analysis["guidance"]
61
+
62
+ return {
63
+ "context_bundle_schema_version": "0.1",
64
+ "artifact_type": "qcoder.preflight_context",
65
+ "basis": "deterministic_analysis_plus_optional_guidance",
66
+ "generated_utc": generated_utc or utc_now_iso(),
67
+ "qcoder_version": qcoder_version,
68
+ "circuit": circuit,
69
+ "hashes": {
70
+ "qasm_sha256": qasm_sha256(qasm_path),
71
+ "analysis_fingerprint": analysis_fingerprint(analysis),
72
+ },
73
+ "analysis": analysis_block,
74
+ "assumptions": [
75
+ "No backend execution was performed.",
76
+ "This artifact is deterministic context, not execution results.",
77
+ ],
78
+ "llm_use": {
79
+ "intended_use": "Attach or paste this artifact for AI-assisted circuit planning.",
80
+ "limits": [
81
+ "Do not interpret this artifact as simulator or hardware execution evidence.",
82
+ "Guidance is heuristic and non-guaranteed when present.",
83
+ ],
84
+ },
85
+ }
86
+
@@ -0,0 +1,90 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any
4
+
5
+
6
+ def _fmt_num(value: Any) -> str:
7
+ if isinstance(value, float) and value.is_integer():
8
+ return str(int(value))
9
+ return str(value)
10
+
11
+
12
+ def render_context_markdown(bundle: dict[str, Any]) -> str:
13
+ circuit = bundle.get("circuit", {})
14
+ analysis = bundle.get("analysis", {})
15
+ feature_map = analysis.get("feature_map", {})
16
+ feature_defs = analysis.get("feature_definitions", {})
17
+ defs_scope = analysis.get("feature_definitions_scope", "selected")
18
+ features_obj = analysis.get("features", {})
19
+ feature_names = list(features_obj.get("feature_names") or [])
20
+ feature_values = list(features_obj.get("features") or [])
21
+ guidance = analysis.get("guidance")
22
+ lines: list[str] = []
23
+
24
+ lines.append("# qCoder Preflight Context")
25
+ lines.append("")
26
+ lines.append("## Purpose")
27
+ lines.append("Deterministic pre-execution context artifact for planning and review.")
28
+ lines.append("")
29
+ lines.append("## Circuit")
30
+ lines.append(f"- Path: `{circuit.get('qasm_path')}`")
31
+ lines.append(f"- Source format: `{circuit.get('source_format')}`")
32
+ lines.append(f"- Circuit id: `{circuit.get('circuit_id')}`")
33
+ lines.append(f"- Circuit name: `{circuit.get('circuit_name')}`")
34
+ lines.append(f"- n_qubits: `{_fmt_num(circuit.get('n_qubits'))}`")
35
+ lines.append(f"- n_cbits: `{_fmt_num(circuit.get('n_cbits'))}`")
36
+ lines.append(f"- n_ops: `{_fmt_num(circuit.get('n_ops'))}`")
37
+ lines.append("")
38
+ lines.append("## Structural Summary")
39
+ summary_keys = [
40
+ "real_depth",
41
+ "entangling_depth",
42
+ "n_2q_gate_ops",
43
+ "span_max",
44
+ "cut_max",
45
+ "ig_edge_density",
46
+ ]
47
+ for key in summary_keys:
48
+ if key in feature_map:
49
+ meaning = feature_defs.get(key, "")
50
+ if meaning:
51
+ lines.append(f"- {key}: `{_fmt_num(feature_map.get(key))}` — {meaning}")
52
+ else:
53
+ lines.append(f"- {key}: `{_fmt_num(feature_map.get(key))}`")
54
+ lines.append("")
55
+ if guidance is not None:
56
+ shot = guidance.get("shot_guidance", {})
57
+ sim = guidance.get("simulation_guidance", {})
58
+ mps = sim.get("mps_bond_dimension", {})
59
+ lines.append("## Resource Guidance")
60
+ lines.append("- Non-guaranteed heuristic starting points; no backend execution performed.")
61
+ lines.append(
62
+ f"- Shots: applicability=`{shot.get('applicability')}` starting=`{shot.get('starting_shots', [])}`"
63
+ )
64
+ lines.append(
65
+ f"- Simulation: statevector_scale=`{sim.get('statevector', {}).get('scale')}` "
66
+ f"mps_pressure=`{mps.get('pressure')}` mps_starting_points=`{mps.get('starting_points', [])}`"
67
+ )
68
+ lines.append("")
69
+ if defs_scope == "full" and feature_names and feature_values:
70
+ value_map = dict(zip(feature_names, feature_values))
71
+ lines.append("## Full Feature Reference")
72
+ for name in feature_names:
73
+ value = value_map.get(name)
74
+ meaning = feature_defs.get(name, "")
75
+ if meaning:
76
+ lines.append(f"- {name}: `{_fmt_num(value)}` — {meaning}")
77
+ else:
78
+ lines.append(f"- {name}: `{_fmt_num(value)}`")
79
+ lines.append("")
80
+ lines.append("## Assumptions and Limits")
81
+ for item in bundle.get("assumptions", []):
82
+ lines.append(f"- {item}")
83
+ for item in bundle.get("llm_use", {}).get("limits", []):
84
+ lines.append(f"- {item}")
85
+ lines.append("")
86
+ lines.append("## Suggested Use With an LLM")
87
+ lines.append(bundle.get("llm_use", {}).get("intended_use", ""))
88
+ lines.append("")
89
+ return "\n".join(lines)
90
+