60歳になりました

10年前にとうとう50歳になってしまいました - 開発思考実験日記を書いてから10年、なんかいろいろなものが変わりました。

大きく変わったのはやはりLLMの登場で、GPT-3が僕が気になったのが2022年でここ数年で実用的なレベルに、さらにプログラム開発自体を根本的にかえるレベルになっていいます。この流れは今後も加速度的に変わるように思います。

この環境変化は僕的に非常に嬉しいというか第2次AI世代なのでその頃に夢見た世界が現実になり、ある意味僕のコンピュータ人生のクライマックス的なものを感じています。本当に僕の人生の中でコンピュータというものは中心的なもので、趣味や勉強、仕事、投資など生きていく上でのベースというか体の一部ようなものだったので、コンピュータの発展の完成形が見えつつある状況を重ねるとノスタルジーさえ感じています。

 

さて、前の記事からの10年間の振り返りもしておくと

新しいプロダクトでビジネスを目指していたけど結局それが実現せず、コンサルのサービスをベースに仕事をするようになりました。ま、楽な方に日和った感じです。

コンサルのサービスはアジャイルやリーンスタートアップの考え方を開発チームにトレーニングするような仕事でそれまでスタートアップを目指していた知識は役に立ちました。この仕事も割り面白く、あとなんか自分でスタートアップやっている感じがして、それでお腹いっぱいになったのかそれ以降は本気でサービスを興そうとかのパッションは小さくなっていった気がします。

それ以外は一応ビジネスマネージャもしていたので、ノーコード・ローコードのビジネスチャンスを考えPowerPlatformをやったりしました。この頃には趣味の自転車や投資などの方に興味が移ってきて仕事をこのまま続けるかを考え始めた時期でもありました。

そしてここ数年はビジネスマネージャを下ろしてもらって、技術支援的ポジションな仕事にさせてもらっています。生活面においても仕事をしない状態に向けてどのようにしていくか予行演習もしていました。仕事や趣味などの心地よい生活バランスを模索してきました。

今後も仕事は小さていいので続けていくのがバランスが良さそうなので続けて、残りは趣味を楽しみながら少し時間をゆっくり流れるように過ごしたいを思っています。

長年続く趣味として自転車の輪行旅行があって、最近は月1回ぐらいはどこかにいっています。体力が持つ限り続けたいと思っています。

あとは、LLMの登場で自分の今までの知識をAIエージェントにするのもライフワークとしていけたらと思っています。1回ぐらいは仕事で試したいのはありますが、しんどそうなので無理かな...

 

10年前の記事で「死ぬまでコード書けたら本望」と書いていましたが、今はコードはほぼLLMが書くようになって僕も定年を迎えて10年前に比べて大きく環境は変わりました。しかし、コンピュータを使って何かをしてきた人生はまだまだ続くんだと思っています。

10年後生きていたら続編を書きます

 

 

AIエージェントシステム開発とトレーサビリティ

AIエージェントによるシステム開発では、トレーサビリティが以前より大切になると思っています。

これまでのシステム開発でも、どの要求に基づいて実装し、どのように検証したのかを説明するために、トレーサビリティは必要でした。ただ、人手ですべての成果物を緻密につなぎ、変更のたびに更新するのはかなり難しかったと思います。

AIエージェントを使えば、成果物間の関係も記録させ、原資料から要求、設計、テスト、実行されたコード、検証結果、承認までをIDでつなげられます。さらに、そのつながりをハーネスでチェックすれば、変更後も追跡関係を維持できます。

トレーサビリティは、人間が説明責任を果たすための重要な仕組みです。同時に、AIエージェントが生成した成果物の抜けや不整合を確認する仕組みにもなる。この二つを実現できることが、大きなメリットだと思います。

AIに思考は外注できるが、理解は外注できない

最近、「AIに思考は外注できるが、理解は外注できない」という言葉を聞きました。

AIエージェントが開発する時代に技術者がシステム開発の技術を磨く意味はあるのか、 ということについて答えを持っていなかったのですが、 やはり技術は必要なんだと思いました。

 

今、AIエージェントを働かせるハーネスを作っていて、その改善もAI自身にやらせています。 これが結構うまくいっていて AIスゲー と素直に思うのですが、 改善を重ねるうちにどこが?良くなっているのかが、自分自身でもよく分からなくなってきました。 前より良い。だったら良いやん、とも思うのですが、内容を理解しなくてもいいのか?と不安になります。

 

コードのレベルで理解するのか、モデルのレベルで理解するのか、戦術や戦略のレベルで理解するのか。 その選択はあると思いまますがやっぱり理解は必要なんだと

「AIに思考は外注できるが、理解は外注できない」

今はこの言葉が、かなり腹落ちしています。

AIに「正しい業務システム」を作らせるには

[AIによる執筆注記] 生成AIを活用して執筆しています。内容の監修・確認は著者が行っています。

前回の引き続きAIを使った業務システムの開発について 実規模の勤怠管理システムを題材にしています。 1件の勤怠入力が、要件、業務モデル、画面、テスト、証跡へ変わっていく過程を、実在する成果物に沿って追いかけます。

はじめに

勤怠入力は、簡単な機能に見えます。

日付の行を選ぶ。

開始時刻と終了時刻を入力する。

別の行へ移動したら保存する。

これだけなら、すぐに作れそうです。

しかし、実際の業務では、ここから急に難しくなります。

提出済みの月は編集できません。

入力に問題があるなら、編集中の行から離れてはいけません。

エラーは画面上部ではなく、問題が起きた行に表示したい。

保存ボタンは置かず、行を離れた瞬間に保存したい。

しかも、保存に失敗したときは、入力前のデータを壊してはいけません。

ひとつひとつは小さな条件です。

ところが、この小さな条件が、要件書、画面、API、業務ロジック、テストへ別々に書かれ始めると、少しずつ意味がずれていきます。

画面では編集できそうに見えるのに、保存すると拒否される。

エラーメッセージは合っているのに、表示場所が違う。

テストは通っているのに、業務担当者が期待した動きではない。

業務システムで怖いのは、派手な障害だけではありません。

こうした小さなずれが積み重なり、誰も全体を説明できなくなることです。

では、どうすればよいのでしょうか。

今回は、山田太郎さんの「2026年7月3日の勤怠行」を1本の糸として追いかけます。

この1行が、要件の文章から実際に動く画面になるまでを見ていきます。

そして、その途中で現れる課題を、業務コンパイラがどう扱っているのかを確認します。


全体の流れと、人間が関わる場所

