シャットダウンを、待たないAIと「退勤打刻」を組み上げた半日のタイムライン
常駐している決裁通知クライアントに、PC起動=出勤・シャットダウン=退勤の打刻をやらせられないか。その一言から始まった半日を、提案・AIの回答・条件追加・実機試験での発見と改修まで、往復の順に記録した。ハートビート方式、操作ログの意外な転用、ネットワーク越しのIP食い違い。
いつもは完成したものの解説を書く。今日は趣向を変える。ひとつの機能が思いつきから現場に出せる形になるまでの往復を、そのまま記録に残す。私が何を要求し、AI が何を返し、実機の試験で何につまずき、どう直したか。半日の出来事を順に書く。
0. きっかけ — 「もう常駐しているのだから」
決裁通知クライアント(NgwNotificationClient)は、PC に常駐して NGW の通知を知らせる。ある日ふと思った。もう常駐しているのだから、これに勤怠の打刻もやらせられないか。起動したら出勤、シャットダウンしたら退勤。勤怠はいまも、その日最初のログインで出勤、ログアウトで退勤を記録している。だったら PC の電源そのものに合わせられないか。
1. 提案と、AIの最初の回答
私の要求は一行だ。「起動=出勤、シャットダウン=退勤の打刻はできないか」。
AI はまず現状を調べ、要点を返してきた。出勤はログイン時、退勤はログアウト時に記録している。起動時の出勤は簡単だ。だが退勤が難所だという。シャットダウンの瞬間にサーバへ通信を投げても、ネットワークはもう畳まれ始め、プロセスは OS に先に落とされる。間に合わない。
代わりに出してきたのがハートビート方式だった。
クライアントが一定間隔で「動いています」とサーバに伝える。その最後の一報が、シャットダウンの近似になる。退勤=その日の最後のハートビート、とすればいい。
シャットダウンを検知するのではなく、最後の稼働記録を退勤とみなす。 ここがこの機能のいちばんの発想の転換だった。
2. 条件を、少しずつ足していく
ここから、要求を継ぎ足す往復が続いた。
- 定時でない時に限る。 定時どおりなら、わざわざ記録しなくていい。
- ただし時間外勤務の申請がある日は、何もしない。 申請は前もって出ていることもある。申請が最優先だ。勝手に打刻して二重にしてはいけない。
- 勤怠管理を使っている団体だけ。 文書管理しか入れていない団体では動かさない。
- 登録した職員とは別の人がそのPCでNGWにログインしたら、利用者が変わったか尋ねる。 打刻が別人のものになっては困る。
AI はそのつど判定の順序を組み替えて返してきた。団体で使うかどうか、申請の有無、定時の取り方、利用者の交代検出。条件が増えるたびに設計が整理されていく。最終的には「申請が無ければ、起動と終了の実時刻をそのまま入れる」で単純化した。ルールは、足すよりも削って落ち着いた。
3. なりすましを、どう防ぐか — 操作ログの転用
勤怠は給与に直結する。だがクライアントは職員コードを名乗るだけで、パスワードは持たない。別人のコードを設定すれば、他人の勤怠を打ててしまう。 放置できない。
AI が目をつけたのは操作ログだった。もともと監査・調査用に、誰が・どの端末から・いつ操作したかを淡々と残していた記録だ。これをその職員がその端末を普段使っている証跡として転用する。過去にその端末から NGW にログインした実績がある職員のときだけ打刻し、実績が無ければ何もしない。なりすましの多くはこれで弾ける。
デバッグ用のつもりで仕込んだログが、認証の裏付けに化けた。そんな使い方は考えていなかった。正直うなった。
4. 実機試験 — つまずきと発見
ここからが本番だ。実機に入れ、サーバのログを見ながら試す。
つまずき①:打刻が通らない。 ログには「本人確認できず」でスキップ、と出続けた。職員コードは合っている。なのに弾かれる。AI が診断用のログを一行足して原因を可視化した。その職員の過去のログイン履歴の IP と、いま常駐ツールが名乗る IP が、まったくの別物だった。
種明かしはこうだ。試験は、その職員が普段いる場所とは違うネットワークから行っていた。しかも一般に、ブラウザはプロキシ経由、常駐ツールは直接と、経路が違えば同じ PC でもサーバから見える送信元 IP は食い違う。「同一PCなら同じIP」という素朴な前提が、環境の前で崩れていた。
対処は単純だった。その端末から一度、NGW にログインする。 履歴に正しい IP が刻まれ、次のハートビートで打刻が通った。カレンダーに、その日の出勤時刻がすっと入った。仕組みは正しかった。前提を環境に合わせるだけだった。(本番でこの照合が成立するかは、庁内ネットワークの経路しだいだ。そこは別途詰める宿題として残した。)
判断:負荷と、退勤の粒度。 退勤を毎分更新すると、稼働中はずっと退勤時刻が動いて見える。しかも通知(60秒間隔)に、打刻の問い合わせがもう一本増える。私は負荷を気にした。AI の答えは明快だった。「退勤の精度は分単位で十分。ハートビートだけ間引けばいい」。通知は60秒のまま、打刻は30分間隔へ。追加の負荷は数十分の一に落ちた。
ついでに定時の判定も外し、実時刻をそのまま残すことにした。するとおまけがついた。早退の時刻まで自然に拾える。 定時前に帰って PC を切れば、その最後のハートビートがそのまま退勤になるからだ。
つまずき②:利用者交代のあとの、通知の嵐。 別の職員に切り替えたら、その人の過去の回覧が一件ずつポップアップし始めた。画面の隅で通知がポン、ポン、ポンと積み上がっていく。起動直後の未読はまとめて既読扱いにする仕様のはずが、切替のときだけ抜けていた。
AI が追うと、原因は一点だった。切替後は次の巡回で新しい職員の未読をまとめて処理すべきなのに、その「初回まとめ」の合図が次の巡回へ引き継がれていなかった。 切替を検知したらその回はそこで打ち切り、合図を次へ渡す。数行の修正で嵐は止まった。切替のあと新しく届いた一件だけが、静かに通知された。
5. 仕上げ
あとは店じまいだ。調査用のデバッグログを止め、バージョンを上げ、完了メッセージを直し、配布物一式とマニュアルを整えた。朝の思いつきは、半日で現場に出せる機能になっていた。
6. 記事を書きながら、もう一手
ところが、この記事を書いている最中に引っかかった。「30分間隔で、実時刻をそのまま」。さっき、そう決めたばかりである。だがそれだと定時ちょうどに帰った人の退勤が取りこぼれる。 定時の終わりが17時15分でも、最後のハートビートが16時45分なら、退勤は16時45分。定時退勤が30分ぶん早まる。
タイムラインを見返す作業が、そのまま設計の見直しになった。手はふたつ打った。まずハートビートを5分間隔に詰める。 定期リクエストは増えるが、打刻は軽い問い合わせだ。ここは精度を取った。そのうえで定時の終わりの30分前を過ぎたら定時退勤とみなす。 定時の直前まで働いた人は、きっちり定時退勤で計上する。残業はこれまでどおり実時刻。そして30分を超える早退だけが、早退として実時刻で残る。
記事を書くつもりが、書きながら直していた。往復は、記事にしてもなお続いていたのである。
AIとの協働作業での学び
この半日、AI の働きは大きく二つだった。ひとつは発想の転換。「シャットダウンを検知する」を「最後の稼働記録を退勤とみなす」に置き換えたのは、私ひとりでは出てこなかった角度だ。もうひとつは執拗な地道さ。通らない打刻に診断ログを一行足し、IP の食い違いを突き止め、通知の嵐の原因を合図ひとつまで追い詰める。この根気を厭わない。
一方、現場を知っているのは人間だった。申請が最優先。団体で分ける。早退も拾いたい。要求のひとつひとつは、現場の手ざわりからしか出てこない。そして試験は、普段と違う場所でやると環境ごと結論が変わる。
AI が角度と根気を出し、人間が要求と現実を出す。 その往復のログが、そのままこの記事になった。今日いちばんの収穫は、機能そのものより、この往復が一本の記録として残せると分かったことかもしれない。……もっとも、記事を書きながら仕様を直す羽目になるとは思っていなかった。書くというのは、いちばん厳しいレビューである。