Skip to content

feat(core): unify error codes and messages on a bilingual error catalog - #1

Open
codetalks-hw wants to merge 242 commits into
mainfrom
feat/error-code-catalog
Open

codetalks-hw wants to merge 242 commits into
mainfrom
feat/error-code-catalog

Conversation

@codetalks-hw

Copy link
Copy Markdown
Owner

PR feat/error-code-catalog — Error Code & Message Refactor

Summary

Rebuilds the SDK's entire error surface around a single, closed, bilingual error catalog, fixing the inconsistent codes and garbled messages reported in review ("错误码和错误消息狗屁不通").

Before: four parallel error vocabularies (A2ATErrorCodes exception codes, result failure codes, free-form LLM-instructed codes, uncoded JDK exceptions), the same code carrying up to 17 different messages (negotiation_llm_infrastructure_error), the same semantic under 2–3 different codes (missing_required / missing_input / bare IllegalArgumentException), an open LLM code set, mixed message languages (hardcoded English, LLM-improvised Chinese, one prompt forcing English even on zh-CN), and error messages generated as LLM free text — the direct source of awkward outputs like "参数章节 '订阅条件' 下没有提供参数值行,参数未被提供。".

After: one ErrorCatalog (42 dotted domain.semantic codes, BUSINESS/INFRA category, declared fact parameters), LLM validation steps report structured facts only — {slot_name, code, facts} — and every user-facing message is rendered by the SDK from errors/{lang}/errors.json templates, following A2AT_LANGUAGE. Same semantic ⇒ same code ⇒ same message, deterministically.

Key changes

  • a2a-t-core: new ErrorCatalog enum, ErrorMessages renderer (classpath errors/{zh-CN,en-US}/errors.json, en-US fallback), A2ATBusinessException base (D6 three-layer model: programming errors stay IAE/NPE, business failures carry codes, infra failures are A2ATError); SlotValidationError keeps message (now template-rendered) and gains a facts map; A2ATErrorCodes is a @Deprecated(forRemoval) forwarding facade.
  • Prompts: the four error-defining prompt groups (content_validation, slot_extraction, semantic_validation, negotiation_semantic_validation) rewritten in both languages — closed code sets with three-part definitions (判定/不适用/正例), {slot_name, code, facts} output schema (no message), unified terminology (参数/slot), and the en-US content_validation structural description corrected to match actual renderer behavior (C1). The message 必须为英文 contradiction is gone.
  • Migrations: negotiation / server / client / prompt modules emit catalog codes everywhere; the ParamExtractor runtime vocabulary-mapping layer is deleted; negotiation fromData content-data checks moved from bare IllegalArgumentException to coded business exceptions (URI-shape IAEs intentionally stay); previously-uncaught exceptions on the legacy generateTaskPrompt path are caught and mapped into result failures (P8); LLM slot errors that were silently discarded are now surfaced (P9); server semantic validator restricts LLM codes to its slot.* domain with a *.rule_violation fallback + WARN for unknown codes (P7 closed).
  • Tests & docs: corpus (~1,900 tests), sample suites and tools migrated; docs/en + docs/zh API references and developer guides updated with the new code table, facts schema and old→new mapping; template_lint.py gains a CI gate: prompt code sets ⊆ catalog, every catalog code has zh-CN and en-US templates, template placeholders ⊆ declared fact parameters.

Compatibility

Breaking change, error paths only (see docs-local/error-code-refactor-plan.md §六 in the source workspace): facade signatures, success-path structures and config keys are unchanged; all error codes are new values (old→new mapping table in the docs), errors[] items gain facts and their message values change from LLM free text to rendered templates. Consumers that serialize errors[] over the wire should upgrade client and server together.

Verification

mvn -B clean verify green (all 11 modules, ~1,900 tests, 0 failures) after the final slot.not_provided rename; python tools/template_lint.py --resource-root ... green including the new catalog gate.

