@oqtopus-team/pi-qdash 0.1.1 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -24,6 +24,14 @@ It uses [`@oqtopus-team/qdash-client`](https://www.npmjs.com/package/@oqtopus-te
24
24
 
25
25
  ## Installation
26
26
 
27
+ Install pi first if needed:
28
+
29
+ ```bash
30
+ npm install -g --ignore-scripts @earendil-works/pi-coding-agent
31
+ ```
32
+
33
+ Install the published extension:
34
+
27
35
  ```bash
28
36
  pi install npm:@oqtopus-team/pi-qdash
29
37
  ```
@@ -47,10 +55,25 @@ In interactive pi, set up the session context first:
47
55
 
48
56
  See the documentation below for the full tool and command reference.
49
57
 
58
+ ## Developing from a Fork
59
+
60
+ For local development, clone your fork, install dependencies, and run pi against the checkout:
61
+
62
+ ```bash
63
+ git clone https://github.com/<your-user>/pi-qdash.git
64
+ cd pi-qdash
65
+ npm install
66
+ npm run check
67
+ pi -e .
68
+ ```
69
+
70
+ See [Development Guide](./docs/DEVELOPMENT.md) for the fork workflow, local testing, PR expectations, and the extension-vs-skill design policy.
71
+
50
72
  ## Documentation
51
73
 
52
74
  - [Tool Reference](./docs/tools.md)
53
75
  - [Commands & Skills](./docs/commands.md)
76
+ - [Development Guide](./docs/DEVELOPMENT.md)
54
77
  - [Contributing](./docs/CONTRIBUTING.md)
55
78
 
56
79
  ## Citation
@@ -2062,6 +2062,102 @@ function figureComponent(details: FigureDetails, theme: Theme) {
2062
2062
  return textComponent(figureResultText(details).split("\n"), theme);
2063
2063
  }
2064
2064
 
2065
+ type PlotlyTrace = Record<string, unknown>;
2066
+
2067
+ type FigureAnalysis = {
2068
+ path: string;
2069
+ taskId?: string;
2070
+ traceCount: number;
2071
+ summaries: string[];
2072
+ warnings: string[];
2073
+ };
2074
+
2075
+ function numericArray(value: unknown): number[] {
2076
+ return Array.isArray(value) ? value.filter((item): item is number => typeof item === "number" && Number.isFinite(item)) : [];
2077
+ }
2078
+
2079
+ function numericMatrix(value: unknown): number[][] {
2080
+ return Array.isArray(value)
2081
+ ? value.map((row) => numericArray(row)).filter((row) => row.length > 0)
2082
+ : [];
2083
+ }
2084
+
2085
+ function matrixValue(matrix: number[][], row: number, column: number): number | undefined {
2086
+ return matrix[row]?.[column];
2087
+ }
2088
+
2089
+ function compactStats(values: number[]): string {
2090
+ if (!values.length) return "no numeric values";
2091
+ const min = Math.min(...values);
2092
+ const max = Math.max(...values);
2093
+ const mean = values.reduce((sum, value) => sum + value, 0) / values.length;
2094
+ return `n=${values.length} min=${formatNumber(min)} max=${formatNumber(max)} mean=${formatNumber(mean)}`;
2095
+ }
2096
+
2097
+ function formatMaybeNumber(value: number | undefined): string {
2098
+ return typeof value === "number" && Number.isFinite(value) ? formatNumber(value) : "n/a";
2099
+ }
2100
+
2101
+ function analyzePlotlyFigure(path: string, figure: unknown, taskId?: string): FigureAnalysis {
2102
+ const object = figure && typeof figure === "object" ? figure as Record<string, unknown> : {};
2103
+ const traces = Array.isArray(object.data) ? object.data.filter((trace): trace is PlotlyTrace => Boolean(trace) && typeof trace === "object") : [];
2104
+ const summaries: string[] = [];
2105
+ const warnings: string[] = [];
2106
+
2107
+ traces.forEach((trace, index) => {
2108
+ const type = typeof trace.type === "string" ? trace.type : "unknown";
2109
+ const name = typeof trace.name === "string" ? trace.name : `trace ${index}`;
2110
+ if (type === "scatter" || Array.isArray(trace.y)) {
2111
+ const y = numericArray(trace.y);
2112
+ const x = numericArray(trace.x);
2113
+ const err = trace.error_y && typeof trace.error_y === "object" ? (trace.error_y as Record<string, unknown>).value : undefined;
2114
+ summaries.push(`${index}: scatter ${name} y(${compactStats(y)}) first=${formatMaybeNumber(y[0])} last=${formatMaybeNumber(y[y.length - 1])}${typeof err === "number" ? ` err=${formatNumber(err)}` : ""}`);
2115
+ if (y.length >= 5) {
2116
+ const tail = y.slice(Math.floor(y.length / 2));
2117
+ const tailSpan = Math.max(...tail) - Math.min(...tail);
2118
+ if (tailSpan > 0.4) warnings.push(`scatter ${name}: late repetitions still have large span ${formatNumber(tailSpan)}; repeated-pulse response may be unstable`);
2119
+ const firstStep = Math.abs((y[1] ?? y[0]) - y[0]);
2120
+ if (firstStep > 0.6 && Math.abs(y[y.length - 1]) > 0.1) warnings.push(`scatter ${name}: large first-step contrast but non-zero final offset ${formatNumber(y[y.length - 1])}`);
2121
+ }
2122
+ if (x.length && y.length && x.length !== y.length) warnings.push(`scatter ${name}: x/y length mismatch ${x.length}/${y.length}`);
2123
+ return;
2124
+ }
2125
+
2126
+ if (type === "heatmap" || Array.isArray(trace.z)) {
2127
+ const z = numericMatrix(trace.z);
2128
+ const flat = z.flat();
2129
+ summaries.push(`${index}: heatmap ${z.length}x${z[0]?.length ?? 0} z(${compactStats(flat)})`);
2130
+ if (z.length === 4 && z.every((row) => row.length === 4)) {
2131
+ const diag = [0, 1, 2, 3].map((i) => z[i][i]);
2132
+ const pop10 = diag[2];
2133
+ const coh0011Re = matrixValue(z, 0, 3);
2134
+ summaries.push(` 4x4 diag=[${diag.map(formatNumber).join(", ")}] z00,11=${formatMaybeNumber(coh0011Re)}`);
2135
+ if (pop10 > 0.15) warnings.push(`4x4 heatmap: |10> population/component is high (${formatNumber(pop10)}); suspect Bell/Zx angle, phase, or cancel error`);
2136
+ }
2137
+ return;
2138
+ }
2139
+
2140
+ summaries.push(`${index}: ${type}`);
2141
+ });
2142
+
2143
+ if (!traces.length) warnings.push("no Plotly data traces found");
2144
+ return { path, taskId, traceCount: traces.length, summaries, warnings };
2145
+ }
2146
+
2147
+ function figureAnalysisText(analysis: FigureAnalysis): string {
2148
+ return boxed("QDash Figure Analysis", [
2149
+ `path ${analysis.path}`,
2150
+ ...(analysis.taskId ? [`task ${analysis.taskId}`] : []),
2151
+ `traces ${analysis.traceCount}`,
2152
+ "",
2153
+ "Summaries",
2154
+ ...analysis.summaries.map((line) => ` - ${line}`),
2155
+ "",
2156
+ "Warnings",
2157
+ ...(analysis.warnings.length ? analysis.warnings.map((line) => ` - ${line}`) : [" - none"]),
2158
+ ]).join("\n");
2159
+ }
2160
+
2065
2161
  async function executeQuery(params: QDashQueryParams) {
2066
2162
  params = applyQDashContext(params);
2067
2163
  const client = await makeClient(params);
@@ -3150,6 +3246,41 @@ export default function qdashExtension(pi: ExtensionAPI) {
3150
3246
  },
3151
3247
  });
