Skip to content

CI rehearsal only (do not merge) - #13

Open
michael-moffett wants to merge 6 commits into
mainfrom
pay-kit-89-m1-kotlin-runner-a2-next
Open

michael-moffett wants to merge 6 commits into
mainfrom
pay-kit-89-m1-kotlin-runner-a2-next

Conversation

@michael-moffett

Copy link
Copy Markdown
Member

Fork CI only. Do not merge.

michael-moffett and others added 2 commits October 2, 2026 07:36
…matrix

A Gradle stdin/stdout runner over the Kotlin SDK's protocol functions, plus `harness/protocol-runners/kotlin.json`, so the spawned-runner block drives Kotlin.

No protocol-layer vector reaches Kotlin today. Milestone 1 of our harness proposal puts Kotlin in the divergence matrix.
@greptile-apps

greptile-apps Bot commented Oct 2, 2026 •

Copy link
Copy Markdown

RetriggerConfidence Score: 2/5

[Medium risk] Adds a Kotlin test harness for protocol conformance.

The PR does not appear safe to merge while the Kotlin runner still fails valid challenge and credential cases.

Findings

  1. P1 Challenge description is dropped ▶
  2. P1 Plain opaque values fail parsing ▶
  3. P1 Hash payload is lost ▶
  4. P2 Gradle runs for every request ▶

Summary

This PR adds a spawned Kotlin protocol runner and changes the conformance tests to assert specific known divergences. The follow-up changes build the runner when launched and make credential decoding strict. The manifest now repeats the Gradle build step for each request.

Reviews (3) · Last reviewed commit: "greptile.json: review on request only"

Comment thread harness/protocol-runners/kotlin.json Outdated
Comment on lines +59 to +68
return buildJsonObject {
put("id", challenge.id)
put("realm", challenge.realm)
put("method", challenge.method)
put("intent", challenge.intent)
put("request", decodeJson(challenge.request))
challenge.expires?.let { put("expires", it) }
challenge.digest?.let { put("digest", it) }
challenge.opaque?.let { put("opaque", decodeJson(it)) }
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Challenge description is dropped When a valid header contains a top-level description, such as the canonical full_challenge, this response omits it. The parsed challenge no longer matches the expected object, and the basic-only runner test does not catch the difference.

put("request", decodeJson(challenge.request))
challenge.expires?.let { put("expires", it) }
challenge.digest?.let { put("digest", it) }
challenge.opaque?.let { put("opaque", decodeJson(it)) }

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Plain opaque values fail parsing The SDK treats opaque as a pass-through string. When a valid challenge contains a plain value such as trace-123, decoding it as base64url JSON throws, so the runner returns parse_error instead of the parsed challenge.

Suggested change
challenge.opaque?.let { put("opaque", decodeJson(it)) }
challenge.opaque?.let { put("opaque", it) }

val request = challenge["request"] ?: JsonObject(emptyMap())
val encoded = Base64.getUrlEncoder().withoutPadding().encodeToString(request.toString().encodeToByteArray())
val wire = JsonObject(credential + ("challenge" to JsonObject(challenge + ("request" to JsonPrimitive(encoded)))))
return MppHeaders.formatAuthorization(json.decodeFromJsonElement(PaymentCredential.serializer(), wire))

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Hash payload is lost The canonical credential_with_source case contains a valid hash payload. This code deserializes it while ignoring unknown fields, but the Kotlin payload type has no hash property. Formatting then emits an Authorization header without the hash value.

@greptile-apps

This comment has been minimized.

michael-moffett and others added 4 commits October 2, 2026 07:52
…in divergences pinned to exact responses, extended to the description and hash gaps, with a missing-binary test
… before exec, so a clean checkout can run it; divergence-map comment trimmed to the changed claim
@@ -0,0 +1,5 @@
{
"language": "kotlin",
"command": ["sh", "-c", "gradle -q installDist >&2 && exec build/install/mpp-kotlin-protocol-runner/bin/mpp-kotlin-protocol-runner"],

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Gradle runs for every request The spawned adapter starts a new process for each protocol case, so this command runs gradle installDist for every Kotlin request—about 13 times in the current suite. Even after the first build, repeated Gradle startup and build checks substantially slow the conformance run. Build the distribution once before running the cases, then launch the installed executable for each request.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

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