<!-- event: create author: "yoi ticket" at: 2026-07-08T19:18:25Z -->

## 作成

LocalTicketBackend によって作成されました。

---

<!-- event: intake_summary author: hare at: 2026-07-09T07:18:33Z -->

## Intake summary

Marked ready by `yoi ticket state`.

---

<!-- event: state_changed author: "yoi ticket" at: 2026-07-09T07:18:33Z from: planning to: ready reason: cli_state field: state -->

## State changed

Marked ready by `yoi ticket state`.


---

<!-- event: state_changed author: workspace-panel at: 2026-07-09T07:56:07Z from: ready to: queued reason: queued field: state -->

## State changed

Ticket を `workspace-panel` が queued にしました。


---

<!-- event: decision author: orchestrator at: 2026-07-09T07:57:36Z -->

## Decision

Routing decision: implementation_ready

Reason:
- Declared dependency `00001KWZ5KERY` is closed, so Decodal ProfileSourceArchive / archive verify / Runtime FSなし resolution の基礎は available。
- Related follow-up `00001KX0DSMPT` Workspace/Profile settings API/pages is also closed, so settings/profile editing surface exists and this Ticket can refine it to ProfileSourceTree virtual filesystem + Decodal editor。
- Ticket body gives concrete model/API/UI/editor/dependency/validation requirements and clear non-goals。
- typed relation blocker is resolved; OrchestrationPlan record は 0 件。inprogress Ticket も 0 件。
- queued notification is human authorized routing/start。

Evidence checked:
- Ticket body / thread / artifacts。
- `TicketRelationQuery(00001KX1JNJ2Y)`: outgoing `depends_on 00001KWZ5KERY`; target is closed。
- `TicketOrchestrationPlanQuery(00001KX1JNJ2Y)`: 0 件。
- `TicketList`: queued はこの Ticket 1件、inprogress は 0 件。
- Orchestrator worktree git status: clean on `orchestration`。
- Relevant prior work: Decodal/ProfileSourceArchive closed, Workspace/Profile settings closed。

IntentPacket:

Intent:
- Add Backend-owned `ProfileSourceTree` virtual filesystem for Decodal profile sources, connect ProfileSourceArchive import closure building to that tree, strengthen Runtime archive import validation, and add Workspace settings Profile source tree editor using `decodal-codemirror@0.1.2` / CodeMirror 6。

Binding decisions / invariants:
- Browser/editor works with virtual relative paths and safe source tree/file ids, never host absolute paths or raw filesystem authority。
- Backend validation is authority; Browser editor diagnostics are only assistance。
- Runtime reads only ProfileSourceArchive manifest / virtual paths, not Workspace filesystem。
- `ProfileSourceArchive` is a snapshot of source tree revision + selected root + import closure。
- Browser-facing API must not expose host absolute path, symlink target path, Runtime endpoint/socket/session path, secret values, WorkingDirectory root path, raw resource handles, archive digest/content, or backend-private paths。
- `decodal-codemirror@0.1.2` / CodeMirror 6 dependency is in scope; formatter and Browser-side Decodal materialization as authority are out of scope。

Requirements / acceptance criteria:
- Implement typed `ProfileSourceTree` model with tree id, revision/generation, virtual root metadata, files, provenance, diagnostics, and safe summaries。
- Implement virtual import resolver for relative imports and adopted namespace imports, with normalization and typed diagnostics for root escape, absolute path, URL/unsupported scheme, extension/content-type, depth/count/bytes limits。
- Build `ProfileSourceArchive` from selected root virtual path and source tree import closure, including virtual path / source key / digest / size / content type / import map in manifest。
- Runtime `ArchiveSourceLoader` validates manifest-contained virtual paths only and rejects manifest-outside import, absolute path, `..`, unsupported namespace。
- Add scoped Profile settings file-tree API: list trees, list files, read/write/create/delete file, validate tree/file; rename/move optional。
- Add Settings UI profile source tree list and file tree editor routes/pages using Decodal CodeMirror extension and Backend save/create/delete/validate APIs。
- Focused backend/runtime/web tests cover path normalization, import closure, archive manifest validation, Runtime import resolution, Browser redaction, file tree API, and editor route smoke。

