ラボに「研究員」を置く — VMOST を抽象と具体に割り、実験ログを人に帰属させた
サイトには VMOST も Roadmap も Log もあるのに、「誰が・なぜ挑戦しているのか」を語る顔がなかった。そこで研究員ページ(/researchers)を建てた記録。単なる自己紹介ページではなく、サイト共通の VMOST を『抽象(どんな生き方を設計するか)』に寄せ、数値・行動の『具体版 VMOST』を研究員に持たせる情報設計の組み替えになった。全実験ログを研究員に帰属させ、Person の構造化データ・RSS の dc:creator・JSON Feed・llms.txt まで貫いた配線、AI 調査で実在人物の経歴を盛り込んで判断して全部剥がした persona 設計、そして「静かな脱落をビルドで落とす」チェックの追加まで、つまずきごと残します。
何をしたかったか — ラボに「顔」がなかった
VMOST で設計図を描き、Roadmap で次の一手に落とし、 Log で実施結果を一次情報として残す——この線は前に一本につないだ。 解説トピックもショーケースもある。それでも一つ、決定的に欠けていた。
「誰が・なぜ、これをやっているのか」を語る場がなかった。
Vision に掲げたのは「その姿そのものを、次に続く人へのロールモデルとして示す」こと。
なのにサイトのどこにも、その「姿」の入口がない。ロードマップにも about-profile
(プロフィール/ロールモデルページ)が P2 で積まれたまま、構造化データを実装したとき
に「Person の JSON-LD はプロフィールページを作るときに足す」と保留したままだった。
だから顔を作ることにした。ただし、ありがちな「About Me」ページにはしたくなかった。 このサイトは VMOST で生き方そのものを設計している。その設計図と切り離した自己紹介を 別に置くと、また分断が生まれる。顔を、VMOST の線の上に載せる——それが狙いだった。
設計 — VMOST を「抽象」と「具体」に割る
考えているうちに、これは自己紹介ページの問題ではなく VMOST の粒度の問題だと分かった。
いまの /vmost には、Vision も Objectives も「週 4 件の発信」「TOEFL iBT 100」のような
具体的な数値・期限が書いてあった。だがサイトの VMOST は本来「どんな生き方を設計するか」
という枠組みのはず。個人の実数値がそこに混ざっていると、将来 research を担う人が増えたとき
(このラボは「一人の人間が自分の生き方を実験台にする私設ラボ」で、いまは一人だが)、
サイト共通の枠組みと個人の数値が同じ場所で二重管理になる。
そこで一本、線を引いた。
- 抽象 VMOST(/vmost) … 「どんな生き方を設計するか」の枠組み。サイト共通。
- 具体 VMOST(各研究員) … その枠組みを本人の数値・行動に落とし込んだ版。
/vmost から具体的な数値・期限を剥がし、それを研究員の「具体 VMOST」へ移す。
両者は相互リンクで往復できるようにする。研究員とは、抽象 VMOST を具体に落とす器
——この見立てが、顔ページの背骨になった。
やってみたこと
1. 研究員というデータモデル
研究員の唯一の出所を content/researchers.ts に作った。1 人分は slug / name /
handle(@ 抜き)/ status(active・alumni)/ role / tagline / bio / focus
(3 本柱に対応する注力領域)/ vmost?(具体版)/ cover を持つ。いまは Hiro 一人。
単一の出所を貫くために、地味だが効く判断を一つ。X の URL はフィールドで持たず、handle から導出する。
// handle(@抜き)だけを持ち、URL は必ずここで組む。二重管理を作らない。
export const researcherXUrl = (r: Researcher): string =>
`https://x.com/${r.handle}`;
当初は x: "https://..." を手書きしていたが、handle 表記とズレても型では気づけない。
URL を組む場所を一箇所に寄せ、詳細ページの X ボタン・JSON-LD の sameAs・llms.txt の
著者行が、すべてこの関数を通るようにした。
2. VMOST 抽象/具体分離
/vmost の objectives から個人固有の数値・期限を剥がし、抽象文言へ書き換えた
(「週 4 件の発信を定常化」→「発信の定常化」、期限 2027-06 → 中期)。数値が抽象側から
消えたので、「この数値は暫定」を示していた Objective.provisional(暫定バッジ)フィールドは
型ごと削除した。抽象化がデータモデルを一段単純にした。
剥がした具体は研究員の vmost.concrete へ移した。concrete は V/M/O/S/T ごとに散文でも
箇条書き配列でも持てる形にし、表示側が配列なら <ul> に開く。
表示フォーマットは分けた。トップの VMOST サマリーは各階層を一行で並べる VmostStepList、
研究員ページは各階層を 1 枚のカードにして、上に小さく「抽象 / SUZ-LAB」、下に大きく
「具体 / 本人」を縦に対比させる専用の ResearcherVmost。抽象と具体を隣り合わせて見せる
のが研究員ページの主役なので、共有をあえてやめた(この判断の紆余曲折は後述)。
導線も往復で閉じた。/vmost(抽象)→「具体的な VMOST は各研究員のページへ」→ /researchers、
研究員カードの各階層「抽象 / SUZ-LAB」行 → /vmost#{anchor}(具体 → 抽象)。
3. 実験ログを研究員に帰属させる
「実験は研究員が回す」という見立てを、ログのメタデータに落とした。ログ frontmatter に
任意の author(研究員 slug)を足し、省略時は既定の研究員(いまは Hiro)に帰属させる。
export const DEFAULT_LOG_AUTHOR_SLUG = "hiro";
// frontmatter の author か、省略時は既定の研究員に解決する。
export const logAuthor = (log: LogFrontmatter): Researcher | null =>
getResearcher(log.author ?? DEFAULT_LOG_AUTHOR_SLUG);
既存 12 本のログには author を書いていない——全部が既定の Hiro に帰属する。1 人のうちは
これで十分で、増えたら書くだけ。この帰属を、体裁と機械可読の両レイヤーへ貫いた。
- ログ詳細の byline に「研究員 」を出し、
/researchers/{slug}へ逆リンク。 - 研究員ページは
getLogsByAuthor(slug)で「その研究員の実験ログ」を並べる。 - JSON-LD … BlogPosting の
authorを Person 化し、@id: /researchers/{slug}#personで研究員の Person ノードと連結(構造化データで保留にした Person をここで出した)。トピックは発行元を Organization のままにした。 - RSS …
<author>は仕様上メールアドレス必須なので、名前だけ出せる Dublin Core の<dc:creator>を採用した。 - JSON Feed …
authors(名前+プロフィール URL)と、拡張名前空間で著者の X URL (一次情報の入口)を添えた。 - llms.txt … 各ログの Markdown 版に「著者: (・プロフィール・X)」を追記。
これで「ログ ⇄ 研究員 ⇄ VMOST 具体」がひとつながりになった。
4. ロードマップを追随させる
顔ができたので、ロードマップを実態に合わせた(この更新はこの記事と同じ変更に含めた)。
about-profileを 未着手 → 完了に。frontmatter のroadmap: "about-profile"で、 この記事がその実施 Log として逆引きされる。objectives-smart(Objectives を SMART に)とdashboard(進捗ダッシュボード)の本文を、 具体的な数値・期限の出所が研究員の具体 VMOST(content/researchers.ts)に移ったことに 合わせて書き直した。SMART 化もダッシュボードの計測も、これからは抽象 VMOST ではなく 研究員の具体側を対象にする。
顔を足すだけのつもりが、VMOST → Roadmap → Log の背骨に「研究員」というノードを一つ挿し、 数値の置き場所を組み替える変更になった。
つまずき
調査を入れて、全部剥がした
一番の紆余曲折はここ。研究員に厚みを持たせようと、まず AI に Web 調査(一次情報中心・ 敵対的検証つき)をやらせ、実在の経歴——本名、CTO 経験、技術書の共著、大学院——を bio・ 「経歴・実績」節・VMOST へ盛り込んだ。「まず、やってみる」で、いったん全部入れた。
そのあと、判断して全部剥がした。段階的に、実名表示 → 「経歴・実績」節と background
フィールド → bio の職歴段落 → focus / VMOST の職歴語、の順で。理由は二つ。
- 実在人物のプライバシー。 実名と勤務先を紐づけた経歴を、本人の生き方の実験ログと 同じ場所に常設で置く必然性はない。ラボの語り口は persona「Hiro」で通すことにした。
- AI 調査は裏取りしても残余リスクがある。 敵対的検証の過程で「ある受賞歴」が本人には 無いと反証され、記載を見送った一件があった。個別には潰せても、実在人物の経歴を丸ごと 載せる限り「もっともらしい誤り」の混入リスクはゼロにならない。
残したのは、VMOST の具体と、手を動かした実験ログそのもの。経歴で語るのではなく、 やったことで語る——このラボの Strategy「一次情報で語る」と、結果的にきれいに揃った。
VMOST 表示フォーマットの二転三転
共有(DRY)を狙って、分離に転じた話
最初は VmostStepList を「本文だけ差し替えれば抽象版と具体版で使い回せる」共有部品に
しようとした。DRY の直感としては正しい。だが作ってみると、研究員ページで見せたいのは
「抽象と具体の対比」で、トップで見せたいのは「抽象版の一覧」——そもそも見せ方が違う
と気づいた。無理に一つの部品へ畳むと、両方に効く分岐が増えて読みにくくなる。
そこで割り切った。VmostStepList は抽象版専用に戻し、研究員の対比表示は専用の
ResearcherVmost を新設。「同じに見えるから共有」ではなく「意図が同じなら共有」。
一度 DRY を狙って、意図が違うと分かって分離した——この往復自体が判断の記録になる。
静かな脱落をビルドで落とす
author を導入して怖かったのは、解決に失敗したとき静かに消えること。logAuthor が
null を返すと、byline も JSON-LD も RSS も Feed も llms.txt も研究員一覧も、
エラーを出さずにただ「著者なし」になる。壊れているのに気づけない。
そこで check:content(pnpm build に組み込み済みのコンテンツ検査)に一節足した。
- 既定著者 slug と、全ログの
authorが、実在する研究員に解決することを検査する。 author: 123のような文字列以外は型エラーで落とす。空文字・空白は「未指定」として 既定へフォールバックするが、誤った型は静かに既定化させず、はっきり落とす。
TypeScript では守れない「Markdown の値が実在する slug を指しているか」を、ビルド時に 潰す。公開 MCP サーバの slug 検証と同じ思想で、 静かな脱落は実行時に晒す前にビルドで殺す。
検証
pnpm typecheck/pnpm lint/pnpm format:check… いずれもパス。pnpm build(check:content込み)…/researchersと/researchers/hiro、全ログが 静的生成され、authorと既定著者が実在研究員へ解決することを確認。- 生成物を突き合わせ、双方向リンクが実際に描画されることを確認した——ログ詳細から
研究員への byline、研究員ページの「Hiro の実験ログ」、
/vmost⇄/researchersの 抽象/具体リンク、JSON-LD の Person が@idで BlogPosting の author と連結、RSS の<dc:creator>。
学び
- 「自己紹介ページが無い」という UI の欠落に見えたものは、掘ると VMOST の粒度(抽象と 具体の混在) という情報設計の問題だった。器を足す前に「何をどの層で持つか」を割ると、 ページは自然に決まる。
- 単一の出所は、剥がすときにも効く。 数値を抽象 VMOST から研究員の具体へ移すのも、
経歴を丸ごと抜くのも、出所が
content/*の一箇所に寄っていたから安全に動かせた。 - 「まず、やってみる」は「まず、残す」ではない。 AI 調査で経歴を入れてみて、判断して 剥がす——やってみたからこそ、persona で通すという線引きに確信が持てた。やってみることと、 出すことは別の判断。
- 顔をこのサイトで作る営みそのものが、ドッグフーディングだった。
次はこの研究員の具体 VMOST を出所に、
objectives-smart(数値の SMART 化)とdashboard(進捗の可視化)へ進む。