Commits

  1. feat(core): error catalog, message templates and business exception base
  2. feat(resources): validation prompt error contracts rewritten to facts schema
  3. refactor(prompt): validators and extractors on catalog codes
  4. refactor(negotiation): content and validation errors on catalog codes
  5. refactor(client,server): facades on catalog codes, no more raw-error leaks
  6. test(corpus,sample): expectations migrated
  7. docs(en,zh): new error contract documented

Known follow-ups (not in this PR)

  • errors/{lang}/errors.json loads from the classpath only; a local-file dual-source variant can follow the existing loader pattern later.
  • Legacy Map negotiation APIs (start/receive/continueNegotiation, deprecated) intentionally untouched, including their old exception codes.
  • Version bump strategy (recommended: ship as 2.0.0 together with the August breaking changes) is pending review.

zhangwenjun-huawei and others added 30 commits August 21, 2026 11:55
build(pom): add Error Prone, NullAway and JSpecify to build
…le code

Move the error code contract to the A2ATError root (getCode() never null,
default sdk_internal_error) and delete SdkException; re-parent
ConfigFileNotFoundException / ResourceNotFoundException /
PromptGenerationException / ContentValidationException onto A2ATError,
retype OperationResult.error to A2ATError, and convert ValidationPipeline
argument checks to NPE/IllegalArgumentException.

Signed-off-by: codetalks-hw <lihaizhen5@huawei.com>
LLMError now extends A2ATError so LLMConfigError/LLMRuntimeError join the
unified processing-failure tree; ClasspathPromptResourceLoader I/O wraps
use A2ATError.

Signed-off-by: codetalks-hw <lihaizhen5@huawei.com>
ScenarioRecognitionException / TaskPromptRenderException extend A2ATError;
loader and validator I/O wraps use A2ATError; TaskPromptRenderer null
template becomes Objects.requireNonNull (outside the tree).

Signed-off-by: codetalks-hw <lihaizhen5@huawei.com>
… NPE/IAE

All ~45 argument-contract throw sites now use Objects.requireNonNull for
null and IllegalArgumentException for blank/malformed/semantic violations,
staying outside the A2ATError tree; NegotiationReference.parse becomes
tryParse returning Optional (removing catch-based control flow);
NegotiationProcessingException delegates its code to the A2ATError root;
observability boundary tests rewritten against the new carriers.

Signed-off-by: codetalks-hw <lihaizhen5@huawei.com>
Client orchestrator catches a single A2ATError (LLMRuntimeError and config
errors now converge into result failures); PromptComplianceCheckException
extends A2ATError keeping stage; blank/malformed template URIs on facade
entry surface as NPE/IllegalArgumentException per the boundary contract;
facade @throws javadoc updated.

Signed-off-by: codetalks-hw <lihaizhen5@huawei.com>
Document the single A2ATError root with machine-readable code, the
NPE/IllegalArgumentException boundary for programming errors, tryParse,
and the removed SdkException/NegotiationContentException; both languages
in sync.

Signed-off-by: codetalks-hw <lihaizhen5@huawei.com>
…tion-unification

Refactor/exception unification
Signed-off-by: w00609601 <wushunhao1@huawei.com>
…dation

refactor: rename template_uri metadata key to templateUri
- TemplateUri: structured always-valid template identifier composed of
  extensionName, version and trailing segments; of() validates segments,
  parse() mirrors NegotiationReference.tryParse semantics, withLanguage()
  binds runtime language into a TemplateReference
- StandardTemplates: 11 built-in template constants in the spirit of
  java.nio.charset.StandardCharsets, with TASK/NOTIFICATION/AUTHORIZATION/
  NEGOTIATION group views
- TemplateReference: rename extensionPrefix() to extensionName() and move
  SimpleTemplateReference from DefaultContentValidator into core
- lock constants to bundled resource tree (a2a-t-resources) and to
  NegotiationReference composition (a2a-t-negotiation) via consistency tests

Signed-off-by: codetalks-hw <lihaizhen5@huawei.com>
…prone compatibility

