Final cleanup before beginning the MVP implementation

This commit is contained in:
2026-05-30 20:33:53 -05:00
parent 39548cefbe
commit 0818733b19
5 changed files with 56 additions and 13 deletions

7
.gitignore vendored
View File

@@ -1,3 +1,7 @@
# distributor binary and testing workspace
/distributor
/workspace
# ---> Go # ---> Go
# If you prefer the allow list template instead of the deny list, see community template: # If you prefer the allow list template instead of the deny list, see community template:
# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore # https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore
@@ -47,7 +51,8 @@ go.work.sum
.LSOverride .LSOverride
# Icon must end with two \r # Icon must end with two \r
Icon Icon
# Thumbnails # Thumbnails
._* ._*

View File

@@ -1,2 +1,5 @@
# go-application-template # distributor
`distributor` is a planned Go application for validating and publishing manifested Markdown bundles.
Implementation has not started yet. Current design and implementation planning lives under `docs/roadmap/`.

View File

@@ -477,7 +477,7 @@ pipelines:
destinations: destinations:
- id: markdown-archive - id: markdown-archive
backend: s3 backend: s3
endpoint: https://s3.maximumdirect.net endpoint: https://s3.example.com
bucket: reports bucket: reports
prefix: weather/archive prefix: weather/archive
region: us-east-1 region: us-east-1
@@ -491,7 +491,7 @@ pipelines:
- id: static-site - id: static-site
backend: ssh backend: ssh
uri: ssh://deploy@web.maximumdirect.net:22 uri: ssh://deploy@web.example.com:22
path: /srv/www/weather path: /srv/www/weather
publish: publish:
source: false source: false
@@ -514,7 +514,7 @@ pipelines:
destinations: destinations:
- id: private-markdown-archive - id: private-markdown-archive
backend: s3 backend: s3
endpoint: https://s3.maximumdirect.net endpoint: https://s3.example.com
bucket: reports bucket: reports
prefix: dnd/session-recaps prefix: dnd/session-recaps
region: us-east-1 region: us-east-1

View File

@@ -36,12 +36,12 @@ A source bundle is a directory containing a `manifest.json` file. For MVP, the m
{ {
"schema_version": 1, "schema_version": 1,
"id": "weather.daily.brentwood.2026-05-30", "id": "weather.daily.brentwood.2026-05-30",
"digest": "sha256:...", "digest": "sha256:0000000000000000000000000000000000000000000000000000000000000000",
"created": "2026-05-30T11:10:00Z", "created": "2026-05-30T11:10:00Z",
"files": [ "files": [
{ {
"path": "report.md", "path": "report.md",
"sha256": "sha256:...", "sha256": "sha256:1111111111111111111111111111111111111111111111111111111111111111",
"size": 12345 "size": 12345
} }
] ]
@@ -168,12 +168,12 @@ A destination bundle path is considered distributor-managed only when it contain
"manifest": { "manifest": {
"schema_version": 1, "schema_version": 1,
"id": "weather.daily.brentwood.2026-05-30", "id": "weather.daily.brentwood.2026-05-30",
"digest": "sha256:...", "digest": "sha256:0000000000000000000000000000000000000000000000000000000000000000",
"created": "2026-05-30T11:10:00Z", "created": "2026-05-30T11:10:00Z",
"files": [ "files": [
{ {
"path": "report.md", "path": "report.md",
"sha256": "sha256:...", "sha256": "sha256:1111111111111111111111111111111111111111111111111111111111111111",
"size": 12345 "size": 12345
} }
] ]
@@ -185,7 +185,7 @@ A destination bundle path is considered distributor-managed only when it contain
"kind": "generated", "kind": "generated",
"source_path": "report.md", "source_path": "report.md",
"transform": "markdown_to_html", "transform": "markdown_to_html",
"sha256": "sha256:...", "sha256": "sha256:3333333333333333333333333333333333333333333333333333333333333333",
"size": 23456 "size": 23456
} }
] ]

View File

