Skip to content

feat(operations): separate liveness and readiness probes - #265

Draft
seonghobae wants to merge 67 commits into
mainfrom
feat/liveness-readiness-probes
Draft

feat(operations): separate liveness and readiness probes#265
seonghobae wants to merge 67 commits into
mainfrom
feat/liveness-readiness-probes

Conversation

@seonghobae

@seonghobae seonghobae commented Aug 5, 2026

Copy link
Copy Markdown
Collaborator

Buyer-visible operational gap

GET /healthz was implemented as a static liveness response while README and architecture material described it as readiness. An orchestrator could therefore treat a process-alive signal as permission to route traffic. This bounded slice separates restart eligibility from traffic eligibility without adding a model, network, database, or external-service dependency to liveness.

Changes

  • Preserve the successful GET /healthz payload as 200 {"status":"ok"} while sourcing it from Spring Boot LivenessState.
  • Return 503 {"status":"broken"} when the application liveness state is BROKEN.
  • Add GET /readyz, returning 200 {"status":"ready"} only for ReadinessState.ACCEPTING_TRAFFIC and 503 {"status":"not_ready"} otherwise.
  • Add Cache-Control: no-store to both probes so intermediaries cannot replay stale availability state.
  • Keep both probes unauthenticated and limited to controlled state labels; no tenant, document, queue, dependency, credential, build, or exception detail is exposed.
  • Add complete public Javadoc and fail-fast construction without an ApplicationAvailability provider.
  • Add executable WebFlux controller tests for every liveness/readiness state, status code, complete response payload, cache policy, and constructor failure.
  • Enforce zero missed production lines and branches through mvn -B --no-transfer-progress verify, emit actionable JaCoCo diagnostics on failure, and run warning-free Java 21 public Javadoc validation in the same acceptance lifecycle.
  • Add an accepted availability ADR with a startup/liveness/readiness Kubernetes example and APA 7th references to official Kubernetes and version-aligned Spring Boot 3.5.16 documentation.
  • Make exact-head coverage, Javadoc, CI, security, static-analysis, fuzz, and repository-policy requirements authoritative in the engineering acceptance criteria.
  • Align the buyer threat model with the shipped /healthz liveness and /readyz readiness roles and protect the terminology with executable documentation contract tests.
  • Redact rejected external path/query values in type-mismatch API error details while retaining the non-sensitive parameter name.
  • Serialize JVM-global security-provider mutation across coverage tests with one shared lock and JUnit resource boundary, restoring providers at their original positions.
  • Remove an unreachable null-secret branch after proving ConversionProperties normalizes null to its supported blank disabled value.
  • Correct public API Javadoc and align the architecture map with the authoritative verify merge-evidence command.
  • Update README, root and detailed architecture maps, engineering acceptance criteria, CLAUDE.md, and CHANGELOG.md.

Test-first and review evidence

The red commit d39551d104fc918664c3d1aac0e7f2be3d05dbcb contained only the desired availability-contract tests. CI run 30977698977, Maven job 92215161701, failed at test compilation because production HealthController did not yet accept ApplicationAvailability.

The minimal production implementation at 25ea732d901bc64da9c17a6cfe9d6999d6c8d6a3 made those tests pass. CI run 30977769822 executed 438 tests with zero failures, errors, or skips and reported BUILD SUCCESS.

When the acceptance lifecycle was strengthened from mvn test to mvn verify, exact head c067b974db1ce2f720abab658025a05878a743a9 correctly failed on one uncovered production line and three uncovered branches. The subsequent changes removed unreachable filename and configuration branches and added executable fail-closed edge tests.

CodeRabbit review on 1645ba381dfa41f5793e0af8d97923f805662bd7 identified four valid findings: rejected external values were reflected in error payloads, one public field Javadoc overstated normalization, a mock bypassed the real configuration contract, and two tests used independent locks while mutating one JVM-global provider registry. Exact current head 8d7c55d94c40689ff28f45c787c77c31fa5e1c98 addresses all four findings. Every corresponding review thread is resolved.

The intermediate head 72d9e14b7d7526e7fd040d25c3a4166b0ebbf064 ran all 452 tests successfully but correctly failed the zero-missed-branch JaCoCo gate because the invalid mock test had been removed while its unreachable production null branch remained. The exact current head removes only that unreachable branch and preserves the supported blank-secret fail-closed behavior.

Exact-head evidence

Exact current head 8d7c55d94c40689ff28f45c787c77c31fa5e1c98 is mergeable against protected main and has successful same-head technical evidence:

  • CI run 30988328363: Maven verify and buyer-readiness script jobs succeeded.
  • Maven verification executed 452 tests with zero failures, errors, or skips and passed the zero-missed-line and zero-missed-branch JaCoCo gates plus warning-free public Javadoc validation.
  • Security Scan run 30988328479: succeeded.
  • SAST Semgrep run 30988329094: succeeded.
  • fuzz run 30988328476: succeeded.
  • Exact-head CodeRabbit commit status: succeeded.
  • Review threads: zero unresolved.

