From 2f384e22b399ab541b344fd78ac84630ac19e3df Mon Sep 17 00:00:00 2001 From: Transaction Science Date: Mon, 26 Oct 2026 08:17:10 -0400 Subject: [PATCH] Quantum Studio: a program from elsewhere is named for where it came from The Versions pane said "started by the start (the example Bell pair)". A version from elsewhere now reads "started from the example Bell pair", or "opened the file x.qasm", and a merge's detail reads "merged by you, from v4 and v6". The Studio's browser test checks the first version's name. Co-Authored-By: Claude Opus 5.5 --- wai/quantum-studio/src/versions.js | 11 +++++++---- wai/quantum-studio/test/studio.test.mjs | 4 +++- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/wai/quantum-studio/src/versions.js b/wai/quantum-studio/src/versions.js index d56cdc5e3..792d48961 100644 --- a/wai/quantum-studio/src/versions.js +++ b/wai/quantum-studio/src/versions.js @@ -18,9 +18,12 @@ export const HANDS = { person: 'you', assistant: 'the assistant', agent: 'an agent', engine: 'the engine', origin: 'where it came from', assistant_then_person: 'the assistant, then you', agent_then_person: 'an agent, then you', }; -const KINDS = { person: 'you', assistant: 'the assistant', agent: 'an agent', engine: 'the engine', origin: 'the start' }; +const KINDS = { person: 'you', assistant: 'the assistant', agent: 'an agent', engine: 'the engine' }; const HOW = { start: 'started', edit: 'edited', proposal: 'proposed', merge: 'merged' }; -export const whoName = (by) => `${KINDS[by?.kind] || by?.kind || '?'}${by?.name ? ` (${by.name})` : ''}`; +// Who, as the reader is told: a program from elsewhere is named for where it came from. +export const whoName = (by) => (by?.kind === 'origin' ? by.name || 'where it came from' : `${KINDS[by?.kind] || by?.kind || '?'}${by?.name ? ` (${by.name})` : ''}`); +// How a version was made, and by whom: “edited by you”, “started from the example Bell pair”. +const made = (v) => (v.by?.kind === 'origin' ? `${v.how === 'start' ? 'started from' : 'opened'} ${whoName(v.by)}` : `${HOW[v.how] || v.how} by ${whoName(v.by)}`); const plural = (n, w) => `${n} ${w}${n === 1 ? '' : 's'}`; const svg = (tag, attrs = {}) => { @@ -229,7 +232,7 @@ export function versionsPane({ engine, text, setText, inputs, lock, reviewHost, if (heads.includes(v.id) && v.id !== current) actions.push(el('button', { class: 'qs-btn qs-small', id: 'qs-vs-merge', type: 'button', text: `Bring ${v.id} in`, title: 'Review its changes against the program and take the ones you want; recorded as a merge', onclick: () => review(v.source, { kind: 'person' }, null, { merge: v.id }) })); const r = v.review; detail.replaceChildren( - el('p', { class: 'qs-vs-what' }, el('b', { text: v.id }), el('span', { text: ` ${HOW[v.how] || v.how} by ${whoName(v.by)}${v.parents?.length ? ` from ${v.parents.join(' and ')}` : ''}, ${new Date(v.at).toLocaleString()}` })), + el('p', { class: 'qs-vs-what' }, el('b', { text: v.id }), el('span', { text: ` ${made(v)}${v.parents?.length ? `, from ${v.parents.join(' and ')}` : ''}, ${new Date(v.at).toLocaleString()}` })), v.note ? el('p', { class: 'qs-note', text: v.note }) : null, r ? el('p', { class: 'qs-note', id: 'qs-vs-review', text: `${r.accepted.length} of ${plural(r.offered, 'change')} taken${r.accepted.length < r.offered ? '; the rest were rejected, and the whole proposal is kept below' : ''}.` }) : null, r && r.accepted.length < r.offered ? el('details', {}, el('summary', { text: 'The whole proposal' }), el('pre', { class: 'qs-ai-code', text: r.proposed })) : null, @@ -256,7 +259,7 @@ export function versionsPane({ engine, text, setText, inputs, lock, reviewHost, return el('li', { 'data-id': v.id, class: v.id === current ? 'here' : '' }, el('button', { type: 'button', class: 'qs-vs-item', onclick: () => showDetail(v, log) }, el('span', { class: 'qs-vs-id', text: v.id }), - el('span', { class: 'qs-vs-by', text: `${HOW[v.how] || v.how} by ${whoName(v.by)}` }), + el('span', { class: 'qs-vs-by', text: made(v) }), el('span', { class: 'qs-note', text: `${e.review ? `${e.review.accepted} of ${e.review.offered} taken · ` : ''}+${e.added ?? 0} −${e.removed ?? 0}${tags.length ? ` · ${tags.join(', ')}` : ''}` }))); })); const b = await blame().catch(() => null); diff --git a/wai/quantum-studio/test/studio.test.mjs b/wai/quantum-studio/test/studio.test.mjs index a69a0bd7b..b1047d6bb 100644 --- a/wai/quantum-studio/test/studio.test.mjs +++ b/wai/quantum-studio/test/studio.test.mjs @@ -231,6 +231,8 @@ const chip = (k) => page.$eval(`#qs-measures [data-k=${k}]`, (c) => c.textConten await setProgram(BASE); await record(); check(/edited by you/.test(await here()), `what the reader types is recorded as theirs (${await here()})`); + const first = await page.textContent('#qs-vs-list li:last-child'); + check(/^v0started from the example /.test(first), `the first version is named for where the program came from (${first})`); const mine = await page.$eval('#qs-vs-list li.here', (l) => l.dataset.id); const PROPOSED = 'OPENQASM 3.0;\nqubit[3] q;\nbit[3] c;\nh q[1];\ncx q[0], q[1];\ncx q[1], q[2];\nc = measure q;\n'; await page.evaluate((q) => { window.quantumStudio.propose(q, { kind: 'assistant', name: 'scripted' }, 'entangle the third qubit'); }, PROPOSED); @@ -280,7 +282,7 @@ const chip = (k) => page.$eval(`#qs-measures [data-k=${k}]`, (c) => c.textConten await page.click('#qs-review-apply'); await page.waitForFunction(() => /merged by you/.test(document.querySelector('#qs-vs-list li.here')?.textContent ?? ''), null, { timeout: LONG }); const merged = await doc(); - check(/x q\[2\];/.test(merged) && /cx q\[0\], q\[2\];/.test(merged) && /from v\d+ and v\d+/.test(await page.textContent('#qs-vs-detail')), + check(/x q\[2\];/.test(merged) && /cx q\[0\], q\[2\];/.test(merged) && /, from v\d+ and v\d+/.test(await page.textContent('#qs-vs-detail')), `bringing a line of work back in is a merge of both (${other}, ${otherHead})`); check(/the assistant, then you \(scripted\): 1 gate/.test(await page.textContent('#qs-vs-share')), 'the merge keeps each line’s author'); const count = (await page.$$('#qs-vs-list li')).length; -- 2.54.0 (Apple Git-157)