本題に入る前に、全体の流れを簡単に示しておきます。

業務コンパイラの開発は、おおまかに次の順で進みます。

  1. 人間が業務の要求を文章で書く
  2. AIが業務モデルと画面の契約を作る
  3. AIが日本語の検証シナリオを作る
  4. 別のAIがモデルとシナリオを疑いの目で読み直し、疑問点を人間への質問にまとめる
  5. 人間が承認する
  6. AIがテストと実装を作り、機械検査が通るまで直す
  7. 実ブラウザの E2E テストを流し、画面の証跡を残す
  8. 人間が最終確認して、出荷を判断する

このうち、人間が判断のために立ち止まるのは、原則として3つのゲートと、途中で出てくる質問への回答だけです。

業務ゲートでは、業務オーナーが業務マニュアルと検証シナリオを読み、「この業務で成立するか」を判断します。

技術ゲートでは、アーキテクトが方式設計書と ADR を読み、「この方式で作ってよいか」を判断します。

最終ゲートでは、検証レポートと画面証跡を確認し、「出荷してよいか」を判断します。

その間の工程——テストの生成、実装、機械検査、差し戻し——は、人間の承認を挟まずに自動で連鎖します。

機械検査が通らないとき、そして AI が判断に迷って質問を返したときだけ、工程が止まり、人間へ戻ってきます。

つまり人間の仕事は、コードを書くことでも、AIの出力を全部読むことでもありません。

業務の意味を最初に与えること。

そして、要所で判断を下すことです。

この記事で追いかける1件の勤怠入力も、この流れの上を通っていきます。


1. 課題: 最初からコードを書くと、業務の意味が見えなくなる

勤怠画面を作るとなると、すぐに画面やデータベースを考えたくなります。

テーブルには何列必要か。

API はどんな JSON を返すか。

React の state をどう持つか。

どれも必要な検討です。

しかし、最初にそれを考えると、ひとつ困ることがあります。

「そもそも、業務として何を実現したかったのか」が、技術の言葉に埋もれてしまうのです。

まず、業務の文章を書く

今回の出発点は、次の要求です。

他の行がクリックされたとき、またはタブ移動で行の外へフォーカスが出たとき、
その行の入力検査と保存を実行する。

保存に失敗した場合はフォーカス移動を取り消し、
エラーが解消するまで編集状態を維持する。

Esc を押すと編集を取り消して元の値に戻す。

保存ボタンは画面のどこにも置かない。

ここには、HTML も API もデータベースも登場しません。

書かれているのは、利用者から見た振る舞いだけです。

これなら、業務担当者も内容を判断できます。

「保存ボタンは必要なのではないか」

「提出済み月では、そもそも編集状態にしてよいのか」

「エラーのときに別の行へ移れてしまうと困る」

このような会話を、コードを読むことなく始められます。

どう対処しているのか

業務コンパイラでは、この文章を起点にします。

最初に書かれた要求は、原文のまま残します。

そして、後から作られるモデルには source_ref を持たせます。

つまり、モデル、画面、テストを見て疑問が出たとき、最初の要求へ戻れるようにしています。

ここで固定するのは、プログラムの形ではありません。

最初に固定するのは、業務上の意味です。

では次に、この文章をどのようにして、機械が扱える形へ変えるのでしょうか。


2. 課題: 文章だけでは、同じルールを何度も書くことになる

自然な文章は、人間には読みやすいものです。

一方で、文章だけでは機械が安定して扱えません。

「提出済みの月は編集できない」という一文を考えてみます。

この一文は、実装の中では何か所にも関係します。

保存処理で拒否する必要があります。

画面を編集可能にするかどうかにも関係します。

エラーメッセージにも関係します。

テストの期待結果にも関係します。

文章から人が読み取って、それぞれの場所へ書き写すと、少しずつ表現が変わります。

やがて、同じはずのルールが別々のルールになってしまいます。

ユースケースに名前を付ける

まず、利用者が何をしたいのかを、ユースケースとして定義します。

- id: UC-A001
  name: 日々の勤務時間を記録する
  actor: 利用者
  goal: 対象月の各日の出退勤と休憩と休暇種別を一覧の上で入力し、
        その月の勤怠を記録し終える

ここで重要なのは、UC-A001 という識別子です。

識別子があると、画面、シナリオ、テスト、証跡が、同じ業務を指していることを確認できます。

「勤務時間の画面のあれ」ではなく、「UC-A001 の話」と言えるようになります。

業務ルールを分けて定義する

今回の1行には、少なくとも2つのルールが効いています。

ひとつは、保存を許可するかどうかです。

- id: BR-M004
  name: 提出済みの月は編集できない
  expectation: 呼び出しを拒否し
               「提出済みの月は編集できません」を提示する

もうひとつは、エラーをどこに表示するかです。

- id: BR-P026
  name: 行インライン編集で発生したエラーは行内に表示する
  expectation: エラーを行内に表示し、
               共通のエラー領域は使わない

この2つは似ていますが、役割が違います。

BR-M004 は、業務として保存を許すかどうかを決めます。

BR-P026 は、拒否された結果を利用者へどう見せるかを決めます。

分けておけば、保存条件を変えずに表示方法だけを見直すこともできます。

逆に、表示方法を変えずに、保存条件だけを変えることもできます。

判定の順番も、業務ルールになる

1行を保存するときは、次の順番で確認します。

  1. 実行者に書き込み権限があるか
  2. 対象利用者が存在するか
  3. 対象月が提出済みではないか
  4. 入力値が正しいか

これは、単なる実装上の並びではありません。

たとえば、権限のない利用者に、対象ユーザーが存在するかどうかを先に教えてよいとは限りません。

どのエラーを先に返すかは、利用者への説明や情報の扱いに影響します。

そのため、判定順序も services.yaml に宣言します。

preconditions_expr:
  - predicate: can_write_work_records
  - exists: User
  - not: month_is_submitted
  - predicate: work_date_is_parsable

どう対処しているのか

業務の文章を、識別子の付いたモデルへ変換します。

文章は、人間が意味を確認するために残します。

式は、機械が実行コードを作るために使います。

同じ内容を、目的の違う2つの形で持つわけです。

ここまでで、業務の意味は整理できました。

しかし、次の疑問が出てきます。

この意味を、画面へどう運ぶのでしょうか。

画面を作る人が、また独自に解釈してしまわないでしょうか。


3. 課題: 画面を見た目だけで決めると、業務との接続が切れる

画面設計というと、レイアウトを思い浮かべます。

表をどこに置くか。

ボタンを何色にするか。

入力欄の幅をどうするか。

もちろん、見た目は大切です。

しかし、業務画面では、見た目だけでは足りません。

この入力欄は、どの業務サービスへ値を渡すのか。

別の行へ移動したとき、何が実行されるのか。

その操作は、どの条件で利用可能になるのか。

ここが曖昧だと、画面は動いていても、業務モデルとは別の世界になってしまいます。

画面を3つの契約に分ける

今回の画面は、次の3層に分けて定義します。

  • 遷移: どの操作が何を起こすか
  • 束縛: 画面の値をどのサービスへ渡すか
  • 配置: 何を、どのように並べるか

まず、行を離れたときの動きを定義します。

- from: SCR-A001
  trigger: row-commit:dailyRows
  fire: saveRow

これで、「別の行へ移動する」という画面操作が、saveRow という操作に結びつきます。

次に、値の行き先を定義します。

- id: saveRow
  service: SV-A005
  args:
    WorkRecord.WorkDate: dailyRows.committed.WorkDate
    WorkRecord.StartTime: dailyRows.committed.StartTime
    WorkRecord.EndTime: dailyRows.committed.EndTime

これで、画面の開始時刻と終了時刻が、どの業務サービスへ渡るのかが分かります。

最後に、一覧の意味を定義します。

- list: dailyRows
  title: 勤務時間記録
  editable: true
  editing: row

ここでは、まだ HTML の table や input を書いていません。

宣言しているのは、「勤務時間記録という一覧を、行単位で編集する」という意味です。

どう対処しているのか

画面を、完成した見た目ではなく、業務との約束として記述します。

その約束をもとに、実際の React 画面を生成します。

こうすると、画面の見た目を変更しても、saveRow や SV-A005 との接続は追跡できます。

画面が業務モデルから離れて、独自のルールを持ち始めることを防ぎやすくなります。

ただし、ここで別の問題が現れます。

モデルも画面契約も、人間がそのまま読むには情報量が多すぎます。

では、人間は何を読んで、何を承認すればよいのでしょうか。


4. 課題: 人間がすべての YAML とコードを読むことはできない

このサンプルには、24件のユースケースがあります。

業務サービスは49件です。

業務ルールは118件あります。

画面、エラー、シナリオ、ADR もあります。

すべての YAML とコードを業務オーナーに読んでもらうのは現実的ではありません。

かといって、「AIが作ったので大丈夫です」と済ませるわけにもいきません。

人間が判断すべきなのは、コードがきれいかどうかではありません。

業務として成立しているかどうかです。

日本語のシナリオまでを、人間の承認対象にする

今回の異常系シナリオは、次のような内容です。

前提として、山田太郎さんの2026年7月は提出済みです。

7月3日の記録は、開始09:00、終了18:00、休憩1.0です。

利用者は、次の操作をします。

  1. 2026年7月を表示する
  2. 7月3日の行を編集状態にする
  3. 開始時刻を10:00へ変更する
  4. 終了時刻を19:00へ変更する
  5. 別の行へ移動する

期待する結果は、次のとおりです。

  • MonthAlreadySubmitted が返る
  • 「提出済みの月は編集できません」が、編集していた行に表示される
  • 共通エラー領域には表示されない
  • 元の09:00から18:00という記録は変わらない
  • 月の集計も変わらない
  • 提出済みという状態も変わらない

ここで確認しているのは、「エラーになったか」だけではありません。

どこに表示されたか。

何が変更されなかったか。

周辺の集計が影響を受けていないか。

利用者から見える結果と、データの結果を一緒に確認しています。

モデルを、業務マニュアルへ戻す

人間は YAML を読む代わりに、モデルから生成された業務マニュアルを読みます。

そこには、誰が、何をして、どのルールで結果が決まるかが書かれています。

各項目には、UC-A001、SV-A005、BR-P026 のような識別子があります。

違和感があれば、識別子を使って指摘できます。

「画面のどこか」ではなく、「BR-P026 の表示ルール」として話せます。

また、モデルの要素がマニュアルから抜け落ちていないことも機械で検査します。

都合のよい部分だけを抜き出したマニュアルではないことを、生成工程で確認しています。

どう対処しているのか

人間の承認対象を、日本語で理解できるところまでにします。

業務オーナーは、業務マニュアルと検証シナリオを読みます。

そして、「この業務で成立するか」を判断します。

承認後にモデルが変更された場合は、承認との結びつきが切れます。

一度承認したから、その後は何を変えてもよい、とはしません。

ここまで読むと、ひとつ気になることがあります。

業務として正しくても、技術的に危うい作り方になっているかもしれません。

それは、誰が判断するのでしょうか。


5. 課題: 業務の判断と、技術の判断を同じ承認に混ぜてしまう

業務オーナーが判断するのは、「この業務で成立するか」です。

しかし、次のような問いは、業務だけでは決められません。

保存の成功を、クライアントだけで確定してよいか。

認可は、画面とサーバのどちらで強制するか。

エラーメッセージを API が直接組み立ててよいか。

行内編集の状態を、どの部品が持つか。

これらは技術上の決定です。

業務オーナーへ判断を求めるのも違います。

一方で、実装者がその場で決め続けると、システム全体の方針がばらばらになります。

決定者を2種類に分ける

このハーネスには、2種類の決定者がいます。

業務オーナーは、業務マニュアルとシナリオを読みます。

アーキテクトは、方式設計書と ADR を読みます。

最後は両者が、検証レポート、保証マニフェスト、画面証跡を確認します。

ゲートにすると、次の3段階です。

  1. 業務ゲートで、業務として成立するかを判断する
  2. 技術ゲートで、この方式で作ってよいかを判断する
  3. 最終ゲートで、出荷してよいかを判断する

技術の決定は ADR に残す

今回の行内編集には、ADR-0008 が直接効いています。

この ADR では、たとえば次のことを決めています。

  • 行内編集では、生成されたフィールドと操作タグを使う
  • 保存はサーバの Application Service を通す
  • 型検証、業務ルール、認可はサーバで行う
  • クライアントだけで成功状態を確定しない

この決定があることで、画面側だけで「保存できたこと」にしてしまう実装を防ぎます。

提出済み月の拒否も、サーバの業務サービスを通して判断されます。

ADR と方式設計書の役割を分ける

ADR は、ひとつの決定について「なぜそう決めたか」を残します。

方式設計書は、複数の ADR を統合し、「現在のシステムが全体としてどうなっているか」を説明します。