No queued, pending, cancelled, stale-head, or skipped-required result is counted as passing.

Merge gate and ordering

Keep this pull request draft while authoritative privacy-and-Netty parent #270 remains unmerged. #270 must integrate first; this change must then be reconciled and revalidated against the resulting protected main exact head because both slices touch shared production code, documentation, tests, and acceptance infrastructure. After reconciliation, require fresh exact-head CI, Security Scan, SAST, every fuzz matrix job, CodeRabbit, Strix/OpenCode/Noema review, zero unresolved threads, and an independent approving review from a reviewer whose repository permission GitHub counts. Do not bypass branch protection, weaken tests, or treat advisory bot review as counted approval.

@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

HealthController가 liveness와 readiness 프로브를 분리합니다. Maven 검증에 JaCoCo와 Javadoc 게이트를 추가합니다. 문서 계약과 보안·저장소·파일명 경계 테스트를 확장하고 공개 API 문서와 기본 생성자를 보강합니다.

Changes

가용성 프로브 계약과 구현

Layer / File(s) Summary
프로브 엔드포인트와 운영 계약
src/main/java/.../controller/HealthController.java, src/test/java/.../controller/HealthControllerTest.java, docs/operations/*, README.md, docs/architecture.md, ARCHITECTURE.md, CHANGELOG.md, docs/security/*, scripts/test_documentation_contracts.py
/healthzLivenessState를 사용하고 /readyzReadinessState를 사용합니다. 각 상태에 따라 200 또는 503과 제한된 JSON 응답을 반환합니다. 두 응답에 Cache-Control: no-store를 적용합니다.

Maven verify 품질 게이트

Layer / File(s) Summary
커버리지·Javadoc 검증
.github/workflows/ci.yml, pom.xml, docs/engineering/acceptance-criteria.md, CLAUDE.md
CI가 mvn verify를 실행합니다. JaCoCo 라인·분기 누락과 Javadoc 오류를 빌드 실패로 처리합니다. 실패 시 JaCoCo 보고서에서 누락 위치를 출력합니다.

경계 조건 회귀 테스트

Layer / File(s) Summary
보안·저장소·파일명 경계 테스트
src/test/java/.../artifact/*, src/test/java/.../config/*, src/test/java/.../controller/*, src/test/java/.../repository/*, src/test/java/.../service/*, src/main/java/.../controller/ConversionController.java
파일명 정제, null byte 거부, SHA-256 제공자 부재, 로그 구분자, 정책 시크릿 정규화, 아티팩트 삭제, 테넌트 범위 삭제를 검증합니다.

공개 API 문서와 기본 생성자

Layer / File(s) Summary
Javadoc 및 명시적 생성자
src/main/java/com/clearfolio/viewer/{api,artifact,auth,config,controller,exception,model,repository,service}/*, src/main/java/com/clearfolio/viewer/ClearfolioViewerApplication.java
공개 응답·예외·설정·서비스 구성 요소의 Javadoc을 확장합니다. 여러 Spring 구성 요소와 저장소에 동작 없는 public 기본 생성자를 추가합니다.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant ProbeClient
  participant HealthController
  participant ApplicationAvailability
  ProbeClient->>HealthController: GET /healthz 또는 /readyz
  HealthController->>ApplicationAvailability: 가용성 상태 조회
  ApplicationAvailability-->>HealthController: LivenessState 또는 ReadinessState
  HealthController-->>ProbeClient: 200/503 응답과 no-store 캐시 정책
Loading

Possibly related PRs

  • ContextualWisdomLab/clearfolio#165: ConversionProperties와 정책·보안 검증 테스트를 공유하지만, 이 변경은 주로 커버리지와 생성자를 추가합니다.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 38.46% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 제목은 /healthz/readyz 프로브를 분리하는 PR의 주요 변경 사항을 정확하고 간결하게 설명합니다.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/liveness-readiness-probes

Comment @coderabbitai help to get the list of available commands.

Copy link
Copy Markdown
Collaborator Author

@opencode-agent @cwl-noema-review Please independently inspect exact current head 787d8a250cc8b2bbb55242f166a0d7f5bdc804c3 while the final fuzz matrix completes. Verify the liveness/readiness semantic split against the Spring Boot 3.5 ApplicationAvailability contract and Kubernetes startup/liveness/readiness guidance; check that unauthenticated probe responses expose only controlled labels and are non-cacheable; validate the red-green test evidence, public Javadocs, Markdown/APA 7 documentation, 100% production line and branch coverage, and repository-policy compliance. Do not approve or recommend merge unless every exact-head required check, including all fuzz matrix jobs, is successful. Any review is advisory unless the reviewer identity has repository write permission.

Copy link
Copy Markdown
Collaborator Author

@coderabbitai review

Review exact current head 787d8a250cc8b2bbb55242f166a0d7f5bdc804c3. Verify the executable availability semantics, controlled unauthenticated response surface, no-store policy, startup/liveness/readiness deployment guidance, Spring Boot 3.5.16 alignment, APA 7 documentation, public Javadocs, and test completeness. Treat all three exact-head fuzz jobs, CI, Security Scan, and SAST as required evidence. Report any unresolved blocker; do not treat this request as independent write-permission approval.

@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown

@seonghobae I will review exact head 787d8a250cc8b2bbb55242f166a0d7f5bdc804c3.

I will treat CI, Security Scan, SAST, and all three fuzz jobs as required evidence. I will report unresolved blockers. I will not approve or recommend merge unless every required exact-head check succeeds.

⚠️ Action not completed

Review rate limited.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown
Collaborator Author

@coderabbitai review

Re-review exact current head 1c34120e6320c932565aacbdb3878e5d039f7095. The prior valid threat-model finding is addressed: the security threat model now distinguishes process liveness at /healthz from traffic readiness at /readyz, and scripts/test_documentation_contracts.py prevents that terminology from regressing without relying on brittle exact prose. Red evidence is CI run 30982831869, buyer-readiness job 92230813200; the replacement exact-head script job 92231770447 is green. Verify the current code, documentation, 451-test Maven acceptance gate, zero missed production lines/branches, warning-free public Javadocs, Security Scan, SAST, and all three fuzz matrix jobs. Treat queued or pending checks as not passing and report only current actionable blockers. This automated review is not independent write-authorized approval.

Copy link
Copy Markdown
Collaborator Author

@opencode-agent @cwl-noema-review Independently review exact current head 1c34120e6320c932565aacbdb3878e5d039f7095. Validate the corrected security threat-model terminology and its regression test, executable liveness/readiness semantics, non-cacheable controlled probe responses, Kubernetes startup/liveness/readiness guidance, Spring Boot 3.5.16 and APA 7 source alignment, zero missed production lines/branches, warning-free public Javadocs, and exact-head CI/Security/SAST/fuzz evidence. Distinguish current findings from stale superseded heads. Do not approve or recommend merge while any exact-head check is pending, and note that automated review does not satisfy independent write-authorized approval.

@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown
🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

repo="ContextualWisdomLab/clearfolio"
expected="1c34120e6320c932565aacbdb3878e5d039f7095"

echo "== Revision identity =="
printf 'checked_out='; git rev-parse HEAD
printf 'expected='; printf '%s\n' "$expected"
git status --short

echo "== Exact-head pull request checks and reviews =="
gh pr view 265 --repo "$repo" \
  --json number,headRefOid,isDraft,reviewDecision,statusCheckRollup,reviews \
  --jq '{
    number, headRefOid, isDraft, reviewDecision,
    checks: [.statusCheckRollup[] | {name,status,conclusion,detailsUrl}],
    reviews: [.reviews[] | {author:.author.login,state,commit:.commit.oid}]
  }'

echo "== Candidate files =="
fd -t f . | rg '(^|/)(HealthController|HealthControllerTest|SecurityConfig|.*Security.*Config|test_documentation_contracts|pom|README|CHANGELOG|.*availability-probes|.*threat-model.*)\.(java|py|xml|md)$|(^|/)pom\.xml$' || true

echo "== Availability controller and tests =="
controller="$(fd -t f -e java 'HealthController.java' src | head -n1)"
testfile="$(fd -t f -e java 'HealthControllerTest.java' src | head -n1)"
printf 'controller=%s\ntest=%s\n' "$controller" "$testfile"
test -n "$controller" && sed -n '1,260p' "$controller"
test -n "$testfile" && sed -n '1,360p' "$testfile"

echo "== Probe authorization rules =="
rg -n -C 5 --glob '*.java' '(pathMatchers|authorizeExchange|permitAll|healthz|readyz)' src/main/java

echo "== Maven acceptance gates =="
sed -n '1,360p' pom.xml | rg -n -C 5 '(jacoco|javadoc|doclint|failOnWarnings|verify|check)'

echo "== Operations and security documentation =="
for file in \
  "$(fd -t f -e md . docs | rg 'availability-probes\.md$' | head -n1)" \
  "$(fd -t f -e md . docs | rg 'threat-model-data-handling\.md$' | head -n1)" \
  "$(fd -t f -e py 'test_documentation_contracts.py' scripts | head -n1)"
do
  if test -n "$file"; then
    echo "--- $file ---"
    sed -n '1,340p' "$file"
  fi
done

echo "== PR change scope =="
git diff --name-status origin/main...HEAD

Length of output: 53437


@seonghobae Review of exact head 1c34120e6320c932565aacbdb3878e5d039f7095 found two current blockers.

  1. src/test/java/com/clearfolio/viewer/controller/HealthControllerTest.java checks only $.status. It does not verify that the response body contains no additional properties. The implementation currently returns only {"status": ...}, but the test suite does not protect the controlled unauthenticated response surface from later expansion. Assert the complete JSON body for all four state cases.

  2. Required exact-head checks remain incomplete. The following checks are IN_PROGRESS:

    • fuzz (ArtifactTokenParserFuzzTest)
    • fuzz (DocumentValidationFuzzTest)
    • fuzz (TenantClaimsFuzzTest)
    • Analyze (java-kotlin)
    • strix

Maven verify and the buyer-readiness script tests succeeded on the exact head. The current code separates LivenessState at /healthz from ReadinessState at /readyz. Both probe responses use Cache-Control: no-store. The threat model now has the correct liveness and readiness terms. The documentation contract test protects this distinction.

Do not approve or merge until the response-body regression coverage is complete and every required exact-head check succeeds. This automated review is advisory and is not an independent write-authorized approval.

⚠️ Action not completed

Review rate limited.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@seonghobae
seonghobae marked this pull request as ready for review August 5, 2026 07:00
@seonghobae
seonghobae enabled auto-merge (squash) August 5, 2026 07:00

Copy link
Copy Markdown
Collaborator Author

@opencode-agent @cwl-noema-review @coderabbitai Please review exact current head 1c34120e6320c932565aacbdb3878e5d039f7095. Verify the /healthz liveness and /readyz traffic-readiness separation, Spring Boot availability-state mapping, Cache-Control: no-store, controlled unauthenticated response surface, fail-fast dependency construction, zero missed production lines/branches, warning-free public Javadocs, Kubernetes/ADR/threat-model consistency, successful exact-head CI/Security/SAST/fuzz, and zero unresolved findings.

@seonghobae
seonghobae marked this pull request as draft August 5, 2026 07:01
auto-merge was automatically disabled August 5, 2026 07:01

Pull request was converted to draft

@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

repo="ContextualWisdomLab/clearfolio"
expected="1c34120e6320c932565aacbdb3878e5d039f7095"

echo "== Revision identity =="
printf 'checked_out='; git rev-parse HEAD
printf 'expected='; printf '%s\n' "$expected"
git status --short

echo "== Exact-head PR checks and unresolved review state =="
gh pr view 265 --repo "$repo" \
  --json headRefOid,isDraft,reviewDecision,statusCheckRollup,reviews \
  --jq '{
    headRefOid, isDraft, reviewDecision,
    checks: [.statusCheckRollup[] | {name,status,conclusion,detailsUrl}],
    reviews: [.reviews[] | {author:.author.login,state,commit:.commit.oid}]
  }'

echo "== Target source/test/documentation files =="
fd -t f -e java 'HealthController.java' src
fd -t f -e java 'HealthControllerTest.java' src
fd -t f -e java . src/main | xargs -r ast-grep outline --items all --type class,method --match 'HealthController|Security|Availability' || true
fd -t f -e md . docs | rg '(availability-probes|threat-model-data-handling)\.md$'
fd -t f -e py 'test_documentation_contracts.py' scripts

echo "== Probe implementation and tests =="
for f in \
  "$(fd -t f -e java 'HealthController.java' src | head -n1)" \
  "$(fd -t f -e java 'HealthControllerTest.java' src | head -n1)"
do
  test -z "$f" || { echo "--- $f ---"; sed -n '1,340p' "$f"; }
done

echo "== Probe authorization configuration =="
rg -n -C 5 --glob '*.java' '(pathMatchers|authorizeExchange|permitAll|healthz|readyz)' src/main/java

echo "== Verify, JaCoCo, and Javadoc gates =="
rg -n -C 8 --glob 'pom.xml' '(jacoco|javadoc|doclint|failOnWarnings|<phase>verify</phase>|<goal>check</goal>)' pom.xml

echo "== Operations, threat-model, and documentation contract =="
for f in \
  "$(fd -t f -e md . docs | rg 'availability-probes\.md$' | head -n1)" \
  "$(fd -t f -e md . docs | rg 'threat-model-data-handling\.md$' | head -n1)" \
  "$(fd -t f -e py 'test_documentation_contracts.py' scripts | head -n1)"
do
  test -z "$f" || { echo "--- $f ---"; sed -n '1,360p' "$f"; }
done

echo "== Availability terminology in changed Markdown =="
git diff --name-only origin/main...HEAD -- '*.md' | while IFS= read -r f; do
  rg -n -i -C 2 '(healthz|readyz|liveness|readiness|startupProbe|Spring Boot 3\.5\.16|APA)' "$f" || true
done

Length of output: 72140


🏁 Script executed:

#!/bin/bash
set -euo pipefail

repo="ContextualWisdomLab/clearfolio"
requested="1c34120e6320c932565aacbdb3878e5d039f7095"
current="1645ba381dfa41f5793e0af8d97923f805662bd7"

echo "== Requested commit identity =="
git show -s --format='commit=%H%nparents=%P%nsubject=%s%ncommitter=%cI' "$requested"

echo "== Requested-commit check runs =="
gh api "repos/$repo/commits/$requested/check-runs?per_page=100" \
  --jq '[.check_runs[] | {name,status,conclusion,details_url,started_at,completed_at}]'

echo "== Requested-commit combined status =="
gh api "repos/$repo/commits/$requested/status" \
  --jq '{state, statuses:[.statuses[] | {context,state,target_url,updated_at}]}'

echo "== Relevant files at requested commit =="
for path in \
  src/main/java/com/clearfolio/viewer/controller/HealthController.java \
  src/test/java/com/clearfolio/viewer/controller/HealthControllerTest.java \
  docs/operations/2026-08-05-availability-probes.md \
  docs/security/2026-07-02-threat-model-data-handling.md \
  scripts/test_documentation_contracts.py \
  pom.xml
do
  echo "--- $path @ $requested ---"
  git show "$requested:$path" | sed -n '1,360p'
done

echo "== Change from requested commit to current PR head =="
git diff --stat "$requested..$current"
git diff --name-status "$requested..$current"
git diff -- "$requested..$current" \
  src/main/java/com/clearfolio/viewer/controller/HealthController.java \
  src/test/java/com/clearfolio/viewer/controller/HealthControllerTest.java \
  docs/operations/2026-08-05-availability-probes.md \
  docs/security/2026-07-02-threat-model-data-handling.md \
  scripts/test_documentation_contracts.py \
  pom.xml || true

Length of output: 54014


@seonghobae Review of requested commit 1c34120e6320c932565aacbdb3878e5d039f7095 found two blockers.

  1. src/test/java/com/clearfolio/viewer/controller/HealthControllerTest.java verifies only $.status for each probe response. It does not verify that the unauthenticated body has no additional fields. The implementation currently returns only the controlled status label, but the test does not prevent a later addition of tenant, dependency, exception, or other detail. Assert the complete JSON body for all four state cases.

  2. The required strix check for the requested commit was cancelled. Do not treat this as successful exact-head evidence. Do not approve or merge this commit until strix completes successfully.

The remaining requested contract is correct at this commit:

  • /healthz uses LivenessState and returns ok or broken.
  • /readyz uses ReadinessState and returns ready or not_ready.
  • Both routes set Cache-Control: no-store.
  • The constructor fails fast when ApplicationAvailability is absent.
  • The ADR, Kubernetes example, threat model, and documentation contract test use consistent liveness and readiness roles.
  • Maven verify, all three fuzz jobs, SAST, and the listed security jobs succeeded.
  • pom.xml binds zero missed JaCoCo production lines and branches, plus warning-failing public Javadoc generation, to verify.

The PR has since advanced to 1645ba381dfa41f5793e0af8d97923f805662bd7. That later commit changes the response tests to assert complete JSON strings, but its required checks were still in progress at inspection time. This review is advisory and is not an independent write-authorized approval.

You are interacting with an AI system.

Copy link
Copy Markdown
Collaborator Author

@coderabbitai review

Re-review exact current head 1645ba381dfa41f5793e0af8d97923f805662bd7. The valid prior blocker is addressed: all four availability scenarios now assert the complete JSON payload by exact response-body equality, so no additional fields can be introduced without failing tests. The prior exact-head check-latency warning is superseded. Current exact-head evidence is CI 30983390425 (Maven job 92232587801, buyer-readiness job 92232587740), Security Scan 30983390474, SAST Semgrep 30983390391, and fuzz 30983390457; all completed successfully. Maven verified 451 tests with zero failures/errors/skips, 57 production classes with zero missed lines/branches, warning-free public Javadocs, and BUILD SUCCESS. Review only current code and report actionable blockers; this automated review is not independent write-authorized approval.

Copy link
Copy Markdown
Collaborator Author

@opencode-agent @cwl-noema-review Independently review exact current head 1645ba381dfa41f5793e0af8d97923f805662bd7. Verify that every liveness/readiness status now has an exact complete-payload assertion, the threat model and regression contract distinguish /healthz liveness from /readyz readiness, probe responses remain controlled and non-cacheable, Kubernetes and Spring Boot 3.5.16 guidance remains accurate, and exact-head CI 30983390425, Security 30983390474, SAST 30983390391, and fuzz 30983390457 are successful. Distinguish current findings from stale/superseded heads. Do not treat automated review as independent write-authorized approval; this draft must remain blocked until critical parent/security ordering and protected-branch approval requirements are satisfied.

@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown
🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

repo="ContextualWisdomLab/clearfolio"
expected="1645ba381dfa41f5793e0af8d97923f805662bd7"

echo "== Commit identity =="
printf 'checked_out='; git rev-parse HEAD
printf 'expected='; printf '%s\n' "$expected"
git show -s --format='subject=%s%ncommitted=%cI' "$expected"
git status --short

echo "== Exact-commit checks and combined statuses =="
gh api "repos/$repo/commits/$expected/check-runs?per_page=100" \
  --jq '[.check_runs[] | {name,status,conclusion,details_url,completed_at}]'
gh api "repos/$repo/commits/$expected/status" \
  --jq '{state,statuses:[.statuses[] | {context,state,target_url,updated_at}]}'

echo "== Pull request head and unresolved review threads =="
gh pr view 265 --repo "$repo" \
  --json headRefOid,isDraft,reviewDecision,statusCheckRollup,reviews \
  --jq '{headRefOid,isDraft,reviewDecision,checks:[.statusCheckRollup[] | {name,status,conclusion}],reviews:[.reviews[] | {author:.author.login,state,commit:.commit.oid}]}'
gh api graphql -F owner="ContextualWisdomLab" -F name="clearfolio" -F number=265 -f query='
query($owner: String!, $name: String!, $number: Int!) {
  repository(owner: $owner, name: $name) {
    pullRequest(number: $number) {
      reviewThreads(first: 100) {
        nodes { isResolved comments(first: 1) { nodes { author { login } body path line } } }
      }
    }
  }
}' --jq '[.data.repository.pullRequest.reviewThreads.nodes[] | select(.isResolved == false)]'

echo "== Implementation, tests, and access control at exact commit =="
for path in \
  src/main/java/com/clearfolio/viewer/controller/HealthController.java \
  src/test/java/com/clearfolio/viewer/controller/HealthControllerTest.java \
  pom.xml \
  docs/operations/2026-08-05-availability-probes.md \
  docs/security/2026-07-02-threat-model-data-handling.md \
  scripts/test_documentation_contracts.py
do
  echo "--- $path ---"
  git show "$expected:$path" | sed -n '1,380p'
done

echo "== Authorization rules =="
git grep -n -C 5 -E '(healthz|readyz|pathMatchers|authorizeExchange|permitAll)' "$expected" -- 'src/main/java/**/*.java' || true

