qcoder 0.5.0a2__tar.gz → 0.5.0a3__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 (69) hide show
  1. {qcoder-0.5.0a2 → qcoder-0.5.0a3}/CHANGELOG.md +8 -0
  2. {qcoder-0.5.0a2 → qcoder-0.5.0a3}/PKG-INFO +26 -3
  3. {qcoder-0.5.0a2 → qcoder-0.5.0a3}/README.md +25 -2
  4. {qcoder-0.5.0a2 → qcoder-0.5.0a3}/pyproject.toml +1 -1
  5. {qcoder-0.5.0a2 → qcoder-0.5.0a3}/src/qcoder/__init__.py +1 -1
  6. {qcoder-0.5.0a2 → qcoder-0.5.0a3}/src/qcoder/cli.py +118 -13
  7. {qcoder-0.5.0a2 → qcoder-0.5.0a3}/src/qcoder/pro_preview/__init__.py +18 -3
  8. {qcoder-0.5.0a2 → qcoder-0.5.0a3}/src/qcoder/pro_preview/client.py +96 -1
  9. {qcoder-0.5.0a2 → qcoder-0.5.0a3}/src/qcoder.egg-info/PKG-INFO +26 -3
  10. {qcoder-0.5.0a2 → qcoder-0.5.0a3}/LICENSE +0 -0
  11. {qcoder-0.5.0a2 → qcoder-0.5.0a3}/MANIFEST.in +0 -0
  12. {qcoder-0.5.0a2 → qcoder-0.5.0a3}/NOTICE +0 -0
  13. {qcoder-0.5.0a2 → qcoder-0.5.0a3}/setup.cfg +0 -0
  14. {qcoder-0.5.0a2 → qcoder-0.5.0a3}/src/qcoder/__main__.py +0 -0
  15. {qcoder-0.5.0a2 → qcoder-0.5.0a3}/src/qcoder/core/__init__.py +0 -0
  16. {qcoder-0.5.0a2 → qcoder-0.5.0a3}/src/qcoder/core/context.py +0 -0
  17. {qcoder-0.5.0a2 → qcoder-0.5.0a3}/src/qcoder/core/qasm2/__init__.py +0 -0
  18. {qcoder-0.5.0a2 → qcoder-0.5.0a3}/src/qcoder/core/qasm2/adjoint_eligibility.py +0 -0
  19. {qcoder-0.5.0a2 → qcoder-0.5.0a3}/src/qcoder/core/qasm2/mirror_build.py +0 -0
  20. {qcoder-0.5.0a2 → qcoder-0.5.0a3}/src/qcoder/core/run_config.py +0 -0
  21. {qcoder-0.5.0a2 → qcoder-0.5.0a3}/src/qcoder/core/schema.py +0 -0
  22. {qcoder-0.5.0a2 → qcoder-0.5.0a3}/src/qcoder/engines/context/__init__.py +0 -0
  23. {qcoder-0.5.0a2 → qcoder-0.5.0a3}/src/qcoder/engines/context/bundle.py +0 -0
  24. {qcoder-0.5.0a2 → qcoder-0.5.0a3}/src/qcoder/engines/context/markdown.py +0 -0
  25. {qcoder-0.5.0a2 → qcoder-0.5.0a3}/src/qcoder/engines/feature_extraction/adapters/__init__.py +0 -0
  26. {qcoder-0.5.0a2 → qcoder-0.5.0a3}/src/qcoder/engines/feature_extraction/adapters/cirq_intake.py +0 -0
  27. {qcoder-0.5.0a2 → qcoder-0.5.0a3}/src/qcoder/engines/feature_extraction/adapters/pennylane_intake.py +0 -0
  28. {qcoder-0.5.0a2 → qcoder-0.5.0a3}/src/qcoder/engines/feature_extraction/adapters/qiskit_intake.py +0 -0
  29. {qcoder-0.5.0a2 → qcoder-0.5.0a3}/src/qcoder/engines/feature_extraction/extractor.py +0 -0
  30. {qcoder-0.5.0a2 → qcoder-0.5.0a3}/src/qcoder/engines/feature_extraction/features/compute_v0.py +0 -0
  31. {qcoder-0.5.0a2 → qcoder-0.5.0a3}/src/qcoder/engines/feature_extraction/features/glossary_v0.py +0 -0
  32. {qcoder-0.5.0a2 → qcoder-0.5.0a3}/src/qcoder/engines/feature_extraction/features/schema_v0.py +0 -0
  33. {qcoder-0.5.0a2 → qcoder-0.5.0a3}/src/qcoder/engines/feature_extraction/ir.py +0 -0
  34. {qcoder-0.5.0a2 → qcoder-0.5.0a3}/src/qcoder/engines/feature_extraction/labeling.py +0 -0
  35. {qcoder-0.5.0a2 → qcoder-0.5.0a3}/src/qcoder/engines/feature_extraction/parsers/__init__.py +0 -0
  36. {qcoder-0.5.0a2 → qcoder-0.5.0a3}/src/qcoder/engines/feature_extraction/qasm2_regex_parser.py +0 -0
  37. {qcoder-0.5.0a2 → qcoder-0.5.0a3}/src/qcoder/engines/feature_extraction/reps/cut_profile.py +0 -0
  38. {qcoder-0.5.0a2 → qcoder-0.5.0a3}/src/qcoder/engines/feature_extraction/reps/depth.py +0 -0
  39. {qcoder-0.5.0a2 → qcoder-0.5.0a3}/src/qcoder/engines/feature_extraction/reps/entangling_layers.py +0 -0
  40. {qcoder-0.5.0a2 → qcoder-0.5.0a3}/src/qcoder/engines/feature_extraction/reps/gate_set_stats.py +0 -0
  41. {qcoder-0.5.0a2 → qcoder-0.5.0a3}/src/qcoder/engines/feature_extraction/reps/interaction_graph.py +0 -0
  42. {qcoder-0.5.0a2 → qcoder-0.5.0a3}/src/qcoder/engines/feature_extraction/reps/interaction_graph_metrics.py +0 -0
  43. {qcoder-0.5.0a2 → qcoder-0.5.0a3}/src/qcoder/engines/feature_extraction/reps/spans.py +0 -0
  44. {qcoder-0.5.0a2 → qcoder-0.5.0a3}/src/qcoder/engines/guidance/__init__.py +0 -0
  45. {qcoder-0.5.0a2 → qcoder-0.5.0a3}/src/qcoder/engines/guidance/model_pack.py +0 -0
  46. {qcoder-0.5.0a2 → qcoder-0.5.0a3}/src/qcoder/engines/guidance/resource.py +0 -0
  47. {qcoder-0.5.0a2 → qcoder-0.5.0a3}/src/qcoder/engines/guidance/structural_scores.py +0 -0
  48. {qcoder-0.5.0a2 → qcoder-0.5.0a3}/src/qcoder/engines/profiles/__init__.py +0 -0
  49. {qcoder-0.5.0a2 → qcoder-0.5.0a3}/src/qcoder/engines/profiles/feature_profiles_v0.py +0 -0
  50. {qcoder-0.5.0a2 → qcoder-0.5.0a3}/src/qcoder/engines/review/__init__.py +0 -0
  51. {qcoder-0.5.0a2 → qcoder-0.5.0a3}/src/qcoder/engines/review/bundle.py +0 -0
  52. {qcoder-0.5.0a2 → qcoder-0.5.0a3}/src/qcoder/engines/review/counts_v0.py +0 -0
  53. {qcoder-0.5.0a2 → qcoder-0.5.0a3}/src/qcoder/engines/review/markdown.py +0 -0
  54. {qcoder-0.5.0a2 → qcoder-0.5.0a3}/src/qcoder/engines/review/qiskit_counts.py +0 -0
  55. {qcoder-0.5.0a2 → qcoder-0.5.0a3}/src/qcoder/model_packs/__init__.py +0 -0
  56. {qcoder-0.5.0a2 → qcoder-0.5.0a3}/src/qcoder/model_packs/resource_guidance_local_v0.json +0 -0
  57. {qcoder-0.5.0a2 → qcoder-0.5.0a3}/src/qcoder/pipelines/analyze.py +0 -0
  58. {qcoder-0.5.0a2 → qcoder-0.5.0a3}/src/qcoder/pipelines/batch.py +0 -0
  59. {qcoder-0.5.0a2 → qcoder-0.5.0a3}/src/qcoder/pipelines/context.py +0 -0
  60. {qcoder-0.5.0a2 → qcoder-0.5.0a3}/src/qcoder/pipelines/review.py +0 -0
  61. {qcoder-0.5.0a2 → qcoder-0.5.0a3}/src/qcoder/pro_preview/config.py +0 -0
  62. {qcoder-0.5.0a2 → qcoder-0.5.0a3}/src/qcoder/pro_preview/errors.py +0 -0
  63. {qcoder-0.5.0a2 → qcoder-0.5.0a3}/src/qcoder/pro_preview/manifest.py +0 -0
  64. {qcoder-0.5.0a2 → qcoder-0.5.0a3}/src/qcoder/tools/batch.py +0 -0
  65. {qcoder-0.5.0a2 → qcoder-0.5.0a3}/src/qcoder.egg-info/SOURCES.txt +0 -0
  66. {qcoder-0.5.0a2 → qcoder-0.5.0a3}/src/qcoder.egg-info/dependency_links.txt +0 -0
  67. {qcoder-0.5.0a2 → qcoder-0.5.0a3}/src/qcoder.egg-info/entry_points.txt +0 -0
  68. {qcoder-0.5.0a2 → qcoder-0.5.0a3}/src/qcoder.egg-info/requires.txt +0 -0
  69. {qcoder-0.5.0a2 → qcoder-0.5.0a3}/src/qcoder.egg-info/top_level.txt +0 -0