The old_jdk_support profile lowers error-prone to 2.42.0 + nullaway 0.12.10 for older JDKs, but its activation boundary (17, 21] excluded JDK 17 itself. As a result JDK 17 fell back to the default error-prone 2.50.0, whose class files target Java 21 (version 65), so javac failed to load the annotation processor via ServiceLoader (ClassLoader.defineClass1). Switch the boundary to the closed interval [17, 21] so JDK 17 activates the downgrade and installs cleanly.

Signed-off-by: ZhouJie6 <ivo.zhou@huawei.com>
fix(profile): include JDK 17 in old_jdk_support activation for error-prone compatibility
…ndardTemplates

- main code: DefaultA2ATServerBuilder validator prefixes, loader
  KNOWN_TEMPLATE_TYPES/KNOWN_SLOT_TYPES lists and NegotiationReference
  URI_PREFIX now derive from StandardTemplates *_EXTENSION_NAME constants
  (probe order preserved); core is the single source of extension names
- tests: ~90 hardcoded builtin template URI literals across a2a-t-client,
  a2a-t-server, a2a-t-negotiation, a2a-t-prompt, a2a-t-core and
  a2a-t-sample replaced with StandardTemplates.XXX.uri() references;
  local *_URI test constants keep their names, only initializers swapped
- negative/malformed URI fixtures, non-builtin fixture URIs and
  compositional URI constructions intentionally left as raw strings
- javadoc value-documentation literals kept raw (they describe what the
  value is, not how to use it)

Signed-off-by: codetalks-hw <lihaizhen5@huawei.com>
…dard-template-uri

Refactor/standard template uri
…peline over TemplateUri

Analysis showed the TemplateReference interface carried no weight: no
caller ever read language() through the interface (language flows from
global prompt config each validator already holds), and its remaining
surface (uri + extensionName) is exactly TemplateUri. The instanceof
escape hatch in NegotiationSemanticValidator existed only because the
interface could not express negotiation-specific data.

- delete TemplateReference, SimpleTemplateReference and
  TemplateUri.withLanguage()/extensionPrefix(); language is runtime
  config, never an addressability dimension of the template
- genericize core pipeline: SemanticValidator<T> and ValidationPipeline<T>
- prompt module: ValidationPipeline<TemplateUri>,
  DefaultSemanticValidator implements SemanticValidator<TemplateUri>,
  DefaultContentValidator builds a TemplateUri after its structural checks
- negotiation module: ValidationPipeline<NegotiationReference>,
  NegotiationSemanticValidator extends SemanticValidator<NegotiationReference>
  with the negotiation-specific method renamed to validateNegotiation;
  the instanceof/cast default adapter is gone
- NegotiationReference is a plain record again, its uncalled
  extensionName() override removed

Signed-off-by: codetalks-hw <lihaizhen5@huawei.com>
…dard-template-uri

refactor(validation): remove TemplateReference in favor of generic pipeline over TemplateUri
…h trailing version

Internal review decision: drop the extension version segment, keep a
trailing template version (default v1) and insert a network-layer domain
segment into the Task-T and Notification-T paths. The URI now mirrors
the resource directory one-to-one and the Authorization-T scenario is
renamed to authorization-policy-management.

New layout:
- Task-T/network-layer/<scenario>/v1
- Notification-T/network-layer/<scenario>/v1
- Authorization-T/authorization-policy-management/v1
- Negotiation-T/<type>/<phase>/v1

- TemplateUri record is now {extensionName, pathSegments, templateVersion}
  with TemplateUri.DEFAULT_TEMPLATE_VERSION and a parse() that expects
  >= 3 segments (extension + >= 1 path segment + trailing version)
- StandardTemplates constants updated, AUTHZ_POLICY_MGR renamed to
  AUTHORIZATION_POLICY_MANAGEMENT, new NETWORK_LAYER_SEGMENT constant
- bundled templates/slots trees git-mv'd to mirror the new URIs; the
  template lint gate rules follow the new layouts
