Appearance
休憩の扱い
労働基準法34条の休憩をどう記録し、どう検知し、どこまで自動化するかの設計です。
34条が求めていること
| 実労働時間 | 必要な休憩 |
|---|---|
| 6時間以下 | 不要 |
| 6時間超 | 45分以上 |
| 8時間超 | 60分以上 |
「超える」は厳密な超過です。実労働ちょうど6時間なら休憩義務は発生せず、8時間ちょうどなら45分で足ります。 判定に使う「労働時間」は実労働時間(休憩控除後)であって拘束時間ではありません。
さらに34条1項は休憩を労働時間の途中に与えることを求めています(勤務の先頭や末尾に付けるのは不可)。 KIZAMI は現時点でこの「途中付与」までは検知していません。
34条にはこのほか、一斉付与の原則(2項。事業場の労働者に休憩を一斉に与える。労使協定で例外可)と 自由利用の原則(3項。休憩時間を労働者が自由に利用できるようにする)がある。どちらも KIZAMI の検知対象外である — 休憩の「量」(時間数)は打刻・自動控除から機械的に判定できるが、 「一斉に与えたか」「自由に利用できたか」は打刻データだけからは判定できない運用上の事実だからである。
判定の単位は「勤怠日のチェーン」であって単独の勤務区間でも勤怠日そのものでもない(2026-08-23 改定)
34条は継続した勤務に対する義務です。日界をまたぐ夜勤を勤怠日で機械的に割ると、8時間の勤務が 「2時間の日」と「6時間の日」に分かれ、どちらも義務を免れます。これは実際に起きる見落としなので、 KIZAMI は出勤〜退勤の1まとまり(WorkStretch)を、その開始時刻(clockInAt)が属する勤怠日 ごとにまとめた「チェーン」単位で判定します。夜勤(例: 22:00出勤〜翌7:00退勤)の1区間はそもそも 分割の対象になる複数区間ではなく、開始日のチェーンに丸ごと属するため、この夜勤保護は 維持されます。
同一勤怠日に複数区間がある日(中抜け)は合算する
区間ごとに独立して判定すると過剰検知になります。「6時間半勤務 → 1.5時間の中抜け → 1時間勤務」 という1日は、最初の区間だけを見れば「6時間半・休憩0分」で違反に見えますが、中抜けの1.5時間は 労働から完全に解放された時間であり、打刻上「休憩」として記録されていないだけで実態としては 休憩の役割を果たしています。そこでチェーン内では
- 実労働 = チェーン内の各区間の
workedMinutes(自動控除適用後)の合計 - 休憩 = 打刻休憩の合計 + 自動控除(
breakRuleの auto/both。engine が合算して渡す)+ 区間と区間の間の空白(前の区間のclockOutAtから次の区間のclockInAtまでの分数)
を合算し、チェーンの実労働合計に対して法定要件(6時間超45分・8時間超60分)を適用します。
空白を数えるのは区間「の間」だけで、チェーン最後の区間の後(退勤後)の空白は数えません。 34条1項が求めるのは「労働時間の途中」に与える休憩であり、最後の区間の後は帰宅であって休憩では ないためです。この非対称性(間だけを数え、末尾の後は数えない)によって「途中に与える」という 要件を構造的に満たします(休憩の位置そのものまでは判定しない、というスコープ外の限界は変わりません)。
日をまたぐ空白(ある日の退勤〜翌日の出勤の間)はチェーン化の時点でそもそも発生しません。別の 勤怠日は別のチェーンだからです。これは意図的な設計で、勤務間インターバル(次の勤務までの 休息時間)を34条の休憩と混同しないためのものです。両者は法的に別概念であり、「翌日の勤務まで 12時間あったから今日の休憩は足りている」という判定は誤りになります。
自動控除の判定単位はチェーンにしない(非対称)
自動控除(auto-break.ts)の判定・控除は引き続き区間単位のままです。自動控除は「打刻が なくても休憩を取れたはず」とみなして実労働を機械的に削る危険な機能であり、控除の可否は 他区間の空白を借りずに各区間が単独で閾値を満たすかどうかで厳密に判定すべきだからです。
結果として、4時間+中抜け+4時間の日は各区間が閾値未満のためどちらにも自動控除はかからず (中抜けの空白そのものが休憩の役割を担っているため、それ以上機械的に削る必要がない)、 一方で休憩不足検知はチェーンで合算するため、その中抜けの空白はちゃんと休憩として算入されます。 「自動控除は保守的に区間単位・休憩不足検知は実態を捉えるためチェーン単位」という使い分けは、 それぞれ「過少申告の防止」「過剰検知の防止」という目的に応じた意図的な選択です。
未退勤の区間は判定しません。実労働がまだ確定していないためです。
自動控除をどう設計するか(2026-08-23 決定)
自動控除は「便利機能」ではなく危険な機能
所定の休憩時間を機械的に差し引く実装は、実際には休憩を取れなかった日にも差し引きます。 結果は労働時間の過少申告であり、サービス残業の温床として是正勧告の対象になりやすい箇所です。
したがって自動控除を入れるなら、本人が「取れなかった」と申告して打ち消せることが 機能の一部であって、後付けのオプションではありません。
打刻を生成する案は採らない
自動控除を source: "auto" の休憩打刻として punch_events に書けば、既存の修正申請フローが そのまま打ち消しに使えます。実装は最小で済みます。
それでもこの案は採りません。 punch_events が「実際に起きたこと」の記録である、という不変条件を 壊すためです。この不変条件は不可変監査ログの土台であり、KIZAMI が既存OSSに対して主張している 差別化点そのものです。推定値を事実の記録に混ぜると、監査証跡の意味が薄まります。
採る設計: 集計時に控除し、打ち消しは独立した申請
tenant_setting_versions.break_ruleに{ mode: "auto" | "both", rules: [...] }を追加するpunch— 打刻された休憩のみ控除(現行)auto— 打刻を無視し、実労働に応じた所定の休憩を控除both— 打刻された休憩を使い、法定の最低休憩に満たなければ差分を追加控除
- 集計エンジンが控除を行い、
DailyBreakdownに打刻由来と自動控除を分けて持たせる。 合算した1つの数字にしない — 本人が「これは自動で引かれた分だ」と気づけることが要件だから - 打ち消しは
auto_break_waivers(追記専用)への申請。correction_requestsはpunch_eventsに 強く結びついており、打刻の存在しない自動控除には使えないため、目的の異なる別テーブルにする (leave_requests/correction_requestsと同じ「追記専用の申請テーブル」の流儀) - 承認済みの打ち消し日は engine の入力に渡り、その日は自動控除しない
この形なら、設定は effective-dated の仕組みにそのまま乗り、過去期間へ遡及せず、 締め済み月はスナップショットで二重に保護されます(原則6)。
UI 上の扱い
自動控除された日は月次一覧でそれと分かる表示にします。休憩の数字を打刻由来と区別せずに 出すと、本人が打ち消すべき日に気づけません。控除された旨と、そこから打ち消し申請へ進む導線を 同じ場所に置きます。