Self-hosting artifacts for generated docs: config contract, release.json, deploy/selfhost, Containerfile, operations facts #1156

Open
opened 2026-10-05 15:28:17 +00:00 by kayg · 19 comments
Owner

Self-hosting source-of-truth artifacts for generated docs (handover from the Mac thread, #1143)

Goal: docs.calternal.com gets a self-hosting guide (install, configure, upgrade, back up) where every fact is generated from code, like the CLI/action/API/Rust reference pages (#971). The Mac thread owns apps/docs and apps/website and will write the generators and guide pages; this issue produces the artifacts, in crates/, contracts/, deploy/ only. Never write in apps/docs or apps/website.

  1. contracts/config.json generated from the config struct that crates/calternal-server/src/main.rs loads with Environment::with_prefix("CALTERNAL") (separator __). Per key: env name (e.g. CALTERNAL_SERVER__PUBLIC_URL), type, default, required, description = the field's /// doc comment, secret: true where it applies. Every field gets an STE doc comment. Contract test in the style of the existing cli_contract: fails when the file does not match the struct; regenerate with CALTERNAL_WRITE_CONTRACTS=1.
  2. contracts/release.json written by the release script (not by hand): image name, tag scheme, supported architectures. The registry is the owner's choice (pending, see the orchestrator's question); build the writer and leave the registry value as a parameter until decided. Do not publish anything.
  3. deploy/selfhost/: canonical, commented examples: Podman Quadlet calternal.container, compose.yaml, and calternal.env.example GENERATED from contracts/config.json (required keys first, secrets as placeholders). Port, volume path (/data), user (10001) and health URL must match the image. A test checks the env example (and the port/volume/user/health values in the Quadlet and compose files) against contracts/config.json and the Containerfile.
  4. Root Containerfile: make it build on a clean checkout (the #1143 findings: missing components.json, contracts/, apps/web/scripts, OpenSSL/cmake/clang toolchain, Debian trixie base), or delete it in favour of the release path and point docs at that. Prove it with a clean-clone podman build (quote the tail of the log).
  5. Upgrade and backup facts as data (e.g. contracts/operations.json, generated or tested against code): migration behaviour on start (startup may take minutes after migrations; expose a /healthz state such as migrating with progress so docs and orchestrators can wait), which paths to back up (the data dir; the Index is rebuildable except security state, DESIGN §2), and restore steps. Licence facts only once DESIGN.md §43 reflects the owner's 2026-10-05 decision (free up to 6 active users, yearly key, perpetual fallback, no phone-home; #1145): update §43 accordingly in this job if #1145 has not.

Rules: CLAUDE.md, CONTEXT.md terms, STE doc comments, no secrets, no prices. Gates: cargo fmt --check, clippy -D warnings, cargo test for touched crates + the new contract tests; quote output on this issue and comment on #1143 with the SHA when it lands on dev.

## Self-hosting source-of-truth artifacts for generated docs (handover from the Mac thread, #1143) Goal: docs.calternal.com gets a self-hosting guide (install, configure, upgrade, back up) where every fact is generated from code, like the CLI/action/API/Rust reference pages (#971). The Mac thread owns apps/docs and apps/website and will write the generators and guide pages; this issue produces the artifacts, in crates/, contracts/, deploy/ only. Never write in apps/docs or apps/website. 1. **contracts/config.json** generated from the config struct that crates/calternal-server/src/main.rs loads with `Environment::with_prefix("CALTERNAL")` (separator `__`). Per key: env name (e.g. `CALTERNAL_SERVER__PUBLIC_URL`), type, default, required, description = the field's `///` doc comment, `secret: true` where it applies. Every field gets an STE doc comment. Contract test in the style of the existing `cli_contract`: fails when the file does not match the struct; regenerate with `CALTERNAL_WRITE_CONTRACTS=1`. 2. **contracts/release.json** written by the release script (not by hand): image name, tag scheme, supported architectures. The registry is the owner's choice (pending, see the orchestrator's question); build the writer and leave the registry value as a parameter until decided. Do not publish anything. 3. **deploy/selfhost/**: canonical, commented examples: Podman Quadlet `calternal.container`, `compose.yaml`, and `calternal.env.example` GENERATED from contracts/config.json (required keys first, secrets as placeholders). Port, volume path (/data), user (10001) and health URL must match the image. A test checks the env example (and the port/volume/user/health values in the Quadlet and compose files) against contracts/config.json and the Containerfile. 4. **Root Containerfile**: make it build on a clean checkout (the #1143 findings: missing components.json, contracts/, apps/web/scripts, OpenSSL/cmake/clang toolchain, Debian trixie base), or delete it in favour of the release path and point docs at that. Prove it with a clean-clone `podman build` (quote the tail of the log). 5. **Upgrade and backup facts as data** (e.g. contracts/operations.json, generated or tested against code): migration behaviour on start (startup may take minutes after migrations; expose a `/healthz` state such as `migrating` with progress so docs and orchestrators can wait), which paths to back up (the data dir; the Index is rebuildable except security state, DESIGN §2), and restore steps. Licence facts only once DESIGN.md §43 reflects the owner's 2026-10-05 decision (free up to 6 active users, yearly key, perpetual fallback, no phone-home; #1145): update §43 accordingly in this job if #1145 has not. Rules: CLAUDE.md, CONTEXT.md terms, STE doc comments, no secrets, no prices. Gates: cargo fmt --check, clippy -D warnings, cargo test for touched crates + the new contract tests; quote output on this issue and comment on #1143 with the SHA when it lands on dev.
Author
Owner

Owner decision (2026-10-05): the public self-host image is published ONLY to the Forgejo container registry at git.kayg.org (image git.kayg.org/kayg/calternal) for now. No GHCR mirror. contracts/release.json records that registry; the release script pushes there only when the owner asks (no publishing in this job).

Owner decision (2026-10-05): the public self-host image is published ONLY to the Forgejo container registry at git.kayg.org (image `git.kayg.org/kayg/calternal`) for now. No GHCR mirror. contracts/release.json records that registry; the release script pushes there only when the owner asks (no publishing in this job).
Author
Owner

Starting #1156 on job/selfhost-1156, based at de654a42ac4f9a6dca83bed8e0eebc99706f7dfe (the current merge-base with origin/dev). I am checking the config and migration source before generating the contracts and deployment examples. The owner decision for the image registry is Forgejo at git.kayg.org/kayg/calternal; this job will add metadata and release-script support only, with no publish.

Starting #1156 on `job/selfhost-1156`, based at `de654a42ac4f9a6dca83bed8e0eebc99706f7dfe` (the current merge-base with `origin/dev`). I am checking the config and migration source before generating the contracts and deployment examples. The owner decision for the image registry is Forgejo at `git.kayg.org/kayg/calternal`; this job will add metadata and release-script support only, with no publish.
Author
Owner

Source inspection found two gaps relevant to the generated self-host guide:

  • Containerfile runs bun run --cwd apps/web build, whose package script calls apps/web/scripts/canvas-assets.mjs, canvas-renderer.mjs and compress-static-assets.mjs, but the build stage does not copy apps/web/scripts. The Vite config also reads contracts/public-auth-routes.json, which the Containerfile does not copy.
  • crates/calternal-server/src/main.rs::healthz always returns ok. In crates/calternal-server/src/wire.rs, schema migrations complete before listener bind, while startup reconciliation runs after bind and can continue through Notes, Search, Files and Tags scans. I will expose that post-bind work as health state with bounded phase progress; the operations contract will state that schema migrations finish before the health endpoint is available.
Source inspection found two gaps relevant to the generated self-host guide: - `Containerfile` runs `bun run --cwd apps/web build`, whose package script calls `apps/web/scripts/canvas-assets.mjs`, `canvas-renderer.mjs` and `compress-static-assets.mjs`, but the build stage does not copy `apps/web/scripts`. The Vite config also reads `contracts/public-auth-routes.json`, which the Containerfile does not copy. - `crates/calternal-server/src/main.rs::healthz` always returns `ok`. In `crates/calternal-server/src/wire.rs`, schema migrations complete before listener bind, while startup reconciliation runs after bind and can continue through Notes, Search, Files and Tags scans. I will expose that post-bind work as health state with bounded phase progress; the operations contract will state that schema migrations finish before the health endpoint is available.
Author
Owner

A second source mismatch was in docs/DESIGN.md §43: it still described a one-time self-host licence, no key enforcement, and an open payment model. Those statements conflict with #1145. I replaced them with the 2026-10-05 owner decision: free through six active Users, yearly keys, perpetual fallback for earlier releases, local Ed25519 checks, and no phone-home. No prices or signing secrets were added.

A second source mismatch was in `docs/DESIGN.md` §43: it still described a one-time self-host licence, no key enforcement, and an open payment model. Those statements conflict with #1145. I replaced them with the 2026-10-05 owner decision: free through six active Users, yearly keys, perpetual fallback for earlier releases, local Ed25519 checks, and no phone-home. No prices or signing secrets were added.
Author
Owner

The first CALTERNAL_WRITE_CONTRACTS=1 cargo test -p calternal-server config_contract attempt stopped at #[derive(RustEmbed)]: apps/web/build/ was absent, followed by missing Frontend::get methods. This clean checkout needs the real SPA production build before the server crate can compile. I will build the SPA, then rerun the contract test and use that same build prerequisite in the clean Containerfile build.

The first `CALTERNAL_WRITE_CONTRACTS=1 cargo test -p calternal-server config_contract` attempt stopped at `#[derive(RustEmbed)]`: `apps/web/build/` was absent, followed by missing `Frontend::get` methods. This clean checkout needs the real SPA production build before the server crate can compile. I will build the SPA, then rerun the contract test and use that same build prerequisite in the clean Containerfile build.
Author
Owner

Finding: deploy/selfhost/test_artifacts.py failed test_env_example_matches_the_generated_config_contract because the Notes submission field description changed in Rust while contracts/config.json and calternal.env.example still had the prior text. I am regenerating both artifacts from the contract source, then I will rerun the focused deploy tests.

Finding: `deploy/selfhost/test_artifacts.py` failed `test_env_example_matches_the_generated_config_contract` because the Notes submission field description changed in Rust while `contracts/config.json` and `calternal.env.example` still had the prior text. I am regenerating both artifacts from the contract source, then I will rerun the focused deploy tests.
Author
Owner

Finding: the clean image context also needs contracts/action-policy.json and contracts/openapi.json. crates/calternal-server/src/action_contract.rs and agent_docs.rs use compile-time includes for those files, while the Containerfile previously copied only actions.json and public-auth-routes.json. I added both files to the server build stage and added a deploy artifact check for all four compile-time contracts.

Finding: the clean image context also needs `contracts/action-policy.json` and `contracts/openapi.json`. `crates/calternal-server/src/action_contract.rs` and `agent_docs.rs` use compile-time includes for those files, while the Containerfile previously copied only `actions.json` and `public-auth-routes.json`. I added both files to the server build stage and added a deploy artifact check for all four compile-time contracts.
Author
Owner

Finding: the first operations contract test run failed its licence check because it searched for the literal string DESIGN §43 inside the Design text. The section heading is ## 43 and cites #1145 instead. I am changing the test to isolate §43 and compare the owner decision facts in that section.

Finding: the first operations contract test run failed its licence check because it searched for the literal string `DESIGN §43` inside the Design text. The section heading is `## 43` and cites `#1145` instead. I am changing the test to isolate §43 and compare the owner decision facts in that section.
Author
Owner

Finding: the config contract generator hard-coded CALTERNAL and __, while Settings::load configured its prefix and separator independently. The contract could stay green if the loader changed later. I am moving those values into constants used by both the loader and generator, so the generated names follow the code that reads them.

Finding: the config contract generator hard-coded `CALTERNAL` and `__`, while `Settings::load` configured its prefix and separator independently. The contract could stay green if the loader changed later. I am moving those values into constants used by both the loader and generator, so the generated names follow the code that reads them.
Author
Owner

Finding: the expanded operations contract run passed the migration-order check but failed two new Design text checks. DESIGN §2 wraps the rebuildability sentence across Markdown lines, and §43 says every release dated before the expiry (singular). I am normalizing whitespace in the checks and matching the exact owner wording.

Finding: the expanded operations contract run passed the migration-order check but failed two new Design text checks. DESIGN §2 wraps the rebuildability sentence across Markdown lines, and §43 says `every release dated before the expiry` (singular). I am normalizing whitespace in the checks and matching the exact owner wording.
Author
Owner

Finding: cargo test -p calternal-server passed 262 unit tests, then tests/perf_guards.rs::deterministic_performance_guards failed. perf-lint reports the exception ratchet is over by one for several source policies and by 13 total (21977 vs 21964). I am locating the new exception entries. I will not increase the existing ratchet ceiling.

Finding: `cargo test -p calternal-server` passed 262 unit tests, then `tests/perf_guards.rs::deterministic_performance_guards` failed. `perf-lint` reports the exception ratchet is over by one for several source policies and by 13 total (`21977` vs `21964`). I am locating the new exception entries. I will not increase the existing ratchet ceiling.
Author
Owner

Finding from the post-merge cargo test -p calternal-server: all 262 server unit tests passed, then tests/perf_guards.rs::deterministic_performance_guards rejected the health handler with coverage.router-handler ... /healthz ... unused or changed exception. The new route uses a constant path that the route inventory cannot resolve, and its handler syntax changed by this issue. I will retain the literal route path and refresh the existing exact syntax pin only; no perf exception count or ratchet ceiling will change.

Finding from the post-merge `cargo test -p calternal-server`: all 262 server unit tests passed, then `tests/perf_guards.rs::deterministic_performance_guards` rejected the health handler with `coverage.router-handler ... /healthz ... unused or changed exception`. The new route uses a constant path that the route inventory cannot resolve, and its handler syntax changed by this issue. I will retain the literal route path and refresh the existing exact syntax pin only; no perf exception count or ratchet ceiling will change.
Author
Owner

Final clippy caught one implementation issue: HEALTHZ_PATH is used only by the cfg(test) operations contract, so the production target reported dead code under -D warnings. I will compile that constant only for tests; the live route stays a literal so the existing route inventory can verify it.

Final clippy caught one implementation issue: `HEALTHZ_PATH` is used only by the `cfg(test)` operations contract, so the production target reported dead code under `-D warnings`. I will compile that constant only for tests; the live route stays a literal so the existing route inventory can verify it.
Author
Owner

The clean-clone podman build failed at Containerfile step 12 because apps/web/components.json does not exist in this repository. A repository search found no components.json and no web build reference to it. I will remove this unused COPY and add a small artifact test that checks every build-context COPY source exists.

The clean-clone `podman build` failed at Containerfile step 12 because `apps/web/components.json` does not exist in this repository. A repository search found no `components.json` and no web build reference to it. I will remove this unused COPY and add a small artifact test that checks every build-context COPY source exists.
Author
Owner

The clean-clone build now passes the web build-context copies and reaches bun run build, then fails because apps/web/src/lib/webmcp/generated.ts imports contracts/actions.json. public-auth-routes.json is the other runtime contract imported by the web build. I will copy both into the web stage and assert both inputs in the artifact test.

The clean-clone build now passes the web build-context copies and reaches `bun run build`, then fails because `apps/web/src/lib/webmcp/generated.ts` imports `contracts/actions.json`. `public-auth-routes.json` is the other runtime contract imported by the web build. I will copy both into the web stage and assert both inputs in the artifact test.
Author
Owner

The clean-clone image build reached cargo build --release and failed in openssl-sys: pkg-config could not find openssl.pc, and the build output says the OpenSSL development package is required. The builder already has the vendored OpenSSL tools; I will add Trixie's libssl-dev for the system OpenSSL dependency and rerun the clean build.

The clean-clone image build reached `cargo build --release` and failed in `openssl-sys`: pkg-config could not find `openssl.pc`, and the build output says the OpenSSL development package is required. The builder already has the vendored OpenSSL tools; I will add Trixie's `libssl-dev` for the system OpenSSL dependency and rerun the clean build.
Author
Owner

The clean-clone build completed the 33-minute release compile and runtime package setup, then Podman rejected HEALTHCHECK ... CMD-SHELL with Unknown type "CMD-SHELL" in HEALTHCHECK (try CMD). CMD-SHELL remains correct in Compose and Quadlet; the root Containerfile needs Dockerfile shell-form CMD for its pipeline. I will change only the Containerfile health-check syntax and rerun the clean-clone build using its completed build layers.

The clean-clone build completed the 33-minute release compile and runtime package setup, then Podman rejected `HEALTHCHECK ... CMD-SHELL` with `Unknown type "CMD-SHELL" in HEALTHCHECK (try CMD)`. `CMD-SHELL` remains correct in Compose and Quadlet; the root Containerfile needs Dockerfile shell-form `CMD` for its pipeline. I will change only the Containerfile health-check syntax and rerun the clean-clone build using its completed build layers.
Author
Owner

The clean-clone build passed, but its tail warned HEALTHCHECK is not supported for OCI image format and will be ignored. Must use docker format; podman image inspect confirmed .Config.Healthcheck was <nil>. I will set the release writer's Podman build to --format docker, test that build argument, and rebuild the clean checkout so the shipped image carries the ready-state health check.

The clean-clone build passed, but its tail warned `HEALTHCHECK is not supported for OCI image format and will be ignored. Must use docker format`; `podman image inspect` confirmed `.Config.Healthcheck` was `<nil>`. I will set the release writer's Podman build to `--format docker`, test that build argument, and rebuild the clean checkout so the shipped image carries the ready-state health check.
Author
Owner

Finished selfhost-1156 on job/selfhost-1156.

Head: 04c2127d5530e87368aa2f5c94926a8f0532df63

Built

  • Generated contracts/config.json from the server settings schemas and Rust defaults. The contract includes environment names, types, defaults, required flags, STE descriptions and secret flags. The contract test checks drift and supports CALTERNAL_WRITE_CONTRACTS=1.
  • Added contracts/operations.json for schema migration order, post-migration startup progress, backup paths, restore steps and the owner-decided licence facts. Contract tests compare these facts with the server, filesystem and DESIGN §43.
  • Added GET /healthz JSON progress for the seven post-bind startup stages. It returns migrating with a phase and progress fields until the stages finish, then ready. Schema migrations still run before HTTP bind.
  • Added the generated release contract and release writer for git.kayg.org/kayg/calternal:v<version>, currently linux/amd64. The writer publishes only with explicit --publish; nothing was published.
  • Added the Quadlet, Compose and generated environment examples. Tests check environment keys, container values and local Containerfile copy sources.
  • Fixed the root Containerfile for a clean checkout. A clean clone built successfully with Docker-format output, and image inspection confirmed Podman retained the health check.
  • Updated DESIGN §43 to record the owner’s 2026-10-05 decision.

Files

  • Containerfile
  • contracts/config.json, contracts/operations.json, contracts/release.json, contracts/perf/exceptions.json
  • crates/calternal-server/src/config_contract.rs, main.rs, notes_imap.rs, operations_contract.rs, wire.rs
  • deploy/release-selfhost.py
  • deploy/selfhost/calternal.container, calternal.env.example, compose.yaml, generate_env.py, test_artifacts.py
  • docs/DESIGN.md

Gates

Output excerpts below are verbatim. cargo fmt --check, generated-file checks and git diff --check exited 0 with no output.

   Compiling calternal-server v0.0.1 (/home/kayg/Developer/calternal-wt/selfhost-1156/crates/calternal-server)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 25.80s
test result: ok. 263 passed; 0 failed; 10 ignored; 0 measured; 0 filtered out; finished in 133.29s
test deterministic_performance_guards ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 33.90s
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.30s
test config_contract::config_contract_matches_settings_structs ... ok
test operations_contract::operations_backup_facts_match_data_layout ... ok
test operations_contract::operations_licence_facts_match_design_section_43 ... ok
test operations_contract::operations_migration_facts_match_server_order ... ok
test operations_contract::operations_contract_matches_server_facts ... ok
test result: ok. 18 passed; 0 failed; 0 ignored; 0 measured; 254 filtered out; finished in 0.28s
......
----------------------------------------------------------------------
Ran 6 tests in 0.109s

OK

Clean-clone Podman build tail:

[3/3] STEP 8/12: VOLUME ["/data"]
--> d0e32d173ef9
[3/3] STEP 9/12: EXPOSE 8080
--> 31ade3b997d4
[3/3] STEP 10/12: USER 10001:10001
--> 3c6e0bf416b9
[3/3] STEP 11/12: HEALTHCHECK --interval=30s --timeout=3s --start-period=10m --retries=3     CMD curl --fail --silent http://127.0.0.1:8080/healthz | grep -q '"state":"ready"'
--> fb484d55ad19
[3/3] STEP 12/12: ENTRYPOINT ["/usr/local/bin/calternal-server"]
[3/3] COMMIT localhost/calternal-selfhost-1156:test
--> e408799a2fff
Successfully tagged localhost/calternal-selfhost-1156:test
e408799a2fff54fd58ff6601c8f6c5dfa69c4fb975724effdb8a0c4c8a167df7

The build exited 0. Image inspection returned:
{"Test":["CMD-SHELL","curl --fail --silent http://127.0.0.1:8080/healthz | grep -q '\"state\":\"ready\"'"],"StartPeriod":600000000000,"Interval":30000000000,"Timeout":3000000000,"Retries":3}

Known gaps

  • The guide pages remain with the #1143 Mac thread; this change supplies their generated source artifacts.
  • The health endpoint is not available during schema migrations because the server binds after they finish. Its progress covers the post-bind startup work.
  • The release contract currently supports linux/amd64 only. No image was published.
  • The real-server adversarial matrix remains for the merge round. The existing startup benchmark already exercises /healthz latency and a 64-request burst; no performance measurement was run because this issue is not a performance issue.

Decisions

  • Expose startup progress as HTTP 200 JSON with state, phase, completed/total steps and percentage. Use migrating for post-bind startup work and ready after all seven stages.
  • Use Docker-format image output because the clean OCI-format build discarded the Containerfile health check in Podman.
  • Record only the Forgejo registry and amd64 architecture per the owner decision. Publishing remains explicit and was not requested.

UX gaps closed: none; no UI changed. UX gaps left: not applicable.

For the merge round

Run bash tests/adversarial/run.sh against the real local server. It must complete the XUser/authz reviews and hostile-input/concurrency probes without crashes or non-SLOW 5xx findings. If this branch has not yet landed on dev, post the #1143 handoff comment with this SHA after it lands.

Finished selfhost-1156 on `job/selfhost-1156`. Head: `04c2127d5530e87368aa2f5c94926a8f0532df63` ### Built - Generated `contracts/config.json` from the server settings schemas and Rust defaults. The contract includes environment names, types, defaults, required flags, STE descriptions and secret flags. The contract test checks drift and supports `CALTERNAL_WRITE_CONTRACTS=1`. - Added `contracts/operations.json` for schema migration order, post-migration startup progress, backup paths, restore steps and the owner-decided licence facts. Contract tests compare these facts with the server, filesystem and DESIGN §43. - Added `GET /healthz` JSON progress for the seven post-bind startup stages. It returns `migrating` with a phase and progress fields until the stages finish, then `ready`. Schema migrations still run before HTTP bind. - Added the generated release contract and release writer for `git.kayg.org/kayg/calternal:v<version>`, currently `linux/amd64`. The writer publishes only with explicit `--publish`; nothing was published. - Added the Quadlet, Compose and generated environment examples. Tests check environment keys, container values and local Containerfile copy sources. - Fixed the root Containerfile for a clean checkout. A clean clone built successfully with Docker-format output, and image inspection confirmed Podman retained the health check. - Updated DESIGN §43 to record the owner’s 2026-10-05 decision. ### Files - `Containerfile` - `contracts/config.json`, `contracts/operations.json`, `contracts/release.json`, `contracts/perf/exceptions.json` - `crates/calternal-server/src/config_contract.rs`, `main.rs`, `notes_imap.rs`, `operations_contract.rs`, `wire.rs` - `deploy/release-selfhost.py` - `deploy/selfhost/calternal.container`, `calternal.env.example`, `compose.yaml`, `generate_env.py`, `test_artifacts.py` - `docs/DESIGN.md` ### Gates Output excerpts below are verbatim. `cargo fmt --check`, generated-file checks and `git diff --check` exited 0 with no output. ```text Compiling calternal-server v0.0.1 (/home/kayg/Developer/calternal-wt/selfhost-1156/crates/calternal-server) Finished `dev` profile [unoptimized + debuginfo] target(s) in 25.80s ``` ```text test result: ok. 263 passed; 0 failed; 10 ignored; 0 measured; 0 filtered out; finished in 133.29s test deterministic_performance_guards ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 33.90s test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.30s ``` ```text test config_contract::config_contract_matches_settings_structs ... ok test operations_contract::operations_backup_facts_match_data_layout ... ok test operations_contract::operations_licence_facts_match_design_section_43 ... ok test operations_contract::operations_migration_facts_match_server_order ... ok test operations_contract::operations_contract_matches_server_facts ... ok test result: ok. 18 passed; 0 failed; 0 ignored; 0 measured; 254 filtered out; finished in 0.28s ``` ```text ...... ---------------------------------------------------------------------- Ran 6 tests in 0.109s OK ``` Clean-clone Podman build tail: ```text [3/3] STEP 8/12: VOLUME ["/data"] --> d0e32d173ef9 [3/3] STEP 9/12: EXPOSE 8080 --> 31ade3b997d4 [3/3] STEP 10/12: USER 10001:10001 --> 3c6e0bf416b9 [3/3] STEP 11/12: HEALTHCHECK --interval=30s --timeout=3s --start-period=10m --retries=3 CMD curl --fail --silent http://127.0.0.1:8080/healthz | grep -q '"state":"ready"' --> fb484d55ad19 [3/3] STEP 12/12: ENTRYPOINT ["/usr/local/bin/calternal-server"] [3/3] COMMIT localhost/calternal-selfhost-1156:test --> e408799a2fff Successfully tagged localhost/calternal-selfhost-1156:test e408799a2fff54fd58ff6601c8f6c5dfa69c4fb975724effdb8a0c4c8a167df7 ``` The build exited 0. Image inspection returned: `{"Test":["CMD-SHELL","curl --fail --silent http://127.0.0.1:8080/healthz | grep -q '\"state\":\"ready\"'"],"StartPeriod":600000000000,"Interval":30000000000,"Timeout":3000000000,"Retries":3}` ### Known gaps - The guide pages remain with the #1143 Mac thread; this change supplies their generated source artifacts. - The health endpoint is not available during schema migrations because the server binds after they finish. Its progress covers the post-bind startup work. - The release contract currently supports `linux/amd64` only. No image was published. - The real-server adversarial matrix remains for the merge round. The existing startup benchmark already exercises `/healthz` latency and a 64-request burst; no performance measurement was run because this issue is not a performance issue. ### Decisions - Expose startup progress as HTTP 200 JSON with `state`, `phase`, completed/total steps and percentage. Use `migrating` for post-bind startup work and `ready` after all seven stages. - Use Docker-format image output because the clean OCI-format build discarded the Containerfile health check in Podman. - Record only the Forgejo registry and amd64 architecture per the owner decision. Publishing remains explicit and was not requested. UX gaps closed: none; no UI changed. UX gaps left: not applicable. ### For the merge round Run `bash tests/adversarial/run.sh` against the real local server. It must complete the XUser/authz reviews and hostile-input/concurrency probes without crashes or non-SLOW 5xx findings. If this branch has not yet landed on dev, post the #1143 handoff comment with this SHA after it lands.
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
kayg/calternal#1156
No description provided.