현재 명세된 AT URI 문법이 왜 유효한 URI나 URL이 아닌지, 무엇이 잘못되었는지, 그리고 생태계가 고려할 수 있는 수정 방향을 살펴봅니다.
가정용 오븐에서 구워지는 피자
이제 atproto 명세에서 가장 불행한 흠집 중 하나를 다룰 때가 되었습니다. 현재 명세된 AT URI 문법은 유효한 URI도, URL도 아닙니다. 우리는 URI의 "authority" 위치(at:// 바로 뒤)에 DID를 넣고 있는데, 이것이 RFC 3986에서 지정한 host/port 계층형 URI 문법 구성요소와 충돌합니다.
핵심 문제는 2025년에 (@mcc가 이 github 이슈에서) 드러났고, 지금 두 가지 이유로 본격적인 분기점에 와 있습니다. 첫째, 더 많은 사람들이 HTML <link> 태그 같은, 올바른 형식의 URI(또는 URL)를 기대하는 곳에서 AT URI를 사용하려고 하고 있습니다. 둘째, IETF의 ATP Working Group은 영구 등록과 함께 AT URI 스킴을 표준화하는 산출물을 맡고 있습니다.
이 글의 목적은 먼저 이 상황에 대한 배경을 설명하고, 그다음 우리가 이를 고치기 위해 시도할 수 있는 몇 가지 방법을 살펴보는 것입니다. 안타깝게도, 현재로서는 아주 훌륭한 선택지가 있다고 생각하지 않습니다. 생태계가 어떤 길을 택하든 개발자들의 고통과 혼란은 어느 정도 불가피할 것입니다.
저는 이 문제를 매우 중요하게 생각합니다. AT URI는 조용히 프로토콜의 가장 훌륭하고 중요한 기능 중 하나라고 생각하기 때문입니다! 공급자 hostname 대신 개별 계정 식별자를 authority 구역에 넣는 것은, 구체적으로도 상징적으로도 atproto의 핵심 아이디어 가운데 하나입니다. 계정은 자기 콘텐츠에 대한 최종 권한을 가지며, 호스팅 제공자 사이를 매끄럽게 이동할 수 있습니다. 계정이 주도권을 쥐고 있고, 현재의 네트워크 위치로 해석됩니다. 이 점은 바뀌지 않을 것이며, 이 문법 난장판만 해결할 수 있다면 사람들은 곳곳에서 AT URI를 마음껏 쓰기 시작할 수 있을 것입니다.
조금 더 구체적으로 보기 위해, authority 위치에 DID가 들어간 특정 레코드를 가리키는 AT URI 예시를 보겠습니다:
at://did:plc:vwzwgnygau7ed7b7wt5ux7y2/app.bsky.feed.post/3k5nobkf2w72g
그리고 일반적인 문법은 다음과 같습니다:
at:// <authority> / <collection> / <record-key>
at: URI 스키마는 원래 2022년에 설계되었고, 2023년에 임시 등록되었습니다. authority 부분에 DID를 넣으면 호환성 문제가 생길 수 있고, WHATWG 명세상 유효한 웹 URL 문법이 아니라는 점은 알고 있었습니다. 하지만 우리는 그것이 여전히 RFC-3986에서 표준화된 URI 문법에는 부합한다고 (잘못) 생각했습니다.
AT Protocol을 설계하는 일은 Bluesky 안팎 모두에서 늘 공동 작업이었지만, 이 특정한 문법 난장판에 대해서는 개인적인 책임을 느낍니다. 저는 2023년 봄에 이런 종류의 문제를 정확히 잡아내기 위해 작성된 명세를 검토하고 "단단하게 만드는" 데 꽤 많은 시간을 썼습니다.
문제의 뿌리는 RFC-3986에 대한 의도에 끌린 해석, 특히 Section 1.2.3에서 시작되었습니다:
일부 URI 스킴의 경우, 보이는 계층 구조는 스킴 자체로 제한된다. 즉, 스킴 구성요소 구분자(":") 뒤의 모든 것은 URI 처리에 대해 불투명한 것으로 간주된다.
당시 저는 이것을, URI의 근본 원리는 스킴 이름과 그 뒤의 콜론 문자라는 뜻으로 해석했습니다. 그 이후의 모든 것, 즉 section 3.2, 3.3 이후에서 설명하는 내용은 선택적인 "계층형" 문법으로 보였고, 무시할 수 있다고 생각했습니다. 실제로 이런 방식의 유효한 URI 스킴은 많이 있습니다. 예를 들면 이메일(mailto:John.Doe@example.com), 유즈넷(news:comp.infosystems.www.servers.unix)이 있습니다.
영구적인 IANA 등록을 의도하는 URI에 대한 추가 지침(우리가 AT URI 스킴에 대해 원하는 것)은 RFC-7595 Section 3.2에 설명되어 있으며, 다음과 같이 말합니다:
스킴은 "//"의 부적절한 사용을 피해야 한다. URI의 첫 부분에서 이중 슬래시는 그 뒤에 오는 것이 URI라는 스타일상의 표시가 아니다. 이중 슬래시는 <scheme-specific-part>의 문법이 계층 구조를 포함할 때에만 사용되어야 한다. 그런 스킴의 URI에서 이중 슬래시의 사용은 그 뒤에 오는 것이 명명 권한을 위한 최상위 계층 요소임을 나타낸다(RFC 3986의 Section 3.2에 더 자세한 내용이 있다). <scheme-specific-part> 안에 적합한 계층 구조를 포함하지 않는 스킴은 "<scheme>:" 문자열 뒤에 이중 슬래시를 사용하지 말아야 한다.
이것은 최선의 관행이 무엇인지를 분명하게 보여 줍니다. 다만 이것들이 "MUST"가 아니라 "SHOULD"라는 점은 언급해 두겠습니다.
전반적으로 보면, //가 사용될 때 일반/계층형 문법 제한이 요구된다는 것은 분명해 보입니다. RFC-3986 Appendix A의 형식적 ABNF 문법도 그렇게 요구합니다. WHATWG URL 문법 역시 이 점에 아무런 모호함을 남기지 않습니다. 그리고 실용적인 수준에서도, 실제 문자열들은 대부분의 현실 세계 URL 및 URI 라이브러리에서 파싱에 실패합니다.
애초에 왜 이런 의도에 끌린 해석을 했을까요? 우리가 지금의 단순한 문법을 사랑하기 때문입니다. 깔끔하고 관용적입니다. 개발자에게 익숙해 보이고, 어떤 인코딩/디코딩이나 문자열 변형도 필요 없으며, 이미 받아들여진 의미 체계를 활용합니다. DID에는 항상 최소 두 개의 콜론이 있기 때문에, hostname(또는 IP 주소)과의 혼동도 실제로는 모호하지 않습니다. 만약 이 URI 문법이 유효했다면, 시간이 지나며 브라우저나 범용 URI 파싱 라이브러리 같은 다른 곳에서도 지원을 얻을 길이 있을 것처럼 느껴졌습니다.
오늘날 이미 세상에는 수십억 개의 AT URI가 존재합니다. 이들 중 상당수는 콘텐츠 주소 기반 데이터 레코드 안에 들어 있으며, 레코드 버전(hash)을 바꾸지 않고는 업데이트할 수 없습니다. 또는 수백 개의 제공자가 만든 수백만 개의 암호학적으로 서명된 label 객체 안에 들어 있기도 합니다. 이는 현재 문법이 앞으로도 계속 마주치게 될 것이며, atproto 구현체들은 이를 적어도 부분적으로는 사실상 무기한 지원해야 한다는 뜻입니다.
이 점을 염두에 두면, 생태계가 취할 수 있는 큰 접근법은 몇 가지가 있다고 생각합니다:
기존 문법을 유지하되, 그것을 "URI"라고 부르지 않는 것입니다. 예를 들어 "AT 참조 식별자" 같은 이름으로 부를 수 있습니다. 이는 URI 스킴을 표준화하겠다는 IETF 작업반 헌장의 목표를 포기하는 뜻이 됩니다. 또한 이 문자열을 웹이나 다른 프로토콜 등에서 쓰려 할 때 끝없는 혼란과 모호함을 초래할 것입니다. 저는 이것이 나쁜 결과라고 생각하며, 이 길은 택하지 말아야 한다고 봅니다.
기존 문법을 유지하되, IETF URI 문법 규칙 자체를 바꾸는 것입니다. 이것은 아주 거대한 작업, 말하자면 "산을 옮기는" 수입니다. 엄청난 양의 표준 기구 외교와 사회적 자본이 필요할 것이고, 아마 수년이 걸릴 것입니다. 그래도 결과 자체는 atproto 생태계와 인터넷 프로토콜 공간 모두에 가장 좋을 수도 있다고 생각합니다. 일반적인 경우 authority 부분이 더 유연하다면 URI/URL 명세는 더 깔끔해지고, 구현도 더 명확해질 것이라고 봅니다. 그러면 미래의 프로토콜과 URI 스킴도 인코딩이나 문자열 변형 해킹 없이 대안적 의미 체계를 쓰기 쉬워질 것입니다. 하지만 이것은 큰 승부수이며, 시도하는 것이 현명할지는 잘 모르겠습니다.
AT URI 문법을 IETF 준수 형태로 바꾸는 것입니다. 아래 별도 섹션에서 논의하겠지만, 여기에는 몇 가지 다른 접근이 가능합니다. 어느 것도 현재 문법만큼 깔끔하지는 않으며, atproto 구현체들은 두 버전을 모두 지원하고 정규화와 동등성 검사도 매우 신중히 처리해야 합니다. 이 변경을 배포하는 데는 오랜 시간이 걸릴 것이고, 개발자의 시간과 주의를 많이 소모할 것이며, 그 과정에서 어느 정도 사용자에게 영향을 주는 파손은 피할 수 없을 것 같습니다. 배포된 모든 소프트웨어가 새 문법을 지원하지는 않을 테니까요. 반면 사람들은 더 빨리 다른 소프트웨어 및 프로토콜과의 통합을 시작할 수 있을 것이고, IETF 작업반도 초기 헌장을 통과시키기가 더 쉬워질 것입니다.
지금 제 생각으로는, 두 번째와 세 번째 선택지를 병행해서 탐색해야 합니다. 실제로 얼마나 많은 작업과 혼란이 따르는지 파악하고, 더 확실한 제안을 만들고, 사람들과 논의해야 합니다. 최종 결정을 내리는 장은 IETF 작업반, 즉 메일링 리스트가 되어야겠지만, 더 넓은 atmosphere 개발자 생태계의 의견도 고려해야 합니다.
기존 IETF URI 규칙 아래에서 유효하도록 AT URI 문법을 어떻게 바꿀 수 있을까요?
개인적으로 저는 다른 URI 스킴, 문자열 인코딩/디코딩, 대체 식별자, 또는 식별자 변형을 수반하는 접근에 대체로 반대합니다. 먼저 그런 예시 몇 가지를 훑어보겠습니다.
보다 직접적인 접근 가운데 하나는 authority 구역의 DID를 퍼센트 인코딩하는 것입니다. 따라서 at://did:plc:abc123/... 대신 at://did%3Aplc%3Aabc123/...를 사용하는 식입니다. 이 방법의 장점 중 하나는, 미래의 DID method가 예약 문자를 포함하더라도 사용할 수 있고, 심지어 DID가 아닌 다른 식별자도 사용할 수 있다는 점입니다. 하지만 웹 URL에서의 사용 경험으로 알듯, 퍼센트 인코딩은 정말 끔찍할 수 있습니다. 보기에도 못생기고 의미도 불분명해서, 사람들은 자주 원래 형태로 표시하려 할 것입니다. AT URI 전체를 쿼리 파라미터 안에 넣으려면 이중 인코딩이 필요합니다. 입력 문자열이 충분히 인코딩되었는지/디코딩되었는지 아는 명확하고 신뢰할 만한 방법도 없습니다. 문자열을 만들 때 인코딩을 빼먹기도 매우 쉽습니다. 디코딩에는 추가적인 문자열 순회/복사가 필요하고, 종종 메모리 할당도 필요합니다. 으. 그래도 표준 쪽 사람들은 아마 이 방향으로 우리를 유도할 것이라고 짐작합니다.
비슷한 범주의 접근으로는 DID 문법을 허용된 URI "host" 문법에 맞게 대응시키는 방법이 있습니다. 예를 들어 콜론을 대시로 바꾸거나(at://did-plc-abc123/...), 새로운 hostname을 발명하는 방식입니다(at://abc123.plc.did/...). 이런 방법은 보기에는 더 깔끔하고 인코딩 문제도 일부 피할 수 있지만, 번역과 간접 계층이 하나 더 생기므로 혼란을 유발할 가능성이 큽니다.
어떤 사람들은 AT URI 스키마 자체를 건너뛰고 did:plc:vwzwgnygau7ed7b7wt5ux7y2/at/app.bsky.feed.post/3k5nobkf2w72g 같은 "DID URL"을 쓰자고 제안했습니다. 저는 이것을 좋아하지 않습니다. 세상에 떠도는 DID URL 문자열을 어떻게 해석해야 하는지가 모호하기 때문입니다. 그것이 "atproto용"이라고 추측해야만 합니다. URI 문자열의 식별 가능성도 떨어집니다("이건 무엇을 위한 거지?"). 또한 장기적으로 프로토콜을 DID 사용에 묶어 버리게 되며, 미래에는 DID가 아닌 영속적 계정 식별자를 지원하고 싶을 수도 있습니다.
또 다른 사람들은 AT URI에서 항상 DID 대신 handle을 쓰자고 제안했습니다(at://handle.example.com/...). 이것은 이미 AT URI 명세에서 허용되며, IETF URI 규칙도 따릅니다. 하지만 이것은 atproto에서 DID가 가지는 "영속 식별자"의 강점에 어긋납니다. handle은 바뀔 수 있지만, DID는 계정의 전체 수명 동안 동일하게 유지됩니다.
URI에서 //를 없애고, 단일 슬래시(at:/did:plc:abc123/...) 또는 아예 없는 형태(at:did:plc:abc123/...)로 갈 수도 있습니다. 저는 사람들이 단일 슬래시 버전을 자주 at://로 입력하거나 고쳐 쓸 것이라고 생각합니다. 그리고 슬래시가 없는 버전은 URN처럼 보여서 새로운 개발자나 최종 사용자에게 혼란스러울 수 있습니다. 그래도 방향 자체는 맞는 쪽으로 가고 있다고 생각합니다.
현재 제가 고를 대체 문법은 비어 있는 authority 구역과 세 개의 슬래시를 사용하는 방식입니다: at:///did:plc:abc123/.... 이것은 URI 규칙상 허용되며, authority 부분이 선택 사항인 file URI(file:///home/root/notes.txt)에서 자주 보입니다. 이렇게 하면 DID는 첫 번째 path 세그먼트 아래로 들어가고, 인코딩하거나 변형할 필요가 없습니다. 일반적인 URI/URL 라이브러리도 잘 동작해야 합니다. 현재의 AT URI와도 간단히 구분할 수 있습니다(문자열이 at:///로 시작하는지만 확인하면 됩니다). 문자 하나만 바꾸면 됩니다. 반면 이것은 URI 문법의 정신을 비트는 느낌도 있습니다. 문법 제약을 해결하기 위해 "authority" 부분을 "path" 부분으로 옮기는 셈이니까요. IETF 쪽 사람들과 IANA URI 레지스트리 검토자들이 이것을 어떻게 볼지는 잘 모르겠습니다. 시각적으로도 약간 어색하고, 사람들은 수동으로 이것을 이중 슬래시로 "고쳐" 쓰기 쉬울 것입니다.
이 글은 AT URI의 주된 사용 사례, 즉 네트워크에서 공개 레코드를 전역적으로 참조하는 일에 초점을 맞추었습니다. 하지만 atproto URI와 관련해 주목할 만한 다른 점도 몇 가지 있습니다.
AT URI의 짧은 형태는 DID 문서에서 DID/handle 매핑을 확인하는 데 사용됩니다. 이것들은 URI의 alsoKnownAs 배열에 나타나며, at://username.example.com처럼 생겼습니다. handle은 언제나 유효한 hostname이므로, 이것들은 이미 유효한 URI이자 URL입니다. 이것들을 전부 바꾸려면 광범위한 DID 문서 업데이트가 필요하며, 상당히 번거로울 것입니다. 저는 이 사용 사례에 대해서는 큰 혼란이나 혼선 없이 이 문법을 그대로 유지할 수 있다고 생각합니다.
atproto를 위한 "permissioned data" 설계 작업도 진행 중입니다. 이것은 현재 IETF 작업반 헌장 범위에는 없지만, 미래의 재헌장 과정에서 결국 그쪽으로 들어갈 것으로 예상합니다. 현재의 "spaces" 제안 일부에는 새로운 ats:// URI 스킴("Authenticated Transfer Space")이 포함됩니다. 이 스킴은 at://와 유사한 문법을 가지며, URI authority 위치에 "space authority DID"를 둡니다. 우리가 AT URI를 위해 떠올리는 어떤 해결책이든, 아마 ATS URI에도 그대로 옮겨갈 것입니다.
IETF 작업반 헌장의 일부는 "account identifier systems"에 대한 기준과 레지스트리를 만드는 것입니다. 현재 atproto 명세는 DID 사용을 요구하며, 특히 두 가지 DID method(DID PLC와 DID Web)를 지원합니다. 작업반이 결국 DID가 아닌 식별자 시스템도 허용하게 될 가능성은 있습니다. 일반적으로 미래의 계정 식별자의 일반 문법은 AT URI 문법과 관련이 있으며, 최종 기준의 일부로 포함되어야 합니다.
blob references나 record versioning 같은, AT URI에 가할 수 있는 다른 작은 변화들도 있습니다. 이런 것들은 path 구조에 대한 비교적 단순한 변경이며, 여기서의 핵심 질문인 authority 부분 문법에는 닿지 않습니다.
이것이 전체 그림입니다! 앞으로 몇 달 동안 이 문제는 IETF ATP 메일링 리스트와 그 밖의 atproto 개발자 생태계 곳곳에서 논의될 것으로 예상합니다. 올해 말까지는 대략적인 합의에 도달할 수 있으면 좋겠습니다. 아마 11월의 IETF 127 회의쯤이면 가능할지도 모르겠습니다.