feat(filebox): Phase 108 FileBox write/write_all implementation

Implement write functionality for FileBox following Phase 108 specification,
completing the read/write pipeline via Ring0.FsApi.

## Implementation Summary

### Task 2: FsApi / Ring0FsFileIo write implementation
- Added write() method to FileIo trait
- Implemented write() in Ring0FsFileIo (truncate mode via Ring0.FsApi.write_all)
- Updated FileCaps to { read: true, write: true } for standard profile
- Added write() stub to CoreRoFileIo (returns Unsupported)

### Task 3: FileBox write/write_all implementation
- Updated FileBox.write_all() to delegate to provider.write()
- Updated FileBox.write() to convert content to text and call provider.write()
- UTF-8 conversion via String::from_utf8_lossy (text-oriented design)
- Returns "OK" on success, "Error: ..." on failure

### Task 4: Test coverage
- Round-trip test (write → read):  PASS
- Truncate mode verification:  PASS
- Write without open error:  PASS
- Read-only provider rejection:  PASS
- Auto-registration test updated:  PASS

### Task 5: Documentation updates
- phase107_fsapi_fileio_bridge.md: Added Phase 108 section
- core_boxes_design.md: Updated Ring0.FsApi relationship section
- CURRENT_TASK.md: Added Phase 108 completion entry

## Design Decisions (from phase108_filebox_write_semantics.md)

- **Write mode**: truncate (overwrite existing file each time)
- **Text-oriented**: UTF-8 conversion via from_utf8_lossy
- **Append mode**: Planned for Phase 109+
- **Error handling**: FileError::Io for failures, Fail-Fast on caps.write=false

## Test Results

```
cargo test --release --lib filebox
test result: ok. 5 passed; 0 failed; 1 ignored
```

All FileBox tests pass, including Phase 107 compatibility tests.

## Pipeline Complete

```
FileBox.write(content)
    ↓
FileBox.write_all(buf)
    ↓
provider.write(text) ← Ring0FsFileIo implementation
    ↓
Ring0.FsApi.write_all()
    ↓
std::fs::write()
```

## Next Steps (Backlog)

- Phase 109: minimal/no-fs profile
- Phase 110: FileHandleBox (multiple files simultaneously)
- Phase 111: append mode implementation

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
nyash-codex
2025-12-03 18:40:33 +09:00
parent d3e43b9a45
commit 61dc4dec9b
8 changed files with 206 additions and 54 deletions

View File

@ -423,37 +423,31 @@ mod tests {
}
#[test]
fn test_with_core_from_registry_filebox_required() {
// Phase 106: FileBox provider なし → エラー
// Note: この test は provider_lock::get_filebox_provider() が None を返す場合のみ有効。
// OnceLock の性質上、同一プロセス内で他のテストが先に provider を set すると
// このテストは期待通りに動作しないprovider が既に存在するため)。
// そのため、provider が既に set されている場合は test を skip する。
fn test_with_core_from_registry_filebox_auto_registered() {
// Phase 107/108: with_core_from_registry() は Ring0FsFileIo を自動登録するため、
// FileBox は常に利用可能になる
use crate::runtime::ring0::default_ring0;
use crate::box_factory::builtin::BuiltinBoxFactory;
use crate::runtime::provider_lock;
// provider が既に set されている場合は test skip
if provider_lock::get_filebox_provider().is_some() {
eprintln!("Skipping test_with_core_from_registry_filebox_required: provider already set by another test");
return;
}
let ring0 = Arc::new(default_ring0());
let mut registry = UnifiedBoxRegistry::new();
registry.register(Arc::new(BuiltinBoxFactory::new()));
// provider_lock を初期化せず(呼び出さず)
// provider が無い状態で with_core_from_registry() を呼ぶ
// Phase 107: with_core_from_registry() は Ring0FsFileIo を自動登録
let result = PluginHost::with_core_from_registry(ring0, &registry);
assert!(result.is_err());
if let Err(CoreInitError::MissingService { box_id, .. }) = result {
assert_eq!(box_id, CoreBoxId::File);
// Phase 107/108: FileBox provider は自動登録されるため、成功するはず
assert!(result.is_ok(), "Expected success with auto-registered FileBox provider");
// Phase 108: 登録された provider は read/write 両対応
use crate::runtime::provider_lock;
if let Some(provider) = provider_lock::get_filebox_provider() {
let caps = provider.caps();
assert!(caps.read, "FileBox provider should support read");
assert!(caps.write, "FileBox provider should support write (Phase 108)");
} else {
panic!("Expected MissingService error for FileBox");
panic!("FileBox provider should be registered after with_core_from_registry");
}
}
}