qcoder 0.5.0a5__tar.gz → 0.5.0a6__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.
- {qcoder-0.5.0a5 → qcoder-0.5.0a6}/CHANGELOG.md +12 -0
- {qcoder-0.5.0a5/src/qcoder.egg-info → qcoder-0.5.0a6}/PKG-INFO +12 -1
- {qcoder-0.5.0a5 → qcoder-0.5.0a6}/README.md +11 -0
- {qcoder-0.5.0a5 → qcoder-0.5.0a6}/pyproject.toml +1 -1
- {qcoder-0.5.0a5 → qcoder-0.5.0a6}/src/qcoder/__init__.py +1 -1
- {qcoder-0.5.0a5 → qcoder-0.5.0a6}/src/qcoder/cli.py +79 -19
- {qcoder-0.5.0a5 → qcoder-0.5.0a6}/src/qcoder/core/run_config.py +6 -0
- qcoder-0.5.0a6/src/qcoder/core/share_safe.py +278 -0
- {qcoder-0.5.0a5 → qcoder-0.5.0a6}/src/qcoder/engines/context/bundle.py +2 -1
- {qcoder-0.5.0a5 → qcoder-0.5.0a6}/src/qcoder/engines/context/markdown.py +7 -1
- {qcoder-0.5.0a5 → qcoder-0.5.0a6}/src/qcoder/engines/review/bundle.py +4 -1
- {qcoder-0.5.0a5 → qcoder-0.5.0a6}/src/qcoder/engines/review/markdown.py +7 -1
- {qcoder-0.5.0a5 → qcoder-0.5.0a6}/src/qcoder/pipelines/analyze.py +11 -0
- {qcoder-0.5.0a5 → qcoder-0.5.0a6}/src/qcoder/pipelines/context.py +4 -1
- {qcoder-0.5.0a5 → qcoder-0.5.0a6}/src/qcoder/pipelines/review.py +13 -1
- {qcoder-0.5.0a5 → qcoder-0.5.0a6/src/qcoder.egg-info}/PKG-INFO +12 -1
- {qcoder-0.5.0a5 → qcoder-0.5.0a6}/src/qcoder.egg-info/SOURCES.txt +1 -0
- {qcoder-0.5.0a5 → qcoder-0.5.0a6}/LICENSE +0 -0
- {qcoder-0.5.0a5 → qcoder-0.5.0a6}/MANIFEST.in +0 -0
- {qcoder-0.5.0a5 → qcoder-0.5.0a6}/NOTICE +0 -0
- {qcoder-0.5.0a5 → qcoder-0.5.0a6}/setup.cfg +0 -0
- {qcoder-0.5.0a5 → qcoder-0.5.0a6}/src/qcoder/__main__.py +0 -0
- {qcoder-0.5.0a5 → qcoder-0.5.0a6}/src/qcoder/core/__init__.py +0 -0
- {qcoder-0.5.0a5 → qcoder-0.5.0a6}/src/qcoder/core/context.py +0 -0
- {qcoder-0.5.0a5 → qcoder-0.5.0a6}/src/qcoder/core/qasm2/__init__.py +0 -0
- {qcoder-0.5.0a5 → qcoder-0.5.0a6}/src/qcoder/core/qasm2/adjoint_eligibility.py +0 -0
- {qcoder-0.5.0a5 → qcoder-0.5.0a6}/src/qcoder/core/qasm2/mirror_build.py +0 -0
- {qcoder-0.5.0a5 → qcoder-0.5.0a6}/src/qcoder/core/schema.py +0 -0
- {qcoder-0.5.0a5 → qcoder-0.5.0a6}/src/qcoder/engines/context/__init__.py +0 -0
- {qcoder-0.5.0a5 → qcoder-0.5.0a6}/src/qcoder/engines/feature_extraction/adapters/__init__.py +0 -0
- {qcoder-0.5.0a5 → qcoder-0.5.0a6}/src/qcoder/engines/feature_extraction/adapters/cirq_intake.py +0 -0
- {qcoder-0.5.0a5 → qcoder-0.5.0a6}/src/qcoder/engines/feature_extraction/adapters/pennylane_intake.py +0 -0
- {qcoder-0.5.0a5 → qcoder-0.5.0a6}/src/qcoder/engines/feature_extraction/adapters/qiskit_intake.py +0 -0
- {qcoder-0.5.0a5 → qcoder-0.5.0a6}/src/qcoder/engines/feature_extraction/extractor.py +0 -0
- {qcoder-0.5.0a5 → qcoder-0.5.0a6}/src/qcoder/engines/feature_extraction/features/compute_v0.py +0 -0
- {qcoder-0.5.0a5 → qcoder-0.5.0a6}/src/qcoder/engines/feature_extraction/features/glossary_v0.py +0 -0
- {qcoder-0.5.0a5 → qcoder-0.5.0a6}/src/qcoder/engines/feature_extraction/features/schema_v0.py +0 -0
- {qcoder-0.5.0a5 → qcoder-0.5.0a6}/src/qcoder/engines/feature_extraction/ir.py +0 -0
- {qcoder-0.5.0a5 → qcoder-0.5.0a6}/src/qcoder/engines/feature_extraction/labeling.py +0 -0
- {qcoder-0.5.0a5 → qcoder-0.5.0a6}/src/qcoder/engines/feature_extraction/parsers/__init__.py +0 -0
- {qcoder-0.5.0a5 → qcoder-0.5.0a6}/src/qcoder/engines/feature_extraction/qasm2_regex_parser.py +0 -0
- {qcoder-0.5.0a5 → qcoder-0.5.0a6}/src/qcoder/engines/feature_extraction/reps/cut_profile.py +0 -0
- {qcoder-0.5.0a5 → qcoder-0.5.0a6}/src/qcoder/engines/feature_extraction/reps/depth.py +0 -0
- {qcoder-0.5.0a5 → qcoder-0.5.0a6}/src/qcoder/engines/feature_extraction/reps/entangling_layers.py +0 -0
- {qcoder-0.5.0a5 → qcoder-0.5.0a6}/src/qcoder/engines/feature_extraction/reps/gate_set_stats.py +0 -0
- {qcoder-0.5.0a5 → qcoder-0.5.0a6}/src/qcoder/engines/feature_extraction/reps/interaction_graph.py +0 -0
- {qcoder-0.5.0a5 → qcoder-0.5.0a6}/src/qcoder/engines/feature_extraction/reps/interaction_graph_metrics.py +0 -0
- {qcoder-0.5.0a5 → qcoder-0.5.0a6}/src/qcoder/engines/feature_extraction/reps/spans.py +0 -0
- {qcoder-0.5.0a5 → qcoder-0.5.0a6}/src/qcoder/engines/guidance/__init__.py +0 -0
- {qcoder-0.5.0a5 → qcoder-0.5.0a6}/src/qcoder/engines/guidance/model_pack.py +0 -0
- {qcoder-0.5.0a5 → qcoder-0.5.0a6}/src/qcoder/engines/guidance/resource.py +0 -0
- {qcoder-0.5.0a5 → qcoder-0.5.0a6}/src/qcoder/engines/guidance/structural_scores.py +0 -0
- {qcoder-0.5.0a5 → qcoder-0.5.0a6}/src/qcoder/engines/profiles/__init__.py +0 -0
- {qcoder-0.5.0a5 → qcoder-0.5.0a6}/src/qcoder/engines/profiles/feature_profiles_v0.py +0 -0
- {qcoder-0.5.0a5 → qcoder-0.5.0a6}/src/qcoder/engines/review/__init__.py +0 -0
- {qcoder-0.5.0a5 → qcoder-0.5.0a6}/src/qcoder/engines/review/counts_v0.py +0 -0
- {qcoder-0.5.0a5 → qcoder-0.5.0a6}/src/qcoder/engines/review/qiskit_counts.py +0 -0
- {qcoder-0.5.0a5 → qcoder-0.5.0a6}/src/qcoder/explorer/__init__.py +0 -0
- {qcoder-0.5.0a5 → qcoder-0.5.0a6}/src/qcoder/explorer/derived_evidence.py +0 -0
- {qcoder-0.5.0a5 → qcoder-0.5.0a6}/src/qcoder/model_packs/__init__.py +0 -0
- {qcoder-0.5.0a5 → qcoder-0.5.0a6}/src/qcoder/model_packs/resource_guidance_local_v0.json +0 -0
- {qcoder-0.5.0a5 → qcoder-0.5.0a6}/src/qcoder/pipelines/batch.py +0 -0
- {qcoder-0.5.0a5 → qcoder-0.5.0a6}/src/qcoder/pro_preview/__init__.py +0 -0
- {qcoder-0.5.0a5 → qcoder-0.5.0a6}/src/qcoder/pro_preview/client.py +0 -0
- {qcoder-0.5.0a5 → qcoder-0.5.0a6}/src/qcoder/pro_preview/config.py +0 -0
- {qcoder-0.5.0a5 → qcoder-0.5.0a6}/src/qcoder/pro_preview/errors.py +0 -0
- {qcoder-0.5.0a5 → qcoder-0.5.0a6}/src/qcoder/pro_preview/manifest.py +0 -0
- {qcoder-0.5.0a5 → qcoder-0.5.0a6}/src/qcoder/tools/batch.py +0 -0
- {qcoder-0.5.0a5 → qcoder-0.5.0a6}/src/qcoder.egg-info/dependency_links.txt +0 -0
- {qcoder-0.5.0a5 → qcoder-0.5.0a6}/src/qcoder.egg-info/entry_points.txt +0 -0
- {qcoder-0.5.0a5 → qcoder-0.5.0a6}/src/qcoder.egg-info/requires.txt +0 -0
- {qcoder-0.5.0a5 → qcoder-0.5.0a6}/src/qcoder.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,18 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
3
|
|
|
4
|
+
## 0.5.0a6
|
|
5
|
+
|
|
6
|
+
- Add share-safe / redacted artifact mode for artifacts intended for ChatGPT, Cursor, email, GitHub issues, or support threads.
|
|
7
|
+
- Add `--share-safe` / `--redact` to OSS artifact commands and Explorer evidence file output.
|
|
8
|
+
- Emit share-safety metadata in JSON artifacts: `share_safe`, `redactions_applied`, `raw_qasm_included`, `local_paths_included`, and `tokens_included`.
|
|
9
|
+
- Add a visible share-safe note to Markdown artifacts.
|
|
10
|
+
- Fix Windows free-text path redaction, including `C:\Users\...` paths, Windows forward-slash paths, UNC paths, home-relative paths, Linux home paths, and WSL-mounted Windows paths.
|
|
11
|
+
- Preserve normal rich local artifacts by default; share-safe mode is opt-in.
|
|
12
|
+
- Share-safe mode is designed for safer sharing and users should still review artifacts before sharing. It is not a privacy guarantee.
|
|
13
|
+
- Remaining P1 hardening: forward-slash UNC variants, broader Linux root patterns, independent post-scan hardening, and expanded docs wording.
|
|
14
|
+
|
|
15
|
+
|
|
4
16
|
## 0.5.0a5
|
|
5
17
|
|
|
6
18
|
- Add `qcoder explorer evidence` as the primary Explorer Beta guided-evidence surface.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: qcoder
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.0a6
|
|
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>
|
|
@@ -77,6 +77,16 @@ qcoder context path/to/circuit.qasm --out-json preflight.context.json --out-md p
|
|
|
77
77
|
qcoder review --counts-json counts.json --format qiskit_counts --preflight-json preflight.context.json --out-json execution.review.json --out-md execution.review.md
|
|
78
78
|
```
|
|
79
79
|
|
|
80
|
+
For artifacts you intend to paste into ChatGPT, Cursor, email, GitHub issues, or support threads, add `--share-safe`:
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
qcoder analyze path/to/circuit.qasm --json --share-safe
|
|
84
|
+
qcoder context path/to/circuit.qasm --out-json preflight.context.json --out-md preflight.context.md --share-safe
|
|
85
|
+
qcoder review --counts-json counts.json --format qiskit_counts --preflight-json preflight.context.json --out-json execution.review.json --out-md execution.review.md --share-safe
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Share-safe mode is designed for safer sharing: it redacts local paths and token/header-like strings, adds `share_safe=true`, and marks raw QASM/local paths/tokens as not included. Review artifacts before sharing; this is not a guarantee that all sensitive project content has been removed.
|
|
89
|
+
|
|
80
90
|
Explorer Beta compatibility checks and archived Pro bootstrap:
|
|
81
91
|
|
|
82
92
|
```bash
|
|
@@ -85,6 +95,7 @@ qcoder explorer demo
|
|
|
85
95
|
qcoder explorer evidence
|
|
86
96
|
qcoder explorer evidence --qasm path/to/circuit.qasm
|
|
87
97
|
qcoder explorer evidence --context-json preflight.context.json
|
|
98
|
+
qcoder explorer evidence --qasm path/to/circuit.qasm --out-json explorer.json --out-md explorer.md --share-safe
|
|
88
99
|
qcoder pro --help
|
|
89
100
|
```
|
|
90
101
|
|
|
@@ -47,6 +47,16 @@ qcoder context path/to/circuit.qasm --out-json preflight.context.json --out-md p
|
|
|
47
47
|
qcoder review --counts-json counts.json --format qiskit_counts --preflight-json preflight.context.json --out-json execution.review.json --out-md execution.review.md
|
|
48
48
|
```
|
|
49
49
|
|
|
50
|
+
For artifacts you intend to paste into ChatGPT, Cursor, email, GitHub issues, or support threads, add `--share-safe`:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
qcoder analyze path/to/circuit.qasm --json --share-safe
|
|
54
|
+
qcoder context path/to/circuit.qasm --out-json preflight.context.json --out-md preflight.context.md --share-safe
|
|
55
|
+
qcoder review --counts-json counts.json --format qiskit_counts --preflight-json preflight.context.json --out-json execution.review.json --out-md execution.review.md --share-safe
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Share-safe mode is designed for safer sharing: it redacts local paths and token/header-like strings, adds `share_safe=true`, and marks raw QASM/local paths/tokens as not included. Review artifacts before sharing; this is not a guarantee that all sensitive project content has been removed.
|
|
59
|
+
|
|
50
60
|
Explorer Beta compatibility checks and archived Pro bootstrap:
|
|
51
61
|
|
|
52
62
|
```bash
|
|
@@ -55,6 +65,7 @@ qcoder explorer demo
|
|
|
55
65
|
qcoder explorer evidence
|
|
56
66
|
qcoder explorer evidence --qasm path/to/circuit.qasm
|
|
57
67
|
qcoder explorer evidence --context-json preflight.context.json
|
|
68
|
+
qcoder explorer evidence --qasm path/to/circuit.qasm --out-json explorer.json --out-md explorer.md --share-safe
|
|
58
69
|
qcoder pro --help
|
|
59
70
|
```
|
|
60
71
|
|
|
@@ -8,6 +8,11 @@ from pathlib import Path
|
|
|
8
8
|
from qcoder.pipelines.analyze import analyze_qasm
|
|
9
9
|
from qcoder.pipelines.context import write_preflight_context
|
|
10
10
|
from qcoder.pipelines.review import write_execution_review
|
|
11
|
+
from qcoder.core.share_safe import (
|
|
12
|
+
make_share_safe_payload,
|
|
13
|
+
render_share_safe_note,
|
|
14
|
+
render_share_safe_provenance,
|
|
15
|
+
)
|
|
11
16
|
from qcoder.explorer.derived_evidence import (
|
|
12
17
|
ExplorerDerivedEvidenceRequestError,
|
|
13
18
|
build_derived_evidence_request_from_context_json,
|
|
@@ -100,6 +105,13 @@ def _cmd_analyze(argv: list[str]) -> int:
|
|
|
100
105
|
help="Include derived feature_profiles in JSON output (requires --json for analyze)",
|
|
101
106
|
)
|
|
102
107
|
p.add_argument("--json", action="store_true", help="Emit machine-readable JSON")
|
|
108
|
+
p.add_argument(
|
|
109
|
+
"--share-safe",
|
|
110
|
+
"--redact",
|
|
111
|
+
dest="share_safe",
|
|
112
|
+
action="store_true",
|
|
113
|
+
help="Redact local paths and sensitive runtime details in JSON output intended for sharing.",
|
|
114
|
+
)
|
|
103
115
|
args = p.parse_args(argv)
|
|
104
116
|
|
|
105
117
|
if args.profiles and not args.json:
|
|
@@ -120,9 +132,12 @@ def _cmd_analyze(argv: list[str]) -> int:
|
|
|
120
132
|
)
|
|
121
133
|
|
|
122
134
|
if args.json:
|
|
135
|
+
payload = report.to_json_dict(include_guidance=args.guidance, include_profiles=args.profiles)
|
|
136
|
+
if args.share_safe:
|
|
137
|
+
payload = make_share_safe_payload(payload)
|
|
123
138
|
print(
|
|
124
139
|
json.dumps(
|
|
125
|
-
|
|
140
|
+
payload,
|
|
126
141
|
indent=2,
|
|
127
142
|
sort_keys=True,
|
|
128
143
|
)
|
|
@@ -131,7 +146,9 @@ def _cmd_analyze(argv: list[str]) -> int:
|
|
|
131
146
|
|
|
132
147
|
ex = report.example
|
|
133
148
|
rc = report.run_config
|
|
134
|
-
print(f"file: {ex.qasm_path}")
|
|
149
|
+
print(f"file: {'<redacted-local-path>' if args.share_safe else ex.qasm_path}")
|
|
150
|
+
if args.share_safe:
|
|
151
|
+
print("share_safe: true")
|
|
135
152
|
print(f"format: {ex.ir.source_format}")
|
|
136
153
|
if ex.name:
|
|
137
154
|
print(f"name: {ex.name}")
|
|
@@ -218,6 +235,13 @@ def _cmd_context(argv: list[str]) -> int:
|
|
|
218
235
|
action="store_true",
|
|
219
236
|
help="Include full feature glossary/appendix in context artifacts (default: selected structural features only)",
|
|
220
237
|
)
|
|
238
|
+
p.add_argument(
|
|
239
|
+
"--share-safe",
|
|
240
|
+
"--redact",
|
|
241
|
+
dest="share_safe",
|
|
242
|
+
action="store_true",
|
|
243
|
+
help="Write artifacts designed for safer sharing by redacting local paths and sensitive runtime details.",
|
|
244
|
+
)
|
|
221
245
|
args = p.parse_args(argv)
|
|
222
246
|
|
|
223
247
|
write_preflight_context(
|
|
@@ -229,9 +253,12 @@ def _cmd_context(argv: list[str]) -> int:
|
|
|
229
253
|
include_full_features=args.full_features,
|
|
230
254
|
circuit_id=args.circuit_id,
|
|
231
255
|
circuit_name=args.circuit_name,
|
|
256
|
+
share_safe=args.share_safe,
|
|
232
257
|
)
|
|
233
|
-
|
|
234
|
-
|
|
258
|
+
json_label = "<redacted-local-path>" if args.share_safe else args.out_json
|
|
259
|
+
md_label = "<redacted-local-path>" if args.share_safe else args.out_md
|
|
260
|
+
print(f"Wrote preflight context JSON to {json_label}", file=sys.stderr)
|
|
261
|
+
print(f"Wrote preflight context Markdown to {md_label}", file=sys.stderr)
|
|
235
262
|
return 0
|
|
236
263
|
|
|
237
264
|
|
|
@@ -248,6 +275,13 @@ def _cmd_review(argv: list[str]) -> int:
|
|
|
248
275
|
p.add_argument("--preflight-json", default=None, help="Optional preflight context JSON path for linkage/checks")
|
|
249
276
|
p.add_argument("--out-json", required=True, help="Output execution review JSON path")
|
|
250
277
|
p.add_argument("--out-md", required=True, help="Output execution review Markdown path")
|
|
278
|
+
p.add_argument(
|
|
279
|
+
"--share-safe",
|
|
280
|
+
"--redact",
|
|
281
|
+
dest="share_safe",
|
|
282
|
+
action="store_true",
|
|
283
|
+
help="Write artifacts designed for safer sharing by redacting local paths and sensitive runtime details.",
|
|
284
|
+
)
|
|
251
285
|
args = p.parse_args(argv)
|
|
252
286
|
|
|
253
287
|
write_execution_review(
|
|
@@ -256,9 +290,12 @@ def _cmd_review(argv: list[str]) -> int:
|
|
|
256
290
|
preflight_json=args.preflight_json,
|
|
257
291
|
out_json=args.out_json,
|
|
258
292
|
out_md=args.out_md,
|
|
293
|
+
share_safe=args.share_safe,
|
|
259
294
|
)
|
|
260
|
-
|
|
261
|
-
|
|
295
|
+
json_label = "<redacted-local-path>" if args.share_safe else args.out_json
|
|
296
|
+
md_label = "<redacted-local-path>" if args.share_safe else args.out_md
|
|
297
|
+
print(f"Wrote execution review JSON to {json_label}", file=sys.stderr)
|
|
298
|
+
print(f"Wrote execution review Markdown to {md_label}", file=sys.stderr)
|
|
262
299
|
return 0
|
|
263
300
|
|
|
264
301
|
|
|
@@ -318,14 +355,20 @@ def _format_summary_value(value: str | int | float | bool) -> str:
|
|
|
318
355
|
return str(value)
|
|
319
356
|
|
|
320
357
|
|
|
321
|
-
def _print_raw_payload_json(payload: dict[str, object] | None) -> None:
|
|
322
|
-
|
|
358
|
+
def _print_raw_payload_json(payload: dict[str, object] | None, *, share_safe: bool = False) -> None:
|
|
359
|
+
out = payload or {}
|
|
360
|
+
if share_safe:
|
|
361
|
+
out = make_share_safe_payload(out)
|
|
362
|
+
print(json.dumps(out, indent=2, sort_keys=True))
|
|
323
363
|
|
|
324
364
|
|
|
325
|
-
def _write_json_payload(path: str, payload: dict[str, object] | None) -> None:
|
|
365
|
+
def _write_json_payload(path: str, payload: dict[str, object] | None, *, share_safe: bool = False) -> None:
|
|
366
|
+
out = payload or {}
|
|
367
|
+
if share_safe:
|
|
368
|
+
out = make_share_safe_payload(out)
|
|
326
369
|
out_path = Path(path)
|
|
327
370
|
out_path.parent.mkdir(parents=True, exist_ok=True)
|
|
328
|
-
out_path.write_text(json.dumps(
|
|
371
|
+
out_path.write_text(json.dumps(out, indent=2, sort_keys=True), encoding="utf-8")
|
|
329
372
|
|
|
330
373
|
|
|
331
374
|
def _is_scalar(value: object) -> bool:
|
|
@@ -468,6 +511,11 @@ def _render_student_evidence_markdown(payload: dict[str, object] | None) -> str:
|
|
|
468
511
|
"# qCoder Explorer Beta Guided Evidence",
|
|
469
512
|
"",
|
|
470
513
|
]
|
|
514
|
+
if payload and payload.get("share_safe") is True:
|
|
515
|
+
lines.append(render_share_safe_note().strip())
|
|
516
|
+
lines.append("")
|
|
517
|
+
lines.append(render_share_safe_provenance(payload).strip())
|
|
518
|
+
lines.append("")
|
|
471
519
|
for line in _summarize_student_evidence_payload(payload):
|
|
472
520
|
lines.append(f"- {line}")
|
|
473
521
|
if payload:
|
|
@@ -490,10 +538,13 @@ def _render_student_evidence_markdown(payload: dict[str, object] | None) -> str:
|
|
|
490
538
|
return "\n".join(lines)
|
|
491
539
|
|
|
492
540
|
|
|
493
|
-
def _write_markdown_payload(path: str, payload: dict[str, object] | None) -> None:
|
|
541
|
+
def _write_markdown_payload(path: str, payload: dict[str, object] | None, *, share_safe: bool = False) -> None:
|
|
542
|
+
out = payload or {}
|
|
543
|
+
if share_safe:
|
|
544
|
+
out = make_share_safe_payload(out)
|
|
494
545
|
out_path = Path(path)
|
|
495
546
|
out_path.parent.mkdir(parents=True, exist_ok=True)
|
|
496
|
-
out_path.write_text(_render_student_evidence_markdown(
|
|
547
|
+
out_path.write_text(_render_student_evidence_markdown(out), encoding="utf-8")
|
|
497
548
|
|
|
498
549
|
|
|
499
550
|
def _run_student_builtin_review_check(
|
|
@@ -577,6 +628,7 @@ def _run_student_evidence_check(
|
|
|
577
628
|
context_json_path: str | None = None,
|
|
578
629
|
out_json: str | None = None,
|
|
579
630
|
out_md: str | None = None,
|
|
631
|
+
share_safe: bool = False,
|
|
580
632
|
) -> int:
|
|
581
633
|
request_payload: dict[str, object] | None = None
|
|
582
634
|
if qasm_path and context_json_path:
|
|
@@ -618,11 +670,11 @@ def _run_student_evidence_check(
|
|
|
618
670
|
return 2
|
|
619
671
|
|
|
620
672
|
if json_output:
|
|
621
|
-
_print_raw_payload_json(response.payload)
|
|
673
|
+
_print_raw_payload_json(response.payload, share_safe=share_safe)
|
|
622
674
|
if out_json:
|
|
623
|
-
_write_json_payload(out_json, response.payload)
|
|
675
|
+
_write_json_payload(out_json, response.payload, share_safe=share_safe)
|
|
624
676
|
if out_md:
|
|
625
|
-
_write_markdown_payload(out_md, response.payload)
|
|
677
|
+
_write_markdown_payload(out_md, response.payload, share_safe=share_safe)
|
|
626
678
|
return 0 if response.status_code == 200 else 1 if response.status_code in {401, 403} else 2
|
|
627
679
|
|
|
628
680
|
if response.status_code == 200:
|
|
@@ -637,11 +689,11 @@ def _run_student_evidence_check(
|
|
|
637
689
|
for line in _summarize_student_evidence_payload(response.payload):
|
|
638
690
|
print(f" {line}")
|
|
639
691
|
if out_json:
|
|
640
|
-
_write_json_payload(out_json, response.payload)
|
|
641
|
-
print(f" wrote_json: {out_json}")
|
|
692
|
+
_write_json_payload(out_json, response.payload, share_safe=share_safe)
|
|
693
|
+
print(f" wrote_json: {'<redacted-local-path>' if share_safe else out_json}")
|
|
642
694
|
if out_md:
|
|
643
|
-
_write_markdown_payload(out_md, response.payload)
|
|
644
|
-
print(f" wrote_md: {out_md}")
|
|
695
|
+
_write_markdown_payload(out_md, response.payload, share_safe=share_safe)
|
|
696
|
+
print(f" wrote_md: {'<redacted-local-path>' if share_safe else out_md}")
|
|
645
697
|
return 0
|
|
646
698
|
if response.status_code == 401:
|
|
647
699
|
print(
|
|
@@ -724,6 +776,13 @@ def _cmd_explorer(argv: list[str], *, compatibility_alias: bool = False) -> int:
|
|
|
724
776
|
)
|
|
725
777
|
p_evidence.add_argument("--out-json", default=None, help="Write Explorer evidence response JSON.")
|
|
726
778
|
p_evidence.add_argument("--out-md", default=None, help="Write Explorer evidence response Markdown.")
|
|
779
|
+
p_evidence.add_argument(
|
|
780
|
+
"--share-safe",
|
|
781
|
+
"--redact",
|
|
782
|
+
dest="share_safe",
|
|
783
|
+
action="store_true",
|
|
784
|
+
help="Write output artifacts with explicit share-safe metadata and local-sensitive details redacted.",
|
|
785
|
+
)
|
|
727
786
|
p_evidence.set_defaults(explorer_command="evidence")
|
|
728
787
|
|
|
729
788
|
args = p.parse_args(argv)
|
|
@@ -749,6 +808,7 @@ def _cmd_explorer(argv: list[str], *, compatibility_alias: bool = False) -> int:
|
|
|
749
808
|
context_json_path=args.context_json,
|
|
750
809
|
out_json=args.out_json,
|
|
751
810
|
out_md=args.out_md,
|
|
811
|
+
share_safe=args.share_safe,
|
|
752
812
|
)
|
|
753
813
|
|
|
754
814
|
p.print_help()
|
|
@@ -60,9 +60,15 @@ class RunConfig:
|
|
|
60
60
|
)
|
|
61
61
|
|
|
62
62
|
def to_dict(self) -> dict:
|
|
63
|
+
analysis_backend = "local_gpu" if self.backend == "GPU" else "local_cpu"
|
|
63
64
|
return {
|
|
64
65
|
"processor": self.processor,
|
|
65
66
|
"backend": self.backend,
|
|
67
|
+
"analysis_backend": analysis_backend,
|
|
68
|
+
"local_analysis_backend": analysis_backend,
|
|
69
|
+
"backend_meaning": (
|
|
70
|
+
"local analysis backend; not a simulator, QPU, or hardware execution backend"
|
|
71
|
+
),
|
|
66
72
|
"precision": self.precision,
|
|
67
73
|
"threshold": self.threshold,
|
|
68
74
|
}
|
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import copy
|
|
4
|
+
import re
|
|
5
|
+
from pathlib import PurePath
|
|
6
|
+
from typing import Any
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
SHARE_SAFE_NOTE = (
|
|
10
|
+
"Share-safe means local paths, raw circuit text, and token-like values are "
|
|
11
|
+
"omitted or redacted where detected. It is designed for safer sharing, not "
|
|
12
|
+
"a privacy guarantee, and it does not hide circuit structure."
|
|
13
|
+
)
|
|
14
|
+
SCHEMA_VERSION_NOTE = (
|
|
15
|
+
"qCoder package versions and artifact/schema versions are versioned separately."
|
|
16
|
+
)
|
|
17
|
+
SUPPORTED_CLAIMS = (
|
|
18
|
+
"deterministic structural features",
|
|
19
|
+
"pre-execution circuit shape",
|
|
20
|
+
"local artifact review context",
|
|
21
|
+
)
|
|
22
|
+
UNSUPPORTED_CLAIMS = (
|
|
23
|
+
"runtime prediction",
|
|
24
|
+
"fidelity or backend ranking",
|
|
25
|
+
"correctness proof",
|
|
26
|
+
"quantum advantage",
|
|
27
|
+
"raw hosted QASM",
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
_REDACTED_LOCAL_PATH = "<redacted-local-path>"
|
|
31
|
+
_REDACTED_SENSITIVE_VALUE = "<redacted-sensitive-value>"
|
|
32
|
+
|
|
33
|
+
_PATH_TERMINATOR_CHARS = r"\s`'\"<>|"
|
|
34
|
+
_LOCAL_PATH_RE = re.compile(
|
|
35
|
+
r"(?P<path>"
|
|
36
|
+
r"(?:[A-Za-z]:[\\/][^" + _PATH_TERMINATOR_CHARS + r"]+)"
|
|
37
|
+
r"|(?:\\\\[^\\/" + _PATH_TERMINATOR_CHARS + r"]+[\\/][^" + _PATH_TERMINATOR_CHARS + r"]+)"
|
|
38
|
+
r"|(?:~[\\/][^" + _PATH_TERMINATOR_CHARS + r"]+)"
|
|
39
|
+
r"|(?:/(?:home|Users|mnt|private|var|tmp|workspace|workspaces)/[^" + _PATH_TERMINATOR_CHARS + r"]+)"
|
|
40
|
+
r")"
|
|
41
|
+
)
|
|
42
|
+
_TOKEN_LIKE_RE = re.compile(
|
|
43
|
+
r"(?i)(bearer\s+)[A-Za-z0-9._~+/=-]{8,}|"
|
|
44
|
+
r"(authorization\s*[:=]\s*)(?:bearer\s+)?[^\n,;]+|"
|
|
45
|
+
r"(cookie\s*[:=]\s*)[^\n,;]+|"
|
|
46
|
+
r"(session\s*[:=]\s*)[^\n,;]+|"
|
|
47
|
+
r"(identity[-_ ]?token\s*[:=]\s*)[^\n,;]+|"
|
|
48
|
+
r"(QCODER_[A-Z_]*TOKEN\s*=\s*)[^\s]+|"
|
|
49
|
+
r"(pypi-)[A-Za-z0-9._-]{8,}"
|
|
50
|
+
)
|
|
51
|
+
_FORBIDDEN_TEXT_MARKERS = (
|
|
52
|
+
"OPENQASM 2.0",
|
|
53
|
+
"OPENQASM 3.0",
|
|
54
|
+
"qreg ",
|
|
55
|
+
"creg ",
|
|
56
|
+
"Secret Manager",
|
|
57
|
+
"Postmark",
|
|
58
|
+
)
|
|
59
|
+
_PATH_KEYS = {
|
|
60
|
+
"qasm_path",
|
|
61
|
+
"preflight_context_path",
|
|
62
|
+
"counts_json",
|
|
63
|
+
"source_path",
|
|
64
|
+
"local_path",
|
|
65
|
+
"path",
|
|
66
|
+
}
|
|
67
|
+
_RAW_KEYS = {
|
|
68
|
+
"raw_qasm",
|
|
69
|
+
"qasm_text",
|
|
70
|
+
"source_text",
|
|
71
|
+
"raw_source_text",
|
|
72
|
+
"prompt",
|
|
73
|
+
"notebook",
|
|
74
|
+
"auth_header",
|
|
75
|
+
"authorization",
|
|
76
|
+
"cookie",
|
|
77
|
+
"session",
|
|
78
|
+
"token",
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def make_share_safe_payload(payload: dict[str, Any]) -> dict[str, Any]:
|
|
83
|
+
redactions: set[str] = set()
|
|
84
|
+
sanitized = _sanitize(copy.deepcopy(payload), redactions=redactions, key_path=())
|
|
85
|
+
if not isinstance(sanitized, dict):
|
|
86
|
+
sanitized = {"value": sanitized}
|
|
87
|
+
_add_artifact_identity(sanitized)
|
|
88
|
+
_clarify_run_config(sanitized)
|
|
89
|
+
sanitized["share_safe"] = True
|
|
90
|
+
sanitized["redactions_applied"] = sorted(redactions)
|
|
91
|
+
serialized = _stable_string(sanitized)
|
|
92
|
+
sanitized["raw_qasm_included"] = contains_raw_qasm_marker(serialized)
|
|
93
|
+
sanitized["local_paths_included"] = contains_local_path(serialized)
|
|
94
|
+
token_like_secrets_included = contains_token_or_header(serialized)
|
|
95
|
+
sanitized["token_like_secrets_included"] = token_like_secrets_included
|
|
96
|
+
sanitized["tokens_included"] = token_like_secrets_included
|
|
97
|
+
sanitized["tokens_included_meaning"] = (
|
|
98
|
+
"authentication tokens or token-like secrets, not LLM token counts"
|
|
99
|
+
)
|
|
100
|
+
sanitized["share_safe_note"] = SHARE_SAFE_NOTE
|
|
101
|
+
sanitized["schema_version_note"] = SCHEMA_VERSION_NOTE
|
|
102
|
+
sanitized["supported_claims"] = list(SUPPORTED_CLAIMS)
|
|
103
|
+
sanitized["unsupported_claims"] = list(UNSUPPORTED_CLAIMS)
|
|
104
|
+
return sanitized
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def render_share_safe_note() -> str:
|
|
108
|
+
return f"> **{SHARE_SAFE_NOTE}**\n\n"
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def render_share_safe_provenance(payload: dict[str, Any]) -> str:
|
|
112
|
+
"""Render compact share-safe provenance for Markdown artifacts."""
|
|
113
|
+
lines = ["## Share-safe provenance", ""]
|
|
114
|
+
for label, value in _provenance_items(payload):
|
|
115
|
+
lines.append(f"- {label}: `{value}`")
|
|
116
|
+
redactions = payload.get("redactions_applied")
|
|
117
|
+
if isinstance(redactions, list):
|
|
118
|
+
redaction_text = ", ".join(str(item) for item in redactions) if redactions else "none"
|
|
119
|
+
lines.append(f"- redactions_applied: `{redaction_text}`")
|
|
120
|
+
lines.append("")
|
|
121
|
+
lines.append(SCHEMA_VERSION_NOTE)
|
|
122
|
+
lines.append("")
|
|
123
|
+
lines.append("## Supported by this artifact")
|
|
124
|
+
for item in SUPPORTED_CLAIMS:
|
|
125
|
+
lines.append(f"- {item}")
|
|
126
|
+
lines.append("")
|
|
127
|
+
lines.append("## Not supported by this artifact")
|
|
128
|
+
for item in UNSUPPORTED_CLAIMS:
|
|
129
|
+
lines.append(f"- {item}")
|
|
130
|
+
lines.append("")
|
|
131
|
+
return "\n".join(lines)
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def _provenance_items(payload: dict[str, Any]) -> list[tuple[str, Any]]:
|
|
135
|
+
schema = (
|
|
136
|
+
payload.get("schema_id")
|
|
137
|
+
or payload.get("context_bundle_schema_version")
|
|
138
|
+
or payload.get("review_bundle_schema_version")
|
|
139
|
+
or payload.get("artifact_type")
|
|
140
|
+
or "unknown"
|
|
141
|
+
)
|
|
142
|
+
fingerprint = None
|
|
143
|
+
hashes = payload.get("hashes")
|
|
144
|
+
if isinstance(hashes, dict):
|
|
145
|
+
fingerprint = hashes.get("qasm_sha256") or hashes.get("analysis_fingerprint")
|
|
146
|
+
if fingerprint is None:
|
|
147
|
+
linkage = payload.get("linkage")
|
|
148
|
+
if isinstance(linkage, dict):
|
|
149
|
+
fingerprint = linkage.get("qasm_sha256") or linkage.get("analysis_fingerprint")
|
|
150
|
+
return [
|
|
151
|
+
("qcoder_version", payload.get("qcoder_version", "unknown")),
|
|
152
|
+
("artifact_schema", schema),
|
|
153
|
+
("qcoder_product_path", payload.get("qcoder_product_path", "unknown")),
|
|
154
|
+
("artifact_role", payload.get("artifact_role", "unknown")),
|
|
155
|
+
("share_safe", payload.get("share_safe", "unknown")),
|
|
156
|
+
("raw_qasm_included", payload.get("raw_qasm_included", "unknown")),
|
|
157
|
+
("local_paths_included", payload.get("local_paths_included", "unknown")),
|
|
158
|
+
(
|
|
159
|
+
"token_like_secrets_included",
|
|
160
|
+
payload.get("token_like_secrets_included", payload.get("tokens_included", "unknown")),
|
|
161
|
+
),
|
|
162
|
+
("qasm_sha256_or_analysis_fingerprint", fingerprint or "not_available"),
|
|
163
|
+
]
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
def _add_artifact_identity(payload: dict[str, Any]) -> None:
|
|
167
|
+
if payload.get("qcoder_product_path") and payload.get("artifact_role"):
|
|
168
|
+
return
|
|
169
|
+
schema_id = str(payload.get("schema_id") or "")
|
|
170
|
+
mode = str(payload.get("mode") or "")
|
|
171
|
+
artifact_type = str(payload.get("artifact_type") or "")
|
|
172
|
+
if schema_id.startswith("qcoder.explorer.") or mode == "explorer-custom-guided-evidence":
|
|
173
|
+
payload.setdefault("qcoder_product_path", "explorer_beta")
|
|
174
|
+
payload.setdefault("artifact_role", "derived_context_guided_evidence")
|
|
175
|
+
elif payload.get("context_bundle_schema_version") or artifact_type == "qcoder.preflight_context":
|
|
176
|
+
payload.setdefault("qcoder_product_path", "oss")
|
|
177
|
+
payload.setdefault("artifact_role", "local_preflight_context")
|
|
178
|
+
elif payload.get("review_bundle_schema_version") or artifact_type == "qcoder.execution_review":
|
|
179
|
+
payload.setdefault("qcoder_product_path", "oss")
|
|
180
|
+
payload.setdefault("artifact_role", "local_execution_review")
|
|
181
|
+
elif "feature_map" in payload and "features" in payload:
|
|
182
|
+
payload.setdefault("qcoder_product_path", "oss")
|
|
183
|
+
payload.setdefault("artifact_role", "local_analysis_report")
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
def _clarify_run_config(payload: dict[str, Any]) -> None:
|
|
187
|
+
run_config = payload.get("run_config")
|
|
188
|
+
if not isinstance(run_config, dict):
|
|
189
|
+
return
|
|
190
|
+
backend = str(run_config.get("backend") or "").strip().lower()
|
|
191
|
+
if backend == "gpu":
|
|
192
|
+
local_backend = "local_gpu"
|
|
193
|
+
else:
|
|
194
|
+
local_backend = "local_cpu"
|
|
195
|
+
run_config.setdefault("analysis_backend", local_backend)
|
|
196
|
+
run_config.setdefault("local_analysis_backend", local_backend)
|
|
197
|
+
run_config.setdefault(
|
|
198
|
+
"backend_meaning",
|
|
199
|
+
"local analysis backend; not a simulator, QPU, or hardware execution backend",
|
|
200
|
+
)
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
def _sanitize(value: Any, *, redactions: set[str], key_path: tuple[str, ...]) -> Any:
|
|
204
|
+
key = key_path[-1] if key_path else ""
|
|
205
|
+
key_lower = key.lower()
|
|
206
|
+
if isinstance(value, dict):
|
|
207
|
+
out: dict[str, Any] = {}
|
|
208
|
+
for child_key, child_value in value.items():
|
|
209
|
+
child_key_str = str(child_key)
|
|
210
|
+
if child_key_str.lower() in _RAW_KEYS:
|
|
211
|
+
out[child_key_str] = _REDACTED_SENSITIVE_VALUE
|
|
212
|
+
redactions.add(f"field:{child_key_str}")
|
|
213
|
+
continue
|
|
214
|
+
out[child_key_str] = _sanitize(
|
|
215
|
+
child_value,
|
|
216
|
+
redactions=redactions,
|
|
217
|
+
key_path=key_path + (child_key_str,),
|
|
218
|
+
)
|
|
219
|
+
return out
|
|
220
|
+
if isinstance(value, list):
|
|
221
|
+
return [_sanitize(item, redactions=redactions, key_path=key_path) for item in value]
|
|
222
|
+
if isinstance(value, tuple):
|
|
223
|
+
return [_sanitize(item, redactions=redactions, key_path=key_path) for item in value]
|
|
224
|
+
if isinstance(value, str):
|
|
225
|
+
if key_lower in _PATH_KEYS:
|
|
226
|
+
redactions.add(f"field:{key}")
|
|
227
|
+
return _REDACTED_LOCAL_PATH
|
|
228
|
+
return _sanitize_text(value, redactions=redactions)
|
|
229
|
+
return value
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
def _sanitize_text(text: str, *, redactions: set[str]) -> str:
|
|
233
|
+
out = text
|
|
234
|
+
for marker in _FORBIDDEN_TEXT_MARKERS:
|
|
235
|
+
if marker in out:
|
|
236
|
+
out = out.replace(marker, _REDACTED_SENSITIVE_VALUE)
|
|
237
|
+
redactions.add("raw_or_sensitive_text")
|
|
238
|
+
|
|
239
|
+
def _path_repl(match: re.Match[str]) -> str:
|
|
240
|
+
redactions.add("absolute_path")
|
|
241
|
+
return _REDACTED_LOCAL_PATH
|
|
242
|
+
|
|
243
|
+
out = _LOCAL_PATH_RE.sub(_path_repl, out)
|
|
244
|
+
|
|
245
|
+
def _token_repl(match: re.Match[str]) -> str:
|
|
246
|
+
redactions.add("token_or_header_like_text")
|
|
247
|
+
return _REDACTED_SENSITIVE_VALUE
|
|
248
|
+
|
|
249
|
+
out = _TOKEN_LIKE_RE.sub(_token_repl, out)
|
|
250
|
+
return out
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
def _stable_string(value: Any) -> str:
|
|
254
|
+
try:
|
|
255
|
+
import json
|
|
256
|
+
|
|
257
|
+
return json.dumps(value, sort_keys=True, ensure_ascii=False)
|
|
258
|
+
except Exception:
|
|
259
|
+
return str(value)
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
def contains_local_path(text: str) -> bool:
|
|
263
|
+
return bool(_LOCAL_PATH_RE.search(text))
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
def contains_token_or_header(text: str) -> bool:
|
|
267
|
+
return bool(_TOKEN_LIKE_RE.search(text))
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
def contains_raw_qasm_marker(text: str) -> bool:
|
|
271
|
+
return any(marker in text for marker in ("OPENQASM 2.0", "OPENQASM 3.0", "qreg ", "creg "))
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
def is_probable_absolute_path(value: str) -> bool:
|
|
275
|
+
try:
|
|
276
|
+
return PurePath(value).is_absolute() or contains_local_path(value)
|
|
277
|
+
except Exception:
|
|
278
|
+
return False
|
|
@@ -88,6 +88,8 @@ def build_context_bundle(
|
|
|
88
88
|
return {
|
|
89
89
|
"context_bundle_schema_version": "0.1",
|
|
90
90
|
"artifact_type": "qcoder.preflight_context",
|
|
91
|
+
"qcoder_product_path": "oss",
|
|
92
|
+
"artifact_role": "local_preflight_context",
|
|
91
93
|
"basis": context_bundle_basis(analysis),
|
|
92
94
|
"generated_utc": generated_utc or utc_now_iso(),
|
|
93
95
|
"qcoder_version": qcoder_version,
|
|
@@ -106,4 +108,3 @@ def build_context_bundle(
|
|
|
106
108
|
"limits": llm_limits,
|
|
107
109
|
},
|
|
108
110
|
}
|
|
109
|
-
|
|
@@ -2,6 +2,8 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
from typing import Any
|
|
4
4
|
|
|
5
|
+
from qcoder.core.share_safe import render_share_safe_note, render_share_safe_provenance
|
|
6
|
+
|
|
5
7
|
|
|
6
8
|
def _fmt_num(value: Any) -> str:
|
|
7
9
|
if isinstance(value, float) and value.is_integer():
|
|
@@ -24,6 +26,11 @@ def render_context_markdown(bundle: dict[str, Any]) -> str:
|
|
|
24
26
|
|
|
25
27
|
lines.append("# qCoder Preflight Context")
|
|
26
28
|
lines.append("")
|
|
29
|
+
if bundle.get("share_safe") is True:
|
|
30
|
+
lines.append(render_share_safe_note().strip())
|
|
31
|
+
lines.append("")
|
|
32
|
+
lines.append(render_share_safe_provenance(bundle).strip())
|
|
33
|
+
lines.append("")
|
|
27
34
|
lines.append("## Purpose")
|
|
28
35
|
lines.append("Deterministic pre-execution context artifact for planning and review.")
|
|
29
36
|
lines.append("")
|
|
@@ -121,4 +128,3 @@ def render_context_markdown(bundle: dict[str, Any]) -> str:
|
|
|
121
128
|
lines.append(bundle.get("llm_use", {}).get("intended_use", ""))
|
|
122
129
|
lines.append("")
|
|
123
130
|
return "\n".join(lines)
|
|
124
|
-
|
|
@@ -50,6 +50,7 @@ def build_review_bundle(
|
|
|
50
50
|
counts_v0: dict[str, Any],
|
|
51
51
|
preflight_context: dict[str, Any] | None = None,
|
|
52
52
|
preflight_context_path: str | None = None,
|
|
53
|
+
qcoder_version: str | None = None,
|
|
53
54
|
generated_utc: str | None = None,
|
|
54
55
|
) -> dict[str, Any]:
|
|
55
56
|
counts = counts_v0.get("counts", {})
|
|
@@ -193,6 +194,9 @@ def build_review_bundle(
|
|
|
193
194
|
return {
|
|
194
195
|
"review_bundle_schema_version": "0.1",
|
|
195
196
|
"artifact_type": "qcoder.execution_review",
|
|
197
|
+
"qcoder_product_path": "oss",
|
|
198
|
+
"artifact_role": "local_execution_review",
|
|
199
|
+
"qcoder_version": qcoder_version,
|
|
196
200
|
"basis": "deterministic_counts_review",
|
|
197
201
|
"generated_utc": generated_utc or utc_now_iso(),
|
|
198
202
|
"inputs": {
|
|
@@ -228,4 +232,3 @@ def build_review_bundle(
|
|
|
228
232
|
],
|
|
229
233
|
},
|
|
230
234
|
}
|
|
231
|
-
|
|
@@ -2,6 +2,8 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
from typing import Any
|
|
4
4
|
|
|
5
|
+
from qcoder.core.share_safe import render_share_safe_note, render_share_safe_provenance
|
|
6
|
+
|
|
5
7
|
|
|
6
8
|
def render_review_markdown(bundle: dict[str, Any]) -> str:
|
|
7
9
|
lines: list[str] = []
|
|
@@ -14,6 +16,11 @@ def render_review_markdown(bundle: dict[str, Any]) -> str:
|
|
|
14
16
|
|
|
15
17
|
lines.append("# qCoder Execution Review")
|
|
16
18
|
lines.append("")
|
|
19
|
+
if bundle.get("share_safe") is True:
|
|
20
|
+
lines.append(render_share_safe_note().strip())
|
|
21
|
+
lines.append("")
|
|
22
|
+
lines.append(render_share_safe_provenance(bundle).strip())
|
|
23
|
+
lines.append("")
|
|
17
24
|
lines.append("## Purpose")
|
|
18
25
|
lines.append("Deterministic post-execution review artifact from provided counts.")
|
|
19
26
|
lines.append("Counts are user-provided; qCoder did not execute the circuit.")
|
|
@@ -107,4 +114,3 @@ def render_review_markdown(bundle: dict[str, Any]) -> str:
|
|
|
107
114
|
lines.append(bundle.get("llm_use", {}).get("intended_use", ""))
|
|
108
115
|
lines.append("")
|
|
109
116
|
return "\n".join(lines)
|
|
110
|
-
|
|
@@ -2,12 +2,20 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
import hashlib
|
|
4
4
|
from dataclasses import dataclass
|
|
5
|
+
from importlib.metadata import PackageNotFoundError, version
|
|
5
6
|
from pathlib import Path
|
|
6
7
|
|
|
7
8
|
from qcoder.core.run_config import RunConfig
|
|
8
9
|
from qcoder.engines.feature_extraction.extractor import CircuitExample, extract_example
|
|
9
10
|
|
|
10
11
|
|
|
12
|
+
def _qcoder_version() -> str:
|
|
13
|
+
try:
|
|
14
|
+
return version("qcoder")
|
|
15
|
+
except PackageNotFoundError:
|
|
16
|
+
return "0+unknown"
|
|
17
|
+
|
|
18
|
+
|
|
11
19
|
@dataclass(frozen=True)
|
|
12
20
|
class AnalyzeReport:
|
|
13
21
|
example: CircuitExample
|
|
@@ -19,6 +27,9 @@ class AnalyzeReport:
|
|
|
19
27
|
fv = ex.global_features
|
|
20
28
|
feature_map = dict(zip(fv.feature_names, fv.features))
|
|
21
29
|
out = {
|
|
30
|
+
"qcoder_product_path": "oss",
|
|
31
|
+
"artifact_role": "local_analysis_report",
|
|
32
|
+
"qcoder_version": _qcoder_version(),
|
|
22
33
|
"circuit_id": ex.id,
|
|
23
34
|
"circuit_name": ex.name,
|
|
24
35
|
"function_hint": ex.function_hint,
|
|
@@ -8,6 +8,7 @@ from typing import Any
|
|
|
8
8
|
from qcoder.engines.context.bundle import build_context_bundle
|
|
9
9
|
from qcoder.engines.context.markdown import render_context_markdown
|
|
10
10
|
from qcoder.pipelines.analyze import analyze_qasm
|
|
11
|
+
from qcoder.core.share_safe import make_share_safe_payload
|
|
11
12
|
|
|
12
13
|
|
|
13
14
|
def _qcoder_version() -> str:
|
|
@@ -49,6 +50,7 @@ def write_preflight_context(
|
|
|
49
50
|
include_full_features: bool = False,
|
|
50
51
|
circuit_id: str | None = None,
|
|
51
52
|
circuit_name: str | None = None,
|
|
53
|
+
share_safe: bool = False,
|
|
52
54
|
) -> dict[str, Any]:
|
|
53
55
|
bundle = build_preflight_context(
|
|
54
56
|
qasm_path,
|
|
@@ -58,6 +60,8 @@ def write_preflight_context(
|
|
|
58
60
|
circuit_id=circuit_id,
|
|
59
61
|
circuit_name=circuit_name,
|
|
60
62
|
)
|
|
63
|
+
if share_safe:
|
|
64
|
+
bundle = make_share_safe_payload(bundle)
|
|
61
65
|
out_json_path = Path(out_json)
|
|
62
66
|
out_md_path = Path(out_md)
|
|
63
67
|
out_json_path.parent.mkdir(parents=True, exist_ok=True)
|
|
@@ -65,4 +69,3 @@ def write_preflight_context(
|
|
|
65
69
|
out_json_path.write_text(json.dumps(bundle, indent=2, sort_keys=True), encoding="utf-8")
|
|
66
70
|
out_md_path.write_text(render_context_markdown(bundle), encoding="utf-8")
|
|
67
71
|
return bundle
|
|
68
|
-
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import json
|
|
4
|
+
from importlib.metadata import PackageNotFoundError, version
|
|
4
5
|
from pathlib import Path
|
|
5
6
|
from typing import Any
|
|
6
7
|
|
|
@@ -8,6 +9,14 @@ from qcoder.engines.review.bundle import build_review_bundle
|
|
|
8
9
|
from qcoder.engines.review.counts_v0 import normalize_counts_v0
|
|
9
10
|
from qcoder.engines.review.markdown import render_review_markdown
|
|
10
11
|
from qcoder.engines.review.qiskit_counts import normalize_qiskit_counts_payload
|
|
12
|
+
from qcoder.core.share_safe import make_share_safe_payload
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def _qcoder_version() -> str:
|
|
16
|
+
try:
|
|
17
|
+
return version("qcoder")
|
|
18
|
+
except PackageNotFoundError:
|
|
19
|
+
return "0+unknown"
|
|
11
20
|
|
|
12
21
|
|
|
13
22
|
def _load_json(path: str) -> dict[str, Any]:
|
|
@@ -37,6 +46,7 @@ def build_execution_review(
|
|
|
37
46
|
counts_v0=counts_v0,
|
|
38
47
|
preflight_context=preflight,
|
|
39
48
|
preflight_context_path=preflight_json,
|
|
49
|
+
qcoder_version=_qcoder_version(),
|
|
40
50
|
)
|
|
41
51
|
|
|
42
52
|
|
|
@@ -47,12 +57,15 @@ def write_execution_review(
|
|
|
47
57
|
out_json: str,
|
|
48
58
|
out_md: str,
|
|
49
59
|
preflight_json: str | None = None,
|
|
60
|
+
share_safe: bool = False,
|
|
50
61
|
) -> dict[str, Any]:
|
|
51
62
|
bundle = build_execution_review(
|
|
52
63
|
counts_json=counts_json,
|
|
53
64
|
counts_format=counts_format,
|
|
54
65
|
preflight_json=preflight_json,
|
|
55
66
|
)
|
|
67
|
+
if share_safe:
|
|
68
|
+
bundle = make_share_safe_payload(bundle)
|
|
56
69
|
out_json_path = Path(out_json)
|
|
57
70
|
out_md_path = Path(out_md)
|
|
58
71
|
out_json_path.parent.mkdir(parents=True, exist_ok=True)
|
|
@@ -60,4 +73,3 @@ def write_execution_review(
|
|
|
60
73
|
out_json_path.write_text(json.dumps(bundle, indent=2, sort_keys=True), encoding="utf-8")
|
|
61
74
|
out_md_path.write_text(render_review_markdown(bundle), encoding="utf-8")
|
|
62
75
|
return bundle
|
|
63
|
-
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: qcoder
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.0a6
|
|
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>
|
|
@@ -77,6 +77,16 @@ qcoder context path/to/circuit.qasm --out-json preflight.context.json --out-md p
|
|
|
77
77
|
qcoder review --counts-json counts.json --format qiskit_counts --preflight-json preflight.context.json --out-json execution.review.json --out-md execution.review.md
|
|
78
78
|
```
|
|
79
79
|
|
|
80
|
+
For artifacts you intend to paste into ChatGPT, Cursor, email, GitHub issues, or support threads, add `--share-safe`:
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
qcoder analyze path/to/circuit.qasm --json --share-safe
|
|
84
|
+
qcoder context path/to/circuit.qasm --out-json preflight.context.json --out-md preflight.context.md --share-safe
|
|
85
|
+
qcoder review --counts-json counts.json --format qiskit_counts --preflight-json preflight.context.json --out-json execution.review.json --out-md execution.review.md --share-safe
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Share-safe mode is designed for safer sharing: it redacts local paths and token/header-like strings, adds `share_safe=true`, and marks raw QASM/local paths/tokens as not included. Review artifacts before sharing; this is not a guarantee that all sensitive project content has been removed.
|
|
89
|
+
|
|
80
90
|
Explorer Beta compatibility checks and archived Pro bootstrap:
|
|
81
91
|
|
|
82
92
|
```bash
|
|
@@ -85,6 +95,7 @@ qcoder explorer demo
|
|
|
85
95
|
qcoder explorer evidence
|
|
86
96
|
qcoder explorer evidence --qasm path/to/circuit.qasm
|
|
87
97
|
qcoder explorer evidence --context-json preflight.context.json
|
|
98
|
+
qcoder explorer evidence --qasm path/to/circuit.qasm --out-json explorer.json --out-md explorer.md --share-safe
|
|
88
99
|
qcoder pro --help
|
|
89
100
|
```
|
|
90
101
|
|
|
@@ -17,6 +17,7 @@ src/qcoder/core/__init__.py
|
|
|
17
17
|
src/qcoder/core/context.py
|
|
18
18
|
src/qcoder/core/run_config.py
|
|
19
19
|
src/qcoder/core/schema.py
|
|
20
|
+
src/qcoder/core/share_safe.py
|
|
20
21
|
src/qcoder/core/qasm2/__init__.py
|
|
21
22
|
src/qcoder/core/qasm2/adjoint_eligibility.py
|
|
22
23
|
src/qcoder/core/qasm2/mirror_build.py
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{qcoder-0.5.0a5 → qcoder-0.5.0a6}/src/qcoder/engines/feature_extraction/adapters/__init__.py
RENAMED
|
File without changes
|
{qcoder-0.5.0a5 → qcoder-0.5.0a6}/src/qcoder/engines/feature_extraction/adapters/cirq_intake.py
RENAMED
|
File without changes
|
{qcoder-0.5.0a5 → qcoder-0.5.0a6}/src/qcoder/engines/feature_extraction/adapters/pennylane_intake.py
RENAMED
|
File without changes
|
{qcoder-0.5.0a5 → qcoder-0.5.0a6}/src/qcoder/engines/feature_extraction/adapters/qiskit_intake.py
RENAMED
|
File without changes
|
|
File without changes
|
{qcoder-0.5.0a5 → qcoder-0.5.0a6}/src/qcoder/engines/feature_extraction/features/compute_v0.py
RENAMED
|
File without changes
|
{qcoder-0.5.0a5 → qcoder-0.5.0a6}/src/qcoder/engines/feature_extraction/features/glossary_v0.py
RENAMED
|
File without changes
|
{qcoder-0.5.0a5 → qcoder-0.5.0a6}/src/qcoder/engines/feature_extraction/features/schema_v0.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{qcoder-0.5.0a5 → qcoder-0.5.0a6}/src/qcoder/engines/feature_extraction/qasm2_regex_parser.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{qcoder-0.5.0a5 → qcoder-0.5.0a6}/src/qcoder/engines/feature_extraction/reps/entangling_layers.py
RENAMED
|
File without changes
|
{qcoder-0.5.0a5 → qcoder-0.5.0a6}/src/qcoder/engines/feature_extraction/reps/gate_set_stats.py
RENAMED
|
File without changes
|
{qcoder-0.5.0a5 → qcoder-0.5.0a6}/src/qcoder/engines/feature_extraction/reps/interaction_graph.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|