所見を起票する
点検の成果物は点群そのものではなく、所見(どこに・どんな損傷が・どの判定区分か)です。 oniyanma は所見を、点群とは別のデータとして持ちます。
ツールレール 📍 所見 から起票・一覧・返信ができます。 window.oniyanma / AI コンソール / MCP からも同じコマンドで扱えます (このページのコードはどの経路でも同じ結果になります)。
型そのものがデータ
点検要領は発注者ごとに違い、改定もされます。項目をコードに直書きすると、 案件が増えるたびにアプリを直すことになります。
そこで oniyanma は所見の型(FindingType)をデータとして持ちます。 型を定義すると、その型がそのまま JSON Schema になり、AI のツール定義に載ります。 顧客が定義した項目を、AI がその日から埋められる、ということです。
既定で damage(損傷)という型が 1 つ入っています。橋梁点検の最小形です。
| フィールド | 型 | 内容 |
|---|---|---|
kind | enum(必須) | ひび割れ / 剥離・鉄筋露出 / 漏水・遊離石灰 / 腐食 / その他 |
grade | enum(必須) | a / b / c / d / e(国交省の判定区分に相当) |
size | measurement (mm) | ひび割れ幅・剥離範囲など |
note | text | 所見 |
photo | text | 写真番号 |
inspectedOn | date | 点検日 |
previous | link → Finding | 前回点検の所見(点検周期5年での再発判定に使う) |
これは例です。実際の案件では顧客の点検要領に置き換えます。
型を定義する
フィールドの型は text / number / enum / boolean / date / link / measurement の 7 種です。
await oniyanma.execute('defineFindingType', {
def: {
id: 'crack',
label: 'ひび割れ',
standard: '道路橋定期点検要領(H31.3)',
fields: [
{ id: 'width', label: 'ひび割れ幅', type: 'measurement', unit: 'mm', required: true },
{ id: 'length', label: '長さ', type: 'measurement', unit: 'm' },
{ id: 'grade', label: '判定区分', type: 'enum', required: true, options: ['a', 'b', 'c', 'd', 'e'] },
{ id: 'note', label: '所見', type: 'text', maxLength: 2000 },
],
},
})同じ id があれば新しい版として更新されます。型定義も所見と同じく版・来歴・下書き / 公開を持つので、 「要領の改定を下書きしてから切り替える」がそのまま乗ります。
一覧は listFindingTypes、 JSON Schema として取り出すなら getFindingTypeSchema です。
起票する
await oniyanma.execute('createFinding', {
typeId: 'crack',
fields: { width: { value: 0.3, unit: 'mm' }, grade: 'c', note: '主桁下フランジに縦断方向' },
pin: [x, y, z], // 実座標 (m)。省略可
})
// → { id: 'e_…', typeId: 'crack', version: 1, draft: true }fields は型定義に従って検証されます。合わない場合は 「どのフィールドがなぜ駄目か」を並べたエラーが返るので、AI も人もそのまま直せます。
pin は実座標です。クリックした点の座標が画面左下に出るので、そこから拾えます。
点群上のピンと一覧
UI から起票するときは、ツールレール 📍 所見 を選んで点群上をクリックすると、 その場に入力フォームが開きます(型を選んでフィールドを埋めるだけで、座標は自動で入ります)。
起票済みの所見は点群上にピンとして表示され、サイドパネルに一覧も出ます。 一覧の項目をクリックするとカメラがそのピンへ寄るので、「一覧で拾って現地を見る」がそのまま行えます。 ピンや一覧上のコマンドはすべて上のコマンド呼び出しと同じものを叩いているので、 UI で起票した所見も AI やスクリプトからそのまま扱えます。
下書きと公開
起票した所見は下書きです。発注者には見えません。 publishFinding で公開版として確定します。
await oniyanma.execute('publishFinding', { id })公開は「保存の副作用」ではなく明示的な操作です。 公開後に updateFinding で内容を変えると、 再度 publish するまで発注者には旧版が見え続けます (一覧の hasUnpublishedChanges が true になります)。
| 操作 | コマンド |
|---|---|
一部だけ更新(値 null でそのフィールドを消す) | updateFinding |
一覧(draft 既定 / published / deleted) | listFindings |
| 公開 / 取り下げ | publishFinding / unpublishFinding |
| 削除 / 復元 | deleteFinding / restoreFinding |
削除はトゥームストーンです。記録は残り、一覧と公開面から外れるだけなので、 restoreFinding で(取り下げ中に入った編集も含めて)戻せます。 機械から呼ぶときは確認ゲートがかかります。
書き出す
exportFindings で CSV か GeoJSON に出します。 既定は公開版のみ=発注者に渡せる形です。view: 'draft' で下書きも含めた社内用になります。
await oniyanma.execute('exportFindings') // 公開版・CSV
await oniyanma.execute('exportFindings', { format: 'geojson', view: 'draft' })CSV の列は「共通列(id / version / updatedAt / actor / x,y,z)+ 出てきた値キーの合併」です。 型ごとにファイルを分けないのは、1 回の点検で複数の型が混ざるのが普通で、 分けると突き合わせが人手作業になるためです。空セルは「その型にその項目が無い」を意味します。
点検調書の様式(様式2・3)に合わせて出すなら exportFindingsForm23 を使います。 defineFindingType で bridge_form23 型(様式2・3準拠の項目)に載せた所見だけを、 様式の記入順で列を固定した CSV に出します——汎用の exportFindings と違い、 出てきた値キーの合併ではなく様式側の列順が先に決まっています。 電子納品要領の XML や様式そのもの(.xlsx)ではなく、貼り付けて使う CSV です。
返信する
所見には**返信(thread)**を付けられます。判定区分に疑問があるときや、 現地確認を頼むときに、所見そのものを直さずやり取りを残せます。UI ではピンをクリックすると 所見と返信が並んで表示され、その場で返信を書けます。
const c = await oniyanma.execute('commentFinding', { id, text: '要領のどの項に該当するか確認してください' })
await oniyanma.execute('editComment', { id: c.id, text: '様式2の3項に該当するか確認してください' })
await oniyanma.execute('listComments', { id })
// → [{ id, text, actor, createdAt, editedAt }, …](古い順)返信も所見と同じく、出したあとに直せます(UI では返信の ⋯ から)。 本文を直すのは editComment(updateFinding ではありません——返信の本文は予約キー $text で、 updateFinding は型定義の項目だけを相手にするので届きません)。取り下げは所見と同じ deleteFinding で、返信も Entry だからです。直した返信には editedAt が付きます (黙って書き換わっていないことが読める必要があるため。直していなければ null)。
返信そのものは listFindings の一覧や exportFindings には出ません (発注者への成果物と、社内・チーム内のやり取りを混ぜないため)。 listFindings の各所見には返信件数が comments として付くので、 一覧を見るだけで「どの所見にやり取りが溜まっているか」は分かります。 返信への返信はできません(会話が入れ子になって追えなくなるため、必ず親の所見に付けます)。
AI 検出のインポートとトリアージ
外部の損傷検出 AI(写真からひび割れ等を検出するモデル)の出力を、下書きの所見として 一括で取り込めます。写真とカメラ姿勢(COLMAP 等)を先に登録しておくと、 検出の 2D 座標(bbox / polygon / 代表点)を実座標へ投影してピンを立てます。
await oniyanma.execute('importDetections', {
photoSetId: 'set1',
detections: [
{ photoId: 'IMG_001.jpg', typeId: 'crack', bbox: [120, 340, 60, 20], confidence: 0.83, sourceLabel: 'crack_v3' },
// …
],
})
// → { batchId: 'b_…', created: [...], count: 12, noIntersection: 0, total: 12 }全件を先に型検証・写真姿勢の確認まで済ませてから作成します(1 件でも通らなければ 1 件も作らない)。 取り込みは 1 つの束にまとまるので、 スキーマや投影の設定を間違えたときは revertBatch で丸ごと戻せます。
同じ損傷が複数の写真に写る場合(多視点統合)
写真ごとに検出すると、同じひび割れが複数枚に写った分だけ件数が重複します。 3D 位置が近い検出を候補としてグループ化し、確定した分だけ 1 件にまとめられます。
const { groups } = await oniyanma.execute('queryMergeCandidates', { radiusM: 0.5 })
await oniyanma.execute('mergeFindings', { ids: groups[0] }) // 生き残りは確信度最大を自動選出
await oniyanma.execute('unmergeFinding', { id }) // 統合の解除統合は削除ではなく $mergedInto を刻むだけなので、一覧・帳票から外れても記録は残り、 いつでも個別に解除できます。フィールドの値そのものは統合されません (「調書の数字が黙って変わる」ことを避けるため、確定は常に人が行います)。
トリアージ UI(数千件を素早く捌く)
検出は 1 案件で数千件出ることがあるため、ツールレール ☑ トリアージ に専用の面があります。 確信度順に 1 件ずつ写真のクロップと 3D 位置を並べて表示し、キーボードだけで進められます。
| キー | 操作 |
|---|---|
A | 採用(confirmFinding)して次へ |
R | 却下(rejectFinding)して次へ |
M | 統合候補があれば統合して次へ |
採用・却下は誰が・いつ確認したかを来歴($review)として記録します。 却下は削除ではないので一覧・統合候補からは外れますが記録は残り、 restoreFinding では戻せません(取り消すなら updateFinding で $review を直します)。
名前の無い検出を指す
「あの主桁のひび割れ」のように所見を id ではなく条件で指したいときは queryFindings を使います。
await oniyanma.execute('queryFindings', { typeId: 'crack', near: [x, y, z], maxDistance: 2 })
// → { results: [{ id, pin, distance, sourceLabel, confidence, reviewStatus }, …], consideredCount, withoutPin }typeId(損傷区分)・sourceLabel(検出 AI の生ラベル、部分一致)・ near + maxDistance(実座標 m での近さ)を組み合わせて絞り込め、 near を指定すると近い順に返ります。
協働での共有
所見はアプリが所有する Y.Doc に載っていて、入室すると そこへ同期の provider が後付けされます。所有の向きがこちらなので、 部屋を出ても所見は手元に残ります(協働の Doc に載せると退室時に消えてしまう)。
同期は編集ログとは別のルーム(<room>:entries)で行います。1 本の WebSocket に 2 つの Y.Doc を流すと、Yjs の同期メッセージは doc を区別しないので相手の doc が壊れるためです。 招待リンクは 1 本のままで、派生名は双方が同じ規則で導出します。
参加前にローカルで起票した所見は、接続した瞬間に CRDT が合流させます (同じ id は 1 件に、別の id は和になる)。編集ログのように「持ち込み」を自前で積む必要が ないのは、所見が id をキーにした Y.Map の集合だからです。
同じ所見の別の項目を 2 人が同時に直しても、どちらも失われません (最小の交換単位がフィールド 1 つ)。同じ項目を同時に直したときは後勝ちですが、 両者は必ず同じ値に収束します。
いまの制約
多視点統合はフィールドの値を自動で合わせません。 生き残る所見を選ぶだけで、 食い違う値(例:確信度以外のフィールド)が入っていても統合しません—— 「調書の数字が黙って変わる」事故を避けるため、値の扱いは常に人が決めます。
トリアージの「採用」は所見自体を変えません。 confirmFinding は $review に 記録を残すだけで、内容の修正は別途 updateFinding で行います。
監査ログはまだありません。 誰が・いつ・どの指示で確認/却下したかは $review に残りますが、 AI に送った状態やプロンプトの全文までは残らない別トラックの課題です。
保存はサイドカーに同居します。 所見と型定義は、非破壊編集と同じ <dataset>.oniyanma.json(version 2 以降)に入ります。保存経路が 1 本のまま所見も残ります。 読み戻しのとき、手元にある同じ id は上書きしません(読み込みが作業を潰さないように)。 → 保存と書き出し