- NegotiationReference composes and parses the new 4-segment negotiation
  URIs; DefaultNegotiationTemplateLoader paths updated
- PromptResourceKey redesigned around path segments with template()/
  slotSchema()/scenario() factories taking TemplateUri; classpath and
  local-file loaders resolve full URIs directly and probe bare scenario
  codes against both the network-layer and plain layouts
- DefaultContentValidator validates first (extension name) and last
  (template version) segments
- tests, test fixture trees and bilingual docs migrated to the new layout

Signed-off-by: codetalks-hw <lihaizhen5@huawei.com>
…dard-template-uri

refactor(templates): reshape template URI layout to path-segments with trailing version
…cade chain and add JSpecify nullness annotations

Signed-off-by: codetalks-hw <lihaizhen5@huawei.com>
… to core.model, NegotiationContentService to generation, flatten taskrendering.api

Signed-off-by: codetalks-hw <lihaizhen5@huawei.com>
…asses to package-private visibility

Signed-off-by: codetalks-hw <lihaizhen5@huawei.com>
…lateUri.of version

Signed-off-by: codetalks-hw <lihaizhen5@huawei.com>
…idate duplicate value types and align nullness contracts

Signed-off-by: codetalks-hw <lihaizhen5@huawei.com>
…ateUri value type

Signed-off-by: codetalks-hw <lihaizhen5@huawei.com>
…s single source of truth

Signed-off-by: codetalks-hw <lihaizhen5@huawei.com>
…dard-template-uri

refactor(api): replace String templateUri with TemplateUri type on fa…
…ing with the template regime

Signed-off-by: codetalks-hw <lihaizhen5@huawei.com>
…dard-template-uri

refactor: tighten internal structure, naming and error-code surface across modules
…dard-template-uri-2

refactor/standard-template-uri-2 — Typed PromptTemplate URI + file-driven negotiation vocabulary
zhangwenjun-huawei and others added 29 commits August 28, 2026 16:29
…ion-confirm-request

feat(negotiation): add confirm-request rounds to target and feasibility propose
Signed-off-by: gcw_mr3RVhmf <cnafan@outlook.com>
Signed-off-by: gcw_mr3RVhmf <cnafan@outlook.com>
…normal-github-pr

test(sample): add negotiation abnormal evaluations
…mple-run-guide

docs(sample): document negotiation evaluation runs
Align the propose cases with the request semantics of a propose message:
items carry the field expectation as a meaning-plus-sample description
("接入端口名称,如P781-..."), per the propose template's own requirement
(name + meaning/format/sample) - not the field's real value, which read as
"asking for the answer while carrying it". Accept keeps real values,
reject keeps field-plus-reason; all three message types now carry exactly
what the protocol transports.

The propose extraction assertions are sharpened against the
description-vs-value confusion: the extracted expectation must keep the
meaning head (a sample-only extraction would read as if the field were
already supplied) and must stay within the stated expectation (no
hallucinated content). Depends on the propose-branch extraction contract
in the stacked SDK change.

Signed-off-by: ZhouJie6 <ivo.zhou@huawei.com>
…k object

Review feedback on the propose cases:

- the task-object expectation now presents the three selectable forms the
  Task-T template defines (service name / service identifier / access
  port name, each with its sample) instead of the access-port form alone;
  the accept cases rotate the filled task object across the three forms
  so every legal shape round-trips
- the extraction schema mirrors the SDK's own model of the message
  content (NegotiationJsonSchemaBuilder) instead of an invented flat
  field map: propose extracts {items: [{name, value}], relationship},
  endings extract {conclusion, items: [{name, value}]} - the
  validation-side contract is now aligned end to end with the
  generation-side model. The assertions walk the items array: every input
  slot appears as an item with the matching value (expectation guards for
  propose, value fidelity for accept, reasons for reject), plus the
  relationship and conclusion checks.

Verified on glm-5.2: 14/14 on the first and a confirmation rerun; one
intermittent run failed a single case on an LLM infrastructure error
(model returned markdown-fenced JSON) - transient, not a case defect.

