CHO-FAM ANS

Markdown 내려받기 ANS 규격 v1 용어 구분 확장 어휘 등록 안내

Agent Card 규격 v1.7 — 패밀리 공통

v1.7은 확장 URI를 옮긴다 — 유일한 파괴적 변경이다. https://cho-fam.web.app/ans/v1https://cho-fam.com/ans/v1, /hire/v1도 같다.

이유는 배포처다. *"배포처는 바뀔 수 있다"*(주관자). web.app은 Firebase에 묶인 이름이라 호스팅을 옮기면 식별자가 죽거나 억지로 살려 둬야 한다. URI는 위치가 아니라 이름이므로 더욱 그렇다 — 이름이 특정 공급자에 매여 있으면 안 된다.

지금이 가장 싸다. 등재된 이름이 0개이고 배포 전이다. 패밀리 카드 넷만 한 줄씩 고치면 된다 — 외부 등재자가 생기면 그들의 카드를 고치는 일이 된다.

ANS 파서는 새 값만 받는다. 둘 다 받는 경로를 만들지 않는다 — 지울 시점을 정해야 하고 그 시점이 오지 않는다. 등재 0건이라 갈아타는 중에 떨어질 카드가 없다.

v1.6은 §4.1의 한 문장을 고친다 — *"계약을 세울 때 카드에서 읽어 unit_price에 박는다."* 복사가 아니다. 주관자가 단가의 성립 절차를 확정했다 — 비용에서 시작하고 가격 협상을 거쳐 계약으로 확정된다(AP-1 회신). 협상이 있으면 카드의 값과 계약의 값은 다를 수 있다. §4.1을 그에 맞춘다.

§4.2와 게시본도 같은 이유로 틀려 있었다. v1.5가 *"hire/v1이 없으면 고용이 열리지 않는다"*고 적은 것은 계약가가 카드에서 복사된다는 전제 위에 서 있었고, 그 전제가 지워졌으므로 결론도 선다 — 없어도 고용된다. /hire/v1 게시본은 **v1.4의 *"없으면 등재되지 않습니다"*를 아직 띄우고 있었다. §1 예시 카드의 unitPrice: 5도 뺀다 — 예시의 숫자가 자기 값인 줄 알고 게시되면 호가가 아니라 옮겨 적은 값이 된다.**

v1.5는 v1.4의 V9를 고친다무조건 검사로 세운 것이 틀렸다. V9가 모든 카드에 양의 정수 단가를 요구했는데, 지금 패밀리 카드 전부가 떨어진다 — mentor·ethos·terra 어디에도 단가가 없고, 그 값은 그들이 정하는 것이 아니다(주관자 항목 AP-1). mentor 4차 질의 Q11이 구현 중에 짚었다. §4.2를 더하고 V9를 조건부로 바꾼다.

v1.4는 규격을 바꾼다외부 등록 에이전트가 실을 자리가 없던 것 둘을 만든다(업무지시서 §7.2 K-2·K-3). 대상 선언(§2.3)과 고용료 단가(§4.1)다. 패밀리는 이 둘을 내부 합의로 알고 있었으나 외부 에이전트는 카드가 게시하는 전부다.

패밀리 저장소가 할 일은 태그 한 줄과 단가 한 줄이다. 구조가 바뀌지 않는다.

v1.3은 규격을 바꾼다 — v1.2와 다르다. E4(멱등)가 어느 키를 말하는지 명시한다(§2.1). 규격이 침묵한 탓에 서버 발급 Task ID를 쓰는 틀린 선택이 규격 준수처럼 보였다.

다시 할 일이 있는 저장소는 없다 — 1차에 실행성 skill을 노출하는 곳은 terra뿐이고, terra의 이벤트 id는 이미 발행자가 만든다. §7에 카드 생성 권고를 더했다(afo가 실제로 겪은 것).

v1.2는 규격을 바꾸지 않았다 — society 구성 확정(ANS 설계 §13)이 이 규격이 무엇을 전제하고 있었는지를 드러냈으므로 그 전제와 미결(§9)을 적은 것이다.

저장소가 /.well-known/agent-card.json에 게시할 카드의 규격이다. A2A 표준을 그대로 쓰되, 표준에 없어서 따로 정해야 하는 것 여섯을 여기서 정한다.

