Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 81 additions & 0 deletions .github/workflows/upstream-behind.yml
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
# Measures how far this fork is behind upstream (dlunch/RustJava) and reports the number.
#
# Why this exists: the 2026-09-04 cadence decision (docs/upstream-sync-approach.md §5-B, landed
# in PR #29) fixed the trigger at `behind >= 20` but left nothing that *measures* it — the number
# was only ever read when a human remembered to ask. This job asks on a schedule.
#
# ── Why it never fails ────────────────────────────────────────────────────────
# A red run was considered and rejected on evidence from this repo, not taste:
# `rust-audit.yaml` (the scheduled-workflow precedent) has been `failure` in 19 of its last 20
# runs and produced zero response tickets, and the `coverage` lineage already resolved a
# chronically-red workflow by making it green rather than by acting on the red. A scheduled
# failure also attaches check-runs to main's tip (measured on 8c1238b5: 7 `audit` failures),
# which muddies the "landed main is green" read that every gate3 round performs. So the number
# is reported, not raised as an error. Issues were not an option either: this fork has issues
# disabled (`hasIssuesEnabled: false`).
#
# ── Reading it ────────────────────────────────────────────────────────────────
# The canonical read stays local and costs nothing:
# git fetch -q upstream && git rev-list --count origin/main..upstream/main
# This workflow does not replace that; it makes the number appear when nobody asked.
#
# ── Boundaries ────────────────────────────────────────────────────────────────
# Read-only toward upstream: it adds a remote and fetches. No push, no PR, no issue, no comment.
# It does not open a sync round — issuance stays with a person (the cadence decision says so).
# The threshold below is the landed decision's value; changing it is a new decision, not an edit.

name: upstream behind

on:
schedule:
# Weekly, Mondays 06:17 UTC. Weekly rather than daily because the measured time to
# accumulate 20 commits upstream is a median of 44 days and a minimum of 9 (12-month
# window, 144 commits / 51 weeks) — a 7-day period is shorter than the fastest observed
# crossing, so it cannot miss one by more than a period, while daily would cost 7x the
# runs for a decision nobody can act on faster than one sync round. The offset avoids
# the top of the hour (GitHub queues those hardest) and `rust-audit.yaml`'s 00:00 slot.
- cron: "17 6 * * 1"
workflow_dispatch:

permissions:
contents: read

jobs:
behind:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
with:
fetch-depth: 0

- name: Measure behind
env:
THRESHOLD: "20" # docs/upstream-sync-approach.md §5-B — landed in PR #29
run: |
set -euo pipefail
git remote add upstream https://github.com/dlunch/RustJava.git
git fetch -q --no-tags upstream
behind=$(git rev-list --count HEAD..upstream/main)
base=$(git merge-base HEAD upstream/main)
{
echo "## upstream behind"
echo
echo "| axis | value |"
echo "| --- | --- |"
echo "| behind | **$behind** |"
echo "| threshold | $THRESHOLD |"
echo "| merge-base | \`$base\` |"
echo "| upstream HEAD | \`$(git rev-parse --short upstream/main)\` |"
echo
if [ "$behind" -ge "$THRESHOLD" ]; then
echo "**At or over the threshold — a sync round is due.** Issuance stays with a person;"
echo "this job does not open one. See docs/upstream-sync-approach.md §5-B."
else
echo "Under the threshold — nothing to do."
fi
} >> "$GITHUB_STEP_SUMMARY"
if [ "$behind" -ge "$THRESHOLD" ]; then
echo "::warning title=upstream behind $behind::at or over the threshold ($THRESHOLD) — a sync round is due"
else
echo "::notice title=upstream behind $behind::under the threshold ($THRESHOLD)"
fi
16 changes: 16 additions & 0 deletions REPORT.md
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,21 @@
# REPORT

