Skip to content

Feature s3-sink: hy-s3-1: @hypaware/s3 blob destination plugin (hy-myln) - #10

Merged
philcunliffe merged 1 commit into
integration/s3-sinkfrom
polecat/hy-myln
May 21, 2026
Merged

Feature s3-sink: hy-s3-1: @hypaware/s3 blob destination plugin (hy-myln)#10
philcunliffe merged 1 commit into
integration/s3-sinkfrom
polecat/hy-myln

Conversation

@philcunliffe

Copy link
Copy Markdown
Contributor

Summary

Feature s3-sink: hy-s3-1: @hypaware/s3 blob destination plugin

Implemented: @hypaware/s3 blob destination plugin. Plugin tree under hypaware-core/plugins-workspace/s3/ (manifest + config + keys + client + errors + index), bundled allowlist entry, AWS SDK v3 deps, 44 new unit tests across keys/config/client/errors, and a hermetic s3_sink_export_fixture smoke that drives one driver tick through an injected fake S3 client. Updated cli_bundled_plugins_activated to expect plugins_skipped=2 (format-jsonl + s3 now both skipped when not configured).

Delivery

  • Issue: hy-myln
  • Branch: polecat/hy-myln
  • Integration target: integration/s3-sink
  • Eventual target: master

This PR is auto-merged into the integration branch once CI is green. Human
review for the full feature happens on the downstream PR
(integration/s3-sink -> master), which is opened separately when the feature
is ready to ship.

