0.0 / 30
What changed in the harness
Selection accuracy 93→93, token cost up 3%, unconfirmed writes 0%→0%.
Category breakdown
Where the score comes from.
Earned points across the four signals Gradable measures. Safety and Legibility are scored out of 30; Economics and Discoverability are scored out of 20.
01Safety
02Legibility
25.8 / 30
03Economics
16.7 / 20
04Discoverability
11.6 / 20
Highest-impact fix
Estimated gain +30 pointsAdd explicit identity and permission preflight tools
Expose machine-readable principal/tenant confirmation and a non-mutating permission check so agents can verify both before destructive actions.
Description evidence
Defects and rewrites.
2 defects found across the exposed tool descriptions. Suggested rewrites make purpose, inputs, boundaries, and returns easier for an agent to understand.
| Tool | Defect types | Suggested rewrite |
|---|---|---|
notation_validate |
params_unexplained |
Pre-flight validate a notation_render input without rendering. Returns errors with a concrete `fix` field that tells the agent exactly how to repair malformed input (e.g. "Use scientific notation: letter A-G + optional # or b + octave number, e.g. C4, F#5, Bb3."). Substantially cheaper than notation_render because it skips the Verovio engraving step entirely. WHEN TO USE: when iterating on input shape and uncertain whether it is well-formed; when input came from user-supplied or LLM-generated data that may be malformed; when surfacing precise validation errors to your end user before committing to a full render; when learning the input format (combine with notation_examples to see canonical inputs). WHEN NOT TO USE: if input is known to be valid (just call notation_render directly — it validates internally too); if you have not learned the schema yet (call notation_schema or notation_examples first to see the format). INPUT: identical shape to notation_render. `instruments` array required (each with `name` and `notes` or `voices`). Optional fields match notation_render: `title` (optional title rendered above the score), `composer` (optional composer rendered top-right), `tempo` (BPM; affects MIDI timing only, not visual rendering), `timeSignature` ([beats, beat-unit] with 2 items, e.g. [4,4], [3,4], [6,8]; default [4,4]), `keySignature` (human-readable key such as "C major", "G major", "Bb minor", "F# major"; default "C major"). OUTPUT (JSON, valid): { ok: true, requestId, valid: true, warnings: ValidationIssue[], meta: { measureCount, instrumentCount, voiceCount, durationBeats }, attribution }. Warnings are non-blocking notices (e.g. unusual time signature handling). OUTPUT (JSON, invalid): { ok: false, requestId, valid: false, errors: ValidationIssue[], warnings, attribution }. Each ValidationIssue: { path: "instruments[0].voices[0].notes[3]", code: "BAD_PITCH"|"BAD_DURATION"|"MISSING_FIELD"|"BAD_KEY_SIG"|..., message, fix, severity: "error"|"warning" }. Surface the `fix` to your user or use it to auto-repair. EXAMPLE INPUT: { "instruments": [{ "name": "Violin", "notes": ["C5/q","D5/q","E5/q","F5/q"] }] } TYPICAL LATENCY: 30-100 ms (no Verovio render; pure JSON-to-Score conversion + bar-line arithmetic). |
theory_validate_ranges |
params_unexplained |
Check every note in a maestroAnalyst Score JSON against its instrument's standard practical range. Returns warnings for out-of-range pitches with measure, beat, MIDI number, and severity. WHEN TO USE: after parsing a MusicXML file with theory_parse_xml and before analysis — catch unplayable or extreme notes early; when generating or editing a score programmatically and wanting to verify instrument idiomatic range; when a student submits a composition for critique and range errors should be flagged. SEVERITY LEVELS: "error" = note is > 1 semitone outside the practical range; "warn" = note is at the boundary (within 1 semitone). SUPPORTED INSTRUMENTS (partial name match, case-insensitive): Violin, Viola, Cello, Double Bass, Harp, Flute, Piccolo, Oboe, English Horn, Clarinet, Bass Clarinet, Bassoon, Contrabassoon, Soprano/Alto/Tenor/Baritone Sax, Horn, Trumpet, Trombone, Tuba, Piano, Organ, Marimba, Xylophone, Vibraphone, Glockenspiel, Timpani, Soprano/Mezzo/Alto/Tenor/Baritone/Bass (voice). INPUT: a maestroAnalyst Score object — obtain one by calling theory_parse_xml with MusicXML text, and pass it through with its fields: `notes` (required; flat array of Note objects from the Score, each carrying pitch, measure, beat, and part info), `parts` (required; array of PartInfo objects { id, name }), `measureCount` (integer; total number of measures in the score, used to size bar-line arithmetic), `keySignatures` (array of the score's key signatures), and `timeSignatures` (array of the score's time signatures). OUTPUT: { ok, requestId, warnings: [{ measure, beat, pitch, midi, partId, instrumentName, min, max, severity }], attribution }. An empty `warnings` array means all notes are in range. EXAMPLE: pass a Score with a Violin part containing a note at A7 (MIDI 105) — it will return severity "error" since violin tops out around B7/MIDI 107 but A7 is beyond practical range. |
Selection evidence
Confusable tool pairs.
16 pairs where similar names or overlapping descriptions may send an agent toward the wrong tool.
| Tool A | Tool B | Confidence | Why they collide |
|---|---|---|---|
notation_examples |
notation_schema |
high | Both take empty input, return cached format documentation, and are explicitly cross-referenced as alternatives ('use notation_examples instead' / 'use notation_schema instead'). A task like 'what is the notation_render input format?' or 'fetch the docs for this API' maps plausibly to either. |
notation_validate |
theory_validate_ranges |
medium | Both are 'validate' tools whose descriptions invoke 'validate input', 'errors', and 'score'. A task like 'validate this composition / validate this score' is ambiguous unless the agent distinguishes JSON-input syntax validation from instrument-range checking; the descriptions do differentiate, but the shared validate+score framing creates real confusion risk. |
notation_render |
notation_validate |
medium | Both consume identical input and both mention that notation_render validates internally; a task like 'check my score and render it' or 'make sure this notation is correct' could route to either. Validate is cheaper, so render's own warning even tells agents to call validate first, muddying which tool a validation-flavored task should pick. |
notation_render |
notation_schema |
low | A task like 'what fields does the render input need?' or 'get the input format for rendering' could suggest either, but descriptions cleanly separate rendering from returning a JSON Schema, so confusion is only marginal. |
notation_validate |
notation_schema |
low | 'Check my input against the schema' could name either, but validate's concrete error-list-for-malformed-input role is distinct enough from returning the schema document that real mis-selection is unlikely. |
notation_validate |
notation_examples |
low | One returns worked payloads, the other returns validation errors; the 'learning the format' mention in validate's WHEN TO USE faintly overlaps examples, but the separation is clear. |
notation_render |
notation_examples |
low | Shared token 'render' plus examples being render-ready payloads invites a task like 'give me a renderable example', but descriptions route that carefully to examples first; low real confusion. |
theory_respell |
theory_analyze_score |
low | Only shared 'theory'; respell is pointedly not an analysis pipeline and analyze_score's WHEN NOT TO USE explicitly says 'if you only need re-spelling (theory_respell)', so mis-selection is unlikely. |
theory_respell |
theory_parse_xml |
low | Shared only 'theory' token; parse_xml is an input-format entry point, respell is a pitch-spelling utility — descriptions are unambiguous. |
theory_respell |
theory_pitch_utils |
low | Both do pitch-string manipulation, so a task like 'fix the accidentals to fit the key' could touch either on the surface, but pitch_utils is pure arithmetic (transpose/midi/interval) while respell is key-context spelling — the keyContext requirement distinguishes tasks clearly. |
theory_parse_xml |
theory_analyze_score |
low | Both take raw MusicXML and both parse it, but analyze_score is explicitly a one-shot superset; descriptions clearly direct users to parse_xml for lightweight needs and analyze_score for full analysis, so confusion is marginal. |
theory_validate_ranges |
theory_analyze_score |
low | Both consume a score and could appear in 'check this composition' tasks, but analyze_score's WHEN NOT TO USE explicitly names range checking as theory_validate_ranges' job; low genuine ambiguity. |
theory_validate_ranges |
theory_parse_xml |
low | parse_xml is described as the entry point that produces the Score for validate_ranges, so a task like 'get a Score to check ranges' is clearly a two-step chain, not an either/or choice. |
theory_validate_ranges |
theory_respell |
low | Only shared 'theory'; ranges is about instrument tessitura, respell about enharmonic spelling — no overlapping task naturally names both. |
theory_analyze_score |
theory_pitch_utils |
low | Full harmonic analysis vs a fast pitch-arithmetic utility; task scope is overwhelmingly distinct (rich end-to-end analysis vs one-pitch ops). |
theory_parse_xml |
theory_pitch_utils |
low | Parsing a MusicXML document vs pitch-string math; no plausible task conflates them beyond the shared 'theory' prefix. |
Compare the field