Skip to content

Release 0.4.0 - #1

Merged
cmir79 merged 8 commits into
mainfrom
dev
Sep 10, 2026
Merged

cmir79 merged 8 commits into
mainfrom
dev

Conversation

@cmir79

@cmir79 cmir79 commented Sep 10, 2026 •

Copy link
Copy Markdown
Owner

What changed and why

Library

  • GevFrame.IsExtendedId (new): tells whether FrameId is the 64-bit extended block id or the 16-bit one that wraps from 65535 to 1. A consumer that tracks frame-id continuity needs to know which comparison to use; the receiver already knew per packet from the EI bit but did not pass it on.
  • GevControlLostException now says why control was lost, judged from the gap between the last heartbeat that reached the device and the device timeout: a heartbeat period longer than the timeout (configuration), a gap longer than the timeout (this process or the host was stalled — debugger break, memory snapshot, machine suspend — or the link was down), or a loss within the timeout (another application took or released the channel, or the device restarted). The reason is kept and repeated by the exception of every later call, so a caller that missed the ControlLost event still sees it. Prompted by a real case: a memory snapshot during live view dropped control, the live view kept showing its last frame, and the first grab 53 minutes later looked like the cause.

Documentation

  • docs/evaluation.md: every scenario heading now carries a one-line measurement layer — "bench measurement with the CLI harness, protocol layer only", or, for the MG-A320K-35 section, "reported from a production line through the CvInspect adapter". Two consumers quoted single sections and misread bench runs as field results; the line travels with a quoted section. The intro asks readers to cite the file rather than copy its numbers.

Release process

  • main now always holds the latest release; development happens on dev and reaches main through a release pull request whose description is the change log — this is the first one. release-pr-guard.yml checks that the PR head contains all of main and that the version no longer carries -dev; publish.yml checks that the tag commit is on main and takes the release notes from the merged PR's body. A pull request template was added.

Version

0.4.0 — minor: the public API grew (GevFrame.IsExtendedId).

Checks

  • dotnet build in the default configuration reports 0 warnings
  • main is an ancestor of this branch (the release-pr-guard job verifies it)
  • the tag will be created on the merge commit, main merged back into dev afterwards, and dev bumped to the next -dev version

main 은 언제나 마지막 릴리스이고 릴리스마다 v* 태그가 병합 커밋에 붙는다. 작업은 dev 에서 하고 릴리스 PR 로
main 에 들어간다. 그 PR 본문이 변경 기록이다.

- Directory.Build.props: 판 번호를 0.3.1-dev 로 — 로컬 빌드가 정식판으로 오인되지 않게. 릴리스 PR 의
  마지막 커밋에서 -dev 를 뗀다.
- ci.yml: dev 푸시에도 돌고, main 으로 가는 PR 에는 release-pr-guard 잡이 붙는다 — main 이 head 의 조상인지
  (핫픽스가 dev 에 병합되지 않은 채 나가는 회귀 방지), 판 번호에 -dev 가 남지 않았는지.
- publish.yml: 태그 커밋이 main 에 있는지 검사한다(dev 에서 태그를 미는 실수 방지). 이력이 필요해 fetch-depth 0.
- PR 템플릿과 README Status 문단을 새 흐름으로 바꾼다.
검토에서 확정된 것: release-pr-guard 가 룰셋의 필수 검사가 아니어서 빨간 가드로도 병합이 됐다. 룰셋에
release-pr-guard 와 build-test 두 레그를 필수로 걸고 최신 상태를 강제했다(저장소 설정, 이 커밋 밖).
저장소 안에서 고친 것:
- ci.yml: pull_request 에 edited 를 넣어 base 를 dev→main 으로 바꾼 PR 에서도 가드가 다시 돈다. 무거운
  잡은 edited 에서 건너뛴다. 가드는 <Version> 부재를 진단하고 대소문자를 가리지 않는다. 주석의 잡 이름과
  concurrency 설명을 바로잡는다.
- publish.yml: 태그 커밋이 main 에 없을 때의 문구에 복구 절차(main 먼저 푸시, 태그를 ref 로 재실행)를
  적는다. 릴리스를 만들 때 태그 커밋에 딸린 PR 본문을 노트로 쓴다 — PR 본문이 변경 기록이라는 약속을
  자동으로 지킨다. 없으면 자동 생성 노트. 그 API 를 읽으려고 tools 잡에 pull-requests: read 를 준다.
- PR 템플릿·Directory.Build.props·README: 문서만으로는 내지 않는다는 규칙, 릴리스 뒤 dev 판 번호 올리기,
  핫픽스 경로 한 구절을 보탠다.
