feat(amicode): system card renders the recorded Hamiltonian, and stops inventing one - #93

Merged
jack-champagne merged 4 commits into
local/amicodefrom
feat/amicode-system-card-model
Jul 29, 2026
Merged

feat(amicode): system card renders the recorded Hamiltonian, and stops inventing one#93
jack-champagne merged 4 commits into
local/amicodefrom
feat/amicode-system-card-model

Conversation

@aarontrowbridge

Copy link
Copy Markdown
Member

The System card re-derived the Hamiltonian in the renderer from (role, levels, platform) using hardcoded tables. So it could only ever be right for platforms someone had hardcoded, and was confidently wrong for the rest — most recently showing the transmon ladder, and asking for an anharmonicity, on an exchange-only spin qubit.

Recording half of this is harmoniqs/amicode#AMICODE_PR.

Three commits

1 · per-component physics rows — the row list was a fixed transmon spec (frequency · anharmonicity · drive bound · decay) emitted for every component, while the Hamiltonian directly above it was role-aware. A Rydberg atom got asked for its anharmonicity. Rows now come from the component's model; params it doesn't have are absent, not shown as unanswered. Units are never assumed (transmon params are GHz, the Rydberg templates work in rad/µs) — a unit renders only when the recorded key spells it.

2 · Hamiltonian composed over the actual component and edge sets — the old composer deduped term strings over the set of distinct roles, so it rendered "which kinds of term appear", not the Hamiltonian of the system. It meant: a 2-atom and a 20-atom register rendered identically; an N-edge chain rendered one edge hardcoded to sites (1),(2); a qubit and a cavity both used â; the drive-arch badge had no counterpart in the equation; + -Δ printed literally; and \hat ^\dagger (a KaTeX error box) for any exchange/CR/mode-mediated edge with a non-bosonic endpoint. Now: components group by model and sum over their site indices, each bosonic group gets its own operator letter, like edges aggregate into Σ_⟨ij⟩, and the drive arch decides whether a control carries a site index — Ω(t) shared, Ω_i(t) per site, Ω_z(i)(t) per zone.

3 · recorded beats inferredsystemHamiltonian() returns {latex, source}. A model recorded on the entity renders verbatim; otherwise the canonical form renders under an inferred · confirm or correct label. When nothing is recorded and nothing is modelled the card says "not recorded" rather than showing Ĥ_drift + Ĥ_c(t) — true of every control problem ever posed, and it would occupy the slot the real model belongs in.

The rule that matters

Two separate leaks put the transmon model on a spin qubit, and the second is the subtle one:

  • platformDefaultRole maps every unfamiliar platform to "qubit" — fixed on the plugin side.
  • levels >= 3 was read as "anharmonic ladder". It is not. Three levels is a Hilbert-space dimension: an exchange-only qubit at levels=3 is three dots; a spin-1 defect is three Zeeman sublevels. Neither is an oscillator.

So the platform is now the only thing that licenses a ladder for a qubit role. levels=2 still earns the generic two-level model — safe anywhere, since every two-level system has an ω σ_z/2 splitting and σx/σy control. Everything else is opaque.

One classify() drives both the equation and the physics rows, so the two halves of the card cannot describe different physics again.

Bonus: a three-way drift

The ladder drive was a single ε(t)(â+â†), while the plugin's TRANSMON_LATEX (what Amico shows in chat) and Piccolo's n_drives = 2 both say two quadratures. Same device, same session, two different answers — nobody had noticed because both look plausible. Two is correct; the card now matches.

What it looks like

exchange-only-spin · 1 qubit × 3 levels · per-component drive
HAMILTONIAN not recorded
No model for this platform yet — tell Amico the terms.
LEVELS 3
transmon · 1 qubit × 3 levels · per-component drive
HAMILTONIAN inferred · confirm or correct
Ĥ/ℏ = ω â†â + δ/2 ↲Ⲡ+ u₁(t)(â+â†) + i u₂(t)(â−â†)

Verification

399 pass across 30 files, tsgo clean. The KaTeX sweep crosses role × coupling kind × drive arch × N × platform (~8k systems) and asserts both directions: every rendered system parses, no output when nothing is modelled, and never a model invented for an all-unmodelled system.

Branched off local/amicode; these three commits are extracted from a local integration branch and touch only the system-card files.

🤖 Generated with Claude Code

