spec 1.0 · 規範
コンテンツカテゴリ
Leji は、5 つの論理的なコンテンツカテゴリを定義します。分類の基準は、文書が何のためにあるかであり、どこに置かれているかではありません。カテゴリ名は、マニフェスト、インデックス、ツールで使われる安定した識別子です。ディレクトリ名はチームが自由に決められます。
5 つのカテゴリ#
| カテゴリ | そこに属するもの |
|---|---|
domain |
ビジネスの言葉と製品の意味づけを、チーム自身の言葉で。中心となる名詞が何を意味し、互いにどう関係し、どの語がその現場だけの意味を持つか。ビジネスの状態の記録(案件のステータス、市場のスナップショット)も、記録としてここに分類されます。 |
system |
アーキテクチャとその不変条件。サービスの境界、データの所有、統合の契約、一貫性のモデル、失敗時の契約、すべての変更が付き合う制約。技術的な評価やシステムの報告も、記録としてここに分類されます。 |
practice |
自動的に適用される規約とパターン。コードの規約、テストのパターン、そして効果が確かめられたプロンプトやワークフローのパターン(下の収集のゲートを参照)。ある手法を適用した記録(振り返り、ランブックの実行ログ)も、記録としてここに分類されます。 |
governance |
エージェントのガードレールと運用の規則。エージェントが指示なしに何をしてよいか、何に人のゲートが要るか、データの取り扱い規則、エスカレーションの契機、コンプライアンスの統制。ガバナンスの証拠(監査ログ、レビュー報告)も、記録としてここに分類されます。 |
decisions |
物事がいまの形である理由の、日付のある記録。decisions.md に従います。 |
意図と記録#
統制される文書はすべて、カテゴリとは別に、意図か記録のいずれかに分類されます。
- 意図は、現在の真実として維持されるものです。用語集、不変条件、規約、ガードレールなどが該当します。読み手はこれを現行の情報として頼るため、現実が変われば文書を更新します。レビューの期限と鮮度の仕組みは、意図のためにあります(governance.md を参照)。
- 記録は、明示された時点または出来事の範囲内で主張を保存します。ステータス、評価、台帳、報告、会議の結論、アーカイブなどが該当します。後の状態は記録を訂正するのではなく取って代わり、元の記録はその時点の妥当な説明として残ります。記録がいつ時点のものかを示すのは、その日付であり、レビューの期限ではありません。
分類は、ひとつの問いで判断できます。後から得た情報がこの文書と食い違った場合、読み手が現在の情報として頼っているため文書を直す必要があるのか。それとも、新しい情報が文書に取って代わり、元の文書はその時点の妥当な説明として残るのか。 直すなら意図、取って代わるなら記録です。
記録は意図とまったく同じように統制されます。インデックスされ、レビューされ、所有者を持ち、経路が定められます。違うのは、読み手がそれをどう扱ってよいかです。読み手は、記録をいまの意図として扱ってはなりません(MUST NOT)。それは日付のある証拠です(context-layer.md の「記録を読む」を参照)。決定記録は、正式な記録の下位種です。本質的に記録であり、decisions.md に従う独自のスキーマとライフサイクルを持ちます。
記録に関するいくつかの論点は、意図的に 1.0 の対象外とされ、そのこと自体も明示されています。記録の系列という機械的な概念はありません(したがって、ツールがどの記録が「最新」かを認定することもありません)。ストリームの新しさを扱う仕組み(次に来るはずの記録が遅れているかどうか)もありません。意図と記録の内容が実質的に混在する文書について、セクション単位で種別を指定する仕組みもありません。混在する文書は分割すべきです(SHOULD)。分割の負担に見合わない場合は、下流の読み手が主に頼る契約に基づいて分類してください。どのカテゴリにも適切に収まらない内容は、参考資料のままにします。分類に判断が不要だと保証するものではありません。
要件#
- マニフェストは、宣言する各カテゴリを、リポジトリルートからの相対パスで表される 1 つ以上のインデックスファイル(
categories.<id>.indexes)に割り当てなければなりません(MUST)。各インデックスファイルは、context-layer.md に従って、宣言されたコンテキストルートの下にあるべきです(SHOULD)。インデックスファイルが宣言するのは収録であって、移動ではありません。内容はチームがすでに置いている場所(たとえばbusiness/、technology/、architecture/)に残り、ひとつのディレクトリが、何の名前も変えずに複数のカテゴリへ文書を提供できます。 - インデックスファイルは、
leji-indexのフェンス付きコードブロックを 1 つ以上持つ、人が選んで書いた markdown です。ブロックは、3 つ以上のバッククォートに続けてそのブロックの info 文字列を書いた行で開き、次の 3 つ以上のバッククォートの行で閉じます。閉じフェンスのバッククォートの数が開きフェンスと一致している必要はありません。妥当な info 文字列はちょうど 3 つです。leji-index(意図のブロック)、leji-index intent(同じものを明示したもの)、leji-index record(記録のブロックで、その各エントリは記録として解決されます)。leji-indexの後にそれ以外のトークンが続くものはパースエラーであり、黙って無視されることはありません。この文法は意図して有限です。各ブロックは内容を 1 行に 1 エントリ、- path: <リポジトリルートからの相対パス>の形で列挙します。パスはディレクトリ(その下の markdown が再帰的に含まれます)か、markdown ファイル 1 つです。パスはリポジトリルートからの相対の POSIX 形式でなければなりません(MUST)。先頭の/、..のセグメント、バックスラッシュは不正であり、拒否されます。空行と行全体の#コメントは無視され、エントリは末尾に空白を前置した# コメントを持っても構いません(MAY)。この文法における空白は ASCII のスペース(U+0020)とタブ(U+0009)だけです。これは、文法が空白を参照するすべての場所、すなわちフェンスのバッククォートと info 文字列の周り、エントリ行の前後の空白、末尾コメントを開く#の前にも当てはまります。先頭の UTF-8 バイトオーダーマークは、パースの前に取り除かれます。行は LF で分割され、末尾の CR は許容されます。ファイルは UTF-8 です。実装はここでランタイムの空白クラスを使ってはなりません(MUST NOT)。ランタイムがたまたま空白に分類するそれ以外の文字は、U+0085 と U+00A0 を含めて通常のパスの内容であり、そうした文字を含むパスを持つエントリは、黙って切り詰められるのではなく、見つからないものとして報告されます。boot-profile.md のleji-mountsブロックも同じ文字集合に固定されているので、ひとつのスキャナが両方の文法を読め、3 つの実装がフェンスの有無について食い違うことはありません。ひとつのファイルの中の複数のブロックは、文書の順に連結されます。ブロックの周りに散文や見出しを置いてよいので、インデックスファイルは人が読めるそのカテゴリの地図も兼ねます。走査は行単位で、markdown の構造は参照しません。任意のスペースまたはタブの字下げのあとに 3 つ以上のバッククォートとタグを持つ行は、より長いフェンス付きの例の中でも、リスト項目の中でも、文書のどこにあっても本物のブロックを開きます。したがって、宣言ではなく説明のための例は別のタグでフェンスします。leji-indexの後にトークンを足すのではありません。スキャナが照合するのはタグなので、leji-index exampleは本物のブロックを開いてパースエラーを報告し、textとタグ付けされたフェンスは何も開きません。推奨される場所は、コンテキストルート下のcontext/<id>.mdです。場所は設定可能であり、ツールがそれを固定的に埋め込むことはありません。 - コンテキストレイヤーは、いずれかの適合レベルを宣言するために、少なくとも
domainかsystemのどちらかと、decisionsを割り当てなければなりません(MUST。conformance.md を参照)。また、内容のあるdomain/systemの最低要件には、少なくとも 1 つの意図の文書が含まれなければなりません(MUST)。記録だけのコンテキストレイヤーは、履歴は保存しますが、運用上のコンテキストを持ちません。他のカテゴリは、チームが実際の問いにぶつかるにつれて積み上がります。空のカテゴリ(インデックスファイルがどの文書にも解決しないもの)を、チェックリストを満たすために割り当ててはなりません(MUST NOT)。 - 文書は、ちょうど 1 つのカテゴリと 1 つの種別に解決されます。インデックスのエントリはセレクタであり、解決はセレクタの限定度に従います。ファイルを直接指すセレクタは、あらゆるディレクトリのセレクタに勝ち、より深いディレクトリのセレクタは、その祖先のディレクトリのセレクタに勝ちます。ある文書を覆うもっとも限定的なセレクタが、その文書のカテゴリとブロックの種別を決めます。より広いセレクタが覆っていても、より限定的なセレクタが勝った文書は、単にその広いセレクタの内容ではなくなります(記録のディレクトリの中にある、いまのものとして維持される 1 ファイルや、より広く割り当てられたツリーの中にあるひとつのチームの決定ログは、こうして何も動かさずに表現されます)。カテゴリまたは種別について食い違う同じ限定度のセレクタはエラーであり、インデックスの順序で解決されることは決してありません。同じ限定度で同一の割り当てをするものは一度だけ解決され、ひとつのインデックスファイルの中で文字どおり重複したエントリは拒否されます。ツールは、覆っているすべての文書がより限定的なセレクタに取られてしまったセレクタ(影に隠れたセレクタ)を示すべきです(SHOULD)。それは人が書いた地図に残る不要な記述であって、エラーではありません。それ以外の点で解決は決定的です。ディレクトリのエントリは、その下の markdown へ POSIX の辞書順(Unicode コードポイント順。実装をまたいで順序が一意になるよう、パスは ASCII にとどめることが推奨されます)に展開され、実際の場所(シンボリックリンクを解決したあと)がリポジトリルートの外に出るパスは、たどられるのではなく除外されます。インデックスのエントリ(machine-readable-surface.md を参照)は、カテゴリ識別子と種別を持ちます。
- 文書は、自らの種別をフロントマターで宣言しても構いません(MAY。
kind: intentまたはkind: record)。フロントマターは、勝ったセレクタのブロック種別を上書きしますが、カテゴリを上書きすることは決してありません。それ以外のkindの値はエラーです。決定記録はkindキーを取りません(そのスキーマは閉じており、本質的に記録だからです)。記録はフロントマターのdate(YYYY-MM-DD)を持っても構いません(MAY)。ツールが記録の日付を読むのはその項目からだけであり、散文、見出しの慣習、ファイル名から読むことはありません。記録はfreshness.reviewAfterを持ってはなりません(MUST NOT)。レビューの期限は意図のための仕組みであり、記録に付けると、その文書が持ち得ない現在性を約束することになるので、エラーです。 - プロンプトやワークフローのパターンを記した practice の内容は、そのパターンが少なくとも二度うまくいったあとにだけ収集すべきです(SHOULD。二度実証のゲート)。早すぎる収集こそが、practice のディレクトリを願望で埋める原因です。
補足(非規範的)#
初日からすべてのカテゴリを揃える必要はありません。最小限のコンテキストレイヤーに必要なのは、最初の 1 か月の仕事で実際に頼る内容です。カテゴリを設ける目的は、人やエージェントが「これはどの種類の真実か」を判断し、ツリー全体ではなく、目の前の作業に有効な部分だけを読み込めるようにすることです。
2 つの種別を設けているのは、実際のリポジトリにあるドキュメントには、真実の捉え方が異なる 2 種類の情報が混在するからです。運用に関する情報まで意図として扱うと、どちらもうまく機能しません。守れない鮮度の保証が生まれるか、リポジトリの大半がガバナンスの対象外になるかのどちらかです。記録用ディレクトリ内に意図の例外を 1 つ置く場合、実際の形は次のようになります。
# Domain context
```leji-index
- path: docs/glossary.md
```
Operational state is governed as records; the escalation policy stays intent.
```leji-index record
- path: docs/operations/
```
```leji-index intent
- path: docs/operations/escalation-policy.md
```