@oqtopus-team/pi-qdash 0.1.4 → 0.1.6
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 +5 -2
- package/extensions/lib/forum-images.ts +82 -0
- package/extensions/lib/investigation-context.ts +169 -0
- package/extensions/lib/timeseries-analysis.ts +609 -0
- package/extensions/lib/write-gate.ts +1 -0
- package/extensions/qdash.ts +222 -52
- package/extensions/tools/timeseries.ts +211 -0
- package/package.json +7 -3
- package/skills/qdash/SKILL.md +48 -7
- package/skills/qdash-calibration-agent/SKILL.md +4 -1
- package/skills/qdash-timeseries-diagnosis/SKILL.md +155 -0
- package/skills/qdash-two-qubit-calibration-diagnosis/SKILL.md +4 -3
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
import type { QDashClient } from "@oqtopus-team/qdash-client";
|
|
3
|
+
import { Type } from "typebox";
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
compareTimeseries,
|
|
7
|
+
csvInspectionText,
|
|
8
|
+
inspectExternalCsv,
|
|
9
|
+
loadExternalCsvSeries,
|
|
10
|
+
timeseriesComparisonText,
|
|
11
|
+
type CsvTimeFormat,
|
|
12
|
+
type ExternalCsvSpec,
|
|
13
|
+
type NumericTimeseries,
|
|
14
|
+
} from "../lib/timeseries-analysis.js";
|
|
15
|
+
import type { TimeseriesInvestigationContext } from "../lib/investigation-context.js";
|
|
16
|
+
import { toTextToolResult } from "../lib/results.js";
|
|
17
|
+
import { timeseriesPoints } from "../lib/timeseries-plot.js";
|
|
18
|
+
|
|
19
|
+
type ComparisonToolParams = {
|
|
20
|
+
profile?: string;
|
|
21
|
+
configPath?: string;
|
|
22
|
+
useEnv?: boolean;
|
|
23
|
+
chipId?: string;
|
|
24
|
+
startAt?: string;
|
|
25
|
+
endAt?: string;
|
|
26
|
+
withinHours?: number;
|
|
27
|
+
qdashSeries?: Array<{ parameter: string; qid?: string; tag?: string; label?: string; unit?: string; scale?: number; offset?: number }>;
|
|
28
|
+
csvSeries?: Array<ExternalCsvSpec & { timeFormat?: CsvTimeFormat }>;
|
|
29
|
+
resampleMinutes?: number;
|
|
30
|
+
smoothingWindowMinutes?: number;
|
|
31
|
+
detrend?: string;
|
|
32
|
+
normalize?: string;
|
|
33
|
+
maxInterpolationGapMinutes?: number;
|
|
34
|
+
periodSearch?: { minMinutes: number; maxMinutes: number; stepMinutes?: number };
|
|
35
|
+
includeAlignedData?: boolean;
|
|
36
|
+
useInvestigationContext?: boolean;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export type TimeseriesToolDependencies = {
|
|
40
|
+
makeClient: (params: { profile?: string; configPath?: string; useEnv?: boolean }) => Promise<QDashClient>;
|
|
41
|
+
defaultChipId: (client: QDashClient, chipId?: string) => Promise<string>;
|
|
42
|
+
investigationContext?: () => TimeseriesInvestigationContext | undefined;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export function registerTimeseriesComparisonTool(pi: ExtensionAPI, dependencies: TimeseriesToolDependencies): void {
|
|
46
|
+
pi.registerTool({
|
|
47
|
+
name: "qdash_inspect_timeseries_csv",
|
|
48
|
+
label: "QDash Inspect Timeseries CSV",
|
|
49
|
+
description: "Inspect a local CSV schema and numeric/time characteristics before mapping it into a QDash timeseries comparison. Read-only; never uploads the file.",
|
|
50
|
+
promptSnippet: "Inspect local CSV columns, numeric ranges, timestamps, and cadence before comparison",
|
|
51
|
+
promptGuidelines: [
|
|
52
|
+
"Use qdash_inspect_timeseries_csv before qdash_compare_timeseries when a local CSV schema, timestamp format, timezone, or numeric columns are not already known.",
|
|
53
|
+
"Do not infer the timezone of naive timestamps from qdash_inspect_timeseries_csv samples; ask for or supply an explicit timezone offset.",
|
|
54
|
+
],
|
|
55
|
+
parameters: Type.Object({
|
|
56
|
+
path: Type.String({ description: "Local CSV path, absolute or relative to the current working directory." }),
|
|
57
|
+
delimiter: Type.Optional(Type.String({ description: "Single-character delimiter. Defaults to comma." })),
|
|
58
|
+
skipRows: Type.Optional(Type.Number({ description: "Rows before the header. Defaults to 0." })),
|
|
59
|
+
timeColumn: Type.Optional(Type.String({ description: "Optional timestamp column to validate." })),
|
|
60
|
+
timeFormat: Type.Optional(Type.String({ description: "iso, yyyy/M/d H:mm, yyyy-MM-dd HH:mm:ss, unix-seconds, or unix-milliseconds." })),
|
|
61
|
+
timezoneOffsetMinutes: Type.Optional(Type.Number({ description: "Required to validate timestamps without an explicit zone; JST is 540." })),
|
|
62
|
+
scanRows: Type.Optional(Type.Number({ description: "Rows to profile, from 1 to 100000. Defaults to 10000." })),
|
|
63
|
+
}),
|
|
64
|
+
async execute(_toolCallId, params: {
|
|
65
|
+
path: string;
|
|
66
|
+
delimiter?: string;
|
|
67
|
+
skipRows?: number;
|
|
68
|
+
timeColumn?: string;
|
|
69
|
+
timeFormat?: CsvTimeFormat;
|
|
70
|
+
timezoneOffsetMinutes?: number;
|
|
71
|
+
scanRows?: number;
|
|
72
|
+
}, _signal, _onUpdate, ctx) {
|
|
73
|
+
const inspection = inspectExternalCsv(params, ctx.cwd);
|
|
74
|
+
return toTextToolResult(csvInspectionText(inspection), inspection, {
|
|
75
|
+
tool: "qdash_inspect_timeseries_csv",
|
|
76
|
+
path: inspection.path,
|
|
77
|
+
});
|
|
78
|
+
},
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
pi.registerTool({
|
|
82
|
+
name: "qdash_compare_timeseries",
|
|
83
|
+
label: "QDash Compare Timeseries",
|
|
84
|
+
description: "Compare two or more QDash and/or local CSV numeric timeseries on a common time grid. Read-only; reports alignment, correlations, optional shared-period fits, phases, and statistical caveats without inferring causality.",
|
|
85
|
+
promptSnippet: "Compare generic QDash metrics and external CSV sensor timeseries",
|
|
86
|
+
promptGuidelines: [
|
|
87
|
+
"Use qdash_compare_timeseries when comparing multiple QDash metrics, targets, or local CSV sensor logs over time.",
|
|
88
|
+
"For qdash_compare_timeseries local CSV inputs, explicitly specify timestamp format and timezone offset when timestamps have no zone.",
|
|
89
|
+
"Treat qdash_compare_timeseries correlations and shared periods as evidence of association, not proof of causality.",
|
|
90
|
+
],
|
|
91
|
+
parameters: Type.Object({
|
|
92
|
+
profile: Type.Optional(Type.String({ description: "QDash profile name. Defaults to env when QDASH_BASE_URL is set, otherwise 'default'." })),
|
|
93
|
+
configPath: Type.Optional(Type.String({ description: "Optional path to qdash config.ini." })),
|
|
94
|
+
useEnv: Type.Optional(Type.Boolean({ description: "Force QDASH_* environment variables instead of a profile." })),
|
|
95
|
+
chipId: Type.Optional(Type.String({ description: "Chip ID. Defaults to the active/default chip when omitted." })),
|
|
96
|
+
startAt: Type.Optional(Type.String({ description: "Optional common start timestamp as an ISO timestamp with timezone." })),
|
|
97
|
+
endAt: Type.Optional(Type.String({ description: "Optional common end timestamp as an ISO timestamp with timezone." })),
|
|
98
|
+
withinHours: Type.Optional(Type.Number({ description: "QDash lookback when startAt is omitted. Defaults to 168 hours." })),
|
|
99
|
+
useInvestigationContext: Type.Optional(Type.Boolean({ description: "Use missing series/window/transform defaults from the active investigation context. Defaults to true." })),
|
|
100
|
+
qdashSeries: Type.Optional(Type.Array(Type.Object({
|
|
101
|
+
parameter: Type.String({ description: "QDash task-result parameter name." }),
|
|
102
|
+
qid: Type.Optional(Type.String()),
|
|
103
|
+
tag: Type.Optional(Type.String()),
|
|
104
|
+
label: Type.Optional(Type.String({ description: "Unique display label. Defaults to parameter plus qid/returned series." })),
|
|
105
|
+
unit: Type.Optional(Type.String({ description: "Optional output unit override." })),
|
|
106
|
+
scale: Type.Optional(Type.Number({ description: "Multiply QDash values by this factor. Defaults to 1." })),
|
|
107
|
+
offset: Type.Optional(Type.Number({ description: "Add this value after scaling. Defaults to 0." })),
|
|
108
|
+
}), { maxItems: 12 })),
|
|
109
|
+
csvSeries: Type.Optional(Type.Array(Type.Object({
|
|
110
|
+
path: Type.String({ description: "Local CSV path, absolute or relative to the current working directory." }),
|
|
111
|
+
timeColumn: Type.String(),
|
|
112
|
+
valueColumns: Type.Array(Type.Object({
|
|
113
|
+
column: Type.String(),
|
|
114
|
+
label: Type.Optional(Type.String()),
|
|
115
|
+
unit: Type.Optional(Type.String()),
|
|
116
|
+
scale: Type.Optional(Type.Number()),
|
|
117
|
+
offset: Type.Optional(Type.Number()),
|
|
118
|
+
}), { minItems: 1, maxItems: 12 }),
|
|
119
|
+
timeFormat: Type.Optional(Type.String({ description: "iso, yyyy/M/d H:mm, yyyy-MM-dd HH:mm:ss, unix-seconds, or unix-milliseconds. Defaults to iso." })),
|
|
120
|
+
timezoneOffsetMinutes: Type.Optional(Type.Number({ description: "Required for timestamps without an explicit zone; for JST use 540." })),
|
|
121
|
+
delimiter: Type.Optional(Type.String({ description: "Single-character delimiter. Defaults to comma." })),
|
|
122
|
+
skipRows: Type.Optional(Type.Number({ description: "Rows to skip before the header. Defaults to 0." })),
|
|
123
|
+
filters: Type.Optional(Type.Record(Type.String(), Type.Array(Type.String()), { description: "Optional exact-match row filters keyed by column name." })),
|
|
124
|
+
}), { maxItems: 8 })),
|
|
125
|
+
resampleMinutes: Type.Optional(Type.Number({ description: "Common grid interval. Defaults to 1 minute." })),
|
|
126
|
+
smoothingWindowMinutes: Type.Optional(Type.Number({ description: "Centered moving-average window. Zero disables smoothing." })),
|
|
127
|
+
detrend: Type.Optional(Type.String({ description: "none or linear. Defaults to none." })),
|
|
128
|
+
normalize: Type.Optional(Type.String({ description: "none or zscore. Defaults to none." })),
|
|
129
|
+
maxInterpolationGapMinutes: Type.Optional(Type.Number({ description: "Do not interpolate across larger source gaps." })),
|
|
130
|
+
periodSearch: Type.Optional(Type.Object({
|
|
131
|
+
minMinutes: Type.Number(),
|
|
132
|
+
maxMinutes: Type.Number(),
|
|
133
|
+
stepMinutes: Type.Optional(Type.Number()),
|
|
134
|
+
})),
|
|
135
|
+
includeAlignedData: Type.Optional(Type.Boolean({ description: "Include transformed aligned rows in structured details. Defaults to false." })),
|
|
136
|
+
}),
|
|
137
|
+
async execute(_toolCallId, params: ComparisonToolParams, _signal, _onUpdate, ctx) {
|
|
138
|
+
const investigation = params.useInvestigationContext === false ? undefined : dependencies.investigationContext?.();
|
|
139
|
+
const analysis = investigation?.analysis;
|
|
140
|
+
const detrend = params.detrend ?? analysis?.detrend ?? "none";
|
|
141
|
+
const normalize = params.normalize ?? analysis?.normalize ?? "none";
|
|
142
|
+
if (detrend !== "none" && detrend !== "linear") throw new Error("detrend must be 'none' or 'linear'");
|
|
143
|
+
if (normalize !== "none" && normalize !== "zscore") throw new Error("normalize must be 'none' or 'zscore'");
|
|
144
|
+
const csvSpecs = (params.csvSeries ?? investigation?.csvSeries ?? []).map((spec) => ({
|
|
145
|
+
...spec,
|
|
146
|
+
timezoneOffsetMinutes: spec.timezoneOffsetMinutes ?? investigation?.timezoneOffsetMinutes,
|
|
147
|
+
}));
|
|
148
|
+
const qdashSpecs = (params.qdashSeries ?? investigation?.qdashSeries ?? []).map((spec) => ({
|
|
149
|
+
...spec,
|
|
150
|
+
tag: spec.tag ?? investigation?.tag,
|
|
151
|
+
}));
|
|
152
|
+
const csv = csvSpecs.flatMap((spec) => loadExternalCsvSeries(spec, ctx.cwd));
|
|
153
|
+
const qdash: NumericTimeseries[] = [];
|
|
154
|
+
let resolvedStartAt = params.startAt ?? investigation?.startAt;
|
|
155
|
+
let resolvedEndAt = params.endAt ?? investigation?.endAt;
|
|
156
|
+
if (qdashSpecs.length > 0) {
|
|
157
|
+
resolvedEndAt = resolvedEndAt ?? new Date().toISOString();
|
|
158
|
+
resolvedStartAt = resolvedStartAt ?? new Date(Date.parse(resolvedEndAt) - (params.withinHours ?? 168) * 3_600_000).toISOString();
|
|
159
|
+
const client = await dependencies.makeClient(params);
|
|
160
|
+
const chipId = await dependencies.defaultChipId(client, params.chipId);
|
|
161
|
+
const fetched = await Promise.all(qdashSpecs.map(async (spec) => {
|
|
162
|
+
const data = await client.getTaskResultsTimeseries({
|
|
163
|
+
chipId,
|
|
164
|
+
parameter: spec.parameter,
|
|
165
|
+
qid: spec.qid,
|
|
166
|
+
tag: spec.tag,
|
|
167
|
+
startAt: resolvedStartAt!,
|
|
168
|
+
endAt: resolvedEndAt!,
|
|
169
|
+
});
|
|
170
|
+
return { spec, points: timeseriesPoints(data) };
|
|
171
|
+
}));
|
|
172
|
+
for (const { spec, points } of fetched) {
|
|
173
|
+
const groups = new Map<string, typeof points>();
|
|
174
|
+
for (const point of points) {
|
|
175
|
+
if (!point.at) continue;
|
|
176
|
+
const group = spec.qid ?? point.series;
|
|
177
|
+
groups.set(group, [...(groups.get(group) ?? []), point]);
|
|
178
|
+
}
|
|
179
|
+
for (const [group, values] of groups) {
|
|
180
|
+
const suffix = spec.qid ? ` q${spec.qid}` : groups.size > 1 ? ` ${group}` : "";
|
|
181
|
+
qdash.push({
|
|
182
|
+
label: spec.label ? groups.size > 1 ? `${spec.label} ${group}` : spec.label : `${spec.parameter}${suffix}`,
|
|
183
|
+
unit: spec.unit ?? values.find((point) => point.unit)?.unit,
|
|
184
|
+
source: "qdash",
|
|
185
|
+
points: values.map((point) => ({
|
|
186
|
+
at: point.at!,
|
|
187
|
+
value: point.value * (spec.scale ?? 1) + (spec.offset ?? 0),
|
|
188
|
+
})),
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
const comparison = compareTimeseries([...qdash, ...csv], {
|
|
194
|
+
startAt: resolvedStartAt,
|
|
195
|
+
endAt: resolvedEndAt,
|
|
196
|
+
resampleMinutes: params.resampleMinutes ?? analysis?.resampleMinutes,
|
|
197
|
+
smoothingWindowMinutes: params.smoothingWindowMinutes ?? analysis?.smoothingWindowMinutes,
|
|
198
|
+
detrend,
|
|
199
|
+
normalize,
|
|
200
|
+
maxInterpolationGapMinutes: params.maxInterpolationGapMinutes ?? analysis?.maxInterpolationGapMinutes,
|
|
201
|
+
periodSearch: params.periodSearch ?? analysis?.periodSearch,
|
|
202
|
+
includeAlignedData: params.includeAlignedData,
|
|
203
|
+
});
|
|
204
|
+
return toTextToolResult(timeseriesComparisonText(comparison), comparison, {
|
|
205
|
+
tool: "qdash_compare_timeseries",
|
|
206
|
+
seriesCount: comparison.series.length,
|
|
207
|
+
investigation: investigation?.name,
|
|
208
|
+
});
|
|
209
|
+
},
|
|
210
|
+
});
|
|
211
|
+
}
|
package/package.json
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oqtopus-team/pi-qdash",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.6",
|
|
4
4
|
"description": "Pi extension for querying QDash via @oqtopus-team/qdash-client",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "Apache-2.0",
|
|
7
7
|
"author": "OQTOPUS Team <oqtopus-team@googlegroups.com>",
|
|
8
|
+
"engines": {
|
|
9
|
+
"node": ">=20.0.0"
|
|
10
|
+
},
|
|
8
11
|
"repository": {
|
|
9
12
|
"type": "git",
|
|
10
13
|
"url": "git+https://github.com/oqtopus-team/pi-qdash.git"
|
|
@@ -24,7 +27,7 @@
|
|
|
24
27
|
"access": "public"
|
|
25
28
|
},
|
|
26
29
|
"dependencies": {
|
|
27
|
-
"@oqtopus-team/qdash-client": "^
|
|
30
|
+
"@oqtopus-team/qdash-client": "^1.9.11"
|
|
28
31
|
},
|
|
29
32
|
"peerDependencies": {
|
|
30
33
|
"@earendil-works/pi-coding-agent": "*",
|
|
@@ -39,7 +42,8 @@
|
|
|
39
42
|
]
|
|
40
43
|
},
|
|
41
44
|
"scripts": {
|
|
42
|
-
"check": "tsc --noEmit"
|
|
45
|
+
"check": "tsc --noEmit",
|
|
46
|
+
"test": "rm -rf .test-dist && tsc --noEmit false --outDir .test-dist && node --test tests/*.test.mjs; status=$?; rm -rf .test-dist; exit $status"
|
|
43
47
|
},
|
|
44
48
|
"devDependencies": {
|
|
45
49
|
"@earendil-works/pi-coding-agent": "^0.74.0",
|
package/skills/qdash/SKILL.md
CHANGED
|
@@ -15,7 +15,7 @@ Use the pi-qdash tools instead of scraping the UI or hand-writing auth headers.
|
|
|
15
15
|
- `qdash_get_chip_metrics`, `qdash_list_chip_qubits`, `qdash_list_chip_couplings`
|
|
16
16
|
- `qdash_list_cryostats`, `qdash_list_cooldowns`
|
|
17
17
|
- `qdash_get_cooldown_wiring`, `qdash_wiring_insights`, `qdash_list_cooldown_wiring_events`
|
|
18
|
-
- `qdash_get_timeseries`, `qdash_plot_timeseries`
|
|
18
|
+
- `qdash_get_timeseries`, `qdash_plot_timeseries`, `qdash_inspect_timeseries_csv`, `qdash_compare_timeseries`
|
|
19
19
|
- `qdash_list_task_results`, `qdash_get_task_result`
|
|
20
20
|
- `qdash_list_issues`
|
|
21
21
|
- `qdash_list_flows`, `qdash_get_flow`
|
|
@@ -24,6 +24,7 @@ Use the pi-qdash tools instead of scraping the UI or hand-writing auth headers.
|
|
|
24
24
|
- `qdash_list_forum_posts`, `qdash_get_forum_post`, `qdash_list_forum_replies`
|
|
25
25
|
- `qdash_get_figure`, `qdash_get_task_figures`, `qdash_recent_calibration_figure`, `qdash_analyze_figure_json`, `qdash_build_qcal_evidence`
|
|
26
26
|
- `qdash_create_forum_evidence_reply` for confirmed evidence curation replies with visible task figures
|
|
27
|
+
- `qdash_preview_forum_image_reply`, then `qdash_create_forum_image_reply` for confirmed uploads of locally generated analysis images
|
|
27
28
|
3. Use harness overview tools for status and triage:
|
|
28
29
|
- `qdash_investigate` for natural-language requests to investigate or compare recent calibration, target history, figures, failures, issues, and Forum context
|
|
29
30
|
- `qdash_compare_calibration` for read-only before/after comparison of repeated target calibration results
|
|
@@ -64,6 +65,8 @@ Use these commands to make pi behave like a QDash-specific harness with persiste
|
|
|
64
65
|
/qdash-use-chip [chip_id]
|
|
65
66
|
/qdash-use-target qid <qid> | coupling <coupling_id>
|
|
66
67
|
/qdash-use-agent-session <session_id>
|
|
68
|
+
/qdash-investigation-setup [json]
|
|
69
|
+
/qdash-clear-investigation
|
|
67
70
|
/qdash-context
|
|
68
71
|
/qdash-dashboard [limit]
|
|
69
72
|
/qdash-wiring-insights
|
|
@@ -73,6 +76,43 @@ Use these commands to make pi behave like a QDash-specific harness with persiste
|
|
|
73
76
|
|
|
74
77
|
Prefer the current context when the user has already selected a profile/chip/session. Tools use that context when parameters are omitted.
|
|
75
78
|
|
|
79
|
+
## Cooldown-aware investigations
|
|
80
|
+
|
|
81
|
+
Treat cooldown identity as mandatory investigation context whenever comparing calibration results, coherence metrics, drift, failures, or Forum evidence across time:
|
|
82
|
+
|
|
83
|
+
1. Call `qdash_list_cooldowns` for the chip early in the investigation and record the relevant `cooldown_id`, `started_at`, and `ended_at` boundaries.
|
|
84
|
+
2. Assign every result or Forum observation used in a comparison to a cooldown. Prefer an explicit `cooldown_id`; when it is absent, infer membership only from the chip association and timestamp boundaries, and label it as inferred.
|
|
85
|
+
3. Do not describe values from different cooldowns as one continuous degradation, recovery, or before/after trend. Partition the evidence by cooldown first. Cross-cooldown comparison is allowed only when it is explicitly identified as such.
|
|
86
|
+
4. State plainly whether the compared evidence comes from the same cooldown, different cooldowns, or an unresolved cooldown context. Include the cooldown IDs in the report and in Forum evidence replies when relevant.
|
|
87
|
+
5. Same cooldown does not guarantee identical measurement conditions. If cabling, attenuation, instruments, or wiring may have changed, inspect `qdash_get_cooldown_wiring` with history or `qdash_list_cooldown_wiring_events`, then distinguish a cooldown boundary from an in-cooldown wiring change.
|
|
88
|
+
6. Do not treat a temporary disconnect/reconnect as a new cooldown unless QDash records a new cooldown. Describe it as an in-cooldown wiring event and report whether the wiring was nominally restored.
|
|
89
|
+
7. Prefer same-cooldown, temporally adjacent measurements for physical interpretation. Older-cooldown evidence may provide context but must not be used to explain a current-cooldown anomaly without an explicit caveat.
|
|
90
|
+
|
|
91
|
+
Before publishing investigated evidence, verify that every date-based claim respects these rules.
|
|
92
|
+
|
|
93
|
+
## Generic timeseries comparison
|
|
94
|
+
|
|
95
|
+
Use `qdash_compare_timeseries` when the investigation needs to align multiple
|
|
96
|
+
QDash metrics/targets, local CSV sensor logs, or both. For repeated calls, use
|
|
97
|
+
`/qdash-investigation-setup` to store the arbitrary series mappings, window,
|
|
98
|
+
timezone, and transform defaults; explicit tool arguments override the preset.
|
|
99
|
+
Do not assume a specific
|
|
100
|
+
CSV layout, metric name, target, unit, timestamp format, or timezone:
|
|
101
|
+
|
|
102
|
+
1. Inspect unknown CSV headers, numeric coverage, and optional time cadence with
|
|
103
|
+
`qdash_inspect_timeseries_csv` first.
|
|
104
|
+
2. Supply `timeColumn`, one or more `valueColumns`, and optional exact-match
|
|
105
|
+
`filters`; use `scale`/`offset` only for explicit unit conversion.
|
|
106
|
+
3. For timestamps without a zone, require an explicit
|
|
107
|
+
`timezoneOffsetMinutes` (JST is `540`) rather than relying on the host clock.
|
|
108
|
+
4. Start with raw/no-transform comparison, then state any smoothing,
|
|
109
|
+
interpolation, detrending, normalization, and period-search settings.
|
|
110
|
+
5. Report overlap duration, source point counts, aligned point count, number of
|
|
111
|
+
observed cycles, correlations, phases, and explained fractions together.
|
|
112
|
+
6. Treat correlation and shared periodicity as evidence of association. Do not
|
|
113
|
+
claim direct causality without intervention, longer observation, or evidence
|
|
114
|
+
that excludes a common driver.
|
|
115
|
+
|
|
76
116
|
For cryostat wiring requests, start with `qdash_get_cooldown_wiring`. Pass `cooldownId` when the user names one; otherwise pass `cryoId`, or omit both to resolve the active/newest cooldown from the current/default chip. Prefer the compact `wiring.markdown`; request raw blocks only when structural or embedded BlockNote data is necessary, and request history when investigating wiring changes. Set `includeInsights` or call `qdash_wiring_insights` when the user asks what is characteristic, unusual, or worth checking in attenuation; summarize control/readout totals and affected qubits/MUXes instead of dumping the raw table.
|
|
77
117
|
|
|
78
118
|
## Configuration
|
|
@@ -90,14 +130,15 @@ If `QDASH_BASE_URL` is set and no profile is specified, the tools default to env
|
|
|
90
130
|
|
|
91
131
|
When the user wants to preserve an investigated observation in QDash forum/notes:
|
|
92
132
|
|
|
93
|
-
1. Inspect the task result, task figure, timeseries/history,
|
|
94
|
-
2. Summarize the observation as evidence, not as an automatic calibration decision.
|
|
133
|
+
1. Inspect the task result, task figure, timeseries/history, related Forum context, and cooldown membership first.
|
|
134
|
+
2. Summarize the observation as evidence, not as an automatic calibration decision. State whether compared observations are from the same cooldown, and separate in-cooldown wiring changes from cooldown boundaries.
|
|
95
135
|
3. Prefer replying to an existing target/coupling forum thread when one exists.
|
|
96
136
|
4. Use `qdash_create_forum_evidence_reply` for task-result evidence so figures are embedded as QDash UI image blocks (`/api/executions/figure?path=...`) and visible in the forum.
|
|
97
|
-
5.
|
|
98
|
-
6.
|
|
99
|
-
7.
|
|
100
|
-
8.
|
|
137
|
+
5. For locally generated analysis images, call `qdash_preview_forum_image_reply` first, show the exact paths and reply text, then use `qdash_create_forum_image_reply` only after explicit confirmation. Supported images are PNG, JPEG, GIF, and WebP up to 5 MB each.
|
|
138
|
+
6. Include task and execution QDash Web URLs in the reply when applicable.
|
|
139
|
+
7. When mentioning history or trends, include links to representative historical task results.
|
|
140
|
+
8. Mark agent-authored evidence with a footer such as `— 🤖 by pi-qdash`.
|
|
141
|
+
9. Ask for confirmation before uploading images or creating/updating the forum post.
|
|
101
142
|
|
|
102
143
|
## Safety
|
|
103
144
|
|
|
@@ -32,7 +32,8 @@ This skill defines how pi should behave as a conservative, confirmation-gated ca
|
|
|
32
32
|
|
|
33
33
|
- Work one target at a time: one qubit or one coupling per action/session when possible.
|
|
34
34
|
- Diagnose before changing parameters.
|
|
35
|
-
-
|
|
35
|
+
- Establish cooldown identity before interpreting history: partition evidence by `cooldown_id`, never present different cooldowns as one continuous trend, and distinguish cooldown boundaries from in-cooldown wiring changes.
|
|
36
|
+
- Prefer read-only inspection first: dashboard, cooldowns and wiring events, failed task results, history, figures, forum posts, and task knowledge when available.
|
|
36
37
|
- Use narrow agent session policies with the smallest allowed task/action/parameter scope.
|
|
37
38
|
- Do not commit or apply parameter candidates until a validation task succeeds and the user explicitly confirms.
|
|
38
39
|
- Avoid blind parameter sweeps. If two conservative probes fail, step back to a diagnostic task.
|
|
@@ -42,6 +43,8 @@ This skill defines how pi should behave as a conservative, confirmation-gated ca
|
|
|
42
43
|
|
|
43
44
|
1. Establish context:
|
|
44
45
|
- profile and chip
|
|
46
|
+
- active/relevant `cooldown_id` and its time boundaries via `qdash_list_cooldowns`
|
|
47
|
+
- any in-cooldown wiring changes relevant to the target
|
|
45
48
|
- failed task(s)
|
|
46
49
|
- qid/coupling_id
|
|
47
50
|
- recent executions and open forum/issue context
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: qdash-timeseries-diagnosis
|
|
3
|
+
description: Diagnose common-mode drift, shared periodicity, phase relationships, and possible environmental coupling across arbitrary QDash metrics and external sensor CSV logs. Use when calibration metrics oscillate, drift together, appear delayed or anti-correlated, or may be influenced by cryostat/environmental cycles.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# QDash Timeseries Diagnosis
|
|
7
|
+
|
|
8
|
+
Use this skill for evidence-based multi-timeseries investigation. Keep the
|
|
9
|
+
measurement schema and physical interpretation separate: the comparison tool
|
|
10
|
+
extracts mechanical evidence, while this skill guides conclusions and next
|
|
11
|
+
checks.
|
|
12
|
+
|
|
13
|
+
## Principles
|
|
14
|
+
|
|
15
|
+
- Do not hard-code metric names, targets, sensors, units, CSV columns, periods,
|
|
16
|
+
or timezone assumptions.
|
|
17
|
+
- Preserve both raw and transformed results. A visually clean transformed plot
|
|
18
|
+
must not replace the raw evidence.
|
|
19
|
+
- Correlation, shared periodicity, and phase alignment establish association,
|
|
20
|
+
not causal direction.
|
|
21
|
+
- Consider a shared driver when multiple targets and an environmental sensor
|
|
22
|
+
move together. The sensor itself may be a proxy for an unmeasured actuator,
|
|
23
|
+
vibration, electrical noise, magnetic noise, or control cycle.
|
|
24
|
+
- Count observed cycles, not raw sample points, when judging periodic evidence.
|
|
25
|
+
- Resolve cooldown boundaries before interpreting drift or shared periodicity. Analyze each cooldown separately by default; never smooth, interpolate, correlate, or fit a period across a cooldown boundary unless an explicit cross-cooldown comparison is intended and clearly reported.
|
|
26
|
+
|
|
27
|
+
## Workflow
|
|
28
|
+
|
|
29
|
+
### 1. Fix the investigation scope
|
|
30
|
+
|
|
31
|
+
Record the reusable scope with `/qdash-investigation-setup` when multiple
|
|
32
|
+
comparison passes are expected. The JSON context accepts arbitrary QDash
|
|
33
|
+
series, CSV mappings, window/timezone, and transform defaults. Record:
|
|
34
|
+
|
|
35
|
+
- QDash profile and chip
|
|
36
|
+
- cooldown IDs and start/end boundaries from `qdash_list_cooldowns`
|
|
37
|
+
- any in-cooldown wiring events that overlap the window
|
|
38
|
+
- metrics and target IDs
|
|
39
|
+
- tags
|
|
40
|
+
- start/end timestamps
|
|
41
|
+
- timezone for every source
|
|
42
|
+
- expected cadence and units
|
|
43
|
+
- local CSV path, time column, value columns, and any row filters
|
|
44
|
+
|
|
45
|
+
For timestamps without an explicit zone, require a declared offset. Never infer
|
|
46
|
+
a timezone from the host machine.
|
|
47
|
+
|
|
48
|
+
### 2. Inspect source integrity
|
|
49
|
+
|
|
50
|
+
Before comparing, use `qdash_inspect_timeseries_csv` for local files whose
|
|
51
|
+
schema or time encoding is not already established. Use `qdash_list_cooldowns`
|
|
52
|
+
to split the requested window at cooldown boundaries, and inspect cooldown
|
|
53
|
+
wiring events when hardware conditions may have changed. Then:
|
|
54
|
+
|
|
55
|
+
- verify first/last timestamps and overlap
|
|
56
|
+
- check source point counts and cadence
|
|
57
|
+
- identify duplicate timestamps, missing intervals, and long gaps
|
|
58
|
+
- verify scale and offset conversions
|
|
59
|
+
- ensure labels are unique
|
|
60
|
+
|
|
61
|
+
Do not bridge long outages. Set `maxInterpolationGapMinutes` explicitly when the
|
|
62
|
+
default is unsuitable for the slowest source.
|
|
63
|
+
|
|
64
|
+
### 3. Establish a raw baseline
|
|
65
|
+
|
|
66
|
+
Call `qdash_compare_timeseries` first with:
|
|
67
|
+
|
|
68
|
+
- no smoothing
|
|
69
|
+
- no detrending
|
|
70
|
+
- no normalization
|
|
71
|
+
- no period search unless a period was specified independently
|
|
72
|
+
|
|
73
|
+
Report ranges, units, overlap, and raw correlation. Different units are fine for
|
|
74
|
+
correlation, but do not visually overlay incomparable scales without separate
|
|
75
|
+
axes or normalization.
|
|
76
|
+
|
|
77
|
+
### 4. Compare oscillatory components
|
|
78
|
+
|
|
79
|
+
When looking for common cycles, rerun with explicit settings such as:
|
|
80
|
+
|
|
81
|
+
- a smoothing window justified by source cadence
|
|
82
|
+
- `detrend: linear` when slow drift would dominate
|
|
83
|
+
- `normalize: zscore` for shape/phase comparison
|
|
84
|
+
- a period-search range chosen from prior evidence or a broad physically
|
|
85
|
+
plausible interval
|
|
86
|
+
|
|
87
|
+
Report all transform settings with the result. Compare:
|
|
88
|
+
|
|
89
|
+
- full transformed correlation
|
|
90
|
+
- selected shared period
|
|
91
|
+
- per-series periodic explained fraction
|
|
92
|
+
- pairwise phase differences
|
|
93
|
+
- observed cycle count
|
|
94
|
+
|
|
95
|
+
A near-0° phase difference indicates in-phase periodic components. A near-180°
|
|
96
|
+
difference indicates anti-phase components. Intermediate phase may represent a
|
|
97
|
+
delay, but phase alone does not identify response direction.
|
|
98
|
+
|
|
99
|
+
### 5. Grade the evidence conservatively
|
|
100
|
+
|
|
101
|
+
Use qualitative language:
|
|
102
|
+
|
|
103
|
+
- **weak**: unstable period/phase, low explained fraction, or fewer than about
|
|
104
|
+
three observed cycles
|
|
105
|
+
- **suggestive**: similar periods with plausible phase but short observation or
|
|
106
|
+
substantial residual variation
|
|
107
|
+
- **strong association**: repeated common period and stable phase across
|
|
108
|
+
multiple targets/sensors, with substantial explained fractions
|
|
109
|
+
- **causal evidence**: requires intervention, independently controlled input,
|
|
110
|
+
repeated response, or evidence excluding plausible shared drivers
|
|
111
|
+
|
|
112
|
+
These are reasoning categories, not fixed acceptance thresholds. Explain which
|
|
113
|
+
facts support the chosen category.
|
|
114
|
+
|
|
115
|
+
### 6. Test alternatives
|
|
116
|
+
|
|
117
|
+
For apparent environmental or cryostat coupling, distinguish:
|
|
118
|
+
|
|
119
|
+
1. the measured sensor variable directly affecting the metric
|
|
120
|
+
2. a controller/refrigerator cycle affecting both
|
|
121
|
+
3. periodic measurement or scheduling artifacts
|
|
122
|
+
4. timestamp offset or resampling artifacts
|
|
123
|
+
5. target-local behavior coincidentally near the same frequency
|
|
124
|
+
|
|
125
|
+
Check additional targets in different control/readout groups and, when
|
|
126
|
+
available, actuator state, compressor/pulse-tube, vibration, rack temperature,
|
|
127
|
+
magnetic field, pressure, and control-system logs.
|
|
128
|
+
|
|
129
|
+
### 7. Recommend discriminating measurements
|
|
130
|
+
|
|
131
|
+
Prefer measurements that separate hypotheses:
|
|
132
|
+
|
|
133
|
+
- extend observation to cover at least 8–10 candidate cycles
|
|
134
|
+
- preserve the same cadence and synchronized clocks
|
|
135
|
+
- record actuator/controller state in addition to sensor output
|
|
136
|
+
- test multiple targets and control/readout groups
|
|
137
|
+
- perform a safe controlled setpoint or operating-state change when authorized
|
|
138
|
+
- compare lag/phase stability across independent runs
|
|
139
|
+
|
|
140
|
+
Do not initiate operational changes without an explicit plan and user
|
|
141
|
+
confirmation.
|
|
142
|
+
|
|
143
|
+
## Reporting template
|
|
144
|
+
|
|
145
|
+
Include:
|
|
146
|
+
|
|
147
|
+
1. sources and exact time window
|
|
148
|
+
2. timezone and unit conversions
|
|
149
|
+
3. raw-data integrity and overlap
|
|
150
|
+
4. transformation settings
|
|
151
|
+
5. raw/transformed correlations
|
|
152
|
+
6. shared period, phase, explained fraction, and observed cycles
|
|
153
|
+
7. strongest association statement
|
|
154
|
+
8. causal alternatives still open
|
|
155
|
+
9. next measurement that best discriminates those alternatives
|
|
@@ -17,7 +17,8 @@ Use this skill when investigating coupling-level calibration quality, especially
|
|
|
17
17
|
|
|
18
18
|
- Treat `completed` as execution status, not proof of calibration quality.
|
|
19
19
|
- Diagnose from evidence before suggesting operational actions.
|
|
20
|
-
-
|
|
20
|
+
- Resolve cooldown membership before comparing calibrations or coherence limits. Keep different cooldowns separate, and distinguish a cooldown boundary from an in-cooldown wiring change.
|
|
21
|
+
- Prefer read-only tools first: `qdash_list_cooldowns`, `qdash_target_report`, `qdash_list_task_results`, `qdash_get_task_result`, `qdash_analyze_figure_json`, and `qdash_get_task_figures`.
|
|
21
22
|
- Do not rerun RB first when validation quality is suspicious. Walk back through prerequisites.
|
|
22
23
|
- Do not commit or apply candidates without explicit user confirmation, and only after downstream validation.
|
|
23
24
|
|
|
@@ -25,8 +26,8 @@ Use this skill when investigating coupling-level calibration quality, especially
|
|
|
25
26
|
|
|
26
27
|
For a coupling `cA-B`:
|
|
27
28
|
|
|
28
|
-
1. Build context with `qdash_target_report
|
|
29
|
-
2. Inspect the latest tasks in this chain:
|
|
29
|
+
1. Build context with `qdash_list_cooldowns`, `qdash_target_report`, and recent task results for the coupling. Record the cooldown ID for each result and inspect wiring events when measurement conditions may have changed.
|
|
30
|
+
2. Inspect the latest same-cooldown tasks in this chain by default:
|
|
30
31
|
- `CheckCrossResonance`
|
|
31
32
|
- `CreateZX90`
|
|
32
33
|
- `CheckZX90`
|