게시 위치 — 조회 https://cho-fam.com/ans/card-spec · 다운로드 https://cho-fam.com/ans/agent-card-spec.md. 이 파일이 원본이고 사이트의 것은 scripts/build-ans-spec.js가 만드는 산출물이다. 저장소와 외부 등재자는 사이트를 본다 — 이 저장소는 비공개이므로 git 링크로는 읽히지 않는다. 함께 읽을 것: 용어 구분 — 이 규격의 값은 계약의 말이다. 화면에 그대로 내보내지 않는다(V-2). 함께 읽을 것: ANS 규격 — 이름 형식·등록 심사·API·신호는 그쪽이 정본이다. 기준일: 2026-08-17 (v1.7 — 확장 URI 이전) 시점: Phase 0 — 각 저장소의 A-1(Agent Card 작성)이 이 문서를 선행으로 갖는다 근거: A2A 채택 · ANS·A2A 설계 §5 · 1차 답변서 §4.1·§4.3 · 업무지시서 §3.1 대상: mentor · ethos · afo · terra (+ 향후 외부 등재자)

society는 대상이 아니다. 카드는 *상대*가 게시하는 것이고 society는 *자리*다 — 자기 채널 밖에 계약을 팔지 않으므로 ANS 이름도 카드도 갖지 않는다(ANS 설계 §13). society는 이 규격의 검증자다(§8 V7).

규격을 chofam이 소유하는 이유 — ANS 설계 §4.2가 소유권 증명을 "신청한 endpoint의 카드가 신청한 이름을 담고 있으면 인정한다"로 정했다. ANS는 이미 카드를 파싱해야 하므로 규격이 다른 곳에 있으면 검증 로직이 남의 문서를 좇게 된다.

0. 표준을 벗어나지 않는다

카드는 A2A AgentCard(protocolVersion: "1.0.1")이다. 아래 여섯은 전부 표준이 이미 가진 자리에 얹는다 — 표준 파서가 읽을 수 없는 필드를 새로 만들지 않는다.

#패밀리가 정하는 것표준의 어느 자리에
1skill 분류 — 자문 / 조회 / 실행skills[].tags§2
2ANS 이름 — 소유권 증명의 근거capabilities.extensions[]§3
3trustTier카드에 담지 않는다§4
4인증 선언 — 경로별로 다르다securitySchemes · security§5
5대상 선언(v1.4)skills[].tags§2.3
6고용료 단가(v1.4) — 선택(v1.6)capabilities.extensions[]§4.1

1차 endpoint 규칙은 필드가 아니라 해석 규칙이므로 §6에 따로 둔다.

v1.1 개정 — 규격은 실행성 skill을 금지하지 않는다. v1.0은 "실행성 skill은 카드에 올리지 않는다"를 규격의 규칙으로 적었다. 그것은 과했다. afo에 실행성이 없는 것은 현 단계에 afo I-1이 적용된 결과이지 카드 규격이 정할 일이 아니고, 상위 적용 단계의 계획에는 실행성이 있다. 공용 규격이 다른 저장소의 로드맵을 미리 막는 자리에 서면 안 된다.

다만 실행성 skill을 자문·조회와 같이 취급할 수는 없다. 금지 대신 분류(§2)와 전용 요구(§2.1)로 바꾼다. 무엇을 노출할지는 각 저장소의 불변 조건과 현 단계 범위가 정한다(§2.2).

이 개정은 1차 답변서 §4.1의 "실행성 skill은 카드에 올리지 않는다"는 문구를 대체한다.

1. 최소 카드

{
  "protocolVersion": "1.0.1",
  "name": "Ethos Decision",
  "description": "결정 세션을 진행해 기준과 가정을 명료화한다. 판정을 반환하지 않는다.",
  "url": "https://ethos.internal/a2a",
  "supportedInterfaces": [
    { "url": "https://ethos.internal/a2a", "protocolBinding": "JSONRPC" }
  ],
  "version": "1.0.0",
  "provider": { "organization": "CHOFAM", "url": "https://cho-fam.com" },
  "capabilities": {
    "streaming": false,
    "pushNotifications": false,
    "extensions": [
      {
        "uri": "https://cho-fam.com/ans/v1",
        "description": "ANS 이름 — 이름 권위는 chofam ANS",
        "required": false,
        "params": { "name": "ethos.decision.v1" }
      }
    ]
  },
  "defaultInputModes": ["text/plain"],
  "defaultOutputModes": ["text/plain"],
  "securitySchemes": {
    "userBearer": { "type": "http", "scheme": "bearer", "bearerFormat": "JWT" }
  },
  "security": [{ "userBearer": [] }],
  "skills": [
    {
      "id": "decision-session",
      "name": "결정 세션",
      "description": "기준·가정을 되묻고 정리한다. input-required로 질문을 되돌린다.",
      "tags": ["chofam:kind/advisory", "chofam:scope/party"],
      "inputModes": ["text/plain"],
      "outputModes": ["text/plain"]
    }
  ]
}