Implementation latitude:
- Exact endpoint names, source tree storage format, namespace enum details, UI route/component split, and editor model can follow existing workspace-server/Svelte style。
- v0 may keep source tree storage minimal and project/workspace-backed, provided Browser contract remains virtual-path based and Backend validation remains authority。

Escalate if:
- Browser-facing raw host path authority, Runtime workspace filesystem discovery, Browser-side Decodal materialization as authority, formatter integration, plugin/MCP/sandbox artifact sync, or Profile source RDB-normalized editor becomes required。

Validation:
- `cargo test -p yoi-workspace-server`
- `cargo test -p worker-runtime --features ws-server,fs-store`
- `cargo check -p yoi`
- `cd web/workspace && deno task check && deno task test`
- `git diff --check`
- `yoi ticket doctor`
- `nix build .#yoi --no-link`

Current code map:
- Backend profile settings/source model: `crates/workspace-server/src/profile_settings.rs`, `server.rs`, `hosts.rs`。
- Decodal/Profile archive: `crates/worker-runtime/src/profile_archive.rs`, `config_bundle.rs`。
- Frontend settings/profile editor: `web/workspace/src/routes/w/[workspaceId]/settings/**`, `web/workspace/src/lib/workspace-settings/**`。

Critical risks / reviewer focus:
- virtual paths and tar paths must not allow absolute path / `..` / symlink/path escape。
- Browser must never receive host absolute path, secret, runtime endpoint, archive digest/content, or raw handle。
- Runtime SourceLoader must be archive-manifest/import-map only, no FS/backend fallback。
- source tree validation/write must be revision-aware and fail closed with typed diagnostics。
- new editor dependency and Nix/lock updates must be correct。

---

<!-- event: state_changed author: orchestrator at: 2026-07-09T07:57:59Z from: queued to: inprogress reason: routing_acceptance_implementation_ready field: state -->

## State changed

Queued acceptance recorded after Workspace Dashboard Queue notification authorized Orchestrator routing.

Checked context:
- Ticket body / thread / artifacts。
- `TicketRelationQuery(00001KX1JNJ2Y)`: depends_on `00001KWZ5KERY`; target is closed。
- `TicketOrchestrationPlanQuery(00001KX1JNJ2Y)`: prior record 0 件。今回 accepted_plan を記録済み。
- Orchestrator worktree git status: clean on `orchestration`。
- queued Ticket はこの Ticket 1件のみ。inprogress は 0 件。

Acceptance basis:
- concrete missing decision / information は残っていない。
- Ticket scope is ProfileSourceTree virtual filesystem + Decodal editor follow-up on top of closed Decodal/ProfileSourceArchive and Workspace/Profile settings work。
- side effect はこの `queued -> inprogress` acceptance 後に、worktree-workflow に沿って implementation worktree を作成してから開始する。

---

<!-- event: implementation_report author: orchestrator at: 2026-07-09T07:58:54Z -->

## Implementation report

Implementation routing update:

- Worktree-workflow に従い implementation worktree を作成した。
  - Worktree: `/home/hare/Projects/yoi/.worktree/00001KX1JNJ2Y-profile-source-tree`
  - Branch: `work/00001KX1JNJ2Y-profile-source-tree`
- Worktree には tracked `.yoi` project records が見えている。
- `.yoi/memory` / `.yoi/runtime` / `.yoi/log` / `.yoi/logs` / `.yoi/local` / `.yoi/*.lock` / `.yoi/*secret*` は作成直後に存在しないことを確認した。
- Sibling Coder Pod `yoi-coder-00001KX1JNJ2Y-source-tree` を起動した。
- Scope policy: runtime workspace root は read-only、implementation worktree は write 可。Coder task では root/original workspace での read/write/validation/git operation を禁止し、この implementation worktree だけを作業対象に指定した。
- 初回プロンプト肥大化を避けるため、Coder には短い task と Ticket record 読み取り指示を渡した。
- 完了後は diff / validation evidence を Orchestrator が確認し、別 sibling Reviewer Pod に read-only review を依頼する。`StopPod` は既知の不具合があるため使用しない。

---

<!-- event: implementation_report author: orchestrator at: 2026-07-09T08:28:11Z -->

## Implementation report

Implementation progress report:

- Coder Pod completed implementation and committed `81abfa63 feat: add profile source tree editor` on branch `work/00001KX1JNJ2Y-profile-source-tree`.
- Worktree status was clean after commit。
- Changed files include:
  - `crates/worker-runtime/src/profile_archive.rs`
  - `crates/workspace-server/src/profile_settings.rs`
  - `crates/workspace-server/src/server.rs`
  - `web/workspace/deno.json`, `web/workspace/deno.lock`
  - `web/workspace/src/lib/workspace-settings/DecodalSourceEditor.svelte`
  - `web/workspace/src/lib/workspace-settings/{profile-api.ts,profile-types.ts}`
  - `web/workspace/src/routes/w/[workspaceId]/settings/profiles/+page.svelte`
  - child implementation also committed `.yoi/tickets/00001KX1JNJ2Y/{item.md,thread.md}` changes; Orchestrator will preserve authoritative Ticket records during merge if conflicts occur。
- Implementation summary:
  - Added Runtime archive validation for virtual source metadata, duplicate/undeclared entries, scoped import maps, namespace/path safety, and relative virtual import resolution。
  - Added Backend-owned project `ProfileSourceTree` support with virtual `profiles/...` paths, tree scanning, revision-aware file read/write/delete API, and tree-based archive/config-bundle generation。
  - Added workspace server routes and Browser API/types for scoped source-tree access without host paths or backend-private/archive internals。
  - Added Profiles settings Decodal CodeMirror editor using virtual paths and revision tokens。
  - Added worker-runtime tests for scoped virtual import resolution and import-map mismatch rejection。
- Orchestrator reran validation in the implementation worktree:
  - `git diff --check`: pass
  - `cargo test -p yoi-workspace-server`: pass（91 lib tests + 2 main tests）
  - `cargo test -p worker-runtime --features ws-server,fs-store`: pass（47 lib tests + 5 main tests + doc tests）
  - `cargo check -p yoi`: pass
  - `cd web/workspace && deno task check`: pass（0 errors / 0 warnings）
  - `cd web/workspace && deno task test`: pass（17 tests）
  - `yoi ticket doctor`: ok
  - `nix build .#yoi --no-link`: pass
- External review will be requested via a read-only sibling Reviewer Pod. `StopPod` は使わない。

---

<!-- event: review author: reviewer at: 2026-07-09T08:32:35Z status: request_changes -->

## Review: request changes

External review result: request_changes

Blockers:

1. Decodal CodeMirror integration is missing。
   - Ticket requires `decodal-codemirror@0.1.2` and the `decodal()` CodeMirror 6 extension。
   - Implementation only adds `@codemirror/state` / `@codemirror/view` (`web/workspace/deno.json`) and `deno.lock` has no `decodal-codemirror` specifier。
   - `DecodalSourceEditor.svelte` builds a plain CodeMirror editor with line numbers/selection/theme only, so there is no Decodal highlighting/indent/folding extension。

2. Settings UI does not implement the required tree route or create/delete editor operations。
   - Ticket requires `/w/<workspace-id>/settings/profiles/trees/<source-tree-id>` plus save/create/delete via Backend APIs。
   - Route tree only contains `web/workspace/src/routes/w/[workspaceId]/settings/profiles/+page.svelte`; no `trees/[sourceTreeId]` route。
   - Page imports/uses only `writeProfileTreeFile` and renders only Save; no create/delete UI is wired despite `deleteProfileTreeFile` existing in API wrapper。

3. Archive construction is not a selected-root import-closure snapshot。
   - `build_workspace_profile_archive(workspace_root, selector)` reads whole tree and calls `build_profile_archive_from_tree_sources`; selector is used only for post-build validation。
   - Builder adds entrypoints for every project registry entry, scans every source for imports, and passes entire `sources` map into `ProfileSourceArchive::build`。
   - This violates requirement that archive is generated from `ProfileSourceTree revision + selected root + import closure`, with closure-only contents。

4. `ProfileSourceTree` typed model is incomplete against Ticket contract。
   - Browser/backend structs expose tree id/root/revision/file count and file path/kind/revision/size, but no content digest, content type, or provenance field/typed provenance enum。
   - These are explicit Ticket requirements for the typed model。

5. Symlink/path-escape write safety has a side-effect before containment validation。
   - `write_profile_tree_file` calls `fs::create_dir_all(parent)` on unresolved workspace path before `checked_source_path` canonical root containment checks。
   - With a symlinked intermediate directory under `.yoi/profiles`, this can create directories outside source root before later rejection。
   - Path/symlink escape should fail closed without outside filesystem mutation。