echo "== Changed paths at exact commit =="
git diff-tree --no-commit-id --name-status -r "$expected"

Length of output: 62612


@seonghobae Review of exact head 1645ba381dfa41f5793e0af8d97923f805662bd7 found one current blocker.

  • The required exact-head strix check is still IN_PROGRESS. Both the commit check-runs API and the PR status rollup report this state. Do not approve or merge until strix completes with success.

The prior test-coverage blocker is addressed. HealthControllerTest now asserts the complete JSON body for all four availability cases.

The current implementation is otherwise consistent with the requested contract:

  • /healthz maps LivenessState.CORRECT to 200 {"status":"ok"} and other liveness states to 503 {"status":"broken"}.
  • /readyz maps ReadinessState.ACCEPTING_TRAFFIC to 200 {"status":"ready"} and other readiness states to 503 {"status":"not_ready"}.
  • Both probes set Cache-Control: no-store.
  • The controller rejects a missing ApplicationAvailability provider.
  • The ADR, threat model, and documentation contract test use the correct liveness and readiness roles.
  • mvn verify permanently enforces zero missed production lines and branches, plus warning-free public Javadocs.
  • Maven verify, buyer-readiness, Security Scan, SAST, CodeQL, and all three fuzz jobs succeeded for this commit.
  • GitHub reports no unresolved review threads.