@@ -1,5 +1,13 @@
1
1
  # Changelog
2
2
 
3
+
4
+ ## 0.5.0a3
5
+
6
+ - Add public hosted Preview client commands: `qcoder pro preview status` and `qcoder pro preview demo`.
7
+ - Support env-based hosted Preview configuration with `QCODER_PREVIEW_BASE_URL` / `QCODER_PREVIEW_TOKEN`, with `QCODER_PRO_API_URL` / `QCODER_PRO_TOKEN` compatibility fallbacks.
8
+ - Keep hosted Preview output bounded and token-safe: no token persistence, no Authorization header printing, and safe handling for 200/401/403/network failures.
9
+ - Preserve public package boundary: no confidential Pro implementation, account service, protected service, uploads, QPU/provider execution, payment, hosted MCP, or Pro V0.0 launch claim is included in this package.
10
+
3
11
  All notable changes to this project will be documented in this file.
4
12
 
5
13
  The format is based on common practice for pre-1.0 semantic versioning: **`MAJOR.MINOR.PATCH`** with **`aN`** for alpha prereleases.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: qcoder
3
- Version: 0.5.0a2
3
+ Version: 0.5.0a3
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>
@@ -46,11 +46,13 @@ Free `qcoder` commands run offline and do not call hosted services, upload telem
46
46
 