@aarontrowbridge
aarontrowbridgeforce-pushed the feat/amicode-system-card-model branch from ac7078f to 4118aaaCompareJuly 28, 2026 21:52
aarontrowbridge added a commit to harmoniqs/amicode that referenced this pull request Jul 28, 2026
…bricating roles
The System card re-derives the Hamiltonian in the renderer from (role, levels,
platform) with hardcoded tables, so it is only ever right for platforms someone
hardcoded — and silently wrong for the rest. It showed the transmon ladder, and
asked for an anharmonicity, on an exchange-only spin qubit. Two changes here; the
renderer half is harmoniqs/opencode#93.
1. `amicode_set_model` gains `hamiltonian` — the model term by term
({kind: drift|coupling|drive, latex, acts_on?, label?}) plus `hamiltonian_notes`
for frame/unit/basis conventions. The agent already understands the model well
enough to author the Julia solve; this is where that understanding gets written
down instead of evaporating into the script. It knows what an exchange-only spin
qubit is — the renderer's table never will. Full path: validation (closed kind
set, non-empty latex, acts_on ids must exist, brace balance since the plugin
can't parse LaTeX but the card renders it straight into KaTeX), TOML round-trip,
wholesale patch-replace, hashing, normalizeSystem read-through.
2. `role` gains `other`, and `platformDefaultRole` stops inventing one. Only
platforms we model get a role from the string (rydberg→atom, transmon→qubit,
bosonic→mode); everything else is `other` until MODEL asks. The old blanket
"unknown → qubit" was also wrong for photonic and bosonic, which are modes.
AGENTS.md tells the interview to record the Hamiltonian — mandatory off-template,
worth confirming even on template — and to use `other` over a near-miss.
Note for the reviewer: this lands the recording side. The card only renders it once
the fork release carrying #93 is pinned via `pnpm opencode:pin`, so there
is no lock bump here.
Verified: 782 tests pass (78 files), tsc clean.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
aarontrowbridgeand others added 3 commits July 28, 2026 18:51
The card made its component-count claim implicitly, so an unanswered 'how many
atoms?' read as 'one'. systemCountLabel now states it as its own badge ('2 atoms
x 3 levels') that a researcher can read and correct.
componentPhysicsRows renders what each role actually has, in card order:
- unanswered params read 'not set', so the list doubles as the interview's to-do
- anything else on file is still shown, so nothing recorded is dropped
- an unrecognized role expects NOTHING -- the honest floor for a platform we have
no model for
- units are never assumed (transmon params are GHz, the Rydberg templates work in
rad/us, a bare omega says which only by convention), so a unit appears only when
the recorded key spells it out
- a zero keeps the '0 means unset' reading, so an all-zeros seed does not look
like a specified device
driftTerm now keys the qubit ladder off LEVELS rather than off whether delta
happens to be filled in: a 3-level transmon with empty params is still an
anharmonic ladder, and rendering it as a bare spin misstates the model the solve
will use. A mode's Kerr stays params-driven, since a linear cavity genuinely has
none.
Continues 0793fd6. Committed on the author's behalf as part of folding the
worktree's in-progress work onto the branch; the content is theirs.
+169 lines of tests alongside +278 of implementation; ui suite 442 -> 448 pass.
…f-template
The card re-derived the Hamiltonian in the renderer from (role, levels, platform)
using hardcoded tables, so it could only ever be right for platforms someone had
hardcoded. Two separate leaks put the transmon model on a spin qubit:
- `platformDefaultRole` maps every unfamiliar platform to "qubit", so an
exchange-only HRL spin qubit arrived indistinguishable from a transmon.
- levels >= 3 was read as "anharmonic ladder". It is not. Three levels is a
Hilbert-space DIMENSION: an exchange-only qubit at levels=3 is three dots, a
spin-1 defect is three Zeeman sublevels. Neither is an oscillator.
So the platform is now the only thing that licenses a ladder for a `qubit` role
(transmon, bosonic). levels=2 still earns the generic two-level model, which is
safe on any platform — every two-level system has an ω σ_z/2 splitting and σx/σy
control. Everything else is opaque.
Recorded beats inferred. `systemHamiltonian()` returns {latex, source}: a model
recorded on the entity (amicode_set_model's `hamiltonian`, see harmoniqs/amicode#220) renders
verbatim; otherwise the canonical form for the platform renders under an
"inferred · confirm or correct" label. When nothing is recorded AND nothing is
modelled the card says "not recorded" rather than showing `Ĥ_drift + Ĥ_c(t)`, which
is true of every control problem ever posed and would occupy the slot the real model
belongs in. Mixed systems still get a named placeholder per unmodelled component.
One `classify()` now drives both the equation and the physics rows, so the two
halves of the card cannot describe different physics again.
Also fixes a three-way drift found while doing this: the ladder drive was a single
`ε(t)(â+â†)` while the plugin's TRANSMON_LATEX (shown in chat) and Piccolo's
n_drives = 2 both say two quadratures. Two is correct; the card now matches.
Verified: 399 pass across 30 files, tsgo clean. The KaTeX sweep now crosses the
platform axis too (8k systems) and asserts BOTH directions: no output when nothing
is modelled, and never a model invented for an all-unmodelled system.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@jack-champagne
jack-champagneforce-pushed the feat/amicode-system-card-model branch from 4118aaa to e4e0133CompareJuly 28, 2026 22:52
… once
The sweep enumerates ~8k systems, but they collapse onto a few hundred distinct
equations, and KaTeX is the expensive part. Rendering the same string 200 times
proves nothing and took 22s on CI against a 5s default timeout (it passed locally
on a fast machine, and I had only been running src/amicode — CI runs all of src).
Coverage is unchanged: every distinct output is still parsed, and the mapping back
to a producing system is kept for the failure message. Adds an assertion that the
sweep really does vary its output, so a future change that collapses everything to
one equation can't quietly pass.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
jack-champagne added a commit that referenced this pull request Jul 29, 2026
…t tests (#98)
The three `session.llm native recorded` scenarios are the only failures on
`local/amicode`, so the fork's `test` job is red and every PR into it inherits a
red check — including #93, whose own suite is 3366 pass / 3 fail with zero
failures of its own.
Cause is ours. AMICODE-PATCHES.md ADDENDUM 2 consolidated the prompt so
`system.ts provider()` returns `[providerBase(model), PROMPT_COMMUNICATING]`,
appending `communicating.txt` for every model family. The cassettes still record
the pre-patch prompt, so all three break on a diff of prose.
Those tests assert TRANSPORT mechanics — that a tool loop is driven to a final
text answer. The prompt is incidental, so matching on it couples them to text
they do not test. Patching the recorded prompt instead would work until the next
prompt edit, and that patch already has three addenda.
`RecorderOptions.match` is an existing seam (types.ts:85, threaded through
`http()` to `recordingLayer`) that nothing used. Adds `promptAgnosticMatcher`
alongside `defaultMatcher` and passes it from this one test.
The prompt arrives in three shapes, all covered:
instructions OpenAI Responses
system[] Anthropic Messages
input[].role=="system" the OpenCode proxy
System-message content is replaced with a placeholder rather than deleted, so
"a system message is present, with content" stays part of the match.
Verified narrow, in test/matching.test.ts: it ignores prompt prose in all three
shapes, and still rejects a different user message, model, tool set, URL, or a
missing-vs-present system message. 49 pass in http-recorder; the three recorded
scenarios go 3 fail -> 3 pass; typecheck green across 23 packages.
@jack-champagne
jack-champagne merged commit 9bd4649 into local/amicodeJul 29, 2026
1 of 4 checks passed
@jack-champagne
jack-champagne deleted the feat/amicode-system-card-model branch July 29, 2026 02:38
jack-champagne pushed a commit to harmoniqs/amicode that referenced this pull request Jul 29, 2026
…bricating roles (#220)
The System card re-derives the Hamiltonian in the renderer from (role, levels,
platform) with hardcoded tables, so it is only ever right for platforms someone
hardcoded — and silently wrong for the rest. It showed the transmon ladder, and
asked for an anharmonicity, on an exchange-only spin qubit. Two changes here; the
renderer half is harmoniqs/opencode#93.
1. `amicode_set_model` gains `hamiltonian` — the model term by term
({kind: drift|coupling|drive, latex, acts_on?, label?}) plus `hamiltonian_notes`
for frame/unit/basis conventions. The agent already understands the model well
enough to author the Julia solve; this is where that understanding gets written
down instead of evaporating into the script. It knows what an exchange-only spin
qubit is — the renderer's table never will. Full path: validation (closed kind
set, non-empty latex, acts_on ids must exist, brace balance since the plugin
can't parse LaTeX but the card renders it straight into KaTeX), TOML round-trip,
wholesale patch-replace, hashing, normalizeSystem read-through.
2. `role` gains `other`, and `platformDefaultRole` stops inventing one. Only
platforms we model get a role from the string (rydberg→atom, transmon→qubit,
bosonic→mode); everything else is `other` until MODEL asks. The old blanket
"unknown → qubit" was also wrong for photonic and bosonic, which are modes.
AGENTS.md tells the interview to record the Hamiltonian — mandatory off-template,
worth confirming even on template — and to use `other` over a near-miss.
Note for the reviewer: this lands the recording side. The card only renders it once
the fork release carrying #93 is pinned via `pnpm opencode:pin`, so there
is no lock bump here.
Verified: 782 tests pass (78 files), tsc clean.
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@aarontrowbridge@jack-champagne
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

feat(amicode): system card renders the recorded Hamiltonian, and stops inventing one - #93

Merged
jack-champagne merged 4 commits into
local/amicodefrom
feat/amicode-system-card-model
Jul 29, 2026
Merged

feat(amicode): system card renders the recorded Hamiltonian, and stops inventing one#93
jack-champagne merged 4 commits into
local/amicodefrom
feat/amicode-system-card-model

Conversation

@aarontrowbridge

Copy link
Copy Markdown
Member

The System card re-derived the Hamiltonian in the renderer from (role, levels, platform) using hardcoded tables. So it could only ever be right for platforms someone had hardcoded, and was confidently wrong for the rest — most recently showing the transmon ladder, and asking for an anharmonicity, on an exchange-only spin qubit.

Recording half of this is harmoniqs/amicode#AMICODE_PR.

Three commits

1 · per-component physics rows — the row list was a fixed transmon spec (frequency · anharmonicity · drive bound · decay) emitted for every component, while the Hamiltonian directly above it was role-aware. A Rydberg atom got asked for its anharmonicity. Rows now come from the component's model; params it doesn't have are absent, not shown as unanswered. Units are never assumed (transmon params are GHz, the Rydberg templates work in rad/µs) — a unit renders only when the recorded key spells it.

2 · Hamiltonian composed over the actual component and edge sets — the old composer deduped term strings over the set of distinct roles, so it rendered "which kinds of term appear", not the Hamiltonian of the system. It meant: a 2-atom and a 20-atom register rendered identically; an N-edge chain rendered one edge hardcoded to sites (1),(2); a qubit and a cavity both used â; the drive-arch badge had no counterpart in the equation; + -Δ printed literally; and \hat ^\dagger (a KaTeX error box) for any exchange/CR/mode-mediated edge with a non-bosonic endpoint. Now: components group by model and sum over their site indices, each bosonic group gets its own operator letter, like edges aggregate into Σ_⟨ij⟩, and the drive arch decides whether a control carries a site index — Ω(t) shared, Ω_i(t) per site, Ω_z(i)(t) per zone.

3 · recorded beats inferredsystemHamiltonian() returns {latex, source}. A model recorded on the entity renders verbatim; otherwise the canonical form renders under an inferred · confirm or correct label. When nothing is recorded and nothing is modelled the card says "not recorded" rather than showing Ĥ_drift + Ĥ_c(t) — true of every control problem ever posed, and it would occupy the slot the real model belongs in.

The rule that matters

Two separate leaks put the transmon model on a spin qubit, and the second is the subtle one:

  • platformDefaultRole maps every unfamiliar platform to "qubit" — fixed on the plugin side.
  • levels >= 3 was read as "anharmonic ladder". It is not. Three levels is a Hilbert-space dimension: an exchange-only qubit at levels=3 is three dots; a spin-1 defect is three Zeeman sublevels. Neither is an oscillator.

So the platform is now the only thing that licenses a ladder for a qubit role. levels=2 still earns the generic two-level model — safe anywhere, since every two-level system has an ω σ_z/2 splitting and σx/σy control. Everything else is opaque.

One classify() drives both the equation and the physics rows, so the two halves of the card cannot describe different physics again.

Bonus: a three-way drift

The ladder drive was a single ε(t)(â+â†), while the plugin's TRANSMON_LATEX (what Amico shows in chat) and Piccolo's n_drives = 2 both say two quadratures. Same device, same session, two different answers — nobody had noticed because both look plausible. Two is correct; the card now matches.

What it looks like

exchange-only-spin · 1 qubit × 3 levels · per-component drive
HAMILTONIAN not recorded
No model for this platform yet — tell Amico the terms.
LEVELS 3
transmon · 1 qubit × 3 levels · per-component drive
HAMILTONIAN inferred · confirm or correct
Ĥ/ℏ = ω â†â + δ/2 ↲Ⲡ+ u₁(t)(â+â†) + i u₂(t)(â−â†)

Verification

399 pass across 30 files, tsgo clean. The KaTeX sweep crosses role × coupling kind × drive arch × N × platform (~8k systems) and asserts both directions: every rendered system parses, no output when nothing is modelled, and never a model invented for an all-unmodelled system.

Branched off local/amicode; these three commits are extracted from a local integration branch and touch only the system-card files.

🤖 Generated with Claude Code

@aarontrowbridge
aarontrowbridgeforce-pushed the feat/amicode-system-card-model branch from ac7078f to 4118aaaCompareJuly 28, 2026 21:52
aarontrowbridge added a commit to harmoniqs/amicode that referenced this pull request Jul 28, 2026
…bricating roles
The System card re-derives the Hamiltonian in the renderer from (role, levels,
platform) with hardcoded tables, so it is only ever right for platforms someone
hardcoded — and silently wrong for the rest. It showed the transmon ladder, and
asked for an anharmonicity, on an exchange-only spin qubit. Two changes here; the
renderer half is harmoniqs/opencode#93.
1. `amicode_set_model` gains `hamiltonian` — the model term by term
({kind: drift|coupling|drive, latex, acts_on?, label?}) plus `hamiltonian_notes`
for frame/unit/basis conventions. The agent already understands the model well
enough to author the Julia solve; this is where that understanding gets written
down instead of evaporating into the script. It knows what an exchange-only spin
qubit is — the renderer's table never will. Full path: validation (closed kind
set, non-empty latex, acts_on ids must exist, brace balance since the plugin
can't parse LaTeX but the card renders it straight into KaTeX), TOML round-trip,
wholesale patch-replace, hashing, normalizeSystem read-through.
2. `role` gains `other`, and `platformDefaultRole` stops inventing one. Only
platforms we model get a role from the string (rydberg→atom, transmon→qubit,
bosonic→mode); everything else is `other` until MODEL asks. The old blanket
"unknown → qubit" was also wrong for photonic and bosonic, which are modes.
AGENTS.md tells the interview to record the Hamiltonian — mandatory off-template,
worth confirming even on template — and to use `other` over a near-miss.
Note for the reviewer: this lands the recording side. The card only renders it once
the fork release carrying #93 is pinned via `pnpm opencode:pin`, so there
is no lock bump here.
Verified: 782 tests pass (78 files), tsc clean.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
aarontrowbridgeand others added 3 commits July 28, 2026 18:51
The card made its component-count claim implicitly, so an unanswered 'how many
atoms?' read as 'one'. systemCountLabel now states it as its own badge ('2 atoms
x 3 levels') that a researcher can read and correct.
componentPhysicsRows renders what each role actually has, in card order:
- unanswered params read 'not set', so the list doubles as the interview's to-do
- anything else on file is still shown, so nothing recorded is dropped
- an unrecognized role expects NOTHING -- the honest floor for a platform we have
no model for
- units are never assumed (transmon params are GHz, the Rydberg templates work in
rad/us, a bare omega says which only by convention), so a unit appears only when
the recorded key spells it out
- a zero keeps the '0 means unset' reading, so an all-zeros seed does not look
like a specified device
driftTerm now keys the qubit ladder off LEVELS rather than off whether delta
happens to be filled in: a 3-level transmon with empty params is still an
anharmonic ladder, and rendering it as a bare spin misstates the model the solve
will use. A mode's Kerr stays params-driven, since a linear cavity genuinely has
none.
Continues 0793fd6. Committed on the author's behalf as part of folding the
worktree's in-progress work onto the branch; the content is theirs.
+169 lines of tests alongside +278 of implementation; ui suite 442 -> 448 pass.
…f-template
The card re-derived the Hamiltonian in the renderer from (role, levels, platform)
using hardcoded tables, so it could only ever be right for platforms someone had
hardcoded. Two separate leaks put the transmon model on a spin qubit:
- `platformDefaultRole` maps every unfamiliar platform to "qubit", so an
exchange-only HRL spin qubit arrived indistinguishable from a transmon.
- levels >= 3 was read as "anharmonic ladder". It is not. Three levels is a
Hilbert-space DIMENSION: an exchange-only qubit at levels=3 is three dots, a
spin-1 defect is three Zeeman sublevels. Neither is an oscillator.
So the platform is now the only thing that licenses a ladder for a `qubit` role
(transmon, bosonic). levels=2 still earns the generic two-level model, which is
safe on any platform — every two-level system has an ω σ_z/2 splitting and σx/σy
control. Everything else is opaque.
Recorded beats inferred. `systemHamiltonian()` returns {latex, source}: a model
recorded on the entity (amicode_set_model's `hamiltonian`, see harmoniqs/amicode#220) renders
verbatim; otherwise the canonical form for the platform renders under an
"inferred · confirm or correct" label. When nothing is recorded AND nothing is
modelled the card says "not recorded" rather than showing `Ĥ_drift + Ĥ_c(t)`, which
is true of every control problem ever posed and would occupy the slot the real model
belongs in. Mixed systems still get a named placeholder per unmodelled component.
One `classify()` now drives both the equation and the physics rows, so the two
halves of the card cannot describe different physics again.
Also fixes a three-way drift found while doing this: the ladder drive was a single
`ε(t)(â+â†)` while the plugin's TRANSMON_LATEX (shown in chat) and Piccolo's
n_drives = 2 both say two quadratures. Two is correct; the card now matches.
Verified: 399 pass across 30 files, tsgo clean. The KaTeX sweep now crosses the
platform axis too (8k systems) and asserts BOTH directions: no output when nothing
is modelled, and never a model invented for an all-unmodelled system.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@jack-champagne
jack-champagneforce-pushed the feat/amicode-system-card-model branch from 4118aaa to e4e0133CompareJuly 28, 2026 22:52
… once
The sweep enumerates ~8k systems, but they collapse onto a few hundred distinct
equations, and KaTeX is the expensive part. Rendering the same string 200 times
proves nothing and took 22s on CI against a 5s default timeout (it passed locally
on a fast machine, and I had only been running src/amicode — CI runs all of src).
Coverage is unchanged: every distinct output is still parsed, and the mapping back
to a producing system is kept for the failure message. Adds an assertion that the
sweep really does vary its output, so a future change that collapses everything to
one equation can't quietly pass.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
jack-champagne added a commit that referenced this pull request Jul 29, 2026
…t tests (#98)
The three `session.llm native recorded` scenarios are the only failures on
`local/amicode`, so the fork's `test` job is red and every PR into it inherits a
red check — including #93, whose own suite is 3366 pass / 3 fail with zero
failures of its own.
Cause is ours. AMICODE-PATCHES.md ADDENDUM 2 consolidated the prompt so
`system.ts provider()` returns `[providerBase(model), PROMPT_COMMUNICATING]`,
appending `communicating.txt` for every model family. The cassettes still record
the pre-patch prompt, so all three break on a diff of prose.
Those tests assert TRANSPORT mechanics — that a tool loop is driven to a final
text answer. The prompt is incidental, so matching on it couples them to text
they do not test. Patching the recorded prompt instead would work until the next
prompt edit, and that patch already has three addenda.
`RecorderOptions.match` is an existing seam (types.ts:85, threaded through
`http()` to `recordingLayer`) that nothing used. Adds `promptAgnosticMatcher`
alongside `defaultMatcher` and passes it from this one test.
The prompt arrives in three shapes, all covered:
instructions OpenAI Responses
system[] Anthropic Messages
input[].role=="system" the OpenCode proxy
System-message content is replaced with a placeholder rather than deleted, so
"a system message is present, with content" stays part of the match.
Verified narrow, in test/matching.test.ts: it ignores prompt prose in all three
shapes, and still rejects a different user message, model, tool set, URL, or a
missing-vs-present system message. 49 pass in http-recorder; the three recorded
scenarios go 3 fail -> 3 pass; typecheck green across 23 packages.
@jack-champagne
jack-champagne merged commit 9bd4649 into local/amicodeJul 29, 2026
1 of 4 checks passed
@jack-champagne
jack-champagne deleted the feat/amicode-system-card-model branch July 29, 2026 02:38
jack-champagne pushed a commit to harmoniqs/amicode that referenced this pull request Jul 29, 2026
…bricating roles (#220)
The System card re-derives the Hamiltonian in the renderer from (role, levels,
platform) with hardcoded tables, so it is only ever right for platforms someone
hardcoded — and silently wrong for the rest. It showed the transmon ladder, and
asked for an anharmonicity, on an exchange-only spin qubit. Two changes here; the
renderer half is harmoniqs/opencode#93.
1. `amicode_set_model` gains `hamiltonian` — the model term by term
({kind: drift|coupling|drive, latex, acts_on?, label?}) plus `hamiltonian_notes`
for frame/unit/basis conventions. The agent already understands the model well
enough to author the Julia solve; this is where that understanding gets written
down instead of evaporating into the script. It knows what an exchange-only spin
qubit is — the renderer's table never will. Full path: validation (closed kind
set, non-empty latex, acts_on ids must exist, brace balance since the plugin
can't parse LaTeX but the card renders it straight into KaTeX), TOML round-trip,
wholesale patch-replace, hashing, normalizeSystem read-through.
2. `role` gains `other`, and `platformDefaultRole` stops inventing one. Only
platforms we model get a role from the string (rydberg→atom, transmon→qubit,
bosonic→mode); everything else is `other` until MODEL asks. The old blanket
"unknown → qubit" was also wrong for photonic and bosonic, which are modes.
AGENTS.md tells the interview to record the Hamiltonian — mandatory off-template,
worth confirming even on template — and to use `other` over a near-miss.
Note for the reviewer: this lands the recording side. The card only renders it once
the fork release carrying #93 is pinned via `pnpm opencode:pin`, so there
is no lock bump here.
Verified: 782 tests pass (78 files), tsc clean.
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@aarontrowbridge@jack-champagne
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(amicode): system card renders the recorded Hamiltonian, and stops inventing one - #93

Merged
jack-champagne merged 4 commits into
local/amicodefrom
feat/amicode-system-card-model
Jul 29, 2026
Merged

feat(amicode): system card renders the recorded Hamiltonian, and stops inventing one#93
jack-champagne merged 4 commits into
local/amicodefrom
feat/amicode-system-card-model

Conversation

@aarontrowbridge

Copy link
Copy Markdown
Member

The System card re-derived the Hamiltonian in the renderer from (role, levels, platform) using hardcoded tables. So it could only ever be right for platforms someone had hardcoded, and was confidently wrong for the rest — most recently showing the transmon ladder, and asking for an anharmonicity, on an exchange-only spin qubit.

Recording half of this is harmoniqs/amicode#AMICODE_PR.

Three commits

1 · per-component physics rows — the row list was a fixed transmon spec (frequency · anharmonicity · drive bound · decay) emitted for every component, while the Hamiltonian directly above it was role-aware. A Rydberg atom got asked for its anharmonicity. Rows now come from the component's model; params it doesn't have are absent, not shown as unanswered. Units are never assumed (transmon params are GHz, the Rydberg templates work in rad/µs) — a unit renders only when the recorded key spells it.

2 · Hamiltonian composed over the actual component and edge sets — the old composer deduped term strings over the set of distinct roles, so it rendered "which kinds of term appear", not the Hamiltonian of the system. It meant: a 2-atom and a 20-atom register rendered identically; an N-edge chain rendered one edge hardcoded to sites (1),(2); a qubit and a cavity both used â; the drive-arch badge had no counterpart in the equation; + -Δ printed literally; and \hat ^\dagger (a KaTeX error box) for any exchange/CR/mode-mediated edge with a non-bosonic endpoint. Now: components group by model and sum over their site indices, each bosonic group gets its own operator letter, like edges aggregate into Σ_⟨ij⟩, and the drive arch decides whether a control carries a site index — Ω(t) shared, Ω_i(t) per site, Ω_z(i)(t) per zone.

3 · recorded beats inferredsystemHamiltonian() returns {latex, source}. A model recorded on the entity renders verbatim; otherwise the canonical form renders under an inferred · confirm or correct label. When nothing is recorded and nothing is modelled the card says "not recorded" rather than showing Ĥ_drift + Ĥ_c(t) — true of every control problem ever posed, and it would occupy the slot the real model belongs in.

The rule that matters

Two separate leaks put the transmon model on a spin qubit, and the second is the subtle one:

  • platformDefaultRole maps every unfamiliar platform to "qubit" — fixed on the plugin side.
  • levels >= 3 was read as "anharmonic ladder". It is not. Three levels is a Hilbert-space dimension: an exchange-only qubit at levels=3 is three dots; a spin-1 defect is three Zeeman sublevels. Neither is an oscillator.

So the platform is now the only thing that licenses a ladder for a qubit role. levels=2 still earns the generic two-level model — safe anywhere, since every two-level system has an ω σ_z/2 splitting and σx/σy control. Everything else is opaque.

One classify() drives both the equation and the physics rows, so the two halves of the card cannot describe different physics again.

Bonus: a three-way drift

The ladder drive was a single ε(t)(â+â†), while the plugin's TRANSMON_LATEX (what Amico shows in chat) and Piccolo's n_drives = 2 both say two quadratures. Same device, same session, two different answers — nobody had noticed because both look plausible. Two is correct; the card now matches.

What it looks like

exchange-only-spin · 1 qubit × 3 levels · per-component drive
HAMILTONIAN not recorded
No model for this platform yet — tell Amico the terms.
LEVELS 3
transmon · 1 qubit × 3 levels · per-component drive
HAMILTONIAN inferred · confirm or correct
Ĥ/ℏ = ω â†â + δ/2 ↲Ⲡ+ u₁(t)(â+â†) + i u₂(t)(â−â†)

Verification

399 pass across 30 files, tsgo clean. The KaTeX sweep crosses role × coupling kind × drive arch × N × platform (~8k systems) and asserts both directions: every rendered system parses, no output when nothing is modelled, and never a model invented for an all-unmodelled system.

Branched off local/amicode; these three commits are extracted from a local integration branch and touch only the system-card files.

🤖 Generated with Claude Code

@aarontrowbridge
aarontrowbridgeforce-pushed the feat/amicode-system-card-model branch from ac7078f to 4118aaaCompareJuly 28, 2026 21:52
aarontrowbridge added a commit to harmoniqs/amicode that referenced this pull request Jul 28, 2026
…bricating roles
The System card re-derives the Hamiltonian in the renderer from (role, levels,
platform) with hardcoded tables, so it is only ever right for platforms someone
hardcoded — and silently wrong for the rest. It showed the transmon ladder, and
asked for an anharmonicity, on an exchange-only spin qubit. Two changes here; the
renderer half is harmoniqs/opencode#93.
1. `amicode_set_model` gains `hamiltonian` — the model term by term
({kind: drift|coupling|drive, latex, acts_on?, label?}) plus `hamiltonian_notes`
for frame/unit/basis conventions. The agent already understands the model well
enough to author the Julia solve; this is where that understanding gets written
down instead of evaporating into the script. It knows what an exchange-only spin
qubit is — the renderer's table never will. Full path: validation (closed kind
set, non-empty latex, acts_on ids must exist, brace balance since the plugin
can't parse LaTeX but the card renders it straight into KaTeX), TOML round-trip,
wholesale patch-replace, hashing, normalizeSystem read-through.
2. `role` gains `other`, and `platformDefaultRole` stops inventing one. Only
platforms we model get a role from the string (rydberg→atom, transmon→qubit,
bosonic→mode); everything else is `other` until MODEL asks. The old blanket
"unknown → qubit" was also wrong for photonic and bosonic, which are modes.
AGENTS.md tells the interview to record the Hamiltonian — mandatory off-template,
worth confirming even on template — and to use `other` over a near-miss.
Note for the reviewer: this lands the recording side. The card only renders it once
the fork release carrying #93 is pinned via `pnpm opencode:pin`, so there
is no lock bump here.
Verified: 782 tests pass (78 files), tsc clean.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
aarontrowbridgeand others added 3 commits July 28, 2026 18:51
The card made its component-count claim implicitly, so an unanswered 'how many
atoms?' read as 'one'. systemCountLabel now states it as its own badge ('2 atoms
x 3 levels') that a researcher can read and correct.
componentPhysicsRows renders what each role actually has, in card order:
- unanswered params read 'not set', so the list doubles as the interview's to-do
- anything else on file is still shown, so nothing recorded is dropped
- an unrecognized role expects NOTHING -- the honest floor for a platform we have
no model for
- units are never assumed (transmon params are GHz, the Rydberg templates work in
rad/us, a bare omega says which only by convention), so a unit appears only when
the recorded key spells it out
- a zero keeps the '0 means unset' reading, so an all-zeros seed does not look
like a specified device
driftTerm now keys the qubit ladder off LEVELS rather than off whether delta
happens to be filled in: a 3-level transmon with empty params is still an
anharmonic ladder, and rendering it as a bare spin misstates the model the solve
will use. A mode's Kerr stays params-driven, since a linear cavity genuinely has
none.
Continues 0793fd6. Committed on the author's behalf as part of folding the
worktree's in-progress work onto the branch; the content is theirs.
+169 lines of tests alongside +278 of implementation; ui suite 442 -> 448 pass.
…f-template
The card re-derived the Hamiltonian in the renderer from (role, levels, platform)
using hardcoded tables, so it could only ever be right for platforms someone had
hardcoded. Two separate leaks put the transmon model on a spin qubit:
- `platformDefaultRole` maps every unfamiliar platform to "qubit", so an
exchange-only HRL spin qubit arrived indistinguishable from a transmon.
- levels >= 3 was read as "anharmonic ladder". It is not. Three levels is a
Hilbert-space DIMENSION: an exchange-only qubit at levels=3 is three dots, a
spin-1 defect is three Zeeman sublevels. Neither is an oscillator.
So the platform is now the only thing that licenses a ladder for a `qubit` role
(transmon, bosonic). levels=2 still earns the generic two-level model, which is
safe on any platform — every two-level system has an ω σ_z/2 splitting and σx/σy
control. Everything else is opaque.
Recorded beats inferred. `systemHamiltonian()` returns {latex, source}: a model
recorded on the entity (amicode_set_model's `hamiltonian`, see harmoniqs/amicode#220) renders
verbatim; otherwise the canonical form for the platform renders under an
"inferred · confirm or correct" label. When nothing is recorded AND nothing is
modelled the card says "not recorded" rather than showing `Ĥ_drift + Ĥ_c(t)`, which
is true of every control problem ever posed and would occupy the slot the real model
belongs in. Mixed systems still get a named placeholder per unmodelled component.
One `classify()` now drives both the equation and the physics rows, so the two
halves of the card cannot describe different physics again.
Also fixes a three-way drift found while doing this: the ladder drive was a single
`ε(t)(â+â†)` while the plugin's TRANSMON_LATEX (shown in chat) and Piccolo's
n_drives = 2 both say two quadratures. Two is correct; the card now matches.
Verified: 399 pass across 30 files, tsgo clean. The KaTeX sweep now crosses the
platform axis too (8k systems) and asserts BOTH directions: no output when nothing
is modelled, and never a model invented for an all-unmodelled system.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@jack-champagne
jack-champagneforce-pushed the feat/amicode-system-card-model branch from 4118aaa to e4e0133CompareJuly 28, 2026 22:52
… once
The sweep enumerates ~8k systems, but they collapse onto a few hundred distinct
equations, and KaTeX is the expensive part. Rendering the same string 200 times
proves nothing and took 22s on CI against a 5s default timeout (it passed locally
on a fast machine, and I had only been running src/amicode — CI runs all of src).
Coverage is unchanged: every distinct output is still parsed, and the mapping back
to a producing system is kept for the failure message. Adds an assertion that the
sweep really does vary its output, so a future change that collapses everything to
one equation can't quietly pass.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
jack-champagne added a commit that referenced this pull request Jul 29, 2026
…t tests (#98)
The three `session.llm native recorded` scenarios are the only failures on
`local/amicode`, so the fork's `test` job is red and every PR into it inherits a
red check — including #93, whose own suite is 3366 pass / 3 fail with zero
failures of its own.
Cause is ours. AMICODE-PATCHES.md ADDENDUM 2 consolidated the prompt so
`system.ts provider()` returns `[providerBase(model), PROMPT_COMMUNICATING]`,
appending `communicating.txt` for every model family. The cassettes still record
the pre-patch prompt, so all three break on a diff of prose.
Those tests assert TRANSPORT mechanics — that a tool loop is driven to a final
text answer. The prompt is incidental, so matching on it couples them to text
they do not test. Patching the recorded prompt instead would work until the next
prompt edit, and that patch already has three addenda.
`RecorderOptions.match` is an existing seam (types.ts:85, threaded through
`http()` to `recordingLayer`) that nothing used. Adds `promptAgnosticMatcher`
alongside `defaultMatcher` and passes it from this one test.
The prompt arrives in three shapes, all covered:
instructions OpenAI Responses
system[] Anthropic Messages
input[].role=="system" the OpenCode proxy
System-message content is replaced with a placeholder rather than deleted, so
"a system message is present, with content" stays part of the match.
Verified narrow, in test/matching.test.ts: it ignores prompt prose in all three
shapes, and still rejects a different user message, model, tool set, URL, or a
missing-vs-present system message. 49 pass in http-recorder; the three recorded
scenarios go 3 fail -> 3 pass; typecheck green across 23 packages.
@jack-champagne
jack-champagne merged commit 9bd4649 into local/amicodeJul 29, 2026
1 of 4 checks passed
@jack-champagne
jack-champagne deleted the feat/amicode-system-card-model branch July 29, 2026 02:38
jack-champagne pushed a commit to harmoniqs/amicode that referenced this pull request Jul 29, 2026
…bricating roles (#220)
The System card re-derives the Hamiltonian in the renderer from (role, levels,
platform) with hardcoded tables, so it is only ever right for platforms someone
hardcoded — and silently wrong for the rest. It showed the transmon ladder, and
asked for an anharmonicity, on an exchange-only spin qubit. Two changes here; the
renderer half is harmoniqs/opencode#93.
1. `amicode_set_model` gains `hamiltonian` — the model term by term
({kind: drift|coupling|drive, latex, acts_on?, label?}) plus `hamiltonian_notes`
for frame/unit/basis conventions. The agent already understands the model well
enough to author the Julia solve; this is where that understanding gets written
down instead of evaporating into the script. It knows what an exchange-only spin
qubit is — the renderer's table never will. Full path: validation (closed kind
set, non-empty latex, acts_on ids must exist, brace balance since the plugin
can't parse LaTeX but the card renders it straight into KaTeX), TOML round-trip,
wholesale patch-replace, hashing, normalizeSystem read-through.
2. `role` gains `other`, and `platformDefaultRole` stops inventing one. Only
platforms we model get a role from the string (rydberg→atom, transmon→qubit,
bosonic→mode); everything else is `other` until MODEL asks. The old blanket
"unknown → qubit" was also wrong for photonic and bosonic, which are modes.
AGENTS.md tells the interview to record the Hamiltonian — mandatory off-template,
worth confirming even on template — and to use `other` over a near-miss.
Note for the reviewer: this lands the recording side. The card only renders it once
the fork release carrying #93 is pinned via `pnpm opencode:pin`, so there
is no lock bump here.
Verified: 782 tests pass (78 files), tsc clean.
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@aarontrowbridge@jack-champagne
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(amicode): system card renders the recorded Hamiltonian, and stops inventing one - #93

Merged
jack-champagne merged 4 commits into
local/amicodefrom
feat/amicode-system-card-model
Jul 29, 2026
Merged

feat(amicode): system card renders the recorded Hamiltonian, and stops inventing one#93
jack-champagne merged 4 commits into
local/amicodefrom
feat/amicode-system-card-model

Conversation

@aarontrowbridge

Copy link
Copy Markdown
Member

The System card re-derived the Hamiltonian in the renderer from (role, levels, platform) using hardcoded tables. So it could only ever be right for platforms someone had hardcoded, and was confidently wrong for the rest — most recently showing the transmon ladder, and asking for an anharmonicity, on an exchange-only spin qubit.

Recording half of this is harmoniqs/amicode#AMICODE_PR.

Three commits

1 · per-component physics rows — the row list was a fixed transmon spec (frequency · anharmonicity · drive bound · decay) emitted for every component, while the Hamiltonian directly above it was role-aware. A Rydberg atom got asked for its anharmonicity. Rows now come from the component's model; params it doesn't have are absent, not shown as unanswered. Units are never assumed (transmon params are GHz, the Rydberg templates work in rad/µs) — a unit renders only when the recorded key spells it.

2 · Hamiltonian composed over the actual component and edge sets — the old composer deduped term strings over the set of distinct roles, so it rendered "which kinds of term appear", not the Hamiltonian of the system. It meant: a 2-atom and a 20-atom register rendered identically; an N-edge chain rendered one edge hardcoded to sites (1),(2); a qubit and a cavity both used â; the drive-arch badge had no counterpart in the equation; + -Δ printed literally; and \hat ^\dagger (a KaTeX error box) for any exchange/CR/mode-mediated edge with a non-bosonic endpoint. Now: components group by model and sum over their site indices, each bosonic group gets its own operator letter, like edges aggregate into Σ_⟨ij⟩, and the drive arch decides whether a control carries a site index — Ω(t) shared, Ω_i(t) per site, Ω_z(i)(t) per zone.

3 · recorded beats inferredsystemHamiltonian() returns {latex, source}. A model recorded on the entity renders verbatim; otherwise the canonical form renders under an inferred · confirm or correct label. When nothing is recorded and nothing is modelled the card says "not recorded" rather than showing Ĥ_drift + Ĥ_c(t) — true of every control problem ever posed, and it would occupy the slot the real model belongs in.

The rule that matters

Two separate leaks put the transmon model on a spin qubit, and the second is the subtle one:

  • platformDefaultRole maps every unfamiliar platform to "qubit" — fixed on the plugin side.
  • levels >= 3 was read as "anharmonic ladder". It is not. Three levels is a Hilbert-space dimension: an exchange-only qubit at levels=3 is three dots; a spin-1 defect is three Zeeman sublevels. Neither is an oscillator.

So the platform is now the only thing that licenses a ladder for a qubit role. levels=2 still earns the generic two-level model — safe anywhere, since every two-level system has an ω σ_z/2 splitting and σx/σy control. Everything else is opaque.

One classify() drives both the equation and the physics rows, so the two halves of the card cannot describe different physics again.

Bonus: a three-way drift

The ladder drive was a single ε(t)(â+â†), while the plugin's TRANSMON_LATEX (what Amico shows in chat) and Piccolo's n_drives = 2 both say two quadratures. Same device, same session, two different answers — nobody had noticed because both look plausible. Two is correct; the card now matches.

What it looks like

exchange-only-spin · 1 qubit × 3 levels · per-component drive
HAMILTONIAN not recorded
No model for this platform yet — tell Amico the terms.
LEVELS 3
transmon · 1 qubit × 3 levels · per-component drive
HAMILTONIAN inferred · confirm or correct
Ĥ/ℏ = ω â†â + δ/2 ↲Ⲡ+ u₁(t)(â+â†) + i u₂(t)(â−â†)

Verification

399 pass across 30 files, tsgo clean. The KaTeX sweep crosses role × coupling kind × drive arch × N × platform (~8k systems) and asserts both directions: every rendered system parses, no output when nothing is modelled, and never a model invented for an all-unmodelled system.

Branched off local/amicode; these three commits are extracted from a local integration branch and touch only the system-card files.

🤖 Generated with Claude Code

@aarontrowbridge
aarontrowbridgeforce-pushed the feat/amicode-system-card-model branch from ac7078f to 4118aaaCompareJuly 28, 2026 21:52
aarontrowbridge added a commit to harmoniqs/amicode that referenced this pull request Jul 28, 2026
…bricating roles
The System card re-derives the Hamiltonian in the renderer from (role, levels,
platform) with hardcoded tables, so it is only ever right for platforms someone
hardcoded — and silently wrong for the rest. It showed the transmon ladder, and
asked for an anharmonicity, on an exchange-only spin qubit. Two changes here; the
renderer half is harmoniqs/opencode#93.
1. `amicode_set_model` gains `hamiltonian` — the model term by term
({kind: drift|coupling|drive, latex, acts_on?, label?}) plus `hamiltonian_notes`
for frame/unit/basis conventions. The agent already understands the model well
enough to author the Julia solve; this is where that understanding gets written
down instead of evaporating into the script. It knows what an exchange-only spin
qubit is — the renderer's table never will. Full path: validation (closed kind
set, non-empty latex, acts_on ids must exist, brace balance since the plugin
can't parse LaTeX but the card renders it straight into KaTeX), TOML round-trip,
wholesale patch-replace, hashing, normalizeSystem read-through.
2. `role` gains `other`, and `platformDefaultRole` stops inventing one. Only
platforms we model get a role from the string (rydberg→atom, transmon→qubit,
bosonic→mode); everything else is `other` until MODEL asks. The old blanket
"unknown → qubit" was also wrong for photonic and bosonic, which are modes.
AGENTS.md tells the interview to record the Hamiltonian — mandatory off-template,
worth confirming even on template — and to use `other` over a near-miss.
Note for the reviewer: this lands the recording side. The card only renders it once
the fork release carrying #93 is pinned via `pnpm opencode:pin`, so there
is no lock bump here.
Verified: 782 tests pass (78 files), tsc clean.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
aarontrowbridgeand others added 3 commits July 28, 2026 18:51
The card made its component-count claim implicitly, so an unanswered 'how many
atoms?' read as 'one'. systemCountLabel now states it as its own badge ('2 atoms
x 3 levels') that a researcher can read and correct.
componentPhysicsRows renders what each role actually has, in card order:
- unanswered params read 'not set', so the list doubles as the interview's to-do
- anything else on file is still shown, so nothing recorded is dropped
- an unrecognized role expects NOTHING -- the honest floor for a platform we have
no model for
- units are never assumed (transmon params are GHz, the Rydberg templates work in
rad/us, a bare omega says which only by convention), so a unit appears only when
the recorded key spells it out
- a zero keeps the '0 means unset' reading, so an all-zeros seed does not look
like a specified device
driftTerm now keys the qubit ladder off LEVELS rather than off whether delta
happens to be filled in: a 3-level transmon with empty params is still an
anharmonic ladder, and rendering it as a bare spin misstates the model the solve
will use. A mode's Kerr stays params-driven, since a linear cavity genuinely has
none.
Continues 0793fd6. Committed on the author's behalf as part of folding the
worktree's in-progress work onto the branch; the content is theirs.
+169 lines of tests alongside +278 of implementation; ui suite 442 -> 448 pass.
…f-template
The card re-derived the Hamiltonian in the renderer from (role, levels, platform)
using hardcoded tables, so it could only ever be right for platforms someone had
hardcoded. Two separate leaks put the transmon model on a spin qubit:
- `platformDefaultRole` maps every unfamiliar platform to "qubit", so an
exchange-only HRL spin qubit arrived indistinguishable from a transmon.
- levels >= 3 was read as "anharmonic ladder". It is not. Three levels is a
Hilbert-space DIMENSION: an exchange-only qubit at levels=3 is three dots, a
spin-1 defect is three Zeeman sublevels. Neither is an oscillator.
So the platform is now the only thing that licenses a ladder for a `qubit` role
(transmon, bosonic). levels=2 still earns the generic two-level model, which is
safe on any platform — every two-level system has an ω σ_z/2 splitting and σx/σy
control. Everything else is opaque.
Recorded beats inferred. `systemHamiltonian()` returns {latex, source}: a model
recorded on the entity (amicode_set_model's `hamiltonian`, see harmoniqs/amicode#220) renders
verbatim; otherwise the canonical form for the platform renders under an
"inferred · confirm or correct" label. When nothing is recorded AND nothing is
modelled the card says "not recorded" rather than showing `Ĥ_drift + Ĥ_c(t)`, which
is true of every control problem ever posed and would occupy the slot the real model
belongs in. Mixed systems still get a named placeholder per unmodelled component.
One `classify()` now drives both the equation and the physics rows, so the two
halves of the card cannot describe different physics again.
Also fixes a three-way drift found while doing this: the ladder drive was a single
`ε(t)(â+â†)` while the plugin's TRANSMON_LATEX (shown in chat) and Piccolo's
n_drives = 2 both say two quadratures. Two is correct; the card now matches.
Verified: 399 pass across 30 files, tsgo clean. The KaTeX sweep now crosses the
platform axis too (8k systems) and asserts BOTH directions: no output when nothing
is modelled, and never a model invented for an all-unmodelled system.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@jack-champagne
jack-champagneforce-pushed the feat/amicode-system-card-model branch from 4118aaa to e4e0133CompareJuly 28, 2026 22:52
… once
The sweep enumerates ~8k systems, but they collapse onto a few hundred distinct
equations, and KaTeX is the expensive part. Rendering the same string 200 times
proves nothing and took 22s on CI against a 5s default timeout (it passed locally
on a fast machine, and I had only been running src/amicode — CI runs all of src).
Coverage is unchanged: every distinct output is still parsed, and the mapping back
to a producing system is kept for the failure message. Adds an assertion that the
sweep really does vary its output, so a future change that collapses everything to
one equation can't quietly pass.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
jack-champagne added a commit that referenced this pull request Jul 29, 2026
…t tests (#98)
The three `session.llm native recorded` scenarios are the only failures on
`local/amicode`, so the fork's `test` job is red and every PR into it inherits a
red check — including #93, whose own suite is 3366 pass / 3 fail with zero
failures of its own.
Cause is ours. AMICODE-PATCHES.md ADDENDUM 2 consolidated the prompt so
`system.ts provider()` returns `[providerBase(model), PROMPT_COMMUNICATING]`,
appending `communicating.txt` for every model family. The cassettes still record
the pre-patch prompt, so all three break on a diff of prose.
Those tests assert TRANSPORT mechanics — that a tool loop is driven to a final
text answer. The prompt is incidental, so matching on it couples them to text
they do not test. Patching the recorded prompt instead would work until the next
prompt edit, and that patch already has three addenda.
`RecorderOptions.match` is an existing seam (types.ts:85, threaded through
`http()` to `recordingLayer`) that nothing used. Adds `promptAgnosticMatcher`
alongside `defaultMatcher` and passes it from this one test.
The prompt arrives in three shapes, all covered:
instructions OpenAI Responses
system[] Anthropic Messages
input[].role=="system" the OpenCode proxy
System-message content is replaced with a placeholder rather than deleted, so
"a system message is present, with content" stays part of the match.
Verified narrow, in test/matching.test.ts: it ignores prompt prose in all three
shapes, and still rejects a different user message, model, tool set, URL, or a
missing-vs-present system message. 49 pass in http-recorder; the three recorded
scenarios go 3 fail -> 3 pass; typecheck green across 23 packages.
@jack-champagne
jack-champagne merged commit 9bd4649 into local/amicodeJul 29, 2026
1 of 4 checks passed
@jack-champagne
jack-champagne deleted the feat/amicode-system-card-model branch July 29, 2026 02:38
jack-champagne pushed a commit to harmoniqs/amicode that referenced this pull request Jul 29, 2026
…bricating roles (#220)
The System card re-derives the Hamiltonian in the renderer from (role, levels,
platform) with hardcoded tables, so it is only ever right for platforms someone
hardcoded — and silently wrong for the rest. It showed the transmon ladder, and
asked for an anharmonicity, on an exchange-only spin qubit. Two changes here; the
renderer half is harmoniqs/opencode#93.
1. `amicode_set_model` gains `hamiltonian` — the model term by term
({kind: drift|coupling|drive, latex, acts_on?, label?}) plus `hamiltonian_notes`
for frame/unit/basis conventions. The agent already understands the model well
enough to author the Julia solve; this is where that understanding gets written
down instead of evaporating into the script. It knows what an exchange-only spin
qubit is — the renderer's table never will. Full path: validation (closed kind
set, non-empty latex, acts_on ids must exist, brace balance since the plugin
can't parse LaTeX but the card renders it straight into KaTeX), TOML round-trip,
wholesale patch-replace, hashing, normalizeSystem read-through.
2. `role` gains `other`, and `platformDefaultRole` stops inventing one. Only
platforms we model get a role from the string (rydberg→atom, transmon→qubit,
bosonic→mode); everything else is `other` until MODEL asks. The old blanket
"unknown → qubit" was also wrong for photonic and bosonic, which are modes.
AGENTS.md tells the interview to record the Hamiltonian — mandatory off-template,
worth confirming even on template — and to use `other` over a near-miss.
Note for the reviewer: this lands the recording side. The card only renders it once
the fork release carrying #93 is pinned via `pnpm opencode:pin`, so there
is no lock bump here.
Verified: 782 tests pass (78 files), tsc clean.
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@aarontrowbridge@jack-champagne
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

feat(amicode): system card renders the recorded Hamiltonian, and stops inventing one - #93

Merged
jack-champagne merged 4 commits into
local/amicodefrom
feat/amicode-system-card-model
Jul 29, 2026
Merged

feat(amicode): system card renders the recorded Hamiltonian, and stops inventing one#93
jack-champagne merged 4 commits into
local/amicodefrom
feat/amicode-system-card-model

Conversation

@aarontrowbridge

Copy link
Copy Markdown
Member

The System card re-derived the Hamiltonian in the renderer from (role, levels, platform) using hardcoded tables. So it could only ever be right for platforms someone had hardcoded, and was confidently wrong for the rest — most recently showing the transmon ladder, and asking for an anharmonicity, on an exchange-only spin qubit.

Recording half of this is harmoniqs/amicode#AMICODE_PR.

Three commits

1 · per-component physics rows — the row list was a fixed transmon spec (frequency · anharmonicity · drive bound · decay) emitted for every component, while the Hamiltonian directly above it was role-aware. A Rydberg atom got asked for its anharmonicity. Rows now come from the component's model; params it doesn't have are absent, not shown as unanswered. Units are never assumed (transmon params are GHz, the Rydberg templates work in rad/µs) — a unit renders only when the recorded key spells it.

2 · Hamiltonian composed over the actual component and edge sets — the old composer deduped term strings over the set of distinct roles, so it rendered "which kinds of term appear", not the Hamiltonian of the system. It meant: a 2-atom and a 20-atom register rendered identically; an N-edge chain rendered one edge hardcoded to sites (1),(2); a qubit and a cavity both used â; the drive-arch badge had no counterpart in the equation; + -Δ printed literally; and \hat ^\dagger (a KaTeX error box) for any exchange/CR/mode-mediated edge with a non-bosonic endpoint. Now: components group by model and sum over their site indices, each bosonic group gets its own operator letter, like edges aggregate into Σ_⟨ij⟩, and the drive arch decides whether a control carries a site index — Ω(t) shared, Ω_i(t) per site, Ω_z(i)(t) per zone.

3 · recorded beats inferredsystemHamiltonian() returns {latex, source}. A model recorded on the entity renders verbatim; otherwise the canonical form renders under an inferred · confirm or correct label. When nothing is recorded and nothing is modelled the card says "not recorded" rather than showing Ĥ_drift + Ĥ_c(t) — true of every control problem ever posed, and it would occupy the slot the real model belongs in.

The rule that matters

Two separate leaks put the transmon model on a spin qubit, and the second is the subtle one:

  • platformDefaultRole maps every unfamiliar platform to "qubit" — fixed on the plugin side.
  • levels >= 3 was read as "anharmonic ladder". It is not. Three levels is a Hilbert-space dimension: an exchange-only qubit at levels=3 is three dots; a spin-1 defect is three Zeeman sublevels. Neither is an oscillator.

So the platform is now the only thing that licenses a ladder for a qubit role. levels=2 still earns the generic two-level model — safe anywhere, since every two-level system has an ω σ_z/2 splitting and σx/σy control. Everything else is opaque.

One classify() drives both the equation and the physics rows, so the two halves of the card cannot describe different physics again.

Bonus: a three-way drift

The ladder drive was a single ε(t)(â+â†), while the plugin's TRANSMON_LATEX (what Amico shows in chat) and Piccolo's n_drives = 2 both say two quadratures. Same device, same session, two different answers — nobody had noticed because both look plausible. Two is correct; the card now matches.

What it looks like

exchange-only-spin · 1 qubit × 3 levels · per-component drive
HAMILTONIAN not recorded
No model for this platform yet — tell Amico the terms.
LEVELS 3
transmon · 1 qubit × 3 levels · per-component drive
HAMILTONIAN inferred · confirm or correct
Ĥ/ℏ = ω â†â + δ/2 ↲Ⲡ+ u₁(t)(â+â†) + i u₂(t)(â−â†)

Verification

399 pass across 30 files, tsgo clean. The KaTeX sweep crosses role × coupling kind × drive arch × N × platform (~8k systems) and asserts both directions: every rendered system parses, no output when nothing is modelled, and never a model invented for an all-unmodelled system.

Branched off local/amicode; these three commits are extracted from a local integration branch and touch only the system-card files.

🤖 Generated with Claude Code

@aarontrowbridge
aarontrowbridgeforce-pushed the feat/amicode-system-card-model branch from ac7078f to 4118aaaCompareJuly 28, 2026 21:52
aarontrowbridge added a commit to harmoniqs/amicode that referenced this pull request Jul 28, 2026
…bricating roles
The System card re-derives the Hamiltonian in the renderer from (role, levels,
platform) with hardcoded tables, so it is only ever right for platforms someone
hardcoded — and silently wrong for the rest. It showed the transmon ladder, and
asked for an anharmonicity, on an exchange-only spin qubit. Two changes here; the
renderer half is harmoniqs/opencode#93.
1. `amicode_set_model` gains `hamiltonian` — the model term by term
({kind: drift|coupling|drive, latex, acts_on?, label?}) plus `hamiltonian_notes`
for frame/unit/basis conventions. The agent already understands the model well
enough to author the Julia solve; this is where that understanding gets written
down instead of evaporating into the script. It knows what an exchange-only spin
qubit is — the renderer's table never will. Full path: validation (closed kind
set, non-empty latex, acts_on ids must exist, brace balance since the plugin
can't parse LaTeX but the card renders it straight into KaTeX), TOML round-trip,
wholesale patch-replace, hashing, normalizeSystem read-through.
2. `role` gains `other`, and `platformDefaultRole` stops inventing one. Only
platforms we model get a role from the string (rydberg→atom, transmon→qubit,
bosonic→mode); everything else is `other` until MODEL asks. The old blanket
"unknown → qubit" was also wrong for photonic and bosonic, which are modes.
AGENTS.md tells the interview to record the Hamiltonian — mandatory off-template,
worth confirming even on template — and to use `other` over a near-miss.
Note for the reviewer: this lands the recording side. The card only renders it once
the fork release carrying #93 is pinned via `pnpm opencode:pin`, so there
is no lock bump here.
Verified: 782 tests pass (78 files), tsc clean.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
aarontrowbridgeand others added 3 commits July 28, 2026 18:51
The card made its component-count claim implicitly, so an unanswered 'how many
atoms?' read as 'one'. systemCountLabel now states it as its own badge ('2 atoms
x 3 levels') that a researcher can read and correct.
componentPhysicsRows renders what each role actually has, in card order:
- unanswered params read 'not set', so the list doubles as the interview's to-do
- anything else on file is still shown, so nothing recorded is dropped
- an unrecognized role expects NOTHING -- the honest floor for a platform we have
no model for
- units are never assumed (transmon params are GHz, the Rydberg templates work in
rad/us, a bare omega says which only by convention), so a unit appears only when
the recorded key spells it out
- a zero keeps the '0 means unset' reading, so an all-zeros seed does not look
like a specified device
driftTerm now keys the qubit ladder off LEVELS rather than off whether delta
happens to be filled in: a 3-level transmon with empty params is still an
anharmonic ladder, and rendering it as a bare spin misstates the model the solve
will use. A mode's Kerr stays params-driven, since a linear cavity genuinely has
none.
Continues 0793fd6. Committed on the author's behalf as part of folding the
worktree's in-progress work onto the branch; the content is theirs.
+169 lines of tests alongside +278 of implementation; ui suite 442 -> 448 pass.
…f-template
The card re-derived the Hamiltonian in the renderer from (role, levels, platform)
using hardcoded tables, so it could only ever be right for platforms someone had
hardcoded. Two separate leaks put the transmon model on a spin qubit:
- `platformDefaultRole` maps every unfamiliar platform to "qubit", so an
exchange-only HRL spin qubit arrived indistinguishable from a transmon.
- levels >= 3 was read as "anharmonic ladder". It is not. Three levels is a
Hilbert-space DIMENSION: an exchange-only qubit at levels=3 is three dots, a
spin-1 defect is three Zeeman sublevels. Neither is an oscillator.
So the platform is now the only thing that licenses a ladder for a `qubit` role
(transmon, bosonic). levels=2 still earns the generic two-level model, which is
safe on any platform — every two-level system has an ω σ_z/2 splitting and σx/σy
control. Everything else is opaque.
Recorded beats inferred. `systemHamiltonian()` returns {latex, source}: a model
recorded on the entity (amicode_set_model's `hamiltonian`, see harmoniqs/amicode#220) renders
verbatim; otherwise the canonical form for the platform renders under an
"inferred · confirm or correct" label. When nothing is recorded AND nothing is
modelled the card says "not recorded" rather than showing `Ĥ_drift + Ĥ_c(t)`, which
is true of every control problem ever posed and would occupy the slot the real model
belongs in. Mixed systems still get a named placeholder per unmodelled component.
One `classify()` now drives both the equation and the physics rows, so the two
halves of the card cannot describe different physics again.
Also fixes a three-way drift found while doing this: the ladder drive was a single
`ε(t)(â+â†)` while the plugin's TRANSMON_LATEX (shown in chat) and Piccolo's
n_drives = 2 both say two quadratures. Two is correct; the card now matches.
Verified: 399 pass across 30 files, tsgo clean. The KaTeX sweep now crosses the
platform axis too (8k systems) and asserts BOTH directions: no output when nothing
is modelled, and never a model invented for an all-unmodelled system.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@jack-champagne
jack-champagneforce-pushed the feat/amicode-system-card-model branch from 4118aaa to e4e0133CompareJuly 28, 2026 22:52
… once
The sweep enumerates ~8k systems, but they collapse onto a few hundred distinct
equations, and KaTeX is the expensive part. Rendering the same string 200 times
proves nothing and took 22s on CI against a 5s default timeout (it passed locally
on a fast machine, and I had only been running src/amicode — CI runs all of src).
Coverage is unchanged: every distinct output is still parsed, and the mapping back
to a producing system is kept for the failure message. Adds an assertion that the
sweep really does vary its output, so a future change that collapses everything to
one equation can't quietly pass.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
jack-champagne added a commit that referenced this pull request Jul 29, 2026
…t tests (#98)
The three `session.llm native recorded` scenarios are the only failures on
`local/amicode`, so the fork's `test` job is red and every PR into it inherits a
red check — including #93, whose own suite is 3366 pass / 3 fail with zero
failures of its own.
Cause is ours. AMICODE-PATCHES.md ADDENDUM 2 consolidated the prompt so
`system.ts provider()` returns `[providerBase(model), PROMPT_COMMUNICATING]`,
appending `communicating.txt` for every model family. The cassettes still record
the pre-patch prompt, so all three break on a diff of prose.
Those tests assert TRANSPORT mechanics — that a tool loop is driven to a final
text answer. The prompt is incidental, so matching on it couples them to text
they do not test. Patching the recorded prompt instead would work until the next
prompt edit, and that patch already has three addenda.
`RecorderOptions.match` is an existing seam (types.ts:85, threaded through
`http()` to `recordingLayer`) that nothing used. Adds `promptAgnosticMatcher`
alongside `defaultMatcher` and passes it from this one test.
The prompt arrives in three shapes, all covered:
instructions OpenAI Responses
system[] Anthropic Messages
input[].role=="system" the OpenCode proxy
System-message content is replaced with a placeholder rather than deleted, so
"a system message is present, with content" stays part of the match.
Verified narrow, in test/matching.test.ts: it ignores prompt prose in all three
shapes, and still rejects a different user message, model, tool set, URL, or a
missing-vs-present system message. 49 pass in http-recorder; the three recorded
scenarios go 3 fail -> 3 pass; typecheck green across 23 packages.
@jack-champagne
jack-champagne merged commit 9bd4649 into local/amicodeJul 29, 2026
1 of 4 checks passed
@jack-champagne
jack-champagne deleted the feat/amicode-system-card-model branch July 29, 2026 02:38
jack-champagne pushed a commit to harmoniqs/amicode that referenced this pull request Jul 29, 2026
…bricating roles (#220)
The System card re-derives the Hamiltonian in the renderer from (role, levels,
platform) with hardcoded tables, so it is only ever right for platforms someone
hardcoded — and silently wrong for the rest. It showed the transmon ladder, and
asked for an anharmonicity, on an exchange-only spin qubit. Two changes here; the
renderer half is harmoniqs/opencode#93.
1. `amicode_set_model` gains `hamiltonian` — the model term by term
({kind: drift|coupling|drive, latex, acts_on?, label?}) plus `hamiltonian_notes`
for frame/unit/basis conventions. The agent already understands the model well
enough to author the Julia solve; this is where that understanding gets written
down instead of evaporating into the script. It knows what an exchange-only spin
qubit is — the renderer's table never will. Full path: validation (closed kind
set, non-empty latex, acts_on ids must exist, brace balance since the plugin
can't parse LaTeX but the card renders it straight into KaTeX), TOML round-trip,
wholesale patch-replace, hashing, normalizeSystem read-through.
2. `role` gains `other`, and `platformDefaultRole` stops inventing one. Only
platforms we model get a role from the string (rydberg→atom, transmon→qubit,
bosonic→mode); everything else is `other` until MODEL asks. The old blanket
"unknown → qubit" was also wrong for photonic and bosonic, which are modes.
AGENTS.md tells the interview to record the Hamiltonian — mandatory off-template,
worth confirming even on template — and to use `other` over a near-miss.
Note for the reviewer: this lands the recording side. The card only renders it once
the fork release carrying #93 is pinned via `pnpm opencode:pin`, so there
is no lock bump here.
Verified: 782 tests pass (78 files), tsc clean.
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@aarontrowbridge@jack-champagne
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(amicode): system card renders the recorded Hamiltonian, and stops inventing one - #93

Merged
jack-champagne merged 4 commits into
local/amicodefrom
feat/amicode-system-card-model
Jul 29, 2026
Merged

feat(amicode): system card renders the recorded Hamiltonian, and stops inventing one#93
jack-champagne merged 4 commits into
local/amicodefrom
feat/amicode-system-card-model

Conversation

@aarontrowbridge

Copy link
Copy Markdown
Member

The System card re-derived the Hamiltonian in the renderer from (role, levels, platform) using hardcoded tables. So it could only ever be right for platforms someone had hardcoded, and was confidently wrong for the rest — most recently showing the transmon ladder, and asking for an anharmonicity, on an exchange-only spin qubit.

Recording half of this is harmoniqs/amicode#AMICODE_PR.

Three commits

1 · per-component physics rows — the row list was a fixed transmon spec (frequency · anharmonicity · drive bound · decay) emitted for every component, while the Hamiltonian directly above it was role-aware. A Rydberg atom got asked for its anharmonicity. Rows now come from the component's model; params it doesn't have are absent, not shown as unanswered. Units are never assumed (transmon params are GHz, the Rydberg templates work in rad/µs) — a unit renders only when the recorded key spells it.

2 · Hamiltonian composed over the actual component and edge sets — the old composer deduped term strings over the set of distinct roles, so it rendered "which kinds of term appear", not the Hamiltonian of the system. It meant: a 2-atom and a 20-atom register rendered identically; an N-edge chain rendered one edge hardcoded to sites (1),(2); a qubit and a cavity both used â; the drive-arch badge had no counterpart in the equation; + -Δ printed literally; and \hat ^\dagger (a KaTeX error box) for any exchange/CR/mode-mediated edge with a non-bosonic endpoint. Now: components group by model and sum over their site indices, each bosonic group gets its own operator letter, like edges aggregate into Σ_⟨ij⟩, and the drive arch decides whether a control carries a site index — Ω(t) shared, Ω_i(t) per site, Ω_z(i)(t) per zone.

3 · recorded beats inferredsystemHamiltonian() returns {latex, source}. A model recorded on the entity renders verbatim; otherwise the canonical form renders under an inferred · confirm or correct label. When nothing is recorded and nothing is modelled the card says "not recorded" rather than showing Ĥ_drift + Ĥ_c(t) — true of every control problem ever posed, and it would occupy the slot the real model belongs in.

The rule that matters

Two separate leaks put the transmon model on a spin qubit, and the second is the subtle one:

  • platformDefaultRole maps every unfamiliar platform to "qubit" — fixed on the plugin side.
  • levels >= 3 was read as "anharmonic ladder". It is not. Three levels is a Hilbert-space dimension: an exchange-only qubit at levels=3 is three dots; a spin-1 defect is three Zeeman sublevels. Neither is an oscillator.

So the platform is now the only thing that licenses a ladder for a qubit role. levels=2 still earns the generic two-level model — safe anywhere, since every two-level system has an ω σ_z/2 splitting and σx/σy control. Everything else is opaque.

One classify() drives both the equation and the physics rows, so the two halves of the card cannot describe different physics again.

Bonus: a three-way drift

The ladder drive was a single ε(t)(â+â†), while the plugin's TRANSMON_LATEX (what Amico shows in chat) and Piccolo's n_drives = 2 both say two quadratures. Same device, same session, two different answers — nobody had noticed because both look plausible. Two is correct; the card now matches.

What it looks like

exchange-only-spin · 1 qubit × 3 levels · per-component drive
HAMILTONIAN not recorded
No model for this platform yet — tell Amico the terms.
LEVELS 3
transmon · 1 qubit × 3 levels · per-component drive
HAMILTONIAN inferred · confirm or correct
Ĥ/ℏ = ω â†â + δ/2 ↲Ⲡ+ u₁(t)(â+â†) + i u₂(t)(â−â†)

Verification

399 pass across 30 files, tsgo clean. The KaTeX sweep crosses role × coupling kind × drive arch × N × platform (~8k systems) and asserts both directions: every rendered system parses, no output when nothing is modelled, and never a model invented for an all-unmodelled system.

Branched off local/amicode; these three commits are extracted from a local integration branch and touch only the system-card files.

🤖 Generated with Claude Code

@aarontrowbridge
aarontrowbridgeforce-pushed the feat/amicode-system-card-model branch from ac7078f to 4118aaaCompareJuly 28, 2026 21:52
aarontrowbridge added a commit to harmoniqs/amicode that referenced this pull request Jul 28, 2026
…bricating roles
The System card re-derives the Hamiltonian in the renderer from (role, levels,
platform) with hardcoded tables, so it is only ever right for platforms someone
hardcoded — and silently wrong for the rest. It showed the transmon ladder, and
asked for an anharmonicity, on an exchange-only spin qubit. Two changes here; the
renderer half is harmoniqs/opencode#93.
1. `amicode_set_model` gains `hamiltonian` — the model term by term
({kind: drift|coupling|drive, latex, acts_on?, label?}) plus `hamiltonian_notes`
for frame/unit/basis conventions. The agent already understands the model well
enough to author the Julia solve; this is where that understanding gets written
down instead of evaporating into the script. It knows what an exchange-only spin
qubit is — the renderer's table never will. Full path: validation (closed kind
set, non-empty latex, acts_on ids must exist, brace balance since the plugin
can't parse LaTeX but the card renders it straight into KaTeX), TOML round-trip,
wholesale patch-replace, hashing, normalizeSystem read-through.
2. `role` gains `other`, and `platformDefaultRole` stops inventing one. Only
platforms we model get a role from the string (rydberg→atom, transmon→qubit,
bosonic→mode); everything else is `other` until MODEL asks. The old blanket
"unknown → qubit" was also wrong for photonic and bosonic, which are modes.
AGENTS.md tells the interview to record the Hamiltonian — mandatory off-template,
worth confirming even on template — and to use `other` over a near-miss.
Note for the reviewer: this lands the recording side. The card only renders it once
the fork release carrying #93 is pinned via `pnpm opencode:pin`, so there
is no lock bump here.
Verified: 782 tests pass (78 files), tsc clean.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
aarontrowbridgeand others added 3 commits July 28, 2026 18:51
The card made its component-count claim implicitly, so an unanswered 'how many
atoms?' read as 'one'. systemCountLabel now states it as its own badge ('2 atoms
x 3 levels') that a researcher can read and correct.
componentPhysicsRows renders what each role actually has, in card order:
- unanswered params read 'not set', so the list doubles as the interview's to-do
- anything else on file is still shown, so nothing recorded is dropped
- an unrecognized role expects NOTHING -- the honest floor for a platform we have
no model for
- units are never assumed (transmon params are GHz, the Rydberg templates work in
rad/us, a bare omega says which only by convention), so a unit appears only when
the recorded key spells it out
- a zero keeps the '0 means unset' reading, so an all-zeros seed does not look
like a specified device
driftTerm now keys the qubit ladder off LEVELS rather than off whether delta
happens to be filled in: a 3-level transmon with empty params is still an
anharmonic ladder, and rendering it as a bare spin misstates the model the solve
will use. A mode's Kerr stays params-driven, since a linear cavity genuinely has
none.
Continues 0793fd6. Committed on the author's behalf as part of folding the
worktree's in-progress work onto the branch; the content is theirs.
+169 lines of tests alongside +278 of implementation; ui suite 442 -> 448 pass.
…f-template
The card re-derived the Hamiltonian in the renderer from (role, levels, platform)
using hardcoded tables, so it could only ever be right for platforms someone had
hardcoded. Two separate leaks put the transmon model on a spin qubit:
- `platformDefaultRole` maps every unfamiliar platform to "qubit", so an
exchange-only HRL spin qubit arrived indistinguishable from a transmon.
- levels >= 3 was read as "anharmonic ladder". It is not. Three levels is a
Hilbert-space DIMENSION: an exchange-only qubit at levels=3 is three dots, a
spin-1 defect is three Zeeman sublevels. Neither is an oscillator.
So the platform is now the only thing that licenses a ladder for a `qubit` role
(transmon, bosonic). levels=2 still earns the generic two-level model, which is
safe on any platform — every two-level system has an ω σ_z/2 splitting and σx/σy
control. Everything else is opaque.
Recorded beats inferred. `systemHamiltonian()` returns {latex, source}: a model
recorded on the entity (amicode_set_model's `hamiltonian`, see harmoniqs/amicode#220) renders
verbatim; otherwise the canonical form for the platform renders under an
"inferred · confirm or correct" label. When nothing is recorded AND nothing is
modelled the card says "not recorded" rather than showing `Ĥ_drift + Ĥ_c(t)`, which
is true of every control problem ever posed and would occupy the slot the real model
belongs in. Mixed systems still get a named placeholder per unmodelled component.
One `classify()` now drives both the equation and the physics rows, so the two
halves of the card cannot describe different physics again.
Also fixes a three-way drift found while doing this: the ladder drive was a single
`ε(t)(â+â†)` while the plugin's TRANSMON_LATEX (shown in chat) and Piccolo's
n_drives = 2 both say two quadratures. Two is correct; the card now matches.
Verified: 399 pass across 30 files, tsgo clean. The KaTeX sweep now crosses the
platform axis too (8k systems) and asserts BOTH directions: no output when nothing
is modelled, and never a model invented for an all-unmodelled system.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@jack-champagne
jack-champagneforce-pushed the feat/amicode-system-card-model branch from 4118aaa to e4e0133CompareJuly 28, 2026 22:52
… once
The sweep enumerates ~8k systems, but they collapse onto a few hundred distinct
equations, and KaTeX is the expensive part. Rendering the same string 200 times
proves nothing and took 22s on CI against a 5s default timeout (it passed locally
on a fast machine, and I had only been running src/amicode — CI runs all of src).
Coverage is unchanged: every distinct output is still parsed, and the mapping back
to a producing system is kept for the failure message. Adds an assertion that the
sweep really does vary its output, so a future change that collapses everything to
one equation can't quietly pass.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
jack-champagne added a commit that referenced this pull request Jul 29, 2026
…t tests (#98)
The three `session.llm native recorded` scenarios are the only failures on
`local/amicode`, so the fork's `test` job is red and every PR into it inherits a
red check — including #93, whose own suite is 3366 pass / 3 fail with zero
failures of its own.
Cause is ours. AMICODE-PATCHES.md ADDENDUM 2 consolidated the prompt so
`system.ts provider()` returns `[providerBase(model), PROMPT_COMMUNICATING]`,
appending `communicating.txt` for every model family. The cassettes still record
the pre-patch prompt, so all three break on a diff of prose.
Those tests assert TRANSPORT mechanics — that a tool loop is driven to a final
text answer. The prompt is incidental, so matching on it couples them to text
they do not test. Patching the recorded prompt instead would work until the next
prompt edit, and that patch already has three addenda.
`RecorderOptions.match` is an existing seam (types.ts:85, threaded through
`http()` to `recordingLayer`) that nothing used. Adds `promptAgnosticMatcher`
alongside `defaultMatcher` and passes it from this one test.
The prompt arrives in three shapes, all covered:
instructions OpenAI Responses
system[] Anthropic Messages
input[].role=="system" the OpenCode proxy
System-message content is replaced with a placeholder rather than deleted, so
"a system message is present, with content" stays part of the match.
Verified narrow, in test/matching.test.ts: it ignores prompt prose in all three
shapes, and still rejects a different user message, model, tool set, URL, or a
missing-vs-present system message. 49 pass in http-recorder; the three recorded
scenarios go 3 fail -> 3 pass; typecheck green across 23 packages.
@jack-champagne
jack-champagne merged commit 9bd4649 into local/amicodeJul 29, 2026
1 of 4 checks passed
@jack-champagne
jack-champagne deleted the feat/amicode-system-card-model branch July 29, 2026 02:38
jack-champagne pushed a commit to harmoniqs/amicode that referenced this pull request Jul 29, 2026
…bricating roles (#220)
The System card re-derives the Hamiltonian in the renderer from (role, levels,
platform) with hardcoded tables, so it is only ever right for platforms someone
hardcoded — and silently wrong for the rest. It showed the transmon ladder, and
asked for an anharmonicity, on an exchange-only spin qubit. Two changes here; the
renderer half is harmoniqs/opencode#93.
1. `amicode_set_model` gains `hamiltonian` — the model term by term
({kind: drift|coupling|drive, latex, acts_on?, label?}) plus `hamiltonian_notes`
for frame/unit/basis conventions. The agent already understands the model well
enough to author the Julia solve; this is where that understanding gets written
down instead of evaporating into the script. It knows what an exchange-only spin
qubit is — the renderer's table never will. Full path: validation (closed kind
set, non-empty latex, acts_on ids must exist, brace balance since the plugin
can't parse LaTeX but the card renders it straight into KaTeX), TOML round-trip,
wholesale patch-replace, hashing, normalizeSystem read-through.
2. `role` gains `other`, and `platformDefaultRole` stops inventing one. Only
platforms we model get a role from the string (rydberg→atom, transmon→qubit,
bosonic→mode); everything else is `other` until MODEL asks. The old blanket
"unknown → qubit" was also wrong for photonic and bosonic, which are modes.
AGENTS.md tells the interview to record the Hamiltonian — mandatory off-template,
worth confirming even on template — and to use `other` over a near-miss.
Note for the reviewer: this lands the recording side. The card only renders it once
the fork release carrying #93 is pinned via `pnpm opencode:pin`, so there
is no lock bump here.
Verified: 782 tests pass (78 files), tsc clean.
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@aarontrowbridge@jack-champagne
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(amicode): system card renders the recorded Hamiltonian, and stops inventing one - #93

Merged
jack-champagne merged 4 commits into
local/amicodefrom
feat/amicode-system-card-model
Jul 29, 2026
Merged

feat(amicode): system card renders the recorded Hamiltonian, and stops inventing one#93
jack-champagne merged 4 commits into
local/amicodefrom
feat/amicode-system-card-model

Conversation

@aarontrowbridge

Copy link
Copy Markdown
Member

The System card re-derived the Hamiltonian in the renderer from (role, levels, platform) using hardcoded tables. So it could only ever be right for platforms someone had hardcoded, and was confidently wrong for the rest — most recently showing the transmon ladder, and asking for an anharmonicity, on an exchange-only spin qubit.

Recording half of this is harmoniqs/amicode#AMICODE_PR.

Three commits

1 · per-component physics rows — the row list was a fixed transmon spec (frequency · anharmonicity · drive bound · decay) emitted for every component, while the Hamiltonian directly above it was role-aware. A Rydberg atom got asked for its anharmonicity. Rows now come from the component's model; params it doesn't have are absent, not shown as unanswered. Units are never assumed (transmon params are GHz, the Rydberg templates work in rad/µs) — a unit renders only when the recorded key spells it.

2 · Hamiltonian composed over the actual component and edge sets — the old composer deduped term strings over the set of distinct roles, so it rendered "which kinds of term appear", not the Hamiltonian of the system. It meant: a 2-atom and a 20-atom register rendered identically; an N-edge chain rendered one edge hardcoded to sites (1),(2); a qubit and a cavity both used â; the drive-arch badge had no counterpart in the equation; + -Δ printed literally; and \hat ^\dagger (a KaTeX error box) for any exchange/CR/mode-mediated edge with a non-bosonic endpoint. Now: components group by model and sum over their site indices, each bosonic group gets its own operator letter, like edges aggregate into Σ_⟨ij⟩, and the drive arch decides whether a control carries a site index — Ω(t) shared, Ω_i(t) per site, Ω_z(i)(t) per zone.

3 · recorded beats inferredsystemHamiltonian() returns {latex, source}. A model recorded on the entity renders verbatim; otherwise the canonical form renders under an inferred · confirm or correct label. When nothing is recorded and nothing is modelled the card says "not recorded" rather than showing Ĥ_drift + Ĥ_c(t) — true of every control problem ever posed, and it would occupy the slot the real model belongs in.

The rule that matters

Two separate leaks put the transmon model on a spin qubit, and the second is the subtle one:

  • platformDefaultRole maps every unfamiliar platform to "qubit" — fixed on the plugin side.
  • levels >= 3 was read as "anharmonic ladder". It is not. Three levels is a Hilbert-space dimension: an exchange-only qubit at levels=3 is three dots; a spin-1 defect is three Zeeman sublevels. Neither is an oscillator.

So the platform is now the only thing that licenses a ladder for a qubit role. levels=2 still earns the generic two-level model — safe anywhere, since every two-level system has an ω σ_z/2 splitting and σx/σy control. Everything else is opaque.

One classify() drives both the equation and the physics rows, so the two halves of the card cannot describe different physics again.

Bonus: a three-way drift

The ladder drive was a single ε(t)(â+â†), while the plugin's TRANSMON_LATEX (what Amico shows in chat) and Piccolo's n_drives = 2 both say two quadratures. Same device, same session, two different answers — nobody had noticed because both look plausible. Two is correct; the card now matches.

What it looks like

exchange-only-spin · 1 qubit × 3 levels · per-component drive
HAMILTONIAN not recorded
No model for this platform yet — tell Amico the terms.
LEVELS 3
transmon · 1 qubit × 3 levels · per-component drive
HAMILTONIAN inferred · confirm or correct
Ĥ/ℏ = ω â†â + δ/2 ↲Ⲡ+ u₁(t)(â+â†) + i u₂(t)(â−â†)

Verification

399 pass across 30 files, tsgo clean. The KaTeX sweep crosses role × coupling kind × drive arch × N × platform (~8k systems) and asserts both directions: every rendered system parses, no output when nothing is modelled, and never a model invented for an all-unmodelled system.

Branched off local/amicode; these three commits are extracted from a local integration branch and touch only the system-card files.

🤖 Generated with Claude Code

@aarontrowbridge
aarontrowbridgeforce-pushed the feat/amicode-system-card-model branch from ac7078f to 4118aaaCompareJuly 28, 2026 21:52
aarontrowbridge added a commit to harmoniqs/amicode that referenced this pull request Jul 28, 2026
…bricating roles
The System card re-derives the Hamiltonian in the renderer from (role, levels,
platform) with hardcoded tables, so it is only ever right for platforms someone
hardcoded — and silently wrong for the rest. It showed the transmon ladder, and
asked for an anharmonicity, on an exchange-only spin qubit. Two changes here; the
renderer half is harmoniqs/opencode#93.
1. `amicode_set_model` gains `hamiltonian` — the model term by term
({kind: drift|coupling|drive, latex, acts_on?, label?}) plus `hamiltonian_notes`
for frame/unit/basis conventions. The agent already understands the model well
enough to author the Julia solve; this is where that understanding gets written
down instead of evaporating into the script. It knows what an exchange-only spin
qubit is — the renderer's table never will. Full path: validation (closed kind
set, non-empty latex, acts_on ids must exist, brace balance since the plugin
can't parse LaTeX but the card renders it straight into KaTeX), TOML round-trip,
wholesale patch-replace, hashing, normalizeSystem read-through.
2. `role` gains `other`, and `platformDefaultRole` stops inventing one. Only
platforms we model get a role from the string (rydberg→atom, transmon→qubit,
bosonic→mode); everything else is `other` until MODEL asks. The old blanket
"unknown → qubit" was also wrong for photonic and bosonic, which are modes.
AGENTS.md tells the interview to record the Hamiltonian — mandatory off-template,
worth confirming even on template — and to use `other` over a near-miss.
Note for the reviewer: this lands the recording side. The card only renders it once
the fork release carrying #93 is pinned via `pnpm opencode:pin`, so there
is no lock bump here.
Verified: 782 tests pass (78 files), tsc clean.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
aarontrowbridgeand others added 3 commits July 28, 2026 18:51
The card made its component-count claim implicitly, so an unanswered 'how many
atoms?' read as 'one'. systemCountLabel now states it as its own badge ('2 atoms
x 3 levels') that a researcher can read and correct.
componentPhysicsRows renders what each role actually has, in card order:
- unanswered params read 'not set', so the list doubles as the interview's to-do
- anything else on file is still shown, so nothing recorded is dropped
- an unrecognized role expects NOTHING -- the honest floor for a platform we have
no model for
- units are never assumed (transmon params are GHz, the Rydberg templates work in
rad/us, a bare omega says which only by convention), so a unit appears only when
the recorded key spells it out
- a zero keeps the '0 means unset' reading, so an all-zeros seed does not look
like a specified device
driftTerm now keys the qubit ladder off LEVELS rather than off whether delta
happens to be filled in: a 3-level transmon with empty params is still an
anharmonic ladder, and rendering it as a bare spin misstates the model the solve
will use. A mode's Kerr stays params-driven, since a linear cavity genuinely has
none.
Continues 0793fd6. Committed on the author's behalf as part of folding the
worktree's in-progress work onto the branch; the content is theirs.
+169 lines of tests alongside +278 of implementation; ui suite 442 -> 448 pass.
…f-template
The card re-derived the Hamiltonian in the renderer from (role, levels, platform)
using hardcoded tables, so it could only ever be right for platforms someone had
hardcoded. Two separate leaks put the transmon model on a spin qubit:
- `platformDefaultRole` maps every unfamiliar platform to "qubit", so an
exchange-only HRL spin qubit arrived indistinguishable from a transmon.
- levels >= 3 was read as "anharmonic ladder". It is not. Three levels is a
Hilbert-space DIMENSION: an exchange-only qubit at levels=3 is three dots, a
spin-1 defect is three Zeeman sublevels. Neither is an oscillator.
So the platform is now the only thing that licenses a ladder for a `qubit` role
(transmon, bosonic). levels=2 still earns the generic two-level model, which is
safe on any platform — every two-level system has an ω σ_z/2 splitting and σx/σy
control. Everything else is opaque.
Recorded beats inferred. `systemHamiltonian()` returns {latex, source}: a model
recorded on the entity (amicode_set_model's `hamiltonian`, see harmoniqs/amicode#220) renders
verbatim; otherwise the canonical form for the platform renders under an
"inferred · confirm or correct" label. When nothing is recorded AND nothing is
modelled the card says "not recorded" rather than showing `Ĥ_drift + Ĥ_c(t)`, which
is true of every control problem ever posed and would occupy the slot the real model
belongs in. Mixed systems still get a named placeholder per unmodelled component.
One `classify()` now drives both the equation and the physics rows, so the two
halves of the card cannot describe different physics again.
Also fixes a three-way drift found while doing this: the ladder drive was a single
`ε(t)(â+â†)` while the plugin's TRANSMON_LATEX (shown in chat) and Piccolo's
n_drives = 2 both say two quadratures. Two is correct; the card now matches.
Verified: 399 pass across 30 files, tsgo clean. The KaTeX sweep now crosses the
platform axis too (8k systems) and asserts BOTH directions: no output when nothing
is modelled, and never a model invented for an all-unmodelled system.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@jack-champagne
jack-champagneforce-pushed the feat/amicode-system-card-model branch from 4118aaa to e4e0133CompareJuly 28, 2026 22:52
… once
The sweep enumerates ~8k systems, but they collapse onto a few hundred distinct
equations, and KaTeX is the expensive part. Rendering the same string 200 times
proves nothing and took 22s on CI against a 5s default timeout (it passed locally
on a fast machine, and I had only been running src/amicode — CI runs all of src).
Coverage is unchanged: every distinct output is still parsed, and the mapping back
to a producing system is kept for the failure message. Adds an assertion that the
sweep really does vary its output, so a future change that collapses everything to
one equation can't quietly pass.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
jack-champagne added a commit that referenced this pull request Jul 29, 2026
…t tests (#98)
The three `session.llm native recorded` scenarios are the only failures on
`local/amicode`, so the fork's `test` job is red and every PR into it inherits a
red check — including #93, whose own suite is 3366 pass / 3 fail with zero
failures of its own.
Cause is ours. AMICODE-PATCHES.md ADDENDUM 2 consolidated the prompt so
`system.ts provider()` returns `[providerBase(model), PROMPT_COMMUNICATING]`,
appending `communicating.txt` for every model family. The cassettes still record
the pre-patch prompt, so all three break on a diff of prose.
Those tests assert TRANSPORT mechanics — that a tool loop is driven to a final
text answer. The prompt is incidental, so matching on it couples them to text
they do not test. Patching the recorded prompt instead would work until the next
prompt edit, and that patch already has three addenda.
`RecorderOptions.match` is an existing seam (types.ts:85, threaded through
`http()` to `recordingLayer`) that nothing used. Adds `promptAgnosticMatcher`
alongside `defaultMatcher` and passes it from this one test.
The prompt arrives in three shapes, all covered:
instructions OpenAI Responses
system[] Anthropic Messages
input[].role=="system" the OpenCode proxy
System-message content is replaced with a placeholder rather than deleted, so
"a system message is present, with content" stays part of the match.
Verified narrow, in test/matching.test.ts: it ignores prompt prose in all three
shapes, and still rejects a different user message, model, tool set, URL, or a
missing-vs-present system message. 49 pass in http-recorder; the three recorded
scenarios go 3 fail -> 3 pass; typecheck green across 23 packages.
@jack-champagne
jack-champagne merged commit 9bd4649 into local/amicodeJul 29, 2026
1 of 4 checks passed
@jack-champagne
jack-champagne deleted the feat/amicode-system-card-model branch July 29, 2026 02:38
jack-champagne pushed a commit to harmoniqs/amicode that referenced this pull request Jul 29, 2026
…bricating roles (#220)
The System card re-derives the Hamiltonian in the renderer from (role, levels,
platform) with hardcoded tables, so it is only ever right for platforms someone
hardcoded — and silently wrong for the rest. It showed the transmon ladder, and
asked for an anharmonicity, on an exchange-only spin qubit. Two changes here; the
renderer half is harmoniqs/opencode#93.
1. `amicode_set_model` gains `hamiltonian` — the model term by term
({kind: drift|coupling|drive, latex, acts_on?, label?}) plus `hamiltonian_notes`
for frame/unit/basis conventions. The agent already understands the model well
enough to author the Julia solve; this is where that understanding gets written
down instead of evaporating into the script. It knows what an exchange-only spin
qubit is — the renderer's table never will. Full path: validation (closed kind
set, non-empty latex, acts_on ids must exist, brace balance since the plugin
can't parse LaTeX but the card renders it straight into KaTeX), TOML round-trip,
wholesale patch-replace, hashing, normalizeSystem read-through.
2. `role` gains `other`, and `platformDefaultRole` stops inventing one. Only
platforms we model get a role from the string (rydberg→atom, transmon→qubit,
bosonic→mode); everything else is `other` until MODEL asks. The old blanket
"unknown → qubit" was also wrong for photonic and bosonic, which are modes.
AGENTS.md tells the interview to record the Hamiltonian — mandatory off-template,
worth confirming even on template — and to use `other` over a near-miss.
Note for the reviewer: this lands the recording side. The card only renders it once
the fork release carrying #93 is pinned via `pnpm opencode:pin`, so there
is no lock bump here.
Verified: 782 tests pass (78 files), tsc clean.
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@aarontrowbridge@jack-champagne
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

feat(amicode): system card renders the recorded Hamiltonian, and stops inventing one - #93

Merged
jack-champagne merged 4 commits into
local/amicodefrom
feat/amicode-system-card-model
Jul 29, 2026
Merged

feat(amicode): system card renders the recorded Hamiltonian, and stops inventing one#93
jack-champagne merged 4 commits into
local/amicodefrom
feat/amicode-system-card-model

Conversation

@aarontrowbridge

Copy link
Copy Markdown
Member

The System card re-derived the Hamiltonian in the renderer from (role, levels, platform) using hardcoded tables. So it could only ever be right for platforms someone had hardcoded, and was confidently wrong for the rest — most recently showing the transmon ladder, and asking for an anharmonicity, on an exchange-only spin qubit.

Recording half of this is harmoniqs/amicode#AMICODE_PR.

Three commits

1 · per-component physics rows — the row list was a fixed transmon spec (frequency · anharmonicity · drive bound · decay) emitted for every component, while the Hamiltonian directly above it was role-aware. A Rydberg atom got asked for its anharmonicity. Rows now come from the component's model; params it doesn't have are absent, not shown as unanswered. Units are never assumed (transmon params are GHz, the Rydberg templates work in rad/µs) — a unit renders only when the recorded key spells it.

2 · Hamiltonian composed over the actual component and edge sets — the old composer deduped term strings over the set of distinct roles, so it rendered "which kinds of term appear", not the Hamiltonian of the system. It meant: a 2-atom and a 20-atom register rendered identically; an N-edge chain rendered one edge hardcoded to sites (1),(2); a qubit and a cavity both used â; the drive-arch badge had no counterpart in the equation; + -Δ printed literally; and \hat ^\dagger (a KaTeX error box) for any exchange/CR/mode-mediated edge with a non-bosonic endpoint. Now: components group by model and sum over their site indices, each bosonic group gets its own operator letter, like edges aggregate into Σ_⟨ij⟩, and the drive arch decides whether a control carries a site index — Ω(t) shared, Ω_i(t) per site, Ω_z(i)(t) per zone.

3 · recorded beats inferredsystemHamiltonian() returns {latex, source}. A model recorded on the entity renders verbatim; otherwise the canonical form renders under an inferred · confirm or correct label. When nothing is recorded and nothing is modelled the card says "not recorded" rather than showing Ĥ_drift + Ĥ_c(t) — true of every control problem ever posed, and it would occupy the slot the real model belongs in.

The rule that matters

Two separate leaks put the transmon model on a spin qubit, and the second is the subtle one:

  • platformDefaultRole maps every unfamiliar platform to "qubit" — fixed on the plugin side.
  • levels >= 3 was read as "anharmonic ladder". It is not. Three levels is a Hilbert-space dimension: an exchange-only qubit at levels=3 is three dots; a spin-1 defect is three Zeeman sublevels. Neither is an oscillator.

So the platform is now the only thing that licenses a ladder for a qubit role. levels=2 still earns the generic two-level model — safe anywhere, since every two-level system has an ω σ_z/2 splitting and σx/σy control. Everything else is opaque.

One classify() drives both the equation and the physics rows, so the two halves of the card cannot describe different physics again.

Bonus: a three-way drift

The ladder drive was a single ε(t)(â+â†), while the plugin's TRANSMON_LATEX (what Amico shows in chat) and Piccolo's n_drives = 2 both say two quadratures. Same device, same session, two different answers — nobody had noticed because both look plausible. Two is correct; the card now matches.

What it looks like

exchange-only-spin · 1 qubit × 3 levels · per-component drive
HAMILTONIAN not recorded
No model for this platform yet — tell Amico the terms.
LEVELS 3
transmon · 1 qubit × 3 levels · per-component drive
HAMILTONIAN inferred · confirm or correct
Ĥ/ℏ = ω â†â + δ/2 ↲Ⲡ+ u₁(t)(â+â†) + i u₂(t)(â−â†)

Verification

399 pass across 30 files, tsgo clean. The KaTeX sweep crosses role × coupling kind × drive arch × N × platform (~8k systems) and asserts both directions: every rendered system parses, no output when nothing is modelled, and never a model invented for an all-unmodelled system.

Branched off local/amicode; these three commits are extracted from a local integration branch and touch only the system-card files.

🤖 Generated with Claude Code

@aarontrowbridge
aarontrowbridgeforce-pushed the feat/amicode-system-card-model branch from ac7078f to 4118aaaCompareJuly 28, 2026 21:52
aarontrowbridge added a commit to harmoniqs/amicode that referenced this pull request Jul 28, 2026
…bricating roles
The System card re-derives the Hamiltonian in the renderer from (role, levels,
platform) with hardcoded tables, so it is only ever right for platforms someone
hardcoded — and silently wrong for the rest. It showed the transmon ladder, and
asked for an anharmonicity, on an exchange-only spin qubit. Two changes here; the
renderer half is harmoniqs/opencode#93.
1. `amicode_set_model` gains `hamiltonian` — the model term by term
({kind: drift|coupling|drive, latex, acts_on?, label?}) plus `hamiltonian_notes`
for frame/unit/basis conventions. The agent already understands the model well
enough to author the Julia solve; this is where that understanding gets written
down instead of evaporating into the script. It knows what an exchange-only spin
qubit is — the renderer's table never will. Full path: validation (closed kind
set, non-empty latex, acts_on ids must exist, brace balance since the plugin
can't parse LaTeX but the card renders it straight into KaTeX), TOML round-trip,
wholesale patch-replace, hashing, normalizeSystem read-through.
2. `role` gains `other`, and `platformDefaultRole` stops inventing one. Only
platforms we model get a role from the string (rydberg→atom, transmon→qubit,
bosonic→mode); everything else is `other` until MODEL asks. The old blanket
"unknown → qubit" was also wrong for photonic and bosonic, which are modes.
AGENTS.md tells the interview to record the Hamiltonian — mandatory off-template,
worth confirming even on template — and to use `other` over a near-miss.
Note for the reviewer: this lands the recording side. The card only renders it once
the fork release carrying #93 is pinned via `pnpm opencode:pin`, so there
is no lock bump here.
Verified: 782 tests pass (78 files), tsc clean.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
aarontrowbridgeand others added 3 commits July 28, 2026 18:51
The card made its component-count claim implicitly, so an unanswered 'how many
atoms?' read as 'one'. systemCountLabel now states it as its own badge ('2 atoms
x 3 levels') that a researcher can read and correct.
componentPhysicsRows renders what each role actually has, in card order:
- unanswered params read 'not set', so the list doubles as the interview's to-do
- anything else on file is still shown, so nothing recorded is dropped
- an unrecognized role expects NOTHING -- the honest floor for a platform we have
no model for
- units are never assumed (transmon params are GHz, the Rydberg templates work in
rad/us, a bare omega says which only by convention), so a unit appears only when
the recorded key spells it out
- a zero keeps the '0 means unset' reading, so an all-zeros seed does not look
like a specified device
driftTerm now keys the qubit ladder off LEVELS rather than off whether delta
happens to be filled in: a 3-level transmon with empty params is still an
anharmonic ladder, and rendering it as a bare spin misstates the model the solve
will use. A mode's Kerr stays params-driven, since a linear cavity genuinely has
none.
Continues 0793fd6. Committed on the author's behalf as part of folding the
worktree's in-progress work onto the branch; the content is theirs.
+169 lines of tests alongside +278 of implementation; ui suite 442 -> 448 pass.
…f-template
The card re-derived the Hamiltonian in the renderer from (role, levels, platform)
using hardcoded tables, so it could only ever be right for platforms someone had
hardcoded. Two separate leaks put the transmon model on a spin qubit:
- `platformDefaultRole` maps every unfamiliar platform to "qubit", so an
exchange-only HRL spin qubit arrived indistinguishable from a transmon.
- levels >= 3 was read as "anharmonic ladder". It is not. Three levels is a
Hilbert-space DIMENSION: an exchange-only qubit at levels=3 is three dots, a
spin-1 defect is three Zeeman sublevels. Neither is an oscillator.
So the platform is now the only thing that licenses a ladder for a `qubit` role
(transmon, bosonic). levels=2 still earns the generic two-level model, which is
safe on any platform — every two-level system has an ω σ_z/2 splitting and σx/σy
control. Everything else is opaque.
Recorded beats inferred. `systemHamiltonian()` returns {latex, source}: a model
recorded on the entity (amicode_set_model's `hamiltonian`, see harmoniqs/amicode#220) renders
verbatim; otherwise the canonical form for the platform renders under an
"inferred · confirm or correct" label. When nothing is recorded AND nothing is
modelled the card says "not recorded" rather than showing `Ĥ_drift + Ĥ_c(t)`, which
is true of every control problem ever posed and would occupy the slot the real model
belongs in. Mixed systems still get a named placeholder per unmodelled component.
One `classify()` now drives both the equation and the physics rows, so the two
halves of the card cannot describe different physics again.
Also fixes a three-way drift found while doing this: the ladder drive was a single
`ε(t)(â+â†)` while the plugin's TRANSMON_LATEX (shown in chat) and Piccolo's
n_drives = 2 both say two quadratures. Two is correct; the card now matches.
Verified: 399 pass across 30 files, tsgo clean. The KaTeX sweep now crosses the
platform axis too (8k systems) and asserts BOTH directions: no output when nothing
is modelled, and never a model invented for an all-unmodelled system.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@jack-champagne
jack-champagneforce-pushed the feat/amicode-system-card-model branch from 4118aaa to e4e0133CompareJuly 28, 2026 22:52
… once
The sweep enumerates ~8k systems, but they collapse onto a few hundred distinct
equations, and KaTeX is the expensive part. Rendering the same string 200 times
proves nothing and took 22s on CI against a 5s default timeout (it passed locally
on a fast machine, and I had only been running src/amicode — CI runs all of src).
Coverage is unchanged: every distinct output is still parsed, and the mapping back
to a producing system is kept for the failure message. Adds an assertion that the
sweep really does vary its output, so a future change that collapses everything to
one equation can't quietly pass.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
jack-champagne added a commit that referenced this pull request Jul 29, 2026
…t tests (#98)
The three `session.llm native recorded` scenarios are the only failures on
`local/amicode`, so the fork's `test` job is red and every PR into it inherits a
red check — including #93, whose own suite is 3366 pass / 3 fail with zero
failures of its own.
Cause is ours. AMICODE-PATCHES.md ADDENDUM 2 consolidated the prompt so
`system.ts provider()` returns `[providerBase(model), PROMPT_COMMUNICATING]`,
appending `communicating.txt` for every model family. The cassettes still record
the pre-patch prompt, so all three break on a diff of prose.
Those tests assert TRANSPORT mechanics — that a tool loop is driven to a final
text answer. The prompt is incidental, so matching on it couples them to text
they do not test. Patching the recorded prompt instead would work until the next
prompt edit, and that patch already has three addenda.
`RecorderOptions.match` is an existing seam (types.ts:85, threaded through
`http()` to `recordingLayer`) that nothing used. Adds `promptAgnosticMatcher`
alongside `defaultMatcher` and passes it from this one test.
The prompt arrives in three shapes, all covered:
instructions OpenAI Responses
system[] Anthropic Messages
input[].role=="system" the OpenCode proxy
System-message content is replaced with a placeholder rather than deleted, so
"a system message is present, with content" stays part of the match.
Verified narrow, in test/matching.test.ts: it ignores prompt prose in all three
shapes, and still rejects a different user message, model, tool set, URL, or a
missing-vs-present system message. 49 pass in http-recorder; the three recorded
scenarios go 3 fail -> 3 pass; typecheck green across 23 packages.
@jack-champagne
jack-champagne merged commit 9bd4649 into local/amicodeJul 29, 2026
1 of 4 checks passed
@jack-champagne
jack-champagne deleted the feat/amicode-system-card-model branch July 29, 2026 02:38
jack-champagne pushed a commit to harmoniqs/amicode that referenced this pull request Jul 29, 2026
…bricating roles (#220)
The System card re-derives the Hamiltonian in the renderer from (role, levels,
platform) with hardcoded tables, so it is only ever right for platforms someone
hardcoded — and silently wrong for the rest. It showed the transmon ladder, and
asked for an anharmonicity, on an exchange-only spin qubit. Two changes here; the
renderer half is harmoniqs/opencode#93.
1. `amicode_set_model` gains `hamiltonian` — the model term by term
({kind: drift|coupling|drive, latex, acts_on?, label?}) plus `hamiltonian_notes`
for frame/unit/basis conventions. The agent already understands the model well
enough to author the Julia solve; this is where that understanding gets written
down instead of evaporating into the script. It knows what an exchange-only spin
qubit is — the renderer's table never will. Full path: validation (closed kind
set, non-empty latex, acts_on ids must exist, brace balance since the plugin
can't parse LaTeX but the card renders it straight into KaTeX), TOML round-trip,
wholesale patch-replace, hashing, normalizeSystem read-through.
2. `role` gains `other`, and `platformDefaultRole` stops inventing one. Only
platforms we model get a role from the string (rydberg→atom, transmon→qubit,
bosonic→mode); everything else is `other` until MODEL asks. The old blanket
"unknown → qubit" was also wrong for photonic and bosonic, which are modes.
AGENTS.md tells the interview to record the Hamiltonian — mandatory off-template,
worth confirming even on template — and to use `other` over a near-miss.
Note for the reviewer: this lands the recording side. The card only renders it once
the fork release carrying #93 is pinned via `pnpm opencode:pin`, so there
is no lock bump here.
Verified: 782 tests pass (78 files), tsc clean.
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@aarontrowbridge@jack-champagne