Implements hy-s3-1: a bundled first-party plugin providing
hypaware.blob-store@1.0.0 and contributing the `s3` sink.
Plugin tree under hypaware-core/plugins-workspace/s3/:
- manifest declares network + read_env permissions and the s3 sink
- src/config.js: validates bucket/prefix/region/profile/storage_class/
server_side_encryption + endpoint_url/force_path_style; emits stable
s3_config_invalid errors
- src/keys.js: renders <prefix>/<dataset>/<segment>/<filename> matching
local-fs layout; normalizes prefix slashes; rejects keys outside the
configured prefix
- src/client.js: AWS SDK v3 wiring with injectable client factory and
a credential_source_kind detector that never leaks secret material
- src/errors.js: AWS SDK error -> stable error_kind mapping
(s3_credentials_missing, s3_access_denied, s3_bucket_missing,
s3_region_mismatch, s3_throttled, s3_put_failed, encoder_failed)
- src/index.js: sink composes ctx.query schema + ctx.storage rows + the
paired encoder; emits s3.client.init / s3.put_object /
s3.put_object.failed telemetry; closes terminal errors as
status=failed and surfaces transient failures as status=partial
Bundled wiring + dependencies:
- @hypaware/s3 added to V1_BUNDLED_PLUGIN_ALLOWLIST
- @aws-sdk/client-s3 + @aws-sdk/credential-provider-ini added to root
dependencies; npm pack --dry-run ships the new plugin tree
Tests (test/plugins/s3-*.test.js):
- s3-keys: key composition, prefix normalization, path-separator
stripping, within-prefix guard
- s3-config: required/optional fields, storage_class allowlist,
endpoint_url URL parsing, S3-compatible (MinIO) shape
- s3-client: credential_source_kind precedence + redaction contract
- s3-errors: full AWS SDK error -> stable kind mapping table
Hermetic smoke (s3_sink_export_fixture):
- Activates real format-parquet + s3 plugin trees with a fake injected
S3 client; fires one driver tick; asserts PutObject bucket/key/body,
decodes the body back into Parquet rows, and verifies the
s3.client.init / s3.put_object / sink.encode_partition telemetry
carries the expected attributes with no credential-shaped substring
Smoke fix (cli_bundled_plugins_activated):
- The allowlist now has 8 entries; the smoke selects 6, so
plugins_skipped is 2 and both format-jsonl and s3 emit
plugin.skipped logs
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@philcunliffe
philcunliffe merged commit 4864784 into integration/s3-sinkMay 21, 2026
6 checks passed
@philcunliffe
philcunliffe deleted the polecat/hy-myln branch May 21, 2026 20:16
philcunliffe added a commit that referenced this pull request May 22, 2026
* chore: seed integration/s3-sink for feature flow
* feat(s3): add @hypaware/s3 blob destination plugin (hy-myln) (#10)
Implements hy-s3-1: a bundled first-party plugin providing
hypaware.blob-store@1.0.0 and contributing the `s3` sink.
Plugin tree under hypaware-core/plugins-workspace/s3/:
- manifest declares network + read_env permissions and the s3 sink
- src/config.js: validates bucket/prefix/region/profile/storage_class/
server_side_encryption + endpoint_url/force_path_style; emits stable
s3_config_invalid errors
- src/keys.js: renders <prefix>/<dataset>/<segment>/<filename> matching
local-fs layout; normalizes prefix slashes; rejects keys outside the
configured prefix
- src/client.js: AWS SDK v3 wiring with injectable client factory and
a credential_source_kind detector that never leaks secret material
- src/errors.js: AWS SDK error -> stable error_kind mapping
(s3_credentials_missing, s3_access_denied, s3_bucket_missing,
s3_region_mismatch, s3_throttled, s3_put_failed, encoder_failed)
- src/index.js: sink composes ctx.query schema + ctx.storage rows + the
paired encoder; emits s3.client.init / s3.put_object /
s3.put_object.failed telemetry; closes terminal errors as
status=failed and surfaces transient failures as status=partial
Bundled wiring + dependencies:
- @hypaware/s3 added to V1_BUNDLED_PLUGIN_ALLOWLIST
- @aws-sdk/client-s3 + @aws-sdk/credential-provider-ini added to root
dependencies; npm pack --dry-run ships the new plugin tree
Tests (test/plugins/s3-*.test.js):
- s3-keys: key composition, prefix normalization, path-separator
stripping, within-prefix guard
- s3-config: required/optional fields, storage_class allowlist,
endpoint_url URL parsing, S3-compatible (MinIO) shape
- s3-client: credential_source_kind precedence + redaction contract
- s3-errors: full AWS SDK error -> stable kind mapping table
Hermetic smoke (s3_sink_export_fixture):
- Activates real format-parquet + s3 plugin trees with a fake injected
S3 client; fires one driver tick; asserts PutObject bucket/key/body,
decodes the body back into Parquet rows, and verifies the
s3.client.init / s3.put_object / sink.encode_partition telemetry
carries the expected attributes with no credential-shaped substring
Smoke fix (cli_bundled_plugins_activated):
- The allowlist now has 8 entries; the smoke selects 6, so
plugins_skipped is 2 and both format-jsonl and s3 emit
plugin.skipped logs
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(s3): return retryPartitions on terminal failure (hy-dq5u) (#15)
Address the major review finding on PR #7: the s3 sink's `exportBatch`
terminal-failure return (`s3_credentials_missing`, `s3_access_denied`,
`s3_bucket_missing`, `s3_region_mismatch`, `s3_config_invalid`) omitted
`retryPartitions`. The sink driver at `src/core/sinks/driver.js:146`
falls back to the entire batch in that case, so a terminal error
landing on partition N caused the driver to outbox every partition in
the batch — including the N-1 partitions that had already been PUT to
S3. Subsequent retries would then double-export those objects.
Return `retryPartitions: failures` so the driver outboxes only the
partitions that actually failed. `failures` always has at least one
entry when `lastConfigFailure` is set because both are pushed in the
same catch block.
Adds `test/plugins/s3-export-batch.test.js` covering the terminal,
partial, and all-success exit paths, exercised through the real
`activate` registration path with an injected `__clientFactory`.
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: feature-launch <feature-launch@gas.city>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@philcunliffe