ci.yml 에 edited 를 넣은 것이 역효과였다: 제목·본문 편집마다 무거운 잡이 필수 검사 이름으로 "건너뜀" 을
남겨(건너뜀 = 성공) 빨간 PR 이 편집 한 번에 초록이 되고, 같은 concurrency 그룹에서 돌던 CI 를 취소한다.
릴리스 노트가 PR 본문에서 나오므로 본문 편집은 릴리스 절차의 일부라 이 구멍은 실제로 밟힌다.

- release-pr-guard.yml: main 으로 가는 PR 에만, edited 포함, PR 번호별 concurrency. 잡 이름은 그대로라
  룰셋의 필수 검사 이름도 그대로다.
- ci.yml: pull_request 유형과 잡별 if 를 원래대로.
- publish.yml: PR 조회가 실패하면 "PR 없음" 으로 읽고 자동 노트로 릴리스를 만들어 버리지 않고 멈춘다
  (릴리스가 생기면 재실행이 노트를 다시 보지 않는다). 콘솔 인코딩을 UTF-8 로 고정하고 병합된 PR 만 고른다.
FrameId 는 GVSP 블록 ID 그대로라 16비트 장치에서는 65535 다음이 1 이고, 번호의 연속·선후를 따지는 소비자는
그 되돌이를 감안해 비교해야 한다. 64비트 확장 ID 면 그럴 필요가 없는데, 어느 쪽인지 소비자가 알 길이
없었다. 수신부는 패킷 헤더의 EI 비트로 슬롯마다 이미 알고 있으므로 리더를 적용할 때 메타에 실어 프레임
속성으로 낸다. 속성 설명에 수신부가 쓰는 모듈러 비교식을 적어 소비자가 같은 식을 쓰게 한다.

테스트: 단위(같은 스트림에서 EI 비트 없는 프레임은 false, 있는 프레임은 true — 수신부 대입을 빼면 실패),
통합(확장 ID 시뮬레이터의 프레임은 true). 문서의 GevFrame 절에 한 줄.
GevFrame.IsExtendedId 가 공개 API 추가라 다음 릴리스는 규칙상 minor 다. dev 가 0.3.1-dev 를 달고 있으면
로컬 빌드와 미리 만든 도구가 patch 판처럼 보이므로 지금 맞춘다. 확정은 여전히 릴리스 PR 의 마지막 커밋에서
-dev 를 뗄 때 한다.
디버거 중단·메모리 스냅샷·절전으로 프로세스가 멈추면 하트비트가 끊기고 장치는 시한 뒤 CCP 를 놓는다. 라이브
화면은 마지막 프레임을 붙들고 있어 아무것도 달라 보이지 않으므로, 한참 뒤의 첫 조작이 원인처럼 보인다 — 실제로
그렇게 한 시간 가까이 잃은 일이 있었다. 문구가 그 자리에서 풀어야 한다.

하트비트 루프가 마지막으로 장치에 닿은 시각을 기억하고, CCP 에서 제어 비트가 사라지면 세 갈래로 말한다:
주기가 시한보다 긴 설정 / 시한보다 긴 공백(이 프로세스·호스트가 멈췄거나 링크가 끊겼다) / 시한 안인데
사라짐(다른 애플리케이션이 놓거나 가져갔거나 장치 재시작). 연속 실패로 잃을 때도 마지막으로 닿은 시각을 싣는다.
사유는 저장해 두어 그 뒤 모든 조작이 던지는 GevControlLostException 에도 실린다 — 이벤트를 놓친 쪽이 첫
예외에서 같은 답을 본다.

테스트: 외부 해제(다른 애플리케이션), 응답기 침묵으로 만든 공백(정지, 뒤이은 호출에도 같은 사유), 시뮬레이터에서
주기 > 시한(설정).
소비자 둘이 같은 방식으로 오독했다: 8시간 실측 절만 읽고 형제 저장소의 현장 내구 실적으로 옮겨 적었고, 컬러 절을
못 보고 자기 취득을 "컬러 첫 검증" 으로 적었다. 출처는 문서 5행에 한 번 있지만 인용하는 사람은 필요한 절만 찾아
들어온다. 그래서 헤딩 바로 아래에 "CLI 하네스 벤치 측정, 프로토콜 층만, 소비자 애플리케이션 없음" 을 한 줄로
두어 절을 잘라 인용해도 층이 따라붙게 한다. 가동 라인에서 보고된 MG-A320K-35 절만 "CvInspect 어댑터를 거친
현장 보고, 하네스 측정 아님" 으로 다르게 적는다. 인트로에는 수치를 복사하지 말고 이 파일을 가리키라고 적는다 —
사본은 원본이 고쳐질 때 갈린다.
릴리스 PR 의 마지막 커밋 — -dev 를 뗀다. GevFrame.IsExtendedId 가 공개 API 추가라 minor.
@cmir79
cmir79 merged commit 034d2e7 into main Sep 10, 2026
11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant