Commit Graph

3 Commits

Author SHA1 Message Date
agra
ea2cf14f48 P3.4a-001: ci publish loads existing db.json (cross-invocation persistence)
`dist ci publish` now seeds the Repo from a pre-existing <store>/db.json
before find-or-create, so separate CLI invocations share state: a new
version accumulates under the single found app, and re-publishing the same
release id is rejected by the P2.3 integrity transaction (db.json left
unchanged). An absent db.json still starts empty. The loaded model grows
through its owning allocator (context.allocator), per the long-lived rule.

Wiring db.load into the dist program (which already links manifest.sx)
exposed two latent issues, both fixed:
- db.sx's load-path helpers (dup_str/obj_find/req_obj/req_arr/
  artifact_from_json) collided by name with manifest.sx's same-named
  helpers; sx resolves bare top-level names across the whole program, so
  load_into bound to manifest's versions and failed the LoadErr error-set
  check. Renamed db.sx's five helpers with a db_ prefix (load-path only;
  save path and public API untouched).
- publish's `existing!.id` (only reachable once an app is found, i.e. never
  before this change) read garbage: sx miscompiles postfix-`!` chained with
  `.field`. Bound the unwrap to a local first, matching the codebase idiom.

tests/publish_persist.sx drives build/dist twice into one store: publish A,
then a different version B accumulates (two releases, one app, both objects),
then re-publishing A's id fails and leaves db.json unchanged. Fails on the
pre-fix write-only persistence, passes after.
2026-06-06 06:41:11 +03:00
agra
622ad91e26 P3.4a: dist ci publish happy path + persistence (manifest->store->validate->publish->db.json->JSON)
Real local publish success pipeline replacing the ci-publish stub: validate manifest,
find/create app + draft release, per-artifact content-address store (P2.2) + common
validation (P3.3) with optional manifest-declared size/sha256 (PO ruling), publish via
the repo integrity transaction with channel promotion + audit events (P2.3), persist
db.json (P2.3), emit stable JSON (release id, artifact ids, sha256, file:// URLs) with
--json purity. make publish-example target + tests/publish_happy.sx (fail-before/pass-after).

Salvaged from a worker that completed the work (make test 10/10) but hit the 50-min wall
before committing; manager-verified at ground truth (make test green, make publish-example
exit 0, stored object re-hashes to its key via shasum, db.json records release/2 artifacts/
channel/4 audit events).
2026-06-06 05:59:38 +03:00
agra
aa3b690381 P2.3: in-memory repository + db.json persistence (SQLite stand-in)
Adds the in-memory repository over the P2.1 domain and whole-model
persistence to <root>/db.json via std.json (subplan-02 Slice 1, the part
P2.1's mapping deferred).

src/repo/repo.sx
  - Repo over App/Release/Artifact/Channel/AuditEvent, each a growable
    List scanned LINEARLY (no index — Slice 1).
  - create/get/list/update per entity; find_app_by_slug;
    find_artifact_by_digest (the P2.2 content-address key).
  - publish(): atomic-ish transaction (release + artifacts + channel
    pointer). A failure midway rolls the model back by snapshot/restore —
    no half-inserted entities and no channel left pointing at a release
    that isn't in the repo.
  - Long-lived-container rule: init captures own_allocator :=
    context.allocator and every List growth forwards it explicitly, so the
    backing stores outlive any single call's transient context allocator.

src/repo/db.sx
  - save()/load() the whole model to/from <root>/db.json via std.json.
  - Stable (insertion-order) field order: entities emit in declaration
    order; top-level order is apps, releases, artifacts, channels,
    audit_events. Re-saving an unchanged model is byte-identical.
  - Enums serialize as their variant name. Read-back is strict: a missing
    field, wrong JSON type, or unknown enum name -> typed LoadErr.BadShape.
    Loaded strings are copied into the new repo's own allocator.

tests/
  - repo_roundtrip.sx: save -> reparse (valid JSON) -> reload into a fresh
    repo, asserting every field round-trips and a re-save is byte-identical.
  - repo_transaction.sx: a publish that fails midway leaves the model
    unchanged (no dangling release/channel), in memory and after reload.
  - repo_owns_allocator.sx: deterministic proof that every owned list grows
    through the captured allocator, not the call-site context allocator.

Gate: make build + make test both green (6/6).
2026-06-06 01:08:01 +03:00