@@ -29,7 +29,9 @@ File paths:
- must not contain backslashes; - must not contain backslashes;
- must not resolve outside the backend root. - must not resolve outside the backend root.
Prefix paths use the same slash-separated model. A prefix may be empty to represent the backend root for listing and destination emptiness checks. Prefix paths use the same slash-separated model. A prefix may be empty to represent the backend root for traversal and destination emptiness checks.
Prefix matching must preserve logical path boundaries. A prefix of `foo` matches `foo` and entries below `foo/`; it must not match a sibling path such as `foobar`. Backends that map logical paths to object keys must apply the same normalized boundary rule after combining configured backend prefixes with caller-provided logical prefixes.
Backends own conversion from logical paths to native paths or object keys. Core packages should not construct local filesystem paths, SFTP paths, or S3 object keys directly. Backends own conversion from logical paths to native paths or object keys. Core packages should not construct local filesystem paths, SFTP paths, or S3 object keys directly.
@@ -54,6 +56,34 @@ Byte helpers are expected to cover manifests, destination state, small source ar
Write operations should create required parent directories or prefixes as needed. Write operations should create required parent directories or prefixes as needed.
Concrete option and callback types should use this shape:
```go
type WalkOptions struct {
Recursive bool
Limit int
}
type WalkFunc func(Entry) error
var ErrStopWalk = errors.New("stop walk")
type WriteOptions struct {
ContentType string
Overwrite bool
PreferAtomic bool
Size int64
SizeKnown bool
}
type DeleteOptions struct {
IgnoreMissing bool
PruneEmptyDirs bool
}
```
`WalkOptions.Limit == 0` means no explicit limit. `SizeKnown` applies primarily to `WriteFrom`; byte writes can infer size from the provided data.
## Entries and Metadata ## Entries and Metadata
Storage metadata should be represented by an `Entry` model with at least: Storage metadata should be represented by an `Entry` model with at least:
@@ -69,13 +99,15 @@ Entry types:
- `symlink`: local filesystem symlink; - `symlink`: local filesystem symlink;
- `other`: unknown or unsupported native entry type. - `other`: unknown or unsupported native entry type.
`Stat` returns metadata for one logical path. `Stat` returns metadata for one exact logical path. It may report a real filesystem directory, symlink, file, or exact object. It must not synthesize S3-like directory metadata solely because objects exist below a prefix; callers that need prefix existence or destination emptiness must use `HasAny` or `Walk`.
`Walk` traverses entries below a prefix and calls a callback for each entry. `WalkOptions` should include: `Walk` traverses entries below a prefix and calls a callback for each entry. `WalkOptions` should include:
- whether traversal is recursive; - whether traversal is recursive;
- an optional entry limit for callers that only need to know whether content exists. - an optional entry limit for callers that only need to know whether content exists.
If a callback returns `ErrStopWalk`, traversal stops successfully and `Walk` returns nil. Any other callback error stops traversal and is returned with storage context where practical. If `WalkOptions.Limit` is greater than zero, reaching the limit stops traversal successfully.
Backends may stream or paginate traversal internally. S3-compatible adapters should not need to load a whole prefix into memory to satisfy traversal. Backends may stream or paginate traversal internally. S3-compatible adapters should not need to load a whole prefix into memory to satisfy traversal.
Raw traversal is not required to be lexically sorted. A helper that materializes walk results for bundle discovery, tests, or CLI output should sort entries lexically by logical path before returning them. Raw traversal is not required to be lexically sorted. A helper that materializes walk results for bundle discovery, tests, or CLI output should sort entries lexically by logical path before returning them.
@@ -102,7 +134,8 @@ Both read methods must:
- content type, when the destination backend can use it; - content type, when the destination backend can use it;
- overwrite permission; - overwrite permission;
- atomic or staged write preference. - atomic or staged write preference;
- optional known size for stream writes.
Backends own staging and atomic behavior where practical: Backends own staging and atomic behavior where practical:
@@ -110,6 +143,8 @@ Backends own staging and atomic behavior where practical:
- SSH/SFTP backend should use a temporary remote file and rename where available. - SSH/SFTP backend should use a temporary remote file and rename where available.
- S3-compatible backend treats a successful object PUT as publish-on-success and applies content type metadata. - S3-compatible backend treats a successful object PUT as publish-on-success and applies content type metadata.
Remote adapters may buffer or spool `WriteFrom` input when needed to satisfy backend requirements such as content length, multipart upload, or retry behavior. Callers that know the stream size should set `SizeKnown` and `Size`.
If overwrite is false and the target exists, writes should fail with an already-exists error. If overwrite is false and the target exists, writes should fail with an already-exists error.
`WriteFile` and `WriteFrom` should return the written `Entry`, including final path and size where available. `WriteFile` and `WriteFrom` should return the written `Entry`, including final path and size where available.