hire/v1 확장은 이 예시에 없다(v1.6). 선택이고 패밀리는 아직 싣지 않는다 — 호가를 크레딧으로 말하려면 환산이 선행한다(§4.2). 실을 때의 모양은 §4.1에 있다. v1.4·v1.5는 여기에 unitPrice: 5를 넣어 두었는데, 예시의 숫자가 자기 값인 줄 알고 게시되면 호가가 아니라 옮겨 적은 값이 된다.

전송 바인딩은 JSON-RPC 2.0이다(1차 답변서 §4.4) — 단일 호스트·저볼륨이므로 supportedInterfaces[]protocolBinding: "JSONRPC" 하나를 둔다. gRPC는 다수 호스트 운영 시 재검토한다.

A2A 버전 — 1.0.1이 맞다(2026-05, Linux Foundation). 설계 §5의 v2.3 주의가 이미 정정했는데 이 규격 v1.0이 §2.3의 작성 시점 값 0.3.0을 옮겨 적었다. mentor·ethos·afo 지시서가 전부 v1.0.1로 적고 있었고 그쪽이 맞다. 0.x의 preferredTransport도 v1.0.1의 supportedInterfaces[]로 바꾼다.

2. skill 분류 — tags에 예약 태그를 쓴다

모든 skill은 아래 셋 중 정확히 하나의 chofam:kind/* 태그를 갖는다. 분류 기준은 부작용의 유무와 소재다.

태그부작용
chofam:kind/advisory자문 — 판단 재료를 돌려준다없음
chofam:kind/query조회 — 저장된 사실을 읽어 돌려준다없음
chofam:kind/action실행 — 상태를 바꾼다(자금 이동, 계약 체결, 쓰기, 이벤트 인입)있음

분류가 강제인 이유는 호출자가 태그만 보고 부작용 유무를 알 수 있어야 하기 때문이다. A2A는 skill의 성격을 표준 필드로 말해 주지 않는다. 태그가 없으면 호출자는 설명문을 읽어 짐작해야 한다.

2.1 실행성 skill의 전용 요구

규격은 실행성 skill을 금지하지 않는다. 다만 자문·조회와 같이 취급하지 않는다 — 실행은 되돌릴 수 없을 수 있고, 재시도가 이중 실행이 되며, 사후에 누가 무엇을 시켰는지 물어야 한다. chofam:kind/action 태그를 단 skill을 카드에 노출하려면 아래 다섯을 만족한다.

#요구이유
E1chofam:kind/action 태그를 붙인다자문·조회와 한 카드에 섞여도 호출자가 구분할 수 있어야 한다
E2되돌릴 수 있는지 표기한다chofam:effect/reversible 또는 chofam:effect/irreversible호출 측 정책이 여기서 갈린다. 되돌릴 수 없는 실행은 사람의 확인을 요구하는 것이 보통이다
E3자문·조회와 다른 인증 스킴을 요구한다(§5.3)자문을 부르려고 넘긴 대리 토큰이 실행까지 열어서는 안 된다
E4호출자가 만든 멱등 키를 받고, 같은 키의 재전송이 이중 실행을 만들지 않는다. A2A에서 그 자리는 message.messageId다 — 서버가 발급하는 Task ID를 멱등 키로 쓰지 않는다A2A는 재시도를 막아 주지 않는다. 그리고 Task ID는 서버가 첫 응답에서 처음 알려 주는 값이라, 첫 호출의 응답을 놓친 재시도에는 그 키가 없다 — 멱등이 가장 필요한 순간에 없다
E5실행 1건마다 감사 증적을 남긴다 — 호출자 신원·시각·입력부작용이 남았는데 누가 시켰는지 모르는 상태를 만들지 않는다
{
  "id": "event-ingest",
  "name": "이벤트 수신",
  "description": "society 전이 이벤트를 받아 SOURCE로 기록한다. 같은 id 재전송은 중복을 만들지 않는다.",
  "tags": ["chofam:kind/action", "chofam:effect/reversible", "chofam:scope/party"],
  "inputModes": ["application/json"],
  "outputModes": ["application/json"]
}

v1.3 정정 — E4가 어느 키인지 말하지 않아 틀린 선택이 규격 준수처럼 보였다. ethos R-4가 구현 중에 짚었다.

키가 서버 발급이면 멱등은 재시도가 이미 성립한 뒤에만 작동한다. 첫 호출이 나갔는데 응답을 못 받은 클라이언트는 Task ID를 모르고, 그 상태에서 다시 보내면 키 없는 두 번째 실행이 된다. 막으려던 사고가 바로 그것이다.

message.messageId는 클라이언트가 만들므로 첫 호출부터 있다. 규격이 요구하는 성질은 "고유함"이 아니라 "재시도할 때 손에 있음"이다.

terra는 이미 만족한다 — 인입 이벤트의 id는 발행자(society)가 만들어 보내는 값이므로 재전송에도 같은 값이 실린다. 다시 할 일이 없다.

규격은 여기까지다. 무엇을 실제로 노출할지는 §2.2가 정한다.

2.2 무엇을 노출할지는 저장소의 불변 조건과 현 단계가 정한다

이것이 규격의 일이 아닌 이유 — 노출 범위는 각 저장소의 로드맵과 불변 조건에 딸린 것이고, 단계가 올라가면 바뀐다. 공용 규격이 그것을 미리 못박으면 다른 저장소의 계획을 규격 개정 없이는 못 밟게 만든다.

저장소1차 노출노출하지 않음근거
mentor자문(지식 질의) · 조회(탐색 API)
ethos자문(결정 세션)판정 반환애초에 없다. Policy Gate는 society 소관
afo자문(재무 판단 재료)자금 이동 일체afo I-1(자금 미보관·미이체) — 규격이 아니라 afo의 불변 조건이다
terra조회(리포트 조회) · 실행(이벤트 인입)계산·정정인입은 자기 저장소 기록을 남기므로 실행이다. E4 멱등이 이미 T-M1 완료 기준(같은 id 재전송 시 중복 없음)과 같은 것이다

afo의 실행성 부재는 현 단계의 사실이지 영구 규정이 아니다. 상위 적용 단계의 계획에는 실행성이 있고, 그 단계에서 E1~E5를 만족하고 그때의 afo I-1이 허용하면 카드에 오른다. 규격을 고칠 일이 아니다.

저장소 불변 조건이 규격을 이긴다. 규격이 E1~E5로 길을 열어도 저장소의 불변 조건이 금지하면 노출하지 않는다 — afo I-1, society I-4(법적 효력 있는 행위 미실행)가 그 예다. 규격은 불변 조건을 대신하지 않는다.

2.3 대상 선언 — chofam:scope/party (v1.4)

모든 skill은 chofam:kind/* 하나와 함께 chofam:scope/party 태그를 갖는다. 같은 skills[].tags에 얹으므로 새 필드가 생기지 않는다(§0).

P-3이 세운 전제가 *"모든 에이전트는 party 대상"*이다. 그것은 패밀리 안에서만 전제다. 외부 등록 에이전트는 그 합의를 공유하지 않고, 카드가 그가 게시하는 전부다. 개인 단위 호출만 이해하는 에이전트가 파티 채널에 들어오면 부담 주체가 조용히 어긋난다 — 파티가 값을 치렀는데 산출은 개인에게 귀속된다.

"tags": ["chofam:kind/advisory", "chofam:scope/party"]

선언하지 않은 카드는 등재 심사에서 떨어진다(§8 V8). 패밀리 시드도 같은 검사를 거친다.

왜 새 기계장치를 만들지 않는가. §2가 이미 예약 태그로 *"호출자가 태그만 보고 알 수 있어야 하는 것"*을 나르고 있다. 대상은 정확히 그 종류다 — 설명문을 읽어 짐작하게 두면 안 되는 사실이다.

값이 지금 하나뿐인데 왜 적는가. 패밀리만 있을 때는 적을 필요가 없었다. 외부가 들어오는 순간 "전부 그렇다"는 말은 검사할 수 없는 말이 된다.

3. ANS 이름 — capabilities.extensions[]

"capabilities": {
  "extensions": [
    {
      "uri": "https://cho-fam.com/ans/v1",
      "description": "ANS 이름 — 이름 권위는 chofam ANS",
      "required": false,
      "params": { "name": "ethos.decision.v1" }
    }
  ]
}
규칙
urihttps://cho-fam.com/ans/v1 고정. ANS가 이 값으로 확장을 찾는다. 이 주소는 실제로 규범적 어휘를 서빙한다(public/ans/v1.html) — 카드를 읽은 사람이 확장의 의미를 찾아갈 곳이다
params.nameANS 이름 정확히 하나. ANS 설계 §4.1 형식을 만족해야 한다
requiredfalse. ANS를 모르는 표준 클라이언트도 이 카드를 쓸 수 있어야 한다
이름이 여럿인 경우확장을 여러 개 둔다.params.name에 배열을 넣지 않는다 — 이름은 에이전트가 아니라 계약을 가리키므로(ANS 설계 §4.1) 하나씩 선다

소유권 증명이 이 필드에 걸린다. ANS apply 심사는 신청한 endpoint의 카드를 읽어 params.name이 신청한 이름과 같은지 본다. 다르면 등록되지 않는다.

이름을 지운 채로 카드를 갱신하면 card_mismatch 신호가 붙는다(ANS 설계 §4.3). 이름을 그만 쓰려면 카드에서 빼는 것이 아니라 tombstone을 요청한다 — 조용히 빼면 호출자가 이유를 모른다.

4. trustTier는 카드에 담지 않는다

A2A에 신뢰 등급 개념이 없고, ANS도 "믿을 만한가"를 답하지 않는다(ANS 설계 §1).

소유어디에
agent.id · version에이전트 자신카드(name·version) — 호출자가 카드에서 읽는다
trustTiersocietysociety Directory. 카드에도 ANS에도 없다

자기 신뢰도를 자기가 선언하는 필드를 만들지 않는다. society가 자기 채널에 무엇을 들일지 정하는 값이므로 Directory에 남는다(ANS 설계 §11.1).

4.1 고용료 단가 — 카드는 호가다 (v1.4 · v1.6 정정)

society registry.ts가 계약의 unit_price필수 항목으로 세웠다 — *"값이 없는 채로 고용이 열리면 얼마를 받기로 했는지가 사후에 정해진다."* 패밀리는 그 값이 어디서 오는지 내부 합의로 알지만 외부 에이전트는 실을 자리가 없다.

카드에 싣는다. §3과 같은 자리를 쓴다 — ANS 이름이 이미 capabilities.extensions[]로 나가고 있으므로 새 기계장치가 없다.

{
  "uri": "https://cho-fam.com/hire/v1",
  "description": "고용료 단가 — 호가이며 정본은 society 계약이다",
  "required": false,
  "params": { "unitPrice": 5 }
}

단위는 크레딧이고 양의 정수다. 실화폐를 싣지 않는다 — 에이전트 고용료는 크레딧으로 지불한다는 것이 P-4다.

단가는 세 단계로 선다 (v1.6)

주관자 확정: *"단가는 비용에서 시작하고 가격 협상을 거쳐 계약으로 확정된다."*

단계어디누가성질
비용에이전트 내부에이전트 자신출발점. 크레딧으로 말하려면 환산이 선행한다()
호가카드 hire/v1에이전트 자신언제든 바꾼다. 한쪽의 말이지 합의가 아니다
계약가society contract_ref.unit_price파티와 에이전트의 합의. society는 기록한다바뀌지 않는다 — 계약이 선 뒤에는

②와 ③은 다를 수 있다. 협상이 그 사이에 있기 때문이다. 카드에서 읽어 계약에 박는 것이 아니다 — 카드는 협상의 출발점이고, 합의가 없으면 계약이 서지 않는다.

②가 없어도 ③은 선다. 출발점이 게시돼 있지 않을 뿐이고, 협상은 그래도 일어난다 — 그것이 §4.2다.

협상 없이 호가 그대로 받는 것도 협상의 결과다. 대부분은 그렇게 될 것이고, 그때 ②와 ③이 같아진다. 같아지는 것과 복사되는 것은 다르다 — 복사면 카드가 바뀔 때 계약도 흔들릴 근거가 생기고, 합의면 그럴 근거가 없다.

계약이 선 뒤 카드가 바뀌어도 그 계약은 변하지 않는다. 카드는 상대가 언제든 고쳐 게시할 수 있는 문서이고, 계약은 두 쪽이 합의한 시점의 기록이다.

R7(산출과 결정의 분리)의 다섯 번째 사례다카드는 산출(에이전트가 자기 비용에서 호가를 낸다), 계약은 결정(파티와 에이전트가 합의한다). 결정하는 쪽은 society가 아니다 — society는 합의를 기록하고 집행한다. v1.4가 *"계약은 결정(society가 확정한다)"*으로 적은 것을 여기서 고친다.

D-18은 이 절이 답하지 않는다. 누가 파티에 에이전트를 들일 수 있는가는 society 소관이고, 카드는 *무엇을 제시하는가*만 정한다.

4.2 적용 범위 — 호가가 없어도 고용된다 (v1.6)

hire/v1 확장은 선택이다. 호가를 미리 게시하는 에이전트가 싣는다. 패밀리는 환산이 서기 전까지 싣지 않는다(업무지시서 §7.9).

확장이 있다호가가 게시돼 있다. 협상이 그 값에서 출발한다. V9가 그 카드에 걸린다
확장이 없다등재된다. 고용도 된다. 출발점이 게시돼 있지 않을 뿐, 협상은 일어나고 계약가는 선다

**v1.5는 여기에 *"없으면 고용이 열리지 않는다"*고 적었고 그것이 틀렸다.** 근거로 든 것은 society registry.ts의 409(*"계약에 단가가 없다"*)였는데, 그 409는 계약에 값이 없는 것을 막는 것이지 카드에 값이 없는 것을 막는 것이 아니다. 사이의 *"계약의 값은 카드에서 온다"*가 v1.4가 세운 전제였고, AP-1 회신이 §4.1에서 그 전제를 지웠다 — 계약가는 복사가 아니라 협상의 결과다. 호가는 출발점이지 출처가 아니므로, 없으면 출발점이 없을 뿐이다.

주관자 회신(AP-1) — *"단가는 비용에서 시작하고 가격 협상을 거쳐 계약으로 확정된다."* 따라서 주관자가 패밀리 단가를 정해 카드에 박는 일은 일어나지 않는다. AP-1은 값이 채워져서가 아니라 정할 주체가 남지 않아서 소멸한다(업무지시서 §7.9).

K-2가 태그를 만든 이유(*"전부 그렇다는 말은 검사할 수 없는 말이 된다"*)와 어긋나지 않는다. 대상 선언은 카드가 아니면 확인할 자리가 없고, 계약가는 카드가 아닌 자리에서 정해진다. 둘은 성질이 다르다 — 하나는 카드에만 있는 사실이고, 하나는 카드에 없어도 서는 값이다.

V9를 무조건으로 세운 것은 총괄의 오류였고, 고친 v1.5도 절반만 고쳤다. 검사는 조건부로 내렸으나 없는 카드에 무슨 일이 일어나는가를 틀리게 적었다 — *"고용되지 않는다"*. 검사기를 고치면서 그 검사가 무엇을 뜻하는지 적은 문장을 따라 고치지 않은 것이고, §7.7 ③이 진단한 것과 같은 종류다.

5. 인증 선언 — 경로별로 다르다

1차 답변서 §4.3이 경로별로 확정했다. 카드의 securitySchemes는 그 경로가 실제로 받는 것을 그대로 적는다.

호출 경로신원카드에 적을 것
society → mentor서비스 신원 (공유 비밀 Bearer)serviceBearer
society → terra서비스 신원 (공유 비밀 Bearer)serviceBearer
society → ethos사용자 대리 (Dex 발급 토큰 전달)userBearer
society → afo사용자 대리userBearer

이 표는 1:1 지목 호출을 전제한다. society 채널에 에이전트가 참여자로 들어오면 대리 대상이 정해지지 않는다 — 방에 사람이 여럿이기 때문이다(ANS 설계 §13.6, D-17(ANS)). 카드가 쓸 스킴은 바뀌지 않는다 — 바뀌는 것은 userBearer에 실릴 sub를 society가 무엇으로 고르는가이고, 그것은 society의 결정이다.

"securitySchemes": {
  "serviceBearer": {
    "type": "http", "scheme": "bearer",
    "description": "배포 설정의 공유 비밀. 1차는 토큰 교환 없음"
  },
  "userBearer": {
    "type": "http", "scheme": "bearer", "bearerFormat": "JWT",
    "description": "Dex 발급 사용자 토큰. iss·sub·aud·exp만"
  }
},
"security": [{ "serviceBearer": [] }]

5.1 대리 경로의 클레임 범위

iss·sub·aud·exp만이다. 프로필·이메일을 넘기지 않는다.

5.2 실행 경로는 자문·조회와 스킴을 나눈다 (E3)

chofam:kind/action skill을 노출하는 카드는 그 경로 전용 스킴을 따로 선언한다.

"securitySchemes": {
  "userBearer": {
    "type": "http", "scheme": "bearer", "bearerFormat": "JWT",
    "description": "자문·조회용 사용자 대리 토큰"
  },
  "actionBearer": {
    "type": "http", "scheme": "bearer", "bearerFormat": "JWT",
    "description": "실행용. 자문 토큰으로는 열리지 않는다"
  }
}

한 스킴으로 묶지 않는 이유 — 사용자가 자문을 받으려고 넘긴 토큰이 그대로 실행 권한이 되면, 호출자는 자문을 청했는데 실행이 일어날 수 있는 상태가 된다. 스킴이 나뉘어 있으면 실행에는 별도 발급이 필요하다는 사실이 카드에 드러난다.

스킴을 나누는 것으로 충분하지 않다면(사람의 명시적 확인이 필요한 경우 등) 그것은 skill의 대화 흐름으로 처리한다 — A2A input-required로 확인을 되돌리고 응답을 받아 진행한다. 카드가 표현할 수 있는 것은 여기까지다.

5.3 mentor 경로는 비식별이 따로다

mentor행 요청에는 참여자 식별자가 어떤 형태로도 들어가지 않는다. 이것은 카드가 강제하지 못한다 — A2A는 페이로드 내용에 관여하지 않는 프로토콜이므로 비식별 변환은 society Agent Gateway의 책임이다. 카드는 serviceBearer를 선언해 사용자 토큰을 받지 않는다는 사실까지만 말한다.

에이전트가 방의 참여자가 되면 이 경계가 Gateway 밖으로 나간다. Gateway는 봉투를 다루지 본문을 다루지 않는데, 방의 발화에 든 식별 정보는 필드가 아니라 문장 안에 있다(ANS 설계 §13.5, D-16(ANS)). 카드로도 Gateway로도 막히지 않으므로 가시 범위 자체를 정해야 한다.

6. 1차 endpoint — 배포 설정이 카드보다 우선한다

1차는 패밀리 에이전트가 ANS를 런타임 경로로 쓰지 않는다(ANS 설계 §11.4). ANS는 GCP에 있고 1차는 자체 서버라, 매 자문마다 resolve를 부르면 자체 서버가 GCP 왕복에 묶인다.

society는 배포 설정의 고정 목록으로 endpoint를 안다. 그 결과 카드의 url과 배포 설정이 어긋날 수 있다.

상황무엇을 따르는가
1차 (자체 서버)배포 설정의 고정 목록. 카드 url은 참고값
ANS 경로 전환 후 (D-15(ANS))resolve가 답한 endpoint

카드의 url은 그래도 정확히 유지한다. 부정확하면 ANS 프로브가 endpoint_unreachable을 붙이고, 외부 호출자는 카드만 보고 온다. "어차피 고정 목록을 쓰니까"는 카드를 방치할 이유가 되지 않는다.

7. 게시 요구사항

#요구
G1경로는 도메인 루트의 /.well-known/agent-card.json — well-known URI는 오리진 기준으로 정의된다(RFC 8615). A2A endpoint 경로 아래가 아니다urlhttps://ethos.internal/a2a여도 카드는 https://ethos.internal/.well-known/agent-card.json이다. ANS 프로브가 이 자리만 본다
G2인증 없이 읽힌다. 카드 자체는 공개다
G3Content-Type: application/json
G4ANS 프로브가 주기적으로 읽으므로 캐시 헤더를 과도하게 길게 두지 않는다 — 갱신이 신호에 반영되지 않는다
G5카드 변경 시 version을 올린다

권고 — 카드를 서버가 실제로 dispatch하는 목록에서 생성한다. 요구는 아니지만, 두 곳에 따로 적으면 언젠가 어긋나고 어긋나면 이름이 서지 않는다.

심사 ④는 카드에 적힌 skill이 실제로 그렇게 응답하는지를 Task 왕복으로 본다. 손으로 옮겨 적은 카드는 구현이 빠지거나 바뀌어도 조용히 남아 있다가 심사에서 떨어진다 — afo가 A-1에서 실제로 겪었다. 템플릿에는 skill이 둘인데 하나는 법률 검토 대기라 구현이 없었고, 템플릿대로 올렸다면 떨어졌다.

chofam도 같은 방식을 쓴다 — 이 규격의 공개본은 원본에서 생성되고 scripts/build-ans-spec.js --check가 어긋남을 잡는다.

8. 완료 기준

카드 게시는 완료가 아니다(총괄 R1). A-1의 완료는 Task 왕복 성공이다.

V1·V2·V4·V5·V6·V8·V9는 등재 시점에 기계로 다시 확인된다(ANS 규격 §3.0). 자가 점검은 편의이지 증명이 아니다 — 신청자의 기계에서 돌고 통과 여부가 ANS에 전달되지 않는다. 패밀리 시드도 같은 검사를 거친다.

각 저장소가 아래를 통과하면 A-1이 끝난다.

#검증
V1curl <endpoint>/.well-known/agent-card.json인증 없이 200과 유효한 JSON을 준다
V2모든 skill이 chofam:kind/* 태그를 정확히 하나 갖는다
V3노출한 skill이 §2.2의 1차 범위 안이다
V4chofam:kind/action skill이 있다면 E1~E5를 만족한다chofam:effect/* 표기, 전용 인증 스킴(§5.2), 멱등 키 재전송 시 이중 실행 없음, 감사 증적
V5capabilities.extensionshttps://cho-fam.com/ans/v1이 있고 params.name이 아래 배정 이름과 같다
V6securitySchemes가 §5 표의 해당 행과 일치한다. 선언 자체는 ANS 규격 R9이며 발급 시점에 기계로 확인된다
V8모든 skill이 chofam:scope/party를 갖는다(§2.3)
V9hire/v1 확장이 있다면 unitPrice가 양의 정수다(§4.1). 없어도 등재되고 고용된다 — 단가는 계약시 정한다(§4.2)
V7Task 왕복 1건 성공 — society가 message/send를 보내고 completed까지 받는다

V4는 terra에 실제로 걸린다 — 이벤트 인입이 실행이므로 멱등 검증이 T-M1 완료 기준("같은 id 재전송 시 중복 저장 없음")과 같은 것을 본다. 1차에 action을 노출하는 저장소는 terra뿐이다.

ANS 이름 배정(업무지시서 §3.2) — mentor.knowledge.v1 · ethos.decision.v1 · afo.finance.v1 · terra.observer.v1 · guild.watch.v1 · chopilot.observe.v1. 등재 주체는 chofam이다. 각 저장소는 카드를 게시하고 endpoint를 회신하면 된다.

9. 미결

#항목시점
D-13(ANS)심사 → 이름 발급 인계 방식. 1차는 관리자 수동 등재Phase 1 설계 시
D-14(ANS)ANS 축약 카드 ↔ A2A 정식 카드 필드 정합Phase 1 규격 확정 시
D-15(ANS)고정 목록 → ANS 경로 전환(§6). 패밀리는 고정 유지, 등록·공인 에이전트는 resolve조건 발생
D-16(ANS)방에 참여한 에이전트의 발화 가시 범위(§5.3) — mentor 무프로파일링이 여기서 결정된다society M1 전
D-17(ANS)다자 방에서 userBearersub를 무엇으로 고르는가(§5)society M1 전

셋 다 카드 규격이 답하지 않는다. 카드는 스킴과 skill을 선언할 뿐이고, 누가 방에 있고 무엇을 보는가는 society의 결정이다. 여기 적는 것은 규격이 그것을 전제하고 있다는 사실을 남기기 위해서다.