Skip to content

extdeps gcp.SecretManager: wire types carry GCP's real JSON keys (native broker class D) - #13147

Merged
gunbai-bot[bot] merged 1 commit into
mainfrom
loyal-gull-749/secret-manager-wire-keys
Oct 3, 2026
Merged

gunbai-bot[bot] merged 1 commit into
mainfrom
loyal-gull-749/secret-manager-wire-keys

Conversation

@gunbai-bot

@gunbai-bot gunbai-bot Bot commented Oct 3, 2026 •

Copy link
Copy Markdown
Contributor

Native broker wave 2D (program: gentle-dove-36), class D, part 1 of 2.

Re-derivation (DESIGN §6b)

Class D on the broker probe is REST typed response path could not be resolved against declared 200 body (v1.compiler.emit_rust emit_typed_wire_field_assign). Reading the slice shows it is two defects:

  • This PR: the emitter's refusal was correct. The native REST op deserializes the declared 200 body type with serde and projects each output's from path through it. Only a wire field's own from key names its JSON key, and the rest of extdeps.cloud.gcp already carries camelCase keys (gcp.dag, iam.dag). In secret_manager, GcpSecret.create_time, GcpSecretVersion.create_time/destroy_time and ListSecretVersionsResponse.next_page_token/total_size carried none, so serde would read "create_time" from a body that says "createTime". AccessVersion declared its 200 body as the bare SecretPayload { data: Bytes }, where the API returns AccessSecretVersionResponse { name, payload: { data } } and data is base64 text. The earliest unjustified boundary is the extdeps model (DESIGN §3: model what the API actually returns). The emitter is not touched.
  • Not this PR: outcome: RestOutcome has no native lowering at all. Ruled model-first by gentle-dove-36 and staffed as lane 2R (gentle-bee-744), with this lane's trace handed over.

Change (dag/extdeps/cloud/gcp/secret_manager.dag only)

  • from "createTime", from "destroyTime", from "nextPageToken", from "totalSize" on the wire fields.
  • New AccessSecretVersionResponse { name, payload: SecretPayload } is AccessVersion's 200 body. SecretPayload.data is String (base64 on the JSON wire; decoding stays in decode_sm_access_version_payload_wire). SecretPayload had no other consumer.
  • ListVersions.next_page_token and DestroyVersion.destroy_time outputs become String?. GCP omits the token on the last page and destroyTime under delayed destruction; the wire already declared both Optional. Neither output has a consumer.
  • Deliberately NOT keyed: SmRotationSchedule.rotation_period_seconds. GCP's rotationPeriod is a Duration string ("86400s"), so a from key there would assert a false wire fact. It is unconsumed and left as is.

Evidence (broker probe, one remote dispatch, local-only 1B hoist)

gunbc compile --entry dag/gunbc/auth/approval_broker_serve.dag --target rust then cargo check, at fd30a50 with and without this model change (measured together with #13154, whose files are disjoint):

  • removed: the 5 secret_manager path refusals (createTime, destroyTime, nextPageToken, payload/data, name).
  • exposed: one expected String, found Option<String> at DestroyVersion. The model fix above (destroy_time: String?) landed after that measurement and is not yet re-probed.
  • unchanged: the pre-existing GetVersion etag: String vs wire etag: String? E0308. Settling it needs a citation for whether GCP always returns a version etag, so it is left out of this PR.

Interpreter route: map_response_to_value_json walks the output from paths over the JSON body, and the declared 200 type does not enter it. The access/rotation witnesses construct output fields directly, so none of them reads a changed declaration.

🤖 Generated with Claude Code

…response shapes

Native emission projects typed REST outputs through the declared 200 body, and
five paths did not resolve because the model disagreed with the upstream
(Secret Manager v1): createTime, destroyTime, nextPageToken and totalSize had
no camelCase from-keys, and AccessVersion declared its 200 body as the bare
SecretPayload { data: Bytes } where GCP returns AccessSecretVersionResponse
{ name, payload { data: base64 string } }. ListVersions.next_page_token and
DestroyVersion.destroy_time become Optional, because GCP omits them (last page,
delayed destruction); neither has a consumer.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

@briansrls briansrls left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. The wire model now matches Secret Manager's REST shape: camelCase JSON keys, the AccessSecretVersionResponse envelope, base64 text at payload.data, and Optional outputs where the response can omit destroyTime or nextPageToken. This fixes the model at its owning boundary rather than weakening the emitter.

@gunbai-bot
gunbai-bot Bot added this pull request to the merge queue Oct 3, 2026
Merged via the queue into main with commit 6efd184 Oct 3, 2026
4 checks passed
@gunbai-bot
gunbai-bot Bot deleted the loyal-gull-749/secret-manager-wire-keys branch October 3, 2026 23:23
Sign up for free to 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