This review is advisory. It is not an independent write-authorized approval.

⚠️ Action not completed

Review rate limited.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@seonghobae
seonghobae marked this pull request as ready for review August 5, 2026 07:04
@seonghobae
seonghobae enabled auto-merge (squash) August 5, 2026 07:04
@seonghobae
seonghobae marked this pull request as draft August 5, 2026 07:04
auto-merge was automatically disabled August 5, 2026 07:04

Pull request was converted to draft

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
ARCHITECTURE.md (1)

67-72: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

운영 게이트를 verify 계약과 일치시키십시오.

이 목록은 mvn test와 독립 Javadoc 명령을 게이트로 제시합니다. 그러나 현재 수용 기준은 mvn -B --no-transfer-progress verify만 완전한 병합 증거로 허용합니다. 이 목록을 verify 명령과 그 안의 JaCoCo 및 Javadoc 게이트로 변경하십시오.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ARCHITECTURE.md` around lines 67 - 72, Update the build and test gates
section in ARCHITECTURE.md to identify `mvn -B --no-transfer-progress verify` as
the single complete merge-evidence command, and describe the JaCoCo and JavaDoc
gates as checks executed within that verify lifecycle. Remove the standalone
`mvn test` and independent Javadoc command entries while retaining the Markdown
lint requirement for changed documentation.
🧹 Nitpick comments (1)
src/test/java/com/clearfolio/viewer/controller/ApiExceptionHandlerCoverageTest.java (1)

14-23: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

차단 범위 안쪽 문자에 대한 검증도 추가하십시오.

현재 테스트는 U+202F가 보존되는 것만 확인합니다. 이 단방향 경계 검증은 sanitizeForLog가 전혀 치환하지 않도록 회귀해도 통과합니다. 보안 정제 경로에는 차단 범위 안쪽 문자가 실제로 치환되는지도 확인해야 합니다. DefaultDocumentValidationCoverageTest의 line 86과 동일한 양방향 검증 방식을 적용하십시오.

♻️ 제안 변경
-        String sanitized = (String) method.invoke(handler, "\u202F");
-
-        assertEquals("\u202F", sanitized);
+        assertEquals("\u202F", (String) method.invoke(handler, "\u202F"));
+        assertEquals("_", (String) method.invoke(handler, "\u202E"));
+        assertEquals("__", (String) method.invoke(handler, "\r\n"));

위 기대값은 ApiExceptionHandler.sanitizeForLog의 치환 문자에 맞추어 조정하십시오.

As per coding guidelines: "Tests must exercise real behavior, including failure, security, concurrency, and recovery paths; coverage-only assertions must represent a valid contract."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/test/java/com/clearfolio/viewer/controller/ApiExceptionHandlerCoverageTest.java`
around lines 14 - 23, Extend
logSanitizationPreservesTheCodePointImmediatelyAfterTheBlockedRange to also pass
a code point inside sanitizeForLog’s blocked range and assert that it is
replaced with the sanitizer’s configured replacement character, while retaining
the existing U+202F preservation assertion. Mirror the two-sided validation used
by DefaultDocumentValidationCoverageTest.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/main/java/com/clearfolio/viewer/api/ApiErrorResponse.java`:
- Around line 10-14: Update ApiExceptionHandler.handleTypeMismatch so failed
UUID and Boolean conversion inputs are not copied directly into
details["value"]; redact them or include them only through an appropriate
allowlist, preserving ApiErrorResponse’s contract that details contain no secret
values.

In
`@src/main/java/com/clearfolio/viewer/exception/UnsupportedDocumentFormatException.java`:
- Line 10: Update the Javadoc for the extension field in
UnsupportedDocumentFormatException to describe it as the blocked extension
supplied to the constructor, replacing the inaccurate “Normalized extension”
wording. Keep the constructor’s behavior of storing the input unchanged.

In
`@src/test/java/com/clearfolio/viewer/service/DefaultDocumentValidationCoverageTest.java`:
- Around line 89-118: Replace the class-private SECURITY_PROVIDERS_LOCK in
src/test/java/com/clearfolio/viewer/service/DefaultDocumentValidationCoverageTest.java:89-118
with the shared test lock, and add
`@ResourceLock`("java.security.Security.providers") to serialize access. Apply the
same shared lock and resource annotation in
src/test/java/com/clearfolio/viewer/controller/ConversionControllerCoverageTest.java:57-92,
extracting the duplicated sha256ProviderPositions and ProviderPosition helpers
into the shared test utility.
- Around line 33-38: Update
rejectsANullPolicySecretSuppliedByAnExternalConfigurationSource and its
JavaDoc/name to reflect the actual ConversionProperties contract, since
getPolicyOverrideSecret() normalizes null to "". Remove the mock-based null
getter scenario or change the test to verify the supported default/normalization
behavior; only add a production configuration path if null is genuinely valid
there.

---

Outside diff comments:
In `@ARCHITECTURE.md`:
- Around line 67-72: Update the build and test gates section in ARCHITECTURE.md
to identify `mvn -B --no-transfer-progress verify` as the single complete
merge-evidence command, and describe the JaCoCo and JavaDoc gates as checks
executed within that verify lifecycle. Remove the standalone `mvn test` and
independent Javadoc command entries while retaining the Markdown lint
requirement for changed documentation.

---

Nitpick comments:
In
`@src/test/java/com/clearfolio/viewer/controller/ApiExceptionHandlerCoverageTest.java`:
- Around line 14-23: Extend
logSanitizationPreservesTheCodePointImmediatelyAfterTheBlockedRange to also pass
a code point inside sanitizeForLog’s blocked range and assert that it is
replaced with the sanitizer’s configured replacement character, while retaining
the existing U+202F preservation assertion. Mirror the two-sided validation used
by DefaultDocumentValidationCoverageTest.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: bcc1d0d4-ad1c-497c-8840-34cc9759a24a

📥 Commits

Reviewing files that changed from the base of the PR and between f3cc09a and 1645ba3.

📒 Files selected for processing (44)
  • .github/workflows/ci.yml
  • ARCHITECTURE.md
  • CHANGELOG.md
  • CLAUDE.md
  • README.md
  • docs/architecture.md
  • docs/engineering/acceptance-criteria.md
  • docs/operations/2026-08-05-availability-probes.md
  • docs/security/2026-07-02-threat-model-data-handling.md
  • pom.xml
  • scripts/test_documentation_contracts.py
  • src/main/java/com/clearfolio/viewer/ClearfolioViewerApplication.java
  • src/main/java/com/clearfolio/viewer/api/AdminJobListResponse.java
  • src/main/java/com/clearfolio/viewer/api/ApiErrorResponse.java
  • src/main/java/com/clearfolio/viewer/api/ConversionJobStatusResponse.java
  • src/main/java/com/clearfolio/viewer/api/SubmitConversionResponse.java
  • src/main/java/com/clearfolio/viewer/api/ViewerBootstrapResponse.java
  • src/main/java/com/clearfolio/viewer/artifact/ArtifactLinkService.java
  • src/main/java/com/clearfolio/viewer/artifact/ArtifactTokenException.java
  • src/main/java/com/clearfolio/viewer/artifact/InMemoryArtifactStore.java
  • src/main/java/com/clearfolio/viewer/auth/TenantContext.java
  • src/main/java/com/clearfolio/viewer/config/ArtifactStoreConfig.java
  • src/main/java/com/clearfolio/viewer/config/ArtifactStoreProperties.java
  • src/main/java/com/clearfolio/viewer/config/ConversionExecutorConfig.java
  • src/main/java/com/clearfolio/viewer/config/ConversionProperties.java
  • src/main/java/com/clearfolio/viewer/config/ViewerSecurityHeadersWebFilter.java
  • src/main/java/com/clearfolio/viewer/controller/ApiExceptionHandler.java
  • src/main/java/com/clearfolio/viewer/controller/ConversionController.java
  • src/main/java/com/clearfolio/viewer/controller/HealthController.java
  • src/main/java/com/clearfolio/viewer/controller/ViewerUiController.java
  • src/main/java/com/clearfolio/viewer/exception/UnsupportedDocumentFormatException.java
  • src/main/java/com/clearfolio/viewer/model/ConversionJobStatus.java
  • src/main/java/com/clearfolio/viewer/repository/InMemoryConversionJobRepository.java
  • src/main/java/com/clearfolio/viewer/service/DefaultConversionWorker.java
  • src/main/java/com/clearfolio/viewer/service/DefaultDocumentConversionService.java
  • src/test/java/com/clearfolio/viewer/artifact/FileSystemArtifactStoreCoverageTest.java
  • src/test/java/com/clearfolio/viewer/config/ConversionPropertiesCoverageTest.java
  • src/test/java/com/clearfolio/viewer/controller/ApiExceptionHandlerCoverageTest.java
  • src/test/java/com/clearfolio/viewer/controller/ConversionControllerCoverageTest.java
  • src/test/java/com/clearfolio/viewer/controller/HealthControllerTest.java
  • src/test/java/com/clearfolio/viewer/repository/InMemoryConversionJobRepositoryCoverageTest.java
  • src/test/java/com/clearfolio/viewer/service/DefaultDocumentConversionServiceCoverageTest.java
  • src/test/java/com/clearfolio/viewer/service/DefaultDocumentValidationCoverageTest.java
  • src/test/java/com/clearfolio/viewer/service/DocumentConversionServiceCoverageTest.java

Comment thread src/main/java/com/clearfolio/viewer/api/ApiErrorResponse.java

Copy link
Copy Markdown
Collaborator Author

@opencode-agent Rebuild this bounded availability slice cleanly on authoritative parent #270 exact head 91091ddc212dac328ff36696f56c0a15c21407f4 instead of carrying the pre-parent main history. Preserve only the liveness/readiness contracts, cache-control behavior, redacted mismatch details, shared security-provider test serialization, executable documentation contracts, and their realistic tests. Reconcile shared pom.xml, CI, CHANGELOG.md, AGENTS.md, architecture/acceptance documents, public Javadocs, and security test utilities without dropping #270's audit-key, Netty/SBOM, filesystem TOCTOU, zero-coverage, or warning-free-Javadoc contracts. Do not add temporary/write-scoped workflows or import predecessor evidence. Keep the PR draft, run mvn -B --no-transfer-progress verify, and report the exact rebuilt head for fresh stack verification.

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