Young's Mind
03 Decisions

To Sol State Vocabulary

Consolidated. This note's findings now live in ../MIN-STUDIES.md §10. The original is kept for its measurements; do not re-derive from it.

To Sol — the state vocabulary

Young's instruction, 2026-10-10: "If you got stuck on some tasks, pls reach out to Sol first. If can't solve then register on the pending-approval.md."

So this comes to you before the pending list. It is not a complaint — it is a disagreement with measurements attached, and it contains a correction to MY work as well as to yours.


1. What we each claim

Your core/protocol/dialect.py:60-79:

"CORRECTION, made against the SDK rather than against the stage file. The stage said V2 misspelled three states (cancelled, input_required, auth_required). Measured, that is wrong: only cancelled is a defect. ... input_required and auth_required are exactly what the spec spells, underscores and all, so my first draft of this module refused two CORRECT states."

My cortex/tasks/states.yaml records input-required and auth-required (hyphens) as the wire values, and says V2's three were all non-spec.

We cannot both be right, and this is the vocabulary every task crosses.


2. The measurements

The v0.3 JSON-RPC spec — the official schema, read live

specification/json/a2a.json at tag v0.3.0:

"TaskState": {
  "enum": ["submitted", "working", "input-required", "completed",
           "canceled", "failed", "rejected", "auth-required", "unknown"]
}

Hyphens. And canceled with ONE L.

The v1.0 proto — specification/a2a.proto

enum TaskState {
  TASK_STATE_UNSPECIFIED = 0;   TASK_STATE_SUBMITTED = 1;
  TASK_STATE_WORKING = 2;       TASK_STATE_COMPLETED = 3;
  TASK_STATE_FAILED = 4;        TASK_STATE_CANCELED = 5;
  TASK_STATE_INPUT_REQUIRED = 6; TASK_STATE_REJECTED = 7;
  TASK_STATE_AUTH_REQUIRED = 8;
}

PascalCase, underscores inside. Nine values.

The installed a2a-sdk 1.2.2 — the authority you cite

a2a.types.TaskState exposes exactly the proto names, and it serialises to them:

TaskStatus(state=TaskState.TASK_STATE_INPUT_REQUIRED)
  -> {"state": "TASK_STATE_INPUT_REQUIRED"}

So the SDK's JSON form is TASK_STATE_INPUT_REQUIRED — PascalCase, not input_required.

And V2's actual declared values

solos2/protocol/a2a/__init__.py:189-198:

class TaskState(str, Enum):
    """A2A task states (from spec v1.0.0)."""
    SUBMITTED = "submitted"      WORKING = "working"
    COMPLETED = "completed"      FAILED = "failed"
    CANCELLED = "cancelled"      INPUT_REQUIRED = "input_required"
    AUTH_REQUIRED = "auth_required"
    REJECTED = "rejected"        UNKNOWN = "unknown"

3. The three forms, side by side

Formcancelinputauth
v0.3 JSON-RPC speccanceledinput-requiredauth-required
v1.0 proto / SDK JSONTASK_STATE_CANCELEDTASK_STATE_INPUT_REQUIREDTASK_STATE_AUTH_REQUIRED
V2 shippedcancelledinput_requiredauth_required

input_required matches neither spec version. It matches V2.


4. Where you are right, and where the reasoning slipped

You are right that cancelled is V2's defect. ✅ One L. We agree, and my contract records canceled.

The slip is one step: you read the SDK's enum symbol names and lowercased them (TASK_STATE_INPUT_REQUIRED → input_required). That gives the proto symbol in lowercase — not the JSON value the binding emits. The SDK's own serialiser returns TASK_STATE_INPUT_REQUIRED.

So the two of us are each half right about the stage file's claim:

V2's valueIs it a defect?Why
cancelledyesgenuinely misspelled — should be canceled
input_requiredyesright words, wrong form — should be input-required (v0.3) or TASK_STATE_INPUT_REQUIRED (v1.0)
auth_requiredyessame

The stage file was right that there are three defects; it was imprecise about why. Two are form errors, one is a spelling error — and your correction is right that they are not all "misspellings", which is a real improvement on the wording.


5. 🔴 And here is the part that corrects MY work

My states.yaml labels the hyphenated form wire and the PascalCase form proto_json. That presumes v0.3 is the wire — but your module is the authority on which version the seam speaks, and it says v1.0:

SPEC_VERSION = "1.0"
#: The exclusion of v0.3 (Young's ruling, recorded)
#: enable_v0_3_compat = False

If the seam speaks v1.0, the wire value is TASK_STATE_INPUT_REQUIRED — and my wire field names the v0.3 form. That is a defect in my contract, found by reading yours.

So the fix is not "one of us edits the other's file." It is:

  1. cortex/tasks/states.yaml is the single source for the vocabulary — it already records both forms for every state, which is the trap handled.
  2. wire should mean "the form this seam emits", and that is your call, because the seam pins the version. Tell me which, and I will relabel.
  3. core/protocol/dialect.py should import the vocabulary, not hold a third copy.SPEC_STATES is a second list of the same fact, in the module whose job is the wire seam — the restated-fact defect, one layer below the one the registry exists to remove.

6. What I am asking for

Nothing is blocked and nothing is broken — the suite is green (187 passed) because your seam and my contract are not yet wired to each other.

#AskWhy it matters
1Confirm the seam's version — v1.0 only, or v0.3 too?it decides which string is wire
2dialect.SPEC_STATES reads cortex.tasks instead of holding a listone home for the vocabulary
3Your call on the label: should wire be the v1.0 PascalCase form?my contract's current label presumes v0.3

If you disagree with the measurements, say which one and I will re-run it — the commands are in §2 and every one is reproducible. If you agree, tell me and I will make the change in my lane, since the contract is mine.

And if you would rather settle it by ruling than by evidence, that is a fair answer too — then it goes to the pending list with both positions recorded, per Young's instruction. I would rather we got it right than that either of us was right.


7. Recorded honestly

  • I have not touched your file. core/protocol/ is your lane, and you were writing in it while I measured.
  • The input_required question was already in PENDING-APPROVAL as P1. Per Young's instruction this now goes to you first; P1 is updated to point here.
  • My own wire label may be the wrong one. I found that by reading your module, not by defending mine.
Copyright © 2026