決定の履歴を知りたいなら ADR を読む。

現在の全体像を知りたいなら方式設計書を読む。

同じ技術資料でも、役割が違います。

業務と技術の両方に関係する問いはどうするか

現実には、業務だけでも技術だけでも決められない問題があります。

今回の例では、方針値をモデルへどのように持たせるかという論点が、両方のゲートに提示されました。

同じ問いを、業務側と技術側へ見せます。

そして、相手側と矛盾した回答にならないように確認します。

業務上の決定は、業務判断の記録として残します。

技術上の決定は ADR に残します。

決定の種類によって、後から探す場所も分けています。

どう対処しているのか

「人間が承認する」という一言でまとめず、誰が何を決めるかを分けています。

業務の決定者と技術の決定者では、読む資料も、答える問いも違います。

この分離によって、業務オーナーへ技術責任を押し付けず、アーキテクトが業務を勝手に変えることも防ぎます。

しかし、ADR を書いただけで、本当にその決定は守られるのでしょうか。

時間がたてば、実装が決定から離れていくかもしれません。

次は、その問題を見てみます。


6. 課題: 設計書は、書いた瞬間から古くなり始める

ADR に立派な決定を書いても、実装者が読まなければ意味がありません。

最初は守られていても、半年後の改修で崩れることもあります。

「サーバで状態を確定する」と書かれているのに、画面側だけで更新が完了したことにする。

「生成された属性を使う」と書かれているのに、共有部品へ業務固有の条件を書き始める。

設計書と実装がずれていても、普通の機能テストは通るかもしれません。

業務の結果がたまたま合っていれば、方式の違反は見逃されます。

ADR に Fitness Function を付ける

ADR-0008 には、その決定が守られていることを確認するテストが指定されています。

Fitness Function です。

実際のテストでは、次のようなことを確認します。

  • 行の確定先が、生成された DOM 属性から取得されているか
  • 共有部品が入力値を独自に書き戻していないか
  • 編集用の入力欄が、編集中の行にだけ表示されるか
test("ADR-0008 keeps row selection and commit coordinates in generated DOM attributes", () => {
  const router = readProject("dev/src/components/shared/router.tsx");
  assert.match(router, /data-commit-service/);
  assert.doesNotMatch(router, /(?:input|target)\.value\s*=/);
});

通常の E2E テストは、業務の結果を確認します。

Fitness Function は、アーキテクトが決めた方式を確認します。

似ていますが、見ているものが違います。

約束したテストが存在するかも確認する

ADR に Fitness Function の名前を書いても、テストファイルが作られなければ意味がありません。

そこで check_adr_fitness.py が、ADR で約束した検証場所が実在するかを確認します。

今回の走行では、この仕組みによって、承認済みのADRのうち4件が未実装だったことが見つかりました。

全体のテストが green でも、技術上の約束は果たされていなかったのです。

工程は、実装からアーキテクチャへ差し戻されました。

ここは興味深いところです。

機能テストが成功することと、設計上の決定が守られていることは、同じではありません。

どう対処しているのか

技術決定を、機械が実行できる検査へつなげます。

ADR を読むだけではなく、継続的に実装とのずれを確認します。

ただし、この仕組みにも限界があります。

check_adr_fitness.py が確認するのは、約束した場所にテストが存在するかどうかです。

そのテストが、ADR の決定を十分に検証しているかまでは判断しません。

最後の一段は、アーキテクトが引き受けます。

では、業務のルールと技術の決定は、実際のコードでどのように合流するのでしょうか。


7. 課題: モデルがあっても、実装が別の判断を始めるかもしれない

モデルに正しい事前条件を書いても、実装者が同じ条件を手で書き直せば、ずれが生まれます。

画面には「編集不可」と書かれているのに、API は保存できる。

サーバでは拒否するのに、画面は編集可能に見える。

同じ条件を複数の場所へ手書きすると、いつかどこかだけが変わります。

事前条件を実行コードへ変換する

services.yaml の preconditions_expr は、PreconditionsGen.ts へ変換されます。

// auto-generated
// model/services.yaml の preconditions_expr から機械的に生成
// 手編集は禁止

SV-A005 の判定は、モデルと同じ順序を持ちます。

  1. 書き込み権限
  2. 対象利用者の存在
  3. 提出済み月
  4. 行の値

手書きの保存処理も、この生成された判定器を呼びます。

const authority = PreconditionsGen.check("SV-A005", authorityContext);
const preconditions = PreconditionsGen.check("SV-A005", finalContext);

提出済み月の条件に失敗した場合、MonthAlreadySubmitted を返します。

すべてを生成するわけではない

業務コンパイラは、何もかも生成する仕組みではありません。

エラーメッセージの文言は、手書きのエラーカタログにあります。

MonthAlreadySubmitted: {
  display: "shell",
  message: "提出済みの月は編集できません"
}

ただし、このカタログは、エラーが発生したかどうかを決めません。

発生条件は、モデル由来の判定が決めます。

カタログは、人間へ見せる文言を提供します。

さらに、今回の行内編集では、BR-P026 に従って表示先を行内へ切り替えます。

ここには、役割分担があります。

  • 業務モデルが、エラーの発生条件を決める
  • エラーカタログが、文言を提供する
  • 画面の文脈が、表示場所を決める
  • ADR が、それらをどう接続するかを決める

業務側の決定と技術側の決定は、実装のこの場所で合流します。

画面には契約の手がかりを残す

生成された画面には、次のような属性が残ります。

<table
  data-list-source="dailyRows"
  data-edit-mode="row"
  data-commit-action="saveRow"
  data-commit-service="SV-A005">

E2E テストは、見た目のクラス名ではなく、この契約を使って画面を操作します。

そのため、CSS を変更しても、業務上の接続が変わっていなければテストは影響を受けにくくなります。

逆に、保存先のサービスや行編集の意味を変えたなら、契約の変更として検出できます。

どう対処しているのか

業務ルールをモデルから生成し、手書き実装も生成物を通すようにします。

生成と手書きの境界を明示します。

どちらか一方へ寄せ切るのではなく、誰が何を決めるかを分けます。

ここまでで、要件、モデル、画面、ADR、実装がつながりました。

しかし、最後に確かめたいのは、実際の利用者操作です。

本当にブラウザ上で、期待した動きになるのでしょうか。


8. 実際に、1件の勤怠入力を動かしてみる

ここからは、山田太郎さんの2026年7月3日の行を、実ブラウザで操作します。

前提は次のとおりです。

2026年7月は、すでに月次提出済みです。

