hero_foundry_server HTTP files API returns 503 under default hero_foundry --start registration #17
Labels
No labels
prio_critical
prio_low
type_bug
type_contact
type_issue
type_lead
type_question
type_story
type_task
No milestone
No project
No assignees
2 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
lhumina_code/hero_foundry#17
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
When hero_foundry_server is started via the hero_foundry CLI (hero_foundry --start, which registers the service with hero_proc), the HTTP files API at /api/files/* returns 503 Service Unavailable with "Storage not configured". This breaks any client that talks to that endpoint (e.g. the Office integration).
Reproduction
make stop && make run on development (pre-fix)
curl -i http:///api/files/ → 503 Service Unavailable / "Storage not configured"
Verification (post-fix)
make stop && make run
Confirm ~/hero/foundry-storage/ is created
curl -i http:///api/files/... no longer 503s
Office (or whichever client surfaced the bug) can read/write through /api/files/*
FIX
when starting the _server
check there is a default fossil repo, put in ~/hero/var/fossil/core.fossil
if not create one which will be an empty repo
put a readme in to stay this is the starting point
so basically we get a default repo
Implementation Spec — Issue #17: Default fossil repo on server start
Objective
Ensure that whenever
hero_foundry_serverstarts (in particular under the defaulthero_foundry --startregistration path), a default fossil repository file exists at~/hero/var/fossil/core.fossil. If it already exists, leave it alone. If it does not exist, create:~/hero/var/fossil/(and any missing ancestors).core.fossilat that path, usinghero_foundry_core::Repository::init(which produces a SQLite database with the fossil schema).README.mdfile inside the fossil repo as the initial commit ontrunk, stating that this is the seeded default repository.This complements PR #18 (which already added the WebDAV storage directory). Issue #17 explicitly asks for an additional default fossil repo so that any client expecting a default repository can find one.
Requirements
--startinvocations must not modify or overwrite an existingcore.fossil. They must not error if the parent directory or the file already exist.hero_foundry --start— the rest of the registration withhero_procmust still proceed.$HOMEexactly the way the existing CLI does (std::env::var("HOME").unwrap_or_default()), to keep behaviour aligned withdefault_dirandstorage_dir.fossilbinary. The repo is created in-process viahero_foundry_core::Repository::init, which is already what the rest of this codebase uses.README.mdinto the new repo as its first check-in, on thetrunkbranch.Files to modify / create
Modify:
crates/hero_foundry/src/main.rsAdd a new helper function
ensure_default_fossil_repo()and call it fromself_start()beforerestart_service. The helper useshero_foundry_core::Repositoryto do the work.Modify:
crates/hero_foundry/Cargo.tomlAdd a path dependency on
hero_foundry_core.Do NOT modify
crates/hero_foundry_server/src/main.rs— server binary should remain agnostic about the default repo location. The CLI is the orchestrator.crates/hero_foundry_core/*—Repository::initalready does everything required.Step-by-step implementation plan
Step 1 — Add
hero_foundry_coredependency to the CLI crateFile:
crates/hero_foundry/Cargo.tomlUnder
[dependencies], add:Step 2 — Add the helper to
main.rsFile:
crates/hero_foundry/src/main.rsAdd a top-level function
ensure_default_fossil_repo()that:~/hero/var/fossil/core.fossilfrom$HOME.hero_foundry_core::Repository::init.README.mdas the initial check-in ontrunkusing the commit builder with.initial()(authorhero_foundry).Step 3 — Call helper from
self_start()File:
crates/hero_foundry/src/main.rsInside
fn self_start(), invokeensure_default_fossil_repo()beforerestart_serviceruns.Step 4 — Verify locally
cargo build -p hero_foundry— must succeed.cargo build -p hero_foundry_server— must still succeed.make stop && rm -rf ~/hero/var/fossil && make run, then checkls ~/hero/var/fossil/core.fossilexists.make stop && make run—core.fossilmtime/contents must be unchanged.Acceptance criteria
crates/hero_foundry/Cargo.tomldeclareshero_foundry_coreas a path dependency.crates/hero_foundry/src/main.rsdefinesensure_default_fossil_repo()with idempotent behaviour and non-fatal error handling.self_start()callsensure_default_fossil_repo()exactly once, beforerestart_service.hero_foundry --starton a clean machine creates~/hero/var/fossil/core.fossil.hero_foundry --starttwice is a no-op for the file.$HOMEis empty/unset, the CLI logs a warning and continues without aborting.cargo build) succeeds.fossilC binary) are introduced.Notes / decisions
Why not call the external
fossilbinary? It would add an undeclared runtime dependency that isn't currently required anywhere else in this Rust workspace. Every other place creates repos viaRepository::init. The pure-Rust path is already exercised byhero_foundry_demoand the unit tests inhero_foundry_core.README placement — committed file vs. sibling. A
.fossilfile is a SQLite database, not a directory, so a README cannot live "inside" it on disk. The chosen approach commits the README as the first check-in inside the repo (visible via/api/files/.../README.md), matching exactly howhero_foundry_demoseedshero-app.forge. The alternative of dropping a siblingREADME.mdwas rejected because it would not be reachable via/api/files/*, which is the exact endpoint the bug report exercises.Why seed in the CLI rather than in the server. The CLI is already the orchestration boundary that owns "what files/dirs must exist before the server runs" (see PR #18, where
default_dirandstorage_dirare also created). Keeping all such side-effects in the CLI keeps the server binary side-effect-free for tests and ad-hoc invocations.Idempotency under concurrent starts. The helper does an
exists()check followed bycreate_dir_allandRepository::init.hero_procitself serializes service registration;Repository::initwould refuse to re-init a populated database. Acceptable for this CLI-driven one-shot..fossilvs.forgeextension. The rest of this codebase generally uses.forge, but the issue explicitly namescore.fossil. We honor the issue. Both extensions are just naming conventions — the on-disk format is identical.Test Results
All tests passed.
Implementation Summary
Changes
crates/hero_foundry/Cargo.toml— addedhero_foundry_corepath dependency.crates/hero_foundry/src/main.rs— added top-level helperensure_default_fossil_repo()and a single call to it fromself_start()beforerestart_service.Behaviour
On
hero_foundry --start, the CLI now ensures that~/hero/var/fossil/core.fossilexists before registering the server with hero_proc:$HOMEis unset, a warning is logged to stderr and the seeding step is skipped (the rest of--startproceeds normally).core.fossilalready exists, the function is a no-op (idempotent across repeat starts).~/hero/var/fossil/is created (recursively), the repo is initialised in-process viahero_foundry_core::Repository::init, and aREADME.mdis committed as the initial check-in ontrunkwith authorhero_foundry.--start, so a permission error or a stray file at the seed path will never block service registration.Implementation notes
fossilC binary). The repo is created via the samehero_foundry_core::Repository::initcode path used byhero_foundry_demo./api/files/.../README.md), not dropped as a sibling file. This makes the seed visible through the same/api/files/*endpoint that the original bug report exercised.default_dirand WebDAVstorage_dirsetup. The server binary remains side-effect-free for direct/test use.Test results
cargo test --workspace --no-fail-fast— 179 passed, 0 failed, 2 ignored. Bothcargo build -p hero_foundryandcargo build -p hero_foundry_serversucceed.Manual verification (recommended on the deploying machine)
make stop && rm -rf ~/hero/var/fossil && make runls ~/hero/var/fossil/core.fossil— file exists.curl -i http://<server>/api/files/...— no longer returns 503.make stop && make runagain —core.fossilmtime/contents unchanged on the second run.