はじめての問題パック Stable
このチュートリアルは、空のディレクトリから問題パック (problem pack) を 1 つ作り、検証し、
不変な Git リビジョンに固定して公開し、インストールし、テナントに対して有効化し、
イベントに固定するまでの、開発者の主要な道筋を 1 本でたどります。最小の 1 パック
(com.example.starter、問題 1 個の hello-world) だけを使います。
パックの概念そのものは problem packs を、 最初のデプロイ全体像は getting started を参照してください。 このページは契約 (スキーマや診断コードの一覧) を再掲せず、各リファレンスへリンクします。
既存のパックを動かしたいだけの場合は → 既存パックを使う を参照してください。
前提条件
このチュートリアルの「作成 → 検証 → インストール → 有効化」までは、クラウド資格情報なしの 完全オフラインで完了します。プラットフォームへの実デプロイに到達する手順 (最後の節) でのみ AWS アカウントが必要です。
- Bun 1.3.11
- リポジトリのチェックアウト (
git clone済み)。packCLI は リポジトリルートからmake pack-*ターゲット経由で呼び出します (実体は./node_modules/.bin/tsx infrastructure/bin/tenkacloud-pack.ts。CLI の既定 store./.tenkacloud/pack-storeは CWD 基準で解決されるため、リポジトリルート実行が前提です)。 git2.x 以降 (固定リビジョンの SHA を取得する手順で使用)
CLI は完全にオフラインです。ネットワーク・CDK synth・クラウド資格情報を一切使いません。
1. パックを作成する
空の作業ディレクトリから始めます。pack init <dir> は、検証を 0 件の診断で通過する
パック (マニフェスト + 問題 1 個 + プロバイダー成果物のプレースホルダー + README) を生成します。
make pack-init ARGS="./my-first-pack"
期待される出力:
Pack scaffolded at ./my-first-pack (4 files). Run 'pack validate ./my-first-pack' to check it.
--runtime <provider/engine> を付けるとランタイムを選べます (既定は aws/cloudformation)。
対応ランタイムは aws/cloudformation / gcp/infra-manager / azure/bicep / sakura/apprun です。
生成されるマニフェスト (tenkacloud-pack.json)
パックの唯一のエントリーポイントです。完全な最小例:
{
"schemaVersion": 1,
"id": "com.example.starter",
"version": "0.1.0",
"core": "^1.0.0",
"title": "Starter pack",
"description": "A scaffolded TenkaCloud problem pack. Edit the metadata and artifact, then validate.",
"license": "Apache-2.0",
"problemsRoot": "problems",
"requiredRuntimes": [
{
"provider": "aws",
"engine": "cloudformation"
}
]
}
生成される問題メタデータ (problems/challenges/hello-world/metadata.json)
完全な最小例:
{
"id": "hello-world",
"title": "Hello World",
"category": "challenges",
"description": "A starter problem. Replace this with your own challenge.",
"runtime": {
"provider": "aws",
"engine": "cloudformation",
"entry": "template.yaml"
}
}
マニフェストと metadata.json の各フィールドの意味は problem packs を参照してください。
2. パックを検証する
pack validate <dir> はオフライン検証器です。スキーマ・問題 ID の一意性・成果物の存在・
ランタイム整合などを検査します。
make pack-validate ARGS="./my-first-pack"
期待される出力:
Pack is valid: 1 problem.
- hello-world
機械可読な出力が必要なときは --json を付けます。
終了コードは 0 (成功) / 1 (検証失敗) / 2 (ツール失敗: ディレクトリ欠落・マニフェスト欠落・誤用) です。
3. 不変な Git リビジョンに固定して公開する
公開はパックを「不変な Git のコミット」に固定して共有することです。**ブランチ名・タグ・HEAD・
短縮ハッシュは設計上拒否されます。**固定できるのは完全な 40 桁の SHA だけで、これにより
同じパック内容が将来にわたって絶対に変わらないこと (immutability) を保証します。
別の Git リポジトリ (このコアリポジトリの problems/ ツリーの外) にパックをコミット・push し、
固定したいリビジョンの完全な SHA を取得します:
git -C ./my-first-pack init
git -C ./my-first-pack add .
git -C ./my-first-pack commit -m "First pack"
git -C ./my-first-pack rev-parse HEAD
期待される出力 (40 桁の 16 進数。値はコミットごとに異なります):
3f1c226be0565fa2c90df44e9b1acd5a90e84be2
この SHA が公開単位です。リモートに push し、HTTPS URL と SHA を配布します。
固定リビジョンの実運用手順は
infrastructure/lib/problem-pack/README-external-git-pack.md のランバックに対応します。
4. パックをインストールする
ローカルディレクトリからインストールできます。インストールは「検証 → スナップショット → ロック → dry-run compose」を原子的に行い、有効化はしません。失敗したインストールは残骸を残しません。
make pack-install ARGS="./my-first-pack"
期待される出力 (digest はパック内容のハッシュで、ここでは生成物に対する一例):
Pack installed: com.example.starter@0.1.0
source: local
digest: b1acd5a90e84be2a2e1ca78f77396ee6c447c9c3f1c226be0565fa2c90df44e9
problems: 1
固定した Git リビジョンからインストールするときは install git を使います。HTTPS URL と
完全な 40 桁 SHA が必須です:
make pack-install ARGS="git https://github.com/<you>/my-first-pack.git --commit <full-40-hex-sha>"
ロック (packs-lock.json) には sourceKind: "git"・解決済みコミット・任意の subdir・
コンテンツダイジェストが記録されます。インストール済みパックは list で確認できます:
make pack-list
期待される出力:
Installed packs: 1
- com.example.starter@0.1.0 (local, 1 problem, b1acd5a90e84be2a2e1ca78f77396ee6c447c9c3f1c226be0565fa2c90df44e9)
5. テナントに対して有効化する
インストール済みの不変リビジョンを、1 つのテナントに対して有効化します。重複する問題 ID・ 利用不可なランタイム・ダイジェスト不一致・未インストールは拒否されます (終了コード 1)。
make pack-activate ARGS="com.example.starter@0.1.0 --tenant acme"
期待される出力:
Pack activated for tenant 'acme': com.example.starter@0.1.0
別テナントからは見えません (テナント分離)。元に戻すには deactivate を使います。
6. イベントを作成する Preview
イベント作成は、そのテナントの実効カタログ (core + 有効化済みパックリビジョン) を
作成時点で不変なスナップショットに固定します。一度固定したイベントのカタログは、後から
deactivate / install / activate をしても書き換わりません。
イベントのスナップショット固定を実際に行うのは、イベント作成 API (handlers/event-handler/create.ts
の Lambda) です。作成時に catalogSnapshotId とパック provenance を、そのイベント行へ直接焼き込みます。
使う provenance は synth 時点で有効化済みのパックから焼き込まれた provenance map
(環境変数 BATTLE_PROBLEMS_PROVENANCE として埋め込み済み) から取り出します。ライブラリ
infrastructure/lib/problem-pack/event-pin.ts の createEventSnapshot / EventSnapshotStore は、
この API と同じ契約を CLI やテストからオフラインで再現するための等価実装であり、実際にデプロイされる
経路そのものではありません。ここまでの CLI 手順 (作成 → 検証 → インストール → 有効化) はすべて
実装済み (stable) ですが、ブラウザからのイベント作成 UI はプラットフォーム層であり、このページでは
preview として扱います。
7. オーガナイザーコンソールで検証する Preview
イベント作成後、オーガナイザーコンソールでイベントが固定スナップショットを参照していること、
デプロイがそのイベントの固定パック provenance を解決していることを確認します。
オフラインの等価チェックは infrastructure/test/problem-pack/external-git-pack-e2e.test.ts が
注入したフェイク transport に対して同じ契約を検証します。加えて
infrastructure/test/problem-pack/pack-lite-full-chain-e2e.test.ts は、CLI の作成・検証・
インストール・有効化から Lite の synth 配線・実際のイベント作成ハンドラ・デプロイ provenance の
刻印までを、実コードのみで一本の鎖として通す、より広いオフライン E2E です。
8. 撤去する
不要になったリビジョンは remove で取り除けます。イベントや有効化がそのリビジョンを
固定している間は拒否されます (不変カタログの保護)。先に deactivate し、固定参照を外してから
削除します。
make pack-deactivate ARGS="com.example.starter@0.1.0 --tenant acme"
./node_modules/.bin/tsx infrastructure/bin/tenkacloud-pack.ts remove com.example.starter@0.1.0
期待される出力:
Pack deactivated for tenant 'acme': com.example.starter@0.1.0
Removed com.example.starter@0.1.0.
pack CLI には update がありません。新しいバージョンは別のインストールとして扱います。
よくある失敗 → 診断コード
検証失敗のとき CLI は [CODE] file:path 形式で診断を表示します。コードが契約であり、
メッセージ文字列は契約ではありません。診断コードの完全な一覧と公開名前空間付きコードへの対応は
problem packs を参照してください。実際に観測できる例:
| 症状 | コード | 意味 |
|---|---|---|
| ディレクトリが存在しない | PACK_DIR_MISSING |
渡したパスにパックがない。tenkacloud-pack.json を含むディレクトリを渡す。 |
tenkacloud-pack.json がない |
MANIFEST_MISSING |
ルートにマニフェストがない。すべてのパックは 1 つ宣言する。 |
version が SemVer でない |
MANIFEST_INVALID |
例: version must be a valid SemVer。tenkacloud-pack.json:version を直す。 |
| 問題 ID が重複している | DUPLICATE_PROBLEM_ID |
パック内で問題 ID が一意でない。 |
| 成果物 (template など) が欠落 | ARTIFACT_MISSING |
metadata の runtime.entry が指すファイルがない。 |
| ランタイムがマニフェストと不一致 | RUNTIME_MISMATCH |
問題のランタイムが requiredRuntimes にない。 |
例えば version を壊して検証すると次のように出ます:
Pack validation failed: 1 diagnostic(s).
[MANIFEST_INVALID] tenkacloud-pack.json:version
version must be a valid SemVer
PACK_DIR_MISSING / MANIFEST_MISSING / MANIFEST_UNREADABLE は終了コード 2 (ツール失敗)、
それ以外の検証診断は終了コード 1 (検証失敗) です。
プラットフォームへデプロイする Preview
ここから先は AWS アカウントが必要です。固定パックをプラットフォームに載せ、参加者ポータルまで
通すには getting started の Lite モード (make deploy) に従います。
パックは Lite モード専用です。Lite の固定 tenantId は local なので、有効化は
--tenant local で行ってください (make pack-activate ARGS="com.example.starter@0.1.0 --tenant local")。ここまでの手順で --tenant acme を使った場合はオフライン検証のためで、
そのままではクラウドデプロイに反映されません。SaaS モード (make deploy-saas) はパックを
サポートしません。有効化が 1 件でも残っていると synth を明示的に拒否します
(エスケープハッチは CDK_PARAM_SAAS_IGNORE_PACKS=true ですが、その場合パック問題は
デプロイに現れません)。
次のステップ
- problem packs でパックの概念を確認します。
- getting started から始めます。
- API リファレンス を参照します。