3152
3248
 
3249
+ pi.registerTool({
3250
+ name: "qdash_analyze_figure_json",
3251
+ label: "QDash Analyze Figure JSON",
3252
+ description: "Read-only helper that fetches a Plotly JSON calibration figure and summarizes numeric traces for agentic diagnosis.",
3253
+ promptSnippet: "Analyze QDash calibration figure JSON traces without changing parameters",
3254
+ promptGuidelines: [
3255
+ "Use qdash_analyze_figure_json when a calibration figure has json_figure_path and you need numeric evidence from scatter or heatmap traces.",
3256
+ "Treat the output as evidence for a skill/runbook decision; do not commit/apply parameters from this analysis alone.",
3257
+ ],
3258
+ parameters: Type.Object({
3259
+ ...connectionParams,
3260
+ path: Type.Optional(Type.String({ description: "Absolute JSON figure path. If omitted, taskId is required." })),
3261
+ taskId: Type.Optional(Type.String({ description: "Task result ID used to select json_figure_path." })),
3262
+ index: Type.Optional(Type.Number({ description: "JSON figure index for taskId selection. Defaults to 0." })),
3263
+ includeData: Type.Optional(Type.Boolean({ description: "Include parsed Plotly JSON in structured data. Defaults to false." })),
3264
+ }),
3265
+ async execute(_toolCallId, params: { profile?: string; configPath?: string; useEnv?: boolean; path?: string; taskId?: string; index?: number; includeData?: boolean }) {
3266
+ const client = await makeClient(params);
3267
+ let path = params.path;
3268
+ let text = "";
3269
+ if (path) {
3270
+ const details = await fetchFigureDetails(client, path);
3271
+ text = details.text ?? "";
3272
+ } else {
3273
+ const taskId = requireValue(params.taskId, "taskId");
3274
+ const file: TaskResultFigureFile = await client.getTaskResultFigure(taskId, { index: params.index, preferJson: true });
3275
+ path = file.path;
3276
+ text = Buffer.from(file.data).toString("utf8");
3277
+ }
3278
+ const figure = JSON.parse(text) as unknown;
3279
+ const analysis = analyzePlotlyFigure(path ?? "", figure, params.taskId);
3280
+ return toTextToolResult(figureAnalysisText(analysis), { analysis, figure: params.includeData ? figure : undefined }, { tool: "qdash_analyze_figure_json", path, data: analysis });
3281
+ },
3282
+ });
3283
+
3153
3284
  registerQueryTool({
3154
3285
  name: "qdash_get_provenance_stats",
3155
3286
  label: "QDash Provenance Stats",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oqtopus-team/pi-qdash",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "Pi extension for querying QDash via @oqtopus-team/qdash-client",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
@@ -22,7 +22,7 @@ Use the pi-qdash tools instead of scraping the UI or hand-writing auth headers.
22
22
  - `qdash_list_executions`, `qdash_get_execution`
23
23
  - `qdash_list_ai_reviews`, `qdash_get_provenance_stats`
24
24
  - `qdash_list_forum_posts`, `qdash_get_forum_post`, `qdash_list_forum_replies`
25
- - `qdash_get_figure`, `qdash_get_task_figures`, `qdash_recent_calibration_figure`
25
+ - `qdash_get_figure`, `qdash_get_task_figures`, `qdash_recent_calibration_figure`, `qdash_analyze_figure_json`
26
26
  - `qdash_create_forum_evidence_reply` for confirmed evidence curation replies with visible task figures
27
27
  3. Use harness overview tools for status and triage:
28
28
  - `qdash_investigate` for natural-language requests to investigate or compare recent calibration, target history, figures, failures, issues, and Forum context
@@ -107,4 +107,5 @@ When the user wants to preserve an investigated observation in QDash forum/notes
107
107
  - Use `qdash_investigate` for natural-language requests to investigate, compare, or understand a target or recent calibration; it is read-only and combines recent results with target, Forum, issue, and recommendation context.
108
108
  - Use `qdash_compare_calibration` when the user asks what changed between recent calibration experiments; treat differences as evidence, not automatic approval to commit/apply parameters.
109
109
  - Use `qdash_recent_calibration_figure` when the user asks to see recent experiment images without a task ID.
110
+ - Use `qdash_analyze_figure_json` for read-only numeric summaries of Plotly JSON calibration figures; keep domain-specific interpretation in the matching skill.
110
111
  - Prefer summarizing large responses with counts, IDs, time ranges, and notable values.
@@ -1,6 +1,6 @@
1
1
  ---
2
- name: qdash-calibration
3
- description: Guide conservative autonomous QDash calibration workflows from pi. Use when the user asks to calibrate, tune, recover failed calibration tasks, run agent calibration sessions, or decide the next calibration action for qubits/couplings.
2
+ name: qdash-calibration-agent
3
+ description: Guide conservative confirmation-gated QDash calibration execution workflows from pi. Use when the user asks to calibrate, tune, recover failed calibration tasks, run agent calibration sessions, or decide the next calibration action for qubits/couplings.
4
4
  license: Apache-2.0
5
5
  compatibility: pi-coding-agent >=0.74, pi-qdash extension, QDash agent-session APIs
6
6
  metadata:
@@ -9,7 +9,7 @@ metadata:
9
9
  maturity: experimental
10
10
  safety_level: operational-write-gated
11
11
  default_mode: one-target-one-action
12
- source_of_truth: pi-qdash skill until QDash task-knowledge operation is finalized
12
+ source_of_truth: pi-qdash skills until QDash task-knowledge operation is finalized
13
13
  preferred_qubit_recovery_recipe: CheckRabi -> CheckChevron -> Configure -> CheckRabi
14
14
  requires_confirmation_for:
15
15
  - agent session creation
@@ -26,7 +26,7 @@ metadata:
26
26
 
27
27
  # QDash Calibration Agent
28
28
 
29
- This skill defines how pi should behave as a conservative calibration agent. It is operational guidance for the agent; long-lived physics/task knowledge may later move to QDash task-knowledge, but until that process is settled, keep practical calibration recipes here.
29
+ This skill defines how pi should behave as a conservative, confirmation-gated calibration execution agent. It should orchestrate safe operational steps after diagnosis. Long-lived physics/task knowledge may later move to QDash task-knowledge; detailed read-only diagnosis should live in dedicated diagnosis skills.
30
30
 
31
31
  ## Core principles
32
32
 
@@ -139,6 +139,8 @@ Known failed pattern:
139
139
 
140
140
  ## Coupling / two-qubit recovery rules
141
141
 
142
+ For detailed two-qubit quality diagnosis, use the `qdash-two-qubit-calibration-diagnosis` skill. Keep this section as the conservative operational rule set.
143
+
142
144
  For `ZX90InterleavedRandomizedBenchmarking` or two-qubit validation failures, do not rerun RB first. Walk back through prerequisites:
143
145
 
144
146
  1. `CheckCrossResonance`
@@ -148,6 +150,8 @@ For `ZX90InterleavedRandomizedBenchmarking` or two-qubit validation failures, do
148
150
  5. `CheckBellStateTomography`
149
151
  6. then RB validation
150
152
 
153
+ Treat `completed` as execution status, not proof of quality. If Bell fidelity is low, IRB uncertainty is large, or coherence-limit fidelity is much higher than measured Bell/IRB fidelity, suspect ZX90 angle/phase/cancel/rotary calibration before blaming T1/T2.
154
+
151
155
  If CR rotation is weak, inspect qubit detuning/frequency collisions and coupling history before increasing CR amplitude.
152
156
 
153
157
  ## Session policy guidelines
@@ -0,0 +1,125 @@
1
+ ---
2
+ name: qdash-two-qubit-calibration-diagnosis
3
+ description: Diagnose QDash two-qubit calibration quality from CR, ZX90, Bell-state, tomography, coherence-limit, and IRB task results. Use when a coupling calibration completes but gate fidelity, Bell fidelity, or validation quality may be poor.
4
+ license: Apache-2.0
5
+ compatibility: pi-coding-agent >=0.74, pi-qdash extension
6
+ metadata:
7
+ domain: quantum-calibration
8
+ safety_level: read-only-first-write-gated
9
+ preferred_validation_chain: CheckCrossResonance -> CreateZX90 -> CheckZX90 -> CheckBellState -> CheckBellStateTomography -> ZX90InterleavedRandomizedBenchmarking
10
+ ---
11
+
12
+ # QDash Two-Qubit Calibration Diagnosis
13
+
14
+ Use this skill when investigating coupling-level calibration quality, especially when tasks are `completed` but quality may be poor.
15
+
16
+ ## Principles
17
+
18
+ - Treat `completed` as execution status, not proof of calibration quality.
19
+ - Diagnose from evidence before suggesting operational actions.
20
+ - Prefer read-only tools first: `qdash_target_report`, `qdash_list_task_results`, `qdash_get_task_result`, `qdash_analyze_figure_json`, and `qdash_get_task_figures`.
21
+ - Do not rerun RB first when validation quality is suspicious. Walk back through prerequisites.
22
+ - Do not commit or apply candidates without explicit user confirmation, and only after downstream validation.
23
+
24
+ ## Standard read-only investigation
25
+
26
+ For a coupling `cA-B`:
27
+
28
+ 1. Build context with `qdash_target_report` and recent task results for the coupling.
29
+ 2. Inspect the latest tasks in this chain:
30
+ - `CheckCrossResonance`
31
+ - `CreateZX90`
32
+ - `CheckZX90`
33
+ - `CheckBellState`
34
+ - `CheckBellStateTomography`
35
+ - `Check2QGateCoherenceLimit`
36
+ - `ZX90InterleavedRandomizedBenchmarking`
37
+ 3. Fetch task details and record:
38
+ - CR: `cr_amplitude`, `cr_phase`, `cancel_amplitude`, `cancel_phase`, `rotary_amplitude`, `zx_rotation_rate`
39
+ - ZX90: `zx90_gate_time`
40
+ - Bell tomography: `bell_state_fidelity`
41
+ - Coherence limit: `two_qubit_gate_coherence_limit`
42
+ - IRB: `zx90_gate_fidelity`, its error, `zx90_depolarizing_rate`, `n_trials`
43
+ 4. For JSON figures, use `qdash_analyze_figure_json` before manually reading raw Plotly JSON.
44
+ 5. Summarize symptoms, likely failure mode, and the next *read-only or confirmation-gated* step.
45
+
46
+ ## Interpretation rules
47
+
48
+ ### Completed but low quality
49
+
50
+ Flag as suspicious when any of these hold:
51
+
52
+ - Bell-state tomography fidelity is below ~0.8.
53
+ - IRB fidelity has a large uncertainty/error bar, or `n_trials` is small.
54
+ - Coherence-limit fidelity is high but Bell/IRB fidelity is much lower.
55
+ - `CheckZX90` repeated-pulse traces do not show a stable/consistent response.
56
+ - CR parameter generation succeeds but `cr_amplitude` is near saturation or `zx_rotation_rate` is very small.
57
+
58
+ ### Coherence limit gap
59
+
60
+ If `two_qubit_gate_coherence_limit` is high but measured Bell/IRB fidelity is low, do not attribute the issue primarily to T1/T2. Suspect control/calibration issues such as:
61
+
62
+ - ZX90 angle error
63
+ - CR phase error
64
+ - cancel-pulse amplitude/phase mismatch
65
+ - rotary compensation mismatch
66
+ - readout/classification contribution to validation figures
67
+
68
+ ### Bell tomography signals
69
+
70
+ For a Bell target resembling `( |00> + |11> ) / sqrt(2)`:
71
+
72
+ - Large `|10>` or `|01>` population suggests population/conditional-rotation error, not just dephasing.
73
+ - Weak `|00><11|` coherence suggests phase, dephasing, or preparation error.
74
+ - Large imaginary coherence can indicate phase-compensation error.
75
+
76
+ Use the heatmap summaries from `qdash_analyze_figure_json` as numeric evidence. Do not overfit a single plot; correlate with `CheckZX90` and IRB.
77
+
78
+ ### CheckZX90 repeated-pulse signals
79
+
80
+ Look for stable repeated-pulse behavior. Warnings include:
81
+
82
+ - Large scatter or non-decaying erratic points after the first few repetitions.
83
+ - Large first-step contrast followed by a non-zero offset.
84
+ - Different qualitative behavior between control and target qubit plots.
85
+
86
+ These symptoms point toward angle/phase/cancel/rotary issues and should be investigated before trusting IRB.
87
+
88
+ ### IRB caveats
89
+
90
+ - A `completed` IRB with large error bar is weak evidence.
91
+ - Small `n_trials` should be reported explicitly.
92
+ - If Bell tomography is poor, do not use IRB alone as a pass signal.
93
+
94
+ ## Recommended action sequence
95
+
96
+ When validation quality is poor:
97
+
98
+ ```text
99
+ Inspect figures/results
100
+ -> CheckCrossResonance
101
+ -> CreateZX90
102
+ -> CheckZX90
103
+ -> CheckBellState
104
+ -> CheckBellStateTomography
105
+ -> ZX90InterleavedRandomizedBenchmarking
106
+ ```
107
+
108
+ Each operational step requires explicit confirmation. Validate Bell/tomography before using IRB as the final quality signal.
109
+
110
+ ## Known case: mackerel 144Qv1 c48-50, 20260725-003
111
+
112
+ Symptoms observed:
113
+
114
+ - `CheckCrossResonance` completed with `zx_rotation_rate ~ 1.69e-3`.
115
+ - `Check2QGateCoherenceLimit` reported ~0.978.
116
+ - `CheckBellStateTomography` reported `bell_state_fidelity ~ 0.60`.
117
+ - Bell tomography had high `|10>` component/population (~0.29) and non-ideal coherence.
118
+ - `ZX90InterleavedRandomizedBenchmarking` completed with `zx90_gate_fidelity ~0.94` but large error (~0.087) and `n_trials=10`.
119
+ - `CheckZX90` repeated-pulse traces were not clean/stable.
120
+
121
+ Interpretation:
122
+
123
+ - This is not primarily coherence-limited.
124
+ - Suspect ZX90 angle/phase/cancel/rotary calibration quality.
125
+ - Prefer walking back through `CheckCrossResonance -> CreateZX90 -> CheckZX90`, then validate with Bell tomography before trusting IRB.