47
47
  Public `qcoder` ships **Free local commands** plus a **Pro bootstrap/client contract**. It is **not** the sellable hosted Pro product.
48
48
 
49
- - **Free commands** (`analyze`, `batch`, `context`, `review`) run offline. They do not upload data, call a qCoder hosted service, or run QPU/simulator jobs.
49
+ For a public, pilot-safe walkthrough, see the [Pro Preview pilot walkthrough](https://qcoder.ai/manual/pro-preview-pilot-walkthrough/). The current public PyPI alpha client surface for Pro Preview is **`qcoder==0.5.0a2`**. It is not Pro V0.0 and not a sellable launched Pro product.
50
+
51
+ - **Free commands** (`analyze`, `batch`, `context`, `review`) are Apache-2.0, local-first/offline, and useful without Pro. They do not upload data, call a qCoder hosted service, or run QPU/simulator jobs.
50
52
  - **`qcoder pro` bootstrap** (`signup`, `login`, `install`, `status`, `validate`) stores local token/config only. It does not upload circuits, run confidential analysis, or generate Pro cards locally.
51
53
  - **`qcoder pro workflow --dry-run-manifest`** writes a local JSON contract (`qcoder.pro_preview.workflow_manifest.v0`) and performs **no network calls**. This is the default path for most users.
52
54
  - **`qcoder pro workflow --submit`** posts a **sanitized manifest only** to an **explicitly configured** `--service-url` (or `QCODER_PRO_API_URL`). Use it only when QRS has given you a service URL and token. The default `https://qcoder.ai/preview` URL is **not** accepted for submit.
53
- - There is **no generally available production hosted Pro service**, account/token issuance, or artifact upload in this public-main surface. Production hosted service, Cloud Run/GCS, and confidential analysis are separate/future.
55
+ - There is **no generally available production hosted Pro service**, account/token issuance, artifact/source upload, telemetry/training ingest, confidential local analyzer/cards, QPU/provider execution, or launched Pro V0.0 behavior in this public-main surface.
54
56
  - **No confidential Pro analysis or cards** are bundled in this package. Token-gating is **access control only**, not a secrecy boundary.
55
57
 
56
58
  ## Quick start
@@ -91,6 +93,27 @@ Use **`--dry-run-manifest`** unless QRS has given you a non-default service URL
91
93
  qcoder pro workflow --qasm path/to/circuit.qasm --submit --service-url <url-qrs-provided>
92
94
  ```
93
95
 
96
+ **Support-safe checklist for Pro Preview pilots**
97
+
98
+ Safe to share with QRS support:
99
+
100
+ - `qcoder --version`
101
+ - command name
102
+ - HTTP status or CLI error code
103
+ - `job_id`, if produced
104
+ - redacted output
105
+ - manifest schema/version
106
+
107
+ Do not share:
108
+
109
+ - bearer tokens
110
+ - secrets
111
+ - source code
112
+ - repository archives
113
+ - notebooks
114
+ - private prompts or chat transcripts
115
+ - raw QASM/source artifacts through unsupported paths
116
+
94
117
  Architecture notes: [`docs/architecture.md`](docs/architecture.md).
95
118
 
96
119
  ## Optional extras
@@ -16,11 +16,13 @@ Free `qcoder` commands run offline and do not call hosted services, upload telem
16
16
 
17
17
  Public `qcoder` ships **Free local commands** plus a **Pro bootstrap/client contract**. It is **not** the sellable hosted Pro product.
18
18
 
19
- - **Free commands** (`analyze`, `batch`, `context`, `review`) run offline. They do not upload data, call a qCoder hosted service, or run QPU/simulator jobs.
19
+ For a public, pilot-safe walkthrough, see the [Pro Preview pilot walkthrough](https://qcoder.ai/manual/pro-preview-pilot-walkthrough/). The current public PyPI alpha client surface for Pro Preview is **`qcoder==0.5.0a2`**. It is not Pro V0.0 and not a sellable launched Pro product.
20
+
21
+ - **Free commands** (`analyze`, `batch`, `context`, `review`) are Apache-2.0, local-first/offline, and useful without Pro. They do not upload data, call a qCoder hosted service, or run QPU/simulator jobs.
20
22
  - **`qcoder pro` bootstrap** (`signup`, `login`, `install`, `status`, `validate`) stores local token/config only. It does not upload circuits, run confidential analysis, or generate Pro cards locally.
21
23
  - **`qcoder pro workflow --dry-run-manifest`** writes a local JSON contract (`qcoder.pro_preview.workflow_manifest.v0`) and performs **no network calls**. This is the default path for most users.
22
24
  - **`qcoder pro workflow --submit`** posts a **sanitized manifest only** to an **explicitly configured** `--service-url` (or `QCODER_PRO_API_URL`). Use it only when QRS has given you a service URL and token. The default `https://qcoder.ai/preview` URL is **not** accepted for submit.
23
- - There is **no generally available production hosted Pro service**, account/token issuance, or artifact upload in this public-main surface. Production hosted service, Cloud Run/GCS, and confidential analysis are separate/future.
25
+ - There is **no generally available production hosted Pro service**, account/token issuance, artifact/source upload, telemetry/training ingest, confidential local analyzer/cards, QPU/provider execution, or launched Pro V0.0 behavior in this public-main surface.
24
26
  - **No confidential Pro analysis or cards** are bundled in this package. Token-gating is **access control only**, not a secrecy boundary.
25
27
 
26
28
  ## Quick start
@@ -61,6 +63,27 @@ Use **`--dry-run-manifest`** unless QRS has given you a non-default service URL
61
63
  qcoder pro workflow --qasm path/to/circuit.qasm --submit --service-url <url-qrs-provided>
62
64
  ```
63
65
 
66
+ **Support-safe checklist for Pro Preview pilots**
67
+
68
+ Safe to share with QRS support:
69
+
70
+ - `qcoder --version`
71
+ - command name
72
+ - HTTP status or CLI error code
73
+ - `job_id`, if produced
74
+ - redacted output
75
+ - manifest schema/version
76
+
77
+ Do not share:
78
+
79
+ - bearer tokens
80
+ - secrets
81
+ - source code
82
+ - repository archives
83
+ - notebooks
84
+ - private prompts or chat transcripts
85
+ - raw QASM/source artifacts through unsupported paths
86
+
64
87
  Architecture notes: [`docs/architecture.md`](docs/architecture.md).
65
88
 
66
89
  ## Optional extras
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "qcoder"
7
- version = "0.5.0a2"
7
+ version = "0.5.0a3"
8
8
  description = "Quantum circuit analysis and structured feature extraction tools."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
@@ -1,3 +1,3 @@
1
1
  __all__ = []
2
- __version__ = "0.5.0a2"
2
+ __version__ = "0.5.0a3"
3
3
  file = __file__
@@ -17,6 +17,12 @@ from qcoder.pro_preview.config import (
17
17
  store_local_bootstrap_config,
18
18
  )
19
19
  from qcoder.pro_preview.client import ProServiceClient, ProServiceClientError
20
+ from qcoder.pro_preview.client import (
21
+ PreviewClientNetworkError,
22
+ call_builtin_review_demo,
23
+ resolve_preview_client_config,
24
+ summarize_demo_payload,
25
+ )
20
26
  from qcoder.pro_preview.errors import ProPreviewManifestError
21
27
  from qcoder.pro_preview.manifest import (
22
28
  build_workflow_manifest,
@@ -28,6 +34,12 @@ from qcoder.tools.batch import analyze_qasm_dir_to_jsonl
28
34
  PREVIEW_SIGNUP_URL = "https://qcoder.ai/preview"
29
35
 
30
36
 
37
+ def _is_non_default_service_url(value: str | None) -> bool:
38
+ if not value:
39
+ return False
40
+ return value.strip() != DEFAULT_PRO_API_URL
41
+
42
+
31
43
  def _build_pro_bootstrap_payload(status: str) -> dict[str, object]:
32
44
  token = resolve_token()
33
45
  api_url = resolve_api_url()
@@ -242,6 +254,48 @@ def _cmd_review(argv: list[str]) -> int:
242
254
  return 0
243
255
 
244
256
 
257
+ def _run_pro_preview_demo_check(*, base_url_override: str | None) -> int:
258
+ try:
259
+ config = resolve_preview_client_config(base_url_override=base_url_override)
260
+ except ValueError as exc:
261
+ print(f"qcoder pro preview: {exc}", file=sys.stderr)
262
+ return 2
263
+
264
+ try:
265
+ response = call_builtin_review_demo(config)
266
+ except PreviewClientNetworkError:
267
+ print(
268
+ "qCoder Pro Preview demo: FAIL (network). Base URL may be unreachable.",
269
+ file=sys.stderr,
270
+ )
271
+ print(f" base_url: {config.base_url}", file=sys.stderr)
272
+ return 2
273
+
274
+ if response.status_code == 200:
275
+ print("qCoder Pro Preview demo: PASS (HTTP 200).")
276
+ print(f" base_url: {config.base_url}")
277
+ for line in summarize_demo_payload(response.payload):
278
+ print(f" {line}")
279
+ return 0
280
+ if response.status_code == 401:
281
+ print(
282
+ "qCoder Pro Preview demo: FAIL (HTTP 401). Token is missing, invalid, or revoked.",
283
+ file=sys.stderr,
284
+ )
285
+ return 1
286
+ if response.status_code == 403:
287
+ print(
288
+ "qCoder Pro Preview demo: FAIL (HTTP 403). Private/outer service access may be blocking access.",
289
+ file=sys.stderr,
290
+ )
291
+ return 1
292
+
293
+ print(f"qCoder Pro Preview demo: FAIL (HTTP {response.status_code}).", file=sys.stderr)
294
+ for line in summarize_demo_payload(response.payload):
295
+ print(f" {line}", file=sys.stderr)
296
+ return 2
297
+
298
+
245
299
  def _cmd_pro(argv: list[str]) -> int:
246
300
  p = argparse.ArgumentParser(
247
301
  prog="qcoder pro",
@@ -265,16 +319,24 @@ def _cmd_pro(argv: list[str]) -> int:
265
319
  p_status.set_defaults(pro_command="status")
266
320
 
267
321
  p_login = sub.add_parser("login", help="Store Preview token locally (no remote validation in this slice).")
268
- p_login.add_argument("--token", required=True, help="Preview token for local entitlement/config bootstrap.")
322
+ p_login.add_argument(
323
+ "--token",
324
+ required=True,
325
+ help="QRS-provided Preview token for local config. Treat as private credential.",
326
+ )
269
327
  p_login.add_argument("--api-url", required=False, help="Optional service URL override for local config.")
270
328
  p_login.set_defaults(pro_command="login")
271
329
 
272
- p_install = sub.add_parser("install", help="Configure local Pro bootstrap token (no code download in this slice).")
273
- p_install.add_argument("--token", required=True, help="Preview token for local bootstrap config.")
330
+ p_install = sub.add_parser("install", help="Configure local Pro Preview token (no code download in this slice).")
331
+ p_install.add_argument(
332
+ "--token",
333
+ required=True,
334
+ help="QRS-provided Preview token for local config. Treat as private credential.",
335
+ )
274
336
  p_install.add_argument("--api-url", required=False, help="Optional service URL override for local config.")
275
337
  p_install.set_defaults(pro_command="install")
276
338
 
277
- p_validate = sub.add_parser("validate", help="Validate local Pro bootstrap config and public boundary posture.")
339
+ p_validate = sub.add_parser("validate", help="Validate local Pro Preview config and public package boundaries.")
278
340
  p_validate.set_defaults(pro_command="validate")
279
341
 
280
342
  p_workflow = sub.add_parser(
@@ -307,6 +369,31 @@ def _cmd_pro(argv: list[str]) -> int:
307
369
  )
308
370
  p_workflow.set_defaults(pro_command="workflow")
309
371
 
372
+ p_preview = sub.add_parser("preview", help="Hosted Preview demo connectivity checks.")
373
+ p_preview_sub = p_preview.add_subparsers(dest="pro_preview_command")
374
+
375
+ p_preview_status = p_preview_sub.add_parser(
376
+ "status",
377
+ help="Call hosted Preview demo endpoint and print safe connectivity summary.",
378
+ )
379
+ p_preview_status.add_argument(
380
+ "--base-url",
381
+ default=None,
382
+ help="Override hosted Preview base URL (default env: QCODER_PREVIEW_BASE_URL or QCODER_PRO_API_URL).",
383
+ )
384
+ p_preview_status.set_defaults(pro_command="preview-status")
385
+
386
+ p_preview_demo = p_preview_sub.add_parser(
387
+ "demo",
388
+ help="Alias of preview status check; calls /v0/demo/builtin-review.",
389
+ )
390
+ p_preview_demo.add_argument(
391
+ "--base-url",
392
+ default=None,
393
+ help="Override hosted Preview base URL (default env: QCODER_PREVIEW_BASE_URL or QCODER_PRO_API_URL).",
394
+ )
395
+ p_preview_demo.set_defaults(pro_command="preview-demo")
396
+
310
397
  args, unknown = p.parse_known_args(argv)
311
398
  cmd = args.pro_command
312
399
  json_output = args.json or ("--json" in unknown)
@@ -335,16 +422,20 @@ def _cmd_pro(argv: list[str]) -> int:
335
422
 
336
423
  if cmd == "status":
337
424
  payload = _build_pro_bootstrap_payload(status="configured" if resolve_token().present else "not_configured")
425
+ submit_ready = bool(payload["token_present"]) and _is_non_default_service_url(resolve_api_url().value)
338
426
  if json_output:
339
427
  print(json.dumps(payload, indent=2, sort_keys=True))
340
428
  else:
341
429
  print(f"qCoder Pro status: {payload['status']}.")
342
430
  print(" mode: service-backed bootstrap shell")
343
431
  print(f" token: {'present' if payload['token_present'] else 'not set'} ({payload['token_source']})")
344
- print(
345
- f" api_url: {'configured' if payload['api_url_configured'] else 'not set'} "
346
- f"({payload['api_url_source']})"
347
- )
432
+ if payload["api_url_source"] == "default":
433
+ print(" submit-ready service URL: not set (default Preview URL is informational)")
434
+ else:
435
+ print(" submit-ready service URL: configured")
436
+ print(f" service URL source: {payload['api_url_source']}")
437
+ print(f" pilot submit readiness: {'ready' if submit_ready else 'not ready'}")
438
+ print(" submit requirement: QRS-provided token + non-default service URL")
348
439
  print(" service validation: not available in this slice")
349
440
  print(" local cards/analysis: disabled in public package")
350
441
  print(f" signup: {PREVIEW_SIGNUP_URL}")
@@ -362,10 +453,11 @@ def _cmd_pro(argv: list[str]) -> int:
362
453
  if json_output:
363
454
  print(json.dumps(payload, indent=2, sort_keys=True))
364
455
  else:
365
- print("Configured qCoder Pro Preview/V0 local bootstrap.")
456
+ print("Configured qCoder Pro Preview local token settings.")
366
457
  print(f" operation: {cmd}")
367
458
  print(f" config: {config_path}")
368
459
  print(" token: stored locally (not displayed)")
460
+ print(" token hygiene: do not paste tokens into tickets, screenshots, or chat")
369
461
  print(" service validation: not performed in this slice")
370
462
  print(" upload: none performed")
371
463
  print(" local package: non-confidential bootstrap plumbing only")
@@ -381,6 +473,7 @@ def _cmd_pro(argv: list[str]) -> int:
381
473
  except ProPreviewConfigError:
382
474
  local_config_valid = False
383
475
  pro_v0_py_exists = any((Path(__file__).resolve().parent / "pro_v0").glob("*.py"))
476
+ submit_ready = token.present and _is_non_default_service_url(api_url.value)
384
477
  payload = {
385
478
  "schema_id": "qcoder.pro_preview_validate.v0",
386
479
  "status": "ok" if local_config_valid else "config_error",
@@ -403,12 +496,22 @@ def _cmd_pro(argv: list[str]) -> int:
403
496
  print("qCoder Pro validate")
404
497
  print(f" status: {payload['status']}")
405
498
  print(f" token: {'present' if token.present else 'not set'} ({token.source})")
406
- print(f" api_url: {'configured' if api_url.present else 'not set'} ({api_url.source})")
407
- print(f" pro_v0 local module present: {pro_v0_py_exists}")
499
+ if api_url.source == "default":
500
+ print(" submit-ready service URL: not set (default Preview URL is informational)")
501
+ else:
502
+ print(" submit-ready service URL: configured")
503
+ print(f" service URL source: {api_url.source}")
504
+ print(f" public package boundary checks: {'ok' if payload['public_boundary_ok'] else 'needs attention'}")
505
+ print(f" pilot submit readiness: {'ready' if submit_ready else 'not ready'}")
506
+ print(" submit requirement: QRS-provided token + non-default service URL")
408
507
  print(" service validation: not available in this slice")
409
508
  print(" local cards/confidential analysis: absent")
509
+ print(" artifact/source upload: not performed in this command path")
410
510
  return 0 if payload["status"] == "ok" else 2
411
511
 
512
+ if cmd in {"preview-status", "preview-demo"}:
513
+ return _run_pro_preview_demo_check(base_url_override=args.base_url)
514
+
412
515
  if cmd == "workflow":
413
516
  if args.dry_run_manifest:
414
517
  try:
@@ -466,7 +569,8 @@ def _cmd_pro(argv: list[str]) -> int:
466
569
  if not token.present:
467
570
  print(
468
571
  "qcoder pro workflow: --submit requires a configured token.\n"
469
- "Run `qcoder pro login --token <token>` or set QCODER_PRO_TOKEN.",
572
+ "Run `qcoder pro login --token <token>` or set QCODER_PRO_TOKEN.\n"
573
+ "Do not share your token in tickets, screenshots, or chat.",
470
574
  file=sys.stderr,
471
575
  )
472
576
  return 2
@@ -483,7 +587,8 @@ def _cmd_pro(argv: list[str]) -> int:
483
587
  print(
484
588
  "qcoder pro workflow: No production hosted Pro service is configured for "
485
589
  "this release. Service submit URL is not configured; use --service-url or "
486
- "QCODER_PRO_API_URL only if QRS provided one.",
590
+ "QCODER_PRO_API_URL only if QRS provided one.\n"
591
+ "For support, share only redacted output and error/status codes.",
487
592
  file=sys.stderr,
488
593
  )
489
594
  return 2
@@ -1,4 +1,4 @@
1
- """Public-safe Pro Preview/V0 bootstrap plumbing (non-confidential only)."""
1
+ """Public-safe Pro Preview client surface helpers (non-confidential only)."""
2
2
 
3
3
  from qcoder.pro_preview.config import (
4
4
  ProPreviewConfigError,
@@ -7,7 +7,16 @@ from qcoder.pro_preview.config import (
7
7
  resolve_token,
8
8
  store_local_bootstrap_config,
9
9
  )
10
- from qcoder.pro_preview.client import ProServiceClient, ProServiceClientError
10
+ from qcoder.pro_preview.client import (
11
+ PreviewClientConfig,
12
+ PreviewClientNetworkError,
13
+ PreviewClientResponse,
14
+ ProServiceClient,
15
+ ProServiceClientError,
16
+ call_builtin_review_demo,
17
+ resolve_preview_client_config,
18
+ summarize_demo_payload,
19
+ )
11
20
  from qcoder.pro_preview.errors import ProPreviewManifestError
12
21
  from qcoder.pro_preview.manifest import (
13
22
  WORKFLOW_MANIFEST_SCHEMA_ID,
@@ -17,16 +26,22 @@ from qcoder.pro_preview.manifest import (
17
26
  )
18
27
 
19
28
  __all__ = [
29
+ "PreviewClientConfig",
30
+ "PreviewClientNetworkError",
31
+ "PreviewClientResponse",
20
32
  "ProPreviewConfigError",
33
+ "ProPreviewManifestError",
21
34
  "ProServiceClient",
22
35
  "ProServiceClientError",
23
- "ProPreviewManifestError",
24
36
  "WORKFLOW_MANIFEST_SCHEMA_ID",
25
37
  "build_workflow_manifest",
38
+ "call_builtin_review_demo",
26
39
  "load_local_config",
27
40
  "resolve_api_url",
41
+ "resolve_preview_client_config",
28
42
  "resolve_token",
29
43
  "sanitize_manifest_for_submit",
30
44
  "store_local_bootstrap_config",
45
+ "summarize_demo_payload",
31
46
  "write_workflow_manifest",
32
47
  ]
@@ -1,8 +1,9 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import os
3
4
  import json
4
5
  from dataclasses import dataclass
5
- from typing import Any
6
+ from typing import Any, Mapping
6
7
  from urllib.error import HTTPError, URLError
7
8
  from urllib.parse import urljoin
8
9
  from urllib.request import Request, urlopen
@@ -120,3 +121,97 @@ def _parse_http_error(exc: HTTPError) -> ServiceErrorDetail:
120
121
  else:
121
122
  safe_message = f"service returned HTTP {status_code}"
122
123
  return ServiceErrorDetail(status_code=status_code, error_code=error_code, message=safe_message)
124
+
125
+ PREVIEW_BASE_URL_ENV = "QCODER_PREVIEW_BASE_URL"
126
+ PREVIEW_TOKEN_ENV = "QCODER_PREVIEW_TOKEN"
127
+ PRO_API_URL_ENV = "QCODER_PRO_API_URL"
128
+ PRO_TOKEN_ENV = "QCODER_PRO_TOKEN"
129
+ BUILTIN_REVIEW_PATH = "/v0/demo/builtin-review"
130
+
131
+
132
+ @dataclass(frozen=True)
133
+ class PreviewClientConfig:
134
+ base_url: str
135
+ token: str
136
+
137
+
138
+ @dataclass(frozen=True)
139
+ class PreviewClientResponse:
140
+ status_code: int
141
+ payload: dict[str, Any] | None
142
+
143
+
144
+ class PreviewClientNetworkError(RuntimeError):
145
+ """Raised when hosted Preview cannot be reached."""
146
+
147
+
148
+ def resolve_preview_client_config(
149
+ *, base_url_override: str | None = None, env_map: Mapping[str, str] | None = None
150
+ ) -> PreviewClientConfig:
151
+ env = os.environ if env_map is None else env_map
152
+ base_url = _normalize_base_url(
153
+ base_url_override
154
+ if base_url_override is not None
155
+ else str(env.get(PREVIEW_BASE_URL_ENV) or env.get(PRO_API_URL_ENV) or "")
156
+ )
157
+ token = str(env.get(PREVIEW_TOKEN_ENV) or env.get(PRO_TOKEN_ENV) or "").strip()
158
+ if not token:
159
+ raise ValueError("missing hosted Preview token; set QCODER_PREVIEW_TOKEN or QCODER_PRO_TOKEN")
160
+ return PreviewClientConfig(base_url=base_url, token=token)
161
+
162
+
163
+ def call_builtin_review_demo(
164
+ config: PreviewClientConfig, *, timeout_s: float = 10.0
165
+ ) -> PreviewClientResponse:
166
+ """Call the hosted Preview builtin-review demo endpoint.
167
+
168
+ HTTP 401/403 are valid service responses and must not be treated as
169
+ network failures. HTTPError is a subclass of URLError, so keep this
170
+ handler before the URLError handler.
171
+ """
172
+ request = Request(
173
+ _join_service_url(config.base_url, BUILTIN_REVIEW_PATH),
174
+ headers={"Authorization": f"Bearer {config.token}"},
175
+ method="GET",
176
+ )
177
+ try:
178
+ with urlopen(request, timeout=timeout_s) as response:
179
+ body = response.read().decode("utf-8", errors="replace")
180
+ status_code = int(getattr(response, "status", 200))
181
+ return PreviewClientResponse(status_code=status_code, payload=_safe_json_decode(body))
182
+ except HTTPError as err:
183
+ body = err.read().decode("utf-8", errors="replace")
184
+ return PreviewClientResponse(status_code=int(err.code), payload=_safe_json_decode(body))
185
+ except URLError as exc:
186
+ raise PreviewClientNetworkError(str(exc)) from exc
187
+
188
+ def summarize_demo_payload(payload: dict[str, Any] | None) -> list[str]:
189
+ if not payload:
190
+ return []
191
+ lines: list[str] = []
192
+ for key in ("service", "mode", "status", "demo_level"):
193
+ value = payload.get(key)
194
+ if isinstance(value, (str, int, float, bool)):
195
+ lines.append(f" {key}: {value}")
196
+ samples = payload.get("samples")
197
+ if isinstance(samples, list):
198
+ lines.append(f" samples: {len(samples)}")
199
+ return lines
200
+
201
+
202
+ def _normalize_base_url(raw_base_url: str) -> str:
203
+ base_url = raw_base_url.strip().rstrip("/")
204
+ if not base_url:
205
+ raise ValueError(
206
+ "missing hosted Preview base URL; set QCODER_PREVIEW_BASE_URL or "
207
+ "QCODER_PRO_API_URL, or pass --base-url"
208
+ )
209
+ return base_url
210
+
211
+
212
+ def _safe_json_decode(raw: str) -> dict[str, Any] | None:
213
+ try:
214
+ payload = json.loads(raw)
215
+ except json.JSONDecodeError:
216
+ return None
217
+ return payload if isinstance(payload, dict) else None
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: qcoder
3
- Version: 0.5.0a2
3
+ Version: 0.5.0a3
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>
@@ -46,11 +46,13 @@ Free `qcoder` commands run offline and do not call hosted services, upload telem
46
46
 
47
47
  Public `qcoder` ships **Free local commands** plus a **Pro bootstrap/client contract**. It is **not** the sellable hosted Pro product.
48
48
 
49
- - **Free commands** (`analyze`, `batch`, `context`, `review`) run offline. They do not upload data, call a qCoder hosted service, or run QPU/simulator jobs.
49
+ For a public, pilot-safe walkthrough, see the [Pro Preview pilot walkthrough](https://qcoder.ai/manual/pro-preview-pilot-walkthrough/). The current public PyPI alpha client surface for Pro Preview is **`qcoder==0.5.0a2`**. It is not Pro V0.0 and not a sellable launched Pro product.
50
+
51
+ - **Free commands** (`analyze`, `batch`, `context`, `review`) are Apache-2.0, local-first/offline, and useful without Pro. They do not upload data, call a qCoder hosted service, or run QPU/simulator jobs.
50
52
  - **`qcoder pro` bootstrap** (`signup`, `login`, `install`, `status`, `validate`) stores local token/config only. It does not upload circuits, run confidential analysis, or generate Pro cards locally.
51
53
  - **`qcoder pro workflow --dry-run-manifest`** writes a local JSON contract (`qcoder.pro_preview.workflow_manifest.v0`) and performs **no network calls**. This is the default path for most users.
52
54
  - **`qcoder pro workflow --submit`** posts a **sanitized manifest only** to an **explicitly configured** `--service-url` (or `QCODER_PRO_API_URL`). Use it only when QRS has given you a service URL and token. The default `https://qcoder.ai/preview` URL is **not** accepted for submit.
53
- - There is **no generally available production hosted Pro service**, account/token issuance, or artifact upload in this public-main surface. Production hosted service, Cloud Run/GCS, and confidential analysis are separate/future.
55
+ - There is **no generally available production hosted Pro service**, account/token issuance, artifact/source upload, telemetry/training ingest, confidential local analyzer/cards, QPU/provider execution, or launched Pro V0.0 behavior in this public-main surface.
54
56
  - **No confidential Pro analysis or cards** are bundled in this package. Token-gating is **access control only**, not a secrecy boundary.
55
57
 
56
58
  ## Quick start
@@ -91,6 +93,27 @@ Use **`--dry-run-manifest`** unless QRS has given you a non-default service URL
91
93
  qcoder pro workflow --qasm path/to/circuit.qasm --submit --service-url <url-qrs-provided>
92
94
  ```
93
95
 
96
+ **Support-safe checklist for Pro Preview pilots**
97
+
98
+ Safe to share with QRS support:
99
+
100
+ - `qcoder --version`
101
+ - command name
102
+ - HTTP status or CLI error code
103
+ - `job_id`, if produced
104
+ - redacted output
105
+ - manifest schema/version
106
+
107
+ Do not share:
108
+
109
+ - bearer tokens
110
+ - secrets
111
+ - source code
112
+ - repository archives
113
+ - notebooks
114
+ - private prompts or chat transcripts
115
+ - raw QASM/source artifacts through unsupported paths
116
+
94
117
  Architecture notes: [`docs/architecture.md`](docs/architecture.md).
95
118
 
96
119
  ## Optional extras
File without changes
File without changes
File without changes
File without changes