Validation performed:
- Read Ticket item, routing IntentPacket, and implementation report。
- Inspected implementation commit metadata and relevant backend/runtime/frontend files in the implementation worktree only。
- Did not rerun reported cargo/deno/nix validations; Orchestrator-reported validation was passing, but blockers are functional/design acceptance gaps。

Non-blocking follow-ups:
- After blockers are fixed, add focused regression coverage for selected-root closure behavior, tree route smoke, Decodal editor extension wiring, UI create/delete flows, and symlinked-directory tree-write rejection-before-side-effect。

---

<!-- event: implementation_report author: orchestrator at: 2026-07-09T08:52:14Z -->

## Implementation report

Review-fix implementation report:

- Coder Pod completed requested changes and committed follow-up `941b9126 fix: complete profile source tree review fixes` on branch `work/00001KX1JNJ2Y-profile-source-tree`.
- Worktree status was clean after commit。
- Fix summary:
  - Added `decodal-codemirror@0.1.2` and wired `decodal()` into the CodeMirror 6 editor。
  - Added source tree settings route `/w/<workspace-id>/settings/profiles/trees/<source-tree-id>`。
  - Wired UI create/save/delete operations through Backend virtual-path source tree APIs。
  - Changed archive construction to selected selector/root + import closure only, avoiding unrelated project tree sources。
  - Added safe typed source/tree metadata including content type, content digest, and typed provenance。
  - Hardened tree writes against symlinked intermediate directories before any outside filesystem mutation。
  - Added focused regression coverage for selected-root closure-only archive contents, symlink write rejection before side effects, and web model smoke tests for tree routes / virtual create paths。
- Orchestrator reran validation in the implementation worktree:
  - `git diff --check`: pass
  - `cargo test -p yoi-workspace-server`: pass（93 lib tests + 2 main tests）
  - `cargo test -p worker-runtime --features ws-server,fs-store`: pass（47 lib tests + 5 main tests + doc tests）
  - `cargo check -p yoi`: pass
  - `cd web/workspace && deno task check`: pass（0 errors / 0 warnings）
  - `cd web/workspace && deno task test`: pass（19 tests）
  - `yoi ticket doctor`: ok
  - `nix build .#yoi --no-link`: pass
- Requesting follow-up external review against `81abfa63..941b9126` and full combined implementation。

---

<!-- event: review author: reviewer at: 2026-07-09T08:57:15Z status: request_changes -->

## Review: request changes

External follow-up review result: request_changes

Blockers:

1. Tree writes still allow a source-root symlink escape before/at filesystem mutation。
   - Fix rejects symlinked intermediate directories under `.yoi/profiles`, but not `.yoi/profiles` itself being a symlink。
   - `prepare_source_path_for_write()` creates/canonicalizes `source_root` without checking `symlink_metadata(source_root)` or verifying canonical source root remains under canonical workspace root。
   - If `.yoi/profiles` is a symlink to an outside directory, `canonical_root` becomes outside target; `parent_relative` strips against textual symlink path and missing children can be created outside workspace。
   - `checked_source_path()` repeats the escaped-root comparison and can accept files under escaped root。
   - `list_profile_tree_files()` starts `read_dir` at `workspace_root/.yoi/profiles`, so symlinked source root can expose outside `.dcdl` files as virtual tree files。
   - Required fix: reject symlinked source root and ensure canonical source root is confined under canonical workspace root before list/read/write/delete/archive operations。

2. Regression coverage for the remaining symlink escape is missing。
   - Existing test covers symlinked child directory only。
   - Add focused regression for `.yoi/profiles -> outside_dir` asserting tree write is rejected before side effects, outside target is not created/modified, and preferably list/read/archive construction also fail closed or do not traverse escaped root。

Evidence / resolved items:
- `decodal-codemirror@0.1.2` is present and `DecodalSourceEditor.svelte` imports/uses `decodal()` in CM6 extensions。
- Required tree route exists at `web/workspace/src/routes/w/[workspaceId]/settings/profiles/trees/[sourceTreeId]/...`; create/save/delete call Backend APIs。
- Selected-root archive construction now collects only import closure; tests assert unrelated sources are excluded。
- Browser-facing typed summaries include virtual path/root, content type/digest, and typed provenance without host paths。
- Runtime `ArchiveSourceLoader` remains manifest/import-map backed with no filesystem fallback。

