Commit Graph

59 Commits

Author SHA1 Message Date
agra
3bc019c736 P2.2: fix put_file content-addressing — hash the published bytes (single source read)
put_file hashed the source path, then copied the source again — two reads.
A source mutated in between would publish bytes whose digest != returned key,
breaking the content-addressed invariant. Now copy the source once into a
provisional staging file, derive the key from the SHA-256 of that staged file
(the exact bytes published), then dedup/atomic-rename. Guarantees
key == digest(published object) with a single source read.

Extends the acceptance test: re-hashes the stored object and asserts it equals
the returned key (and std.hash / shasum of the fixture), asserts cross-path
dedup (put_file and put_bytes of identical content share one object), and
asserts the staging temp is cleaned up on both the success and dedup paths.
2026-06-06 00:47:45 +03:00
agra
68c002ab06 P2.2: content-addressed artifact store (staging -> atomic move, dedup)
Local blob store under src/store/, the first real consumer of std.hash.
Objects are addressed by lowercase-hex SHA-256: the digest is the storage
key and bytes live at <root>/objects/<sha256>.

- put_bytes / put_file compute the digest via std.hash, write to a
  staging file, then atomically rename into objects/<sha256>. The rename
  is the only step that publishes, so an interrupted/failed write never
  leaves a torn object at the final path.
- Dedup: an already-published object short-circuits without re-staging.
- stage_write/stage_copy + publish expose the two phases for the test.

tests/store_content_addressed.sx asserts the storage key equals std.hash,
an independent `shasum -a 256`, and the pinned SHA-256("abc") vector;
that dedup stores one object and never rewrites it; that a staged write
is invisible until publish and a failed publish leaves no object; and
that put_file round-trips bytes. Gate: make build + make test both green.
2026-06-06 00:34:21 +03:00
agra
b552958378 Merge branch 'flow/distribution/P2.1' into distribution-plan 2026-06-06 00:18:26 +03:00
agra
fd0ebd64f4 P2.1: record flow-step <-> subplan-slice scope mapping
Document the already-decided decomposition of subplan-02 Slice 1 so the
P2.1 boundary is verifiable from the repo:
- P2.1 = Core Structs + boundary validation (validation portion of Slice 1)
- P2.3 = in-memory repository + db.json (rest of Slice 1)
- Token = Slice 5 (Token Security), out of both

Planning-doc record only; no domain or test code changed.
2026-06-06 00:16:17 +03:00
agra
85f9c7c487 P2.1: address review — harden artifact validation, release/artifact fields
- validate_artifact: add empty content_type -> MissingField; size_bytes <= 0
  -> new BadSize; sha256 not exactly 64 lowercase-hex -> new BadDigest (via
  validate_sha256). The valid fixture (64-hex sha, positive size, non-empty
  content_type) stays accepted.
- Release: rename updated_at -> published_at (published_at = 0 means draft).
  Final order: id, app_id, version, build, channel, notes, created_by,
  created_at, published_at.
- Artifact: add opaque metadata: string before validation_status.
- tests: add empty-content_type/MissingField, bad-size/BadSize,
  malformed-sha256/BadDigest cases and contract pins reading back
  Release.published_at and Artifact.metadata.

PO-ruled out of scope and NOT added: Token model, in-memory repository (P2.3).
2026-06-06 00:09:21 +03:00
agra
c3897e3508 P2.1: domain structs + boundary validation
Add the core distribution domain model under src/domain/ (App, Release,
Artifact, Channel, AuditEvent + Platform/Visibility/ValidationStatus/
RolloutPolicy enums) and a boundary validator that returns one distinct
typed ValidationErr per failure class (BadSlug, EmptyVersion, BadVersion,
BadChannelName, UnknownPlatform, MissingField, BadRollout).

Pure sx, depends only on modules/std.sx; lookups left as linear scans over
List (no HashMap). tests/domain_validate.sx asserts valid App/Release/
Artifact/Channel are accepted and each invalid case is rejected with the
exact expected error tag.
2026-06-05 23:02:41 +03:00
agra
331a3e06dc Merge branch 'flow/distribution/P1.1' into distribution-plan 2026-06-03 17:24:09 +03:00
agra
e0f8b96d33 P1.1: repo skeleton + sx build/test gate
Stand up the foundation every later step depends on:

- Source layout: src/, src/infra/, tests/, examples/ (.gitkeep markers).
- Makefile: `build` compiles the smoke program via $SX, `test` runs the
  runner over tests/**/*.sx, `publish-example` placeholder (real in P3.4).
  Compiler located via `SX ?= /Users/agra/projects/sx/zig-out/bin/sx`.
- tests/run.sh: POSIX-sh runner; discovers tests/**/*.sx, runs each via
  `$SX run`, prints ok/FAIL, exits 0 only when all pass (errors on zero
  tests so the gate is never silently empty).
- tests/smoke.sx: passing smoke test importing modules/std.sx — proves
  toolchain wiring end-to-end (std resolves via the binary's own location).
- .gitignore: ignore build/ artifacts.
2026-06-03 17:18:19 +03:00
agra
055c8ced15 Baseline: distribution workspace before observability redesign 2026-06-02 16:12:15 +03:00