docs(hub): gate 7개와 조건부 차단(NOT_APPLICABLE) 개념 추가

capability 가 OFF 인 프로젝트에서 gate 를 PASS 라 하면 거짓말이고 FAIL
이라 하면 영원히 배포할 수 없다. NOT_APPLICABLE 을 도입하되 FE-GATE-033
이 번들 부재를 증명했을 때만 유효하게 묶었다.
FE-GATE-033 자신은 NOT_APPLICABLE 을 취할 수 없다 — capability 를 하나도
쓰지 않는 프로젝트도 '쓰지 않는다'를 증명해야 한다.
This commit is contained in:
DongHyeonka
2026-07-28 14:21:30 +09:00
parent 511b6bb022
commit 1f5a5ced3a
@@ -1853,7 +1853,9 @@ Script 이름을 바꾸는 것은 허용되지만 acceptance gate와 artifact ma
<!-- section-id: gate-matrix --> <!-- section-id: gate-matrix -->
### 15.1 Gate ownership ### 15.1 Gate ownership
현재 stable gate registry는 26개 row이며, 새 gate를 추가하거나 supersede할 때 이 수와 promotion formula를 함께 갱신한다. 현재 stable gate registry는 33개 row이며, 새 gate를 추가하거나 supersede할 때 이 수와 promotion formula를 함께 갱신한다.
`FE-GATE-027`~`FE-GATE-032`는 **capability-scoped gate**다. 대응 capability가 비활성이면 `NOT_APPLICABLE`을 취할 수 있으나, 그 상태는 `FE-GATE-033`이 PASS일 때만 유효하다(§18.1).
> 이 표가 gate 의 **정의**다. `Covered FE-OC` 열은 gate 와 계약의 대응 관계이지 계약 내용의 사본이 아니다. > 이 표가 gate 의 **정의**다. `Covered FE-OC` 열은 gate 와 계약의 대응 관계이지 계약 내용의 사본이 아니다.
> branch 는 이 표를 옮겨 적지 않는다 — gate ID 를 행 키로 쓰고 자기 control 만 적는다(예: [[raw/branch-notes/feature-frontend-build-bundle-supply-chain-contract]]). > branch 는 이 표를 옮겨 적지 않는다 — gate ID 를 행 키로 쓰고 자기 control 만 적는다(예: [[raw/branch-notes/feature-frontend-build-bundle-supply-chain-contract]]).
@@ -1886,6 +1888,13 @@ Script 이름을 바꾸는 것은 허용되지만 acceptance gate와 artifact ma
| `FE-GATE-024` | `FE-RB-004` drill | production promotion | `FE-OC-025` | `FE-NFR-010` | telemetry degradation | containment, escalation, recovery assertions pass | `FE-RB-004` record | `FAIL_UNVERIFIED` | | `FE-GATE-024` | `FE-RB-004` drill | production promotion | `FE-OC-025` | `FE-NFR-010` | telemetry degradation | containment, escalation, recovery assertions pass | `FE-RB-004` record | `FAIL_UNVERIFIED` |
| `FE-GATE-025` | `FE-RB-005` drill | production promotion | `FE-OC-025` | — | blocking release defect | rollback decision, escalation, recovery assertions pass | `FE-RB-005` record | `FAIL_UNVERIFIED` | | `FE-GATE-025` | `FE-RB-005` drill | production promotion | `FE-OC-025` | — | blocking release defect | rollback decision, escalation, recovery assertions pass | `FE-RB-005` record | `FAIL_UNVERIFIED` |
| `FE-GATE-026` | lab performance | release | `FE-OC-021` | `FE-NFR-003`, `FE-NFR-004`, `FE-NFR-005` | recorded runner/throttling/cache context + named interactions | every lab threshold passes and report contains reproducibility metadata | lab performance report | `FAIL_UNVERIFIED` | | `FE-GATE-026` | lab performance | release | `FE-OC-021` | `FE-NFR-003`, `FE-NFR-004`, `FE-NFR-005` | recorded runner/throttling/cache context + named interactions | every lab threshold passes and report contains reproducibility metadata | lab performance report | `FAIL_UNVERIFIED` |
| `FE-GATE-027` | binary I-O & local store | merge | `FE-OC-013`, `FE-OC-027` | — | picker 취소·거부, quota 초과 fallback, OPFS 순차 write, Cache Storage 버전 파티션, object URL 해제 | 모든 fixture가 기대 kind로 처리되고 object URL 누수 0 | binary I-O report | `FAIL_UNVERIFIED` |
| `FE-GATE-028` | cache tier & cross-tab | merge | `FE-OC-012`, `FE-OC-028` | — | 영속 캐시 version 파티션, 탭 A mutation → 탭 B 무효화, BroadcastChannel 부재 fallback | 불일치 version 캐시는 복원되지 않고 탭 간 무효화가 도달 | cache tier report | `FAIL_UNVERIFIED` |
| `FE-GATE-029` | large object transfer | merge + release | `FE-OC-019`, `FE-OC-029` | `FE-NFR-018` | presign 만료, part 재시도 상한, stream 중단 후 재개, 무결성 불일치, credential 첨부 negative | 모든 fixture 통과 + 전송 요청에 session credential 0건 | transfer report | `FAIL_UNVERIFIED` |
| `FE-GATE-030` | multi-protocol transport | merge | `FE-OC-006`, `FE-OC-007`, `FE-OC-030` | — | GraphQL `200 + errors[]`, gRPC status ↔ HTTP status, codec decode 실패, gateway fallback | 모든 protocol 실패가 기대 kind로 정규화 | protocol mapping report | `FAIL_UNVERIFIED` |
| `FE-GATE-031` | realtime lifecycle | merge + release | `FE-OC-011`, `FE-OC-031` | `FE-NFR-016`, `FE-NFR-017` | 결정론 fake clock backoff, resume gap 감지, unmount 후 열린 연결(`SUBSCRIPTION_LEAKED` fixture), 이벤트 스키마 거부, `FE-RB-006` drill | backoff가 cap을 넘지 않고 unmount 후 열린 연결 0, 미검증 이벤트 0건 도달 | realtime lifecycle report | `FAIL_UNVERIFIED` |
| `FE-GATE-032` | background execution | merge + release | `FE-OC-016`, `FE-OC-017`, `FE-OC-032` | `FE-NFR-019` | SW 등록·갱신 UX, rollback 시 SW 되돌림, background sync keyed-only, worker timeout·terminate, `FE-RB-007` drill | 모든 fixture 통과 + keyed 아닌 mutation replay 0건 | background execution report | `FAIL_UNVERIFIED` |
| `FE-GATE-033` | capability default-off | merge + release | `FE-OC-004`, `FE-OC-022`, `FE-OC-027`, `FE-OC-028`, `FE-OC-029`, `FE-OC-030`, `FE-OC-031`, `FE-OC-032` | `FE-NFR-020` | 기본 config로 production build, 각 capability ON 조합 build | 비활성 capability의 adapter 모듈이 어떤 chunk에도 없고 initial JS 증가 0 | capability bundle report | `FAIL_UNVERIFIED` |
### 15.2 Negative fixture requirement ### 15.2 Negative fixture requirement
@@ -1902,20 +1911,34 @@ Gate가 실제로 동작한다고 말하려면 최소 하나의 deliberately fai
| release | HTML build A + asset manifest B | | release | HTML build A + asset manifest B |
| reload guard | second chunk failure in same release pair | | reload guard | second chunk failure in same release pair |
| lab performance | context metadata missing 또는 one named threshold exceeded | | lab performance | context metadata missing 또는 one named threshold exceeded |
| binary I-O | quota 초과인데 `UPLOAD_PART_STATE`가 memory로 fallback |
| cache tier | release/config version 불일치 캐시를 복원해 사용 |
| large object transfer | transfer 요청에 session credential 헤더가 첨부 |
| multi-protocol | `200 OK` + `errors[]`를 success로 반환 |
| realtime lifecycle | unmount 후에도 구독이 살아 있음 / 미검증 프레임이 application 도달 |
| background execution | `idempotency: none` mutation이 background sync로 replay |
| capability default-off | flag OFF인데 adapter가 initial chunk에 포함 |
Negative fixture를 실행하지 않고 rule 존재만 확인한 결과는 `locally-verified` 증거로 부족하다. Negative fixture를 실행하지 않고 rule 존재만 확인한 결과는 `locally-verified` 증거로 부족하다.
### 15.3 Promotion rule ### 15.3 Promotion rule
```text ```text
MERGE_READY = FE-GATE-001, FE-GATE-002, FE-GATE-003, FE-GATE-004, FE-GATE-005, FE-GATE-006, FE-GATE-007, FE-GATE-008, FE-GATE-009, FE-GATE-010, FE-GATE-011, FE-GATE-013, FE-GATE-020 PASS MERGE_READY = FE-GATE-001, FE-GATE-002, FE-GATE-003, FE-GATE-004, FE-GATE-005, FE-GATE-006,
FE-GATE-007, FE-GATE-008, FE-GATE-009, FE-GATE-010, FE-GATE-011, FE-GATE-013,
FE-GATE-020, FE-GATE-033 PASS
AND FE-GATE-027, FE-GATE-028, FE-GATE-030 각각 PASS 또는 유효한 NOT_APPLICABLE
RELEASE_READY = MERGE_READY AND FE-GATE-012, FE-GATE-014, FE-GATE-015, FE-GATE-019, FE-GATE-026 PASS RELEASE_READY = MERGE_READY AND FE-GATE-012, FE-GATE-014, FE-GATE-015, FE-GATE-019, FE-GATE-026 PASS
PROD_PROMOTION_READY = RELEASE_READY AND FE-GATE-016, FE-GATE-021, FE-GATE-022, FE-GATE-023, FE-GATE-024, FE-GATE-025 PASS AND FE-GATE-029, FE-GATE-031, FE-GATE-032 각각 PASS 또는 유효한 NOT_APPLICABLE
PROD_PROMOTION_READY = RELEASE_READY AND FE-GATE-016, FE-GATE-021, FE-GATE-022, FE-GATE-023,
FE-GATE-024, FE-GATE-025 PASS
FIELD_SLO_READY = PROD_PROMOTION_READY AND FE-GATE-018 PASS FIELD_SLO_READY = PROD_PROMOTION_READY AND FE-GATE-018 PASS
DOCUMENTATION_READY = FE-GATE-017 PASS_SCOPED AND evidence ledger updated DOCUMENTATION_READY = FE-GATE-017 PASS_SCOPED AND evidence ledger updated
PROJECT_READY = all applicable blocking gates PASS PROJECT_READY = all applicable blocking gates PASS
``` ```
`FE-GATE-033``NOT_APPLICABLE`을 취할 수 없으므로 항상 `MERGE_READY`에 무조건 포함된다. capability를 하나도 쓰지 않는 프로젝트도 "쓰지 않는다"를 증명해야 한다.
현재는 `PROJECT_READY = false`, 즉 `NOT_READY`다. 현재는 `PROJECT_READY = false`, 즉 `NOT_READY`다.
--- ---
@@ -2250,12 +2273,20 @@ To mark `prod-verified`:
```text ```text
PASS_STATES = {PASS, PASS_SCOPED} PASS_STATES = {PASS, PASS_SCOPED}
READY iff every blocking row Current is in PASS_STATES NOT_APPLICABLE = capability-scoped gate 가, 대응 capability flag 가 OFF 이고
FE-GATE-033 이 그 adapter 의 번들 부재를 증명했을 때만 취할 수 있는 상태
READY iff every blocking row Current is in PASS_STATES or is a valid NOT_APPLICABLE
otherwise NOT_READY otherwise NOT_READY
``` ```
`PASS_SCOPED`는 Blocking question과 Required evidence가 명시적으로 같은 제한 범위를 물을 때만 허용한다. 점수 평균으로 blocking failure를 상쇄하지 않는다. `PASS_SCOPED`는 Blocking question과 Required evidence가 명시적으로 같은 제한 범위를 물을 때만 허용한다. 점수 평균으로 blocking failure를 상쇄하지 않는다.
`NOT_APPLICABLE`은 다음을 `MUST` 지킨다.
- `FE-GATE-027`~`FE-GATE-032`**만** 취할 수 있다. `FE-GATE-033` 자신은 취할 수 없다.
- `FE-GATE-033`이 PASS가 아니면 모든 `NOT_APPLICABLE`은 무효이며 `FAIL_UNVERIFIED`로 강등된다.
- "안 쓴다"는 주장은 선언이 아니라 **번들에 그 adapter가 없다는 증거**로만 성립한다.
### 18.2 Current scorecard ### 18.2 Current scorecard
| Readiness ID | Blocking question | Required evidence | Current | Reason | | Readiness ID | Blocking question | Required evidence | Current | Reason |
@@ -2268,7 +2299,7 @@ otherwise NOT_READY
| `FE-RDY-006` | runtime config boot gate가 검증됐는가 | schema + boot tests | `FAIL` | test evidence `UNVERIFIED` | | `FE-RDY-006` | runtime config boot gate가 검증됐는가 | schema + boot tests | `FAIL` | test evidence `UNVERIFIED` |
| `FE-RDY-007` | failure taxonomy가 test matrix로 강제되는가 | integration artifacts | `FAIL` | test evidence `UNVERIFIED` | | `FE-RDY-007` | failure taxonomy가 test matrix로 강제되는가 | integration artifacts | `FAIL` | test evidence `UNVERIFIED` |
| `FE-RDY-008` | auth boundary가 token lifecycle을 침범하지 않는가 | port/import tests | `FAIL` | implementation evidence 없음 | | `FE-RDY-008` | auth boundary가 token lifecycle을 침범하지 않는가 | port/import tests | `FAIL` | implementation evidence 없음 |
| `FE-RDY-009` | 8 registry가 single owner로 구현됐는가 | registry snapshots | `FAIL` | implementation evidence 없음 | | `FE-RDY-009` | 9 registry가 single owner로 구현됐는가 | registry snapshots | `FAIL` | implementation evidence 없음 |
| `FE-RDY-010` | lint/checkJs/runtime-schema/unit/component/integration/e2e/a11y가 통과했는가 | CI artifacts | `FAIL` | CI evidence `UNVERIFIED` | | `FE-RDY-010` | lint/checkJs/runtime-schema/unit/component/integration/e2e/a11y가 통과했는가 | CI artifacts | `FAIL` | CI evidence `UNVERIFIED` |
| `FE-RDY-011` | build/bundle/security gate가 통과했는가 | release artifacts | `FAIL` | build evidence `UNVERIFIED` | | `FE-RDY-011` | build/bundle/security gate가 통과했는가 | release artifacts | `FAIL` | build evidence `UNVERIFIED` |
| `FE-RDY-012` | lab·field NFR context와 측정값이 있는가 | lab + field reports | `FAIL` | target만 존재; `FE-GATE-018`, `FE-GATE-026``FAIL_UNVERIFIED` | | `FE-RDY-012` | lab·field NFR context와 측정값이 있는가 | lab + field reports | `FAIL` | target만 존재; `FE-GATE-018`, `FE-GATE-026``FAIL_UNVERIFIED` |
@@ -2276,6 +2307,7 @@ otherwise NOT_READY
| `FE-RDY-014` | rollback drill이 수행됐는가 | drill record | `FAIL` | deploy/drill evidence `UNVERIFIED` | | `FE-RDY-014` | rollback drill이 수행됐는가 | drill record | `FAIL` | deploy/drill evidence `UNVERIFIED` |
| `FE-RDY-015` | runbook이 실제 hosting command와 evidence path를 가지는가 | provider runbook | `FAIL` | provider 미정 | | `FE-RDY-015` | runbook이 실제 hosting command와 evidence path를 가지는가 | provider runbook | `FAIL` | provider 미정 |
| `FE-RDY-016` | evidence ledger에 과장 없는 grade가 유지되는가 | ledger review | `PASS` | 현재 문서 경계 명시 | | `FE-RDY-016` | evidence ledger에 과장 없는 grade가 유지되는가 | ledger review | `PASS` | 현재 문서 경계 명시 |
| `FE-RDY-017` | 비활성 capability가 번들에서 실제로 부재한가 | capability bundle report | `FAIL` | build evidence `UNVERIFIED` |
**Current verdict: `NOT_READY`** **Current verdict: `NOT_READY`**