## [2026-09-05] `behind` 를 «재는» 예약 워크플로 신설 (rustjava-upstream-behind-measure-scheduled-workflow)
- 무엇을: `.github/workflows/upstream-behind.yml` **1개 신설**. 주 1회 upstream 을 **read-only fetch** 해
`rev-list --count` 를 찍고 **Job Summary + annotation** 으로 보고한다. ★**코드(`.rs`) 0줄 · `scripts/` 무접촉.**
- 왜: 2026-09-04 판정이 트리거를 **`behind ≥ 20`** 으로 못박았는데 ★**그 수를 «재는 주체»가 없었다**
(`rev-list --count` 를 가진 파일 **0건**). 임계만 있고 관측이 없으면 「아무도 안 챙긴다」가 그대로 남는다.
- 사용자 영향: 런타임·CI 게이트 **무변경**(새 워크플로는 예약 전용이라 PR 검사에 들어가지 않는다).
★**다음 동기 회차의 시점이 «사람 기억»에서 «주간 관측»으로 옮겨졌다.**
- 검증: ★**한 번 돌려** 오늘의 값을 냈다 — **behind `0`** · `merge-base` `bd42427` = upstream HEAD ⇒ 임계 미만.
무회귀: `check-dod-ci-parity.py` **rc=0** · `check-worklog-json.py` **rc=0**.
- ★★**알림 방식을 «실측으로» 골랐다**(이 회차 결정의 대부분): ⒜red 는 여기서 **안 듣는다**
(선례 `rust-audit` 최근 **20 run 중 19 failure** · ★**대응 티켓 0건** · `coverage` 리니지도 만성 red 를 «green 으로» 끝냈다)
이고 예약 red 는 **main tip check-run 을 오염**시킨다(★단 **PR 은 막지 않는다** — 확인했다) ·
⒞이슈는 ★**이 fork 가 issues 비활성이라 불가** ⇒ ★**⒝ 가 «남은 것»이고 그 수동성은 재개 조건으로 잰다.**
- ★**후속 추천**: ⑴`behind ≥ 20` 이 **7일 이상**인데 회차가 안 열리면 **알림 방식을 다시 열어라**(세는 명령은 §5-B ⒠).
⑵★**임계 20 과 「발권은 사람이 한다」는 이 회차가 건드리지 않았다** — 바꾸려면 새 결정이다.

## [2026-09-05] 워크로그 «부재» 기계 강제 판정 — 넣지 않는다 (rustjava-worklog-absence-machine-enforcement-decision)
- 무엇을: 채택 제안 `2026-09-04-worklog-mandate-and-local-gate#p0` 에 대한 **판정**이다.
★**결론: 워크로그 «부재»를 잡는 기계 강제를 지금은 넣지 않는다** — `check-worklog-json.py` 의
Expand Down
17 changes: 17 additions & 0 deletions STATE.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -23,6 +23,23 @@
(25번째 run, 앞선 24건 전부 red). **PR 대기 — 게이트③ 미착지.**