Non-blocking follow-ups:
- Current web tests cover route helper/path normalization but not actual Svelte create/save/delete interaction behavior。
- Editor extension wiring is compile/static-source covered rather than directly unit-tested; acceptable for now, but smoke coverage would help future dependency regressions。

---

<!-- event: implementation_report author: orchestrator at: 2026-07-09T09:10:00Z -->

## Implementation report

Second review-fix implementation report:

- Coder Pod completed remaining requested changes and committed follow-up `13c6548b fix: reject profile source root symlinks` on branch `work/00001KX1JNJ2Y-profile-source-tree`。
- Worktree status was clean after commit。
- Fix summary:
  - Added shared `ProfileSourceRoot` guard。
  - Rejects `.yoi/profiles` when it is a symlink。
  - Verifies canonical `.yoi/profiles` remains under the canonical workspace root。
  - Applied the guard consistently to source tree listing, file read/delete checks, write preparation, source summaries, and archive construction through tree scan/read paths。
  - Hardened writes so `.yoi` and `.yoi/profiles` are created one component at a time only after symlink/canonical containment checks。
  - Added regression coverage for `.yoi/profiles -> outside_dir`: write rejects before outside side effects, outside target is not created/modified, source tree read/list fails closed, and archive construction fails closed。
- Orchestrator reran validation in the implementation worktree:
  - `git diff --check`: pass
  - `cargo test -p yoi-workspace-server`: pass（94 lib tests + 2 main tests）
  - `cargo test -p worker-runtime --features ws-server,fs-store`: pass（47 lib tests + 5 main tests + doc tests）
  - `cargo check -p yoi`: pass
  - `cd web/workspace && deno task check`: pass（0 errors / 0 warnings）
  - `cd web/workspace && deno task test`: pass（19 tests）
  - `yoi ticket doctor`: ok
  - `nix build .#yoi --no-link`: pass
- Requesting second follow-up external review against `941b9126..13c6548b` and full combined implementation。

---

<!-- event: review author: reviewer at: 2026-07-09T09:16:20Z status: approve -->

## Review: approve

External second follow-up review result: approve

Blockers verified:
- Source-root symlink rejection is now in the shared source-root path validation:
  - `existing_profile_source_root` rejects `.yoi/profiles` when the final component is a symlink。
  - `prepare_profile_source_root_for_write` rejects both `.yoi` symlink parents and `.yoi/profiles` symlink roots before create/write operations。
  - `checked_source_path`, tree listing, file read/write/delete, and archive construction all flow through these guards before touching tree contents。
- Regression coverage for `.yoi/profiles -> outside_dir` exists:
  - `source_root_symlink_is_rejected_before_tree_side_effects` covers write rejection before outside side effects, `read_profile_source_tree` fail-closed behavior, and `build_workspace_profile_archive` fail-closed behavior。
  - Existing symlink-parent / entry symlink tests remain in place for nested escape cases。

Still-good items checked and intact:
- Decodal editor wiring remains present via the Svelte editor component using `decodal()` / CodeMirror integration。
- Profile tree API routes remain wired for tree read and file create/save/delete:
  - `/settings/profiles/trees/{source_tree_id}`
  - `/settings/profiles/trees/{source_tree_id}/file`
- Virtual source tree summaries still expose virtual metadata/provenance/digest-type fields without host path disclosure。
- Selected-root archive construction still uses the selected profile entrypoint plus import closure rather than blindly archiving every source。
- `Runtime ArchiveSourceLoader` behavior remains bounded to archive manifest/import-map package files plus archive-backed imports; no host filesystem fallback was introduced。

Validation performed:
- Read Ticket records in `.yoi/tickets/00001KX1JNJ2Y/`, including latest implementation/review context。
- Inspected latest fix `13c6548b`, diff from `941b9126..13c6548b`, and relevant source files in the implementation worktree only。
- Reviewed the orchestrator-provided successful validation list; Reviewer did not rerun tests or modify files。

Non-blocking follow-up:
- A direct assertion for `read_profile_tree_file` against a root-symlinked `.yoi/profiles` would make the regression matrix even more explicit, but the implementation path already uses the same guarded `checked_source_path`, so this is not a merge blocker。

No merge-blocking issues found.

---