7月3日の記録は、開始09:00、終了18:00、休憩1.0です。

行を編集する

画面で2026年7月を表示します。

7月3日の行をクリックします。

行が編集状態になります。

開始時刻を10:00へ変更します。

終了時刻を19:00へ変更します。

そして、別の行をクリックします。

保存ボタンはありません。

別の行へ移動したことが、保存のきっかけになります。

サーバで保存が拒否される

SV-A005 が実行されます。

まず、書き込み権限を確認します。

次に、対象利用者が存在するかを確認します。

その後、対象月が提出済みかを確認します。

今回は提出済みです。

そのため、保存は拒否されます。

MonthAlreadySubmitted が返ります。

画面の正しい場所に表示される

画面には、次のメッセージが表示されます。

提出済みの月は編集できません

重要なのは、文言だけではありません。

このメッセージは、画面上部の共通エラー領域には出ません。

編集していた7月3日の行の中に表示されます。

これは BR-P026 で決めた表示方法です。

データが変わっていないことを確認する

データベースを確認します。

結果は次のままです。

開始時刻: 09:00
終了時刻: 18:00
休憩時間: 1.0

入力した10:00から19:00は保存されていません。

月の作業時間合計も変わっていません。

提出済みという状態も変わっていません。

何を検証したのか

このシナリオでは、少なくとも次のことを確認しています。

  • 正しい業務エラーが返ったか
  • エラーが正しい行に表示されたか
  • 共通エラー領域へ誤表示されていないか
  • 元の勤務時間が変わっていないか
  • 月の集計が変わっていないか
  • 提出状態が変わっていないか

「エラーが出た」だけでは、十分な検証ではありません。

利用者が見る結果。

保存されるデータ。

周辺の集計。

変わってはいけない状態。

これらをまとめて確認します。

証跡を残す

E2E テストは、実ブラウザを操作します。

そして、各ステップの画面を PNG として保存します。

今回のシナリオでは、提出済みの7月を表示した画面と、保存が拒否された画面が残ります。

サンプル全体では、証跡は147枚あります。

それらは紙芝居形式の HTML に綴じられます。

PNG が147枚あり、HTML の img も147個あることを、機械が確認します。

ここまで来ると、ひとつの勤怠入力が、要件から画面証跡までつながりました。

では、プロジェクト全体では、どこまで確認できたのでしょうか。


9. 課題: テストが通ったことを、どこまで信じてよいのか

2026年9月1日の検証レポートでは、次の結果になっています。

検査 結果
TypeScript の内側テスト 302件中302件成功
実 DOM の E2E 49件中49件成功
型検査 成功
Vite build 成功
カバレッジ検査 成功
証跡の再生成一致 PNG 147枚と img 147個が一致
トレーサビリティの再生成一致 551行

数字だけを見ると、かなり安心できそうです。

しかし、テストがすべて green であることと、システムの正しさが完全に証明されたことは同じではありません。

追跡できる範囲を確認する

今回の1件は、次のようにつながっています。

段階 実体
要件 勤務時間入力の原文
業務モデル UC-A001、BR-M004、BR-P026、SV-A005
画面契約 SCR-A001、VM-A001、VIEW-A001
検証シナリオ SC-E-A001-002
技術決定 ADR-0007、ADR-0008、ADR-0009
実装 事前条件生成コードと勤務時間サービス
画面 生成された勤務時間管理画面
検証 実 DOM E2E と Fitness Function
証跡 ステップごとの PNG

この対応は、トレーサビリティの表として出力されます。

また、各サービスに正常系があるか、宣言したエラーに異常系があるかを、義務台帳で数えます。

必要なシナリオが欠けていれば、工程は先へ進みません。

どう対処しているのか

「テストが何件通ったか」だけでなく、「何を起点に、どのシナリオとテストへつながったか」を確認します。

件数ではなく、意味のつながりを見ます。

ここまでで、1件の勤怠入力が、要件から証跡までどのようにつながるのかを確認できました。


10. この1件から見えてくるもの

今回追いかけたのは、たった1件の勤怠入力です。

しかし、その1件は、次の工程を通りました。

  1. 人間が業務の文章を書く
  2. ユースケースと業務ルールへ名前を付ける
  3. 画面の遷移、束縛、配置を契約にする
  4. 業務オーナーが日本語のシナリオを承認する
  5. アーキテクトが実装方式を ADR として承認する
  6. モデルから事前条件と画面を生成する
  7. 手書き実装を生成された判定へ接続する
  8. Fitness Function で技術上の約束を検査する
  9. 実ブラウザで利用者操作を確認する
  10. データと集計が変わっていないことを確認する
  11. 画面証跡を残す

業務コンパイラの中心は、AIにコードを書かせることではありません。

業務上の意味を、途中で失わないように運ぶことです。

要件からモデルへ。

モデルから画面へ。

画面から実装へ。

実装からテストへ。

テストから証跡へ。

そして、業務の決定と技術の決定を、別々の人が追えるようにすることです。

今回伝えたかったこと

この記事では、1件の勤怠入力を利用者に近いところから追いかけました。

小さな入力機能であっても、その裏側には業務ルール、画面契約、技術上の決定、実装、テスト、証跡があります。

大切なのは、それらをたくさん作ることではありません。

最初に決めた業務の意味が、最後の画面とデータまでつながっていることです。

もちろん、開発工程の内側には、まだ掘り下げられる話があります。

モデルを変更したときに何を作り直すのか。

不整合が見つかったとき、どの工程へ戻るのか。

49件の E2E と147枚の証跡を、どのように対応付けているのか。

こうしたハーネス内部の動きについては、また機会があれば、開発者の視点から整理したいと思います。

まずは、たった1件の勤怠入力にも、要件から証跡まで切れない道筋を作れること。

それが、今回お伝えしたかった業務コンパイラの姿です。

AIに「狙った業務システム」を作らせるための5つの仕組み

[AIによる執筆注記] 生成AIを活用して執筆しています。内容の監修・確認は著者が行っています。

0. AIはコードを書ける

生成AIにコードを書かせることは、難しくなくなりました。

「休暇申請システムを作って」と頼めば、画面もプログラムも作ってくれます。

一見すると、それらしいシステムが完成します。

しかし、業務システムで難しいのは、コードを書くことではありません。

例えば休暇申請には、次のようなルールがあります。

  • いつまで申請できるのか
  • 誰が承認できるのか
  • 承認後に取り消せるのか
  • 残日数が足りない場合はどうするのか
  • 代理申請を認めるのか

