ソース調査ポインタ集
このノートは腐る
行番号は当時のリポジトリのスナップショットであり、対象リポジトリが更新されれば合わなくなる。ここにあるのは結論ではなく再調査の足がかり — 「どのファイルのどのあたりを見れば確認できるか」の記録である。行番号が合わない場合は関数名・シンボル名で探し直すこと。調査時点は2026-04-26〜2026-04-27。
CDK
論理ID生成
aws/constructsリポジトリのsrc/construct.ts:503(Constructクラス)node.path: scope列を/区切りで連結(construct.ts:92-100)Stack.allocateLogicalId(packages/aws-cdk-lib/core/lib/stack.ts:1393-1398)makeUniqueId()(packages/aws-cdk-lib/core/lib/private/uniqueid.ts:21-23, 65-83)- MD5(path.join('/'))の先頭8文字を大文字16進
- removeNonAlphanumeric(各component).join('')を最大240文字に切ったもの + 8文字ハッシュ(合計 ≤ 255)
- 親stack名はpathに含まれない(stack単位でローカル)
Defaultは完全除外、Resourceはhuman portionからは除かれるがハッシュには含まれる
- ハッシュなし条件(
uniqueid.ts:34-63): components.length === 1かつ非英数字除去後が255文字以内、stack直下のL1のみ
Escape hatches
node.defaultChildでL1取得addPropertyOverride/addOverride/addDeletionOverrideoverrideLogicalId('FixedId')で論理ID明示制御
synth / deploy
- 公式: Configure synth, Deploy applications, cdk deploy CLI ref
- 出力: cloud assembly (
cdk.out/配下、CFNテンプレート + assets + metadata) - deployment method:デフォルトChangeSet経由(
--method change-set)、--method directでスキップ可、hotswapモードあり
Token
- 公式Tokens
Token.asString()/Token.asNumber()/Token.asList()で生成- 内部にplaceholder文字列
${Token[Bucket.Arn.0]}を持ち、synth時にCFNテンプレートのFn::GetAtt,Fn::Join等に変換される
context lookup
- 公式Context values
- 経路: contextが不足しているとappがCDK Toolkitに通知 → CLIがAWSアカウントに問い合わせ →
cdk.context.jsonに保存 → その値を渡してappを再実行。AWSを呼ぶのはCLIであって、synth中のapp自身ではない - キャッシュ: 一度取れた値は
cdk.context.jsonに凍結され、以降のsynthは同じ値を使う。cdk context --reset <key>/cdk context --clearで明示的に捨てるまで更新されない。狙いは「AZが増えた」等の外界の変化が予期せぬdiffになるのを防ぐこと - キー形式:
availability-zones:account=123456789012:region=eu-central-1のようにaccountとregionを含む(環境ごとに衝突しないため) - lookupを起こすメソッド:
HostedZone.fromLookup/stack.availabilityZones/StringParameter.valueFromLookup/Vpc.fromLookup/LookupMachineImage Vpc.fromLookupのAPI doc: 「CDK CLI実行時にlookupが起きる。したがってCloudFormation実行時にしか判明しない値(Token)は渡せない」cdk.json/cdk.context.jsonは「アプリケーションの状態の一部」としてソース管理へのコミットが要求されている。コミットしないとCIなど別環境で結果が食い違う
Best practices
- Best practices — 「Make decisions at synthesis time」。ホスト言語ループでのConstruct生成を推奨、配列/Map格納も推奨例。statefulリソースのlogical ID変更で置き換えが発生する旨の注意喚起あり
Pulumi
URN
- フォーマット:
urn:pulumi:<Stack>::<Project>::<Qualified$Type$Name>::<Name>(sdk/go/common/resource/urn/urn.go:38) - 区切り文字:
NameDelimiter = "::",TypeDelimiter = "$"(L54-55) - 親type連結ロジック(L80-93):
if parentType != "" && parentType != tokens.RootStackType { typ = string(parentType) + TypeDelimiter + typ } - physical name生成(
pulumi-terraform-bridge/pkg/tfbridge/names.go:181-185): "8 character random suffix ('-' + 7 random chars)" aliasesで旧URNを保持: docsを要確認- 公式Names and URNs — resourceオブジェクト参照を変数で渡すパターンを推奨。名前やparentの階層変更でURNが変わると別リソース扱いになる警告あり
実行モデル
- 公式: How Pulumi Works, resource-registration.md
- proto:
proto/pulumi/resource.proto(ResourceMonitorサービス、RegisterResourceRPC)、proto/pulumi/provider.proto、proto/pulumi/language.proto、proto/pulumi/engine.proto - TS SDK:
sdk/nodejs/runtime/resource.ts(registerResource())、sdk/nodejs/resource.ts(Resourceクラス) - engine側:
pkg/resource/deploy/source_eval.go(RegisterResource受信ループ)、step_generator.go(差分→step生成)、deployment_executor.go(step実行) - preview/up:
pkg/engine/preview.go,pkg/engine/update.go - Update Plans: docs, PR #8448
- PCL: Converters docs
Output<T>
行番号は master cd514ac1d(2026-08-14、sdk/nodejs/output.ts 全1341行)で確認したもの。初出時から概ね+1ずれていたので更新した。
- 実装:
sdk/nodejs/output.ts:65-391(OutputImpl<T>クラス。旧記載の64-144はフィールド宣言の範囲でクラス全体ではなかった) - 型定義:
export type Output<T> = OutputInstance<T> & Lifted<T>(L1137) then不在: Proxyのgetトラップでif (prop === "then") return undefined(L301-306)。コメントは「他のシステムがPromiseかどうかの判定に使うので、そうだと示したくない」。プロパティ持ち上げのProxyを入れたPR #2510(2019-03)で同時に入っており、任意のプロパティ名をapplyに持ち上げる仕組みの副作用(thenまで持ち上がってawaitが壊れる)を塞ぐための処置- 内部状態:
isSecret: Promise<boolean>(L84)、isKnown: Promise<boolean>(L96、preview時に未確定ならfalse)、promise: () => Promise<T>(L110)、resources: () => Set<Resource>(L124)、allResources?: () => Promise<Set<Resource>>(L144) Input<T>:export type Input<T> = T | Promise<T> | OutputInstance<T>(L935)- 連鎖メソッド:
apply()(L370),pulumi.all()(実体L795、doc含めL773-806),pulumi.interpolate(L1248),concat(L1232) - preview時の挙動:
applyHelperAsync(L490-523)でconst doApply = isKnown || runWithUnknowns(L500)、偽ならreturn { value: undefined, isKnown: false, isSecret }(L502-509) —funcを実行せず未知Outputを返す。isKnownはエンジン由来の値をそのまま使わず、コンストラクタ(L246-248)でcontainsUnknowns(val)をANDして再計算する。runWithUnknownsは公開シグネチャに無い内部の抜け穴(apply<U>(func, runWithUnknowns?)L370、SDK内の唯一の呼び手は持ち上げProxy自身 L356)で、この経路ではコールバックに未知センチネルが渡る。詳細はpreviewはapplyのコールバックを近似しない、実行しない - deploy中実行: 「
pulumi upでプログラムが実行されるとき、apply関数はリソースが作られてプロパティが解決するまで待ってから目的の値を出力する」(applyページ) toString/toJSON:OutputToStringError(L23-54)、宣言はL168 / L191。既定では投げない —utils.errorOutputStringが設定されているときだけ投げ、既定ではエラー文言を文字列として返しThis function may throw in a future version of @pulumi/pulumi.を付ける。つまり`${output}`は既定でエラーメッセージを埋め込む- secret伝播: 実行された場合は
liftInnerOutput(allResources, transformed, /*isKnown*/ true, isSecret)(定義L461、呼び出しL523)。コールバックがOutputを返した場合は外側と内側のORを取る(L485)。スキップされた場合もisSecretはそのまま引き継ぐ(L508) allの集約は非対称: known はevery、secret はsome(L825-859)。1つでも未知なら全体が未知になり(=previewでコールバックが飛ぶ)、1つでもsecretなら全体がsecretになる- stack outputs は
applyの中で作ることができない(禁止)。「applyの中でリソースを作るのは避けよ」(非推奨)と併記されているので混同しないこと - 公式docs: inputs-outputs, applyページ, allページ
Terraform
resource address
<type>.<label>形式(例:aws_s3_bucket.foo)- module内:
module.network.aws_s3_bucket.foo for_each付き:aws_s3_bucket.foo["key"]count付き:aws_s3_bucket.foo[0]movedブロック(1.1+):moved { from = aws_s3_bucket.old to = aws_s3_bucket.new }
plan / state / 型
- tfplan binaryは不可侵だが
terraform show -jsonでJSON出力可、terraform-jsonGoライブラリで型付き読み取り可。内部加工する標準手段はない terraform testでアサーション、OPA/Sentinel/conftestでポリシー検査エコシステムが成立- backend設計: Terraform backends
- state操作:
terraform stateCLI - refinements (1.6+): 「unknownだがnonnull」「unknownだが長さ既知」「unknownだがprefix既知」等の部分情報を保持。cty.Valueのunknownフラグの拡張
- module:
module.<MODULE NAME>はmoduleブロックの結果を表す値(expressions/references)。sourceはリテラル文字列のみ(block/module)。OpenTofu 1.8+ のearly evaluationでもstaticにしか解決できない
Carina
identity
- named binding:
let foo = ...でid.name = "foo"(ハッシュなし) - anonymous resource:
aws.s3.Bucket { name = "foo" }(letなし)- parse時:
id.name = ""(empty) - 後処理
compute_anonymous_identifiersでcreate-only attributesから standard hash (u32, 8 hex) を計算 - create-only attrsがない場合は SimHash (u64, 16 hex) にフォールバック
- 出典:
carina-core/src/identifier/mod.rs:380-468
- parse時:
- anonymous module call:
thing { name = 'alpha' }instance_prefix = thing_<16hex SimHash>- SimHashはmodule_name + flattened argumentsから決定(content-based)
- Hamming distance対応で小さい引数変更時もstate内のリソースを追跡可能
- 出典:
carina-core/src/module_resolver/mod.rs:577-591
name属性とstate identifierは独立 (carina-core/src/parser/mod.rs:5395-5404)
plan / effect / state
Plan<Effect>:carina-core/src/plan.rs(Plan構造体、Effects集合)add_state_block_effects:wiring.rsでplan生成後にstate blocks反映- Effect:
carina-core/src/effect.rs(Create/Update/Delete/Read enum) - state v3:
carina-statecrate。binding/dependency_bindingsの意味、state CLI、手動編集機構は要確認
型とunknown
Valueenum:String, Int, Float, Bool, List, Map, ResourceRef { path }, Interpolation(parts), FunctionCall { name, args }, Secret, Closure(carina-core/src/resource.rs:173-216)。Value::Unknownバリアントは存在しない- resolver (
carina-core/src/resolver.rs)の挙動:ResourceRefはstateから解決できれば具体値に置換しできなければRefのまま、Interpolationは全パーツ解決でStringに連結し未解決ならInterpolationのまま、FunctionCallは全引数解決で即評価し未解決ならFunctionCallのまま(部分評価) for式が未解決なiterableを持つ場合:DeferredForExpressionとしてdeferred_for_expressionsに退避(carina-core/src/parser/mod.rs:531)expand_deferred_for_expressions()でupstream_state (他プロジェクトのstate)から解決できれば展開、できなければdeferredのままplan表示に回される(carina-cli/src/display.rs:248-251)AttributeType:Union { members }(sum type)、StringEnum { values, namespace }、Custom { base, validate, pattern, length, semantic_name, namespace }(nominal refinement type)、Struct { name, fields }
DSL構文の制約
sourceフィールドはリテラル文字列のみ: parserでValue::String以外を弾く(carina-core/src/parser/mod.rs:1664-1669)