Skip to content

Commit bfb448e

Browse files
authored
feat: release Sync Web 1.3.0 (#22)
Summary - Release Sync Web 1.3.0. - Add the document record abstraction and integrate document metadata through ledger/interface reads, writes, resolves, traces, slices, and prunes. - Migrate public record paths to flat staged/indexed/bridge traversal forms across records, gateway clients, Explorer, tests, and examples. - Replace the old file-system adapter with a gateway-backed WebDAV service, including navigable ledger index paths, WebDAV directory markers, `/control/pin`, and updated local/API smoke coverage. - Move user document payloads to byte-vector-only storage, with explicit `expression? #t` boundary codecs for expression-oriented API calls. - Align Explorer, WebDAV, gateway/workbench examples, locust, and social-agent workloads with byte-vector documents and metadata-aware access. - Add gateway-local SSE change hints and Explorer stale-while-revalidate refreshes for live staged/admin/ledger views. - Add the static router journal-node splash page and WebDAV guide, served by the router without a new service. - Harden local/network operations: isolated Compose stack names, safer teardown docs, runtime-neutral Docker/Podman helpers, healthchecks, development check docs, and screenshot helper updates. - Improve bridge workflows: negotiated bridge modes, journal peer identity defaults, JSON batch normalization/decoding, content-only directory discovery, accurate local `pinned?` semantics, and historical multi-hop bridge proof resolution. - Stabilize Explorer/network behavior: preserve active staged edits during refresh, fix bridged pin/unpin display, show node loading feedback, default Explorer stage to user home, and write social-agent documents as plain UTF-8 byte-vectors. Testing - `git diff --check` - `./records/tests/test.sh ./journal/target/release/journal-sdk` - `cd services/explorer && npm test -- --watchAll=false` - `cd tests/network/common/social-agent && python -m unittest discover -s tests` - `cd services/gateway && npm test` (run earlier in branch) - `cd services/file-system && go test ./...` (run earlier in branch) - `cd tests/load/locust && python -m unittest discover -s tests` (run earlier in branch) - Local 8-node Podman compose smoke: router health, splash/WebDAV guide, raw byte-vector social-agent documents, bridged pin/unpin sibling behavior, and historical multi-hop bridge resolve. Notes/Risks - Durable document payloads are now byte-vector-only. Use `expression? #t` for public API calls that intentionally encode/decode Scheme expressions. - Public path syntax is now the flat path shape; older nested public path shapes are intentionally not preserved. - `pinned?` now means local permanent proof can resolve the value: confirmed values, including `(nothing)`, are pinned; `(unknown)` is not pinned. The check does not perform remote bridge fetches. - Chain `get` returns `(unknown)` for unavailable pruned proof paths instead of leaking low-level sync-node access errors, allowing bridge fallback fetch/merge to continue. - WebDAV is a protocol endpoint; browser users should use the new router WebDAV guide instead of opening `/webdav/` directly.
1 parent d147a39 commit bfb448e

139 files changed

Lines changed: 6261 additions & 11952 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/journal.yml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -97,13 +97,10 @@ jobs:
9797
runs-on: ubuntu-latest
9898
steps:
9999
- uses: actions/checkout@v4
100-
- name: Install smbclient
101-
run: sudo apt-get update && sudo apt-get install -y smbclient
102100
- name: Run compose smoke test
103101
run: |
104102
SECRET=password \
105103
PORT=8192 \
106-
SMB_PORT=1445 \
107104
tests/api/local-compose.sh smoke
108105
109106
tag-version:

AGENTS.md

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# Agent Guidance
2+
3+
## Git
4+
5+
- Do all work on separate branches, never push or otherwise edit `main` directly.
6+
- Do not push any branch unless explicitly asked.
7+
- All pull requests to `main` should consist of a single squashed commit with a detailed markdown message.
8+
9+
## Versioning
10+
11+
- The platform version in `/VERSION` and the journal-sdk crate version is in `journal/Cargo.toml`.
12+
- Platform version should be updated for all pull requests
13+
- Crate version should only be updated for pull requests that affect the journal-sdk
14+
- For both notions of version:
15+
- Bump the relevant version for every pull request. Confirm the type first: patch, minor, or (rarely) major.
16+
- When bumping version, update all deployment configurations to reference the latest version.
17+
- When bumping minor or major versions, update the changelog if one already exists.
18+
19+
## Documentation
20+
- Before final pull requests, ensure that documentation in `/docs` track the implementation
21+
- Before final pull requests, ensure that README.md and other repo-level documents track the implementation.
22+
- When adding or changing modules, classes, or functions, ensure that docstrings are correct and consistent.
23+
24+
## Deployment
25+
26+
- Preserve both deployment paths:
27+
- `deploy/compose/general/compose.yaml` is the primary single-node deployment path.
28+
- `tests/api/local-compose.sh` is the primary local smoke-test path.
29+
- Preserve both TLS and plaintext deployment paths
30+
- HTTP-only deployment must keep working for internal networks.
31+
- TLS deployment must keep working with host-provided certificate/key paths.
32+
- Preserve both Docker, Podman, and other standard container runtimes where possible.
33+
- Consider Windows, macOS, and Linux (Ubuntu and Fedora SELinux) compatibility posture where possible.
34+
35+
## Testing
36+
37+
- Before submitting pull requests, identify and run Github Actions locally where relevant and possible.
38+
- Relevant actions are in .github/workflows/*.yml.
39+
40+
## Development
41+
42+
- When working with s7 scheme/lisp code, consult `/records/LANGUAGE.md`
43+
- In Scheme, avoid polluting local namespaces with low-value intermediate variables when collection references are short and explicit.
44+
- Prefer exact expected data shapes that fail quickly when malformed over networks of ad hoc fallbacks that become hard to reason about.
45+
- For high-blast-radius changes, roll out from lower layers to higher layers in separate commits/PR slices where practical: Rust/journal changes first, then Scheme record changes, then service/UI changes. Run/update relevant tests incrementally with each slice.

CHANGELOG.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,28 @@
11
# Changelog
22

3+
## 1.3.0
4+
5+
### Added
6+
7+
- **Document records** — Added byte-vector-only document payloads with metadata support and explicit `expression?` public I/O codec for expression-oriented callers.
8+
- **WebDAV file-system service** — Replaced the previous file-system adapter with a gateway-backed WebDAV service and navigable ledger index paths.
9+
- **Gateway events** — Added authenticated Server-Sent Events change hints and Explorer live refresh integration.
10+
- **Router splash page** — Added a static journal node home page and WebDAV guide served directly by the router.
11+
12+
### Changed
13+
14+
- **Record paths** — Public ledger/interface paths now use flat path syntax for staged, indexed, and bridge traversal paths.
15+
- **Document adapters** — Explorer, WebDAV, gateway examples, social-agent, and load workloads now write normal document content as byte-vectors unless explicitly using `expression?`.
16+
- **Pinned state**`pinned?` now reports local permanent proof value availability; confirmed values including `(nothing)` are pinned, while `(unknown)` is not.
17+
- **Compose defaults** — All service image tags default to `1.3.0`.
18+
19+
### Fixed
20+
21+
- **Bridge resolution** — Historical multi-hop bridge paths now return semantic values/unknowns instead of low-level sync-node access errors.
22+
- **Explorer stability** — Preserved active staged edits during background refreshes and fixed bridged file pin/unpin display.
23+
- **Batch JSON** — Normalized JSON batch subqueries and decoded batch results consistently.
24+
- **Directory discovery** — Explorer directory discovery uses content-only reads to avoid unnecessary proof/pin coupling.
25+
326
## 1.2.0
427

528
### Added

README.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ Full documentation: [sandialabs.github.io/sync-web](https://sandialabs.github.io
1111
| `journal/` | Rust journal-sdk: HTTP server, S7 Scheme evaluator, RocksDB persistence |
1212
| `records/` | Scheme record logic: `root`, `standard`, `tree`, `chain`, `ledger`, `interface` |
1313
| `services/` | Web services: `gateway`, `router`, `explorer`, `workbench`, `file-system` |
14-
| `deploy/` | Single-node Docker Compose deployment |
14+
| `deploy/` | Single-node Compose-compatible container deployment |
1515
| `tests/` | API smoke tests, load tests, multi-node network tests |
1616
| `docs/` | Documentation site (Astro/Starlight) |
1717

@@ -20,11 +20,12 @@ Full documentation: [sandialabs.github.io/sync-web](https://sandialabs.github.io
2020
The fastest way to run a local stack:
2121

2222
```sh
23-
cd deploy/compose/general
24-
SECRET=yourpassword docker compose up
23+
COMPOSE_PROJECT_NAME=sync-local SECRET=yourpassword \
24+
HTTP_PORT=8192 HTTPS_PORT=8193 \
25+
docker compose -f deploy/compose/general/compose.yaml up
2526
```
2627

27-
See `deploy/compose/general/README.md` for full configuration options.
28+
Use `podman-compose` or `podman compose` instead of `docker compose` if that is your container runtime. See `deploy/compose/general/README.md` for full configuration options and `docs/development-checks.md` for validation commands and tool dependencies.
2829

2930
## License
3031

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
1.2.2
1+
1.3.0

deploy/compose/general/README.md

Lines changed: 73 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,62 @@
11
# Synchronic Web Ledger Compose Network
22

3-
This compose stack runs one journal with gateway, explorer, workbench, router, and the `file-system` SMB service.
3+
This compose stack runs one journal with gateway, explorer, workbench, router, identity-provider, and the WebDAV `file-system` service.
44

5-
The journal service uses the generic `journal-sdk` image directly. The general
6-
interface is assembled at startup from mounted deployment inputs:
5+
The journal service uses the generic `journal-sdk` image directly. The general interface is assembled at startup from mounted deployment inputs:
76

87
- `records/lisp/*.scm`
98
- `deploy/compose/general/run.sh`
109
- the persistent `database` volume
1110

12-
For a fresh database, `run.sh` installs the general interface from the mounted Lisp
13-
files. For an existing database, mounted Lisp files are only applied when
14-
`JOURNAL_UPDATE=1`; otherwise the durable journal state continues from the database.
11+
For a fresh database, `run.sh` installs the general interface from the mounted Lisp files. For an existing database, mounted Lisp files are only applied when `JOURNAL_UPDATE=1`; otherwise the durable journal state continues from the database.
1512

1613
## Requirements
1714

18-
- Docker
19-
- Docker Compose
20-
- Podman Compose on Fedora is also supported. The bind mounts use SELinux
21-
relabel flags so rootless Podman can read the mounted startup script and Lisp
22-
files.
15+
- A Compose-compatible container runtime: Docker Compose, Podman Compose, or `podman-compose`
16+
- `curl` for the local smoke helper
17+
18+
The bind mounts use SELinux relabel flags (`:Z`) so rootless Podman can read the mounted startup script and Lisp files.
19+
20+
## Stack identity and ports
21+
22+
Use `COMPOSE_PROJECT_NAME` to isolate local, public, and experimental stacks. Container and network names are prefixed from this value, for example `sync-dev-journal` and `sync-prod-gateway`.
23+
24+
Default local ports are adjacent and non-privileged:
25+
26+
- `HTTP_PORT` default `8192`
27+
- `HTTPS_PORT` default `8193`
28+
29+
Example local stack:
30+
31+
```bash
32+
COMPOSE_PROJECT_NAME=sync-dev SECRET=password \
33+
HTTP_PORT=8192 HTTPS_PORT=8193 \
34+
docker compose -f deploy/compose/general/compose.yaml up -d
35+
```
36+
37+
Example public stack using standard ports:
38+
39+
```bash
40+
COMPOSE_PROJECT_NAME=sync-prod SECRET=password \
41+
ORIGIN=https://example.com HTTP_PORT=80 HTTPS_PORT=443 \
42+
docker compose -f deploy/compose/general/compose.yaml up -d
43+
```
44+
45+
With Podman Compose:
46+
47+
```bash
48+
COMPOSE_PROJECT_NAME=sync-dev SECRET=password \
49+
HTTP_PORT=8192 HTTPS_PORT=8193 \
50+
podman-compose -f deploy/compose/general/compose.yaml up -d
51+
```
2352

2453
## Configuration
2554

55+
- `COMPOSE_PROJECT_NAME` (recommended): stack/project identity used for generated volumes and parameterized container/network names
2656
- `SECRET` (required): authentication secret for restricted journal/gateway operations
27-
- `PORT` (default `8192`): host HTTP port exposed by router
28-
- `HTTPS_PORT` (default `443`): host TLS port exposed by router
57+
- `HTTP_PORT` (default `8192`): host HTTP port exposed by router
58+
- `HTTPS_PORT` (default `8193`): host TLS port exposed by router
59+
- `ORIGIN` (default `http://localhost:8192`): public origin used by the identity provider; set this explicitly when using non-default/public ports or hostnames
2960
- `PERIOD` (default `2`): journal periodicity exponent
3061
- `WINDOW` (default `1024`): retained historical state window
3162
- `JOURNAL_UPDATE` (default empty): set to `1` to update an existing journal database from the mounted Lisp files before serving
@@ -34,79 +65,59 @@ files. For an existing database, mounted Lisp files are only applied when
3465
- `ACME_WEBROOT_HOST_PATH` (default `./acme-challenge`): host directory mounted at `/var/www/acme-challenge` for HTTP-01 challenge files
3566
- `TLS_CERT_FILE` (default `/etc/nginx/certs/tls.crt`): in-container certificate path used by router
3667
- `TLS_KEY_FILE` (default `/etc/nginx/certs/tls.key`): in-container key path used by router
37-
- `SMB_PORT` (default `445`): host port exposed by the `file-system` service
38-
- `FILE_SYSTEM_IMAGE` (default `ghcr.io/sandialabs/sync-web/file-system:1.2.2`): image used by the optional `file-system` service
39-
- `SYNC_FS_Backend` (default `http-journal-stage`): file-system backend override
40-
- `SYNC_FS_JournalJsonUrl` (default `http://journal/interface`): direct journal JSON endpoint used by the default file-system backend
41-
- `SYNC_FS_GatewayBaseUrl` (default `http://gateway/api/v1`): gateway endpoint used only when gateway-backed file-system modes are selected
68+
- `FILE_SYSTEM_IMAGE` (default `ghcr.io/sandialabs/sync-web/file-system:1.3.0`): image used by the `file-system` service
69+
- `SYNC_FS_MAX_OBJECT_BYTES` (default `1048576`): maximum WebDAV object size
4270

4371
Gateway note:
72+
4473
- `ALLOW_ADMIN_ROUTES` is enabled by default in `deploy/compose/general/compose.yaml`.
4574
- Gateway landing page is exposed through the router at `/gateway`.
4675
- Public/client-facing API traffic should go to `gateway` under `/api/v1/general/*` and `/api/v1/root/*`.
76+
- WebDAV traffic is exposed through the router under `/webdav/`.
4777
- The raw `/interface` endpoint is still present for direct journal transport use and bridge-oriented internals.
4878
- The journal's periodic scheduler uses the raw root-step call `(*step* "<secret>")`, which depends on the merged `records/` root-step pipeline.
4979

50-
## TLS Behavior
80+
## TLS behavior
5181

5282
This stack uses one compose file. Router auto-selects mode at startup:
5383

5484
- HTTP mode: if TLS cert/key files are not present
5585
- TLS mode: if both `TLS_CERT_FILE` and `TLS_KEY_FILE` exist
5686

57-
`tests/api/local-compose.sh` forces HTTP mode by default (`LOCAL_COMPOSE_FORCE_HTTP=1`) for predictable local smoke runs.
58-
Set `LOCAL_COMPOSE_FORCE_HTTP=0` if you explicitly want TLS behavior during local-compose execution.
87+
`tests/api/local-compose.sh` forces HTTP mode by default (`LOCAL_COMPOSE_FORCE_HTTP=1`) for predictable local smoke runs. Set `LOCAL_COMPOSE_FORCE_HTTP=0` if you explicitly want TLS behavior during local-compose execution.
5988

6089
In TLS mode, router serves:
61-
- `80` for ACME HTTP-01 challenge path and HTTPS redirects
62-
- `443` for proxied application routes
6390

64-
This is certificate-provider agnostic. Only file paths are required.
91+
- container port `80` for ACME HTTP-01 challenge path and HTTPS redirects
92+
- container port `443` for proxied application routes
6593

66-
HTTP-only deployment (no TLS files configured):
94+
The host ports are controlled by `HTTP_PORT` and `HTTPS_PORT`.
6795

68-
```bash
69-
SECRET=password PORT=8192 \
70-
docker compose -f deploy/compose/general/compose.yaml up -d
71-
```
96+
The default compose stack mounts ACME webroot to `/var/www/acme-challenge`. Use `ACME_WEBROOT_HOST_PATH` to override where challenge files come from on the host.
7297

73-
With Podman Compose:
74-
75-
```bash
76-
SECRET=password PORT=8192 \
77-
podman-compose -f deploy/compose/general/compose.yaml up -d
78-
```
79-
80-
The default compose stack now mounts ACME webroot to `/var/www/acme-challenge`.
81-
Use `ACME_WEBROOT_HOST_PATH` to override where challenge files come from on the host.
82-
83-
Example:
98+
Example TLS-backed public stack:
8499

85100
```bash
101+
COMPOSE_PROJECT_NAME=sync-prod \
86102
TLS_CERT_HOST_PATH=/absolute/path/to/fullchain.pem \
87103
TLS_KEY_HOST_PATH=/absolute/path/to/privkey.pem \
88-
SECRET=password PORT=8192 \
89-
HTTPS_PORT=443 \
104+
SECRET=password ORIGIN=https://example.com HTTP_PORT=80 HTTPS_PORT=443 \
90105
docker compose -f deploy/compose/general/compose.yaml up -d
91106
```
92107

93-
## Local Runner
108+
## Local runner
94109

95110
Use the local helper from repository root:
96111

97112
```bash
98113
# Interactive run
99-
tests/api/local-compose.sh up
114+
COMPOSE_PROJECT_NAME=sync-local tests/api/local-compose.sh up
100115

101116
# Smoke test
102-
tests/api/local-compose.sh smoke
117+
COMPOSE_PROJECT_NAME=sync-local tests/api/local-compose.sh smoke
103118
```
104119

105-
The local compose helper enables the SMB file-system service by default.
106-
107-
The helper builds a local `journal-sdk` image and uses the same mounted Lisp/runtime
108-
script layout as the reference compose stack. It no longer builds a separate
109-
`general` image.
120+
The local compose helper defaults to `COMPOSE_PROJECT_NAME=sync-local`, `HTTP_PORT=8192`, and `HTTPS_PORT=8193`. It builds local service images, enables the WebDAV file-system service by default, and uses the same mounted Lisp/runtime script layout as the reference compose stack.
110121

111122
To override the file-system image during local development:
112123

@@ -115,8 +126,18 @@ FILE_SYSTEM_IMAGE=sync-web/local-file-system:1.0.0 tests/api/local-compose.sh up
115126
FILE_SYSTEM_IMAGE=sync-web/local-file-system:1.0.0 tests/api/local-compose.sh smoke
116127
```
117128

118-
## Manual Teardown
129+
## Teardown
130+
131+
Stop a stack without deleting data:
119132

120133
```bash
121-
docker compose -f deploy/compose/general/compose.yaml down -v
134+
COMPOSE_PROJECT_NAME=sync-dev docker compose -f deploy/compose/general/compose.yaml down
122135
```
136+
137+
Delete stack volumes only when you intentionally want to remove the journal database and identity-provider state:
138+
139+
```bash
140+
COMPOSE_PROJECT_NAME=sync-dev docker compose -f deploy/compose/general/compose.yaml down -v
141+
```
142+
143+
Do not run `down -v` against a public/prod `COMPOSE_PROJECT_NAME` unless you intend to destroy that stack's persisted data.

0 commit comments

Comments
 (0)