Add shared managed lock broker

This commit is contained in:
2026-10-07 02:23:39 +00:00
parent 18676070b2
commit 470c7fb09b
16 changed files with 1583 additions and 120 deletions
@@ -1,7 +1,7 @@
---
name: gitea-discovery-authoring
description: Gitea Issue의 Discovery 초안을 작성하고 게시한다.
version: 0.4.0
version: 0.4.1
author: genichin, Hermes Agent
license: MIT
platforms: [linux]
@@ -15,6 +15,11 @@ metadata:
Gitea Issue 원본과 저장소 근거를 조사해 Discovery 초안을 작성하고 Issue 본문에 게시한다. Gitea 인증과 readback은 [Gitea authenticated access 운영 지침](../../../../operations/gitea-access.md), 작성 규칙은 [Discovery 작성 방법](../../../../docs/discovery/README.md), 문서 구조는 [Discovery 템플릿](../../../../docs/discovery/TEMPLATE.md)만 정본으로 사용하며 이 스킬에 복제하거나 임의로 확장하지 않는다.
## Managed-lock broker gate
Bootstrap 이후 Issue workflow는 canonical [Repository cache 운영 지침](../../../../operations/repository-cache.md)의 공통 managed-lock broker 하나를 사용한다. Checkout 밖 pre-created mode `0700` role-owned runtime directory와 unique handle/socket을 사용해 tracked `serve`를 시작하고 ready JSON을 기다린다. Client는 raw token을 inspect/log하지 않으며 public `request` API가 token을 캡슐화한다. 같은 handle의 `acquire_repository`/`release_repository`로만 nested repository lock을 관리하고 TTL 전에 `renew`한다. 정상·오류·cancel 모두 repository release(보유 시), Issue release, broker wait/reap, `probe` `free=true` readback 순서가 검증돼야 완료·로그·보고할 수 있다. Raw `flock ... sleep`, lock-file unlink와 client-side lock holder는 금지한다.
## 사용 시점
다음과 같이 정확한 저장소와 Issue를 지정해 Discovery 초안 작성을 요청할 때 사용한다.
@@ -31,24 +36,24 @@ Gitea Issue 원본과 저장소 근거를 조사해 Discovery 초안을 작성
Repository cache의 구조와 운영 규칙은 [Repository cache 운영 지침](../../../../operations/repository-cache.md)만 정본으로 사용한다. 작업할 때마다 이 문서를 새로 읽고 상세 규칙을 이 스킬에 복제하거나 완화하지 않는다.
Discovery 초안을 작성하기 전에 repository cache admission gate를 반드시 통과한다. 대상 cache가 없으면 Issue lock 획득 전에 `gitea-repository-cache-bootstrap` 스킬로 초기화하며, 기존 cache가 유효하지 않으면 자동 초기화하지 않고 중단한다. 초기화 여부와 관계없이 Issue lock 아래에서 canonical origin의 cache를 갱신하고, 갱신 후 다시 읽은 Gitea authoritative default-branch SHA와 local ref SHA가 정확히 일치해야 한다. 일치한 SHA를 pinned source revision으로 고정하며, gate가 실패하면 초안을 작성하지 않는다.
Discovery 초안을 작성하기 전에 repository cache admission gate를 반드시 통과한다. 대상 cache가 없으면 broker Issue lease 확인 전에 `gitea-repository-cache-bootstrap` 스킬로 초기화하며, 기존 cache가 유효하지 않으면 자동 초기화하지 않고 중단한다. 초기화 여부와 관계없이 broker Issue lease 아래에서 같은 handle의 `acquire_repository` request로 canonical origin의 cache를 갱신하고, 갱신 후 다시 읽은 Gitea authoritative default-branch SHA와 local ref SHA가 정확히 일치해야 한다. 일치한 SHA를 pinned source revision으로 고정하며, gate가 실패하면 초안을 작성하지 않는다.
## 절차
1. 요청에서 exact `owner`, `repository`, Issue 번호를 추출하고 형식을 검증한다. `read_file`로 `operations/repository-cache.md`를 새로 읽고 canonical cache 경로를 계산·검증한다.
2. Canonical authenticated Gitea API adapter로 spec-agent의 stable account identity와 exact repository metadata를 확인한다.
3. 대상 cache가 없으면 `gitea-repository-cache-bootstrap` 스킬로 초기화하고 관련 lock이 해제됐는지 확인한다. 기존 cache가 있으면 자동 초기화하지 않고 canonical 검증 절차를 따른다.
4. Cache와 lock 경로의 안전성을 검증한 뒤 canonical Issue lock을 획득한다. 같은 adapter로 Issue 전체 내용과 전체 comment baseline을 새로 읽고, Issue title, body, state, labels, assignees, milestone과 `updated_at`을 immutable pre-write snapshot으로 보존한다.
5. Issue lock을 유지한 채 canonical 순서에 따라 repository lock을 획득한다. path, bare 상태와 remote identity를 검증한 뒤 authoritative origin에서 prune/fetch한다. fetch 후 Gitea default branch와 SHA를 다시 읽고 local ref가 exact SHA와 일치하는지 확인하여 pinned source revision으로 기록한다. 어느 단계든 실패하면 획득한 lock을 canonical 규칙에 따라 해제하고 외부 write와 Discovery 작성을 수행하지 않는다.
4. Cache와 lock 경로의 안전성을 검증한 뒤 broker `serve`의 ready 응답과 public `request` API로 canonical Issue lease를 확인한다. 같은 adapter로 Issue 전체 내용과 전체 comment baseline을 새로 읽고, Issue title, body, state, labels, assignees, milestone과 `updated_at`을 immutable pre-write snapshot으로 보존한다.
5. Issue lease를 유지한 채 같은 broker handle로 `acquire_repository` request를 보낸다. path, bare 상태와 remote identity를 검증한 뒤 authoritative origin에서 prune/fetch한다. fetch 후 Gitea default branch와 SHA를 다시 읽고 local ref가 exact SHA와 일치하는지 확인하여 pinned source revision으로 기록한다. 어느 단계든 실패하면 보유 lease에 `release_repository`/`release` request를 보내고 외부 write와 Discovery 작성을 수행하지 않는다.
6. `read_file`로 `docs/discovery/README.md`와 `docs/discovery/TEMPLATE.md`를 새로 읽는다.
7. repository lock을 유지한 채 Issue 원본과 pinned repository SHA의 tree 및 파일을 조사한다. 움직이는 branch 이름 대신 exact pinned SHA를 사용하고, `git --git-dir=<path>/repository.git`의 read-only 명령 또는 이에 상응하는 안전한 reader만 사용하며 조사한 경로와 SHA를 기록한다. README가 정한 후속 문서의 exact 경로 존재 여부와 기존 요구사항명세서의 ID·파일명을 함께 조사한다.
8. 조사 종료 시 Gitea default-branch SHA와 local ref를 다시 읽어 pinned SHA와 모두 일치하는지 확인하고 repository lock을 해제한다. Issue lock은 전체 Issue workflow가 끝날 때까지 유지한다.
7. repository lease를 유지한 채 Issue 원본과 pinned repository SHA의 tree 및 파일을 조사한다. 움직이는 branch 이름 대신 exact pinned SHA를 사용하고, `git --git-dir=<path>/repository.git`의 read-only 명령 또는 이에 상응하는 안전한 reader만 사용하며 조사한 경로와 SHA를 기록한다. README가 정한 후속 문서의 exact 경로 존재 여부와 기존 요구사항명세서의 ID·파일명을 함께 조사한다.
8. 조사 종료 시 Gitea default-branch SHA와 local ref를 다시 읽어 pinned SHA와 모두 일치하는지 확인하고 `release_repository` request를 보낸다. Issue lease는 전체 Issue workflow가 끝날 때까지 유지한다.
9. README의 작성 규칙과 TEMPLATE의 visible 구조를 그대로 적용해 Discovery body artifact를 작성한다. `문서 영향 및 산출물`은 README가 정한 모든 문서 유형을 빠짐없이 판정하고 문서별 필수 내용을 구현 에이전트가 추가 설계 없이 작성할 수 있을 정도로 구체화한다. 요구사항명세서는 pinned SHA에서 충돌 여부를 확인한 exact 문서 ID·경로·제목·포함할 내용·제외할 내용을 기록한다. 모든 `${...}` placeholder를 교체하고 TEMPLATE에 없는 hidden state, marker 또는 metadata를 추가하지 않는다.
10. README의 작성 후 검증에 따라 형식 검증과 내용 검토를 각각 수행한다. body artifact의 첫 marker, 섹션 순서·제목, placeholder 부재, `문서 영향 및 산출물`의 문서 유형·순서·조치·경로·변경 내용·근거와 문서별 필수 내용 및 모든 저장소 근거가 pinned SHA에서 확인됐는지 검증한다. 신규 요구사항명세서의 경로에 `NNN`, `<slug>` 또는 다른 미확정 값이 남아 있거나 ID 충돌·형식 오류를 해소할 수 없으면 외부 write 없이 중단한다.
11. write 직전에 Issue와 comments를 다시 읽는다. pre-write snapshot의 body와 `updated_at`이 달라졌거나 comment baseline이 drift했으면 중단한다.
12. 아래의 단순 원본 보존 comment 형식으로 exact comment artifact를 만들고 한 번 작성한 뒤, 곧바로 comment 목록에서 authoritative readback한다.
13. comment readback 직후 Issue와 comments를 다시 읽어 post-comment snapshot을 만든다. body와 비본문 필드가 pre-write snapshot과 같고 comments가 baseline과 exact 신규 comment 하나로만 구성돼야 한다. 다르면 body를 변경하지 않고 partial 상태로 중단한다.
14. 보존 comment가 정확히 확인된 경우에만 Issue body 하나만 Discovery 초안으로 교체한다. provider가 조건부 update를 지원하면 post-comment `updated_at` 또는 ETag를 precondition으로 사용한다. 지원하지 않으면 Issue lock 아래에서 13번 read 직후 write하며 title, state, labels, assignees, milestone 등 다른 필드는 write payload에 포함하지 않는다.
14. 보존 comment가 정확히 확인된 경우에만 Issue body 하나만 Discovery 초안으로 교체한다. provider가 조건부 update를 지원하면 post-comment `updated_at` 또는 ETag를 precondition으로 사용한다. 지원하지 않으면 broker-managed Issue lease 아래에서 13번 read 직후 write하며 title, state, labels, assignees, milestone 등 다른 필드는 write payload에 포함하지 않는다.
15. 동일 Issue를 다시 읽어 body가 초안과 정확히 일치하고 다른 snapshot 필드가 변경되지 않았는지 확인한다. comments도 다시 읽어 보존 comment가 정확히 하나인지 확인한다.
## 원본 보존 comment