この部分が曖昧なままでは、AIはもっともらしい答えを補います。

そして、

動くけれど、業務では使えないシステム

ができます。

必要なのは、うまいプロンプトだけではありません。

AIが間違いにくく、間違えても発見できる開発の仕組みです。

この記事では、その仕組みを五つに分けて説明します。


1. AIへ正しい材料を渡す

1.1 最初にコードを作らない

AIに狙ったコードを書かせる第一歩は、コードを書かせないことです。

最初に、システムが守る業務ルールを整理します。

長い説明文を一つ渡すのではなく、一つのルールを一つの項目として管理します。

例えば休暇申請。

ルールID: BR-001
ルール: 休暇の申請日数は、申請者の有給休暇残日数を超えてはならない
根拠: 就業規則 第12条
確認状態: 確認済み

ルールだけではなく、根拠と確認状態も記録します。

業務担当者から、次の説明を受けたとします。

有給休暇は残日数の範囲内で申請できます。たぶん、当日の申請もできると思います。

この文章には、確定した情報と推測が混ざっています。

そのままAIへ渡すと、「当日申請できる」が正式な仕様になるかもしれません。

そこで、二つに分けます。

BR-001:申請日数は有給休暇残日数を超えてはならない
状態:確認済み

Q-001:当日の休暇申請を認めるか
状態:未確認
確認先:人事責任者

人事責任者から「当日申請は午前9時まで」と回答を得たら、新しいBusiness Ruleとして追加します。

AIへ渡す情報は、多ければよいわけではありません。

確認済みの事実、AIの推測、未確認の質問を分ける

ことが重要です。

1.2 押さえるポイント

  • コードより先に、業務の流れと判断条件を整理する
  • Business Ruleを一つずつ分け、IDと根拠を付ける
  • 確認済みの事実と未確認事項を混ぜない
  • 情報が足りないときは、AIに推測させず質問として残す

2. AIの自由を制限する

2.1 AIは目的を達成しようとする

AIは、与えられた目的を達成するために方法を選びます。

これは便利な性質です。

しかし、業務システムでは問題になることがあります。

例えば、

すべてのテストを成功させてください

と依頼したとします。

AIはプログラムを直すかもしれません。テストの期待値を変えるかもしれません。テストをスキップするかもしれません。

どの方法でも、画面上はテスト成功になります。

しかし、業務要件を満たしたとは限りません。

2.2 作業段階ごとに権限を分ける

開発を次のように分けます。

要件整理    業務モデルとテストを作成できる
実装        プログラムだけを変更できる
画面テスト  E2Eテストを追加できる
最終確認    原則として変更できない

指示文に書くだけでは不十分です。

実装段階では、要件ファイルとテストファイルへの書き込みをシステム側で拒否します。

例えば、次のテストを先に作ります。

def test_残日数を超える休暇は申請できない():
    result = apply_leave(remaining_days=2, requested_days=3)
    assert result.error == "残日数が不足しています"

まだ実装していないため、テストは失敗します。

実装担当のAIが行うべきことは、apply_leaveへ残日数の検査を追加することです。

テストも編集できると、AIは期待値を現在の動作に合わせることができます。

テストを変更禁止にすれば、選択肢は二つになります。

  • コードを正しく直す
  • 解決できないと報告する

これはAIを信用するかどうかの話ではありません。

AIが迷ったときに、正しい方向へ進みやすくする

ための設計です。

2.3 押さえるポイント

  • 要件整理、テスト、実装、レビューを別の作業にする
  • 作業ごとに、AIが変更できるファイルを制限する
  • 実現できない要件は簡略化させず、問題として報告させる
  • 同じ修正に失敗し続けたら、人間による設計確認へ戻す

3. テストで完成条件を固定する

3.1 完成とは何か

「休暇申請機能を実装する」だけでは、完成の意味が決まりません。

そこでコードを書く前に、入力と期待結果をテストにします。

残日数の確認なら、少なくとも次のケースが必要です。

残日数 申請日数 期待結果
5日 3日 申請できる
5日 5日 申請できる
5日 6日 申請できない
0日 1日 申請できない

「5日まで」というルールに対して、4日だけを確認しても境界はわかりません。

5日と6日の両方を試します。

3.2 境界で間違える

AIが次のコードを生成したとします。

if requested_days >= remaining_days:
    return Error("残日数が不足しています")

一見、正しそうに見えます。

しかし、残日数と申請日数が同じ場合もエラーになります。

正しくは > です。

if requested_days > remaining_days:
    return Error("残日数が不足しています")

「残日数5日、申請日数5日」のテストがあれば、この間違いを検出できます。

ただし、テストがあるだけでは不十分です。

assert result == result

このテストは必ず成功します。何も確認していません。

実装前には失敗し、正しい実装後には成功し、間違った実装では再び失敗する。

必要なのは、通るテストではなく、間違いを止めるテスト

です。

3.3 押さえるポイント

  • コードより先に、業務ルールからテストを作る
  • 正常系だけでなく、エラーと境界値を試す
  • 間違った実装で本当に失敗するテストか確認する
  • 未実行やスキップを、テスト成功として扱わない

4. 人間と別のAIが意味を確認する

4.1 形式が正しくても、業務は間違う

ファイル形式が正しい。すべての参照先が存在する。テストも成功している。

それでも、業務上の矛盾が残ることがあります。

機械的な検査が得意なのは、書かれている内容の形を調べることです。

一方、

そもそも、この業務は成立するのか

という確認には、別の視点が必要です。

作成担当とは別のAIに、次の問いを与えます。

  • この条件を満たす具体的な利用者を作れるか
  • すべてのエラーを実際に発生させられるか
  • 利用者が判断するための情報は画面に表示されているか
  • 二つのルールが同時に成立しない場面はないか
  • 書かれていない前提を補っていないか

4.2 矛盾を具体例で見つける

休暇申請システムに、二つのルールがあるとします。

BR-010:承認済みの申請は変更できない
BR-011:申請者は休暇開始日の前日まで申請内容を修正できる

どちらも単独では自然です。

では、休暇開始日の3日前に承認された申請はどうなるでしょうか。

  • BR-010に従えば変更できない
  • BR-011に従えば前日まで変更できる

ファイル形式やIDの検査では、この矛盾を発見できません。

具体的な利用場面を作ると、ルール同士の衝突が見えます。

人間は、次のどちらかを決めます。

A. 承認された時点で変更できなくなる
B. 前日までは変更できるが、変更すると再承認が必要になる