Signed-off-by: ZhouJie6 <ivo.zhou@huawei.com>
…proposes

A single requested field has no inter-field relationship, so the rendered
propose must not carry the canned relationship sentence: the eval app and
the server executor now pass a null relationship when only one item is
missing, and the phrasing template states the AND relation explicitly.

Signed-off-by: ZhouJie6 <ivo.zhou@huawei.com>
The generation-only fromData/fromText 3x3 samples printed summaries
without assertions and are fully covered by the stronger evaluators:
NegotiationFromDataApiEvalApp (fromData generate-validate round trip)
and NegotiationEvalApp plus the private-line corpus evaluation
(fromText with golden comparison). Removes the samples, their shared
support class, the now-orphaned ScenarioData case accessors, the
negotiation_cases scenario section, the javaargs generation blocks,
and the corresponding README/design-doc sections. Also aligns the
scenario field model with the Task-T template vocabulary.

Signed-off-by: ZhouJie6 <ivo.zhou@huawei.com>
…orpus on both channels

InformationNegotiationSchemas moves from the private-line sample to the
shared negotiation package: the validate*AndDataFilling contracts are
channel-agnostic, so the fromText flows and the fromData evaluator now
use one schema (items:[{name, requirement|value|reason}]). The fromData
API evaluator delegates to the shared schemas and additionally asserts
the extracted accept values and reject reasons.

The labelled corpus (cases.json) gains a structured data field parallel
to each text input and switches expected keys to the display names, so
one corpus drives both generation channels. The corpus evaluation runs
the protocol-correct chain: the server proposes, the client validates
the inbound propose and discovers the fields to supplement, the client
generates the accept/reject from that discovery, and the server
validates the ending. The fromData channel additionally requires an
exact completedPrompt match because its rendering is deterministic.
Fixes the expected-value matching that silently always failed since the
schema moved to the item-array shape.

Signed-off-by: ZhouJie6 <ivo.zhou@huawei.com>
…raction-contract

fix(negotiation): define the propose-branch extraction contract as full expectation text
…eneration

Terse corpus ending texts may omit or paraphrase the field names, so the
LLM extraction could not recover the requested items (three smoke cases
failed with extraction errors and most ending extractions missed). The
fromText ending input now leads with an explicit supplement built from
the fields the client discovered in the inbound propose, mirroring
NegotiationEvalApp step 6.

Signed-off-by: ZhouJie6 <ivo.zhou@huawei.com>
…se-expectation

feat(sample): unify negotiation validation schemas and evaluate the corpus on both channels
The content validation prompt now draws a division of labor between
validation sources: the template body carries business rules
(per-operation-type required fields, modifiability, operation scope)
while the parameter schema carries value and format constraints. The
schema's field set and descriptive statements no longer participate in
judging field existence or required-ness - a field missing from the
schema does not exempt the template's requirement, and a schema
description contradicting a template required field does not alter it.
Format compliance is decided by the schema's declaration when it
disagrees with the template's shape description for the same field, so
declared format tightenings (single date, ISO timestamp) now reject
mismatched range values. The format_error definition gains inverted
date ranges, the key-set contract requires schema key names for empty
values, and the format-compliance example avoids literal date patterns.

The suite grows to 102 cases. Four varreq variants flip from success
to rejected pairs (format tightening beats template range wording),
b3-conflict pair input moves the conflicting dual value onto the
modifiable validity period (the scene variant collided with the
modifiability rule and double-triggered), a-nl-neg-03 becomes a
two-stage expectation (client renders faithfully, server rejects the
identifier-less delete), the c4 varfields schema drops its stale
conditional-delete description, and two new cases join: a
description-antagonist variant (schema text says condition delete is
fine, template still wins) and a multi-error case covering the
previously untested multi-slot_errors path. LoaderTest counts follow
(102 total, 47 variants including the -varuuid/-vardesc suffixes, 9
interceptions, 37 rejections, 43 validate_schemas).

