atel-protocol-schema
v0.1.0
Published
Single source of truth for ATEL cross-repo protocol — order/milestone status enums, event types & payloads, DID format. JSON Schemas + TS types.
Readme
@atel-ai/protocol-schema
Single source of truth for ATEL cross-repo protocol — order status, milestone status, event types, payloads, DID format.
Why: today the same OrderStatus enum is hand-written in Go (atel-platform), TS (atel-portal, atel-mcp server), JS (atel-mcp plugin), TS (atel-tg-bot, atel-sdk). Drift between them is a leading cause of silent bugs (see 5.16/今日工作总结.md for the M0/rejected event case study).
The deal: add a value here, all consumers see a compile-time type error until they handle it. Same for renames, removals, payload shape changes.
Layout
schemas/ # JSON Schema (Draft 7) — main source of truth
order-status.schema.json
milestone-status.schema.json
did.schema.json
event-envelope.schema.json
events/ # per-event payload schemas
order_created.schema.json
order_accepted.schema.json
order_settled.schema.json
milestone_plan_confirmed.schema.json
milestone_submitted.schema.json
milestone_verified.schema.json
milestone_rejected.schema.json
milestone_arbitration.schema.json
src/ # TypeScript types — npm package @atel-ai/protocol-schema
index.ts
types.ts
events.ts
conversions.ts # snake_case ↔ dot.case event type bridge
pkg/protocol/ # Go types — module github.com/AtelLab/protocol-schema
status.go
events.go
did.go
conversions.go
scripts/
validate.sh # ajv-cli over schemas/
generate-ts.sh # JSON Schema → TS types (json-schema-to-typescript)
generate-go.sh # JSON Schema → Go types (quicktype)The JSON Schemas are authoritative. TS / Go types are kept in sync; in v1 they are hand-written (small surface); v2 we can wire generate-{ts,go}.sh for full codegen.
Versioning
SemVer. Major bump = enum value removed/renamed OR payload field removed/renamed OR event type renamed (breaking changes to consumers). Minor bump = new enum value or new payload field (backward-compatible). Patch bump = docs / comments / non-functional.
Adopting
TypeScript (atel-mcp server / atel-portal / atel-onepage / atel-tg-bot / atel-sdk)
npm i @atel-ai/protocol-schemaimport { OrderStatus, MilestoneStatus, EventType, MilestoneSubmittedPayload } from "@atel-ai/protocol-schema";
if (order.status === OrderStatus.MilestoneReview) { ... }
function onSubmit(payload: MilestoneSubmittedPayload) {
// payload.orderId / payload.milestoneIndex / payload.submitCount are all typed
}Go (atel-platform / atel-tokenhub)
go get github.com/AtelLab/protocol-schemaimport "github.com/AtelLab/protocol-schema/pkg/protocol"
if order.Status == protocol.OrderStatusMilestoneReview { ... }
var payload protocol.MilestoneSubmittedPayload
json.Unmarshal(raw, &payload)JS plugin (atel-mcp openclaw-plugin)
import { EventTypes, normalizeEventType } from "@atel-ai/protocol-schema";
// normalizeEventType("milestone.submitted") -> "milestone_submitted"CI validation
Add to each consumer repo's CI:
- run: npx ajv-cli validate -s node_modules/@atel-ai/protocol-schema/schemas/event-envelope.schema.json -d "test/fixtures/events/*.json"Naming traps captured here
- dot.case vs snake_case event types — platform uses
milestone.submittedinternally, wire usesmilestone_submitted.conversionshelpers expose both forms + a normalizer. - camelCase payload fields — wire-level fields are
orderId/milestoneIndex/submitCount(NOTorder_id/milestone_index/submit_count). - DB columns are snake_case — DB layer is platform-internal; not exposed in this schema package.
completedvssettled—completed= all milestones verified, awaiting on-chain settlement;settled= funds released. These are two distinct order statuses.in_progressis a UI alias — not a real platform status. Maps toexecuting.
Phase 3 (consumer adoption) — see workspace 5.17/schema化-todo-checklist.md
Phases 1 + 2 of Task 3 are this package. Phase 3 = each consumer repo replaces hand-written string constants with imports from here. That is a separate ticket per consumer, NOT done here.