決定した内容をBusiness Ruleとテストへ反映します。

レビュー担当AIには、修正までさせません。

AIは疑問と選択肢を出す。業務上の意味は人間が決める。

この境界が重要です。

4.3 押さえるポイント

  • 作成担当とは別のAIに、矛盾や抜けを探させる
  • AIは疑問と選択肢を出し、業務上の答えは人間が決める
  • 人間には設定ファイルではなく、具体例や操作できる試作品を見せる
  • 人間はコードより、業務の流れと例外時の扱いを確認する

5. 作業結果を記録する

5.1 会話は引き継げない

AIとの開発では、会話が長くなります。

セッションが終了することもあります。別のAIへ担当を交代することもあります。

重要な情報が会話の中にしかないと、判断の理由が失われます。

最低限、次の情報をファイルとして残します。

  • 確定したBusiness Rule
  • 未回答の質問と回答
  • 設計を選んだ理由
  • 実行したテストと結果
  • 人間が承認した対象
  • 変更によって影響を受ける範囲

5.2 承認した内容を特定する

月曜日に、人事担当者が次の仕様を承認したとします。

BR-020:休暇申請の取り消しは、休暇開始日の前日まで可能

火曜日に別の担当者が、要件ファイルを変更しました。

BR-020:休暇申請の取り消しは、休暇開始時刻まで可能

変更履歴と承認対象が結び付いていなければ、「承認済み」と判断されるかもしれません。

しかし、月曜日に承認した内容と、現在の内容は違います。

承認時のファイルハッシュを保存しておけば、変更を検出できます。

承認後にBR-020が変更されています。
業務担当者による再確認が必要です。

同じ考え方は、テスト結果にも使えます。

どのコード、どの要件、どの検査プログラムで実行した結果なのかを記録します。

そうすれば、「以前成功した」という曖昧な説明ではなく、現在もその結果を利用できるか判断できます。

記録は監査のためだけにあるのではありません。

次のAIが、過去の会話を知らなくても作業を再開できるようにする

ためにあります。

5.3 押さえるポイント

  • 決定、未確認事項、テスト結果を会話の中だけに残さない
  • 承認した内容を、ハッシュやコミットで特定する
  • 承認後に内容が変わったら、再承認を必要とする
  • 次のAIがファイルだけを読んで再開できる状態にする

6. まとめ

AIに狙った業務システムを作らせるための仕組みは、五つです。

  1. AIへ正しい材料を渡す
  2. AIの自由を制限する
  3. テストで完成条件を固定する
  4. 人間と別のAIが意味を確認する
  5. 作業結果を記録する

共通しているのは、AIへすべてを任せないことです。

AIは、コード生成、形式変換、候補の洗い出し、繰り返し作業を高速に行えます。

一方、会社固有のルールを決めることはできません。矛盾した要求のどちらを優先するか、その責任も持てません。

役割は次のようになります。

業務上の意味を決める        人間
決まった内容を構造化する    AIと生成ツール
コードを作る                AI
形式と実行結果を確認する    自動検査
矛盾や未確認事項を判断する  人間

重要なのは、AIが完璧に答えることではありません。

正しい材料を渡す。

変更できる範囲を限定する。

テストで完成条件を固定する。

間違いがあれば、人間へ戻す。

この流れを作ることで、生成AIは単なるコード補完ツールではなくなります。

業務システム開発を支える、実用的な実装担当になります。

【AIエージェントのための画面モデル #13】生成された出荷UIを検査する

[AIによる執筆注記] 生成AIを活用して執筆しています。内容の監修・確認は著者が行っています。

~一つのテストですべてを証明しない~


13.1 はじめに

前回は、画面モデルを画面構造IRへ合成し、レンダラから出荷UIを生成する流れを説明しました。

今回は、生成プログラムと生成されたUIをどのように検査するかを考えます。

重要なのは、確認対象を分けることです。


13.2 検査を四段階に分ける

出荷UIの正しさを、一種類のテストだけで確認することはできません。

確認対象を四段階に分けます。

段階 確認すること
画面モデル検査 参照、型、値の受け渡し、遷移が成立しているか
生成プログラム検査 画面モデルの語彙をIRとUIへ正しく運べるか
出荷UI適合検査 必要な項目、操作、領域、順序が実際のUIにあるか
実操作検査 ブラウザ上の操作からServiceまで正しく到達するか

最初の段階では、画面モデル自体の矛盾を探します。

次に、生成プログラムが情報を落としていないかを確認します。

その後、生成された個々のUIが契約どおりかを確認します。

最後に、実際のブラウザを使って操作を確認します。


13.3 生成プログラムと生成物を別々に検査する

生成プログラムのテストと、生成された画面の検査は別物です。

生成プログラムには、代表的な入力を与えます。

単一field
一覧
編集可能な一覧
ダイアログ
条件付きの遷移
非表示列
異なるcontrol

それぞれが正しいIRとUIへ変換されるかを確認します。

これは、生成規則そのもののテストです。

一方、生成物の検査では、実際の画面ごとに必要な項目と操作を確認します。

生成プログラムのテスト
  → 規則が正しいか

生成された画面の検査
  → この画面が契約どおりか

生成器が正しくても、入力モデルが間違っている場合があります。

入力モデルが正しくても、生成器の新しい不具合で出力が欠ける場合があります。

両方を分けて確認する必要があります。


13.4 再生成して同じ結果になるか

決定的生成では、同じ入力から同じ出力が得られることが重要です。

同じ画面モデル + 同じ生成プログラム
              ↓
          同じ出荷UI

一度生成したUIを保存し、もう一度生成した結果と比較します。

差分がなければ、再生成可能性を確認できます。

意図しない差分が出た場合は、どこかに次のような要因があります。

  • 現在時刻に依存している
  • 並び順が固定されていない
  • LLMを生成処理の途中で毎回呼んでいる
  • レンダラが独自の判断をしている

出荷UIの生成経路から偶然性を減らすことが大切です。


13.5 E2Eと人間の確認は残る

決定的に生成できても、すべてが自動的に正しいとは限りません。

ブラウザ上で、次のことを確認します。

  • 入力できるか
  • 行を選べるか
  • ダイアログが開閉するか
  • commandが正しいServiceへ届くか
  • 成功とエラーが利用者へ伝わるか

さらに、人間はプロトタイプを触って確認します。

  • 情報量は適切か
  • 作業順に並んでいるか
  • 誤操作しにくいか
  • 業務担当者が意味を理解できるか

機械は、構造と接続を確認できます。