Template lint and the sample test suite pass; smoke passes 15/15 and
the transcript is regenerated. Full-suite runs after the model change
sit at 98-99/102 with residual mismatches attributed to LLM
non-determinism (error-code wobble on one variant) and transient
gateway JSON failures.

Signed-off-by: w00609601 <wushunhao1@huawei.com>
…xtend

feat(sample): split validation and extraction sources in authz suite
…routing and frozen snapshots

Signed-off-by: w00609601 <wushunhao1@huawei.com>
…iss warning

Signed-off-by: w00609601 <wushunhao1@huawei.com>
…th fail-fast

Signed-off-by: w00609601 <wushunhao1@huawei.com>
…tale language hint

Signed-off-by: w00609601 <wushunhao1@huawei.com>
…mpt-resource-config

feat(prompt): unify prompt resource configurability (ADR 0004)
…on base

Introduce ErrorCatalog (42 dotted domain.semantic codes with BUSINESS/INFRA
category and fact-parameter declarations), ErrorMessages renderer over
errors/{lang}/errors.json (en-US fallback), A2ATBusinessException base and
SlotValidationError facts field. A2ATErrorCodes becomes a deprecated
forwarding facade. template_lint gains a catalog-consistency gate.

Signed-off-by: codetalks-hw <lihaizhen5@huawei.com>
…chema

Rewrite the four error-code prompt groups (content_validation,
slot_extraction, semantic_validation, negotiation_semantic_validation) in
both languages: errors[] items become {slot_name, code, facts} with closed
dotted code sets and three-part definitions, unified terminology
(参数/slot), and the en-US rendered-structure description fixed to match
the actual renderer behavior. Fix the stale missing_input code reference
in the authz slot schema.

Signed-off-by: codetalks-hw <lihaizhen5@huawei.com>
DefaultSemanticValidator and DefaultContentValidator parse the new facts
schema and render messages via ErrorMessages; the structured slot value
extractor emits slot.not_provided / slot.constraint_violated; loader
failures map to template.* and infra.* codes; the ValidationPipeline emits
final catalog codes directly (the ParamExtractor mapping layer is gone).

Signed-off-by: codetalks-hw <lihaizhen5@huawei.com>
…og codes

Migrate generation/validation error codes to the dotted catalog
(negotiation.*, llm.*, template.*), re-parent the module business
exceptions onto A2ATBusinessException, replace fromData content-data
IllegalArguments with coded business exceptions (D7: URI-shape IAEs stay),
close the semantic validator code set with domain restriction, and
surface LLM-reported slot errors instead of discarding them.

Signed-off-by: codetalks-hw <lihaizhen5@huawei.com>
…aking raw errors

Client orchestrator failure codes move to scenario.not_matched /
template.* / slot.* with rendered messages and the legacy path now catches
and maps previously-uncaught exceptions into result failures; server
compliance and semantic validators adopt the facts schema, the slot.*
domain restriction and input.text_too_long; both facades' javadocs state
the new error contract.

Signed-off-by: codetalks-hw <lihaizhen5@huawei.com>
Rewrite corpus golden expectations and injected LLM fixtures to the
{slot_name, code, facts} schema and dotted codes, migrate the authz sample
scenario sets and evaluators, and update corpus_review.py code dictionary
to the new codes.

Signed-off-by: codetalks-hw <lihaizhen5@huawei.com>
Update API references and developer guides in both languages with the new
code table, the errors[] facts schema, rendered-message behavior
(language follows A2AT_LANGUAGE) and the old-to-new code mapping.

Signed-off-by: codetalks-hw <lihaizhen5@huawei.com>
…catalog codes

Signed-off-by: codetalks-hw <lihaizhen5@huawei.com>
Signed-off-by: codetalks-hw <lihaizhen5@huawei.com>
@codetalks-hw
codetalks-hw force-pushed the feat/error-code-catalog branch from 2b5fad4 to 4e1cda1 Compare August 29, 2026 07:59
Sign up for free to 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.

7 participants