## 완료
- [rustjava-upstream-behind-measure-scheduled-workflow] ★★**`behind` 를 «재는» 자리 신설 — `.github/workflows/upstream-behind.yml`.**
채택 제안 `2026-09-04-upstream-sync-cadence-decision#p0`. ★임계는 정해졌는데(**`behind ≥ 20`** · PR #29 착지) ★**재는 주체가 없었다**
(`git grep -lI 'rev-list --count' origin/main -- .github/ scripts/` → **0건**).
★**주기 = 주 1회**(`cron: "17 6 * * 1"`) — 선례(`rust-audit` 일간)를 **베끼지 않고** 임계 도달 속도로 정당화했다:
behind 20 도달 **중앙 44일 · ★최소 9일** ⇒ ★**7 < 9 라 한 주기 넘게 못 놓친다** · 일간은 7배 비용에 판단 가치 0.
★★**알림 = ⒝ Job Summary + annotation · «항상 green»** — ★**취향이 아니라 실측으로 골랐다**:
⒜red 는 여기서 **안 듣는다**(선례 `rust-audit` 최근 **20 run 중 19 failure** 인데 ★**대응 티켓 0건**) ·
예약 red 는 ★**main tip check-run 에 붙어**(실측 `8c1238b5` 에 `audit` failure **7건**) 게이트③의 「착지본 green」 읽기를 **흐린다**
(★단 **PR 은 막지 않는다** — PR head 와 sha 가 다르다) · ⒞이슈는 ★**이 fork 가 issues 비활성이라 «불가»**.
⇒ ★**⒝ 가 «남은 것»이고 그 «수동성»을 알고 골랐다** — ★**재개 조건이 그 대가를 «잰다»**
(「`behind ≥ 20` 이 7일 이상인데 회차 미개시」 · 세는 명령·오늘의 값을 §5-B ⒠ 에 박았다).
★**한 번 돌려 오늘의 값**: ★**behind `0`** · `merge-base` `bd42427` = upstream HEAD ⇒ 임계 미만.
★**upstream 발신 0**(remote 추가 + fetch 뿐 · `permissions: contents: read`) · ★**자동 발권 0** · ★**임계 20 무접촉** ·
★`bin/healthcheck`·orchestrator 무접촉 · `scripts/` 무접촉(파리티 rc=0) · `.rs` **0줄** · S9 미개시.
★게이트③ 완료: PR #31 — ★★**`--merge` 착지**(★`--squash` 아님 · 등재 repo). 머지커밋 sha 는 회신 `merged:` 참조.
★**착지 후 «워크플로를 실제로 돌려» 확인했다** — 구현 회차가 「본문 명령만 태웠고 워크플로 자체는 못 돌렸다」고 자인한 그 구멍이다.
결과는 회신 참조. ★**게이트② 1회차 approve** — 반려 0.
- [rustjava-worklog-absence-machine-enforcement-decision] ★★**워크로그 «부재»를 기계로 잡을지 «판정» — 결론: 지금은 «넣지 않는다».**
채택 제안 `2026-09-04-worklog-mandate-and-local-gate#p0`. ★**`scripts/check-worklog-json.py` 무접촉**(6축 무회귀 · rc=0) ·
`.rs` **0줄** · 과거 backfill **0** · qts 잠금·upstream 리니지·파리티 검사기 **무접촉**.
Expand Down
28 changes: 28 additions & 0 deletions docs/upstream-sync-approach.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -1007,6 +1007,34 @@ git fetch -q upstream && git rev-list --count origin/main..upstream/main # ★
이유: 회차마다 **설계 판단**(우리 포크 지점 유지 여부)이 들어가고, 그것은 S1·S2·S3 에서 실제로 필요했다.
- ★**구현은 «별건»이다 — 이 판정 회차에서 만들지 않았다**(검사기·크론·워크플로 신설 **0**).

★★★**[2026-09-05 착지] «재는 자리»가 생겼다 — `.github/workflows/upstream-behind.yml`**
(제안 `2026-09-04-upstream-sync-cadence-decision#p0` 집행 · 위 「구현은 별건」이 그 별건이다).

- **주기 = 주 1회**(`cron: "17 6 * * 1"`). ★**일간이 아니다** — 임계 20 에 닿는 시간이 **중앙 44일 · 최소 9일**(§⒞)이라
★**7일 주기는 «가장 빠른 관측 상승»보다도 짧아** 한 주기 넘게 놓칠 수 없고, 일간은 **7배 비용**에 판단 가치가 0 이다
(회차보다 빨리 움직일 수 없다). 정시·`rust-audit` 의 00:00 슬롯을 피해 오프셋을 뒀다.
- ★★**알림 방식 = ⒝ «Job Summary + annotation» · 워크플로는 «항상 green»** — ★**취향이 아니라 이 저장소 실측으로 골랐다**:
⒤★**⒜(red)는 여기서 «안 듣는다»** — 선례 `rust-audit.yaml` 이 최근 **20 run 중 19 가 failure** 인데
★**대응 티켓이 «0건»**이다(제목 기준 전수 조회). ★**`coverage` 리니지도 만성 red 를 «행동»이 아니라 «green 으로» 끝냈다.**
⒥★**그리고 예약 red 는 «main tip 의 check-run»에 붙는다**(실측 `8c1238b5` 에 `audit` failure **7건**) ⇒
게이트③이 매 회차 하는 「착지본 green」 읽기를 **흐린다**. ※단 ★**PR 을 막지는 않는다**(PR head 와 sha 가 다르다).
⒦★**⒞(이슈)는 «불가»다** — 이 fork 는 ★**issues 가 비활성**이다(`hasIssuesEnabled: false`).
⇒ ★**남은 것이 ⒝ 이고, 그 «수동성»을 알고 고른다**(아래 재개 조건이 그 대가를 잰다).
- ★**정본 «읽기»는 여전히 로컬 한 줄이다** — 워크플로는 그것을 **대체하지 않고**, ★**아무도 안 물어도 재는** 역할이다.
- ★**upstream 발신 0** — remote 추가 + `fetch` 뿐이다(push·PR·issue·comment 0) · `permissions: contents: read`.
- ★★**자동 발권 0** — 임계를 넘어도 워크플로는 **회차를 열지 않는다**. 발권은 사람이 한다(위 ⒠ 그대로).
- ★**임계 20 은 이 회차가 바꾸지 않았다** — 그 수는 착지한 판정(PR #29 · 머지 `4b91e8f8`)이다.

★★**알림 방식의 «재개 조건» — 수동성이 실제로 대가를 치렀는지 잰다**:
> ★**`behind ≥ 20` 이 «7일 이상» 지속됐는데 그 사이 동기 회차가 «열리지 않았으면» 알림 방식을 다시 연다**
> (⒞ 는 issues 를 켜야 하고, ⒜ 는 위 ⒥ 를 감수해야 한다 — 그때 «다시» 저울질하라).
```sh
# ⑴ 지금 값 ⑵ 마지막 동기 회차 착지 시각
git fetch -q upstream && git rev-list --count origin/main..upstream/main
git log -1 --format=%ci --grep='upstream 동기' --first-parent origin/main
```
★**오늘의 값 = behind `0` · 마지막 동기 착지 `a76b305`(S8)** ⇒ ★**대가를 아직 치르지 않았다**(관측 시작점).

### ⒡ ★재개(재측정) 조건 — 세는 법과 오늘의 값

> ★**새 축으로 «3회차»를 돈 뒤 다시 재라.** 임계 20 은 «시작값»이지 상수가 아니다.
Expand Down
Loading