<!-- event: state_changed author: orchestrator at: 2026-07-09T09:18:29Z from: inprogress to: done reason: merged_validated_review_approved field: state -->

## State changed

Merge/validation acceptance:

- Second follow-up external review approved the implementation after symlink-root blocker fix。
- Implementation branch `work/00001KX1JNJ2Y-profile-source-tree` was merged into the orchestration branch with merge commit `9a2e57fb merge: profile source tree editor`。
- Ticket-record conflicts during merge were resolved by preserving Orchestrator-side Ticket item/thread records; product/code changes were merged。
- Final validation in Orchestrator worktree passed:
  - `git diff --check`: pass
  - `cargo test -p yoi-workspace-server`: pass（94 lib tests + 2 main tests）
  - `cargo test -p worker-runtime --features ws-server,fs-store`: pass（47 lib tests + 5 main tests + doc tests）
  - `cargo check -p yoi`: pass
  - `cd web/workspace && deno task check`: pass（0 errors / 0 warnings）
  - `cd web/workspace && deno task test`: pass（19 tests）
  - `yoi ticket doctor`: ok
  - `nix build .#yoi --no-link`: pass

Implementation commits:
- `81abfa63 feat: add profile source tree editor`
- `941b9126 fix: complete profile source tree review fixes`
- `13c6548b fix: reject profile source root symlinks`

No merge-blocking issues remain.

---

<!-- event: state_changed author: hare at: 2026-07-09T09:18:48Z from: done to: closed reason: closed field: state -->

## State changed

Ticket を closed にしました。


---

<!-- event: close author: hare at: 2026-07-09T09:18:48Z status: closed -->

## 完了

完了。

実装内容:
- Backend-owned `ProfileSourceTree` virtual filesystem model を追加した。
- virtual relative paths / safe source tree ids / file ids / revision / content digest / content type / typed provenance / diagnostics を扱う safe summaries を追加した。
- Profile source tree list/read/write/create/delete/validate scoped APIs を追加した。
- virtual import resolver を追加し、relative imports / scoped namespace imports を扱い、absolute path、URL/unsupported scheme、root escape、unsupported namespace、limit excess を fail closed するようにした。
- `ProfileSourceArchive` construction を selected root/selector + source tree revision + import closure snapshot に変更し、unrelated sources を archive に含めないようにした。
- Runtime `ArchiveSourceLoader` / archive verification を virtual path / import-map only に強化し、Workspace filesystem/backend fallback を導入しないまま維持した。
- Settings UI に Profile source tree list と Decodal source editor route を追加した。
- `decodal-codemirror@0.1.2` と CodeMirror 6 の `decodal()` extension を editor に接続した。
- UI create/save/delete operations を Backend virtual-path APIs に接続した。
- `.yoi/profiles` source root symlink と symlink/path escape を list/read/write/delete/archive construction paths で reject し、outside filesystem mutation 前に fail closed するようにした。
- Focused backend/runtime/web tests を追加した。

主な commit / merge:
- implementation: `81abfa63 feat: add profile source tree editor`
- review fix: `941b9126 fix: complete profile source tree review fixes`
- symlink-root fix: `13c6548b fix: reject profile source root symlinks`
- merge into orchestration: `9a2e57fb merge: profile source tree editor`

Review:
- 初回 external review は request_changes。
- first follow-up review も request_changes（source-root symlink blocker）。
- second follow-up review は approve。merge-blocking issue なし。

Final validation in Orchestrator worktree:
- `git diff --check`: pass
- `cargo test -p yoi-workspace-server`: pass（94 lib tests + 2 main tests）
- `cargo test -p worker-runtime --features ws-server,fs-store`: pass（47 lib tests + 5 main tests + doc tests）
- `cargo check -p yoi`: pass
- `cd web/workspace && deno task check`: pass（0 errors / 0 warnings）
- `cd web/workspace && deno task test`: pass（19 tests）
- `yoi ticket doctor`: ok
- `nix build .#yoi --no-link`: pass

補足:
- implementation branch merge 時に Ticket record conflict が発生したため、Orchestrator 側の Ticket item/thread を保持して解決した。product/code changes は merge 済み。
- Reviewer の non-blocking follow-up: `read_profile_tree_file` に対する root-symlink direct assertion を追加すると regression matrix がさらに明示的になるが、同じ guarded `checked_source_path` を通るため merge blocker ではない。

---