人間は、意味と使いやすさを確認します。

両方が必要です。


13.6 例外としての手書きUI

すべてのUIが、共通の生成語彙に向いているとは限りません。

一度しか使わない特殊な可視化や、高度な直接操作が必要な画面もあります。

その場合は、手書きUIを例外として扱えます。

ただし、生成経路から外れるため、別の保証が必要です。

  • なぜ手書きにするかを記録する
  • 画面モデルとの対応を残す
  • 実DOMを検査する
  • E2Eで主要操作を確認する
  • モデル変更後に古いまま残っていないか確認する

例外を禁止するのではありません。

例外で失う保証を、別の方法で補います。


13.7 まとめ

画面モデルから出荷UIを作る流れは、次のようになります。

画面モデル + 業務モデル
          ↓ 合成
      画面構造IR
          ↓ 表示上の決定
      決定済みIR
          ↓ レンダラ
        出荷UI

そして、検査を段階に分けます。

  • 画面モデル自体を検査する
  • 生成プログラムの変換規則を検査する
  • 出荷UIが契約どおりか検査する
  • ブラウザ上の操作をE2Eで確認する
  • 意味と使いやすさを人間が確認する

LLMの役割は、出荷画面を毎回自由に書くことではありません。

画面モデルの語彙を正しく運ぶ生成プログラムやレンダラを作り、改善することです。

画面モデルからのUI生成で重要なのは、生成できることではなく、同じ意味を再現し、検査できることです。

【AIエージェントのための画面モデル #12】画面モデルから出荷UIを生成する

[AIによる執筆注記] 生成AIを活用して執筆しています。内容の監修・確認は著者が行っています。

~生成できることと、正しく生成できることは違う~


12.1 はじめに

前回までに、画面契約の考え方と、YAMLによる参考例を説明しました。

今回は、画面モデルから実際に利用者へ届けるUIを作る流れを見ていきます。

ここでは、利用者へ届けるUIを出荷UIと呼びます。

大切なのは、画面コードを生成できることだけではありません。

画面モデルに書かれた意味が、途中で失われずに出荷UIへ届いたか。

これを確認できる仕組みが必要です。


12.2 画面モデルを直接HTMLへ変換しない

画面モデルには、ViewModel、Screen、View Structureがあります。

さらに、Domain、Dictionary、Serviceから導出する情報もあります。

例えば、View Structureには次の指定しかないとします。

- field: targetMonth

これだけでは、HTMLのどの要素を使うか分かりません。

しかし、参照先をたどれば、次の情報が分かります。

targetMonth
  → LeaveRequest.TargetMonth
  → YearMonthという意味型
  → 年月入力として表示する

画面モデルだけで決まる情報と、他のモデルから導く情報を合成してから、出荷UIを作ります。


12.3 まず画面構造IRへ合成する

生成の途中に、画面構造IRを置きます。

IRはIntermediate Representationの略です。

日本語では、中間表現と呼ばれます。

ViewModel
  + Screen
  + View Structure
  + Domain
  + Dictionary
  + Service
        ↓ 合成
    画面構造IR

画面構造IRには、生成に必要な情報を集めます。

  • 表示するfield
  • 一覧と列
  • 項目の順序
  • commandとServiceの接続
  • 画面とダイアログの遷移
  • 型と表示形式
  • 必須性と編集可否
  • ボタンの活性条件

レンダラが複数のモデルを直接読んで、その場で解釈しないことが重要です。

先に一つの中間表現へまとめれば、解釈する場所を限定できます。


12.4 表示上の決定を一度だけ行う

画面構造IRを作った後、表示方法を決めます。

例えば、同じ選択値でも、select、radio、comboboxなどの表現があります。

一覧にも、tableやcardsなどの表現があります。

この判断を、プロトタイプと出荷UIが別々に行ってはいけません。

悪い例

画面モデル
  ├─ プロトタイプが独自に判断
  └─ 出荷UIが独自に判断

別々に判断すると、承認した画面と出荷する画面がずれる可能性があります。

表示上の決定は、一つの決定層で行います。

画面構造IR
      ↓ 表示方法を決定する
決定済み画面構造IR
      ├─ プロトタイプ
      ├─ 出荷UI
      └─ 業務マニュアル

同じ決定済みIRを使えば、三つの成果物が同じ構造を共有できます。


12.5 レンダラは決められた形へ写す

レンダラは、決定済みIRをHTMLやフレームワーク固有のUIコードへ変換します。

レンダラの仕事は、意味を考え直すことではありません。

すでに決まった内容を、決められた形へ写すことです。

例えば、IRに次の情報があるとします。

field = targetMonth
control = month
editable = true
required = true

HTMLレンダラなら、年月入力として出力します。

別のUI技術なら、その技術に対応する年月入力へ変換します。

技術が違っても、fieldの意味、必須性、編集可否は変えません。


12.6 安定した座標を出荷UIへ残す

生成したUIには、画面モデルとの対応を示す安定したIDを残します。

例えば、次のような座標です。

画面      SCR-R001
項目      targetMonth
一覧      pendingRequests
操作      approveRequest
領域      main

HTMLでは、data-fieldやdata-actionのような属性として表現できます。

<input data-field="targetMonth">
<button data-action="approveRequest">承認する</button>

この座標があると、機械は次のことを確認できます。

  • 必要な項目が出荷UIに存在するか
  • 必要な操作が存在するか
  • 項目の順序が正しいか
  • 変更された画面を特定できるか
  • E2Eテストが安定した対象を選べるか

見た目の文言だけをテストの目印にすると、ラベル変更でテストが壊れます。

意味のあるIDを残すことで、画面モデルと出荷UIを結び続けます。


12.7 まとめ

画面モデルから出荷UIを作る流れは、次のようになります。

画面モデル + 業務モデル
          ↓ 合成
      画面構造IR
          ↓ 表示上の決定
      決定済みIR
          ↓ レンダラ
        出荷UI

ポイントは次のとおりです。

  • 複数のモデルを画面構造IRへ合成する
  • 表示上の決定を一度だけ行う
  • プロトタイプと出荷UIで同じ決定済みIRを使う
  • レンダラは意味を考え直さず、決められた形へ写す
  • 出荷UIへ画面モデルの安定した座標を残す

LLMの役割は、画面を毎回自由に書くことではありません。

画面モデルを決まった形へ変換する生成プログラムやレンダラを作り、改善することです。(この改善もAIエージェントがやってくれます)

次回は、生成プログラムと生成された出荷UIを、どのように検査するかを説明します。